clickgo 3.1.5-dev14 → 3.1.6-dev15

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.
Files changed (92) hide show
  1. package/README.md +7 -7
  2. package/dist/app/demo/app.js +28 -2
  3. package/dist/app/demo/config.json +17 -1
  4. package/dist/app/demo/form/control/box/box.js +66 -0
  5. package/dist/app/demo/form/control/box/box.xml +18 -0
  6. package/dist/app/demo/form/control/button/button.js +24 -1
  7. package/dist/app/demo/form/control/check/check.js +24 -1
  8. package/dist/app/demo/form/control/dialog/dialog.js +24 -1
  9. package/dist/app/demo/form/control/file/file.js +24 -1
  10. package/dist/app/demo/form/control/flow/flow.js +24 -1
  11. package/dist/app/demo/form/control/form/form.js +24 -1
  12. package/dist/app/demo/form/control/layout/layout.js +57 -0
  13. package/dist/app/demo/form/control/layout/layout.xml +16 -0
  14. package/dist/app/demo/form/control/list/list.js +24 -1
  15. package/dist/app/demo/form/control/list/list.xml +8 -2
  16. package/dist/app/demo/form/control/marquee/marquee.js +24 -2
  17. package/dist/app/demo/form/control/marquee/marquee.xml +2 -5
  18. package/dist/app/demo/form/control/menu/menu.js +24 -1
  19. package/dist/app/demo/form/control/monaco/monaco.js +24 -1
  20. package/dist/app/demo/form/control/nav/nav.js +52 -0
  21. package/dist/app/demo/form/control/nav/nav.xml +43 -0
  22. package/dist/app/demo/form/control/panel/panel.js +67 -0
  23. package/dist/app/demo/form/control/panel/panel.xml +11 -0
  24. package/dist/app/demo/form/control/panel/test1.js +58 -0
  25. package/dist/app/demo/form/control/panel/test1.xml +16 -0
  26. package/dist/app/demo/form/control/panel/test2.xml +3 -0
  27. package/dist/app/demo/form/control/property/property.js +24 -1
  28. package/dist/app/demo/form/control/radio/radio.js +24 -1
  29. package/dist/app/demo/form/control/scroll/scroll.js +25 -1
  30. package/dist/app/demo/form/control/scroll/scroll.xml +5 -2
  31. package/dist/app/demo/form/control/select/select.js +24 -1
  32. package/dist/app/demo/form/control/tab/tab.js +24 -1
  33. package/dist/app/demo/form/control/table/table.js +164 -0
  34. package/dist/app/demo/form/control/table/table.xml +35 -0
  35. package/dist/app/demo/form/control/text/text.js +24 -1
  36. package/dist/app/demo/form/control/vflow/vflow.js +24 -1
  37. package/dist/app/demo/form/event/form/form.js +24 -1
  38. package/dist/app/demo/form/event/other/other.js +24 -1
  39. package/dist/app/demo/form/event/screen/screen.js +24 -1
  40. package/dist/app/demo/form/event/task/task.js +24 -1
  41. package/dist/app/demo/form/main.js +84 -33
  42. package/dist/app/demo/form/main.xml +5 -0
  43. package/dist/app/demo/form/method/aform/aform.js +28 -2
  44. package/dist/app/demo/form/method/aform/sd.js +24 -1
  45. package/dist/app/demo/form/method/core/core.js +24 -1
  46. package/dist/app/demo/form/method/dom/dom.js +48 -2
  47. package/dist/app/demo/form/method/dom/dom.xml +11 -0
  48. package/dist/app/demo/form/method/form/form.js +35 -1
  49. package/dist/app/demo/form/method/form/form.xml +2 -0
  50. package/dist/app/demo/form/method/fs/fs.js +138 -4
  51. package/dist/app/demo/form/method/fs/fs.xml +11 -1
  52. package/dist/app/demo/form/method/fs/text.js +24 -1
  53. package/dist/app/demo/form/method/native/native.js +24 -1
  54. package/dist/app/demo/form/method/system/system.js +24 -1
  55. package/dist/app/demo/form/method/task/task.js +31 -4
  56. package/dist/app/demo/form/method/task/task.xml +6 -1
  57. package/dist/app/demo/form/method/theme/theme.js +24 -1
  58. package/dist/app/demo/form/method/tool/tool.js +35 -1
  59. package/dist/app/demo/form/method/zip/zip.js +29 -3
  60. package/dist/app/task/app.js +28 -2
  61. package/dist/app/task/form/bar/bar.js +24 -1
  62. package/dist/clickgo.js +33 -10
  63. package/dist/control/box.cgc +0 -0
  64. package/dist/control/common.cgc +0 -0
  65. package/dist/control/form.cgc +0 -0
  66. package/dist/control/monaco.cgc +0 -0
  67. package/dist/control/nav.cgc +0 -0
  68. package/dist/control/property.cgc +0 -0
  69. package/dist/control/table.cgc +0 -0
  70. package/dist/control/task.cgc +0 -0
  71. package/dist/global.css +1 -1
  72. package/dist/lib/control.js +53 -12
  73. package/dist/lib/control.ts +25 -5
  74. package/dist/lib/core.js +44 -45
  75. package/dist/lib/core.ts +17 -41
  76. package/dist/lib/dom.js +322 -108
  77. package/dist/lib/dom.ts +394 -127
  78. package/dist/lib/form.js +441 -58
  79. package/dist/lib/form.ts +525 -74
  80. package/dist/lib/fs.js +485 -224
  81. package/dist/lib/fs.ts +493 -287
  82. package/dist/lib/native.js +24 -1
  83. package/dist/lib/task.js +143 -136
  84. package/dist/lib/task.ts +124 -127
  85. package/dist/lib/theme.js +27 -4
  86. package/dist/lib/tool.js +19 -2
  87. package/dist/lib/tool.ts +23 -1
  88. package/dist/lib/zip.js +29 -3
  89. package/dist/lib/zip.ts +1 -1
  90. package/dist/theme/familiar.cgt +0 -0
  91. package/package.json +4 -6
  92. package/types/index.d.ts +42 -34
package/dist/lib/form.ts CHANGED
@@ -30,6 +30,8 @@ let focusId: number | null = null;
30
30
  const info: {
31
31
  /** --- 最后一个窗体 id --- */
32
32
  lastId: number;
33
+ /** --- 最后一个 panel id --- */
34
+ lastPanelId: number;
33
35
  /** --- 最后一个窗体层级,1000(一千)开始 --- */
34
36
  lastZIndex: number;
35
37
  /** --- 最后一个置顶窗体层级,10000000(一千万)开始 --- */
@@ -44,6 +46,7 @@ const info: {
44
46
  }>;
45
47
  } = {
46
48
  'lastId': 0,
49
+ 'lastPanelId': 0,
47
50
  'lastZIndex': 999,
48
51
  'topLastZIndex': 9999999,
49
52
  'locale': {
@@ -78,8 +81,8 @@ const info: {
78
81
  }
79
82
  };
80
83
 
81
- /** --- 窗体的抽象类 --- */
82
- export abstract class AbstractForm {
84
+ /** --- Panel 与 Form 共用的抽象类 --- */
85
+ abstract class AbstractCommon {
83
86
 
84
87
  /** --- 当前文件路径 --- */
85
88
  public get filename(): string {
@@ -127,7 +130,7 @@ export abstract class AbstractForm {
127
130
  });
128
131
  }
129
132
 
130
- /** --- 当前窗体的包内路径不以 / 结尾 --- */
133
+ /** --- 当前文件的包内路径不以 / 结尾 --- */
131
134
  public get path(): string {
132
135
  // --- 将在初始化时系统自动重写本函数 ---
133
136
  return '';
@@ -147,9 +150,20 @@ export abstract class AbstractForm {
147
150
  /**
148
151
  * --- 获取语言内容 ---
149
152
  */
150
- public get l(): (key: string) => string {
151
- return (key: string): string => {
152
- return task.list[this.taskId].locale.data[this.locale]?.[key] ?? task.list[this.taskId].locale.data['en']?.[key] ?? 'LocaleError';
153
+ public get l(): (key: string, data?: string[]) => string {
154
+ return (key: string, data?: string[]): string => {
155
+ const loc = task.list[this.taskId].locale.data[this.locale]?.[key] ?? task.list[this.taskId].locale.data['en']?.[key] ?? 'LocaleError';
156
+ if (!data) {
157
+ return loc;
158
+ }
159
+ let i: number = -1;
160
+ return loc.replace(/\?/g, function() {
161
+ ++i;
162
+ if (!data[i]) {
163
+ return '';
164
+ }
165
+ return data[i];
166
+ });
153
167
  };
154
168
  }
155
169
 
@@ -164,9 +178,6 @@ export abstract class AbstractForm {
164
178
  };
165
179
  }
166
180
 
167
- /** --- 当前窗体是否和 native 的实体窗体大小、状态同步 --- */
168
- public isNativeSync: boolean = false;
169
-
170
181
  /**
171
182
  * --- 监视变动 ---
172
183
  * @param name 监视的属性
@@ -219,6 +230,87 @@ export abstract class AbstractForm {
219
230
  core.trigger(name, this.taskId, this.formId, param1, param2);
220
231
  }
221
232
 
233
+ /**
234
+ * --- 给一个窗体发送一个对象,不会知道成功与失败状态 ---
235
+ * @param fid formId 要接收对象的 form id
236
+ * @param obj 要发送的对象
237
+ */
238
+ public send(fid: number, obj: Record<string, any>): void {
239
+ obj.taskId = this.taskId;
240
+ obj.formId = this.formId;
241
+ send(fid, obj);
242
+ }
243
+
244
+ // --- 控件响应事件,都可由用户重写 ---
245
+
246
+ public onBeforeCreate(): void | Promise<void> {
247
+ return;
248
+ }
249
+
250
+ public onCreated(): void | Promise<void> {
251
+ return;
252
+ }
253
+
254
+ public onBeforeMount(): void | Promise<void> {
255
+ return;
256
+ }
257
+
258
+ public onBeforeUpdate(): void | Promise<void> {
259
+ return;
260
+ }
261
+
262
+ public onUpdated(): void | Promise<void> {
263
+ return;
264
+ }
265
+
266
+ public onBeforeUnmount(): void | Promise<void> {
267
+ return;
268
+ }
269
+
270
+ public onUnmounted(): void | Promise<void> {
271
+ return;
272
+ }
273
+
274
+ }
275
+
276
+ /** --- Panel 控件抽象类 --- */
277
+ export abstract class AbstractPanel extends AbstractCommon {
278
+
279
+ /** --- 当前的 panel ID --- */
280
+ public get panelId(): number {
281
+ // --- panel 创建时 createPanel 自动重写本函数 ---
282
+ return 0;
283
+ }
284
+
285
+ public onShow(data: Record<string, any>): void | Promise<void>;
286
+ public onShow(): void {
287
+ return;
288
+ }
289
+
290
+ public onHide(): void | Promise<void>;
291
+ public onHide(): void {
292
+ return;
293
+ }
294
+
295
+ public onMounted(): void | Promise<void>;
296
+ public onMounted(): void {
297
+ return;
298
+ }
299
+
300
+ /** --- 接收 send 传递过来的 data 数据(是 panel 控件的 send,不是 form 的 send) --- */
301
+ public onReceive(data: Record<string, any>): void | Promise<void>;
302
+ public onReceive(): void {
303
+ return;
304
+ }
305
+
306
+ }
307
+
308
+ /** --- 窗体的抽象类 --- */
309
+ export abstract class AbstractForm extends AbstractCommon {
310
+
311
+ /** --- 当前窗体是否和 native 的实体窗体大小、状态同步 --- */
312
+ public isNativeSync: boolean = false;
313
+
222
314
  // --- 以下为窗体有,但 control 没有 ---
223
315
 
224
316
  /** --- 是否是置顶 --- */
@@ -231,17 +323,6 @@ export abstract class AbstractForm {
231
323
  // --- 会进行重写 ---
232
324
  }
233
325
 
234
- /**
235
- * --- 给一个窗体发送一个对象,不会知道成功与失败状态 ---
236
- * @param fid formId 要接收对象的 form id
237
- * @param obj 要发送的对象
238
- */
239
- public send(fid: number, obj: Record<string, any>): void {
240
- obj.taskId = this.taskId;
241
- obj.formId = this.formId;
242
- send(fid, obj);
243
- }
244
-
245
326
  /**
246
327
  * --- 是否在本窗体上显示遮罩层 ---
247
328
  */
@@ -314,43 +395,13 @@ export abstract class AbstractForm {
314
395
  */
315
396
  public dialogResult: string = '';
316
397
 
317
- // --- 控件响应事件,都可由用户重写 ---
318
-
319
- public onBeforeCreate(): void | Promise<void> {
320
- return;
321
- }
322
-
323
- public onCreated(): void | Promise<void> {
324
- return;
325
- }
326
-
327
- public onBeforeMount(): void | Promise<void> {
328
- return;
329
- }
398
+ // --- 窗体可以接收到的事件 ---
330
399
 
331
400
  public onMounted(obj: Record<string, any>): void | Promise<void>;
332
- public onMounted(): void | Promise<void> {
401
+ public onMounted(): void {
333
402
  return;
334
403
  }
335
404
 
336
- public onBeforeUpdate(): void | Promise<void> {
337
- return;
338
- }
339
-
340
- public onUpdated(): void | Promise<void> {
341
- return;
342
- }
343
-
344
- public onBeforeUnmount(): void | Promise<void> {
345
- return;
346
- }
347
-
348
- public onUnmounted(): void | Promise<void> {
349
- return;
350
- }
351
-
352
- // --- 窗体可以接收到的事件 ---
353
-
354
405
  /** --- 接收 send 传递过来的 data 数据 --- */
355
406
  public onReceive(data: Record<string, any>): void | Promise<void>;
356
407
  public onReceive(): void {
@@ -383,13 +434,13 @@ export abstract class AbstractForm {
383
434
 
384
435
  /** --- 窗体标题改变事件 */
385
436
  public onFormTitleChanged(taskId: number, formId: number, title: string): void | Promise<void>;
386
- public onFormTitleChanged(): void | Promise<void> {
437
+ public onFormTitleChanged(): void {
387
438
  return;
388
439
  }
389
440
 
390
441
  /** --- 窗体图标改变事件 --- */
391
442
  public onFormIconChanged(taskId: number, formId: number, icon: string): void | Promise<void>;
392
- public onFormIconChanged(): void | Promise<void> {
443
+ public onFormIconChanged(): void {
393
444
  return;
394
445
  }
395
446
 
@@ -431,13 +482,13 @@ export abstract class AbstractForm {
431
482
 
432
483
  /** --- 任务开始事件 --- */
433
484
  public onTaskStarted(taskId: number): void | Promise<void>;
434
- public onTaskStarted(): void | Promise<void> {
485
+ public onTaskStarted(): void {
435
486
  return;
436
487
  }
437
488
 
438
489
  /** --- 任务结束事件 --- */
439
490
  public onTaskEnded(taskId: number): void | Promise<void>;
440
- public onTaskEnded(): void | Promise<void> {
491
+ public onTaskEnded(): void {
441
492
  return;
442
493
  }
443
494
 
@@ -1035,6 +1086,76 @@ export function getFocus(): number | null {
1035
1086
  return focusId;
1036
1087
  }
1037
1088
 
1089
+ /**
1090
+ * --- 当前活跃中的 panelId 列表 ---
1091
+ */
1092
+ export const activePanels: Record<string, number[]> = {};
1093
+
1094
+ /**
1095
+ * --- 获取窗体当前活跃中的 panelId 列表 ---
1096
+ * @param formId 要获取的窗体 id
1097
+ */
1098
+ export function getActivePanel(formId: number): number[] {
1099
+ return activePanels[formId] ?? [];
1100
+ }
1101
+
1102
+ /**
1103
+ * --- 移除 form 中正在活跃中的 panel id (panel 本身被置于隐藏时)
1104
+ * @param panelId panel id
1105
+ * @param formId 所属 form id
1106
+ * @param taskId task id 校验,App 模式下无效
1107
+ */
1108
+ export function removeActivePanel(panelId: number, formId: number, taskId?: number): boolean {
1109
+ if (!taskId) {
1110
+ return false;
1111
+ }
1112
+ if (!task.list[taskId]) {
1113
+ return false;
1114
+ }
1115
+ if (!task.list[taskId].forms[formId]) {
1116
+ return false;
1117
+ }
1118
+ if (!activePanels[formId]) {
1119
+ return true;
1120
+ }
1121
+ const io = activePanels[formId].indexOf(panelId);
1122
+ if (io === -1) {
1123
+ return true;
1124
+ }
1125
+ activePanels[formId].splice(io, 1);
1126
+ if (!activePanels[formId].length) {
1127
+ delete activePanels[formId];
1128
+ }
1129
+ return true;
1130
+ }
1131
+
1132
+ /**
1133
+ * --- 将 form 中某个 panel 设置为活动的 ---
1134
+ * @param panelId panel id
1135
+ * @param formId 所属 form id
1136
+ * @param taskId task id 校验,App 模式下无效
1137
+ */
1138
+ export function setActivePanel(panelId: number, formId: number, taskId?: number): boolean {
1139
+ if (!taskId) {
1140
+ return false;
1141
+ }
1142
+ if (!task.list[taskId]) {
1143
+ return false;
1144
+ }
1145
+ if (!task.list[taskId].forms[formId]) {
1146
+ return false;
1147
+ }
1148
+ if (!activePanels[formId]) {
1149
+ activePanels[formId] = [];
1150
+ }
1151
+ const io = activePanels[formId].indexOf(panelId);
1152
+ if (io !== -1) {
1153
+ return true;
1154
+ }
1155
+ activePanels[formId].push(panelId);
1156
+ return true;
1157
+ }
1158
+
1038
1159
  /**
1039
1160
  * --- 改变 form 的焦点 class ---
1040
1161
  * @param formId 变更后的 form id
@@ -1805,6 +1926,7 @@ export function remove(formId: number): boolean {
1805
1926
  dom.clearWatchStyle(formId);
1806
1927
  dom.clearWatchProperty(formId);
1807
1928
  native.clear(formId, taskId);
1929
+ delete activePanels[formId];
1808
1930
  // --- 检测是否已经没有窗体了,如果没有了的话就要结束任务了 ---
1809
1931
  if (Object.keys(task.list[taskId].forms).length === 0) {
1810
1932
  task.end(taskId);
@@ -1817,6 +1939,45 @@ export function remove(formId: number): boolean {
1817
1939
  }
1818
1940
  }
1819
1941
 
1942
+ /**
1943
+ * --- 移除 panel 挂载,通常发生在 panel 控件的 onBeforeUnmount 中 ---
1944
+ * @param id panel id
1945
+ * @param vapp panel 的 vapp 对象 ---
1946
+ * @param el panel 控件
1947
+ */
1948
+ export function removePanel(id: number, vapp: types.IVApp, el: HTMLElement): boolean {
1949
+ const formWrap = dom.findParentByClass(el, 'cg-form-wrap');
1950
+ if (!formWrap) {
1951
+ return false;
1952
+ }
1953
+ const formId = formWrap.dataset.formId;
1954
+ if (!formId) {
1955
+ return false;
1956
+ }
1957
+ const taskId = formWrap.dataset.taskId;
1958
+ if (!taskId) {
1959
+ return false;
1960
+ }
1961
+ const tid = parseInt(taskId);
1962
+ vapp.unmount();
1963
+ vapp._container.remove();
1964
+ el.querySelector('[data-panel-id="' + id.toString() + '"]')?.remove();
1965
+ // --- 移除 form 的 style ---
1966
+ dom.removeStyle(tid, 'form', formId, id);
1967
+ dom.clearWatchStyle(formId, id);
1968
+ dom.clearWatchProperty(formId, id);
1969
+ if (activePanels[formId]) {
1970
+ const io = activePanels[formId].indexOf(id);
1971
+ if (io >= 0) {
1972
+ activePanels[formId].splice(io, 1);
1973
+ }
1974
+ if (!activePanels[formId].length) {
1975
+ delete activePanels[formId];
1976
+ }
1977
+ }
1978
+ return true;
1979
+ }
1980
+
1820
1981
  /**
1821
1982
  * --- 根据任务 id 和 form id 获取 IForm 对象,App 模式下无效 ---
1822
1983
  * @param taskId 任务 id
@@ -1835,6 +1996,297 @@ function getForm(taskId: number, formId: number): types.IForm | null {
1835
1996
  return form;
1836
1997
  }
1837
1998
 
1999
+ /**
2000
+ * --- 创建 panel 对象,一般情况下无需使用 ---
2001
+ * @param cls 路径字符串或 AbstractPanel 类
2002
+ * @param el 要挂载的节点
2003
+ * @param formId 当前窗体 ID
2004
+ * @param taskId 任务ID,App 模式下无效
2005
+ */
2006
+ export async function createPanel<T extends AbstractPanel>(
2007
+ cls: string | (new () => T),
2008
+ el: HTMLElement,
2009
+ formId: number,
2010
+ taskId?: number
2011
+ ): Promise<{
2012
+ 'id': number;
2013
+ 'vapp': types.IVApp;
2014
+ 'vroot': T;
2015
+ }> {
2016
+ if (!taskId) {
2017
+ const err = new Error('form.createPanel: -1');
2018
+ core.trigger('error', 0, 0, err, err.message);
2019
+ throw err;
2020
+ }
2021
+ if (el.dataset.cgControl !== 'panel') {
2022
+ const err = new Error('form.createPanel: -2');
2023
+ core.trigger('error', 0, 0, err, err.message);
2024
+ throw err;
2025
+ }
2026
+ /** --- 当前的 task 对象 --- */
2027
+ const t = task.list[taskId];
2028
+ if (!t) {
2029
+ const err = new Error('form.createPanel: -3');
2030
+ core.trigger('error', 0, 0, err, err.message);
2031
+ throw err;
2032
+ }
2033
+ /** --- 文件在包内的路径,不以 / 结尾 --- */
2034
+ let filename = '';
2035
+ if (typeof cls === 'string') {
2036
+ filename = cls + '.js';
2037
+ cls = class extends AbstractPanel {
2038
+ public get filename(): string {
2039
+ return filename;
2040
+ }
2041
+
2042
+ public get taskId(): number {
2043
+ return t.id;
2044
+ }
2045
+ } as (new () => T);
2046
+ }
2047
+
2048
+ // --- 申请 panelId ---
2049
+ const panelId = ++info.lastPanelId;
2050
+ /** --- 要新建的 panel 类对象 --- */
2051
+ const panel = new cls();
2052
+ if (!filename) {
2053
+ filename = panel.filename;
2054
+ }
2055
+ const lio = filename.lastIndexOf('/');
2056
+ const path = filename.slice(0, lio);
2057
+
2058
+ // --- 布局 ---
2059
+ const l = t.app.files[filename.slice(0, -2) + 'xml'];
2060
+ if (typeof l !== 'string') {
2061
+ const err = new Error('form.createPanel: -4');
2062
+ core.trigger('error', 0, 0, err, err.message);
2063
+ throw err;
2064
+ }
2065
+ let layout = l;
2066
+
2067
+ // --- 样式 ---
2068
+ /** --- 样式内容 --- */
2069
+ let style: string = '';
2070
+ /** --- 样式前缀 --- */
2071
+ let prep = '';
2072
+ const s = t.app.files[filename.slice(0, -2) + 'css'];
2073
+ if (typeof s === 'string') {
2074
+ style = s;
2075
+ // --- 将 style 中的 tag 标签转换为 class,如 button 变为 .tag-button,然后将 class 进行标准程序,添加 prep 进行区分隔离 ---
2076
+ const r = tool.stylePrepend(style);
2077
+ prep = r.prep;
2078
+ style = await tool.styleUrl2DataUrl(path + '/', r.style, t.app.files);
2079
+ }
2080
+
2081
+ // --- 纯净化 ---
2082
+ layout = tool.purify(layout);
2083
+ // --- 标签增加 cg- 前缀,增加 class 为 tag-xxx ---
2084
+ layout = tool.layoutAddTagClassAndReTagName(layout, true);
2085
+ // --- 给所有控件传递窗体的 focus 信息 ---
2086
+ layout = tool.layoutInsertAttr(layout, ':form-focus=\'formFocus\'', {
2087
+ 'include': [/^cg-.+/]
2088
+ });
2089
+ // --- 给 layout 的 class 增加前置 ---
2090
+ const prepList = ['cg-task' + t.id.toString() + '_'];
2091
+ if (prep !== '') {
2092
+ prepList.push(prep);
2093
+ }
2094
+ layout = tool.layoutClassPrepend(layout, prepList);
2095
+ // --- 给 event 增加包裹 ---
2096
+ layout = tool.eventsAttrWrap(layout);
2097
+ // --- 给 teleport 做处理 ---
2098
+ if (layout.includes('<teleport')) {
2099
+ layout = tool.teleportGlue(layout, formId);
2100
+ }
2101
+ // --- 获取要定义的控件列表 ---
2102
+ const components = control.buildComponents(t.id, formId, path);
2103
+ if (!components) {
2104
+ const err = new Error('form.createPanel: -5');
2105
+ core.trigger('error', 0, 0, err, err.message);
2106
+ throw err;
2107
+ }
2108
+ /** --- class 对象类的属性列表 --- */
2109
+ const idata: Record<string, any> = {};
2110
+ const cdata = Object.entries(panel);
2111
+ for (const item of cdata) {
2112
+ if (item[0] === 'access') {
2113
+ // --- access 属性不放在 data 当中 ---
2114
+ continue;
2115
+ }
2116
+ idata[item[0]] = item[1];
2117
+ }
2118
+ idata._formFocus = false;
2119
+ /** --- class 对象的方法和 getter/setter 列表 --- */
2120
+ const prot = tool.getClassPrototype(panel);
2121
+ const methods = prot.method;
2122
+ const computed = prot.access;
2123
+ computed.formId = {
2124
+ get: function(): number {
2125
+ return formId;
2126
+ },
2127
+ set: function(this: types.IVue): void {
2128
+ notify({
2129
+ 'title': 'Error',
2130
+ 'content': `The software tries to modify the system variable "formId".\nPath: ${this.filename}`,
2131
+ 'type': 'danger'
2132
+ });
2133
+ return;
2134
+ }
2135
+ };
2136
+ computed.panelId = {
2137
+ get: function(): number {
2138
+ return panelId;
2139
+ },
2140
+ set: function(this: types.IVue): void {
2141
+ notify({
2142
+ 'title': 'Error',
2143
+ 'content': `The software tries to modify the system variable "panelId".\nPath: ${this.filename}`,
2144
+ 'type': 'danger'
2145
+ });
2146
+ return;
2147
+ }
2148
+ };
2149
+ computed.path = {
2150
+ get: function(): string {
2151
+ return path;
2152
+ },
2153
+ set: function(this: types.IVue): void {
2154
+ notify({
2155
+ 'title': 'Error',
2156
+ 'content': `The software tries to modify the system variable "path".\nPath: ${this.filename}`,
2157
+ 'type': 'danger'
2158
+ });
2159
+ return;
2160
+ }
2161
+ };
2162
+ computed.prep = {
2163
+ get: function(): string {
2164
+ return prep;
2165
+ },
2166
+ set: function(this: types.IVue): void {
2167
+ notify({
2168
+ 'title': 'Error',
2169
+ 'content': `The software tries to modify the system variable "cgPrep".\nPath: ${this.filename}`,
2170
+ 'type': 'danger'
2171
+ });
2172
+ return;
2173
+ }
2174
+ };
2175
+
2176
+ // --- 插入 dom ---
2177
+ el.insertAdjacentHTML('beforeend', `<div data-panel-id="${panelId.toString()}"></div>`);
2178
+ if (style) {
2179
+ dom.pushStyle(t.id, style, 'form', formId, panelId);
2180
+ }
2181
+ /** --- panel wrap element 对象 --- */
2182
+ const mel: HTMLElement = el.children.item(el.children.length - 1) as HTMLElement;
2183
+ mel.style.flex = '1';
2184
+
2185
+ // --- 创建 app 对象 ---
2186
+ const rtn: {
2187
+ 'vapp': types.IVApp;
2188
+ 'vroot': types.IVue;
2189
+ } = await new Promise(function(resolve) {
2190
+ const vapp = clickgo.vue.createApp({
2191
+ 'template': layout.replace(/^<cg-panel([\s\S]+)-panel>$/, '<cg-layout$1-layout>'),
2192
+ 'data': function() {
2193
+ return tool.clone(idata);
2194
+ },
2195
+ 'methods': methods,
2196
+ 'computed': computed,
2197
+
2198
+ 'beforeCreate': (panel as any).onBeforeCreate,
2199
+ 'created': function(this: types.IVue) {
2200
+ if ((panel as any).access) {
2201
+ this.access = tool.clone((panel as any).access);
2202
+ }
2203
+ this.onCreated();
2204
+ },
2205
+ 'beforeMount': function(this: types.IVue) {
2206
+ this.onBeforeMount();
2207
+ },
2208
+ 'mounted': async function(this: types.IVue) {
2209
+ await this.$nextTick();
2210
+ (mel.children.item(0) as HTMLElement).style.flex = '1';
2211
+ // --- 完成 ---
2212
+ resolve({
2213
+ 'vapp': vapp,
2214
+ 'vroot': this
2215
+ });
2216
+ },
2217
+ 'beforeUpdate': function(this: types.IVue) {
2218
+ this.onBeforeUpdate();
2219
+ },
2220
+ 'updated': async function(this: types.IVue) {
2221
+ await this.$nextTick();
2222
+ this.onUpdated();
2223
+ },
2224
+ 'beforeUnmount': function(this: types.IVue) {
2225
+ this.onBeforeUnmount();
2226
+ },
2227
+ 'unmounted': async function(this: types.IVue) {
2228
+ await this.$nextTick();
2229
+ this.onUnmounted();
2230
+ }
2231
+ });
2232
+ vapp.config.errorHandler = function(err: Error, vm: types.IVue, info: string): void {
2233
+ notify({
2234
+ 'title': 'Runtime Error',
2235
+ 'content': `Message: ${err.message}\nTask id: ${vm.taskId}\nForm id: ${vm.formId}`,
2236
+ 'type': 'danger'
2237
+ });
2238
+ core.trigger('error', vm.taskId, vm.formId, err, info + '(-3,' + vm.taskId + ',' + vm.formId + ')');
2239
+ };
2240
+ // --- 挂载控件对象到 vapp ---
2241
+ for (const key in components) {
2242
+ vapp.component(key, components[key]);
2243
+ }
2244
+ try {
2245
+ vapp.mount(mel);
2246
+ }
2247
+ catch (err: any) {
2248
+ notify({
2249
+ 'title': 'Runtime Error',
2250
+ 'content': `Message: ${err.message}\nTask id: ${t.id}\nForm id: ${formId}`,
2251
+ 'type': 'danger'
2252
+ });
2253
+ core.trigger('error', t.id, formId, err, err.message);
2254
+ }
2255
+ });
2256
+ // --- 执行 mounted ---
2257
+ await tool.sleep(34);
2258
+ try {
2259
+ await panel.onMounted.call(rtn.vroot);
2260
+ }
2261
+ catch (err: any) {
2262
+ // --- 创建失败,做垃圾回收 ---
2263
+ core.trigger('error', rtn.vroot.taskId, rtn.vroot.formId, err, 'Create panel mounted error: -6.');
2264
+ try {
2265
+ rtn.vapp.unmount();
2266
+ }
2267
+ catch (err: any) {
2268
+ const msg = `Message: ${err.message}\nTask id: ${t.id}\nForm id: ${formId}\nFunction: form.createPanel, unmount.`;
2269
+ notify({
2270
+ 'title': 'Panel Unmount Error',
2271
+ 'content': msg,
2272
+ 'type': 'danger'
2273
+ });
2274
+ console.log('Panel Unmount Error', msg, err);
2275
+ }
2276
+ rtn.vapp._container.remove();
2277
+ dom.clearWatchStyle(rtn.vroot.formId, panelId);
2278
+ dom.clearWatchProperty(rtn.vroot.formId, panelId);
2279
+ // --- 移除 style ---
2280
+ dom.removeStyle(rtn.vroot.taskId, 'form', rtn.vroot.formId, panelId);
2281
+ throw err;
2282
+ }
2283
+ return {
2284
+ 'id': panelId,
2285
+ 'vapp': rtn.vapp,
2286
+ 'vroot': rtn.vroot as any
2287
+ };
2288
+ }
2289
+
1838
2290
  /**
1839
2291
  * --- 创建一个窗体 ---
1840
2292
  * @param cls 路径字符串或 AbstractForm 类
@@ -1872,11 +2324,11 @@ export async function create<T extends AbstractForm>(
1872
2324
  }
1873
2325
  /** --- 样式内容 --- */
1874
2326
  let style: string = '';
2327
+ /** --- 样式前缀 --- */
2328
+ let prep = '';
1875
2329
  if (opt.style) {
1876
2330
  style = opt.style;
1877
2331
  }
1878
- /** --- 样式前缀 --- */
1879
- let prep = '';
1880
2332
  /** --- 文件在包内的路径,不以 / 结尾 --- */
1881
2333
  let filename = '';
1882
2334
  if (typeof cls === 'string') {
@@ -1907,7 +2359,7 @@ export async function create<T extends AbstractForm>(
1907
2359
  } as (new () => T);
1908
2360
  }
1909
2361
 
1910
- // --- 申请 formId ---
2362
+ // --- 申请 formId ---
1911
2363
  const formId = ++info.lastId;
1912
2364
  /** --- 要新建的窗体类对象 --- */
1913
2365
  const frm = new cls();
@@ -1916,6 +2368,18 @@ export async function create<T extends AbstractForm>(
1916
2368
  }
1917
2369
  const lio = filename.lastIndexOf('/');
1918
2370
  const path = filename.slice(0, lio);
2371
+
2372
+ // --- 布局 ---
2373
+ if (!layout) {
2374
+ const l = t.app.files[filename.slice(0, -2) + 'xml'];
2375
+ if (typeof l !== 'string') {
2376
+ const err = new Error('form.create: -4');
2377
+ core.trigger('error', 0, 0, err, err.message);
2378
+ throw err;
2379
+ }
2380
+ layout = l;
2381
+ }
2382
+
1919
2383
  // --- 样式 ---
1920
2384
  if (!style) {
1921
2385
  const s = t.app.files[filename.slice(0, -2) + 'css'];
@@ -1930,16 +2394,6 @@ export async function create<T extends AbstractForm>(
1930
2394
  style = await tool.styleUrl2DataUrl(path + '/', r.style, t.app.files);
1931
2395
  }
1932
2396
 
1933
- // --- 布局 ---
1934
- if (!layout) {
1935
- const l = t.app.files[frm.filename.slice(0, -2) + 'xml'];
1936
- if (typeof l !== 'string') {
1937
- const err = new Error('form.create: -4');
1938
- core.trigger('error', 0, 0, err, err.message);
1939
- throw err;
1940
- }
1941
- layout = l;
1942
- }
1943
2397
  // --- 纯净化 ---
1944
2398
  layout = tool.purify(layout);
1945
2399
  // --- 标签增加 cg- 前缀,增加 class 为 tag-xxx ---
@@ -2098,10 +2552,7 @@ export async function create<T extends AbstractForm>(
2098
2552
  // --- 为啥要在这搞,因为 form 控件中读取,将可能导致下方的 formCreate 事件获取不到 icon 图标 ---
2099
2553
  // --- 而如果用延迟的方式获取,将可能导致 changeFocus 的窗体焦点事件先于 formCreate 触发 ---
2100
2554
  if (this.$refs.form.icon) {
2101
- const icon = await fs.getContent(this.$refs.form.icon, {
2102
- 'current': t.current,
2103
- 'files': t.app.files
2104
- });
2555
+ const icon = await fs.getContent(this.$refs.form.icon, undefined, taskId);
2105
2556
  this.$refs.form.iconDataUrl = (icon instanceof Blob) ? await tool.blob2DataUrl(icon) : '';
2106
2557
  }
2107
2558
  // --- 完成 ---
@@ -2164,7 +2615,7 @@ export async function create<T extends AbstractForm>(
2164
2615
  }
2165
2616
  catch (err: any) {
2166
2617
  // --- 窗体创建失败,做垃圾回收 ---
2167
- core.trigger('error', rtn.vroot.taskId, rtn.vroot.formId, err, 'Create form mounted error: -7.');
2618
+ core.trigger('error', rtn.vroot.taskId, rtn.vroot.formId, err, 'Create form mounted error: -6.');
2168
2619
  delete t.forms[formId];
2169
2620
  try {
2170
2621
  rtn.vapp.unmount();