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.
- package/README.md +1 -1
- package/dist/app/demo/form/method/native/native.js +26 -0
- package/dist/app/demo/form/method/native/native.xml +2 -0
- package/dist/clickgo.d.ts +17 -0
- package/dist/clickgo.js +1 -1
- package/dist/control/arteditor.cgc +0 -0
- package/dist/control/box.cgc +0 -0
- package/dist/control/captcha.cgc +0 -0
- package/dist/control/common.cgc +0 -0
- package/dist/control/desc.cgc +0 -0
- package/dist/control/drawer.cgc +0 -0
- package/dist/control/echarts.cgc +0 -0
- package/dist/control/form.cgc +0 -0
- package/dist/control/iconview.cgc +0 -0
- package/dist/control/jodit.cgc +0 -0
- package/dist/control/map.cgc +0 -0
- package/dist/control/monaco.cgc +0 -0
- package/dist/control/mpegts.cgc +0 -0
- package/dist/control/nav.cgc +0 -0
- package/dist/control/page.cgc +0 -0
- package/dist/control/pdf.cgc +0 -0
- package/dist/control/property.cgc +0 -0
- package/dist/control/qrcode.cgc +0 -0
- package/dist/control/table.cgc +0 -0
- package/dist/control/task.cgc +0 -0
- package/dist/control/tplink.cgc +0 -0
- package/dist/control/tuieditor.cgc +0 -0
- package/dist/control/tuiviewer.cgc +0 -0
- package/dist/control/xterm.cgc +0 -0
- package/dist/index.d.ts +51 -0
- package/dist/lib/control.d.ts +53 -0
- package/dist/lib/core.d.ts +47 -0
- package/dist/lib/dom.d.ts +74 -0
- package/dist/lib/dom.js +7 -7
- package/dist/lib/form.d.ts +222 -0
- package/dist/lib/fs.d.ts +35 -0
- package/dist/lib/fs.js +2 -2
- package/dist/lib/native.d.ts +36 -0
- package/dist/lib/native.js +8 -0
- package/dist/lib/storage.d.ts +6 -0
- package/dist/lib/task.d.ts +32 -0
- package/dist/lib/task.js +7 -1
- package/dist/lib/theme.d.ts +8 -0
- package/dist/lib/tool.d.ts +120 -0
- package/dist/lib/zip.d.ts +40 -0
- package/dist/theme/blue.cgt +0 -0
- package/dist/theme/byterun.cgt +0 -0
- package/dist/theme/light.cgt +0 -0
- package/package.json +7 -5
- package/dist/clickgo.ts +0 -68
- package/dist/index.ts +0 -282
- package/dist/lib/control.ts +0 -751
- package/dist/lib/core.ts +0 -1145
- package/dist/lib/dom.ts +0 -2728
- package/dist/lib/form.ts +0 -3829
- package/dist/lib/fs.ts +0 -1324
- package/dist/lib/native.ts +0 -236
- package/dist/lib/storage.ts +0 -229
- package/dist/lib/task.ts +0 -2160
- package/dist/lib/theme.ts +0 -199
- package/dist/lib/tool.ts +0 -1278
- package/dist/lib/zip.ts +0 -444
- package/eslint.config.js +0 -22
package/dist/lib/core.ts
DELETED
|
@@ -1,1145 +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 fs from './fs';
|
|
19
|
-
import * as form from './form';
|
|
20
|
-
import * as task from './task';
|
|
21
|
-
import * as tool from './tool';
|
|
22
|
-
import * as zip from './zip';
|
|
23
|
-
|
|
24
|
-
/** --- Config 原始参考对象 --- */
|
|
25
|
-
const configOrigin: types.IConfig = {
|
|
26
|
-
'locale': 'en',
|
|
27
|
-
'task.position': 'bottom',
|
|
28
|
-
'task.pin': {},
|
|
29
|
-
'desktop.icon.storage': true,
|
|
30
|
-
'desktop.icon.recycler': true,
|
|
31
|
-
'desktop.wallpaper': null,
|
|
32
|
-
'desktop.path': null,
|
|
33
|
-
'launcher.list': []
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/** --- Config 配置对象 --- */
|
|
37
|
-
export const config: types.IConfig = clickgo.vue.reactive({
|
|
38
|
-
'locale': 'en',
|
|
39
|
-
'task.position': 'bottom',
|
|
40
|
-
'task.pin': {},
|
|
41
|
-
'desktop.icon.storage': true,
|
|
42
|
-
'desktop.icon.recycler': true,
|
|
43
|
-
'desktop.wallpaper': null,
|
|
44
|
-
'desktop.path': null,
|
|
45
|
-
'launcher.list': []
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
/** --- 用户在浏览器页面定义的全局数据 --- */
|
|
49
|
-
export const global: any = (window as any).clickgoGlobal ?? {};
|
|
50
|
-
|
|
51
|
-
/** --- App 抽象类 --- */
|
|
52
|
-
export abstract class AbstractApp {
|
|
53
|
-
|
|
54
|
-
/** --- 当前 js 文件在包内的完整路径 --- */
|
|
55
|
-
public get filename(): string {
|
|
56
|
-
return '';
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** --- invoke 时系统会自动设置本项 --- */
|
|
60
|
-
public get taskId(): number {
|
|
61
|
-
return 0;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
public set taskId(v: number) {
|
|
65
|
-
form.notify({
|
|
66
|
-
'title': 'Error',
|
|
67
|
-
'content': `The software tries to modify the system variable "taskId" to "${v}".\nPath: ${this.filename}`,
|
|
68
|
-
'type': 'danger'
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** --- App 的入口文件 --- */
|
|
73
|
-
public abstract main(data: Record<string, any>): Promise<void>;
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* --- 以某个窗体进行正式启动这个 app(入口 form),不启动则任务也启动失败 ---
|
|
77
|
-
* @param form 窗体对象
|
|
78
|
-
*/
|
|
79
|
-
public run(form: form.AbstractForm): void {
|
|
80
|
-
form.show();
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** --- 全局错误事件 --- */
|
|
84
|
-
public onError(taskId: number, formId: number, error: Error, info: string): void | Promise<void>;
|
|
85
|
-
public onError(): void {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/** --- 屏幕大小改变事件 --- */
|
|
90
|
-
public onScreenResize(): void | Promise<void>;
|
|
91
|
-
public onScreenResize(): void {
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/** --- 系统配置变更事件 --- */
|
|
96
|
-
public onConfigChanged<T extends types.IConfig, TK extends keyof T>(n: TK, v: T[TK]): void | Promise<void>;
|
|
97
|
-
public onConfigChanged(): void {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/** --- 窗体创建事件 --- */
|
|
102
|
-
public onFormCreated(
|
|
103
|
-
taskId: number, formId: number, title: string, icon: string, showInSystemTask: boolean
|
|
104
|
-
): void | Promise<void>;
|
|
105
|
-
public onFormCreated(): void {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/** --- 窗体销毁事件 */
|
|
110
|
-
public onFormRemoved(taskId: number, formId: number, title: string, icon: string): void | Promise<void>;
|
|
111
|
-
public onFormRemoved(): void {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/** --- 窗体标题改变事件 */
|
|
116
|
-
public onFormTitleChanged(taskId: number, formId: number, title: string): void | Promise<void>;
|
|
117
|
-
public onFormTitleChanged(): void | Promise<void> {
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/** --- 窗体图标改变事件 --- */
|
|
122
|
-
public onFormIconChanged(taskId: number, formId: number, icon: string): void | Promise<void>;
|
|
123
|
-
public onFormIconChanged(): void | Promise<void> {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/** --- 窗体最小化状态改变事件 --- */
|
|
128
|
-
public onFormStateMinChanged(taskId: number, formId: number, state: boolean): void | Promise<void>;
|
|
129
|
-
public onFormStateMinChanged(): void {
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** --- 窗体最大化状态改变事件 --- */
|
|
134
|
-
public onFormStateMaxChanged(taskId: number, formId: number, state: boolean): void | Promise<void>;
|
|
135
|
-
public onFormStateMaxChanged(): void {
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/** --- 窗体显示状态改变事件 --- */
|
|
140
|
-
public onFormShowChanged(taskId: number, formId: number, state: boolean): void | Promise<void>;
|
|
141
|
-
public onFormShowChanged(): void {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/** --- 窗体获得焦点事件 --- */
|
|
146
|
-
public onFormFocused(taskId: number, formId: number): void | Promise<void>;
|
|
147
|
-
public onFormFocused(): void {
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/** --- 窗体丢失焦点事件 --- */
|
|
152
|
-
public onFormBlurred(taskId: number, formId: number): void | Promise<void>;
|
|
153
|
-
public onFormBlurred(): void {
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/** --- 窗体闪烁事件 --- */
|
|
158
|
-
public onFormFlash(taskId: number, formId: number): void | Promise<void>;
|
|
159
|
-
public onFormFlash(): void {
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/** --- 窗体是否显示在任务栏属性改变事件 --- */
|
|
164
|
-
public onFormShowInSystemTaskChange(taskId: number, formId: number, value: boolean): void | Promise<void>;
|
|
165
|
-
public onFormShowInSystemTaskChange(): void {
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/** --- 窗体的 formHash 改变事件 --- */
|
|
170
|
-
public onFormHashChange(
|
|
171
|
-
taskId: number, formId: number, value: string, data: Record<string, any>
|
|
172
|
-
): void | Promise<void>;
|
|
173
|
-
public onFormHashChange(): void {
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/** --- 任务开始事件 --- */
|
|
178
|
-
public onTaskStarted(taskId: number): void | Promise<void>;
|
|
179
|
-
public onTaskStarted(): void | Promise<void> {
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/** --- 任务结束事件 --- */
|
|
184
|
-
public onTaskEnded(taskId: number): void | Promise<void>;
|
|
185
|
-
public onTaskEnded(): void | Promise<void> {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/** --- launcher 文件夹名称修改事件 --- */
|
|
190
|
-
public onLauncherFolderNameChanged(id: string, name: string): void | Promise<void>;
|
|
191
|
-
public onLauncherFolderNameChanged(): void {
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/** --- location hash 改变事件 --- */
|
|
196
|
-
public onHashChanged(hash: string): void | Promise<void>;
|
|
197
|
-
public onHashChanged(): void {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/** --- 键盘按下事件 --- */
|
|
202
|
-
public onKeydown(e: KeyboardEvent): void | Promise<void>;
|
|
203
|
-
public onKeydown(): void {
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/** --- 键盘弹起事件 --- */
|
|
208
|
-
public onKeyup(e: KeyboardEvent): void | Promise<void>;
|
|
209
|
-
public onKeyup(): void {
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/** --- CDN 地址 --- */
|
|
216
|
-
export function getCdn(): string {
|
|
217
|
-
return loader.cdn;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/** --- boot 类 --- */
|
|
221
|
-
export let boot: import('../index').AbstractBoot;
|
|
222
|
-
|
|
223
|
-
clickgo.vue.watch(config, function() {
|
|
224
|
-
// --- 检测有没有缺少的 config key ---
|
|
225
|
-
for (const key in configOrigin) {
|
|
226
|
-
if ((config as any)[key] !== undefined) {
|
|
227
|
-
continue;
|
|
228
|
-
}
|
|
229
|
-
form.notify({
|
|
230
|
-
'title': 'Warning',
|
|
231
|
-
'content': 'There is a software that maliciously removed the system config item.\nKey: ' + key,
|
|
232
|
-
'type': 'warning'
|
|
233
|
-
});
|
|
234
|
-
(config as any)[key] = (configOrigin as any)[key];
|
|
235
|
-
}
|
|
236
|
-
for (const key in config) {
|
|
237
|
-
if (!Object.keys(configOrigin).includes(key)) {
|
|
238
|
-
form.notify({
|
|
239
|
-
'title': 'Warning',
|
|
240
|
-
'content': 'There is a software that maliciously modifies the system config.\nKey: ' + key,
|
|
241
|
-
'type': 'warning'
|
|
242
|
-
});
|
|
243
|
-
delete (config as any)[key];
|
|
244
|
-
continue;
|
|
245
|
-
}
|
|
246
|
-
if (key === 'task.pin') {
|
|
247
|
-
// --- 如果是 pin,要检查老的和新的的 path 是否相等 ---
|
|
248
|
-
const paths = Object.keys(config['task.pin']).sort().toString();
|
|
249
|
-
const originPaths = Object.keys(configOrigin['task.pin']).sort().toString();
|
|
250
|
-
if (paths === originPaths) {
|
|
251
|
-
continue;
|
|
252
|
-
}
|
|
253
|
-
configOrigin['task.pin'] = {};
|
|
254
|
-
for (const path in config['task.pin']) {
|
|
255
|
-
configOrigin['task.pin'][path] = config['task.pin'][path];
|
|
256
|
-
}
|
|
257
|
-
trigger('configChanged', 'task.pin', config['task.pin']);
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
// --- 别的要判断值是否和比对组一样 ---
|
|
261
|
-
if ((config as any)[key] === (configOrigin as any)[key]) {
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
(configOrigin as any)[key] = (config as any)[key];
|
|
265
|
-
if (key === 'task.position') {
|
|
266
|
-
task.refreshSystemPosition();
|
|
267
|
-
}
|
|
268
|
-
trigger('configChanged', key, (config as any)[key]);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}, {
|
|
272
|
-
'deep': true
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
/** --- module 列表 --- */
|
|
276
|
-
const modules: Record<string, {
|
|
277
|
-
func: () => any | Promise<any>;
|
|
278
|
-
'obj': null | any;
|
|
279
|
-
'loading': boolean;
|
|
280
|
-
'resolve': Array<() => void | Promise<void>>;
|
|
281
|
-
}> = {
|
|
282
|
-
'monaco': {
|
|
283
|
-
func: async function() {
|
|
284
|
-
return new Promise(function(resolve, reject) {
|
|
285
|
-
fetch(loader.cdn + '/npm/monaco-editor@0.50.0/min/vs/loader.js').then(function(r) {
|
|
286
|
-
return r.blob();
|
|
287
|
-
}).then(function(b) {
|
|
288
|
-
return tool.blob2DataUrl(b);
|
|
289
|
-
}).then(function(d) {
|
|
290
|
-
resolve(d);
|
|
291
|
-
}).catch(function(e) {
|
|
292
|
-
reject(e);
|
|
293
|
-
});
|
|
294
|
-
});
|
|
295
|
-
},
|
|
296
|
-
'obj': null,
|
|
297
|
-
'loading': false,
|
|
298
|
-
'resolve': []
|
|
299
|
-
},
|
|
300
|
-
'xterm': {
|
|
301
|
-
func: async function() {
|
|
302
|
-
await loader.loadScripts([
|
|
303
|
-
loader.cdn + '/npm/xterm@5.3.0/lib/xterm.js',
|
|
304
|
-
loader.cdn + '/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js',
|
|
305
|
-
loader.cdn + '/npm/xterm-addon-webgl@0.16.0/lib/xterm-addon-webgl.js'
|
|
306
|
-
]);
|
|
307
|
-
if (!(window as any).Terminal) {
|
|
308
|
-
throw Error('Xterm load failed.');
|
|
309
|
-
}
|
|
310
|
-
await loader.loadLinks([
|
|
311
|
-
loader.cdn + '/npm/xterm@5.3.0/css/xterm.min.css'
|
|
312
|
-
]);
|
|
313
|
-
loader.loadStyle('.xterm-viewport::-webkit-scrollbar{display:none;}');
|
|
314
|
-
return [(window as any).Terminal, (window as any).FitAddon.FitAddon, (window as any).WebglAddon.WebglAddon];
|
|
315
|
-
},
|
|
316
|
-
'obj': null,
|
|
317
|
-
'loading': false,
|
|
318
|
-
'resolve': []
|
|
319
|
-
},
|
|
320
|
-
'echarts': {
|
|
321
|
-
func: async function() {
|
|
322
|
-
await loader.loadScript(loader.cdn + '/npm/echarts@5.4.2/dist/echarts.min.js');
|
|
323
|
-
if (!(window as any).echarts) {
|
|
324
|
-
throw Error('Echarts load failed.');
|
|
325
|
-
}
|
|
326
|
-
return (window as any).echarts;
|
|
327
|
-
},
|
|
328
|
-
'obj': null,
|
|
329
|
-
'loading': false,
|
|
330
|
-
'resolve': []
|
|
331
|
-
},
|
|
332
|
-
'tuieditor': {
|
|
333
|
-
func: async function() {
|
|
334
|
-
await loader.loadScripts([
|
|
335
|
-
__dirname + '/../ext/toastui-editor-all.min.js'
|
|
336
|
-
]);
|
|
337
|
-
if (!(window as any).toastui.Editor) {
|
|
338
|
-
throw Error('Tuieditor load failed.');
|
|
339
|
-
}
|
|
340
|
-
await loader.loadScripts([
|
|
341
|
-
loader.cdn + '/npm/@toast-ui/editor@3.2.2/dist/i18n/zh-cn.min.js',
|
|
342
|
-
loader.cdn + '/npm/@toast-ui/editor@3.2.2/dist/i18n/zh-tw.min.js',
|
|
343
|
-
loader.cdn + '/npm/@toast-ui/editor@3.2.2/dist/i18n/ja-jp.min.js',
|
|
344
|
-
loader.cdn + '/npm/@toast-ui/editor@3.2.2/dist/i18n/ko-kr.min.js',
|
|
345
|
-
loader.cdn + '/npm/@toast-ui/editor@3.2.2/dist/i18n/es-es.min.js',
|
|
346
|
-
loader.cdn + '/npm/@toast-ui/editor@3.2.2/dist/i18n/de-de.min.js',
|
|
347
|
-
loader.cdn + '/npm/@toast-ui/editor@3.2.2/dist/i18n/fr-fr.min.js',
|
|
348
|
-
loader.cdn + '/npm/@toast-ui/editor@3.2.2/dist/i18n/pt-br.min.js',
|
|
349
|
-
loader.cdn + '/npm/@toast-ui/editor@3.2.2/dist/i18n/ru-ru.min.js'
|
|
350
|
-
]);
|
|
351
|
-
await loader.loadLinks([
|
|
352
|
-
loader.cdn + '/npm/@toast-ui/editor@3.2.2/dist/toastui-editor.min.css',
|
|
353
|
-
loader.cdn + '/npm/@toast-ui/editor@3.2.2/dist/theme/toastui-editor-dark.css'
|
|
354
|
-
]);
|
|
355
|
-
loader.loadStyle('.toastui-editor-defaultUI-toolbar,.ProseMirror{box-sizing:initial !important}.toastui-editor-main{background:var(--g-plain-background);border-radius:0 0 3px 3px}.ProseMirror{cursor:text}.jodit ::-webkit-scrollbar{width:6px;cursor:default;}.jodit ::-webkit-scrollbar-thumb{background:rgba(0,0,0,.1);border-radius:3px;}.jodit ::-webkit-scrollbar-thumb:hover{background: rgba(0,0,0,.2);}');
|
|
356
|
-
return (window as any).toastui.Editor;
|
|
357
|
-
},
|
|
358
|
-
'obj': null,
|
|
359
|
-
'loading': false,
|
|
360
|
-
'resolve': []
|
|
361
|
-
},
|
|
362
|
-
'jodit': {
|
|
363
|
-
func: async function() {
|
|
364
|
-
await loader.loadScripts([
|
|
365
|
-
loader.cdn + '/npm/jodit@4.2.27/es2015/jodit.fat.min.js'
|
|
366
|
-
]);
|
|
367
|
-
await loader.loadLinks([
|
|
368
|
-
loader.cdn + '/npm/jodit@4.2.27/es2015/jodit.fat.min.css'
|
|
369
|
-
]);
|
|
370
|
-
loader.loadStyle('.jodit-container:not(.jodit_inline){border:none;display:flex;flex-direction:column;}.jodit-container:not(.jodit_inline) .jodit-workplace{cursor:text;flex:1;}.jodit-wysiwyg a{color:unset;}');
|
|
371
|
-
return (window as any).Jodit;
|
|
372
|
-
},
|
|
373
|
-
'obj': null,
|
|
374
|
-
'loading': false,
|
|
375
|
-
'resolve': []
|
|
376
|
-
},
|
|
377
|
-
'compressorjs': {
|
|
378
|
-
func: async function() {
|
|
379
|
-
await loader.loadScripts([
|
|
380
|
-
loader.cdn + '/npm/compressorjs@1.2.1/dist/compressor.min.js'
|
|
381
|
-
]);
|
|
382
|
-
if (!(window as any).Compressor) {
|
|
383
|
-
throw Error('Compressor load failed.');
|
|
384
|
-
}
|
|
385
|
-
return [(window as any).Compressor];
|
|
386
|
-
},
|
|
387
|
-
'obj': null,
|
|
388
|
-
'loading': false,
|
|
389
|
-
'resolve': []
|
|
390
|
-
},
|
|
391
|
-
'pdfjs': {
|
|
392
|
-
func: async function() {
|
|
393
|
-
await loader.loadScripts([
|
|
394
|
-
loader.cdn + '/npm/pdfjs-dist@4.7.76/build/pdf.min.mjs'
|
|
395
|
-
], {
|
|
396
|
-
'module': true
|
|
397
|
-
});
|
|
398
|
-
if (!(window as any).pdfjsLib) {
|
|
399
|
-
throw Error('pdf.js load failed.');
|
|
400
|
-
}
|
|
401
|
-
(window as any).pdfjsLib.GlobalWorkerOptions.workerSrc = loader.cdn + '/npm/pdfjs-dist@4.7.76/build/pdf.worker.min.mjs';
|
|
402
|
-
return (window as any).pdfjsLib;
|
|
403
|
-
},
|
|
404
|
-
'obj': null,
|
|
405
|
-
'loading': false,
|
|
406
|
-
'resolve': []
|
|
407
|
-
},
|
|
408
|
-
'qrcode': {
|
|
409
|
-
func: async function() {
|
|
410
|
-
await loader.loadScripts([
|
|
411
|
-
loader.cdn + '/npm/qrcode@1.5.1/build/qrcode.js'
|
|
412
|
-
]);
|
|
413
|
-
if (!(window as any).QRCode) {
|
|
414
|
-
throw Error('QRCode load failed.');
|
|
415
|
-
}
|
|
416
|
-
return (window as any).QRCode;
|
|
417
|
-
},
|
|
418
|
-
'obj': null,
|
|
419
|
-
'loading': false,
|
|
420
|
-
'resolve': []
|
|
421
|
-
},
|
|
422
|
-
'mpegts': {
|
|
423
|
-
func: async function() {
|
|
424
|
-
await loader.loadScripts([
|
|
425
|
-
loader.cdn + '/npm/mpegts.js@1.7.3/dist/mpegts.min.js'
|
|
426
|
-
]);
|
|
427
|
-
if (!(window as any).mpegts) {
|
|
428
|
-
throw Error('mpegts load failed.');
|
|
429
|
-
}
|
|
430
|
-
(window as any).mpegts.LoggingControl.enableAll = false;
|
|
431
|
-
return (window as any).mpegts;
|
|
432
|
-
},
|
|
433
|
-
'obj': null,
|
|
434
|
-
'loading': false,
|
|
435
|
-
'resolve': []
|
|
436
|
-
},
|
|
437
|
-
'tplink': {
|
|
438
|
-
func: async function() {
|
|
439
|
-
await loader.loadScripts([
|
|
440
|
-
__dirname + '/../ext/tplinkhd.min.js'
|
|
441
|
-
]);
|
|
442
|
-
if (!(window as any).HDPluginControl) {
|
|
443
|
-
throw Error('Tplink load failed.');
|
|
444
|
-
}
|
|
445
|
-
return (window as any).HDPluginControl;
|
|
446
|
-
},
|
|
447
|
-
'obj': null,
|
|
448
|
-
'loading': false,
|
|
449
|
-
'resolve': [],
|
|
450
|
-
},
|
|
451
|
-
// --- 腾讯云验证码 ---
|
|
452
|
-
'tcc': {
|
|
453
|
-
func: async function() {
|
|
454
|
-
await loader.loadScripts([
|
|
455
|
-
'https://turing.captcha.qcloud.com/TJCaptcha.js'
|
|
456
|
-
]);
|
|
457
|
-
if (!(window as any).TencentCaptcha) {
|
|
458
|
-
throw Error('tcc load failed.');
|
|
459
|
-
}
|
|
460
|
-
return (window as any).TencentCaptcha;
|
|
461
|
-
},
|
|
462
|
-
'obj': null,
|
|
463
|
-
'loading': false,
|
|
464
|
-
'resolve': [],
|
|
465
|
-
},
|
|
466
|
-
// --- cf 验证码 ---
|
|
467
|
-
'cft': {
|
|
468
|
-
func: async function() {
|
|
469
|
-
await loader.loadScripts([
|
|
470
|
-
'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit'
|
|
471
|
-
]);
|
|
472
|
-
if (!(window as any).turnstile) {
|
|
473
|
-
throw Error('cft load failed.');
|
|
474
|
-
}
|
|
475
|
-
return (window as any).turnstile;
|
|
476
|
-
},
|
|
477
|
-
'obj': null,
|
|
478
|
-
'loading': false,
|
|
479
|
-
'resolve': [],
|
|
480
|
-
},
|
|
481
|
-
};
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* --- 注册新的外接模块,App 模式下无效 ---
|
|
485
|
-
* @param name 模块名
|
|
486
|
-
* @param func 执行加载函数
|
|
487
|
-
*/
|
|
488
|
-
export function regModule(name: string, func: () => any | Promise<any>): boolean {
|
|
489
|
-
if (modules[name]) {
|
|
490
|
-
return false;
|
|
491
|
-
}
|
|
492
|
-
modules[name] = {
|
|
493
|
-
func: func,
|
|
494
|
-
'obj': null,
|
|
495
|
-
'loading': false,
|
|
496
|
-
'resolve': []
|
|
497
|
-
};
|
|
498
|
-
return true;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
/**
|
|
502
|
-
* --- 获取外接模块 ---
|
|
503
|
-
* @param name 模块名
|
|
504
|
-
*/
|
|
505
|
-
export function getModule(name: string): Promise<null | any> {
|
|
506
|
-
return new Promise((resolve) => {
|
|
507
|
-
if (!modules[name]) {
|
|
508
|
-
resolve(null);
|
|
509
|
-
return;
|
|
510
|
-
}
|
|
511
|
-
if (!modules[name].obj) {
|
|
512
|
-
// --- obj 是 null 判断是否要初始化 ---
|
|
513
|
-
if (modules[name].loading) {
|
|
514
|
-
// --- 加载中,等待 ---
|
|
515
|
-
modules[name].resolve.push(() => {
|
|
516
|
-
resolve(modules[name].obj);
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
else {
|
|
520
|
-
// --- 没加载,开始加载 ---
|
|
521
|
-
const rtn = modules[name].func();
|
|
522
|
-
if (rtn instanceof Promise) {
|
|
523
|
-
modules[name].loading = true;
|
|
524
|
-
rtn.then(function(obj) {
|
|
525
|
-
modules[name].obj = obj;
|
|
526
|
-
modules[name].loading = false;
|
|
527
|
-
resolve(obj);
|
|
528
|
-
for (const r of modules[name].resolve) {
|
|
529
|
-
r() as any;
|
|
530
|
-
}
|
|
531
|
-
}).catch(function() {
|
|
532
|
-
modules[name].loading = false;
|
|
533
|
-
resolve(null);
|
|
534
|
-
for (const r of modules[name].resolve) {
|
|
535
|
-
r() as any;
|
|
536
|
-
}
|
|
537
|
-
});
|
|
538
|
-
}
|
|
539
|
-
else {
|
|
540
|
-
modules[name].obj = rtn;
|
|
541
|
-
resolve(rtn);
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
return;
|
|
545
|
-
}
|
|
546
|
-
resolve(modules[name].obj);
|
|
547
|
-
return;
|
|
548
|
-
});
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
/** --- 系统要处理的全局响应事件 --- */
|
|
552
|
-
const globalEvents = {
|
|
553
|
-
screenResize: function(): void {
|
|
554
|
-
form.refreshMaxPosition();
|
|
555
|
-
},
|
|
556
|
-
formRemoved: function(taskId: number, formId: number): void {
|
|
557
|
-
if (!form.simpleSystemTaskRoot.forms[formId]) {
|
|
558
|
-
return;
|
|
559
|
-
}
|
|
560
|
-
delete form.simpleSystemTaskRoot.forms[formId];
|
|
561
|
-
},
|
|
562
|
-
formTitleChanged: function(taskId: number, formId: number, title: string): void {
|
|
563
|
-
if (!form.simpleSystemTaskRoot.forms[formId]) {
|
|
564
|
-
return;
|
|
565
|
-
}
|
|
566
|
-
form.simpleSystemTaskRoot.forms[formId].title = title;
|
|
567
|
-
},
|
|
568
|
-
formIconChanged: function(taskId: number, formId: number, icon: string): void {
|
|
569
|
-
if (!form.simpleSystemTaskRoot.forms[formId]) {
|
|
570
|
-
return;
|
|
571
|
-
}
|
|
572
|
-
form.simpleSystemTaskRoot.forms[formId].icon = icon;
|
|
573
|
-
},
|
|
574
|
-
formStateMinChanged: function(taskId: number, formId: number, state: boolean): void {
|
|
575
|
-
if (task.systemTaskInfo.taskId > 0) {
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
if (state) {
|
|
579
|
-
const item = form.get(formId);
|
|
580
|
-
if (!item) {
|
|
581
|
-
return;
|
|
582
|
-
}
|
|
583
|
-
form.simpleSystemTaskRoot.forms[formId] = {
|
|
584
|
-
'title': item.title,
|
|
585
|
-
'icon': item.icon
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
else {
|
|
589
|
-
if (!form.simpleSystemTaskRoot.forms[formId]) {
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
delete form.simpleSystemTaskRoot.forms[formId];
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
};
|
|
596
|
-
|
|
597
|
-
/**
|
|
598
|
-
* --- 主动触发系统级事件,App 中无效,用 this.trigger 替代 ---
|
|
599
|
-
*/
|
|
600
|
-
export function trigger(name: types.TGlobalEvent, taskId: number | string | boolean | KeyboardEvent = 0, formId: number | string | boolean | Record<string, any> | null = 0, param1: boolean | Error | string = '', param2: string | Record<string, any> = '', param3: boolean = true): void {
|
|
601
|
-
const eventName = 'on' + name[0].toUpperCase() + name.slice(1);
|
|
602
|
-
switch (name) {
|
|
603
|
-
case 'error': {
|
|
604
|
-
if (typeof taskId !== 'number' || typeof formId !== 'number') {
|
|
605
|
-
break;
|
|
606
|
-
}
|
|
607
|
-
(boot as any)?.[eventName](taskId, formId, param1, param2);
|
|
608
|
-
for (const tid in task.list) {
|
|
609
|
-
const t = task.list[tid];
|
|
610
|
-
(t.class as any)?.[eventName](taskId, formId, param1, param2);
|
|
611
|
-
for (const fid in t.forms) {
|
|
612
|
-
t.forms[fid].vroot[eventName]?.(taskId, formId, param1, param2);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
break;
|
|
616
|
-
}
|
|
617
|
-
case 'screenResize': {
|
|
618
|
-
globalEvents.screenResize();
|
|
619
|
-
(boot as any)?.[eventName]();
|
|
620
|
-
for (const tid in task.list) {
|
|
621
|
-
const t = task.list[tid];
|
|
622
|
-
(t.class as any)?.[eventName]();
|
|
623
|
-
for (const fid in t.forms) {
|
|
624
|
-
t.forms[fid].vroot[eventName]?.();
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
break;
|
|
628
|
-
}
|
|
629
|
-
case 'configChanged': {
|
|
630
|
-
if ((typeof taskId !== 'string') || (typeof formId === 'number')) {
|
|
631
|
-
break;
|
|
632
|
-
}
|
|
633
|
-
(boot as any)?.[eventName]();
|
|
634
|
-
for (const tid in task.list) {
|
|
635
|
-
const t = task.list[tid];
|
|
636
|
-
(t.class as any)?.[eventName](taskId, formId);
|
|
637
|
-
for (const fid in t.forms) {
|
|
638
|
-
t.forms[fid].vroot[eventName]?.(taskId, formId);
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
break;
|
|
642
|
-
}
|
|
643
|
-
case 'formCreated':
|
|
644
|
-
case 'formRemoved': {
|
|
645
|
-
(globalEvents as any)[name]?.(taskId, formId, param1, param2, param3);
|
|
646
|
-
(boot as any)?.[eventName](taskId, formId, param1, param2, param3);
|
|
647
|
-
for (const tid in task.list) {
|
|
648
|
-
const t = task.list[tid];
|
|
649
|
-
(t.class as any)?.[eventName](taskId, formId, param1, param2, param3);
|
|
650
|
-
for (const fid in t.forms) {
|
|
651
|
-
t.forms[fid].vroot[eventName]?.(taskId, formId, param1, param2, param3);
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
break;
|
|
655
|
-
}
|
|
656
|
-
case 'formTitleChanged':
|
|
657
|
-
case 'formIconChanged': {
|
|
658
|
-
(globalEvents as any)[name]?.(taskId, formId, param1);
|
|
659
|
-
(boot as any)?.[eventName](taskId, formId, param1);
|
|
660
|
-
for (const tid in task.list) {
|
|
661
|
-
const t = task.list[tid];
|
|
662
|
-
(t.class as any)?.[eventName](taskId, formId, param1);
|
|
663
|
-
for (const fid in t.forms) {
|
|
664
|
-
t.forms[fid].vroot[eventName]?.(taskId, formId, param1);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
break;
|
|
668
|
-
}
|
|
669
|
-
case 'formStateMinChanged':
|
|
670
|
-
case 'formStateMaxChanged':
|
|
671
|
-
case 'formShowChanged': {
|
|
672
|
-
(globalEvents as any)[name]?.(taskId, formId, param1);
|
|
673
|
-
(boot as any)?.[eventName](taskId, formId, param1);
|
|
674
|
-
for (const tid in task.list) {
|
|
675
|
-
const t = task.list[tid];
|
|
676
|
-
(t.class as any)?.[eventName](taskId, formId, param1);
|
|
677
|
-
for (const fid in t.forms) {
|
|
678
|
-
t.forms[fid].vroot[eventName]?.(taskId, formId, param1);
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
break;
|
|
682
|
-
}
|
|
683
|
-
case 'formFocused':
|
|
684
|
-
case 'formBlurred':
|
|
685
|
-
case 'formFlash': {
|
|
686
|
-
(globalEvents as any)[name]?.(taskId, formId);
|
|
687
|
-
(boot as any)?.[eventName](taskId, formId);
|
|
688
|
-
for (const tid in task.list) {
|
|
689
|
-
const t = task.list[tid];
|
|
690
|
-
(t.class as any)?.[eventName](taskId, formId);
|
|
691
|
-
for (const fid in t.forms) {
|
|
692
|
-
t.forms[fid].vroot[eventName]?.(taskId, formId);
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
break;
|
|
696
|
-
}
|
|
697
|
-
case 'formShowInSystemTaskChange': {
|
|
698
|
-
(globalEvents as any)[name]?.(taskId, formId, param1);
|
|
699
|
-
(boot as any)?.[eventName](taskId, formId, param1);
|
|
700
|
-
for (const tid in task.list) {
|
|
701
|
-
const t = task.list[tid];
|
|
702
|
-
(t.class as any)?.[eventName](taskId, formId, param1);
|
|
703
|
-
for (const fid in t.forms) {
|
|
704
|
-
t.forms[fid].vroot[eventName]?.(taskId, formId, param1);
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
break;
|
|
708
|
-
}
|
|
709
|
-
case 'formHashChange': {
|
|
710
|
-
(globalEvents as any)[name]?.(taskId, formId, param1, param2);
|
|
711
|
-
(boot as any)?.[eventName](taskId, formId, param1, param2);
|
|
712
|
-
for (const tid in task.list) {
|
|
713
|
-
const t = task.list[tid];
|
|
714
|
-
(t.class as any)?.[eventName](taskId, formId, param1, param2);
|
|
715
|
-
for (const fid in t.forms) {
|
|
716
|
-
t.forms[fid].vroot[eventName]?.(taskId, formId, param1, param2);
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
break;
|
|
720
|
-
}
|
|
721
|
-
case 'taskStarted':
|
|
722
|
-
case 'taskEnded': {
|
|
723
|
-
(globalEvents as any)[name]?.(taskId, formId);
|
|
724
|
-
(boot as any)?.[eventName](taskId, formId);
|
|
725
|
-
for (const tid in task.list) {
|
|
726
|
-
const t = task.list[tid];
|
|
727
|
-
(t.class as any)?.[eventName](taskId);
|
|
728
|
-
for (const fid in t.forms) {
|
|
729
|
-
t.forms[fid].vroot[eventName]?.(taskId);
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
break;
|
|
733
|
-
}
|
|
734
|
-
case 'launcherFolderNameChanged': {
|
|
735
|
-
if (typeof formId !== 'string') {
|
|
736
|
-
break;
|
|
737
|
-
}
|
|
738
|
-
if (typeof taskId !== 'string') {
|
|
739
|
-
taskId = taskId.toString();
|
|
740
|
-
}
|
|
741
|
-
(boot as any)?.[eventName](taskId, formId);
|
|
742
|
-
for (const tid in task.list) {
|
|
743
|
-
const t = task.list[tid];
|
|
744
|
-
(t.class as any)?.[eventName](taskId, formId);
|
|
745
|
-
for (const fid in t.forms) {
|
|
746
|
-
t.forms[fid].vroot[eventName]?.(taskId, formId);
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
break;
|
|
750
|
-
}
|
|
751
|
-
case 'hashChanged': {
|
|
752
|
-
if (typeof taskId !== 'string') {
|
|
753
|
-
break;
|
|
754
|
-
}
|
|
755
|
-
(boot as any)?.[eventName](taskId);
|
|
756
|
-
for (const tid in task.list) {
|
|
757
|
-
const t = task.list[tid];
|
|
758
|
-
(t.class as any)?.[eventName](taskId);
|
|
759
|
-
for (const fid in t.forms) {
|
|
760
|
-
t.forms[fid].vroot[eventName]?.(taskId);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
break;
|
|
764
|
-
}
|
|
765
|
-
case 'keydown':
|
|
766
|
-
case 'keyup': {
|
|
767
|
-
(globalEvents as any)[name]?.(taskId);
|
|
768
|
-
(boot as any)?.[eventName](taskId);
|
|
769
|
-
for (const tid in task.list) {
|
|
770
|
-
const t = task.list[tid];
|
|
771
|
-
(t.class as any)?.[eventName](taskId);
|
|
772
|
-
for (const fid in t.forms) {
|
|
773
|
-
t.forms[fid].vroot[eventName]?.(taskId);
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
break;
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
/**
|
|
782
|
-
* --- cga blob 文件解包 ---
|
|
783
|
-
* @param blob blob 对象
|
|
784
|
-
*/
|
|
785
|
-
export async function readApp(blob: Blob): Promise<false | types.IApp> {
|
|
786
|
-
const head = await tool.blob2Text(blob.slice(0, 5));
|
|
787
|
-
if (head !== '-CGA-') {
|
|
788
|
-
return false;
|
|
789
|
-
}
|
|
790
|
-
const iconLength = parseInt(await blob.slice(21, 28).text());
|
|
791
|
-
if (Number.isNaN(iconLength)) {
|
|
792
|
-
return false;
|
|
793
|
-
}
|
|
794
|
-
const icon = iconLength ? await tool.blob2DataUrl(blob.slice(28, 28 + iconLength)) : '';
|
|
795
|
-
const nb = new Blob([blob.slice(5, 21), blob.slice(28 + iconLength)], {
|
|
796
|
-
'type': blob.type
|
|
797
|
-
});
|
|
798
|
-
const z = await zip.get(nb);
|
|
799
|
-
if (!z) {
|
|
800
|
-
return false;
|
|
801
|
-
}
|
|
802
|
-
// --- 开始读取文件 ---
|
|
803
|
-
const files: Record<string, Blob | string> = {};
|
|
804
|
-
/** --- 配置文件 --- */
|
|
805
|
-
const configContent = await z.getContent('/config.json');
|
|
806
|
-
if (!configContent) {
|
|
807
|
-
return false;
|
|
808
|
-
}
|
|
809
|
-
const config: types.IAppConfig = JSON.parse(configContent);
|
|
810
|
-
// --- 读取包 ---
|
|
811
|
-
const list = z.readDir('/', {
|
|
812
|
-
'hasChildren': true
|
|
813
|
-
});
|
|
814
|
-
for (const file of list) {
|
|
815
|
-
const mime = tool.getMimeByPath(file.name);
|
|
816
|
-
if (['txt', 'json', 'js', 'css', 'xml', 'html'].includes(mime.ext)) {
|
|
817
|
-
const fab = await z.getContent(file.path + file.name, 'string');
|
|
818
|
-
if (!fab) {
|
|
819
|
-
continue;
|
|
820
|
-
}
|
|
821
|
-
files[file.path + file.name] = fab.replace(/^\ufeff/, '');
|
|
822
|
-
}
|
|
823
|
-
else {
|
|
824
|
-
const fab = await z.getContent(file.path + file.name, 'arraybuffer');
|
|
825
|
-
if (!fab) {
|
|
826
|
-
continue;
|
|
827
|
-
}
|
|
828
|
-
files[file.path + file.name] = new Blob([fab], {
|
|
829
|
-
'type': mime.mime
|
|
830
|
-
});
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
return {
|
|
834
|
-
'type': 'app',
|
|
835
|
-
'config': config,
|
|
836
|
-
'files': files,
|
|
837
|
-
'icon': icon
|
|
838
|
-
};
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
/**
|
|
842
|
-
* --- 从网址下载应用,App 模式下本方法不可用 ---
|
|
843
|
-
* @param url 对于当前网页的相对、绝对路径,以 / 结尾的目录或 .cga 结尾的文件 ---
|
|
844
|
-
* @param opt,notifyId:显示进度条的 notify id,current:设置则以设置的为准,不以 / 结尾,否则以 location 为准 ---
|
|
845
|
-
* @param taskId 所属任务 ID
|
|
846
|
-
*/
|
|
847
|
-
export async function fetchApp(
|
|
848
|
-
url: string,
|
|
849
|
-
opt: types.ICoreFetchAppOptions = {},
|
|
850
|
-
taskId?: number
|
|
851
|
-
): Promise<null | types.IApp> {
|
|
852
|
-
/** --- 若是 cga 文件,则是 cga 的文件名,含 .cga --- */
|
|
853
|
-
let cga: string = '';
|
|
854
|
-
if (!url.endsWith('/')) {
|
|
855
|
-
const lio = url.lastIndexOf('/');
|
|
856
|
-
cga = lio === -1 ? url : url.slice(lio + 1);
|
|
857
|
-
if (!cga.endsWith('.cga')) {
|
|
858
|
-
return null;
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
// --- 非 taskId 模式下 current 以 location 为准 ---
|
|
862
|
-
if (!taskId &&
|
|
863
|
-
!url.startsWith('/clickgo/') &&
|
|
864
|
-
!url.startsWith('/storage/') &&
|
|
865
|
-
!url.startsWith('/mounted/') &&
|
|
866
|
-
!url.startsWith('/package/') &&
|
|
867
|
-
!url.startsWith('/current/') &&
|
|
868
|
-
!url.startsWith('http:') &&
|
|
869
|
-
!url.startsWith('https:') &&
|
|
870
|
-
!url.startsWith('file:')
|
|
871
|
-
) {
|
|
872
|
-
url = tool.urlResolve(window.location.href, url);
|
|
873
|
-
}
|
|
874
|
-
// --- 如果是 cga 文件,直接读取并交给 readApp 函数处理 ---
|
|
875
|
-
if (cga) {
|
|
876
|
-
try {
|
|
877
|
-
const blob = await fs.getContent(url, {
|
|
878
|
-
'progress': (loaded: number, total: number): void => {
|
|
879
|
-
if (opt.notifyId) {
|
|
880
|
-
form.notifyProgress(opt.notifyId, loaded / total);
|
|
881
|
-
}
|
|
882
|
-
if (opt.progress) {
|
|
883
|
-
opt.progress(loaded, total) as unknown;
|
|
884
|
-
}
|
|
885
|
-
},
|
|
886
|
-
'cache': opt.cache
|
|
887
|
-
}, taskId);
|
|
888
|
-
if ((blob === null) || typeof blob === 'string') {
|
|
889
|
-
return null;
|
|
890
|
-
}
|
|
891
|
-
if (opt.notifyId) {
|
|
892
|
-
form.notifyProgress(opt.notifyId, 1);
|
|
893
|
-
}
|
|
894
|
-
return await readApp(blob) || null;
|
|
895
|
-
}
|
|
896
|
-
catch {
|
|
897
|
-
return null;
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
// --- 从网络加载 app ---
|
|
901
|
-
let config: types.IAppConfig;
|
|
902
|
-
/** --- 已加载的 files --- */
|
|
903
|
-
const files: Record<string, Blob | string> = {};
|
|
904
|
-
try {
|
|
905
|
-
const blob = await fs.getContent(url + 'config.json', {
|
|
906
|
-
'cache': opt.cache
|
|
907
|
-
}, taskId);
|
|
908
|
-
if (blob === null || typeof blob === 'string') {
|
|
909
|
-
return null;
|
|
910
|
-
}
|
|
911
|
-
config = JSON.parse(await tool.blob2Text(blob));
|
|
912
|
-
await new Promise<void>(function(resolve) {
|
|
913
|
-
if (!config.files) {
|
|
914
|
-
return;
|
|
915
|
-
}
|
|
916
|
-
const total = config.files.length;
|
|
917
|
-
let loaded = 0;
|
|
918
|
-
if (opt.progress) {
|
|
919
|
-
opt.progress(loaded + 1, total + 1) as unknown;
|
|
920
|
-
}
|
|
921
|
-
for (const file of config.files) {
|
|
922
|
-
fs.getContent(url + file.slice(1), {
|
|
923
|
-
'cache': opt.cache
|
|
924
|
-
}, taskId).then(async function(blob) {
|
|
925
|
-
if (blob === null || typeof blob === 'string') {
|
|
926
|
-
clickgo.form.notify({
|
|
927
|
-
'title': 'File not found',
|
|
928
|
-
'content': url + file.slice(1),
|
|
929
|
-
'type': 'danger'
|
|
930
|
-
});
|
|
931
|
-
return;
|
|
932
|
-
}
|
|
933
|
-
const mime = tool.getMimeByPath(file);
|
|
934
|
-
if (['txt', 'json', 'js', 'css', 'xml', 'html'].includes(mime.ext)) {
|
|
935
|
-
files[file] = (await tool.blob2Text(blob)).replace(/^\ufeff/, '');
|
|
936
|
-
}
|
|
937
|
-
else {
|
|
938
|
-
files[file] = blob;
|
|
939
|
-
}
|
|
940
|
-
++loaded;
|
|
941
|
-
if (opt.notifyId) {
|
|
942
|
-
form.notifyProgress(opt.notifyId, loaded / total);
|
|
943
|
-
}
|
|
944
|
-
if (opt.progress) {
|
|
945
|
-
opt.progress(loaded + 1, total + 1) as unknown;
|
|
946
|
-
}
|
|
947
|
-
if (loaded < total) {
|
|
948
|
-
return;
|
|
949
|
-
}
|
|
950
|
-
resolve();
|
|
951
|
-
}).catch(function() {
|
|
952
|
-
++loaded;
|
|
953
|
-
if (opt.notifyId) {
|
|
954
|
-
form.notifyProgress(opt.notifyId, loaded / total);
|
|
955
|
-
}
|
|
956
|
-
if (opt.progress) {
|
|
957
|
-
opt.progress(loaded + 1, total + 1) as unknown;
|
|
958
|
-
}
|
|
959
|
-
if (loaded < total) {
|
|
960
|
-
return;
|
|
961
|
-
}
|
|
962
|
-
resolve();
|
|
963
|
-
});
|
|
964
|
-
}
|
|
965
|
-
});
|
|
966
|
-
}
|
|
967
|
-
catch (e: any) {
|
|
968
|
-
console.log('core.fetchApp', e);
|
|
969
|
-
trigger('error', 0, 0, e, e.message);
|
|
970
|
-
return null;
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
let icon = '';
|
|
974
|
-
if (config.icon && (files[config.icon] instanceof Blob)) {
|
|
975
|
-
icon = await tool.blob2DataUrl(files[config.icon] as Blob);
|
|
976
|
-
}
|
|
977
|
-
if (icon === '') {
|
|
978
|
-
const iconBlob = await fs.getContent('/clickgo/icon.png', undefined, taskId);
|
|
979
|
-
if (iconBlob instanceof Blob) {
|
|
980
|
-
icon = await tool.blob2DataUrl(iconBlob);
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
return {
|
|
985
|
-
'type': 'app',
|
|
986
|
-
'config': config,
|
|
987
|
-
'files': files,
|
|
988
|
-
'icon': icon
|
|
989
|
-
};
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
/**
|
|
993
|
-
* --- 获取屏幕可用区域 ---
|
|
994
|
-
*/
|
|
995
|
-
export function getAvailArea(): types.IAvailArea {
|
|
996
|
-
if (Object.keys(form.simpleSystemTaskRoot.forms).length > 0) {
|
|
997
|
-
return {
|
|
998
|
-
'left': 0,
|
|
999
|
-
'top': 0,
|
|
1000
|
-
'width': window.innerWidth,
|
|
1001
|
-
'height': window.innerHeight - 46,
|
|
1002
|
-
'owidth': window.innerWidth,
|
|
1003
|
-
'oheight': window.innerHeight
|
|
1004
|
-
};
|
|
1005
|
-
}
|
|
1006
|
-
else {
|
|
1007
|
-
let left: number = 0;
|
|
1008
|
-
let top: number = 0;
|
|
1009
|
-
let width: number = 0;
|
|
1010
|
-
let height: number = 0;
|
|
1011
|
-
switch (config['task.position']) {
|
|
1012
|
-
case 'left': {
|
|
1013
|
-
left = task.systemTaskInfo.length;
|
|
1014
|
-
top = 0;
|
|
1015
|
-
width = window.innerWidth - task.systemTaskInfo.length;
|
|
1016
|
-
height = window.innerHeight;
|
|
1017
|
-
break;
|
|
1018
|
-
}
|
|
1019
|
-
case 'right': {
|
|
1020
|
-
left = 0;
|
|
1021
|
-
top = 0;
|
|
1022
|
-
width = window.innerWidth - task.systemTaskInfo.length;
|
|
1023
|
-
height = window.innerHeight;
|
|
1024
|
-
break;
|
|
1025
|
-
}
|
|
1026
|
-
case 'top': {
|
|
1027
|
-
left = 0;
|
|
1028
|
-
top = task.systemTaskInfo.length;
|
|
1029
|
-
width = window.innerWidth;
|
|
1030
|
-
height = window.innerHeight - task.systemTaskInfo.length;
|
|
1031
|
-
break;
|
|
1032
|
-
}
|
|
1033
|
-
case 'bottom': {
|
|
1034
|
-
left = 0;
|
|
1035
|
-
top = 0;
|
|
1036
|
-
width = window.innerWidth;
|
|
1037
|
-
height = window.innerHeight - task.systemTaskInfo.length;
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
return {
|
|
1041
|
-
'left': left,
|
|
1042
|
-
'top': top,
|
|
1043
|
-
'width': width,
|
|
1044
|
-
'height': height,
|
|
1045
|
-
'owidth': window.innerWidth,
|
|
1046
|
-
'oheight': window.innerHeight
|
|
1047
|
-
};
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
/**
|
|
1052
|
-
* --- 修改浏览器 hash ---
|
|
1053
|
-
* @param hash 修改的值,不含 #
|
|
1054
|
-
* @param taskId 基任务,App 模式下无效
|
|
1055
|
-
*/
|
|
1056
|
-
export function hash(hash: string, taskId?: number): boolean {
|
|
1057
|
-
if (!taskId) {
|
|
1058
|
-
return false;
|
|
1059
|
-
}
|
|
1060
|
-
const t = task.list[taskId];
|
|
1061
|
-
if (!t) {
|
|
1062
|
-
return false;
|
|
1063
|
-
}
|
|
1064
|
-
if (!t.runtime.permissions.includes('root') && !t.runtime.permissions.includes('hash')) {
|
|
1065
|
-
return false;
|
|
1066
|
-
}
|
|
1067
|
-
window.location.hash = hash;
|
|
1068
|
-
return true;
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
/**
|
|
1072
|
-
* --- 获取当前浏览器的 hash ---
|
|
1073
|
-
*/
|
|
1074
|
-
export function getHash(): string {
|
|
1075
|
-
return window.location.hash ? decodeURIComponent(window.location.hash.slice(1)) : '';
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
/**
|
|
1079
|
-
* --- 获取当前浏览器的 host ---
|
|
1080
|
-
*/
|
|
1081
|
-
export function getHost(): string {
|
|
1082
|
-
const match = /https?:\/\/([-a-zA-Z0-9:.]+)/.exec(window.location.href);
|
|
1083
|
-
if (!match) {
|
|
1084
|
-
return '';
|
|
1085
|
-
}
|
|
1086
|
-
return match[1];
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
/**
|
|
1090
|
-
* --- 对浏览器做跳转操作 ---
|
|
1091
|
-
* @param url 要跳转的新 URL
|
|
1092
|
-
* @param taskId 基任务,App 模式下无效
|
|
1093
|
-
*/
|
|
1094
|
-
export function location(url: string, taskId?: number): boolean {
|
|
1095
|
-
if (!taskId) {
|
|
1096
|
-
return false;
|
|
1097
|
-
}
|
|
1098
|
-
const t = task.list[taskId];
|
|
1099
|
-
if (!t) {
|
|
1100
|
-
return false;
|
|
1101
|
-
}
|
|
1102
|
-
if (!t.runtime.permissions.includes('root') && !t.runtime.permissions.includes('location')) {
|
|
1103
|
-
return false;
|
|
1104
|
-
}
|
|
1105
|
-
window.location.href = url;
|
|
1106
|
-
return true;
|
|
1107
|
-
}
|
|
1108
|
-
|
|
1109
|
-
/**
|
|
1110
|
-
* --- 获取当前的浏览器的 url ---
|
|
1111
|
-
*/
|
|
1112
|
-
export function getLocation(): string {
|
|
1113
|
-
return window.location.href;
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
/**
|
|
1117
|
-
* --- 对浏览器做返回操作 ---
|
|
1118
|
-
* @param taskId 基任务,App 模式下无效
|
|
1119
|
-
*/
|
|
1120
|
-
export function back(taskId?: number): boolean {
|
|
1121
|
-
if (!taskId) {
|
|
1122
|
-
return false;
|
|
1123
|
-
}
|
|
1124
|
-
const t = task.list[taskId];
|
|
1125
|
-
if (!t) {
|
|
1126
|
-
return false;
|
|
1127
|
-
}
|
|
1128
|
-
if (!t.runtime.permissions.includes('root') && !t.runtime.permissions.includes('location')) {
|
|
1129
|
-
return false;
|
|
1130
|
-
}
|
|
1131
|
-
window.history.back();
|
|
1132
|
-
return true;
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
/**
|
|
1136
|
-
* --- 打开新的标签页
|
|
1137
|
-
* @param url 要访问的网址
|
|
1138
|
-
*/
|
|
1139
|
-
export function open(url: string): void {
|
|
1140
|
-
window.open(url);
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
window.addEventListener('hashchange', function() {
|
|
1144
|
-
trigger('hashChanged', window.location.hash ? decodeURIComponent(window.location.hash.slice(1)) : '');
|
|
1145
|
-
});
|