@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.cjs
CHANGED
|
@@ -20,7 +20,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
Bag: () => Bag,
|
|
24
23
|
CALL_BREAK_TIME: () => CALL_BREAK_TIME,
|
|
25
24
|
Cache: () => Cache,
|
|
26
25
|
EVENT_METHOD_REGEXP: () => EVENT_METHOD_REGEXP,
|
|
@@ -29,6 +28,7 @@ __export(index_exports, {
|
|
|
29
28
|
Frame: () => Frame,
|
|
30
29
|
Framework: () => Framework,
|
|
31
30
|
LARK_VIEW: () => LARK_VIEW,
|
|
31
|
+
Payload: () => Payload,
|
|
32
32
|
Platform: () => Platform,
|
|
33
33
|
ROUTER_EVENTS: () => ROUTER_EVENTS,
|
|
34
34
|
Router: () => Router,
|
|
@@ -67,7 +67,6 @@ __export(index_exports, {
|
|
|
67
67
|
getUseStore: () => getUseStore,
|
|
68
68
|
has: () => has,
|
|
69
69
|
installFrameVisualizerBridge: () => installFrameVisualizerBridge,
|
|
70
|
-
isArray: () => isArray,
|
|
71
70
|
isPlainObject: () => isPlainObject,
|
|
72
71
|
isPrimitive: () => isPrimitive,
|
|
73
72
|
isPrimitiveOrFunc: () => isPrimitiveOrFunc,
|
|
@@ -147,7 +146,6 @@ function isPlainObject(value) {
|
|
|
147
146
|
if (proto === null) return true;
|
|
148
147
|
return proto === Object.prototype || proto === null;
|
|
149
148
|
}
|
|
150
|
-
var isArray = Array.isArray;
|
|
151
149
|
function isPrimitiveOrFunc(value) {
|
|
152
150
|
return !value || typeof value !== "object" && typeof value !== "function";
|
|
153
151
|
}
|
|
@@ -188,13 +186,13 @@ function assign(target, ...sources) {
|
|
|
188
186
|
return target;
|
|
189
187
|
}
|
|
190
188
|
function funcWithTry(fns, args, context, configError) {
|
|
191
|
-
const fnArray = isArray(fns) ? fns : [fns];
|
|
189
|
+
const fnArray = Array.isArray(fns) ? fns : [fns];
|
|
192
190
|
let ret;
|
|
193
191
|
for (const fn of fnArray) {
|
|
194
192
|
try {
|
|
195
193
|
ret = Function.prototype.apply.call(fn, context, args);
|
|
196
194
|
} catch (e) {
|
|
197
|
-
configError(e);
|
|
195
|
+
configError?.(e);
|
|
198
196
|
}
|
|
199
197
|
}
|
|
200
198
|
return ret;
|
|
@@ -222,7 +220,7 @@ function translateData(data, value) {
|
|
|
222
220
|
}
|
|
223
221
|
return value;
|
|
224
222
|
}
|
|
225
|
-
if (isPlainObject(value) || isArray(value)) {
|
|
223
|
+
if (isPlainObject(value) || Array.isArray(value)) {
|
|
226
224
|
for (const p in value) {
|
|
227
225
|
if (has(value, p)) {
|
|
228
226
|
const val = value[p];
|
|
@@ -317,11 +315,11 @@ function now() {
|
|
|
317
315
|
}
|
|
318
316
|
function classExtend(make, base, props, statics) {
|
|
319
317
|
const baseProto = base["prototype"] ?? {};
|
|
320
|
-
const
|
|
321
|
-
assign(
|
|
318
|
+
const classProto = Object.create(baseProto);
|
|
319
|
+
assign(classProto, props);
|
|
322
320
|
Object.assign(make, statics);
|
|
323
|
-
|
|
324
|
-
make["prototype"] =
|
|
321
|
+
classProto.constructor = make;
|
|
322
|
+
make["prototype"] = classProto;
|
|
325
323
|
}
|
|
326
324
|
|
|
327
325
|
// src/apply-style.ts
|
|
@@ -362,8 +360,8 @@ function applyStyle(styleIdOrPairs, css) {
|
|
|
362
360
|
}
|
|
363
361
|
|
|
364
362
|
// src/mark.ts
|
|
365
|
-
var DELETED_KEY = SPLITTER + "$
|
|
366
|
-
var MARK_OBJECT_KEY = SPLITTER + "$
|
|
363
|
+
var DELETED_KEY = SPLITTER + "$delFlag";
|
|
364
|
+
var MARK_OBJECT_KEY = SPLITTER + "$markKey";
|
|
367
365
|
function mark(host, key) {
|
|
368
366
|
let sign = 0;
|
|
369
367
|
const hostRecord = host;
|
|
@@ -387,7 +385,7 @@ function unmark(host) {
|
|
|
387
385
|
|
|
388
386
|
// src/safeguard.ts
|
|
389
387
|
var proxiesPool = /* @__PURE__ */ new Map();
|
|
390
|
-
var SAFEGUARD_SENTINEL = "
|
|
388
|
+
var SAFEGUARD_SENTINEL = "_safe_";
|
|
391
389
|
function safeguard(data, getter, setter, isRoot) {
|
|
392
390
|
if (typeof window.__lark_Debug === "undefined" || !window.__lark_Debug) {
|
|
393
391
|
return data;
|
|
@@ -428,7 +426,7 @@ function safeguard(data, getter, setter, isRoot) {
|
|
|
428
426
|
if (!prefix && getter) {
|
|
429
427
|
getter(property);
|
|
430
428
|
}
|
|
431
|
-
if (!isRoot && has(target, property) && (isArray(out) || isPlainObject(out))) {
|
|
429
|
+
if (!isRoot && has(target, property) && (Array.isArray(out) || isPlainObject(out))) {
|
|
432
430
|
return build(prefix + property + ".", out);
|
|
433
431
|
}
|
|
434
432
|
return out;
|
|
@@ -603,7 +601,10 @@ var EventEmitter = class {
|
|
|
603
601
|
}
|
|
604
602
|
} else {
|
|
605
603
|
this.listeners.delete(key);
|
|
606
|
-
Reflect.deleteProperty(
|
|
604
|
+
Reflect.deleteProperty(
|
|
605
|
+
this,
|
|
606
|
+
`on${event[0].toUpperCase() + event.slice(1)}`
|
|
607
|
+
);
|
|
607
608
|
}
|
|
608
609
|
return this;
|
|
609
610
|
}
|
|
@@ -644,7 +645,7 @@ var EventEmitter = class {
|
|
|
644
645
|
}
|
|
645
646
|
}
|
|
646
647
|
}
|
|
647
|
-
const onMethodName = `on${event}`;
|
|
648
|
+
const onMethodName = `on${event[0].toUpperCase() + event.slice(1)}`;
|
|
648
649
|
const onMethod = this[onMethodName];
|
|
649
650
|
if (typeof onMethod === "function") {
|
|
650
651
|
funcWithTry(
|
|
@@ -835,6 +836,7 @@ var State = {
|
|
|
835
836
|
emitter.fire(event, data, remove);
|
|
836
837
|
return State;
|
|
837
838
|
}
|
|
839
|
+
// onChanged: noop,
|
|
838
840
|
};
|
|
839
841
|
|
|
840
842
|
// src/router.ts
|
|
@@ -1140,9 +1142,9 @@ var Router = {
|
|
|
1140
1142
|
window.addEventListener("hashchange", watchChange);
|
|
1141
1143
|
window.addEventListener("popstate", watchChange);
|
|
1142
1144
|
window.addEventListener("beforeunload", (domEvent) => {
|
|
1143
|
-
const
|
|
1144
|
-
Router.fire(ROUTER_EVENTS.PAGE_UNLOAD,
|
|
1145
|
-
const msg =
|
|
1145
|
+
const data = {};
|
|
1146
|
+
Router.fire(ROUTER_EVENTS.PAGE_UNLOAD, data);
|
|
1147
|
+
const msg = data["msg"];
|
|
1146
1148
|
if (msg) {
|
|
1147
1149
|
domEvent.returnValue = msg;
|
|
1148
1150
|
}
|
|
@@ -1174,16 +1176,16 @@ var frameGetter;
|
|
|
1174
1176
|
function parseEventInfo(eventInfo) {
|
|
1175
1177
|
const cached = eventInfoCache.get(eventInfo);
|
|
1176
1178
|
if (cached) {
|
|
1177
|
-
return assign({}, cached, {
|
|
1179
|
+
return assign({}, cached, { value: eventInfo });
|
|
1178
1180
|
}
|
|
1179
1181
|
const match = eventInfo.match(EVENT_METHOD_REGEXP) || [];
|
|
1180
1182
|
const result = {
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1183
|
+
id: match[1] || "",
|
|
1184
|
+
name: match[2] || "",
|
|
1185
|
+
params: match[3] || ""
|
|
1184
1186
|
};
|
|
1185
1187
|
eventInfoCache.set(eventInfo, result);
|
|
1186
|
-
return assign({}, result, {
|
|
1188
|
+
return assign({}, result, { value: eventInfo });
|
|
1187
1189
|
}
|
|
1188
1190
|
function findFrameInfo(current, eventType) {
|
|
1189
1191
|
const eventInfos = [];
|
|
@@ -1193,7 +1195,7 @@ function findFrameInfo(current, eventType) {
|
|
|
1193
1195
|
if (info) {
|
|
1194
1196
|
match = parseEventInfo(info);
|
|
1195
1197
|
}
|
|
1196
|
-
if (match && !match.
|
|
1198
|
+
if (match && !match.id || selectorEvents[eventType]) {
|
|
1197
1199
|
let selectorFrameId = "#";
|
|
1198
1200
|
let backtrace = 0;
|
|
1199
1201
|
while (begin && begin !== document.body) {
|
|
@@ -1219,10 +1221,10 @@ function findFrameInfo(current, eventType) {
|
|
|
1219
1221
|
if (selectorEntry) {
|
|
1220
1222
|
for (const selectorName of selectorEntry.selectors) {
|
|
1221
1223
|
const entry = {
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1224
|
+
value: selectorName,
|
|
1225
|
+
id: frameId,
|
|
1226
|
+
name: selectorName,
|
|
1227
|
+
params: ""
|
|
1226
1228
|
};
|
|
1227
1229
|
if (selectorName) {
|
|
1228
1230
|
if (!backtrace && elementMatchesSelector(current, selectorName)) {
|
|
@@ -1234,8 +1236,8 @@ function findFrameInfo(current, eventType) {
|
|
|
1234
1236
|
}
|
|
1235
1237
|
}
|
|
1236
1238
|
if (view.template && !backtrace) {
|
|
1237
|
-
if (match && !match.
|
|
1238
|
-
match.
|
|
1239
|
+
if (match && !match.id) {
|
|
1240
|
+
match.id = frameId;
|
|
1239
1241
|
}
|
|
1240
1242
|
break;
|
|
1241
1243
|
}
|
|
@@ -1251,10 +1253,10 @@ function findFrameInfo(current, eventType) {
|
|
|
1251
1253
|
}
|
|
1252
1254
|
if (match) {
|
|
1253
1255
|
eventInfos.push({
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1256
|
+
id: match.id,
|
|
1257
|
+
value: match.value,
|
|
1258
|
+
name: match.name,
|
|
1259
|
+
params: match.params
|
|
1258
1260
|
});
|
|
1259
1261
|
}
|
|
1260
1262
|
return eventInfos;
|
|
@@ -1275,7 +1277,7 @@ function domEventProcessor(domEvent) {
|
|
|
1275
1277
|
const eventInfos = findFrameInfo(current, eventType);
|
|
1276
1278
|
if (eventInfos.length) {
|
|
1277
1279
|
for (const info of eventInfos) {
|
|
1278
|
-
const {
|
|
1280
|
+
const { id: frameId, name: handlerName, params } = info;
|
|
1279
1281
|
if (lastFrameId !== frameId) {
|
|
1280
1282
|
if (lastFrameId && domEvent.isPropagationStopped?.()) {
|
|
1281
1283
|
break;
|
|
@@ -1374,8 +1376,8 @@ var WrapMeta = {
|
|
|
1374
1376
|
td: [3, "<table><tbody><tr>"],
|
|
1375
1377
|
area: [1, "<map>"],
|
|
1376
1378
|
param: [1, "<object>"],
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
+
svg: [1, '<svg xmlns="' + SVG_NS + '">'],
|
|
1380
|
+
math: [1, '<math xmlns="' + MATH_NS + '">'],
|
|
1379
1381
|
_: [0, ""]
|
|
1380
1382
|
};
|
|
1381
1383
|
WrapMeta["optgroup"] = WrapMeta["option"];
|
|
@@ -1408,9 +1410,9 @@ function vdomGetNode(html, refNode) {
|
|
|
1408
1410
|
const ns = refNode.namespaceURI;
|
|
1409
1411
|
let tag;
|
|
1410
1412
|
if (ns === SVG_NS) {
|
|
1411
|
-
tag = "
|
|
1413
|
+
tag = "svg";
|
|
1412
1414
|
} else if (ns === MATH_NS) {
|
|
1413
|
-
tag = "
|
|
1415
|
+
tag = "math";
|
|
1414
1416
|
} else {
|
|
1415
1417
|
const match = TAG_NAME_REGEXP.exec(html);
|
|
1416
1418
|
tag = match ? match[1] : "";
|
|
@@ -1855,221 +1857,6 @@ if (typeof window !== "undefined") {
|
|
|
1855
1857
|
if (typeof document !== "undefined") {
|
|
1856
1858
|
VIEW_GLOBALS["document"] = document;
|
|
1857
1859
|
}
|
|
1858
|
-
function viewPrepare(oView) {
|
|
1859
|
-
if (oView.ctors) {
|
|
1860
|
-
return oView.ctors;
|
|
1861
|
-
}
|
|
1862
|
-
const ctors = [];
|
|
1863
|
-
oView.ctors = ctors;
|
|
1864
|
-
const proto = oView.prototype;
|
|
1865
|
-
const eventsObject = {};
|
|
1866
|
-
const eventsList = [];
|
|
1867
|
-
const selectorObject = {};
|
|
1868
|
-
const mixins = proto["mixins"];
|
|
1869
|
-
if (mixins && Array.isArray(mixins)) {
|
|
1870
|
-
viewMergeMixins(mixins, oView, ctors);
|
|
1871
|
-
}
|
|
1872
|
-
for (const p in proto) {
|
|
1873
|
-
if (!has(proto, p)) continue;
|
|
1874
|
-
const currentFn = proto[p];
|
|
1875
|
-
if (typeof currentFn !== "function") continue;
|
|
1876
|
-
const matches = p.match(VIEW_EVENT_METHOD_REGEXP);
|
|
1877
|
-
if (!matches) continue;
|
|
1878
|
-
const isSelector = matches[1];
|
|
1879
|
-
const selectorOrCallback = matches[2];
|
|
1880
|
-
const events = matches[3];
|
|
1881
|
-
const modifiers = matches[4];
|
|
1882
|
-
const mod = {};
|
|
1883
|
-
if (modifiers) {
|
|
1884
|
-
for (const item of modifiers.split(",")) {
|
|
1885
|
-
mod[item] = true;
|
|
1886
|
-
}
|
|
1887
|
-
}
|
|
1888
|
-
const eventTypes = events.split(",");
|
|
1889
|
-
for (const item of eventTypes) {
|
|
1890
|
-
const globalNode = VIEW_GLOBALS[selectorOrCallback];
|
|
1891
|
-
let mask = 1;
|
|
1892
|
-
if (isSelector) {
|
|
1893
|
-
if (globalNode) {
|
|
1894
|
-
eventsList.push({
|
|
1895
|
-
handler: currentFn,
|
|
1896
|
-
element: globalNode,
|
|
1897
|
-
eventName: item,
|
|
1898
|
-
modifiers: mod
|
|
1899
|
-
});
|
|
1900
|
-
continue;
|
|
1901
|
-
}
|
|
1902
|
-
mask = 2;
|
|
1903
|
-
let selectorEntry = selectorObject[item];
|
|
1904
|
-
if (!selectorEntry) {
|
|
1905
|
-
selectorEntry = selectorObject[item] = {
|
|
1906
|
-
selectors: []
|
|
1907
|
-
};
|
|
1908
|
-
}
|
|
1909
|
-
if (!selectorEntry[selectorOrCallback]) {
|
|
1910
|
-
selectorEntry[selectorOrCallback] = 1;
|
|
1911
|
-
selectorEntry.selectors.push(selectorOrCallback);
|
|
1912
|
-
}
|
|
1913
|
-
}
|
|
1914
|
-
eventsObject[item] = (eventsObject[item] || 0) | mask;
|
|
1915
|
-
const combinedKey = selectorOrCallback + SPLITTER + item;
|
|
1916
|
-
const existingFn = proto[combinedKey];
|
|
1917
|
-
if (!existingFn) {
|
|
1918
|
-
proto[combinedKey] = currentFn;
|
|
1919
|
-
} else {
|
|
1920
|
-
const mixinFn = currentFn;
|
|
1921
|
-
const existingMixin = existingFn;
|
|
1922
|
-
if (existingMixin.b) {
|
|
1923
|
-
if (mixinFn.b) {
|
|
1924
|
-
proto[combinedKey] = processMixinsSameEvent(
|
|
1925
|
-
currentFn,
|
|
1926
|
-
existingFn
|
|
1927
|
-
);
|
|
1928
|
-
} else if (has(proto, p)) {
|
|
1929
|
-
proto[combinedKey] = currentFn;
|
|
1930
|
-
}
|
|
1931
|
-
}
|
|
1932
|
-
}
|
|
1933
|
-
}
|
|
1934
|
-
}
|
|
1935
|
-
viewWrapMethod(proto, "render", "$b");
|
|
1936
|
-
proto["$eo"] = eventsObject;
|
|
1937
|
-
proto["$el"] = eventsList;
|
|
1938
|
-
proto["$so"] = selectorObject;
|
|
1939
|
-
proto["$f"] = proto["assign"];
|
|
1940
|
-
return ctors;
|
|
1941
|
-
}
|
|
1942
|
-
function viewWrapMethod(proto, fnName, shortKey) {
|
|
1943
|
-
const originalFn = proto[fnName];
|
|
1944
|
-
if (typeof originalFn !== "function") return;
|
|
1945
|
-
const wrapped = function(...args) {
|
|
1946
|
-
if (this.signature > 0) {
|
|
1947
|
-
this.signature++;
|
|
1948
|
-
this.fire("rendercall");
|
|
1949
|
-
destroyAllResources(this, false);
|
|
1950
|
-
const instanceFn = typeof this[fnName] === "function" ? this[fnName] : originalFn;
|
|
1951
|
-
const fnToCall = instanceFn === wrapped ? originalFn : instanceFn;
|
|
1952
|
-
return funcWithTry(fnToCall, args, this, noop);
|
|
1953
|
-
}
|
|
1954
|
-
return void 0;
|
|
1955
|
-
};
|
|
1956
|
-
proto[fnName] = wrapped;
|
|
1957
|
-
proto[shortKey] = wrapped;
|
|
1958
|
-
}
|
|
1959
|
-
function processMixinsSameEvent(additional, exist) {
|
|
1960
|
-
let temp;
|
|
1961
|
-
const existMixin = exist;
|
|
1962
|
-
if (existMixin.a) {
|
|
1963
|
-
temp = existMixin;
|
|
1964
|
-
} else {
|
|
1965
|
-
temp = function(...e) {
|
|
1966
|
-
funcWithTry(temp.a ?? [], e, this, noop);
|
|
1967
|
-
};
|
|
1968
|
-
temp.a = [exist];
|
|
1969
|
-
temp.b = 1;
|
|
1970
|
-
}
|
|
1971
|
-
const additionalMixin = additional;
|
|
1972
|
-
temp.a = (temp.a ?? []).concat(additionalMixin.a ?? [additional]);
|
|
1973
|
-
return temp;
|
|
1974
|
-
}
|
|
1975
|
-
function viewMergeMixins(mixins, viewClass, ctors) {
|
|
1976
|
-
const proto = viewClass.prototype;
|
|
1977
|
-
const temp = {};
|
|
1978
|
-
for (const node of mixins) {
|
|
1979
|
-
for (const p in node) {
|
|
1980
|
-
if (!has(node, p)) continue;
|
|
1981
|
-
const fn = node[p];
|
|
1982
|
-
const exist = temp[p];
|
|
1983
|
-
if (p === "make") {
|
|
1984
|
-
ctors.push(fn);
|
|
1985
|
-
continue;
|
|
1986
|
-
}
|
|
1987
|
-
if (VIEW_EVENT_METHOD_REGEXP.test(p)) {
|
|
1988
|
-
if (exist) {
|
|
1989
|
-
temp[p] = processMixinsSameEvent(fn, exist);
|
|
1990
|
-
} else {
|
|
1991
|
-
fn.b = 1;
|
|
1992
|
-
temp[p] = fn;
|
|
1993
|
-
}
|
|
1994
|
-
} else {
|
|
1995
|
-
if (!exist) {
|
|
1996
|
-
temp[p] = fn;
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
2001
|
-
for (const p in temp) {
|
|
2002
|
-
if (!has(proto, p)) {
|
|
2003
|
-
proto[p] = temp[p];
|
|
2004
|
-
}
|
|
2005
|
-
}
|
|
2006
|
-
}
|
|
2007
|
-
function viewDelegateEvents(view, destroy = false) {
|
|
2008
|
-
const proto = Object.getPrototypeOf(view) ?? {};
|
|
2009
|
-
const eventsObject = proto["$eo"] || view.eventObjectMap;
|
|
2010
|
-
const selectorObject = proto["$so"] || view.eventSelectorMap;
|
|
2011
|
-
const eventsList = proto["$el"] || view.globalEventList;
|
|
2012
|
-
for (const e in eventsObject) {
|
|
2013
|
-
if (has(eventsObject, e)) {
|
|
2014
|
-
if (destroy) {
|
|
2015
|
-
EventDelegator.unbind(e, !!selectorObject[e]);
|
|
2016
|
-
} else {
|
|
2017
|
-
EventDelegator.bind(e, !!selectorObject[e]);
|
|
2018
|
-
}
|
|
2019
|
-
}
|
|
2020
|
-
}
|
|
2021
|
-
for (const entry of eventsList) {
|
|
2022
|
-
if (destroy) {
|
|
2023
|
-
entry.element.removeEventListener(
|
|
2024
|
-
entry.eventName,
|
|
2025
|
-
entry.boundHandler
|
|
2026
|
-
);
|
|
2027
|
-
} else {
|
|
2028
|
-
const handler = entry.handler;
|
|
2029
|
-
const element = entry.element;
|
|
2030
|
-
const modifiers = entry.modifiers;
|
|
2031
|
-
entry.boundHandler = function(domEvent) {
|
|
2032
|
-
const extendedEvent = domEvent;
|
|
2033
|
-
extendedEvent.eventTarget = element;
|
|
2034
|
-
if (modifiers) {
|
|
2035
|
-
const kbEvent = domEvent;
|
|
2036
|
-
if (modifiers["ctrl"] && !kbEvent.ctrlKey || modifiers["shift"] && !kbEvent.shiftKey || modifiers["alt"] && !kbEvent.altKey || modifiers["meta"] && !kbEvent.metaKey) {
|
|
2037
|
-
return;
|
|
2038
|
-
}
|
|
2039
|
-
}
|
|
2040
|
-
funcWithTry(handler, [domEvent], view, noop);
|
|
2041
|
-
};
|
|
2042
|
-
entry.element.addEventListener(
|
|
2043
|
-
entry.eventName,
|
|
2044
|
-
entry.boundHandler
|
|
2045
|
-
);
|
|
2046
|
-
}
|
|
2047
|
-
}
|
|
2048
|
-
}
|
|
2049
|
-
function destroyAllResources(view, lastly) {
|
|
2050
|
-
const cache = view.resources;
|
|
2051
|
-
for (const p in cache) {
|
|
2052
|
-
if (has(cache, p)) {
|
|
2053
|
-
const entry = cache[p];
|
|
2054
|
-
if (lastly || entry.destroyOnRender) {
|
|
2055
|
-
destroyResource(cache, p, true);
|
|
2056
|
-
}
|
|
2057
|
-
}
|
|
2058
|
-
}
|
|
2059
|
-
}
|
|
2060
|
-
function destroyResource(cache, key, callDestroy, oldEntity) {
|
|
2061
|
-
const entry = cache[key];
|
|
2062
|
-
if (!entry || entry.entity === oldEntity) return void 0;
|
|
2063
|
-
const entity = entry.entity;
|
|
2064
|
-
if (entity && typeof entity === "object") {
|
|
2065
|
-
const destroyFn = entity["destroy"];
|
|
2066
|
-
if (typeof destroyFn === "function" && callDestroy) {
|
|
2067
|
-
funcWithTry(destroyFn, [], entity, noop);
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
Reflect.deleteProperty(cache, key);
|
|
2071
|
-
return entity;
|
|
2072
|
-
}
|
|
2073
1860
|
var View = class _View {
|
|
2074
1861
|
/** View ID (same as owner frame ID) */
|
|
2075
1862
|
id = "";
|
|
@@ -2093,18 +1880,43 @@ var View = class _View {
|
|
|
2093
1880
|
observedStateKeys;
|
|
2094
1881
|
/** Resource map */
|
|
2095
1882
|
resources = {};
|
|
2096
|
-
/** Selector event map: eventType -> handler name list */
|
|
2097
|
-
eventSelectorMap = {};
|
|
2098
|
-
/** Event object map: eventType -> bitmask */
|
|
2099
|
-
eventObjectMap = {};
|
|
2100
|
-
/** Global event list */
|
|
2101
|
-
globalEventList = [];
|
|
2102
1883
|
/** Assign method reference */
|
|
2103
1884
|
assignMethod;
|
|
2104
1885
|
/** Whether endUpdate pending */
|
|
2105
1886
|
endUpdatePending;
|
|
2106
1887
|
/** Internal event storage */
|
|
2107
1888
|
_events = new EventEmitter();
|
|
1889
|
+
// ============================================================
|
|
1890
|
+
// Getters for prototype-stored event maps
|
|
1891
|
+
// ============================================================
|
|
1892
|
+
/**
|
|
1893
|
+
* Event bitmask map: eventType -> bitmask (1=root, 2=selector).
|
|
1894
|
+
* Read from prototype ($evtObjMap) set by View.prepare.
|
|
1895
|
+
* Using a getter avoids ES6 class field shadowing the prototype value.
|
|
1896
|
+
*/
|
|
1897
|
+
get eventObjectMap() {
|
|
1898
|
+
const proto = Object.getPrototypeOf(this);
|
|
1899
|
+
return proto["$evtObjMap"] || {};
|
|
1900
|
+
}
|
|
1901
|
+
/**
|
|
1902
|
+
* Selector event map: eventType -> selector list.
|
|
1903
|
+
* Read from prototype ($selMap) set by View.prepare.
|
|
1904
|
+
*/
|
|
1905
|
+
get eventSelectorMap() {
|
|
1906
|
+
const proto = Object.getPrototypeOf(this);
|
|
1907
|
+
return proto["$selMap"] || {};
|
|
1908
|
+
}
|
|
1909
|
+
/**
|
|
1910
|
+
* Global event list: [{handler, element, eventName, modifiers}].
|
|
1911
|
+
* Read from prototype ($globalEvtList) set by View.prepare.
|
|
1912
|
+
*/
|
|
1913
|
+
get globalEventList() {
|
|
1914
|
+
const proto = Object.getPrototypeOf(this);
|
|
1915
|
+
return proto["$globalEvtList"] || [];
|
|
1916
|
+
}
|
|
1917
|
+
// ============================================================
|
|
1918
|
+
// Instance lifecycle methods
|
|
1919
|
+
// ============================================================
|
|
2108
1920
|
/**
|
|
2109
1921
|
* Initialize view (called by Frame when mounting).
|
|
2110
1922
|
*/
|
|
@@ -2112,14 +1924,7 @@ var View = class _View {
|
|
|
2112
1924
|
}
|
|
2113
1925
|
/**
|
|
2114
1926
|
* Render view template (called by Frame after init).
|
|
2115
|
-
* Wrapped by
|
|
2116
|
-
*
|
|
2117
|
-
* Default implementation calls updater.digest() which:
|
|
2118
|
-
* 1. Executes the template function with current data
|
|
2119
|
-
* 2. Runs VDOM diff against previous DOM
|
|
2120
|
-
* 3. Applies DOM operations
|
|
2121
|
-
* 4. Calls endUpdate to mount child frames
|
|
2122
|
-
*
|
|
1927
|
+
* Wrapped by View.wrapMethod to manage signature + resources.
|
|
2123
1928
|
*/
|
|
2124
1929
|
render() {
|
|
2125
1930
|
this.updater.digest();
|
|
@@ -2171,7 +1976,7 @@ var View = class _View {
|
|
|
2171
1976
|
if (!flag) {
|
|
2172
1977
|
setTimeout(
|
|
2173
1978
|
this.wrapAsync(() => {
|
|
2174
|
-
runInvokes(ownerFrame);
|
|
1979
|
+
_View.runInvokes(ownerFrame);
|
|
2175
1980
|
}),
|
|
2176
1981
|
0
|
|
2177
1982
|
);
|
|
@@ -2247,7 +2052,7 @@ var View = class _View {
|
|
|
2247
2052
|
capture(key, resource, destroyOnRender = false) {
|
|
2248
2053
|
const cache = this.resources;
|
|
2249
2054
|
if (resource) {
|
|
2250
|
-
destroyResource(cache, key, true, resource);
|
|
2055
|
+
_View.destroyResource(cache, key, true, resource);
|
|
2251
2056
|
cache[key] = {
|
|
2252
2057
|
entity: resource,
|
|
2253
2058
|
destroyOnRender
|
|
@@ -2263,7 +2068,7 @@ var View = class _View {
|
|
|
2263
2068
|
* If destroy=true, calls the resource's destroy() method.
|
|
2264
2069
|
*/
|
|
2265
2070
|
release(key, destroy = true) {
|
|
2266
|
-
return destroyResource(this.resources, key, destroy);
|
|
2071
|
+
return _View.destroyResource(this.resources, key, destroy);
|
|
2267
2072
|
}
|
|
2268
2073
|
// ============================================================
|
|
2269
2074
|
// Leave tip
|
|
@@ -2309,10 +2114,273 @@ var View = class _View {
|
|
|
2309
2114
|
});
|
|
2310
2115
|
}
|
|
2311
2116
|
// ============================================================
|
|
2312
|
-
// Static
|
|
2117
|
+
// Static public methods
|
|
2313
2118
|
// ============================================================
|
|
2314
2119
|
/** Collected ctors from mixins */
|
|
2315
2120
|
static ctors;
|
|
2121
|
+
/**
|
|
2122
|
+
* Prepare a View subclass by scanning its prototype for event method patterns.
|
|
2123
|
+
* Pattern: `$?name<eventType1,eventType2>(&modifiers)`
|
|
2124
|
+
*
|
|
2125
|
+
* Only runs once per View subclass (guarded by ctors marker).
|
|
2126
|
+
* Called from Frame.mountView before creating the view instance.
|
|
2127
|
+
*/
|
|
2128
|
+
static prepare(oView) {
|
|
2129
|
+
if (oView.ctors) {
|
|
2130
|
+
return oView.ctors;
|
|
2131
|
+
}
|
|
2132
|
+
const ctors = [];
|
|
2133
|
+
oView.ctors = ctors;
|
|
2134
|
+
const proto = oView.prototype;
|
|
2135
|
+
const eventsObject = {};
|
|
2136
|
+
const eventsList = [];
|
|
2137
|
+
const selectorObject = {};
|
|
2138
|
+
const mixins = proto["mixins"];
|
|
2139
|
+
if (mixins && Array.isArray(mixins)) {
|
|
2140
|
+
_View.mergeMixins(mixins, oView, ctors);
|
|
2141
|
+
}
|
|
2142
|
+
for (const p in proto) {
|
|
2143
|
+
if (!has(proto, p)) continue;
|
|
2144
|
+
const currentFn = proto[p];
|
|
2145
|
+
if (typeof currentFn !== "function") continue;
|
|
2146
|
+
const matches = p.match(VIEW_EVENT_METHOD_REGEXP);
|
|
2147
|
+
if (!matches) continue;
|
|
2148
|
+
const isSelector = matches[1];
|
|
2149
|
+
const selectorOrCallback = matches[2];
|
|
2150
|
+
const events = matches[3];
|
|
2151
|
+
const modifiers = matches[4];
|
|
2152
|
+
const mod = {};
|
|
2153
|
+
if (modifiers) {
|
|
2154
|
+
for (const item of modifiers.split(",")) {
|
|
2155
|
+
mod[item] = true;
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
const eventTypes = events.split(",");
|
|
2159
|
+
for (const item of eventTypes) {
|
|
2160
|
+
const globalNode = VIEW_GLOBALS[selectorOrCallback];
|
|
2161
|
+
let mask = 1;
|
|
2162
|
+
if (isSelector) {
|
|
2163
|
+
if (globalNode) {
|
|
2164
|
+
eventsList.push({
|
|
2165
|
+
handler: currentFn,
|
|
2166
|
+
element: globalNode,
|
|
2167
|
+
eventName: item,
|
|
2168
|
+
modifiers: mod
|
|
2169
|
+
});
|
|
2170
|
+
continue;
|
|
2171
|
+
}
|
|
2172
|
+
mask = 2;
|
|
2173
|
+
let selectorEntry = selectorObject[item];
|
|
2174
|
+
if (!selectorEntry) {
|
|
2175
|
+
selectorEntry = selectorObject[item] = {
|
|
2176
|
+
selectors: []
|
|
2177
|
+
};
|
|
2178
|
+
}
|
|
2179
|
+
if (!selectorEntry[selectorOrCallback]) {
|
|
2180
|
+
selectorEntry[selectorOrCallback] = 1;
|
|
2181
|
+
selectorEntry.selectors.push(selectorOrCallback);
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
eventsObject[item] = (eventsObject[item] || 0) | mask;
|
|
2185
|
+
const combinedKey = selectorOrCallback + SPLITTER + item;
|
|
2186
|
+
const existingFn = proto[combinedKey];
|
|
2187
|
+
if (!existingFn) {
|
|
2188
|
+
proto[combinedKey] = currentFn;
|
|
2189
|
+
} else {
|
|
2190
|
+
const mixinFn = currentFn;
|
|
2191
|
+
const existingMixin = existingFn;
|
|
2192
|
+
if (existingMixin.marker) {
|
|
2193
|
+
if (mixinFn.marker) {
|
|
2194
|
+
proto[combinedKey] = _View.processMixinsSameEvent(
|
|
2195
|
+
currentFn,
|
|
2196
|
+
existingFn
|
|
2197
|
+
);
|
|
2198
|
+
} else if (has(proto, p)) {
|
|
2199
|
+
proto[combinedKey] = currentFn;
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
_View.wrapMethod(proto, "render", "$renderWrap");
|
|
2206
|
+
proto["$evtObjMap"] = eventsObject;
|
|
2207
|
+
proto["$globalEvtList"] = eventsList;
|
|
2208
|
+
proto["$selMap"] = selectorObject;
|
|
2209
|
+
proto["$assignFn"] = proto["assign"];
|
|
2210
|
+
return ctors;
|
|
2211
|
+
}
|
|
2212
|
+
/**
|
|
2213
|
+
* Bind or unbind event delegation for a view instance.
|
|
2214
|
+
* Called from Frame during mount/unmount.
|
|
2215
|
+
*/
|
|
2216
|
+
static delegateEvents(view, destroy = false) {
|
|
2217
|
+
const eventsObject = view.eventObjectMap;
|
|
2218
|
+
const selectorObject = view.eventSelectorMap;
|
|
2219
|
+
const eventsList = view.globalEventList;
|
|
2220
|
+
for (const e in eventsObject) {
|
|
2221
|
+
if (has(eventsObject, e)) {
|
|
2222
|
+
if (destroy) {
|
|
2223
|
+
EventDelegator.unbind(e, !!selectorObject[e]);
|
|
2224
|
+
} else {
|
|
2225
|
+
EventDelegator.bind(e, !!selectorObject[e]);
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
for (const entry of eventsList) {
|
|
2230
|
+
if (destroy) {
|
|
2231
|
+
entry.element.removeEventListener(
|
|
2232
|
+
entry.eventName,
|
|
2233
|
+
entry.boundHandler
|
|
2234
|
+
);
|
|
2235
|
+
} else {
|
|
2236
|
+
const handler = entry.handler;
|
|
2237
|
+
const element = entry.element;
|
|
2238
|
+
const modifiers = entry.modifiers;
|
|
2239
|
+
entry.boundHandler = function(domEvent) {
|
|
2240
|
+
const extendedEvent = domEvent;
|
|
2241
|
+
extendedEvent.eventTarget = element;
|
|
2242
|
+
if (modifiers) {
|
|
2243
|
+
const kbEvent = domEvent;
|
|
2244
|
+
if (modifiers["ctrl"] && !kbEvent.ctrlKey || modifiers["shift"] && !kbEvent.shiftKey || modifiers["alt"] && !kbEvent.altKey || modifiers["meta"] && !kbEvent.metaKey) {
|
|
2245
|
+
return;
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
funcWithTry(handler, [domEvent], view, noop);
|
|
2249
|
+
};
|
|
2250
|
+
entry.element.addEventListener(
|
|
2251
|
+
entry.eventName,
|
|
2252
|
+
entry.boundHandler
|
|
2253
|
+
);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
/**
|
|
2258
|
+
* Destroy all resources managed by a view.
|
|
2259
|
+
* If lastly=true, destroy ALL resources; otherwise only destroyOnRender ones.
|
|
2260
|
+
*/
|
|
2261
|
+
static destroyAllResources(view, lastly) {
|
|
2262
|
+
const cache = view.resources;
|
|
2263
|
+
for (const p in cache) {
|
|
2264
|
+
if (has(cache, p)) {
|
|
2265
|
+
const entry = cache[p];
|
|
2266
|
+
if (lastly || entry.destroyOnRender) {
|
|
2267
|
+
_View.destroyResource(cache, p, true);
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
/**
|
|
2273
|
+
* Process deferred invoke calls on a frame.
|
|
2274
|
+
*/
|
|
2275
|
+
static runInvokes(frame) {
|
|
2276
|
+
const list = frame.invokeList;
|
|
2277
|
+
if (!list) return;
|
|
2278
|
+
while (list.length) {
|
|
2279
|
+
const entry = list.shift();
|
|
2280
|
+
if (entry && !entry.removed) {
|
|
2281
|
+
frame.invoke(entry.name, entry.args);
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
// ============================================================
|
|
2286
|
+
// Static private methods
|
|
2287
|
+
// ============================================================
|
|
2288
|
+
/**
|
|
2289
|
+
* Wrap a method on the prototype to add signature checking and resource cleanup.
|
|
2290
|
+
*/
|
|
2291
|
+
static wrapMethod(proto, fnName, shortKey) {
|
|
2292
|
+
const originalFn = proto[fnName];
|
|
2293
|
+
if (typeof originalFn !== "function") return;
|
|
2294
|
+
const wrapped = function(...args) {
|
|
2295
|
+
if (this.signature > 0) {
|
|
2296
|
+
this.signature++;
|
|
2297
|
+
this.fire("render");
|
|
2298
|
+
_View.destroyAllResources(this, false);
|
|
2299
|
+
const instanceFn = typeof this[fnName] === "function" ? this[fnName] : originalFn;
|
|
2300
|
+
const fnToCall = instanceFn === wrapped ? originalFn : instanceFn;
|
|
2301
|
+
return funcWithTry(fnToCall, args, this, noop);
|
|
2302
|
+
}
|
|
2303
|
+
return void 0;
|
|
2304
|
+
};
|
|
2305
|
+
proto[fnName] = wrapped;
|
|
2306
|
+
proto[shortKey] = wrapped;
|
|
2307
|
+
}
|
|
2308
|
+
/**
|
|
2309
|
+
* When two mixins define the same event method, merge them into
|
|
2310
|
+
* a single function that calls both in sequence.
|
|
2311
|
+
*/
|
|
2312
|
+
static processMixinsSameEvent(additional, exist) {
|
|
2313
|
+
let temp;
|
|
2314
|
+
const existMixin = exist;
|
|
2315
|
+
if (existMixin.handlerList) {
|
|
2316
|
+
temp = existMixin;
|
|
2317
|
+
} else {
|
|
2318
|
+
temp = function(...e) {
|
|
2319
|
+
funcWithTry(temp.handlerList ?? [], e, this, noop);
|
|
2320
|
+
};
|
|
2321
|
+
temp.handlerList = [exist];
|
|
2322
|
+
temp.marker = 1;
|
|
2323
|
+
}
|
|
2324
|
+
const additionalMixin = additional;
|
|
2325
|
+
temp.handlerList = (temp.handlerList ?? []).concat(
|
|
2326
|
+
additionalMixin.handlerList ?? [additional]
|
|
2327
|
+
);
|
|
2328
|
+
return temp;
|
|
2329
|
+
}
|
|
2330
|
+
/**
|
|
2331
|
+
* Merge an array of mixin objects into the view prototype.
|
|
2332
|
+
*/
|
|
2333
|
+
static mergeMixins(mixins, viewClass, ctors) {
|
|
2334
|
+
const proto = viewClass.prototype;
|
|
2335
|
+
const temp = {};
|
|
2336
|
+
for (const node of mixins) {
|
|
2337
|
+
for (const p in node) {
|
|
2338
|
+
if (!has(node, p)) continue;
|
|
2339
|
+
const fn = node[p];
|
|
2340
|
+
const exist = temp[p];
|
|
2341
|
+
if (p === "make") {
|
|
2342
|
+
ctors.push(fn);
|
|
2343
|
+
continue;
|
|
2344
|
+
}
|
|
2345
|
+
if (VIEW_EVENT_METHOD_REGEXP.test(p)) {
|
|
2346
|
+
if (exist) {
|
|
2347
|
+
temp[p] = _View.processMixinsSameEvent(fn, exist);
|
|
2348
|
+
} else {
|
|
2349
|
+
fn.marker = 1;
|
|
2350
|
+
temp[p] = fn;
|
|
2351
|
+
}
|
|
2352
|
+
} else {
|
|
2353
|
+
if (!exist) {
|
|
2354
|
+
temp[p] = fn;
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
for (const p in temp) {
|
|
2360
|
+
if (!has(proto, p)) {
|
|
2361
|
+
proto[p] = temp[p];
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
/**
|
|
2366
|
+
* Destroy a single resource entry.
|
|
2367
|
+
*/
|
|
2368
|
+
static destroyResource(cache, key, callDestroy, oldEntity) {
|
|
2369
|
+
const entry = cache[key];
|
|
2370
|
+
if (!entry || entry.entity === oldEntity) return void 0;
|
|
2371
|
+
const entity = entry.entity;
|
|
2372
|
+
if (entity && typeof entity === "object") {
|
|
2373
|
+
const destroyFn = entity["destroy"];
|
|
2374
|
+
if (typeof destroyFn === "function" && callDestroy) {
|
|
2375
|
+
funcWithTry(destroyFn, [], entity, noop);
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
Reflect.deleteProperty(cache, key);
|
|
2379
|
+
return entity;
|
|
2380
|
+
}
|
|
2381
|
+
// ============================================================
|
|
2382
|
+
// Static: extend and merge
|
|
2383
|
+
// ============================================================
|
|
2316
2384
|
/**
|
|
2317
2385
|
* Extend View to create a new View subclass.
|
|
2318
2386
|
*
|
|
@@ -2333,7 +2401,7 @@ var View = class _View {
|
|
|
2333
2401
|
constructor(nodeId, ownerFrame, initParams, node, mixinCtors) {
|
|
2334
2402
|
super(nodeId, ownerFrame, initParams, node, []);
|
|
2335
2403
|
for (const key in props) {
|
|
2336
|
-
if (has(props, key) && key !== "make") {
|
|
2404
|
+
if (has(props, key) && key !== "make" && key !== "render") {
|
|
2337
2405
|
this[key] = props[key];
|
|
2338
2406
|
}
|
|
2339
2407
|
}
|
|
@@ -2366,36 +2434,17 @@ var View = class _View {
|
|
|
2366
2434
|
}
|
|
2367
2435
|
}
|
|
2368
2436
|
}
|
|
2369
|
-
ChildView.merge = viewMerge;
|
|
2370
|
-
ChildView.extend = _View.extend;
|
|
2371
2437
|
return ChildView;
|
|
2372
2438
|
}
|
|
2373
2439
|
/**
|
|
2374
2440
|
* Merge mixins into View prototype.
|
|
2375
2441
|
*/
|
|
2376
2442
|
static merge(...mixins) {
|
|
2377
|
-
const
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
return self;
|
|
2443
|
+
const existingCtors = this.ctors || [];
|
|
2444
|
+
_View.mergeMixins(mixins, this, existingCtors);
|
|
2445
|
+
return this;
|
|
2381
2446
|
}
|
|
2382
2447
|
};
|
|
2383
|
-
function viewMerge(...mixins) {
|
|
2384
|
-
const self = this;
|
|
2385
|
-
const existingCtors = self.ctors || [];
|
|
2386
|
-
viewMergeMixins(mixins, self, existingCtors);
|
|
2387
|
-
return self;
|
|
2388
|
-
}
|
|
2389
|
-
function runInvokes(frame) {
|
|
2390
|
-
const list = frame.invokeList;
|
|
2391
|
-
if (!list) return;
|
|
2392
|
-
while (list.length) {
|
|
2393
|
-
const entry = list.shift();
|
|
2394
|
-
if (entry && !entry.removed) {
|
|
2395
|
-
frame.invoke(entry.name, entry.args);
|
|
2396
|
-
}
|
|
2397
|
-
}
|
|
2398
|
-
}
|
|
2399
2448
|
|
|
2400
2449
|
// src/frame.ts
|
|
2401
2450
|
var frameRegistry = /* @__PURE__ */ new Map();
|
|
@@ -2503,7 +2552,7 @@ var Frame = class _Frame extends EventEmitter {
|
|
|
2503
2552
|
*/
|
|
2504
2553
|
doMountView(ViewClass, params, node, sign) {
|
|
2505
2554
|
if (sign !== this.signature) return;
|
|
2506
|
-
const mixinCtors =
|
|
2555
|
+
const mixinCtors = View.prepare(ViewClass);
|
|
2507
2556
|
const ViewConstructor = ViewClass;
|
|
2508
2557
|
const view = new ViewConstructor(
|
|
2509
2558
|
this.id,
|
|
@@ -2514,7 +2563,7 @@ var Frame = class _Frame extends EventEmitter {
|
|
|
2514
2563
|
);
|
|
2515
2564
|
this.viewInstance = view;
|
|
2516
2565
|
view.signature = 1;
|
|
2517
|
-
|
|
2566
|
+
View.delegateEvents(view);
|
|
2518
2567
|
const initResult = funcWithTry(
|
|
2519
2568
|
view.init,
|
|
2520
2569
|
[params, { node, deep: !view.template }],
|
|
@@ -2525,13 +2574,10 @@ var Frame = class _Frame extends EventEmitter {
|
|
|
2525
2574
|
Promise.resolve(initResult).then(() => {
|
|
2526
2575
|
if (nextSign !== this.signature) return;
|
|
2527
2576
|
if (view.template) {
|
|
2528
|
-
|
|
2529
|
-
if (renderFn) {
|
|
2530
|
-
renderFn.call(view);
|
|
2531
|
-
}
|
|
2577
|
+
view.render();
|
|
2532
2578
|
} else {
|
|
2533
2579
|
this.hasAltered = 0;
|
|
2534
|
-
if (!view
|
|
2580
|
+
if (!view.endUpdatePendingFlag) {
|
|
2535
2581
|
view.endUpdate();
|
|
2536
2582
|
}
|
|
2537
2583
|
}
|
|
@@ -2718,7 +2764,7 @@ var Frame = class _Frame extends EventEmitter {
|
|
|
2718
2764
|
/** Get or create root frame */
|
|
2719
2765
|
static root(rootId) {
|
|
2720
2766
|
if (!rootFrame) {
|
|
2721
|
-
rootId = rootId || "
|
|
2767
|
+
rootId = rootId || "root";
|
|
2722
2768
|
let rootElement = document.getElementById(rootId);
|
|
2723
2769
|
if (!rootElement) {
|
|
2724
2770
|
rootElement = document.body;
|
|
@@ -2839,19 +2885,19 @@ function registerViewClass(viewPath, ViewClass) {
|
|
|
2839
2885
|
}
|
|
2840
2886
|
|
|
2841
2887
|
// src/service.ts
|
|
2842
|
-
var
|
|
2843
|
-
/**
|
|
2888
|
+
var Payload = class {
|
|
2889
|
+
/** Payload data */
|
|
2844
2890
|
data;
|
|
2845
2891
|
/** Internal cache info */
|
|
2846
2892
|
cacheInfo;
|
|
2847
2893
|
constructor(data = {}) {
|
|
2848
2894
|
this.data = data;
|
|
2849
2895
|
}
|
|
2850
|
-
/** Get a value from
|
|
2896
|
+
/** Get a value from payload data */
|
|
2851
2897
|
get(key) {
|
|
2852
2898
|
return this.data[key];
|
|
2853
2899
|
}
|
|
2854
|
-
/** Set a value in
|
|
2900
|
+
/** Set a value in payload data */
|
|
2855
2901
|
set(keyOrData, value) {
|
|
2856
2902
|
if (typeof keyOrData === "string") {
|
|
2857
2903
|
this.data[keyOrData] = value;
|
|
@@ -2863,287 +2909,366 @@ var Bag = class {
|
|
|
2863
2909
|
};
|
|
2864
2910
|
var FETCH_FLAGS_ALL = 1;
|
|
2865
2911
|
var FETCH_FLAGS_ONE = 2;
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2912
|
+
var Service = class {
|
|
2913
|
+
/** Service instance ID */
|
|
2914
|
+
id = "";
|
|
2915
|
+
/** Whether service is busy (1 = busy) */
|
|
2916
|
+
busy = 0;
|
|
2917
|
+
/** Whether service is destroyed (1 = destroyed) */
|
|
2918
|
+
destroyed = 0;
|
|
2919
|
+
/** Task queue for sequential operations */
|
|
2920
|
+
taskQueue = [];
|
|
2921
|
+
/** Previous dequeue arguments */
|
|
2922
|
+
prevArgs = [];
|
|
2923
|
+
/** Instance event emitter */
|
|
2924
|
+
_emitter = new EventEmitter();
|
|
2925
|
+
constructor() {
|
|
2926
|
+
this.id = generateId("service");
|
|
2927
|
+
}
|
|
2928
|
+
// ============================================================
|
|
2929
|
+
// Instance accessors for type-level data
|
|
2930
|
+
// ============================================================
|
|
2931
|
+
/** Instance event emitter (public accessor) */
|
|
2932
|
+
get emitter() {
|
|
2933
|
+
return this._emitter;
|
|
2934
|
+
}
|
|
2935
|
+
/**
|
|
2936
|
+
* Get internals object for serviceSend compatibility.
|
|
2937
|
+
* References per-type static state from the current class.
|
|
2938
|
+
*/
|
|
2939
|
+
get internals() {
|
|
2940
|
+
const ctor = this.constructor;
|
|
2941
|
+
return {
|
|
2942
|
+
metaList: ctor._metaList,
|
|
2943
|
+
payloadCache: ctor._payloadCache,
|
|
2944
|
+
pendingCacheKeys: ctor._pendingCacheKeys,
|
|
2945
|
+
syncFn: ctor._syncFn,
|
|
2946
|
+
staticEmitter: ctor._staticEmitter
|
|
2947
|
+
};
|
|
2948
|
+
}
|
|
2949
|
+
/**
|
|
2950
|
+
* Get type reference (the constructor) for serviceSend compatibility.
|
|
2951
|
+
* Static methods like get/create are accessible via the constructor.
|
|
2952
|
+
*/
|
|
2953
|
+
get type() {
|
|
2954
|
+
return this.constructor;
|
|
2955
|
+
}
|
|
2956
|
+
// ============================================================
|
|
2957
|
+
// Instance methods
|
|
2958
|
+
// ============================================================
|
|
2959
|
+
/**
|
|
2960
|
+
* Fetch all endpoints, callback when all complete.
|
|
2961
|
+
* Uses cache when available.
|
|
2962
|
+
*/
|
|
2963
|
+
all(attrs, done) {
|
|
2964
|
+
serviceSend(this, attrs, done, FETCH_FLAGS_ALL, false);
|
|
2965
|
+
return this;
|
|
2966
|
+
}
|
|
2967
|
+
/**
|
|
2968
|
+
* Fetch all endpoints, callback on each completion.
|
|
2969
|
+
*/
|
|
2970
|
+
one(attrs, done) {
|
|
2971
|
+
serviceSend(this, attrs, done, FETCH_FLAGS_ONE, false);
|
|
2972
|
+
return this;
|
|
2973
|
+
}
|
|
2974
|
+
/**
|
|
2975
|
+
* Fetch all endpoints, skip cache (always request).
|
|
2976
|
+
*/
|
|
2977
|
+
save(attrs, done) {
|
|
2978
|
+
serviceSend(this, attrs, done, FETCH_FLAGS_ALL, true);
|
|
2979
|
+
return this;
|
|
2980
|
+
}
|
|
2981
|
+
/**
|
|
2982
|
+
* Enqueue a task for sequential execution.
|
|
2983
|
+
*/
|
|
2984
|
+
enqueue(callback) {
|
|
2985
|
+
if (!this.destroyed) {
|
|
2986
|
+
this.taskQueue.push(callback);
|
|
2987
|
+
this.dequeue(...this.prevArgs);
|
|
2988
|
+
}
|
|
2989
|
+
return this;
|
|
2990
|
+
}
|
|
2991
|
+
/**
|
|
2992
|
+
* Dequeue and execute the next task in queue.
|
|
2993
|
+
*/
|
|
2994
|
+
dequeue(...args) {
|
|
2995
|
+
if (!this.busy && !this.destroyed) {
|
|
2996
|
+
this.busy = 1;
|
|
2997
|
+
setTimeout(() => {
|
|
2998
|
+
this.busy = 0;
|
|
2999
|
+
if (!this.destroyed) {
|
|
3000
|
+
const task2 = this.taskQueue.shift();
|
|
3001
|
+
if (task2) {
|
|
3002
|
+
this.prevArgs = args;
|
|
3003
|
+
funcWithTry(task2, args, this, noop);
|
|
2943
3004
|
}
|
|
2944
|
-
return cached;
|
|
2945
3005
|
}
|
|
3006
|
+
}, 0);
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
/**
|
|
3010
|
+
* Destroy the service instance.
|
|
3011
|
+
* After destruction, no new requests can be sent.
|
|
3012
|
+
*/
|
|
3013
|
+
destroy() {
|
|
3014
|
+
this.destroyed = 1;
|
|
3015
|
+
this.taskQueue = [];
|
|
3016
|
+
}
|
|
3017
|
+
// Instance event methods (delegate to instance emitter)
|
|
3018
|
+
on(event, handler) {
|
|
3019
|
+
this._emitter.on(event, handler);
|
|
3020
|
+
return this;
|
|
3021
|
+
}
|
|
3022
|
+
off(event, handler) {
|
|
3023
|
+
this._emitter.off(event, handler);
|
|
3024
|
+
return this;
|
|
3025
|
+
}
|
|
3026
|
+
fire(event, data) {
|
|
3027
|
+
this._emitter.fire(event, data);
|
|
3028
|
+
return this;
|
|
3029
|
+
}
|
|
3030
|
+
// ============================================================
|
|
3031
|
+
// Per-type static state
|
|
3032
|
+
// ============================================================
|
|
3033
|
+
/** Per-type metadata registry */
|
|
3034
|
+
static _metaList = {};
|
|
3035
|
+
/** Per-type payload cache (LFU with frequency eviction) */
|
|
3036
|
+
static _payloadCache = new Cache({
|
|
3037
|
+
maxSize: 20,
|
|
3038
|
+
bufferSize: 5
|
|
3039
|
+
});
|
|
3040
|
+
/** Per-type pending cache keys for deduplication */
|
|
3041
|
+
static _pendingCacheKeys = {};
|
|
3042
|
+
/** Per-type sync function */
|
|
3043
|
+
static _syncFn = noop;
|
|
3044
|
+
/** Per-type static event emitter */
|
|
3045
|
+
static _staticEmitter = new EventEmitter();
|
|
3046
|
+
/** Per-type cache max size */
|
|
3047
|
+
static _cacheMax = 20;
|
|
3048
|
+
/** Per-type cache buffer size */
|
|
3049
|
+
static _cacheBuffer = 5;
|
|
3050
|
+
// ============================================================
|
|
3051
|
+
// Static methods (operate on per-type state via `this`)
|
|
3052
|
+
// ============================================================
|
|
3053
|
+
/**
|
|
3054
|
+
* Register API endpoint metadata.
|
|
3055
|
+
*/
|
|
3056
|
+
static add(attrs) {
|
|
3057
|
+
if (!Array.isArray(attrs)) {
|
|
3058
|
+
attrs = [attrs];
|
|
3059
|
+
}
|
|
3060
|
+
for (const payload of attrs) {
|
|
3061
|
+
if (payload) {
|
|
3062
|
+
const name = payload.name;
|
|
3063
|
+
const cache = payload.cache;
|
|
3064
|
+
payload.cache = cache ? cache | 0 : 0;
|
|
3065
|
+
this._metaList[name] = payload;
|
|
2946
3066
|
}
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
/**
|
|
3070
|
+
* Get metadata for an API endpoint.
|
|
3071
|
+
*/
|
|
3072
|
+
static meta(attrs) {
|
|
3073
|
+
const name = typeof attrs === "string" ? attrs : attrs["name"];
|
|
3074
|
+
return this._metaList[name] || attrs;
|
|
3075
|
+
}
|
|
3076
|
+
/**
|
|
3077
|
+
* Create a Payload for an API request.
|
|
3078
|
+
*/
|
|
3079
|
+
static create(attrs) {
|
|
3080
|
+
const meta = this.meta(attrs);
|
|
3081
|
+
const cache = attrs["cache"] | 0 || meta.cache || 0;
|
|
3082
|
+
const entity = new Payload();
|
|
3083
|
+
entity.set(meta);
|
|
3084
|
+
entity.cacheInfo = {
|
|
3085
|
+
name: meta.name,
|
|
3086
|
+
after: meta.after,
|
|
3087
|
+
cleans: meta.cleanKeys,
|
|
3088
|
+
key: cache ? defaultCacheKey(meta, attrs) : "",
|
|
3089
|
+
time: 0
|
|
3090
|
+
};
|
|
3091
|
+
if (typeof attrs === "object" && attrs !== null) {
|
|
3092
|
+
entity.set(attrs);
|
|
3093
|
+
}
|
|
3094
|
+
const before = meta.before;
|
|
3095
|
+
if (before) {
|
|
3096
|
+
funcWithTry(before, [entity], entity, noop);
|
|
3097
|
+
}
|
|
3098
|
+
this._staticEmitter.fire("begin", { payload: entity });
|
|
3099
|
+
return entity;
|
|
3100
|
+
}
|
|
3101
|
+
/**
|
|
3102
|
+
* Get or create a Payload for an API request.
|
|
3103
|
+
*/
|
|
3104
|
+
static get(attrs, createNew) {
|
|
3105
|
+
let entity;
|
|
3106
|
+
let needsUpdate = false;
|
|
3107
|
+
if (!createNew) {
|
|
3108
|
+
entity = this.cached(attrs);
|
|
3109
|
+
}
|
|
3110
|
+
if (!entity) {
|
|
3111
|
+
entity = this.create(attrs);
|
|
3112
|
+
needsUpdate = true;
|
|
3113
|
+
}
|
|
3114
|
+
return { entity, needsUpdate };
|
|
3115
|
+
}
|
|
3116
|
+
/**
|
|
3117
|
+
* Get cached Payload if available and not expired.
|
|
3118
|
+
*/
|
|
3119
|
+
static cached(attrs) {
|
|
3120
|
+
const meta = this.meta(attrs);
|
|
3121
|
+
const cache = attrs["cache"] | 0 || meta.cache || 0;
|
|
3122
|
+
let cacheKey = "";
|
|
3123
|
+
if (cache) {
|
|
3124
|
+
cacheKey = defaultCacheKey(meta, attrs);
|
|
3125
|
+
}
|
|
3126
|
+
if (cacheKey) {
|
|
3127
|
+
const info = this._pendingCacheKeys[cacheKey];
|
|
3128
|
+
if (info) {
|
|
3129
|
+
return info.entity;
|
|
2954
3130
|
}
|
|
2955
|
-
const
|
|
2956
|
-
|
|
2957
|
-
if (
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
}
|
|
3131
|
+
const cached = this._payloadCache.get(cacheKey);
|
|
3132
|
+
if (cached && cached.cacheInfo) {
|
|
3133
|
+
if (now() - cached.cacheInfo.time > cache) {
|
|
3134
|
+
this._payloadCache.del(cacheKey);
|
|
3135
|
+
return void 0;
|
|
2961
3136
|
}
|
|
2962
|
-
|
|
2963
|
-
for (const key of keysToDelete) {
|
|
2964
|
-
bagCache.del(key);
|
|
3137
|
+
return cached;
|
|
2965
3138
|
}
|
|
2966
|
-
},
|
|
2967
|
-
on(event, handler) {
|
|
2968
|
-
staticEmitter2.on(event, handler);
|
|
2969
|
-
},
|
|
2970
|
-
off(event, handler) {
|
|
2971
|
-
staticEmitter2.off(event, handler);
|
|
2972
|
-
},
|
|
2973
|
-
fire(event, data) {
|
|
2974
|
-
staticEmitter2.fire(event, data);
|
|
2975
|
-
},
|
|
2976
|
-
extend(newSyncFn, newCacheMax, newCacheBuffer) {
|
|
2977
|
-
return createServiceType(
|
|
2978
|
-
newSyncFn,
|
|
2979
|
-
newCacheMax || cacheMax,
|
|
2980
|
-
newCacheBuffer || cacheBuffer
|
|
2981
|
-
);
|
|
2982
3139
|
}
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
this
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
}
|
|
3001
|
-
ServiceInstance.prototype = {
|
|
3002
|
-
all(attrs, done) {
|
|
3003
|
-
serviceSend(this, attrs, done, FETCH_FLAGS_ALL, false);
|
|
3004
|
-
return this;
|
|
3005
|
-
},
|
|
3006
|
-
one(attrs, done) {
|
|
3007
|
-
serviceSend(this, attrs, done, FETCH_FLAGS_ONE, false);
|
|
3008
|
-
return this;
|
|
3009
|
-
},
|
|
3010
|
-
save(attrs, done) {
|
|
3011
|
-
serviceSend(this, attrs, done, FETCH_FLAGS_ALL, true);
|
|
3012
|
-
return this;
|
|
3013
|
-
},
|
|
3014
|
-
enqueue(callback) {
|
|
3015
|
-
if (!this["$d"]) {
|
|
3016
|
-
this["$g"].push(callback);
|
|
3017
|
-
this.dequeue(...this["$h"]);
|
|
3018
|
-
}
|
|
3019
|
-
return this;
|
|
3020
|
-
},
|
|
3021
|
-
dequeue(...args) {
|
|
3022
|
-
if (!this["$e"] && !this["$d"]) {
|
|
3023
|
-
this["$e"] = 1;
|
|
3024
|
-
setTimeout(() => {
|
|
3025
|
-
this["$e"] = 0;
|
|
3026
|
-
if (!this["$d"]) {
|
|
3027
|
-
const task2 = this["$g"].shift();
|
|
3028
|
-
if (task2) {
|
|
3029
|
-
this["$h"] = args;
|
|
3030
|
-
funcWithTry(task2, args, this, noop);
|
|
3031
|
-
}
|
|
3032
|
-
}
|
|
3033
|
-
}, 0);
|
|
3140
|
+
return void 0;
|
|
3141
|
+
}
|
|
3142
|
+
/**
|
|
3143
|
+
* Clear cached payloads by endpoint name.
|
|
3144
|
+
*/
|
|
3145
|
+
static clear(names) {
|
|
3146
|
+
const nameList = (typeof names === "string" ? names : names.join(",")).split(",");
|
|
3147
|
+
const nameSet = {};
|
|
3148
|
+
for (const n of nameList) {
|
|
3149
|
+
nameSet[n] = 1;
|
|
3150
|
+
}
|
|
3151
|
+
const keysToDelete = [];
|
|
3152
|
+
this._payloadCache.forEach((payload) => {
|
|
3153
|
+
if (payload?.cacheInfo && nameSet[payload.cacheInfo.name]) {
|
|
3154
|
+
if (payload.cacheInfo.key) {
|
|
3155
|
+
keysToDelete.push(payload.cacheInfo.key);
|
|
3156
|
+
}
|
|
3034
3157
|
}
|
|
3035
|
-
}
|
|
3036
|
-
|
|
3037
|
-
this
|
|
3038
|
-
this["$g"] = [];
|
|
3039
|
-
},
|
|
3040
|
-
on(event, handler) {
|
|
3041
|
-
this._emitter.on(event, handler);
|
|
3042
|
-
return this;
|
|
3043
|
-
},
|
|
3044
|
-
off(event, handler) {
|
|
3045
|
-
this._emitter.off(event, handler);
|
|
3046
|
-
return this;
|
|
3047
|
-
},
|
|
3048
|
-
fire(event, data) {
|
|
3049
|
-
this._emitter.fire(event, data);
|
|
3050
|
-
return this;
|
|
3158
|
+
});
|
|
3159
|
+
for (const key of keysToDelete) {
|
|
3160
|
+
this._payloadCache.del(key);
|
|
3051
3161
|
}
|
|
3052
|
-
}
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
}
|
|
3072
|
-
|
|
3162
|
+
}
|
|
3163
|
+
// Static event methods (operate on per-type emitter)
|
|
3164
|
+
static on(event, handler) {
|
|
3165
|
+
this._staticEmitter.on(event, handler);
|
|
3166
|
+
}
|
|
3167
|
+
static off(event, handler) {
|
|
3168
|
+
this._staticEmitter.off(event, handler);
|
|
3169
|
+
}
|
|
3170
|
+
static fire(event, data) {
|
|
3171
|
+
this._staticEmitter.fire(event, data);
|
|
3172
|
+
}
|
|
3173
|
+
/**
|
|
3174
|
+
* Create a new Service subclass with a custom sync function.
|
|
3175
|
+
* Each subclass gets its own per-type state (metaList, cache, etc.)
|
|
3176
|
+
* to ensure isolation between different Service types.
|
|
3177
|
+
*/
|
|
3178
|
+
static extend(newSyncFn, newCacheMax, newCacheBuffer) {
|
|
3179
|
+
const ParentService = this;
|
|
3180
|
+
class ChildService extends ParentService {
|
|
3181
|
+
static _metaList = {};
|
|
3182
|
+
static _payloadCache = new Cache({
|
|
3183
|
+
maxSize: newCacheMax || ParentService._cacheMax,
|
|
3184
|
+
bufferSize: newCacheBuffer || ParentService._cacheBuffer
|
|
3185
|
+
});
|
|
3186
|
+
static _pendingCacheKeys = {};
|
|
3187
|
+
static _syncFn = newSyncFn;
|
|
3188
|
+
static _staticEmitter = new EventEmitter();
|
|
3189
|
+
static _cacheMax = newCacheMax || ParentService._cacheMax;
|
|
3190
|
+
static _cacheBuffer = newCacheBuffer || ParentService._cacheBuffer;
|
|
3191
|
+
}
|
|
3192
|
+
return ChildService;
|
|
3193
|
+
}
|
|
3194
|
+
};
|
|
3073
3195
|
function defaultCacheKey(meta, attrs) {
|
|
3074
3196
|
return JSON.stringify(attrs) + SPLITTER + JSON.stringify(meta);
|
|
3075
3197
|
}
|
|
3076
3198
|
function serviceSend(service, attrs, done, flag, save) {
|
|
3077
|
-
if (service["
|
|
3078
|
-
if (service["
|
|
3199
|
+
if (service["destroyed"]) return;
|
|
3200
|
+
if (service["busy"]) {
|
|
3079
3201
|
service.enqueue(
|
|
3080
3202
|
serviceSend.bind(null, service, attrs, done, flag, save)
|
|
3081
3203
|
);
|
|
3082
3204
|
return;
|
|
3083
3205
|
}
|
|
3084
|
-
service["
|
|
3206
|
+
service["busy"] = 1;
|
|
3085
3207
|
let attrList;
|
|
3086
3208
|
if (typeof attrs === "string") {
|
|
3087
3209
|
attrList = [{ name: attrs }];
|
|
3088
|
-
} else if (isArray(attrs)) {
|
|
3210
|
+
} else if (Array.isArray(attrs)) {
|
|
3089
3211
|
attrList = attrs;
|
|
3090
3212
|
} else {
|
|
3091
3213
|
attrList = [attrs];
|
|
3092
3214
|
}
|
|
3093
|
-
const internals = service.
|
|
3215
|
+
const internals = service.internals;
|
|
3094
3216
|
const { syncFn, pendingCacheKeys, staticEmitter: staticEmitter2 } = internals;
|
|
3095
3217
|
let requestCount = 0;
|
|
3096
3218
|
const total = attrList.length;
|
|
3097
3219
|
const doneArr = new Array(total + 1);
|
|
3098
3220
|
const errorArgs = [];
|
|
3099
3221
|
const remoteComplete = (idx, error) => {
|
|
3100
|
-
const
|
|
3101
|
-
let
|
|
3222
|
+
const payload = doneArr[idx + 1];
|
|
3223
|
+
let newPayload = false;
|
|
3102
3224
|
if (error) {
|
|
3103
3225
|
errorArgs[idx] = error;
|
|
3104
|
-
staticEmitter2.fire("fail", {
|
|
3226
|
+
staticEmitter2.fire("fail", { payload, error });
|
|
3105
3227
|
} else {
|
|
3106
|
-
|
|
3107
|
-
staticEmitter2.fire("done", {
|
|
3228
|
+
newPayload = true;
|
|
3229
|
+
staticEmitter2.fire("done", { payload });
|
|
3108
3230
|
}
|
|
3109
|
-
if (!service["
|
|
3231
|
+
if (!service["destroyed"]) {
|
|
3110
3232
|
const finish = requestCount === total;
|
|
3111
3233
|
if (finish) {
|
|
3112
|
-
service["
|
|
3234
|
+
service["busy"] = 0;
|
|
3113
3235
|
if (flag === FETCH_FLAGS_ALL) {
|
|
3114
3236
|
doneArr[0] = errorArgs;
|
|
3115
3237
|
funcWithTry(done, doneArr, service, noop);
|
|
3116
3238
|
}
|
|
3117
3239
|
}
|
|
3118
3240
|
if (flag === FETCH_FLAGS_ONE) {
|
|
3119
|
-
funcWithTry(done, [error || null,
|
|
3241
|
+
funcWithTry(done, [error || null, payload, finish, idx], service, noop);
|
|
3120
3242
|
}
|
|
3121
3243
|
}
|
|
3122
|
-
if (
|
|
3123
|
-
staticEmitter2.fire("end", {
|
|
3244
|
+
if (newPayload) {
|
|
3245
|
+
staticEmitter2.fire("end", { payload, error });
|
|
3124
3246
|
}
|
|
3125
3247
|
};
|
|
3126
3248
|
for (const attr of attrList) {
|
|
3127
3249
|
if (!attr) continue;
|
|
3128
3250
|
const attrObj = typeof attr === "string" ? { name: attr } : attr;
|
|
3129
|
-
const
|
|
3130
|
-
|
|
3131
|
-
|
|
3251
|
+
const payloadInfo = service.type.get(
|
|
3252
|
+
attrObj,
|
|
3253
|
+
save
|
|
3254
|
+
);
|
|
3255
|
+
const payloadEntity = payloadInfo.entity;
|
|
3256
|
+
const cacheKey = payloadEntity.cacheInfo?.key || "";
|
|
3132
3257
|
const complete = remoteComplete.bind(null, requestCount++);
|
|
3133
3258
|
if (cacheKey && pendingCacheKeys[cacheKey]) {
|
|
3134
3259
|
pendingCacheKeys[cacheKey].push(complete);
|
|
3135
|
-
} else if (
|
|
3260
|
+
} else if (payloadInfo.needsUpdate) {
|
|
3136
3261
|
if (cacheKey) {
|
|
3137
3262
|
const cacheList = [complete];
|
|
3138
|
-
cacheList.
|
|
3263
|
+
cacheList.entity = payloadEntity;
|
|
3139
3264
|
pendingCacheKeys[cacheKey] = cacheList;
|
|
3140
3265
|
const cacheComplete = () => {
|
|
3141
3266
|
const list = pendingCacheKeys[cacheKey];
|
|
3142
|
-
const entity = list.
|
|
3267
|
+
const entity = list.entity;
|
|
3143
3268
|
if (entity.cacheInfo) {
|
|
3144
3269
|
entity.cacheInfo.time = now();
|
|
3145
3270
|
}
|
|
3146
|
-
internals.
|
|
3271
|
+
internals.payloadCache.set(cacheKey, entity);
|
|
3147
3272
|
Reflect.deleteProperty(pendingCacheKeys, cacheKey);
|
|
3148
3273
|
for (const cb of list) {
|
|
3149
3274
|
if (typeof cb === "function") {
|
|
@@ -3151,9 +3276,9 @@ function serviceSend(service, attrs, done, flag, save) {
|
|
|
3151
3276
|
}
|
|
3152
3277
|
}
|
|
3153
3278
|
};
|
|
3154
|
-
syncFn(
|
|
3279
|
+
syncFn(payloadEntity, cacheComplete);
|
|
3155
3280
|
} else {
|
|
3156
|
-
syncFn(
|
|
3281
|
+
syncFn(payloadEntity, complete);
|
|
3157
3282
|
}
|
|
3158
3283
|
} else {
|
|
3159
3284
|
complete();
|
|
@@ -3161,12 +3286,12 @@ function serviceSend(service, attrs, done, flag, save) {
|
|
|
3161
3286
|
}
|
|
3162
3287
|
}
|
|
3163
3288
|
|
|
3164
|
-
// src/frame-visualizer
|
|
3165
|
-
var MSG_PING = "
|
|
3166
|
-
var MSG_PONG = "
|
|
3167
|
-
var MSG_REQUEST_TREE = "
|
|
3168
|
-
var MSG_TREE = "
|
|
3169
|
-
var MSG_TREE_DELTA = "
|
|
3289
|
+
// src/frame-visualizer.ts
|
|
3290
|
+
var MSG_PING = "LARK_VISUALIZER_PING";
|
|
3291
|
+
var MSG_PONG = "LARK_VISUALIZER_PONG";
|
|
3292
|
+
var MSG_REQUEST_TREE = "LARK_VISUALIZER_REQUEST_TREE";
|
|
3293
|
+
var MSG_TREE = "LARK_VISUALIZER_TREE";
|
|
3294
|
+
var MSG_TREE_DELTA = "LARK_VISUALIZER_TREE_DELTA";
|
|
3170
3295
|
function serializeView(view) {
|
|
3171
3296
|
return {
|
|
3172
3297
|
id: view.id,
|
|
@@ -3271,7 +3396,7 @@ function pushTreeUpdate() {
|
|
|
3271
3396
|
|
|
3272
3397
|
// src/framework.ts
|
|
3273
3398
|
var config = {
|
|
3274
|
-
rootId: "
|
|
3399
|
+
rootId: "root",
|
|
3275
3400
|
hashbang: "#!",
|
|
3276
3401
|
error: (error) => {
|
|
3277
3402
|
throw error;
|
|
@@ -3364,7 +3489,12 @@ function dispatcherUpdate(frame, stateKeys) {
|
|
|
3364
3489
|
const isChanged = stateKeys ? stateIsObserveChanged(view, stateKeys) : viewIsObserveChanged(view);
|
|
3365
3490
|
let renderPromise;
|
|
3366
3491
|
if (isChanged) {
|
|
3367
|
-
const renderResult = funcWithTry(
|
|
3492
|
+
const renderResult = funcWithTry(
|
|
3493
|
+
view.renderMethod ?? view.render,
|
|
3494
|
+
[],
|
|
3495
|
+
view,
|
|
3496
|
+
noop
|
|
3497
|
+
);
|
|
3368
3498
|
if (renderResult && typeof renderResult.then === "function") {
|
|
3369
3499
|
renderPromise = renderResult;
|
|
3370
3500
|
}
|
|
@@ -3386,13 +3516,13 @@ function dispatcherUpdate(frame, stateKeys) {
|
|
|
3386
3516
|
}
|
|
3387
3517
|
function dispatcherNotifyChange(e) {
|
|
3388
3518
|
const rootFrame2 = Frame.root();
|
|
3389
|
-
const view = e
|
|
3519
|
+
const view = e.view;
|
|
3390
3520
|
if (view) {
|
|
3391
3521
|
const viewPath = typeof view === "object" && view !== null ? String(view.to || "") : String(view);
|
|
3392
3522
|
rootFrame2.mountView(viewPath);
|
|
3393
3523
|
} else {
|
|
3394
3524
|
dispatcherUpdateTag++;
|
|
3395
|
-
dispatcherUpdate(rootFrame2, e
|
|
3525
|
+
dispatcherUpdate(rootFrame2, e.keys);
|
|
3396
3526
|
}
|
|
3397
3527
|
}
|
|
3398
3528
|
function dispatchEvent(target, eventType, eventInit) {
|
|
@@ -3403,8 +3533,6 @@ function dispatchEvent(target, eventType, eventInit) {
|
|
|
3403
3533
|
});
|
|
3404
3534
|
target.dispatchEvent(event);
|
|
3405
3535
|
}
|
|
3406
|
-
var Base = class extends EventEmitter {
|
|
3407
|
-
};
|
|
3408
3536
|
function use(names, callback) {
|
|
3409
3537
|
if (!config.require) {
|
|
3410
3538
|
if (callback) callback();
|
|
@@ -3419,7 +3547,7 @@ function use(names, callback) {
|
|
|
3419
3547
|
}
|
|
3420
3548
|
}
|
|
3421
3549
|
var WAIT_OK = 1;
|
|
3422
|
-
var
|
|
3550
|
+
var WAIT_TIMEOUT_OR_NOT_FOUND = 0;
|
|
3423
3551
|
function waitZoneViewsRendered(viewId, timeout) {
|
|
3424
3552
|
if (timeout == null) {
|
|
3425
3553
|
timeout = 30 * 1e3;
|
|
@@ -3430,7 +3558,7 @@ function waitZoneViewsRendered(viewId, timeout) {
|
|
|
3430
3558
|
const check = () => {
|
|
3431
3559
|
const currentTime = now();
|
|
3432
3560
|
if (currentTime > endTime || !checkFrame) {
|
|
3433
|
-
resolve(
|
|
3561
|
+
resolve(WAIT_TIMEOUT_OR_NOT_FOUND);
|
|
3434
3562
|
} else if (checkFrame.childrenCount === checkFrame.readyCount) {
|
|
3435
3563
|
resolve(WAIT_OK);
|
|
3436
3564
|
} else {
|
|
@@ -3467,10 +3595,10 @@ var Framework = {
|
|
|
3467
3595
|
Router._setConfig(config);
|
|
3468
3596
|
EventDelegator.setFrameGetter((id) => Frame.get(id));
|
|
3469
3597
|
Router.on(ROUTER_EVENTS.CHANGED, (data) => {
|
|
3470
|
-
dispatcherNotifyChange(data);
|
|
3598
|
+
if (data) dispatcherNotifyChange(data);
|
|
3471
3599
|
});
|
|
3472
3600
|
State.on(ROUTER_EVENTS.CHANGED, (data) => {
|
|
3473
|
-
dispatcherNotifyChange(data);
|
|
3601
|
+
if (data) dispatcherNotifyChange(data);
|
|
3474
3602
|
});
|
|
3475
3603
|
booted3 = true;
|
|
3476
3604
|
markBooted();
|
|
@@ -3507,7 +3635,7 @@ var Framework = {
|
|
|
3507
3635
|
/** Wait for zone views to be rendered */
|
|
3508
3636
|
waitZoneViewsRendered,
|
|
3509
3637
|
WAIT_OK,
|
|
3510
|
-
|
|
3638
|
+
WAIT_TIMEOUT_OR_NOT_FOUND,
|
|
3511
3639
|
/**
|
|
3512
3640
|
* Convert array to hash map.
|
|
3513
3641
|
*/
|
|
@@ -3572,7 +3700,7 @@ var Framework = {
|
|
|
3572
3700
|
/**
|
|
3573
3701
|
* Base class with EventEmitter.
|
|
3574
3702
|
*/
|
|
3575
|
-
Base,
|
|
3703
|
+
Base: EventEmitter,
|
|
3576
3704
|
// ============================================================
|
|
3577
3705
|
// Module access
|
|
3578
3706
|
// ============================================================
|
|
@@ -3590,10 +3718,11 @@ if (typeof window !== "undefined") {
|
|
|
3590
3718
|
window.__lark_State = State;
|
|
3591
3719
|
window.__lark_Router = Router;
|
|
3592
3720
|
window.__lark_Frame = Frame;
|
|
3721
|
+
window.__lark_View = View;
|
|
3593
3722
|
}
|
|
3594
3723
|
|
|
3595
3724
|
// src/store.ts
|
|
3596
|
-
var LARK_GLOBAL = "
|
|
3725
|
+
var LARK_GLOBAL = "lark-global";
|
|
3597
3726
|
var Platform = /* @__PURE__ */ ((Platform2) => {
|
|
3598
3727
|
Platform2["Lark"] = "lark";
|
|
3599
3728
|
Platform2["React"] = "react";
|
|
@@ -3636,8 +3765,10 @@ var Queue = class {
|
|
|
3636
3765
|
const flushTickTask = () => {
|
|
3637
3766
|
while (queue.length > 0) {
|
|
3638
3767
|
const task2 = queue.shift();
|
|
3639
|
-
|
|
3640
|
-
|
|
3768
|
+
if (task2) {
|
|
3769
|
+
pendingTasks.delete(task2);
|
|
3770
|
+
runTask(task2);
|
|
3771
|
+
}
|
|
3641
3772
|
}
|
|
3642
3773
|
};
|
|
3643
3774
|
Promise.resolve().then(flushTickTask);
|
|
@@ -3736,9 +3867,11 @@ var setStateConfig = (target, config2) => {
|
|
|
3736
3867
|
if (target && isObject(config2)) StateConfigMap.set(target, config2);
|
|
3737
3868
|
};
|
|
3738
3869
|
var getStateConfig = (target, key) => {
|
|
3739
|
-
if (!StateConfigMap.has(target))
|
|
3870
|
+
if (!StateConfigMap.has(target)) {
|
|
3871
|
+
return void 0;
|
|
3872
|
+
}
|
|
3740
3873
|
const config2 = StateConfigMap.get(target);
|
|
3741
|
-
return key ? config2[key] : config2;
|
|
3874
|
+
return key ? config2?.[key] : config2;
|
|
3742
3875
|
};
|
|
3743
3876
|
var isState = (target) => isObject(target) && StateConfigMap.has(target);
|
|
3744
3877
|
var createLinkKeys = (target, property) => {
|
|
@@ -4305,14 +4438,11 @@ function defineStore(name, creator, config2) {
|
|
|
4305
4438
|
const useStore = adapter.useStore;
|
|
4306
4439
|
const store = new StoreClass(name, config2);
|
|
4307
4440
|
store[_storeCreate](
|
|
4308
|
-
creator(
|
|
4309
|
-
store[_innerStore](),
|
|
4310
|
-
extendApis
|
|
4311
|
-
)
|
|
4441
|
+
creator(store[_innerStore](), extendApis)
|
|
4312
4442
|
);
|
|
4313
4443
|
Object.defineProperties(useStore, {
|
|
4314
4444
|
$storeName: { value: name, configurable: true },
|
|
4315
|
-
$
|
|
4445
|
+
$destroyFn: { value: () => store[_storeDestroy](), configurable: true }
|
|
4316
4446
|
});
|
|
4317
4447
|
if (!StoreCache.has(name)) {
|
|
4318
4448
|
StoreCache.set(name, { store, creator, config: config2, useStore });
|
|
@@ -4377,7 +4507,7 @@ function observeCell(state, cb, immediate = true) {
|
|
|
4377
4507
|
}
|
|
4378
4508
|
function multi(useStore) {
|
|
4379
4509
|
const storeName = useStore["$storeName"];
|
|
4380
|
-
const flagSym = `
|
|
4510
|
+
const flagSym = `lark-comp-${storeName}`;
|
|
4381
4511
|
const map = /* @__PURE__ */ new Map();
|
|
4382
4512
|
let rootViewPath;
|
|
4383
4513
|
const getFlag = (viewContext) => {
|
|
@@ -4386,7 +4516,7 @@ function multi(useStore) {
|
|
|
4386
4516
|
const viewId = owner?.["id"] || "";
|
|
4387
4517
|
let flag;
|
|
4388
4518
|
if (viewPath === rootViewPath) {
|
|
4389
|
-
flag = `${flagSym}
|
|
4519
|
+
flag = `${flagSym}-${viewId}`;
|
|
4390
4520
|
} else {
|
|
4391
4521
|
flag = owner?.["viewInitParams"]?.[flagSym];
|
|
4392
4522
|
}
|
|
@@ -4403,14 +4533,13 @@ function multi(useStore) {
|
|
|
4403
4533
|
};
|
|
4404
4534
|
const useFn = ((view) => {
|
|
4405
4535
|
if (!view)
|
|
4406
|
-
throw new Error(
|
|
4536
|
+
throw new Error(
|
|
4537
|
+
"[@lark.js/mvc error] multi: cannot find the view instance"
|
|
4538
|
+
);
|
|
4407
4539
|
const viewCtx = view;
|
|
4408
4540
|
const flag = viewCtx[flagSym];
|
|
4409
4541
|
if (map.has(flag)) return map.get(flag);
|
|
4410
|
-
const newFn = cloneStore(
|
|
4411
|
-
flag,
|
|
4412
|
-
useStore
|
|
4413
|
-
);
|
|
4542
|
+
const newFn = cloneStore(flag, useStore);
|
|
4414
4543
|
map.set(flag, newFn);
|
|
4415
4544
|
return useFn(view);
|
|
4416
4545
|
});
|
|
@@ -4548,7 +4677,7 @@ function convertArtSyntax(source, debug) {
|
|
|
4548
4677
|
}
|
|
4549
4678
|
if (blockStack.length > 0) {
|
|
4550
4679
|
const unclosed = blockStack.map((b) => `"${b.ctrl}" at line ${b.line}`).join(", ");
|
|
4551
|
-
throw new Error(`[@lark/mvc error] unclosed block(s): ${unclosed}`);
|
|
4680
|
+
throw new Error(`[@lark.js/mvc error] unclosed block(s): ${unclosed}`);
|
|
4552
4681
|
}
|
|
4553
4682
|
return result.join("");
|
|
4554
4683
|
}
|
|
@@ -4642,12 +4771,12 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
|
|
|
4642
4771
|
}
|
|
4643
4772
|
return `${debugPrefix}<%}else{%>`;
|
|
4644
4773
|
}
|
|
4645
|
-
case "
|
|
4646
|
-
blockStack.push({ ctrl: "
|
|
4774
|
+
case "forOf": {
|
|
4775
|
+
blockStack.push({ ctrl: "forOf", line: lineNo });
|
|
4647
4776
|
const object = tokens[0];
|
|
4648
4777
|
if (tokens.length > 1 && tokens[1] !== "as") {
|
|
4649
4778
|
throw new Error(
|
|
4650
|
-
`[@lark/mvc error] bad
|
|
4779
|
+
`[@lark.js/mvc error] bad forOf syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{forOf list as item [index]}}`
|
|
4651
4780
|
);
|
|
4652
4781
|
}
|
|
4653
4782
|
const restTokens = tokens.slice(2);
|
|
@@ -4669,12 +4798,12 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
|
|
|
4669
4798
|
}
|
|
4670
4799
|
return `${debugPrefix}<%for(let ${index}=0${refExpr},${refObjCount}=${refObj}.length${lastCount};${index}<${refObjCount};${index}++){${firstAndLast}${valueDecl}%>`;
|
|
4671
4800
|
}
|
|
4672
|
-
case "
|
|
4673
|
-
blockStack.push({ ctrl: "
|
|
4801
|
+
case "forIn": {
|
|
4802
|
+
blockStack.push({ ctrl: "forIn", line: lineNo });
|
|
4674
4803
|
const object = tokens[0];
|
|
4675
4804
|
if (tokens.length > 1 && tokens[1] !== "as") {
|
|
4676
4805
|
throw new Error(
|
|
4677
|
-
`[@lark/mvc error] bad
|
|
4806
|
+
`[@lark.js/mvc error] bad forIn syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{for-in obj as val [key]}}`
|
|
4678
4807
|
);
|
|
4679
4808
|
}
|
|
4680
4809
|
const restTokens2 = tokens.slice(2);
|
|
@@ -4694,19 +4823,19 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
|
|
|
4694
4823
|
case "set":
|
|
4695
4824
|
return `${debugPrefix}<%let ${tokens.join(" ")};%>`;
|
|
4696
4825
|
case "/if":
|
|
4697
|
-
case "/
|
|
4698
|
-
case "/
|
|
4826
|
+
case "/forOf":
|
|
4827
|
+
case "/forIn":
|
|
4699
4828
|
case "/for": {
|
|
4700
4829
|
const expectedCtrl = keyword.substring(1);
|
|
4701
4830
|
const last = blockStack.pop();
|
|
4702
4831
|
if (!last) {
|
|
4703
4832
|
throw new Error(
|
|
4704
|
-
`[@lark/mvc error] unexpected {{${code}}}: no matching open block`
|
|
4833
|
+
`[@lark.js/mvc error] unexpected {{${code}}}: no matching open block`
|
|
4705
4834
|
);
|
|
4706
4835
|
}
|
|
4707
4836
|
if (last.ctrl !== expectedCtrl) {
|
|
4708
4837
|
throw new Error(
|
|
4709
|
-
`[@lark/mvc error] unexpected {{${code}}}: expected {{/${last.ctrl}}} to close block opened at line ${last.line}`
|
|
4838
|
+
`[@lark.js/mvc error] unexpected {{${code}}}: expected {{/${last.ctrl}}} to close block opened at line ${last.line}`
|
|
4710
4839
|
);
|
|
4711
4840
|
}
|
|
4712
4841
|
return `${debugPrefix}<%}%>`;
|
|
@@ -4770,7 +4899,7 @@ function parseAsExpr(expr) {
|
|
|
4770
4899
|
function compileToFunction(source, debug, file) {
|
|
4771
4900
|
const matcher = /<%([@=!:])?([\s\S]*?)%>|$/g;
|
|
4772
4901
|
let index = 0;
|
|
4773
|
-
let funcSource = `$
|
|
4902
|
+
let funcSource = `$out+='`;
|
|
4774
4903
|
let hasAtRule = false;
|
|
4775
4904
|
const escapeSlashRegExp = /\\|'/g;
|
|
4776
4905
|
const escapeBreakReturnRegExp = /\r|\n/g;
|
|
@@ -4796,17 +4925,17 @@ function compileToFunction(source, debug, file) {
|
|
|
4796
4925
|
}
|
|
4797
4926
|
if (operate === "@") {
|
|
4798
4927
|
hasAtRule = true;
|
|
4799
|
-
funcSource += `'+($
|
|
4928
|
+
funcSource += `'+($dbgExpr='<%${operate + expr}%>',$refFn($refAlt,${content}))+'`;
|
|
4800
4929
|
} else if (operate === "=" || operate === ":") {
|
|
4801
|
-
funcSource += `'+($
|
|
4930
|
+
funcSource += `'+($dbgExpr='<%${operate + expr}%>',$encHtml(${content}))+'`;
|
|
4802
4931
|
} else if (operate === "!") {
|
|
4803
|
-
if (!content.startsWith("$
|
|
4804
|
-
content = `$
|
|
4932
|
+
if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
|
|
4933
|
+
content = `$strSafe(${content})`;
|
|
4805
4934
|
}
|
|
4806
|
-
funcSource += `'+($
|
|
4935
|
+
funcSource += `'+($dbgExpr='<%${operate + expr}%>',${content})+'`;
|
|
4807
4936
|
} else if (content) {
|
|
4808
4937
|
if (line > -1) {
|
|
4809
|
-
funcSource += `';$
|
|
4938
|
+
funcSource += `';$dbgLine=${line};$dbgArt='${art}';`;
|
|
4810
4939
|
content = "";
|
|
4811
4940
|
} else {
|
|
4812
4941
|
funcSource += `';`;
|
|
@@ -4815,19 +4944,19 @@ function compileToFunction(source, debug, file) {
|
|
|
4815
4944
|
funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
|
|
4816
4945
|
}
|
|
4817
4946
|
if (expr) {
|
|
4818
|
-
funcSource += `$
|
|
4947
|
+
funcSource += `$dbgExpr='<%${expr}%>';`;
|
|
4819
4948
|
}
|
|
4820
|
-
funcSource += content + `;$
|
|
4949
|
+
funcSource += content + `;$out+='`;
|
|
4821
4950
|
}
|
|
4822
4951
|
} else {
|
|
4823
4952
|
if (operate === "@") {
|
|
4824
4953
|
hasAtRule = true;
|
|
4825
|
-
funcSource += `'+$
|
|
4954
|
+
funcSource += `'+$refFn($refAlt,${content})+'`;
|
|
4826
4955
|
} else if (operate === "=" || operate === ":") {
|
|
4827
|
-
funcSource += `'+$
|
|
4956
|
+
funcSource += `'+$encHtml(${content})+'`;
|
|
4828
4957
|
} else if (operate === "!") {
|
|
4829
|
-
if (!content.startsWith("$
|
|
4830
|
-
content = `$
|
|
4958
|
+
if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
|
|
4959
|
+
content = `$strSafe(${content})`;
|
|
4831
4960
|
}
|
|
4832
4961
|
funcSource += `'+${content}+'`;
|
|
4833
4962
|
} else if (content) {
|
|
@@ -4835,28 +4964,28 @@ function compileToFunction(source, debug, file) {
|
|
|
4835
4964
|
if (funcSource.endsWith(`+'';`)) {
|
|
4836
4965
|
funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
|
|
4837
4966
|
}
|
|
4838
|
-
funcSource += `${content};$
|
|
4967
|
+
funcSource += `${content};$out+='`;
|
|
4839
4968
|
}
|
|
4840
4969
|
}
|
|
4841
4970
|
return match;
|
|
4842
4971
|
});
|
|
4843
4972
|
funcSource += `';`;
|
|
4844
|
-
funcSource = funcSource.replace(/\$
|
|
4845
|
-
funcSource = funcSource.replace(/\$
|
|
4973
|
+
funcSource = funcSource.replace(/\$out\+='';/g, "");
|
|
4974
|
+
funcSource = funcSource.replace(/\$out\+=''\+/g, "$out+=");
|
|
4846
4975
|
if (debug) {
|
|
4847
4976
|
const filePart = file ? `\\r\\n\\tat file:${file}` : "";
|
|
4848
|
-
funcSource = `let $
|
|
4977
|
+
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;}`;
|
|
4849
4978
|
}
|
|
4850
4979
|
const viewIdRegExp = new RegExp(String.fromCharCode(31), "g");
|
|
4851
4980
|
funcSource = funcSource.replace(viewIdRegExp, `'+$viewId+'`);
|
|
4852
|
-
const atRule = hasAtRule ? `if(!$
|
|
4853
|
-
const encode = `if(!$
|
|
4854
|
-
const encodeURIMore = `if(!$
|
|
4855
|
-
const encodeQuote = `if(!$
|
|
4856
|
-
const refFallback = "if(
|
|
4981
|
+
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;}}` : "";
|
|
4982
|
+
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)}`;
|
|
4983
|
+
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)}`;
|
|
4984
|
+
const encodeQuote = `if(!$encQuote){let $qReg=/['"\\\\]/g;$encQuote=v=>$strSafe(v).replace($qReg,'\\\\$&')}`;
|
|
4985
|
+
const refFallback = "if(!$refAlt)$refAlt=$data;";
|
|
4857
4986
|
const fns = `${refFallback}${encode}${encodeURIMore}${encodeQuote}${atRule};`;
|
|
4858
|
-
const fullSource = `${fns}let $
|
|
4859
|
-
return `(
|
|
4987
|
+
const fullSource = `${fns}let $splitter='\\x1e',$tmp,$out=''{{VARS}};${funcSource}return $out`;
|
|
4988
|
+
return `($data,$viewId,$refAlt,$encHtml,$strSafe,$encUri,$refFn,$encQuote)=>{${fullSource}}`;
|
|
4860
4989
|
}
|
|
4861
4990
|
function compileTemplate(source, options = {}) {
|
|
4862
4991
|
const { debug = false, globalVars = [], file } = options;
|
|
@@ -4865,17 +4994,17 @@ function compileTemplate(source, options = {}) {
|
|
|
4865
4994
|
const viewEventProcessed = processViewEvents(converted);
|
|
4866
4995
|
const finalSource = restoreComments(viewEventProcessed, comments);
|
|
4867
4996
|
const funcBody = compileToFunction(finalSource, debug, file);
|
|
4868
|
-
const varDeclarations = globalVars.map((key) => `,${key}
|
|
4997
|
+
const varDeclarations = globalVars.map((key) => `,${key}=$data.${key}`).join("");
|
|
4869
4998
|
const funcWithVars = funcBody.replace("{{VARS}}", () => varDeclarations);
|
|
4870
4999
|
return `export default function(data, selfId, refData) {
|
|
4871
|
-
let
|
|
5000
|
+
let $data = data || {},
|
|
4872
5001
|
$viewId = selfId || '';
|
|
4873
|
-
return (${funcWithVars})(
|
|
4874
|
-
/* $
|
|
4875
|
-
/* $
|
|
4876
|
-
/* $
|
|
4877
|
-
/* $
|
|
4878
|
-
/* $
|
|
5002
|
+
return (${funcWithVars})($data, $viewId, refData,
|
|
5003
|
+
/* $encHtml */ v => String(v == null ? '' : v).replace(/[&<>"'\`]/g, m => '&' + ({'&':'amp','<':'lt','>':'gt','"':'#34',"'":'#39','\`':'#96'})[m] + ';'),
|
|
5004
|
+
/* $strSafe */ v => String(v == null ? '' : v),
|
|
5005
|
+
/* $encUri */ null,
|
|
5006
|
+
/* $refFn */ null,
|
|
5007
|
+
/* $encQuote */ null
|
|
4879
5008
|
);
|
|
4880
5009
|
}`;
|
|
4881
5010
|
}
|
|
@@ -4984,7 +5113,7 @@ function fallbackExtractVariables(source) {
|
|
|
4984
5113
|
while ((m = outputRegExp.exec(source)) !== null) {
|
|
4985
5114
|
vars.add(m[1]);
|
|
4986
5115
|
}
|
|
4987
|
-
const eachRegExp = /\{\{
|
|
5116
|
+
const eachRegExp = /\{\{forOf\s+([a-zA-Z_$][\w$]*)\s+as/g;
|
|
4988
5117
|
while ((m = eachRegExp.exec(source)) !== null) {
|
|
4989
5118
|
vars.add(m[1]);
|
|
4990
5119
|
}
|
|
@@ -5030,52 +5159,64 @@ var BUILTIN_GLOBALS = {
|
|
|
5030
5159
|
//
|
|
5031
5160
|
// These variables appear in the generated template function signature
|
|
5032
5161
|
// or body. They must be excluded from extractGlobalVars() so that
|
|
5033
|
-
// they are not mistaken for user data variables and destructured from
|
|
5162
|
+
// they are not mistaken for user data variables and destructured from $data.
|
|
5034
5163
|
// SPLITTER character constant (same as \x1e), used as namespace separator
|
|
5035
5164
|
// for refData keys, event attribute encoding, and internal data structures.
|
|
5036
|
-
// Declared as: let $
|
|
5037
|
-
$
|
|
5038
|
-
//
|
|
5039
|
-
// User variables are destructured from
|
|
5040
|
-
// let {name, age} =
|
|
5165
|
+
// Declared as: let $splitter='\x1e'
|
|
5166
|
+
$splitter: 1,
|
|
5167
|
+
// Data — the data object passed from Updater to the template function.
|
|
5168
|
+
// User variables are destructured from $data at the top of the function:
|
|
5169
|
+
// let {name, age} = $data;
|
|
5041
5170
|
// This is the first parameter of the generated arrow function.
|
|
5042
|
-
|
|
5171
|
+
$data: 1,
|
|
5043
5172
|
// Null-safe toString: v => '' + (v == null ? '' : v)
|
|
5044
5173
|
// Converts null/undefined to empty string, otherwise calls toString().
|
|
5045
5174
|
// Wraps every {{!raw}} output to prevent "null" / "undefined" rendering.
|
|
5046
|
-
$
|
|
5047
|
-
// HTML entity encoder: v => $
|
|
5175
|
+
$strSafe: 1,
|
|
5176
|
+
// HTML entity encoder: v => $strSafe(v).replace(/[&<>"'`]/g, entityMap)
|
|
5048
5177
|
// Encodes &, <, >, ", ', ` to HTML entities (& < etc.)
|
|
5049
5178
|
// Applied to all {{=escaped}} and {{:binding}} outputs.
|
|
5050
|
-
$
|
|
5051
|
-
// HTML entity map — internal object used by $
|
|
5179
|
+
$encHtml: 1,
|
|
5180
|
+
// HTML entity map — internal object used by $encHtml:
|
|
5052
5181
|
// {'&':'amp','<':'gt','>':'gt','"':'#34','\'':'#39','`':'#96'}
|
|
5053
|
-
// Not a standalone function; referenced inside $
|
|
5054
|
-
$
|
|
5055
|
-
// HTML entity RegExp — internal regexp used by $
|
|
5182
|
+
// Not a standalone function; referenced inside $encHtml's closure.
|
|
5183
|
+
$entMap: 1,
|
|
5184
|
+
// HTML entity RegExp — internal regexp used by $encHtml:
|
|
5056
5185
|
// /[&<>"'`]/g
|
|
5057
|
-
$
|
|
5058
|
-
// HTML entity replacer function — internal helper used by $
|
|
5059
|
-
// m => '&' + $
|
|
5060
|
-
// Maps
|
|
5061
|
-
$
|
|
5186
|
+
$entReg: 1,
|
|
5187
|
+
// HTML entity replacer function — internal helper used by $encHtml:
|
|
5188
|
+
// m => '&' + $entMap[m] + ';'
|
|
5189
|
+
// Maps matched character to its entity string.
|
|
5190
|
+
$entFn: 1,
|
|
5062
5191
|
// Output buffer — the string accumulator for rendered HTML.
|
|
5063
|
-
// All template output is appended via $
|
|
5064
|
-
// Declared as: let $
|
|
5065
|
-
$
|
|
5192
|
+
// All template output is appended via $out += '...'.
|
|
5193
|
+
// Declared as: let $out = ''
|
|
5194
|
+
$out: 1,
|
|
5066
5195
|
// Reference lookup: (refData, value) => key
|
|
5067
5196
|
// Finds or allocates a SPLITTER-prefixed key in refData for a given
|
|
5068
5197
|
// object reference. Used by {{@ref}} operator for passing object
|
|
5069
5198
|
// references to child views via v-lark attributes.
|
|
5070
|
-
$
|
|
5071
|
-
// URI encoder: v => encodeURIComponent($
|
|
5199
|
+
$refFn: 1,
|
|
5200
|
+
// URI encoder: v => encodeURIComponent($strSafe(v)).replace(/[!')(*]/g, extraMap)
|
|
5072
5201
|
// Extends encodeURIComponent with encoding of ! ' ( ) *.
|
|
5073
5202
|
// Applied to values in @event URL parameters and {{!uri}} contexts.
|
|
5074
|
-
$
|
|
5075
|
-
//
|
|
5203
|
+
$encUri: 1,
|
|
5204
|
+
// URI encode map — internal object used by $encUri:
|
|
5205
|
+
// {'!':'%21','\'':'%27','(':'%28',')':'%29','*':'%2A'}
|
|
5206
|
+
$uriMap: 1,
|
|
5207
|
+
// URI encode replacer — internal helper used by $encUri:
|
|
5208
|
+
// m => $uriMap[m]
|
|
5209
|
+
$uriFn: 1,
|
|
5210
|
+
// URI encode regexp — internal regexp used by $encUri:
|
|
5211
|
+
// /[!')(*]/g
|
|
5212
|
+
$uriReg: 1,
|
|
5213
|
+
// Quote encoder: v => $strSafe(v).replace(/['"\\]/g, '\\$&')
|
|
5076
5214
|
// Escapes quotes and backslashes for safe embedding in HTML attribute
|
|
5077
5215
|
// values (e.g. data-json='...').
|
|
5078
|
-
$
|
|
5216
|
+
$encQuote: 1,
|
|
5217
|
+
// Quote encode regexp — internal regexp used by $encQuote:
|
|
5218
|
+
// /['"\\]/g
|
|
5219
|
+
$qReg: 1,
|
|
5079
5220
|
// View ID — the unique identifier of the owning View instance.
|
|
5080
5221
|
// Injected into @event attribute values at render time so that
|
|
5081
5222
|
// EventDelegator can dispatch events to the correct View handler.
|
|
@@ -5083,23 +5224,23 @@ var BUILTIN_GLOBALS = {
|
|
|
5083
5224
|
$viewId: 1,
|
|
5084
5225
|
// Debug: current expression text — stores the template expression being
|
|
5085
5226
|
// evaluated, for error reporting. Only present in debug mode.
|
|
5086
|
-
// e.g. $
|
|
5087
|
-
$
|
|
5227
|
+
// e.g. $dbgExpr='<%=user.name%>'
|
|
5228
|
+
$dbgExpr: 1,
|
|
5088
5229
|
// Debug: original art syntax — stores the {{}} template syntax before
|
|
5089
5230
|
// conversion, for error reporting. Only present in debug mode.
|
|
5090
|
-
// e.g. $
|
|
5091
|
-
$
|
|
5231
|
+
// e.g. $dbgArt='{{=user.name}}'
|
|
5232
|
+
$dbgArt: 1,
|
|
5092
5233
|
// Debug: source line number — tracks the current line in the template
|
|
5093
5234
|
// source, for error reporting. Only present in debug mode.
|
|
5094
|
-
$
|
|
5095
|
-
//
|
|
5096
|
-
// Defaults to
|
|
5097
|
-
// Ensures $
|
|
5098
|
-
|
|
5235
|
+
$dbgLine: 1,
|
|
5236
|
+
// RefData alias — fallback reference lookup table.
|
|
5237
|
+
// Defaults to $data when no explicit $refAlt is provided.
|
|
5238
|
+
// Ensures $refFn() does not crash when @ operator is used without refData.
|
|
5239
|
+
$refAlt: 1,
|
|
5099
5240
|
// Temporary variable — used by the compiler for intermediate
|
|
5100
5241
|
// expression results in generated code (e.g. loop variables,
|
|
5101
|
-
// conditional branches). Declared as: let $
|
|
5102
|
-
$
|
|
5242
|
+
// conditional branches). Declared as: let $tmp
|
|
5243
|
+
$tmp: 1,
|
|
5103
5244
|
// JS literals
|
|
5104
5245
|
undefined: 1,
|
|
5105
5246
|
null: 1,
|
|
@@ -5165,7 +5306,6 @@ var BUILTIN_GLOBALS = {
|
|
|
5165
5306
|
var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
|
|
5166
5307
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5167
5308
|
0 && (module.exports = {
|
|
5168
|
-
Bag,
|
|
5169
5309
|
CALL_BREAK_TIME,
|
|
5170
5310
|
Cache,
|
|
5171
5311
|
EVENT_METHOD_REGEXP,
|
|
@@ -5174,6 +5314,7 @@ var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
|
|
|
5174
5314
|
Frame,
|
|
5175
5315
|
Framework,
|
|
5176
5316
|
LARK_VIEW,
|
|
5317
|
+
Payload,
|
|
5177
5318
|
Platform,
|
|
5178
5319
|
ROUTER_EVENTS,
|
|
5179
5320
|
Router,
|
|
@@ -5212,7 +5353,6 @@ var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
|
|
|
5212
5353
|
getUseStore,
|
|
5213
5354
|
has,
|
|
5214
5355
|
installFrameVisualizerBridge,
|
|
5215
|
-
isArray,
|
|
5216
5356
|
isPlainObject,
|
|
5217
5357
|
isPrimitive,
|
|
5218
5358
|
isPrimitiveOrFunc,
|