### Install QTI Components Source: https://github.com/citolab/qti-components/blob/main/docs/hi-qti.mdx Use npm to install the QTI Components package. This is the first step before importing the web components. ```sh npm install @citolab/qti-components ``` -------------------------------- ### Install Dependencies Source: https://github.com/citolab/qti-components/blob/main/AGENTS.md Use this command to install all project dependencies. ```bash pnpm install ``` -------------------------------- ### Start Interactions Storybook Only Source: https://github.com/citolab/qti-components/blob/main/AGENTS.md Launches the Storybook instance specifically for the QTI interaction package. ```bash pnpm storybook:interactions ``` -------------------------------- ### Start Root Storybook and CEM Watch Source: https://github.com/citolab/qti-components/blob/main/AGENTS.md Starts the main Storybook instance and the CEM (Component, Element, Module) watch process for the entire repository. ```bash pnpm storybook ``` -------------------------------- ### qti-graphic-gap-match-interaction Drag and Drop Setup Source: https://github.com/citolab/qti-components/blob/main/packages/interactions/core/src/mixins/drag-drop/drag-drop.md Illustrates the HTML structure for a qti-graphic-gap-match-interaction, featuring slots for prompts, draggable images, and hotspots. ```html prompt Choice D, Bay of Pigs ``` -------------------------------- ### qti-order-interaction Drag and Drop Setup Source: https://github.com/citolab/qti-components/blob/main/packages/interactions/core/src/mixins/drag-drop/drag-drop.md Shows the HTML structure for a qti-order-interaction, defining slots for prompts, draggable choices, and a droppable list. ```html prompt
Rubens <-- drag Jenson <-- drag Michael <-- drag
{ <-- drop correctResponse }
``` -------------------------------- ### qti-associate-interaction Drag and Drop Setup Source: https://github.com/citolab/qti-components/blob/main/packages/interactions/core/src/mixins/drag-drop/drag-drop.md Shows the HTML structure for a qti-associate-interaction, with slots for prompts, draggable choices, and distinct droppable areas. ```html prompt Antonio Capulet Demetrius
{
}
``` -------------------------------- ### qti-match-interaction Drag and Drop Setup Source: https://github.com/citolab/qti-components/blob/main/packages/interactions/core/src/mixins/drag-drop/drag-drop.md Illustrates the HTML structure for a qti-match-interaction using slots for prompts and draggable/droppable choices within simple match sets. ```html prompt Capulet <-- drag Demetrius <-- drag A Midsummer-Night's <-- drop Romeo and Juliet <-- drop ``` -------------------------------- ### qti-gap-match-interaction Drag and Drop Setup Source: https://github.com/citolab/qti-components/blob/main/packages/interactions/core/src/mixins/drag-drop/drag-drop.md Defines the HTML structure for a qti-gap-match-interaction, with slots for prompts, draggable gap texts, and droppable gaps. ```html prompt winter <-- drag spring <-- drag summer <-- drag autumn <-- drag

Now is the of our discontent
Made glorious by this sun of York;
And all the clouds that lour'd upon our house
In the deep bosom of the ocean buried.

``` -------------------------------- ### Simplified GET and POST Requests Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Provides simplified interfaces for making GET and POST requests. These methods abstract away some of the complexity of the core AJAX function. ```javascript n.each(['get', 'post'], function (a, b) { n[b] = function (a, c, d, e) { return ( n.isFunction(c) && ((e = e || d), (d = c), (c = void 0)), n.ajax(n.extend({ url: a, type: b, dataT ); }; }) ``` -------------------------------- ### Handle Touch Start Event Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Initializes touch event tracking by storing the touch coordinates. This is a precursor to handling touch move and end events. ```javascript if (void 0 === a.changedTouches) return void this._mousedown(a); var b = a.changedTouches[0]; (this.touchX = b.pageX), (this.touchY = b.pageY); ``` -------------------------------- ### Register Web Components Source: https://github.com/citolab/qti-components/blob/main/readme.md Import and register the web components in your JavaScript application to enable the rendering of QTI items. This step is necessary after installing via npm. ```javascript import '@citolab/qti-components'; ``` -------------------------------- ### Get Default Options for BMI-meter Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Retrieves the default configuration options for the BMI-meter component. ```javascript (c.prototype.getDefaults = function () { return c.DEFAULTS; }) ``` -------------------------------- ### QTI Gap Match Interaction Example Source: https://github.com/citolab/qti-components/blob/main/packages/interactions/core/src/mixins/drag-drop-observables/drag-drop.md Illustrates a QTI gap match interaction where gap text elements are draggable and gap elements are the drop targets. Does not use clone drags. ```html prompt winter <-- drag spring <-- drag summer <-- drag autumn <-- drag

Now is the of our discontent
Made glorious by this sun of York; And all the clouds that lour'd upon our house In the deep bosom of the ocean buried.

``` -------------------------------- ### jQuery Animation Setup Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Configures jQuery's animation speed and default settings. It allows setting custom durations, easing functions, and completion callbacks for animations. ```javascript (n.Animation = n.extend(_a, { tweeners: { '*': [ function (a, b) { var c = this.createTween(a, b); return W(c.elem, a, T.exec(b), c), c; } ] }, tweener: function (a, b) { n.isFunction(a) ? ((b = a), (a = ['*'])) : (a = a.match(G)); for (var c, d = 0, e = a.length; e > d; d++) (c = a[d]), (_a.tweeners[c] = _a.tweeners[c] || []), _a.tweeners[c].unshift(b); }, prefilters: [Za], prefilter: function (a, b) { b ? _a.prefilters.unshift(a) : _a.prefilters.push(a); } })), (n.speed = function (a, b, c) { var d = a && 'object' == typeof a ? n.extend({}, a) : { complete: c || (!c && b) || (n.isFunction(a) && a), duration: a, easing: (c && b) || (b && !n.isFunction(b) && b) }; return ( ((d.duration = n.fx.off ? 0 : 'number' == typeof d.duration ? d.duration : d.duration in n.fx.speeds ? n.fx.speeds[d.duration] : n.fx.speeds._default), (null != d.queue && d.queue !== !0) || (d.queue = 'fx'), (d.old = d.complete), (d.complete = function () { n.isFunction(d.old) && d.old.call(this), d.queue && n.dequeue(this, d.queue); }), d ); }); ``` -------------------------------- ### Queue Management: .queue() Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/index.html Manage the queue of functions to be executed for a specific element and event queue (default 'fx'). Use .queue() to get the current queue, or to add a function to it. Ensure proper handling of 'inprogress' states for animations. ```javascript d.queue(this, e, t) ``` -------------------------------- ### Handle CSS Properties and Styles Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Provides utilities for getting and setting CSS properties, including handling vendor prefixes and complex calculations like pixel margins and widths. Use this for reliable style manipulation across different browsers. ```javascript createElement('div'); if (h.style) { (h.style.backgroundClip = 'content-box'), (h.cloneNode(!0).style.backgroundClip = ''), (l.clearCloneStyle = 'content-box' === h.style.backgroundClip), (g.style.cssText = 'border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute'), g.appendChild(h); function i() { (h.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%'), (h.innerHTML = ''), Ea.appendChild(g); var d = a.getComputedStyle(h); (b = '1%' !== d.top), (f = '2px' === d.marginLeft), (c = '4px' === d.width), (h.style.marginRight = '50%'), (e = '4px' === d.marginRight), Ea.removeChild(g); } n.extend(l, { pixelPosition: function () { return i(), b; }, boxSizingReliable: function () { return null == c && i(), c; }, pixelMarginRight: function () { return null == c && i(), e; }, reliableMarginLeft: function () { return null == c && i(), f; }, reliableMarginRight: function () { var b, c = h.appendChild(d.createElement('div')); return ( (c.style.cssText = h.style.cssText = '-webkit-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0'), (c.style.marginRight = c.style.width = '0'), (h.style.width = '1px'), Ea.appendChild(g), (b = !parseFloat(a.getComputedStyle(c).marginRight)), Ea.removeChild(g), h.removeChild(c), b ); } }); } ``` -------------------------------- ### FacetCommunication Class for QTI Player Interaction Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Handles communication with the QTI player, including getting and setting responses. It finds the CES object in the window or parent window and binds a reset event handler. ```javascript var FacetCommunication = (function () { function FacetCommunication(initialResponse, resetElement) { this.ces = null; this.initialResponse = null; if (window['CES']) { this.ces = window['CES']; } else if (window.parent['CES']) { this.ces = window.parent['CES']; } if (this.ces) { this.initialResponse = initialResponse; if (resetElement != null) resetElement.addEventListener('click', this.resetResponse.bind(this)); } else { console.log('No player found. No communication possible with QTI-Player'); } } FacetCommunication.prototype.getResponse = function () { var response = null; if (this.ces) { if (this.ces.getResponse() != undefined && this.ces.getResponse() != '') { try { response = JSON.parse(this.ces.getResponse()); } catch (e) { console.log('Not a valid response : ' + e); } } else { console.log('Empty response'); } } else { console.log('No player found'); } return response; }; FacetCommunication.prototype.setResponse = function (model, answer) { if (answer === void 0) { answer = null; } var responseArray = []; var modelSerialized = null; try { if (model) modelSerialized = JSON.stringify(model); else modelSerialized = ''; } catch (e) { console.log('Not a valid model : ' + e); } responseArray.push(modelSerialized); if (answer != null && answer.constructor === Array) { responseArray = responseArray.concat(answer); } if (modelSerialized != null) { if (this.ces) { console.log('setAnswer'); this.ces.setResponse(modelSerialized); } else { console.log('setResponse : No communication possible with QTI-Player'); console.log('answer from CI was : ' + modelSerialized); } } }; FacetCommunication.prototype.resetResponse = function (e) { if (e === void 0) { e = null; } this.setResponse(this.initialResponse); }; return FacetCommunication; })(); ``` -------------------------------- ### jQuery Queue and Dequeue Plugin Methods Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Extends jQuery.fn to provide chainable methods for managing element queues. Use `.queue()` to set or get a queue, and `.dequeue()` to advance to the next item. ```javascript n.fn.extend({ queue: function (a, b) { var c = 2; return ( 'string' != typeof a && ((b = a), (a = 'fx'), c--) ), arguments.length < c ? n.queue(this[0], a) : void 0 === b ? this : this.each(function () { var c = n.queue(this, a, b); n._queueHooks(this, a), 'fx' === a && 'inprogress' !== c[0] && n.dequeue(this, a); }) ); }, dequeue: function (a) { return this.each(function () { n.dequeue(this, a); }); }, clearQueue: function (a) { return this.queue(a || 'fx', []); }, promise: function (a, b) { var c, d = 1, e = n.Deferred(), f = this, g = this.length, h = function () { --d || e.resolveWith(f, [f]); }; 'string' != typeof a && ((b = a), (a = void 0)), (a = a || 'fx'); while (g--) (c = N.get(f[g], a + 'queueHooks')), c && c.empty && (d++, c.empty.add(h)); return h(), e.promise(b); } }); ``` -------------------------------- ### Function Proxying and Guid Generation Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/index.html Creates a new function that, when called, has its 'this' keyword set to a provided value. Also manages a unique GUID for functions. ```javascript guid: 1, ``` ```javascript proxy: function (e, t) { var n, r, o; return ( 'string' == typeof t && ((n = e[t]), (t = e), (e = n)), d.isFunction(e) ? ((r = i.call(arguments, 2)), ((o = function () { return e.apply(t || this, r.concat(i.call(arguments))); }).guid = e.guid = e.guid || d.guid++), o) : void 0 ); } ``` -------------------------------- ### Get and Set CSS Properties Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Provides functions to get and set CSS properties of an element, including handling different units and box-sizing models. Use this for direct manipulation of element styles. ```javascript css: function (a, b, c, d) { var e, f, g, h = n.camelCase(b); return ( (b = n.cssProps[h] || (n.cssProps[h] = Ma(h) || h)), (g = n.cssHooks[b] || n.cssHooks[h]), g && 'get' in g && (e = g.get(a, !0, c)), void 0 === e && (e = Fa(a, b, d)), 'normal' === e && b in Ja && (e = Ja[b]), '' === c || c ? ((f = parseFloat(e)), c === !0 || isFinite(f) ? f || 0 : e) : e ); } ``` -------------------------------- ### Get and Set Form Element Values with jQuery Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Handles getting and setting values for various form elements like select, radio, and checkbox. Includes specific hooks for options and select elements. ```javascript n.fn.extend({ val: function (a) { var b, c, d, e = this[0] { if (arguments.length) return ( (d = n.isFunction(a)), this.each(function (c) { var e 1 === this.nodeType && ((e = d ? a.call(this, c, n(this).val()) : a), null == e ? (e = '') : 'number' == typeof e ? (e += '') : n.isArray(e) && (e = n.map(e, function (a) { return null == a ? '' : a + '' })), (b = n.valHooks[this.type] || n.valHooks[this.nodeName.toLowerCase()]), (b && 'set' in b && void 0 !== b.set(this, e, 'value')) || (this.value = e)) }) ) if (e) return ( (b = n.valHooks[e.type] || n.valHooks[e.nodeName.toLowerCase()]), b && 'get' in b && void 0 !== (c = b.get(e, 'value')) ? c : ((c = e.value), 'string' == typeof c ? c.replace(gb, '') : null == c ? '' : c) ) } } }), n.extend({ valHooks: { option: { get: function (a) { var b = n.find.attr(a, 'value') return null != b ? b : n.trim(n.text(a)).replace(hb, ' ') } }, select: { get: function (a) { for ( var b, c, d = a.options, e = a.selectedIndex, f = 'select-one' === a.type || 0 > e, g = f ? null : [], h = f ? e + 1 : d.length, i = 0 > e ? h : f ? e : 0; h > i; i++ ) if ( ((c = d[i]), (c.selected || i === e) && (l.optDisabled ? !c.disabled : null === c.getAttribute('disabled')) && (!c.parentNode.disabled || !n.nodeName(c.parentNode, 'optgroup'))) ) { if (((b = n(c).val()), f)) return b g.push(b) } return g }, set: function (a, b) { var c, d, e = a.options, f = n.makeArray(b), g = e.length while (g--) (d = e[g]), (d.selected = n.inArray(n.valHooks.option.get(d), f) > -1) && (c = !0) return c || (a.selectedIndex = -1), f } } } }), n.each(['radio', 'checkbox'], function () { (n.valHooks[this] = { set: function (a, b) { return n.isArray(b) ? (a.checked = n.inArray(n(a).val(), b) > -1) : void 0 } }), l.checkOn || (n.valHooks[this].get = function (a) { return null === a.getAttribute('value') ? 'on' : a.value }) }); ``` -------------------------------- ### Get Keycode for Comma Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/index.html Returns the keycode value for the comma character (44). ```javascript getkeycodeComma() { return 44; } ``` -------------------------------- ### Import QTI Web Components Source: https://github.com/citolab/qti-components/blob/main/docs/hi-qti.mdx Import the necessary QTI web components into your project. This includes core components and specific test navigation components. ```js import '@citolab/qti-components/qti-components'; import '@citolab/qti-components/qti-test/core'; import '@citolab/qti-components/qti-test/components/test-next'; import '@citolab/qti-components/qti-test/components/test-prev'; ``` -------------------------------- ### Controller Class Initialization Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/index.html Initializes the Controller and FacetCommunication, and sets up the ViewModel and data handling. ```javascript var ctrl, FacetCommunication = com.cito.custominteraction.communication.FacetCommunication; class ViewModel { constructor() { this.data = []; } } window.onload = function() { ctrl = new Controller(); }; class Controller { constructor() { (this.placeTopRowTooltipBottom = !1), (this.decimalsAllowed = !0), (this.maxlength = 5), (this.copyPasteAllowed = !0), (this.copiedText = ''), document.getElementById('help').addEventListener('click', this.help.bind(this)); var e = document.getElementById('reset'); e.addEventListener('click', this.reset.bind(this)), (this.facetCommunication = new FacetCommunication(e)), (this.viewModel = this.facetCommunication.getResponse()), this.viewModel ? (this.data = this.viewModel.data) : (this.viewModel = new ViewModel()), this.setMaxlength(), this.data ? this.restoreData(this.data) : this.initializeData(), this.setClassesForTooltipPlacement; } } ``` -------------------------------- ### Get Element Offset Left Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Retrieves the left offset of an element relative to the viewport. ```javascript function (a) { return a.getBoundingClient ``` -------------------------------- ### Build All Packages Source: https://github.com/citolab/qti-components/blob/main/AGENTS.md Compiles and builds all packages within the monorepo. ```bash pnpm build ``` -------------------------------- ### Get Element Dimensions Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Determines the dimensions of an element, handling different node types and browser compatibility. ```javascript ow(b) ? b.document.documentElement['client' + a] : 9 === b.nodeType ? ((e = b.documentElement), Math.max( b.body['scroll' + a], e['scroll' + a], b.body['offset' + a], e['offset' + a], e['client' + a] )) : void 0 === d ? n.css(b, c, g) : n.style(b, c, d, g); }, b, f ? d : void 0, f, null ); }; }); ``` -------------------------------- ### Get Number of Decimal Places Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Calculates the number of digits after the decimal point in a number, considering scientific notation. ```javascript function (a) { var b = ('' + a).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/); return b ? Math.max(0, (b[1] ? b[1].length : 0) - (b[2] ? +b[2] : 0)) : 0; } ``` -------------------------------- ### Get Delegate Options for BMI-meter Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Constructs an options object for delegated events, excluding any options that match the defaults. ```javascript (c.prototype.getDelegateOptions = function () { var b = {}, c = this.getDefaults(); return ( this._options && a.each(this._options, function (a, d) { c[a] != d && (b[a] = d); }), b ); }) ``` -------------------------------- ### Create a Changeset Source: https://github.com/citolab/qti-components/blob/main/docs/publishing.mdx Use this command to initiate the creation of a new changeset file, which records changes for versioning and changelog generation. ```bash pnpm run changeset ``` -------------------------------- ### Configure AJAX Settings Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Sets up default AJAX settings and allows for merging custom configurations. Use this to define global defaults for all AJAX requests. ```javascript ajaxSetup: function (a, b) { return b ? yb(yb(a, n.ajaxSettings), b) : yb(n.ajaxSettings, a); } ``` -------------------------------- ### FacetCommunication Class Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/index.html Manages communication with the QTI Player using the CES API. Handles setting and getting responses, and resetting them. ```javascript var com; !(function(e) { !(function(e) { !(function(e) { !(function(e) { var s = (function() { function e(e, s) { (this.ces = null), (this.initialResponse = null), window.CES ? (this.ces = window.CES) : window.parent.CES && (this.ces = window.parent.CES), this.ces ? (e instanceof HTMLElement ? (s = e) : (this.initialResponse = e), null != s && s.addEventListener('click', this.resetResponse.bind(this))) : console.log('No player found. No communication possible with QTI-Player'); } return ( (e.prototype.getResponse = function() { var e = null; if (this.ces) if (void 0 !== this.ces.getResponse() && '' !== this.ces.getResponse()) try { e = JSON.parse(this.ces.getResponse()); } catch (e) { console.log('Not a valid response : ' + e); } else console.log('Empty response'); else console.log('No player found'); return e; }), (e.prototype.setResponse = function(e) { var s = null; try { s = e ? JSON.stringify(e) : ''; } catch (e) { console.log('Not a valid model : ' + e); } null != s && (this.ces ? s === JSON.stringify(this.initialResponse) ? this.ces.setResponse('') : (console.log('setAnswer'), this.ces.setResponse(s)) : (console.log('setResponse : No communication possible with QTI-Player'), console.log('answer from CI was : ' + s))); }), (e.prototype.resetResponse = function(e) { void 0 === e && (e = null), this.setResponse(this.initialResponse); }), e ); })(); e.FacetCommunication = s; })(e.communication || (e.communication = {})); })(e.custominteraction || (e.custominteraction = {})); })(e.cito || (e.cito = {})); })(com || (com = {})); ``` -------------------------------- ### Run Test Pipeline Source: https://github.com/citolab/qti-components/blob/main/AGENTS.md Executes the standard test suite across all packages. ```bash pnpm test ``` -------------------------------- ### Get Offset Parent Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Extends jQuery to find the closest positioned ancestor of an element. This is crucial for understanding positioning contexts. ```javascript offsetParent: function () { return this.map(function () { var a = this.offsetParent; while (a && 'static' === n.css(a, 'position')) a = a.offsetParent; return a || Ea; }); } ``` -------------------------------- ### Import Components via CDN Source: https://github.com/citolab/qti-components/blob/main/readme.md Use this script to import the web components directly from a CDN. This is useful for quick integration without a build process. ```html ``` -------------------------------- ### Initialize BMI-meter Component Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Initializes the BMI-meter component, setting up event listeners for click, hover, and focus events. It throws an error if the 'selector' option is not provided when initializing on the window.document object. ```javascript this.init = function () { if (void 0 === this.options.viewport ? this.options.viewport = a(document.viewport || document.body) : 'string' == typeof this.options.viewport && (this.options.viewport = a(this.options.viewport)), (this.inState = { click: !1, hover: !1, focus: !1 }), this.$element[0] instanceof document.constructor && !this.options.selector) throw new Error( '\`selector\` option must be specified when initializing ' + this.type + ' on the window.document object!' ); for (var e = this.options.trigger.split(' '), f = e.length; f--; ) { var g = e[f]; if ('click' == g) this.$element.on('click.' + this.type, this.options.selector, a.proxy(this.toggle, this)); else if ('manual' != g) { var h = 'hover' == g ? 'mouseenter' : 'focusin', i = 'hover' == g ? 'mouseleave' : 'focusout'; this.$element.on(h + '.' + this.type, this.options.selector, a.proxy(this.enter, this)), this.$element.on(i + '.' + this.type, this.options.selector, a.proxy(this.leave, this)); } } this.options.selector ? (this._options = a.extend({}, this.options, { trigger: 'manual', selector: '' })) : this.fixTitle(); } ``` -------------------------------- ### Publish Packages Locally Source: https://github.com/citolab/qti-components/blob/main/docs/publishing.mdx Use this command to perform a local publish of packages, typically for testing the publishing process before a full release. ```bash pnpm run changeset:publish ``` -------------------------------- ### Check if Highlight Range is Valid Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Validates if the provided start and end values for a highlight range are within the acceptable bounds (0 to 100). ```javascript a >= 0 && 100 >= a && b >= 0 && 100 >= b ? !0 : !1; ``` -------------------------------- ### Bootstrap Affix Plugin Initialization Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Initializes the Bootstrap affix plugin for elements that need to stick to the viewport. Configure with 'offset' for scroll-based positioning. ```javascript var d = a.fn.affix; (a.fn.affix = b), (a.fn.affix.Constructor = c), (a.fn.affix.noConflict = function () { return (a.fn.affix = d), this; }); a(window).on('load', function () { a('[data-spy="affix"]').each(function () { var c = a(this), d = c.data(); (d.offset = d.offset || {}), null != d.offsetBottom && (d.offset.bottom = d.offsetBottom), null != d.offsetTop && (d.offset.top = d.offsetTop), b.call(c, d); }); }); ``` -------------------------------- ### Preview Pending Releases Source: https://github.com/citolab/qti-components/blob/main/docs/publishing.mdx This command shows a summary of the changes that will be included in the next release, based on the existing changeset files. ```bash pnpm run changeset:status ``` -------------------------------- ### Fade In/Out Animation Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Provides a convenient method for fading an element to a specific opacity. It ensures the element is visible before starting the fade animation. ```javascript n.fn.extend({ fadeTo: function (a, b, c, d) { return this.filter(V).css('opacity', 0).show().end().animate({ opacity: b }, a, c, d); }, animate: function (a, b, c, d) { var e = n.isEmptyObject(a), f = n.speed(b, c, d), g = function () { var b = _a(this, n.extend({}, a), f); (e || N.get(this, 'finish')) && b.stop(!0); }; return (g.finish = g), e || f.queue === !1 ? this.each(g) : this.queue(f.queue, g); }, stop: function (a, b, c) { var d = function (a) { var b = a.stop; delete a.stop; b(c); }; return ('string' != typeof a && ((c = b), (b = a), (a = void 0)), b && a !== !1 && this.queue(a || 'fx', []), this.each(function () { var b = !0, e = null != a && a + 'queueHooks', f = n.timers, g = N.get(this); if (e) g[e] && g[e].stop && d(g[e]); else for (e in g) g[e] && g[e].stop && Va.test(e) && d(g[e]); for (e = f.length; e--; ) f[e].elem !== this || (null != a && f[e].queue !== a) || (f[e].anim.stop(c), (b = !1)); })); } }); ``` -------------------------------- ### Get Active Element Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Safely retrieves the currently active element in the document. Returns the element or null if an error occurs or no element is active. ```javascript function ia() { try { return d.activeElement; } catch (a) {} } ``` -------------------------------- ### Bootstrap Affix Plugin Constructor Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/index.html Defines the Affix plugin constructor. It initializes the plugin with options and attaches it to the target element. Use this for custom affix implementations. ```javascript function e(e) { return this.each(function () { var o = t(this), n = o.data('bs.affix'), s = 'object' == typeof e && e; n || o.data('bs.affix', (n = new i(this, s))), 'string' == typeof e && n[e](); }); } ``` -------------------------------- ### Bootstrap Tooltip Plugin Initialization Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/index.html Initializes the Bootstrap tooltip plugin, handling hover and focus triggers. Includes options for placement, template, and delay. Requires 'selector' for window.document initialization. ```javascript var e = function (t, e) { (this.type = null), (this.options = null), (this.enabled = null), (this.timeout = null), (this.hoverState = null), (this.$element = null), (this.inState = null), this.init('tooltip', t, e); }; (e.VERSION = '3.3.6'), (e.TRANSITION_DURATION = 150), (e.DEFAULTS = { animation: !0, placement: 'top', selector: !1, template: '', trigger: 'hover focus', title: '', delay: 0, html: !1, container: !1, viewport: { selector: 'body', padding: 0 } }), (e.prototype.init = function (e, i, o) { if ( ((this.enabled = !0), (this.type = e), (this.$element = t(i)), (this.options = this.getOptions(o)), (this.$viewport = this.options.viewport && t( t.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : this.options.viewport.selector || this.options.viewport )), (this.inState = { click: !1, hover: !1, focus: !1 }), this.$element[0] instanceof document.constructor && !this.options.selector ) ) throw new Error( '`selector` option must be specified when initializing ' + this.type + ' on the window.document object!' ); for (var n = this.options.trigger.split(' '), s = n.length; s--; ) { var a = n[s]; if ('click' == a) this.$element.on('click.' + this.type, this.options.selector, t.proxy(this.toggle, this)); else if ('manual' != a) { var r = 'hover' == a ? 'mouseenter' : 'focusin', l = 'hover' == a ? 'mouseleave' : 'focusout'; this.$element.on(r + '.' + this.type, this.options.selector, t.proxy(this.enter, this)), this.$element.on(l + '.' + this.type, this.options.selector, t.proxy(this.leave, this)); } } this.options.selector ? (this._options = t.extend({}, this.options, { trigger: 'manual', selector: '' })) : this.fixTitle(); }), (e.prototype.getDefaults = function () { return e.DEFAULTS; }), (e.prototype.getOptions = function (e) { return ( (e = t.extend({}, this.getDefaults(), this.$element.data(), e)).delay && 'number' == typeof e.delay && (e.delay = { show: e.delay, hide: e.delay }), e ); }), (e.prototype.getDelegateOptions = function () { var e = {}, i = this.getDefaults(); return ( this._options && t.each(this._options, function (t, o) { i[t] != o && (e[t] = o); }), e ); }), (e.prototype.enter = function (e) { var i = e instanceof this.constructor ? e : t(e.currentTarget).data('bs.' + this.type); return ( i || ((i = new this.constructor(e.currentTarget, this.getDelegateOptions())), t(e.currentTarget).data('bs.' + this.type, i)), e instanceof t.Event && (i.inState['focusin'] = !0) ); }); ``` -------------------------------- ### Get Element Position Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Extends jQuery to calculate an element's position relative to its offset parent. Useful for understanding layout and internal positioning. ```javascript position: function () { if (this[0]) { var a, b, c = this[0], d = { top: 0, left: 0 }; return ( 'fixed' === n.css(c, 'position') ? (b = c.getBoundingClientRect()) : ((a = this.offsetParent()), (b = this.offset()), n.nodeName(a[0], 'html') || (d = a.offset()), (d.top += n.css(a[0], 'borderTopWidth', !0)), (d.left += n.css(a[0], 'borderLeftWidth', !0))), { top: b.top - d.top - n.css(c, 'marginTop', !0), left: b.left - d.left - n.css(c, 'marginLeft', !0) } ); } } ``` -------------------------------- ### Get Element Offset Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Extends jQuery's offset method to retrieve the position of an element relative to the document. Handles cases where the element is not in the document. ```javascript n.fn.extend({ offset: function (a) { if (arguments.length) return void 0 === a ? this : this.each(function (b) { n.offset.setOffset(this, a, b); }); var b, c, d = this[0], e = { top: 0, left: 0 }, f = d && d.ownerDocument; if (f) return ( (b = f.documentElement), n.contains(b, d) ? ((e = d.getBoundingClientRect()), (c = Mb(f)), { top: e.top + c.pageYOffset - b.clientTop, left: e.left + c.pageXOffset - b.clientLeft }) : e ); } }); ``` -------------------------------- ### Popover Constructor Initialization Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Initializes a new Popover instance, inheriting defaults from the tooltip constructor. It requires the 'tooltip.js' plugin to be loaded. ```javascript if (!a.fn.tooltip) throw new Error('Popover requires tooltip.js'); (c.VERSION = '3.3.7'), (c.DEFAULTS = a.extend({}, a.fn.tooltip.Constructor.DEFAULTS, { placement: 'right', trigger: 'click', content: '', template: '' })); ``` -------------------------------- ### Get Window Object Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Helper function to retrieve the window object associated with a DOM element or node. Essential for operations requiring window context. ```javascript function Mb(a) { return n.isWindow(a) ? a : 9 === a.nodeType && a.defaultView; } ``` -------------------------------- ### Bootstrap Dropdown Plugin Initialization Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/index.html Initializes the Bootstrap dropdown plugin, handling click events to toggle dropdown menus and keyboard navigation. Includes backdrop functionality for touch devices. ```javascript (function (t) { 'use strict'; function e(e) { var i = e.attr('data-target'); i || (i = (i = e.attr('href')) && /#\[A-Za-z\]/.test(i) && i.replace(/.\*?(?=#\[^\\s\*$\])/, '')); var o = i && t(i); return o && o.length ? o : e.parent(); } function i(i) { (i && 3 === i.which) || (t(o).remove(), t(n).each(function () { var o = t(this), n = e(o), s = { relatedTarget: this }; n.hasClass('open') && ((i && 'click' == i.type && /input|textarea/i.test(i.target.tagName) && t.contains(n[0], i.target)) || (n.trigger((i = t.Event('hide.bs.dropdown', s))), i.isDefaultPrevented() || (o.attr('aria-expanded', 'false'), n.removeClass('open').trigger(t.Event('hidden.bs.dropdown', s)))))); })); } var o = '.dropdown-backdrop', n = '[data-toggle="dropdown"]', s = function (e) { t(e).on('click.bs.dropdown', this.toggle); }; (s.VERSION = '3.3.6'), (s.prototype.toggle = function (o) { var n = t(this); if (!n.is('.disabled, :disabled')) { var s = e(n), a = s.hasClass('open'); if ((i(), !a)) { 'ontouchstart' in document.documentElement && !s.closest('.navbar-nav').length && t(document.createElement('div')) .addClass('dropdown-backdrop') .insertAfter(t(this)) .on('click', i); var r = { relatedTarget: this }; if ((s.trigger((o = t.Event('show.bs.dropdown', r))), o.isDefaultPrevented())) return; n.trigger('focus').attr('aria-expanded', 'true'), s.toggleClass('open').trigger(t.Event('shown.bs.dropdown', r)); } return !1; } }), (s.prototype.keydown = function (i) { if (/(38|40|27|32)/.test(i.which) && !/input|textarea/i.test(i.target.tagName)) { var o = t(this); if ((i.preventDefault(), i.stopPropagation(), !o.is('.disabled, :disabled'))) { var s = e(o), a = s.hasClass('open'); (!a && 27 != i.which) || (a && 27 == i.which) ? 27 == i.which && s.find(n).trigger('focus'), o.trigger('click') : void 0; var r = s.find('.dropdown-menu li:not(.disabled):visible a'); if (r.length) { var l = r.index(i.target); 38 == i.which && l > 0 && l--, 40 == i.which && l < r.length - 1 && l++, ~l || (l = 0), r.eq(l).trigger('focus'); } } } }); var a = t.fn.dropdown; (t.fn.dropdown = function (e) { return this.each(function () { var i = t(this), o = i.data('bs.dropdown'); o || i.data('bs.dropdown', (o = new s(this))), 'string' == typeof e && o[e].call(o); }); }), (t.fn.dropdown.Constructor = s), (t.fn.dropdown.noConflict = function () { return (t.fn.dropdown = a), this; }), t(document) .on('click.bs.dropdown.data-api', n, s.prototype.toggle) .on('keydown.bs.dropdown.data-api', n, s.prototype.keydown) .on('keydown.bs.dropdown.data-api', '.dropdown-menu', s.prototype.keydown); })(jQuery); ``` -------------------------------- ### Manage Margin and Padding CSS Source: https://github.com/citolab/qti-components/blob/main/public/assets/qti-custom-interaction/ref/6047-BiKB-bmi_467x370_29/html/BMI.html Sets up CSS hooks for 'margin', 'padding', and 'borderWidth' to handle shorthand properties and expand them into individual directional properties. Use this for setting consistent spacing around elements. ```javascript n.each({ margin: '', padding: '', border: 'Width' }, function (a, b) { (n.cssHooks[a + b] = { expand: function (c) { for (var d = 0, e = {}, f = 'string' == typeof c ? c.split(' ') : [c]; 4 > d; d++) e[a + U[d] + b] = f[d] || f[d - 2] || f[0]; return e; } }), Aa.test(a) || (n.cssHooks[a + b].set = Na); }) ```