clickgo 3.0.7-dev8 → 3.1.1-dev10

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 (41) hide show
  1. package/README.md +1 -1
  2. package/dist/app/demo/app.js +93 -0
  3. package/dist/app/demo/form/control/dialog/dialog.js +10 -6
  4. package/dist/app/demo/form/control/form/form.js +21 -20
  5. package/dist/app/demo/form/control/form/form.xml +3 -3
  6. package/dist/app/demo/form/main.js +34 -10
  7. package/dist/app/demo/form/main.xml +4 -4
  8. package/dist/app/demo/form/method/form/form.js +103 -101
  9. package/dist/app/demo/form/method/form/form.xml +9 -10
  10. package/dist/app/task/app.js +46 -0
  11. package/dist/app/task/form/bar/bar.js +84 -88
  12. package/dist/app/task/form/bar/bar.xml +4 -5
  13. package/dist/clickgo.js +1 -10
  14. package/dist/clickgo.ts +0 -8
  15. package/dist/control/common.cgc +0 -0
  16. package/dist/control/form.cgc +0 -0
  17. package/dist/control/monaco.cgc +0 -0
  18. package/dist/control/property.cgc +0 -0
  19. package/dist/control/task.cgc +0 -0
  20. package/dist/index.js +105 -56
  21. package/dist/index.ts +164 -59
  22. package/dist/lib/control.js +363 -240
  23. package/dist/lib/control.ts +497 -284
  24. package/dist/lib/core.js +313 -228
  25. package/dist/lib/core.ts +400 -255
  26. package/dist/lib/dom.ts +1 -3
  27. package/dist/lib/form.js +447 -951
  28. package/dist/lib/form.ts +686 -1097
  29. package/dist/lib/fs.js +42 -39
  30. package/dist/lib/fs.ts +45 -41
  31. package/dist/lib/native.ts +3 -0
  32. package/dist/lib/task.js +708 -182
  33. package/dist/lib/task.ts +778 -200
  34. package/dist/lib/theme.ts +2 -2
  35. package/dist/lib/tool.js +58 -48
  36. package/dist/lib/tool.ts +80 -64
  37. package/dist/theme/familiar.cgt +0 -0
  38. package/package.json +5 -7
  39. package/types/index.d.ts +284 -335
  40. package/dist/app/demo/config.json +0 -106
  41. package/dist/app/task/config.json +0 -32
package/dist/lib/form.ts CHANGED
@@ -20,6 +20,7 @@ import * as task from './task';
20
20
  import * as tool from './tool';
21
21
  import * as dom from './dom';
22
22
  import * as control from './control';
23
+ import * as fs from './fs';
23
24
  import * as native from './native';
24
25
 
25
26
  /** --- form 相关信息 --- */
@@ -74,6 +75,461 @@ const info: {
74
75
  }
75
76
  };
76
77
 
78
+ /** --- 窗体的抽象类 --- */
79
+ export class AbstractForm {
80
+
81
+ /**
82
+ * --- 创建窗体工厂函数 ---
83
+ * @param data 要传递的对象
84
+ * @param layout 是否使用此参数替换 layout 值
85
+ */
86
+ public static async create(data?: Record<string, any>, layout?: string): Promise<AbstractForm | number> {
87
+ const frm = new this();
88
+ /** --- 要挂载的 vue 参数 --- */
89
+ const code: types.IFormCreateCode = {
90
+ 'data': {},
91
+ 'methods': {},
92
+ 'computed': {},
93
+
94
+ beforeCreate: (frm as any).onBeforeCreate,
95
+ created: function(this: types.IVue) {
96
+ this.onCreated();
97
+ },
98
+ beforeMount: function(this: types.IVue) {
99
+ this.onBeforeMount();
100
+ },
101
+ mounted: function(this: types.IVue, data?: Record<string, any>) {
102
+ // await this.$nextTick();
103
+ // --- form 不用 nextTick,因为全部处理完后才会主动调用本方法 ---
104
+ this.onMounted(data);
105
+ },
106
+ beforeUpdate: function(this: types.IVue) {
107
+ this.onBeforeUpdate();
108
+ },
109
+ updated: async function(this: types.IVue) {
110
+ await this.$nextTick();
111
+ this.onUpdated();
112
+ },
113
+ beforeUnmount: function(this: types.IVue) {
114
+ this.onBeforeUnmount();
115
+ },
116
+ unmounted: async function(this: types.IVue) {
117
+ await this.$nextTick();
118
+ this.onUnmounted();
119
+ }
120
+ };
121
+ /** --- class 对象类的属性列表 --- */
122
+ const cdata = Object.entries(frm);
123
+ for (const item of cdata) {
124
+ code.data![item[0]] = item[1];
125
+ }
126
+ if (!layout) {
127
+ const l = task.list[frm.taskId].app.files[frm.filename.slice(0, -2) + 'xml'];
128
+ if (typeof l !== 'string') {
129
+ return 0;
130
+ }
131
+ layout = l;
132
+ }
133
+ const prot = tool.getClassPrototype(frm);
134
+ code.methods = prot.method;
135
+ code.computed = prot.access;
136
+ // --- 窗体样式 ---
137
+ let style: string | undefined = undefined;
138
+ const fstyle = task.list[frm.taskId].app.files[frm.filename.slice(0, -2) + 'css'];
139
+ if (typeof fstyle === 'string') {
140
+ style = fstyle;
141
+ }
142
+ const fid = await create({
143
+ 'code': code,
144
+ 'layout': layout,
145
+ 'style': style,
146
+
147
+ 'path': frm.filename.slice(0, frm.filename.lastIndexOf('/')),
148
+ 'data': data,
149
+ 'taskId': frm.taskId
150
+ });
151
+ if (fid > 0) {
152
+ return task.list[frm.taskId].forms[fid].vroot as any;
153
+ }
154
+ else {
155
+ return fid;
156
+ }
157
+ }
158
+
159
+ /** --- 当前文件路径 --- */
160
+ public get filename(): string {
161
+ // --- require 时系统自动在继承类中重写本函数 ---
162
+ return '';
163
+ }
164
+
165
+ /** --- 当前控件的名字 --- */
166
+ public get controlName(): string {
167
+ return 'root';
168
+ }
169
+
170
+ public set controlName(v: string) {
171
+ notify({
172
+ 'title': 'Error',
173
+ 'content': `The software tries to modify the system variable "controlName".\nPath: ${this.filename}`,
174
+ 'type': 'danger'
175
+ });
176
+ return;
177
+ }
178
+
179
+ /** --- 当前的任务 ID --- */
180
+ public get taskId(): number {
181
+ // --- 系统 invoke 继承时重写本函数 ---
182
+ return 0;
183
+ }
184
+
185
+ /** --- 当前的窗体 ID --- */
186
+ public get formId(): number {
187
+ // --- 窗体创建时 create 系统自动重写本函数 ---
188
+ return 0;
189
+ }
190
+
191
+ /** --- 当前窗体是否是焦点 --- */
192
+ public get formFocus(): boolean {
193
+ // --- _formFocus 在初始化时由系统设置 ---
194
+ return (this as any)._formFocus;
195
+ }
196
+
197
+ public set formFocus(b: boolean) {
198
+ notify({
199
+ 'title': 'Error',
200
+ 'content': `The software tries to modify the system variable "formFocus".\nPath: ${this.filename}`,
201
+ 'type': 'danger'
202
+ });
203
+ }
204
+
205
+ /** --- 当前窗体的包内路径不以 / 结尾 --- */
206
+ public get path(): string {
207
+ // --- 将在初始化时系统自动重写本函数 ---
208
+ return '';
209
+ }
210
+
211
+ /** --- 样式独占前缀 --- */
212
+ public get prep(): string {
213
+ // --- 将在初始化时系统自动重写本函数 ---
214
+ return '';
215
+ }
216
+
217
+ /** --- 当前的语言 --- */
218
+ public get locale(): string {
219
+ return task.list[this.taskId].locale.lang || core.config.locale;
220
+ }
221
+
222
+ /**
223
+ * --- 获取语言内容 ---
224
+ */
225
+ public get l(): (key: string) => string {
226
+ return (key: string): string => {
227
+ return task.list[this.taskId].locale.data[this.locale]?.[key] ?? task.list[this.taskId].locale.data['en']?.[key] ?? 'LocaleError';
228
+ };
229
+ }
230
+
231
+ /** --- layout 中 :class 的转义 --- */
232
+ public classPrepend(): (cla: any) => string {
233
+ return (cla: any): string => {
234
+ if (typeof cla !== 'string') {
235
+ return cla;
236
+ }
237
+ // --- 没有单独的窗体样式,则只应用任务级样式 ---
238
+ return `cg-task${this.taskId}_${cla}${this.prep ? (' ' + this.prep + cla) : ''}`;
239
+ };
240
+ }
241
+
242
+ /**
243
+ * --- 监视变动 ---
244
+ * @param name 监视的属性
245
+ * @param cb 回调
246
+ * @param opt 参数
247
+ */
248
+ public watch<T extends this, TK extends keyof T>(
249
+ name: TK,
250
+ cb: (val: T[TK], old: T[TK]) => void | Promise<void>,
251
+ opt: {
252
+ 'immediate'?: boolean;
253
+ 'deep'?: boolean;
254
+ } = {}
255
+ ): () => void {
256
+ return (this as any).$watch(name, cb, opt);
257
+ }
258
+
259
+ /**
260
+ * --- 获取 refs 情况 ---
261
+ */
262
+ public get refs(): Record<string, HTMLElement & types.IVue> {
263
+ return (this as any).$refs;
264
+ }
265
+
266
+ /**
267
+ * --- 等待渲染 ---
268
+ */
269
+ public get nextTick(): () => Promise<void> {
270
+ return (this as any).$nextTick;
271
+ }
272
+
273
+ /**
274
+ * --- 判断当前事件可否执行 ---
275
+ * @param e 鼠标、触摸、键盘事件
276
+ */
277
+ public allowEvent(e: MouseEvent | TouchEvent | KeyboardEvent): boolean {
278
+ return dom.allowEvent(e);
279
+ }
280
+
281
+ /**
282
+ * --- 触发系统方法 ---
283
+ * @param name 方法名
284
+ * @param param1 参数1
285
+ * @param param2 参数2
286
+ */
287
+ public trigger(name: types.TGlobalEvent, param1: boolean | Error | string = '', param2: string = ''): void {
288
+ if (!['formTitleChanged', 'formIconChanged', 'formStateMinChanged', 'formStateMaxChanged', 'formShowChanged'].includes(name)) {
289
+ return;
290
+ }
291
+ core.trigger(name, this.taskId, this.formId, param1, param2);
292
+ }
293
+
294
+ // --- 以下为窗体有,但 control 没有 ---
295
+
296
+ /**
297
+ * --- 无 js 文件的窗体创建 ---
298
+ * @param path 包内相对于本窗体的路径或包内绝对路径,不含扩展名
299
+ * @param data 要传递的值
300
+ */
301
+ public async createForm(path: string, data?: Record<string, any>): Promise<AbstractForm | number> {
302
+ path = tool.urlResolve(this.filename, path);
303
+ const taskId = this.taskId;
304
+ const cls = class extends AbstractForm {
305
+ public get filename(): string {
306
+ return path + '.js';
307
+ }
308
+
309
+ public get taskId(): number {
310
+ return taskId;
311
+ }
312
+ };
313
+ return cls.create(data);
314
+ }
315
+
316
+ /** --- 是否是置顶 --- */
317
+ public get topMost(): boolean {
318
+ // --- 将在初始化时系统自动重写本函数 ---
319
+ return false;
320
+ }
321
+
322
+ public set topMost(v: boolean) {
323
+ // --- 会进行重写 ---
324
+ }
325
+
326
+ /**
327
+ * --- 给一个窗体发送一个对象,不会知道成功与失败状态 ---
328
+ * @param fid formId 要接收对象的 form id
329
+ * @param obj 要发送的对象
330
+ */
331
+ public send(fid: number, obj: Record<string, any>): void {
332
+ obj.taskId = this.taskId;
333
+ obj.formId = this.formId;
334
+ send(fid, obj);
335
+ }
336
+
337
+ /**
338
+ * --- 是否在本窗体上显示遮罩层 ---
339
+ */
340
+ public get isMask(): boolean {
341
+ return !task.list[this.taskId].runtime.dialogFormIds.length ||
342
+ task.list[this.taskId].runtime.dialogFormIds[task.list[this.taskId].runtime.dialogFormIds.length - 1]
343
+ === this.formId ? false : true;
344
+ }
345
+
346
+ /** --- 当前是不是初次显示 --- */
347
+ private _firstShow: boolean = true;
348
+
349
+ /**
350
+ * --- 显示窗体 ---
351
+ */
352
+ public show(): void {
353
+ // --- 创建成功的窗体,可以直接显示 ---
354
+ const v = this as any;
355
+ v.$refs.form.$data.showData = true;
356
+ if (this._firstShow) {
357
+ this._firstShow = false;
358
+ // --- 将窗体居中 ---
359
+ const area = core.getAvailArea();
360
+ if (!v.$refs.form.stateMaxData) {
361
+ if (v.$refs.form.left === -1) {
362
+ v.$refs.form.setPropData('left', (area.width - v.$el.offsetWidth) / 2);
363
+ }
364
+ if (v.$refs.form.top === -1) {
365
+ v.$refs.form.setPropData('top', (area.height - v.$el.offsetHeight) / 2);
366
+ }
367
+ }
368
+ v.$refs.form.$data.showData = true;
369
+ changeFocus(this.formId);
370
+ }
371
+ }
372
+
373
+ /**
374
+ * --- 显示独占的窗体 ---
375
+ */
376
+ public async showDialog(): Promise<string> {
377
+ this.show();
378
+ task.list[this.taskId].runtime.dialogFormIds.push(this.formId);
379
+ return new Promise((resolve) => {
380
+ (this as any).cgDialogCallback = () => {
381
+ resolve(this.dialogResult);
382
+ };
383
+ });
384
+ }
385
+
386
+ /**
387
+ * --- 让窗体隐藏 ---
388
+ */
389
+ public hide(): void {
390
+ const v = this as any;
391
+ v.$refs.form.$data.showData = false;
392
+ }
393
+
394
+ /**
395
+ * --- dialog mask 窗体返回值,在 close 之后会进行传导 ---
396
+ */
397
+ public dialogResult: string = '';
398
+
399
+ // --- 控件响应事件,都可由用户重写 ---
400
+
401
+ public onBeforeCreate(): void | Promise<void> {
402
+ return;
403
+ }
404
+
405
+ public onCreated(): void | Promise<void> {
406
+ return;
407
+ }
408
+
409
+ public onBeforeMount(): void | Promise<void> {
410
+ return;
411
+ }
412
+
413
+ public onMounted(): void | Promise<void> {
414
+ return;
415
+ }
416
+
417
+ public onBeforeUpdate(): void | Promise<void> {
418
+ return;
419
+ }
420
+
421
+ public onUpdated(): void | Promise<void> {
422
+ return;
423
+ }
424
+
425
+ public onBeforeUnmount(): void | Promise<void> {
426
+ return;
427
+ }
428
+
429
+ public onUnmounted(): void | Promise<void> {
430
+ return;
431
+ }
432
+
433
+ // --- 窗体可以接收到的事件 ---
434
+
435
+ /** --- 接收 send 传递过来的 data 数据 --- */
436
+ public onReceive(data: Record<string, any>): void | Promise<void>;
437
+ public onReceive(): void {
438
+ return;
439
+ }
440
+
441
+ /** --- 屏幕大小改变事件 --- */
442
+ public onScreenResize(): void | Promise<void>;
443
+ public onScreenResize(): void {
444
+ return;
445
+ }
446
+
447
+ /** --- 系统配置变更事件 --- */
448
+ public onConfigChanged<T extends keyof types.IConfig>(n: keyof types.IConfig, v: types.IConfig[T]): void;
449
+ public onConfigChanged(): void {
450
+ return;
451
+ }
452
+
453
+ /** --- 窗体创建事件 --- */
454
+ public onFormCreated(taskId: number, formId: number, title: string, icon: string): void | Promise<void>;
455
+ public onFormCreated(): void {
456
+ return;
457
+ }
458
+
459
+ /** --- 窗体销毁事件 */
460
+ public onFormRemoved(taskId: number, formId: number, title: string, icon: string): void | Promise<void>;
461
+ public onFormRemoved(): void {
462
+ return;
463
+ }
464
+
465
+ /** --- 窗体标题改变事件 */
466
+ public onFormTitleChanged(taskId: number, formId: number, title: string): void | Promise<void>;
467
+ public onFormTitleChanged(): void | Promise<void> {
468
+ return;
469
+ }
470
+
471
+ /** --- 窗体图标改变事件 --- */
472
+ public onFormIconChanged(taskId: number, formId: number, icon: string): void | Promise<void>;
473
+ public onFormIconChanged(): void | Promise<void> {
474
+ return;
475
+ }
476
+
477
+ /** --- 窗体最小化状态改变事件 --- */
478
+ public onFormStateMinChanged(taskId: number, formId: number, state: boolean): void | Promise<void>;
479
+ public onFormStateMinChanged(): void {
480
+ return;
481
+ }
482
+
483
+ /** --- 窗体最大化状态改变事件 --- */
484
+ public onFormStateMaxChanged(taskId: number, formId: number, state: boolean): void | Promise<void>;
485
+ public onFormStateMaxChanged(): void {
486
+ return;
487
+ }
488
+
489
+ /** --- 窗体显示状态改变事件 --- */
490
+ public onFormShowChanged(taskId: number, formId: number, state: boolean): void | Promise<void>;
491
+ public onFormShowChanged(): void {
492
+ return;
493
+ }
494
+
495
+ /** --- 窗体获得焦点事件 --- */
496
+ public onFormFocused(taskId: number, formId: number): void | Promise<void>;
497
+ public onFormFocused(): void {
498
+ return;
499
+ }
500
+
501
+ /** --- 窗体丢失焦点事件 --- */
502
+ public onFormBlurred(taskId: number, formId: number): void | Promise<void>;
503
+ public onFormBlurred(): void {
504
+ return;
505
+ }
506
+
507
+ /** --- 窗体闪烁事件 --- */
508
+ public onFormFlash(taskId: number, formId: number): void | Promise<void>;
509
+ public onFormFlash(): void {
510
+ return;
511
+ }
512
+
513
+ /** --- 任务开始事件 --- */
514
+ public onTaskStarted(taskId: number): void | Promise<void>;
515
+ public onTaskStarted(): void | Promise<void> {
516
+ return;
517
+ }
518
+
519
+ /** --- 任务结束事件 --- */
520
+ public onTaskEnded(taskId: number): void | Promise<void>;
521
+ public onTaskEnded(): void | Promise<void> {
522
+ return;
523
+ }
524
+
525
+ /** --- launcher 文件夹名称修改事件 --- */
526
+ public onLauncherFolderNameChanged(id: string, name: string): void | Promise<void>;
527
+ public onLauncherFolderNameChanged(): void {
528
+ return;
529
+ }
530
+
531
+ }
532
+
77
533
  /** --- pop 相关信息 --- */
78
534
  const popInfo: {
79
535
  /** --- 当前显示的 pop 列表 --- */
@@ -240,7 +696,7 @@ const elements: {
240
696
  }
241
697
  },
242
698
  'mounted': function(this: types.IVue): void {
243
- simpleSystemTaskRoot = this;
699
+ simpleSystemTaskRoot = this as any;
244
700
  }
245
701
  });
246
702
  simpletaskApp.mount('#cg-simpletask');
@@ -424,7 +880,7 @@ const elements: {
424
880
  }
425
881
  },
426
882
  'mounted': function(this: types.IVue): void {
427
- launcherRoot = this;
883
+ launcherRoot = this as any;
428
884
  }
429
885
  });
430
886
  launcherApp.mount('#cg-launcher');
@@ -439,10 +895,7 @@ elements.init();
439
895
  * @param state 最大化、最小化或关闭
440
896
  * @param formId 窗体 id
441
897
  */
442
- function changeState(state: 'min' | 'max' | 'close', formId?: number): boolean {
443
- if (!formId) {
444
- return false;
445
- }
898
+ function changeState(state: 'min' | 'max' | 'close', formId: number): boolean {
446
899
  const tid: number = getTaskId(formId);
447
900
  const t = task.list[tid];
448
901
  if (!t) {
@@ -466,25 +919,25 @@ function changeState(state: 'min' | 'max' | 'close', formId?: number): boolean {
466
919
 
467
920
  /**
468
921
  * --- 最小化某个窗体 ---
469
- * @param formId 窗体 id,App 模式下可省略
922
+ * @param formId 窗体 id
470
923
  */
471
- export function min(formId?: number): boolean {
924
+ export function min(formId: number): boolean {
472
925
  return changeState('min', formId);
473
926
  }
474
927
 
475
928
  /**
476
929
  * --- 最大化某个窗体 ---
477
- * @param formId formId 窗体 id,App 模式下可省略
930
+ * @param formId 窗体 id
478
931
  */
479
- export function max(formId?: number): boolean {
932
+ export function max(formId: number): boolean {
480
933
  return changeState('max', formId);
481
934
  }
482
935
 
483
936
  /**
484
937
  * --- 关闭一个窗体 ---
485
- * @param formId formId 窗体 id,App 模式下可省略
938
+ * @param formId 窗体 id
486
939
  */
487
- export function close(formId?: number): boolean {
940
+ export function close(formId: number): boolean {
488
941
  return changeState('close', formId);
489
942
  }
490
943
 
@@ -493,7 +946,7 @@ export function close(formId?: number): boolean {
493
946
  * @param e 事件源
494
947
  * @param border 调整大小的方位
495
948
  */
496
- export function bindResize(e: MouseEvent | TouchEvent, border: types.TBorder): void {
949
+ export function bindResize(e: MouseEvent | TouchEvent, border: types.TDomBorder): void {
497
950
  const formWrap = dom.findParentByClass(e.target as HTMLElement, 'cg-form-wrap');
498
951
  if (!formWrap) {
499
952
  return;
@@ -534,7 +987,7 @@ export function bindDrag(e: MouseEvent | TouchEvent): void {
534
987
  }
535
988
 
536
989
  /**
537
- * --- 重置所有已经最大化的窗体大小和位置 ---
990
+ * --- 重置所有已经最大化的窗体大小和位置,App 模式下无效 ---
538
991
  */
539
992
  export function refreshMaxPosition(): void {
540
993
  const area = core.getAvailArea();
@@ -591,12 +1044,12 @@ export function get(formId: number): types.IFormInfo | null {
591
1044
  'stateMax': item.vroot.$refs.form.stateMaxData,
592
1045
  'stateMin': item.vroot.$refs.form.stateMinData,
593
1046
  'show': item.vroot.$refs.form.showData,
594
- 'focus': item.vroot.cgFocus
1047
+ 'focus': item.vroot.formFocus
595
1048
  };
596
1049
  }
597
1050
 
598
1051
  /**
599
- * --- 给一个窗体发送一个对象,不会知道成功与失败状态 ---
1052
+ * --- 给一个窗体发送一个对象,不会知道成功与失败状态,APP 模式下无效用 this.send 替代 ---
600
1053
  * @param formId 要接收对象的 form id
601
1054
  * @param obj 要发送的对象
602
1055
  */
@@ -606,10 +1059,7 @@ export function send(formId: number, obj: Record<string, any>): void {
606
1059
  return;
607
1060
  }
608
1061
  const item = task.list[taskId].forms[formId];
609
- if (!item.vroot.cgReceive) {
610
- return;
611
- }
612
- item.vroot.cgReceive(obj);
1062
+ item.vroot.onReceive(obj);
613
1063
  }
614
1064
 
615
1065
  /**
@@ -630,7 +1080,7 @@ export function getList(taskId: number): Record<string, types.IFormInfo> {
630
1080
  'stateMax': item.vroot.$refs.form.stateMaxData,
631
1081
  'stateMin': item.vroot.$refs.form.stateMinData,
632
1082
  'show': item.vroot.$refs.form.showData,
633
- 'focus': item.vroot.cgFocus
1083
+ 'focus': item.vroot.formFocus
634
1084
  };
635
1085
  }
636
1086
  return list;
@@ -649,7 +1099,7 @@ export function changeFocus(formId: number = 0): void {
649
1099
  });
650
1100
  return;
651
1101
  }
652
- const focusElement = document.querySelector('#cg-form-list > [data-cg-focus]');
1102
+ const focusElement = document.querySelector('#cg-form-list > [data-form-focus]');
653
1103
  if (focusElement) {
654
1104
  const dataFormId = focusElement.getAttribute('data-form-id');
655
1105
  if (dataFormId) {
@@ -660,8 +1110,8 @@ export function changeFocus(formId: number = 0): void {
660
1110
  else {
661
1111
  const taskId = parseInt(focusElement.getAttribute('data-task-id') ?? '0');
662
1112
  const t = task.list[taskId];
663
- t.forms[dataFormIdNumber].vapp._container.removeAttribute('data-cg-focus');
664
- t.forms[dataFormIdNumber].vroot._cgFocus = false;
1113
+ t.forms[dataFormIdNumber].vapp._container.removeAttribute('data-form-focus');
1114
+ t.forms[dataFormIdNumber].vroot._formFocus = false;
665
1115
  // --- 触发 formBlurred 事件 ---
666
1116
  core.trigger('formBlurred', taskId, dataFormIdNumber);
667
1117
  }
@@ -684,44 +1134,42 @@ export function changeFocus(formId: number = 0): void {
684
1134
  // --- 获取所属的 taskId ---
685
1135
  const taskId: number = parseInt(el.getAttribute('data-task-id') ?? '0');
686
1136
  const t = task.list[taskId];
687
- // --- 如果不是自定义的 zindex,则设置 zIndex 为最大 ---
688
- if (!t.forms[formId].vroot.cgCustomZIndex) {
689
- if (t.forms[formId].vroot.cgTopMost) {
690
- t.forms[formId].vroot.$refs.form.setPropData('zIndex', ++info.topLastZIndex);
691
- }
692
- else {
693
- t.forms[formId].vroot.$refs.form.setPropData('zIndex', ++info.lastZIndex);
694
- }
695
- }
696
- // --- 检测 maskFor ---
697
- const maskFor = t.forms[formId].vroot.$refs.form.maskFor;
698
- if ((typeof maskFor === 'number') && (task.list[taskId].forms[maskFor])) {
699
- // --- 有 maskFor 窗体 ---
1137
+ // --- 检测是否有 dialog mask ---
1138
+ if (t.runtime.dialogFormIds.length) {
1139
+ // --- 有 dialog ---
1140
+ const dialogFormId = t.runtime.dialogFormIds[t.runtime.dialogFormIds.length - 1];
700
1141
  // --- 如果是最小化状态的话,需要还原 ---
701
- if (get(maskFor)!.stateMin) {
702
- min(maskFor);
1142
+ if (get(dialogFormId)!.stateMin) {
1143
+ min(dialogFormId);
703
1144
  }
704
- // --- 如果不是自定义的 zindex,则设置 zIndex 为最大 ---
705
- if (!task.list[taskId].forms[maskFor].vroot.cgCustomZIndex) {
706
- if (task.list[taskId].forms[maskFor].vroot.cgTopMost) {
707
- task.list[taskId].forms[maskFor].vroot.$refs.form.setPropData('zIndex', ++info.topLastZIndex);
708
- }
709
- else {
710
- task.list[taskId].forms[maskFor].vroot.$refs.form.setPropData('zIndex', ++info.lastZIndex);
711
- }
1145
+ if (t.forms[dialogFormId].vroot._topMost) {
1146
+ t.forms[dialogFormId].vroot.$refs.form.$data.zIndexData = ++info.topLastZIndex;
1147
+ }
1148
+ else {
1149
+ t.forms[dialogFormId].vroot.$refs.form.$data.zIndexData = ++info.lastZIndex;
712
1150
  }
713
1151
  // --- 开启 focus ---
714
- task.list[taskId].forms[maskFor].vapp._container.dataset.cgFocus = '';
715
- task.list[taskId].forms[maskFor].vroot._cgFocus = true;
1152
+ t.forms[dialogFormId].vapp._container.dataset.formFocus = '';
1153
+ t.forms[dialogFormId].vroot._formFocus = true;
716
1154
  // --- 触发 formFocused 事件 ---
717
- core.trigger('formFocused', taskId, maskFor);
718
- // --- 闪烁 ---
719
- clickgo.form.flash(maskFor, taskId);
1155
+ core.trigger('formFocused', taskId, dialogFormId);
1156
+ // --- 判断点击的窗体是不是就是 dialog mask 窗体本身 ---
1157
+ if (dialogFormId !== formId) {
1158
+ // --- 闪烁 ---
1159
+ clickgo.form.flash(dialogFormId, taskId);
1160
+ }
720
1161
  }
721
1162
  else {
1163
+ // --- 没有 dialog,才修改 zindex ---
1164
+ if (t.forms[formId].vroot._topMost) {
1165
+ t.forms[formId].vroot.$refs.form.$data.zIndexData = ++info.topLastZIndex;
1166
+ }
1167
+ else {
1168
+ t.forms[formId].vroot.$refs.form.$data.zIndexData = ++info.lastZIndex;
1169
+ }
722
1170
  // --- 正常开启 focus ---
723
- t.forms[formId].vapp._container.dataset.cgFocus = '';
724
- t.forms[formId].vroot._cgFocus = true;
1171
+ t.forms[formId].vapp._container.dataset.formFocus = '';
1172
+ t.forms[formId].vroot._formFocus = true;
725
1173
  // --- 触发 formFocused 事件 ---
726
1174
  core.trigger('formFocused', taskId, formId);
727
1175
  }
@@ -740,6 +1188,9 @@ export function getMaxZIndexID(out: {
740
1188
  for (let i = 0; i < elements.list.children.length; ++i) {
741
1189
  const formWrap = elements.list.children.item(i) as HTMLDivElement;
742
1190
  const formInner = formWrap.children.item(0) as HTMLDivElement;
1191
+ if (!formInner) {
1192
+ continue;
1193
+ }
743
1194
  // --- 排除 top most 窗体 ---
744
1195
  const z = parseInt(formInner.style.zIndex);
745
1196
  if (z > 9999999) {
@@ -771,7 +1222,7 @@ export function getMaxZIndexID(out: {
771
1222
  * --- 根据 border 方向 获取理论窗体大小 ---
772
1223
  * @param border 显示的位置代号
773
1224
  */
774
- export function getRectByBorder(border: types.TBorder): { 'width': number; 'height': number; 'left': number; 'top': number; } {
1225
+ export function getRectByBorder(border: types.TDomBorderCustom): { 'width': number; 'height': number; 'left': number; 'top': number; } {
775
1226
  const area = core.getAvailArea();
776
1227
  let width!: number, height!: number, left!: number, top!: number;
777
1228
  if (typeof border === 'string') {
@@ -881,7 +1332,7 @@ export function showCircular(x: number, y: number): void {
881
1332
  * --- 移动矩形到新位置 ---
882
1333
  * @param border 显示的位置代号
883
1334
  */
884
- export function moveRectangle(border: types.TBorder): void {
1335
+ export function moveRectangle(border: types.TDomBorderCustom): void {
885
1336
  const dataReady = elements.rectangle.getAttribute('data-ready') ?? '0';
886
1337
  if (dataReady === '0') {
887
1338
  return;
@@ -911,7 +1362,7 @@ export function moveRectangle(border: types.TBorder): void {
911
1362
  * @param y 起始位置
912
1363
  * @param border 最大时位置代号
913
1364
  */
914
- export function showRectangle(x: number, y: number, border: types.TBorder): void {
1365
+ export function showRectangle(x: number, y: number, border: types.TDomBorderCustom): void {
915
1366
  elements.rectangle.style.transition = 'none';
916
1367
  requestAnimationFrame(function() {
917
1368
  elements.rectangle.style.width = '5px';
@@ -987,7 +1438,7 @@ let notifyTop: number = 10;
987
1438
  let notifyId: number = 0;
988
1439
  /**
989
1440
  * --- 弹出右上角信息框 ---
990
- * @param opt timeout 默认 5 秒
1441
+ * @param opt timeout 默认 5 秒,最大 30
991
1442
  */
992
1443
  export function notify(opt: types.INotifyOptions): number {
993
1444
  // --- 申请 nid ---
@@ -1099,7 +1550,7 @@ export function hideNotify(notifyId: number): void {
1099
1550
  }
1100
1551
 
1101
1552
  /**
1102
- * --- 将标签追加到 pop ---
1553
+ * --- 将标签追加到 pop 层,App 模式下无效 ---
1103
1554
  * @param el 要追加的标签
1104
1555
  */
1105
1556
  export function appendToPop(el: HTMLElement): void {
@@ -1107,7 +1558,7 @@ export function appendToPop(el: HTMLElement): void {
1107
1558
  }
1108
1559
 
1109
1560
  /**
1110
- * --- 将标签从 pop 层移除 ---
1561
+ * --- 将标签从 pop 层移除,App 模式下无效 ---
1111
1562
  * @param el 要移除的标签
1112
1563
  */
1113
1564
  export function removeFromPop(el: HTMLElement): void {
@@ -1305,7 +1756,7 @@ export function hidePop(pop?: HTMLElement): void {
1305
1756
  }
1306
1757
 
1307
1758
  /**
1308
- * --- 点下 (mousedown / touchstart) 屏幕任意一位置时根据点击处处理隐藏 pop 和焦点丢失事件,鼠标和 touch 只会响应一个 ---
1759
+ * --- 点下 (mousedown / touchstart) 屏幕任意一位置时根据点击处处理隐藏 pop 和焦点丢失事件,鼠标和 touch 只会响应一个,App 模式下无效 ---
1309
1760
  * @param e 事件对象
1310
1761
  */
1311
1762
  export function doFocusAndPopEvent(e: MouseEvent | TouchEvent): void {
@@ -1364,7 +1815,7 @@ window.addEventListener('touchstart', doFocusAndPopEvent, {
1364
1815
  window.addEventListener('mousedown', doFocusAndPopEvent);
1365
1816
 
1366
1817
  /**
1367
- * --- 移除一个 form(关闭窗口) ---
1818
+ * --- 移除一个 form(关闭窗口),App 模式下无效 ---
1368
1819
  * @param formId 要移除的 form id
1369
1820
  */
1370
1821
  export function remove(formId: number): boolean {
@@ -1374,9 +1825,10 @@ export function remove(formId: number): boolean {
1374
1825
  if (task.list[taskId].forms[formId]) {
1375
1826
  title = task.list[taskId].forms[formId].vroot.$refs.form.title;
1376
1827
  icon = task.list[taskId].forms[formId].vroot.$refs.form.iconData;
1377
- if (task.list[taskId].forms[formId].vroot.$refs.form.maskFrom !== undefined) {
1378
- const fid = task.list[taskId].forms[formId].vroot.$refs.form.maskFrom;
1379
- task.list[taskId].forms[fid].vroot.$refs.form.maskFor = undefined;
1828
+ const io = task.list[taskId].runtime.dialogFormIds.indexOf(formId);
1829
+ if (io > -1) {
1830
+ // --- 取消 dialog mask 记录 ---
1831
+ task.list[taskId].runtime.dialogFormIds.splice(io, 1);
1380
1832
  }
1381
1833
  task.list[taskId].forms[formId].vroot.$refs.form.$data.showData = false;
1382
1834
  setTimeout(function() {
@@ -1397,6 +1849,10 @@ export function remove(formId: number): boolean {
1397
1849
  }
1398
1850
  task.list[taskId].forms[formId].vapp.unmount();
1399
1851
  task.list[taskId].forms[formId].vapp._container.remove();
1852
+ if (io > -1) {
1853
+ // --- 如果是 dialog 则要执行回调 ---
1854
+ task.list[taskId].forms[formId].vroot.cgDialogCallback();
1855
+ }
1400
1856
  delete task.list[taskId].forms[formId];
1401
1857
  // --- 移除 form 的 style ---
1402
1858
  dom.removeStyle(taskId, 'form', formId);
@@ -1415,22 +1871,16 @@ export function remove(formId: number): boolean {
1415
1871
  }
1416
1872
 
1417
1873
  /**
1418
- * --- 根据任务 id 和 form id 获取 IForm 对象 ---
1874
+ * --- 根据任务 id 和 form id 获取 IForm 对象,App 模式下无效 ---
1419
1875
  * @param taskId 任务 id
1420
1876
  * @param formId 窗体 id
1421
1877
  */
1422
- function getForm(taskId?: number, formId?: number): types.IForm | null {
1423
- if (!taskId) {
1424
- return null;
1425
- }
1878
+ function getForm(taskId: number, formId: number): types.IForm | null {
1426
1879
  /** --- 当前的 task 对象 --- */
1427
1880
  const t = task.list[taskId];
1428
1881
  if (!t) {
1429
1882
  return null;
1430
1883
  }
1431
- if (!formId) {
1432
- return null;
1433
- }
1434
1884
  const form = t.forms[formId];
1435
1885
  if (!form) {
1436
1886
  return null;
@@ -1439,791 +1889,71 @@ function getForm(taskId?: number, formId?: number): types.IForm | null {
1439
1889
  }
1440
1890
 
1441
1891
  /**
1442
- * --- 直接创建一个窗体(需要验证传入 code、layout 等是否能成功创建) ---
1892
+ * --- 创建一个窗体,App 模式下无效 ---
1443
1893
  * @param opt 创建窗体的配置对象
1444
1894
  */
1445
- export async function create(opt: string | types.IFormCreateOptions): Promise<number | types.IForm> {
1446
- if (typeof opt === 'string') {
1447
- return 0;
1448
- }
1895
+ export async function create(opt: types.IFormCreateOptions): Promise<number> {
1449
1896
  if (!opt.taskId) {
1450
1897
  return -1;
1451
1898
  }
1452
- if (opt.path && (!opt.path.endsWith('/') || !opt.path?.startsWith('/'))) {
1453
- return -2;
1454
- }
1455
- const taskId = opt.taskId;
1456
1899
  /** --- 当前的 task 对象 --- */
1457
- const t = task.list[taskId];
1900
+ const t = task.list[opt.taskId];
1458
1901
  if (!t) {
1459
- return -3;
1460
- }
1461
- let form: types.IForm | null = null;
1462
- if (opt.formId) {
1463
- if (!t.forms[opt.formId]) {
1464
- return -4;
1465
- }
1466
- form = t.forms[opt.formId];
1902
+ return -2;
1467
1903
  }
1468
- /** --- 是否创建置顶的窗体 --- */
1469
- let topMost = opt.topMost ?? false;
1470
- if (form?.vroot.cgTopMost) {
1471
- topMost = true;
1904
+ // --- 申请 formId ---
1905
+ const formId = ++info.lastId;
1906
+ // --- 获取要定义的控件列表 ---
1907
+ const components = control.buildComponents(t.id, formId, opt.path ?? '');
1908
+ if (!components) {
1909
+ return -3;
1472
1910
  }
1473
- // --- 是否要给原窗体增加遮罩 ---
1474
- if (opt.mask && form) {
1475
- form.vroot.$refs.form.maskFor = 0;
1911
+ // --- 准备相关变量 ---
1912
+ let data: Record<string, any> = {};
1913
+ let methods: Record<string, any> | undefined = undefined;
1914
+ let computed: Record<string, any> = {};
1915
+ let beforeCreate: (() => void) | undefined = undefined;
1916
+ let created: (() => void) | undefined = undefined;
1917
+ let beforeMount: (() => void) | undefined = undefined;
1918
+ let mounted: ((data?: Record<string, any>) => void | Promise<void>) | undefined = undefined;
1919
+ let beforeUpdate: (() => void) | undefined = undefined;
1920
+ let updated: (() => void) | undefined = undefined;
1921
+ let beforeUnmount: (() => void) | undefined = undefined;
1922
+ let unmounted: (() => void) | undefined = undefined;
1923
+ if (opt.code) {
1924
+ data = opt.code.data ?? {};
1925
+ methods = opt.code.methods;
1926
+ computed = opt.code.computed ?? {};
1927
+ beforeCreate = opt.code.beforeCreate;
1928
+ created = opt.code.created;
1929
+ beforeMount = opt.code.beforeMount;
1930
+ mounted = opt.code.mounted;
1931
+ beforeUpdate = opt.code.beforeUpdate;
1932
+ updated = opt.code.updated;
1933
+ beforeUnmount = opt.code.beforeUnmount;
1934
+ unmounted = opt.code.unmounted;
1476
1935
  }
1477
- /** --- 当前父 form 的路径(以 / 结尾)或 /(没有基路径的话) --- */
1478
- const base: string = form ? form.vroot.cgPath : '/';
1479
- /** --- 要新建的 form 的文件路径 --- */
1480
- let filePath = '', newBase = '';
1481
- if (opt.file) {
1482
- filePath = clickgo.tool.urlResolve(base, opt.file);
1483
- newBase = filePath.slice(0, filePath.lastIndexOf('/') + 1);
1936
+ // --- 应用样式表 ---
1937
+ let style = '';
1938
+ let prep = '';
1939
+ if (opt.style) {
1940
+ // --- 将 style 中的 tag 标签转换为 class,如 button 变为 .tag-button,然后将 class 进行标准程序,添加 prep 进行区分隔离 ---
1941
+ const r = tool.stylePrepend(opt.style);
1942
+ prep = r.prep;
1943
+ style = await tool.styleUrl2DataUrl(opt.path ?? '/', r.style, t.app.files);
1484
1944
  }
1485
- else {
1486
- newBase = opt.path ?? base;
1487
- }
1488
-
1489
- /** --- 当前的 APP 对象 --- */
1490
- const app: types.IApp = t.app;
1491
- // --- 申请 formId ---
1492
- const formId = ++info.lastId;
1493
- // --- 注入的参数,屏蔽浏览器全局对象,注入新的对象 ---
1494
- const invoke: Record<string, any> = {};
1495
- if (clickgo.getSafe()) {
1496
- invoke.window = undefined;
1497
- invoke.loader = undefined;
1498
- const ks = Object.getOwnPropertyNames(window);
1499
- for (const k of ks) {
1500
- if (k.includes('Event')) {
1501
- continue;
1502
- }
1503
- if (k.includes('-')) {
1504
- continue;
1505
- }
1506
- if (/^[0-9]+$/.test(k)) {
1507
- continue;
1508
- }
1509
- if ([
1510
- 'require',
1511
- '__awaiter', 'eval', 'Math', 'Array', 'Blob', 'Infinity', 'parseInt', 'parseFloat', 'Promise', 'Date', 'JSON', 'fetch'].includes(k)) {
1512
- continue;
1513
- }
1514
- invoke[k] = undefined;
1515
- }
1516
- // --- console ---
1517
- invoke.console = {
1518
- log: function(message?: any, ...optionalParams: any[]) {
1519
- console.log(message, ...optionalParams);
1520
- }
1521
- };
1522
- // --- loader ---
1523
- invoke.loader = {
1524
- require: function(paths: string | string[], files: Record<string, Blob | string>, opt?: {
1525
- 'executed'?: Record<string, any>;
1526
- 'map'?: Record<string, string>;
1527
- 'dir'?: string;
1528
- 'style'?: string;
1529
- 'invoke'?: Record<string, any>;
1530
- 'preprocess'?: (code: string, path: string) => string;
1531
- }): any[] {
1532
- return loader.require(paths, files, opt);
1533
- }
1534
- };
1535
- // --- Object ---
1536
- invoke.Object = {
1537
- defineProperty: function(): void {
1538
- return;
1539
- },
1540
- keys: function(o: any): string[] {
1541
- return Object.keys(o);
1542
- },
1543
- assign: function(o: any, o2: any): any {
1544
- if (o.controlName !== undefined) {
1545
- return o;
1546
- }
1547
- return Object.assign(o, o2);
1548
- }
1549
- };
1550
- invoke.navigator = {};
1551
- if (navigator.clipboard) {
1552
- invoke.navigator.clipboard = navigator.clipboard;
1553
- }
1554
- // --- ClickGo 相关 ---
1555
- invoke.invokeClickgo = {
1556
- getVersion: function(): string {
1557
- return clickgo.getVersion();
1558
- },
1559
- getNative(): boolean {
1560
- return clickgo.getNative();
1561
- },
1562
- getPlatform(): string {
1563
- return clickgo.getPlatform();
1564
- },
1565
- getSafe(): boolean {
1566
- return clickgo.getSafe();
1567
- },
1568
- 'control': {
1569
- read: function(blob: Blob): Promise<false | types.TControl> {
1570
- return clickgo.control.read(blob);
1571
- }
1572
- },
1573
- 'core': {
1574
- 'config': clickgo.core.config,
1575
- 'cdn': loader.cdn,
1576
- initModules: function(names: string | string[]): Promise<number> {
1577
- return clickgo.core.initModules(names);
1578
- },
1579
- getModule: function(name: string): null | any {
1580
- return clickgo.core.getModule(name);
1581
- },
1582
- setSystemEventListener: function(
1583
- name: types.TGlobalEvent,
1584
- func: (...any: any) => void | Promise<void>,
1585
- fid?: number
1586
- ): void {
1587
- clickgo.core.setSystemEventListener(name, func, fid ?? formId, taskId);
1588
- },
1589
- removeSystemEventListener: function(
1590
- name: types.TGlobalEvent,
1591
- fid?: number
1592
- ): void {
1593
- clickgo.core.removeSystemEventListener(name, fid ?? formId, taskId);
1594
- },
1595
- trigger: function(name: types.TGlobalEvent, param1: boolean | Error | string = '', param2: string = ''): void {
1596
- if (!['formTitleChanged', 'formIconChanged', 'formStateMinChanged', 'formStateMaxChanged', 'formShowChanged'].includes(name)) {
1597
- return;
1598
- }
1599
- clickgo.core.trigger(name, taskId, formId, param1, param2);
1600
- },
1601
- readApp: function(blob: Blob): Promise<false | types.IApp> {
1602
- return clickgo.core.readApp(blob);
1603
- },
1604
- getAvailArea: function(): types.IAvailArea {
1605
- return clickgo.core.getAvailArea();
1606
- }
1607
- },
1608
- 'dom': {
1609
- setGlobalCursor: function(type?: string): void {
1610
- clickgo.dom.setGlobalCursor(type);
1611
- },
1612
- hasTouchButMouse: function(e: MouseEvent | TouchEvent | PointerEvent): boolean {
1613
- return clickgo.dom.hasTouchButMouse(e);
1614
- },
1615
- getStyleCount: function(taskId: number, type: 'theme' | 'control' | 'form'): number {
1616
- return clickgo.dom.getStyleCount(taskId, type);
1617
- },
1618
- getSize: function(el: HTMLElement): types.IDomSize {
1619
- return clickgo.dom.getSize(el);
1620
- },
1621
- watchSize: function(
1622
- el: HTMLElement,
1623
- cb: (size: types.IDomSize) => Promise<void> | void,
1624
- immediate: boolean = false
1625
- ): types.IDomSize {
1626
- return clickgo.dom.watchSize(el, cb, immediate, taskId);
1627
- },
1628
- unwatchSize: function(el: HTMLElement): void {
1629
- clickgo.dom.unwatchSize(el, taskId);
1630
- },
1631
- clearWatchSize(): void {
1632
- clickgo.dom.clearWatchSize(taskId);
1633
- },
1634
- watch: function(el: HTMLElement, cb: () => void, mode: 'child' | 'childsub' | 'style' | 'default' = 'default', immediate: boolean = false): void {
1635
- clickgo.dom.watch(el, cb, mode, immediate, taskId);
1636
- },
1637
- unwatch: function(el: HTMLElement): void {
1638
- clickgo.dom.unwatch(el, taskId);
1639
- },
1640
- clearWatch: function(): void {
1641
- clickgo.dom.clearWatch(taskId);
1642
- },
1643
- watchStyle: function(
1644
- el: HTMLElement,
1645
- name: string | string[],
1646
- cb: (name: string, value: string) => void,
1647
- immediate: boolean = false
1648
- ): void {
1649
- clickgo.dom.watchStyle(el, name, cb, immediate);
1650
- },
1651
- isWatchStyle: function(el: HTMLElement): boolean {
1652
- return clickgo.dom.isWatchStyle(el);
1653
- },
1654
- bindDown: function(oe: MouseEvent | TouchEvent, opt: types.IBindDownOptions) {
1655
- clickgo.dom.bindDown(oe, opt);
1656
- },
1657
- bindGesture: function(e: MouseEvent | TouchEvent | WheelEvent | { 'x'?: number; 'y'?: number; }, opt: types.IBindGestureOptions): void {
1658
- clickgo.dom.bindGesture(e, opt);
1659
- },
1660
- bindLong: function(
1661
- e: MouseEvent | TouchEvent,
1662
- long: (e: MouseEvent | TouchEvent) => void | Promise<void>
1663
- ): void {
1664
- clickgo.dom.bindLong(e, long);
1665
- },
1666
- bindDrag: function(e: MouseEvent | TouchEvent, opt: { 'el': HTMLElement; 'data'?: any; }): void {
1667
- clickgo.dom.bindDrag(e, opt);
1668
- },
1669
- 'is': clickgo.dom.is,
1670
- bindMove: function(e: MouseEvent | TouchEvent, opt: types.IBindMoveOptions): types.IBindMoveResult {
1671
- return clickgo.dom.bindMove(e, opt);
1672
- },
1673
- bindResize: function(e: MouseEvent | TouchEvent, opt: types.IBindResizeOptions): void {
1674
- clickgo.dom.bindResize(e, opt);
1675
- },
1676
- findParentByData: function(el: HTMLElement, name: string): HTMLElement | null {
1677
- return clickgo.dom.findParentByData(el, name);
1678
- },
1679
- findParentByClass: function(el: HTMLElement, name: string): HTMLElement | null {
1680
- return clickgo.dom.findParentByClass(el, name);
1681
- },
1682
- siblings: function(el: HTMLElement): HTMLElement[] {
1683
- return clickgo.dom.siblings(el);
1684
- },
1685
- siblingsData: function(el: HTMLElement, name: string): HTMLElement[] {
1686
- return clickgo.dom.siblingsData(el, name);
1687
- },
1688
- fullscreen: function(): boolean {
1689
- return clickgo.dom.fullscreen();
1690
- }
1691
- },
1692
- 'form': {
1693
- min: function(fid?: number): boolean {
1694
- return clickgo.form.min(fid ?? formId);
1695
- },
1696
- max: function max(fid?: number): boolean {
1697
- return clickgo.form.max(fid ?? formId);
1698
- },
1699
- close: function(fid?: number): boolean {
1700
- return clickgo.form.close(fid ?? formId);
1701
- },
1702
- bindResize: function(e: MouseEvent | TouchEvent, border: types.TBorder): void {
1703
- clickgo.form.bindResize(e, border);
1704
- },
1705
- bindDrag: function(e: MouseEvent | TouchEvent): void {
1706
- clickgo.form.bindDrag(e);
1707
- },
1708
- getTaskId: function(fid: number): number {
1709
- return clickgo.form.getTaskId(fid);
1710
- },
1711
- get: function(fid: number): types.IFormInfo | null {
1712
- return clickgo.form.get(fid);
1713
- },
1714
- send: function(fid: number, obj: Record<string, any>): void {
1715
- obj.taskId = taskId;
1716
- obj.formId = formId;
1717
- clickgo.form.send(fid, obj);
1718
- },
1719
- getList: function(tid: number): Record<string, types.IFormInfo> {
1720
- return clickgo.form.getList(tid);
1721
- },
1722
- changeFocus: function(fid: number = 0): void {
1723
- clickgo.form.changeFocus(fid);
1724
- },
1725
- getMaxZIndexID: function(out?: {
1726
- 'taskIds'?: number[];
1727
- 'formIds'?: number[];
1728
- }): number | null {
1729
- return clickgo.form.getMaxZIndexID(out);
1730
- },
1731
- getRectByBorder: function(border: types.TBorder): { 'width': number; 'height': number; 'left': number; 'top': number; } {
1732
- return clickgo.form.getRectByBorder(border);
1733
- },
1734
- showCircular: function(x: number, y: number): void {
1735
- clickgo.form.showCircular(x, y);
1736
- },
1737
- moveRectangle: function(border: types.TBorder): void {
1738
- clickgo.form.moveRectangle(border);
1739
- },
1740
- showRectangle: function(x: number, y: number, border: types.TBorder): void {
1741
- clickgo.form.showRectangle(x, y, border);
1742
- },
1743
- hideRectangle: function(): void {
1744
- clickgo.form.hideRectangle();
1745
- },
1746
- showDrag: function(): void {
1747
- clickgo.form.showDrag();
1748
- },
1749
- moveDrag: function(opt: types.IMoveDragOptions): void {
1750
- clickgo.form.moveDrag(opt);
1751
- },
1752
- hideDrag: function(): void {
1753
- clickgo.form.hideDrag();
1754
- },
1755
- notify: function(opt: types.INotifyOptions): number {
1756
- return clickgo.form.notify(opt);
1757
- },
1758
- notifyProgress: function(notifyId: number, per: number): void {
1759
- clickgo.form.notifyProgress(notifyId, per);
1760
- },
1761
- hideNotify: function(notifyId: number): void {
1762
- clickgo.form.hideNotify(notifyId);
1763
- },
1764
- showPop: function(el: HTMLElement, pop: HTMLElement | undefined, direction: 'h' | 'v' | MouseEvent | TouchEvent | { x: number; y: number; }, opt: { 'size'?: { width?: number; height?: number; }; 'null'?: boolean; } = {}): void {
1765
- clickgo.form.showPop(el, pop, direction, opt);
1766
- },
1767
- hidePop: function(pop?: HTMLElement): void {
1768
- clickgo.form.hidePop(pop);
1769
- },
1770
- create: function(opt: string | types.IFormCreateOptions): Promise<number | types.IForm> {
1771
- if (typeof opt === 'string') {
1772
- opt = {
1773
- 'file': opt
1774
- };
1775
- }
1776
- opt.taskId = taskId;
1777
- opt.formId = formId;
1778
- return clickgo.form.create(opt);
1779
- },
1780
- dialog: function(opt: string | types.IFormDialogOptions): Promise<string> {
1781
- if (typeof opt === 'string') {
1782
- opt = {
1783
- 'content': opt
1784
- };
1785
- }
1786
- opt.formId = formId;
1787
- return clickgo.form.dialog(opt);
1788
- },
1789
- confirm: function(opt: string | types.IFormConfirmOptions): Promise<boolean | number> {
1790
- if (typeof opt === 'string') {
1791
- opt = {
1792
- 'content': opt
1793
- };
1794
- }
1795
- opt.formId = formId;
1796
- return clickgo.form.confirm(opt);
1797
- },
1798
- setTopMost: function(top: boolean, opt: types.IFormSetTopMostOptions = {}): void {
1799
- opt.taskId = taskId;
1800
- opt.formId = formId;
1801
- clickgo.form.setTopMost(top, opt);
1802
- },
1803
- flash: function(fid?: number): void {
1804
- clickgo.form.flash(fid ?? formId, taskId);
1805
- },
1806
- show: function(fid?: number): void {
1807
- clickgo.form.show(fid ?? formId, taskId);
1808
- },
1809
- hide: function(fid?: number): void {
1810
- clickgo.form.hide(fid ?? formId, taskId);
1811
- },
1812
- showLauncher: function(): void {
1813
- clickgo.form.showLauncher();
1814
- },
1815
- hideLauncher: function(): void {
1816
- clickgo.form.hideLauncher();
1817
- }
1818
- },
1819
- 'fs': {
1820
- getContent: function(
1821
- path: string,
1822
- options: any = {}
1823
- ): Promise<Blob | string | null> {
1824
- if (!options.files) {
1825
- options.files = t.files;
1826
- }
1827
- if (!options.current) {
1828
- options.current = t.path;
1829
- }
1830
- return clickgo.fs.getContent(path, options);
1831
- },
1832
- putContent: function(path: string, data: string | Buffer, options: any = {}) {
1833
- if (!options.current) {
1834
- options.current = t.path;
1835
- }
1836
- return clickgo.fs.putContent(path, data, options);
1837
- },
1838
- readLink: function(path: string, options: any = {}): Promise<string | null> {
1839
- if (!options.current) {
1840
- options.current = t.path;
1841
- }
1842
- return clickgo.fs.readLink(path, options);
1843
- },
1844
- symlink: function(fPath: string, linkPath: string, options: any = {}): Promise<boolean> {
1845
- if (!options.current) {
1846
- options.current = t.path;
1847
- }
1848
- return clickgo.fs.symlink(fPath, linkPath, options);
1849
- },
1850
- unlink: function(path: string, options: any = {}): Promise<boolean> {
1851
- if (!options.current) {
1852
- options.current = t.path;
1853
- }
1854
- return clickgo.fs.unlink(path, options);
1855
- },
1856
- stats: function(path: string, options: any = {}): Promise<types.IStats | null> {
1857
- if (!options.files) {
1858
- options.files = t.files;
1859
- }
1860
- if (!options.current) {
1861
- options.current = t.path;
1862
- }
1863
- return clickgo.fs.stats(path, options);
1864
- },
1865
- isDir: function(path: string, options: any = {}): Promise<types.IStats | false> {
1866
- if (!options.files) {
1867
- options.files = t.files;
1868
- }
1869
- if (!options.current) {
1870
- options.current = t.path;
1871
- }
1872
- return clickgo.fs.isDir(path, options);
1873
- },
1874
- isFile: function(path: string, options: any = {}): Promise<types.IStats | false> {
1875
- if (!options.files) {
1876
- options.files = t.files;
1877
- }
1878
- if (!options.current) {
1879
- options.current = t.path;
1880
- }
1881
- return clickgo.fs.isFile(path, options);
1882
- },
1883
- mkdir: function(path: string, mode?: number, options: any = {}): Promise<boolean> {
1884
- if (!options.current) {
1885
- options.current = t.path;
1886
- }
1887
- return clickgo.fs.mkdir(path, mode, options);
1888
- },
1889
- rmdir: function(path: string, options: any = {}): Promise<boolean> {
1890
- if (!options.current) {
1891
- options.current = t.path;
1892
- }
1893
- return clickgo.fs.rmdir(path, options);
1894
- },
1895
- rmdirDeep: function(path: string, options: any = {}): Promise<boolean> {
1896
- if (!options.current) {
1897
- options.current = t.path;
1898
- }
1899
- return clickgo.fs.rmdirDeep(path, options);
1900
- },
1901
- chmod: function(path: string, mod: string | number, options: any = {}): Promise<boolean> {
1902
- if (!options.current) {
1903
- options.current = t.path;
1904
- }
1905
- return clickgo.fs.chmod(path, mod, options);
1906
- },
1907
- rename(oldPath: string, newPath: string, options: any = {}): Promise<boolean> {
1908
- if (!options.current) {
1909
- options.current = t.path;
1910
- }
1911
- return clickgo.fs.rename(oldPath, newPath, options);
1912
- },
1913
- readDir(path: string, options: any = {}): Promise<types.IDirent[]> {
1914
- if (!options.files) {
1915
- options.files = t.files;
1916
- }
1917
- if (!options.current) {
1918
- options.current = t.path;
1919
- }
1920
- return clickgo.fs.readDir(path, options);
1921
- },
1922
- copyFolder(from: string, to: string, options: any = {}): Promise<number> {
1923
- if (!options.current) {
1924
- options.current = t.path;
1925
- }
1926
- return clickgo.fs.copyFolder(from, to, options);
1927
- },
1928
- copyFile(src: string, dest: string, options: any = {}): Promise<boolean> {
1929
- if (!options.current) {
1930
- options.current = t.path;
1931
- }
1932
- return clickgo.fs.copyFile(src, dest, options);
1933
- }
1934
- },
1935
- 'native': {
1936
- invoke: function(name: string, ...param: any[]): any {
1937
- return clickgo.native.invoke(name, ...param);
1938
- },
1939
- max: function(): void {
1940
- clickgo.native.max();
1941
- },
1942
- min: function(): void {
1943
- clickgo.native.min();
1944
- },
1945
- restore: function(): void {
1946
- clickgo.native.restore();
1947
- },
1948
- size: function(width: number, height: number): void {
1949
- clickgo.native.size(width, height);
1950
- }
1951
- },
1952
- 'task': {
1953
- onFrame: function(fun: () => void | Promise<void>, opt: {
1954
- 'scope'?: 'form' | 'task';
1955
- 'count'?: number;
1956
- 'taskId'?: number;
1957
- 'formId'?: number;
1958
- } = {}): number {
1959
- opt.taskId = taskId;
1960
- opt.formId = formId;
1961
- return clickgo.task.onFrame(fun, opt);
1962
- },
1963
- offFrame: function(ft: number, opt: {
1964
- 'taskId'?: number;
1965
- } = {}): void {
1966
- opt.taskId = taskId;
1967
- clickgo.task.offFrame(ft, opt);
1968
- },
1969
- get: function(tid: number): types.ITaskInfo | null {
1970
- return clickgo.task.get(tid);
1971
- },
1972
- getList: function(): Record<string, types.ITaskInfo> {
1973
- return clickgo.task.getList();
1974
- },
1975
- run: function(url: string, opt: types.ITaskRunOptions = {}): Promise<number> {
1976
- opt.taskId = taskId;
1977
- opt.main = false;
1978
- return clickgo.task.run(url, opt);
1979
- },
1980
- end: function(tid: number): boolean {
1981
- return clickgo.task.end(tid ?? taskId);
1982
- },
1983
- loadLocaleData: function(lang: string, data: Record<string, any>, pre: string = ''): void {
1984
- clickgo.task.loadLocaleData(lang, data, pre, taskId);
1985
- },
1986
- loadLocale: function(lang: string, path: string): Promise<boolean> {
1987
- return clickgo.task.loadLocale(lang, path, taskId, formId);
1988
- },
1989
- clearLocale: function(): void {
1990
- clickgo.task.clearLocale(taskId);
1991
- },
1992
- setLocale: function(lang: string, path: string): Promise<boolean> {
1993
- return clickgo.task.setLocale(lang, path, taskId, formId);
1994
- },
1995
- setLocaleLang: function(lang: string): void {
1996
- clickgo.task.setLocaleLang(lang, taskId);
1997
- },
1998
- clearLocaleLang: function(): void {
1999
- clickgo.task.clearLocaleLang(taskId);
2000
- },
2001
- createTimer: function(
2002
- fun: () => void | Promise<void>,
2003
- delay: number,
2004
- opt: types.ICreateTimerOptions = {}
2005
- ): number {
2006
- opt.taskId = taskId;
2007
- if (!opt.formId) {
2008
- opt.formId = formId;
2009
- }
2010
- return clickgo.task.createTimer(fun, delay, opt);
2011
- },
2012
- removeTimer: function(timer: number): void {
2013
- clickgo.task.removeTimer(timer, taskId);
2014
- },
2015
- sleep: function(fun: () => void | Promise<void>, delay: number): number {
2016
- return clickgo.task.sleep(fun, delay, taskId, formId);
2017
- },
2018
- systemTaskInfo: clickgo.task.systemTaskInfo,
2019
- setSystem: function(fid?: number): boolean {
2020
- return clickgo.task.setSystem(fid ?? formId, taskId);
2021
- },
2022
- clearSystem: function(): boolean {
2023
- return clickgo.task.clearSystem(taskId);
2024
- }
2025
- },
2026
- 'theme': {
2027
- read: function(blob: Blob): Promise<types.ITheme | false> {
2028
- return clickgo.theme.read(blob);
2029
- },
2030
- load: async function(theme?: types.ITheme): Promise<boolean> {
2031
- if (!theme) {
2032
- return false;
2033
- }
2034
- return clickgo.theme.load(theme, taskId);
2035
- },
2036
- remove: function(name: string): Promise<void> {
2037
- return clickgo.theme.remove(name, taskId);
2038
- },
2039
- clear: function(): Promise<void> {
2040
- return clickgo.theme.clear(taskId);
2041
- },
2042
- setGlobal: function(theme: types.ITheme): Promise<void> {
2043
- return clickgo.theme.setGlobal(theme);
2044
- },
2045
- clearGlobal: function(): void {
2046
- clickgo.theme.clearGlobal();
2047
- }
2048
- },
2049
- 'tool': {
2050
- blob2ArrayBuffer: function(blob: Blob): Promise<ArrayBuffer> {
2051
- return clickgo.tool.blob2ArrayBuffer(blob);
2052
- },
2053
- clone: function(obj: Record<string, any> | any[]): any[] | any {
2054
- return clickgo.tool.clone(obj);
2055
- },
2056
- sleep: function(ms: number = 0): Promise<boolean> {
2057
- return clickgo.tool.sleep(ms);
2058
- },
2059
- purify: function(text: string): string {
2060
- return clickgo.tool.purify(text);
2061
- },
2062
- createObjectURL: function(object: Blob): string {
2063
- return clickgo.tool.createObjectURL(object, taskId);
2064
- },
2065
- revokeObjectURL: function(url: string): void {
2066
- clickgo.tool.revokeObjectURL(url, taskId);
2067
- },
2068
- rand: function(min: number, max: number): number {
2069
- return clickgo.tool.rand(min, max);
2070
- },
2071
- 'RANDOM_N': clickgo.tool.RANDOM_N,
2072
- 'RANDOM_U': clickgo.tool.RANDOM_U,
2073
- 'RANDOM_L': clickgo.tool.RANDOM_L,
2074
- 'RANDOM_UN': clickgo.tool.RANDOM_UN,
2075
- 'RANDOM_LN': clickgo.tool.RANDOM_LN,
2076
- 'RANDOM_LU': clickgo.tool.RANDOM_LU,
2077
- 'RANDOM_LUN': clickgo.tool.RANDOM_LUN,
2078
- 'RANDOM_V': clickgo.tool.RANDOM_V,
2079
- 'RANDOM_LUNS': clickgo.tool.RANDOM_LUNS,
2080
- random: function(length: number = 8, source: string = clickgo.tool.RANDOM_LN, block: string = ''): string {
2081
- return clickgo.tool.random(length, source, block);
2082
- },
2083
- getBoolean: function(param: boolean | string | number): boolean {
2084
- return clickgo.tool.getBoolean(param);
2085
- },
2086
- escapeHTML: function(html: string): string {
2087
- return clickgo.tool.escapeHTML(html);
2088
- },
2089
- request: function(url: string, opt: types.IRequestOptions): Promise<null | any> {
2090
- return clickgo.tool.request(url, opt);
2091
- },
2092
- parseUrl: function(url: string): ILoaderUrl {
2093
- return clickgo.tool.parseUrl(url);
2094
- },
2095
- urlResolve: function(from: string, to: string): string {
2096
- return clickgo.tool.urlResolve(from, to);
2097
- },
2098
- blob2Text: function(blob: Blob): Promise<string> {
2099
- return clickgo.tool.blob2Text(blob);
2100
- },
2101
- blob2DataUrl: function(blob: Blob): Promise<string> {
2102
- return clickgo.tool.blob2DataUrl(blob);
2103
- },
2104
- execCommand: function(ac: string): void {
2105
- clickgo.tool.execCommand(ac);
2106
- }
2107
- },
2108
- 'zip': {
2109
- get: function(data?: types.TZipInputFileFormat) {
2110
- return clickgo.zip.get(data);
2111
- }
2112
- }
2113
- };
2114
- }
2115
- else {
2116
- invoke.invokeClickgo = clickgo;
2117
- }
2118
- // --- 代码预处理 ---
2119
- const preprocess = clickgo.getSafe() ? function(code: string, path: string): string {
2120
- const exec = /eval\W/.exec(code);
2121
- if (exec) {
2122
- notify({
2123
- 'title': 'Error',
2124
- 'content': `The "eval" is prohibited.\nFile: "${path}".`,
2125
- 'type': 'danger'
2126
- });
2127
- return '';
2128
- }
2129
- return code;
2130
- } : undefined;
2131
- // --- 获取要定义的控件列表 ---
2132
- const components = await control.init(t.id, formId, newBase, preprocess, invoke);
2133
- if (!components) {
2134
- if (form?.vroot.$refs.form.maskFor !== undefined) {
2135
- form.vroot.$refs.form.maskFor = undefined;
2136
- }
2137
- return -5;
2138
- }
2139
- // --- 获取 style、layout ---
2140
- let style = opt.style;
2141
- let layout: string | undefined = opt.layout;
2142
- if (filePath) {
2143
- if (!filePath.startsWith('/package/')) {
2144
- return -6;
2145
- }
2146
- const file = filePath.slice(8);
2147
- const layoutFile = app.files[file + '.xml'] as string;
2148
- if (layoutFile) {
2149
- layout = layoutFile.replace(/^\ufeff/, '');
2150
- }
2151
- const styleFile = app.files[file + '.css'] as string;
2152
- if (styleFile) {
2153
- style = styleFile.replace(/^\ufeff/, '');
2154
- }
2155
- }
2156
- if (layout === undefined) {
2157
- if (form?.vroot.$refs.form.maskFor !== undefined) {
2158
- form.vroot.$refs.form.maskFor = undefined;
2159
- }
2160
- return -7;
2161
- }
2162
- // --- 准备相关变量 ---
2163
- let data: Record<string, any> = {};
2164
- let methods: any = {};
2165
- let computed: any = {};
2166
- let watch = {};
2167
- let beforeCreate: (() => void) | undefined = undefined;
2168
- let created: (() => void) | undefined = undefined;
2169
- let beforeMount: (() => void) | undefined = undefined;
2170
- let mounted: ((data?: Record<string, any>) => void | Promise<void>) | undefined = undefined;
2171
- let beforeUpdate: (() => void) | undefined = undefined;
2172
- let updated: (() => void) | undefined = undefined;
2173
- let beforeUnmount: (() => void) | undefined = undefined;
2174
- let unmounted: (() => void) | undefined = undefined;
2175
- let receive: ((obj: Record<string, any>) => void) | undefined = undefined;
2176
- // --- 检测是否有 js ---
2177
- let expo = opt.code;
2178
- if (filePath?.startsWith('/package/') && app.files[filePath.slice(8) + '.js']) {
2179
- const file = filePath.slice(8);
2180
- if (app.files[file + '.js']) {
2181
- app.files['/invoke/clickgo.js'] = `module.exports = invokeClickgo;`;
2182
- expo = loader.require(file, app.files, {
2183
- 'dir': '/',
2184
- 'invoke': invoke,
2185
- 'preprocess': preprocess,
2186
- 'map': {
2187
- 'clickgo': '/invoke/clickgo'
2188
- }
2189
- })[0];
2190
- }
2191
- }
2192
- if (expo) {
2193
- data = expo.data ?? {};
2194
- methods = expo.methods || {};
2195
- computed = expo.computed || {};
2196
- watch = expo.watch || {};
2197
- beforeCreate = expo.beforeCreate;
2198
- created = expo.created;
2199
- beforeMount = expo.beforeMount;
2200
- mounted = expo.mounted;
2201
- beforeUpdate = expo.beforeUpdate;
2202
- updated = expo.updated;
2203
- beforeUnmount = expo.beforeUnmount;
2204
- unmounted = expo.unmounted;
2205
- receive = expo.receive;
2206
- }
2207
- // --- 应用样式表 ---
2208
- let prep = '';
2209
- if (style) {
2210
- // --- 将 style 中的 tag 标签转换为 class,如 button 变为 .tag-button,然后将 class 进行标准程序,添加 prep 进行区分隔离 ---
2211
- const r = tool.stylePrepend(style);
2212
- prep = r.prep;
2213
- style = await tool.styleUrl2DataUrl(newBase, r.style, app.files);
2214
- }
2215
- // --- 要创建的 form 的 layout 所有标签增加 cg 前缀,并增加新的 class 为 tag-xxx ---
2216
- layout = tool.purify(layout);
2217
- // --- 标签增加 cg- 前缀,增加 class 为 tag-xxx ---
2218
- layout = tool.layoutAddTagClassAndReTagName(layout, true);
2219
- // --- 给所有控件传递窗体的 focus 信息 ---
2220
- layout = tool.layoutInsertAttr(layout, ':cg-focus=\'cgFocus\'', {
2221
- 'include': [/^cg-.+/]
2222
- });
2223
- // --- 给 layout 的 class 增加前置 ---
2224
- const prepList = ['cg-task' + opt.taskId.toString() + '_'];
2225
- if (prep !== '') {
2226
- prepList.push(prep);
1945
+ // --- 要创建的 form 的 layout 所有标签增加 cg 前缀,并增加新的 class 为 tag-xxx ---
1946
+ let layout = tool.purify(opt.layout);
1947
+ // --- 标签增加 cg- 前缀,增加 class 为 tag-xxx ---
1948
+ layout = tool.layoutAddTagClassAndReTagName(layout, true);
1949
+ // --- 给所有控件传递窗体的 focus 信息 ---
1950
+ layout = tool.layoutInsertAttr(layout, ':form-focus=\'formFocus\'', {
1951
+ 'include': [/^cg-.+/]
1952
+ });
1953
+ // --- layout 的 class 增加前置 ---
1954
+ const prepList = ['cg-task' + opt.taskId.toString() + '_'];
1955
+ if (prep !== '') {
1956
+ prepList.push(prep);
2227
1957
  }
2228
1958
  layout = tool.layoutClassPrepend(layout, prepList);
2229
1959
  // --- 给 event 增加包裹 ---
@@ -2238,20 +1968,6 @@ export async function create(opt: string | types.IFormCreateOptions): Promise<nu
2238
1968
  // --- 获取刚才的 form wrap element 对象 ---
2239
1969
  const el: HTMLElement = elements.list.children.item(elements.list.children.length - 1) as HTMLElement;
2240
1970
  // --- 创建窗体对象 ---
2241
- // --- 初始化系统初始 data ---
2242
- computed.taskId = {
2243
- get: function(): number {
2244
- return taskId;
2245
- },
2246
- set: function(): void {
2247
- notify({
2248
- 'title': 'Error',
2249
- 'content': `The software tries to modify the system variable "taskId".\nPath: ${this.cgPath}`,
2250
- 'type': 'danger'
2251
- });
2252
- return;
2253
- }
2254
- };
2255
1971
  computed.formId = {
2256
1972
  get: function(): number {
2257
1973
  return formId;
@@ -2259,161 +1975,100 @@ export async function create(opt: string | types.IFormCreateOptions): Promise<nu
2259
1975
  set: function(): void {
2260
1976
  notify({
2261
1977
  'title': 'Error',
2262
- 'content': `The software tries to modify the system variable "formId".\nPath: ${this.cgPath}`,
1978
+ 'content': `The software tries to modify the system variable "formId".\nPath: ${this.filename}`,
2263
1979
  'type': 'danger'
2264
1980
  });
2265
1981
  return;
2266
1982
  }
2267
1983
  };
2268
- computed.controlName = {
1984
+ data._formFocus = false;
1985
+ computed.path = {
2269
1986
  get: function(): string {
2270
- return 'root';
1987
+ return opt.path ?? '';
2271
1988
  },
2272
1989
  set: function(): void {
2273
1990
  notify({
2274
1991
  'title': 'Error',
2275
- 'content': `The software tries to modify the system variable "controlName".\nPath: ${this.cgPath}`,
1992
+ 'content': `The software tries to modify the system variable "path".\nPath: ${this.filename}`,
2276
1993
  'type': 'danger'
2277
1994
  });
2278
1995
  return;
2279
1996
  }
2280
1997
  };
2281
- data._cgFocus = false;
2282
- computed.cgFocus = {
2283
- get: function(): number {
2284
- return this._cgFocus;
2285
- },
2286
- set: function(): void {
2287
- notify({
2288
- 'title': 'Error',
2289
- 'content': `The software tries to modify the system variable "cgFocus".\nPath: ${this.cgPath}`,
2290
- 'type': 'danger'
2291
- });
2292
- return;
2293
- }
2294
- };
2295
- computed.cgPath = {
2296
- get: function(): string {
2297
- return newBase;
2298
- },
2299
- set: function(): void {
2300
- notify({
2301
- 'title': 'Error',
2302
- 'content': `The software tries to modify the system variable "cgPath".\nPath: ${this.cgPath}`,
2303
- 'type': 'danger'
2304
- });
2305
- return;
2306
- }
2307
- };
2308
- computed.cgPrep = {
1998
+ computed.prep = {
2309
1999
  get: function(): string {
2310
2000
  return prep;
2311
2001
  },
2312
2002
  set: function(): void {
2313
2003
  notify({
2314
2004
  'title': 'Error',
2315
- 'content': `The software tries to modify the system variable "cgPrep".\nPath: ${this._cgPath}`,
2316
- 'type': 'danger'
2317
- });
2318
- return;
2319
- }
2320
- };
2321
- data._cgCustomZIndex = false;
2322
- computed.cgCustomZIndex = {
2323
- get: function(): number {
2324
- return this._cgCustomZIndex;
2325
- },
2326
- set: function(): void {
2327
- notify({
2328
- 'title': 'Error',
2329
- 'content': `The software tries to modify the system variable "cgCustomZIndex".\nPath: ${this.cgPath}`,
2005
+ 'content': `The software tries to modify the system variable "cgPrep".\nPath: ${this.filename}`,
2330
2006
  'type': 'danger'
2331
2007
  });
2332
2008
  return;
2333
2009
  }
2334
2010
  };
2335
- if (topMost) {
2336
- data._cgTopMost = true;
2337
- }
2338
- else {
2339
- data._cgTopMost = false;
2340
- }
2341
- computed.cgTopMost = {
2011
+ // --- 是否在顶层的窗体 ---
2012
+ data._topMost = false;
2013
+ computed.topMost = {
2342
2014
  get: function(): number {
2343
- return this._cgTopMost;
2015
+ return this._topMost;
2344
2016
  },
2345
- set: function(): void {
2346
- notify({
2347
- 'title': 'Error',
2348
- 'content': `The software tries to modify the system variable "cgTopMost".\nPath: ${this.cgPath}`,
2349
- 'type': 'danger'
2350
- });
2017
+ set: function(v: boolean): void {
2018
+ const form = t.forms[formId];
2019
+ if (!form) {
2020
+ return;
2021
+ }
2022
+ if (v) {
2023
+ // --- 置顶 ---
2024
+ form.vroot.$data._topMost = true;
2025
+ if (!form.vroot._formFocus) {
2026
+ changeFocus(form.id);
2027
+ }
2028
+ else {
2029
+ form.vroot.$refs.form.$data.zIndexData = ++info.topLastZIndex;
2030
+ }
2031
+ }
2032
+ else {
2033
+ // --- 取消置顶 ---
2034
+ form.vroot.$data._topMost = false;
2035
+ form.vroot.$refs.form.$data.zIndexData = ++info.lastZIndex;
2036
+ }
2351
2037
  return;
2352
2038
  }
2353
2039
  };
2354
- // --- 预设 computed ---
2355
- computed.cgLocale = function(this: types.IVForm): string {
2356
- if (task.list[this.taskId].locale.lang === '') {
2357
- return core.config.locale;
2358
- }
2359
- return task.list[this.taskId].locale.lang;
2360
- };
2361
- // --- 获取语言 ---
2362
- computed.l = function(this: types.IVForm): (key: string) => string {
2363
- return (key: string): string => {
2364
- return task.list[this.taskId].locale.data[this.cgLocale]?.[key] ?? task.list[this.taskId].locale.data['en']?.[key] ?? 'LocaleError';
2365
- };
2366
- };
2367
- // --- layout 中 :class 的转义 ---
2368
- methods.cgClassPrepend = function(this: types.IVForm, cla: any): string {
2369
- if (typeof cla !== 'string') {
2370
- return cla;
2371
- }
2372
- /*
2373
- if (cla.startsWith('cg-')) {
2374
- return cla;
2375
- }
2376
- */
2377
- return `cg-task${this.taskId}_${cla} ${this.cgPrep}${cla}`;
2378
- };
2379
- // --- 判断当前事件可否执行 ---
2380
- methods.cgAllowEvent = function(this: types.IVForm, e: MouseEvent | TouchEvent | KeyboardEvent): boolean {
2381
- return dom.allowEvent(e);
2382
- };
2383
- // --- 窗体接收 send 事件 ---
2384
- methods.cgReceive = function(obj: Record<string, any>) {
2385
- receive?.call(this, obj);
2386
- };
2387
2040
  // --- 挂载 style ---
2388
2041
  if (style) {
2389
2042
  // --- 窗体的 style ---
2390
- dom.pushStyle(taskId, style, 'form', formId);
2043
+ dom.pushStyle(opt.taskId, style, 'form', formId);
2391
2044
  }
2392
2045
  // --- 创建 app 对象 ---
2393
2046
  const rtn: {
2394
- 'vapp': types.IVueApp;
2395
- 'vroot': types.IVForm;
2047
+ 'vapp': types.IVApp;
2048
+ 'vroot': types.IVue;
2396
2049
  } = await new Promise(function(resolve) {
2397
2050
  const vapp = clickgo.vue.createApp({
2398
- 'template': layout!.replace(/^<cg-form/, '<cg-form ref="form"'),
2051
+ 'template': layout.replace(/^<cg-form/, '<cg-form ref="form"'),
2399
2052
  'data': function() {
2400
2053
  return tool.clone(data);
2401
2054
  },
2402
2055
  'methods': methods,
2403
2056
  'computed': computed,
2404
- 'watch': watch,
2405
2057
 
2406
2058
  'beforeCreate': beforeCreate,
2407
2059
  'created': created,
2408
2060
  'beforeMount': beforeMount,
2409
- 'mounted': async function(this: types.IVForm) {
2061
+ 'mounted': async function(this: types.IVue) {
2410
2062
  await this.$nextTick();
2411
2063
  // --- 判断是否有 icon,对 icon 进行第一次读取 ---
2412
2064
  // --- 为啥要在这搞,因为 form 控件中读取,将可能导致下方的 formCreate 事件获取不到 icon 图标 ---
2413
2065
  // --- 而如果用延迟的方式获取,将可能导致 changeFocus 的窗体焦点事件先于 formCreate 触发 ---
2414
- if (this.$refs.form.icon !== '') {
2415
- const icon = await clickgo.fs.getContent(this.$refs.form.icon);
2416
- this.$refs.form.iconData = (icon instanceof Blob) ? await clickgo.tool.blob2DataUrl(icon) : '';
2066
+ if (this.$refs.form.icon) {
2067
+ const icon = await fs.getContent(this.$refs.form.icon, {
2068
+ 'current': t.current,
2069
+ 'files': t.app.files
2070
+ });
2071
+ this.$refs.form.iconData = (icon instanceof Blob) ? await tool.blob2DataUrl(icon) : '';
2417
2072
  }
2418
2073
  // --- 完成 ---
2419
2074
  resolve({
@@ -2422,41 +2077,42 @@ export async function create(opt: string | types.IFormCreateOptions): Promise<nu
2422
2077
  });
2423
2078
  },
2424
2079
  'beforeUpdate': beforeUpdate,
2425
- 'updated': async function(this: types.IVue) {
2426
- await this.$nextTick();
2427
- updated?.call(this);
2428
- },
2080
+ 'updated': updated,
2429
2081
  'beforeUnmount': beforeUnmount,
2430
- 'unmounted': unmounted,
2082
+ 'unmounted': unmounted
2431
2083
  });
2432
- vapp.config.errorHandler = function(err: Error, vm: types.IVForm, info: string): void {
2084
+ vapp.config.errorHandler = function(err: Error, vm: types.IVue, info: string): void {
2433
2085
  notify({
2434
2086
  'title': 'Runtime Error',
2435
- 'content': `Message: ${err.message}\ntask id: ${vm.taskId}\nForm id: ${vm.formId}`,
2087
+ 'content': `Message: ${err.message}\nTask id: ${vm.taskId}\nForm id: ${vm.formId}`,
2436
2088
  'type': 'danger'
2437
2089
  });
2438
- core.trigger('error', vm.taskId, vm.formId, err, info);
2090
+ core.trigger('error', vm.taskId, vm.formId, err, info + '(-3,' + vm.taskId + ',' + vm.formId + ')');
2439
2091
  };
2440
2092
  // --- 挂载控件对象到 vapp ---
2441
2093
  for (const key in components) {
2442
2094
  vapp.component(key, components[key]);
2443
2095
  }
2444
- vapp.mount(el);
2096
+ try {
2097
+ vapp.mount(el);
2098
+ }
2099
+ catch (err: any) {
2100
+ notify({
2101
+ 'title': 'Runtime Error',
2102
+ 'content': `Message: ${err.message}\nTask id: ${opt.taskId}\nForm id: ${formId}`,
2103
+ 'type': 'danger'
2104
+ });
2105
+ core.trigger('error', opt.taskId, formId, err, err.message + '(-2)');
2106
+ }
2445
2107
  });
2446
2108
  // --- 创建 form 信息对象 ---
2447
2109
  const nform: types.IForm = {
2448
2110
  'id': formId,
2449
2111
  'vapp': rtn.vapp,
2450
- 'vroot': rtn.vroot,
2451
- 'events': {}
2112
+ 'vroot': rtn.vroot
2452
2113
  };
2453
2114
  // --- 挂载 form ---
2454
2115
  t.forms[formId] = nform;
2455
- // --- 检测 mask ---
2456
- if (opt.mask && form) {
2457
- form.vroot.$refs.form.maskFor = formId;
2458
- nform.vroot.$refs.form.maskFrom = form.id;
2459
- }
2460
2116
  // --- 执行 mounted ---
2461
2117
  await tool.sleep(34);
2462
2118
  if (mounted) {
@@ -2464,9 +2120,6 @@ export async function create(opt: string | types.IFormCreateOptions): Promise<nu
2464
2120
  await mounted.call(rtn.vroot, opt.data);
2465
2121
  }
2466
2122
  catch (err: any) {
2467
- if (nform?.vroot.$refs.form.maskFor !== undefined) {
2468
- nform.vroot.$refs.form.maskFor = undefined;
2469
- }
2470
2123
  core.trigger('error', rtn.vroot.taskId, rtn.vroot.formId, err, 'Create form mounted error.');
2471
2124
  t.forms[formId] = undefined as any;
2472
2125
  delete t.forms[formId];
@@ -2476,27 +2129,9 @@ export async function create(opt: string | types.IFormCreateOptions): Promise<nu
2476
2129
  return -8;
2477
2130
  }
2478
2131
  }
2479
- // --- 将窗体居中 ---
2480
- const area = core.getAvailArea();
2481
- if (!rtn.vroot.$refs.form.stateMaxData) {
2482
- if (rtn.vroot.$refs.form.left === -1) {
2483
- rtn.vroot.$refs.form.setPropData('left', (area.width - rtn.vroot.$el.offsetWidth) / 2);
2484
- }
2485
- if (rtn.vroot.$refs.form.top === -1) {
2486
- rtn.vroot.$refs.form.setPropData('top', (area.height - rtn.vroot.$el.offsetHeight) / 2);
2487
- }
2488
- }
2489
- if (rtn.vroot.$refs.form.zIndex !== -1) {
2490
- rtn.vroot._cgCustomZIndex = true;
2491
- }
2492
- if (rtn.vroot.$refs.form.$data.show !== false) {
2493
- rtn.vroot.$refs.form.$data.showData = true;
2494
- }
2495
2132
  // --- 触发 formCreated 事件 ---
2496
- core.trigger('formCreated', taskId, formId, rtn.vroot.$refs.form.title, rtn.vroot.$refs.form.iconData);
2497
- // --- 绑定获取焦点事件 ---
2498
- changeFocus(formId);
2499
- return nform;
2133
+ core.trigger('formCreated', opt.taskId, formId, rtn.vroot.$refs.form.title, rtn.vroot.$refs.form.iconData);
2134
+ return formId;
2500
2135
  }
2501
2136
 
2502
2137
  /**
@@ -2510,48 +2145,54 @@ export function dialog(opt: string | types.IFormDialogOptions): Promise<string>
2510
2145
  'content': opt
2511
2146
  };
2512
2147
  }
2513
- const formId = opt.formId;
2514
- if (!formId) {
2148
+ const nopt = opt;
2149
+ const taskId = nopt.taskId;
2150
+ if (!taskId) {
2515
2151
  resolve('');
2516
2152
  return;
2517
2153
  }
2518
- const taskId = getTaskId(formId);
2519
2154
  const t = task.list[taskId];
2520
2155
  if (!t) {
2521
2156
  resolve('');
2522
2157
  return;
2523
2158
  }
2524
- const locale = t.forms[formId].vroot.cgLocale;
2525
- if (opt.buttons === undefined) {
2526
- opt.buttons = [info.locale[locale]?.ok ?? info.locale['en'].ok];
2159
+ const locale = t.locale.lang || core.config.locale;
2160
+ if (nopt.buttons === undefined) {
2161
+ nopt.buttons = [info.locale[locale]?.ok ?? info.locale['en'].ok];
2527
2162
  }
2528
- create({
2529
- 'taskId': taskId,
2530
- 'formId': formId,
2531
- 'layout': `<form title="${opt.title ?? 'dialog'}" width="auto" height="auto" :min="false" :max="false" :resize="false" border="${opt.title ? 'normal' : 'plain'}" direction="v"><dialog :buttons="buttons" @select="select"${opt.direction ? ` direction="${opt.direction}"` : ''}>${opt.content}</dialog></form>`,
2532
- 'code': {
2533
- data: {
2534
- 'buttons': opt.buttons
2535
- },
2536
- methods: {
2537
- select: function(this: types.IVForm, button: string) {
2538
- const event = {
2539
- 'go': true,
2540
- preventDefault: function() {
2541
- this.go = false;
2542
- }
2543
- };
2544
- (opt as types.IFormDialogOptions).select?.(event as unknown as Event, button);
2545
- if (event.go) {
2546
- close(this.formId);
2547
- resolve(button);
2548
- }
2163
+ const cls = class extends AbstractForm {
2164
+ public buttons = nopt.buttons;
2165
+
2166
+ public get taskId(): number {
2167
+ return taskId;
2168
+ }
2169
+
2170
+ public select(button: string): void {
2171
+ const event = {
2172
+ 'go': true,
2173
+ preventDefault: function() {
2174
+ this.go = false;
2549
2175
  }
2176
+ };
2177
+ nopt.select?.(event as unknown as Event, button);
2178
+ if (event.go) {
2179
+ this.dialogResult = button;
2180
+ close(this.formId);
2550
2181
  }
2551
- },
2552
- 'mask': true
2553
- }).catch((e) => {
2554
- throw e;
2182
+ }
2183
+ };
2184
+ cls.create(undefined, `<form title="${nopt.title ?? 'dialog'}" min="false" max="false" resize="false" height="0" border="${nopt.title ? 'normal' : 'plain'}" direction="v"><dialog :buttons="buttons" @select="select"${nopt.direction ? ` direction="${nopt.direction}"` : ''}>${nopt.content}</dialog></form>`).then((frm) => {
2185
+ if (typeof frm === 'number') {
2186
+ resolve('');
2187
+ return;
2188
+ }
2189
+ frm.showDialog().then((v) => {
2190
+ resolve(v);
2191
+ }).catch(() => {
2192
+ resolve('');
2193
+ });
2194
+ }).catch(() => {
2195
+ resolve('');
2555
2196
  });
2556
2197
  });
2557
2198
  }
@@ -2566,22 +2207,21 @@ export async function confirm(opt: string | types.IFormConfirmOptions): Promise<
2566
2207
  'content': opt
2567
2208
  };
2568
2209
  }
2569
- const formId = opt.formId;
2570
- if (!formId) {
2210
+ const taskId = opt.taskId;
2211
+ if (!taskId) {
2571
2212
  return false;
2572
2213
  }
2573
- const taskId = getTaskId(formId);
2574
2214
  const t = task.list[taskId];
2575
2215
  if (!t) {
2576
2216
  return false;
2577
2217
  }
2578
- const locale = t.forms[formId].vroot.cgLocale;
2218
+ const locale = t.locale.lang || core.config.locale;
2579
2219
  const buttons = [info.locale[locale]?.yes ?? info.locale['en'].yes, info.locale[locale]?.no ?? info.locale['en'].no];
2580
2220
  if (opt.cancel) {
2581
2221
  buttons.push(info.locale[locale]?.cancel ?? info.locale['en'].cancel);
2582
2222
  }
2583
2223
  const res = await dialog({
2584
- 'formId': formId,
2224
+ 'taskId': taskId,
2585
2225
 
2586
2226
  'content': opt.content,
2587
2227
  'buttons': buttons
@@ -2596,47 +2236,22 @@ export async function confirm(opt: string | types.IFormConfirmOptions): Promise<
2596
2236
  }
2597
2237
 
2598
2238
  /**
2599
- * --- 设置窗体置顶和取消置顶 ---
2600
- * @param top true: 置顶, false: 不置顶
2601
- * @param opt 选项
2239
+ * --- 让窗体闪烁 ---
2240
+ * @param formId 要闪烁的窗体 id,必填
2241
+ * @param taskId 所属的 taskId,必填,App 模式下仅能闪烁本任务的窗体
2602
2242
  */
2603
- export function setTopMost(top: boolean, opt: types.IFormSetTopMostOptions = {}): void {
2604
- const form = getForm(opt.taskId, opt.formId);
2605
- if (!form) {
2243
+ export function flash(formId: number, taskId?: number): void {
2244
+ if (!taskId) {
2606
2245
  return;
2607
2246
  }
2608
- form.vroot.$data._cgCustomZIndex = false;
2609
- if (top) {
2610
- // --- 置顶 ---
2611
- form.vroot.$data._cgTopMost = true;
2612
- if (!form.vroot.cgFocus) {
2613
- changeFocus(form.id);
2614
- }
2615
- else {
2616
- form.vroot.$refs.form.setPropData('zIndex', ++info.topLastZIndex);
2617
- }
2618
- }
2619
- else {
2620
- // --- 取消置顶 ---
2621
- form.vroot.$data._cgTopMost = false;
2622
- form.vroot.$refs.form.setPropData('zIndex', ++info.lastZIndex);
2623
- }
2624
- }
2625
-
2626
- /**
2627
- * --- 让窗体闪烁 ---
2628
- * @param formId 要闪烁的窗体 id,必填,但 App 模式下留空为当前窗体
2629
- * @param taskId 所属的 taskId,必填,但 App 模式下无效
2630
- */
2631
- export function flash(formId?: number, taskId?: number): void {
2632
2247
  const form = getForm(taskId, formId);
2633
2248
  if (!form) {
2634
2249
  return;
2635
2250
  }
2636
- if (!form.vroot.cgFocus) {
2251
+ if (!form.vroot._formFocus) {
2637
2252
  changeFocus(form.id);
2638
2253
  }
2639
- if (form.vroot.$refs.form?.flashTimer) {
2254
+ if (form.vroot.$refs.form.flashTimer) {
2640
2255
  clearTimeout(form.vroot.$refs.form.flashTimer);
2641
2256
  form.vroot.$refs.form.flashTimer = undefined;
2642
2257
  }
@@ -2649,32 +2264,6 @@ export function flash(formId?: number, taskId?: number): void {
2649
2264
  core.trigger('formFlash', taskId, formId);
2650
2265
  }
2651
2266
 
2652
- /**
2653
- * --- 让窗体显示 ---
2654
- * @param formId 要显示的窗体 id,App 模式下留空为当前窗体
2655
- * @param taskId 所属的 taskId,App 模式下无效
2656
- */
2657
- export function show(formId?: number, taskId?: number): void {
2658
- const form = getForm(taskId, formId);
2659
- if (!form) {
2660
- return;
2661
- }
2662
- form.vroot.$refs.form.$data.showData = true;
2663
- }
2664
-
2665
- /**
2666
- * --- 让窗体隐藏 ---
2667
- * @param formId 要隐藏的窗体 id,App 模式下留空为当前窗体
2668
- * @param taskId 所属的 taskId,App 模式下无效
2669
- */
2670
- export function hide(formId?: number, taskId?: number): void {
2671
- const form = getForm(taskId, formId);
2672
- if (!form) {
2673
- return;
2674
- }
2675
- form.vroot.$refs.form.$data.showData = false;
2676
- }
2677
-
2678
2267
  /**
2679
2268
  * --- 显示 launcher 界面 ---
2680
2269
  */