resonantjs 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Demo.gif +0 -0
- package/README.md +5 -16
- package/examples/example-taskmanager.html +3 -6
- package/package.json +1 -1
- package/resonant.js +60 -4
- package/resonant.min.js +1 -1
package/Demo.gif
CHANGED
|
Binary file
|
package/README.md
CHANGED
|
@@ -9,7 +9,6 @@ Resonant.js is an open-source lightweight JavaScript framework that enables reac
|
|
|
9
9
|
- **Bidirectional Input Binding**: Bind HTML input fields directly to your data model.
|
|
10
10
|
- **Efficient Conditional Updates**: Only evaluate conditional expressions tied to specific variable changes.
|
|
11
11
|
- **Lightweight and Easy to Integrate**: Minimal setup required to get started.
|
|
12
|
-
- **Compatible with Modern Browsers**: Works seamlessly across all modern web browsers.
|
|
13
12
|
## Installation
|
|
14
13
|
## NPM
|
|
15
14
|
To install via NPM, use the following command:
|
|
@@ -48,7 +47,10 @@ Include resonant.js in your HTML file, and use the following example to understa
|
|
|
48
47
|
|
|
49
48
|
<script>
|
|
50
49
|
const resonantJs = new Resonant();
|
|
51
|
-
resonantJs.add("counter", 0);
|
|
50
|
+
resonantJs.add("counter", 0, true);
|
|
51
|
+
//counter will instantiate the variable with name "counter"
|
|
52
|
+
//0 is the initial value of the variable
|
|
53
|
+
//true is optional, if true the variable will be stored in local storage
|
|
52
54
|
</script>
|
|
53
55
|
</body>
|
|
54
56
|
</html>
|
|
@@ -70,20 +72,7 @@ Include resonant.js in your HTML file, and use the following example to understa
|
|
|
70
72
|
- **Dynamic Arrays and Objects**: Easily handle collections and nested objects to dynamically add or remove elements based on your data structures.
|
|
71
73
|
- **Event Callbacks**: Register custom functions to execute whenever your data model changes.
|
|
72
74
|
- **Bidirectional Input Binding**: Bind form input fields directly to your data, making two-way synchronization simple.
|
|
73
|
-
|
|
74
|
-
### New Features in Version 1.0.2
|
|
75
|
-
|
|
76
|
-
#### Pending Updates Mechanism
|
|
77
|
-
- Introduced to prevent redundant updates and ensure callbacks are only triggered once per update cycle, improving performance and user experience.
|
|
78
|
-
|
|
79
|
-
#### Callback Parameter Enhancement
|
|
80
|
-
- Callbacks now receive detailed parameters including the specific action taken (`added`, `modified`, `removed`), the item affected, and the previous value. This provides better context for handling updates.
|
|
81
|
-
|
|
82
|
-
#### Batched Updates for Object Properties
|
|
83
|
-
- Improved handling of object property updates to ensure changes are batched together, preventing multiple redundant callback triggers.
|
|
84
|
-
|
|
85
|
-
#### Refined Data Binding
|
|
86
|
-
- Enhanced data binding between model and view to ensure consistent synchronization without unnecessary updates.
|
|
75
|
+
- **Optional Persistent Data**: Save your data model to local storage for easy retrieval and persistence across sessions.
|
|
87
76
|
|
|
88
77
|
## Other Information
|
|
89
78
|
- The demo HTML file uses the Pico CSS framework for styling. You can find more information about Pico CSS [here](https://picocss.com/).
|
|
@@ -45,15 +45,12 @@
|
|
|
45
45
|
|
|
46
46
|
// Add a callback to log actions taken on tasks
|
|
47
47
|
resonantJs.addCallback("tasks", (tasks, task, action) => {
|
|
48
|
-
console.log(`Action taken: ${action}
|
|
48
|
+
console.log(`Action taken: ${action}`);
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
function remove(task) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
tasks.splice(index, 1);
|
|
55
|
-
|
|
56
|
-
//You could use as well, still trying to figure out if I want to leave this or not
|
|
52
|
+
const index = tasks.indexOf(task);
|
|
53
|
+
tasks.delete(index);
|
|
57
54
|
}
|
|
58
55
|
|
|
59
56
|
// Add a function to add a new task
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "resonantjs",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "A lightweight JavaScript framework that enables reactive data-binding for building dynamic and responsive web applications. It simplifies creating interactive UIs by automatically updating the DOM when your data changes.",
|
|
5
5
|
"main": "resonant.js",
|
|
6
6
|
"repository": {
|
package/resonant.js
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
class ObservableArray extends Array {
|
|
2
2
|
constructor(variableName, resonantInstance, ...args) {
|
|
3
|
+
if(resonantInstance === undefined) {
|
|
4
|
+
return super(...args);
|
|
5
|
+
}
|
|
3
6
|
super(...args);
|
|
4
7
|
this.variableName = variableName;
|
|
5
8
|
this.resonantInstance = resonantInstance;
|
|
6
9
|
this.isDeleting = false;
|
|
7
10
|
}
|
|
8
11
|
|
|
12
|
+
//temp fix for issues
|
|
13
|
+
forceUpdate() {
|
|
14
|
+
this.resonantInstance.arrayDataChangeDetection[this.variableName] = this.slice();
|
|
15
|
+
this.resonantInstance._queueUpdate(this.variableName, 'modified', this.slice());
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
update(array) {
|
|
19
|
+
window[this.variableName] = array;
|
|
20
|
+
this.resonantInstance._queueUpdate(this.variableName, 'updated', array);
|
|
21
|
+
}
|
|
22
|
+
|
|
9
23
|
push(...args) {
|
|
10
24
|
const result = super.push(...args);
|
|
11
25
|
this.resonantInstance.arrayDataChangeDetection[this.variableName] = this.slice();
|
|
@@ -69,6 +83,17 @@ class ObservableArray extends Array {
|
|
|
69
83
|
this.isDeleting = false;
|
|
70
84
|
return true;
|
|
71
85
|
}
|
|
86
|
+
|
|
87
|
+
filter(filter, actuallyFilter = true) {
|
|
88
|
+
if(this.resonantInstance === undefined || actuallyFilter === false) {
|
|
89
|
+
return super.filter(filter);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const result = super.filter(filter);
|
|
93
|
+
this.resonantInstance.arrayDataChangeDetection[this.variableName] = this.slice();
|
|
94
|
+
this.resonantInstance._queueUpdate(this.variableName, 'filtered');
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
72
97
|
}
|
|
73
98
|
|
|
74
99
|
class Resonant {
|
|
@@ -76,10 +101,11 @@ class Resonant {
|
|
|
76
101
|
this.data = {};
|
|
77
102
|
this.callbacks = {};
|
|
78
103
|
this.pendingUpdates = new Map();
|
|
79
|
-
this.arrayDataChangeDetection = {};
|
|
104
|
+
this.arrayDataChangeDetection = {};
|
|
80
105
|
}
|
|
81
106
|
|
|
82
|
-
add(variableName, value) {
|
|
107
|
+
add(variableName, value, persist) {
|
|
108
|
+
value = this.persist(variableName, value, persist);
|
|
83
109
|
if (Array.isArray(value)) {
|
|
84
110
|
this.data[variableName] = new ObservableArray(variableName, this, ...value);
|
|
85
111
|
this.arrayDataChangeDetection[variableName] = this.data[variableName].slice();
|
|
@@ -93,6 +119,25 @@ class Resonant {
|
|
|
93
119
|
this.updateElement(variableName);
|
|
94
120
|
}
|
|
95
121
|
|
|
122
|
+
persist(variableName, value, persist) {
|
|
123
|
+
if (persist === undefined || !persist) {
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
var found = localStorage.getItem('res_' + variableName);
|
|
127
|
+
if (found !== null && found !== undefined){
|
|
128
|
+
return JSON.parse(localStorage.getItem('res_' + variableName));
|
|
129
|
+
} else {
|
|
130
|
+
localStorage.setItem('res_' + variableName, JSON.stringify(value));
|
|
131
|
+
return value;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
updatePersistantData(variableName) {
|
|
136
|
+
if (localStorage.getItem('res_' + variableName)) {
|
|
137
|
+
localStorage.setItem('res_' + variableName, JSON.stringify(this.data[variableName]));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
96
141
|
addAll(config) {
|
|
97
142
|
Object.entries(config).forEach(([variableName, value]) => {
|
|
98
143
|
this.add(variableName, value);
|
|
@@ -146,6 +191,7 @@ class Resonant {
|
|
|
146
191
|
if (this.pendingUpdates.get(variableName).length === 1) {
|
|
147
192
|
setTimeout(() => {
|
|
148
193
|
const updates = this.pendingUpdates.get(variableName);
|
|
194
|
+
this.updatePersistantData(variableName);
|
|
149
195
|
this.pendingUpdates.delete(variableName);
|
|
150
196
|
updates.forEach(update => {
|
|
151
197
|
this._triggerCallbacks(variableName, update);
|
|
@@ -155,6 +201,7 @@ class Resonant {
|
|
|
155
201
|
this.updateStylesFor(variableName);
|
|
156
202
|
}, 0);
|
|
157
203
|
}
|
|
204
|
+
|
|
158
205
|
}
|
|
159
206
|
|
|
160
207
|
_triggerCallbacks(variableName, callbackData) {
|
|
@@ -256,6 +303,14 @@ class Resonant {
|
|
|
256
303
|
parent = parent.parentElement;
|
|
257
304
|
}
|
|
258
305
|
|
|
306
|
+
let resStyles = styleElement.getAttribute('res-styles');
|
|
307
|
+
if (resStyles) {
|
|
308
|
+
let resStylesArray = resStyles.split(' ');
|
|
309
|
+
resStylesArray.forEach(resStyle => {
|
|
310
|
+
styleElement.classList.remove(resStyle);
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
259
314
|
if (index !== null) {
|
|
260
315
|
const item = this.data[variableName][index];
|
|
261
316
|
styleCondition = styleCondition.replace(new RegExp(`\\b${variableName}\\b`, 'g'), 'item');
|
|
@@ -271,8 +326,10 @@ class Resonant {
|
|
|
271
326
|
}
|
|
272
327
|
} else {
|
|
273
328
|
const styleClass = eval(styleCondition);
|
|
329
|
+
|
|
274
330
|
if (styleClass) {
|
|
275
331
|
styleElement.classList.add(styleClass);
|
|
332
|
+
styleElement.setAttribute('res-styles', styleClass);
|
|
276
333
|
} else {
|
|
277
334
|
var elementHasStyle = styleElement.classList.contains(styleClass);
|
|
278
335
|
if (elementHasStyle) {
|
|
@@ -339,7 +396,6 @@ class Resonant {
|
|
|
339
396
|
onclickElements.forEach(onclickEl => {
|
|
340
397
|
const functionName = onclickEl.getAttribute('res-onclick');
|
|
341
398
|
const removeKey = onclickEl.getAttribute('res-onclick-remove');
|
|
342
|
-
|
|
343
399
|
if (functionName) {
|
|
344
400
|
onclickEl.onclick = () => {
|
|
345
401
|
const func = new Function('item', `return ${functionName}(item)`);
|
|
@@ -368,4 +424,4 @@ class Resonant {
|
|
|
368
424
|
}
|
|
369
425
|
this.callbacks[variableName].push(method);
|
|
370
426
|
}
|
|
371
|
-
}
|
|
427
|
+
}
|
package/resonant.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
class ObservableArray extends Array{constructor(e,t,...a){super(...a),this.variableName=e,this.resonantInstance=t,this.isDeleting=!1}push(...e){var t=super.push(...e);return this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),e.forEach((e,t)=>{this.resonantInstance._queueUpdate(this.variableName,"added",e,this.length-1-t)}),t}splice(a,e,...t){var s=super.splice(a,e,...t);return this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),0<e&&s.forEach((e,t)=>{this.resonantInstance._queueUpdate(this.variableName,"removed",e,a+t)}),0<t.length&&t.forEach((e,t)=>{this.resonantInstance._queueUpdate(this.variableName,"added",e,a+t)}),s}set(t,a){if(this[t]!==a){if(this.isDeleting)return!0;var s=this.resonantInstance.arrayDataChangeDetection[this.variableName];let e="modified";(t>=s.length||void 0===s[t])&&(e="added"),this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice();s=this[t];this[t]=a,this.resonantInstance._queueUpdate(this.variableName,e,this[t],t,s)}return!0}delete(e){var t=this[e];return this.isDeleting=!0,this.splice(e,1),this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),this.resonantInstance._queueUpdate(this.variableName,"removed",null,e,t),!(this.isDeleting=!1)}}class Resonant{constructor(){this.data={},this.callbacks={},this.pendingUpdates=new Map,this.arrayDataChangeDetection={}}add(e,t){Array.isArray(t)?(this.data[e]=new ObservableArray(e,this,...t),this.arrayDataChangeDetection[e]=this.data[e].slice()):this.data[e]="object"==typeof t?this._createObject(e,t):t,this._defineProperty(e),this.updateElement(e)}addAll(e){Object.entries(e).forEach(([e,t])=>{this.add(e,t)})}_createObject(i,e){return e[Symbol("isProxy")]=!0,new Proxy(e,{set:(e,t,a)=>{var s;return e[t]!==a&&(s=e[t],e[t]=a,this._queueUpdate(i,"modified",e,t,s)),!0}})}_defineProperty(t){Object.defineProperty(window,t,{get:()=>this.data[t],set:e=>{Array.isArray(e)?(this.data[t]=new ObservableArray(t,this,...e),this.arrayDataChangeDetection[t]=this.data[t].slice()):this.data[t]="object"==typeof e?this._createObject(t,e):e,this.updateElement(t),this.updateDisplayConditionalsFor(t),this.updateStylesFor(t),Array.isArray(e)||"object"==typeof e||this._queueUpdate(t,"modified",this.data[t])}})}_queueUpdate(t,e,a,s,i){this.pendingUpdates.has(t)||this.pendingUpdates.set(t,[]),this.pendingUpdates.get(t).push({action:e,item:a,property:s,oldValue:i}),1===this.pendingUpdates.get(t).length&&setTimeout(()=>{var e=this.pendingUpdates.get(t);this.pendingUpdates.delete(t),e.forEach(e=>{this._triggerCallbacks(t,e)}),this.updateElement(t),this.updateDisplayConditionalsFor(t),this.updateStylesFor(t)},0)}_triggerCallbacks(a,s){this.callbacks[a]&&this.callbacks[a].forEach(e=>{var t=s.item||s.oldValue;e(this.data[a],t,s.action)})}updateElement(a){var e=document.querySelectorAll(`[res="${a}"]`);const s=this.data[a];e.forEach(e=>{e.value=s,"INPUT"===e.tagName||"TEXTAREA"===e.tagName?e.hasAttribute("data-resonant-bound")||(e.oninput=()=>{this.data[a]=e.value,this._queueUpdate(a,"modified",this.data[a])},e.setAttribute("data-resonant-bound","true")):Array.isArray(s)?(e.querySelectorAll(`[res="${a}"][res-rendered=true]`).forEach(e=>e.remove()),this._renderArray(a,e)):"object"==typeof s?e.querySelectorAll("[res-prop]").forEach(e=>{const t=e.getAttribute("res-prop");t&&t in s&&(e.hasAttribute("data-resonant-bound")?"INPUT"===e.tagName||"TEXTAREA"===e.tagName?"checkbox"===e.type?e.checked=s[t]:e.value=s[t]:e.innerHTML=s[t]:("INPUT"===e.tagName||"TEXTAREA"===e.tagName?"checkbox"===e.type?(e.checked=s[t],e.onchange=()=>{this.data[a][t]=e.checked}):(e.value=s[t],e.oninput=()=>{this.data[a][t]=e.value}):e.innerHTML=s[t],e.setAttribute("data-resonant-bound","true")))}):e.innerHTML=s}),this.updateDisplayConditionalsFor(a),this.updateStylesFor(a)}updateDisplayConditionalsFor(variableName){const conditionalElements=document.querySelectorAll(`[res-display*="${variableName}"]`);conditionalElements.forEach(conditionalElement=>{const condition=conditionalElement.getAttribute("res-display");try{eval(condition)?conditionalElement.style.display="":conditionalElement.style.display="none"}catch(e){}})}updateStylesFor(variableName){const styleElements=document.querySelectorAll(`[res-style*="${variableName}"]`);styleElements.forEach(styleElement=>{let styleCondition=styleElement.getAttribute("res-style");try{let parent=styleElement,index=null;for(;parent&&!index;)index=parent.getAttribute("res-index"),parent=parent.parentElement;if(null!==index){const item=this.data[variableName][index],styleClass=(styleCondition=styleCondition.replace(new RegExp(`\\b${variableName}\\b`,"g"),"item"),new Function("item","return "+styleCondition)(item));var elementHasStyle;styleClass?styleElement.classList.add(styleClass):(elementHasStyle=styleElement.classList.contains(styleClass),elementHasStyle&&styleElement.classList.remove(styleClass))}else{const styleClass=eval(styleCondition);var elementHasStyle;styleClass?styleElement.classList.add(styleClass):(elementHasStyle=styleElement.classList.contains(styleClass),elementHasStyle&&styleElement.classList.remove(styleClass))}}catch(e){}})}_renderArray(i,n){let r=n.cloneNode(!0);n.innerHTML="",window[i+"_template"]?r=window[i+"_template"]:window[i+"_template"]=r,this.data[i].forEach((s,e)=>{var t=r.cloneNode(!0);t.setAttribute("res-index",e);for(let e in s){const a=t.querySelector(`[res-prop="${e}"]`);a&&(a.hasAttribute("data-resonant-bound")?"INPUT"===a.tagName||"TEXTAREA"===a.tagName?"checkbox"===a.type?a.checked=s[e]:a.value=s[e]:a.innerHTML=s[e]:("INPUT"===a.tagName||"TEXTAREA"===a.tagName?"checkbox"===a.type?(a.checked=s[e],a.onchange=()=>{s[e]=a.checked,this._queueUpdate(i,"modified",s,e,s[e])}):(a.value=s[e],a.oninput=()=>{s[e]=a.value,this._queueUpdate(i,"modified",s,e,s[e])}):a.innerHTML=s[e],a.setAttribute("data-resonant-bound","true")))}t.querySelectorAll("[res-onclick], [res-onclick-remove]").forEach(e=>{const t=e.getAttribute("res-onclick"),a=e.getAttribute("res-onclick-remove");t&&(e.onclick=()=>{new Function("item",`return ${t}(item)`)(s)}),a&&(e.onclick=()=>{var e=this.data[i].findIndex(e=>e[a]===s[a]);-1!==e&&this.data[i].splice(e,1)})}),t.setAttribute("res-rendered",!0),n.appendChild(t)})}addCallback(e,t){this.callbacks[e]||(this.callbacks[e]=[]),this.callbacks[e].push(t)}}
|
|
1
|
+
class ObservableArray extends Array{constructor(e,t,...a){if(void 0===t)return super(...a);super(...a),this.variableName=e,this.resonantInstance=t,this.isDeleting=!1}forceUpdate(){this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),this.resonantInstance._queueUpdate(this.variableName,"modified",this.slice())}update(e){window[this.variableName]=e,this.resonantInstance._queueUpdate(this.variableName,"updated",e)}push(...e){var t=super.push(...e);return this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),e.forEach((e,t)=>{this.resonantInstance._queueUpdate(this.variableName,"added",e,this.length-1-t)}),t}splice(a,e,...t){var s=super.splice(a,e,...t);return this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),0<e&&s.forEach((e,t)=>{this.resonantInstance._queueUpdate(this.variableName,"removed",e,a+t)}),0<t.length&&t.forEach((e,t)=>{this.resonantInstance._queueUpdate(this.variableName,"added",e,a+t)}),s}set(t,a){if(this[t]!==a){if(this.isDeleting)return!0;var s=this.resonantInstance.arrayDataChangeDetection[this.variableName];let e="modified";(t>=s.length||void 0===s[t])&&(e="added"),this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice();s=this[t];this[t]=a,this.resonantInstance._queueUpdate(this.variableName,e,this[t],t,s)}return!0}delete(e){var t=this[e];return this.isDeleting=!0,this.splice(e,1),this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),this.resonantInstance._queueUpdate(this.variableName,"removed",null,e,t),!(this.isDeleting=!1)}filter(e,t=!0){return void 0===this.resonantInstance||!1===t?super.filter(e):(t=super.filter(e),this.resonantInstance.arrayDataChangeDetection[this.variableName]=this.slice(),this.resonantInstance._queueUpdate(this.variableName,"filtered"),t)}}class Resonant{constructor(){this.data={},this.callbacks={},this.pendingUpdates=new Map,this.arrayDataChangeDetection={}}add(e,t,a){t=this.persist(e,t,a),Array.isArray(t)?(this.data[e]=new ObservableArray(e,this,...t),this.arrayDataChangeDetection[e]=this.data[e].slice()):this.data[e]="object"==typeof t?this._createObject(e,t):t,this._defineProperty(e),this.updateElement(e)}persist(e,t,a){return void 0!==a&&a?null!=localStorage.getItem("res_"+e)?JSON.parse(localStorage.getItem("res_"+e)):(localStorage.setItem("res_"+e,JSON.stringify(t)),t):t}updatePersistantData(e){localStorage.getItem("res_"+e)&&localStorage.setItem("res_"+e,JSON.stringify(this.data[e]))}addAll(e){Object.entries(e).forEach(([e,t])=>{this.add(e,t)})}_createObject(i,e){return e[Symbol("isProxy")]=!0,new Proxy(e,{set:(e,t,a)=>{var s;return e[t]!==a&&(s=e[t],e[t]=a,this._queueUpdate(i,"modified",e,t,s)),!0}})}_defineProperty(t){Object.defineProperty(window,t,{get:()=>this.data[t],set:e=>{Array.isArray(e)?(this.data[t]=new ObservableArray(t,this,...e),this.arrayDataChangeDetection[t]=this.data[t].slice()):this.data[t]="object"==typeof e?this._createObject(t,e):e,this.updateElement(t),this.updateDisplayConditionalsFor(t),this.updateStylesFor(t),Array.isArray(e)||"object"==typeof e||this._queueUpdate(t,"modified",this.data[t])}})}_queueUpdate(t,e,a,s,i){this.pendingUpdates.has(t)||this.pendingUpdates.set(t,[]),this.pendingUpdates.get(t).push({action:e,item:a,property:s,oldValue:i}),1===this.pendingUpdates.get(t).length&&setTimeout(()=>{var e=this.pendingUpdates.get(t);this.updatePersistantData(t),this.pendingUpdates.delete(t),e.forEach(e=>{this._triggerCallbacks(t,e)}),this.updateElement(t),this.updateDisplayConditionalsFor(t),this.updateStylesFor(t)},0)}_triggerCallbacks(a,s){this.callbacks[a]&&this.callbacks[a].forEach(e=>{var t=s.item||s.oldValue;e(this.data[a],t,s.action)})}updateElement(a){var e=document.querySelectorAll(`[res="${a}"]`);const s=this.data[a];e.forEach(e=>{e.value=s,"INPUT"===e.tagName||"TEXTAREA"===e.tagName?e.hasAttribute("data-resonant-bound")||(e.oninput=()=>{this.data[a]=e.value,this._queueUpdate(a,"modified",this.data[a])},e.setAttribute("data-resonant-bound","true")):Array.isArray(s)?(e.querySelectorAll(`[res="${a}"][res-rendered=true]`).forEach(e=>e.remove()),this._renderArray(a,e)):"object"==typeof s?e.querySelectorAll("[res-prop]").forEach(e=>{const t=e.getAttribute("res-prop");t&&t in s&&(e.hasAttribute("data-resonant-bound")?"INPUT"===e.tagName||"TEXTAREA"===e.tagName?"checkbox"===e.type?e.checked=s[t]:e.value=s[t]:e.innerHTML=s[t]:("INPUT"===e.tagName||"TEXTAREA"===e.tagName?"checkbox"===e.type?(e.checked=s[t],e.onchange=()=>{this.data[a][t]=e.checked}):(e.value=s[t],e.oninput=()=>{this.data[a][t]=e.value}):e.innerHTML=s[t],e.setAttribute("data-resonant-bound","true")))}):e.innerHTML=s}),this.updateDisplayConditionalsFor(a),this.updateStylesFor(a)}updateDisplayConditionalsFor(variableName){const conditionalElements=document.querySelectorAll(`[res-display*="${variableName}"]`);conditionalElements.forEach(conditionalElement=>{const condition=conditionalElement.getAttribute("res-display");try{eval(condition)?conditionalElement.style.display="":conditionalElement.style.display="none"}catch(e){}})}updateStylesFor(variableName){const styleElements=document.querySelectorAll(`[res-style*="${variableName}"]`);styleElements.forEach(styleElement=>{let styleCondition=styleElement.getAttribute("res-style");try{let parent=styleElement,index=null;for(;parent&&!index;)index=parent.getAttribute("res-index"),parent=parent.parentElement;let resStyles=styleElement.getAttribute("res-styles");if(resStyles){let resStylesArray=resStyles.split(" ");resStylesArray.forEach(e=>{styleElement.classList.remove(e)})}if(null!==index){const item=this.data[variableName][index],styleClass=(styleCondition=styleCondition.replace(new RegExp(`\\b${variableName}\\b`,"g"),"item"),new Function("item","return "+styleCondition)(item));var elementHasStyle;styleClass?styleElement.classList.add(styleClass):(elementHasStyle=styleElement.classList.contains(styleClass),elementHasStyle&&styleElement.classList.remove(styleClass))}else{const styleClass=eval(styleCondition);var elementHasStyle;styleClass?(styleElement.classList.add(styleClass),styleElement.setAttribute("res-styles",styleClass)):(elementHasStyle=styleElement.classList.contains(styleClass),elementHasStyle&&styleElement.classList.remove(styleClass))}}catch(e){}})}_renderArray(i,n){let r=n.cloneNode(!0);n.innerHTML="",window[i+"_template"]?r=window[i+"_template"]:window[i+"_template"]=r,this.data[i].forEach((s,e)=>{var t=r.cloneNode(!0);t.setAttribute("res-index",e);for(let e in s){const a=t.querySelector(`[res-prop="${e}"]`);a&&(a.hasAttribute("data-resonant-bound")?"INPUT"===a.tagName||"TEXTAREA"===a.tagName?"checkbox"===a.type?a.checked=s[e]:a.value=s[e]:a.innerHTML=s[e]:("INPUT"===a.tagName||"TEXTAREA"===a.tagName?"checkbox"===a.type?(a.checked=s[e],a.onchange=()=>{s[e]=a.checked,this._queueUpdate(i,"modified",s,e,s[e])}):(a.value=s[e],a.oninput=()=>{s[e]=a.value,this._queueUpdate(i,"modified",s,e,s[e])}):a.innerHTML=s[e],a.setAttribute("data-resonant-bound","true")))}t.querySelectorAll("[res-onclick], [res-onclick-remove]").forEach(e=>{const t=e.getAttribute("res-onclick"),a=e.getAttribute("res-onclick-remove");t&&(e.onclick=()=>{new Function("item",`return ${t}(item)`)(s)}),a&&(e.onclick=()=>{var e=this.data[i].findIndex(e=>e[a]===s[a]);-1!==e&&this.data[i].splice(e,1)})}),t.setAttribute("res-rendered",!0),n.appendChild(t)})}addCallback(e,t){this.callbacks[e]||(this.callbacks[e]=[]),this.callbacks[e].push(t)}}
|