clickgo 3.1.2-dev11 → 3.1.4-dev13

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 (110) hide show
  1. package/README.md +1 -1
  2. package/dist/app/demo/app.js +0 -73
  3. package/dist/app/demo/config.json +113 -0
  4. package/dist/app/demo/form/control/button/button.js +12 -11
  5. package/dist/app/demo/form/control/button/button.xml +6 -6
  6. package/dist/app/demo/form/control/check/check.js +14 -10
  7. package/dist/app/demo/form/control/file/file.js +15 -13
  8. package/dist/app/demo/form/control/{overflow/overflow.css → flow/flow.css} +0 -0
  9. package/dist/app/demo/form/control/flow/flow.js +64 -0
  10. package/dist/app/demo/form/control/{overflow/overflow.scss → flow/flow.scss} +0 -0
  11. package/dist/app/demo/form/control/flow/flow.xml +101 -0
  12. package/dist/app/demo/form/control/form/form.js +1 -1
  13. package/dist/app/demo/form/control/form/form.xml +3 -3
  14. package/dist/app/demo/form/control/img/img.xml +2 -2
  15. package/dist/app/demo/form/control/list/list.js +95 -75
  16. package/dist/app/demo/form/control/list/list.xml +15 -11
  17. package/dist/app/demo/form/control/marquee/marquee.js +12 -10
  18. package/dist/app/demo/form/control/menu/menu.js +10 -6
  19. package/dist/app/demo/form/control/monaco/monaco.js +50 -60
  20. package/dist/app/demo/form/control/monaco/monaco.xml +6 -5
  21. package/dist/app/demo/form/control/property/property.js +131 -127
  22. package/dist/app/demo/form/control/radio/radio.js +9 -5
  23. package/dist/app/demo/form/control/scroll/scroll.js +16 -12
  24. package/dist/app/demo/form/control/scroll/scroll.xml +10 -10
  25. package/dist/app/demo/form/control/select/select.js +132 -71
  26. package/dist/app/demo/form/control/select/select.xml +69 -67
  27. package/dist/app/demo/form/control/tab/tab.js +21 -20
  28. package/dist/app/demo/form/control/tab/tab.xml +2 -2
  29. package/dist/app/demo/form/control/text/text.js +53 -45
  30. package/dist/app/demo/form/control/text/text.xml +3 -3
  31. package/dist/app/demo/form/control/{greatview/greatview.css → vflow/vflow.css} +0 -0
  32. package/dist/app/demo/form/control/vflow/vflow.js +79 -0
  33. package/dist/app/demo/form/control/{greatview/greatview.scss → vflow/vflow.scss} +0 -0
  34. package/dist/app/demo/form/control/{greatview/greatview.xml → vflow/vflow.xml} +25 -25
  35. package/dist/app/demo/form/event/form/form.js +58 -56
  36. package/dist/app/demo/form/event/form/form.xml +3 -3
  37. package/dist/app/demo/form/event/other/other.js +29 -0
  38. package/dist/app/demo/form/event/other/other.xml +5 -0
  39. package/dist/app/demo/form/event/screen/screen.js +30 -28
  40. package/dist/app/demo/form/event/screen/screen.xml +2 -2
  41. package/dist/app/demo/form/event/task/task.js +31 -31
  42. package/dist/app/demo/form/event/task/task.xml +3 -3
  43. package/dist/app/demo/form/main.js +166 -5
  44. package/dist/app/demo/form/main.xml +37 -35
  45. package/dist/app/demo/form/method/aform/aform.js +2 -1
  46. package/dist/app/demo/form/method/aform/aform.xml +3 -2
  47. package/dist/app/demo/form/method/aform/sd.js +28 -0
  48. package/dist/app/demo/form/method/aform/sd.xml +7 -0
  49. package/dist/app/demo/form/method/aform/test.xml +4 -5
  50. package/dist/app/demo/form/method/core/core.js +23 -8
  51. package/dist/app/demo/form/method/core/core.xml +6 -1
  52. package/dist/app/demo/form/method/dom/dom.js +91 -99
  53. package/dist/app/demo/form/method/dom/dom.xml +6 -7
  54. package/dist/app/demo/form/method/form/form.js +8 -8
  55. package/dist/app/demo/form/method/form/form.xml +4 -4
  56. package/dist/app/demo/form/method/fs/fs.js +34 -33
  57. package/dist/app/demo/form/method/fs/fs.xml +1 -1
  58. package/dist/app/demo/form/method/fs/text.js +12 -12
  59. package/dist/app/demo/form/method/native/native.js +50 -0
  60. package/dist/app/demo/form/method/native/native.xml +12 -0
  61. package/dist/app/demo/form/method/system/system.js +50 -0
  62. package/dist/app/demo/form/method/system/system.xml +11 -0
  63. package/dist/app/demo/form/method/task/task.js +68 -62
  64. package/dist/app/demo/form/method/task/task.xml +5 -6
  65. package/dist/app/demo/form/method/theme/theme.js +14 -14
  66. package/dist/app/demo/form/method/tool/tool.js +29 -28
  67. package/dist/app/demo/form/method/tool/tool.xml +3 -3
  68. package/dist/app/demo/form/method/zip/zip.js +46 -41
  69. package/dist/app/demo/form/method/zip/zip.xml +1 -1
  70. package/dist/app/task/app.js +0 -25
  71. package/dist/app/task/config.json +29 -0
  72. package/dist/app/task/form/bar/bar.js +1 -1
  73. package/dist/app/task/form/bar/bar.xml +1 -1
  74. package/dist/clickgo.js +1 -1
  75. package/dist/clickgo.ts +1 -1
  76. package/dist/control/common.cgc +0 -0
  77. package/dist/control/form.cgc +0 -0
  78. package/dist/control/monaco.cgc +0 -0
  79. package/dist/control/property.cgc +0 -0
  80. package/dist/control/task.cgc +0 -0
  81. package/dist/global.css +1 -1
  82. package/dist/index.js +6 -3
  83. package/dist/index.ts +9 -3
  84. package/dist/lib/control.js +70 -104
  85. package/dist/lib/control.ts +97 -123
  86. package/dist/lib/core.js +163 -253
  87. package/dist/lib/core.ts +185 -268
  88. package/dist/lib/dom.js +565 -484
  89. package/dist/lib/dom.ts +704 -547
  90. package/dist/lib/form.js +211 -159
  91. package/dist/lib/form.ts +196 -121
  92. package/dist/lib/fs.js +107 -12
  93. package/dist/lib/fs.ts +111 -20
  94. package/dist/lib/native.js +142 -8
  95. package/dist/lib/native.ts +181 -11
  96. package/dist/lib/task.js +526 -164
  97. package/dist/lib/task.ts +598 -179
  98. package/dist/lib/tool.js +48 -1
  99. package/dist/lib/tool.ts +61 -0
  100. package/dist/lib/zip.ts +2 -0
  101. package/dist/theme/familiar.cgt +0 -0
  102. package/package.json +2 -2
  103. package/types/index.d.ts +83 -39
  104. package/dist/app/demo/form/control/greatview/greatview.js +0 -92
  105. package/dist/app/demo/form/control/overflow/overflow.js +0 -70
  106. package/dist/app/demo/form/control/overflow/overflow.xml +0 -98
  107. package/dist/app/demo/form/control/view/view.css +0 -1
  108. package/dist/app/demo/form/control/view/view.js +0 -73
  109. package/dist/app/demo/form/control/view/view.scss +0 -18
  110. package/dist/app/demo/form/control/view/view.xml +0 -94
package/dist/lib/form.ts CHANGED
@@ -23,6 +23,9 @@ import * as control from './control';
23
23
  import * as fs from './fs';
24
24
  import * as native from './native';
25
25
 
26
+ /** --- 当前有焦点的窗体 id --- */
27
+ let focusId: number | null = null;
28
+
26
29
  /** --- form 相关信息 --- */
27
30
  const info: {
28
31
  /** --- 最后一个窗体 id --- */
@@ -76,7 +79,7 @@ const info: {
76
79
  };
77
80
 
78
81
  /** --- 窗体的抽象类 --- */
79
- export class AbstractForm {
82
+ export abstract class AbstractForm {
80
83
 
81
84
  /**
82
85
  * --- 创建窗体工厂函数 ---
@@ -84,7 +87,7 @@ export class AbstractForm {
84
87
  * @param layout 是否使用此参数替换 layout 值
85
88
  */
86
89
  public static async create(data?: Record<string, any>, layout?: string): Promise<AbstractForm | number> {
87
- const frm = new this();
90
+ const frm: AbstractForm = new (this as any)();
88
91
  /** --- 要挂载的 vue 参数 --- */
89
92
  const code: types.IFormCreateCode = {
90
93
  'data': {},
@@ -121,6 +124,11 @@ export class AbstractForm {
121
124
  /** --- class 对象类的属性列表 --- */
122
125
  const cdata = Object.entries(frm);
123
126
  for (const item of cdata) {
127
+ if (item[0] === 'access') {
128
+ // --- access 属性不放在 data 当中 ---
129
+
130
+ continue;
131
+ }
124
132
  code.data![item[0]] = item[1];
125
133
  }
126
134
  if (!layout) {
@@ -229,7 +237,7 @@ export class AbstractForm {
229
237
  }
230
238
 
231
239
  /** --- layout 中 :class 的转义 --- */
232
- public classPrepend(): (cla: any) => string {
240
+ public get classPrepend(): (cla: any) => string {
233
241
  return (cla: any): string => {
234
242
  if (typeof cla !== 'string') {
235
243
  return cla;
@@ -239,15 +247,18 @@ export class AbstractForm {
239
247
  };
240
248
  }
241
249
 
250
+ /** --- 当前窗体是否和 native 的实体窗体大小、状态同步 --- */
251
+ public isNativeSync: boolean = false;
252
+
242
253
  /**
243
254
  * --- 监视变动 ---
244
255
  * @param name 监视的属性
245
256
  * @param cb 回调
246
257
  * @param opt 参数
247
258
  */
248
- public watch<T extends this, TK extends keyof T>(
249
- name: TK,
250
- cb: (val: T[TK], old: T[TK]) => void | Promise<void>,
259
+ public watch<T extends this, TK extends keyof T, TR>(
260
+ name: TK | (() => TR),
261
+ cb: (val: T[TK] & TR, old: T[TK] & TR) => void | Promise<void>,
251
262
  opt: {
252
263
  'immediate'?: boolean;
253
264
  'deep'?: boolean;
@@ -374,9 +385,9 @@ export class AbstractForm {
374
385
  * --- 显示独占的窗体 ---
375
386
  */
376
387
  public async showDialog(): Promise<string> {
377
- this.topMost = true;
378
- this.show();
379
388
  task.list[this.taskId].runtime.dialogFormIds.push(this.formId);
389
+ this.show();
390
+ this.topMost = true;
380
391
  return new Promise((resolve) => {
381
392
  (this as any).cgDialogCallback = () => {
382
393
  resolve(this.dialogResult);
@@ -392,6 +403,13 @@ export class AbstractForm {
392
403
  v.$refs.form.$data.isShow = false;
393
404
  }
394
405
 
406
+ /**
407
+ * --- 关闭当前窗体 ---
408
+ */
409
+ public close(): void {
410
+ close(this.formId);
411
+ }
412
+
395
413
  /**
396
414
  * --- dialog mask 窗体返回值,在 close 之后会进行传导 ---
397
415
  */
@@ -411,6 +429,7 @@ export class AbstractForm {
411
429
  return;
412
430
  }
413
431
 
432
+ public onMounted(obj: Record<string, any>): void | Promise<void>;
414
433
  public onMounted(): void | Promise<void> {
415
434
  return;
416
435
  }
@@ -529,6 +548,12 @@ export class AbstractForm {
529
548
  return;
530
549
  }
531
550
 
551
+ /** --- location hash 改变事件 --- */
552
+ public onHashChanged(hash: string): void | Promise<void>;
553
+ public onHashChanged(): void {
554
+ return;
555
+ }
556
+
532
557
  }
533
558
 
534
559
  /** --- pop 相关信息 --- */
@@ -547,7 +572,11 @@ const popInfo: {
547
572
 
548
573
  export let simpleSystemTaskRoot: types.IVue;
549
574
  export let launcherRoot: types.IVue;
550
- const elements: {
575
+
576
+ /** --- 系统级 confirm 的用户回调函数 --- */
577
+ let superConfirmHandler: undefined | ((result: boolean) => void | Promise<void>) = undefined;
578
+
579
+ export const elements: {
551
580
  'wrap': HTMLDivElement;
552
581
  'list': HTMLDivElement;
553
582
  'popList': HTMLDivElement;
@@ -555,10 +584,10 @@ const elements: {
555
584
  'rectangle': HTMLDivElement;
556
585
  'gesture': HTMLDivElement;
557
586
  'drag': HTMLDivElement;
558
- 'dragIcon'?: HTMLElement;
559
- 'system': HTMLElement;
560
- 'simpleSystemtask': HTMLDivElement;
587
+ 'notify': HTMLElement;
588
+ 'simpletask': HTMLDivElement;
561
589
  'launcher': HTMLDivElement;
590
+ 'confirm': HTMLDivElement;
562
591
  'init': () => void;
563
592
  } = {
564
593
  'wrap': document.createElement('div'),
@@ -568,28 +597,15 @@ const elements: {
568
597
  'rectangle': document.createElement('div'),
569
598
  'gesture': document.createElement('div'),
570
599
  'drag': document.createElement('div'),
571
- 'dragIcon': undefined,
572
- 'system': document.createElement('div'),
573
- 'simpleSystemtask': document.createElement('div'),
600
+ 'notify': document.createElement('div'),
601
+ 'simpletask': document.createElement('div'),
574
602
  'launcher': document.createElement('div'),
603
+ 'confirm': document.createElement('div'),
575
604
  'init': function() {
576
605
  /** --- clickgo 所有的 div wrap --- */
577
606
  this.wrap.id = 'cg-wrap';
578
607
  document.getElementsByTagName('body')[0].appendChild(this.wrap);
579
- if (clickgo.isImmersion()) {
580
- // --- 只有沉浸式模式(Windows 下非 frame 的 native)才会绑定这个事件 ---
581
- this.wrap.addEventListener('mouseenter', function() {
582
- native.invoke('cg-mouse-ignore', native.getToken(), false);
583
- });
584
- this.wrap.addEventListener('mouseleave', function() {
585
- native.invoke('cg-mouse-ignore', native.getToken(), true);
586
- });
587
- }
588
-
589
- /** --- form list 的 div --- */
590
- this.list.id = 'cg-form-list';
591
- this.wrap.appendChild(this.list);
592
- this.list.addEventListener('touchmove', function(e): void {
608
+ this.wrap.addEventListener('touchmove', function(e): void {
593
609
  // --- 防止拖动时整个网页跟着动 ---
594
610
  if (e.cancelable) {
595
611
  e.preventDefault();
@@ -598,28 +614,32 @@ const elements: {
598
614
  }, {
599
615
  'passive': false
600
616
  });
601
- this.list.addEventListener('wheel', function(e): void {
602
- // --- 防止不小心前进后退,或上下缓动滚动(Mac ---
617
+ this.wrap.addEventListener('wheel', function(e): void {
618
+ // --- 防止不小心前进后退,或上下缓动滚动(Mac、触摸板) ---
603
619
  e.preventDefault();
604
620
  }, {
605
621
  'passive': false
606
622
  });
607
- this.list.addEventListener('contextmenu', function(e): void {
623
+ this.wrap.addEventListener('contextmenu', function(e): void {
608
624
  e.preventDefault();
609
625
  });
626
+ if (clickgo.isImmersion()) {
627
+ // --- 只有沉浸式模式(Windows 下非 frame 的 native)才会绑定这个事件 ---
628
+ this.wrap.addEventListener('mouseenter', function() {
629
+ native.invoke('cg-mouse-ignore', native.getToken(), false) as any;
630
+ });
631
+ this.wrap.addEventListener('mouseleave', function() {
632
+ native.invoke('cg-mouse-ignore', native.getToken(), true) as any;
633
+ });
634
+ }
635
+
636
+ /** --- form list 的 div --- */
637
+ this.list.id = 'cg-form-list';
638
+ this.wrap.appendChild(this.list);
610
639
 
611
640
  /** --- pop list 的 div --- */
612
641
  this.popList.id = 'cg-pop-list';
613
- this.popList.addEventListener('contextmenu', function(e): void {
614
- e.preventDefault();
615
- });
616
642
  this.wrap.appendChild(this.popList);
617
- this.popList.addEventListener('touchmove', function(e): void {
618
- // --- 防止拖动时整个网页跟着动 ---
619
- e.preventDefault();
620
- }, {
621
- 'passive': false
622
- });
623
643
 
624
644
  // --- 从鼠标指针处从小到大缩放然后淡化的圆圈动画特效对象 ---=
625
645
  this.circular.id = 'cg-circular';
@@ -637,34 +657,15 @@ const elements: {
637
657
  // --- drag drop 的拖动占位符 ---
638
658
  this.drag.id = 'cg-drag';
639
659
  this.drag.innerHTML = '<svg width="16" height="16" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 8L40 40" stroke="#FFF" stroke-width="4" stroke-linecap="butt" stroke-linejoin="miter"/><path d="M8 40L40 8" stroke="#FFF" stroke-width="4" stroke-linecap="butt" stroke-linejoin="miter"/></svg>';
640
- this.dragIcon = this.drag.childNodes[0] as HTMLElement;
641
660
  this.wrap.appendChild(this.drag);
642
661
 
643
662
  // --- 添加 cg-system 的 dom ---
644
- this.system.id = 'cg-system';
645
- this.system.addEventListener('contextmenu', function(e): void {
646
- e.preventDefault();
647
- });
648
- this.wrap.appendChild(this.system);
649
- this.system.addEventListener('touchmove', function(e): void {
650
- // --- 防止拖动时整个网页跟着动 ---
651
- e.preventDefault();
652
- }, {
653
- 'passive': false
654
- });
663
+ this.notify.id = 'cg-notify';
664
+ this.wrap.appendChild(this.notify);
655
665
 
656
666
  // --- 添加 cg-simpletask 的 dom ---
657
- this.simpleSystemtask.id = 'cg-simpletask';
658
- this.simpleSystemtask.addEventListener('contextmenu', function(e): void {
659
- e.preventDefault();
660
- });
661
- this.wrap.appendChild(this.simpleSystemtask);
662
- this.simpleSystemtask.addEventListener('touchmove', function(e): void {
663
- // --- 防止拖动时整个网页跟着动 ---
664
- e.preventDefault();
665
- }, {
666
- 'passive': false
667
- });
667
+ this.simpletask.id = 'cg-simpletask';
668
+ this.wrap.appendChild(this.simpletask);
668
669
  const simpletaskApp = clickgo.vue.createApp({
669
670
  'template': '<div v-for="(item, formId) of forms" class="cg-simpletask-item" @click="click(parseInt(formId))"><div v-if="item.icon" class="cg-simpletask-icon" :style="{\'background-image\': \'url(\' + item.icon + \')\'}"></div><div>{{item.title}}</div></div>',
670
671
  'data': function() {
@@ -677,14 +678,14 @@ const elements: {
677
678
  handler: function(this: types.IVue) {
678
679
  const length = Object.keys(this.forms).length;
679
680
  if (length > 0) {
680
- if (elements.simpleSystemtask.style.bottom !== '0px') {
681
- elements.simpleSystemtask.style.bottom = '0px';
681
+ if (elements.simpletask.style.bottom !== '0px') {
682
+ elements.simpletask.style.bottom = '0px';
682
683
  core.trigger('screenResize');
683
684
  }
684
685
  }
685
686
  else {
686
- if (elements.simpleSystemtask.style.bottom === '0px') {
687
- elements.simpleSystemtask.style.bottom = '-46px';
687
+ if (elements.simpletask.style.bottom === '0px') {
688
+ elements.simpletask.style.bottom = '-46px';
688
689
  core.trigger('screenResize');
689
690
  }
690
691
  }
@@ -705,23 +706,14 @@ const elements: {
705
706
 
706
707
  // --- cg-launcher ---
707
708
  this.launcher.id = 'cg-launcher';
708
- this.launcher.addEventListener('contextmenu', function(e): void {
709
- e.preventDefault();
710
- });
711
709
  this.wrap.appendChild(this.launcher);
712
- this.launcher.addEventListener('touchmove', function(e): void {
713
- // --- 防止拖动时整个网页跟着动 ---
714
- e.preventDefault();
715
- }, {
716
- 'passive': false
717
- });
718
710
  // --- Vue 挂载在这里 ---
719
711
  const waiting = function(): void {
720
712
  // --- 必须在这里执行,要不然 computed 无法更新,因为 core 还没加载进来 ---
721
713
  if (!core.config) {
722
714
  setTimeout(function() {
723
715
  waiting();
724
- }, 2000);
716
+ }, 150);
725
717
  return;
726
718
  }
727
719
  const launcherApp = clickgo.vue.createApp({
@@ -752,7 +744,8 @@ const elements: {
752
744
  'data': function() {
753
745
  return {
754
746
  'name': '',
755
- 'folderName': ''
747
+ 'folderName': '',
748
+ 'folderItem': {}
756
749
  };
757
750
  },
758
751
  'computed': {
@@ -888,10 +881,58 @@ const elements: {
888
881
  launcherApp.mount('#cg-launcher');
889
882
  };
890
883
  waiting();
884
+
885
+ // --- cg-confirm ---
886
+ this.confirm.id = 'cg-confirm';
887
+ this.wrap.appendChild(this.confirm);
888
+
889
+ this.confirm.innerHTML = `<div class="cg-confirm-box">` +
890
+ `<div id="cg-confirm-content"></div>` +
891
+ `<div class="cg-confirm-controls">` +
892
+ `<div id="cg-confirm-cancel"></div>` +
893
+ `<div id="cg-confirm-ok"></div>` +
894
+ `</div>` +
895
+ `</div>`;
896
+ this.confirm.style.display = 'none';
897
+ document.getElementById('cg-confirm-cancel')!.addEventListener('click', () => {
898
+ superConfirmHandler?.(false) as any;
899
+ this.confirm.style.display = 'none';
900
+ const fid = getMaxZIndexID();
901
+ if (fid) {
902
+ changeFocus(fid);
903
+ }
904
+ });
905
+ document.getElementById('cg-confirm-ok')!.addEventListener('click', () => {
906
+ superConfirmHandler?.(true) as any;
907
+ this.confirm.style.display = 'none';
908
+ const fid = getMaxZIndexID();
909
+ if (fid) {
910
+ changeFocus(fid);
911
+ }
912
+ });
913
+
891
914
  }
892
915
  };
893
916
  elements.init();
894
917
 
918
+ /** --- 显示系统级询问框,App 模式下无效 --- */
919
+ export function superConfirm(html: string): Promise<boolean> {
920
+ return new Promise((resolve) => {
921
+ if (superConfirmHandler !== undefined) {
922
+ resolve(false);
923
+ return;
924
+ }
925
+ elements.confirm.style.display = 'flex';
926
+ document.getElementById('cg-confirm-content')!.innerHTML = html;
927
+ document.getElementById('cg-confirm-cancel')!.innerHTML = info.locale[core.config.locale]?.cancel ?? info.locale['en'].cancel;
928
+ document.getElementById('cg-confirm-ok')!.innerHTML = info.locale[core.config.locale]?.ok ?? info.locale['en'].ok;
929
+ superConfirmHandler = (result: boolean) => {
930
+ superConfirmHandler = undefined;
931
+ resolve(result);
932
+ };
933
+ });
934
+ }
935
+
895
936
  /**
896
937
  * --- 修改窗体的最大化、最小化状态,外部或不可调整 state 时才调用 ---
897
938
  * @param state 最大化、最小化或关闭
@@ -1088,6 +1129,13 @@ export function getList(taskId: number): Record<string, types.IFormInfo> {
1088
1129
  return list;
1089
1130
  }
1090
1131
 
1132
+ /**
1133
+ * --- 获取当前有焦点的窗体 form id ---
1134
+ */
1135
+ export function getFocus(): number | null {
1136
+ return focusId;
1137
+ }
1138
+
1091
1139
  /**
1092
1140
  * --- 改变 form 的焦点 class ---
1093
1141
  * @param formId 变更后的 form id
@@ -1101,31 +1149,25 @@ export function changeFocus(formId: number = 0): void {
1101
1149
  });
1102
1150
  return;
1103
1151
  }
1104
- const focusElement = document.querySelector('#cg-form-list > [data-form-focus]');
1105
- if (focusElement) {
1106
- const dataFormId = focusElement.getAttribute('data-form-id');
1107
- if (dataFormId) {
1108
- const dataFormIdNumber = parseInt(dataFormId);
1109
- if (dataFormIdNumber === formId) {
1110
- return;
1111
- }
1112
- else {
1113
- const taskId = parseInt(focusElement.getAttribute('data-task-id') ?? '0');
1114
- const t = task.list[taskId];
1115
- t.forms[dataFormIdNumber].vapp._container.removeAttribute('data-form-focus');
1116
- t.forms[dataFormIdNumber].vroot._formFocus = false;
1117
- // --- 触发 formBlurred 事件 ---
1118
- core.trigger('formBlurred', taskId, dataFormIdNumber);
1119
- }
1152
+ const dataFormId = getFocus();
1153
+ if (dataFormId) {
1154
+ if (dataFormId === formId) {
1155
+ return;
1120
1156
  }
1121
1157
  else {
1122
- return;
1158
+ const t = task.list[task.getFocus()!];
1159
+ t.forms[dataFormId].vapp._container.removeAttribute('data-form-focus');
1160
+ t.forms[dataFormId].vroot._formFocus = false;
1161
+ // --- 触发 formBlurred 事件 ---
1162
+ core.trigger('formBlurred', t.id, dataFormId);
1123
1163
  }
1124
1164
  }
1165
+ focusId = null;
1166
+ task.setFocus();
1125
1167
  if (formId === 0) {
1126
1168
  return;
1127
1169
  }
1128
- const el = document.querySelector(`#cg-form-list > [data-form-id='${formId}']`);
1170
+ const el = elements.list.querySelector(`.cg-form-wrap[data-form-id='${formId}']`);
1129
1171
  if (!el) {
1130
1172
  return;
1131
1173
  }
@@ -1153,6 +1195,8 @@ export function changeFocus(formId: number = 0): void {
1153
1195
  // --- 开启 focus ---
1154
1196
  t.forms[dialogFormId].vapp._container.dataset.formFocus = '';
1155
1197
  t.forms[dialogFormId].vroot._formFocus = true;
1198
+ focusId = dialogFormId;
1199
+ task.setFocus(t.id);
1156
1200
  // --- 触发 formFocused 事件 ---
1157
1201
  core.trigger('formFocused', taskId, dialogFormId);
1158
1202
  // --- 判断点击的窗体是不是就是 dialog mask 窗体本身 ---
@@ -1172,6 +1216,8 @@ export function changeFocus(formId: number = 0): void {
1172
1216
  // --- 正常开启 focus ---
1173
1217
  t.forms[formId].vapp._container.dataset.formFocus = '';
1174
1218
  t.forms[formId].vroot._formFocus = true;
1219
+ focusId = formId;
1220
+ task.setFocus(t.id);
1175
1221
  // --- 触发 formFocused 事件 ---
1176
1222
  core.trigger('formFocused', taskId, formId);
1177
1223
  }
@@ -1418,14 +1464,10 @@ export function moveDrag(opt: types.IMoveDragOptions): void {
1418
1464
  elements.drag.style.height = opt.height.toString() + 'px';
1419
1465
  }
1420
1466
  if (opt.icon) {
1421
- if (elements.dragIcon) {
1422
- elements.dragIcon.style.display = 'block';
1423
- }
1467
+ (elements.drag.childNodes[0] as HTMLElement).style.display = 'block';
1424
1468
  }
1425
1469
  else {
1426
- if (elements.dragIcon) {
1427
- elements.dragIcon.style.display = 'none';
1428
- }
1470
+ (elements.drag.childNodes[0] as HTMLElement).style.display = 'none';
1429
1471
  }
1430
1472
  }
1431
1473
 
@@ -1462,21 +1504,21 @@ export function notify(opt: types.INotifyOptions): number {
1462
1504
  // --- 创建 notify element ---
1463
1505
  const el = document.createElement('div');
1464
1506
  const y = notifyTop;
1465
- el.classList.add('cg-system-notify');
1507
+ el.classList.add('cg-notify-wrap');
1466
1508
  el.setAttribute('data-notifyid', nid.toString());
1467
1509
  el.style.transform = `translateY(${y}px) translateX(280px)`;
1468
1510
  el.style.opacity = '1';
1469
- el.innerHTML = `<div class="cg-system-icon cg-${tool.escapeHTML(opt.type ?? 'primary')}"></div>
1511
+ el.innerHTML = `<div class="cg-notify-icon cg-${tool.escapeHTML(opt.type ?? 'primary')}"></div>
1470
1512
  <div style="flex: 1;">
1471
- <div class="cg-system-notify-title">${tool.escapeHTML(opt.title)}</div>
1472
- <div class="cg-system-notify-content">${tool.escapeHTML(opt.content).replace(/\r\n/g, '\n').replace(/\r/g, '\n').replace(/\n/g, '<br>')}</div>
1473
- ${opt.progress ? '<div class="cg-system-notify-progress"></div>' : ''}
1513
+ <div class="cg-notify-title">${tool.escapeHTML(opt.title)}</div>
1514
+ <div class="cg-notify-content">${tool.escapeHTML(opt.content).replace(/\r\n/g, '\n').replace(/\r/g, '\n').replace(/\n/g, '<br>')}</div>
1515
+ ${opt.progress ? '<div class="cg-notify-progress"></div>' : ''}
1474
1516
  </div>`;
1475
1517
  if (opt.icon) {
1476
1518
  (el.childNodes.item(0) as HTMLElement).style.background = 'url(' + opt.icon + ')';
1477
1519
  (el.childNodes.item(0) as HTMLElement).style.backgroundSize = '16px';
1478
1520
  }
1479
- elements.system.appendChild(el);
1521
+ elements.notify.appendChild(el);
1480
1522
  notifyTop += el.offsetHeight + 10;
1481
1523
  requestAnimationFrame(function() {
1482
1524
  el.style.transform = `translateY(${y}px) translateX(-10px)`;
@@ -1494,11 +1536,11 @@ export function notify(opt: types.INotifyOptions): number {
1494
1536
  * @param per 进度,0 - 100 或 0% - 100% (0 - 1)
1495
1537
  */
1496
1538
  export function notifyProgress(notifyId: number, per: number): void {
1497
- const el: HTMLElement = elements.system.querySelector(`[data-notifyid="${notifyId}"]`)!;
1539
+ const el: HTMLElement = elements.notify.querySelector(`[data-notifyid="${notifyId}"]`)!;
1498
1540
  if (!el) {
1499
1541
  return;
1500
1542
  }
1501
- const progress: HTMLElement = el.querySelector('.cg-system-notify-progress')!;
1543
+ const progress: HTMLElement = el.querySelector('.cg-notify-progress')!;
1502
1544
  if (!progress) {
1503
1545
  return;
1504
1546
  }
@@ -1522,7 +1564,7 @@ export function notifyProgress(notifyId: number, per: number): void {
1522
1564
  * @param notifyId 要隐藏的 notify id
1523
1565
  */
1524
1566
  export function hideNotify(notifyId: number): void {
1525
- const el: HTMLElement = elements.system.querySelector(`[data-notifyid="${notifyId}"]`)!;
1567
+ const el: HTMLElement = elements.notify.querySelector(`[data-notifyid="${notifyId}"]`)!;
1526
1568
  if (!el) {
1527
1569
  return;
1528
1570
  }
@@ -1531,7 +1573,7 @@ export function hideNotify(notifyId: number): void {
1531
1573
  el.style.opacity = '0';
1532
1574
  setTimeout(function() {
1533
1575
  notifyTop -= notifyHeight + 10;
1534
- const notifyElementList = document.getElementsByClassName('cg-system-notify') as HTMLCollectionOf<HTMLDivElement>;
1576
+ const notifyElementList = document.getElementsByClassName('cg-notify-wrap') as HTMLCollectionOf<HTMLDivElement>;
1535
1577
  let needSub = false;
1536
1578
  for (const notifyElement of notifyElementList) {
1537
1579
  if (notifyElement === el) {
@@ -1851,6 +1893,7 @@ export function remove(formId: number): boolean {
1851
1893
  }
1852
1894
  task.list[taskId].forms[formId].vapp.unmount();
1853
1895
  task.list[taskId].forms[formId].vapp._container.remove();
1896
+ elements.popList.querySelector('[data-form-id="' + formId.toString() + '"]')?.remove();
1854
1897
  if (io > -1) {
1855
1898
  // --- 如果是 dialog 则要执行回调 ---
1856
1899
  task.list[taskId].forms[formId].vroot.cgDialogCallback();
@@ -1860,6 +1903,9 @@ export function remove(formId: number): boolean {
1860
1903
  dom.removeStyle(taskId, 'form', formId);
1861
1904
  // --- 触发 formRemoved 事件 ---
1862
1905
  core.trigger('formRemoved', taskId, formId, title, icon);
1906
+ dom.clearWatchStyle(formId);
1907
+ dom.clearWatchProperty(formId);
1908
+ native.clear(formId, taskId);
1863
1909
  // --- 检测是否已经没有窗体了,如果没有了的话就要结束任务了 ---
1864
1910
  if (Object.keys(task.list[taskId].forms).length === 0) {
1865
1911
  task.end(taskId);
@@ -1912,6 +1958,7 @@ export async function create(opt: types.IFormCreateOptions): Promise<number> {
1912
1958
  }
1913
1959
  // --- 准备相关变量 ---
1914
1960
  let data: Record<string, any> = {};
1961
+ let access: Record<string, any> = {};
1915
1962
  let methods: Record<string, any> | undefined = undefined;
1916
1963
  let computed: Record<string, any> = {};
1917
1964
  let beforeCreate: (() => void) | undefined = undefined;
@@ -1924,6 +1971,7 @@ export async function create(opt: types.IFormCreateOptions): Promise<number> {
1924
1971
  let unmounted: (() => void) | undefined = undefined;
1925
1972
  if (opt.code) {
1926
1973
  data = opt.code.data ?? {};
1974
+ access = opt.code.access ?? {};
1927
1975
  methods = opt.code.methods;
1928
1976
  computed = opt.code.computed ?? {};
1929
1977
  beforeCreate = opt.code.beforeCreate;
@@ -1965,8 +2013,13 @@ export async function create(opt: types.IFormCreateOptions): Promise<number> {
1965
2013
  layout = layout.replace(/@(touchstart|touchmove|wheel)=/g, '@$1.passive=');
1966
2014
  layout = layout.replace(/@(touchstart|touchmove|wheel)\.not=/g, '@$1=');
1967
2015
  */
2016
+ // --- 给 teleport 做处理 ---
2017
+ if (layout.includes('<teleport')) {
2018
+ layout = tool.teleportGlue(layout, formId);
2019
+ }
1968
2020
  // --- 插入 HTML 到 Element ---
1969
2021
  elements.list.insertAdjacentHTML('beforeend', `<div class="cg-form-wrap" data-form-id="${formId.toString()}" data-task-id="${opt.taskId.toString()}"></div>`);
2022
+ elements.popList.insertAdjacentHTML('beforeend', `<div data-form-id="${formId.toString()}" data-task-id="${opt.taskId.toString()}"></div>`);
1970
2023
  // --- 获取刚才的 form wrap element 对象 ---
1971
2024
  const el: HTMLElement = elements.list.children.item(elements.list.children.length - 1) as HTMLElement;
1972
2025
  // --- 创建窗体对象 ---
@@ -2039,6 +2092,10 @@ export async function create(opt: types.IFormCreateOptions): Promise<number> {
2039
2092
  return;
2040
2093
  }
2041
2094
  };
2095
+ // --- 判断是否要与 native 实体窗体大小同步 ---
2096
+ if (clickgo.isNative() && (formId === 1) && !clickgo.isImmersion() && !clickgo.hasFrame()) {
2097
+ data.isNativeSync = true;
2098
+ }
2042
2099
  // --- 挂载 style ---
2043
2100
  if (style) {
2044
2101
  // --- 窗体的 style ---
@@ -2058,7 +2115,10 @@ export async function create(opt: types.IFormCreateOptions): Promise<number> {
2058
2115
  'computed': computed,
2059
2116
 
2060
2117
  'beforeCreate': beforeCreate,
2061
- 'created': created,
2118
+ 'created': function(this: types.IVue) {
2119
+ this.access = tool.clone(access);
2120
+ created?.call(this);
2121
+ },
2062
2122
  'beforeMount': beforeMount,
2063
2123
  'mounted': async function(this: types.IVue) {
2064
2124
  await this.$nextTick();
@@ -2122,21 +2182,36 @@ export async function create(opt: types.IFormCreateOptions): Promise<number> {
2122
2182
  await mounted.call(rtn.vroot, opt.data);
2123
2183
  }
2124
2184
  catch (err: any) {
2185
+ // --- 窗体创建失败,做垃圾回收 ---
2125
2186
  core.trigger('error', rtn.vroot.taskId, rtn.vroot.formId, err, 'Create form mounted error.');
2126
- t.forms[formId] = undefined as any;
2127
2187
  delete t.forms[formId];
2128
- rtn.vapp.unmount();
2188
+ try {
2189
+ rtn.vapp.unmount();
2190
+ }
2191
+ catch (err: any) {
2192
+ const msg = `Message: ${err.message}\nTask id: ${opt.taskId}\nForm id: ${formId}\nFunction: form.create, unmount.`;
2193
+ notify({
2194
+ 'title': 'Form Unmount Error',
2195
+ 'content': msg,
2196
+ 'type': 'danger'
2197
+ });
2198
+ console.log('Form Unmount Error', msg, err);
2199
+ }
2129
2200
  rtn.vapp._container.remove();
2201
+ elements.popList.querySelector('[data-form-id="' + rtn.vroot.formId + '"]')?.remove();
2202
+ dom.clearWatchStyle(rtn.vroot.formId);
2203
+ dom.clearWatchProperty(rtn.vroot.formId);
2204
+ native.clear(formId, t.id);
2205
+ // --- 移除 style ---
2130
2206
  dom.removeStyle(rtn.vroot.taskId, 'form', rtn.vroot.formId);
2131
2207
  return -8;
2132
2208
  }
2133
2209
  }
2134
2210
  // --- 触发 formCreated 事件 ---
2135
2211
  core.trigger('formCreated', opt.taskId, formId, rtn.vroot.$refs.form.title, rtn.vroot.$refs.form.iconDataUrl);
2136
- // --- 判断是否要与 native 实体窗体大小同步 ---
2137
- if (clickgo.isNative() && (formId === 1) && !clickgo.isImmersion() && !clickgo.hasFrame()) {
2138
- rtn.vroot.$refs.form.isNativeSync = true;
2139
- native.invoke('cg-set-size', native.getToken(), rtn.vroot.$refs.form.$el.offsetWidth, rtn.vroot.$refs.form.$el.offsetHeight);
2212
+ // --- 同步的窗体先进行同步一下 ---
2213
+ if (rtn.vroot.isNativeSync) {
2214
+ await native.invoke('cg-set-size', native.getToken(), rtn.vroot.$refs.form.$el.offsetWidth, rtn.vroot.$refs.form.$el.offsetHeight);
2140
2215
  window.addEventListener('resize', function(): void {
2141
2216
  rtn.vroot.$refs.form.setPropData('width', window.innerWidth);
2142
2217
  rtn.vroot.$refs.form.setPropData('height', window.innerHeight);
@@ -2192,7 +2267,7 @@ export function dialog(opt: string | types.IFormDialogOptions): Promise<string>
2192
2267
  }
2193
2268
  }
2194
2269
  };
2195
- cls.create(undefined, `<form title="${nopt.title ?? 'dialog'}" min="false" max="false" resize="false" height="0" border="${nopt.title ? 'normal' : 'plain'}" direction="v"><dialog :buttons="buttons" @select="select"${nopt.direction ? ` direction="${nopt.direction}"` : ''}>${nopt.content}</dialog></form>`).then((frm) => {
2270
+ cls.create(undefined, `<form title="${nopt.title ?? 'dialog'}" min="false" max="false" resize="false" height="0" width="0" border="${nopt.title ? 'normal' : 'plain'}" direction="v"><dialog :buttons="buttons" @select="select"${nopt.direction ? ` direction="${nopt.direction}"` : ''}>${nopt.content}</dialog></form>`).then((frm) => {
2196
2271
  if (typeof frm === 'number') {
2197
2272
  resolve('');
2198
2273
  return;