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/task.ts CHANGED
@@ -16,19 +16,42 @@
16
16
  import * as types from '../../types';
17
17
  import * as clickgo from '../clickgo';
18
18
  import * as core from './core';
19
- import * as control from './control';
20
19
  import * as dom from './dom';
21
20
  import * as tool from './tool';
22
21
  import * as form from './form';
23
- import * as theme from './theme';
22
+ import * as control from './control';
24
23
  import * as fs from './fs';
25
24
  import * as native from './native';
26
25
 
27
- /** --- 当前运行的程序 --- */
26
+ /** --- 当前运行的程序,App 模式下无效 --- */
28
27
  export const list: Record<number, types.ITask> = {};
29
- /** --- 最后一个 task id --- */
28
+
29
+ /** --- 最后一个 task id,App 模式下无效 --- */
30
30
  export let lastId: number = 0;
31
31
 
32
+ /** --- 当前是否设置的主任务的任务 ID,全局只可设置一次 --- */
33
+ let mainTaskId: number = 0;
34
+
35
+ /**
36
+ * --- 将一个任务设置为主任务,全局只可设置一次 ---
37
+ * @param taskId 任务 ID
38
+ */
39
+ export function setMain(taskId: number): boolean {
40
+ if (mainTaskId > 0) {
41
+ return false;
42
+ }
43
+ mainTaskId = taskId;
44
+ return true;
45
+ }
46
+
47
+ /**
48
+ * --- 判断一个任务 ID 是不是主任务 ---
49
+ * @param taskId 任务 ID
50
+ */
51
+ export function isMain(taskId: number): boolean {
52
+ return taskId === mainTaskId;
53
+ }
54
+
32
55
  /** --- task lib 用到的语言包 --- */
33
56
  const localeData: Record<string, {
34
57
  'loading': string;
@@ -52,24 +75,28 @@ let frameTimer: number = 0;
52
75
  const frameMaps: Record<string, number> = {};
53
76
 
54
77
  /**
55
- * --- 创建 frame 监听 ---
78
+ * --- 创建 frame 监听,formId 存在则为窗体范围,否则为任务级范围 ---
56
79
  * @param fun 监听回调
57
- * @param opt 选项, scope:有效范围,count:执行次数,默认无限次,taskId:APP模式下无效,formId:APP模式下无效
80
+ * @param opt 选项,count:执行次数,默认无限次,taskId:APP模式下无效,formId:APP模式下无效
58
81
  */
59
82
  export function onFrame(fun: () => void | Promise<void>, opt: {
60
- 'scope'?: 'form' | 'task';
61
83
  'count'?: number;
62
84
  'taskId'?: number;
63
85
  'formId'?: number;
64
86
  } = {}): number {
65
87
  const taskId = opt.taskId;
66
88
  const formId = opt.formId;
67
- if (!taskId || !formId) {
89
+ if (!taskId) {
90
+ return 0;
91
+ }
92
+ const task = list[taskId];
93
+ if (!task) {
94
+ return 0;
95
+ }
96
+ if (formId && !task.forms[formId]) {
68
97
  return 0;
69
98
  }
70
99
  const ft = ++frameTimer;
71
- /** --- 作用域 --- */
72
- const scope = opt.scope ?? 'form';
73
100
  /** --- 执行几次,0 代表无限次 --- */
74
101
  const count = opt.count ?? 0;
75
102
  /** --- 当前已经执行的次数 --- */
@@ -77,22 +104,20 @@ export function onFrame(fun: () => void | Promise<void>, opt: {
77
104
  let timer: number;
78
105
  const timerHandler = async (): Promise<void> => {
79
106
  ++c;
80
- if (list[taskId].forms[formId] === undefined) {
107
+ if (formId && task.forms[formId] === undefined) {
81
108
  // --- form 已经没了 ---
82
- if (scope === 'form') {
83
- delete list[taskId].timers['1x' + ft.toString()];
84
- delete frameMaps[ft];
85
- return;
86
- }
109
+ delete task.timers['1x' + ft.toString()];
110
+ delete frameMaps[ft];
111
+ return;
87
112
  }
88
113
  await fun();
89
- if (list[taskId].timers['1x' + ft.toString()] == undefined) {
114
+ if (task.timers['1x' + ft.toString()] == undefined) {
90
115
  return;
91
116
  }
92
117
  if (count > 1) {
93
118
  if (c === count) {
94
119
  // --- 终止循环 ---
95
- delete list[taskId].timers['1x' + ft.toString()];
120
+ delete task.timers['1x' + ft.toString()];
96
121
  delete frameMaps[ft];
97
122
  return;
98
123
  }
@@ -108,7 +133,7 @@ export function onFrame(fun: () => void | Promise<void>, opt: {
108
133
  }
109
134
  else if (count === 1) {
110
135
  // --- 不循环 ---
111
- delete list[taskId].timers['1x' + ft.toString()];
136
+ delete task.timers['1x' + ft.toString()];
112
137
  delete frameMaps[ft];
113
138
  }
114
139
  else {
@@ -128,7 +153,7 @@ export function onFrame(fun: () => void | Promise<void>, opt: {
128
153
  });
129
154
  });
130
155
  frameMaps[ft] = timer;
131
- list[taskId].timers['1x' + ft.toString()] = formId;
156
+ task.timers['1x' + ft.toString()] = formId ?? 0;
132
157
  return ft;
133
158
  }
134
159
 
@@ -144,6 +169,9 @@ export function offFrame(ft: number, opt: {
144
169
  if (!taskId) {
145
170
  return;
146
171
  }
172
+ if (!list[taskId]) {
173
+ return;
174
+ }
147
175
  const formId = list[taskId].timers['1x' + ft.toString()];
148
176
  if (formId === undefined) {
149
177
  return;
@@ -162,12 +190,13 @@ export function get(tid: number): types.ITaskInfo | null {
162
190
  return null;
163
191
  }
164
192
  return {
165
- 'name': list[tid].app.config.name,
193
+ 'name': list[tid].config.name,
166
194
  'locale': list[tid].locale.lang,
167
195
  'customTheme': list[tid].customTheme,
168
196
  'formCount': Object.keys(list[tid].forms).length,
169
- 'icon': list[tid].icon,
170
- 'path': list[tid].path
197
+ 'icon': list[tid].app.icon,
198
+ 'path': list[tid].path,
199
+ 'current': list[tid].current
171
200
  };
172
201
  }
173
202
 
@@ -179,21 +208,22 @@ export function getList(): Record<string, types.ITaskInfo> {
179
208
  for (const tid in list) {
180
209
  const item = list[tid];
181
210
  rtn[tid] = {
182
- 'name': item.app.config.name,
211
+ 'name': item.config.name,
183
212
  'locale': item.locale.lang,
184
213
  'customTheme': item.customTheme,
185
214
  'formCount': Object.keys(item.forms).length,
186
- 'icon': item.icon,
187
- 'path': item.path
215
+ 'icon': item.app.icon,
216
+ 'path': item.path,
217
+ 'current': item.current
188
218
  };
189
219
  }
190
220
  return rtn;
191
221
  }
192
222
 
193
223
  /**
194
- * --- 运行一个应用 ---
224
+ * --- 运行一个应用,cga 直接文件全部正常加载,url 则静态文件需要去 config 里加载 ---
195
225
  * @param url app 路径(以 / 为结尾的路径或以 .cga 结尾的文件)
196
- * @param opt 选项,icon:图标,progress:显示进度条,main:native模式下的主进程,App 模式下无效,taskId:所属任务,App 模式下无效
226
+ * @param opt 选项
197
227
  */
198
228
  export async function run(url: string, opt: types.ITaskRunOptions = {}): Promise<number> {
199
229
  /** --- 是否是在任务当中启动的任务 --- */
@@ -220,161 +250,709 @@ export async function run(url: string, opt: types.ITaskRunOptions = {}): Promise
220
250
  'timeout': 0,
221
251
  'progress': true
222
252
  }) : undefined;
223
- const app: types.IApp | null = await core.fetchApp(url, {
253
+ // --- 获取并加载 app 对象 ---
254
+ const app = await core.fetchApp(url, {
224
255
  'notifyId': notifyId,
225
- 'current': ntask ? ntask.path : undefined,
256
+ 'current': ntask ? ntask.current : undefined,
226
257
  'progress': opt.progress
227
258
  });
228
- if (notifyId) {
259
+ if (!app) {
260
+ // --- fetch 失败,则返回错误,隐藏 notify ---
261
+ if (notifyId) {
262
+ setTimeout(function(): void {
263
+ form.hideNotify(notifyId);
264
+ }, 2000);
265
+ }
266
+ return -1;
267
+ }
268
+ if (notifyId && !app.net) {
269
+ // --- 仅 app 模式隐藏,net 模式还要在 config 当中加载 xml 等非 js 资源文件 ---
229
270
  setTimeout(function(): void {
230
271
  form.hideNotify(notifyId);
231
272
  }, 2000);
232
273
  }
233
- if (!app) {
234
- return -1;
274
+ // --- 申请任务ID ---
275
+ const taskId = ++lastId;
276
+ // --- 注入的参数,屏蔽浏览器全局对象,注入新的对象 ---
277
+ /** --- 不屏蔽的全局对象 --- */
278
+ const unblock = opt.unblock ?? [];
279
+ /** --- 最终注入的对象 --- */
280
+ const invoke: Record<string, any> = {};
281
+ if (!unblock.includes('window')) {
282
+ invoke.window = undefined;
283
+ }
284
+ const ks = Object.getOwnPropertyNames(window);
285
+ for (const k of ks) {
286
+ if (k.includes('Event')) {
287
+ continue;
288
+ }
289
+ if (k.includes('-')) {
290
+ continue;
291
+ }
292
+ if (/^[0-9]+$/.test(k)) {
293
+ continue;
294
+ }
295
+ if ([
296
+ 'require',
297
+ '__awaiter', 'eval', 'Math', 'Array', 'Blob', 'Infinity', 'parseInt', 'parseFloat', 'Promise', 'Date', 'JSON', 'fetch'].includes(k)) {
298
+ continue;
299
+ }
300
+ if (unblock.includes(k)) {
301
+ continue;
302
+ }
303
+ invoke[k] = undefined;
235
304
  }
236
- // --- app 的内置文件以及运行时文件 ---
237
- const files: Record<string, Blob | string> = {};
238
- for (const fpath in app.files) {
239
- files[fpath] = app.files[fpath];
305
+ // --- console ---
306
+ invoke.console = {
307
+ log: function(message?: any, ...optionalParams: any[]) {
308
+ console.log(message, ...optionalParams);
309
+ }
310
+ };
311
+ // --- loader ---
312
+ invoke.loader = {
313
+ require: function(paths: string | string[], files: Record<string, Blob | string>, opt?: {
314
+ 'executed'?: Record<string, any>;
315
+ 'map'?: Record<string, string>;
316
+ 'dir'?: string;
317
+ 'style'?: string;
318
+ 'invoke'?: Record<string, any>;
319
+ 'preprocess'?: (code: string, path: string) => string;
320
+ }): any[] {
321
+ return loader.require(paths, files, opt);
322
+ }
323
+ };
324
+ // --- Object ---
325
+ if (!unblock.includes('Object')) {
326
+ invoke.Object = {
327
+ defineProperty: function(): void {
328
+ return;
329
+ },
330
+ keys: function(o: any): string[] {
331
+ return Object.keys(o);
332
+ },
333
+ assign: function(o: any, o2: any): any {
334
+ if (o.controlName !== undefined) {
335
+ return o;
336
+ }
337
+ return Object.assign(o, o2);
338
+ }
339
+ };
240
340
  }
241
- // --- 创建任务对象 ITask ---
242
- const taskId = ++lastId;
341
+ invoke.navigator = {};
342
+ if (navigator.clipboard) {
343
+ invoke.navigator.clipboard = navigator.clipboard;
344
+ }
345
+ // --- ClickGo 相关 ---
346
+ invoke.invokeClickgo = {
347
+ getVersion: function(): string {
348
+ return clickgo.getVersion();
349
+ },
350
+ getNative(): boolean {
351
+ return clickgo.getNative();
352
+ },
353
+ getPlatform(): string {
354
+ return clickgo.getPlatform();
355
+ },
356
+ 'control': {
357
+ 'AbstractControl': class extends control.AbstractControl {
358
+ public get taskId(): number {
359
+ return taskId;
360
+ }
361
+ },
362
+ read: function(blob: Blob): Promise<false | types.TControlPackage> {
363
+ return control.read(blob);
364
+ }
365
+ },
366
+ 'core': {
367
+ 'config': clickgo.core.config,
368
+ 'AbstractApp': class extends core.AbstractApp {
369
+ // eslint-disable-next-line @typescript-eslint/require-await
370
+ public async main(): Promise<void> {
371
+ return;
372
+ }
373
+
374
+ public get taskId(): number {
375
+ return taskId;
376
+ }
377
+ },
378
+ getCdn: function() {
379
+ return core.getCdn();
380
+ },
381
+ initModules: function(names: string | string[]): Promise<number> {
382
+ return clickgo.core.initModules(names);
383
+ },
384
+ getModule: function(name: string): null | any {
385
+ return clickgo.core.getModule(name);
386
+ },
387
+ readApp: function(blob: Blob): Promise<false | types.IApp> {
388
+ return clickgo.core.readApp(blob);
389
+ },
390
+ getAvailArea: function(): types.IAvailArea {
391
+ return clickgo.core.getAvailArea();
392
+ }
393
+ },
394
+ 'dom': {
395
+ setGlobalCursor: function(type?: string): void {
396
+ clickgo.dom.setGlobalCursor(type);
397
+ },
398
+ hasTouchButMouse: function(e: MouseEvent | TouchEvent | PointerEvent): boolean {
399
+ return clickgo.dom.hasTouchButMouse(e);
400
+ },
401
+ getStyleCount: function(taskId: number, type: 'theme' | 'control' | 'form'): number {
402
+ return clickgo.dom.getStyleCount(taskId, type);
403
+ },
404
+ getSize: function(el: HTMLElement): types.IDomSize {
405
+ return clickgo.dom.getSize(el);
406
+ },
407
+ watchSize: function(
408
+ el: HTMLElement,
409
+ cb: (size: types.IDomSize) => Promise<void> | void,
410
+ immediate: boolean = false
411
+ ): types.IDomSize {
412
+ return clickgo.dom.watchSize(el, cb, immediate, taskId);
413
+ },
414
+ unwatchSize: function(el: HTMLElement): void {
415
+ clickgo.dom.unwatchSize(el, taskId);
416
+ },
417
+ clearWatchSize(): void {
418
+ clickgo.dom.clearWatchSize(taskId);
419
+ },
420
+ watch: function(el: HTMLElement, cb: () => void, mode: 'child' | 'childsub' | 'style' | 'default' = 'default', immediate: boolean = false): void {
421
+ clickgo.dom.watch(el, cb, mode, immediate, taskId);
422
+ },
423
+ unwatch: function(el: HTMLElement): void {
424
+ clickgo.dom.unwatch(el, taskId);
425
+ },
426
+ clearWatch: function(): void {
427
+ clickgo.dom.clearWatch(taskId);
428
+ },
429
+ watchStyle: function(
430
+ el: HTMLElement,
431
+ name: string | string[],
432
+ cb: (name: string, value: string) => void,
433
+ immediate: boolean = false
434
+ ): void {
435
+ clickgo.dom.watchStyle(el, name, cb, immediate);
436
+ },
437
+ isWatchStyle: function(el: HTMLElement): boolean {
438
+ return clickgo.dom.isWatchStyle(el);
439
+ },
440
+ bindDown: function(oe: MouseEvent | TouchEvent, opt: types.IBindDownOptions) {
441
+ clickgo.dom.bindDown(oe, opt);
442
+ },
443
+ bindGesture: function(e: MouseEvent | TouchEvent | WheelEvent | { 'x'?: number; 'y'?: number; }, opt: types.IBindGestureOptions): void {
444
+ clickgo.dom.bindGesture(e, opt);
445
+ },
446
+ bindLong: function(
447
+ e: MouseEvent | TouchEvent,
448
+ long: (e: MouseEvent | TouchEvent) => void | Promise<void>
449
+ ): void {
450
+ clickgo.dom.bindLong(e, long);
451
+ },
452
+ bindDrag: function(e: MouseEvent | TouchEvent, opt: { 'el': HTMLElement; 'data'?: any; }): void {
453
+ clickgo.dom.bindDrag(e, opt);
454
+ },
455
+ 'is': clickgo.dom.is,
456
+ bindMove: function(e: MouseEvent | TouchEvent, opt: types.IBindMoveOptions): types.IBindMoveResult {
457
+ return clickgo.dom.bindMove(e, opt);
458
+ },
459
+ bindResize: function(e: MouseEvent | TouchEvent, opt: types.IBindResizeOptions): void {
460
+ clickgo.dom.bindResize(e, opt);
461
+ },
462
+ findParentByData: function(el: HTMLElement, name: string): HTMLElement | null {
463
+ return clickgo.dom.findParentByData(el, name);
464
+ },
465
+ findParentByClass: function(el: HTMLElement, name: string): HTMLElement | null {
466
+ return clickgo.dom.findParentByClass(el, name);
467
+ },
468
+ siblings: function(el: HTMLElement): HTMLElement[] {
469
+ return clickgo.dom.siblings(el);
470
+ },
471
+ siblingsData: function(el: HTMLElement, name: string): HTMLElement[] {
472
+ return clickgo.dom.siblingsData(el, name);
473
+ },
474
+ fullscreen: function(): boolean {
475
+ return clickgo.dom.fullscreen();
476
+ }
477
+ },
478
+ 'form': {
479
+ 'AbstractForm': class extends form.AbstractForm {
480
+ public get taskId(): number {
481
+ return taskId;
482
+ }
483
+ },
484
+ min: function(fid: number): boolean {
485
+ return clickgo.form.min(fid);
486
+ },
487
+ max: function max(fid: number): boolean {
488
+ return clickgo.form.max(fid);
489
+ },
490
+ close: function(fid: number): boolean {
491
+ return clickgo.form.close(fid);
492
+ },
493
+ bindResize: function(e: MouseEvent | TouchEvent, border: types.TDomBorder): void {
494
+ clickgo.form.bindResize(e, border);
495
+ },
496
+ bindDrag: function(e: MouseEvent | TouchEvent): void {
497
+ clickgo.form.bindDrag(e);
498
+ },
499
+ getTaskId: function(fid: number): number {
500
+ return clickgo.form.getTaskId(fid);
501
+ },
502
+ get: function(fid: number): types.IFormInfo | null {
503
+ return clickgo.form.get(fid);
504
+ },
505
+ getList: function(tid: number): Record<string, types.IFormInfo> {
506
+ return clickgo.form.getList(tid);
507
+ },
508
+ changeFocus: function(fid: number = 0): void {
509
+ clickgo.form.changeFocus(fid);
510
+ },
511
+ getMaxZIndexID: function(out?: {
512
+ 'taskIds'?: number[];
513
+ 'formIds'?: number[];
514
+ }): number | null {
515
+ return clickgo.form.getMaxZIndexID(out);
516
+ },
517
+ getRectByBorder: function(border: types.TDomBorder): { 'width': number; 'height': number; 'left': number; 'top': number; } {
518
+ return clickgo.form.getRectByBorder(border);
519
+ },
520
+ showCircular: function(x: number, y: number): void {
521
+ clickgo.form.showCircular(x, y);
522
+ },
523
+ moveRectangle: function(border: types.TDomBorder): void {
524
+ clickgo.form.moveRectangle(border);
525
+ },
526
+ showRectangle: function(x: number, y: number, border: types.TDomBorder): void {
527
+ clickgo.form.showRectangle(x, y, border);
528
+ },
529
+ hideRectangle: function(): void {
530
+ clickgo.form.hideRectangle();
531
+ },
532
+ showDrag: function(): void {
533
+ clickgo.form.showDrag();
534
+ },
535
+ moveDrag: function(opt: types.IMoveDragOptions): void {
536
+ clickgo.form.moveDrag(opt);
537
+ },
538
+ hideDrag: function(): void {
539
+ clickgo.form.hideDrag();
540
+ },
541
+ notify: function(opt: types.INotifyOptions): number {
542
+ return clickgo.form.notify(opt);
543
+ },
544
+ notifyProgress: function(notifyId: number, per: number): void {
545
+ clickgo.form.notifyProgress(notifyId, per);
546
+ },
547
+ hideNotify: function(notifyId: number): void {
548
+ clickgo.form.hideNotify(notifyId);
549
+ },
550
+ 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 {
551
+ clickgo.form.showPop(el, pop, direction, opt);
552
+ },
553
+ hidePop: function(pop?: HTMLElement): void {
554
+ clickgo.form.hidePop(pop);
555
+ },
556
+ dialog: function(opt: string | types.IFormDialogOptions): Promise<string> {
557
+ if (typeof opt === 'string') {
558
+ opt = {
559
+ 'content': opt
560
+ };
561
+ }
562
+ opt.taskId = taskId;
563
+ return clickgo.form.dialog(opt);
564
+ },
565
+ confirm: function(opt: string | types.IFormConfirmOptions): Promise<boolean | number> {
566
+ if (typeof opt === 'string') {
567
+ opt = {
568
+ 'content': opt
569
+ };
570
+ }
571
+ opt.taskId = taskId;
572
+ return clickgo.form.confirm(opt);
573
+ },
574
+ flash: function(fid: number): void {
575
+ clickgo.form.flash(fid, taskId);
576
+ },
577
+ showLauncher: function(): void {
578
+ clickgo.form.showLauncher();
579
+ },
580
+ hideLauncher: function(): void {
581
+ clickgo.form.hideLauncher();
582
+ }
583
+ },
584
+ 'fs': {
585
+ getContent: function(
586
+ path: string,
587
+ options: any = {}
588
+ ): Promise<Blob | string | null> {
589
+ if (!options.files) {
590
+ options.files = list[taskId].app.files;
591
+ }
592
+ if (!options.current) {
593
+ options.current = list[taskId].current;
594
+ }
595
+ return clickgo.fs.getContent(path, options);
596
+ },
597
+ putContent: function(path: string, data: string | Buffer, options: any = {}) {
598
+ if (!options.current) {
599
+ options.current = list[taskId].current;
600
+ }
601
+ return clickgo.fs.putContent(path, data, options);
602
+ },
603
+ readLink: function(path: string, options: any = {}): Promise<string | null> {
604
+ if (!options.current) {
605
+ options.current = list[taskId].current;
606
+ }
607
+ return clickgo.fs.readLink(path, options);
608
+ },
609
+ symlink: function(fPath: string, linkPath: string, options: any = {}): Promise<boolean> {
610
+ if (!options.current) {
611
+ options.current = list[taskId].current;
612
+ }
613
+ return clickgo.fs.symlink(fPath, linkPath, options);
614
+ },
615
+ unlink: function(path: string, options: any = {}): Promise<boolean> {
616
+ if (!options.current) {
617
+ options.current = list[taskId].current;
618
+ }
619
+ return clickgo.fs.unlink(path, options);
620
+ },
621
+ stats: function(path: string, options: any = {}): Promise<types.IStats | null> {
622
+ if (!options.files) {
623
+ options.files = list[taskId].app.files;
624
+ }
625
+ if (!options.current) {
626
+ options.current = list[taskId].current;
627
+ }
628
+ return clickgo.fs.stats(path, options);
629
+ },
630
+ isDir: function(path: string, options: any = {}): Promise<types.IStats | false> {
631
+ if (!options.files) {
632
+ options.files = list[taskId].app.files;
633
+ }
634
+ if (!options.current) {
635
+ options.current = list[taskId].current;
636
+ }
637
+ return clickgo.fs.isDir(path, options);
638
+ },
639
+ isFile: function(path: string, options: any = {}): Promise<types.IStats | false> {
640
+ if (!options.files) {
641
+ options.files = list[taskId].app.files;
642
+ }
643
+ if (!options.current) {
644
+ options.current = list[taskId].current;
645
+ }
646
+ return clickgo.fs.isFile(path, options);
647
+ },
648
+ mkdir: function(path: string, mode?: number, options: any = {}): Promise<boolean> {
649
+ if (!options.current) {
650
+ options.current = list[taskId].current;
651
+ }
652
+ return clickgo.fs.mkdir(path, mode, options);
653
+ },
654
+ rmdir: function(path: string, options: any = {}): Promise<boolean> {
655
+ if (!options.current) {
656
+ options.current = list[taskId].current;
657
+ }
658
+ return clickgo.fs.rmdir(path, options);
659
+ },
660
+ rmdirDeep: function(path: string, options: any = {}): Promise<boolean> {
661
+ if (!options.current) {
662
+ options.current = list[taskId].current;
663
+ }
664
+ return clickgo.fs.rmdirDeep(path, options);
665
+ },
666
+ chmod: function(path: string, mod: string | number, options: any = {}): Promise<boolean> {
667
+ if (!options.current) {
668
+ options.current = list[taskId].current;
669
+ }
670
+ return clickgo.fs.chmod(path, mod, options);
671
+ },
672
+ rename(oldPath: string, newPath: string, options: any = {}): Promise<boolean> {
673
+ if (!options.current) {
674
+ options.current = list[taskId].current;
675
+ }
676
+ return clickgo.fs.rename(oldPath, newPath, options);
677
+ },
678
+ readDir(path: string, options: any = {}): Promise<types.IDirent[]> {
679
+ if (!options.files) {
680
+ options.files = list[taskId].app.files;
681
+ }
682
+ if (!options.current) {
683
+ options.current = list[taskId].current;
684
+ }
685
+ return clickgo.fs.readDir(path, options);
686
+ },
687
+ copyFolder(from: string, to: string, options: any = {}): Promise<number> {
688
+ if (!options.current) {
689
+ options.current = list[taskId].current;
690
+ }
691
+ return clickgo.fs.copyFolder(from, to, options);
692
+ },
693
+ copyFile(src: string, dest: string, options: any = {}): Promise<boolean> {
694
+ if (!options.current) {
695
+ options.current = list[taskId].current;
696
+ }
697
+ return clickgo.fs.copyFile(src, dest, options);
698
+ }
699
+ },
700
+ 'native': {
701
+ invoke: function(name: string, ...param: any[]): any {
702
+ return clickgo.native.invoke(name, ...param);
703
+ },
704
+ max: function(): void {
705
+ clickgo.native.max();
706
+ },
707
+ min: function(): void {
708
+ clickgo.native.min();
709
+ },
710
+ restore: function(): void {
711
+ clickgo.native.restore();
712
+ },
713
+ size: function(width: number, height: number): void {
714
+ clickgo.native.size(width, height);
715
+ }
716
+ },
717
+ 'task': {
718
+ isMain(taskId: number): boolean {
719
+ return isMain(taskId);
720
+ },
721
+ onFrame: function(fun: () => void | Promise<void>, opt: any = {}): number {
722
+ opt.taskId = taskId;
723
+ return clickgo.task.onFrame(fun, opt);
724
+ },
725
+ offFrame: function(ft: number, opt: {
726
+ 'taskId'?: number;
727
+ } = {}): void {
728
+ opt.taskId = taskId;
729
+ clickgo.task.offFrame(ft, opt);
730
+ },
731
+ get: function(tid: number): types.ITaskInfo | null {
732
+ return clickgo.task.get(tid);
733
+ },
734
+ getList: function(): Record<string, types.ITaskInfo> {
735
+ return clickgo.task.getList();
736
+ },
737
+ run: function(url: string, opt: types.ITaskRunOptions = {}): Promise<number> {
738
+ opt.taskId = taskId;
739
+ opt.main = false;
740
+ return clickgo.task.run(url, opt);
741
+ },
742
+ end: function(tid: number): boolean {
743
+ return clickgo.task.end(tid ?? taskId);
744
+ },
745
+ loadLocaleData: function(lang: string, data: Record<string, any>, pre: string = ''): void {
746
+ clickgo.task.loadLocaleData(lang, data, pre, taskId);
747
+ },
748
+ loadLocale: function(lang: string, path: string): Promise<boolean> {
749
+ return clickgo.task.loadLocale(lang, path, taskId);
750
+ },
751
+ clearLocale: function(): void {
752
+ clickgo.task.clearLocale(taskId);
753
+ },
754
+ setLocale: function(lang: string, path: string): Promise<boolean> {
755
+ return clickgo.task.setLocale(lang, path, taskId);
756
+ },
757
+ setLocaleLang: function(lang: string): void {
758
+ clickgo.task.setLocaleLang(lang, taskId);
759
+ },
760
+ clearLocaleLang: function(): void {
761
+ clickgo.task.clearLocaleLang(taskId);
762
+ },
763
+ createTimer: function(
764
+ fun: () => void | Promise<void>,
765
+ delay: number,
766
+ opt: types.ICreateTimerOptions = {}
767
+ ): number {
768
+ opt.taskId = taskId;
769
+ return clickgo.task.createTimer(fun, delay, opt);
770
+ },
771
+ removeTimer: function(timer: number): void {
772
+ clickgo.task.removeTimer(timer, taskId);
773
+ },
774
+ sleep: function(fun: () => void | Promise<void>, delay: number): number {
775
+ return clickgo.task.sleep(fun, delay, taskId);
776
+ },
777
+ systemTaskInfo: clickgo.task.systemTaskInfo,
778
+ setSystem: function(fid: number): boolean {
779
+ return clickgo.task.setSystem(fid, taskId);
780
+ },
781
+ clearSystem: function(): boolean {
782
+ return clickgo.task.clearSystem(taskId);
783
+ }
784
+ },
785
+ 'theme': {
786
+ read: function(blob: Blob): Promise<types.ITheme | false> {
787
+ return clickgo.theme.read(blob);
788
+ },
789
+ load: async function(theme?: types.ITheme): Promise<boolean> {
790
+ if (!theme) {
791
+ return false;
792
+ }
793
+ return clickgo.theme.load(theme, taskId);
794
+ },
795
+ remove: function(name: string): Promise<void> {
796
+ return clickgo.theme.remove(name, taskId);
797
+ },
798
+ clear: function(): Promise<void> {
799
+ return clickgo.theme.clear(taskId);
800
+ },
801
+ setGlobal: function(theme: types.ITheme): Promise<void> {
802
+ return clickgo.theme.setGlobal(theme);
803
+ },
804
+ clearGlobal: function(): void {
805
+ clickgo.theme.clearGlobal();
806
+ }
807
+ },
808
+ 'tool': {
809
+ blob2ArrayBuffer: function(blob: Blob): Promise<ArrayBuffer> {
810
+ return clickgo.tool.blob2ArrayBuffer(blob);
811
+ },
812
+ clone: function(obj: Record<string, any> | any[]): any[] | any {
813
+ return clickgo.tool.clone(obj);
814
+ },
815
+ sleep: function(ms: number = 0): Promise<boolean> {
816
+ return clickgo.tool.sleep(ms);
817
+ },
818
+ purify: function(text: string): string {
819
+ return clickgo.tool.purify(text);
820
+ },
821
+ rand: function(min: number, max: number): number {
822
+ return clickgo.tool.rand(min, max);
823
+ },
824
+ 'RANDOM_N': clickgo.tool.RANDOM_N,
825
+ 'RANDOM_U': clickgo.tool.RANDOM_U,
826
+ 'RANDOM_L': clickgo.tool.RANDOM_L,
827
+ 'RANDOM_UN': clickgo.tool.RANDOM_UN,
828
+ 'RANDOM_LN': clickgo.tool.RANDOM_LN,
829
+ 'RANDOM_LU': clickgo.tool.RANDOM_LU,
830
+ 'RANDOM_LUN': clickgo.tool.RANDOM_LUN,
831
+ 'RANDOM_V': clickgo.tool.RANDOM_V,
832
+ 'RANDOM_LUNS': clickgo.tool.RANDOM_LUNS,
833
+ random: function(length: number = 8, source: string = clickgo.tool.RANDOM_LN, block: string = ''): string {
834
+ return clickgo.tool.random(length, source, block);
835
+ },
836
+ getBoolean: function(param: boolean | string | number): boolean {
837
+ return clickgo.tool.getBoolean(param);
838
+ },
839
+ getNumber: function(param: string | number): number {
840
+ return clickgo.tool.getNumber(param);
841
+ },
842
+ escapeHTML: function(html: string): string {
843
+ return clickgo.tool.escapeHTML(html);
844
+ },
845
+ request: function(url: string, opt: types.IRequestOptions): Promise<null | any> {
846
+ return clickgo.tool.request(url, opt);
847
+ },
848
+ parseUrl: function(url: string): ILoaderUrl {
849
+ return clickgo.tool.parseUrl(url);
850
+ },
851
+ urlResolve: function(from: string, to: string): string {
852
+ return clickgo.tool.urlResolve(from, to);
853
+ },
854
+ blob2Text: function(blob: Blob): Promise<string> {
855
+ return clickgo.tool.blob2Text(blob);
856
+ },
857
+ blob2DataUrl: function(blob: Blob): Promise<string> {
858
+ return clickgo.tool.blob2DataUrl(blob);
859
+ },
860
+ execCommand: function(ac: string): void {
861
+ clickgo.tool.execCommand(ac);
862
+ }
863
+ },
864
+ 'zip': {
865
+ get: function(data?: types.TZipInputFileFormat) {
866
+ return clickgo.zip.get(data);
867
+ }
868
+ }
869
+ };
870
+ /** --- 加载的 js 文件预处理 --- */
871
+ const preprocess = function(code: string, path: string): string {
872
+ // --- 屏蔽 eval 函数 ---
873
+ const exec = /eval\W/.exec(code);
874
+ if (exec) {
875
+ form.notify({
876
+ 'title': 'Error',
877
+ 'content': `The "eval" is prohibited.\nFile: "${path}".`,
878
+ 'type': 'danger'
879
+ });
880
+ return '';
881
+ }
882
+ // --- 给 form 的 class 增加 filename 的 get ---
883
+ code = code.replace(/extends[\s\S]+?\.\s*(AbstractApp|AbstractForm)\s*{/, (t: string) => {
884
+ return t + 'get filename() {return __filename;}';
885
+ });
886
+ return code;
887
+ };
888
+ app.files['/invoke/clickgo.js'] = `module.exports = invokeClickgo;`;
889
+ /** --- .cga 文件,或者不含 / 结尾的路径 --- */
890
+ const path = url;
891
+ const lio = path.endsWith('.cga') ? path.lastIndexOf('/') : path.slice(0, -1).lastIndexOf('/');
892
+ const current = path.slice(0, lio);
893
+ // --- 创建任务对象 task.IRT ---
243
894
  list[taskId] = {
244
895
  'id': taskId,
245
896
  'app': app,
897
+ // 'class': null,
898
+ // 'config': {},
246
899
  'customTheme': false,
247
900
  'locale': clickgo.vue.reactive({
248
901
  'lang': '',
249
902
  'data': {}
250
903
  }),
251
- 'icon': app.icon ?? icon,
252
- 'path': url,
253
- 'files': files,
254
- 'main': opt.main ?? false,
904
+ 'path': path,
905
+ 'current': current,
255
906
 
256
- 'permissions': {},
907
+ 'runtime': clickgo.vue.reactive({
908
+ 'permissions': {},
909
+ 'dialogFormIds': []
910
+ }),
257
911
  'forms': {},
258
- 'objectURLs': [],
259
- 'controls': {
260
- 'loaded': {},
261
- 'layout': {},
262
- 'prep': {}
263
- },
264
- 'timers': {}
265
- };
266
- const task: types.ITask = list[taskId];
267
- // --- control ---
268
- for (let path of app.config.controls) {
269
- path += '.cgc';
270
- path = tool.urlResolve('/', path);
271
- const file = await fs.getContent(path, {
272
- 'files': task.files
273
- });
274
- if (file && typeof file !== 'string') {
275
- const c = await control.read(file);
276
- if (c) {
277
- task.controls.loaded[path] = c;
278
- }
279
- else {
280
- form.notify({
281
- 'title': 'Control failed to load',
282
- 'content': path
283
- });
912
+ 'controls': {},
913
+ 'timers': {},
914
+ 'invoke': invoke
915
+ } as any;
916
+ let expo: any = [];
917
+ try {
918
+ expo = loader.require('/app.js', app.files, {
919
+ 'dir': '/',
920
+ 'invoke': invoke,
921
+ 'preprocess': preprocess,
922
+ 'map': {
923
+ 'clickgo': '/invoke/clickgo'
284
924
  }
285
- }
925
+ })[0];
286
926
  }
287
- // --- theme ---
288
- if (app.config.themes) {
289
- for (let path of app.config.themes) {
290
- path += '.cgt';
291
- path = tool.urlResolve('/', path);
292
- const file = await fs.getContent(path, {
293
- 'files': task.files
294
- });
295
- if (file && typeof file !== 'string') {
296
- const th = await theme.read(file);
297
- if (th) {
298
- await theme.load(th, taskId);
299
- }
300
- }
301
- }
927
+ catch (e: any) {
928
+ delete list[taskId];
929
+ core.trigger('error', taskId, 0, e, e.message + '(-1)');
930
+ return -2;
302
931
  }
303
- // --- locale ---
304
- if (app.config.locales) {
305
- for (let path in app.config.locales) {
306
- const locale = app.config.locales[path];
307
- if (!path.endsWith('.json')) {
308
- path += '.json';
309
- }
310
- const lcontent = await fs.getContent(path, {
311
- 'encoding': 'utf8',
312
- 'files': task.files,
313
- 'current': task.path
314
- });
315
- if (!lcontent) {
316
- continue;
317
- }
318
- try {
319
- const data = JSON.parse(lcontent);
320
- loadLocaleData(locale, data, '', task.id);
321
- }
322
- catch {
323
- // --- 无所谓 ---
324
- }
325
- }
932
+ if (!expo?.default) {
933
+ delete list[taskId];
934
+ return -3;
326
935
  }
327
- // --- 触发 taskStarted 事件 ---
328
- core.trigger('taskStarted', task.id);
329
936
  // --- 创建 Task 总 style ---
330
- dom.createToStyleList(task.id);
331
- // --- 创建 form ---
332
- const f = await form.create({
333
- 'taskId': task.id,
334
- 'file': app.config.main
335
- });
336
- if (typeof f === 'number') {
937
+ dom.createToStyleList(taskId);
938
+ // --- 执行 app ---
939
+ const appCls: core.AbstractApp = new expo.default();
940
+ await appCls.main();
941
+ if (!list[taskId].class) {
942
+ // --- 创建任务失败,也可能没设置 config,报弹窗错误,清理启动应用并返回错误 ---
337
943
  // --- 结束任务 ---
338
- delete list[task.id];
339
- dom.removeFromStyleList(task.id);
340
- core.trigger('taskEnded', task.id);
341
- return f - 100;
342
- }
343
- // --- 设置 global style(如果 form 创建失败,就不设置 global style 了) ---
344
- if (app.config.style && app.files[app.config.style + '.css']) {
345
- const style = app.files[app.config.style + '.css'] as string;
346
- const r = tool.stylePrepend(style, 'cg-task' + task.id.toString() + '_');
347
- dom.pushStyle(task.id, await tool.styleUrl2DataUrl(app.config.style, r.style, app.files));
348
- }
349
- // --- 是否要加载独立的 theme ---
350
- if (app.config.themes && app.config.themes.length > 0) {
351
- task.customTheme = true;
352
- for (const path of app.config.themes) {
353
- const blob = await fs.getContent(path, {
354
- 'files': task.files,
355
- 'current': task.path
356
- });
357
- if (!(blob instanceof Blob)) {
358
- continue;
359
- }
360
- const th = await theme.read(blob);
361
- if (!th) {
362
- continue;
363
- }
364
- await theme.load(th, task.id);
365
- }
366
- }
367
- else {
368
- // --- 检测是否加载系统 theme ---
369
- if (theme.global) {
370
- await theme.load(undefined, task.id);
371
- }
944
+ delete list[taskId];
945
+ dom.removeFromStyleList(taskId);
946
+ return -4;
372
947
  }
948
+ // --- 触发 taskStarted 事件 ---
949
+ core.trigger('taskStarted', taskId);
373
950
  // --- 给 native 发送任务启动成功的消息 ---
374
- if (task.id === 1) {
951
+ if (taskId === 1) {
375
952
  native.invoke('cg-init', native.getToken());
376
953
  }
377
954
  // --- 提交 sync ---
955
+ /*
378
956
  if (clickgo.getNative() && opt.sync) {
379
957
  f.vroot.$refs.form.isNativeSync = true;
380
958
  native.invoke('cg-set-size', native.getToken(), f.vroot.$refs.form.widthData, f.vroot.$refs.form.heightData);
@@ -383,7 +961,8 @@ export async function run(url: string, opt: types.ITaskRunOptions = {}): Promise
383
961
  f.vroot.$refs.form.setPropData('height', window.innerHeight);
384
962
  });
385
963
  }
386
- return task.id;
964
+ */
965
+ return taskId;
387
966
  }
388
967
 
389
968
  /**
@@ -396,7 +975,7 @@ export function end(taskId: number): boolean {
396
975
  return true;
397
976
  }
398
977
  // --- 如果是 native 模式 ---
399
- if (clickgo.getNative() && task.main) {
978
+ if (clickgo.getNative() && isMain(taskId)) {
400
979
  native.invoke('cg-close', native.getToken());
401
980
  }
402
981
  // --- 获取最大的 z index 窗体,并让他获取焦点 ---
@@ -413,15 +992,26 @@ export function end(taskId: number): boolean {
413
992
  for (const fid in task.forms) {
414
993
  const f = task.forms[fid];
415
994
  core.trigger('formRemoved', taskId, f.id, f.vroot.$refs.form.title, f.vroot.$refs.form.iconData);
416
- f.vapp.unmount();
995
+ try {
996
+ f.vapp.unmount();
997
+ }
998
+ catch (err: any) {
999
+ const msg = `Message: ${err.message}\nTask id: ${task.id}\nForm id: ${fid}\nFunction: task.end, unmount.`;
1000
+ form.notify({
1001
+ 'title': 'Runtime Error',
1002
+ 'content': msg,
1003
+ 'type': 'danger'
1004
+ });
1005
+ console.log('Runtime Error', msg, err);
1006
+ }
417
1007
  f.vapp._container.remove();
418
1008
  }
1009
+ const flist = document.querySelectorAll('#cg-form-list > [data-task-id="' + taskId.toString() + '"]');
1010
+ for (const f of flist) {
1011
+ f.remove();
1012
+ }
419
1013
  // --- 移除 style ---
420
1014
  dom.removeFromStyleList(taskId);
421
- // --- 移除本 task 创建的所有 object url ---
422
- for (const url of task.objectURLs) {
423
- tool.revokeObjectURL(url, task.id);
424
- }
425
1015
  // --- 移除所有 timer ---
426
1016
  for (const timer in list[taskId].timers) {
427
1017
  if (timer.startsWith('1x')) {
@@ -472,11 +1062,10 @@ export function loadLocaleData(lang: string, data: Record<string, any>, pre: str
472
1062
  /**
473
1063
  * --- 加载 locale 文件 json ---
474
1064
  * @param lang 语言名,如 sc
475
- * @param path 地址
1065
+ * @param path 绝对或者相对 app 路径的地址
476
1066
  * @param taskId 所属的 taskId,App 模式下无效
477
- * @param formId 所属的 formId,App 模式下无效
478
1067
  */
479
- export async function loadLocale(lang: string, path: string, taskId?: number, formId?: number): Promise<boolean> {
1068
+ export async function loadLocale(lang: string, path: string, taskId?: number): Promise<boolean> {
480
1069
  if (!taskId) {
481
1070
  return false;
482
1071
  }
@@ -484,21 +1073,13 @@ export async function loadLocale(lang: string, path: string, taskId?: number, fo
484
1073
  if (!task) {
485
1074
  return false;
486
1075
  }
487
- let form: types.IForm | null = null;
488
- if (formId) {
489
- if (!task.forms[formId]) {
490
- return false;
491
- }
492
- form = task.forms[formId];
493
- }
494
1076
  /** --- 当前父 form 的路径(以 / 结尾)或 /(没有基路径的话) --- */
495
- const base: string = form ? form.vroot.cgPath : '/';
496
- path = tool.urlResolve(base, path) + '.json';
1077
+ path = tool.urlResolve(task.current + '/', path) + '.json';
497
1078
  /** --- 获取的语言文件 --- */
498
1079
  const fcontent = await fs.getContent(path, {
499
1080
  'encoding': 'utf8',
500
- 'files': task.files,
501
- 'current': task.path
1081
+ 'files': task.app.files,
1082
+ 'current': task.current
502
1083
  });
503
1084
  if (!fcontent) {
504
1085
  return false;
@@ -531,13 +1112,12 @@ export function clearLocale(taskId?: number): void {
531
1112
  /**
532
1113
  * --- 加载全新 locale(老 locale 的所以语言的缓存会被卸载) ---
533
1114
  * @param lang 语言名,如 sc
534
- * @param path 路径
535
- * @param taskId 所属的 taskId,App 模式下无效
536
- * @param formId 所属的 formId,App 模式下无效
1115
+ * @param path 绝对或者相对 app 路径的地址
1116
+ * @param taskId 所属的 taskId,App 模式下无效z
537
1117
  */
538
- export function setLocale(lang: string, path: string, taskId?: number, formId?: number): Promise<boolean> {
1118
+ export function setLocale(lang: string, path: string, taskId?: number): Promise<boolean> {
539
1119
  clearLocale(taskId);
540
- return loadLocale(lang, path, taskId, formId);
1120
+ return loadLocale(lang, path, taskId);
541
1121
  }
542
1122
 
543
1123
  /**
@@ -583,15 +1163,17 @@ export function createTimer(
583
1163
  opt: types.ICreateTimerOptions = {}
584
1164
  ): number {
585
1165
  const taskId = opt.taskId;
1166
+ const formId = opt.formId;
586
1167
  if (!taskId) {
587
1168
  return 0;
588
1169
  }
589
- const formId = opt.formId;
590
- if (!formId) {
1170
+ const task = list[taskId];
1171
+ if (!task) {
1172
+ return 0;
1173
+ }
1174
+ if (formId && !task.forms[formId]) {
591
1175
  return 0;
592
1176
  }
593
- /** --- 作用域 --- */
594
- const scope = opt.scope ?? 'form';
595
1177
  /** --- 执行几次,0 代表无限次 --- */
596
1178
  const count = opt.count ?? 0;
597
1179
  /** --- 当前已经执行的次数 --- */
@@ -612,13 +1194,11 @@ export function createTimer(
612
1194
  let timer: number;
613
1195
  const timerHandler = (): void => {
614
1196
  ++c;
615
- if (list[taskId].forms[formId] === undefined) {
1197
+ if (formId && task.forms[formId] === undefined) {
616
1198
  // --- form 已经没了 ---
617
- if (scope === 'form') {
618
- clearTimeout(timer);
619
- delete list[taskId].timers[timer];
620
- return;
621
- }
1199
+ clearTimeout(timer);
1200
+ delete task.timers[timer];
1201
+ return;
622
1202
  }
623
1203
  const r = fun();
624
1204
  if (r instanceof Promise) {
@@ -628,7 +1208,7 @@ export function createTimer(
628
1208
  }
629
1209
  if (count > 0 && c === count) {
630
1210
  clearTimeout(timer);
631
- delete list[taskId].timers[timer];
1211
+ delete task.timers[timer];
632
1212
  return;
633
1213
  }
634
1214
  };
@@ -639,7 +1219,7 @@ export function createTimer(
639
1219
  else {
640
1220
  timer = window.setInterval(timerHandler, delay);
641
1221
  }
642
- list[taskId].timers[timer] = formId;
1222
+ task.timers[timer] = formId ?? 0;
643
1223
  return timer;
644
1224
  }
645
1225
 
@@ -669,12 +1249,10 @@ export function removeTimer(timer: number, taskId?: number): void {
669
1249
  * @param fun 回调函数
670
1250
  * @param delay 暂停时间
671
1251
  * @param taskId 任务 id,App 模式下无效
672
- * @param formId 窗体 id,App 模式下无效
673
1252
  */
674
- export function sleep(fun: () => void | Promise<void>, delay: number, taskId?: number, formId?: number): number {
1253
+ export function sleep(fun: () => void | Promise<void>, delay: number, taskId?: number): number {
675
1254
  return createTimer(fun, delay, {
676
1255
  'taskId': taskId,
677
- 'formId': formId,
678
1256
  'count': 1
679
1257
  });
680
1258
  }
@@ -726,11 +1304,11 @@ clickgo.vue.watch(systemTaskInfo, function(n: any, o: any) {
726
1304
 
727
1305
  /**
728
1306
  * --- 将任务注册为系统 task ---
729
- * @param formId task bar 的 form id,App 模式下留空为当前窗体
1307
+ * @param formId task bar 的 form id
730
1308
  * @param taskId task id,App 模式下无效
731
1309
  */
732
- export function setSystem(formId?: number, taskId?: number): boolean {
733
- if (!formId || !taskId) {
1310
+ export function setSystem(formId: number, taskId?: number): boolean {
1311
+ if (!taskId) {
734
1312
  return false;
735
1313
  }
736
1314
  const task = list[taskId];
@@ -805,7 +1383,7 @@ export function clearSystem(taskId?: number): boolean {
805
1383
  }
806
1384
 
807
1385
  /**
808
- * --- 刷新系统任务的 form 的位置以及 length ---
1386
+ * --- 刷新系统任务的 form 的位置以及 length,App 模式下无效 ---
809
1387
  */
810
1388
  export function refreshSystemPosition(): void {
811
1389
  if (systemTaskInfo.taskId > 0) {
@@ -814,14 +1392,14 @@ export function refreshSystemPosition(): void {
814
1392
  switch (core.config['task.position']) {
815
1393
  case 'left':
816
1394
  case 'right': {
817
- form.vroot.$refs.form.setPropData('width', 'auto');
1395
+ form.vroot.$refs.form.setPropData('width', 0);
818
1396
  form.vroot.$refs.form.setPropData('height', window.innerHeight);
819
1397
  break;
820
1398
  }
821
1399
  case 'top':
822
1400
  case 'bottom': {
823
1401
  form.vroot.$refs.form.setPropData('width', window.innerWidth);
824
- form.vroot.$refs.form.setPropData('height', 'auto');
1402
+ form.vroot.$refs.form.setPropData('height', 0);
825
1403
  break;
826
1404
  }
827
1405
  }