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/core.ts CHANGED
@@ -19,10 +19,7 @@ import * as fs from './fs';
19
19
  import * as form from './form';
20
20
  import * as task from './task';
21
21
  import * as tool from './tool';
22
- import * as control from './control';
23
- import * as theme from './theme';
24
22
  import * as zip from './zip';
25
- import * as dom from './dom';
26
23
 
27
24
  /** --- Config 原始参考对象 --- */
28
25
  const configOrigin: types.IConfig = {
@@ -72,153 +69,6 @@ export abstract class AbstractApp {
72
69
  /** --- App 的入口文件 --- */
73
70
  public abstract main(): Promise<void>;
74
71
 
75
- /**
76
- * --- 先设置 App 的配置信息 ---
77
- * @param config 配置对象
78
- */
79
- public async config(config: types.IAppConfig): Promise<boolean> {
80
- const t = task.list[this.taskId];
81
- if (!t) {
82
- return false;
83
- }
84
- t.config = config;
85
- // --- 加载余下的 xml 等静态包内资源,仅限 net 的 app 模式 ---
86
- if (t.app.net) {
87
- if (!t.config.files) {
88
- return false;
89
- }
90
- const files = t.config.files;
91
- const net = t.app.net;
92
- await new Promise<void>(function(resolve) {
93
- let loaded = 0;
94
- const total = files.length;
95
- const beforeTotal = Object.keys(t.app.files).length;
96
- net.progress?.(loaded + beforeTotal, total + beforeTotal) as unknown;
97
- for (const file of files) {
98
- fs.getContent(net.url + file.slice(1), {
99
- 'current': net.current
100
- }).then(async function(blob) {
101
- if (blob === null || typeof blob === 'string') {
102
- clickgo.form.notify({
103
- 'title': 'File not found',
104
- 'content': net.url + file.slice(1),
105
- 'type': 'danger'
106
- });
107
- return;
108
- }
109
- const mime = tool.getMimeByPath(file);
110
- if (['txt', 'json', 'js', 'css', 'xml', 'html'].includes(mime.ext)) {
111
- t.app.files[file] = (await tool.blob2Text(blob)).replace(/^\ufeff/, '');
112
- }
113
- else {
114
- t.app.files[file] = blob;
115
- }
116
- ++loaded;
117
- net.progress?.(loaded + beforeTotal, total + beforeTotal) as unknown;
118
- if (net.notify) {
119
- form.notifyProgress(net.notify, (loaded / total) / 2 + 0.5);
120
- }
121
- if (loaded < total) {
122
- return;
123
- }
124
- resolve();
125
- }).catch(function() {
126
- ++loaded;
127
- net.progress?.(loaded + beforeTotal, total + beforeTotal) as unknown;
128
- if (net.notify) {
129
- form.notifyProgress(net.notify, (loaded / total) / 2 + 0.5);
130
- }
131
- if (loaded < total) {
132
- return;
133
- }
134
- resolve();
135
- });
136
- }
137
- });
138
- if (net.notify) {
139
- setTimeout(function(): void {
140
- form.hideNotify(net.notify!);
141
- }, 2000);
142
- }
143
- }
144
- // --- 要加载 control ---
145
- if (!await control.init(this.taskId)) {
146
- return false;
147
- }
148
- // --- theme ---
149
- if (config.themes?.length) {
150
- for (let path of config.themes) {
151
- path += '.cgt';
152
- path = tool.urlResolve('/', path);
153
- const file = await fs.getContent(path, {
154
- 'files': t.app.files,
155
- 'current': t.current
156
- });
157
- if (file && typeof file !== 'string') {
158
- const th = await theme.read(file);
159
- if (th) {
160
- await theme.load(th, t.id);
161
- }
162
- }
163
- }
164
- }
165
- else {
166
- // --- 加载全局主题 ---
167
- if (theme.global) {
168
- await theme.load(undefined, this.taskId);
169
- }
170
- }
171
- // --- locale ---
172
- if (config.locales) {
173
- for (let path in config.locales) {
174
- const locale = config.locales[path];
175
- if (!path.endsWith('.json')) {
176
- path += '.json';
177
- }
178
- const lcontent = await fs.getContent(path, {
179
- 'encoding': 'utf8',
180
- 'files': t.app.files,
181
- 'current': t.current
182
- });
183
- if (!lcontent) {
184
- continue;
185
- }
186
- try {
187
- const data = JSON.parse(lcontent);
188
- task.loadLocaleData(locale, data, '', t.id);
189
- }
190
- catch {
191
- // --- 无所谓 ---
192
- }
193
- }
194
- }
195
- // --- 加载任务级全局样式 ---
196
- if (config.style) {
197
- const style = await fs.getContent(config.style + '.css', {
198
- 'encoding': 'utf8',
199
- 'files': t.app.files,
200
- 'current': t.current
201
- });
202
- if (style) {
203
- const r = tool.stylePrepend(style, 'cg-task' + this.taskId.toString() + '_');
204
- dom.pushStyle(this.taskId, await tool.styleUrl2DataUrl(config.style, r.style, t.app.files));
205
- }
206
- }
207
- // --- 加载图标 ---
208
- if (config.icon) {
209
- const icon = await fs.getContent(config.icon, {
210
- 'files': t.app.files,
211
- 'current': t.current
212
- });
213
- if (icon && typeof icon !== 'string') {
214
- t.app.icon = await tool.blob2DataUrl(icon);
215
- }
216
- }
217
- // --- 全部成功,设置 t.class 为自己 ---
218
- t.class = this;
219
- return true;
220
- }
221
-
222
72
  /**
223
73
  * --- 以某个窗体进行正式启动这个 app(入口 form),不启动则任务也启动失败 ---
224
74
  * @param form 窗体对象
@@ -329,6 +179,12 @@ export abstract class AbstractApp {
329
179
  return;
330
180
  }
331
181
 
182
+ /** --- location hash 改变事件 --- */
183
+ public onHashChanged(hash: string): void | Promise<void>;
184
+ public onHashChanged(): void {
185
+ return;
186
+ }
187
+
332
188
  }
333
189
 
334
190
  /** --- CDN 地址 --- */
@@ -392,7 +248,12 @@ clickgo.vue.watch(config, function() {
392
248
  });
393
249
 
394
250
  /** --- module 列表 --- */
395
- const modules: Record<string, { func: () => any | Promise<any>; 'obj': null | any; 'loading': boolean; }> = {
251
+ const modules: Record<string, {
252
+ func: () => any | Promise<any>;
253
+ 'obj': null | any;
254
+ 'loading': boolean;
255
+ 'resolve': Array<() => void | Promise<void>>;
256
+ }> = {
396
257
  'monaco': {
397
258
  func: async function() {
398
259
  return new Promise(function(resolve, reject) {
@@ -408,7 +269,8 @@ const modules: Record<string, { func: () => any | Promise<any>; 'obj': null | an
408
269
  });
409
270
  },
410
271
  'obj': null,
411
- 'loading': false
272
+ 'loading': false,
273
+ 'resolve': []
412
274
  }
413
275
  };
414
276
 
@@ -424,97 +286,61 @@ export function regModule(name: string, func: () => any | Promise<any>): boolean
424
286
  modules[name] = {
425
287
  func: func,
426
288
  'obj': null,
427
- 'loading': false
289
+ 'loading': false,
290
+ 'resolve': []
428
291
  };
429
292
  return true;
430
293
  }
431
294
 
432
295
  /**
433
- * --- 外接模块需要 init 后才能使用 ---
434
- * @param names 要加载的模块名
296
+ * --- 获取外接模块 ---
297
+ * @param name 模块名
435
298
  */
436
- export function initModules(names: string | string[]): Promise<number> {
437
- return new Promise(function(resolve) {
438
- if (typeof names === 'string') {
439
- names = [names];
440
- }
441
- if (names.length === 0) {
442
- resolve(0);
443
- return;
299
+ export function getModule(name: string): Promise<null | any> {
300
+ return new Promise((resolve) => {
301
+ if (!modules[name]) {
302
+ return null;
444
303
  }
445
- let loaded = 0;
446
- let successful = 0;
447
- for (const name of names) {
448
- if (!modules[name]) {
449
- ++loaded;
450
- if (loaded === names.length) {
451
- resolve(successful);
452
- return;
453
- }
454
- continue;
455
- }
456
- if (modules[name].obj) {
457
- ++loaded;
458
- ++successful;
459
- if (loaded === names.length) {
460
- resolve(successful);
461
- return;
462
- }
463
- continue;
464
- }
304
+ if (!modules[name].obj) {
305
+ // --- obj 是 null 判断是否要初始化 ---
465
306
  if (modules[name].loading) {
466
- ++loaded;
467
- if (loaded === names.length) {
468
- resolve(successful);
469
- return;
470
- }
471
- continue;
472
- }
473
- // --- 正式开始加载 init ---
474
- modules[name].loading = true;
475
- const rtn = modules[name].func();
476
- if (rtn instanceof Promise) {
477
- rtn.then(function(obj) {
478
- modules[name].obj = obj;
479
- modules[name].loading = false;
480
- ++loaded;
481
- ++successful;
482
- if (loaded === names.length) {
483
- resolve(successful);
484
- return;
485
- }
486
- }).catch(function() {
487
- modules[name].loading = false;
488
- ++loaded;
489
- if (loaded === names.length) {
490
- resolve(successful);
491
- }
307
+ // --- 加载中,等待 ---
308
+ modules[name].resolve.push(() => {
309
+ resolve(modules[name].obj);
492
310
  });
493
311
  }
494
312
  else {
495
- modules[name].obj = rtn;
496
- modules[name].loading = false;
497
- ++loaded;
498
- ++successful;
499
- if (loaded === names.length) {
500
- resolve(successful);
313
+ // --- 没加载,开始加载 ---
314
+ const rtn = modules[name].func();
315
+ if (rtn instanceof Promise) {
316
+ modules[name].loading = true;
317
+ rtn.then(function(obj) {
318
+ modules[name].obj = obj;
319
+ modules[name].loading = false;
320
+ resolve(obj);
321
+ for (const r of modules[name].resolve) {
322
+ r() as any;
323
+ }
324
+ }).catch(function() {
325
+ modules[name].loading = false;
326
+ resolve(null);
327
+ for (const r of modules[name].resolve) {
328
+ r() as any;
329
+ }
330
+ });
331
+ }
332
+ else {
333
+ modules[name].obj = rtn;
334
+ resolve(rtn);
501
335
  }
502
336
  }
337
+ return;
503
338
  }
339
+ resolve(modules[name].obj);
340
+ return;
504
341
  });
505
342
  }
506
343
 
507
- /**
508
- * --- 获取外接模块 ---
509
- * @param name 模块名
510
- */
511
- export function getModule(name: string): null | any {
512
- if (!modules[name]) {
513
- return null;
514
- }
515
- return modules[name].obj;
516
- }
517
-
518
344
  /** --- 系统要处理的全局响应事件 --- */
519
345
  const globalEvents = {
520
346
  screenResize: function(): void {
@@ -678,7 +504,7 @@ export function trigger(name: types.TGlobalEvent, taskId: number | string | bool
678
504
  if (typeof formId !== 'string') {
679
505
  break;
680
506
  }
681
- if (typeof taskId === 'number') {
507
+ if (typeof taskId !== 'string') {
682
508
  taskId = taskId.toString();
683
509
  }
684
510
  (boot as any)[eventName](taskId, formId);
@@ -691,6 +517,20 @@ export function trigger(name: types.TGlobalEvent, taskId: number | string | bool
691
517
  }
692
518
  break;
693
519
  }
520
+ case 'hashChanged': {
521
+ if (typeof taskId !== 'string') {
522
+ break;
523
+ }
524
+ (boot as any)[eventName](taskId);
525
+ for (const tid in task.list) {
526
+ const t = task.list[tid];
527
+ (t.class as any)?.[eventName](taskId);
528
+ for (const fid in t.forms) {
529
+ t.forms[fid].vroot[eventName]?.(taskId);
530
+ }
531
+ }
532
+ break;
533
+ }
694
534
  }
695
535
  }
696
536
 
@@ -707,6 +547,13 @@ export async function readApp(blob: Blob): Promise<false | types.IApp> {
707
547
  }
708
548
  // --- 开始读取文件 ---
709
549
  const files: Record<string, Blob | string> = {};
550
+ /** --- 配置文件 --- */
551
+ const configContent = await z.getContent('/config.json');
552
+ if (!configContent) {
553
+ return false;
554
+ }
555
+ const config: types.IAppConfig = JSON.parse(configContent);
556
+ // --- 读取包 ---
710
557
  const list = z.readDir('/', {
711
558
  'hasChildren': true
712
559
  });
@@ -730,8 +577,10 @@ export async function readApp(blob: Blob): Promise<false | types.IApp> {
730
577
  }
731
578
  }
732
579
  return {
733
- 'icon': icon,
734
- 'files': files
580
+ 'type': 'app',
581
+ 'config': config,
582
+ 'files': files,
583
+ 'icon': icon
735
584
  };
736
585
  }
737
586
 
@@ -798,53 +647,97 @@ export async function fetchApp(
798
647
  return null;
799
648
  }
800
649
  }
801
- // --- 从网络嗅探 ---
802
- let loaded = 0;
803
- let total = 30;
804
- // --- 网络嗅探,不知道文件总数,先暂定 30,不过超出 30 文件的建议打包为 cga ---
805
- const files = await loader.sniffFiles(url + 'app.js', {
806
- 'dir': '/',
807
- adapter: async (url) => {
808
- const r = await fs.getContent(url, {
809
- 'encoding': 'utf8',
810
- 'current': current
811
- });
812
- return r;
813
- },
814
- 'loaded': () => {
815
- ++loaded;
816
- if (loaded === total) {
817
- ++total;
818
- }
819
- if (opt.notifyId) {
820
- form.notifyProgress(opt.notifyId, (loaded / total) / 2);
650
+ // --- 从网络加载 app ---
651
+ let config: types.IAppConfig;
652
+ /** --- 已加载的 files --- */
653
+ const files: Record<string, Blob | string> = {};
654
+ try {
655
+ const blob = await fs.getContent(url + 'config.json', {
656
+ 'current': current
657
+ });
658
+ if (blob === null || typeof blob === 'string') {
659
+ return null;
660
+ }
661
+ config = JSON.parse(await tool.blob2Text(blob));
662
+ await new Promise<void>(function(resolve) {
663
+ if (!config.files) {
664
+ return;
821
665
  }
666
+ const total = config.files.length;
667
+ let loaded = 0;
822
668
  if (opt.progress) {
823
- opt.progress(loaded, total) as unknown;
669
+ opt.progress(loaded + 1, total + 1) as unknown;
670
+ }
671
+ for (const file of config.files) {
672
+ fs.getContent(url + file.slice(1), {
673
+ 'current': current
674
+ }).then(async function(blob) {
675
+ if (blob === null || typeof blob === 'string') {
676
+ clickgo.form.notify({
677
+ 'title': 'File not found',
678
+ 'content': url + file.slice(1),
679
+ 'type': 'danger'
680
+ });
681
+ return;
682
+ }
683
+ const mime = tool.getMimeByPath(file);
684
+ if (['txt', 'json', 'js', 'css', 'xml', 'html'].includes(mime.ext)) {
685
+ files[file] = (await tool.blob2Text(blob)).replace(/^\ufeff/, '');
686
+ }
687
+ else {
688
+ files[file] = blob;
689
+ }
690
+ ++loaded;
691
+ if (opt.notifyId) {
692
+ form.notifyProgress(opt.notifyId, loaded / total);
693
+ }
694
+ if (opt.progress) {
695
+ opt.progress(loaded + 1, total + 1) as unknown;
696
+ }
697
+ if (loaded < total) {
698
+ return;
699
+ }
700
+ resolve();
701
+ }).catch(function() {
702
+ ++loaded;
703
+ if (opt.notifyId) {
704
+ form.notifyProgress(opt.notifyId, loaded / total);
705
+ }
706
+ if (opt.progress) {
707
+ opt.progress(loaded + 1, total + 1) as unknown;
708
+ }
709
+ if (loaded < total) {
710
+ return;
711
+ }
712
+ resolve();
713
+ });
824
714
  }
825
- }
826
- });
827
- // --- net 模式此处加载完只算到 50%,因为还有 app 类当中 config 中的静态部分,暂定预留 50% ---
828
- if (opt.notifyId) {
829
- form.notifyProgress(opt.notifyId, 0.5);
715
+ });
830
716
  }
831
- if (Object.keys(files).length === 0) {
717
+ catch (e: any) {
718
+ console.log('core.fetchApp', e);
719
+ trigger('error', 0, 0, e, e.message);
832
720
  return null;
833
721
  }
834
- const ul = url.length - 1;
835
- for (const fn in files) {
836
- files[fn.slice(ul)] = files[fn];
837
- delete files[fn];
722
+
723
+ let icon = '';
724
+ if (config.icon && (files[config.icon] instanceof Blob)) {
725
+ icon = await tool.blob2DataUrl(files[config.icon] as Blob);
838
726
  }
727
+ if (icon === '') {
728
+ const iconBlob = await fs.getContent('/clickgo/icon.png', {
729
+ 'current': current
730
+ });
731
+ if (iconBlob instanceof Blob) {
732
+ icon = await tool.blob2DataUrl(iconBlob);
733
+ }
734
+ }
735
+
839
736
  return {
840
- 'net': {
841
- 'current': current,
842
- 'notify': opt.notifyId,
843
- 'url': url,
844
- 'progress': opt.progress
845
- },
846
- 'icon': '',
847
- 'files': files
737
+ 'type': 'app',
738
+ 'config': config,
739
+ 'files': files,
740
+ 'icon': icon
848
741
  };
849
742
  }
850
743
 
@@ -902,3 +795,27 @@ export function getAvailArea(): types.IAvailArea {
902
795
  };
903
796
  }
904
797
  }
798
+
799
+ /**
800
+ * --- 修改浏览器 hash ---
801
+ * @param hash 修改的值,不含 #
802
+ * @param taskId 基任务,App 模式下无效
803
+ */
804
+ export function hash(hash: string, taskId?: number): boolean {
805
+ if (!taskId) {
806
+ return false;
807
+ }
808
+ const t = task.list[taskId];
809
+ if (!t) {
810
+ return false;
811
+ }
812
+ if (!t.runtime.permissions.includes('root') && !t.runtime.permissions.includes('hash')) {
813
+ return false;
814
+ }
815
+ window.location.hash = hash;
816
+ return true;
817
+ }
818
+
819
+ window.addEventListener('hashchange', function() {
820
+ trigger('hashChanged', window.location.hash ? window.location.hash.slice(1) : '');
821
+ });