|
15 | 15 | //TODO [ x ] template binding |
16 | 16 | //TODO [ x ] Event > : 'new', 'set', 'reposition', 'delete', '-change', 'bind', 'unbind' |
17 | 17 | //TODO [ x ] DOM Attribute: 'path', 'bind', 'unbinded', 'template', 'templates', 'rebinding', 'onbind', 'link' |
| 18 | + //TODO [ x ] rootDataContext: '#' > document.documentElement.datacontext // bind to root data context |
18 | 19 |
|
19 | 20 | var DataContextBinding = Object.defineProperties(bindDataContext, { |
20 | 21 |
|
|
24 | 25 | bindElement: { value: bindElement, writable: false, configurable: false, enumerable: false }, |
25 | 26 | bindingContext: { value: bindingContext, writable: false, configurable: false, enumerable: false }, |
26 | 27 |
|
| 28 | + progess: { value: progessBind, writable: false, configurable: false, enumerable: false }, |
27 | 29 | context: { value: contextBind, writable: false, configurable: false, enumerable: false }, |
28 | 30 | change: { value: changeBind, writable: false, configurable: false, enumerable: false }, |
29 | 31 | innerHTML: { value: innerHTMLBind, writable: true, configurable: false, enumerable: false }, |
|
104 | 106 | setTimeout(waitForReadyState, 0, state, cb); |
105 | 107 | } |
106 | 108 |
|
107 | | - function bindAllElements(rootElement, rebinding = false) { |
| 109 | + function bindAllElements(rootElement, rebinding = false, isChildrenOnly = false) { |
108 | 110 |
|
109 | 111 | if (!rootElement) { rootElement = document.documentElement; } |
110 | 112 |
|
111 | | - bindElement(rootElement, rebinding); |
| 113 | + if (!isChildrenOnly) { bindElement(rootElement, rebinding); } |
112 | 114 |
|
113 | 115 | rootElement |
114 | 116 | .querySelectorAll(`[bind],[onbind],[template],[templates],[rebinding],[link],[unbinded]`) |
|
202 | 204 |
|
203 | 205 | function _link(path) { |
204 | 206 |
|
205 | | - if (element.linked) { return; } |
| 207 | + if (element.linked) { |
| 208 | + |
| 209 | + if (rebinding) { bindAllElements(element, true, true); } |
| 210 | + |
| 211 | + return; |
| 212 | + } |
206 | 213 |
|
207 | 214 | var { CreateLink } = globalScope?.modules?.['ws-user']; |
208 | 215 |
|
209 | 216 | if (CreateLink) { |
210 | 217 |
|
211 | 218 | element.linked = true; |
212 | 219 | element.wsLink = CreateLink(path, element); |
213 | | - element.wsLink.bindAllElements = function (elem, rebind = false) { bindAllElements(elem, rebind); }; |
214 | 220 | } |
215 | 221 | } |
216 | 222 |
|
217 | 223 | function _template(selectors, isMultiple = false) { |
218 | 224 |
|
219 | 225 | if (!selectors) { _tryBind(); return; } |
220 | 226 |
|
| 227 | + var templateElement = null; |
| 228 | + |
| 229 | + try { templateElement = element.querySelector(selectors) || document.querySelector(selectors); } |
| 230 | + catch { templateElement = null; } |
| 231 | + |
| 232 | + if (!templateElement && element.attributes.template_fetching) { return; } |
| 233 | + |
| 234 | + element.removeAttribute('template_fetching'); |
| 235 | + |
221 | 236 | //remove element children |
222 | 237 | var i = 0; |
223 | 238 | while (i < element.childElementCount) { |
|
232 | 247 | else { i++; } |
233 | 248 | } |
234 | 249 |
|
235 | | - var templateElement = null; |
236 | | - |
237 | | - try { templateElement = element.querySelector(selectors) || document.querySelector(selectors); } |
238 | | - catch { templateElement = null; } |
239 | | - |
240 | 250 |
|
241 | 251 | if (!templateElement) { return fetchContent(); } |
242 | 252 |
|
|
246 | 256 |
|
247 | 257 | function fetchContent() { |
248 | 258 |
|
| 259 | + element.setAttribute('template_fetching', ''); |
| 260 | + |
249 | 261 | fetch(selectors).then(function (res) { |
250 | 262 |
|
251 | 263 | res.text().then(function (textContent) { |
|
255 | 267 | ? templateElement.innerHTML = textContent |
256 | 268 | : templateElement.innerHTML = '<div>' + encodeHTML(textContent) + '</div>'; |
257 | 269 | bindTemplate(); |
| 270 | + |
| 271 | + element.removeAttribute('template_fetching'); |
258 | 272 | }); |
259 | 273 | }); |
260 | 274 |
|
|
289 | 303 |
|
290 | 304 | if (_bindingContext?.value?._isDataContext) { |
291 | 305 |
|
292 | | - if (isFunctionNotAdded('addTemplate')) { |
| 306 | + if (isFunctionNotAdded('addTemplate', element)) { |
293 | 307 |
|
294 | 308 | _bindingContext.value.on( |
295 | 309 | "-", |
|
306 | 320 | ); |
307 | 321 | } |
308 | 322 |
|
309 | | - if (isFunctionNotAdded('removeTemplate')) { |
| 323 | + if (isFunctionNotAdded('removeTemplate', element)) { |
310 | 324 |
|
311 | 325 | _bindingContext.value.on( |
312 | 326 | "-", |
|
334 | 348 | return appendTemplate(); |
335 | 349 |
|
336 | 350 |
|
337 | | - function isFunctionNotAdded(fnName) { |
| 351 | + function isFunctionNotAdded(fnName, element) { |
338 | 352 |
|
339 | 353 | return _bindingContext?.value?._events?.["-"] |
340 | | - ?.find(function (fn) { return fn.name.includes(fnName); }) === undefined; |
| 354 | + ?.find(function (fn) { |
| 355 | + |
| 356 | + return fn.name.includes(fnName) |
| 357 | + && fn.isActive === element; |
| 358 | + |
| 359 | + }) === undefined; |
341 | 360 | } |
342 | 361 | function appendTemplate(key, target) { |
343 | 362 |
|
|
503 | 522 | source: null, |
504 | 523 | property: null, |
505 | 524 | arrPath: [] |
506 | | - }; |
| 525 | + }, |
| 526 | + isMultiple = Boolean(elem.attributes.templates); |
507 | 527 |
|
508 | 528 | _findPathAndSource(); |
509 | 529 | _selectSource(); |
|
573 | 593 | ); |
574 | 594 | } |
575 | 595 |
|
| 596 | + if (d.arrPath.at(-1) === '#') { |
| 597 | + |
| 598 | + d.source = document.documentElement.datacontext; |
| 599 | + d.arrPath.pop(); |
| 600 | + } |
| 601 | + |
576 | 602 | if (d.rootElement.datacontext !== undefined) { |
577 | 603 |
|
578 | 604 | d.source = d.rootElement.datacontext; |
|
606 | 632 | d.source = _nextSource(d, arrPath.pop(), {}); |
607 | 633 | } |
608 | 634 |
|
609 | | - _nextSource(d, d.property, ""); |
| 635 | + _nextSource(d, d.property, isMultiple ? [] : ""); |
610 | 636 | } |
611 | 637 |
|
612 | 638 | function _nextSource(d, property, defValue) { |
|
648 | 674 |
|
649 | 675 | if (d.source[property]?._isDataContext) { return d.source[property]; } |
650 | 676 |
|
| 677 | + if (isMultiple) { |
| 678 | + |
| 679 | + d.source[property] = createDataContext(Array.isArray(d.source[property]) ? d.source[property] : []); |
| 680 | + |
| 681 | + setTimeout(function () { bindElement(d.rootElement, true); }); |
| 682 | + |
| 683 | + return d.source[property]; |
| 684 | + } |
| 685 | + |
651 | 686 | if (d.source[property] !== undefined) { |
652 | 687 |
|
653 | 688 | d.source[property] = createDataContext(d.source[property]); |
|
804 | 839 |
|
805 | 840 | if (event.eventName === "set") { |
806 | 841 |
|
807 | | - event.newValue._events = event.oldValue._events; |
| 842 | + if (event.oldValue?._isDataContext) { |
| 843 | + |
| 844 | + event.newValue._events = event.oldValue._events; |
| 845 | + } |
808 | 846 |
|
809 | 847 | emitProperties(event.newValue, event.oldValue, event.eventName); |
810 | 848 | } |
|
853 | 891 |
|
854 | 892 | //#region *** Default bind *** |
855 | 893 |
|
| 894 | + function progessBind(event) { |
| 895 | + |
| 896 | + if (event.eventName === "unbind") { |
| 897 | + |
| 898 | + if (this.wsLink) { |
| 899 | + |
| 900 | + this.wsLink.onreadystate = null; |
| 901 | + } |
| 902 | + } |
| 903 | + |
| 904 | + if (event.eventName === "bind") { |
| 905 | + |
| 906 | + this.isValueInverted = event.isValueInverted; |
| 907 | + this.attributeBindingName = event.bindArgs[0] || ''; |
| 908 | + this.attributeBindingValue = event.bindArgs[1] || ''; |
| 909 | + |
| 910 | + var parent = this.parentElement; |
| 911 | + |
| 912 | + while (!this.wsLink && parent) { |
| 913 | + |
| 914 | + this.wsLink = parent.wsLink; |
| 915 | + parent = parent.parentElement; |
| 916 | + } |
| 917 | + |
| 918 | + if (this.wsLink) { |
| 919 | + |
| 920 | + this.wsLink.onreadystate = handleReadyState.bind(this); |
| 921 | + } |
| 922 | + |
| 923 | + handleReadyState.call(this, this.wsLink?.readyState); |
| 924 | + } |
| 925 | + |
| 926 | + // I am alive! |
| 927 | + return this.isConnected; |
| 928 | + |
| 929 | + function handleReadyState(wsState) { |
| 930 | + |
| 931 | + if (!this.isConnected) { |
| 932 | + |
| 933 | + this.wsLink.onreadystate = null; |
| 934 | + return; |
| 935 | + } |
| 936 | + |
| 937 | + wsState = wsState === 1; |
| 938 | + wsState = this.isValueInverted ? !wsState : wsState; |
| 939 | + |
| 940 | + updateAttributeBinding.call(this, wsState, this.attributeBindingName, this.attributeBindingValue); |
| 941 | + } |
| 942 | + } |
856 | 943 | function contextBind(event) { |
857 | 944 |
|
858 | 945 | return false; |
|
1148 | 1235 | function toggle(element, isPrimary) { |
1149 | 1236 |
|
1150 | 1237 | if (isPrimary) { |
1151 | | - element.primaryClasses.forEach(function (c) { element.classList.add(c); }); |
1152 | | - element.secondaryClasses.forEach(function (c) { element.classList.remove(c); }); |
| 1238 | + element.primaryClasses?.forEach(function (c) { element.classList.add(c); }); |
| 1239 | + element.secondaryClasses?.forEach(function (c) { element.classList.remove(c); }); |
1153 | 1240 | } |
1154 | 1241 | else { |
1155 | | - element.primaryClasses.forEach(function (c) { element.classList.remove(c); }); |
1156 | | - element.secondaryClasses.forEach(function (c) { element.classList.add(c); }); |
| 1242 | + element.primaryClasses?.forEach(function (c) { element.classList.remove(c); }); |
| 1243 | + element.secondaryClasses?.forEach(function (c) { element.classList.add(c); }); |
1157 | 1244 | } |
1158 | 1245 | } |
1159 | 1246 | } |
|
0 commit comments