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.
- package/README.md +7 -7
- package/dist/app/demo/app.js +28 -2
- package/dist/app/demo/config.json +17 -1
- package/dist/app/demo/form/control/box/box.js +66 -0
- package/dist/app/demo/form/control/box/box.xml +18 -0
- package/dist/app/demo/form/control/button/button.js +24 -1
- package/dist/app/demo/form/control/check/check.js +24 -1
- package/dist/app/demo/form/control/dialog/dialog.js +24 -1
- package/dist/app/demo/form/control/file/file.js +24 -1
- package/dist/app/demo/form/control/flow/flow.js +24 -1
- package/dist/app/demo/form/control/form/form.js +24 -1
- package/dist/app/demo/form/control/layout/layout.js +57 -0
- package/dist/app/demo/form/control/layout/layout.xml +16 -0
- package/dist/app/demo/form/control/list/list.js +24 -1
- package/dist/app/demo/form/control/list/list.xml +8 -2
- package/dist/app/demo/form/control/marquee/marquee.js +24 -2
- package/dist/app/demo/form/control/marquee/marquee.xml +2 -5
- package/dist/app/demo/form/control/menu/menu.js +24 -1
- package/dist/app/demo/form/control/monaco/monaco.js +24 -1
- package/dist/app/demo/form/control/nav/nav.js +52 -0
- package/dist/app/demo/form/control/nav/nav.xml +43 -0
- package/dist/app/demo/form/control/panel/panel.js +67 -0
- package/dist/app/demo/form/control/panel/panel.xml +11 -0
- package/dist/app/demo/form/control/panel/test1.js +58 -0
- package/dist/app/demo/form/control/panel/test1.xml +16 -0
- package/dist/app/demo/form/control/panel/test2.xml +3 -0
- package/dist/app/demo/form/control/property/property.js +24 -1
- package/dist/app/demo/form/control/radio/radio.js +24 -1
- package/dist/app/demo/form/control/scroll/scroll.js +25 -1
- package/dist/app/demo/form/control/scroll/scroll.xml +5 -2
- package/dist/app/demo/form/control/select/select.js +24 -1
- package/dist/app/demo/form/control/tab/tab.js +24 -1
- package/dist/app/demo/form/control/table/table.js +164 -0
- package/dist/app/demo/form/control/table/table.xml +35 -0
- package/dist/app/demo/form/control/text/text.js +24 -1
- package/dist/app/demo/form/control/vflow/vflow.js +24 -1
- package/dist/app/demo/form/event/form/form.js +24 -1
- package/dist/app/demo/form/event/other/other.js +24 -1
- package/dist/app/demo/form/event/screen/screen.js +24 -1
- package/dist/app/demo/form/event/task/task.js +24 -1
- package/dist/app/demo/form/main.js +84 -33
- package/dist/app/demo/form/main.xml +5 -0
- package/dist/app/demo/form/method/aform/aform.js +28 -2
- package/dist/app/demo/form/method/aform/sd.js +24 -1
- package/dist/app/demo/form/method/core/core.js +24 -1
- package/dist/app/demo/form/method/dom/dom.js +48 -2
- package/dist/app/demo/form/method/dom/dom.xml +11 -0
- package/dist/app/demo/form/method/form/form.js +35 -1
- package/dist/app/demo/form/method/form/form.xml +2 -0
- package/dist/app/demo/form/method/fs/fs.js +138 -4
- package/dist/app/demo/form/method/fs/fs.xml +11 -1
- package/dist/app/demo/form/method/fs/text.js +24 -1
- package/dist/app/demo/form/method/native/native.js +24 -1
- package/dist/app/demo/form/method/system/system.js +24 -1
- package/dist/app/demo/form/method/task/task.js +31 -4
- package/dist/app/demo/form/method/task/task.xml +6 -1
- package/dist/app/demo/form/method/theme/theme.js +24 -1
- package/dist/app/demo/form/method/tool/tool.js +35 -1
- package/dist/app/demo/form/method/zip/zip.js +29 -3
- package/dist/app/task/app.js +28 -2
- package/dist/app/task/form/bar/bar.js +24 -1
- package/dist/clickgo.js +33 -10
- package/dist/control/box.cgc +0 -0
- package/dist/control/common.cgc +0 -0
- package/dist/control/form.cgc +0 -0
- package/dist/control/monaco.cgc +0 -0
- package/dist/control/nav.cgc +0 -0
- package/dist/control/property.cgc +0 -0
- package/dist/control/table.cgc +0 -0
- package/dist/control/task.cgc +0 -0
- package/dist/global.css +1 -1
- package/dist/lib/control.js +53 -12
- package/dist/lib/control.ts +25 -5
- package/dist/lib/core.js +44 -45
- package/dist/lib/core.ts +17 -41
- package/dist/lib/dom.js +322 -108
- package/dist/lib/dom.ts +394 -127
- package/dist/lib/form.js +441 -58
- package/dist/lib/form.ts +525 -74
- package/dist/lib/fs.js +485 -224
- package/dist/lib/fs.ts +493 -287
- package/dist/lib/native.js +24 -1
- package/dist/lib/task.js +143 -136
- package/dist/lib/task.ts +124 -127
- package/dist/lib/theme.js +27 -4
- package/dist/lib/tool.js +19 -2
- package/dist/lib/tool.ts +23 -1
- package/dist/lib/zip.js +29 -3
- package/dist/lib/zip.ts +1 -1
- package/dist/theme/familiar.cgt +0 -0
- package/package.json +4 -6
- 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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
// ---
|
|
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: -
|
|
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();
|