|
4 | 4 |
|
5 | 5 | (function () { |
6 | 6 |
|
7 | | - exportModule("data-context-binding", ["data-context"], function factory(DC) { |
| 7 | + exportModule('data-context-binding', ['data-context'], function factory(DC) { |
8 | 8 |
|
9 | 9 | var globalScope = this, |
10 | | - { createDataContext, parse, stringify } = DC; |
| 10 | + { createDataContext, parse, stringify } = DC, |
| 11 | + isDebug = document && Array.from(document.scripts).find(function (s) { return s.src.includes('data-context-binding'); })?.attributes.debug || false; |
11 | 12 |
|
12 | 13 |
|
13 | 14 | //TODO [ x ] default bind ... |
14 | 15 | //TODO [ x ] template binding |
15 | 16 | //TODO [ x ] Event > : 'new', 'set', 'reposition', 'delete', '-change', 'bind', 'unbind' |
16 | | - //TODO [ x ] DOM Attribute: 'path', 'bind', 'unbinded' |
| 17 | + //TODO [ x ] DOM Attribute: 'path', 'bind', 'unbinded', 'template', 'templates', 'rebinding', 'onbind', 'link' |
17 | 18 |
|
18 | 19 | var DataContextBinding = Object.defineProperties(bindDataContext, { |
19 | 20 |
|
|
23 | 24 | bindElement: { value: bindElement, writable: false, configurable: false, enumerable: false }, |
24 | 25 | bindingContext: { value: bindingContext, writable: false, configurable: false, enumerable: false }, |
25 | 26 |
|
| 27 | + context: { value: contextBind, writable: false, configurable: false, enumerable: false }, |
26 | 28 | change: { value: changeBind, writable: false, configurable: false, enumerable: false }, |
27 | 29 | innerHTML: { value: innerHTMLBind, writable: true, configurable: false, enumerable: false }, |
28 | 30 | value: { value: valueBind, writable: true, configurable: false, enumerable: false }, |
|
70 | 72 | */ |
71 | 73 | function bindDataContext(value) { |
72 | 74 |
|
73 | | - var htmlElement = document.querySelector("html"); |
| 75 | + var htmlElement = document.documentElement; |
74 | 76 |
|
75 | 77 | if (htmlElement) { |
76 | 78 |
|
|
89 | 91 | } |
90 | 92 | } |
91 | 93 |
|
| 94 | + globalScope.datacontext = htmlElement?.datacontext; |
| 95 | + |
92 | 96 | return htmlElement?.datacontext; |
93 | 97 | } |
94 | 98 |
|
|
102 | 106 |
|
103 | 107 | function bindAllElements(rootElement, rebinding = false) { |
104 | 108 |
|
105 | | - if (!rootElement) { rootElement = document.querySelector("html"); } |
| 109 | + if (!rootElement) { rootElement = document.documentElement; } |
106 | 110 |
|
107 | 111 | bindElement(rootElement, rebinding); |
108 | 112 |
|
109 | | - rootElement.querySelectorAll(`[bind],[onbind],[template],[templates],[rebinding],[link]`) |
110 | | - .forEach(function (element) { |
| 113 | + rootElement |
| 114 | + .querySelectorAll(`[bind],[onbind],[template],[templates],[rebinding],[link],[unbinded]`) |
| 115 | + .forEach(bind); |
| 116 | + |
| 117 | + if (rootElement !== document.documentElement) { |
111 | 118 |
|
112 | | - if (isParentTemplateOrLink(element)) { return; } |
| 119 | + document |
| 120 | + .documentElement.querySelectorAll(`[unbinded]`) |
| 121 | + .forEach(bind); |
| 122 | + } |
113 | 123 |
|
114 | | - if (!element.contextValue || rebinding) { |
115 | 124 |
|
116 | | - Promise.resolve(1).then((function (element, rebinding) { |
| 125 | + function bind(element) { |
117 | 126 |
|
118 | | - bindElement(element, rebinding); |
119 | | - })(element, rebinding)); |
120 | | - } |
121 | | - }); |
| 127 | + if (isParentTemplateOrLink(element)) { return; } |
122 | 128 |
|
| 129 | + if (!element.contextValue || rebinding || element.attributes.unbinded) { |
| 130 | + |
| 131 | + Promise.resolve(1).then((function (element, rebinding) { |
| 132 | + |
| 133 | + bindElement(element, rebinding); |
| 134 | + })(element, Boolean(rebinding || element.attributes.unbinded))); |
| 135 | + } |
| 136 | + } |
123 | 137 | function isParentTemplateOrLink(element) { |
124 | 138 |
|
125 | 139 | var parent = element.parentElement; |
|
134 | 148 | } |
135 | 149 | } |
136 | 150 |
|
137 | | - function rebindAllElements(rootElement) { |
138 | | - |
139 | | - if (!rootElement) { rootElement = document.body; } |
140 | | - |
141 | | - bindElement(rootElement); |
142 | | - |
143 | | - rootElement.querySelectorAll("[rebinding]") |
144 | | - .forEach(function (element) { bindElement(element); }); |
145 | | - // TODO [ ] test |
146 | | - document.head.querySelectorAll("[rebinding]") |
147 | | - .forEach(function (element) { bindElement(element); }); |
148 | | - } |
149 | | - |
150 | 151 | function bindElement(element, rebinding = false) { |
151 | 152 |
|
152 | 153 | if (!element instanceof HTMLTemplateElement || !element?.isConnected || ( |
|
207 | 208 |
|
208 | 209 | if (CreateLink) { |
209 | 210 |
|
210 | | - //element.setAttribute("linked", path); |
211 | | - //element.removeAttribute("link"); |
212 | 211 | element.linked = true; |
213 | | - element.wsLink = WsUser.CreateLink(path, element); |
| 212 | + element.wsLink = CreateLink(path, element); |
214 | 213 | element.wsLink.bindAllElements = function (elem, rebind = false) { bindAllElements(elem, rebind); }; |
215 | 214 | } |
216 | 215 | } |
|
443 | 442 |
|
444 | 443 | return; |
445 | 444 |
|
446 | | - function _bind(fnBind) { |
447 | 445 |
|
448 | | - fnBind = (function (fn) { |
| 446 | + function _bind(fnBind) { |
449 | 447 |
|
450 | | - return function (event) { |
| 448 | + var _fnBind = function _fnBind(event) { |
451 | 449 |
|
452 | | - if (element.contextValue?.() === undefined) { |
| 450 | + if (_bindingContext.value === undefined && element.isConnected) { |
453 | 451 |
|
454 | | - element.setAttribute("unbinded", ""); |
455 | | - event.named = "unbind"; |
456 | | - } |
457 | | - else { element.removeAttribute("unbinded"); } |
| 452 | + element.setAttribute("unbinded", ""); |
| 453 | + event.eventName = "unbind"; |
| 454 | + } |
458 | 455 |
|
459 | | - return fn.call(this, event); |
460 | | - }; |
| 456 | + return fnBind.call(element, event); |
| 457 | + }; |
461 | 458 |
|
462 | | - })(fnBind); |
| 459 | + _fnBind.element = element; |
| 460 | + element.removeAttribute("unbinded"); |
463 | 461 |
|
464 | | - if (fnBind.call(element, { |
| 462 | + if (_fnBind.call(element, { |
465 | 463 | eventName: "bind", |
466 | 464 | isValueInverted, |
467 | 465 | bindArgs, |
|
475 | 473 |
|
476 | 474 | _bindingContext.source.on( |
477 | 475 | _bindingContext.property, |
478 | | - fnBind.bind(element), |
| 476 | + _fnBind, |
479 | 477 | element |
480 | 478 | ); |
481 | 479 | } |
|
485 | 483 |
|
486 | 484 | function _error(...args) { |
487 | 485 |
|
488 | | - console.log(args, element); |
| 486 | + pDebug(args, element); |
489 | 487 | } |
490 | 488 | } |
491 | 489 |
|
|
553 | 551 | isActive: { value: _isActive, writable: false, configurable: false, enumerable: false }, |
554 | 552 |
|
555 | 553 | remove: { value: _remove, writable: false, configurable: false, enumerable: false }, |
| 554 | + |
| 555 | + removeParent: { value: _removeParent, writable: false, configurable: false, enumerable: false } |
556 | 556 | }); |
557 | 557 |
|
558 | 558 | elem.contextValue = _bindingContext.contextValue; |
|
749 | 749 |
|
750 | 750 | if (Array.isArray(_bindingContext.source)) { |
751 | 751 |
|
752 | | - var index = _bindingContext.source.indexOf(_bindingContext.value); |
| 752 | + _bindingContext.source.splice(_bindingContext.property, 1); |
| 753 | + } |
| 754 | + else { |
753 | 755 |
|
754 | | - if (index > -1) { |
| 756 | + delete _bindingContext.source[_bindingContext.property]; |
| 757 | + } |
| 758 | + } |
755 | 759 |
|
756 | | - _bindingContext.source.splice(index, 1); |
757 | | - } |
| 760 | + function _removeParent() { |
| 761 | + |
| 762 | + if (Array.isArray(_bindingContext.source._parent)) { |
| 763 | + |
| 764 | + var index = _bindingContext.source._propertyName; |
| 765 | + |
| 766 | + _bindingContext.source._parent.splice(index, 1); |
758 | 767 | } |
759 | 768 | else { |
760 | 769 |
|
761 | | - delete _bindingContext.source[_bindingContext.property] |
| 770 | + delete _bindingContext.source._parent[_bindingContext.source._propertyName]; |
762 | 771 | } |
763 | 772 | } |
764 | 773 |
|
765 | 774 | function _error(...args) { |
766 | 775 |
|
767 | | - console.log(args, d.rootElement); |
| 776 | + pDebug(args, d.rootElement); |
768 | 777 | } |
769 | 778 | } |
770 | 779 |
|
771 | 780 | function bindHandler(event) { |
772 | 781 |
|
773 | 782 | if (event.eventName === "delete") { |
774 | 783 |
|
775 | | - //debugger; |
776 | | - rebinding(event.oldValue); |
| 784 | + var deletePropPath = event.propertyPath.join("."); |
| 785 | + |
| 786 | + if (event.target._events[deletePropPath]) { |
| 787 | + |
| 788 | + var current_events = event.oldValue._events; |
| 789 | + event.oldValue._events = event.target._events[deletePropPath]; |
| 790 | + emitProperties(event.newValue, event.oldValue, event.eventName); |
| 791 | + delete event.target._events[deletePropPath]; |
| 792 | + event.oldValue._events = current_events; |
| 793 | + } |
| 794 | + |
| 795 | + else { |
| 796 | + |
| 797 | + emitProperties(event.newValue, event.oldValue, event.eventName); |
| 798 | + } |
777 | 799 |
|
778 | 800 | return true; |
779 | 801 | } |
|
782 | 804 |
|
783 | 805 | if (event.eventName === "set") { |
784 | 806 |
|
785 | | - //debugger; |
786 | | - event.newValue._events = event.oldValue._events || {}; |
787 | | - event.oldValue._events = {}; |
| 807 | + event.newValue._events = event.oldValue._events; |
788 | 808 |
|
789 | 809 | emitProperties(event.newValue, event.oldValue, event.eventName); |
790 | 810 | } |
791 | 811 |
|
792 | 812 | else if (event.eventName === "reposition") { |
793 | 813 |
|
794 | | - //debugger; |
795 | | - rebinding(event.newValue); |
796 | | - rebinding(event.oldValue); |
797 | | - } |
| 814 | + var currentPropPath = event.propertyPath.join("."); |
| 815 | + var newPropPath = event.target._propertyName + "." + event.newValue._propertyName; |
798 | 816 |
|
799 | | - //else if (event.eventName === "new") { debugger; } |
| 817 | + event.target._events[newPropPath] = event.newValue._events; |
800 | 818 |
|
| 819 | + if (event.target._events[currentPropPath]) { |
801 | 820 |
|
802 | | - return true; |
| 821 | + event.newValue._events = event.target._events[currentPropPath]; |
| 822 | + delete event.target._events[currentPropPath]; |
| 823 | + } |
| 824 | + else { |
803 | 825 |
|
804 | | - function emitProperties(newValue, oldValue, eventName) { |
| 826 | + event.newValue._events = event.oldValue._events || {}; |
| 827 | + } |
805 | 828 |
|
806 | | - if (newValue?.emit) { |
| 829 | + emitProperties(event.newValue, event.oldValue, event.eventName); |
| 830 | + } |
807 | 831 |
|
808 | | - Object.keys(newValue).forEach(function (k) { |
| 832 | + //else if (event.eventName === "new") { debugger; } |
809 | 833 |
|
810 | | - newValue.emit(k, { eventName, target: newValue, propertyPath: [k], oldValue: oldValue[k], newValue: newValue[k] }); |
811 | | - emitProperties(newValue[k], oldValue[k], eventName); |
812 | | - }); |
813 | | - } |
814 | | - } |
815 | 834 |
|
816 | | - function rebinding(val) { |
| 835 | + return true; |
817 | 836 |
|
818 | | - if (val?._events) { |
| 837 | + function emitProperties(newValue, oldValue, eventName) { |
819 | 838 |
|
820 | | - Object.keys(val._events).forEach(function (k) { |
| 839 | + var value = eventName === 'delete' ? oldValue : newValue; |
821 | 840 |
|
822 | | - val._events[k].forEach(function (l) { |
| 841 | + if (value?.emit) { |
823 | 842 |
|
824 | | - if (l.isActive instanceof Node) { |
| 843 | + Object.keys(value).forEach(function (k) { |
825 | 844 |
|
826 | | - l.isActive.setAttribute("rebinding", ""); |
827 | | - l.isActive = false; |
828 | | - } |
829 | | - }); |
| 845 | + value.emit(k, { eventName, target: value, propertyPath: [k], oldValue: oldValue?.[k], newValue: newValue?.[k] }); |
| 846 | + emitProperties(newValue?.[k], oldValue?.[k], eventName); |
830 | 847 | }); |
831 | | - val._events = {}; |
832 | 848 | } |
833 | | - |
834 | | - clearTimeout(rebindAllElements.timeout); |
835 | | - rebindAllElements.timeout = setTimeout(function () { |
836 | | - //console.log("RebindingAll"); |
837 | | - rebindAllElements(); |
838 | | - }); |
839 | 849 | } |
840 | 850 | } |
841 | 851 |
|
842 | 852 | function getType(v) { return v === null ? "null" : Array.isArray(v) ? "array" : typeof v; } |
843 | 853 |
|
844 | 854 | //#region *** Default bind *** |
845 | 855 |
|
| 856 | + function contextBind(event) { |
| 857 | + |
| 858 | + return false; |
| 859 | + } |
846 | 860 | function innerHTMLBind(event) { |
847 | 861 |
|
848 | 862 | if (event?.eventName === "unbind") { |
|
1182 | 1196 | } |
1183 | 1197 |
|
1184 | 1198 | //#endregion |
| 1199 | + |
| 1200 | + // Debugging |
| 1201 | + function pDebug(...args) { if (isDebug) { console.log(`[ DEBUG ] `, ...args); } } |
| 1202 | + function pError(...args) { if (isDebug) { console.error(`[ ERROR ] `, ...args); } } |
1185 | 1203 | }); |
1186 | 1204 |
|
1187 | 1205 |
|
|
0 commit comments