sprae 3.0.1 → 4.0.0
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/package.json +5 -3
- package/r&d.md +6 -0
- package/readme.md +55 -82
- package/sprae.auto.js +617 -0
- package/sprae.auto.min.js +1 -0
- package/sprae.js +20 -33
- package/sprae.min.js +1 -1
- package/src/core.js +2 -6
- package/src/directives.js +5 -22
- package/src/index.js +1 -5
- package/src/state.js +13 -10
- package/test/dom.js +78 -22
- package/test/index.html +6 -1
- package/test/state.js +34 -12
- package/todo.md +7 -5
package/sprae.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/state.js
|
|
2
2
|
var currentFx;
|
|
3
|
-
var
|
|
3
|
+
var batch = /* @__PURE__ */ new Set();
|
|
4
|
+
var pendingUpdate;
|
|
4
5
|
var targetFxs = /* @__PURE__ */ new WeakMap();
|
|
5
6
|
var targetProxy = /* @__PURE__ */ new WeakMap();
|
|
6
7
|
var proxyTarget = /* @__PURE__ */ new WeakMap();
|
|
@@ -55,7 +56,8 @@ var handler = {
|
|
|
55
56
|
let propFxs = targetFxs.get(target)?.[prop];
|
|
56
57
|
if (propFxs)
|
|
57
58
|
for (let fx2 of propFxs)
|
|
58
|
-
|
|
59
|
+
batch.add(fx2);
|
|
60
|
+
planUpdate();
|
|
59
61
|
return true;
|
|
60
62
|
},
|
|
61
63
|
deleteProperty(target, prop) {
|
|
@@ -85,14 +87,16 @@ var fx = (fn) => {
|
|
|
85
87
|
call();
|
|
86
88
|
return call;
|
|
87
89
|
};
|
|
88
|
-
var
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
90
|
+
var planUpdate = () => {
|
|
91
|
+
if (!pendingUpdate) {
|
|
92
|
+
pendingUpdate = true;
|
|
93
|
+
queueMicrotask(() => {
|
|
94
|
+
for (let fx2 of batch)
|
|
95
|
+
fx2.call();
|
|
96
|
+
batch.clear();
|
|
97
|
+
pendingUpdate = false;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
96
100
|
};
|
|
97
101
|
|
|
98
102
|
// src/domdiff.js
|
|
@@ -208,8 +212,8 @@ primary["if"] = (el, expr) => {
|
|
|
208
212
|
}
|
|
209
213
|
};
|
|
210
214
|
};
|
|
211
|
-
primary["
|
|
212
|
-
let evaluate = parseExpr(el, expr, "
|
|
215
|
+
primary["scope"] = (el, expr, rootState) => {
|
|
216
|
+
let evaluate = parseExpr(el, expr, "scope");
|
|
213
217
|
const localState = evaluate(rootState);
|
|
214
218
|
let state2 = state(localState, rootState);
|
|
215
219
|
sprae(el, state2);
|
|
@@ -322,22 +326,6 @@ secondary["text"] = (el, expr) => {
|
|
|
322
326
|
el.textContent = value == null ? "" : value;
|
|
323
327
|
};
|
|
324
328
|
};
|
|
325
|
-
secondary["data"] = (el, expr) => {
|
|
326
|
-
let evaluate = parseExpr(el, expr, ":data");
|
|
327
|
-
return (state2) => {
|
|
328
|
-
let value = evaluate(state2);
|
|
329
|
-
for (let key in value)
|
|
330
|
-
el.dataset[key] = value[key];
|
|
331
|
-
};
|
|
332
|
-
};
|
|
333
|
-
secondary["aria"] = (el, expr) => {
|
|
334
|
-
let evaluate = parseExpr(el, expr, ":aria");
|
|
335
|
-
const update = (value) => {
|
|
336
|
-
for (let key in value)
|
|
337
|
-
attr(el, "aria-" + dashcase(key), value[key] == null ? null : value[key] + "");
|
|
338
|
-
};
|
|
339
|
-
return (state2) => update(evaluate(state2));
|
|
340
|
-
};
|
|
341
329
|
secondary[""] = (el, expr) => {
|
|
342
330
|
let evaluate = parseExpr(el, expr, ":");
|
|
343
331
|
if (evaluate)
|
|
@@ -569,11 +557,8 @@ var memo = /* @__PURE__ */ new WeakMap();
|
|
|
569
557
|
function sprae(container, values) {
|
|
570
558
|
if (!container.children)
|
|
571
559
|
return;
|
|
572
|
-
if (memo.has(container))
|
|
573
|
-
|
|
574
|
-
batch(() => Object.assign(state3, values));
|
|
575
|
-
return state3;
|
|
576
|
-
}
|
|
560
|
+
if (memo.has(container))
|
|
561
|
+
return Object.assign(memo.get(container), values);
|
|
577
562
|
const state2 = state(values || {});
|
|
578
563
|
const updates = [];
|
|
579
564
|
const init = (el, parent = el.parentNode) => {
|
|
@@ -626,6 +611,8 @@ function sprae(container, values) {
|
|
|
626
611
|
|
|
627
612
|
// src/index.js
|
|
628
613
|
var src_default = sprae;
|
|
614
|
+
if (document.currentScript)
|
|
615
|
+
sprae(document.documentElement);
|
|
629
616
|
export {
|
|
630
617
|
src_default as default
|
|
631
618
|
};
|
package/sprae.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e,t,r=new
|
|
1
|
+
var e,t,r=new Set,n=new WeakMap,l=new WeakMap,s=new WeakMap,i=Symbol("parent"),a={Array:Array,Object:Object,Number:Number,String:String,Boolean:Boolean,Date:Date,console:console},o={has:()=>!0,get(t,r){if("symbol"==typeof r)return t[r];if(!(r in t))return t[i]?.[r];if(Array.isArray(t)&&r in Array.prototype)return t[r];let s=t[r];if(e){let l=n.get(t);l||n.set(t,l={}),l[r]?l[r].includes(e)||l[r].push(e):l[r]=[e]}if(s&&s.constructor===Object||Array.isArray(s)){let e=l.get(s);return e||l.set(s,e=new Proxy(s,o)),e}return s},set(e,t,l){if(!(t in e)&&e[i]&&t in e[i])return e[i][t]=l;if(Array.isArray(e)&&t in Array.prototype)return e[t]=l;const s=e[t];if(Object.is(s,l))return!0;e[t]=l;let a=n.get(e)?.[t];if(a)for(let e of a)r.add(e);return f(),!0},deleteProperty:(e,t)=>(e[t]=void 0,delete e[t],!0)},u=(e,t)=>{if(l.has(e))return l.get(e);if(s.has(e))return e;let r=new Proxy(e,o);return l.set(e,r),s.set(r,e),e[i]=t?u(t):a,r},c=t=>{const r=()=>{let n=e;e=r,t(),e=n};return r(),r},f=()=>{t||(t=!0,queueMicrotask((()=>{for(let e of r)e.call();r.clear(),t=!1})))},p=new WeakMap,y=class extends Map{#e=new FinalizationRegistry((e=>super.delete(e)));get size(){return[...this].length}constructor(e=[]){super();for(const[t,r]of e)this.set(t,r)}get(e){return super.get(e)?.deref()}set(e,t){let r=super.get(e);return r&&this.#e.unregister(r),r=(e=>p.get(e)||(e=>{const t=new WeakRef(e);return p.set(e,t),t})(e))(t),this.#e.register(t,e,r),super.set(e,r)}},g={},h={};g.if=(e,t)=>{let r=document.createTextNode(""),n=[N(e,t,":if")],l=[e],s=e;for(;(s=e.nextElementSibling)&&s.hasAttribute(":else");)s.removeAttribute(":else"),(t=s.getAttribute(":if"))?(s.removeAttribute(":if"),s.remove(),l.push(s),n.push(N(e,t,":else :if"))):(s.remove(),l.push(s),n.push((()=>1)));return e.replaceWith(s=r),e=>{let t=n.findIndex((t=>t(e)));l[t]!=s&&((s[d]||s).replaceWith(s=l[t]||r),j(s,e))}},g.scope=(e,t,r)=>{const n=N(e,t,"scope")(r);j(e,u(n,r))};var d=Symbol(":each");g.each=(e,t)=>{let r=function(e){let t=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,r=e.match(/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/);if(!r)return;let n=r[2].trim(),l=r[1].replace(/^\s*\(|\)\s*$/g,"").trim(),s=l.match(t);return s?[l.replace(t,"").trim(),s[1].trim(),n]:[l,"",n]}(t);if(!r)return S(new Error,e,t);const n=e[d]=document.createTextNode("");e.replaceWith(n);const l=N(e,r[2],":each"),s=e.getAttribute(":key"),i=s?N(null,s):null;e.removeAttribute(":key");const a=e.getAttribute(":ref"),o=new y,c=new y;let f=[];return s=>{let p=l(s);p?"number"==typeof p?p=Array.from({length:p},((e,t)=>[t,t+1])):Array.isArray(p)?p=p.map(((e,t)=>[t+1,e])):"object"==typeof p?p=Object.entries(p):S(Error("Bad list value"),e,t,":each"):p=[];let y=[],g=[];for(let[t,n]of p){let l,f,p=i?.({[r[0]]:n,[r[1]]:t});null==p?l=e.cloneNode(!0):(l=c.get(p))||c.set(p,l=e.cloneNode(!0)),y.push(l),null!=p&&(f=o.get(p))?f[r[0]]=n:(f=u({[r[0]]:n,[a||""]:null,[r[1]]:t},s),null!=p&&o.set(p,f)),g.push(f)}!function(e,t,r,n){const l=new Map,s=new Map;let i,a;for(i=0;i<t.length;i++)l.set(t[i],i);for(i=0;i<r.length;i++)s.set(r[i],i);for(i=a=0;i!==t.length||a!==r.length;){var o=t[i],u=r[a];if(null===o)i++;else if(r.length<=a)e.removeChild(t[i]),i++;else if(t.length<=i)e.insertBefore(u,t[i]||n),a++;else if(o===u)i++,a++;else{var c=s.get(o),f=l.get(u);void 0===c?(e.removeChild(t[i]),i++):void 0===f?(e.insertBefore(u,t[i]||n),a++):(e.insertBefore(t[f],t[i]||n),t[f]=null,f>i+1&&i++,a++)}}}(n.parentNode,f,y,n),f=y;for(let e=0;e<y.length;e++)j(y[e],g[e])}},h.ref=(e,t,r)=>{r[t]=e},h.id=(e,t)=>{let r=N(e,t,":id");return t=>{return n=r(t),e.id=n||0===n?n:"";var n}},h.class=(e,t)=>{let r=N(e,t,":class"),n=e.className;return t=>{let l=r(t),s="string"==typeof l?l:(Array.isArray(l)?l:Object.entries(l).map((([e,t])=>t?e:""))).filter(Boolean).join(" ");e.className=[n,s].filter(Boolean).join(" ")}},h.style=(e,t)=>{let r=N(e,t,":style"),n=e.getAttribute("style")||"";return n.endsWith(";")||(n+="; "),t=>{let l=r(t);if("string"==typeof l)e.setAttribute("style",n+l);else{e.setAttribute("style",n);for(let t in l)e.style.setProperty(t,l[t])}}},h.text=(e,t)=>{let r=N(e,t,":text");return t=>{let n=r(t);e.textContent=null==n?"":n}},h[""]=(e,t)=>{let r=N(e,t,":");if(r)return t=>{let n=r(t);for(let t in n)W(e,t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(e=>"-"+e.toLowerCase())),n[t])}},h.value=(e,t)=>{let r,n,l=N(e,t,":value"),s="text"===e.type||""===e.type?t=>e.setAttribute("value",e.value=null==t?"":t):"TEXTAREA"===e.tagName||"text"===e.type||""===e.type?t=>(r=e.selectionStart,n=e.selectionEnd,e.setAttribute("value",e.value=null==t?"":t),r&&e.setSelectionRange(r,n)):"checkbox"===e.type?t=>(e.value=t?"on":"",W(e,"checked",t)):"select-one"===e.type?t=>{for(let t in e.options)t.removeAttribute("selected");e.value=t,e.selectedOptions[0]?.setAttribute("selected","")}:t=>e.value=t;return e=>s(l(e))},h.on=(e,t)=>{let r=N(e,t,":on");return t=>{let n=r(t),l=[];for(let t in n)l.push(b(e,t,n[t]));return()=>{for(let e of l)e()}}};var m=(e,t,r,n)=>{let l=n.startsWith("on")&&n.slice(2),s=N(e,t,":"+n);if(s)return l?t=>{let r=s(t)||(()=>{});return b(e,l,r)}:t=>W(e,n,s(t))},b=(e,t,r)=>{if(!r)return;let n=t.split("..").map((t=>{let r={evt:"",target:e,test:()=>!0};return r.evt=(t.startsWith("on")?t.slice(2):t).replace(/\.(\w+)?-?([-\w]+)?/g,((e,t,n="")=>(r.test=v[t]?.(r,...n.split("-"))||r.test,""))),r}));if(1==n.length)return i(r,n[0]);const l=(t,r=0)=>{let s;return s=i((i=>{r&&s();let a=t.call(e,i);"function"!=typeof a&&(a=()=>{}),r+1<n.length&&l(a,r?r+1:1)}),n[r])};let s=l(r);return()=>s();function i(e,{evt:t,target:r,test:n,defer:l,stop:s,prevent:i,...a}){l&&(e=l(e));let o=t=>n(t)&&(s&&t.stopPropagation(),i&&t.preventDefault(),e.call(r,t));return r.addEventListener(t,o,a),()=>r.removeEventListener(t,o,a)}},v={prevent(e){e.prevent=!0},stop(e){e.stop=!0},once(e){e.once=!0},passive(e){e.passive=!0},capture(e){e.capture=!0},window(e){e.target=window},document(e){e.target=document},toggle(e){e.defer=(t,r)=>n=>r?(r.call?.(e.target,n),r=null):r=t()},throttle(e,t){e.defer=e=>k(e,t?Number(t)||0:108)},debounce(e,t){e.defer=e=>w(e,t?Number(t)||0:108)},outside:e=>t=>{let r=e.target;return!(r.contains(t.target)||!1===t.target.isConnected||r.offsetWidth<1&&r.offsetHeight<1)},self:e=>t=>t.target===e.target,ctrl:(e,...t)=>e=>A.ctrl(e)&&t.every((t=>A[t]?A[t](e):e.key===t)),shift:(e,...t)=>e=>A.shift(e)&&t.every((t=>A[t]?A[t](e):e.key===t)),alt:(e,...t)=>e=>A.alt(e)&&t.every((t=>A[t]?A[t](e):e.key===t)),meta:(e,...t)=>e=>A.meta(e)&&t.every((t=>A[t]?A[t](e):e.key===t)),arrow:e=>A.arrow,enter:e=>A.enter,escape:e=>A.escape,tab:e=>A.tab,space:e=>A.space,backspace:e=>A.backspace,delete:e=>A.delete,digit:e=>A.digit,letter:e=>A.letter,character:e=>A.character},A={ctrl:e=>e.ctrlKey||"Control"===e.key||"Ctrl"===e.key,shift:e=>e.shiftKey||"Shift"===e.key,alt:e=>e.altKey||"Alt"===e.key,meta:e=>e.metaKey||"Meta"===e.key||"Command"===e.key,arrow:e=>e.key.startsWith("Arrow"),enter:e=>"Enter"===e.key,escape:e=>e.key.startsWith("Esc"),tab:e=>"Tab"===e.key,space:e=>" "===e.key||"Space"===e.key||" "===e.key,backspace:e=>"Backspace"===e.key,delete:e=>"Delete"===e.key,digit:e=>/^\d$/.test(e.key),letter:e=>/^[a-zA-Z]$/.test(e.key),character:e=>/^\S$/.test(e.key)},k=(e,t)=>{let r,n,l=s=>{r=!0,setTimeout((()=>{if(r=!1,n)return n=!1,l(s),e(s)}),t)};return t=>r?n=!0:(l(t),e(t))},w=(e,t)=>{let r;return n=>{clearTimeout(r),r=setTimeout((()=>{r=null,e(n)}),t)}},W=(e,t,r)=>{null==r||!1===r?e.removeAttribute(t):e.setAttribute(t,!0===r?"":"number"==typeof r||"string"==typeof r?r:"")},x={};function N(e,t,r){let n=x[t];if(!n){let l=/^[\n\s]*if.*\(.*\)/.test(t)||/\b(let|const)\s/.test(t)&&!r.startsWith(":on")?`(() => {${t}})()`:t;try{n=x[t]=new Function("__scope",`with (__scope) { return ${l.trim()} };`)}catch(n){return S(n,e,t,r)}}return l=>{let s;try{s=n.call(e,l)}catch(n){return S(n,e,t,r)}return s}}function S(e,t,r,n){Object.assign(e,{element:t,expression:r}),console.warn(`∴ ${e.message}\n\n${n}=${r?`"${r}"\n\n`:""}`,t),queueMicrotask((()=>{throw e}),0)}j.globals=a;var E=new WeakMap;function j(e,t){if(!e.children)return;if(E.has(e))return Object.assign(E.get(e),t);const r=u(t||{}),n=[],l=(e,t=e.parentNode)=>{for(let l in g){let s=":"+l;if(e.hasAttribute?.(s)){let i=e.getAttribute(s);if(e.removeAttribute(s),n.push(g[l](e,i,r,l)),E.has(e)||e.parentNode!==t)return!1}}if(e.attributes)for(let l=0;l<e.attributes.length;){let s=e.attributes[l];if(":"!==s.name[0]){l++;continue}e.removeAttribute(s.name);let i=s.value,a=s.name.slice(1).split(":");for(let l of a){let s=h[l]||m;if(n.push(s(e,i,r,l)),E.has(e)||e.parentNode!==t)return!1}}for(let t,r=0;t=e.children[r];r++)!1===l(t,e)&&r--};l(e);for(let e of n)if(e){let t;c((()=>{"function"==typeof t&&t(),t=e(r)}))}return E.set(e,r),r}var M=j;document.currentScript&&j(document.documentElement);export{M as default};
|
package/src/core.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { state as createState, fx,
|
|
1
|
+
import { state as createState, fx, sandbox } from './state.js';
|
|
2
2
|
import defaultDirective, { primary, secondary } from './directives.js';
|
|
3
3
|
|
|
4
4
|
sprae.globals=sandbox
|
|
@@ -7,11 +7,7 @@ sprae.globals=sandbox
|
|
|
7
7
|
const memo = new WeakMap
|
|
8
8
|
export default function sprae(container, values) {
|
|
9
9
|
if (!container.children) return
|
|
10
|
-
if (memo.has(container))
|
|
11
|
-
let state = memo.get(container)
|
|
12
|
-
batch(() => Object.assign(state, values))
|
|
13
|
-
return state
|
|
14
|
-
}
|
|
10
|
+
if (memo.has(container)) return Object.assign( memo.get(container), values)
|
|
15
11
|
|
|
16
12
|
// subscribe to reactives
|
|
17
13
|
// for (let prop in values) {
|
package/src/directives.js
CHANGED
|
@@ -10,8 +10,8 @@ export const primary = {}, secondary = {}
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
// :if is interchangeable with :each depending on order, :if :each or :each :if have different meanings
|
|
13
|
-
// as for :if :
|
|
14
|
-
// we consider :
|
|
13
|
+
// as for :if :scope - :if must init first, since it is lazy, to avoid initializing component ahead of time by :scope
|
|
14
|
+
// we consider :scope={x} :if={x} case insignificant
|
|
15
15
|
primary['if'] = (el, expr) => {
|
|
16
16
|
let holder = document.createTextNode(''),
|
|
17
17
|
clauses = [parseExpr(el, expr, ':if')],
|
|
@@ -44,9 +44,9 @@ primary['if'] = (el, expr) => {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
// :
|
|
48
|
-
primary['
|
|
49
|
-
let evaluate = parseExpr(el, expr, '
|
|
47
|
+
// :scope must come before :each, but :if has primary importance
|
|
48
|
+
primary['scope'] = (el, expr, rootState) => {
|
|
49
|
+
let evaluate = parseExpr(el, expr, 'scope')
|
|
50
50
|
const localState = evaluate(rootState)
|
|
51
51
|
let state = createState(localState, rootState)
|
|
52
52
|
// console.log(123, state.foo, state.bar)
|
|
@@ -187,23 +187,6 @@ secondary['text'] = (el, expr) => {
|
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
secondary['data'] = (el, expr) => {
|
|
191
|
-
let evaluate = parseExpr(el, expr, ':data')
|
|
192
|
-
|
|
193
|
-
return ((state) => {
|
|
194
|
-
let value = evaluate(state)
|
|
195
|
-
for (let key in value) el.dataset[key] = value[key];
|
|
196
|
-
})
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
secondary['aria'] = (el, expr) => {
|
|
200
|
-
let evaluate = parseExpr(el, expr, ':aria')
|
|
201
|
-
const update = (value) => {
|
|
202
|
-
for (let key in value) attr(el, 'aria-' + dashcase(key), value[key] == null ? null : value[key] + '');
|
|
203
|
-
}
|
|
204
|
-
return ((state) => update(evaluate(state)))
|
|
205
|
-
}
|
|
206
|
-
|
|
207
190
|
// set props in-bulk or run effect
|
|
208
191
|
secondary[''] = (el, expr) => {
|
|
209
192
|
let evaluate = parseExpr(el, expr, ':')
|
package/src/index.js
CHANGED
|
@@ -3,8 +3,4 @@ import './directives.js';
|
|
|
3
3
|
export default sprae;
|
|
4
4
|
|
|
5
5
|
// autoinit
|
|
6
|
-
|
|
7
|
-
// const s = document.currentScript
|
|
8
|
-
// if (s && s.hasAttribute('init')) {
|
|
9
|
-
// sprae(document.documentElement)
|
|
10
|
-
// }
|
|
6
|
+
if (document.currentScript) sprae(document.documentElement)
|
package/src/state.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// currentFx stack of listeners
|
|
2
|
-
let currentFx,
|
|
2
|
+
let currentFx, batch = new Set, pendingUpdate
|
|
3
3
|
|
|
4
4
|
const targetFxs = new WeakMap
|
|
5
5
|
const targetProxy = new WeakMap
|
|
@@ -60,7 +60,8 @@ const handler = {
|
|
|
60
60
|
// whenever target prop is set, call all dependent fxs
|
|
61
61
|
let propFxs = targetFxs.get(target)?.[prop]
|
|
62
62
|
|
|
63
|
-
if (propFxs) for (let fx of propFxs)
|
|
63
|
+
if (propFxs) for (let fx of propFxs) batch.add(fx)
|
|
64
|
+
planUpdate()
|
|
64
65
|
|
|
65
66
|
// FIXME: unsubscribe / delete effects by setting null/undefined
|
|
66
67
|
// if (value == null) targetFxs.delete(prev)
|
|
@@ -103,11 +104,13 @@ export const fx = (fn) => {
|
|
|
103
104
|
return call
|
|
104
105
|
}
|
|
105
106
|
|
|
106
|
-
export const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
107
|
+
export const planUpdate = () => {
|
|
108
|
+
if (!pendingUpdate) {
|
|
109
|
+
pendingUpdate = true
|
|
110
|
+
queueMicrotask(() => {
|
|
111
|
+
for (let fx of batch) fx.call()
|
|
112
|
+
batch.clear()
|
|
113
|
+
pendingUpdate = false
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
}
|