clickgo 3.16.16 → 3.16.18

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 (63) hide show
  1. package/README.md +1 -1
  2. package/dist/app/demo/form/method/native/native.js +26 -0
  3. package/dist/app/demo/form/method/native/native.xml +2 -0
  4. package/dist/clickgo.d.ts +17 -0
  5. package/dist/clickgo.js +1 -1
  6. package/dist/control/arteditor.cgc +0 -0
  7. package/dist/control/box.cgc +0 -0
  8. package/dist/control/captcha.cgc +0 -0
  9. package/dist/control/common.cgc +0 -0
  10. package/dist/control/desc.cgc +0 -0
  11. package/dist/control/drawer.cgc +0 -0
  12. package/dist/control/echarts.cgc +0 -0
  13. package/dist/control/form.cgc +0 -0
  14. package/dist/control/iconview.cgc +0 -0
  15. package/dist/control/jodit.cgc +0 -0
  16. package/dist/control/map.cgc +0 -0
  17. package/dist/control/monaco.cgc +0 -0
  18. package/dist/control/mpegts.cgc +0 -0
  19. package/dist/control/nav.cgc +0 -0
  20. package/dist/control/page.cgc +0 -0
  21. package/dist/control/pdf.cgc +0 -0
  22. package/dist/control/property.cgc +0 -0
  23. package/dist/control/qrcode.cgc +0 -0
  24. package/dist/control/table.cgc +0 -0
  25. package/dist/control/task.cgc +0 -0
  26. package/dist/control/tplink.cgc +0 -0
  27. package/dist/control/tuieditor.cgc +0 -0
  28. package/dist/control/tuiviewer.cgc +0 -0
  29. package/dist/control/xterm.cgc +0 -0
  30. package/dist/index.d.ts +51 -0
  31. package/dist/lib/control.d.ts +53 -0
  32. package/dist/lib/core.d.ts +47 -0
  33. package/dist/lib/dom.d.ts +74 -0
  34. package/dist/lib/dom.js +7 -7
  35. package/dist/lib/form.d.ts +222 -0
  36. package/dist/lib/fs.d.ts +35 -0
  37. package/dist/lib/fs.js +2 -2
  38. package/dist/lib/native.d.ts +36 -0
  39. package/dist/lib/native.js +8 -0
  40. package/dist/lib/storage.d.ts +6 -0
  41. package/dist/lib/task.d.ts +32 -0
  42. package/dist/lib/task.js +7 -1
  43. package/dist/lib/theme.d.ts +8 -0
  44. package/dist/lib/tool.d.ts +120 -0
  45. package/dist/lib/zip.d.ts +40 -0
  46. package/dist/theme/blue.cgt +0 -0
  47. package/dist/theme/byterun.cgt +0 -0
  48. package/dist/theme/light.cgt +0 -0
  49. package/package.json +7 -5
  50. package/dist/clickgo.ts +0 -68
  51. package/dist/index.ts +0 -282
  52. package/dist/lib/control.ts +0 -751
  53. package/dist/lib/core.ts +0 -1145
  54. package/dist/lib/dom.ts +0 -2728
  55. package/dist/lib/form.ts +0 -3829
  56. package/dist/lib/fs.ts +0 -1324
  57. package/dist/lib/native.ts +0 -236
  58. package/dist/lib/storage.ts +0 -229
  59. package/dist/lib/task.ts +0 -2160
  60. package/dist/lib/theme.ts +0 -199
  61. package/dist/lib/tool.ts +0 -1278
  62. package/dist/lib/zip.ts +0 -444
  63. package/eslint.config.js +0 -22
package/dist/lib/task.ts DELETED
@@ -1,2160 +0,0 @@
1
- /**
2
- * Copyright 2024 Han Guoshuai <zohegs@gmail.com>
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * https://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
- import * as types from '../../types';
17
- import * as clickgo from '../clickgo';
18
- import * as core from './core';
19
- import * as dom from './dom';
20
- import * as tool from './tool';
21
- import * as form from './form';
22
- import * as control from './control';
23
- import * as fs from './fs';
24
- import * as theme from './theme';
25
- import * as native from './native';
26
-
27
- /** --- 当前运行的程序,App 模式下无效 --- */
28
- export const list: Record<number, types.ITask> = {};
29
-
30
- /** --- 最后一个 task id,App 模式下无效 --- */
31
- export let lastId: number = 0;
32
-
33
- /** --- 当前有焦点的任务 ID --- */
34
- let focusId: number | null = null;
35
-
36
- /**
37
- * --- 设置 task focus id ---
38
- * @param id id 或 null
39
- */
40
- export function setFocus(id?: number): void {
41
- focusId = id ?? null;
42
- }
43
-
44
- /** --- 获取当前有焦点的任务 ID --- */
45
- export function getFocus(): number | null {
46
- return focusId;
47
- }
48
-
49
- /** --- task lib 用到的语言包 --- */
50
- const localeData: Record<string, {
51
- 'loading': string;
52
- }> = {
53
- 'en': {
54
- 'loading': 'Loading...',
55
- },
56
- 'sc': {
57
- 'loading': '加载中……'
58
- },
59
- 'tc': {
60
- 'loading': '載入中……'
61
- },
62
- 'ja': {
63
- 'loading': '読み込み中...'
64
- },
65
- 'ko': {
66
- 'loading': '로딩 중...'
67
- },
68
- 'th': {
69
- 'loading': 'กำลังโหลด...'
70
- },
71
- 'es': {
72
- 'loading': 'Cargando...'
73
- },
74
- 'de': {
75
- 'loading': 'Laden...'
76
- },
77
- 'fr': {
78
- 'loading': 'Chargement en cours...'
79
- },
80
- 'pt': {
81
- 'loading': 'Carregando...'
82
- },
83
- 'ru': {
84
- 'loading': 'Загрузка...'
85
- },
86
- 'vi': {
87
- 'loading': 'Đang tải...'
88
- }
89
- };
90
-
91
- // --- 创建 frame 监听 ---
92
- let frameTimer: number = 0;
93
- const frameMaps: Record<string, number> = {};
94
-
95
- /**
96
- * --- 创建 frame 监听,formId 存在则为窗体范围,否则为任务级范围 ---
97
- * @param fun 监听回调
98
- * @param opt 选项,count:执行次数,默认无限次,formId:限定在当前任务的某个窗体,taskId:APP模式下无效
99
- */
100
- export function onFrame(fun: () => void | Promise<void>, opt: {
101
- 'count'?: number;
102
- 'taskId'?: number;
103
- 'formId'?: number;
104
- } = {}): number {
105
- const taskId = opt.taskId;
106
- const formId = opt.formId;
107
- if (!taskId) {
108
- return 0;
109
- }
110
- const task = list[taskId];
111
- if (!task) {
112
- return 0;
113
- }
114
- if (formId && !task.forms[formId]) {
115
- return 0;
116
- }
117
- const ft = ++frameTimer;
118
- /** --- 执行几次,0 代表无限次 --- */
119
- const count = opt.count ?? 0;
120
- /** --- 当前已经执行的次数 --- */
121
- let c: number = 0;
122
- let timer: number;
123
- const timerHandler = async (): Promise<void> => {
124
- ++c;
125
- if (formId && task.forms[formId] === undefined) {
126
- // --- form 已经没了 ---
127
- delete task.timers['1x' + ft.toString()];
128
- delete frameMaps[ft];
129
- return;
130
- }
131
- await fun();
132
- if (task.timers['1x' + ft.toString()] == undefined) {
133
- return;
134
- }
135
- if (count > 1) {
136
- if (c === count) {
137
- // --- 终止循环 ---
138
- delete task.timers['1x' + ft.toString()];
139
- delete frameMaps[ft];
140
- return;
141
- }
142
- else {
143
- // --- 接着循环 ---
144
- timer = requestAnimationFrame(function() {
145
- timerHandler().catch(function(e) {
146
- console.log('task.onFrame: -3', e);
147
- });
148
- });
149
- frameMaps[ft] = timer;
150
- }
151
- }
152
- else if (count === 1) {
153
- // --- 不循环 ---
154
- delete task.timers['1x' + ft.toString()];
155
- delete frameMaps[ft];
156
- }
157
- else {
158
- // --- 无限循环 ---
159
- timer = requestAnimationFrame(function() {
160
- timerHandler().catch(function(e) {
161
- console.log('task.onFrame: -2', e);
162
- });
163
- });
164
- frameMaps[ft] = timer;
165
- }
166
- };
167
- /** --- timer 对象 number --- */
168
- timer = requestAnimationFrame(function() {
169
- timerHandler().catch(function(e) {
170
- console.log('task.onFrame: -1', e);
171
- });
172
- });
173
- frameMaps[ft] = timer;
174
- task.timers['1x' + ft.toString()] = formId ?? 0;
175
- return ft;
176
- }
177
-
178
- /**
179
- * --- 移除 frame 监听 ---
180
- * @param ft 监听 ID
181
- * @param opt 选项,taskId:APP模式下无效
182
- */
183
- export function offFrame(ft: number, opt: {
184
- 'taskId'?: number;
185
- } = {}): void {
186
- const taskId = opt.taskId;
187
- if (!taskId) {
188
- return;
189
- }
190
- if (!list[taskId]) {
191
- return;
192
- }
193
- const formId = list[taskId].timers['1x' + ft.toString()];
194
- if (formId === undefined) {
195
- return;
196
- }
197
- cancelAnimationFrame(frameMaps[ft]);
198
- delete list[taskId].timers['1x' + ft.toString()];
199
- delete frameMaps[ft];
200
- }
201
-
202
- /**
203
- * --- 获取任务当前信息 ---
204
- * @param tid 任务 id
205
- */
206
- export function get(tid: number): types.ITaskInfo | null {
207
- if (list[tid] === undefined) {
208
- return null;
209
- }
210
- return {
211
- 'name': list[tid].app.config.name,
212
- 'locale': list[tid].locale.lang,
213
- 'customTheme': list[tid].customTheme,
214
- 'formCount': Object.keys(list[tid].forms).length,
215
- 'icon': list[tid].app.icon,
216
- 'path': list[tid].path,
217
- 'current': list[tid].current
218
- };
219
- }
220
-
221
- /**
222
- * --- 获取某个任务的已授权权限列表 ---
223
- * @param tid 任务 id
224
- */
225
- export function getPermissions(tid: number): string[] {
226
- if (list[tid] === undefined) {
227
- return [];
228
- }
229
- return tool.clone(list[tid].runtime.permissions);
230
- }
231
-
232
- /**
233
- * --- 获取 task list 的简略情况 ---
234
- */
235
- export function getList(): Record<string, types.ITaskInfo> {
236
- const rtn: Record<string, types.ITaskInfo> = {};
237
- for (const tid in list) {
238
- const item = list[tid];
239
- rtn[tid] = {
240
- 'name': item.app.config.name,
241
- 'locale': item.locale.lang,
242
- 'customTheme': item.customTheme,
243
- 'formCount': Object.keys(item.forms).length,
244
- 'icon': item.app.icon,
245
- 'path': item.path,
246
- 'current': item.current
247
- };
248
- }
249
- return rtn;
250
- }
251
-
252
- /**
253
- * --- 运行一个应用,cga 直接文件全部正常加载,url 则静态文件需要去 config 里加载 ---
254
- * @param url app 路径(以 / 为结尾的路径或以 .cga 结尾的文件),或 APP 包对象
255
- * @param opt 选项
256
- * @param ntid App 模式下无效
257
- */
258
- export async function run(url: string | types.IApp, opt: types.ITaskRunOptions = {}, ntid?: number): Promise<number> {
259
- let app: types.IApp | null = null;
260
- if (typeof url === 'string') {
261
- // --- 检测 url 是否合法 ---
262
- if (!url.endsWith('/') && !url.endsWith('.cga')) {
263
- return 0;
264
- }
265
- /** --- 要显示的应用图标 --- */
266
- let icon = __dirname + '/../icon.png';
267
- if (opt.icon) {
268
- icon = opt.icon;
269
- }
270
- if (opt.notify === undefined) {
271
- opt.notify = true;
272
- }
273
- const notifyId: number | undefined = opt.notify ? form.notify({
274
- 'title': localeData[core.config.locale]?.loading ?? localeData['en'].loading,
275
- 'content': url,
276
- 'icon': icon,
277
- 'timeout': 0,
278
- 'progress': true
279
- }) : undefined;
280
- // --- 非 ntid 模式下 current 以 location 为准 ---
281
- if (!ntid &&
282
- !url.startsWith('/clickgo/') &&
283
- !url.startsWith('/storage/') &&
284
- !url.startsWith('/mounted/') &&
285
- !url.startsWith('/package/') &&
286
- !url.startsWith('/current/')
287
- ) {
288
- url = tool.urlResolve(location.href, url);
289
- }
290
- // --- 获取并加载 app 对象 ---
291
- app = await core.fetchApp(url, {
292
- 'notifyId': notifyId,
293
- 'progress': opt.progress,
294
- 'cache': opt.cache
295
- }, ntid);
296
- // --- 无论是否成功,都可以先隐藏 notify 了 ---
297
- if (notifyId) {
298
- setTimeout(function(): void {
299
- form.hideNotify(notifyId);
300
- }, 3000);
301
- }
302
- }
303
- else if (url.type !== 'app') {
304
- return -1;
305
- }
306
- else {
307
- app = url;
308
- }
309
- if (!app) {
310
- return -1;
311
- }
312
- // --- 申请任务ID ---
313
- const taskId = ++lastId;
314
- // --- 注入的参数,屏蔽一些全局对象 ---
315
- const blocks = ['document', 'localStorage'];
316
- /** --- 最终注入的对象 --- */
317
- const invoke: Record<string, any> = {};
318
- const ks = Object.getOwnPropertyNames(window);
319
- invoke.window = {};
320
- for (const k of ks) {
321
- if (blocks.includes(k)) {
322
- continue;
323
- }
324
- invoke.window[k] = (window as Record<string, any>)[k];
325
- }
326
- for (const block of blocks) {
327
- invoke[block] = undefined;
328
- }
329
- // --- console ---
330
- invoke.console = {
331
- assert: function(condition?: boolean, ...data: any[]): void {
332
- console.assert(condition, ...data);
333
- },
334
- clear: function(): void {
335
- console.clear();
336
- },
337
- count: function(label?: string): void {
338
- console.count(label);
339
- },
340
- countReset: function(label?: string): void {
341
- console.countReset(label);
342
- },
343
- debug: function(...data: any[]): void {
344
- console.debug(...data);
345
- },
346
- dir: function(item?: any, options?: any): void {
347
- console.dir(item, options);
348
- },
349
- dirxml: function(...data: any[]): void {
350
- console.dirxml(...data);
351
- },
352
- error: function(...data: any[]): void {
353
- console.error(...data);
354
- },
355
- group: function(...data: any[]): void {
356
- console.group(...data);
357
- },
358
- groupCollapsed: function(...data: any[]): void {
359
- console.groupCollapsed(...data);
360
- },
361
- groupEnd: function(): void {
362
- console.groupEnd();
363
- },
364
- info: function(...data: any[]): void {
365
- console.info(...data);
366
- },
367
- log: function(...data: any[]): void {
368
- console.log(...data);
369
- },
370
- table: function(tabularData?: any, properties?: string[]): void {
371
- console.table(tabularData, properties);
372
- },
373
- time: function(label?: string): void {
374
- console.time(label);
375
- },
376
- timeEnd: function(label?: string): void {
377
- console.timeEnd(label);
378
- },
379
- timeLog: function(label?: string, ...data: any[]): void {
380
- console.timeLog(label, ...data);
381
- },
382
- timeStamp: function(label?: string): void {
383
- console.timeStamp(label);
384
- },
385
- trace: function(...data: any[]): void {
386
- console.trace(...data);
387
- },
388
- warn: function(...data: any[]): void {
389
- console.warn(...data);
390
- }
391
- };
392
- // --- loader ---
393
- invoke.loader = {
394
- require: function(paths: string | string[], files: Record<string, Blob | string>, opt?: {
395
- 'executed'?: Record<string, any>;
396
- 'map'?: Record<string, string>;
397
- 'dir'?: string;
398
- 'style'?: string;
399
- 'invoke'?: Record<string, any>;
400
- 'preprocess'?: (code: string, path: string) => string;
401
- }): any[] {
402
- return loader.require(paths, files, opt);
403
- }
404
- };
405
- // --- ClickGo 相关 ---
406
- invoke.invokeClickgo = {
407
- getVersion: function(): string {
408
- return clickgo.getVersion();
409
- },
410
- isNative(): boolean {
411
- return clickgo.isNative();
412
- },
413
- getPlatform(): string {
414
- return clickgo.getPlatform();
415
- },
416
- isImmersion(): boolean {
417
- return clickgo.isImmersion();
418
- },
419
- hasFrame(): boolean {
420
- return clickgo.hasFrame();
421
- },
422
- 'control': {
423
- 'AbstractControl': class extends control.AbstractControl {
424
- public get taskId(): number {
425
- return taskId;
426
- }
427
- },
428
- read: function(blob: Blob): Promise<false | types.TControlPackage> {
429
- return control.read(blob);
430
- }
431
- },
432
- 'core': {
433
- 'config': clickgo.core.config,
434
- 'global': clickgo.tool.clone(clickgo.core.global),
435
- 'AbstractApp': class extends core.AbstractApp {
436
- // eslint-disable-next-line @typescript-eslint/require-await
437
- public async main(): Promise<void> {
438
- return;
439
- }
440
-
441
- public get taskId(): number {
442
- return taskId;
443
- }
444
- },
445
- getCdn: function() {
446
- return core.getCdn();
447
- },
448
- getModule: function(name: string): null | any {
449
- return core.getModule(name);
450
- },
451
- readApp: function(blob: Blob): Promise<false | types.IApp> {
452
- return core.readApp(blob);
453
- },
454
- getAvailArea: function(): types.IAvailArea {
455
- return core.getAvailArea();
456
- },
457
- hash: function(hash: string): boolean {
458
- return core.hash(hash, taskId);
459
- },
460
- getHash: function(): string {
461
- return core.getHash();
462
- },
463
- getHost: function(): string {
464
- return core.getHost();
465
- },
466
- location: function(url: string): boolean {
467
- return core.location(url, taskId);
468
- },
469
- getLocation: function(): string {
470
- return core.getLocation();
471
- },
472
- back: function(): boolean {
473
- return core.back(taskId);
474
- },
475
- open: function(url: string): void {
476
- core.open(url);
477
- }
478
- },
479
- 'dom': {
480
- inPage: function(el: HTMLElement): boolean {
481
- return dom.inPage(el);
482
- },
483
- 'dpi': dom.dpi,
484
- setGlobalCursor: function(type?: string): void {
485
- dom.setGlobalCursor(type);
486
- },
487
- hasTouchButMouse: function(e: MouseEvent | TouchEvent | PointerEvent): boolean {
488
- return dom.hasTouchButMouse(e);
489
- },
490
- getStyleCount: function(taskId: number, type: 'theme' | 'control' | 'form'): number {
491
- return dom.getStyleCount(taskId, type);
492
- },
493
- watchPosition: function(el: HTMLElement, cb: (tate: {
494
- 'position': boolean;
495
- 'size': boolean;
496
- }) => void | Promise<void>, immediate: boolean = false
497
- ): boolean {
498
- return dom.watchPosition(el, cb, immediate);
499
- },
500
- unwatchPosition: function(el: HTMLElement): void {
501
- dom.unwatchPosition(el);
502
- },
503
- isWatchPosition: function(el: HTMLElement): boolean {
504
- return dom.isWatchPosition(el);
505
- },
506
- getWatchSizeCount: function(taskId?: number): number {
507
- return dom.getWatchSizeCount(taskId);
508
- },
509
- watchSize: function(
510
- el: HTMLElement,
511
- cb: () => void | Promise<void>,
512
- immediate: boolean = false
513
- ): boolean {
514
- return dom.watchSize(el, cb, immediate, taskId);
515
- },
516
- unwatchSize: function(el: HTMLElement): void {
517
- dom.unwatchSize(el, taskId);
518
- },
519
- isWatchSize: function(el: HTMLElement): boolean {
520
- return dom.isWatchSize(el);
521
- },
522
- getWatchCount: function(taskId?: number): number {
523
- return dom.getWatchCount(taskId);
524
- },
525
- watch: function(el: HTMLElement, cb: (mutations: MutationRecord[]) => void | Promise<void>, mode: 'child' | 'childsub' | 'style' | 'default' = 'default', immediate: boolean = false): void {
526
- dom.watch(el, cb, mode, immediate, taskId);
527
- },
528
- unwatch: function(el: HTMLElement): void {
529
- dom.unwatch(el, taskId);
530
- },
531
- isWatch(el: HTMLElement): boolean {
532
- return dom.isWatch(el);
533
- },
534
- watchStyle: function(
535
- el: HTMLElement,
536
- name: string | string[],
537
- cb: (name: string, value: string, old: string) => void | Promise<void>,
538
- immediate: boolean = false
539
- ): void {
540
- dom.watchStyle(el, name, cb, immediate);
541
- },
542
- isWatchStyle: function(el: HTMLElement): boolean {
543
- return dom.isWatchStyle(el);
544
- },
545
- watchProperty: function(
546
- el: HTMLElement,
547
- name: string | string[],
548
- cb: (name: string, value: any) => void | Promise<void>,
549
- immediate: boolean = false
550
- ): void {
551
- dom.watchProperty(el, name, cb, immediate);
552
- },
553
- isWatchProperty(el: HTMLElement): boolean {
554
- return dom.isWatchProperty(el);
555
- },
556
- getWatchInfo: function(): types.IGetWatchInfoResult {
557
- return dom.getWatchInfo();
558
- },
559
- bindClick: function(
560
- e: MouseEvent | TouchEvent,
561
- handler: (e: MouseEvent | TouchEvent, x: number, y: number) => void | Promise<void>
562
- ): void {
563
- dom.bindClick(e, handler);
564
- },
565
- bindDblClick: function(
566
- e: MouseEvent | TouchEvent,
567
- handler: (e: MouseEvent | TouchEvent) => void | Promise<void>
568
- ): void {
569
- dom.bindDblClick(e, handler);
570
- },
571
- bindDown: function<T extends MouseEvent | TouchEvent>(oe: T, opt: types.IBindDownOptions<T>) {
572
- dom.bindDown(oe, opt);
573
- },
574
- bindScale: function(oe: MouseEvent | TouchEvent | WheelEvent, handler: (e: MouseEvent | TouchEvent | WheelEvent, scale: number, cpos: { 'x': number; 'y': number; }) => void | Promise<void>): void {
575
- dom.bindScale(oe, handler);
576
- },
577
- bindGesture: function(oe: MouseEvent | TouchEvent | WheelEvent, before: (e: MouseEvent | TouchEvent | WheelEvent, dir: 'top' | 'right' | 'bottom' | 'left') => number, handler: (dir: 'top' | 'right' | 'bottom' | 'left') => void): void {
578
- dom.bindGesture(oe, before, handler);
579
- },
580
- bindLong: function(
581
- e: MouseEvent | TouchEvent,
582
- long: (e: MouseEvent | TouchEvent) => void | Promise<void>
583
- ): void {
584
- dom.bindLong(e, long);
585
- },
586
- setDragData(data?: string | number | boolean | Record<string, any>): void {
587
- dom.setDragData(data);
588
- },
589
- bindDrag: function(e: MouseEvent | TouchEvent, opt: {
590
- 'el': HTMLElement;
591
- 'data'?: any;
592
-
593
- 'start'?: (x: number, y: number) => any;
594
- 'move'?: (e: MouseEvent | TouchEvent, opt: types.IBindMoveMoveOptions) => void;
595
- 'end'?: (moveTimes: Array<{ 'time': number; 'ox': number; 'oy': number; }>, e: MouseEvent | TouchEvent) => void;
596
- }): void {
597
- dom.bindDrag(e, opt);
598
- },
599
- 'is': dom.is,
600
- bindMove: function(e: MouseEvent | TouchEvent, opt: types.IBindMoveOptions): types.IBindMoveResult {
601
- return dom.bindMove(e, opt);
602
- },
603
- bindResize: function(e: MouseEvent | TouchEvent, opt: types.IBindResizeOptions): void {
604
- dom.bindResize(e, opt);
605
- },
606
- findParentByData: function(el: HTMLElement, name: string, value?: string): HTMLElement | null {
607
- return dom.findParentByData(el, name, value);
608
- },
609
- findParentByClass: function(el: HTMLElement, name: string): HTMLElement | null {
610
- return dom.findParentByClass(el, name);
611
- },
612
- findParentByTag: function(el: HTMLElement, name: string): HTMLElement | null {
613
- return dom.findParentByTag(el, name);
614
- },
615
- index: function(el: HTMLElement): number {
616
- return dom.index(el);
617
- },
618
- siblings: function(el: HTMLElement): HTMLElement[] {
619
- return dom.siblings(el);
620
- },
621
- siblingsData: function(el: HTMLElement, name: string): HTMLElement[] {
622
- return dom.siblingsData(el, name);
623
- },
624
- fullscreen: function() {
625
- return dom.fullscreen();
626
- },
627
- exitFullscreen: function() {
628
- return dom.exitFullscreen();
629
- },
630
- createElement: function<T extends keyof HTMLElementTagNameMap>(tagName: T): HTMLElementTagNameMap[T] {
631
- return dom.createElement(tagName);
632
- }
633
- },
634
- 'form': {
635
- 'AbstractPanel': class extends form.AbstractPanel {
636
- public get taskId(): number {
637
- return taskId;
638
- }
639
- },
640
- 'AbstractForm': class extends form.AbstractForm {
641
- public get taskId(): number {
642
- return taskId;
643
- }
644
- },
645
- min: function(fid: number): boolean {
646
- return form.min(fid);
647
- },
648
- max: function max(fid: number): boolean {
649
- return form.max(fid);
650
- },
651
- close: function(fid: number): boolean {
652
- return form.close(fid);
653
- },
654
- bindResize: function(e: MouseEvent | TouchEvent, border: types.TDomBorder): void {
655
- form.bindResize(e, border);
656
- },
657
- bindDrag: function(e: MouseEvent | TouchEvent): void {
658
- form.bindDrag(e);
659
- },
660
- getTaskId: function(fid: number): number {
661
- return form.getTaskId(fid);
662
- },
663
- get: function(fid: number): types.IFormInfo | null {
664
- return form.get(fid);
665
- },
666
- getList: function(tid: number): Record<string, types.IFormInfo> {
667
- return form.getList(tid);
668
- },
669
- getFocus: function(): number | null {
670
- return form.getFocus();
671
- },
672
- getActivePanel: function(formId: number): number[] {
673
- return form.getActivePanel(formId);
674
- },
675
- removeActivePanel: function(panelId: number, formId: number): boolean {
676
- return form.removeActivePanel(panelId, formId, taskId);
677
- },
678
- setActivePanel: function(panelId: number, formId: number): boolean {
679
- return form.setActivePanel(panelId, formId, taskId);
680
- },
681
- hash: function(hash: string, formId: number): boolean {
682
- return form.hash(hash, formId);
683
- },
684
- getHash: function(formId: number): string {
685
- return form.getHash(formId);
686
- },
687
- hashBack: function(formId: number): Promise<boolean> {
688
- return form.hashBack(formId);
689
- },
690
- changeFocus: function(fid: number = 0): void {
691
- form.changeFocus(fid);
692
- },
693
- getMaxZIndexID: function(out?: {
694
- 'taskIds'?: number[];
695
- 'formIds'?: number[];
696
- }): number | null {
697
- return form.getMaxZIndexID(out);
698
- },
699
- getRectByBorder: function(border: types.TDomBorder): { 'width': number; 'height': number; 'left': number; 'top': number; } {
700
- return form.getRectByBorder(border);
701
- },
702
- showCircular: function(x: number, y: number): void {
703
- form.showCircular(x, y);
704
- },
705
- moveRectangle: function(border: types.TDomBorder): void {
706
- form.moveRectangle(border);
707
- },
708
- showRectangle: function(x: number, y: number, border: types.TDomBorder): void {
709
- form.showRectangle(x, y, border);
710
- },
711
- hideRectangle: function(): void {
712
- form.hideRectangle();
713
- },
714
- showDrag: function(): void {
715
- form.showDrag();
716
- },
717
- moveDrag: function(opt: types.IMoveDragOptions): void {
718
- form.moveDrag(opt);
719
- },
720
- hideDrag: function(): void {
721
- form.hideDrag();
722
- },
723
- alert: function(content: string, type?: 'default' | 'primary' | 'info' | 'warning' | 'danger'): number {
724
- return form.alert(content, type);
725
- },
726
- notify: function(opt: types.INotifyOptions): number {
727
- return form.notify(opt);
728
- },
729
- notifyProgress: function(notifyId: number, per: number): void {
730
- form.notifyProgress(notifyId, per);
731
- },
732
- notifyContent: function(notifyId: number, opt: types.INotifyContentOptions): void {
733
- form.notifyContent(notifyId, opt);
734
- },
735
- hideNotify: function(notifyId: number): void {
736
- form.hideNotify(notifyId);
737
- },
738
- showPop: function(el: HTMLElement, pop: HTMLElement | undefined, direction: 'h' | 'v' | 't' | MouseEvent | TouchEvent | { x: number; y: number; }, opt: {
739
- 'size'?: { width?: number; height?: number; };
740
- 'null'?: boolean;
741
- 'autoPosition'?: boolean;
742
- 'autoScroll'?: boolean;
743
- 'flow'?: boolean;
744
- 'way'?: 'normal' | 'click' | 'hover';
745
- } = {}): void {
746
- form.showPop(el, pop, direction, opt);
747
- },
748
- hidePop: function(pop?: HTMLElement): void {
749
- form.hidePop(pop);
750
- },
751
- isJustPop: function(el: HTMLElement): boolean {
752
- return form.isJustPop(el);
753
- },
754
- doFocusAndPopEvent: function(e: MouseEvent | TouchEvent): void {
755
- form.doFocusAndPopEvent(e);
756
- },
757
- removePanel(id: number, vapp: types.IVApp, el: HTMLElement): boolean {
758
- return form.removePanel(id, vapp, el);
759
- },
760
- createPanel<T extends form.AbstractPanel>(
761
- rootPanel: control.AbstractControl,
762
- cls: string | (new () => T),
763
- opt?: {
764
- 'layout'?: string;
765
- 'style'?: string;
766
- 'path'?: string;
767
- }
768
- ): Promise<{
769
- 'vapp': types.IVApp;
770
- 'vroot': T;
771
- }> {
772
- return form.createPanel(rootPanel, cls, opt, taskId);
773
- },
774
- create: function<T extends form.AbstractForm>(
775
- cls: string | (new () => T),
776
- data?: Record<string, any>,
777
- opt?: {
778
- 'layout'?: string;
779
- 'style'?: string;
780
- 'path'?: string;
781
- }
782
- ): Promise<T> {
783
- return form.create(cls, data, opt, taskId);
784
- },
785
- dialog: function(opt: string | types.IFormDialogOptions): Promise<string> {
786
- if (typeof opt === 'string') {
787
- opt = {
788
- 'content': opt
789
- };
790
- }
791
- opt.taskId = taskId;
792
- return form.dialog(opt);
793
- },
794
- confirm: function(opt: string | types.IFormConfirmOptions): Promise<boolean | number> {
795
- if (typeof opt === 'string') {
796
- opt = {
797
- 'content': opt
798
- };
799
- }
800
- opt.taskId = taskId;
801
- return form.confirm(opt);
802
- },
803
- prompt: function(opt: string | types.IFormPromptOptions): Promise<string> {
804
- if (typeof opt === 'string') {
805
- opt = {
806
- 'content': opt
807
- };
808
- }
809
- opt.taskId = taskId;
810
- return form.prompt(opt);
811
- },
812
- flash: function(fid: number): void {
813
- form.flash(fid, taskId);
814
- },
815
- showLauncher: function(): void {
816
- form.showLauncher();
817
- },
818
- hideLauncher: function(): void {
819
- form.hideLauncher();
820
- }
821
- },
822
- 'fs': {
823
- mount: function(name: string, handler: types.IMountHandler): boolean {
824
- return clickgo.fs.mount(name, handler, taskId);
825
- },
826
- unmount: function(name: string): Promise<boolean> {
827
- return clickgo.fs.unmount(name);
828
- },
829
- getContent: function(
830
- path: string,
831
- options: any = {}
832
- ): Promise<Blob | string | null> {
833
- return fs.getContent(path, options, taskId);
834
- },
835
- putContent: function(path: string, data: string | Blob, options: any = {}) {
836
- return fs.putContent(path, data, options, taskId);
837
- },
838
- readLink: function(path: string, options: any = {}): Promise<string | null> {
839
- return fs.readLink(path, options, taskId);
840
- },
841
- symlink: function(fPath: string, linkPath: string, options: any = {}): Promise<boolean> {
842
- return fs.symlink(fPath, linkPath, options, taskId);
843
- },
844
- unlink: function(path: string): Promise<boolean> {
845
- return fs.unlink(path, taskId);
846
- },
847
- stats: function(path: string): Promise<types.IStats | null> {
848
- return fs.stats(path, taskId);
849
- },
850
- isDir: function(path: string): Promise<types.IStats | false> {
851
- return fs.isDir(path, taskId);
852
- },
853
- isFile: function(path: string): Promise<types.IStats | false> {
854
- return fs.isFile(path, taskId);
855
- },
856
- mkdir: function(path: string, mode?: number): Promise<boolean> {
857
- return fs.mkdir(path, mode, taskId);
858
- },
859
- rmdir: function(path: string): Promise<boolean> {
860
- return fs.rmdir(path, taskId);
861
- },
862
- rmdirDeep: function(path: string): Promise<boolean> {
863
- return fs.rmdirDeep(path, taskId);
864
- },
865
- chmod: function(path: string, mod: string | number): Promise<boolean> {
866
- return fs.chmod(path, mod, taskId);
867
- },
868
- rename(oldPath: string, newPath: string): Promise<boolean> {
869
- return fs.rename(oldPath, newPath, taskId);
870
- },
871
- readDir(path: string, encoding?: BufferEncoding): Promise<types.IDirent[]> {
872
- return fs.readDir(path, encoding, taskId);
873
- },
874
- copyFolder(from: string, to: string, options: any = {}): Promise<number> {
875
- return fs.copyFolder(from, to, options, taskId);
876
- },
877
- copyFile(src: string, dest: string): Promise<boolean> {
878
- return fs.copyFile(src, dest, taskId);
879
- }
880
- },
881
- 'native': {
882
- on(
883
- name: string,
884
- handler: (...param: any[]) => any | Promise<any>,
885
- once: boolean = false,
886
- formId?: number
887
- ): void {
888
- native.on(name, handler, once, formId, taskId);
889
- },
890
- once(
891
- name: string,
892
- handler: (...param: any[]) => any | Promise<any>,
893
- formId?: number
894
- ): void {
895
- native.once(name, handler, formId, taskId);
896
- },
897
- off(name: string, formId?: number): void {
898
- native.off(name, formId, taskId);
899
- },
900
- clear(formId?: number, taskId?: number): void {
901
- native.clear(formId, taskId);
902
- },
903
- getListenerList(taskId?: number): Record<string, Record<string, Record<string, number>>> {
904
- return native.getListenerList(taskId);
905
- },
906
- invoke: function(name: string, ...param: any[]): Promise<any> {
907
- return native.invoke(name, ...param);
908
- },
909
- size: async function(width: number, height: number): Promise<void> {
910
- const rtn = await checkPermission('native.form', false, undefined, taskId);
911
- if (!rtn[0]) {
912
- return;
913
- }
914
- await native.size(width, height);
915
- },
916
- max: async function(): Promise<void> {
917
- const rtn = await checkPermission('native.form', false, undefined, taskId);
918
- if (!rtn[0]) {
919
- return;
920
- }
921
- await native.max();
922
- },
923
- min: async function(): Promise<void> {
924
- const rtn = await checkPermission('native.form', false, undefined, taskId);
925
- if (!rtn[0]) {
926
- return;
927
- }
928
- await native.min();
929
- },
930
- restore: async function(): Promise<void> {
931
- const rtn = await checkPermission('native.form', false, undefined, taskId);
932
- if (!rtn[0]) {
933
- return;
934
- }
935
- await native.restore();
936
- },
937
- activate: async function(): Promise<void> {
938
- const rtn = await checkPermission('native.form', false, undefined, taskId);
939
- if (!rtn[0]) {
940
- return;
941
- }
942
- await native.activate();
943
- },
944
- maximizable: async function(val: boolean): Promise<void> {
945
- const rtn = await checkPermission('native.form', false, undefined, taskId);
946
- if (!rtn[0]) {
947
- return;
948
- }
949
- await native.maximizable(val);
950
- },
951
- ping: function(val: string): Promise<string> {
952
- return native.ping(val);
953
- },
954
- isMax: function(): Promise<boolean> {
955
- return native.isMax();
956
- }
957
- },
958
- 'storage': {
959
- get: function(key: string): any {
960
- return clickgo.storage.get(key, taskId);
961
- },
962
- set: function(key: string, val: string | number | any[] | Record<string, any>): boolean {
963
- return clickgo.storage.set(key, val, taskId);
964
- },
965
- remove: function(key: string): boolean {
966
- return clickgo.storage.remove(key, taskId);
967
- },
968
- list: function(): Record<string, number> {
969
- return clickgo.storage.list(taskId);
970
- },
971
- all: function(): Record<string, number> {
972
- return clickgo.storage.all();
973
- },
974
- clear: function(path: string): Promise<number> {
975
- return clickgo.storage.clear(path);
976
- }
977
- },
978
- 'task': {
979
- getFocus: function(): number | null {
980
- return focusId;
981
- },
982
- onFrame: function(fun: () => void | Promise<void>, opt: any = {}): number {
983
- opt.taskId = taskId;
984
- return onFrame(fun, opt);
985
- },
986
- offFrame: function(ft: number, opt: {
987
- 'taskId'?: number;
988
- } = {}): void {
989
- opt.taskId = taskId;
990
- offFrame(ft, opt);
991
- },
992
- get: function(tid: number): types.ITaskInfo | null {
993
- return get(tid);
994
- },
995
- getPermissions: function(tid: number): string[] {
996
- return getPermissions(tid);
997
- },
998
- getList: function(): Record<string, types.ITaskInfo> {
999
- return getList();
1000
- },
1001
- run: function(url: string, opt: types.ITaskRunOptions = {}): Promise<number> {
1002
- if (opt.permissions) {
1003
- if (!list[taskId]?.runtime.permissions.includes('root')) {
1004
- opt.permissions = undefined;
1005
- }
1006
- }
1007
- return run(url, opt, taskId);
1008
- },
1009
- checkPermission: function(
1010
- vals: string | string[],
1011
- apply: boolean = false,
1012
- applyHandler?: (list: string[]) => void | Promise<void>
1013
- ): Promise<boolean[]> {
1014
- return checkPermission(vals, apply, applyHandler, taskId);
1015
- },
1016
- end: function(tid: number): boolean {
1017
- return end(tid ?? taskId);
1018
- },
1019
- loadLocaleData: function(lang: string, data: Record<string, any>, pre: string = ''): void {
1020
- loadLocaleData(lang, data, pre, taskId);
1021
- },
1022
- loadLocale: function(lang: string, path: string): Promise<boolean> {
1023
- return loadLocale(lang, path, taskId);
1024
- },
1025
- clearLocale: function(): void {
1026
- clearLocale(taskId);
1027
- },
1028
- setLocale: function(lang: string, path: string): Promise<boolean> {
1029
- return setLocale(lang, path, taskId);
1030
- },
1031
- setLocaleLang: function(lang: string): void {
1032
- setLocaleLang(lang, taskId);
1033
- },
1034
- clearLocaleLang: function(): void {
1035
- clearLocaleLang(taskId);
1036
- },
1037
- createTimer: function(
1038
- fun: () => void | Promise<void>,
1039
- delay: number,
1040
- opt: types.ICreateTimerOptions = {}
1041
- ): number {
1042
- opt.taskId = taskId;
1043
- return createTimer(fun, delay, opt);
1044
- },
1045
- removeTimer: function(timer: number): void {
1046
- removeTimer(timer, taskId);
1047
- },
1048
- sleep: function(fun: () => void | Promise<void>, delay: number): number {
1049
- return sleep(fun, delay, taskId);
1050
- },
1051
- 'systemTaskInfo': clickgo.task.systemTaskInfo,
1052
- setSystem: function(fid: number): boolean {
1053
- return setSystem(fid, taskId);
1054
- },
1055
- clearSystem: function(): boolean {
1056
- return clearSystem(taskId);
1057
- }
1058
- },
1059
- 'theme': {
1060
- read: function(blob: Blob): Promise<types.ITheme | false> {
1061
- return clickgo.theme.read(blob);
1062
- },
1063
- load: async function(theme?: types.ITheme): Promise<boolean> {
1064
- if (!theme) {
1065
- return false;
1066
- }
1067
- return clickgo.theme.load(theme, taskId);
1068
- },
1069
- remove: function(name: string): Promise<void> {
1070
- return clickgo.theme.remove(name, taskId);
1071
- },
1072
- clear: function(): Promise<void> {
1073
- return clickgo.theme.clear(taskId);
1074
- },
1075
- setGlobal: function(theme: types.ITheme): Promise<void> {
1076
- return clickgo.theme.setGlobal(theme);
1077
- },
1078
- clearGlobal: function(): void {
1079
- clickgo.theme.clearGlobal();
1080
- }
1081
- },
1082
- 'tool': {
1083
- compressor: function<T extends File | Blob>(file: T, options: {
1084
- /** --- 最大宽度,默认无限 --- */
1085
- 'maxWidth'?: number;
1086
- /** --- 最高高度,默认无限 --- */
1087
- 'maxHeight'?: number;
1088
- /** --- 压缩质量,默认 0.8 --- */
1089
- 'quality'?: number;
1090
- } = {}): Promise<File | Blob | false> {
1091
- return tool.compressor(file, options);
1092
- },
1093
- blob2ArrayBuffer: function(blob: Blob): Promise<ArrayBuffer> {
1094
- return tool.blob2ArrayBuffer(blob);
1095
- },
1096
- sizeFormat: function(size: number, spliter: string = ' '): string {
1097
- return tool.sizeFormat(size, spliter);
1098
- },
1099
- weightFormat: function(weight: number, spliter: string = ' '): string {
1100
- return tool.weightFormat(weight, spliter);
1101
- },
1102
- clone: function(obj: Record<string, any> | any[]): any[] | any {
1103
- return tool.clone(obj);
1104
- },
1105
- sleep: function(ms: number = 0): Promise<boolean> {
1106
- return tool.sleep(ms);
1107
- },
1108
- nextFrame(): Promise<void> {
1109
- return tool.nextFrame();
1110
- },
1111
- sleepFrame(count: number): Promise<void> {
1112
- return tool.sleepFrame(count);
1113
- },
1114
- purify: function(text: string): string {
1115
- return tool.purify(text);
1116
- },
1117
- match: function(str: string, regs: RegExp[]): boolean {
1118
- return tool.match(str, regs);
1119
- },
1120
- layoutAddTagClassAndReTagName: function(layout: string, retagname: boolean): string {
1121
- return tool.layoutAddTagClassAndReTagName(layout, retagname);
1122
- },
1123
- layoutClassPrepend: function(layout: string, preps: string[]): string {
1124
- return tool.layoutClassPrepend(layout, preps);
1125
- },
1126
- stylePrepend: function(style: string, prep: string = ''): { 'style': string; 'prep': string; } {
1127
- return tool.stylePrepend(style, prep);
1128
- },
1129
- rand: function(min: number, max: number): number {
1130
- return tool.rand(min, max);
1131
- },
1132
- 'RANDOM_N': tool.RANDOM_N,
1133
- 'RANDOM_U': tool.RANDOM_U,
1134
- 'RANDOM_L': tool.RANDOM_L,
1135
- 'RANDOM_UN': tool.RANDOM_UN,
1136
- 'RANDOM_LN': tool.RANDOM_LN,
1137
- 'RANDOM_LU': tool.RANDOM_LU,
1138
- 'RANDOM_LUN': tool.RANDOM_LUN,
1139
- 'RANDOM_V': tool.RANDOM_V,
1140
- 'RANDOM_LUNS': tool.RANDOM_LUNS,
1141
- random: function(length: number = 8, source: string = tool.RANDOM_LN, block: string = ''): string {
1142
- return tool.random(length, source, block);
1143
- },
1144
- getBoolean: function(param: boolean | string | number): boolean {
1145
- return tool.getBoolean(param);
1146
- },
1147
- getNumber: function(param: string | number): number {
1148
- return tool.getNumber(param);
1149
- },
1150
- getArray(param: string | any[]): any[] {
1151
- return tool.getArray(param);
1152
- },
1153
- escapeHTML: function(html: string): string {
1154
- return tool.escapeHTML(html);
1155
- },
1156
- formatColor: function(color: string): number[] {
1157
- return tool.formatColor(color);
1158
- },
1159
- rgb2hex: function(
1160
- r: string | number, g?: string | number, b?: string | number, a: string | number = 1
1161
- ): string {
1162
- return tool.rgb2hex(r, g, b, a);
1163
- },
1164
- hex2rgb: function(hex: string): {
1165
- 'r': number;
1166
- 'g': number;
1167
- 'b': number;
1168
- 'a': number;
1169
- 'rgb': string;
1170
- } {
1171
- return tool.hex2rgb(hex);
1172
- },
1173
- rgb2hsl: function(
1174
- r: string | number, g?: string | number, b?: string | number, a: string | number = 1,
1175
- decimal: boolean = false
1176
- ): {
1177
- 'h': number;
1178
- 's': number;
1179
- 'l': number;
1180
- 'a': number;
1181
- 'hsl': string;
1182
- } {
1183
- return tool.rgb2hsl(r, g, b, a, decimal);
1184
- },
1185
- hsl2rgb: function(
1186
- h: string | number, s?: string | number, l?: string | number, a: string | number = 1,
1187
- decimal: boolean = false
1188
- ): {
1189
- 'r': number;
1190
- 'g': number;
1191
- 'b': number;
1192
- 'a': number;
1193
- 'rgb': string;
1194
- } {
1195
- return tool.hsl2rgb(h, s, l, a, decimal);
1196
- },
1197
- request: function(url: string, opt: types.IRequestOptions): Promise<null | any> {
1198
- return tool.request(url, opt);
1199
- },
1200
- fetch: function(url: string, init?: RequestInit): Promise<string | Blob | null> {
1201
- return tool.fetch(url, init);
1202
- },
1203
- get: function(url: string, opt?: {
1204
- 'credentials'?: 'include' | 'same-origin' | 'omit';
1205
- 'headers'?: HeadersInit;
1206
- }) {
1207
- return tool.get(url, opt);
1208
- },
1209
- post: function(url: string, data: Record<string, any> | FormData, opt?: {
1210
- 'credentials'?: 'include' | 'same-origin' | 'omit';
1211
- 'headers'?: HeadersInit;
1212
- }): Promise<Response | null> {
1213
- return tool.post(url, data, opt);
1214
- },
1215
- getResponseJson: function(url: string, opt?: {
1216
- 'credentials'?: 'include' | 'same-origin' | 'omit';
1217
- 'headers'?: HeadersInit;
1218
- }): Promise<any | null> {
1219
- return tool.getResponseJson(url, opt);
1220
- },
1221
- postResponseJson: function(url: string, data: Record<string, any> | FormData, opt?: {
1222
- 'credentials'?: 'include' | 'same-origin' | 'omit';
1223
- 'headers'?: HeadersInit;
1224
- }): Promise<any | null> {
1225
- return tool.postResponseJson(url, data, opt);
1226
- },
1227
- parseUrl: function(url: string): ILoaderUrl {
1228
- return tool.parseUrl(url);
1229
- },
1230
- urlResolve: function(from: string, to: string): string {
1231
- return tool.urlResolve(from, to);
1232
- },
1233
- urlAtom: function(url: string): string {
1234
- return tool.urlAtom(url);
1235
- },
1236
- blob2Text: function(blob: Blob): Promise<string> {
1237
- return tool.blob2Text(blob);
1238
- },
1239
- blob2DataUrl: function(blob: Blob): Promise<string> {
1240
- return tool.blob2DataUrl(blob);
1241
- },
1242
- execCommand: function(ac: string): void {
1243
- tool.execCommand(ac);
1244
- },
1245
- compar: function(before: string[], after: string[]): {
1246
- 'remove': Record<string, number>;
1247
- 'add': Record<string, number>;
1248
- 'length': {
1249
- 'remove': number;
1250
- 'add': number;
1251
- };
1252
- } {
1253
- return tool.compar(before, after);
1254
- },
1255
- formatSecond: function(second: number): string {
1256
- return tool.formatSecond(second);
1257
- },
1258
- formatTime: function(ts: number | Date, tz?: number): {
1259
- 'date': string;
1260
- 'time': string;
1261
- 'zone': string;
1262
- } {
1263
- return tool.formatTime(ts, tz);
1264
- },
1265
- isMs: function(time: number): boolean {
1266
- return tool.isMs(time);
1267
- },
1268
- queryStringify: function(query: Record<string, any>): string {
1269
- return tool.queryStringify(query);
1270
- },
1271
- queryParse: function(query: string): Record<string, string | string[]> {
1272
- return tool.queryParse(query);
1273
- }
1274
- },
1275
- 'zip': {
1276
- get: function(data?: types.TZipInputFileFormat) {
1277
- return clickgo.zip.get(data);
1278
- }
1279
- }
1280
- };
1281
- /** --- 加载的 js 文件预处理 --- */
1282
- const preprocess = function(code: string, path: string): string {
1283
- // --- 屏蔽 eval 函数 ---
1284
- const exec = /eval\W/.exec(code);
1285
- if (exec) {
1286
- form.notify({
1287
- 'title': 'Error',
1288
- 'content': `The "eval" is prohibited.\nFile: "${path}".`,
1289
- 'type': 'danger'
1290
- });
1291
- return '';
1292
- }
1293
- // --- 给 form 的 class 增加 filename 的 get ---
1294
- code = code.replace(/extends[\s\S]+?\.\s*(AbstractApp|AbstractForm|AbstractPanel)\s*{/, (t: string) => {
1295
- return t + 'get filename() {return __filename;}';
1296
- });
1297
- return code;
1298
- };
1299
- app.files['/invoke/clickgo.js'] = `module.exports = invokeClickgo;`;
1300
- /** --- .cga 文件,或者以 / 结尾的路径 --- */
1301
- const path = opt.path ?? ((typeof url === 'string') ? url : '/runtime/' + tool.random(8, tool.RANDOM_LUN) + '.cga');
1302
- const lio = path.endsWith('.cga') ? path.lastIndexOf('/') : path.slice(0, -1).lastIndexOf('/');
1303
- const current = path.slice(0, lio);
1304
- // --- 创建任务对象 ---
1305
- list[taskId] = {
1306
- 'id': taskId,
1307
- 'app': app,
1308
- // 'class': null,
1309
- 'customTheme': false,
1310
- 'locale': clickgo.vue.reactive({
1311
- 'lang': '',
1312
- 'data': {}
1313
- }),
1314
- 'path': path,
1315
- 'current': current,
1316
-
1317
- 'runtime': clickgo.vue.reactive({
1318
- 'dialogFormIds': [],
1319
- 'permissions': opt.permissions ?? []
1320
- }),
1321
- 'forms': {},
1322
- 'controls': {},
1323
- 'timers': {},
1324
- 'invoke': invoke
1325
- } as any;
1326
- // --- locale ---
1327
- if (app.config.locales) {
1328
- for (let path in app.config.locales) {
1329
- const locale = app.config.locales[path];
1330
- if (!path.endsWith('.json')) {
1331
- path += '.json';
1332
- }
1333
- await opt.initProgress?.('Load local ' + path + ' ...');
1334
- const lcontent = await fs.getContent(path, {
1335
- 'encoding': 'utf8'
1336
- }, taskId);
1337
- if (!lcontent) {
1338
- continue;
1339
- }
1340
- try {
1341
- const data = JSON.parse(lcontent);
1342
- loadLocaleData(locale, data, '', taskId);
1343
- }
1344
- catch {
1345
- // --- 无所谓 ---
1346
- }
1347
- }
1348
- }
1349
- let expo: any = [];
1350
- try {
1351
- const map = {
1352
- 'clickgo': '/invoke/clickgo'
1353
- };
1354
- if (app.config.map) {
1355
- Object.assign(map, app.config.map);
1356
- }
1357
- expo = loader.require('/app.js', app.files, {
1358
- 'dir': '/',
1359
- 'invoke': invoke,
1360
- 'preprocess': preprocess,
1361
- 'map': map
1362
- })[0];
1363
- }
1364
- catch (e: any) {
1365
- delete list[taskId];
1366
- core.trigger('error', taskId, 0, e, e.message + '(-1)');
1367
- return -2;
1368
- }
1369
- if (!expo?.default) {
1370
- delete list[taskId];
1371
- return -3;
1372
- }
1373
- // --- 创建 Task 总 style ---
1374
- dom.createToStyleList(taskId);
1375
- // --- 加载 control ---
1376
- await opt.initProgress?.('Control initialization ...');
1377
- const r = await control.init(taskId, invoke, opt.cache);
1378
- if (r < 0) {
1379
- dom.removeFromStyleList(taskId);
1380
- delete list[taskId];
1381
- return -400 + r;
1382
- }
1383
- // --- 加载 theme ---
1384
- if (app.config.themes?.length) {
1385
- for (let path of app.config.themes) {
1386
- path += '.cgt';
1387
- path = tool.urlResolve('/', path);
1388
- await opt.initProgress?.('Load theme ' + path + ' ...');
1389
- const file = await fs.getContent(path, undefined, taskId);
1390
- if (file && typeof file !== 'string') {
1391
- const th = await theme.read(file);
1392
- if (th) {
1393
- await theme.load(th, taskId);
1394
- }
1395
- }
1396
- }
1397
- }
1398
- else {
1399
- // --- 加载全局主题 ---
1400
- if (theme.global) {
1401
- await opt.initProgress?.('Load global theme ...');
1402
- await theme.load(undefined, taskId);
1403
- }
1404
- }
1405
- // --- 加载任务级全局样式 ---
1406
- if (app.config.style) {
1407
- const style = await fs.getContent(app.config.style + '.css', {
1408
- 'encoding': 'utf8'
1409
- }, taskId);
1410
- if (style) {
1411
- const r = tool.stylePrepend(style, 'cg-task' + taskId.toString() + '_');
1412
- await opt.initProgress?.('Style initialization ...');
1413
- dom.pushStyle(taskId, await tool.styleUrl2DataUrl(app.config.style, r.style, app.files));
1414
- }
1415
- }
1416
- // --- 触发 taskStarted 事件 ---
1417
- core.trigger('taskStarted', taskId);
1418
- // --- 请求权限 ---
1419
- if (app.config.permissions) {
1420
- await opt.initProgress?.('Style initialization ...');
1421
- await checkPermission(app.config.permissions, true, undefined, taskId);
1422
- }
1423
- // --- 执行 app ---
1424
- const appCls: core.AbstractApp = new expo.default();
1425
- list[taskId].class = appCls;
1426
- await opt.initProgress?.('Starting ...');
1427
- await appCls.main(opt.data ?? {});
1428
- return taskId;
1429
- }
1430
-
1431
- /** --- 本页用到的语言包 --- */
1432
- const locale: Record<string, {
1433
- 'unknown': string;
1434
- 'root': string;
1435
- // eslint-disable-next-line @typescript-eslint/naming-convention
1436
- 'apply-permission': string;
1437
- // eslint-disable-next-line @typescript-eslint/naming-convention
1438
- 'native.form': string;
1439
- 'hash': string;
1440
- 'fs': string;
1441
- 'readonly': string;
1442
- // eslint-disable-next-line @typescript-eslint/naming-convention
1443
- 'read-write': string;
1444
- }> = {
1445
- 'sc': {
1446
- 'unknown': '未知权限',
1447
- 'root': '<b>危险!</b>最高权限!请一定确认是否允许!',
1448
- 'apply-permission': '正在申请权限,请您仔细确认',
1449
- 'native.form': '实体窗体控制',
1450
- 'hash': '可修改地址栏 hash',
1451
- 'fs': '文件系统',
1452
- 'readonly': '只读',
1453
- 'read-write': '读写'
1454
- },
1455
- 'tc': {
1456
- 'unknown': '未知許可權',
1457
- 'root': '<b>危險!</b>最高許可權!請一定確認是否允許!',
1458
- 'apply-permission': '正在申請許可權,請您仔細確認',
1459
- 'native.form': '實體視窗控制',
1460
- 'hash': '可修改位址列 hash',
1461
- 'fs': '檔案系統',
1462
- 'readonly': '唯讀',
1463
- 'read-write': '讀寫'
1464
- },
1465
- 'en': {
1466
- 'unknown': 'Unknown',
1467
- 'root': '<b>Danger!</b> Highest permission! Please confirm if you want to allow!',
1468
- 'apply-permission': 'Applying permission, please confirm carefully',
1469
- 'native.form': 'Native window control',
1470
- 'hash': 'Can modify address bar "hash"',
1471
- 'fs': 'File system',
1472
- 'readonly': 'Read-only',
1473
- 'read-write': 'Read and write'
1474
- },
1475
- 'ja': {
1476
- 'unknown': '不明な権限',
1477
- 'root': '<b>危険!</b>最高権限です!許可するかどうか必ず確認してください!',
1478
- 'apply-permission': '権限を申請中です。よくご確認ください',
1479
- 'native.form': 'ネイティブフォームコントロール',
1480
- 'hash': 'アドレスバーの "hash" を変更できます',
1481
- 'fs': 'ファイルシステム',
1482
- 'readonly': '読み取り専用',
1483
- 'read-write': '読み書き可能'
1484
- },
1485
- 'ko': {
1486
- 'unknown': '알 수 없는 권한',
1487
- 'root': '<b>위험!</b> 최고 권한입니다! 반드시 허용할 것인지 확인하십시오!',
1488
- 'apply-permission': '권한을 신청 중입니다. 주의 깊게 확인하십시오',
1489
- 'native.form': '네이티브 폼 제어',
1490
- 'hash': '주소 표시 줄 "hash" 를 수정할 수 있습니다',
1491
- 'fs': '파일 시스템',
1492
- 'readonly': '읽기 전용',
1493
- 'read-write': '읽기 및 쓰기',
1494
- },
1495
- 'th': {
1496
- 'unknown': 'สิทธิ์ที่ไม่รู้จัก',
1497
- 'root': '<b>อันตราย!</b> สิทธิ์สูงสุด! โปรดตรวจสอบว่าต้องการอนุญาตหรือไม่!',
1498
- 'apply-permission': 'กำลังขอสิทธิ์ โปรดตรวจสอบอย่างรอบคอบ',
1499
- 'native.form': 'การควบคุมแบบฟอร์มแบบ Native',
1500
- 'hash': 'สามารถแก้ไขแถบที่อยู่ "hash"',
1501
- 'fs': 'ระบบไฟล์',
1502
- 'readonly': 'อ่านได้อย่างเดียว',
1503
- 'read-write': 'อ่านและเขียนได้'
1504
- },
1505
- 'es': {
1506
- 'unknown': 'Permiso desconocido',
1507
- 'root': '<b>¡Peligro!</b> ¡Permiso máximo! ¡Asegúrese de permitirlo!',
1508
- 'apply-permission': 'Solicitando permiso. Por favor, compruebe cuidadosamente',
1509
- 'native.form': 'Control de formulario nativo',
1510
- 'hash': 'Puede modificar el "hash" de la barra de direcciones',
1511
- 'fs': 'Sistema de archivos',
1512
- 'readonly': 'Solo lectura',
1513
- 'read-write': 'Lectura y escritura',
1514
- },
1515
- 'de': {
1516
- 'unknown': 'Unbekannte Berechtigung',
1517
- 'root': '<b>Gefahr!</b> Höchste Berechtigung! Bitte stellen Sie unbedingt sicher, ob dies erlaubt ist!',
1518
- 'apply-permission': 'Bitte bestätigen Sie die Berechtigungsanfrage sorgfältig',
1519
- 'native.form': 'Natives Formularsteuerelement',
1520
- 'hash': 'Adressleisten "hash" bearbeiten',
1521
- 'fs': 'Dateisystem',
1522
- 'readonly': 'Schreibgeschützt',
1523
- 'read-write': 'Lesen/Schreiben'
1524
- },
1525
- 'fr': {
1526
- 'unknown': 'Autorisation inconnue',
1527
- 'root': '<b>Danger !</b> Autorisation maximale ! Veuillez vous assurer que vous êtes autorisé à le faire !',
1528
- 'apply-permission': 'Demande d\'autorisation en cours, veuillez vérifier attentivement',
1529
- 'native.form': 'Contrôle de formulaire natif',
1530
- 'hash': 'Modifier le "hash" de la barre d\'adresse',
1531
- 'fs': 'Système de fichiers',
1532
- 'readonly': 'Lecture seule',
1533
- 'read-write': 'Lecture/écriture'
1534
- },
1535
- 'pt': {
1536
- 'unknown': 'Permissão desconhecida',
1537
- 'root': '<b>Perigo!</b> Permissão máxima! Certifique-se de ter permissão para fazê-lo!',
1538
- 'apply-permission': 'Solicitando permissão, por favor confirme cuidadosamente',
1539
- 'native.form': 'Controle de formulário nativo',
1540
- 'hash': 'Editar "hash" da barra de endereço',
1541
- 'fs': 'Sistema de arquivos',
1542
- 'readonly': 'Somente leitura',
1543
- 'read-write': 'Leitura/escrita'
1544
- },
1545
- 'ru': {
1546
- 'unknown': 'Неизвестное разрешение',
1547
- 'root': '<b>Опасность!</b> Максимальное разрешение! Пожалуйста, обязательно убедитесь, что это разрешено!',
1548
- 'apply-permission': 'Выполняется запрос на разрешение, пожалуйста, внимательно подтвердите',
1549
- 'native.form': 'Нативный элемент формы',
1550
- 'hash': 'Изменить "hash" адресной строки',
1551
- 'fs': 'Файловая система',
1552
- 'readonly': 'Только для чтения',
1553
- 'read-write': 'Чтение/запись'
1554
- },
1555
- 'vi': {
1556
- 'unknown': 'Quyền không xác định',
1557
- 'root': '<b>Nguy hiểm!</b> Quyền hạn cao nhất! Hãy đảm bảo rằng bạn được phép làm điều này!',
1558
- 'apply-permission': 'Đang yêu cầu quyền truy cập, vui lòng xác nhận cẩn thận',
1559
- 'native.form': 'Thiết bị kiểm soát biểu mẫu gốc',
1560
- 'hash': 'Chỉnh sửa "hash" thanh địa chỉ',
1561
- 'fs': 'Hệ thống tập tin',
1562
- 'readonly': 'Chỉ đọc',
1563
- 'read-write': 'Đọc/ghi'
1564
- }
1565
- };
1566
-
1567
- // fs.{path}{r/w},path 以 / 结尾则是路径权限,不以 / 结尾是文件权限
1568
-
1569
- /**
1570
- * --- 检测应用是否有相应的权限 ---
1571
- * @param vals 要检测的权限
1572
- * @param apply 如果没有权限是否自动弹出申请,默认为否
1573
- * @param applyHandler 向用户申请成功的权限列表回调
1574
- * @param taskId 要检查的任务 ID,App 模式下无效
1575
- */
1576
- export async function checkPermission(
1577
- vals: string | string[],
1578
- apply: boolean = false,
1579
- applyHandler?: (list: string[]) => void | Promise<void>,
1580
- taskId?: number
1581
- ): Promise<boolean[]> {
1582
- if (!taskId) {
1583
- return [false];
1584
- }
1585
- const task = list[taskId];
1586
- if (!task) {
1587
- return [false];
1588
- }
1589
- if (typeof vals === 'string') {
1590
- vals = [vals];
1591
- }
1592
- const rtn: boolean[] = [];
1593
- /** --- 需要申请的权限 --- */
1594
- const applyList: string[] = [];
1595
- for (const val of vals) {
1596
- if (task.runtime.permissions.includes('root')) {
1597
- // --- 有 root 权限,一定成功 ---
1598
- rtn.push(true);
1599
- continue;
1600
- }
1601
- if (val.startsWith('fs.')) {
1602
- // --- fs 判断比较特殊 ---
1603
- let yes = false;
1604
- const path = val.slice(3, -1);
1605
- for (const v of task.runtime.permissions) {
1606
- if (!v.startsWith('fs.')) {
1607
- continue;
1608
- }
1609
- const pa = v.slice(3, -1);
1610
- if (pa.endsWith('/')) {
1611
- if (!path.startsWith(pa)) {
1612
- continue;
1613
- }
1614
- }
1615
- else if (pa !== path) {
1616
- continue;
1617
- }
1618
- // --- 找到了 ---
1619
- if (val.endsWith('w')) {
1620
- // --- 用户要求读写 ---
1621
- if (v.endsWith('r')) {
1622
- // --- 但目前只有读的权限 ---
1623
- continue;
1624
- }
1625
- }
1626
- // --- 正常,有权限 ---
1627
- yes = true;
1628
- break;
1629
- }
1630
- rtn.push(yes);
1631
- if (!yes && apply) {
1632
- // --- 要申请权限 ---
1633
- applyList.push(val);
1634
- }
1635
- continue;
1636
- }
1637
- // --- 其他权限判断 ---
1638
- const result = task.runtime.permissions.includes(val);
1639
- if (!result && apply) {
1640
- // --- 要申请权限 ---
1641
- applyList.push(val);
1642
- }
1643
- rtn.push(result);
1644
- }
1645
- // --- 申请权限 ---
1646
- if (applyList.length) {
1647
- let html = '<div>"' + tool.escapeHTML(task.app.config.name) + '" ' + ((locale[core.config.locale]?.['apply-permission'] ?? locale['en']['apply-permission']) + ':') + '</div>';
1648
- for (const item of applyList) {
1649
- if (item.startsWith('fs.')) {
1650
- // --- fs 判断比较特殊 ---
1651
- const path = item.slice(3, -1);
1652
- html += '<div style="margin-top: 10px;">' +
1653
- (locale[core.config.locale]?.fs ?? locale['en'].fs) + ' ' + tool.escapeHTML(path) + ' ' + (item.endsWith('r') ? (locale[core.config.locale]?.readonly ?? locale['en'].readonly) : (locale[core.config.locale]?.['read-write'] ?? locale['en']['read-write'])) +
1654
- '<div style="color: hsl(0,0%,60%);">' + tool.escapeHTML(item) + '</div>' +
1655
- '</div>';
1656
- continue;
1657
- }
1658
- const lang = (locale as any)[core.config.locale]?.[item] ?? (locale as any)['en'][item];
1659
- html += '<div style="margin-top: 10px;">' +
1660
- (lang ?? locale[core.config.locale]?.unknown ?? locale['en'].unknown) +
1661
- '<div style="color: hsl(0,0%,60%);">' + tool.escapeHTML(item) + '</div>' +
1662
- '</div>';
1663
- }
1664
- if (await form.superConfirm(html)) {
1665
- // --- 所有 false 变成 true ---
1666
- for (let i = 0; i < rtn.length; ++i) {
1667
- if (rtn[i]) {
1668
- continue;
1669
- }
1670
- rtn[i] = true;
1671
- }
1672
- for (const item of applyList) {
1673
- task.runtime.permissions.push(item);
1674
- }
1675
- try {
1676
- applyHandler?.(applyList) as any;
1677
- }
1678
- catch (e) {
1679
- console.log('task.checkPermission', e);
1680
- }
1681
- }
1682
- }
1683
- return rtn;
1684
- }
1685
-
1686
- /**
1687
- * --- 完全结束任务 ---
1688
- * @param taskId 任务 id
1689
- */
1690
- export function end(taskId: number | string): boolean {
1691
- if (typeof taskId === 'string') {
1692
- taskId = parseInt(taskId);
1693
- }
1694
- const task = list[taskId];
1695
- if (!task) {
1696
- return true;
1697
- }
1698
- // --- 如果是 native 模式 ---
1699
- if (clickgo.isNative() && (taskId === 1)) {
1700
- native.invoke('cg-close', native.getToken()) as any;
1701
- }
1702
- // --- 获取最大的 z index 窗体,并让他获取焦点 ---
1703
- const fid = form.getMaxZIndexID({
1704
- 'taskIds': [task.id]
1705
- });
1706
- if (fid) {
1707
- form.changeFocus(fid);
1708
- }
1709
- else {
1710
- form.changeFocus();
1711
- }
1712
- // --- 移除窗体 list ---
1713
- for (const fid in task.forms) {
1714
- // --- 结束任务挨个关闭窗体 ---
1715
- const f = task.forms[fid];
1716
- core.trigger('formRemoved', taskId, f.id, f.vroot.$refs.form.title, f.vroot.$refs.form.iconDataUrl);
1717
- try {
1718
- f.vapp.unmount();
1719
- }
1720
- catch (err: any) {
1721
- const msg = `Message: ${err.message}\nTask id: ${task.id}\nForm id: ${fid}\nFunction: task.end, unmount.`;
1722
- form.notify({
1723
- 'title': 'Form Unmount Error',
1724
- 'content': msg,
1725
- 'type': 'danger'
1726
- });
1727
- console.log('Form Unmount Error', msg, err);
1728
- }
1729
- f.vapp._container.remove();
1730
- form.elements.popList.querySelector('[data-form-id="' + f.id.toString() + '"]')?.remove();
1731
- dom.clearWatchStyle(fid);
1732
- dom.clearWatchProperty(fid);
1733
- dom.clearWatchPosition(fid);
1734
- delete form.activePanels[fid];
1735
- }
1736
- // --- 移除可能残留的 form wrap ---
1737
- const flist = form.elements.list.querySelectorAll('.cg-form-wrap[data-task-id="' + taskId.toString() + '"]');
1738
- for (const f of flist) {
1739
- f.remove();
1740
- }
1741
- // --- 移除 style ---
1742
- dom.removeFromStyleList(taskId);
1743
- // --- 移除所有 timer ---
1744
- for (const timer in list[taskId].timers) {
1745
- if (timer.startsWith('1x')) {
1746
- const ft = timer.slice(2);
1747
- cancelAnimationFrame(frameMaps[ft]);
1748
- delete frameMaps[ft];
1749
- }
1750
- else {
1751
- clearTimeout(parseFloat(timer));
1752
- }
1753
- }
1754
- // --- 移除各类监听 ---
1755
- dom.clearWatchSize(taskId);
1756
- dom.clearWatch(taskId);
1757
- native.clear(undefined, taskId);
1758
- // --- 移除 task ---
1759
- delete list[taskId];
1760
- // --- 触发 taskEnded 事件 ---
1761
- core.trigger('taskEnded', taskId);
1762
- // --- 移除 task bar ---
1763
- clearSystem(taskId);
1764
- return true;
1765
- }
1766
-
1767
- /**
1768
- * --- 加载 locale data 对象到 task ---
1769
- * @param lang 语言名,如 sc
1770
- * @param data 数据
1771
- * @param pre 前置
1772
- * @param taskId 任务ID,App 模式下无效
1773
- */
1774
- export function loadLocaleData(lang: string, data: Record<string, any>, pre: string = '', taskId?: number): void {
1775
- if (!taskId) {
1776
- return;
1777
- }
1778
- if (!list[taskId].locale.data[lang]) {
1779
- list[taskId].locale.data[lang] = {};
1780
- }
1781
- for (const k in data) {
1782
- const v = data[k];
1783
- if (typeof v === 'object') {
1784
- loadLocaleData(lang, v, pre + k + '.', taskId);
1785
- }
1786
- else {
1787
- list[taskId].locale.data[lang][pre + k] = v;
1788
- }
1789
- }
1790
- }
1791
-
1792
- /**
1793
- * --- 加载 locale 文件 json ---
1794
- * @param lang 语言名,如 sc
1795
- * @param path 绝对或者相对 app 路径的地址
1796
- * @param taskId 所属的 taskId,App 模式下无效
1797
- */
1798
- export async function loadLocale(lang: string, path: string, taskId?: number): Promise<boolean> {
1799
- if (!taskId) {
1800
- return false;
1801
- }
1802
- const task = list[taskId];
1803
- if (!task) {
1804
- return false;
1805
- }
1806
- /** --- 获取的语言文件 --- */
1807
- const fcontent = await fs.getContent(path + '.json', {
1808
- 'encoding': 'utf8'
1809
- }, taskId);
1810
- if (!fcontent) {
1811
- return false;
1812
- }
1813
- try {
1814
- const data = JSON.parse(fcontent);
1815
- loadLocaleData(lang, data, '', task.id);
1816
- return true;
1817
- }
1818
- catch {
1819
- return false;
1820
- }
1821
- }
1822
-
1823
- /**
1824
- * --- 清除任务的所有加载的语言包 ---
1825
- * @param taskId 所属的 taskId,App 模式下无效
1826
- */
1827
- export function clearLocale(taskId?: number): void {
1828
- if (!taskId) {
1829
- return;
1830
- }
1831
- const task = list[taskId];
1832
- if (!task) {
1833
- return;
1834
- }
1835
- task.locale.data = {};
1836
- }
1837
-
1838
- /**
1839
- * --- 加载全新 locale(老 locale 的所以语言的缓存会被卸载) ---
1840
- * @param lang 语言名,如 sc
1841
- * @param path 绝对或者相对 app 路径的地址
1842
- * @param taskId 所属的 taskId,App 模式下无效z
1843
- */
1844
- export function setLocale(lang: string, path: string, taskId?: number): Promise<boolean> {
1845
- clearLocale(taskId);
1846
- return loadLocale(lang, path, taskId);
1847
- }
1848
-
1849
- /**
1850
- * --- 设置本 task 的语言 name ---
1851
- * @param lang 语言名,如 sc
1852
- * @param taskId 所属的 taskId,App 模式下无效
1853
- */
1854
- export function setLocaleLang(lang: string, taskId?: number): void {
1855
- if (!taskId) {
1856
- return;
1857
- }
1858
- const task = list[taskId];
1859
- if (!task) {
1860
- return;
1861
- }
1862
- task.locale.lang = lang;
1863
- }
1864
-
1865
- /**
1866
- * --- 清除 task 的语言设置 ---
1867
- * @param taskId 所属的 taskId,App 模式下无效
1868
- */
1869
- export function clearLocaleLang(taskId?: number): void {
1870
- if (!taskId) {
1871
- return;
1872
- }
1873
- const task = list[taskId];
1874
- if (!task) {
1875
- return;
1876
- }
1877
- task.locale.lang = '';
1878
- }
1879
-
1880
- /**
1881
- * --- 创建 timer ---
1882
- * @param fun 执行函数
1883
- * @param delay 延迟/间隔,毫秒
1884
- * @param opt 选项, taskId: App 模式下无效, formId: 可省略,App 模式下省略代表生命周期为当前整个任务,否则只是当前窗体,immediate: 立即执行,默认 false,count: 执行次数,0 为无限次,默认 0
1885
- */
1886
- export function createTimer(
1887
- fun: () => void | Promise<void>,
1888
- delay: number,
1889
- opt: types.ICreateTimerOptions = {}
1890
- ): number {
1891
- const taskId = opt.taskId;
1892
- const formId = opt.formId;
1893
- if (!taskId) {
1894
- return 0;
1895
- }
1896
- const task = list[taskId];
1897
- if (!task) {
1898
- return 0;
1899
- }
1900
- if (formId && !task.forms[formId]) {
1901
- return 0;
1902
- }
1903
- /** --- 执行几次,0 代表无限次 --- */
1904
- const count = opt.count ?? 0;
1905
- /** --- 当前已经执行的次数 --- */
1906
- let c: number = 0;
1907
- // --- 是否立即执行 ---
1908
- if (opt.immediate) {
1909
- const r = fun();
1910
- if (r instanceof Promise) {
1911
- r.catch(function(e) {
1912
- console.log(e);
1913
- });
1914
- }
1915
- ++c;
1916
- if (count > 0 && c === count) {
1917
- return 0;
1918
- }
1919
- }
1920
- let timer: number;
1921
- const timerHandler = (): void => {
1922
- ++c;
1923
- if (formId && task.forms[formId] === undefined) {
1924
- // --- form 已经没了 ---
1925
- clearTimeout(timer);
1926
- delete task.timers[timer];
1927
- return;
1928
- }
1929
- const r = fun();
1930
- if (r instanceof Promise) {
1931
- r.catch(function(e) {
1932
- console.log(e);
1933
- });
1934
- }
1935
- if (count > 0 && c === count) {
1936
- clearTimeout(timer);
1937
- delete task.timers[timer];
1938
- return;
1939
- }
1940
- };
1941
- /** --- timer 对象 number --- */
1942
- if (count === 1) {
1943
- timer = window.setTimeout(timerHandler, delay);
1944
- }
1945
- else {
1946
- timer = window.setInterval(timerHandler, delay);
1947
- }
1948
- task.timers[timer] = formId ?? 0;
1949
- return timer;
1950
- }
1951
-
1952
- /**
1953
- * --- 移除 timer ---
1954
- * @param timer ID
1955
- * @param taskId 任务 id,App 模式下无效
1956
- */
1957
- export function removeTimer(timer: number, taskId?: number): void {
1958
- if (!taskId) {
1959
- return;
1960
- }
1961
- if (list[taskId] === undefined) {
1962
- return;
1963
- }
1964
- const formId = list[taskId].timers[timer];
1965
- if (formId === undefined) {
1966
- return;
1967
- }
1968
- // --- 放在这,防止一个 task 能结束 别的 task 的 timer ---
1969
- clearTimeout(timer);
1970
- delete list[taskId].timers[timer];
1971
- }
1972
-
1973
- /**
1974
- * --- 暂停一小段时间 ---
1975
- * @param fun 回调函数
1976
- * @param delay 暂停时间
1977
- * @param taskId 任务 id,App 模式下无效
1978
- */
1979
- export function sleep(fun: () => void | Promise<void>, delay: number, taskId?: number): number {
1980
- return createTimer(fun, delay, {
1981
- 'taskId': taskId,
1982
- 'count': 1
1983
- });
1984
- }
1985
-
1986
- /** --- task 的信息 --- */
1987
- export const systemTaskInfo: types.ISystemTaskInfo = clickgo.vue.reactive({
1988
- 'taskId': 0,
1989
- 'formId': 0,
1990
- 'length': 0
1991
- });
1992
-
1993
- clickgo.vue.watch(systemTaskInfo, function(n: any, o: any) {
1994
- const originKeys = ['taskId', 'formId', 'length'];
1995
- // --- 检测有没有缺少的 key ---
1996
- for (const key of originKeys) {
1997
- if ((systemTaskInfo as any)[key] !== undefined) {
1998
- continue;
1999
- }
2000
- form.notify({
2001
- 'title': 'Warning',
2002
- 'content': 'There is a software that maliciously removed the system task info item.\nKey: ' + key,
2003
- 'type': 'warning'
2004
- });
2005
- (systemTaskInfo as any)[key] = o[key] ?? 0;
2006
- }
2007
- for (const key in systemTaskInfo) {
2008
- if (!['taskId', 'formId', 'length'].includes(key)) {
2009
- form.notify({
2010
- 'title': 'Warning',
2011
- 'content': 'There is a software that maliciously modifies the system task info item.\nKey: ' + key,
2012
- 'type': 'warning'
2013
- });
2014
- delete (systemTaskInfo as any)[key];
2015
- continue;
2016
- }
2017
- if (typeof (systemTaskInfo as any)[key] === 'number') {
2018
- continue;
2019
- }
2020
- form.notify({
2021
- 'title': 'Warning',
2022
- 'content': 'There is a software that maliciously modifies the system task info item.\nKey: ' + key,
2023
- 'type': 'warning'
2024
- });
2025
- (systemTaskInfo as any)[key] = o[key] ?? 0;
2026
- }
2027
- }, {
2028
- 'deep': true
2029
- });
2030
-
2031
- /**
2032
- * --- 将任务注册为系统 task ---
2033
- * @param formId task bar 的 form id
2034
- * @param taskId task id,App 模式下无效
2035
- */
2036
- export function setSystem(formId: number, taskId?: number): boolean {
2037
- if (!taskId) {
2038
- return false;
2039
- }
2040
- const task = list[taskId];
2041
- if (!task) {
2042
- return false;
2043
- }
2044
- const f = task.forms[formId];
2045
- if (!f) {
2046
- return false;
2047
- }
2048
- if (f.vroot.position === undefined) {
2049
- form.notify({
2050
- 'title': 'Warning',
2051
- 'content': `Task id is "${taskId}" app is not an available task app, position not found.`,
2052
- 'type': 'warning'
2053
- });
2054
- return false;
2055
- }
2056
- if (systemTaskInfo.taskId > 0) {
2057
- form.notify({
2058
- 'title': 'Info',
2059
- 'content': 'More than 1 system-level task application is currently running.',
2060
- 'type': 'info'
2061
- });
2062
- }
2063
- systemTaskInfo.taskId = taskId;
2064
- systemTaskInfo.formId = formId;
2065
- form.simpleSystemTaskRoot.forms = {};
2066
- refreshSystemPosition();
2067
- return true;
2068
- }
2069
-
2070
- /**
2071
- * --- 清除系统任务设定 ---
2072
- * @param taskId 清除的 taskid 为 task id 才能清除,App 模式下无效
2073
- */
2074
- export function clearSystem(taskId?: number | string): boolean {
2075
- if (!taskId) {
2076
- return false;
2077
- }
2078
- if (typeof taskId === 'string') {
2079
- taskId = parseInt(taskId);
2080
- }
2081
- if (systemTaskInfo.taskId !== taskId) {
2082
- return false;
2083
- }
2084
- systemTaskInfo.taskId = 0;
2085
- systemTaskInfo.formId = 0;
2086
- systemTaskInfo.length = 0;
2087
- core.trigger('screenResize');
2088
- // --- 如果此时已经有最小化的窗体,那么他将永远“不见天日”,需要将他们传递给 simpletask ---
2089
- const tasks = getList();
2090
- for (const taskId in tasks) {
2091
- const forms = form.getList(parseInt(taskId));
2092
- for (const formId in forms) {
2093
- const f = forms[formId];
2094
- if (!f.stateMin) {
2095
- continue;
2096
- }
2097
- form.simpleSystemTaskRoot.forms[formId] = {
2098
- 'title': f.title,
2099
- 'icon': f.icon
2100
- };
2101
- }
2102
- }
2103
- return true;
2104
- }
2105
-
2106
- /**
2107
- * --- 刷新系统任务的 form 的位置以及 length,App 模式下无效 ---
2108
- */
2109
- export function refreshSystemPosition(): void {
2110
- if (systemTaskInfo.taskId > 0) {
2111
- const form = list[systemTaskInfo.taskId].forms[systemTaskInfo.formId];
2112
- // --- 更新 task bar 的位置 ---
2113
- switch (core.config['task.position']) {
2114
- case 'left':
2115
- case 'right': {
2116
- form.vroot.$refs.form.setPropData('width', 0);
2117
- form.vroot.$refs.form.setPropData('height', window.innerHeight);
2118
- break;
2119
- }
2120
- case 'top':
2121
- case 'bottom': {
2122
- form.vroot.$refs.form.setPropData('width', window.innerWidth);
2123
- form.vroot.$refs.form.setPropData('height', 0);
2124
- break;
2125
- }
2126
- }
2127
- setTimeout(function() {
2128
- switch (core.config['task.position']) {
2129
- case 'left': {
2130
- systemTaskInfo.length = form.vroot.$el.offsetWidth;
2131
- form.vroot.$refs.form.setPropData('left', 0);
2132
- form.vroot.$refs.form.setPropData('top', 0);
2133
- break;
2134
- }
2135
- case 'right': {
2136
- systemTaskInfo.length = form.vroot.$el.offsetWidth;
2137
- form.vroot.$refs.form.setPropData('left', window.innerWidth - systemTaskInfo.length);
2138
- form.vroot.$refs.form.setPropData('top', 0);
2139
- break;
2140
- }
2141
- case 'top': {
2142
- systemTaskInfo.length = form.vroot.$el.offsetHeight;
2143
- form.vroot.$refs.form.setPropData('left', 0);
2144
- form.vroot.$refs.form.setPropData('top', 0);
2145
- break;
2146
- }
2147
- case 'bottom': {
2148
- systemTaskInfo.length = form.vroot.$el.offsetHeight;
2149
- form.vroot.$refs.form.setPropData('left', 0);
2150
- form.vroot.$refs.form.setPropData('top', window.innerHeight - systemTaskInfo.length);
2151
- break;
2152
- }
2153
- }
2154
- core.trigger('screenResize');
2155
- }, 50);
2156
- }
2157
- else {
2158
- core.trigger('screenResize');
2159
- }
2160
- }