clickgo 3.0.6-dev7 → 3.1.0-dev9

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/form/form.js +21 -20
  4. package/dist/app/demo/form/control/form/form.xml +3 -3
  5. package/dist/app/demo/form/main.js +20 -10
  6. package/dist/app/demo/form/main.xml +1 -1
  7. package/dist/app/task/app.js +46 -0
  8. package/dist/app/task/form/bar/bar.js +85 -86
  9. package/dist/app/task/form/bar/bar.xml +5 -6
  10. package/dist/clickgo.js +1 -10
  11. package/dist/clickgo.ts +0 -8
  12. package/dist/control/common.cgc +0 -0
  13. package/dist/control/form.cgc +0 -0
  14. package/dist/control/monaco.cgc +0 -0
  15. package/dist/control/property.cgc +0 -0
  16. package/dist/control/task.cgc +0 -0
  17. package/dist/global.css +1 -1
  18. package/dist/index.js +105 -56
  19. package/dist/index.ts +164 -59
  20. package/dist/lib/control.js +363 -240
  21. package/dist/lib/control.ts +497 -284
  22. package/dist/lib/core.js +331 -217
  23. package/dist/lib/core.ts +418 -244
  24. package/dist/lib/dom.js +6 -3
  25. package/dist/lib/dom.ts +7 -6
  26. package/dist/lib/form.js +635 -980
  27. package/dist/lib/form.ts +817 -1072
  28. package/dist/lib/fs.js +42 -39
  29. package/dist/lib/fs.ts +45 -41
  30. package/dist/lib/native.js +8 -148
  31. package/dist/lib/native.ts +9 -211
  32. package/dist/lib/task.js +707 -191
  33. package/dist/lib/task.ts +778 -210
  34. package/dist/lib/theme.ts +2 -2
  35. package/dist/lib/tool.js +58 -48
  36. package/dist/lib/tool.ts +79 -64
  37. package/dist/theme/familiar.cgt +0 -0
  38. package/package.json +5 -7
  39. package/types/index.d.ts +286 -324
  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 相关信息 --- */
@@ -36,6 +37,7 @@ const info: {
36
37
  'yes': string;
37
38
  'no': string;
38
39
  'cancel': string;
40
+ 'search': string;
39
41
  }>;
40
42
  } = {
41
43
  'lastId': 0,
@@ -46,29 +48,460 @@ const info: {
46
48
  'ok': '好',
47
49
  'yes': '是',
48
50
  'no': '否',
49
- 'cancel': '取消'
51
+ 'cancel': '取消',
52
+ 'search': '搜索'
50
53
  },
51
54
  'tc': {
52
55
  'ok': '好',
53
56
  'yes': '是',
54
57
  'no': '否',
55
- 'cancel': '取消'
58
+ 'cancel': '取消',
59
+ 'search': '檢索'
56
60
  },
57
61
  'en': {
58
62
  'ok': 'OK',
59
63
  'yes': 'Yes',
60
64
  'no': 'No',
61
- 'cancel': 'Cancel'
65
+ 'cancel': 'Cancel',
66
+ 'search': 'Search'
62
67
  },
63
68
  'ja': {
64
69
  'ok': '好',
65
70
  'yes': 'はい',
66
71
  'no': 'いいえ',
67
- 'cancel': 'キャンセル'
72
+ 'cancel': 'キャンセル',
73
+ 'search': '検索'
68
74
  }
69
75
  }
70
76
  };
71
77
 
78
+ /** --- 窗体的抽象类 --- */
79
+ export class AbstractForm {
80
+
81
+ public static async create(data?: Record<string, any>): Promise<AbstractForm | number> {
82
+ const frm = new this();
83
+ /** --- 要挂载的 vue 参数 --- */
84
+ const code: types.IFormCreateCode = {
85
+ 'data': {},
86
+ 'methods': {},
87
+ 'computed': {},
88
+
89
+ beforeCreate: (frm as any).onBeforeCreate,
90
+ created: function(this: types.IVue) {
91
+ this.onCreated();
92
+ },
93
+ beforeMount: function(this: types.IVue) {
94
+ this.onBeforeMount();
95
+ },
96
+ mounted: function(this: types.IVue, data?: Record<string, any>) {
97
+ // await this.$nextTick();
98
+ // --- form 不用 nextTick,因为全部处理完后才会主动调用本方法 ---
99
+ this.onMounted(data);
100
+ },
101
+ beforeUpdate: function(this: types.IVue) {
102
+ this.onBeforeUpdate();
103
+ },
104
+ updated: async function(this: types.IVue) {
105
+ await this.$nextTick();
106
+ this.onUpdated();
107
+ },
108
+ beforeUnmount: function(this: types.IVue) {
109
+ this.onBeforeUnmount();
110
+ },
111
+ unmounted: async function(this: types.IVue) {
112
+ await this.$nextTick();
113
+ this.onUnmounted();
114
+ }
115
+ };
116
+ /** --- class 对象类的属性列表 --- */
117
+ const cdata = Object.entries(frm);
118
+ for (const item of cdata) {
119
+ code.data![item[0]] = item[1];
120
+ }
121
+ const layout = task.list[frm.taskId].app.files[frm.filename.slice(0, -2) + 'xml'];
122
+ if (typeof layout !== 'string') {
123
+ return 0;
124
+ }
125
+ const prot = tool.getClassPrototype(frm);
126
+ code.methods = prot.method;
127
+ code.computed = prot.access;
128
+ // --- 窗体样式 ---
129
+ let style: string | undefined = undefined;
130
+ const fstyle = task.list[frm.taskId].app.files[frm.filename.slice(0, -2) + 'css'];
131
+ if (typeof fstyle === 'string') {
132
+ style = fstyle;
133
+ }
134
+ const fid = await create({
135
+ 'code': code,
136
+ 'layout': layout,
137
+ 'style': style,
138
+
139
+ 'path': frm.filename.slice(0, frm.filename.lastIndexOf('/')),
140
+ 'data': data,
141
+ 'taskId': frm.taskId
142
+ });
143
+ if (fid > 0) {
144
+ return task.list[frm.taskId].forms[fid].vroot as any;
145
+ }
146
+ else {
147
+ return fid;
148
+ }
149
+ }
150
+
151
+ /** --- 当前文件路径 --- */
152
+ public get filename(): string {
153
+ // --- require 时系统自动在继承类中重写本函数 ---
154
+ return '';
155
+ }
156
+
157
+ /** --- 当前控件的名字 --- */
158
+ public get controlName(): string {
159
+ return 'root';
160
+ }
161
+
162
+ public set controlName(v: string) {
163
+ notify({
164
+ 'title': 'Error',
165
+ 'content': `The software tries to modify the system variable "controlName".\nPath: ${this.filename}`,
166
+ 'type': 'danger'
167
+ });
168
+ return;
169
+ }
170
+
171
+ /** --- 当前的任务 ID --- */
172
+ public get taskId(): number {
173
+ // --- 系统 invoke 继承时重写本函数 ---
174
+ return 0;
175
+ }
176
+
177
+ /** --- 当前的窗体 ID --- */
178
+ public get formId(): number {
179
+ // --- 窗体创建时 create 系统自动重写本函数 ---
180
+ return 0;
181
+ }
182
+
183
+ /** --- 当前窗体是否是焦点 --- */
184
+ public get formFocus(): boolean {
185
+ // --- _formFocus 在初始化时由系统设置 ---
186
+ return (this as any)._formFocus;
187
+ }
188
+
189
+ public set formFocus(b: boolean) {
190
+ notify({
191
+ 'title': 'Error',
192
+ 'content': `The software tries to modify the system variable "formFocus".\nPath: ${this.filename}`,
193
+ 'type': 'danger'
194
+ });
195
+ }
196
+
197
+ /** --- 当前窗体的包内路径不以 / 结尾 --- */
198
+ public get path(): string {
199
+ // --- 将在初始化时系统自动重写本函数 ---
200
+ return '';
201
+ }
202
+
203
+ /** --- 样式独占前缀 --- */
204
+ public get prep(): string {
205
+ // --- 将在初始化时系统自动重写本函数 ---
206
+ return '';
207
+ }
208
+
209
+ /** --- 当前的语言 --- */
210
+ public get locale(): string {
211
+ return task.list[this.taskId].locale.lang || core.config.locale;
212
+ }
213
+
214
+ /**
215
+ * --- 获取语言内容 ---
216
+ */
217
+ public get l(): (key: string) => string {
218
+ return (key: string): string => {
219
+ return task.list[this.taskId].locale.data[this.locale]?.[key] ?? task.list[this.taskId].locale.data['en']?.[key] ?? 'LocaleError';
220
+ };
221
+ }
222
+
223
+ /** --- layout 中 :class 的转义 --- */
224
+ public classPrepend(): (cla: any) => string {
225
+ return (cla: any): string => {
226
+ if (typeof cla !== 'string') {
227
+ return cla;
228
+ }
229
+ // --- 没有单独的窗体样式,则只应用任务级样式 ---
230
+ return `cg-task${this.taskId}_${cla}${this.prep ? (' ' + this.prep + cla) : ''}`;
231
+ };
232
+ }
233
+
234
+ /**
235
+ * --- 监视变动 ---
236
+ * @param name 监视的属性
237
+ * @param cb 回调
238
+ * @param opt 参数
239
+ */
240
+ public watch<T extends this, TK extends keyof T>(
241
+ name: TK,
242
+ cb: (val: T[TK], old: T[TK]) => void | Promise<void>,
243
+ opt: {
244
+ 'immediate'?: boolean;
245
+ 'deep'?: boolean;
246
+ } = {}
247
+ ): () => void {
248
+ return (this as any).$watch(name, cb, opt);
249
+ }
250
+
251
+ /**
252
+ * --- 获取 refs 情况 ---
253
+ */
254
+ public get refs(): Record<string, HTMLElement & types.IVue> {
255
+ return (this as any).$refs;
256
+ }
257
+
258
+ /**
259
+ * --- 等待渲染 ---
260
+ */
261
+ public get nextTick(): () => Promise<void> {
262
+ return (this as any).$nextTick;
263
+ }
264
+
265
+ /**
266
+ * --- 判断当前事件可否执行 ---
267
+ * @param e 鼠标、触摸、键盘事件
268
+ */
269
+ public allowEvent(e: MouseEvent | TouchEvent | KeyboardEvent): boolean {
270
+ return dom.allowEvent(e);
271
+ }
272
+
273
+ /**
274
+ * --- 触发系统方法 ---
275
+ * @param name 方法名
276
+ * @param param1 参数1
277
+ * @param param2 参数2
278
+ */
279
+ public trigger(name: types.TGlobalEvent, param1: boolean | Error | string = '', param2: string = ''): void {
280
+ if (!['formTitleChanged', 'formIconChanged', 'formStateMinChanged', 'formStateMaxChanged', 'formShowChanged'].includes(name)) {
281
+ return;
282
+ }
283
+ core.trigger(name, this.taskId, this.formId, param1, param2);
284
+ }
285
+
286
+ // --- 以下为窗体有,但 control 没有 ---
287
+
288
+ /** --- 是否是置顶 --- */
289
+ public get topMost(): boolean {
290
+ // --- 将在初始化时系统自动重写本函数 ---
291
+ return false;
292
+ }
293
+
294
+ public set topMost(v: boolean) {
295
+ // --- 会进行重写 ---
296
+ }
297
+
298
+ /**
299
+ * --- 给一个窗体发送一个对象,不会知道成功与失败状态 ---
300
+ * @param fid formId 要接收对象的 form id
301
+ * @param obj 要发送的对象
302
+ */
303
+ public send(fid: number, obj: Record<string, any>): void {
304
+ obj.taskId = this.taskId;
305
+ obj.formId = this.formId;
306
+ send(fid, obj);
307
+ }
308
+
309
+ /**
310
+ * --- 是否在本窗体上显示遮罩层 ---
311
+ */
312
+ public get isMask(): boolean {
313
+ return !task.list[this.taskId].runtime.dialogFormIds.length ||
314
+ task.list[this.taskId].runtime.dialogFormIds[task.list[this.taskId].runtime.dialogFormIds.length - 1]
315
+ === this.formId ? false : true;
316
+ }
317
+
318
+ /** --- 当前是不是初次显示 --- */
319
+ private _firstShow: boolean = true;
320
+
321
+ /**
322
+ * --- 显示窗体 ---
323
+ */
324
+ public show(): void {
325
+ // --- 创建成功的窗体,可以直接显示 ---
326
+ const v = this as any;
327
+ v.$refs.form.$data.showData = true;
328
+ if (this._firstShow) {
329
+ this._firstShow = false;
330
+ // --- 将窗体居中 ---
331
+ const area = core.getAvailArea();
332
+ if (!v.$refs.form.stateMaxData) {
333
+ if (v.$refs.form.left === -1) {
334
+ v.$refs.form.setPropData('left', (area.width - v.$el.offsetWidth) / 2);
335
+ }
336
+ if (v.$refs.form.top === -1) {
337
+ v.$refs.form.setPropData('top', (area.height - v.$el.offsetHeight) / 2);
338
+ }
339
+ }
340
+ v.$refs.form.$data.showData = true;
341
+ changeFocus(this.formId);
342
+ }
343
+ }
344
+
345
+ /**
346
+ * --- 显示独占的窗体 ---
347
+ */
348
+ public async showDialog(): Promise<string> {
349
+ this.show();
350
+ task.list[this.taskId].runtime.dialogFormIds.push(this.formId);
351
+ return new Promise((resolve) => {
352
+ (this as any).cgDialogCallback = () => {
353
+ resolve(this.dialogResult);
354
+ };
355
+ });
356
+ }
357
+
358
+ /**
359
+ * --- 让窗体隐藏 ---
360
+ */
361
+ public hide(): void {
362
+ const v = this as any;
363
+ v.$refs.form.$data.showData = false;
364
+ }
365
+
366
+ /**
367
+ * --- dialog mask 窗体返回值,在 close 之后会进行传导 ---
368
+ */
369
+ public dialogResult: string = '';
370
+
371
+ // --- 控件响应事件,都可由用户重写 ---
372
+
373
+ public onBeforeCreate(): void | Promise<void> {
374
+ return;
375
+ }
376
+
377
+ public onCreated(): void | Promise<void> {
378
+ return;
379
+ }
380
+
381
+ public onBeforeMount(): void | Promise<void> {
382
+ return;
383
+ }
384
+
385
+ public onMounted(): void | Promise<void> {
386
+ return;
387
+ }
388
+
389
+ public onBeforeUpdate(): void | Promise<void> {
390
+ return;
391
+ }
392
+
393
+ public onUpdated(): void | Promise<void> {
394
+ return;
395
+ }
396
+
397
+ public onBeforeUnmount(): void | Promise<void> {
398
+ return;
399
+ }
400
+
401
+ public onUnmounted(): void | Promise<void> {
402
+ return;
403
+ }
404
+
405
+ // --- 窗体可以接收到的事件 ---
406
+
407
+ /** --- 接收 send 传递过来的 data 数据 --- */
408
+ public onReceive(data: Record<string, any>): void | Promise<void>;
409
+ public onReceive(): void {
410
+ return;
411
+ }
412
+
413
+ /** --- 屏幕大小改变事件 --- */
414
+ public onScreenResize(): void | Promise<void>;
415
+ public onScreenResize(): void {
416
+ return;
417
+ }
418
+
419
+ /** --- 系统配置变更事件 --- */
420
+ public onConfigChanged<T extends keyof types.IConfig>(n: keyof types.IConfig, v: types.IConfig[T]): void;
421
+ public onConfigChanged(): void {
422
+ return;
423
+ }
424
+
425
+ /** --- 窗体创建事件 --- */
426
+ public onFormCreated(taskId: number, formId: number, title: string, icon: string): void | Promise<void>;
427
+ public onFormCreated(): void {
428
+ return;
429
+ }
430
+
431
+ /** --- 窗体销毁事件 */
432
+ public onFormRemoved(taskId: number, formId: number, title: string, icon: string): void | Promise<void>;
433
+ public onFormRemoved(): void {
434
+ return;
435
+ }
436
+
437
+ /** --- 窗体标题改变事件 */
438
+ public onFormTitleChanged(taskId: number, formId: number, title: string): void | Promise<void>;
439
+ public onFormTitleChanged(): void | Promise<void> {
440
+ return;
441
+ }
442
+
443
+ /** --- 窗体图标改变事件 --- */
444
+ public onFormIconChanged(taskId: number, formId: number, icon: string): void | Promise<void>;
445
+ public onFormIconChanged(): void | Promise<void> {
446
+ return;
447
+ }
448
+
449
+ /** --- 窗体最小化状态改变事件 --- */
450
+ public onFormStateMinChanged(taskId: number, formId: number, state: boolean): void | Promise<void>;
451
+ public onFormStateMinChanged(): void {
452
+ return;
453
+ }
454
+
455
+ /** --- 窗体最大化状态改变事件 --- */
456
+ public onFormStateMaxChanged(taskId: number, formId: number, state: boolean): void | Promise<void>;
457
+ public onFormStateMaxChanged(): void {
458
+ return;
459
+ }
460
+
461
+ /** --- 窗体显示状态改变事件 --- */
462
+ public onFormShowChanged(taskId: number, formId: number, state: boolean): void | Promise<void>;
463
+ public onFormShowChanged(): void {
464
+ return;
465
+ }
466
+
467
+ /** --- 窗体获得焦点事件 --- */
468
+ public onFormFocused(taskId: number, formId: number): void | Promise<void>;
469
+ public onFormFocused(): void {
470
+ return;
471
+ }
472
+
473
+ /** --- 窗体丢失焦点事件 --- */
474
+ public onFormBlurred(taskId: number, formId: number): void | Promise<void>;
475
+ public onFormBlurred(): void {
476
+ return;
477
+ }
478
+
479
+ /** --- 窗体闪烁事件 --- */
480
+ public onFormFlash(taskId: number, formId: number): void | Promise<void>;
481
+ public onFormFlash(): void {
482
+ return;
483
+ }
484
+
485
+ /** --- 任务开始事件 --- */
486
+ public onTaskStarted(taskId: number): void | Promise<void>;
487
+ public onTaskStarted(): void | Promise<void> {
488
+ return;
489
+ }
490
+
491
+ /** --- 任务结束事件 --- */
492
+ public onTaskEnded(taskId: number): void | Promise<void>;
493
+ public onTaskEnded(): void | Promise<void> {
494
+ return;
495
+ }
496
+
497
+ /** --- launcher 文件夹名称修改事件 --- */
498
+ public onLauncherFolderNameChanged(id: string, name: string): void | Promise<void>;
499
+ public onLauncherFolderNameChanged(): void {
500
+ return;
501
+ }
502
+
503
+ }
504
+
72
505
  /** --- pop 相关信息 --- */
73
506
  const popInfo: {
74
507
  /** --- 当前显示的 pop 列表 --- */
@@ -84,6 +517,7 @@ const popInfo: {
84
517
  };
85
518
 
86
519
  export let simpleSystemTaskRoot: types.IVue;
520
+ export let launcherRoot: types.IVue;
87
521
  const elements: {
88
522
  'wrap': HTMLDivElement;
89
523
  'list': HTMLDivElement;
@@ -95,6 +529,7 @@ const elements: {
95
529
  'dragIcon'?: HTMLElement;
96
530
  'system': HTMLElement;
97
531
  'simpleSystemtask': HTMLDivElement;
532
+ 'launcher': HTMLDivElement;
98
533
  'init': () => void;
99
534
  } = {
100
535
  'wrap': document.createElement('div'),
@@ -107,22 +542,17 @@ const elements: {
107
542
  'dragIcon': undefined,
108
543
  'system': document.createElement('div'),
109
544
  'simpleSystemtask': document.createElement('div'),
545
+ 'launcher': document.createElement('div'),
110
546
  'init': function() {
111
547
  /** --- clickgo 所有的 div wrap --- */
112
548
  this.wrap.id = 'cg-wrap';
113
549
  document.getElementsByTagName('body')[0].appendChild(this.wrap);
114
550
  if (clickgo.getNative() && (clickgo.getPlatform() === 'win32')) {
115
551
  this.wrap.addEventListener('mouseenter', function() {
116
- native.send('cg-mouse-ignore', JSON.stringify({
117
- 'token': native.getToken(),
118
- 'param': false
119
- }));
552
+ native.invoke('cg-mouse-ignore', native.getToken(), false);
120
553
  });
121
554
  this.wrap.addEventListener('mouseleave', function() {
122
- native.send('cg-mouse-ignore', JSON.stringify({
123
- 'token': native.getToken(),
124
- 'param': true
125
- }));
555
+ native.invoke('cg-mouse-ignore', native.getToken(), true);
126
556
  });
127
557
  }
128
558
 
@@ -238,10 +668,196 @@ const elements: {
238
668
  }
239
669
  },
240
670
  'mounted': function(this: types.IVue): void {
241
- simpleSystemTaskRoot = this;
671
+ simpleSystemTaskRoot = this as any;
242
672
  }
243
673
  });
244
674
  simpletaskApp.mount('#cg-simpletask');
675
+
676
+ // --- cg-launcher ---
677
+ this.launcher.id = 'cg-launcher';
678
+ this.launcher.addEventListener('contextmenu', function(e): void {
679
+ e.preventDefault();
680
+ });
681
+ this.wrap.appendChild(this.launcher);
682
+ this.launcher.addEventListener('touchmove', function(e): void {
683
+ // --- 防止拖动时整个网页跟着动 ---
684
+ e.preventDefault();
685
+ }, {
686
+ 'passive': false
687
+ });
688
+ // --- Vue 挂载在这里 ---
689
+ const waiting = function(): void {
690
+ // --- 必须在这里执行,要不然 computed 无法更新,因为 core 还没加载进来 ---
691
+ if (!core.config) {
692
+ setTimeout(function() {
693
+ waiting();
694
+ }, 2000);
695
+ return;
696
+ }
697
+ const launcherApp = clickgo.vue.createApp({
698
+ 'template': `<div class="cg-launcher-search">` +
699
+ `<input v-if="folderName === ''" class="cg-launcher-sinput" :placeholder="search" v-model="name">` +
700
+ `<input v-else class="cg-launcher-foldername" :value="folderName" @change="folderNameChange">` +
701
+ `</div>` +
702
+ `<div class="cg-launcher-list" @mousedown="mousedown" @click="listClick" :class="[folderName === '' ? '' : 'cg-folder-open']">` +
703
+ `<div v-for="item of list" class="cg-launcher-item">` +
704
+ `<div class="cg-launcher-inner">` +
705
+ `<div v-if="!item.list || item.list.length === 0" class="cg-launcher-icon" :style="{'background-image': 'url(' + item.icon + ')'}" @click="iconClick($event, item)"></div>` +
706
+ `<div v-else class="cg-launcher-folder" @click="openFolder($event, item)">` +
707
+ `<div>` +
708
+ `<div v-for="sub of item.list" class="cg-launcher-item">` +
709
+ `<div class="cg-launcher-inner">` +
710
+ `<div class="cg-launcher-icon" :style="{'background-image': 'url(' + sub.icon + ')'}" @click="subIconClick($event, sub)"></div>` +
711
+ `<div class="cg-launcher-name">{{sub.name}}</div>` +
712
+ `</div>` +
713
+ `<div class="cg-launcher-space"></div>` +
714
+ `</div>` +
715
+ `</div>` +
716
+ `</div>` +
717
+ `<div class="cg-launcher-name">{{item.name}}</div>` +
718
+ `</div>` +
719
+ `<div class="cg-launcher-space"></div>` +
720
+ `</div>` +
721
+ `</div>`,
722
+ 'data': function() {
723
+ return {
724
+ 'name': '',
725
+ 'folderName': ''
726
+ };
727
+ },
728
+ 'computed': {
729
+ 'search': function() {
730
+ return info.locale[core.config.locale]?.search ?? info.locale['en'].search;
731
+ },
732
+ 'list': function(this: types.IVue) {
733
+ if (this.name === '') {
734
+ return core.config['launcher.list'];
735
+ }
736
+ const list = [];
737
+ for (const item of core.config['launcher.list']) {
738
+ if (item.list && item.list.length > 0) {
739
+ for (const sub of item.list) {
740
+ if (sub.name.toLowerCase().includes(this.name.toLowerCase())) {
741
+ list.push(sub);
742
+ }
743
+ }
744
+ }
745
+ else {
746
+ if (item.name.toLowerCase().includes(this.name.toLowerCase())) {
747
+ list.push(item);
748
+ }
749
+ }
750
+ }
751
+ return list;
752
+ }
753
+ },
754
+ 'methods': {
755
+ mousedown: function(this: types.IVue, e: MouseEvent): void {
756
+ this.md = e.pageX + e.pageY;
757
+ },
758
+ listClick: function(this: types.IVue, e: MouseEvent) {
759
+ if (this.md !== e.pageX + e.pageY) {
760
+ return;
761
+ }
762
+ if (e.currentTarget !== e.target) {
763
+ return;
764
+ }
765
+ if (this.folderName === '') {
766
+ hideLauncher();
767
+ }
768
+ else {
769
+ this.closeFolder();
770
+ }
771
+ },
772
+ iconClick: async function(
773
+ this: types.IVue,
774
+ e: MouseEvent,
775
+ item: types.IConfigLauncherItem
776
+ ): Promise<void> {
777
+ if (this.md !== e.pageX + e.pageY) {
778
+ return;
779
+ }
780
+ hideLauncher();
781
+ await clickgo.task.run(item.path!, {
782
+ 'icon': item.icon
783
+ });
784
+ },
785
+ subIconClick: async function(
786
+ this: types.IVue,
787
+ e: MouseEvent,
788
+ item: types.IConfigLauncherItem
789
+ ): Promise<void> {
790
+ if (this.md !== e.pageX + e.pageY) {
791
+ return;
792
+ }
793
+ hideLauncher();
794
+ await clickgo.task.run(item.path!, {
795
+ 'icon': item.icon
796
+ });
797
+ },
798
+ closeFolder: function(this: types.IVue): void {
799
+ // --- 关闭文件夹 ---
800
+ this.folderName = '';
801
+ const el = this.folderEl as HTMLDivElement;
802
+ const rect = (el.parentNode as HTMLDivElement).getBoundingClientRect();
803
+ el.classList.remove('cg-show');
804
+ el.style.left = (rect.left + 30).toString() + 'px';
805
+ el.style.top = rect.top.toString() + 'px';
806
+ el.style.width = '';
807
+ el.style.height = '';
808
+ setTimeout(() => {
809
+ el.style.position = '';
810
+ el.style.left = '';
811
+ el.style.top = '';
812
+ }, 150);
813
+ },
814
+ openFolder: function(this: types.IVue, e: MouseEvent, item: types.IConfigLauncherItem): void {
815
+ if (this.md !== e.pageX + e.pageY) {
816
+ return;
817
+ }
818
+ if ((e.currentTarget as HTMLElement).childNodes[0] !== e.target) {
819
+ return;
820
+ }
821
+ if (this.folderName !== '') {
822
+ this.closeFolder();
823
+ return;
824
+ }
825
+ this.folderName = item.name;
826
+ this.folderItem = item;
827
+ const el = (e.currentTarget as HTMLDivElement).childNodes.item(0) as HTMLDivElement;
828
+ this.folderEl = el;
829
+ const searchEl = document.getElementsByClassName('cg-launcher-search')[0] as HTMLDivElement;
830
+ const rect = el.getBoundingClientRect();
831
+ el.style.left = rect.left.toString() + 'px';
832
+ el.style.top = rect.top.toString() + 'px';
833
+ el.style.position = 'fixed';
834
+ requestAnimationFrame(() => {
835
+ el.classList.add('cg-show');
836
+ el.style.left = '50px';
837
+ el.style.top = searchEl.offsetHeight.toString() + 'px';
838
+ el.style.width = 'calc(100% - 100px)';
839
+ el.style.height = 'calc(100% - 50px - ' + searchEl.offsetHeight.toString() + 'px)';
840
+ });
841
+ },
842
+ folderNameChange: function(this: types.IVue, e: InputEvent): void {
843
+ const input = e.target as HTMLInputElement;
844
+ const val = input.value.trim();
845
+ if (val === '') {
846
+ input.value = this.folderName;
847
+ return;
848
+ }
849
+ this.folderName = val;
850
+ // --- 触发 folder name change 事件 ---
851
+ core.trigger('launcherFolderNameChanged', this.folderItem.id ?? '', val);
852
+ }
853
+ },
854
+ 'mounted': function(this: types.IVue): void {
855
+ launcherRoot = this as any;
856
+ }
857
+ });
858
+ launcherApp.mount('#cg-launcher');
859
+ };
860
+ waiting();
245
861
  }
246
862
  };
247
863
  elements.init();
@@ -251,10 +867,7 @@ elements.init();
251
867
  * @param state 最大化、最小化或关闭
252
868
  * @param formId 窗体 id
253
869
  */
254
- function changeState(state: 'min' | 'max' | 'close', formId?: number): boolean {
255
- if (!formId) {
256
- return false;
257
- }
870
+ function changeState(state: 'min' | 'max' | 'close', formId: number): boolean {
258
871
  const tid: number = getTaskId(formId);
259
872
  const t = task.list[tid];
260
873
  if (!t) {
@@ -278,25 +891,25 @@ function changeState(state: 'min' | 'max' | 'close', formId?: number): boolean {
278
891
 
279
892
  /**
280
893
  * --- 最小化某个窗体 ---
281
- * @param formId 窗体 id,App 模式下可省略
894
+ * @param formId 窗体 id
282
895
  */
283
- export function min(formId?: number): boolean {
896
+ export function min(formId: number): boolean {
284
897
  return changeState('min', formId);
285
898
  }
286
899
 
287
900
  /**
288
901
  * --- 最大化某个窗体 ---
289
- * @param formId formId 窗体 id,App 模式下可省略
902
+ * @param formId 窗体 id
290
903
  */
291
- export function max(formId?: number): boolean {
904
+ export function max(formId: number): boolean {
292
905
  return changeState('max', formId);
293
906
  }
294
907
 
295
908
  /**
296
909
  * --- 关闭一个窗体 ---
297
- * @param formId formId 窗体 id,App 模式下可省略
910
+ * @param formId 窗体 id
298
911
  */
299
- export function close(formId?: number): boolean {
912
+ export function close(formId: number): boolean {
300
913
  return changeState('close', formId);
301
914
  }
302
915
 
@@ -305,7 +918,7 @@ export function close(formId?: number): boolean {
305
918
  * @param e 事件源
306
919
  * @param border 调整大小的方位
307
920
  */
308
- export function bindResize(e: MouseEvent | TouchEvent, border: types.TBorder): void {
921
+ export function bindResize(e: MouseEvent | TouchEvent, border: types.TDomBorder): void {
309
922
  const formWrap = dom.findParentByClass(e.target as HTMLElement, 'cg-form-wrap');
310
923
  if (!formWrap) {
311
924
  return;
@@ -346,7 +959,7 @@ export function bindDrag(e: MouseEvent | TouchEvent): void {
346
959
  }
347
960
 
348
961
  /**
349
- * --- 重置所有已经最大化的窗体大小和位置 ---
962
+ * --- 重置所有已经最大化的窗体大小和位置,App 模式下无效 ---
350
963
  */
351
964
  export function refreshMaxPosition(): void {
352
965
  const area = core.getAvailArea();
@@ -403,12 +1016,12 @@ export function get(formId: number): types.IFormInfo | null {
403
1016
  'stateMax': item.vroot.$refs.form.stateMaxData,
404
1017
  'stateMin': item.vroot.$refs.form.stateMinData,
405
1018
  'show': item.vroot.$refs.form.showData,
406
- 'focus': item.vroot.cgFocus
1019
+ 'focus': item.vroot.formFocus
407
1020
  };
408
1021
  }
409
1022
 
410
1023
  /**
411
- * --- 给一个窗体发送一个对象,不会知道成功与失败状态 ---
1024
+ * --- 给一个窗体发送一个对象,不会知道成功与失败状态,APP 模式下无效用 this.send 替代 ---
412
1025
  * @param formId 要接收对象的 form id
413
1026
  * @param obj 要发送的对象
414
1027
  */
@@ -418,10 +1031,7 @@ export function send(formId: number, obj: Record<string, any>): void {
418
1031
  return;
419
1032
  }
420
1033
  const item = task.list[taskId].forms[formId];
421
- if (!item.vroot.cgReceive) {
422
- return;
423
- }
424
- item.vroot.cgReceive(obj);
1034
+ item.vroot.onReceive(obj);
425
1035
  }
426
1036
 
427
1037
  /**
@@ -442,7 +1052,7 @@ export function getList(taskId: number): Record<string, types.IFormInfo> {
442
1052
  'stateMax': item.vroot.$refs.form.stateMaxData,
443
1053
  'stateMin': item.vroot.$refs.form.stateMinData,
444
1054
  'show': item.vroot.$refs.form.showData,
445
- 'focus': item.vroot.cgFocus
1055
+ 'focus': item.vroot.formFocus
446
1056
  };
447
1057
  }
448
1058
  return list;
@@ -461,7 +1071,7 @@ export function changeFocus(formId: number = 0): void {
461
1071
  });
462
1072
  return;
463
1073
  }
464
- const focusElement = document.querySelector('#cg-form-list > [data-cg-focus]');
1074
+ const focusElement = document.querySelector('#cg-form-list > [data-form-focus]');
465
1075
  if (focusElement) {
466
1076
  const dataFormId = focusElement.getAttribute('data-form-id');
467
1077
  if (dataFormId) {
@@ -472,8 +1082,8 @@ export function changeFocus(formId: number = 0): void {
472
1082
  else {
473
1083
  const taskId = parseInt(focusElement.getAttribute('data-task-id') ?? '0');
474
1084
  const t = task.list[taskId];
475
- t.forms[dataFormIdNumber].vapp._container.removeAttribute('data-cg-focus');
476
- t.forms[dataFormIdNumber].vroot._cgFocus = false;
1085
+ t.forms[dataFormIdNumber].vapp._container.removeAttribute('data-form-focus');
1086
+ t.forms[dataFormIdNumber].vroot._formFocus = false;
477
1087
  // --- 触发 formBlurred 事件 ---
478
1088
  core.trigger('formBlurred', taskId, dataFormIdNumber);
479
1089
  }
@@ -497,43 +1107,42 @@ export function changeFocus(formId: number = 0): void {
497
1107
  const taskId: number = parseInt(el.getAttribute('data-task-id') ?? '0');
498
1108
  const t = task.list[taskId];
499
1109
  // --- 如果不是自定义的 zindex,则设置 zIndex 为最大 ---
500
- if (!t.forms[formId].vroot.cgCustomZIndex) {
501
- if (t.forms[formId].vroot.cgTopMost) {
502
- t.forms[formId].vroot.$refs.form.setPropData('zIndex', ++info.topLastZIndex);
503
- }
504
- else {
505
- t.forms[formId].vroot.$refs.form.setPropData('zIndex', ++info.lastZIndex);
506
- }
1110
+ if (t.forms[formId].vroot._topMost) {
1111
+ t.forms[formId].vroot.$refs.form.$data.zIndexData = ++info.topLastZIndex;
507
1112
  }
508
- // --- 检测 maskFor ---
509
- const maskFor = t.forms[formId].vroot.$refs.form.maskFor;
510
- if ((typeof maskFor === 'number') && (task.list[taskId].forms[maskFor])) {
511
- // --- maskFor 窗体 ---
512
- // --- 如果是最小化状态的话,需要还原 ---
513
- if (get(maskFor)!.stateMin) {
514
- min(maskFor);
515
- }
516
- // --- 如果不是自定义的 zindex,则设置 zIndex 为最大 ---
517
- if (!task.list[taskId].forms[maskFor].vroot.cgCustomZIndex) {
518
- if (task.list[taskId].forms[maskFor].vroot.cgTopMost) {
519
- task.list[taskId].forms[maskFor].vroot.$refs.form.setPropData('zIndex', ++info.topLastZIndex);
1113
+ else {
1114
+ t.forms[formId].vroot.$refs.form.$data.zIndexData = ++info.lastZIndex;
1115
+ }
1116
+ // --- 检测是否有 dialog mask ---
1117
+ if (t.runtime.dialogFormIds.length) {
1118
+ // --- 有 dialog ---
1119
+ const dialogFormId = t.runtime.dialogFormIds[t.runtime.dialogFormIds.length - 1];
1120
+ // --- 的判断点击的窗体是不是就是 dialog mask 窗体本身 ---
1121
+ if (dialogFormId !== formId) {
1122
+ // --- 如果是最小化状态的话,需要还原 ---
1123
+ if (get(dialogFormId)!.stateMin) {
1124
+ min(dialogFormId);
1125
+ }
1126
+ // --- 如果不是自定义的 zindex,则设置 zIndex 为最大 ---
1127
+ if (task.list[taskId].forms[dialogFormId].vroot._topMost) {
1128
+ task.list[taskId].forms[dialogFormId].vroot.$refs.form.$data.zIndexData = ++info.topLastZIndex;
520
1129
  }
521
1130
  else {
522
- task.list[taskId].forms[maskFor].vroot.$refs.form.setPropData('zIndex', ++info.lastZIndex);
1131
+ task.list[taskId].forms[dialogFormId].vroot.$refs.form.$data.zIndexData = ++info.lastZIndex;
523
1132
  }
1133
+ // --- 开启 focus ---
1134
+ task.list[taskId].forms[dialogFormId].vapp._container.dataset.formFocus = '';
1135
+ task.list[taskId].forms[dialogFormId].vroot._formFocus = true;
1136
+ // --- 触发 formFocused 事件 ---
1137
+ core.trigger('formFocused', taskId, dialogFormId);
1138
+ // --- 闪烁 ---
1139
+ clickgo.form.flash(dialogFormId, taskId);
524
1140
  }
525
- // --- 开启 focus ---
526
- task.list[taskId].forms[maskFor].vapp._container.dataset.cgFocus = '';
527
- task.list[taskId].forms[maskFor].vroot._cgFocus = true;
528
- // --- 触发 formFocused 事件 ---
529
- core.trigger('formFocused', taskId, maskFor);
530
- // --- 闪烁 ---
531
- clickgo.form.flash(maskFor, taskId);
532
1141
  }
533
1142
  else {
534
1143
  // --- 正常开启 focus ---
535
- t.forms[formId].vapp._container.dataset.cgFocus = '';
536
- t.forms[formId].vroot._cgFocus = true;
1144
+ t.forms[formId].vapp._container.dataset.formFocus = '';
1145
+ t.forms[formId].vroot._formFocus = true;
537
1146
  // --- 触发 formFocused 事件 ---
538
1147
  core.trigger('formFocused', taskId, formId);
539
1148
  }
@@ -552,6 +1161,9 @@ export function getMaxZIndexID(out: {
552
1161
  for (let i = 0; i < elements.list.children.length; ++i) {
553
1162
  const formWrap = elements.list.children.item(i) as HTMLDivElement;
554
1163
  const formInner = formWrap.children.item(0) as HTMLDivElement;
1164
+ if (!formInner) {
1165
+ continue;
1166
+ }
555
1167
  // --- 排除 top most 窗体 ---
556
1168
  const z = parseInt(formInner.style.zIndex);
557
1169
  if (z > 9999999) {
@@ -583,7 +1195,7 @@ export function getMaxZIndexID(out: {
583
1195
  * --- 根据 border 方向 获取理论窗体大小 ---
584
1196
  * @param border 显示的位置代号
585
1197
  */
586
- export function getRectByBorder(border: types.TBorder): { 'width': number; 'height': number; 'left': number; 'top': number; } {
1198
+ export function getRectByBorder(border: types.TDomBorderCustom): { 'width': number; 'height': number; 'left': number; 'top': number; } {
587
1199
  const area = core.getAvailArea();
588
1200
  let width!: number, height!: number, left!: number, top!: number;
589
1201
  if (typeof border === 'string') {
@@ -693,7 +1305,7 @@ export function showCircular(x: number, y: number): void {
693
1305
  * --- 移动矩形到新位置 ---
694
1306
  * @param border 显示的位置代号
695
1307
  */
696
- export function moveRectangle(border: types.TBorder): void {
1308
+ export function moveRectangle(border: types.TDomBorderCustom): void {
697
1309
  const dataReady = elements.rectangle.getAttribute('data-ready') ?? '0';
698
1310
  if (dataReady === '0') {
699
1311
  return;
@@ -723,7 +1335,7 @@ export function moveRectangle(border: types.TBorder): void {
723
1335
  * @param y 起始位置
724
1336
  * @param border 最大时位置代号
725
1337
  */
726
- export function showRectangle(x: number, y: number, border: types.TBorder): void {
1338
+ export function showRectangle(x: number, y: number, border: types.TDomBorderCustom): void {
727
1339
  elements.rectangle.style.transition = 'none';
728
1340
  requestAnimationFrame(function() {
729
1341
  elements.rectangle.style.width = '5px';
@@ -799,7 +1411,7 @@ let notifyTop: number = 10;
799
1411
  let notifyId: number = 0;
800
1412
  /**
801
1413
  * --- 弹出右上角信息框 ---
802
- * @param opt timeout 默认 5 秒
1414
+ * @param opt timeout 默认 5 秒,最大 30
803
1415
  */
804
1416
  export function notify(opt: types.INotifyOptions): number {
805
1417
  // --- 申请 nid ---
@@ -911,7 +1523,7 @@ export function hideNotify(notifyId: number): void {
911
1523
  }
912
1524
 
913
1525
  /**
914
- * --- 将标签追加到 pop ---
1526
+ * --- 将标签追加到 pop 层,App 模式下无效 ---
915
1527
  * @param el 要追加的标签
916
1528
  */
917
1529
  export function appendToPop(el: HTMLElement): void {
@@ -919,7 +1531,7 @@ export function appendToPop(el: HTMLElement): void {
919
1531
  }
920
1532
 
921
1533
  /**
922
- * --- 将标签从 pop 层移除 ---
1534
+ * --- 将标签从 pop 层移除,App 模式下无效 ---
923
1535
  * @param el 要移除的标签
924
1536
  */
925
1537
  export function removeFromPop(el: HTMLElement): void {
@@ -1117,7 +1729,7 @@ export function hidePop(pop?: HTMLElement): void {
1117
1729
  }
1118
1730
 
1119
1731
  /**
1120
- * --- 点下 (mousedown / touchstart) 屏幕任意一位置时根据点击处处理隐藏 pop 和焦点丢失事件,鼠标和 touch 只会响应一个 ---
1732
+ * --- 点下 (mousedown / touchstart) 屏幕任意一位置时根据点击处处理隐藏 pop 和焦点丢失事件,鼠标和 touch 只会响应一个,App 模式下无效 ---
1121
1733
  * @param e 事件对象
1122
1734
  */
1123
1735
  export function doFocusAndPopEvent(e: MouseEvent | TouchEvent): void {
@@ -1176,7 +1788,7 @@ window.addEventListener('touchstart', doFocusAndPopEvent, {
1176
1788
  window.addEventListener('mousedown', doFocusAndPopEvent);
1177
1789
 
1178
1790
  /**
1179
- * --- 移除一个 form(关闭窗口) ---
1791
+ * --- 移除一个 form(关闭窗口),App 模式下无效 ---
1180
1792
  * @param formId 要移除的 form id
1181
1793
  */
1182
1794
  export function remove(formId: number): boolean {
@@ -1186,9 +1798,10 @@ export function remove(formId: number): boolean {
1186
1798
  if (task.list[taskId].forms[formId]) {
1187
1799
  title = task.list[taskId].forms[formId].vroot.$refs.form.title;
1188
1800
  icon = task.list[taskId].forms[formId].vroot.$refs.form.iconData;
1189
- if (task.list[taskId].forms[formId].vroot.$refs.form.maskFrom !== undefined) {
1190
- const fid = task.list[taskId].forms[formId].vroot.$refs.form.maskFrom;
1191
- task.list[taskId].forms[fid].vroot.$refs.form.maskFor = undefined;
1801
+ const io = task.list[taskId].runtime.dialogFormIds.indexOf(formId);
1802
+ if (io > -1) {
1803
+ // --- 取消 dialog mask 记录 ---
1804
+ task.list[taskId].runtime.dialogFormIds.splice(io, 1);
1192
1805
  }
1193
1806
  task.list[taskId].forms[formId].vroot.$refs.form.$data.showData = false;
1194
1807
  setTimeout(function() {
@@ -1209,6 +1822,10 @@ export function remove(formId: number): boolean {
1209
1822
  }
1210
1823
  task.list[taskId].forms[formId].vapp.unmount();
1211
1824
  task.list[taskId].forms[formId].vapp._container.remove();
1825
+ if (io > -1) {
1826
+ // --- 如果是 dialog 则要执行回调 ---
1827
+ task.list[taskId].forms[formId].vroot.cgDialogCallback();
1828
+ }
1212
1829
  delete task.list[taskId].forms[formId];
1213
1830
  // --- 移除 form 的 style ---
1214
1831
  dom.removeStyle(taskId, 'form', formId);
@@ -1227,22 +1844,16 @@ export function remove(formId: number): boolean {
1227
1844
  }
1228
1845
 
1229
1846
  /**
1230
- * --- 根据任务 id 和 form id 获取 IForm 对象 ---
1847
+ * --- 根据任务 id 和 form id 获取 IForm 对象,App 模式下无效 ---
1231
1848
  * @param taskId 任务 id
1232
1849
  * @param formId 窗体 id
1233
1850
  */
1234
- function getForm(taskId?: number, formId?: number): types.IForm | null {
1235
- if (!taskId) {
1236
- return null;
1237
- }
1851
+ function getForm(taskId: number, formId: number): types.IForm | null {
1238
1852
  /** --- 当前的 task 对象 --- */
1239
1853
  const t = task.list[taskId];
1240
1854
  if (!t) {
1241
1855
  return null;
1242
1856
  }
1243
- if (!formId) {
1244
- return null;
1245
- }
1246
1857
  const form = t.forms[formId];
1247
1858
  if (!form) {
1248
1859
  return null;
@@ -1251,753 +1862,29 @@ function getForm(taskId?: number, formId?: number): types.IForm | null {
1251
1862
  }
1252
1863
 
1253
1864
  /**
1254
- * --- 直接创建一个窗体(需要验证传入 code、layout 等是否能成功创建) ---
1865
+ * --- 创建一个窗体,App 模式下无效 ---
1255
1866
  * @param opt 创建窗体的配置对象
1256
1867
  */
1257
- export async function create(opt: string | types.IFormCreateOptions): Promise<number | types.IForm> {
1258
- if (typeof opt === 'string') {
1259
- return 0;
1260
- }
1868
+ export async function create(opt: types.IFormCreateOptions): Promise<number> {
1261
1869
  if (!opt.taskId) {
1262
1870
  return -1;
1263
1871
  }
1264
- if (opt.path && (!opt.path.endsWith('/') || !opt.path?.startsWith('/'))) {
1265
- return -2;
1266
- }
1267
- const taskId = opt.taskId;
1268
1872
  /** --- 当前的 task 对象 --- */
1269
- const t = task.list[taskId];
1873
+ const t = task.list[opt.taskId];
1270
1874
  if (!t) {
1271
- return -3;
1272
- }
1273
- let form: types.IForm | null = null;
1274
- if (opt.formId) {
1275
- if (!t.forms[opt.formId]) {
1276
- return -4;
1277
- }
1278
- form = t.forms[opt.formId];
1279
- }
1280
- /** --- 是否创建置顶的窗体 --- */
1281
- let topMost = opt.topMost ?? false;
1282
- if (form?.vroot.cgTopMost) {
1283
- topMost = true;
1284
- }
1285
- // --- 是否要给原窗体增加遮罩 ---
1286
- if (opt.mask && form) {
1287
- form.vroot.$refs.form.maskFor = 0;
1288
- }
1289
- /** --- 当前父 form 的路径(以 / 结尾)或 /(没有基路径的话) --- */
1290
- const base: string = form ? form.vroot.cgPath : '/';
1291
- /** --- 要新建的 form 的文件路径 --- */
1292
- let filePath = '', newBase = '';
1293
- if (opt.file) {
1294
- filePath = clickgo.tool.urlResolve(base, opt.file);
1295
- newBase = filePath.slice(0, filePath.lastIndexOf('/') + 1);
1296
- }
1297
- else {
1298
- newBase = opt.path ?? base;
1875
+ return -2;
1299
1876
  }
1300
-
1301
- /** --- 当前的 APP 对象 --- */
1302
- const app: types.IApp = t.app;
1303
1877
  // --- 申请 formId ---
1304
1878
  const formId = ++info.lastId;
1305
- // --- 注入的参数,屏蔽浏览器全局对象,注入新的对象 ---
1306
- const invoke: Record<string, any> = {};
1307
- if (clickgo.getSafe()) {
1308
- invoke.window = undefined;
1309
- invoke.loader = undefined;
1310
- const ks = Object.getOwnPropertyNames(window);
1311
- for (const k of ks) {
1312
- if (k.includes('Event')) {
1313
- continue;
1314
- }
1315
- if (k.includes('-')) {
1316
- continue;
1317
- }
1318
- if (/^[0-9]+$/.test(k)) {
1319
- continue;
1320
- }
1321
- if ([
1322
- 'require',
1323
- '__awaiter', 'eval', 'Math', 'Array', 'Blob', 'Infinity', 'parseInt', 'parseFloat', 'Promise', 'Date', 'JSON', 'fetch'].includes(k)) {
1324
- continue;
1325
- }
1326
- invoke[k] = undefined;
1327
- }
1328
- // --- console ---
1329
- invoke.console = {
1330
- log: function(message?: any, ...optionalParams: any[]) {
1331
- console.log(message, ...optionalParams);
1332
- }
1333
- };
1334
- // --- loader ---
1335
- invoke.loader = {
1336
- require: function(paths: string | string[], files: Record<string, Blob | string>, opt?: {
1337
- 'executed'?: Record<string, any>;
1338
- 'map'?: Record<string, string>;
1339
- 'dir'?: string;
1340
- 'style'?: string;
1341
- 'invoke'?: Record<string, any>;
1342
- 'preprocess'?: (code: string, path: string) => string;
1343
- }): any[] {
1344
- return loader.require(paths, files, opt);
1345
- }
1346
- };
1347
- // --- Object ---
1348
- invoke.Object = {
1349
- defineProperty: function(): void {
1350
- return;
1351
- },
1352
- keys: function(o: any): string[] {
1353
- return Object.keys(o);
1354
- },
1355
- assign: function(o: any, o2: any): any {
1356
- if (o.controlName !== undefined) {
1357
- return o;
1358
- }
1359
- return Object.assign(o, o2);
1360
- }
1361
- };
1362
- invoke.navigator = {};
1363
- if (navigator.clipboard) {
1364
- invoke.navigator.clipboard = navigator.clipboard;
1365
- }
1366
- // --- ClickGo 相关 ---
1367
- invoke.invokeClickgo = {
1368
- getVersion: function(): string {
1369
- return clickgo.getVersion();
1370
- },
1371
- getNative(): boolean {
1372
- return clickgo.getNative();
1373
- },
1374
- getPlatform(): string {
1375
- return clickgo.getPlatform();
1376
- },
1377
- getSafe(): boolean {
1378
- return clickgo.getSafe();
1379
- },
1380
- 'control': {
1381
- read: function(blob: Blob): Promise<false | types.TControl> {
1382
- return clickgo.control.read(blob);
1383
- }
1384
- },
1385
- 'core': {
1386
- 'config': clickgo.core.config,
1387
- 'cdn': loader.cdn,
1388
- initModules: function(names: string | string[]): Promise<number> {
1389
- return clickgo.core.initModules(names);
1390
- },
1391
- getModule: function(name: string): null | any {
1392
- return clickgo.core.getModule(name);
1393
- },
1394
- setSystemEventListener: function(
1395
- name: types.TGlobalEvent,
1396
- func: (...any: any) => void | Promise<void>,
1397
- fid?: number
1398
- ): void {
1399
- clickgo.core.setSystemEventListener(name, func, fid ?? formId, taskId);
1400
- },
1401
- removeSystemEventListener: function(
1402
- name: types.TGlobalEvent,
1403
- fid?: number
1404
- ): void {
1405
- clickgo.core.removeSystemEventListener(name, fid ?? formId, taskId);
1406
- },
1407
- trigger: function(name: types.TGlobalEvent, param1: boolean | Error | string = '', param2: string = ''): void {
1408
- if (!['formTitleChanged', 'formIconChanged', 'formStateMinChanged', 'formStateMaxChanged', 'formShowChanged'].includes(name)) {
1409
- return;
1410
- }
1411
- clickgo.core.trigger(name, taskId, formId, param1, param2);
1412
- },
1413
- readApp: function(blob: Blob): Promise<false | types.IApp> {
1414
- return clickgo.core.readApp(blob);
1415
- },
1416
- getAvailArea: function(): types.IAvailArea {
1417
- return clickgo.core.getAvailArea();
1418
- }
1419
- },
1420
- 'dom': {
1421
- setGlobalCursor: function(type?: string): void {
1422
- clickgo.dom.setGlobalCursor(type);
1423
- },
1424
- hasTouchButMouse: function(e: MouseEvent | TouchEvent | PointerEvent): boolean {
1425
- return clickgo.dom.hasTouchButMouse(e);
1426
- },
1427
- getStyleCount: function(taskId: number, type: 'theme' | 'control' | 'form'): number {
1428
- return clickgo.dom.getStyleCount(taskId, type);
1429
- },
1430
- getSize: function(el: HTMLElement): types.IDomSize {
1431
- return clickgo.dom.getSize(el);
1432
- },
1433
- watchSize: function(
1434
- el: HTMLElement,
1435
- cb: (size: types.IDomSize) => Promise<void> | void,
1436
- immediate: boolean = false
1437
- ): types.IDomSize {
1438
- return clickgo.dom.watchSize(el, cb, immediate, taskId);
1439
- },
1440
- unwatchSize: function(el: HTMLElement): void {
1441
- clickgo.dom.unwatchSize(el, taskId);
1442
- },
1443
- clearWatchSize(): void {
1444
- clickgo.dom.clearWatchSize(taskId);
1445
- },
1446
- watch: function(el: HTMLElement, cb: () => void, mode: 'child' | 'childsub' | 'style' | 'default' = 'default', immediate: boolean = false): void {
1447
- clickgo.dom.watch(el, cb, mode, immediate, taskId);
1448
- },
1449
- unwatch: function(el: HTMLElement): void {
1450
- clickgo.dom.unwatch(el, taskId);
1451
- },
1452
- clearWatch: function(): void {
1453
- clickgo.dom.clearWatch(taskId);
1454
- },
1455
- watchStyle: function(
1456
- el: HTMLElement,
1457
- name: string | string[],
1458
- cb: (name: string, value: string) => void,
1459
- immediate: boolean = false
1460
- ): void {
1461
- clickgo.dom.watchStyle(el, name, cb, immediate);
1462
- },
1463
- isWatchStyle: function(el: HTMLElement): boolean {
1464
- return clickgo.dom.isWatchStyle(el);
1465
- },
1466
- bindDown: function(oe: MouseEvent | TouchEvent, opt: types.IBindDownOptions) {
1467
- clickgo.dom.bindDown(oe, opt);
1468
- },
1469
- bindGesture: function(e: MouseEvent | TouchEvent | WheelEvent | { 'x'?: number; 'y'?: number; }, opt: types.IBindGestureOptions): void {
1470
- clickgo.dom.bindGesture(e, opt);
1471
- },
1472
- bindLong: function(
1473
- e: MouseEvent | TouchEvent,
1474
- long: (e: MouseEvent | TouchEvent) => void | Promise<void>
1475
- ): void {
1476
- clickgo.dom.bindLong(e, long);
1477
- },
1478
- bindDrag: function(e: MouseEvent | TouchEvent, opt: { 'el': HTMLElement; 'data'?: any; }): void {
1479
- clickgo.dom.bindDrag(e, opt);
1480
- },
1481
- 'is': clickgo.dom.is,
1482
- bindMove: function(e: MouseEvent | TouchEvent, opt: types.IBindMoveOptions): types.IBindMoveResult {
1483
- return clickgo.dom.bindMove(e, opt);
1484
- },
1485
- bindResize: function(e: MouseEvent | TouchEvent, opt: types.IBindResizeOptions): void {
1486
- clickgo.dom.bindResize(e, opt);
1487
- },
1488
- findParentByData: function(el: HTMLElement, name: string): HTMLElement | null {
1489
- return clickgo.dom.findParentByData(el, name);
1490
- },
1491
- findParentByClass: function(el: HTMLElement, name: string): HTMLElement | null {
1492
- return clickgo.dom.findParentByClass(el, name);
1493
- },
1494
- siblings: function(el: HTMLElement): HTMLElement[] {
1495
- return clickgo.dom.siblings(el);
1496
- },
1497
- siblingsData: function(el: HTMLElement, name: string): HTMLElement[] {
1498
- return clickgo.dom.siblingsData(el, name);
1499
- },
1500
- fullscreen: function(): boolean {
1501
- return clickgo.dom.fullscreen();
1502
- }
1503
- },
1504
- 'form': {
1505
- min: function(fid?: number): boolean {
1506
- return clickgo.form.min(fid ?? formId);
1507
- },
1508
- max: function max(fid?: number): boolean {
1509
- return clickgo.form.max(fid ?? formId);
1510
- },
1511
- close: function(fid?: number): boolean {
1512
- return clickgo.form.close(fid ?? formId);
1513
- },
1514
- bindResize: function(e: MouseEvent | TouchEvent, border: types.TBorder): void {
1515
- clickgo.form.bindResize(e, border);
1516
- },
1517
- bindDrag: function(e: MouseEvent | TouchEvent): void {
1518
- clickgo.form.bindDrag(e);
1519
- },
1520
- getTaskId: function(fid: number): number {
1521
- return clickgo.form.getTaskId(fid);
1522
- },
1523
- get: function(fid: number): types.IFormInfo | null {
1524
- return clickgo.form.get(fid);
1525
- },
1526
- send: function(fid: number, obj: Record<string, any>): void {
1527
- obj.taskId = taskId;
1528
- obj.formId = formId;
1529
- clickgo.form.send(fid, obj);
1530
- },
1531
- getList: function(tid: number): Record<string, types.IFormInfo> {
1532
- return clickgo.form.getList(tid);
1533
- },
1534
- changeFocus: function(fid: number = 0): void {
1535
- clickgo.form.changeFocus(fid);
1536
- },
1537
- getMaxZIndexID: function(out?: {
1538
- 'taskIds'?: number[];
1539
- 'formIds'?: number[];
1540
- }): number | null {
1541
- return clickgo.form.getMaxZIndexID(out);
1542
- },
1543
- getRectByBorder: function(border: types.TBorder): { 'width': number; 'height': number; 'left': number; 'top': number; } {
1544
- return clickgo.form.getRectByBorder(border);
1545
- },
1546
- showCircular: function(x: number, y: number): void {
1547
- clickgo.form.showCircular(x, y);
1548
- },
1549
- moveRectangle: function(border: types.TBorder): void {
1550
- clickgo.form.moveRectangle(border);
1551
- },
1552
- showRectangle: function(x: number, y: number, border: types.TBorder): void {
1553
- clickgo.form.showRectangle(x, y, border);
1554
- },
1555
- hideRectangle: function(): void {
1556
- clickgo.form.hideRectangle();
1557
- },
1558
- showDrag: function(): void {
1559
- clickgo.form.showDrag();
1560
- },
1561
- moveDrag: function(opt: types.IMoveDragOptions): void {
1562
- clickgo.form.moveDrag(opt);
1563
- },
1564
- hideDrag: function(): void {
1565
- clickgo.form.hideDrag();
1566
- },
1567
- notify: function(opt: types.INotifyOptions): number {
1568
- return clickgo.form.notify(opt);
1569
- },
1570
- notifyProgress: function(notifyId: number, per: number): void {
1571
- clickgo.form.notifyProgress(notifyId, per);
1572
- },
1573
- hideNotify: function(notifyId: number): void {
1574
- clickgo.form.hideNotify(notifyId);
1575
- },
1576
- 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 {
1577
- clickgo.form.showPop(el, pop, direction, opt);
1578
- },
1579
- hidePop: function(pop?: HTMLElement): void {
1580
- clickgo.form.hidePop(pop);
1581
- },
1582
- create: function(opt: string | types.IFormCreateOptions): Promise<number | types.IForm> {
1583
- if (typeof opt === 'string') {
1584
- opt = {
1585
- 'file': opt
1586
- };
1587
- }
1588
- opt.taskId = taskId;
1589
- opt.formId = formId;
1590
- return clickgo.form.create(opt);
1591
- },
1592
- dialog: function(opt: string | types.IFormDialogOptions): Promise<string> {
1593
- if (typeof opt === 'string') {
1594
- opt = {
1595
- 'content': opt
1596
- };
1597
- }
1598
- opt.formId = formId;
1599
- return clickgo.form.dialog(opt);
1600
- },
1601
- confirm: function(opt: string | types.IFormConfirmOptions): Promise<boolean | number> {
1602
- if (typeof opt === 'string') {
1603
- opt = {
1604
- 'content': opt
1605
- };
1606
- }
1607
- opt.formId = formId;
1608
- return clickgo.form.confirm(opt);
1609
- },
1610
- setTopMost: function(top: boolean, opt: types.IFormSetTopMostOptions = {}): void {
1611
- opt.taskId = taskId;
1612
- opt.formId = formId;
1613
- clickgo.form.setTopMost(top, opt);
1614
- },
1615
- flash: function(fid?: number): void {
1616
- clickgo.form.flash(fid ?? formId, taskId);
1617
- },
1618
- show: function(fid?: number): void {
1619
- clickgo.form.show(fid ?? formId, taskId);
1620
- },
1621
- hide: function(fid?: number): void {
1622
- clickgo.form.hide(fid ?? formId, taskId);
1623
- }
1624
- },
1625
- 'fs': {
1626
- getContent: function(
1627
- path: string,
1628
- options: any = {}
1629
- ): Promise<Blob | string | null> {
1630
- if (!options.files) {
1631
- options.files = t.files;
1632
- }
1633
- if (!options.current) {
1634
- options.current = t.path;
1635
- }
1636
- return clickgo.fs.getContent(path, options);
1637
- },
1638
- putContent: function(path: string, data: string | Buffer, options: any = {}) {
1639
- if (!options.current) {
1640
- options.current = t.path;
1641
- }
1642
- return clickgo.fs.putContent(path, data, options);
1643
- },
1644
- readLink: function(path: string, options: any = {}): Promise<string | null> {
1645
- if (!options.current) {
1646
- options.current = t.path;
1647
- }
1648
- return clickgo.fs.readLink(path, options);
1649
- },
1650
- symlink: function(fPath: string, linkPath: string, options: any = {}): Promise<boolean> {
1651
- if (!options.current) {
1652
- options.current = t.path;
1653
- }
1654
- return clickgo.fs.symlink(fPath, linkPath, options);
1655
- },
1656
- unlink: function(path: string, options: any = {}): Promise<boolean> {
1657
- if (!options.current) {
1658
- options.current = t.path;
1659
- }
1660
- return clickgo.fs.unlink(path, options);
1661
- },
1662
- stats: function(path: string, options: any = {}): Promise<types.IStats | null> {
1663
- if (!options.files) {
1664
- options.files = t.files;
1665
- }
1666
- if (!options.current) {
1667
- options.current = t.path;
1668
- }
1669
- return clickgo.fs.stats(path, options);
1670
- },
1671
- isDir: function(path: string, options: any = {}): Promise<types.IStats | false> {
1672
- if (!options.files) {
1673
- options.files = t.files;
1674
- }
1675
- if (!options.current) {
1676
- options.current = t.path;
1677
- }
1678
- return clickgo.fs.isDir(path, options);
1679
- },
1680
- isFile: function(path: string, options: any = {}): Promise<types.IStats | false> {
1681
- if (!options.files) {
1682
- options.files = t.files;
1683
- }
1684
- if (!options.current) {
1685
- options.current = t.path;
1686
- }
1687
- return clickgo.fs.isFile(path, options);
1688
- },
1689
- mkdir: function(path: string, mode?: number, options: any = {}): Promise<boolean> {
1690
- if (!options.current) {
1691
- options.current = t.path;
1692
- }
1693
- return clickgo.fs.mkdir(path, mode, options);
1694
- },
1695
- rmdir: function(path: string, options: any = {}): Promise<boolean> {
1696
- if (!options.current) {
1697
- options.current = t.path;
1698
- }
1699
- return clickgo.fs.rmdir(path, options);
1700
- },
1701
- rmdirDeep: function(path: string, options: any = {}): Promise<boolean> {
1702
- if (!options.current) {
1703
- options.current = t.path;
1704
- }
1705
- return clickgo.fs.rmdirDeep(path, options);
1706
- },
1707
- chmod: function(path: string, mod: string | number, options: any = {}): Promise<boolean> {
1708
- if (!options.current) {
1709
- options.current = t.path;
1710
- }
1711
- return clickgo.fs.chmod(path, mod, options);
1712
- },
1713
- rename(oldPath: string, newPath: string, options: any = {}): Promise<boolean> {
1714
- if (!options.current) {
1715
- options.current = t.path;
1716
- }
1717
- return clickgo.fs.rename(oldPath, newPath, options);
1718
- },
1719
- readDir(path: string, options: any = {}): Promise<types.IDirent[]> {
1720
- if (!options.files) {
1721
- options.files = t.files;
1722
- }
1723
- if (!options.current) {
1724
- options.current = t.path;
1725
- }
1726
- return clickgo.fs.readDir(path, options);
1727
- },
1728
- copyFolder(from: string, to: string, options: any = {}): Promise<number> {
1729
- if (!options.current) {
1730
- options.current = t.path;
1731
- }
1732
- return clickgo.fs.copyFolder(from, to, options);
1733
- },
1734
- copyFile(src: string, dest: string, options: any = {}): Promise<boolean> {
1735
- if (!options.current) {
1736
- options.current = t.path;
1737
- }
1738
- return clickgo.fs.copyFile(src, dest, options);
1739
- }
1740
- },
1741
- 'native': {
1742
- getListeners: function(): Array<{ 'id': number; 'name': string; 'once': boolean; 'taskId'?: number; }> {
1743
- return clickgo.native.getListeners();
1744
- },
1745
- send: function(
1746
- name: string,
1747
- param?: string,
1748
- handler?: (param?: string) => void | Promise<void>
1749
- ): number {
1750
- return clickgo.native.send(name, param, handler, taskId);
1751
- },
1752
- on: function(
1753
- name: string,
1754
- handler: (param?: string) => void | Promise<void>,
1755
- id?: number,
1756
- once: boolean = false
1757
- ): void {
1758
- clickgo.native.on(name, handler, id, once, taskId);
1759
- },
1760
- once: function(
1761
- name: string,
1762
- handler: (param?: string) => void | Promise<void>,
1763
- id?: number
1764
- ): void {
1765
- clickgo.native.once(name, handler, id, taskId);
1766
- },
1767
- off: function(name: string, handler: (param?: string) => void | Promise<void>): void {
1768
- clickgo.native.off(name, handler, taskId);
1769
- },
1770
- clearListener: function(): void {
1771
- clickgo.native.clearListener(taskId);
1772
- },
1773
- max: function(): void {
1774
- clickgo.native.max();
1775
- },
1776
- min: function(): void {
1777
- clickgo.native.min();
1778
- },
1779
- restore: function(): void {
1780
- clickgo.native.restore();
1781
- },
1782
- size: function(width: number, height: number): void {
1783
- clickgo.native.size(width, height);
1784
- }
1785
- },
1786
- 'task': {
1787
- onFrame: function(fun: () => void | Promise<void>, opt: {
1788
- 'scope'?: 'form' | 'task';
1789
- 'count'?: number;
1790
- 'taskId'?: number;
1791
- 'formId'?: number;
1792
- } = {}): number {
1793
- opt.taskId = taskId;
1794
- opt.formId = formId;
1795
- return clickgo.task.onFrame(fun, opt);
1796
- },
1797
- offFrame: function(ft: number, opt: {
1798
- 'taskId'?: number;
1799
- } = {}): void {
1800
- opt.taskId = taskId;
1801
- clickgo.task.offFrame(ft, opt);
1802
- },
1803
- get: function(tid: number): types.ITaskInfo | null {
1804
- return clickgo.task.get(tid);
1805
- },
1806
- getList: function(): Record<string, types.ITaskInfo> {
1807
- return clickgo.task.getList();
1808
- },
1809
- run: function(url: string, opt: types.ITaskRunOptions = {}): Promise<number> {
1810
- opt.taskId = taskId;
1811
- opt.main = false;
1812
- return clickgo.task.run(url, opt);
1813
- },
1814
- end: function(tid: number): boolean {
1815
- return clickgo.task.end(tid ?? taskId);
1816
- },
1817
- loadLocaleData: function(lang: string, data: Record<string, any>, pre: string = ''): void {
1818
- clickgo.task.loadLocaleData(lang, data, pre, taskId);
1819
- },
1820
- loadLocale: function(lang: string, path: string): Promise<boolean> {
1821
- return clickgo.task.loadLocale(lang, path, taskId, formId);
1822
- },
1823
- clearLocale: function(): void {
1824
- clickgo.task.clearLocale(taskId);
1825
- },
1826
- setLocale: function(lang: string, path: string): Promise<boolean> {
1827
- return clickgo.task.setLocale(lang, path, taskId, formId);
1828
- },
1829
- setLocaleLang: function(lang: string): void {
1830
- clickgo.task.setLocaleLang(lang, taskId);
1831
- },
1832
- clearLocaleLang: function(): void {
1833
- clickgo.task.clearLocaleLang(taskId);
1834
- },
1835
- createTimer: function(
1836
- fun: () => void | Promise<void>,
1837
- delay: number,
1838
- opt: types.ICreateTimerOptions = {}
1839
- ): number {
1840
- opt.taskId = taskId;
1841
- if (!opt.formId) {
1842
- opt.formId = formId;
1843
- }
1844
- return clickgo.task.createTimer(fun, delay, opt);
1845
- },
1846
- removeTimer: function(timer: number): void {
1847
- clickgo.task.removeTimer(timer, taskId);
1848
- },
1849
- sleep: function(fun: () => void | Promise<void>, delay: number): number {
1850
- return clickgo.task.sleep(fun, delay, taskId, formId);
1851
- },
1852
- systemTaskInfo: clickgo.task.systemTaskInfo,
1853
- setSystem: function(fid?: number): boolean {
1854
- return clickgo.task.setSystem(fid ?? formId, taskId);
1855
- },
1856
- clearSystem: function(): boolean {
1857
- return clickgo.task.clearSystem(taskId);
1858
- }
1859
- },
1860
- 'theme': {
1861
- read: function(blob: Blob): Promise<types.ITheme | false> {
1862
- return clickgo.theme.read(blob);
1863
- },
1864
- load: async function(theme?: types.ITheme): Promise<boolean> {
1865
- if (!theme) {
1866
- return false;
1867
- }
1868
- return clickgo.theme.load(theme, taskId);
1869
- },
1870
- remove: function(name: string): Promise<void> {
1871
- return clickgo.theme.remove(name, taskId);
1872
- },
1873
- clear: function(): Promise<void> {
1874
- return clickgo.theme.clear(taskId);
1875
- },
1876
- setGlobal: function(theme: types.ITheme): Promise<void> {
1877
- return clickgo.theme.setGlobal(theme);
1878
- },
1879
- clearGlobal: function(): void {
1880
- clickgo.theme.clearGlobal();
1881
- }
1882
- },
1883
- 'tool': {
1884
- blob2ArrayBuffer: function(blob: Blob): Promise<ArrayBuffer> {
1885
- return clickgo.tool.blob2ArrayBuffer(blob);
1886
- },
1887
- clone: function(obj: Record<string, any> | any[]): any[] | any {
1888
- return clickgo.tool.clone(obj);
1889
- },
1890
- sleep: function(ms: number = 0): Promise<boolean> {
1891
- return clickgo.tool.sleep(ms);
1892
- },
1893
- purify: function(text: string): string {
1894
- return clickgo.tool.purify(text);
1895
- },
1896
- createObjectURL: function(object: Blob): string {
1897
- return clickgo.tool.createObjectURL(object, taskId);
1898
- },
1899
- revokeObjectURL: function(url: string): void {
1900
- clickgo.tool.revokeObjectURL(url, taskId);
1901
- },
1902
- rand: function(min: number, max: number): number {
1903
- return clickgo.tool.rand(min, max);
1904
- },
1905
- 'RANDOM_N': clickgo.tool.RANDOM_N,
1906
- 'RANDOM_U': clickgo.tool.RANDOM_U,
1907
- 'RANDOM_L': clickgo.tool.RANDOM_L,
1908
- 'RANDOM_UN': clickgo.tool.RANDOM_UN,
1909
- 'RANDOM_LN': clickgo.tool.RANDOM_LN,
1910
- 'RANDOM_LU': clickgo.tool.RANDOM_LU,
1911
- 'RANDOM_LUN': clickgo.tool.RANDOM_LUN,
1912
- 'RANDOM_V': clickgo.tool.RANDOM_V,
1913
- 'RANDOM_LUNS': clickgo.tool.RANDOM_LUNS,
1914
- random: function(length: number = 8, source: string = clickgo.tool.RANDOM_LN, block: string = ''): string {
1915
- return clickgo.tool.random(length, source, block);
1916
- },
1917
- getBoolean: function(param: boolean | string | number): boolean {
1918
- return clickgo.tool.getBoolean(param);
1919
- },
1920
- escapeHTML: function(html: string): string {
1921
- return clickgo.tool.escapeHTML(html);
1922
- },
1923
- request: function(url: string, opt: types.IRequestOptions): Promise<null | any> {
1924
- return clickgo.tool.request(url, opt);
1925
- },
1926
- parseUrl: function(url: string): ILoaderUrl {
1927
- return clickgo.tool.parseUrl(url);
1928
- },
1929
- urlResolve: function(from: string, to: string): string {
1930
- return clickgo.tool.urlResolve(from, to);
1931
- },
1932
- blob2Text: function(blob: Blob): Promise<string> {
1933
- return clickgo.tool.blob2Text(blob);
1934
- },
1935
- blob2DataUrl: function(blob: Blob): Promise<string> {
1936
- return clickgo.tool.blob2DataUrl(blob);
1937
- },
1938
- execCommand: function(ac: string): void {
1939
- clickgo.tool.execCommand(ac);
1940
- }
1941
- },
1942
- 'zip': {
1943
- get: function(data?: types.TZipInputFileFormat) {
1944
- return clickgo.zip.get(data);
1945
- }
1946
- }
1947
- };
1948
- }
1949
- else {
1950
- invoke.invokeClickgo = clickgo;
1951
- }
1952
- // --- 代码预处理 ---
1953
- const preprocess = clickgo.getSafe() ? function(code: string, path: string): string {
1954
- const exec = /eval\W/.exec(code);
1955
- if (exec) {
1956
- notify({
1957
- 'title': 'Error',
1958
- 'content': `The "eval" is prohibited.\nFile: "${path}".`,
1959
- 'type': 'danger'
1960
- });
1961
- return '';
1962
- }
1963
- return code;
1964
- } : undefined;
1965
1879
  // --- 获取要定义的控件列表 ---
1966
- const components = await control.init(t.id, formId, newBase, preprocess, invoke);
1880
+ const components = control.buildComponents(t.id, formId, opt.path ?? '');
1967
1881
  if (!components) {
1968
- if (form?.vroot.$refs.form.maskFor !== undefined) {
1969
- form.vroot.$refs.form.maskFor = undefined;
1970
- }
1971
- return -5;
1972
- }
1973
- // --- 获取 style、layout ---
1974
- let style = opt.style;
1975
- let layout: string | undefined = opt.layout;
1976
- if (filePath) {
1977
- if (!filePath.startsWith('/package/')) {
1978
- return -6;
1979
- }
1980
- const file = filePath.slice(8);
1981
- const layoutFile = app.files[file + '.xml'] as string;
1982
- if (layoutFile) {
1983
- layout = layoutFile.replace(/^\ufeff/, '');
1984
- }
1985
- const styleFile = app.files[file + '.css'] as string;
1986
- if (styleFile) {
1987
- style = styleFile.replace(/^\ufeff/, '');
1988
- }
1989
- }
1990
- if (layout === undefined) {
1991
- if (form?.vroot.$refs.form.maskFor !== undefined) {
1992
- form.vroot.$refs.form.maskFor = undefined;
1993
- }
1994
- return -7;
1882
+ return -3;
1995
1883
  }
1996
1884
  // --- 准备相关变量 ---
1997
1885
  let data: Record<string, any> = {};
1998
- let methods: any = {};
1999
- let computed: any = {};
2000
- let watch = {};
1886
+ let methods: Record<string, any> | undefined = undefined;
1887
+ let computed: Record<string, any> = {};
2001
1888
  let beforeCreate: (() => void) | undefined = undefined;
2002
1889
  let created: (() => void) | undefined = undefined;
2003
1890
  let beforeMount: (() => void) | undefined = undefined;
@@ -2006,52 +1893,34 @@ export async function create(opt: string | types.IFormCreateOptions): Promise<nu
2006
1893
  let updated: (() => void) | undefined = undefined;
2007
1894
  let beforeUnmount: (() => void) | undefined = undefined;
2008
1895
  let unmounted: (() => void) | undefined = undefined;
2009
- let receive: ((obj: Record<string, any>) => void) | undefined = undefined;
2010
- // --- 检测是否有 js ---
2011
- let expo = opt.code;
2012
- if (filePath?.startsWith('/package/') && app.files[filePath.slice(8) + '.js']) {
2013
- const file = filePath.slice(8);
2014
- if (app.files[file + '.js']) {
2015
- app.files['/invoke/clickgo.js'] = `module.exports = invokeClickgo;`;
2016
- expo = loader.require(file, app.files, {
2017
- 'dir': '/',
2018
- 'invoke': invoke,
2019
- 'preprocess': preprocess,
2020
- 'map': {
2021
- 'clickgo': '/invoke/clickgo'
2022
- }
2023
- })[0];
2024
- }
2025
- }
2026
- if (expo) {
2027
- data = expo.data ?? {};
2028
- methods = expo.methods || {};
2029
- computed = expo.computed || {};
2030
- watch = expo.watch || {};
2031
- beforeCreate = expo.beforeCreate;
2032
- created = expo.created;
2033
- beforeMount = expo.beforeMount;
2034
- mounted = expo.mounted;
2035
- beforeUpdate = expo.beforeUpdate;
2036
- updated = expo.updated;
2037
- beforeUnmount = expo.beforeUnmount;
2038
- unmounted = expo.unmounted;
2039
- receive = expo.receive;
1896
+ if (opt.code) {
1897
+ data = opt.code.data ?? {};
1898
+ methods = opt.code.methods;
1899
+ computed = opt.code.computed ?? {};
1900
+ beforeCreate = opt.code.beforeCreate;
1901
+ created = opt.code.created;
1902
+ beforeMount = opt.code.beforeMount;
1903
+ mounted = opt.code.mounted;
1904
+ beforeUpdate = opt.code.beforeUpdate;
1905
+ updated = opt.code.updated;
1906
+ beforeUnmount = opt.code.beforeUnmount;
1907
+ unmounted = opt.code.unmounted;
2040
1908
  }
2041
1909
  // --- 应用样式表 ---
1910
+ let style = '';
2042
1911
  let prep = '';
2043
- if (style) {
1912
+ if (opt.style) {
2044
1913
  // --- 将 style 中的 tag 标签转换为 class,如 button 变为 .tag-button,然后将 class 进行标准程序,添加 prep 进行区分隔离 ---
2045
- const r = tool.stylePrepend(style);
1914
+ const r = tool.stylePrepend(opt.style);
2046
1915
  prep = r.prep;
2047
- style = await tool.styleUrl2DataUrl(newBase, r.style, app.files);
1916
+ style = await tool.styleUrl2DataUrl(opt.path ?? '/', r.style, t.app.files);
2048
1917
  }
2049
1918
  // --- 要创建的 form 的 layout 所有标签增加 cg 前缀,并增加新的 class 为 tag-xxx ---
2050
- layout = tool.purify(layout);
1919
+ let layout = tool.purify(opt.layout);
2051
1920
  // --- 标签增加 cg- 前缀,增加 class 为 tag-xxx ---
2052
1921
  layout = tool.layoutAddTagClassAndReTagName(layout, true);
2053
1922
  // --- 给所有控件传递窗体的 focus 信息 ---
2054
- layout = tool.layoutInsertAttr(layout, ':cg-focus=\'cgFocus\'', {
1923
+ layout = tool.layoutInsertAttr(layout, ':form-focus=\'formFocus\'', {
2055
1924
  'include': [/^cg-.+/]
2056
1925
  });
2057
1926
  // --- 给 layout 的 class 增加前置 ---
@@ -2072,20 +1941,6 @@ export async function create(opt: string | types.IFormCreateOptions): Promise<nu
2072
1941
  // --- 获取刚才的 form wrap element 对象 ---
2073
1942
  const el: HTMLElement = elements.list.children.item(elements.list.children.length - 1) as HTMLElement;
2074
1943
  // --- 创建窗体对象 ---
2075
- // --- 初始化系统初始 data ---
2076
- computed.taskId = {
2077
- get: function(): number {
2078
- return taskId;
2079
- },
2080
- set: function(): void {
2081
- notify({
2082
- 'title': 'Error',
2083
- 'content': `The software tries to modify the system variable "taskId".\nPath: ${this.cgPath}`,
2084
- 'type': 'danger'
2085
- });
2086
- return;
2087
- }
2088
- };
2089
1944
  computed.formId = {
2090
1945
  get: function(): number {
2091
1946
  return formId;
@@ -2093,161 +1948,100 @@ export async function create(opt: string | types.IFormCreateOptions): Promise<nu
2093
1948
  set: function(): void {
2094
1949
  notify({
2095
1950
  'title': 'Error',
2096
- 'content': `The software tries to modify the system variable "formId".\nPath: ${this.cgPath}`,
1951
+ 'content': `The software tries to modify the system variable "formId".\nPath: ${this.filename}`,
2097
1952
  'type': 'danger'
2098
1953
  });
2099
1954
  return;
2100
1955
  }
2101
1956
  };
2102
- computed.controlName = {
1957
+ data._formFocus = false;
1958
+ computed.path = {
2103
1959
  get: function(): string {
2104
- return 'root';
1960
+ return opt.path ?? '';
2105
1961
  },
2106
1962
  set: function(): void {
2107
1963
  notify({
2108
1964
  'title': 'Error',
2109
- 'content': `The software tries to modify the system variable "controlName".\nPath: ${this.cgPath}`,
1965
+ 'content': `The software tries to modify the system variable "path".\nPath: ${this.filename}`,
2110
1966
  'type': 'danger'
2111
1967
  });
2112
1968
  return;
2113
1969
  }
2114
1970
  };
2115
- data._cgFocus = false;
2116
- computed.cgFocus = {
2117
- get: function(): number {
2118
- return this._cgFocus;
2119
- },
2120
- set: function(): void {
2121
- notify({
2122
- 'title': 'Error',
2123
- 'content': `The software tries to modify the system variable "cgFocus".\nPath: ${this.cgPath}`,
2124
- 'type': 'danger'
2125
- });
2126
- return;
2127
- }
2128
- };
2129
- computed.cgPath = {
2130
- get: function(): string {
2131
- return newBase;
2132
- },
2133
- set: function(): void {
2134
- notify({
2135
- 'title': 'Error',
2136
- 'content': `The software tries to modify the system variable "cgPath".\nPath: ${this.cgPath}`,
2137
- 'type': 'danger'
2138
- });
2139
- return;
2140
- }
2141
- };
2142
- computed.cgPrep = {
1971
+ computed.prep = {
2143
1972
  get: function(): string {
2144
1973
  return prep;
2145
1974
  },
2146
1975
  set: function(): void {
2147
1976
  notify({
2148
1977
  'title': 'Error',
2149
- 'content': `The software tries to modify the system variable "cgPrep".\nPath: ${this._cgPath}`,
2150
- 'type': 'danger'
2151
- });
2152
- return;
2153
- }
2154
- };
2155
- data._cgCustomZIndex = false;
2156
- computed.cgCustomZIndex = {
2157
- get: function(): number {
2158
- return this._cgCustomZIndex;
2159
- },
2160
- set: function(): void {
2161
- notify({
2162
- 'title': 'Error',
2163
- 'content': `The software tries to modify the system variable "cgCustomZIndex".\nPath: ${this.cgPath}`,
1978
+ 'content': `The software tries to modify the system variable "cgPrep".\nPath: ${this.filename}`,
2164
1979
  'type': 'danger'
2165
1980
  });
2166
1981
  return;
2167
1982
  }
2168
1983
  };
2169
- if (topMost) {
2170
- data._cgTopMost = true;
2171
- }
2172
- else {
2173
- data._cgTopMost = false;
2174
- }
2175
- computed.cgTopMost = {
1984
+ // --- 是否在顶层的窗体 ---
1985
+ data._topMost = false;
1986
+ computed.topMost = {
2176
1987
  get: function(): number {
2177
- return this._cgTopMost;
1988
+ return this._topMost;
2178
1989
  },
2179
- set: function(): void {
2180
- notify({
2181
- 'title': 'Error',
2182
- 'content': `The software tries to modify the system variable "cgTopMost".\nPath: ${this.cgPath}`,
2183
- 'type': 'danger'
2184
- });
1990
+ set: function(v: boolean): void {
1991
+ const form = t.forms[formId];
1992
+ if (!form) {
1993
+ return;
1994
+ }
1995
+ if (v) {
1996
+ // --- 置顶 ---
1997
+ form.vroot.$data._topMost = true;
1998
+ if (!form.vroot._formFocus) {
1999
+ changeFocus(form.id);
2000
+ }
2001
+ else {
2002
+ form.vroot.$refs.form.$data.zIndexData = ++info.topLastZIndex;
2003
+ }
2004
+ }
2005
+ else {
2006
+ // --- 取消置顶 ---
2007
+ form.vroot.$data._topMost = false;
2008
+ form.vroot.$refs.form.$data.zIndexData = ++info.lastZIndex;
2009
+ }
2185
2010
  return;
2186
2011
  }
2187
2012
  };
2188
- // --- 预设 computed ---
2189
- computed.cgLocale = function(this: types.IVForm): string {
2190
- if (task.list[this.taskId].locale.lang === '') {
2191
- return core.config.locale;
2192
- }
2193
- return task.list[this.taskId].locale.lang;
2194
- };
2195
- // --- 获取语言 ---
2196
- computed.l = function(this: types.IVForm): (key: string) => string {
2197
- return (key: string): string => {
2198
- return task.list[this.taskId].locale.data[this.cgLocale]?.[key] ?? task.list[this.taskId].locale.data['en']?.[key] ?? 'LocaleError';
2199
- };
2200
- };
2201
- // --- layout 中 :class 的转义 ---
2202
- methods.cgClassPrepend = function(this: types.IVForm, cla: any): string {
2203
- if (typeof cla !== 'string') {
2204
- return cla;
2205
- }
2206
- /*
2207
- if (cla.startsWith('cg-')) {
2208
- return cla;
2209
- }
2210
- */
2211
- return `cg-task${this.taskId}_${cla} ${this.cgPrep}${cla}`;
2212
- };
2213
- // --- 判断当前事件可否执行 ---
2214
- methods.cgAllowEvent = function(this: types.IVForm, e: MouseEvent | TouchEvent | KeyboardEvent): boolean {
2215
- return dom.allowEvent(e);
2216
- };
2217
- // --- 窗体接收 send 事件 ---
2218
- methods.cgReceive = function(obj: Record<string, any>) {
2219
- receive?.call(this, obj);
2220
- };
2221
2013
  // --- 挂载 style ---
2222
2014
  if (style) {
2223
2015
  // --- 窗体的 style ---
2224
- dom.pushStyle(taskId, style, 'form', formId);
2016
+ dom.pushStyle(opt.taskId, style, 'form', formId);
2225
2017
  }
2226
2018
  // --- 创建 app 对象 ---
2227
2019
  const rtn: {
2228
- 'vapp': types.IVueApp;
2229
- 'vroot': types.IVForm;
2020
+ 'vapp': types.IVApp;
2021
+ 'vroot': types.IVue;
2230
2022
  } = await new Promise(function(resolve) {
2231
2023
  const vapp = clickgo.vue.createApp({
2232
- 'template': layout!.replace(/^<cg-form/, '<cg-form ref="form"'),
2024
+ 'template': layout.replace(/^<cg-form/, '<cg-form ref="form"'),
2233
2025
  'data': function() {
2234
2026
  return tool.clone(data);
2235
2027
  },
2236
2028
  'methods': methods,
2237
2029
  'computed': computed,
2238
- 'watch': watch,
2239
2030
 
2240
2031
  'beforeCreate': beforeCreate,
2241
2032
  'created': created,
2242
2033
  'beforeMount': beforeMount,
2243
- 'mounted': async function(this: types.IVForm) {
2034
+ 'mounted': async function(this: types.IVue) {
2244
2035
  await this.$nextTick();
2245
2036
  // --- 判断是否有 icon,对 icon 进行第一次读取 ---
2246
2037
  // --- 为啥要在这搞,因为 form 控件中读取,将可能导致下方的 formCreate 事件获取不到 icon 图标 ---
2247
2038
  // --- 而如果用延迟的方式获取,将可能导致 changeFocus 的窗体焦点事件先于 formCreate 触发 ---
2248
- if (this.$refs.form.icon !== '') {
2249
- const icon = await clickgo.fs.getContent(this.$refs.form.icon);
2250
- this.$refs.form.iconData = (icon instanceof Blob) ? await clickgo.tool.blob2DataUrl(icon) : '';
2039
+ if (this.$refs.form.icon) {
2040
+ const icon = await fs.getContent(this.$refs.form.icon, {
2041
+ 'current': t.current,
2042
+ 'files': t.app.files
2043
+ });
2044
+ this.$refs.form.iconData = (icon instanceof Blob) ? await tool.blob2DataUrl(icon) : '';
2251
2045
  }
2252
2046
  // --- 完成 ---
2253
2047
  resolve({
@@ -2256,41 +2050,42 @@ export async function create(opt: string | types.IFormCreateOptions): Promise<nu
2256
2050
  });
2257
2051
  },
2258
2052
  'beforeUpdate': beforeUpdate,
2259
- 'updated': async function(this: types.IVue) {
2260
- await this.$nextTick();
2261
- updated?.call(this);
2262
- },
2053
+ 'updated': updated,
2263
2054
  'beforeUnmount': beforeUnmount,
2264
- 'unmounted': unmounted,
2055
+ 'unmounted': unmounted
2265
2056
  });
2266
- vapp.config.errorHandler = function(err: Error, vm: types.IVForm, info: string): void {
2057
+ vapp.config.errorHandler = function(err: Error, vm: types.IVue, info: string): void {
2267
2058
  notify({
2268
2059
  'title': 'Runtime Error',
2269
- 'content': `Message: ${err.message}\ntask id: ${vm.taskId}\nForm id: ${vm.formId}`,
2060
+ 'content': `Message: ${err.message}\nTask id: ${vm.taskId}\nForm id: ${vm.formId}`,
2270
2061
  'type': 'danger'
2271
2062
  });
2272
- core.trigger('error', vm.taskId, vm.formId, err, info);
2063
+ core.trigger('error', vm.taskId, vm.formId, err, info + '(-3,' + vm.taskId + ',' + vm.formId + ')');
2273
2064
  };
2274
2065
  // --- 挂载控件对象到 vapp ---
2275
2066
  for (const key in components) {
2276
2067
  vapp.component(key, components[key]);
2277
2068
  }
2278
- vapp.mount(el);
2069
+ try {
2070
+ vapp.mount(el);
2071
+ }
2072
+ catch (err: any) {
2073
+ notify({
2074
+ 'title': 'Runtime Error',
2075
+ 'content': `Message: ${err.message}\nTask id: ${opt.taskId}\nForm id: ${formId}`,
2076
+ 'type': 'danger'
2077
+ });
2078
+ core.trigger('error', opt.taskId, formId, err, err.message + '(-2)');
2079
+ }
2279
2080
  });
2280
2081
  // --- 创建 form 信息对象 ---
2281
2082
  const nform: types.IForm = {
2282
2083
  'id': formId,
2283
2084
  'vapp': rtn.vapp,
2284
- 'vroot': rtn.vroot,
2285
- 'events': {}
2085
+ 'vroot': rtn.vroot
2286
2086
  };
2287
2087
  // --- 挂载 form ---
2288
2088
  t.forms[formId] = nform;
2289
- // --- 检测 mask ---
2290
- if (opt.mask && form) {
2291
- form.vroot.$refs.form.maskFor = formId;
2292
- nform.vroot.$refs.form.maskFrom = form.id;
2293
- }
2294
2089
  // --- 执行 mounted ---
2295
2090
  await tool.sleep(34);
2296
2091
  if (mounted) {
@@ -2298,9 +2093,6 @@ export async function create(opt: string | types.IFormCreateOptions): Promise<nu
2298
2093
  await mounted.call(rtn.vroot, opt.data);
2299
2094
  }
2300
2095
  catch (err: any) {
2301
- if (nform?.vroot.$refs.form.maskFor !== undefined) {
2302
- nform.vroot.$refs.form.maskFor = undefined;
2303
- }
2304
2096
  core.trigger('error', rtn.vroot.taskId, rtn.vroot.formId, err, 'Create form mounted error.');
2305
2097
  t.forms[formId] = undefined as any;
2306
2098
  delete t.forms[formId];
@@ -2310,27 +2102,9 @@ export async function create(opt: string | types.IFormCreateOptions): Promise<nu
2310
2102
  return -8;
2311
2103
  }
2312
2104
  }
2313
- // --- 将窗体居中 ---
2314
- const area = core.getAvailArea();
2315
- if (!rtn.vroot.$refs.form.stateMaxData) {
2316
- if (rtn.vroot.$refs.form.left === -1) {
2317
- rtn.vroot.$refs.form.setPropData('left', (area.width - rtn.vroot.$el.offsetWidth) / 2);
2318
- }
2319
- if (rtn.vroot.$refs.form.top === -1) {
2320
- rtn.vroot.$refs.form.setPropData('top', (area.height - rtn.vroot.$el.offsetHeight) / 2);
2321
- }
2322
- }
2323
- if (rtn.vroot.$refs.form.zIndex !== -1) {
2324
- rtn.vroot._cgCustomZIndex = true;
2325
- }
2326
- if (rtn.vroot.$refs.form.$data.show !== false) {
2327
- rtn.vroot.$refs.form.$data.showData = true;
2328
- }
2329
2105
  // --- 触发 formCreated 事件 ---
2330
- core.trigger('formCreated', taskId, formId, rtn.vroot.$refs.form.title, rtn.vroot.$refs.form.iconData);
2331
- // --- 绑定获取焦点事件 ---
2332
- changeFocus(formId);
2333
- return nform;
2106
+ core.trigger('formCreated', opt.taskId, formId, rtn.vroot.$refs.form.title, rtn.vroot.$refs.form.iconData);
2107
+ return formId;
2334
2108
  }
2335
2109
 
2336
2110
  /**
@@ -2344,31 +2118,27 @@ export function dialog(opt: string | types.IFormDialogOptions): Promise<string>
2344
2118
  'content': opt
2345
2119
  };
2346
2120
  }
2347
- const formId = opt.formId;
2348
- if (!formId) {
2121
+ const taskId = opt.taskId;
2122
+ if (!taskId) {
2349
2123
  resolve('');
2350
2124
  return;
2351
2125
  }
2352
- const taskId = getTaskId(formId);
2353
2126
  const t = task.list[taskId];
2354
2127
  if (!t) {
2355
2128
  resolve('');
2356
2129
  return;
2357
2130
  }
2358
- const locale = t.forms[formId].vroot.cgLocale;
2131
+ const locale = t.locale.lang || core.config.locale;
2359
2132
  if (opt.buttons === undefined) {
2360
2133
  opt.buttons = [info.locale[locale]?.ok ?? info.locale['en'].ok];
2361
2134
  }
2362
2135
  create({
2363
- 'taskId': taskId,
2364
- 'formId': formId,
2365
- '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>`,
2366
2136
  'code': {
2367
2137
  data: {
2368
2138
  'buttons': opt.buttons
2369
2139
  },
2370
2140
  methods: {
2371
- select: function(this: types.IVForm, button: string) {
2141
+ select: function(this: types.IVue, button: string) {
2372
2142
  const event = {
2373
2143
  'go': true,
2374
2144
  preventDefault: function() {
@@ -2377,13 +2147,16 @@ export function dialog(opt: string | types.IFormDialogOptions): Promise<string>
2377
2147
  };
2378
2148
  (opt as types.IFormDialogOptions).select?.(event as unknown as Event, button);
2379
2149
  if (event.go) {
2150
+ this.dialogResult = button;
2380
2151
  close(this.formId);
2381
- resolve(button);
2382
2152
  }
2383
2153
  }
2384
2154
  }
2385
2155
  },
2386
- 'mask': true
2156
+ 'layout': `<form title="${opt.title ?? 'dialog'}" :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>`,
2157
+ 'taskId': taskId
2158
+ }).then(async (fid: number) => {
2159
+ resolve(await t.forms[fid].vroot.showDialog());
2387
2160
  }).catch((e) => {
2388
2161
  throw e;
2389
2162
  });
@@ -2400,22 +2173,21 @@ export async function confirm(opt: string | types.IFormConfirmOptions): Promise<
2400
2173
  'content': opt
2401
2174
  };
2402
2175
  }
2403
- const formId = opt.formId;
2404
- if (!formId) {
2176
+ const taskId = opt.taskId;
2177
+ if (!taskId) {
2405
2178
  return false;
2406
2179
  }
2407
- const taskId = getTaskId(formId);
2408
2180
  const t = task.list[taskId];
2409
2181
  if (!t) {
2410
2182
  return false;
2411
2183
  }
2412
- const locale = t.forms[formId].vroot.cgLocale;
2184
+ const locale = t.locale.lang || core.config.locale;
2413
2185
  const buttons = [info.locale[locale]?.yes ?? info.locale['en'].yes, info.locale[locale]?.no ?? info.locale['en'].no];
2414
2186
  if (opt.cancel) {
2415
2187
  buttons.push(info.locale[locale]?.cancel ?? info.locale['en'].cancel);
2416
2188
  }
2417
2189
  const res = await dialog({
2418
- 'formId': formId,
2190
+ 'taskId': taskId,
2419
2191
 
2420
2192
  'content': opt.content,
2421
2193
  'buttons': buttons
@@ -2430,47 +2202,22 @@ export async function confirm(opt: string | types.IFormConfirmOptions): Promise<
2430
2202
  }
2431
2203
 
2432
2204
  /**
2433
- * --- 设置窗体置顶和取消置顶 ---
2434
- * @param top true: 置顶, false: 不置顶
2435
- * @param opt 选项
2205
+ * --- 让窗体闪烁 ---
2206
+ * @param formId 要闪烁的窗体 id,必填
2207
+ * @param taskId 所属的 taskId,必填,App 模式下仅能闪烁本任务的窗体
2436
2208
  */
2437
- export function setTopMost(top: boolean, opt: types.IFormSetTopMostOptions = {}): void {
2438
- const form = getForm(opt.taskId, opt.formId);
2439
- if (!form) {
2209
+ export function flash(formId: number, taskId?: number): void {
2210
+ if (!taskId) {
2440
2211
  return;
2441
2212
  }
2442
- form.vroot.$data._cgCustomZIndex = false;
2443
- if (top) {
2444
- // --- 置顶 ---
2445
- form.vroot.$data._cgTopMost = true;
2446
- if (!form.vroot.cgFocus) {
2447
- changeFocus(form.id);
2448
- }
2449
- else {
2450
- form.vroot.$refs.form.setPropData('zIndex', ++info.topLastZIndex);
2451
- }
2452
- }
2453
- else {
2454
- // --- 取消置顶 ---
2455
- form.vroot.$data._cgTopMost = false;
2456
- form.vroot.$refs.form.setPropData('zIndex', ++info.lastZIndex);
2457
- }
2458
- }
2459
-
2460
- /**
2461
- * --- 让窗体闪烁 ---
2462
- * @param formId 要闪烁的窗体 id,必填,但 App 模式下留空为当前窗体
2463
- * @param taskId 所属的 taskId,必填,但 App 模式下无效
2464
- */
2465
- export function flash(formId?: number, taskId?: number): void {
2466
2213
  const form = getForm(taskId, formId);
2467
2214
  if (!form) {
2468
2215
  return;
2469
2216
  }
2470
- if (!form.vroot.cgFocus) {
2217
+ if (!form.vroot._formFocus) {
2471
2218
  changeFocus(form.id);
2472
2219
  }
2473
- if (form.vroot.$refs.form?.flashTimer) {
2220
+ if (form.vroot.$refs.form.flashTimer) {
2474
2221
  clearTimeout(form.vroot.$refs.form.flashTimer);
2475
2222
  form.vroot.$refs.form.flashTimer = undefined;
2476
2223
  }
@@ -2484,29 +2231,27 @@ export function flash(formId?: number, taskId?: number): void {
2484
2231
  }
2485
2232
 
2486
2233
  /**
2487
- * --- 让窗体显示 ---
2488
- * @param formId 要显示的窗体 id,App 模式下留空为当前窗体
2489
- * @param taskId 所属的 taskId,App 模式下无效
2234
+ * --- 显示 launcher 界面 ---
2490
2235
  */
2491
- export function show(formId?: number, taskId?: number): void {
2492
- const form = getForm(taskId, formId);
2493
- if (!form) {
2494
- return;
2495
- }
2496
- form.vroot.$refs.form.$data.showData = true;
2236
+ export function showLauncher(): void {
2237
+ elements.launcher.style.display = 'flex';
2238
+ requestAnimationFrame(function() {
2239
+ elements.launcher.classList.add('cg-show');
2240
+ });
2497
2241
  }
2498
2242
 
2499
2243
  /**
2500
- * --- 让窗体隐藏 ---
2501
- * @param formId 要隐藏的窗体 id,App 模式下留空为当前窗体
2502
- * @param taskId 所属的 taskId,App 模式下无效
2244
+ * --- 隐藏 launcher 界面 ---
2503
2245
  */
2504
- export function hide(formId?: number, taskId?: number): void {
2505
- const form = getForm(taskId, formId);
2506
- if (!form) {
2507
- return;
2508
- }
2509
- form.vroot.$refs.form.$data.showData = false;
2246
+ export function hideLauncher(): void {
2247
+ elements.launcher.classList.remove('cg-show');
2248
+ setTimeout(function() {
2249
+ if (launcherRoot.folderName !== '') {
2250
+ launcherRoot.closeFolder();
2251
+ }
2252
+ launcherRoot.name = '';
2253
+ elements.launcher.style.display = 'none';
2254
+ }, 300);
2510
2255
  }
2511
2256
 
2512
2257
  // --- 绑定 resize 事件 ---