resonantjs 1.0.3 → 1.0.4
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/examples/example-taskmanager.html +2 -5
- package/package.json +1 -1
- package/resonant.js +35 -6
- package/resonant.min.js +1 -1
|
@@ -16,9 +16,6 @@
|
|
|
16
16
|
<div>
|
|
17
17
|
<h2>Add New Task</h2>
|
|
18
18
|
<input type="text" placeholder="Task Name" res="taskName" />
|
|
19
|
-
<p>
|
|
20
|
-
Name: <span res="taskName"></span>
|
|
21
|
-
</p>
|
|
22
19
|
<button onclick="addTask()">Add Task</button>
|
|
23
20
|
</div>
|
|
24
21
|
|
|
@@ -26,10 +23,10 @@
|
|
|
26
23
|
<div>
|
|
27
24
|
<h2>Task List</h2>
|
|
28
25
|
<ul res="tasks">
|
|
29
|
-
<li>
|
|
26
|
+
<li res-style="tasks.done ? 'done' : ''">
|
|
30
27
|
<input type="checkbox" res-prop="done" />
|
|
31
28
|
<span res-prop="name"></span>
|
|
32
|
-
<button res-onclick
|
|
29
|
+
<button res-onclick="remove">Remove</button>
|
|
33
30
|
</li>
|
|
34
31
|
</ul>
|
|
35
32
|
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "resonantjs",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
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
|
@@ -69,6 +69,7 @@ class Resonant {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
_queueUpdate(variableName, action, item, property, oldValue) {
|
|
72
|
+
|
|
72
73
|
if (!this.pendingUpdates.has(variableName)) {
|
|
73
74
|
this.pendingUpdates.add(variableName);
|
|
74
75
|
setTimeout(() => {
|
|
@@ -106,10 +107,12 @@ class Resonant {
|
|
|
106
107
|
const elements = document.querySelectorAll(`[res="${variableName}"]`);
|
|
107
108
|
const value = this.data[variableName];
|
|
108
109
|
|
|
110
|
+
|
|
111
|
+
|
|
109
112
|
elements.forEach(element => {
|
|
110
113
|
if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {
|
|
114
|
+
element.value = value;
|
|
111
115
|
if (!element.hasAttribute('data-resonant-bound')) {
|
|
112
|
-
element.value = value;
|
|
113
116
|
element.oninput = () => {
|
|
114
117
|
this.data[variableName] = element.value;
|
|
115
118
|
this._queueUpdate(variableName, 'modified', this.data[variableName]);
|
|
@@ -181,14 +184,40 @@ class Resonant {
|
|
|
181
184
|
|
|
182
185
|
updateStylesFor(variableName) {
|
|
183
186
|
const styleElements = document.querySelectorAll(`[res-style*="${variableName}"]`);
|
|
187
|
+
|
|
184
188
|
styleElements.forEach(styleElement => {
|
|
185
|
-
|
|
189
|
+
let styleCondition = styleElement.getAttribute('res-style');
|
|
186
190
|
try {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
191
|
+
let parent = styleElement;
|
|
192
|
+
let index = null;
|
|
193
|
+
while (parent && !index) {
|
|
194
|
+
index = parent.getAttribute('res-index');
|
|
195
|
+
parent = parent.parentElement;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (index !== null) {
|
|
199
|
+
const item = this.data[variableName][index];
|
|
200
|
+
styleCondition = styleCondition.replace(new RegExp(`\\b${variableName}\\b`, 'g'), 'item');
|
|
201
|
+
const styleClass = new Function('item', `return ${styleCondition}`)(item);
|
|
202
|
+
|
|
203
|
+
if (styleClass) {
|
|
204
|
+
styleElement.classList.add(styleClass);
|
|
205
|
+
} else {
|
|
206
|
+
var elementHasStyle = styleElement.classList.contains(styleClass);
|
|
207
|
+
if (elementHasStyle) {
|
|
208
|
+
styleElement.classList.remove(styleClass);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
190
211
|
} else {
|
|
191
|
-
|
|
212
|
+
const styleClass = eval(styleCondition);
|
|
213
|
+
if (styleClass) {
|
|
214
|
+
styleElement.classList.add(styleClass);
|
|
215
|
+
} else {
|
|
216
|
+
var elementHasStyle = styleElement.classList.contains(styleClass);
|
|
217
|
+
if (elementHasStyle) {
|
|
218
|
+
styleElement.classList.remove(styleClass);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
192
221
|
}
|
|
193
222
|
} catch (e) {
|
|
194
223
|
console.error(`Error evaluating style for ${variableName}: ${styleCondition}`, e);
|
package/resonant.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
class Resonant{constructor(){this.data={},this.callbacks={},this.pendingUpdates=new Set}add(e,t){this._assignValueToData(e,t),this._defineProperty(e),this.updateElement(e)}addAll(e){Object.entries(e).forEach(([e,t])=>{this.add(e,t)})}_assignValueToData(e,t){Array.isArray(t)?this.data[e]=this._createArray(e,t):this.data[e]="object"==typeof t?this._createObject(e,t):t}_createObject(
|
|
1
|
+
class Resonant{constructor(){this.data={},this.callbacks={},this.pendingUpdates=new Set}add(e,t){this._assignValueToData(e,t),this._defineProperty(e),this.updateElement(e)}addAll(e){Object.entries(e).forEach(([e,t])=>{this.add(e,t)})}_assignValueToData(e,t){Array.isArray(t)?this.data[e]=this._createArray(e,t):this.data[e]="object"==typeof t?this._createObject(e,t):t}_createObject(n,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(n,"modified",e,t,s)),!0}})}_createArray(l,e){const i=this;return new Proxy(e,{get(e,t){return"object"!=typeof e[t]||e[t][Symbol("isProxy")]||(e[t]=i._createObject(l+`[${t}]`,e[t])),e[t]},set(e,t,a){var s,n;return e[t]!==a&&(s=e.hasOwnProperty(t)?"modified":"added",n=e[t],e[t]=a,i._queueUpdate(l,s,e[t],t,n)),!0},deleteProperty(e,t){var a=e[t];return e.splice(t,1),i._queueUpdate(l,"removed",a,t),!0}})}_queueUpdate(e,t,a,s,n){this.pendingUpdates.has(e)||(this.pendingUpdates.add(e),setTimeout(()=>{this.pendingUpdates.delete(e),this._triggerCallbacks(e,t,a,s,n),this.updateElement(e),this.updateConditionalsFor(e),this.updateStylesFor(e)},0))}_triggerCallbacks(t,a,s,n,l){this.callbacks[t]&&this.callbacks[t].forEach(e=>e(this.data[t],s,a,n,l))}_defineProperty(t){Object.defineProperty(window,t,{get:()=>this.data[t],set:e=>{this._assignValueToData(t,e),this.updateElement(t),this.updateConditionalsFor(t),this.updateStylesFor(t),Array.isArray(e)||"object"==typeof e||this._queueUpdate(t,"modified",this.data[t])}})}updateElement(a){var e=document.querySelectorAll(`[res="${a}"]`);const s=this.data[a];e.forEach(e=>{"INPUT"===e.tagName||"TEXTAREA"===e.tagName?(e.value=s,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.updateConditionalsFor(a),this.updateStylesFor(a)}updateConditionalsFor(variableName){const conditionalElements=document.querySelectorAll(`[res-conditional*="${variableName}"]`);conditionalElements.forEach(conditionalElement=>{const condition=conditionalElement.getAttribute("res-conditional");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(n,l){let i=l.cloneNode(!0);l.innerHTML="",window[n+"_template"]?i=window[n+"_template"]:window[n+"_template"]=i,this.data[n].forEach((s,e)=>{var t=i.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(n,"modified",s,e,s[e])}):(a.value=s[e],a.oninput=()=>{s[e]=a.value,this._queueUpdate(n,"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=null,e.onclick=()=>{new Function("item",`return ${t}(item)`)(s)}),a&&(e.onclick=null,e.onclick=()=>{var e=this.data[n].findIndex(e=>e[a]===s[a]);-1!==e&&this.data[n].splice(e,1)})}),t.setAttribute("res-rendered",!0),l.appendChild(t)})}addCallback(e,t){this.callbacks[e]||(this.callbacks[e]=[]),this.callbacks[e].push(t)}}
|