@lark.js/mvc 0.0.3 → 0.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/README.md +554 -786
- package/dist/{chunk-Y72BUONO.js → chunk-ANWA22AX.js} +94 -82
- package/dist/index.cjs +789 -649
- package/dist/index.d.cts +1672 -983
- package/dist/index.d.ts +1672 -983
- package/dist/index.js +788 -647
- package/dist/vite.cjs +94 -82
- package/dist/vite.js +1 -1
- package/dist/webpack.cjs +94 -82
- package/dist/webpack.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -38,7 +38,6 @@ function isPlainObject(value) {
|
|
|
38
38
|
if (proto === null) return true;
|
|
39
39
|
return proto === Object.prototype || proto === null;
|
|
40
40
|
}
|
|
41
|
-
var isArray = Array.isArray;
|
|
42
41
|
function isPrimitiveOrFunc(value) {
|
|
43
42
|
return !value || typeof value !== "object" && typeof value !== "function";
|
|
44
43
|
}
|
|
@@ -79,13 +78,13 @@ function assign(target, ...sources) {
|
|
|
79
78
|
return target;
|
|
80
79
|
}
|
|
81
80
|
function funcWithTry(fns, args, context, configError) {
|
|
82
|
-
const fnArray = isArray(fns) ? fns : [fns];
|
|
81
|
+
const fnArray = Array.isArray(fns) ? fns : [fns];
|
|
83
82
|
let ret;
|
|
84
83
|
for (const fn of fnArray) {
|
|
85
84
|
try {
|
|
86
85
|
ret = Function.prototype.apply.call(fn, context, args);
|
|
87
86
|
} catch (e) {
|
|
88
|
-
configError(e);
|
|
87
|
+
configError?.(e);
|
|
89
88
|
}
|
|
90
89
|
}
|
|
91
90
|
return ret;
|
|
@@ -113,7 +112,7 @@ function translateData(data, value) {
|
|
|
113
112
|
}
|
|
114
113
|
return value;
|
|
115
114
|
}
|
|
116
|
-
if (isPlainObject(value) || isArray(value)) {
|
|
115
|
+
if (isPlainObject(value) || Array.isArray(value)) {
|
|
117
116
|
for (const p in value) {
|
|
118
117
|
if (has(value, p)) {
|
|
119
118
|
const val = value[p];
|
|
@@ -208,11 +207,11 @@ function now() {
|
|
|
208
207
|
}
|
|
209
208
|
function classExtend(make, base, props, statics) {
|
|
210
209
|
const baseProto = base["prototype"] ?? {};
|
|
211
|
-
const
|
|
212
|
-
assign(
|
|
210
|
+
const classProto = Object.create(baseProto);
|
|
211
|
+
assign(classProto, props);
|
|
213
212
|
Object.assign(make, statics);
|
|
214
|
-
|
|
215
|
-
make["prototype"] =
|
|
213
|
+
classProto.constructor = make;
|
|
214
|
+
make["prototype"] = classProto;
|
|
216
215
|
}
|
|
217
216
|
|
|
218
217
|
// src/apply-style.ts
|
|
@@ -253,8 +252,8 @@ function applyStyle(styleIdOrPairs, css) {
|
|
|
253
252
|
}
|
|
254
253
|
|
|
255
254
|
// src/mark.ts
|
|
256
|
-
var DELETED_KEY = SPLITTER + "$
|
|
257
|
-
var MARK_OBJECT_KEY = SPLITTER + "$
|
|
255
|
+
var DELETED_KEY = SPLITTER + "$delFlag";
|
|
256
|
+
var MARK_OBJECT_KEY = SPLITTER + "$markKey";
|
|
258
257
|
function mark(host, key) {
|
|
259
258
|
let sign = 0;
|
|
260
259
|
const hostRecord = host;
|
|
@@ -278,7 +277,7 @@ function unmark(host) {
|
|
|
278
277
|
|
|
279
278
|
// src/safeguard.ts
|
|
280
279
|
var proxiesPool = /* @__PURE__ */ new Map();
|
|
281
|
-
var SAFEGUARD_SENTINEL = "
|
|
280
|
+
var SAFEGUARD_SENTINEL = "_safe_";
|
|
282
281
|
function safeguard(data, getter, setter, isRoot) {
|
|
283
282
|
if (typeof window.__lark_Debug === "undefined" || !window.__lark_Debug) {
|
|
284
283
|
return data;
|
|
@@ -319,7 +318,7 @@ function safeguard(data, getter, setter, isRoot) {
|
|
|
319
318
|
if (!prefix && getter) {
|
|
320
319
|
getter(property);
|
|
321
320
|
}
|
|
322
|
-
if (!isRoot && has(target, property) && (isArray(out) || isPlainObject(out))) {
|
|
321
|
+
if (!isRoot && has(target, property) && (Array.isArray(out) || isPlainObject(out))) {
|
|
323
322
|
return build(prefix + property + ".", out);
|
|
324
323
|
}
|
|
325
324
|
return out;
|
|
@@ -494,7 +493,10 @@ var EventEmitter = class {
|
|
|
494
493
|
}
|
|
495
494
|
} else {
|
|
496
495
|
this.listeners.delete(key);
|
|
497
|
-
Reflect.deleteProperty(
|
|
496
|
+
Reflect.deleteProperty(
|
|
497
|
+
this,
|
|
498
|
+
`on${event[0].toUpperCase() + event.slice(1)}`
|
|
499
|
+
);
|
|
498
500
|
}
|
|
499
501
|
return this;
|
|
500
502
|
}
|
|
@@ -535,7 +537,7 @@ var EventEmitter = class {
|
|
|
535
537
|
}
|
|
536
538
|
}
|
|
537
539
|
}
|
|
538
|
-
const onMethodName = `on${event}`;
|
|
540
|
+
const onMethodName = `on${event[0].toUpperCase() + event.slice(1)}`;
|
|
539
541
|
const onMethod = this[onMethodName];
|
|
540
542
|
if (typeof onMethod === "function") {
|
|
541
543
|
funcWithTry(
|
|
@@ -726,6 +728,7 @@ var State = {
|
|
|
726
728
|
emitter.fire(event, data, remove);
|
|
727
729
|
return State;
|
|
728
730
|
}
|
|
731
|
+
// onChanged: noop,
|
|
729
732
|
};
|
|
730
733
|
|
|
731
734
|
// src/router.ts
|
|
@@ -1031,9 +1034,9 @@ var Router = {
|
|
|
1031
1034
|
window.addEventListener("hashchange", watchChange);
|
|
1032
1035
|
window.addEventListener("popstate", watchChange);
|
|
1033
1036
|
window.addEventListener("beforeunload", (domEvent) => {
|
|
1034
|
-
const
|
|
1035
|
-
Router.fire(ROUTER_EVENTS.PAGE_UNLOAD,
|
|
1036
|
-
const msg =
|
|
1037
|
+
const data = {};
|
|
1038
|
+
Router.fire(ROUTER_EVENTS.PAGE_UNLOAD, data);
|
|
1039
|
+
const msg = data["msg"];
|
|
1037
1040
|
if (msg) {
|
|
1038
1041
|
domEvent.returnValue = msg;
|
|
1039
1042
|
}
|
|
@@ -1065,16 +1068,16 @@ var frameGetter;
|
|
|
1065
1068
|
function parseEventInfo(eventInfo) {
|
|
1066
1069
|
const cached = eventInfoCache.get(eventInfo);
|
|
1067
1070
|
if (cached) {
|
|
1068
|
-
return assign({}, cached, {
|
|
1071
|
+
return assign({}, cached, { value: eventInfo });
|
|
1069
1072
|
}
|
|
1070
1073
|
const match = eventInfo.match(EVENT_METHOD_REGEXP) || [];
|
|
1071
1074
|
const result = {
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
+
id: match[1] || "",
|
|
1076
|
+
name: match[2] || "",
|
|
1077
|
+
params: match[3] || ""
|
|
1075
1078
|
};
|
|
1076
1079
|
eventInfoCache.set(eventInfo, result);
|
|
1077
|
-
return assign({}, result, {
|
|
1080
|
+
return assign({}, result, { value: eventInfo });
|
|
1078
1081
|
}
|
|
1079
1082
|
function findFrameInfo(current, eventType) {
|
|
1080
1083
|
const eventInfos = [];
|
|
@@ -1084,7 +1087,7 @@ function findFrameInfo(current, eventType) {
|
|
|
1084
1087
|
if (info) {
|
|
1085
1088
|
match = parseEventInfo(info);
|
|
1086
1089
|
}
|
|
1087
|
-
if (match && !match.
|
|
1090
|
+
if (match && !match.id || selectorEvents[eventType]) {
|
|
1088
1091
|
let selectorFrameId = "#";
|
|
1089
1092
|
let backtrace = 0;
|
|
1090
1093
|
while (begin && begin !== document.body) {
|
|
@@ -1110,10 +1113,10 @@ function findFrameInfo(current, eventType) {
|
|
|
1110
1113
|
if (selectorEntry) {
|
|
1111
1114
|
for (const selectorName of selectorEntry.selectors) {
|
|
1112
1115
|
const entry = {
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1116
|
+
value: selectorName,
|
|
1117
|
+
id: frameId,
|
|
1118
|
+
name: selectorName,
|
|
1119
|
+
params: ""
|
|
1117
1120
|
};
|
|
1118
1121
|
if (selectorName) {
|
|
1119
1122
|
if (!backtrace && elementMatchesSelector(current, selectorName)) {
|
|
@@ -1125,8 +1128,8 @@ function findFrameInfo(current, eventType) {
|
|
|
1125
1128
|
}
|
|
1126
1129
|
}
|
|
1127
1130
|
if (view.template && !backtrace) {
|
|
1128
|
-
if (match && !match.
|
|
1129
|
-
match.
|
|
1131
|
+
if (match && !match.id) {
|
|
1132
|
+
match.id = frameId;
|
|
1130
1133
|
}
|
|
1131
1134
|
break;
|
|
1132
1135
|
}
|
|
@@ -1142,10 +1145,10 @@ function findFrameInfo(current, eventType) {
|
|
|
1142
1145
|
}
|
|
1143
1146
|
if (match) {
|
|
1144
1147
|
eventInfos.push({
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1148
|
+
id: match.id,
|
|
1149
|
+
value: match.value,
|
|
1150
|
+
name: match.name,
|
|
1151
|
+
params: match.params
|
|
1149
1152
|
});
|
|
1150
1153
|
}
|
|
1151
1154
|
return eventInfos;
|
|
@@ -1166,7 +1169,7 @@ function domEventProcessor(domEvent) {
|
|
|
1166
1169
|
const eventInfos = findFrameInfo(current, eventType);
|
|
1167
1170
|
if (eventInfos.length) {
|
|
1168
1171
|
for (const info of eventInfos) {
|
|
1169
|
-
const {
|
|
1172
|
+
const { id: frameId, name: handlerName, params } = info;
|
|
1170
1173
|
if (lastFrameId !== frameId) {
|
|
1171
1174
|
if (lastFrameId && domEvent.isPropagationStopped?.()) {
|
|
1172
1175
|
break;
|
|
@@ -1265,8 +1268,8 @@ var WrapMeta = {
|
|
|
1265
1268
|
td: [3, "<table><tbody><tr>"],
|
|
1266
1269
|
area: [1, "<map>"],
|
|
1267
1270
|
param: [1, "<object>"],
|
|
1268
|
-
|
|
1269
|
-
|
|
1271
|
+
svg: [1, '<svg xmlns="' + SVG_NS + '">'],
|
|
1272
|
+
math: [1, '<math xmlns="' + MATH_NS + '">'],
|
|
1270
1273
|
_: [0, ""]
|
|
1271
1274
|
};
|
|
1272
1275
|
WrapMeta["optgroup"] = WrapMeta["option"];
|
|
@@ -1299,9 +1302,9 @@ function vdomGetNode(html, refNode) {
|
|
|
1299
1302
|
const ns = refNode.namespaceURI;
|
|
1300
1303
|
let tag;
|
|
1301
1304
|
if (ns === SVG_NS) {
|
|
1302
|
-
tag = "
|
|
1305
|
+
tag = "svg";
|
|
1303
1306
|
} else if (ns === MATH_NS) {
|
|
1304
|
-
tag = "
|
|
1307
|
+
tag = "math";
|
|
1305
1308
|
} else {
|
|
1306
1309
|
const match = TAG_NAME_REGEXP.exec(html);
|
|
1307
1310
|
tag = match ? match[1] : "";
|
|
@@ -1746,221 +1749,6 @@ if (typeof window !== "undefined") {
|
|
|
1746
1749
|
if (typeof document !== "undefined") {
|
|
1747
1750
|
VIEW_GLOBALS["document"] = document;
|
|
1748
1751
|
}
|
|
1749
|
-
function viewPrepare(oView) {
|
|
1750
|
-
if (oView.ctors) {
|
|
1751
|
-
return oView.ctors;
|
|
1752
|
-
}
|
|
1753
|
-
const ctors = [];
|
|
1754
|
-
oView.ctors = ctors;
|
|
1755
|
-
const proto = oView.prototype;
|
|
1756
|
-
const eventsObject = {};
|
|
1757
|
-
const eventsList = [];
|
|
1758
|
-
const selectorObject = {};
|
|
1759
|
-
const mixins = proto["mixins"];
|
|
1760
|
-
if (mixins && Array.isArray(mixins)) {
|
|
1761
|
-
viewMergeMixins(mixins, oView, ctors);
|
|
1762
|
-
}
|
|
1763
|
-
for (const p in proto) {
|
|
1764
|
-
if (!has(proto, p)) continue;
|
|
1765
|
-
const currentFn = proto[p];
|
|
1766
|
-
if (typeof currentFn !== "function") continue;
|
|
1767
|
-
const matches = p.match(VIEW_EVENT_METHOD_REGEXP);
|
|
1768
|
-
if (!matches) continue;
|
|
1769
|
-
const isSelector = matches[1];
|
|
1770
|
-
const selectorOrCallback = matches[2];
|
|
1771
|
-
const events = matches[3];
|
|
1772
|
-
const modifiers = matches[4];
|
|
1773
|
-
const mod = {};
|
|
1774
|
-
if (modifiers) {
|
|
1775
|
-
for (const item of modifiers.split(",")) {
|
|
1776
|
-
mod[item] = true;
|
|
1777
|
-
}
|
|
1778
|
-
}
|
|
1779
|
-
const eventTypes = events.split(",");
|
|
1780
|
-
for (const item of eventTypes) {
|
|
1781
|
-
const globalNode = VIEW_GLOBALS[selectorOrCallback];
|
|
1782
|
-
let mask = 1;
|
|
1783
|
-
if (isSelector) {
|
|
1784
|
-
if (globalNode) {
|
|
1785
|
-
eventsList.push({
|
|
1786
|
-
handler: currentFn,
|
|
1787
|
-
element: globalNode,
|
|
1788
|
-
eventName: item,
|
|
1789
|
-
modifiers: mod
|
|
1790
|
-
});
|
|
1791
|
-
continue;
|
|
1792
|
-
}
|
|
1793
|
-
mask = 2;
|
|
1794
|
-
let selectorEntry = selectorObject[item];
|
|
1795
|
-
if (!selectorEntry) {
|
|
1796
|
-
selectorEntry = selectorObject[item] = {
|
|
1797
|
-
selectors: []
|
|
1798
|
-
};
|
|
1799
|
-
}
|
|
1800
|
-
if (!selectorEntry[selectorOrCallback]) {
|
|
1801
|
-
selectorEntry[selectorOrCallback] = 1;
|
|
1802
|
-
selectorEntry.selectors.push(selectorOrCallback);
|
|
1803
|
-
}
|
|
1804
|
-
}
|
|
1805
|
-
eventsObject[item] = (eventsObject[item] || 0) | mask;
|
|
1806
|
-
const combinedKey = selectorOrCallback + SPLITTER + item;
|
|
1807
|
-
const existingFn = proto[combinedKey];
|
|
1808
|
-
if (!existingFn) {
|
|
1809
|
-
proto[combinedKey] = currentFn;
|
|
1810
|
-
} else {
|
|
1811
|
-
const mixinFn = currentFn;
|
|
1812
|
-
const existingMixin = existingFn;
|
|
1813
|
-
if (existingMixin.b) {
|
|
1814
|
-
if (mixinFn.b) {
|
|
1815
|
-
proto[combinedKey] = processMixinsSameEvent(
|
|
1816
|
-
currentFn,
|
|
1817
|
-
existingFn
|
|
1818
|
-
);
|
|
1819
|
-
} else if (has(proto, p)) {
|
|
1820
|
-
proto[combinedKey] = currentFn;
|
|
1821
|
-
}
|
|
1822
|
-
}
|
|
1823
|
-
}
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
viewWrapMethod(proto, "render", "$b");
|
|
1827
|
-
proto["$eo"] = eventsObject;
|
|
1828
|
-
proto["$el"] = eventsList;
|
|
1829
|
-
proto["$so"] = selectorObject;
|
|
1830
|
-
proto["$f"] = proto["assign"];
|
|
1831
|
-
return ctors;
|
|
1832
|
-
}
|
|
1833
|
-
function viewWrapMethod(proto, fnName, shortKey) {
|
|
1834
|
-
const originalFn = proto[fnName];
|
|
1835
|
-
if (typeof originalFn !== "function") return;
|
|
1836
|
-
const wrapped = function(...args) {
|
|
1837
|
-
if (this.signature > 0) {
|
|
1838
|
-
this.signature++;
|
|
1839
|
-
this.fire("rendercall");
|
|
1840
|
-
destroyAllResources(this, false);
|
|
1841
|
-
const instanceFn = typeof this[fnName] === "function" ? this[fnName] : originalFn;
|
|
1842
|
-
const fnToCall = instanceFn === wrapped ? originalFn : instanceFn;
|
|
1843
|
-
return funcWithTry(fnToCall, args, this, noop);
|
|
1844
|
-
}
|
|
1845
|
-
return void 0;
|
|
1846
|
-
};
|
|
1847
|
-
proto[fnName] = wrapped;
|
|
1848
|
-
proto[shortKey] = wrapped;
|
|
1849
|
-
}
|
|
1850
|
-
function processMixinsSameEvent(additional, exist) {
|
|
1851
|
-
let temp;
|
|
1852
|
-
const existMixin = exist;
|
|
1853
|
-
if (existMixin.a) {
|
|
1854
|
-
temp = existMixin;
|
|
1855
|
-
} else {
|
|
1856
|
-
temp = function(...e) {
|
|
1857
|
-
funcWithTry(temp.a ?? [], e, this, noop);
|
|
1858
|
-
};
|
|
1859
|
-
temp.a = [exist];
|
|
1860
|
-
temp.b = 1;
|
|
1861
|
-
}
|
|
1862
|
-
const additionalMixin = additional;
|
|
1863
|
-
temp.a = (temp.a ?? []).concat(additionalMixin.a ?? [additional]);
|
|
1864
|
-
return temp;
|
|
1865
|
-
}
|
|
1866
|
-
function viewMergeMixins(mixins, viewClass, ctors) {
|
|
1867
|
-
const proto = viewClass.prototype;
|
|
1868
|
-
const temp = {};
|
|
1869
|
-
for (const node of mixins) {
|
|
1870
|
-
for (const p in node) {
|
|
1871
|
-
if (!has(node, p)) continue;
|
|
1872
|
-
const fn = node[p];
|
|
1873
|
-
const exist = temp[p];
|
|
1874
|
-
if (p === "make") {
|
|
1875
|
-
ctors.push(fn);
|
|
1876
|
-
continue;
|
|
1877
|
-
}
|
|
1878
|
-
if (VIEW_EVENT_METHOD_REGEXP.test(p)) {
|
|
1879
|
-
if (exist) {
|
|
1880
|
-
temp[p] = processMixinsSameEvent(fn, exist);
|
|
1881
|
-
} else {
|
|
1882
|
-
fn.b = 1;
|
|
1883
|
-
temp[p] = fn;
|
|
1884
|
-
}
|
|
1885
|
-
} else {
|
|
1886
|
-
if (!exist) {
|
|
1887
|
-
temp[p] = fn;
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1890
|
-
}
|
|
1891
|
-
}
|
|
1892
|
-
for (const p in temp) {
|
|
1893
|
-
if (!has(proto, p)) {
|
|
1894
|
-
proto[p] = temp[p];
|
|
1895
|
-
}
|
|
1896
|
-
}
|
|
1897
|
-
}
|
|
1898
|
-
function viewDelegateEvents(view, destroy = false) {
|
|
1899
|
-
const proto = Object.getPrototypeOf(view) ?? {};
|
|
1900
|
-
const eventsObject = proto["$eo"] || view.eventObjectMap;
|
|
1901
|
-
const selectorObject = proto["$so"] || view.eventSelectorMap;
|
|
1902
|
-
const eventsList = proto["$el"] || view.globalEventList;
|
|
1903
|
-
for (const e in eventsObject) {
|
|
1904
|
-
if (has(eventsObject, e)) {
|
|
1905
|
-
if (destroy) {
|
|
1906
|
-
EventDelegator.unbind(e, !!selectorObject[e]);
|
|
1907
|
-
} else {
|
|
1908
|
-
EventDelegator.bind(e, !!selectorObject[e]);
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
for (const entry of eventsList) {
|
|
1913
|
-
if (destroy) {
|
|
1914
|
-
entry.element.removeEventListener(
|
|
1915
|
-
entry.eventName,
|
|
1916
|
-
entry.boundHandler
|
|
1917
|
-
);
|
|
1918
|
-
} else {
|
|
1919
|
-
const handler = entry.handler;
|
|
1920
|
-
const element = entry.element;
|
|
1921
|
-
const modifiers = entry.modifiers;
|
|
1922
|
-
entry.boundHandler = function(domEvent) {
|
|
1923
|
-
const extendedEvent = domEvent;
|
|
1924
|
-
extendedEvent.eventTarget = element;
|
|
1925
|
-
if (modifiers) {
|
|
1926
|
-
const kbEvent = domEvent;
|
|
1927
|
-
if (modifiers["ctrl"] && !kbEvent.ctrlKey || modifiers["shift"] && !kbEvent.shiftKey || modifiers["alt"] && !kbEvent.altKey || modifiers["meta"] && !kbEvent.metaKey) {
|
|
1928
|
-
return;
|
|
1929
|
-
}
|
|
1930
|
-
}
|
|
1931
|
-
funcWithTry(handler, [domEvent], view, noop);
|
|
1932
|
-
};
|
|
1933
|
-
entry.element.addEventListener(
|
|
1934
|
-
entry.eventName,
|
|
1935
|
-
entry.boundHandler
|
|
1936
|
-
);
|
|
1937
|
-
}
|
|
1938
|
-
}
|
|
1939
|
-
}
|
|
1940
|
-
function destroyAllResources(view, lastly) {
|
|
1941
|
-
const cache = view.resources;
|
|
1942
|
-
for (const p in cache) {
|
|
1943
|
-
if (has(cache, p)) {
|
|
1944
|
-
const entry = cache[p];
|
|
1945
|
-
if (lastly || entry.destroyOnRender) {
|
|
1946
|
-
destroyResource(cache, p, true);
|
|
1947
|
-
}
|
|
1948
|
-
}
|
|
1949
|
-
}
|
|
1950
|
-
}
|
|
1951
|
-
function destroyResource(cache, key, callDestroy, oldEntity) {
|
|
1952
|
-
const entry = cache[key];
|
|
1953
|
-
if (!entry || entry.entity === oldEntity) return void 0;
|
|
1954
|
-
const entity = entry.entity;
|
|
1955
|
-
if (entity && typeof entity === "object") {
|
|
1956
|
-
const destroyFn = entity["destroy"];
|
|
1957
|
-
if (typeof destroyFn === "function" && callDestroy) {
|
|
1958
|
-
funcWithTry(destroyFn, [], entity, noop);
|
|
1959
|
-
}
|
|
1960
|
-
}
|
|
1961
|
-
Reflect.deleteProperty(cache, key);
|
|
1962
|
-
return entity;
|
|
1963
|
-
}
|
|
1964
1752
|
var View = class _View {
|
|
1965
1753
|
/** View ID (same as owner frame ID) */
|
|
1966
1754
|
id = "";
|
|
@@ -1984,18 +1772,43 @@ var View = class _View {
|
|
|
1984
1772
|
observedStateKeys;
|
|
1985
1773
|
/** Resource map */
|
|
1986
1774
|
resources = {};
|
|
1987
|
-
/** Selector event map: eventType -> handler name list */
|
|
1988
|
-
eventSelectorMap = {};
|
|
1989
|
-
/** Event object map: eventType -> bitmask */
|
|
1990
|
-
eventObjectMap = {};
|
|
1991
|
-
/** Global event list */
|
|
1992
|
-
globalEventList = [];
|
|
1993
1775
|
/** Assign method reference */
|
|
1994
1776
|
assignMethod;
|
|
1995
1777
|
/** Whether endUpdate pending */
|
|
1996
1778
|
endUpdatePending;
|
|
1997
1779
|
/** Internal event storage */
|
|
1998
1780
|
_events = new EventEmitter();
|
|
1781
|
+
// ============================================================
|
|
1782
|
+
// Getters for prototype-stored event maps
|
|
1783
|
+
// ============================================================
|
|
1784
|
+
/**
|
|
1785
|
+
* Event bitmask map: eventType -> bitmask (1=root, 2=selector).
|
|
1786
|
+
* Read from prototype ($evtObjMap) set by View.prepare.
|
|
1787
|
+
* Using a getter avoids ES6 class field shadowing the prototype value.
|
|
1788
|
+
*/
|
|
1789
|
+
get eventObjectMap() {
|
|
1790
|
+
const proto = Object.getPrototypeOf(this);
|
|
1791
|
+
return proto["$evtObjMap"] || {};
|
|
1792
|
+
}
|
|
1793
|
+
/**
|
|
1794
|
+
* Selector event map: eventType -> selector list.
|
|
1795
|
+
* Read from prototype ($selMap) set by View.prepare.
|
|
1796
|
+
*/
|
|
1797
|
+
get eventSelectorMap() {
|
|
1798
|
+
const proto = Object.getPrototypeOf(this);
|
|
1799
|
+
return proto["$selMap"] || {};
|
|
1800
|
+
}
|
|
1801
|
+
/**
|
|
1802
|
+
* Global event list: [{handler, element, eventName, modifiers}].
|
|
1803
|
+
* Read from prototype ($globalEvtList) set by View.prepare.
|
|
1804
|
+
*/
|
|
1805
|
+
get globalEventList() {
|
|
1806
|
+
const proto = Object.getPrototypeOf(this);
|
|
1807
|
+
return proto["$globalEvtList"] || [];
|
|
1808
|
+
}
|
|
1809
|
+
// ============================================================
|
|
1810
|
+
// Instance lifecycle methods
|
|
1811
|
+
// ============================================================
|
|
1999
1812
|
/**
|
|
2000
1813
|
* Initialize view (called by Frame when mounting).
|
|
2001
1814
|
*/
|
|
@@ -2003,14 +1816,7 @@ var View = class _View {
|
|
|
2003
1816
|
}
|
|
2004
1817
|
/**
|
|
2005
1818
|
* Render view template (called by Frame after init).
|
|
2006
|
-
* Wrapped by
|
|
2007
|
-
*
|
|
2008
|
-
* Default implementation calls updater.digest() which:
|
|
2009
|
-
* 1. Executes the template function with current data
|
|
2010
|
-
* 2. Runs VDOM diff against previous DOM
|
|
2011
|
-
* 3. Applies DOM operations
|
|
2012
|
-
* 4. Calls endUpdate to mount child frames
|
|
2013
|
-
*
|
|
1819
|
+
* Wrapped by View.wrapMethod to manage signature + resources.
|
|
2014
1820
|
*/
|
|
2015
1821
|
render() {
|
|
2016
1822
|
this.updater.digest();
|
|
@@ -2062,7 +1868,7 @@ var View = class _View {
|
|
|
2062
1868
|
if (!flag) {
|
|
2063
1869
|
setTimeout(
|
|
2064
1870
|
this.wrapAsync(() => {
|
|
2065
|
-
runInvokes(ownerFrame);
|
|
1871
|
+
_View.runInvokes(ownerFrame);
|
|
2066
1872
|
}),
|
|
2067
1873
|
0
|
|
2068
1874
|
);
|
|
@@ -2138,7 +1944,7 @@ var View = class _View {
|
|
|
2138
1944
|
capture(key, resource, destroyOnRender = false) {
|
|
2139
1945
|
const cache = this.resources;
|
|
2140
1946
|
if (resource) {
|
|
2141
|
-
destroyResource(cache, key, true, resource);
|
|
1947
|
+
_View.destroyResource(cache, key, true, resource);
|
|
2142
1948
|
cache[key] = {
|
|
2143
1949
|
entity: resource,
|
|
2144
1950
|
destroyOnRender
|
|
@@ -2154,7 +1960,7 @@ var View = class _View {
|
|
|
2154
1960
|
* If destroy=true, calls the resource's destroy() method.
|
|
2155
1961
|
*/
|
|
2156
1962
|
release(key, destroy = true) {
|
|
2157
|
-
return destroyResource(this.resources, key, destroy);
|
|
1963
|
+
return _View.destroyResource(this.resources, key, destroy);
|
|
2158
1964
|
}
|
|
2159
1965
|
// ============================================================
|
|
2160
1966
|
// Leave tip
|
|
@@ -2200,10 +2006,273 @@ var View = class _View {
|
|
|
2200
2006
|
});
|
|
2201
2007
|
}
|
|
2202
2008
|
// ============================================================
|
|
2203
|
-
// Static
|
|
2009
|
+
// Static public methods
|
|
2204
2010
|
// ============================================================
|
|
2205
2011
|
/** Collected ctors from mixins */
|
|
2206
2012
|
static ctors;
|
|
2013
|
+
/**
|
|
2014
|
+
* Prepare a View subclass by scanning its prototype for event method patterns.
|
|
2015
|
+
* Pattern: `$?name<eventType1,eventType2>(&modifiers)`
|
|
2016
|
+
*
|
|
2017
|
+
* Only runs once per View subclass (guarded by ctors marker).
|
|
2018
|
+
* Called from Frame.mountView before creating the view instance.
|
|
2019
|
+
*/
|
|
2020
|
+
static prepare(oView) {
|
|
2021
|
+
if (oView.ctors) {
|
|
2022
|
+
return oView.ctors;
|
|
2023
|
+
}
|
|
2024
|
+
const ctors = [];
|
|
2025
|
+
oView.ctors = ctors;
|
|
2026
|
+
const proto = oView.prototype;
|
|
2027
|
+
const eventsObject = {};
|
|
2028
|
+
const eventsList = [];
|
|
2029
|
+
const selectorObject = {};
|
|
2030
|
+
const mixins = proto["mixins"];
|
|
2031
|
+
if (mixins && Array.isArray(mixins)) {
|
|
2032
|
+
_View.mergeMixins(mixins, oView, ctors);
|
|
2033
|
+
}
|
|
2034
|
+
for (const p in proto) {
|
|
2035
|
+
if (!has(proto, p)) continue;
|
|
2036
|
+
const currentFn = proto[p];
|
|
2037
|
+
if (typeof currentFn !== "function") continue;
|
|
2038
|
+
const matches = p.match(VIEW_EVENT_METHOD_REGEXP);
|
|
2039
|
+
if (!matches) continue;
|
|
2040
|
+
const isSelector = matches[1];
|
|
2041
|
+
const selectorOrCallback = matches[2];
|
|
2042
|
+
const events = matches[3];
|
|
2043
|
+
const modifiers = matches[4];
|
|
2044
|
+
const mod = {};
|
|
2045
|
+
if (modifiers) {
|
|
2046
|
+
for (const item of modifiers.split(",")) {
|
|
2047
|
+
mod[item] = true;
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
const eventTypes = events.split(",");
|
|
2051
|
+
for (const item of eventTypes) {
|
|
2052
|
+
const globalNode = VIEW_GLOBALS[selectorOrCallback];
|
|
2053
|
+
let mask = 1;
|
|
2054
|
+
if (isSelector) {
|
|
2055
|
+
if (globalNode) {
|
|
2056
|
+
eventsList.push({
|
|
2057
|
+
handler: currentFn,
|
|
2058
|
+
element: globalNode,
|
|
2059
|
+
eventName: item,
|
|
2060
|
+
modifiers: mod
|
|
2061
|
+
});
|
|
2062
|
+
continue;
|
|
2063
|
+
}
|
|
2064
|
+
mask = 2;
|
|
2065
|
+
let selectorEntry = selectorObject[item];
|
|
2066
|
+
if (!selectorEntry) {
|
|
2067
|
+
selectorEntry = selectorObject[item] = {
|
|
2068
|
+
selectors: []
|
|
2069
|
+
};
|
|
2070
|
+
}
|
|
2071
|
+
if (!selectorEntry[selectorOrCallback]) {
|
|
2072
|
+
selectorEntry[selectorOrCallback] = 1;
|
|
2073
|
+
selectorEntry.selectors.push(selectorOrCallback);
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
eventsObject[item] = (eventsObject[item] || 0) | mask;
|
|
2077
|
+
const combinedKey = selectorOrCallback + SPLITTER + item;
|
|
2078
|
+
const existingFn = proto[combinedKey];
|
|
2079
|
+
if (!existingFn) {
|
|
2080
|
+
proto[combinedKey] = currentFn;
|
|
2081
|
+
} else {
|
|
2082
|
+
const mixinFn = currentFn;
|
|
2083
|
+
const existingMixin = existingFn;
|
|
2084
|
+
if (existingMixin.marker) {
|
|
2085
|
+
if (mixinFn.marker) {
|
|
2086
|
+
proto[combinedKey] = _View.processMixinsSameEvent(
|
|
2087
|
+
currentFn,
|
|
2088
|
+
existingFn
|
|
2089
|
+
);
|
|
2090
|
+
} else if (has(proto, p)) {
|
|
2091
|
+
proto[combinedKey] = currentFn;
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
_View.wrapMethod(proto, "render", "$renderWrap");
|
|
2098
|
+
proto["$evtObjMap"] = eventsObject;
|
|
2099
|
+
proto["$globalEvtList"] = eventsList;
|
|
2100
|
+
proto["$selMap"] = selectorObject;
|
|
2101
|
+
proto["$assignFn"] = proto["assign"];
|
|
2102
|
+
return ctors;
|
|
2103
|
+
}
|
|
2104
|
+
/**
|
|
2105
|
+
* Bind or unbind event delegation for a view instance.
|
|
2106
|
+
* Called from Frame during mount/unmount.
|
|
2107
|
+
*/
|
|
2108
|
+
static delegateEvents(view, destroy = false) {
|
|
2109
|
+
const eventsObject = view.eventObjectMap;
|
|
2110
|
+
const selectorObject = view.eventSelectorMap;
|
|
2111
|
+
const eventsList = view.globalEventList;
|
|
2112
|
+
for (const e in eventsObject) {
|
|
2113
|
+
if (has(eventsObject, e)) {
|
|
2114
|
+
if (destroy) {
|
|
2115
|
+
EventDelegator.unbind(e, !!selectorObject[e]);
|
|
2116
|
+
} else {
|
|
2117
|
+
EventDelegator.bind(e, !!selectorObject[e]);
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
for (const entry of eventsList) {
|
|
2122
|
+
if (destroy) {
|
|
2123
|
+
entry.element.removeEventListener(
|
|
2124
|
+
entry.eventName,
|
|
2125
|
+
entry.boundHandler
|
|
2126
|
+
);
|
|
2127
|
+
} else {
|
|
2128
|
+
const handler = entry.handler;
|
|
2129
|
+
const element = entry.element;
|
|
2130
|
+
const modifiers = entry.modifiers;
|
|
2131
|
+
entry.boundHandler = function(domEvent) {
|
|
2132
|
+
const extendedEvent = domEvent;
|
|
2133
|
+
extendedEvent.eventTarget = element;
|
|
2134
|
+
if (modifiers) {
|
|
2135
|
+
const kbEvent = domEvent;
|
|
2136
|
+
if (modifiers["ctrl"] && !kbEvent.ctrlKey || modifiers["shift"] && !kbEvent.shiftKey || modifiers["alt"] && !kbEvent.altKey || modifiers["meta"] && !kbEvent.metaKey) {
|
|
2137
|
+
return;
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
funcWithTry(handler, [domEvent], view, noop);
|
|
2141
|
+
};
|
|
2142
|
+
entry.element.addEventListener(
|
|
2143
|
+
entry.eventName,
|
|
2144
|
+
entry.boundHandler
|
|
2145
|
+
);
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
/**
|
|
2150
|
+
* Destroy all resources managed by a view.
|
|
2151
|
+
* If lastly=true, destroy ALL resources; otherwise only destroyOnRender ones.
|
|
2152
|
+
*/
|
|
2153
|
+
static destroyAllResources(view, lastly) {
|
|
2154
|
+
const cache = view.resources;
|
|
2155
|
+
for (const p in cache) {
|
|
2156
|
+
if (has(cache, p)) {
|
|
2157
|
+
const entry = cache[p];
|
|
2158
|
+
if (lastly || entry.destroyOnRender) {
|
|
2159
|
+
_View.destroyResource(cache, p, true);
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
/**
|
|
2165
|
+
* Process deferred invoke calls on a frame.
|
|
2166
|
+
*/
|
|
2167
|
+
static runInvokes(frame) {
|
|
2168
|
+
const list = frame.invokeList;
|
|
2169
|
+
if (!list) return;
|
|
2170
|
+
while (list.length) {
|
|
2171
|
+
const entry = list.shift();
|
|
2172
|
+
if (entry && !entry.removed) {
|
|
2173
|
+
frame.invoke(entry.name, entry.args);
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
// ============================================================
|
|
2178
|
+
// Static private methods
|
|
2179
|
+
// ============================================================
|
|
2180
|
+
/**
|
|
2181
|
+
* Wrap a method on the prototype to add signature checking and resource cleanup.
|
|
2182
|
+
*/
|
|
2183
|
+
static wrapMethod(proto, fnName, shortKey) {
|
|
2184
|
+
const originalFn = proto[fnName];
|
|
2185
|
+
if (typeof originalFn !== "function") return;
|
|
2186
|
+
const wrapped = function(...args) {
|
|
2187
|
+
if (this.signature > 0) {
|
|
2188
|
+
this.signature++;
|
|
2189
|
+
this.fire("render");
|
|
2190
|
+
_View.destroyAllResources(this, false);
|
|
2191
|
+
const instanceFn = typeof this[fnName] === "function" ? this[fnName] : originalFn;
|
|
2192
|
+
const fnToCall = instanceFn === wrapped ? originalFn : instanceFn;
|
|
2193
|
+
return funcWithTry(fnToCall, args, this, noop);
|
|
2194
|
+
}
|
|
2195
|
+
return void 0;
|
|
2196
|
+
};
|
|
2197
|
+
proto[fnName] = wrapped;
|
|
2198
|
+
proto[shortKey] = wrapped;
|
|
2199
|
+
}
|
|
2200
|
+
/**
|
|
2201
|
+
* When two mixins define the same event method, merge them into
|
|
2202
|
+
* a single function that calls both in sequence.
|
|
2203
|
+
*/
|
|
2204
|
+
static processMixinsSameEvent(additional, exist) {
|
|
2205
|
+
let temp;
|
|
2206
|
+
const existMixin = exist;
|
|
2207
|
+
if (existMixin.handlerList) {
|
|
2208
|
+
temp = existMixin;
|
|
2209
|
+
} else {
|
|
2210
|
+
temp = function(...e) {
|
|
2211
|
+
funcWithTry(temp.handlerList ?? [], e, this, noop);
|
|
2212
|
+
};
|
|
2213
|
+
temp.handlerList = [exist];
|
|
2214
|
+
temp.marker = 1;
|
|
2215
|
+
}
|
|
2216
|
+
const additionalMixin = additional;
|
|
2217
|
+
temp.handlerList = (temp.handlerList ?? []).concat(
|
|
2218
|
+
additionalMixin.handlerList ?? [additional]
|
|
2219
|
+
);
|
|
2220
|
+
return temp;
|
|
2221
|
+
}
|
|
2222
|
+
/**
|
|
2223
|
+
* Merge an array of mixin objects into the view prototype.
|
|
2224
|
+
*/
|
|
2225
|
+
static mergeMixins(mixins, viewClass, ctors) {
|
|
2226
|
+
const proto = viewClass.prototype;
|
|
2227
|
+
const temp = {};
|
|
2228
|
+
for (const node of mixins) {
|
|
2229
|
+
for (const p in node) {
|
|
2230
|
+
if (!has(node, p)) continue;
|
|
2231
|
+
const fn = node[p];
|
|
2232
|
+
const exist = temp[p];
|
|
2233
|
+
if (p === "make") {
|
|
2234
|
+
ctors.push(fn);
|
|
2235
|
+
continue;
|
|
2236
|
+
}
|
|
2237
|
+
if (VIEW_EVENT_METHOD_REGEXP.test(p)) {
|
|
2238
|
+
if (exist) {
|
|
2239
|
+
temp[p] = _View.processMixinsSameEvent(fn, exist);
|
|
2240
|
+
} else {
|
|
2241
|
+
fn.marker = 1;
|
|
2242
|
+
temp[p] = fn;
|
|
2243
|
+
}
|
|
2244
|
+
} else {
|
|
2245
|
+
if (!exist) {
|
|
2246
|
+
temp[p] = fn;
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
for (const p in temp) {
|
|
2252
|
+
if (!has(proto, p)) {
|
|
2253
|
+
proto[p] = temp[p];
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
/**
|
|
2258
|
+
* Destroy a single resource entry.
|
|
2259
|
+
*/
|
|
2260
|
+
static destroyResource(cache, key, callDestroy, oldEntity) {
|
|
2261
|
+
const entry = cache[key];
|
|
2262
|
+
if (!entry || entry.entity === oldEntity) return void 0;
|
|
2263
|
+
const entity = entry.entity;
|
|
2264
|
+
if (entity && typeof entity === "object") {
|
|
2265
|
+
const destroyFn = entity["destroy"];
|
|
2266
|
+
if (typeof destroyFn === "function" && callDestroy) {
|
|
2267
|
+
funcWithTry(destroyFn, [], entity, noop);
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
Reflect.deleteProperty(cache, key);
|
|
2271
|
+
return entity;
|
|
2272
|
+
}
|
|
2273
|
+
// ============================================================
|
|
2274
|
+
// Static: extend and merge
|
|
2275
|
+
// ============================================================
|
|
2207
2276
|
/**
|
|
2208
2277
|
* Extend View to create a new View subclass.
|
|
2209
2278
|
*
|
|
@@ -2224,7 +2293,7 @@ var View = class _View {
|
|
|
2224
2293
|
constructor(nodeId, ownerFrame, initParams, node, mixinCtors) {
|
|
2225
2294
|
super(nodeId, ownerFrame, initParams, node, []);
|
|
2226
2295
|
for (const key in props) {
|
|
2227
|
-
if (has(props, key) && key !== "make") {
|
|
2296
|
+
if (has(props, key) && key !== "make" && key !== "render") {
|
|
2228
2297
|
this[key] = props[key];
|
|
2229
2298
|
}
|
|
2230
2299
|
}
|
|
@@ -2257,36 +2326,17 @@ var View = class _View {
|
|
|
2257
2326
|
}
|
|
2258
2327
|
}
|
|
2259
2328
|
}
|
|
2260
|
-
ChildView.merge = viewMerge;
|
|
2261
|
-
ChildView.extend = _View.extend;
|
|
2262
2329
|
return ChildView;
|
|
2263
2330
|
}
|
|
2264
2331
|
/**
|
|
2265
2332
|
* Merge mixins into View prototype.
|
|
2266
2333
|
*/
|
|
2267
2334
|
static merge(...mixins) {
|
|
2268
|
-
const
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
return self;
|
|
2335
|
+
const existingCtors = this.ctors || [];
|
|
2336
|
+
_View.mergeMixins(mixins, this, existingCtors);
|
|
2337
|
+
return this;
|
|
2272
2338
|
}
|
|
2273
2339
|
};
|
|
2274
|
-
function viewMerge(...mixins) {
|
|
2275
|
-
const self = this;
|
|
2276
|
-
const existingCtors = self.ctors || [];
|
|
2277
|
-
viewMergeMixins(mixins, self, existingCtors);
|
|
2278
|
-
return self;
|
|
2279
|
-
}
|
|
2280
|
-
function runInvokes(frame) {
|
|
2281
|
-
const list = frame.invokeList;
|
|
2282
|
-
if (!list) return;
|
|
2283
|
-
while (list.length) {
|
|
2284
|
-
const entry = list.shift();
|
|
2285
|
-
if (entry && !entry.removed) {
|
|
2286
|
-
frame.invoke(entry.name, entry.args);
|
|
2287
|
-
}
|
|
2288
|
-
}
|
|
2289
|
-
}
|
|
2290
2340
|
|
|
2291
2341
|
// src/frame.ts
|
|
2292
2342
|
var frameRegistry = /* @__PURE__ */ new Map();
|
|
@@ -2394,7 +2444,7 @@ var Frame = class _Frame extends EventEmitter {
|
|
|
2394
2444
|
*/
|
|
2395
2445
|
doMountView(ViewClass, params, node, sign) {
|
|
2396
2446
|
if (sign !== this.signature) return;
|
|
2397
|
-
const mixinCtors =
|
|
2447
|
+
const mixinCtors = View.prepare(ViewClass);
|
|
2398
2448
|
const ViewConstructor = ViewClass;
|
|
2399
2449
|
const view = new ViewConstructor(
|
|
2400
2450
|
this.id,
|
|
@@ -2405,7 +2455,7 @@ var Frame = class _Frame extends EventEmitter {
|
|
|
2405
2455
|
);
|
|
2406
2456
|
this.viewInstance = view;
|
|
2407
2457
|
view.signature = 1;
|
|
2408
|
-
|
|
2458
|
+
View.delegateEvents(view);
|
|
2409
2459
|
const initResult = funcWithTry(
|
|
2410
2460
|
view.init,
|
|
2411
2461
|
[params, { node, deep: !view.template }],
|
|
@@ -2416,13 +2466,10 @@ var Frame = class _Frame extends EventEmitter {
|
|
|
2416
2466
|
Promise.resolve(initResult).then(() => {
|
|
2417
2467
|
if (nextSign !== this.signature) return;
|
|
2418
2468
|
if (view.template) {
|
|
2419
|
-
|
|
2420
|
-
if (renderFn) {
|
|
2421
|
-
renderFn.call(view);
|
|
2422
|
-
}
|
|
2469
|
+
view.render();
|
|
2423
2470
|
} else {
|
|
2424
2471
|
this.hasAltered = 0;
|
|
2425
|
-
if (!view
|
|
2472
|
+
if (!view.endUpdatePendingFlag) {
|
|
2426
2473
|
view.endUpdate();
|
|
2427
2474
|
}
|
|
2428
2475
|
}
|
|
@@ -2609,7 +2656,7 @@ var Frame = class _Frame extends EventEmitter {
|
|
|
2609
2656
|
/** Get or create root frame */
|
|
2610
2657
|
static root(rootId) {
|
|
2611
2658
|
if (!rootFrame) {
|
|
2612
|
-
rootId = rootId || "
|
|
2659
|
+
rootId = rootId || "root";
|
|
2613
2660
|
let rootElement = document.getElementById(rootId);
|
|
2614
2661
|
if (!rootElement) {
|
|
2615
2662
|
rootElement = document.body;
|
|
@@ -2730,19 +2777,19 @@ function registerViewClass(viewPath, ViewClass) {
|
|
|
2730
2777
|
}
|
|
2731
2778
|
|
|
2732
2779
|
// src/service.ts
|
|
2733
|
-
var
|
|
2734
|
-
/**
|
|
2780
|
+
var Payload = class {
|
|
2781
|
+
/** Payload data */
|
|
2735
2782
|
data;
|
|
2736
2783
|
/** Internal cache info */
|
|
2737
2784
|
cacheInfo;
|
|
2738
2785
|
constructor(data = {}) {
|
|
2739
2786
|
this.data = data;
|
|
2740
2787
|
}
|
|
2741
|
-
/** Get a value from
|
|
2788
|
+
/** Get a value from payload data */
|
|
2742
2789
|
get(key) {
|
|
2743
2790
|
return this.data[key];
|
|
2744
2791
|
}
|
|
2745
|
-
/** Set a value in
|
|
2792
|
+
/** Set a value in payload data */
|
|
2746
2793
|
set(keyOrData, value) {
|
|
2747
2794
|
if (typeof keyOrData === "string") {
|
|
2748
2795
|
this.data[keyOrData] = value;
|
|
@@ -2754,287 +2801,366 @@ var Bag = class {
|
|
|
2754
2801
|
};
|
|
2755
2802
|
var FETCH_FLAGS_ALL = 1;
|
|
2756
2803
|
var FETCH_FLAGS_ONE = 2;
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2804
|
+
var Service = class {
|
|
2805
|
+
/** Service instance ID */
|
|
2806
|
+
id = "";
|
|
2807
|
+
/** Whether service is busy (1 = busy) */
|
|
2808
|
+
busy = 0;
|
|
2809
|
+
/** Whether service is destroyed (1 = destroyed) */
|
|
2810
|
+
destroyed = 0;
|
|
2811
|
+
/** Task queue for sequential operations */
|
|
2812
|
+
taskQueue = [];
|
|
2813
|
+
/** Previous dequeue arguments */
|
|
2814
|
+
prevArgs = [];
|
|
2815
|
+
/** Instance event emitter */
|
|
2816
|
+
_emitter = new EventEmitter();
|
|
2817
|
+
constructor() {
|
|
2818
|
+
this.id = generateId("service");
|
|
2819
|
+
}
|
|
2820
|
+
// ============================================================
|
|
2821
|
+
// Instance accessors for type-level data
|
|
2822
|
+
// ============================================================
|
|
2823
|
+
/** Instance event emitter (public accessor) */
|
|
2824
|
+
get emitter() {
|
|
2825
|
+
return this._emitter;
|
|
2826
|
+
}
|
|
2827
|
+
/**
|
|
2828
|
+
* Get internals object for serviceSend compatibility.
|
|
2829
|
+
* References per-type static state from the current class.
|
|
2830
|
+
*/
|
|
2831
|
+
get internals() {
|
|
2832
|
+
const ctor = this.constructor;
|
|
2833
|
+
return {
|
|
2834
|
+
metaList: ctor._metaList,
|
|
2835
|
+
payloadCache: ctor._payloadCache,
|
|
2836
|
+
pendingCacheKeys: ctor._pendingCacheKeys,
|
|
2837
|
+
syncFn: ctor._syncFn,
|
|
2838
|
+
staticEmitter: ctor._staticEmitter
|
|
2839
|
+
};
|
|
2840
|
+
}
|
|
2841
|
+
/**
|
|
2842
|
+
* Get type reference (the constructor) for serviceSend compatibility.
|
|
2843
|
+
* Static methods like get/create are accessible via the constructor.
|
|
2844
|
+
*/
|
|
2845
|
+
get type() {
|
|
2846
|
+
return this.constructor;
|
|
2847
|
+
}
|
|
2848
|
+
// ============================================================
|
|
2849
|
+
// Instance methods
|
|
2850
|
+
// ============================================================
|
|
2851
|
+
/**
|
|
2852
|
+
* Fetch all endpoints, callback when all complete.
|
|
2853
|
+
* Uses cache when available.
|
|
2854
|
+
*/
|
|
2855
|
+
all(attrs, done) {
|
|
2856
|
+
serviceSend(this, attrs, done, FETCH_FLAGS_ALL, false);
|
|
2857
|
+
return this;
|
|
2858
|
+
}
|
|
2859
|
+
/**
|
|
2860
|
+
* Fetch all endpoints, callback on each completion.
|
|
2861
|
+
*/
|
|
2862
|
+
one(attrs, done) {
|
|
2863
|
+
serviceSend(this, attrs, done, FETCH_FLAGS_ONE, false);
|
|
2864
|
+
return this;
|
|
2865
|
+
}
|
|
2866
|
+
/**
|
|
2867
|
+
* Fetch all endpoints, skip cache (always request).
|
|
2868
|
+
*/
|
|
2869
|
+
save(attrs, done) {
|
|
2870
|
+
serviceSend(this, attrs, done, FETCH_FLAGS_ALL, true);
|
|
2871
|
+
return this;
|
|
2872
|
+
}
|
|
2873
|
+
/**
|
|
2874
|
+
* Enqueue a task for sequential execution.
|
|
2875
|
+
*/
|
|
2876
|
+
enqueue(callback) {
|
|
2877
|
+
if (!this.destroyed) {
|
|
2878
|
+
this.taskQueue.push(callback);
|
|
2879
|
+
this.dequeue(...this.prevArgs);
|
|
2880
|
+
}
|
|
2881
|
+
return this;
|
|
2882
|
+
}
|
|
2883
|
+
/**
|
|
2884
|
+
* Dequeue and execute the next task in queue.
|
|
2885
|
+
*/
|
|
2886
|
+
dequeue(...args) {
|
|
2887
|
+
if (!this.busy && !this.destroyed) {
|
|
2888
|
+
this.busy = 1;
|
|
2889
|
+
setTimeout(() => {
|
|
2890
|
+
this.busy = 0;
|
|
2891
|
+
if (!this.destroyed) {
|
|
2892
|
+
const task2 = this.taskQueue.shift();
|
|
2893
|
+
if (task2) {
|
|
2894
|
+
this.prevArgs = args;
|
|
2895
|
+
funcWithTry(task2, args, this, noop);
|
|
2834
2896
|
}
|
|
2835
|
-
return cached;
|
|
2836
2897
|
}
|
|
2898
|
+
}, 0);
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
/**
|
|
2902
|
+
* Destroy the service instance.
|
|
2903
|
+
* After destruction, no new requests can be sent.
|
|
2904
|
+
*/
|
|
2905
|
+
destroy() {
|
|
2906
|
+
this.destroyed = 1;
|
|
2907
|
+
this.taskQueue = [];
|
|
2908
|
+
}
|
|
2909
|
+
// Instance event methods (delegate to instance emitter)
|
|
2910
|
+
on(event, handler) {
|
|
2911
|
+
this._emitter.on(event, handler);
|
|
2912
|
+
return this;
|
|
2913
|
+
}
|
|
2914
|
+
off(event, handler) {
|
|
2915
|
+
this._emitter.off(event, handler);
|
|
2916
|
+
return this;
|
|
2917
|
+
}
|
|
2918
|
+
fire(event, data) {
|
|
2919
|
+
this._emitter.fire(event, data);
|
|
2920
|
+
return this;
|
|
2921
|
+
}
|
|
2922
|
+
// ============================================================
|
|
2923
|
+
// Per-type static state
|
|
2924
|
+
// ============================================================
|
|
2925
|
+
/** Per-type metadata registry */
|
|
2926
|
+
static _metaList = {};
|
|
2927
|
+
/** Per-type payload cache (LFU with frequency eviction) */
|
|
2928
|
+
static _payloadCache = new Cache({
|
|
2929
|
+
maxSize: 20,
|
|
2930
|
+
bufferSize: 5
|
|
2931
|
+
});
|
|
2932
|
+
/** Per-type pending cache keys for deduplication */
|
|
2933
|
+
static _pendingCacheKeys = {};
|
|
2934
|
+
/** Per-type sync function */
|
|
2935
|
+
static _syncFn = noop;
|
|
2936
|
+
/** Per-type static event emitter */
|
|
2937
|
+
static _staticEmitter = new EventEmitter();
|
|
2938
|
+
/** Per-type cache max size */
|
|
2939
|
+
static _cacheMax = 20;
|
|
2940
|
+
/** Per-type cache buffer size */
|
|
2941
|
+
static _cacheBuffer = 5;
|
|
2942
|
+
// ============================================================
|
|
2943
|
+
// Static methods (operate on per-type state via `this`)
|
|
2944
|
+
// ============================================================
|
|
2945
|
+
/**
|
|
2946
|
+
* Register API endpoint metadata.
|
|
2947
|
+
*/
|
|
2948
|
+
static add(attrs) {
|
|
2949
|
+
if (!Array.isArray(attrs)) {
|
|
2950
|
+
attrs = [attrs];
|
|
2951
|
+
}
|
|
2952
|
+
for (const payload of attrs) {
|
|
2953
|
+
if (payload) {
|
|
2954
|
+
const name = payload.name;
|
|
2955
|
+
const cache = payload.cache;
|
|
2956
|
+
payload.cache = cache ? cache | 0 : 0;
|
|
2957
|
+
this._metaList[name] = payload;
|
|
2837
2958
|
}
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
/**
|
|
2962
|
+
* Get metadata for an API endpoint.
|
|
2963
|
+
*/
|
|
2964
|
+
static meta(attrs) {
|
|
2965
|
+
const name = typeof attrs === "string" ? attrs : attrs["name"];
|
|
2966
|
+
return this._metaList[name] || attrs;
|
|
2967
|
+
}
|
|
2968
|
+
/**
|
|
2969
|
+
* Create a Payload for an API request.
|
|
2970
|
+
*/
|
|
2971
|
+
static create(attrs) {
|
|
2972
|
+
const meta = this.meta(attrs);
|
|
2973
|
+
const cache = attrs["cache"] | 0 || meta.cache || 0;
|
|
2974
|
+
const entity = new Payload();
|
|
2975
|
+
entity.set(meta);
|
|
2976
|
+
entity.cacheInfo = {
|
|
2977
|
+
name: meta.name,
|
|
2978
|
+
after: meta.after,
|
|
2979
|
+
cleans: meta.cleanKeys,
|
|
2980
|
+
key: cache ? defaultCacheKey(meta, attrs) : "",
|
|
2981
|
+
time: 0
|
|
2982
|
+
};
|
|
2983
|
+
if (typeof attrs === "object" && attrs !== null) {
|
|
2984
|
+
entity.set(attrs);
|
|
2985
|
+
}
|
|
2986
|
+
const before = meta.before;
|
|
2987
|
+
if (before) {
|
|
2988
|
+
funcWithTry(before, [entity], entity, noop);
|
|
2989
|
+
}
|
|
2990
|
+
this._staticEmitter.fire("begin", { payload: entity });
|
|
2991
|
+
return entity;
|
|
2992
|
+
}
|
|
2993
|
+
/**
|
|
2994
|
+
* Get or create a Payload for an API request.
|
|
2995
|
+
*/
|
|
2996
|
+
static get(attrs, createNew) {
|
|
2997
|
+
let entity;
|
|
2998
|
+
let needsUpdate = false;
|
|
2999
|
+
if (!createNew) {
|
|
3000
|
+
entity = this.cached(attrs);
|
|
3001
|
+
}
|
|
3002
|
+
if (!entity) {
|
|
3003
|
+
entity = this.create(attrs);
|
|
3004
|
+
needsUpdate = true;
|
|
3005
|
+
}
|
|
3006
|
+
return { entity, needsUpdate };
|
|
3007
|
+
}
|
|
3008
|
+
/**
|
|
3009
|
+
* Get cached Payload if available and not expired.
|
|
3010
|
+
*/
|
|
3011
|
+
static cached(attrs) {
|
|
3012
|
+
const meta = this.meta(attrs);
|
|
3013
|
+
const cache = attrs["cache"] | 0 || meta.cache || 0;
|
|
3014
|
+
let cacheKey = "";
|
|
3015
|
+
if (cache) {
|
|
3016
|
+
cacheKey = defaultCacheKey(meta, attrs);
|
|
3017
|
+
}
|
|
3018
|
+
if (cacheKey) {
|
|
3019
|
+
const info = this._pendingCacheKeys[cacheKey];
|
|
3020
|
+
if (info) {
|
|
3021
|
+
return info.entity;
|
|
2845
3022
|
}
|
|
2846
|
-
const
|
|
2847
|
-
|
|
2848
|
-
if (
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
}
|
|
3023
|
+
const cached = this._payloadCache.get(cacheKey);
|
|
3024
|
+
if (cached && cached.cacheInfo) {
|
|
3025
|
+
if (now() - cached.cacheInfo.time > cache) {
|
|
3026
|
+
this._payloadCache.del(cacheKey);
|
|
3027
|
+
return void 0;
|
|
2852
3028
|
}
|
|
2853
|
-
|
|
2854
|
-
for (const key of keysToDelete) {
|
|
2855
|
-
bagCache.del(key);
|
|
3029
|
+
return cached;
|
|
2856
3030
|
}
|
|
2857
|
-
},
|
|
2858
|
-
on(event, handler) {
|
|
2859
|
-
staticEmitter2.on(event, handler);
|
|
2860
|
-
},
|
|
2861
|
-
off(event, handler) {
|
|
2862
|
-
staticEmitter2.off(event, handler);
|
|
2863
|
-
},
|
|
2864
|
-
fire(event, data) {
|
|
2865
|
-
staticEmitter2.fire(event, data);
|
|
2866
|
-
},
|
|
2867
|
-
extend(newSyncFn, newCacheMax, newCacheBuffer) {
|
|
2868
|
-
return createServiceType(
|
|
2869
|
-
newSyncFn,
|
|
2870
|
-
newCacheMax || cacheMax,
|
|
2871
|
-
newCacheBuffer || cacheBuffer
|
|
2872
|
-
);
|
|
2873
3031
|
}
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
this
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
}
|
|
2892
|
-
ServiceInstance.prototype = {
|
|
2893
|
-
all(attrs, done) {
|
|
2894
|
-
serviceSend(this, attrs, done, FETCH_FLAGS_ALL, false);
|
|
2895
|
-
return this;
|
|
2896
|
-
},
|
|
2897
|
-
one(attrs, done) {
|
|
2898
|
-
serviceSend(this, attrs, done, FETCH_FLAGS_ONE, false);
|
|
2899
|
-
return this;
|
|
2900
|
-
},
|
|
2901
|
-
save(attrs, done) {
|
|
2902
|
-
serviceSend(this, attrs, done, FETCH_FLAGS_ALL, true);
|
|
2903
|
-
return this;
|
|
2904
|
-
},
|
|
2905
|
-
enqueue(callback) {
|
|
2906
|
-
if (!this["$d"]) {
|
|
2907
|
-
this["$g"].push(callback);
|
|
2908
|
-
this.dequeue(...this["$h"]);
|
|
2909
|
-
}
|
|
2910
|
-
return this;
|
|
2911
|
-
},
|
|
2912
|
-
dequeue(...args) {
|
|
2913
|
-
if (!this["$e"] && !this["$d"]) {
|
|
2914
|
-
this["$e"] = 1;
|
|
2915
|
-
setTimeout(() => {
|
|
2916
|
-
this["$e"] = 0;
|
|
2917
|
-
if (!this["$d"]) {
|
|
2918
|
-
const task2 = this["$g"].shift();
|
|
2919
|
-
if (task2) {
|
|
2920
|
-
this["$h"] = args;
|
|
2921
|
-
funcWithTry(task2, args, this, noop);
|
|
2922
|
-
}
|
|
2923
|
-
}
|
|
2924
|
-
}, 0);
|
|
3032
|
+
return void 0;
|
|
3033
|
+
}
|
|
3034
|
+
/**
|
|
3035
|
+
* Clear cached payloads by endpoint name.
|
|
3036
|
+
*/
|
|
3037
|
+
static clear(names) {
|
|
3038
|
+
const nameList = (typeof names === "string" ? names : names.join(",")).split(",");
|
|
3039
|
+
const nameSet = {};
|
|
3040
|
+
for (const n of nameList) {
|
|
3041
|
+
nameSet[n] = 1;
|
|
3042
|
+
}
|
|
3043
|
+
const keysToDelete = [];
|
|
3044
|
+
this._payloadCache.forEach((payload) => {
|
|
3045
|
+
if (payload?.cacheInfo && nameSet[payload.cacheInfo.name]) {
|
|
3046
|
+
if (payload.cacheInfo.key) {
|
|
3047
|
+
keysToDelete.push(payload.cacheInfo.key);
|
|
3048
|
+
}
|
|
2925
3049
|
}
|
|
2926
|
-
}
|
|
2927
|
-
|
|
2928
|
-
this
|
|
2929
|
-
this["$g"] = [];
|
|
2930
|
-
},
|
|
2931
|
-
on(event, handler) {
|
|
2932
|
-
this._emitter.on(event, handler);
|
|
2933
|
-
return this;
|
|
2934
|
-
},
|
|
2935
|
-
off(event, handler) {
|
|
2936
|
-
this._emitter.off(event, handler);
|
|
2937
|
-
return this;
|
|
2938
|
-
},
|
|
2939
|
-
fire(event, data) {
|
|
2940
|
-
this._emitter.fire(event, data);
|
|
2941
|
-
return this;
|
|
3050
|
+
});
|
|
3051
|
+
for (const key of keysToDelete) {
|
|
3052
|
+
this._payloadCache.del(key);
|
|
2942
3053
|
}
|
|
2943
|
-
}
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
}
|
|
2963
|
-
|
|
3054
|
+
}
|
|
3055
|
+
// Static event methods (operate on per-type emitter)
|
|
3056
|
+
static on(event, handler) {
|
|
3057
|
+
this._staticEmitter.on(event, handler);
|
|
3058
|
+
}
|
|
3059
|
+
static off(event, handler) {
|
|
3060
|
+
this._staticEmitter.off(event, handler);
|
|
3061
|
+
}
|
|
3062
|
+
static fire(event, data) {
|
|
3063
|
+
this._staticEmitter.fire(event, data);
|
|
3064
|
+
}
|
|
3065
|
+
/**
|
|
3066
|
+
* Create a new Service subclass with a custom sync function.
|
|
3067
|
+
* Each subclass gets its own per-type state (metaList, cache, etc.)
|
|
3068
|
+
* to ensure isolation between different Service types.
|
|
3069
|
+
*/
|
|
3070
|
+
static extend(newSyncFn, newCacheMax, newCacheBuffer) {
|
|
3071
|
+
const ParentService = this;
|
|
3072
|
+
class ChildService extends ParentService {
|
|
3073
|
+
static _metaList = {};
|
|
3074
|
+
static _payloadCache = new Cache({
|
|
3075
|
+
maxSize: newCacheMax || ParentService._cacheMax,
|
|
3076
|
+
bufferSize: newCacheBuffer || ParentService._cacheBuffer
|
|
3077
|
+
});
|
|
3078
|
+
static _pendingCacheKeys = {};
|
|
3079
|
+
static _syncFn = newSyncFn;
|
|
3080
|
+
static _staticEmitter = new EventEmitter();
|
|
3081
|
+
static _cacheMax = newCacheMax || ParentService._cacheMax;
|
|
3082
|
+
static _cacheBuffer = newCacheBuffer || ParentService._cacheBuffer;
|
|
3083
|
+
}
|
|
3084
|
+
return ChildService;
|
|
3085
|
+
}
|
|
3086
|
+
};
|
|
2964
3087
|
function defaultCacheKey(meta, attrs) {
|
|
2965
3088
|
return JSON.stringify(attrs) + SPLITTER + JSON.stringify(meta);
|
|
2966
3089
|
}
|
|
2967
3090
|
function serviceSend(service, attrs, done, flag, save) {
|
|
2968
|
-
if (service["
|
|
2969
|
-
if (service["
|
|
3091
|
+
if (service["destroyed"]) return;
|
|
3092
|
+
if (service["busy"]) {
|
|
2970
3093
|
service.enqueue(
|
|
2971
3094
|
serviceSend.bind(null, service, attrs, done, flag, save)
|
|
2972
3095
|
);
|
|
2973
3096
|
return;
|
|
2974
3097
|
}
|
|
2975
|
-
service["
|
|
3098
|
+
service["busy"] = 1;
|
|
2976
3099
|
let attrList;
|
|
2977
3100
|
if (typeof attrs === "string") {
|
|
2978
3101
|
attrList = [{ name: attrs }];
|
|
2979
|
-
} else if (isArray(attrs)) {
|
|
3102
|
+
} else if (Array.isArray(attrs)) {
|
|
2980
3103
|
attrList = attrs;
|
|
2981
3104
|
} else {
|
|
2982
3105
|
attrList = [attrs];
|
|
2983
3106
|
}
|
|
2984
|
-
const internals = service.
|
|
3107
|
+
const internals = service.internals;
|
|
2985
3108
|
const { syncFn, pendingCacheKeys, staticEmitter: staticEmitter2 } = internals;
|
|
2986
3109
|
let requestCount = 0;
|
|
2987
3110
|
const total = attrList.length;
|
|
2988
3111
|
const doneArr = new Array(total + 1);
|
|
2989
3112
|
const errorArgs = [];
|
|
2990
3113
|
const remoteComplete = (idx, error) => {
|
|
2991
|
-
const
|
|
2992
|
-
let
|
|
3114
|
+
const payload = doneArr[idx + 1];
|
|
3115
|
+
let newPayload = false;
|
|
2993
3116
|
if (error) {
|
|
2994
3117
|
errorArgs[idx] = error;
|
|
2995
|
-
staticEmitter2.fire("fail", {
|
|
3118
|
+
staticEmitter2.fire("fail", { payload, error });
|
|
2996
3119
|
} else {
|
|
2997
|
-
|
|
2998
|
-
staticEmitter2.fire("done", {
|
|
3120
|
+
newPayload = true;
|
|
3121
|
+
staticEmitter2.fire("done", { payload });
|
|
2999
3122
|
}
|
|
3000
|
-
if (!service["
|
|
3123
|
+
if (!service["destroyed"]) {
|
|
3001
3124
|
const finish = requestCount === total;
|
|
3002
3125
|
if (finish) {
|
|
3003
|
-
service["
|
|
3126
|
+
service["busy"] = 0;
|
|
3004
3127
|
if (flag === FETCH_FLAGS_ALL) {
|
|
3005
3128
|
doneArr[0] = errorArgs;
|
|
3006
3129
|
funcWithTry(done, doneArr, service, noop);
|
|
3007
3130
|
}
|
|
3008
3131
|
}
|
|
3009
3132
|
if (flag === FETCH_FLAGS_ONE) {
|
|
3010
|
-
funcWithTry(done, [error || null,
|
|
3133
|
+
funcWithTry(done, [error || null, payload, finish, idx], service, noop);
|
|
3011
3134
|
}
|
|
3012
3135
|
}
|
|
3013
|
-
if (
|
|
3014
|
-
staticEmitter2.fire("end", {
|
|
3136
|
+
if (newPayload) {
|
|
3137
|
+
staticEmitter2.fire("end", { payload, error });
|
|
3015
3138
|
}
|
|
3016
3139
|
};
|
|
3017
3140
|
for (const attr of attrList) {
|
|
3018
3141
|
if (!attr) continue;
|
|
3019
3142
|
const attrObj = typeof attr === "string" ? { name: attr } : attr;
|
|
3020
|
-
const
|
|
3021
|
-
|
|
3022
|
-
|
|
3143
|
+
const payloadInfo = service.type.get(
|
|
3144
|
+
attrObj,
|
|
3145
|
+
save
|
|
3146
|
+
);
|
|
3147
|
+
const payloadEntity = payloadInfo.entity;
|
|
3148
|
+
const cacheKey = payloadEntity.cacheInfo?.key || "";
|
|
3023
3149
|
const complete = remoteComplete.bind(null, requestCount++);
|
|
3024
3150
|
if (cacheKey && pendingCacheKeys[cacheKey]) {
|
|
3025
3151
|
pendingCacheKeys[cacheKey].push(complete);
|
|
3026
|
-
} else if (
|
|
3152
|
+
} else if (payloadInfo.needsUpdate) {
|
|
3027
3153
|
if (cacheKey) {
|
|
3028
3154
|
const cacheList = [complete];
|
|
3029
|
-
cacheList.
|
|
3155
|
+
cacheList.entity = payloadEntity;
|
|
3030
3156
|
pendingCacheKeys[cacheKey] = cacheList;
|
|
3031
3157
|
const cacheComplete = () => {
|
|
3032
3158
|
const list = pendingCacheKeys[cacheKey];
|
|
3033
|
-
const entity = list.
|
|
3159
|
+
const entity = list.entity;
|
|
3034
3160
|
if (entity.cacheInfo) {
|
|
3035
3161
|
entity.cacheInfo.time = now();
|
|
3036
3162
|
}
|
|
3037
|
-
internals.
|
|
3163
|
+
internals.payloadCache.set(cacheKey, entity);
|
|
3038
3164
|
Reflect.deleteProperty(pendingCacheKeys, cacheKey);
|
|
3039
3165
|
for (const cb of list) {
|
|
3040
3166
|
if (typeof cb === "function") {
|
|
@@ -3042,9 +3168,9 @@ function serviceSend(service, attrs, done, flag, save) {
|
|
|
3042
3168
|
}
|
|
3043
3169
|
}
|
|
3044
3170
|
};
|
|
3045
|
-
syncFn(
|
|
3171
|
+
syncFn(payloadEntity, cacheComplete);
|
|
3046
3172
|
} else {
|
|
3047
|
-
syncFn(
|
|
3173
|
+
syncFn(payloadEntity, complete);
|
|
3048
3174
|
}
|
|
3049
3175
|
} else {
|
|
3050
3176
|
complete();
|
|
@@ -3052,12 +3178,12 @@ function serviceSend(service, attrs, done, flag, save) {
|
|
|
3052
3178
|
}
|
|
3053
3179
|
}
|
|
3054
3180
|
|
|
3055
|
-
// src/frame-visualizer
|
|
3056
|
-
var MSG_PING = "
|
|
3057
|
-
var MSG_PONG = "
|
|
3058
|
-
var MSG_REQUEST_TREE = "
|
|
3059
|
-
var MSG_TREE = "
|
|
3060
|
-
var MSG_TREE_DELTA = "
|
|
3181
|
+
// src/frame-visualizer.ts
|
|
3182
|
+
var MSG_PING = "LARK_VISUALIZER_PING";
|
|
3183
|
+
var MSG_PONG = "LARK_VISUALIZER_PONG";
|
|
3184
|
+
var MSG_REQUEST_TREE = "LARK_VISUALIZER_REQUEST_TREE";
|
|
3185
|
+
var MSG_TREE = "LARK_VISUALIZER_TREE";
|
|
3186
|
+
var MSG_TREE_DELTA = "LARK_VISUALIZER_TREE_DELTA";
|
|
3061
3187
|
function serializeView(view) {
|
|
3062
3188
|
return {
|
|
3063
3189
|
id: view.id,
|
|
@@ -3162,7 +3288,7 @@ function pushTreeUpdate() {
|
|
|
3162
3288
|
|
|
3163
3289
|
// src/framework.ts
|
|
3164
3290
|
var config = {
|
|
3165
|
-
rootId: "
|
|
3291
|
+
rootId: "root",
|
|
3166
3292
|
hashbang: "#!",
|
|
3167
3293
|
error: (error) => {
|
|
3168
3294
|
throw error;
|
|
@@ -3255,7 +3381,12 @@ function dispatcherUpdate(frame, stateKeys) {
|
|
|
3255
3381
|
const isChanged = stateKeys ? stateIsObserveChanged(view, stateKeys) : viewIsObserveChanged(view);
|
|
3256
3382
|
let renderPromise;
|
|
3257
3383
|
if (isChanged) {
|
|
3258
|
-
const renderResult = funcWithTry(
|
|
3384
|
+
const renderResult = funcWithTry(
|
|
3385
|
+
view.renderMethod ?? view.render,
|
|
3386
|
+
[],
|
|
3387
|
+
view,
|
|
3388
|
+
noop
|
|
3389
|
+
);
|
|
3259
3390
|
if (renderResult && typeof renderResult.then === "function") {
|
|
3260
3391
|
renderPromise = renderResult;
|
|
3261
3392
|
}
|
|
@@ -3277,13 +3408,13 @@ function dispatcherUpdate(frame, stateKeys) {
|
|
|
3277
3408
|
}
|
|
3278
3409
|
function dispatcherNotifyChange(e) {
|
|
3279
3410
|
const rootFrame2 = Frame.root();
|
|
3280
|
-
const view = e
|
|
3411
|
+
const view = e.view;
|
|
3281
3412
|
if (view) {
|
|
3282
3413
|
const viewPath = typeof view === "object" && view !== null ? String(view.to || "") : String(view);
|
|
3283
3414
|
rootFrame2.mountView(viewPath);
|
|
3284
3415
|
} else {
|
|
3285
3416
|
dispatcherUpdateTag++;
|
|
3286
|
-
dispatcherUpdate(rootFrame2, e
|
|
3417
|
+
dispatcherUpdate(rootFrame2, e.keys);
|
|
3287
3418
|
}
|
|
3288
3419
|
}
|
|
3289
3420
|
function dispatchEvent(target, eventType, eventInit) {
|
|
@@ -3294,8 +3425,6 @@ function dispatchEvent(target, eventType, eventInit) {
|
|
|
3294
3425
|
});
|
|
3295
3426
|
target.dispatchEvent(event);
|
|
3296
3427
|
}
|
|
3297
|
-
var Base = class extends EventEmitter {
|
|
3298
|
-
};
|
|
3299
3428
|
function use(names, callback) {
|
|
3300
3429
|
if (!config.require) {
|
|
3301
3430
|
if (callback) callback();
|
|
@@ -3310,7 +3439,7 @@ function use(names, callback) {
|
|
|
3310
3439
|
}
|
|
3311
3440
|
}
|
|
3312
3441
|
var WAIT_OK = 1;
|
|
3313
|
-
var
|
|
3442
|
+
var WAIT_TIMEOUT_OR_NOT_FOUND = 0;
|
|
3314
3443
|
function waitZoneViewsRendered(viewId, timeout) {
|
|
3315
3444
|
if (timeout == null) {
|
|
3316
3445
|
timeout = 30 * 1e3;
|
|
@@ -3321,7 +3450,7 @@ function waitZoneViewsRendered(viewId, timeout) {
|
|
|
3321
3450
|
const check = () => {
|
|
3322
3451
|
const currentTime = now();
|
|
3323
3452
|
if (currentTime > endTime || !checkFrame) {
|
|
3324
|
-
resolve(
|
|
3453
|
+
resolve(WAIT_TIMEOUT_OR_NOT_FOUND);
|
|
3325
3454
|
} else if (checkFrame.childrenCount === checkFrame.readyCount) {
|
|
3326
3455
|
resolve(WAIT_OK);
|
|
3327
3456
|
} else {
|
|
@@ -3358,10 +3487,10 @@ var Framework = {
|
|
|
3358
3487
|
Router._setConfig(config);
|
|
3359
3488
|
EventDelegator.setFrameGetter((id) => Frame.get(id));
|
|
3360
3489
|
Router.on(ROUTER_EVENTS.CHANGED, (data) => {
|
|
3361
|
-
dispatcherNotifyChange(data);
|
|
3490
|
+
if (data) dispatcherNotifyChange(data);
|
|
3362
3491
|
});
|
|
3363
3492
|
State.on(ROUTER_EVENTS.CHANGED, (data) => {
|
|
3364
|
-
dispatcherNotifyChange(data);
|
|
3493
|
+
if (data) dispatcherNotifyChange(data);
|
|
3365
3494
|
});
|
|
3366
3495
|
booted3 = true;
|
|
3367
3496
|
markBooted();
|
|
@@ -3398,7 +3527,7 @@ var Framework = {
|
|
|
3398
3527
|
/** Wait for zone views to be rendered */
|
|
3399
3528
|
waitZoneViewsRendered,
|
|
3400
3529
|
WAIT_OK,
|
|
3401
|
-
|
|
3530
|
+
WAIT_TIMEOUT_OR_NOT_FOUND,
|
|
3402
3531
|
/**
|
|
3403
3532
|
* Convert array to hash map.
|
|
3404
3533
|
*/
|
|
@@ -3463,7 +3592,7 @@ var Framework = {
|
|
|
3463
3592
|
/**
|
|
3464
3593
|
* Base class with EventEmitter.
|
|
3465
3594
|
*/
|
|
3466
|
-
Base,
|
|
3595
|
+
Base: EventEmitter,
|
|
3467
3596
|
// ============================================================
|
|
3468
3597
|
// Module access
|
|
3469
3598
|
// ============================================================
|
|
@@ -3481,10 +3610,11 @@ if (typeof window !== "undefined") {
|
|
|
3481
3610
|
window.__lark_State = State;
|
|
3482
3611
|
window.__lark_Router = Router;
|
|
3483
3612
|
window.__lark_Frame = Frame;
|
|
3613
|
+
window.__lark_View = View;
|
|
3484
3614
|
}
|
|
3485
3615
|
|
|
3486
3616
|
// src/store.ts
|
|
3487
|
-
var LARK_GLOBAL = "
|
|
3617
|
+
var LARK_GLOBAL = "lark-global";
|
|
3488
3618
|
var Platform = /* @__PURE__ */ ((Platform2) => {
|
|
3489
3619
|
Platform2["Lark"] = "lark";
|
|
3490
3620
|
Platform2["React"] = "react";
|
|
@@ -3527,8 +3657,10 @@ var Queue = class {
|
|
|
3527
3657
|
const flushTickTask = () => {
|
|
3528
3658
|
while (queue.length > 0) {
|
|
3529
3659
|
const task2 = queue.shift();
|
|
3530
|
-
|
|
3531
|
-
|
|
3660
|
+
if (task2) {
|
|
3661
|
+
pendingTasks.delete(task2);
|
|
3662
|
+
runTask(task2);
|
|
3663
|
+
}
|
|
3532
3664
|
}
|
|
3533
3665
|
};
|
|
3534
3666
|
Promise.resolve().then(flushTickTask);
|
|
@@ -3627,9 +3759,11 @@ var setStateConfig = (target, config2) => {
|
|
|
3627
3759
|
if (target && isObject(config2)) StateConfigMap.set(target, config2);
|
|
3628
3760
|
};
|
|
3629
3761
|
var getStateConfig = (target, key) => {
|
|
3630
|
-
if (!StateConfigMap.has(target))
|
|
3762
|
+
if (!StateConfigMap.has(target)) {
|
|
3763
|
+
return void 0;
|
|
3764
|
+
}
|
|
3631
3765
|
const config2 = StateConfigMap.get(target);
|
|
3632
|
-
return key ? config2[key] : config2;
|
|
3766
|
+
return key ? config2?.[key] : config2;
|
|
3633
3767
|
};
|
|
3634
3768
|
var isState = (target) => isObject(target) && StateConfigMap.has(target);
|
|
3635
3769
|
var createLinkKeys = (target, property) => {
|
|
@@ -4196,14 +4330,11 @@ function defineStore(name, creator, config2) {
|
|
|
4196
4330
|
const useStore = adapter.useStore;
|
|
4197
4331
|
const store = new StoreClass(name, config2);
|
|
4198
4332
|
store[_storeCreate](
|
|
4199
|
-
creator(
|
|
4200
|
-
store[_innerStore](),
|
|
4201
|
-
extendApis
|
|
4202
|
-
)
|
|
4333
|
+
creator(store[_innerStore](), extendApis)
|
|
4203
4334
|
);
|
|
4204
4335
|
Object.defineProperties(useStore, {
|
|
4205
4336
|
$storeName: { value: name, configurable: true },
|
|
4206
|
-
$
|
|
4337
|
+
$destroyFn: { value: () => store[_storeDestroy](), configurable: true }
|
|
4207
4338
|
});
|
|
4208
4339
|
if (!StoreCache.has(name)) {
|
|
4209
4340
|
StoreCache.set(name, { store, creator, config: config2, useStore });
|
|
@@ -4268,7 +4399,7 @@ function observeCell(state, cb, immediate = true) {
|
|
|
4268
4399
|
}
|
|
4269
4400
|
function multi(useStore) {
|
|
4270
4401
|
const storeName = useStore["$storeName"];
|
|
4271
|
-
const flagSym = `
|
|
4402
|
+
const flagSym = `lark-comp-${storeName}`;
|
|
4272
4403
|
const map = /* @__PURE__ */ new Map();
|
|
4273
4404
|
let rootViewPath;
|
|
4274
4405
|
const getFlag = (viewContext) => {
|
|
@@ -4277,7 +4408,7 @@ function multi(useStore) {
|
|
|
4277
4408
|
const viewId = owner?.["id"] || "";
|
|
4278
4409
|
let flag;
|
|
4279
4410
|
if (viewPath === rootViewPath) {
|
|
4280
|
-
flag = `${flagSym}
|
|
4411
|
+
flag = `${flagSym}-${viewId}`;
|
|
4281
4412
|
} else {
|
|
4282
4413
|
flag = owner?.["viewInitParams"]?.[flagSym];
|
|
4283
4414
|
}
|
|
@@ -4294,14 +4425,13 @@ function multi(useStore) {
|
|
|
4294
4425
|
};
|
|
4295
4426
|
const useFn = ((view) => {
|
|
4296
4427
|
if (!view)
|
|
4297
|
-
throw new Error(
|
|
4428
|
+
throw new Error(
|
|
4429
|
+
"[@lark.js/mvc error] multi: cannot find the view instance"
|
|
4430
|
+
);
|
|
4298
4431
|
const viewCtx = view;
|
|
4299
4432
|
const flag = viewCtx[flagSym];
|
|
4300
4433
|
if (map.has(flag)) return map.get(flag);
|
|
4301
|
-
const newFn = cloneStore(
|
|
4302
|
-
flag,
|
|
4303
|
-
useStore
|
|
4304
|
-
);
|
|
4434
|
+
const newFn = cloneStore(flag, useStore);
|
|
4305
4435
|
map.set(flag, newFn);
|
|
4306
4436
|
return useFn(view);
|
|
4307
4437
|
});
|
|
@@ -4439,7 +4569,7 @@ function convertArtSyntax(source, debug) {
|
|
|
4439
4569
|
}
|
|
4440
4570
|
if (blockStack.length > 0) {
|
|
4441
4571
|
const unclosed = blockStack.map((b) => `"${b.ctrl}" at line ${b.line}`).join(", ");
|
|
4442
|
-
throw new Error(`[@lark/mvc error] unclosed block(s): ${unclosed}`);
|
|
4572
|
+
throw new Error(`[@lark.js/mvc error] unclosed block(s): ${unclosed}`);
|
|
4443
4573
|
}
|
|
4444
4574
|
return result.join("");
|
|
4445
4575
|
}
|
|
@@ -4533,12 +4663,12 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
|
|
|
4533
4663
|
}
|
|
4534
4664
|
return `${debugPrefix}<%}else{%>`;
|
|
4535
4665
|
}
|
|
4536
|
-
case "
|
|
4537
|
-
blockStack.push({ ctrl: "
|
|
4666
|
+
case "forOf": {
|
|
4667
|
+
blockStack.push({ ctrl: "forOf", line: lineNo });
|
|
4538
4668
|
const object = tokens[0];
|
|
4539
4669
|
if (tokens.length > 1 && tokens[1] !== "as") {
|
|
4540
4670
|
throw new Error(
|
|
4541
|
-
`[@lark/mvc error] bad
|
|
4671
|
+
`[@lark.js/mvc error] bad forOf syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{forOf list as item [index]}}`
|
|
4542
4672
|
);
|
|
4543
4673
|
}
|
|
4544
4674
|
const restTokens = tokens.slice(2);
|
|
@@ -4560,12 +4690,12 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
|
|
|
4560
4690
|
}
|
|
4561
4691
|
return `${debugPrefix}<%for(let ${index}=0${refExpr},${refObjCount}=${refObj}.length${lastCount};${index}<${refObjCount};${index}++){${firstAndLast}${valueDecl}%>`;
|
|
4562
4692
|
}
|
|
4563
|
-
case "
|
|
4564
|
-
blockStack.push({ ctrl: "
|
|
4693
|
+
case "forIn": {
|
|
4694
|
+
blockStack.push({ ctrl: "forIn", line: lineNo });
|
|
4565
4695
|
const object = tokens[0];
|
|
4566
4696
|
if (tokens.length > 1 && tokens[1] !== "as") {
|
|
4567
4697
|
throw new Error(
|
|
4568
|
-
`[@lark/mvc error] bad
|
|
4698
|
+
`[@lark.js/mvc error] bad forIn syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{for-in obj as val [key]}}`
|
|
4569
4699
|
);
|
|
4570
4700
|
}
|
|
4571
4701
|
const restTokens2 = tokens.slice(2);
|
|
@@ -4585,19 +4715,19 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
|
|
|
4585
4715
|
case "set":
|
|
4586
4716
|
return `${debugPrefix}<%let ${tokens.join(" ")};%>`;
|
|
4587
4717
|
case "/if":
|
|
4588
|
-
case "/
|
|
4589
|
-
case "/
|
|
4718
|
+
case "/forOf":
|
|
4719
|
+
case "/forIn":
|
|
4590
4720
|
case "/for": {
|
|
4591
4721
|
const expectedCtrl = keyword.substring(1);
|
|
4592
4722
|
const last = blockStack.pop();
|
|
4593
4723
|
if (!last) {
|
|
4594
4724
|
throw new Error(
|
|
4595
|
-
`[@lark/mvc error] unexpected {{${code}}}: no matching open block`
|
|
4725
|
+
`[@lark.js/mvc error] unexpected {{${code}}}: no matching open block`
|
|
4596
4726
|
);
|
|
4597
4727
|
}
|
|
4598
4728
|
if (last.ctrl !== expectedCtrl) {
|
|
4599
4729
|
throw new Error(
|
|
4600
|
-
`[@lark/mvc error] unexpected {{${code}}}: expected {{/${last.ctrl}}} to close block opened at line ${last.line}`
|
|
4730
|
+
`[@lark.js/mvc error] unexpected {{${code}}}: expected {{/${last.ctrl}}} to close block opened at line ${last.line}`
|
|
4601
4731
|
);
|
|
4602
4732
|
}
|
|
4603
4733
|
return `${debugPrefix}<%}%>`;
|
|
@@ -4661,7 +4791,7 @@ function parseAsExpr(expr) {
|
|
|
4661
4791
|
function compileToFunction(source, debug, file) {
|
|
4662
4792
|
const matcher = /<%([@=!:])?([\s\S]*?)%>|$/g;
|
|
4663
4793
|
let index = 0;
|
|
4664
|
-
let funcSource = `$
|
|
4794
|
+
let funcSource = `$out+='`;
|
|
4665
4795
|
let hasAtRule = false;
|
|
4666
4796
|
const escapeSlashRegExp = /\\|'/g;
|
|
4667
4797
|
const escapeBreakReturnRegExp = /\r|\n/g;
|
|
@@ -4687,17 +4817,17 @@ function compileToFunction(source, debug, file) {
|
|
|
4687
4817
|
}
|
|
4688
4818
|
if (operate === "@") {
|
|
4689
4819
|
hasAtRule = true;
|
|
4690
|
-
funcSource += `'+($
|
|
4820
|
+
funcSource += `'+($dbgExpr='<%${operate + expr}%>',$refFn($refAlt,${content}))+'`;
|
|
4691
4821
|
} else if (operate === "=" || operate === ":") {
|
|
4692
|
-
funcSource += `'+($
|
|
4822
|
+
funcSource += `'+($dbgExpr='<%${operate + expr}%>',$encHtml(${content}))+'`;
|
|
4693
4823
|
} else if (operate === "!") {
|
|
4694
|
-
if (!content.startsWith("$
|
|
4695
|
-
content = `$
|
|
4824
|
+
if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
|
|
4825
|
+
content = `$strSafe(${content})`;
|
|
4696
4826
|
}
|
|
4697
|
-
funcSource += `'+($
|
|
4827
|
+
funcSource += `'+($dbgExpr='<%${operate + expr}%>',${content})+'`;
|
|
4698
4828
|
} else if (content) {
|
|
4699
4829
|
if (line > -1) {
|
|
4700
|
-
funcSource += `';$
|
|
4830
|
+
funcSource += `';$dbgLine=${line};$dbgArt='${art}';`;
|
|
4701
4831
|
content = "";
|
|
4702
4832
|
} else {
|
|
4703
4833
|
funcSource += `';`;
|
|
@@ -4706,19 +4836,19 @@ function compileToFunction(source, debug, file) {
|
|
|
4706
4836
|
funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
|
|
4707
4837
|
}
|
|
4708
4838
|
if (expr) {
|
|
4709
|
-
funcSource += `$
|
|
4839
|
+
funcSource += `$dbgExpr='<%${expr}%>';`;
|
|
4710
4840
|
}
|
|
4711
|
-
funcSource += content + `;$
|
|
4841
|
+
funcSource += content + `;$out+='`;
|
|
4712
4842
|
}
|
|
4713
4843
|
} else {
|
|
4714
4844
|
if (operate === "@") {
|
|
4715
4845
|
hasAtRule = true;
|
|
4716
|
-
funcSource += `'+$
|
|
4846
|
+
funcSource += `'+$refFn($refAlt,${content})+'`;
|
|
4717
4847
|
} else if (operate === "=" || operate === ":") {
|
|
4718
|
-
funcSource += `'+$
|
|
4848
|
+
funcSource += `'+$encHtml(${content})+'`;
|
|
4719
4849
|
} else if (operate === "!") {
|
|
4720
|
-
if (!content.startsWith("$
|
|
4721
|
-
content = `$
|
|
4850
|
+
if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
|
|
4851
|
+
content = `$strSafe(${content})`;
|
|
4722
4852
|
}
|
|
4723
4853
|
funcSource += `'+${content}+'`;
|
|
4724
4854
|
} else if (content) {
|
|
@@ -4726,28 +4856,28 @@ function compileToFunction(source, debug, file) {
|
|
|
4726
4856
|
if (funcSource.endsWith(`+'';`)) {
|
|
4727
4857
|
funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
|
|
4728
4858
|
}
|
|
4729
|
-
funcSource += `${content};$
|
|
4859
|
+
funcSource += `${content};$out+='`;
|
|
4730
4860
|
}
|
|
4731
4861
|
}
|
|
4732
4862
|
return match;
|
|
4733
4863
|
});
|
|
4734
4864
|
funcSource += `';`;
|
|
4735
|
-
funcSource = funcSource.replace(/\$
|
|
4736
|
-
funcSource = funcSource.replace(/\$
|
|
4865
|
+
funcSource = funcSource.replace(/\$out\+='';/g, "");
|
|
4866
|
+
funcSource = funcSource.replace(/\$out\+=''\+/g, "$out+=");
|
|
4737
4867
|
if (debug) {
|
|
4738
4868
|
const filePart = file ? `\\r\\n\\tat file:${file}` : "";
|
|
4739
|
-
funcSource = `let $
|
|
4869
|
+
funcSource = `let $dbgExpr,$dbgArt,$dbgLine;try{${funcSource}}catch(ex){let msg='render view error:'+(ex.message||ex);if($dbgArt)msg+='\\r\\n\\tsrc art:{{'+$dbgArt+'}}\\r\\n\\tat line:'+$dbgLine;msg+='\\r\\n\\t'+($dbgArt?'translate to:':'expr:');msg+=$dbgExpr+'${filePart}';throw msg;}`;
|
|
4740
4870
|
}
|
|
4741
4871
|
const viewIdRegExp = new RegExp(String.fromCharCode(31), "g");
|
|
4742
4872
|
funcSource = funcSource.replace(viewIdRegExp, `'+$viewId+'`);
|
|
4743
|
-
const atRule = hasAtRule ? `if(!$
|
|
4744
|
-
const encode = `if(!$
|
|
4745
|
-
const encodeURIMore = `if(!$
|
|
4746
|
-
const encodeQuote = `if(!$
|
|
4747
|
-
const refFallback = "if(
|
|
4873
|
+
const atRule = hasAtRule ? `if(!$refFn){$refFn=(ref,v,k,f)=>{for(f=ref[$splitter];--f;)if(ref[k=$splitter+f]===v)return k;ref[k=$splitter+ref[$splitter]++]=v;return k;}}` : "";
|
|
4874
|
+
const encode = `if(!$strSafe){let $entMap={'&':'amp','<':'lt','>':'gt','"':'#34','\\'':'#39','\`':'#96'},$entReg=/[&<>"'\`]/g,$entFn=m=>'&'+$entMap[m]+';';$strSafe=v=>''+(v==null?'':v);$encHtml=v=>$strSafe(v).replace($entReg,$entFn)}`;
|
|
4875
|
+
const encodeURIMore = `if(!$encUri){let $uriMap={'!':'%21','\\'':'%27','(':'%28',')':'%29','*':'%2A'},$uriFn=m=>$uriMap[m],$uriReg=/[!')(*]/g;$encUri=v=>encodeURIComponent($strSafe(v)).replace($uriReg,$uriFn)}`;
|
|
4876
|
+
const encodeQuote = `if(!$encQuote){let $qReg=/['"\\\\]/g;$encQuote=v=>$strSafe(v).replace($qReg,'\\\\$&')}`;
|
|
4877
|
+
const refFallback = "if(!$refAlt)$refAlt=$data;";
|
|
4748
4878
|
const fns = `${refFallback}${encode}${encodeURIMore}${encodeQuote}${atRule};`;
|
|
4749
|
-
const fullSource = `${fns}let $
|
|
4750
|
-
return `(
|
|
4879
|
+
const fullSource = `${fns}let $splitter='\\x1e',$tmp,$out=''{{VARS}};${funcSource}return $out`;
|
|
4880
|
+
return `($data,$viewId,$refAlt,$encHtml,$strSafe,$encUri,$refFn,$encQuote)=>{${fullSource}}`;
|
|
4751
4881
|
}
|
|
4752
4882
|
function compileTemplate(source, options = {}) {
|
|
4753
4883
|
const { debug = false, globalVars = [], file } = options;
|
|
@@ -4756,17 +4886,17 @@ function compileTemplate(source, options = {}) {
|
|
|
4756
4886
|
const viewEventProcessed = processViewEvents(converted);
|
|
4757
4887
|
const finalSource = restoreComments(viewEventProcessed, comments);
|
|
4758
4888
|
const funcBody = compileToFunction(finalSource, debug, file);
|
|
4759
|
-
const varDeclarations = globalVars.map((key) => `,${key}
|
|
4889
|
+
const varDeclarations = globalVars.map((key) => `,${key}=$data.${key}`).join("");
|
|
4760
4890
|
const funcWithVars = funcBody.replace("{{VARS}}", () => varDeclarations);
|
|
4761
4891
|
return `export default function(data, selfId, refData) {
|
|
4762
|
-
let
|
|
4892
|
+
let $data = data || {},
|
|
4763
4893
|
$viewId = selfId || '';
|
|
4764
|
-
return (${funcWithVars})(
|
|
4765
|
-
/* $
|
|
4766
|
-
/* $
|
|
4767
|
-
/* $
|
|
4768
|
-
/* $
|
|
4769
|
-
/* $
|
|
4894
|
+
return (${funcWithVars})($data, $viewId, refData,
|
|
4895
|
+
/* $encHtml */ v => String(v == null ? '' : v).replace(/[&<>"'\`]/g, m => '&' + ({'&':'amp','<':'lt','>':'gt','"':'#34',"'":'#39','\`':'#96'})[m] + ';'),
|
|
4896
|
+
/* $strSafe */ v => String(v == null ? '' : v),
|
|
4897
|
+
/* $encUri */ null,
|
|
4898
|
+
/* $refFn */ null,
|
|
4899
|
+
/* $encQuote */ null
|
|
4770
4900
|
);
|
|
4771
4901
|
}`;
|
|
4772
4902
|
}
|
|
@@ -4875,7 +5005,7 @@ function fallbackExtractVariables(source) {
|
|
|
4875
5005
|
while ((m = outputRegExp.exec(source)) !== null) {
|
|
4876
5006
|
vars.add(m[1]);
|
|
4877
5007
|
}
|
|
4878
|
-
const eachRegExp = /\{\{
|
|
5008
|
+
const eachRegExp = /\{\{forOf\s+([a-zA-Z_$][\w$]*)\s+as/g;
|
|
4879
5009
|
while ((m = eachRegExp.exec(source)) !== null) {
|
|
4880
5010
|
vars.add(m[1]);
|
|
4881
5011
|
}
|
|
@@ -4921,52 +5051,64 @@ var BUILTIN_GLOBALS = {
|
|
|
4921
5051
|
//
|
|
4922
5052
|
// These variables appear in the generated template function signature
|
|
4923
5053
|
// or body. They must be excluded from extractGlobalVars() so that
|
|
4924
|
-
// they are not mistaken for user data variables and destructured from
|
|
5054
|
+
// they are not mistaken for user data variables and destructured from $data.
|
|
4925
5055
|
// SPLITTER character constant (same as \x1e), used as namespace separator
|
|
4926
5056
|
// for refData keys, event attribute encoding, and internal data structures.
|
|
4927
|
-
// Declared as: let $
|
|
4928
|
-
$
|
|
4929
|
-
//
|
|
4930
|
-
// User variables are destructured from
|
|
4931
|
-
// let {name, age} =
|
|
5057
|
+
// Declared as: let $splitter='\x1e'
|
|
5058
|
+
$splitter: 1,
|
|
5059
|
+
// Data — the data object passed from Updater to the template function.
|
|
5060
|
+
// User variables are destructured from $data at the top of the function:
|
|
5061
|
+
// let {name, age} = $data;
|
|
4932
5062
|
// This is the first parameter of the generated arrow function.
|
|
4933
|
-
|
|
5063
|
+
$data: 1,
|
|
4934
5064
|
// Null-safe toString: v => '' + (v == null ? '' : v)
|
|
4935
5065
|
// Converts null/undefined to empty string, otherwise calls toString().
|
|
4936
5066
|
// Wraps every {{!raw}} output to prevent "null" / "undefined" rendering.
|
|
4937
|
-
$
|
|
4938
|
-
// HTML entity encoder: v => $
|
|
5067
|
+
$strSafe: 1,
|
|
5068
|
+
// HTML entity encoder: v => $strSafe(v).replace(/[&<>"'`]/g, entityMap)
|
|
4939
5069
|
// Encodes &, <, >, ", ', ` to HTML entities (& < etc.)
|
|
4940
5070
|
// Applied to all {{=escaped}} and {{:binding}} outputs.
|
|
4941
|
-
$
|
|
4942
|
-
// HTML entity map — internal object used by $
|
|
5071
|
+
$encHtml: 1,
|
|
5072
|
+
// HTML entity map — internal object used by $encHtml:
|
|
4943
5073
|
// {'&':'amp','<':'gt','>':'gt','"':'#34','\'':'#39','`':'#96'}
|
|
4944
|
-
// Not a standalone function; referenced inside $
|
|
4945
|
-
$
|
|
4946
|
-
// HTML entity RegExp — internal regexp used by $
|
|
5074
|
+
// Not a standalone function; referenced inside $encHtml's closure.
|
|
5075
|
+
$entMap: 1,
|
|
5076
|
+
// HTML entity RegExp — internal regexp used by $encHtml:
|
|
4947
5077
|
// /[&<>"'`]/g
|
|
4948
|
-
$
|
|
4949
|
-
// HTML entity replacer function — internal helper used by $
|
|
4950
|
-
// m => '&' + $
|
|
4951
|
-
// Maps
|
|
4952
|
-
$
|
|
5078
|
+
$entReg: 1,
|
|
5079
|
+
// HTML entity replacer function — internal helper used by $encHtml:
|
|
5080
|
+
// m => '&' + $entMap[m] + ';'
|
|
5081
|
+
// Maps matched character to its entity string.
|
|
5082
|
+
$entFn: 1,
|
|
4953
5083
|
// Output buffer — the string accumulator for rendered HTML.
|
|
4954
|
-
// All template output is appended via $
|
|
4955
|
-
// Declared as: let $
|
|
4956
|
-
$
|
|
5084
|
+
// All template output is appended via $out += '...'.
|
|
5085
|
+
// Declared as: let $out = ''
|
|
5086
|
+
$out: 1,
|
|
4957
5087
|
// Reference lookup: (refData, value) => key
|
|
4958
5088
|
// Finds or allocates a SPLITTER-prefixed key in refData for a given
|
|
4959
5089
|
// object reference. Used by {{@ref}} operator for passing object
|
|
4960
5090
|
// references to child views via v-lark attributes.
|
|
4961
|
-
$
|
|
4962
|
-
// URI encoder: v => encodeURIComponent($
|
|
5091
|
+
$refFn: 1,
|
|
5092
|
+
// URI encoder: v => encodeURIComponent($strSafe(v)).replace(/[!')(*]/g, extraMap)
|
|
4963
5093
|
// Extends encodeURIComponent with encoding of ! ' ( ) *.
|
|
4964
5094
|
// Applied to values in @event URL parameters and {{!uri}} contexts.
|
|
4965
|
-
$
|
|
4966
|
-
//
|
|
5095
|
+
$encUri: 1,
|
|
5096
|
+
// URI encode map — internal object used by $encUri:
|
|
5097
|
+
// {'!':'%21','\'':'%27','(':'%28',')':'%29','*':'%2A'}
|
|
5098
|
+
$uriMap: 1,
|
|
5099
|
+
// URI encode replacer — internal helper used by $encUri:
|
|
5100
|
+
// m => $uriMap[m]
|
|
5101
|
+
$uriFn: 1,
|
|
5102
|
+
// URI encode regexp — internal regexp used by $encUri:
|
|
5103
|
+
// /[!')(*]/g
|
|
5104
|
+
$uriReg: 1,
|
|
5105
|
+
// Quote encoder: v => $strSafe(v).replace(/['"\\]/g, '\\$&')
|
|
4967
5106
|
// Escapes quotes and backslashes for safe embedding in HTML attribute
|
|
4968
5107
|
// values (e.g. data-json='...').
|
|
4969
|
-
$
|
|
5108
|
+
$encQuote: 1,
|
|
5109
|
+
// Quote encode regexp — internal regexp used by $encQuote:
|
|
5110
|
+
// /['"\\]/g
|
|
5111
|
+
$qReg: 1,
|
|
4970
5112
|
// View ID — the unique identifier of the owning View instance.
|
|
4971
5113
|
// Injected into @event attribute values at render time so that
|
|
4972
5114
|
// EventDelegator can dispatch events to the correct View handler.
|
|
@@ -4974,23 +5116,23 @@ var BUILTIN_GLOBALS = {
|
|
|
4974
5116
|
$viewId: 1,
|
|
4975
5117
|
// Debug: current expression text — stores the template expression being
|
|
4976
5118
|
// evaluated, for error reporting. Only present in debug mode.
|
|
4977
|
-
// e.g. $
|
|
4978
|
-
$
|
|
5119
|
+
// e.g. $dbgExpr='<%=user.name%>'
|
|
5120
|
+
$dbgExpr: 1,
|
|
4979
5121
|
// Debug: original art syntax — stores the {{}} template syntax before
|
|
4980
5122
|
// conversion, for error reporting. Only present in debug mode.
|
|
4981
|
-
// e.g. $
|
|
4982
|
-
$
|
|
5123
|
+
// e.g. $dbgArt='{{=user.name}}'
|
|
5124
|
+
$dbgArt: 1,
|
|
4983
5125
|
// Debug: source line number — tracks the current line in the template
|
|
4984
5126
|
// source, for error reporting. Only present in debug mode.
|
|
4985
|
-
$
|
|
4986
|
-
//
|
|
4987
|
-
// Defaults to
|
|
4988
|
-
// Ensures $
|
|
4989
|
-
|
|
5127
|
+
$dbgLine: 1,
|
|
5128
|
+
// RefData alias — fallback reference lookup table.
|
|
5129
|
+
// Defaults to $data when no explicit $refAlt is provided.
|
|
5130
|
+
// Ensures $refFn() does not crash when @ operator is used without refData.
|
|
5131
|
+
$refAlt: 1,
|
|
4990
5132
|
// Temporary variable — used by the compiler for intermediate
|
|
4991
5133
|
// expression results in generated code (e.g. loop variables,
|
|
4992
|
-
// conditional branches). Declared as: let $
|
|
4993
|
-
$
|
|
5134
|
+
// conditional branches). Declared as: let $tmp
|
|
5135
|
+
$tmp: 1,
|
|
4994
5136
|
// JS literals
|
|
4995
5137
|
undefined: 1,
|
|
4996
5138
|
null: 1,
|
|
@@ -5055,7 +5197,6 @@ var BUILTIN_GLOBALS = {
|
|
|
5055
5197
|
};
|
|
5056
5198
|
var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
|
|
5057
5199
|
export {
|
|
5058
|
-
Bag,
|
|
5059
5200
|
CALL_BREAK_TIME,
|
|
5060
5201
|
Cache,
|
|
5061
5202
|
EVENT_METHOD_REGEXP,
|
|
@@ -5064,6 +5205,7 @@ export {
|
|
|
5064
5205
|
Frame,
|
|
5065
5206
|
Framework,
|
|
5066
5207
|
LARK_VIEW,
|
|
5208
|
+
Payload,
|
|
5067
5209
|
Platform,
|
|
5068
5210
|
ROUTER_EVENTS,
|
|
5069
5211
|
Router,
|
|
@@ -5102,7 +5244,6 @@ export {
|
|
|
5102
5244
|
getUseStore,
|
|
5103
5245
|
has,
|
|
5104
5246
|
installFrameVisualizerBridge,
|
|
5105
|
-
isArray,
|
|
5106
5247
|
isPlainObject,
|
|
5107
5248
|
isPrimitive,
|
|
5108
5249
|
isPrimitiveOrFunc,
|