diff --git a/dist/jaxon.core.js b/dist/jaxon.core.js index 9ab4c4b..fb4dfc1 100644 --- a/dist/jaxon.core.js +++ b/dist/jaxon.core.js @@ -17,7 +17,7 @@ var jaxon = { version: { major: '5', minor: '0', - patch: '0rc-8', + patch: '0rc-9', }, debug: { @@ -457,42 +457,47 @@ window.jaxon = jaxon; (function(self, dom) { /** - * @param {object} aFormValues + * @param {object} xOptions * @param {object} child - * @param {boolean} submitDisabledElements - * @param {string} prefix + * @param {string} child.type + * @param {string} child.name + * @param {string} child.tagName + * @param {boolean} child.checked + * @param {boolean} child.disabled + * @param {mixed} child.value + * @param {array} child.options * * @returns {void} */ - const _getValue = (aFormValues, child, submitDisabledElements, prefix) => { - if (!child.name || 'PARAM' === child.tagName) + const _getValue = (xOptions, { type, name, tagName, checked, disabled, value, options }) => { + if (!name || 'PARAM' === tagName) return; - if (!submitDisabledElements && child.disabled) + if (!xOptions.disabled && disabled) return; - if (prefix !== child.name.substring(0, prefix.length)) + const { prefix } = xOptions; + if (prefix.length > 0 && prefix !== name.substring(0, prefix.length)) return; - if ((child.type === 'radio' || child.type === 'checkbox') && !child.checked) + if ((type === 'radio' || type === 'checkbox') && !checked) return; - if (child.type === 'file') + if (type === 'file') return; - const name = child.name; - const values = child.type !== 'select-multiple' ? child.value : - child.options.filter(({ selected }) => selected).map(({ value }) => value); + const values = type !== 'select-multiple' ? value : + options.filter(({ selected }) => selected).map(({ value: v }) => v); const keyBegin = name.indexOf('['); if (keyBegin < 0) { - aFormValues[name] = values; + xOptions.values[name] = values; return; } // Parse names into brackets let k = name.substring(0, keyBegin); let a = name.substring(keyBegin); - if (aFormValues[k] === undefined) { - aFormValues[k] = {}; + if (xOptions.values[k] === undefined) { + xOptions.values[k] = {}; } - let p = aFormValues; // pointer reset + let p = xOptions.values; // pointer reset while (a.length > 0) { const sa = a.substring(0, a.indexOf(']') + 1); const lastKey = k; //save last key @@ -502,7 +507,7 @@ window.jaxon = jaxon; p = p[k]; k = sa.substring(1, sa.length - 1); if (k === '') { - if ('select-multiple' === child.type) { + if ('select-multiple' === type) { k = lastKey; //restore last key p = lastRef; } else { @@ -510,7 +515,7 @@ window.jaxon = jaxon; } } if (k === undefined) { - /*check against the global aFormValues Stack wich is the next(last) usable index */ + /*check against the global xOptions.values Stack wich is the next(last) usable index */ k = Object.keys(lastRef[lastKey]).length; } p[k] = p[k] || {}; @@ -519,19 +524,18 @@ window.jaxon = jaxon; }; /** - * @param {object} aFormValues + * @param {object} xOptions * @param {array} children - * @param {boolean} submitDisabledElements - * @param {string} prefix * * @returns {void} */ - const _getValues = (aFormValues, children, submitDisabledElements, prefix) => { + const _getValues = (xOptions, children) => { children.forEach(child => { - if (child.childNodes !== undefined && child.type !== 'select-one' && child.type !== 'select-multiple') { - _getValues(aFormValues, child.childNodes, submitDisabledElements, prefix); + const { childNodes, type } = child; + if (childNodes !== undefined && type !== 'select-one' && type !== 'select-multiple') { + _getValues(xOptions, childNodes); } - _getValue(aFormValues, child, submitDisabledElements, prefix); + _getValue(xOptions, child); }); }; @@ -539,20 +543,26 @@ window.jaxon = jaxon; * Build an associative array of form elements and their values from the specified form. * * @param {string} formId The unique name (id) of the form to be processed. - * @param {boolean} disabled (optional): Include form elements which are currently disabled. + * @param {boolean=false} disabled (optional): Include form elements which are currently disabled. * @param {string=''} prefix (optional): A prefix used for selecting form elements. * * @returns {object} An associative array of form element id and value. */ - self.getValues = (formId, disabled, prefix = '') => { - const submitDisabledElements = (disabled === true); - const prefixValue = prefix ?? ''; + self.getValues = (formId, disabled = false, prefix = '') => { + const xOptions = { + // Submit disabled fields + disabled: (disabled === true), + // Only submit fields with a prefix + prefix: prefix ?? '', + // Form values + values: {}, + }; + const form = dom.$(formId); - const aFormValues = {}; if (form && form.childNodes) { - _getValues(aFormValues, form.childNodes, submitDisabledElements, prefixValue); + _getValues(xOptions, form.childNodes); } - return aFormValues; + return xOptions.values; }; })(jaxon.utils.form, jaxon.utils.dom); @@ -986,10 +996,60 @@ window.jaxon = jaxon; */ const sDefaultComponentItem = 'main'; + /** + * The commands to check for changes + * + * @var {array} + */ + const aCommands = ['dom.assign', 'dom.append', 'dom.prepend', 'dom.replace']; + + /** + * The attributes to check for changes + * + * @var {array} + */ + const aAttributes = ['innerHTML', 'outerHTML']; + + /** + * Check if a the attributes on a targeted node must be processed after a command is executed. + * + * @param {Element} xTarget A DOM node. + * @param {string} sCommand The command name. + * @param {string} sAttribute The attribute name. + * + * @returns {void} + */ + self.changed = (xTarget, sCommand, sAttribute) => (xTarget) && + aAttributes.some(sVal => sVal === sAttribute) && + aCommands.some(sVal => sVal === sCommand); + + /** + * @param {Element} xNode A DOM node. + * + * @returns {void} + */ + const setEventHandlers = (xNode) => { + const sEvent = xNode.getAttribute('jxn-on'); + const oHandler = JSON.parse(xNode.getAttribute('jxn-func')); + if(!xNode.hasAttribute('jxn-select')) + { + // Set the event handler on the node. + event.setEventHandler({ target: xNode, event: sEvent, func: oHandler }); + return; + } + // Set the event handler on the selected children nodes. + const sSelector = xNode.getAttribute('jxn-select'); + const aChildren = xNode.querySelectorAll(`:scope ${sSelector}`); + aChildren.forEach(xChild => { + // Set the event handler on the child node. + event.setEventHandler({ target: xChild , event: sEvent, func: oHandler }); + }); + }; + /** * Process the custom attributes in a given DOM node. * - * @param {Element} xContainer The DOM node. + * @param {Element} xContainer A DOM node. * * @returns {void} */ @@ -997,15 +1057,13 @@ window.jaxon = jaxon; // Set event handlers on nodes const aEvents = xContainer.querySelectorAll(':scope [jxn-on]'); aEvents.forEach(xNode => { - if(!xNode.hasAttribute('jxn-func')) + if(xNode.hasAttribute('jxn-func')) { - return; + setEventHandlers(xNode); } - const sEvent = xNode.getAttribute('jxn-on'); - const oHandler = JSON.parse(xNode.getAttribute('jxn-func')); - event.setEventHandler({ target: xNode, event: sEvent, func: oHandler }); xNode.removeAttribute('jxn-on'); xNode.removeAttribute('jxn-func'); + xNode.removeAttribute('jxn-select'); }); // Associate DOM nodes to Jaxon components @@ -1369,23 +1427,16 @@ window.jaxon = jaxon; * * @returns {object} The callback object. */ - self.create = (responseDelayTime, expirationTime) => ({ - timers: { - onResponseDelay: setupTimer(responseDelayTime ?? config.defaultResponseDelayTime), - onExpiration: setupTimer(expirationTime ?? config.defaultExpirationTime), - }, - onInitialize: null, - onProcessParams: null, - onPrepare: null, - onRequest: null, - onResponseDelay: null, - onExpiration: null, - beforeResponseProcessing: null, - onFailure: null, - onRedirect: null, - onSuccess: null, - onComplete: null, - }); + self.create = (responseDelayTime, expirationTime) => { + const oCallback = { + timers: { + onResponseDelay: setupTimer(responseDelayTime ?? config.defaultResponseDelayTime), + onExpiration: setupTimer(expirationTime ?? config.defaultExpirationTime), + }, + }; + aCallbackNames.forEach(sName => oCallback[sName] = null); + return oCallback; + }; /** * The global callback object which is active for every request. @@ -1403,9 +1454,22 @@ window.jaxon = jaxon; * @return {void} */ self.initCallbacks = (oRequest) => { - const callback = self.create(); + if (types.isObject(oRequest.callback)) { + oRequest.callback = [oRequest.callback]; + } + if (types.isArray(oRequest.callback)) { + oRequest.callback.forEach(oCallback => { + // Add the timers attribute, if it is not defined. + if (oCallback.timers === undefined) { + oCallback.timers = {}; + } + }); + return; + } let callbackFound = false; + // Check if any callback is defined in the request object by its own name. + const callback = self.create(); aCallbackNames.forEach(sName => { if (oRequest[sName] !== undefined) { callback[sName] = oRequest[sName]; @@ -1413,38 +1477,18 @@ window.jaxon = jaxon; delete oRequest[sName]; } }); - - if (oRequest.callback === undefined) { - oRequest.callback = callback; - return; - } - // Add the timers attribute, if it is not defined. - if (oRequest.callback.timers === undefined) { - oRequest.callback.timers = {}; - } - if (callbackFound) { - oRequest.callback = [oRequest.callback, callback]; - } + oRequest.callback = callbackFound ? [callback] : []; }; /** * Get a flatten array of callbacks * * @param {object} oRequest The request context object. + * @param {array=} oRequest.callback The request callback(s). * * @returns {array} */ - const getCallbacks = (oRequest) => { - if(!oRequest.callback) - { - return [self.callback]; - } - if(types.isArray(oRequest.callback)) - { - return [self.callback, ...oRequest.callback]; - } - return [self.callback, oRequest.callback]; - }; + const getCallbacks = ({ callback = [] }) => [self.callback, ...callback]; /** * Execute a callback event. @@ -1457,10 +1501,10 @@ window.jaxon = jaxon; */ const execute = (oCallback, sFunction, oRequest) => { const func = oCallback[sFunction]; - const timer = !oCallback.timers ? null : oCallback.timers[sFunction]; if (!func || !types.isFunction(func)) { return; } + const timer = oCallback.timers[sFunction]; if (!timer) { func(oRequest); // Call the function directly. return; @@ -1591,23 +1635,23 @@ window.jaxon = jaxon; * @returns {false} The command signalled that it needs to pause processing. */ self.execute = (command) => { - const { name, args } = command; + const { name, args = {} } = command; if (!self.isRegistered({ name })) { return true; } // If the command has an "id" attr, find the corresponding dom node. - const sComponentName = args?.component?.name; + const sComponentName = args.component?.name; if ((sComponentName)) { args.target = attr.node(sComponentName, args.component.item); } - const id = args?.id; - if (!args?.target && (id)) { + const id = args.id; + if (!args.target && (id)) { args.target = dom.$(id); } // Process the command const bReturnValue = callHandler(name, args, command); // Process Jaxon custom attributes in the new node HTML content. - name === 'dom.assign' && attr.process(args.target); + attr.changed(args.target, name, args.attr) && attr.process(args.target); return bReturnValue; }; @@ -1885,10 +1929,9 @@ window.jaxon = jaxon; * @returns {boolean} */ const initialize = (oRequest) => { - cbk.execute(oRequest, 'onInitialize'); - cfg.setRequestOptions(oRequest); cbk.initCallbacks(oRequest); + cbk.execute(oRequest, 'onInitialize'); oRequest.status = (oRequest.statusMessages) ? cfg.status.update : cfg.status.dontUpdate; oRequest.cursor = (oRequest.waitCursor) ? cfg.cursor.update : cfg.cursor.dontUpdate; @@ -1915,6 +1958,7 @@ window.jaxon = jaxon; * @return {void} */ const prepare = (oRequest) => { + --oRequest.requestRetry; cbk.execute(oRequest, 'onPrepare'); oRequest.httpRequestOptions = { @@ -1962,7 +2006,6 @@ window.jaxon = jaxon; * @returns {mixed} */ const submit = (oRequest) => { - --oRequest.requestRetry; oRequest.status.onRequest(); // The onResponseDelay and onExpiration aren't called immediately, but a timer @@ -2080,7 +2123,7 @@ window.jaxon = jaxon; } catch (e) { cbk.execute(oRequest, 'onFailure'); - if (oRequest.requestRetry === 0) { + if (oRequest.requestRetry <= 0) { throw e; } } @@ -2310,23 +2353,13 @@ window.jaxon = jaxon; * Assign an element's attribute to the specified value. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The HTML element to effect. + * @param {Element} args.target The HTML element to effect. * @param {string} args.attr The name of the attribute to set. * @param {string} args.value The new value to be applied. * * @returns {true} The operation completed successfully. */ self.assign = ({ target, attr, value }) => { - if (attr === 'innerHTML') { - target.innerHTML = value; - return true; - } - if (attr === 'outerHTML') { - target.outerHTML = value; - return true; - } - const xElt = dom.getInnerObject(attr, target); if (xElt !== null) { xElt.node[xElt.attr] = value; @@ -2338,23 +2371,13 @@ window.jaxon = jaxon; * Append the specified value to an element's attribute. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The HTML element to effect. + * @param {Element} args.target The HTML element to effect. * @param {string} args.attr The name of the attribute to append to. * @param {string} args.value The new value to be appended. * * @returns {true} The operation completed successfully. */ self.append = ({ target, attr, value }) => { - if (attr === 'innerHTML') { - target.innerHTML = target.innerHTML + value; - return true; - } - if (attr === 'outerHTML') { - target.outerHTML = target.outerHTML + value; - return true; - } - const xElt = dom.getInnerObject(attr, target); if (xElt !== null) { xElt.node[xElt.attr] = xElt.node[xElt.attr] + value; @@ -2366,23 +2389,13 @@ window.jaxon = jaxon; * Prepend the specified value to an element's attribute. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The HTML element to effect. + * @param {Element} args.target The HTML element to effect. * @param {string} args.attr The name of the attribute. * @param {string} args.value The new value to be prepended. * * @returns {true} The operation completed successfully. */ self.prepend = ({ target, attr, value }) => { - if (attr === 'innerHTML') { - target.innerHTML = value + target.innerHTML; - return true; - } - if (attr === 'outerHTML') { - target.outerHTML = value + target.outerHTML; - return true; - } - const xElt = dom.getInnerObject(attr, target); if (xElt !== null) { xElt.node[xElt.attr] = value + xElt.node[xElt.attr]; @@ -2393,19 +2406,18 @@ window.jaxon = jaxon; /** * Replace a text in the value of a given attribute in an element * - * @param {object} xElement The element to search in - * @param {string} sAttribute The attribute to search in + * @param {object} xElt The value returned by the dom.getInnerObject() function * @param {string} sSearch The text to search * @param {string} sReplace The text to use as replacement * * @returns {void} */ - const replaceText = (xElement, sAttribute, sSearch, sReplace) => { - const bFunction = types.isFunction(xElement[sAttribute]); - const sCurText = bFunction ? xElement[sAttribute].join('') : xElement[sAttribute]; + const replaceText = (xElt, sSearch, sReplace) => { + const bFunction = types.isFunction(xElt.node[xElt.attr]); + const sCurText = bFunction ? xElt.node[xElt.attr].join('') : xElt.node[xElt.attr]; const sNewText = sCurText.replaceAll(sSearch, sReplace); - if (bFunction || dom.willChange(xElement, sAttribute, sNewText)) { - xElement[sAttribute] = sNewText; + if (bFunction || dom.willChange(xElt.node, xElt.attr, sNewText)) { + xElt.node[xElt.attr] = sNewText; } }; @@ -2413,19 +2425,17 @@ window.jaxon = jaxon; * Search and replace the specified text. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The element which is to be modified. + * @param {Element} args.target The element which is to be modified. * @param {string} args.attr The name of the attribute to be set. - * @param {array} args.search The search text and replacement text. - * @param {array} args.replace The search text and replacement text. + * @param {string} args.search The search text and replacement text. + * @param {string} args.replace The search text and replacement text. * * @returns {true} The operation completed successfully. */ self.replace = ({ target, attr, search, replace }) => { - const sSearch = attr === 'innerHTML' ? dom.getBrowserHTML(search) : search; const xElt = dom.getInnerObject(attr, target); if (xElt !== null) { - replaceText(xElt.node, xElt.attr, sSearch, replace); + replaceText(xElt, attr === 'innerHTML' ? dom.getBrowserHTML(search) : search, replace); } return true; }; @@ -2434,8 +2444,7 @@ window.jaxon = jaxon; * Clear an element. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The element which is to be modified. + * @param {Element} args.target The element which is to be modified. * @param {string} args.attr The name of the attribute to clear. * * @returns {true} The operation completed successfully. @@ -2449,8 +2458,7 @@ window.jaxon = jaxon; * Delete an element. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The element which will be deleted. + * @param {Element} args.target The element which will be deleted. * * @returns {true} The operation completed successfully. */ @@ -2475,8 +2483,7 @@ window.jaxon = jaxon; * Create a new element and append it to the specified parent element. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The element which will contain the new element. + * @param {Element} args.target The element which will contain the new element. * @param {string} args.tag.name The tag name for the new element. * @param {string} args.tag.id The id attribute of the new element. * @@ -2491,8 +2498,7 @@ window.jaxon = jaxon; * Insert a new element before the specified element. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The element that will be used as the reference point for insertion. + * @param {Element} args.target The element that will be used as the reference point for insertion. * @param {string} args.tag.name The tag name for the new element. * @param {string} args.tag.id The id attribute of the new element. * @@ -2508,8 +2514,7 @@ window.jaxon = jaxon; * Insert a new element after the specified element. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The element that will be used as the reference point for insertion. + * @param {Element} args.target The element that will be used as the reference point for insertion. * @param {string} args.tag.name The tag name for the new element. * @param {string} args.tag.id The id attribute of the new element. * diff --git a/dist/jaxon.core.min.js b/dist/jaxon.core.min.js index b717b0b..e40f3f5 100644 --- a/dist/jaxon.core.min.js +++ b/dist/jaxon.core.min.js @@ -6,4 +6,4 @@ @copyright Copyright (c) 2017 by Thierry Feuzeu, Joseph Woolley, Steffen Konerow, Jared White & J. Max Wilson @license https://opensource.org/license/bsd-3-clause/ BSD License */ -var jaxon={version:{major:"5",minor:"0",patch:"0rc-8"},debug:{verbose:{}},ajax:{callback:{},handler:{},parameters:{},request:{},response:{}},cmd:{body:{},script:{},event:{}},call:{attr:{},json:{},query:{}},utils:{dom:{},form:{},queue:{},types:{},string:{},upload:{}},dom:{},dialog:{cmd:{},lib:{}},config:{}};!function(e){e.commonHeaders={"If-Modified-Since":"Sat, 1 Jan 2000 00:00:00 GMT"},e.postHeaders={},e.getHeaders={},e.waitCursor=!1,e.statusMessages=!1,e.baseDocument=document,e.requestURI=document.URL,e.defaultMode="asynchronous",e.defaultHttpVersion="HTTP/1.1",e.defaultContentType="application/x-www-form-urlencoded",e.defaultResponseDelayTime=1e3,e.convertResponseToJson=!0,e.defaultExpirationTime=1e4,e.defaultMethod="POST",e.defaultRetry=5,e.defaultReturnValue=!1,e.maxObjectDepth=20,e.maxObjectSize=2e3,e.commandQueueSize=1e3,e.requestQueueSize=1e3,e.httpRequestOptions={mode:"cors",cache:"no-cache",credentials:"same-origin",redirect:"manual"},e.setRequestOptions=t=>{if(void 0===e.requestURI)throw{code:10005};["commonHeaders","postHeaders","getHeaders"].forEach((n=>t[n]={...e[n],...t[n]}));const n={statusMessages:e.statusMessages,waitCursor:e.waitCursor,mode:e.defaultMode,method:e.defaultMethod,URI:e.requestURI,httpVersion:e.defaultHttpVersion,contentType:e.defaultContentType,convertResponseToJson:e.convertResponseToJson,retry:e.defaultRetry,returnValue:e.defaultReturnValue,maxObjectDepth:e.maxObjectDepth,maxObjectSize:e.maxObjectSize,context:window,upload:!1,aborted:!1};Object.keys(n).forEach((e=>t[e]=t[e]??n[e])),t.method=t.method.toUpperCase(),"GET"!==t.method&&(t.method="POST"),t.requestRetry=t.retry},e.status={update:{onRequest:()=>console.log("Sending Request..."),onWaiting:()=>console.log("Waiting for Response..."),onProcessing:()=>console.log("Processing..."),onComplete:()=>console.log("Done.")},dontUpdate:{onRequest:()=>{},onWaiting:()=>{},onProcessing:()=>{},onComplete:()=>{}}},e.cursor={update:{onWaiting:()=>{jaxon.config.baseDocument.body&&(jaxon.config.baseDocument.body.style.cursor="wait")},onComplete:()=>{jaxon.config.baseDocument.body&&(jaxon.config.baseDocument.body.style.cursor="auto")}},dontUpdate:{onWaiting:()=>{},onComplete:()=>{}}}}(jaxon.config),window.jaxon=jaxon,function(e,t,n){e.$=e=>e?t.isString(e)?n.getElementById(e):e:null;e.getBrowserHTML=t=>{const o=(()=>{const t=e.$("jaxon_temp_workspace");if(t)return t;if(!n.body)return null;const o=n.createElement("div");return o.setAttribute("id","jaxon_temp_workspace"),o.style.display="none",o.style.visibility="hidden",n.body.appendChild(o),o})();o.innerHTML=t;const r=o.innerHTML;return o.innerHTML="",r},e.willChange=(t,n,o)=>!!(t=e.$(t))&&o!=t[n],e.removeElement=t=>{(t=e.$(t))&&t.parentNode&&t.parentNode.removeChild&&t.parentNode.removeChild(t)},e.findFunction=(e,n=window)=>{if("toInt"===e&&n===window)return t.toInt;const o=e.split("."),r=o.length;for(let e=0;e{const n=e.split(".");e=n.pop();const o=n.length;for(let e=0;e{t.forEach((t=>{void 0!==t.childNodes&&"select-one"!==t.type&&"select-multiple"!==t.type&&n(e,t.childNodes,o,r),((e,t,n,o)=>{if(!t.name||"PARAM"===t.tagName)return;if(!n&&t.disabled)return;if(o!==t.name.substring(0,o.length))return;if(("radio"===t.type||"checkbox"===t.type)&&!t.checked)return;if("file"===t.type)return;const r=t.name,a="select-multiple"!==t.type?t.value:t.options.filter((({selected:e})=>e)).map((({value:e})=>e)),s=r.indexOf("[");if(s<0)return void(e[r]=a);let l=r.substring(0,s),i=r.substring(s);void 0===e[l]&&(e[l]={});let c=e;for(;i.length>0;){const e=i.substring(0,i.indexOf("]")+1),n=l,o=c;i=i.substring(i.indexOf("]")+1),c=c[l],l=e.substring(1,e.length-1),""===l&&("select-multiple"===t.type?(l=n,c=o):l=c.length),void 0===l&&(l=Object.keys(o[n]).length),c[l]=c[l]||{}}c[l]=a})(e,t,o,r)}))};e.getValues=(e,o,r="")=>{const a=!0===o,s=r??"",l=t.$(e),i={};return l&&l.childNodes&&n(i,l.childNodes,a,s),i}}(jaxon.utils.form,jaxon.utils.dom),function(e){e.create=e=>({start:0,count:0,size:e,end:0,elements:[],paused:!1}),e.empty=e=>e.count<=0,e.full=e=>e.count>=e.size,e.push=(t,n)=>{if(e.full(t))throw{code:10003};return t.elements[t.end]=n,++t.end>=t.size&&(t.end=0),++t.count},e.pushFront=(t,n)=>{if(e.full(t))throw{code:10003};return e.empty(t)?e.push(t,n):(--t.start<0&&(t.start=t.size-1),t.elements[t.start]=n,++t.count)},e.pop=t=>{if(e.empty(t))return null;let n=t.elements[t.start];return delete t.elements[t.start],++t.start>=t.size&&(t.start=0),t.count--,n},e.peek=t=>e.empty(t)?null:t.elements[t.start]}(jaxon.utils.queue),function(e){"use strict";let t=[],n=!1,o=!1;const r=()=>{n||(n=!0,t.forEach((e=>e.fn.call(window,e.ctx))),t=[])};e.ready=function(e,a){n?setTimeout((function(){e(a)}),1):(t.push({fn:e,ctx:a}),"complete"===document.readyState||!document.attachEvent&&"interactive"===document.readyState?setTimeout(r,1):o||(document.addEventListener("DOMContentLoaded",r,!1),window.addEventListener("load",r,!1),o=!0))}}(jaxon.utils.dom),function(e){e.doubleQuotes=e=>void 0!==e&&e.replace(new RegExp("'","g"),'"'),e.singleQuotes=e=>void 0!==e&&e.replace(new RegExp('"',"g"),"'"),e.stripOnPrefix=e=>0===(e=e.toLowerCase()).indexOf("on")?e.replace(/on/,""):e,e.addOnPrefix=e=>0!==(e=e.toLowerCase()).indexOf("on")?"on"+e:e,String.prototype.supplant||(String.prototype.supplant=function(e){return this.replace(/\{([^{}]*)\}/g,((t,n)=>{const o=e[n],r=typeof o;return"string"===r||"number"===r?o:t}))})}(jaxon.utils.string),function(e){e.of=e=>Object.prototype.toString.call(e).slice(8,-1).toLowerCase(),e.isObject=t=>"object"===e.of(t),e.isArray=t=>"array"===e.of(t),e.isString=t=>"string"===e.of(t),e.isFunction=t=>"function"===e.of(t),e.toInt=e=>parseInt(e),Array.prototype.top||(Array.prototype.top=function(){return this.length>0?this[this.length-1]:void 0})}(jaxon.utils.types),function(e,t,n){e.initialize=e=>{(e=>{if(!e.upload)return!1;e.upload={id:e.upload,input:null,form:null};const o=t.$(e.upload.id);return o?"file"!==o.type?(n.log("The upload input field with id "+e.upload.id+" is not of type file"),!1):0===o.files.length?(n.log("There is no file selected for upload in input field with id "+e.upload.id),!1):void 0===o.name?(n.log("The upload input field with id "+e.upload.id+" has no name attribute"),!1):(e.upload.input=o,e.upload.form=o.form,!0):(n.log("Unable to find input field for file upload with id "+e.upload.id),!1)})(e)||(e.postHeaders["content-type"]=e.contentType)}}(jaxon.utils.upload,jaxon.utils.dom,console),function(e,t){const n={},o="main";e.process=(e=document)=>{e.querySelectorAll(":scope [jxn-on]").forEach((e=>{if(!e.hasAttribute("jxn-func"))return;const n=e.getAttribute("jxn-on"),o=JSON.parse(e.getAttribute("jxn-func"));t.setEventHandler({target:e,event:n,func:o}),e.removeAttribute("jxn-on"),e.removeAttribute("jxn-func")}));e.querySelectorAll(":scope [jxn-component]").forEach((e=>{const t=e.getAttribute("jxn-component"),r=e.getAttribute("jxn-item")??o;n[`${t}_${r}`]=e,e.removeAttribute("jxn-component")}))},e.node=(e,t=o)=>n[`${e}_${t}`]??null}(jaxon.call.attr,jaxon.cmd.event),function(e,t,n,o,r,a){const s={comparator:()=>!1,command:e=>{console.error("Unexpected command: "+JSON.stringify({call:e}))}},l={eq:(e,t)=>e==t,teq:(e,t)=>e===t,ne:(e,t)=>e!=t,nte:(e,t)=>e!==t,gt:(e,t)=>e>t,ge:(e,t)=>e>=t,lt:(e,t)=>ee<=t},i=e=>a.isObject(e)&&e._type,c=(e,t)=>{if(!i(e))return e;const{_type:n,_name:a}=e;switch(n){case"form":return r.getValues(a);case"html":return o.$(a).innerHTML;case"input":return o.$(a).value;case"checked":return o.$(a).checked;case"expr":return x(e,{target:window});case"_":return"this"===a?t:void 0;default:return}},u=(e,t)=>e.map((e=>c(e,t))),d={select:({_name:e,context:n=null},o)=>{switch(e){case"this":return t.select(o.target);case"event":return o.event;case"window":return window;default:return t.select(e,n)}},event:({_name:e,func:t},n,o)=>(o.on(e,(e=>x(t,{...n,event:e,target:e.currentTarget}))),o),func:({_name:e,args:t=[]},n,r)=>{const a=o.findFunction(e);return a?a.apply(n,u(t,r)):void 0},method:({_name:e,args:t=[]},n,r)=>{const s=o.findFunction(e,r);return s?s.apply(r,u(t,r)):"toInt"===e?a.toInt(r):void 0},attr:({_name:e,value:t},n,r)=>{const a=o.getInnerObject(e,r||n.target);if(a)return void 0!==t&&(a.node[a.attr]=c(t,r)),a.node[a.attr]}},p=(e,t,n)=>(i(e)?d[e._type]:s.command)(e,t,n);e.execCall=(e,t)=>p(e,{target:window,...t});const m=(e,t)=>{let n;const o=e.length;for(let r=0;r{const n={};let o=1;return t.forEach((e=>n[o++]=c(e))),e.supplant(n)};const f=t=>{if(t){const{lib:o,type:r,content:{title:a,phrase:s}}=t;n.get(o).alert(r,e.makePhrase(s),a)}},x=(t,o)=>{const{calls:r,question:a,condition:i,message:u}=t;if(a)((t,o,r,a)=>{const{lib:s,phrase:l}=o;n.get(s).confirm(e.makePhrase(l),"",(()=>m(t,a)),(()=>f(r)))})(r,a,u,o);else{if(!i)return m(r,o);((e,t,n,o)=>{const[r,a,i]=t;(l[r]??s.comparator)(c(a),c(i))?m(e,o):f(n)})(r,i,u,o)}};e.execExpr=(e,t)=>a.isObject(e)?x(e,{target:window,...t}):null}(jaxon.call.json,jaxon.call.query,jaxon.dialog.lib,jaxon.utils.dom,jaxon.utils.form,jaxon.utils.types),function(e,t){e.jq=t,e.select=(t,n=null)=>n?e.jq(t,n):e.jq(t)}(jaxon.call.query,window.jQuery),function(e,t,n){const o=e=>({timer:null,delay:e}),r=["onInitialize","onProcessParams","onPrepare","onRequest","onResponseDelay","onExpiration","beforeResponseProcessing","onFailure","onRedirect","onSuccess","onComplete"];e.create=(e,t)=>({timers:{onResponseDelay:o(e??n.defaultResponseDelayTime),onExpiration:o(t??n.defaultExpirationTime)},onInitialize:null,onProcessParams:null,onPrepare:null,onRequest:null,onResponseDelay:null,onExpiration:null,beforeResponseProcessing:null,onFailure:null,onRedirect:null,onSuccess:null,onComplete:null}),e.callback=e.create(),e.initCallbacks=t=>{const n=e.create();let o=!1;r.forEach((e=>{void 0!==t[e]&&(n[e]=t[e],o=!0,delete t[e])})),void 0!==t.callback?(void 0===t.callback.timers&&(t.callback.timers={}),o&&(t.callback=[t.callback,n])):t.callback=n};const a=n=>n.callback?t.isArray(n.callback)?[e.callback,...n.callback]:[e.callback,n.callback]:[e.callback];e.execute=(e,n)=>a(e).forEach((o=>((e,n,o)=>{const r=e[n],a=e.timers?e.timers[n]:null;r&&t.isFunction(r)&&(a?a.timer=setTimeout((()=>r(o)),a.delay):r(o))})(o,n,e)));e.clearTimer=(e,t)=>a(e).forEach((e=>((e,t)=>{const n=e.timers[t];void 0!==n&&null!==n.timer&&clearTimeout(n.timer)})(e,t)))}(jaxon.ajax.callback,jaxon.utils.types,jaxon.config),function(e,t,n,o,r,a,s,l){const i={};e.q={send:a.create(t.requestQueueSize),recv:a.create(2*t.requestQueueSize)},e.register=(e,t,n="")=>i[e]={desc:n,func:t},e.unregister=e=>{const t=i[e];return t?(delete i[e],t.func):null},e.isRegistered=({name:e})=>void 0!==e&&void 0!==i[e];e.execute=t=>{const{name:n,args:o}=t;if(!e.isRegistered({name:n}))return!0;const a=o?.component?.name;a&&(o.target=r.node(a,o.component.item));const l=o?.id;!o?.target&&l&&(o.target=s.$(l));const c=((e,t,n)=>{const{func:o,desc:r}=i[e];return o(t,{...n,desc:r})})(n,o,t);return"dom.assign"===n&&r.process(o.target),c},e.popAsyncRequest=e=>a.empty(e)||"synchronous"===a.peek(e).mode?null:a.pop(e),e.sleep=({duration:e},{commandQueue:t})=>(t.paused=!0,setTimeout((()=>{t.paused=!1,n.processCommands(t)}),100*e),!0);const c=(e,t=0)=>{for(;t>0&&e.count>1&&null!==a.pop(e);)--t;e.paused=!1,n.processCommands(e)};e.confirm=({count:e,question:{lib:t,phrase:n}},{commandQueue:r})=>{r.paused=!0;return l.get(t).confirm(o.makePhrase(n),"",(()=>c(r)),(()=>c(r,e))),!0}}(jaxon.ajax.handler,jaxon.config,jaxon.ajax.response,jaxon.call.json,jaxon.call.attr,jaxon.utils.queue,jaxon.utils.dom,jaxon.dialog.lib),function(e,t,n){const o={};e.setBag=(e,t)=>o[e]=t,e.setBags=t=>Object.keys(t).forEach((n=>e.setBag(n,t[n]))),e.clearBag=e=>delete o[e];const r=({func:e,parameters:r,bags:a=[]},s)=>{const l=new Date;var i;s("jxnr",l.getTime()),s("jxnv",`${n.major}.${n.minor}.${n.patch}`),Object.keys(e).forEach((t=>s(t,encodeURIComponent(e[t])))),[...r].forEach((e=>s("jxnargs[]",(e=>{if(null==e)return"*";const n=t.of(e);if("object"===n||"array"===n)try{return encodeURIComponent(JSON.stringify(e))}catch(t){e=""}return e=encodeURIComponent(e),"string"===n?"S"+e:"boolean"===n?"B"+e:"number"===n?"N"+e:e})(e)))),a.length>0&&s("jxnbags",encodeURIComponent((i=a,JSON.stringify(i.reduce(((e,t)=>({...e,[t]:o[t]??"*"})),{})))))};e.process=e=>{e.requestURI=e.URI,e.requestData=(({upload:e})=>e&&e.ajax&&e.input)(e)?(e=>{const t=new FormData;r(e,((e,n)=>t.append(e,n)));const n=e.upload.input;return n.files&&n.files.forEach((e=>t.append(n.name,e))),t})(e):(e=>{const t=[];return r(e,((e,n)=>t.push(e+"="+n))),"POST"===e.method?t.join("&"):(e.requestURI+=(-1===e.requestURI.indexOf("?")?"?":"&")+t.join("&"),"")})(e)}}(jaxon.ajax.parameters,jaxon.utils.types,jaxon.version),function(e,t,n,o,r,a,s,l){const i=e=>{r.execute(e,"onPrepare"),e.httpRequestOptions={...t.httpRequestOptions,method:e.method,headers:{...e.commonHeaders,..."POST"===e.method?e.postHeaders:e.getHeaders},body:e.requestData},e.responseConverter=t=>(e.response=t,e.convertResponseToJson?t.json():t.text()),e.responseHandler=t=>{e.responseContent=t,l.empty(a.q.send)||"synchronous"===e.mode?o.received(e):l.push(a.q.recv,e)},e.errorHandler=t=>{throw r.execute(e,"onFailure"),t},e.responseProcessor||(e.responseProcessor=o.jsonProcessor)},c=e=>(--e.requestRetry,e.status.onRequest(),r.execute(e,"onResponseDelay"),r.execute(e,"onExpiration"),r.execute(e,"onRequest"),e.cursor.onWaiting(),e.status.onWaiting(),fetch(e.requestURI,e.httpRequestOptions).then(e.responseConverter).then(e.responseHandler).catch(e.errorHandler),e.returnValue);e.complete=e=>{if(r.execute(e,"onComplete"),e.cursor.onComplete(),e.status.onComplete(),(e=>{delete e.func,delete e.URI,delete e.requestURI,delete e.requestData,delete e.requestRetry,delete e.httpRequestOptions,delete e.responseHandler,delete e.responseConverter,delete e.responseContent,delete e.response,delete e.errorHandler})(e),"synchronous"===e.mode){for(l.pop(a.q.send),l.pop(a.q.recv);null!==(recvRequest=a.popAsyncRequest(a.q.recv));)o.received(recvRequest);for(;null!==(nextRequest=a.popAsyncRequest(a.q.send));)c(nextRequest);null!==(nextRequest=l.peek(a.q.send))&&c(nextRequest)}},e.abort=t=>{t.aborted=!0,e.complete(t)},e.execute=(e,o)=>{if(void 0===e)return!1;const u=o??{};for(u.func=e,(e=>{r.execute(e,"onInitialize"),t.setRequestOptions(e),r.initCallbacks(e),e.status=e.statusMessages?t.status.update:t.status.dontUpdate,e.cursor=e.waitCursor?t.cursor.update:t.cursor.dontUpdate,s.initialize(e),e.submit=l.empty(a.q.send),"synchronous"===e.mode&&(l.push(a.q.send,e),l.push(a.q.recv,e)),e.submit||l.push(a.q.send,e)})(u),r.execute(u,"onProcessParams"),n.process(u);u.requestRetry>0;)try{return i(u),u.submit?c(u):null}catch(e){if(r.execute(u,"onFailure"),0===u.requestRetry)throw e}return!0}}(jaxon.ajax.request,jaxon.config,jaxon.ajax.parameters,jaxon.ajax.response,jaxon.ajax.callback,jaxon.ajax.handler,jaxon.utils.upload,jaxon.utils.queue),function(e,t,n,o,r,a,s){const l=[0,200],i=[400,401,402,403,404,500,501,502,503],c=[301,302,307],u=e=>{try{return n.execute(e)}catch(e){console.log(e)}return!0};e.processCommands=e=>{let t=null;for(;!e.paused&&null!==(t=a.pop(e));)if(!u(t))return!1;return!0},e.jsonProcessor=t=>l.indexOf(t.response.status)>=0?(r.execute(t,"onSuccess"),(e=>{if(!s.isObject(e.responseContent))return;const{debug:{message:t}={},jxn:{value:n,commands:o=[]}={}}=e.responseContent;e.status.onProcessing(),n&&(e.returnValue=n),t&&console.log(t);let r=0;o.forEach((t=>a.push(e.commandQueue,{fullName:"*unknown*",...t,sequence:r++,commandQueue:e.commandQueue,request:e,context:e.context}))),a.push(e.commandQueue,{name:"response.complete",fullName:"Response Complete",sequence:r,commandQueue:e.commandQueue,request:e,context:e.context})})(t),e.processCommands(t.commandQueue),t.returnValue):c.indexOf(t.response.status)>=0?(r.execute(t,"onRedirect"),o.complete(t),window.location=t.response.headers.get("location"),t.returnValue):i.indexOf(t.response.status)>=0?(r.execute(t,"onFailure"),o.complete(t),t.returnValue):t.returnValue,e.received=e=>e.aborted?null:(e.commandQueue=a.create(t.commandQueueSize),r.clearTimer(e,"onExpiration"),r.clearTimer(e,"onResponseDelay"),r.execute(e,"beforeResponseProcessing"),e.responseProcessor(e))}(jaxon.ajax.response,jaxon.config,jaxon.ajax.handler,jaxon.ajax.request,jaxon.ajax.callback,jaxon.utils.queue,jaxon.utils.types),function(e,t,n,o){e.assign=({target:e,attr:n,value:o})=>{if("innerHTML"===n)return e.innerHTML=o,!0;if("outerHTML"===n)return e.outerHTML=o,!0;const r=t.getInnerObject(n,e);return null!==r&&(r.node[r.attr]=o),!0},e.append=({target:e,attr:n,value:o})=>{if("innerHTML"===n)return e.innerHTML=e.innerHTML+o,!0;if("outerHTML"===n)return e.outerHTML=e.outerHTML+o,!0;const r=t.getInnerObject(n,e);return null!==r&&(r.node[r.attr]=r.node[r.attr]+o),!0},e.prepend=({target:e,attr:n,value:o})=>{if("innerHTML"===n)return e.innerHTML=o+e.innerHTML,!0;if("outerHTML"===n)return e.outerHTML=o+e.outerHTML,!0;const r=t.getInnerObject(n,e);return null!==r&&(r.node[r.attr]=o+r.node[r.attr]),!0};e.replace=({target:e,attr:o,search:r,replace:a})=>{const s="innerHTML"===o?t.getBrowserHTML(r):r,l=t.getInnerObject(o,e);return null!==l&&((e,o,r,a)=>{const s=n.isFunction(e[o]),l=(s?e[o].join(""):e[o]).replaceAll(r,a);(s||t.willChange(e,o,l))&&(e[o]=l)})(l.node,l.attr,s,a),!0},e.clear=({target:t,attr:n})=>(e.assign({target:t,attr:n,value:""}),!0),e.remove=({target:e})=>(t.removeElement(e),!0);const r=(e,t)=>{const n=o.createElement(e);return n.setAttribute("id",t),n};e.create=({target:e,tag:{id:t,name:n}})=>(e&&e.appendChild(r(n,t)),!0),e.insert=({target:e,tag:{id:t,name:n}})=>(e&&e.parentNode&&e.parentNode.insertBefore(r(n,t),e),!0),e.insertAfter=({target:e,tag:{id:t,name:n}})=>(e&&e.parentNode&&e.parentNode.insertBefore(r(n,t),e.nextSibling),!0)}(jaxon.cmd.body,jaxon.utils.dom,jaxon.utils.types,jaxon.config.baseDocument),function(e,t,n,o){e.addHandler=({target:e,event:t,func:r})=>(e.addEventListener(o.stripOnPrefix(t),n.findFunction(r),!1),!0),e.removeHandler=({target:e,event:t,func:r})=>(e.removeEventListener(o.stripOnPrefix(t),n.findFunction(r),!1),!0);const r=(e,n,o)=>{t.execExpr({_type:"expr",...o},{event:e,target:n})};e.addEventHandler=({target:e,event:t,func:n,options:a})=>(e.addEventListener(o.stripOnPrefix(t),(t=>r(t,e,n)),a??!1),!0),e.setEventHandler=({target:e,event:t,func:n})=>(e[o.addOnPrefix(t)]=t=>r(t,e,n),!0)}(jaxon.cmd.event,jaxon.call.json,jaxon.utils.dom,jaxon.utils.string),function(e,t,n,o){e.call=({func:e,args:n},{context:o={}})=>(t.execCall({_type:"func",_name:e,args:n},o),!0),e.exec=({expr:e})=>(t.execExpr(e),!0),e.redirect=({url:e,delay:t})=>t<=0?(window.location=e,!0):(window.setTimeout((()=>window.location=e),1e3*t),!0),e.setDatabag=({values:e})=>(n.setBags(e),!0),e.jquery=({selector:e})=>(t.execExpr(e),!0);const r=(e,t)=>e.map((e=>o.isObject(e)&&"page"===e._type?parseInt(t.parentNode.getAttribute("data-page")):e));e.paginate=({target:e,func:n})=>{const o=e.querySelectorAll("li.enabled > a"),{args:a}=n;return o.forEach((e=>e.addEventListener("click",(()=>t.execCall({...n,_type:"func",args:r(a,e)}))))),!0}}(jaxon.cmd.script,jaxon.call.json,jaxon.ajax.parameters,jaxon.utils.types),function(e,t,n){const o=(e,n)=>{t.has(e)||console.warn(`Unable to find a Jaxon dialog library with name "${e}".`);const o=t.get(e);return o[n]?o:(console.error(`The chosen Jaxon dialog library doesn't implement the "${n}" function.`),null)};e.showMessage=({lib:e,type:t,content:r})=>{const{title:a,phrase:s}=r,l=o(e,"alert");return l&&l.alert(t,n.makePhrase(s),a),!0},e.showModal=({lib:e,dialog:{title:t,content:n,buttons:r,options:a}})=>{const s=o(e,"show");return s&&s.show(t,n,r,a),!0},e.hideModal=({lib:e})=>{const t=o(e,"hide");return t&&t.hide(),!0}}(jaxon.dialog.cmd,jaxon.dialog.lib,jaxon.call.json),function(e,t,n,o,r){const a={yes:"Yes",no:"No"};e.default={},e.has=t=>!!e[t],e.get=t=>e[t]??e.default,e.register=(s,l)=>{e[s]={},l(e[s],{types:t,dom:n,js:o,jq:r,labels:a})},e.register("default",(e=>{e.alert=(e,t,n)=>alert(n?`${n}
${t}`:t),e.confirm=(e,t,n,o)=>{confirm(t?`${t}
${e}`:e)?n():o&&o()}}))}(jaxon.dialog.lib,jaxon.utils.types,jaxon.dom,jaxon.call.json,window.jQuery),jaxon.request=jaxon.ajax.request.execute,jaxon.register=jaxon.ajax.handler.register,jaxon.$=jaxon.utils.dom.$,jaxon.jq=jaxon.call.query.jq,jaxon.exec=jaxon.call.json.execExpr,jaxon.dom.ready=jaxon.utils.dom.ready,jaxon.getFormValues=jaxon.utils.form.getValues,jaxon.setBag=jaxon.ajax.parameters.setBag,jaxon.processCustomAttrs=()=>jaxon.call.attr.process(),jaxon.isLoaded=!0,function(e,t,n,o){e("response.complete",((e,{request:t})=>(n.request.complete(t),!0)),"Response complete"),e("dom.assign",t.body.assign,"Dom::Assign"),e("dom.append",t.body.append,"Dom::Append"),e("dom.prepend",t.body.prepend,"Dom::Prepend"),e("dom.replace",t.body.replace,"Dom::Replace"),e("dom.clear",t.body.clear,"Dom::Clear"),e("dom.remove",t.body.remove,"Dom::Remove"),e("dom.create",t.body.create,"Dom::Create"),e("dom.insert.before",t.body.insert,"Dom::InsertBefore"),e("dom.insert.after",t.body.insertAfter,"Dom::InsertAfter"),e("script.call",t.script.call,"Script::CallJsFunction"),e("script.exec",t.script.exec,"Script::ExecJsonExpression"),e("script.redirect",t.script.redirect,"Script::Redirect"),e("script.sleep",n.handler.sleep,"Handler::Sleep"),e("script.confirm",n.handler.confirm,"Handler::Confirm"),e("handler.event.set",t.event.setEventHandler,"Script::SetEventHandler"),e("handler.event.add",t.event.addEventHandler,"Script::AddEventHandler"),e("handler.add",t.event.addHandler,"Script::AddHandler"),e("handler.remove",t.event.removeHandler,"Script::RemoveHandler"),e("script.debug",(({message:e})=>(console.log(e),!0)),"Debug message"),e("jquery.call",t.script.jquery,"JQuery::CallSelector"),e("pg.paginate",t.script.paginate,"Paginator::Paginate"),e("databag.set",t.script.setDatabag,"Databag:SetValues"),e("databag.clear",t.script.clearDatabag,"Databag:ClearValue"),e("dialog.message",o.cmd.showMessage,"Dialog:ShowMessage"),e("dialog.modal.show",o.cmd.showModal,"Dialog:ShowModal"),e("dialog.modal.hide",o.cmd.hideModal,"Dialog:HideModal")}(jaxon.register,jaxon.cmd,jaxon.ajax,jaxon.dialog); \ No newline at end of file +var jaxon={version:{major:"5",minor:"0",patch:"0rc-9"},debug:{verbose:{}},ajax:{callback:{},handler:{},parameters:{},request:{},response:{}},cmd:{body:{},script:{},event:{}},call:{attr:{},json:{},query:{}},utils:{dom:{},form:{},queue:{},types:{},string:{},upload:{}},dom:{},dialog:{cmd:{},lib:{}},config:{}};!function(e){e.commonHeaders={"If-Modified-Since":"Sat, 1 Jan 2000 00:00:00 GMT"},e.postHeaders={},e.getHeaders={},e.waitCursor=!1,e.statusMessages=!1,e.baseDocument=document,e.requestURI=document.URL,e.defaultMode="asynchronous",e.defaultHttpVersion="HTTP/1.1",e.defaultContentType="application/x-www-form-urlencoded",e.defaultResponseDelayTime=1e3,e.convertResponseToJson=!0,e.defaultExpirationTime=1e4,e.defaultMethod="POST",e.defaultRetry=5,e.defaultReturnValue=!1,e.maxObjectDepth=20,e.maxObjectSize=2e3,e.commandQueueSize=1e3,e.requestQueueSize=1e3,e.httpRequestOptions={mode:"cors",cache:"no-cache",credentials:"same-origin",redirect:"manual"},e.setRequestOptions=t=>{if(void 0===e.requestURI)throw{code:10005};["commonHeaders","postHeaders","getHeaders"].forEach((n=>t[n]={...e[n],...t[n]}));const n={statusMessages:e.statusMessages,waitCursor:e.waitCursor,mode:e.defaultMode,method:e.defaultMethod,URI:e.requestURI,httpVersion:e.defaultHttpVersion,contentType:e.defaultContentType,convertResponseToJson:e.convertResponseToJson,retry:e.defaultRetry,returnValue:e.defaultReturnValue,maxObjectDepth:e.maxObjectDepth,maxObjectSize:e.maxObjectSize,context:window,upload:!1,aborted:!1};Object.keys(n).forEach((e=>t[e]=t[e]??n[e])),t.method=t.method.toUpperCase(),"GET"!==t.method&&(t.method="POST"),t.requestRetry=t.retry},e.status={update:{onRequest:()=>console.log("Sending Request..."),onWaiting:()=>console.log("Waiting for Response..."),onProcessing:()=>console.log("Processing..."),onComplete:()=>console.log("Done.")},dontUpdate:{onRequest:()=>{},onWaiting:()=>{},onProcessing:()=>{},onComplete:()=>{}}},e.cursor={update:{onWaiting:()=>{jaxon.config.baseDocument.body&&(jaxon.config.baseDocument.body.style.cursor="wait")},onComplete:()=>{jaxon.config.baseDocument.body&&(jaxon.config.baseDocument.body.style.cursor="auto")}},dontUpdate:{onWaiting:()=>{},onComplete:()=>{}}}}(jaxon.config),window.jaxon=jaxon,function(e,t,n){e.$=e=>e?t.isString(e)?n.getElementById(e):e:null;e.getBrowserHTML=t=>{const o=(()=>{const t=e.$("jaxon_temp_workspace");if(t)return t;if(!n.body)return null;const o=n.createElement("div");return o.setAttribute("id","jaxon_temp_workspace"),o.style.display="none",o.style.visibility="hidden",n.body.appendChild(o),o})();o.innerHTML=t;const r=o.innerHTML;return o.innerHTML="",r},e.willChange=(t,n,o)=>!!(t=e.$(t))&&o!=t[n],e.removeElement=t=>{(t=e.$(t))&&t.parentNode&&t.parentNode.removeChild&&t.parentNode.removeChild(t)},e.findFunction=(e,n=window)=>{if("toInt"===e&&n===window)return t.toInt;const o=e.split("."),r=o.length;for(let e=0;e{const n=e.split(".");e=n.pop();const o=n.length;for(let e=0;e{t.forEach((t=>{const{childNodes:o,type:r}=t;void 0!==o&&"select-one"!==r&&"select-multiple"!==r&&n(e,o),((e,{type:t,name:n,tagName:o,checked:r,disabled:a,value:s,options:c})=>{if(!n||"PARAM"===o)return;if(!e.disabled&&a)return;const{prefix:i}=e;if(i.length>0&&i!==n.substring(0,i.length))return;if(("radio"===t||"checkbox"===t)&&!r)return;if("file"===t)return;const l="select-multiple"!==t?s:c.filter((({selected:e})=>e)).map((({value:e})=>e)),u=n.indexOf("[");if(u<0)return void(e.values[n]=l);let d=n.substring(0,u),p=n.substring(u);void 0===e.values[d]&&(e.values[d]={});let m=e.values;for(;p.length>0;){const e=p.substring(0,p.indexOf("]")+1),n=d,o=m;p=p.substring(p.indexOf("]")+1),m=m[d],d=e.substring(1,e.length-1),""===d&&("select-multiple"===t?(d=n,m=o):d=m.length),void 0===d&&(d=Object.keys(o[n]).length),m[d]=m[d]||{}}m[d]=l})(e,t)}))};e.getValues=(e,o=!1,r="")=>{const a={disabled:!0===o,prefix:r??"",values:{}},s=t.$(e);return s&&s.childNodes&&n(a,s.childNodes),a.values}}(jaxon.utils.form,jaxon.utils.dom),function(e){e.create=e=>({start:0,count:0,size:e,end:0,elements:[],paused:!1}),e.empty=e=>e.count<=0,e.full=e=>e.count>=e.size,e.push=(t,n)=>{if(e.full(t))throw{code:10003};return t.elements[t.end]=n,++t.end>=t.size&&(t.end=0),++t.count},e.pushFront=(t,n)=>{if(e.full(t))throw{code:10003};return e.empty(t)?e.push(t,n):(--t.start<0&&(t.start=t.size-1),t.elements[t.start]=n,++t.count)},e.pop=t=>{if(e.empty(t))return null;let n=t.elements[t.start];return delete t.elements[t.start],++t.start>=t.size&&(t.start=0),t.count--,n},e.peek=t=>e.empty(t)?null:t.elements[t.start]}(jaxon.utils.queue),function(e){"use strict";let t=[],n=!1,o=!1;const r=()=>{n||(n=!0,t.forEach((e=>e.fn.call(window,e.ctx))),t=[])};e.ready=function(e,a){n?setTimeout((function(){e(a)}),1):(t.push({fn:e,ctx:a}),"complete"===document.readyState||!document.attachEvent&&"interactive"===document.readyState?setTimeout(r,1):o||(document.addEventListener("DOMContentLoaded",r,!1),window.addEventListener("load",r,!1),o=!0))}}(jaxon.utils.dom),function(e){e.doubleQuotes=e=>void 0!==e&&e.replace(new RegExp("'","g"),'"'),e.singleQuotes=e=>void 0!==e&&e.replace(new RegExp('"',"g"),"'"),e.stripOnPrefix=e=>0===(e=e.toLowerCase()).indexOf("on")?e.replace(/on/,""):e,e.addOnPrefix=e=>0!==(e=e.toLowerCase()).indexOf("on")?"on"+e:e,String.prototype.supplant||(String.prototype.supplant=function(e){return this.replace(/\{([^{}]*)\}/g,((t,n)=>{const o=e[n],r=typeof o;return"string"===r||"number"===r?o:t}))})}(jaxon.utils.string),function(e){e.of=e=>Object.prototype.toString.call(e).slice(8,-1).toLowerCase(),e.isObject=t=>"object"===e.of(t),e.isArray=t=>"array"===e.of(t),e.isString=t=>"string"===e.of(t),e.isFunction=t=>"function"===e.of(t),e.toInt=e=>parseInt(e),Array.prototype.top||(Array.prototype.top=function(){return this.length>0?this[this.length-1]:void 0})}(jaxon.utils.types),function(e,t,n){e.initialize=e=>{(e=>{if(!e.upload)return!1;e.upload={id:e.upload,input:null,form:null};const o=t.$(e.upload.id);return o?"file"!==o.type?(n.log("The upload input field with id "+e.upload.id+" is not of type file"),!1):0===o.files.length?(n.log("There is no file selected for upload in input field with id "+e.upload.id),!1):void 0===o.name?(n.log("The upload input field with id "+e.upload.id+" has no name attribute"),!1):(e.upload.input=o,e.upload.form=o.form,!0):(n.log("Unable to find input field for file upload with id "+e.upload.id),!1)})(e)||(e.postHeaders["content-type"]=e.contentType)}}(jaxon.utils.upload,jaxon.utils.dom,console),function(e,t){const n={},o="main",r=["dom.assign","dom.append","dom.prepend","dom.replace"],a=["innerHTML","outerHTML"];e.changed=(e,t,n)=>e&&a.some((e=>e===n))&&r.some((e=>e===t));e.process=(e=document)=>{e.querySelectorAll(":scope [jxn-on]").forEach((e=>{e.hasAttribute("jxn-func")&&(e=>{const n=e.getAttribute("jxn-on"),o=JSON.parse(e.getAttribute("jxn-func"));if(!e.hasAttribute("jxn-select"))return void t.setEventHandler({target:e,event:n,func:o});const r=e.getAttribute("jxn-select");e.querySelectorAll(`:scope ${r}`).forEach((e=>{t.setEventHandler({target:e,event:n,func:o})}))})(e),e.removeAttribute("jxn-on"),e.removeAttribute("jxn-func"),e.removeAttribute("jxn-select")}));e.querySelectorAll(":scope [jxn-component]").forEach((e=>{const t=e.getAttribute("jxn-component"),r=e.getAttribute("jxn-item")??o;n[`${t}_${r}`]=e,e.removeAttribute("jxn-component")}))},e.node=(e,t=o)=>n[`${e}_${t}`]??null}(jaxon.call.attr,jaxon.cmd.event),function(e,t,n,o,r,a){const s={comparator:()=>!1,command:e=>{console.error("Unexpected command: "+JSON.stringify({call:e}))}},c={eq:(e,t)=>e==t,teq:(e,t)=>e===t,ne:(e,t)=>e!=t,nte:(e,t)=>e!==t,gt:(e,t)=>e>t,ge:(e,t)=>e>=t,lt:(e,t)=>ee<=t},i=e=>a.isObject(e)&&e._type,l=(e,t)=>{if(!i(e))return e;const{_type:n,_name:a}=e;switch(n){case"form":return r.getValues(a);case"html":return o.$(a).innerHTML;case"input":return o.$(a).value;case"checked":return o.$(a).checked;case"expr":return f(e,{target:window});case"_":return"this"===a?t:void 0;default:return}},u=(e,t)=>e.map((e=>l(e,t))),d={select:({_name:e,context:n=null},o)=>{switch(e){case"this":return t.select(o.target);case"event":return o.event;case"window":return window;default:return t.select(e,n)}},event:({_name:e,func:t},n,o)=>(o.on(e,(e=>f(t,{...n,event:e,target:e.currentTarget}))),o),func:({_name:e,args:t=[]},n,r)=>{const a=o.findFunction(e);return a?a.apply(n,u(t,r)):void 0},method:({_name:e,args:t=[]},n,r)=>{const s=o.findFunction(e,r);return s?s.apply(r,u(t,r)):"toInt"===e?a.toInt(r):void 0},attr:({_name:e,value:t},n,r)=>{const a=o.getInnerObject(e,r||n.target);if(a)return void 0!==t&&(a.node[a.attr]=l(t,r)),a.node[a.attr]}},p=(e,t,n)=>(i(e)?d[e._type]:s.command)(e,t,n);e.execCall=(e,t)=>p(e,{target:window,...t});const m=(e,t)=>{let n;const o=e.length;for(let r=0;r{const n={};let o=1;return t.forEach((e=>n[o++]=l(e))),e.supplant(n)};const x=t=>{if(t){const{lib:o,type:r,content:{title:a,phrase:s}}=t;n.get(o).alert(r,e.makePhrase(s),a)}},f=(t,o)=>{const{calls:r,question:a,condition:i,message:u}=t;if(a)((t,o,r,a)=>{const{lib:s,phrase:c}=o;n.get(s).confirm(e.makePhrase(c),"",(()=>m(t,a)),(()=>x(r)))})(r,a,u,o);else{if(!i)return m(r,o);((e,t,n,o)=>{const[r,a,i]=t;(c[r]??s.comparator)(l(a),l(i))?m(e,o):x(n)})(r,i,u,o)}};e.execExpr=(e,t)=>a.isObject(e)?f(e,{target:window,...t}):null}(jaxon.call.json,jaxon.call.query,jaxon.dialog.lib,jaxon.utils.dom,jaxon.utils.form,jaxon.utils.types),function(e,t){e.jq=t,e.select=(t,n=null)=>n?e.jq(t,n):e.jq(t)}(jaxon.call.query,window.jQuery),function(e,t,n){const o=e=>({timer:null,delay:e}),r=["onInitialize","onProcessParams","onPrepare","onRequest","onResponseDelay","onExpiration","beforeResponseProcessing","onFailure","onRedirect","onSuccess","onComplete"];e.create=(e,t)=>{const a={timers:{onResponseDelay:o(e??n.defaultResponseDelayTime),onExpiration:o(t??n.defaultExpirationTime)}};return r.forEach((e=>a[e]=null)),a},e.callback=e.create(),e.initCallbacks=n=>{if(t.isObject(n.callback)&&(n.callback=[n.callback]),t.isArray(n.callback))return void n.callback.forEach((e=>{void 0===e.timers&&(e.timers={})}));let o=!1;const a=e.create();r.forEach((e=>{void 0!==n[e]&&(a[e]=n[e],o=!0,delete n[e])})),n.callback=o?[a]:[]};const a=({callback:t=[]})=>[e.callback,...t];e.execute=(e,n)=>a(e).forEach((o=>((e,n,o)=>{const r=e[n];if(!r||!t.isFunction(r))return;const a=e.timers[n];a?a.timer=setTimeout((()=>r(o)),a.delay):r(o)})(o,n,e)));e.clearTimer=(e,t)=>a(e).forEach((e=>((e,t)=>{const n=e.timers[t];void 0!==n&&null!==n.timer&&clearTimeout(n.timer)})(e,t)))}(jaxon.ajax.callback,jaxon.utils.types,jaxon.config),function(e,t,n,o,r,a,s,c){const i={};e.q={send:a.create(t.requestQueueSize),recv:a.create(2*t.requestQueueSize)},e.register=(e,t,n="")=>i[e]={desc:n,func:t},e.unregister=e=>{const t=i[e];return t?(delete i[e],t.func):null},e.isRegistered=({name:e})=>void 0!==e&&void 0!==i[e];e.execute=t=>{const{name:n,args:o={}}=t;if(!e.isRegistered({name:n}))return!0;const a=o.component?.name;a&&(o.target=r.node(a,o.component.item));const c=o.id;!o.target&&c&&(o.target=s.$(c));const l=((e,t,n)=>{const{func:o,desc:r}=i[e];return o(t,{...n,desc:r})})(n,o,t);return r.changed(o.target,n,o.attr)&&r.process(o.target),l},e.popAsyncRequest=e=>a.empty(e)||"synchronous"===a.peek(e).mode?null:a.pop(e),e.sleep=({duration:e},{commandQueue:t})=>(t.paused=!0,setTimeout((()=>{t.paused=!1,n.processCommands(t)}),100*e),!0);const l=(e,t=0)=>{for(;t>0&&e.count>1&&null!==a.pop(e);)--t;e.paused=!1,n.processCommands(e)};e.confirm=({count:e,question:{lib:t,phrase:n}},{commandQueue:r})=>{r.paused=!0;return c.get(t).confirm(o.makePhrase(n),"",(()=>l(r)),(()=>l(r,e))),!0}}(jaxon.ajax.handler,jaxon.config,jaxon.ajax.response,jaxon.call.json,jaxon.call.attr,jaxon.utils.queue,jaxon.utils.dom,jaxon.dialog.lib),function(e,t,n){const o={};e.setBag=(e,t)=>o[e]=t,e.setBags=t=>Object.keys(t).forEach((n=>e.setBag(n,t[n]))),e.clearBag=e=>delete o[e];const r=({func:e,parameters:r,bags:a=[]},s)=>{const c=new Date;var i;s("jxnr",c.getTime()),s("jxnv",`${n.major}.${n.minor}.${n.patch}`),Object.keys(e).forEach((t=>s(t,encodeURIComponent(e[t])))),[...r].forEach((e=>s("jxnargs[]",(e=>{if(null==e)return"*";const n=t.of(e);if("object"===n||"array"===n)try{return encodeURIComponent(JSON.stringify(e))}catch(t){e=""}return e=encodeURIComponent(e),"string"===n?"S"+e:"boolean"===n?"B"+e:"number"===n?"N"+e:e})(e)))),a.length>0&&s("jxnbags",encodeURIComponent((i=a,JSON.stringify(i.reduce(((e,t)=>({...e,[t]:o[t]??"*"})),{})))))};e.process=e=>{e.requestURI=e.URI,e.requestData=(({upload:e})=>e&&e.ajax&&e.input)(e)?(e=>{const t=new FormData;r(e,((e,n)=>t.append(e,n)));const n=e.upload.input;return n.files&&n.files.forEach((e=>t.append(n.name,e))),t})(e):(e=>{const t=[];return r(e,((e,n)=>t.push(e+"="+n))),"POST"===e.method?t.join("&"):(e.requestURI+=(-1===e.requestURI.indexOf("?")?"?":"&")+t.join("&"),"")})(e)}}(jaxon.ajax.parameters,jaxon.utils.types,jaxon.version),function(e,t,n,o,r,a,s,c){const i=e=>{--e.requestRetry,r.execute(e,"onPrepare"),e.httpRequestOptions={...t.httpRequestOptions,method:e.method,headers:{...e.commonHeaders,..."POST"===e.method?e.postHeaders:e.getHeaders},body:e.requestData},e.responseConverter=t=>(e.response=t,e.convertResponseToJson?t.json():t.text()),e.responseHandler=t=>{e.responseContent=t,c.empty(a.q.send)||"synchronous"===e.mode?o.received(e):c.push(a.q.recv,e)},e.errorHandler=t=>{throw r.execute(e,"onFailure"),t},e.responseProcessor||(e.responseProcessor=o.jsonProcessor)},l=e=>(e.status.onRequest(),r.execute(e,"onResponseDelay"),r.execute(e,"onExpiration"),r.execute(e,"onRequest"),e.cursor.onWaiting(),e.status.onWaiting(),fetch(e.requestURI,e.httpRequestOptions).then(e.responseConverter).then(e.responseHandler).catch(e.errorHandler),e.returnValue);e.complete=e=>{if(r.execute(e,"onComplete"),e.cursor.onComplete(),e.status.onComplete(),(e=>{delete e.func,delete e.URI,delete e.requestURI,delete e.requestData,delete e.requestRetry,delete e.httpRequestOptions,delete e.responseHandler,delete e.responseConverter,delete e.responseContent,delete e.response,delete e.errorHandler})(e),"synchronous"===e.mode){for(c.pop(a.q.send),c.pop(a.q.recv);null!==(recvRequest=a.popAsyncRequest(a.q.recv));)o.received(recvRequest);for(;null!==(nextRequest=a.popAsyncRequest(a.q.send));)l(nextRequest);null!==(nextRequest=c.peek(a.q.send))&&l(nextRequest)}},e.abort=t=>{t.aborted=!0,e.complete(t)},e.execute=(e,o)=>{if(void 0===e)return!1;const u=o??{};for(u.func=e,(e=>{t.setRequestOptions(e),r.initCallbacks(e),r.execute(e,"onInitialize"),e.status=e.statusMessages?t.status.update:t.status.dontUpdate,e.cursor=e.waitCursor?t.cursor.update:t.cursor.dontUpdate,s.initialize(e),e.submit=c.empty(a.q.send),"synchronous"===e.mode&&(c.push(a.q.send,e),c.push(a.q.recv,e)),e.submit||c.push(a.q.send,e)})(u),r.execute(u,"onProcessParams"),n.process(u);u.requestRetry>0;)try{return i(u),u.submit?l(u):null}catch(e){if(r.execute(u,"onFailure"),u.requestRetry<=0)throw e}return!0}}(jaxon.ajax.request,jaxon.config,jaxon.ajax.parameters,jaxon.ajax.response,jaxon.ajax.callback,jaxon.ajax.handler,jaxon.utils.upload,jaxon.utils.queue),function(e,t,n,o,r,a,s){const c=[0,200],i=[400,401,402,403,404,500,501,502,503],l=[301,302,307],u=e=>{try{return n.execute(e)}catch(e){console.log(e)}return!0};e.processCommands=e=>{let t=null;for(;!e.paused&&null!==(t=a.pop(e));)if(!u(t))return!1;return!0},e.jsonProcessor=t=>c.indexOf(t.response.status)>=0?(r.execute(t,"onSuccess"),(e=>{if(!s.isObject(e.responseContent))return;const{debug:{message:t}={},jxn:{value:n,commands:o=[]}={}}=e.responseContent;e.status.onProcessing(),n&&(e.returnValue=n),t&&console.log(t);let r=0;o.forEach((t=>a.push(e.commandQueue,{fullName:"*unknown*",...t,sequence:r++,commandQueue:e.commandQueue,request:e,context:e.context}))),a.push(e.commandQueue,{name:"response.complete",fullName:"Response Complete",sequence:r,commandQueue:e.commandQueue,request:e,context:e.context})})(t),e.processCommands(t.commandQueue),t.returnValue):l.indexOf(t.response.status)>=0?(r.execute(t,"onRedirect"),o.complete(t),window.location=t.response.headers.get("location"),t.returnValue):i.indexOf(t.response.status)>=0?(r.execute(t,"onFailure"),o.complete(t),t.returnValue):t.returnValue,e.received=e=>e.aborted?null:(e.commandQueue=a.create(t.commandQueueSize),r.clearTimer(e,"onExpiration"),r.clearTimer(e,"onResponseDelay"),r.execute(e,"beforeResponseProcessing"),e.responseProcessor(e))}(jaxon.ajax.response,jaxon.config,jaxon.ajax.handler,jaxon.ajax.request,jaxon.ajax.callback,jaxon.utils.queue,jaxon.utils.types),function(e,t,n,o){e.assign=({target:e,attr:n,value:o})=>{const r=t.getInnerObject(n,e);return null!==r&&(r.node[r.attr]=o),!0},e.append=({target:e,attr:n,value:o})=>{const r=t.getInnerObject(n,e);return null!==r&&(r.node[r.attr]=r.node[r.attr]+o),!0},e.prepend=({target:e,attr:n,value:o})=>{const r=t.getInnerObject(n,e);return null!==r&&(r.node[r.attr]=o+r.node[r.attr]),!0};e.replace=({target:e,attr:o,search:r,replace:a})=>{const s=t.getInnerObject(o,e);return null!==s&&((e,o,r)=>{const a=n.isFunction(e.node[e.attr]),s=(a?e.node[e.attr].join(""):e.node[e.attr]).replaceAll(o,r);(a||t.willChange(e.node,e.attr,s))&&(e.node[e.attr]=s)})(s,"innerHTML"===o?t.getBrowserHTML(r):r,a),!0},e.clear=({target:t,attr:n})=>(e.assign({target:t,attr:n,value:""}),!0),e.remove=({target:e})=>(t.removeElement(e),!0);const r=(e,t)=>{const n=o.createElement(e);return n.setAttribute("id",t),n};e.create=({target:e,tag:{id:t,name:n}})=>(e&&e.appendChild(r(n,t)),!0),e.insert=({target:e,tag:{id:t,name:n}})=>(e&&e.parentNode&&e.parentNode.insertBefore(r(n,t),e),!0),e.insertAfter=({target:e,tag:{id:t,name:n}})=>(e&&e.parentNode&&e.parentNode.insertBefore(r(n,t),e.nextSibling),!0)}(jaxon.cmd.body,jaxon.utils.dom,jaxon.utils.types,jaxon.config.baseDocument),function(e,t,n,o){e.addHandler=({target:e,event:t,func:r})=>(e.addEventListener(o.stripOnPrefix(t),n.findFunction(r),!1),!0),e.removeHandler=({target:e,event:t,func:r})=>(e.removeEventListener(o.stripOnPrefix(t),n.findFunction(r),!1),!0);const r=(e,n,o)=>{t.execExpr({_type:"expr",...o},{event:e,target:n})};e.addEventHandler=({target:e,event:t,func:n,options:a})=>(e.addEventListener(o.stripOnPrefix(t),(t=>r(t,e,n)),a??!1),!0),e.setEventHandler=({target:e,event:t,func:n})=>(e[o.addOnPrefix(t)]=t=>r(t,e,n),!0)}(jaxon.cmd.event,jaxon.call.json,jaxon.utils.dom,jaxon.utils.string),function(e,t,n,o){e.call=({func:e,args:n},{context:o={}})=>(t.execCall({_type:"func",_name:e,args:n},o),!0),e.exec=({expr:e})=>(t.execExpr(e),!0),e.redirect=({url:e,delay:t})=>t<=0?(window.location=e,!0):(window.setTimeout((()=>window.location=e),1e3*t),!0),e.setDatabag=({values:e})=>(n.setBags(e),!0),e.jquery=({selector:e})=>(t.execExpr(e),!0);const r=(e,t)=>e.map((e=>o.isObject(e)&&"page"===e._type?parseInt(t.parentNode.getAttribute("data-page")):e));e.paginate=({target:e,func:n})=>{const o=e.querySelectorAll("li.enabled > a"),{args:a}=n;return o.forEach((e=>e.addEventListener("click",(()=>t.execCall({...n,_type:"func",args:r(a,e)}))))),!0}}(jaxon.cmd.script,jaxon.call.json,jaxon.ajax.parameters,jaxon.utils.types),function(e,t,n){const o=(e,n)=>{t.has(e)||console.warn(`Unable to find a Jaxon dialog library with name "${e}".`);const o=t.get(e);return o[n]?o:(console.error(`The chosen Jaxon dialog library doesn't implement the "${n}" function.`),null)};e.showMessage=({lib:e,type:t,content:r})=>{const{title:a,phrase:s}=r,c=o(e,"alert");return c&&c.alert(t,n.makePhrase(s),a),!0},e.showModal=({lib:e,dialog:{title:t,content:n,buttons:r,options:a}})=>{const s=o(e,"show");return s&&s.show(t,n,r,a),!0},e.hideModal=({lib:e})=>{const t=o(e,"hide");return t&&t.hide(),!0}}(jaxon.dialog.cmd,jaxon.dialog.lib,jaxon.call.json),function(e,t,n,o,r){const a={yes:"Yes",no:"No"};e.default={},e.has=t=>!!e[t],e.get=t=>e[t]??e.default,e.register=(s,c)=>{e[s]={},c(e[s],{types:t,dom:n,js:o,jq:r,labels:a})},e.register("default",(e=>{e.alert=(e,t,n)=>alert(n?`${n}
${t}`:t),e.confirm=(e,t,n,o)=>{confirm(t?`${t}
${e}`:e)?n():o&&o()}}))}(jaxon.dialog.lib,jaxon.utils.types,jaxon.dom,jaxon.call.json,window.jQuery),jaxon.request=jaxon.ajax.request.execute,jaxon.register=jaxon.ajax.handler.register,jaxon.$=jaxon.utils.dom.$,jaxon.jq=jaxon.call.query.jq,jaxon.exec=jaxon.call.json.execExpr,jaxon.dom.ready=jaxon.utils.dom.ready,jaxon.getFormValues=jaxon.utils.form.getValues,jaxon.setBag=jaxon.ajax.parameters.setBag,jaxon.processCustomAttrs=()=>jaxon.call.attr.process(),jaxon.isLoaded=!0,function(e,t,n,o){e("response.complete",((e,{request:t})=>(n.request.complete(t),!0)),"Response complete"),e("dom.assign",t.body.assign,"Dom::Assign"),e("dom.append",t.body.append,"Dom::Append"),e("dom.prepend",t.body.prepend,"Dom::Prepend"),e("dom.replace",t.body.replace,"Dom::Replace"),e("dom.clear",t.body.clear,"Dom::Clear"),e("dom.remove",t.body.remove,"Dom::Remove"),e("dom.create",t.body.create,"Dom::Create"),e("dom.insert.before",t.body.insert,"Dom::InsertBefore"),e("dom.insert.after",t.body.insertAfter,"Dom::InsertAfter"),e("script.call",t.script.call,"Script::CallJsFunction"),e("script.exec",t.script.exec,"Script::ExecJsonExpression"),e("script.redirect",t.script.redirect,"Script::Redirect"),e("script.sleep",n.handler.sleep,"Handler::Sleep"),e("script.confirm",n.handler.confirm,"Handler::Confirm"),e("handler.event.set",t.event.setEventHandler,"Script::SetEventHandler"),e("handler.event.add",t.event.addEventHandler,"Script::AddEventHandler"),e("handler.add",t.event.addHandler,"Script::AddHandler"),e("handler.remove",t.event.removeHandler,"Script::RemoveHandler"),e("script.debug",(({message:e})=>(console.log(e),!0)),"Debug message"),e("jquery.call",t.script.jquery,"JQuery::CallSelector"),e("pg.paginate",t.script.paginate,"Paginator::Paginate"),e("databag.set",t.script.setDatabag,"Databag:SetValues"),e("databag.clear",t.script.clearDatabag,"Databag:ClearValue"),e("dialog.message",o.cmd.showMessage,"Dialog:ShowMessage"),e("dialog.modal.show",o.cmd.showModal,"Dialog:ShowModal"),e("dialog.modal.hide",o.cmd.hideModal,"Dialog:HideModal")}(jaxon.register,jaxon.cmd,jaxon.ajax,jaxon.dialog); \ No newline at end of file diff --git a/dist/jaxon.module.js b/dist/jaxon.module.js index 2105bc5..faada85 100644 --- a/dist/jaxon.module.js +++ b/dist/jaxon.module.js @@ -17,7 +17,7 @@ var jaxon = { version: { major: '5', minor: '0', - patch: '0rc-8', + patch: '0rc-9', }, debug: { @@ -457,42 +457,47 @@ window.jaxon = jaxon; (function(self, dom) { /** - * @param {object} aFormValues + * @param {object} xOptions * @param {object} child - * @param {boolean} submitDisabledElements - * @param {string} prefix + * @param {string} child.type + * @param {string} child.name + * @param {string} child.tagName + * @param {boolean} child.checked + * @param {boolean} child.disabled + * @param {mixed} child.value + * @param {array} child.options * * @returns {void} */ - const _getValue = (aFormValues, child, submitDisabledElements, prefix) => { - if (!child.name || 'PARAM' === child.tagName) + const _getValue = (xOptions, { type, name, tagName, checked, disabled, value, options }) => { + if (!name || 'PARAM' === tagName) return; - if (!submitDisabledElements && child.disabled) + if (!xOptions.disabled && disabled) return; - if (prefix !== child.name.substring(0, prefix.length)) + const { prefix } = xOptions; + if (prefix.length > 0 && prefix !== name.substring(0, prefix.length)) return; - if ((child.type === 'radio' || child.type === 'checkbox') && !child.checked) + if ((type === 'radio' || type === 'checkbox') && !checked) return; - if (child.type === 'file') + if (type === 'file') return; - const name = child.name; - const values = child.type !== 'select-multiple' ? child.value : - child.options.filter(({ selected }) => selected).map(({ value }) => value); + const values = type !== 'select-multiple' ? value : + options.filter(({ selected }) => selected).map(({ value: v }) => v); const keyBegin = name.indexOf('['); if (keyBegin < 0) { - aFormValues[name] = values; + xOptions.values[name] = values; return; } // Parse names into brackets let k = name.substring(0, keyBegin); let a = name.substring(keyBegin); - if (aFormValues[k] === undefined) { - aFormValues[k] = {}; + if (xOptions.values[k] === undefined) { + xOptions.values[k] = {}; } - let p = aFormValues; // pointer reset + let p = xOptions.values; // pointer reset while (a.length > 0) { const sa = a.substring(0, a.indexOf(']') + 1); const lastKey = k; //save last key @@ -502,7 +507,7 @@ window.jaxon = jaxon; p = p[k]; k = sa.substring(1, sa.length - 1); if (k === '') { - if ('select-multiple' === child.type) { + if ('select-multiple' === type) { k = lastKey; //restore last key p = lastRef; } else { @@ -510,7 +515,7 @@ window.jaxon = jaxon; } } if (k === undefined) { - /*check against the global aFormValues Stack wich is the next(last) usable index */ + /*check against the global xOptions.values Stack wich is the next(last) usable index */ k = Object.keys(lastRef[lastKey]).length; } p[k] = p[k] || {}; @@ -519,19 +524,18 @@ window.jaxon = jaxon; }; /** - * @param {object} aFormValues + * @param {object} xOptions * @param {array} children - * @param {boolean} submitDisabledElements - * @param {string} prefix * * @returns {void} */ - const _getValues = (aFormValues, children, submitDisabledElements, prefix) => { + const _getValues = (xOptions, children) => { children.forEach(child => { - if (child.childNodes !== undefined && child.type !== 'select-one' && child.type !== 'select-multiple') { - _getValues(aFormValues, child.childNodes, submitDisabledElements, prefix); + const { childNodes, type } = child; + if (childNodes !== undefined && type !== 'select-one' && type !== 'select-multiple') { + _getValues(xOptions, childNodes); } - _getValue(aFormValues, child, submitDisabledElements, prefix); + _getValue(xOptions, child); }); }; @@ -539,20 +543,26 @@ window.jaxon = jaxon; * Build an associative array of form elements and their values from the specified form. * * @param {string} formId The unique name (id) of the form to be processed. - * @param {boolean} disabled (optional): Include form elements which are currently disabled. + * @param {boolean=false} disabled (optional): Include form elements which are currently disabled. * @param {string=''} prefix (optional): A prefix used for selecting form elements. * * @returns {object} An associative array of form element id and value. */ - self.getValues = (formId, disabled, prefix = '') => { - const submitDisabledElements = (disabled === true); - const prefixValue = prefix ?? ''; + self.getValues = (formId, disabled = false, prefix = '') => { + const xOptions = { + // Submit disabled fields + disabled: (disabled === true), + // Only submit fields with a prefix + prefix: prefix ?? '', + // Form values + values: {}, + }; + const form = dom.$(formId); - const aFormValues = {}; if (form && form.childNodes) { - _getValues(aFormValues, form.childNodes, submitDisabledElements, prefixValue); + _getValues(xOptions, form.childNodes); } - return aFormValues; + return xOptions.values; }; })(jaxon.utils.form, jaxon.utils.dom); @@ -986,10 +996,60 @@ window.jaxon = jaxon; */ const sDefaultComponentItem = 'main'; + /** + * The commands to check for changes + * + * @var {array} + */ + const aCommands = ['dom.assign', 'dom.append', 'dom.prepend', 'dom.replace']; + + /** + * The attributes to check for changes + * + * @var {array} + */ + const aAttributes = ['innerHTML', 'outerHTML']; + + /** + * Check if a the attributes on a targeted node must be processed after a command is executed. + * + * @param {Element} xTarget A DOM node. + * @param {string} sCommand The command name. + * @param {string} sAttribute The attribute name. + * + * @returns {void} + */ + self.changed = (xTarget, sCommand, sAttribute) => (xTarget) && + aAttributes.some(sVal => sVal === sAttribute) && + aCommands.some(sVal => sVal === sCommand); + + /** + * @param {Element} xNode A DOM node. + * + * @returns {void} + */ + const setEventHandlers = (xNode) => { + const sEvent = xNode.getAttribute('jxn-on'); + const oHandler = JSON.parse(xNode.getAttribute('jxn-func')); + if(!xNode.hasAttribute('jxn-select')) + { + // Set the event handler on the node. + event.setEventHandler({ target: xNode, event: sEvent, func: oHandler }); + return; + } + // Set the event handler on the selected children nodes. + const sSelector = xNode.getAttribute('jxn-select'); + const aChildren = xNode.querySelectorAll(`:scope ${sSelector}`); + aChildren.forEach(xChild => { + // Set the event handler on the child node. + event.setEventHandler({ target: xChild , event: sEvent, func: oHandler }); + }); + }; + /** * Process the custom attributes in a given DOM node. * - * @param {Element} xContainer The DOM node. + * @param {Element} xContainer A DOM node. * * @returns {void} */ @@ -997,15 +1057,13 @@ window.jaxon = jaxon; // Set event handlers on nodes const aEvents = xContainer.querySelectorAll(':scope [jxn-on]'); aEvents.forEach(xNode => { - if(!xNode.hasAttribute('jxn-func')) + if(xNode.hasAttribute('jxn-func')) { - return; + setEventHandlers(xNode); } - const sEvent = xNode.getAttribute('jxn-on'); - const oHandler = JSON.parse(xNode.getAttribute('jxn-func')); - event.setEventHandler({ target: xNode, event: sEvent, func: oHandler }); xNode.removeAttribute('jxn-on'); xNode.removeAttribute('jxn-func'); + xNode.removeAttribute('jxn-select'); }); // Associate DOM nodes to Jaxon components @@ -1369,23 +1427,16 @@ window.jaxon = jaxon; * * @returns {object} The callback object. */ - self.create = (responseDelayTime, expirationTime) => ({ - timers: { - onResponseDelay: setupTimer(responseDelayTime ?? config.defaultResponseDelayTime), - onExpiration: setupTimer(expirationTime ?? config.defaultExpirationTime), - }, - onInitialize: null, - onProcessParams: null, - onPrepare: null, - onRequest: null, - onResponseDelay: null, - onExpiration: null, - beforeResponseProcessing: null, - onFailure: null, - onRedirect: null, - onSuccess: null, - onComplete: null, - }); + self.create = (responseDelayTime, expirationTime) => { + const oCallback = { + timers: { + onResponseDelay: setupTimer(responseDelayTime ?? config.defaultResponseDelayTime), + onExpiration: setupTimer(expirationTime ?? config.defaultExpirationTime), + }, + }; + aCallbackNames.forEach(sName => oCallback[sName] = null); + return oCallback; + }; /** * The global callback object which is active for every request. @@ -1403,9 +1454,22 @@ window.jaxon = jaxon; * @return {void} */ self.initCallbacks = (oRequest) => { - const callback = self.create(); + if (types.isObject(oRequest.callback)) { + oRequest.callback = [oRequest.callback]; + } + if (types.isArray(oRequest.callback)) { + oRequest.callback.forEach(oCallback => { + // Add the timers attribute, if it is not defined. + if (oCallback.timers === undefined) { + oCallback.timers = {}; + } + }); + return; + } let callbackFound = false; + // Check if any callback is defined in the request object by its own name. + const callback = self.create(); aCallbackNames.forEach(sName => { if (oRequest[sName] !== undefined) { callback[sName] = oRequest[sName]; @@ -1413,38 +1477,18 @@ window.jaxon = jaxon; delete oRequest[sName]; } }); - - if (oRequest.callback === undefined) { - oRequest.callback = callback; - return; - } - // Add the timers attribute, if it is not defined. - if (oRequest.callback.timers === undefined) { - oRequest.callback.timers = {}; - } - if (callbackFound) { - oRequest.callback = [oRequest.callback, callback]; - } + oRequest.callback = callbackFound ? [callback] : []; }; /** * Get a flatten array of callbacks * * @param {object} oRequest The request context object. + * @param {array=} oRequest.callback The request callback(s). * * @returns {array} */ - const getCallbacks = (oRequest) => { - if(!oRequest.callback) - { - return [self.callback]; - } - if(types.isArray(oRequest.callback)) - { - return [self.callback, ...oRequest.callback]; - } - return [self.callback, oRequest.callback]; - }; + const getCallbacks = ({ callback = [] }) => [self.callback, ...callback]; /** * Execute a callback event. @@ -1457,10 +1501,10 @@ window.jaxon = jaxon; */ const execute = (oCallback, sFunction, oRequest) => { const func = oCallback[sFunction]; - const timer = !oCallback.timers ? null : oCallback.timers[sFunction]; if (!func || !types.isFunction(func)) { return; } + const timer = oCallback.timers[sFunction]; if (!timer) { func(oRequest); // Call the function directly. return; @@ -1591,23 +1635,23 @@ window.jaxon = jaxon; * @returns {false} The command signalled that it needs to pause processing. */ self.execute = (command) => { - const { name, args } = command; + const { name, args = {} } = command; if (!self.isRegistered({ name })) { return true; } // If the command has an "id" attr, find the corresponding dom node. - const sComponentName = args?.component?.name; + const sComponentName = args.component?.name; if ((sComponentName)) { args.target = attr.node(sComponentName, args.component.item); } - const id = args?.id; - if (!args?.target && (id)) { + const id = args.id; + if (!args.target && (id)) { args.target = dom.$(id); } // Process the command const bReturnValue = callHandler(name, args, command); // Process Jaxon custom attributes in the new node HTML content. - name === 'dom.assign' && attr.process(args.target); + attr.changed(args.target, name, args.attr) && attr.process(args.target); return bReturnValue; }; @@ -1885,10 +1929,9 @@ window.jaxon = jaxon; * @returns {boolean} */ const initialize = (oRequest) => { - cbk.execute(oRequest, 'onInitialize'); - cfg.setRequestOptions(oRequest); cbk.initCallbacks(oRequest); + cbk.execute(oRequest, 'onInitialize'); oRequest.status = (oRequest.statusMessages) ? cfg.status.update : cfg.status.dontUpdate; oRequest.cursor = (oRequest.waitCursor) ? cfg.cursor.update : cfg.cursor.dontUpdate; @@ -1915,6 +1958,7 @@ window.jaxon = jaxon; * @return {void} */ const prepare = (oRequest) => { + --oRequest.requestRetry; cbk.execute(oRequest, 'onPrepare'); oRequest.httpRequestOptions = { @@ -1962,7 +2006,6 @@ window.jaxon = jaxon; * @returns {mixed} */ const submit = (oRequest) => { - --oRequest.requestRetry; oRequest.status.onRequest(); // The onResponseDelay and onExpiration aren't called immediately, but a timer @@ -2080,7 +2123,7 @@ window.jaxon = jaxon; } catch (e) { cbk.execute(oRequest, 'onFailure'); - if (oRequest.requestRetry === 0) { + if (oRequest.requestRetry <= 0) { throw e; } } @@ -2310,23 +2353,13 @@ window.jaxon = jaxon; * Assign an element's attribute to the specified value. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The HTML element to effect. + * @param {Element} args.target The HTML element to effect. * @param {string} args.attr The name of the attribute to set. * @param {string} args.value The new value to be applied. * * @returns {true} The operation completed successfully. */ self.assign = ({ target, attr, value }) => { - if (attr === 'innerHTML') { - target.innerHTML = value; - return true; - } - if (attr === 'outerHTML') { - target.outerHTML = value; - return true; - } - const xElt = dom.getInnerObject(attr, target); if (xElt !== null) { xElt.node[xElt.attr] = value; @@ -2338,23 +2371,13 @@ window.jaxon = jaxon; * Append the specified value to an element's attribute. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The HTML element to effect. + * @param {Element} args.target The HTML element to effect. * @param {string} args.attr The name of the attribute to append to. * @param {string} args.value The new value to be appended. * * @returns {true} The operation completed successfully. */ self.append = ({ target, attr, value }) => { - if (attr === 'innerHTML') { - target.innerHTML = target.innerHTML + value; - return true; - } - if (attr === 'outerHTML') { - target.outerHTML = target.outerHTML + value; - return true; - } - const xElt = dom.getInnerObject(attr, target); if (xElt !== null) { xElt.node[xElt.attr] = xElt.node[xElt.attr] + value; @@ -2366,23 +2389,13 @@ window.jaxon = jaxon; * Prepend the specified value to an element's attribute. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The HTML element to effect. + * @param {Element} args.target The HTML element to effect. * @param {string} args.attr The name of the attribute. * @param {string} args.value The new value to be prepended. * * @returns {true} The operation completed successfully. */ self.prepend = ({ target, attr, value }) => { - if (attr === 'innerHTML') { - target.innerHTML = value + target.innerHTML; - return true; - } - if (attr === 'outerHTML') { - target.outerHTML = value + target.outerHTML; - return true; - } - const xElt = dom.getInnerObject(attr, target); if (xElt !== null) { xElt.node[xElt.attr] = value + xElt.node[xElt.attr]; @@ -2393,19 +2406,18 @@ window.jaxon = jaxon; /** * Replace a text in the value of a given attribute in an element * - * @param {object} xElement The element to search in - * @param {string} sAttribute The attribute to search in + * @param {object} xElt The value returned by the dom.getInnerObject() function * @param {string} sSearch The text to search * @param {string} sReplace The text to use as replacement * * @returns {void} */ - const replaceText = (xElement, sAttribute, sSearch, sReplace) => { - const bFunction = types.isFunction(xElement[sAttribute]); - const sCurText = bFunction ? xElement[sAttribute].join('') : xElement[sAttribute]; + const replaceText = (xElt, sSearch, sReplace) => { + const bFunction = types.isFunction(xElt.node[xElt.attr]); + const sCurText = bFunction ? xElt.node[xElt.attr].join('') : xElt.node[xElt.attr]; const sNewText = sCurText.replaceAll(sSearch, sReplace); - if (bFunction || dom.willChange(xElement, sAttribute, sNewText)) { - xElement[sAttribute] = sNewText; + if (bFunction || dom.willChange(xElt.node, xElt.attr, sNewText)) { + xElt.node[xElt.attr] = sNewText; } }; @@ -2413,19 +2425,17 @@ window.jaxon = jaxon; * Search and replace the specified text. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The element which is to be modified. + * @param {Element} args.target The element which is to be modified. * @param {string} args.attr The name of the attribute to be set. - * @param {array} args.search The search text and replacement text. - * @param {array} args.replace The search text and replacement text. + * @param {string} args.search The search text and replacement text. + * @param {string} args.replace The search text and replacement text. * * @returns {true} The operation completed successfully. */ self.replace = ({ target, attr, search, replace }) => { - const sSearch = attr === 'innerHTML' ? dom.getBrowserHTML(search) : search; const xElt = dom.getInnerObject(attr, target); if (xElt !== null) { - replaceText(xElt.node, xElt.attr, sSearch, replace); + replaceText(xElt, attr === 'innerHTML' ? dom.getBrowserHTML(search) : search, replace); } return true; }; @@ -2434,8 +2444,7 @@ window.jaxon = jaxon; * Clear an element. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The element which is to be modified. + * @param {Element} args.target The element which is to be modified. * @param {string} args.attr The name of the attribute to clear. * * @returns {true} The operation completed successfully. @@ -2449,8 +2458,7 @@ window.jaxon = jaxon; * Delete an element. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The element which will be deleted. + * @param {Element} args.target The element which will be deleted. * * @returns {true} The operation completed successfully. */ @@ -2475,8 +2483,7 @@ window.jaxon = jaxon; * Create a new element and append it to the specified parent element. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The element which will contain the new element. + * @param {Element} args.target The element which will contain the new element. * @param {string} args.tag.name The tag name for the new element. * @param {string} args.tag.id The id attribute of the new element. * @@ -2491,8 +2498,7 @@ window.jaxon = jaxon; * Insert a new element before the specified element. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The element that will be used as the reference point for insertion. + * @param {Element} args.target The element that will be used as the reference point for insertion. * @param {string} args.tag.name The tag name for the new element. * @param {string} args.tag.id The id attribute of the new element. * @@ -2508,8 +2514,7 @@ window.jaxon = jaxon; * Insert a new element after the specified element. * * @param {object} args The command arguments. - * @param {string} args.id The target element id - * @param {object} args.target The element that will be used as the reference point for insertion. + * @param {Element} args.target The element that will be used as the reference point for insertion. * @param {string} args.tag.name The tag name for the new element. * @param {string} args.tag.id The id attribute of the new element. * diff --git a/src/ajax/handler.js b/src/ajax/handler.js index 1a98d63..edee255 100644 --- a/src/ajax/handler.js +++ b/src/ajax/handler.js @@ -83,23 +83,23 @@ * @returns {false} The command signalled that it needs to pause processing. */ self.execute = (command) => { - const { name, args } = command; + const { name, args = {} } = command; if (!self.isRegistered({ name })) { return true; } // If the command has an "id" attr, find the corresponding dom node. - const sComponentName = args?.component?.name; + const sComponentName = args.component?.name; if ((sComponentName)) { args.target = attr.node(sComponentName, args.component.item); } - const id = args?.id; - if (!args?.target && (id)) { + const id = args.id; + if (!args.target && (id)) { args.target = dom.$(id); } // Process the command const bReturnValue = callHandler(name, args, command); // Process Jaxon custom attributes in the new node HTML content. - name === 'dom.assign' && attr.process(args.target); + attr.changed(args.target, name, args.attr) && attr.process(args.target); return bReturnValue; }; diff --git a/src/call/attr.js b/src/call/attr.js index 6bd2879..f72e78d 100644 --- a/src/call/attr.js +++ b/src/call/attr.js @@ -19,10 +19,60 @@ */ const sDefaultComponentItem = 'main'; + /** + * The commands to check for changes + * + * @var {array} + */ + const aCommands = ['dom.assign', 'dom.append', 'dom.prepend', 'dom.replace']; + + /** + * The attributes to check for changes + * + * @var {array} + */ + const aAttributes = ['innerHTML', 'outerHTML']; + + /** + * Check if a the attributes on a targeted node must be processed after a command is executed. + * + * @param {Element} xTarget A DOM node. + * @param {string} sCommand The command name. + * @param {string} sAttribute The attribute name. + * + * @returns {void} + */ + self.changed = (xTarget, sCommand, sAttribute) => (xTarget) && + aAttributes.some(sVal => sVal === sAttribute) && + aCommands.some(sVal => sVal === sCommand); + + /** + * @param {Element} xNode A DOM node. + * + * @returns {void} + */ + const setEventHandlers = (xNode) => { + const sEvent = xNode.getAttribute('jxn-on'); + const oHandler = JSON.parse(xNode.getAttribute('jxn-func')); + if(!xNode.hasAttribute('jxn-select')) + { + // Set the event handler on the node. + event.setEventHandler({ target: xNode, event: sEvent, func: oHandler }); + return; + } + // Set the event handler on the selected children nodes. + const sSelector = xNode.getAttribute('jxn-select'); + const aChildren = xNode.querySelectorAll(`:scope ${sSelector}`); + aChildren.forEach(xChild => { + // Set the event handler on the child node. + event.setEventHandler({ target: xChild , event: sEvent, func: oHandler }); + }); + }; + /** * Process the custom attributes in a given DOM node. * - * @param {Element} xContainer The DOM node. + * @param {Element} xContainer A DOM node. * * @returns {void} */ @@ -30,15 +80,13 @@ // Set event handlers on nodes const aEvents = xContainer.querySelectorAll(':scope [jxn-on]'); aEvents.forEach(xNode => { - if(!xNode.hasAttribute('jxn-func')) + if(xNode.hasAttribute('jxn-func')) { - return; + setEventHandlers(xNode); } - const sEvent = xNode.getAttribute('jxn-on'); - const oHandler = JSON.parse(xNode.getAttribute('jxn-func')); - event.setEventHandler({ target: xNode, event: sEvent, func: oHandler }); xNode.removeAttribute('jxn-on'); xNode.removeAttribute('jxn-func'); + xNode.removeAttribute('jxn-select'); }); // Associate DOM nodes to Jaxon components diff --git a/src/config.js b/src/config.js index 84d9d85..c970c6a 100644 --- a/src/config.js +++ b/src/config.js @@ -17,7 +17,7 @@ var jaxon = { version: { major: '5', minor: '0', - patch: '0rc-8', + patch: '0rc-9', }, debug: {