resonantjs 1.0.2 → 1.0.3
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 +15 -0
- package/package.json +1 -1
- package/resonant.js +41 -2
- package/resonant.min.js +1 -0
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
<title>Resonant.js Task Manager Demo</title>
|
|
5
5
|
<script src="../resonant.js"></script>
|
|
6
6
|
</head>
|
|
7
|
+
<style>
|
|
8
|
+
.done {
|
|
9
|
+
text-decoration: line-through;
|
|
10
|
+
}
|
|
11
|
+
</style>
|
|
7
12
|
<body>
|
|
8
13
|
<h1>Resonant.js Task Manager Demo</h1>
|
|
9
14
|
|
|
@@ -11,6 +16,9 @@
|
|
|
11
16
|
<div>
|
|
12
17
|
<h2>Add New Task</h2>
|
|
13
18
|
<input type="text" placeholder="Task Name" res="taskName" />
|
|
19
|
+
<p>
|
|
20
|
+
Name: <span res="taskName"></span>
|
|
21
|
+
</p>
|
|
14
22
|
<button onclick="addTask()">Add Task</button>
|
|
15
23
|
</div>
|
|
16
24
|
|
|
@@ -43,6 +51,13 @@
|
|
|
43
51
|
console.log(`Action taken: ${action} for ${task.name}`);
|
|
44
52
|
});
|
|
45
53
|
|
|
54
|
+
function remove(task) {
|
|
55
|
+
const index = tasks.indexOf(task);
|
|
56
|
+
tasks.splice(index, 1);
|
|
57
|
+
|
|
58
|
+
//You could use as well, still trying to figure out if I want to leave this or not
|
|
59
|
+
}
|
|
60
|
+
|
|
46
61
|
// Add a function to add a new task
|
|
47
62
|
function addTask() {
|
|
48
63
|
const newTask = { name: taskName, done: false };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "resonantjs",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
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
|
@@ -76,6 +76,7 @@ class Resonant {
|
|
|
76
76
|
this._triggerCallbacks(variableName, action, item, property, oldValue);
|
|
77
77
|
this.updateElement(variableName);
|
|
78
78
|
this.updateConditionalsFor(variableName);
|
|
79
|
+
this.updateStylesFor(variableName);
|
|
79
80
|
}, 0);
|
|
80
81
|
}
|
|
81
82
|
}
|
|
@@ -93,6 +94,7 @@ class Resonant {
|
|
|
93
94
|
this._assignValueToData(variableName, newValue);
|
|
94
95
|
this.updateElement(variableName);
|
|
95
96
|
this.updateConditionalsFor(variableName);
|
|
97
|
+
this.updateStylesFor(variableName);
|
|
96
98
|
if (!Array.isArray(newValue) && typeof newValue !== 'object') {
|
|
97
99
|
this._queueUpdate(variableName, 'modified', this.data[variableName]);
|
|
98
100
|
}
|
|
@@ -110,6 +112,7 @@ class Resonant {
|
|
|
110
112
|
element.value = value;
|
|
111
113
|
element.oninput = () => {
|
|
112
114
|
this.data[variableName] = element.value;
|
|
115
|
+
this._queueUpdate(variableName, 'modified', this.data[variableName]);
|
|
113
116
|
};
|
|
114
117
|
element.setAttribute('data-resonant-bound', 'true');
|
|
115
118
|
}
|
|
@@ -138,6 +141,16 @@ class Resonant {
|
|
|
138
141
|
subEl.innerHTML = value[key];
|
|
139
142
|
}
|
|
140
143
|
subEl.setAttribute('data-resonant-bound', 'true');
|
|
144
|
+
} else {
|
|
145
|
+
if (subEl.tagName === 'INPUT' || subEl.tagName === 'TEXTAREA') {
|
|
146
|
+
if (subEl.type === 'checkbox') {
|
|
147
|
+
subEl.checked = value[key];
|
|
148
|
+
} else {
|
|
149
|
+
subEl.value = value[key];
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
subEl.innerHTML = value[key];
|
|
153
|
+
}
|
|
141
154
|
}
|
|
142
155
|
}
|
|
143
156
|
});
|
|
@@ -147,6 +160,7 @@ class Resonant {
|
|
|
147
160
|
});
|
|
148
161
|
|
|
149
162
|
this.updateConditionalsFor(variableName);
|
|
163
|
+
this.updateStylesFor(variableName);
|
|
150
164
|
}
|
|
151
165
|
|
|
152
166
|
updateConditionalsFor(variableName) {
|
|
@@ -165,6 +179,23 @@ class Resonant {
|
|
|
165
179
|
});
|
|
166
180
|
}
|
|
167
181
|
|
|
182
|
+
updateStylesFor(variableName) {
|
|
183
|
+
const styleElements = document.querySelectorAll(`[res-style*="${variableName}"]`);
|
|
184
|
+
styleElements.forEach(styleElement => {
|
|
185
|
+
const styleCondition = styleElement.getAttribute('res-style');
|
|
186
|
+
try {
|
|
187
|
+
const styleClass = eval(styleCondition);
|
|
188
|
+
if (styleClass) {
|
|
189
|
+
styleElement.classList.add(styleClass);
|
|
190
|
+
} else {
|
|
191
|
+
styleElement.classList.remove(styleClass);
|
|
192
|
+
}
|
|
193
|
+
} catch (e) {
|
|
194
|
+
console.error(`Error evaluating style for ${variableName}: ${styleCondition}`, e);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
168
199
|
_renderArray(variableName, el) {
|
|
169
200
|
let template = el.cloneNode(true);
|
|
170
201
|
el.innerHTML = '';
|
|
@@ -200,18 +231,26 @@ class Resonant {
|
|
|
200
231
|
subEl.innerHTML = instance[key];
|
|
201
232
|
}
|
|
202
233
|
subEl.setAttribute('data-resonant-bound', 'true');
|
|
234
|
+
} else {
|
|
235
|
+
if (subEl.tagName === 'INPUT' || subEl.tagName === 'TEXTAREA') {
|
|
236
|
+
if (subEl.type === 'checkbox') {
|
|
237
|
+
subEl.checked = instance[key];
|
|
238
|
+
} else {
|
|
239
|
+
subEl.value = instance[key];
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
subEl.innerHTML = instance[key];
|
|
243
|
+
}
|
|
203
244
|
}
|
|
204
245
|
}
|
|
205
246
|
}
|
|
206
247
|
|
|
207
|
-
// Handle res-onclick
|
|
208
248
|
const onclickElements = clonedEl.querySelectorAll('[res-onclick], [res-onclick-remove]');
|
|
209
249
|
onclickElements.forEach(onclickEl => {
|
|
210
250
|
const functionName = onclickEl.getAttribute('res-onclick');
|
|
211
251
|
const removeKey = onclickEl.getAttribute('res-onclick-remove');
|
|
212
252
|
|
|
213
253
|
if (functionName) {
|
|
214
|
-
// Remove any existing event listeners to prevent duplicates
|
|
215
254
|
onclickEl.onclick = null;
|
|
216
255
|
|
|
217
256
|
onclickEl.onclick = () => {
|
package/resonant.min.js
ADDED
|
@@ -0,0 +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(r,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(r,"modified",e,t,s)),!0}})}_createArray(i,e){const n=this;return new Proxy(e,{get(e,t){return"object"!=typeof e[t]||e[t][Symbol("isProxy")]||(e[t]=n._createObject(i+`[${t}]`,e[t])),e[t]},set(e,t,a){var s,r;return e[t]!==a&&(s=e.hasOwnProperty(t)?"modified":"added",r=e[t],e[t]=a,n._queueUpdate(i,s,e[t],t,r)),!0},deleteProperty(e,t){var a=e[t];return e.splice(t,1),n._queueUpdate(i,"removed",a,t),!0}})}_queueUpdate(e,t,a,s,r){this.pendingUpdates.has(e)||(this.pendingUpdates.add(e),setTimeout(()=>{this.pendingUpdates.delete(e),this._triggerCallbacks(e,t,a,s,r),this.updateElement(e),this.updateConditionalsFor(e),this.updateStylesFor(e)},0))}_triggerCallbacks(t,a,s,r,i){this.callbacks[t]&&this.callbacks[t].forEach(e=>e(this.data[t],s,a,r,i))}_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.hasAttribute("data-resonant-bound")||(e.value=s,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=>{const styleCondition=styleElement.getAttribute("res-style");try{const styleClass=eval(styleCondition);styleClass?styleElement.classList.add(styleClass):styleElement.classList.remove(styleClass)}catch(e){}})}_renderArray(r,i){let n=i.cloneNode(!0);i.innerHTML="",window[r+"_template"]?n=window[r+"_template"]:window[r+"_template"]=n,this.data[r].forEach((s,e)=>{var t=n.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(r,"modified",s,e,s[e])}):(a.value=s[e],a.oninput=()=>{s[e]=a.value,this._queueUpdate(r,"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[r].findIndex(e=>e[a]===s[a]);-1!==e&&this.data[r].splice(e,1)})}),t.setAttribute("res-rendered",!0),i.appendChild(t)})}addCallback(e,t){this.callbacks[e]||(this.callbacks[e]=[]),this.callbacks[e].push(t)}}
|