clickgo 3.0.6-dev7 → 3.1.0-dev9
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/app.js +93 -0
- package/dist/app/demo/form/control/form/form.js +21 -20
- package/dist/app/demo/form/control/form/form.xml +3 -3
- package/dist/app/demo/form/main.js +20 -10
- package/dist/app/demo/form/main.xml +1 -1
- package/dist/app/task/app.js +46 -0
- package/dist/app/task/form/bar/bar.js +85 -86
- package/dist/app/task/form/bar/bar.xml +5 -6
- package/dist/clickgo.js +1 -10
- package/dist/clickgo.ts +0 -8
- package/dist/control/common.cgc +0 -0
- package/dist/control/form.cgc +0 -0
- package/dist/control/monaco.cgc +0 -0
- package/dist/control/property.cgc +0 -0
- package/dist/control/task.cgc +0 -0
- package/dist/global.css +1 -1
- package/dist/index.js +105 -56
- package/dist/index.ts +164 -59
- package/dist/lib/control.js +363 -240
- package/dist/lib/control.ts +497 -284
- package/dist/lib/core.js +331 -217
- package/dist/lib/core.ts +418 -244
- package/dist/lib/dom.js +6 -3
- package/dist/lib/dom.ts +7 -6
- package/dist/lib/form.js +635 -980
- package/dist/lib/form.ts +817 -1072
- package/dist/lib/fs.js +42 -39
- package/dist/lib/fs.ts +45 -41
- package/dist/lib/native.js +8 -148
- package/dist/lib/native.ts +9 -211
- package/dist/lib/task.js +707 -191
- package/dist/lib/task.ts +778 -210
- package/dist/lib/theme.ts +2 -2
- package/dist/lib/tool.js +58 -48
- package/dist/lib/tool.ts +79 -64
- package/dist/theme/familiar.cgt +0 -0
- package/package.json +5 -7
- package/types/index.d.ts +286 -324
- package/dist/app/demo/config.json +0 -106
- package/dist/app/task/config.json +0 -32
package/dist/lib/core.ts
CHANGED
|
@@ -19,8 +19,12 @@ import * as fs from './fs';
|
|
|
19
19
|
import * as form from './form';
|
|
20
20
|
import * as task from './task';
|
|
21
21
|
import * as tool from './tool';
|
|
22
|
+
import * as control from './control';
|
|
23
|
+
import * as theme from './theme';
|
|
22
24
|
import * as zip from './zip';
|
|
25
|
+
import * as dom from './dom';
|
|
23
26
|
|
|
27
|
+
/** --- Config 原始参考对象 --- */
|
|
24
28
|
const configOrigin: types.IConfig = {
|
|
25
29
|
'locale': 'en',
|
|
26
30
|
'task.position': 'bottom',
|
|
@@ -28,8 +32,11 @@ const configOrigin: types.IConfig = {
|
|
|
28
32
|
'desktop.icon.storage': true,
|
|
29
33
|
'desktop.icon.recycler': true,
|
|
30
34
|
'desktop.wallpaper': null,
|
|
31
|
-
'desktop.path': null
|
|
35
|
+
'desktop.path': null,
|
|
36
|
+
'launcher.list': []
|
|
32
37
|
};
|
|
38
|
+
|
|
39
|
+
/** --- Config 配置对象 --- */
|
|
33
40
|
export const config: types.IConfig = clickgo.vue.reactive({
|
|
34
41
|
'locale': 'en',
|
|
35
42
|
'task.position': 'bottom',
|
|
@@ -37,10 +44,300 @@ export const config: types.IConfig = clickgo.vue.reactive({
|
|
|
37
44
|
'desktop.icon.storage': true,
|
|
38
45
|
'desktop.icon.recycler': true,
|
|
39
46
|
'desktop.wallpaper': null,
|
|
40
|
-
'desktop.path': null
|
|
47
|
+
'desktop.path': null,
|
|
48
|
+
'launcher.list': []
|
|
41
49
|
});
|
|
42
50
|
|
|
43
|
-
|
|
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(): Promise<void>;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* --- 先设置 App 的配置信息 ---
|
|
77
|
+
* @param config 配置对象
|
|
78
|
+
*/
|
|
79
|
+
public async config(config: types.IAppConfig): Promise<boolean> {
|
|
80
|
+
const t = task.list[this.taskId];
|
|
81
|
+
if (!t) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
t.config = config;
|
|
85
|
+
// --- 加载余下的 xml 等静态包内资源,仅限 net 的 app 模式 ---
|
|
86
|
+
if (t.app.net) {
|
|
87
|
+
if (!t.config.files) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
const files = t.config.files;
|
|
91
|
+
const net = t.app.net;
|
|
92
|
+
await new Promise<void>(function(resolve) {
|
|
93
|
+
let loaded = 0;
|
|
94
|
+
const total = files.length;
|
|
95
|
+
const beforeTotal = Object.keys(t.app.files).length;
|
|
96
|
+
net.progress?.(loaded + beforeTotal, total + beforeTotal) as unknown;
|
|
97
|
+
for (const file of files) {
|
|
98
|
+
fs.getContent(net.url + file.slice(1), {
|
|
99
|
+
'current': net.current
|
|
100
|
+
}).then(async function(blob) {
|
|
101
|
+
if (blob === null || typeof blob === 'string') {
|
|
102
|
+
clickgo.form.notify({
|
|
103
|
+
'title': 'File not found',
|
|
104
|
+
'content': net.url + file.slice(1),
|
|
105
|
+
'type': 'danger'
|
|
106
|
+
});
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const mime = tool.getMimeByPath(file);
|
|
110
|
+
if (['txt', 'json', 'js', 'css', 'xml', 'html'].includes(mime.ext)) {
|
|
111
|
+
t.app.files[file] = (await tool.blob2Text(blob)).replace(/^\ufeff/, '');
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
t.app.files[file] = blob;
|
|
115
|
+
}
|
|
116
|
+
++loaded;
|
|
117
|
+
net.progress?.(loaded + beforeTotal, total + beforeTotal) as unknown;
|
|
118
|
+
if (net.notify) {
|
|
119
|
+
form.notifyProgress(net.notify, (loaded / total) / 2 + 0.5);
|
|
120
|
+
}
|
|
121
|
+
if (loaded < total) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
resolve();
|
|
125
|
+
}).catch(function() {
|
|
126
|
+
++loaded;
|
|
127
|
+
net.progress?.(loaded + beforeTotal, total + beforeTotal) as unknown;
|
|
128
|
+
if (net.notify) {
|
|
129
|
+
form.notifyProgress(net.notify, (loaded / total) / 2 + 0.5);
|
|
130
|
+
}
|
|
131
|
+
if (loaded < total) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
resolve();
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
if (net.notify) {
|
|
139
|
+
setTimeout(function(): void {
|
|
140
|
+
form.hideNotify(net.notify!);
|
|
141
|
+
}, 2000);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// --- 要加载 control ---
|
|
145
|
+
if (!await control.init(this.taskId)) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
// --- theme ---
|
|
149
|
+
if (config.themes?.length) {
|
|
150
|
+
for (let path of config.themes) {
|
|
151
|
+
path += '.cgt';
|
|
152
|
+
path = tool.urlResolve('/', path);
|
|
153
|
+
const file = await fs.getContent(path, {
|
|
154
|
+
'files': t.app.files,
|
|
155
|
+
'current': t.current
|
|
156
|
+
});
|
|
157
|
+
if (file && typeof file !== 'string') {
|
|
158
|
+
const th = await theme.read(file);
|
|
159
|
+
if (th) {
|
|
160
|
+
await theme.load(th, t.id);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
// --- 加载全局主题 ---
|
|
167
|
+
if (theme.global) {
|
|
168
|
+
await theme.load(undefined, this.taskId);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// --- locale ---
|
|
172
|
+
if (config.locales) {
|
|
173
|
+
for (let path in config.locales) {
|
|
174
|
+
const locale = config.locales[path];
|
|
175
|
+
if (!path.endsWith('.json')) {
|
|
176
|
+
path += '.json';
|
|
177
|
+
}
|
|
178
|
+
const lcontent = await fs.getContent(path, {
|
|
179
|
+
'encoding': 'utf8',
|
|
180
|
+
'files': t.app.files,
|
|
181
|
+
'current': t.current
|
|
182
|
+
});
|
|
183
|
+
if (!lcontent) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
const data = JSON.parse(lcontent);
|
|
188
|
+
task.loadLocaleData(locale, data, '', t.id);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// --- 无所谓 ---
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// --- 加载任务级全局样式 ---
|
|
196
|
+
if (config.style) {
|
|
197
|
+
const style = await fs.getContent(config.style + '.css', {
|
|
198
|
+
'encoding': 'utf8',
|
|
199
|
+
'files': t.app.files,
|
|
200
|
+
'current': t.current
|
|
201
|
+
});
|
|
202
|
+
if (style) {
|
|
203
|
+
const r = tool.stylePrepend(style, 'cg-task' + this.taskId.toString() + '_');
|
|
204
|
+
dom.pushStyle(this.taskId, await tool.styleUrl2DataUrl(config.style, r.style, t.app.files));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// --- 加载图标 ---
|
|
208
|
+
if (config.icon) {
|
|
209
|
+
const icon = await fs.getContent(config.icon, {
|
|
210
|
+
'files': t.app.files,
|
|
211
|
+
'current': t.current
|
|
212
|
+
});
|
|
213
|
+
if (icon && typeof icon !== 'string') {
|
|
214
|
+
t.app.icon = await tool.blob2DataUrl(icon);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// --- 全部成功,设置 t.class 为自己 ---
|
|
218
|
+
t.class = this;
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* --- 以某个窗体进行正式启动这个 app(入口 form),不启动则任务也启动失败 ---
|
|
224
|
+
* @param form 窗体对象
|
|
225
|
+
*/
|
|
226
|
+
public run(form: form.AbstractForm | number): void {
|
|
227
|
+
if (typeof form === 'number') {
|
|
228
|
+
// --- 报错 ---
|
|
229
|
+
const msg = 'Application run error, Form creation failed (' + form.toString() + ').';
|
|
230
|
+
trigger('error', this.taskId, 0, new Error(msg), msg);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
form.show();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** --- 全局错误事件 --- */
|
|
237
|
+
public onError(taskId: number, formId: number, error: Error, info: string): void | Promise<void>;
|
|
238
|
+
public onError(): void {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** --- 屏幕大小改变事件 --- */
|
|
243
|
+
public onScreenResize(): void | Promise<void>;
|
|
244
|
+
public onScreenResize(): void {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** --- 系统配置变更事件 --- */
|
|
249
|
+
public onConfigChanged<T extends types.IConfig, TK extends keyof T>(n: TK, v: T[TK]): void | Promise<void>;
|
|
250
|
+
public onConfigChanged(): void {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** --- 窗体创建事件 --- */
|
|
255
|
+
public onFormCreated(taskId: number, formId: number, title: string, icon: string): void | Promise<void>;
|
|
256
|
+
public onFormCreated(): void {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** --- 窗体销毁事件 */
|
|
261
|
+
public onFormRemoved(taskId: number, formId: number, title: string, icon: string): void | Promise<void>;
|
|
262
|
+
public onFormRemoved(): void {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** --- 窗体标题改变事件 */
|
|
267
|
+
public onFormTitleChanged(taskId: number, formId: number, title: string): void | Promise<void>;
|
|
268
|
+
public onFormTitleChanged(): void | Promise<void> {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** --- 窗体图标改变事件 --- */
|
|
273
|
+
public onFormIconChanged(taskId: number, formId: number, icon: string): void | Promise<void>;
|
|
274
|
+
public onFormIconChanged(): void | Promise<void> {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** --- 窗体最小化状态改变事件 --- */
|
|
279
|
+
public onFormStateMinChanged(taskId: number, formId: number, state: boolean): void | Promise<void>;
|
|
280
|
+
public onFormStateMinChanged(): void {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** --- 窗体最大化状态改变事件 --- */
|
|
285
|
+
public onFormStateMaxChanged(taskId: number, formId: number, state: boolean): void | Promise<void>;
|
|
286
|
+
public onFormStateMaxChanged(): void {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** --- 窗体显示状态改变事件 --- */
|
|
291
|
+
public onFormShowChanged(taskId: number, formId: number, state: boolean): void | Promise<void>;
|
|
292
|
+
public onFormShowChanged(): void {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/** --- 窗体获得焦点事件 --- */
|
|
297
|
+
public onFormFocused(taskId: number, formId: number): void | Promise<void>;
|
|
298
|
+
public onFormFocused(): void {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** --- 窗体丢失焦点事件 --- */
|
|
303
|
+
public onFormBlurred(taskId: number, formId: number): void | Promise<void>;
|
|
304
|
+
public onFormBlurred(): void {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** --- 窗体闪烁事件 --- */
|
|
309
|
+
public onFormFlash(taskId: number, formId: number): void | Promise<void>;
|
|
310
|
+
public onFormFlash(): void {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** --- 任务开始事件 --- */
|
|
315
|
+
public onTaskStarted(taskId: number): void | Promise<void>;
|
|
316
|
+
public onTaskStarted(): void | Promise<void> {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** --- 任务结束事件 --- */
|
|
321
|
+
public onTaskEnded(taskId: number): void | Promise<void>;
|
|
322
|
+
public onTaskEnded(): void | Promise<void> {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/** --- launcher 文件夹名称修改事件 --- */
|
|
327
|
+
public onLauncherFolderNameChanged(id: string, name: string): void | Promise<void>;
|
|
328
|
+
public onLauncherFolderNameChanged(): void {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** --- CDN 地址 --- */
|
|
335
|
+
export function getCdn(): string {
|
|
336
|
+
return loader.cdn;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** --- boot 类 --- */
|
|
340
|
+
export let boot: import('../index').AbstractBoot;
|
|
44
341
|
|
|
45
342
|
clickgo.vue.watch(config, function() {
|
|
46
343
|
// --- 检测有没有缺少的 config key ---
|
|
@@ -99,7 +396,7 @@ const modules: Record<string, { func: () => any | Promise<any>; 'obj': null | an
|
|
|
99
396
|
'monaco': {
|
|
100
397
|
func: async function() {
|
|
101
398
|
return new Promise(function(resolve, reject) {
|
|
102
|
-
fetch(loader.cdn + '/npm/monaco-editor@0.
|
|
399
|
+
fetch(loader.cdn + '/npm/monaco-editor@0.34.1/min/vs/loader.js').then(function(r) {
|
|
103
400
|
return r.blob();
|
|
104
401
|
}).then(function(b) {
|
|
105
402
|
return tool.blob2DataUrl(b);
|
|
@@ -116,7 +413,7 @@ const modules: Record<string, { func: () => any | Promise<any>; 'obj': null | an
|
|
|
116
413
|
};
|
|
117
414
|
|
|
118
415
|
/**
|
|
119
|
-
* ---
|
|
416
|
+
* --- 注册新的外接模块,App 模式下无效 ---
|
|
120
417
|
* @param name 模块名
|
|
121
418
|
* @param func 执行加载函数
|
|
122
419
|
*/
|
|
@@ -218,33 +515,30 @@ export function getModule(name: string): null | any {
|
|
|
218
515
|
return modules[name].obj;
|
|
219
516
|
}
|
|
220
517
|
|
|
221
|
-
/** ---
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
screenResizeHandler: function(): void {
|
|
518
|
+
/** --- 系统要处理的全局响应事件 --- */
|
|
519
|
+
const globalEvents = {
|
|
520
|
+
screenResize: function(): void {
|
|
225
521
|
form.refreshMaxPosition();
|
|
226
522
|
},
|
|
227
|
-
|
|
228
|
-
formCreatedHandler: null,
|
|
229
|
-
formRemovedHandler: function(taskId: number, formId: number): void {
|
|
523
|
+
formRemoved: function(taskId: number, formId: number): void {
|
|
230
524
|
if (!form.simpleSystemTaskRoot.forms[formId]) {
|
|
231
525
|
return;
|
|
232
526
|
}
|
|
233
527
|
delete form.simpleSystemTaskRoot.forms[formId];
|
|
234
528
|
},
|
|
235
|
-
|
|
529
|
+
formTitleChanged: function(taskId: number, formId: number, title: string): void {
|
|
236
530
|
if (!form.simpleSystemTaskRoot.forms[formId]) {
|
|
237
531
|
return;
|
|
238
532
|
}
|
|
239
533
|
form.simpleSystemTaskRoot.forms[formId].title = title;
|
|
240
534
|
},
|
|
241
|
-
|
|
535
|
+
formIconChanged: function(taskId: number, formId: number, icon: string): void {
|
|
242
536
|
if (!form.simpleSystemTaskRoot.forms[formId]) {
|
|
243
537
|
return;
|
|
244
538
|
}
|
|
245
539
|
form.simpleSystemTaskRoot.forms[formId].icon = icon;
|
|
246
540
|
},
|
|
247
|
-
|
|
541
|
+
formStateMinChanged: function(taskId: number, formId: number, state: boolean): void {
|
|
248
542
|
if (task.systemTaskInfo.taskId > 0) {
|
|
249
543
|
return;
|
|
250
544
|
}
|
|
@@ -264,118 +558,37 @@ export const globalEvents: types.IGlobalEvents = {
|
|
|
264
558
|
}
|
|
265
559
|
delete form.simpleSystemTaskRoot.forms[formId];
|
|
266
560
|
}
|
|
267
|
-
},
|
|
268
|
-
formStateMaxChangedHandler: null,
|
|
269
|
-
formShowChangedHandler: null,
|
|
270
|
-
formFocusedHandler: null,
|
|
271
|
-
formBlurredHandler: null,
|
|
272
|
-
formFlashHandler: null,
|
|
273
|
-
taskStartedHandler: null,
|
|
274
|
-
taskEndedHandler: null
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* --- 设置系统事件监听,一个窗体只能设置一个监听 ---
|
|
279
|
-
* @param name 系统事件名
|
|
280
|
-
* @param func 回调函数
|
|
281
|
-
* @param formId 窗体 id,app 模式下留空为当前窗体
|
|
282
|
-
* @param taskId 任务 id,app 模式下无效
|
|
283
|
-
*/
|
|
284
|
-
export function setSystemEventListener(
|
|
285
|
-
name: types.TGlobalEvent,
|
|
286
|
-
func: (...any: any) => void | Promise<void>,
|
|
287
|
-
formId?: number,
|
|
288
|
-
taskId?: number
|
|
289
|
-
): void {
|
|
290
|
-
if (!taskId) {
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
const t = task.list[taskId];
|
|
294
|
-
if (!t) {
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
if (!formId) {
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
const f = t.forms[formId];
|
|
301
|
-
if (!f) {
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
f.events[name] = func;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* --- 移除系统事件监听,一个窗体只能设置一个监听 ---
|
|
309
|
-
* @param name name 系统事件名
|
|
310
|
-
* @param formId 窗体 id,app 默认为当前窗体
|
|
311
|
-
* @param taskId 任务 id,app 模式下无效
|
|
312
|
-
*/
|
|
313
|
-
export function removeSystemEventListener(
|
|
314
|
-
name: types.TGlobalEvent,
|
|
315
|
-
formId?: number,
|
|
316
|
-
taskId?: number
|
|
317
|
-
): void {
|
|
318
|
-
if (!taskId) {
|
|
319
|
-
return;
|
|
320
561
|
}
|
|
321
|
-
|
|
322
|
-
if (!t) {
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
if (!formId) {
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
const f = t.forms[formId];
|
|
329
|
-
if (!f) {
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
delete f.events[name];
|
|
333
|
-
}
|
|
562
|
+
};
|
|
334
563
|
|
|
335
564
|
/**
|
|
336
|
-
* ---
|
|
565
|
+
* --- 主动触发系统级事件,App 中无效,用 this.trigger 替代 ---
|
|
337
566
|
*/
|
|
338
|
-
export function trigger(name: types.TGlobalEvent, taskId: number | string = 0, formId: number | string | boolean | Record<string, any> | null = 0, param1: boolean | Error | string = '', param2: string = ''): void {
|
|
567
|
+
export function trigger(name: types.TGlobalEvent, taskId: number | string | boolean = 0, formId: number | string | boolean | Record<string, any> | null = 0, param1: boolean | Error | string = '', param2: string = ''): void {
|
|
568
|
+
const eventName = 'on' + name[0].toUpperCase() + name.slice(1);
|
|
339
569
|
switch (name) {
|
|
340
570
|
case 'error': {
|
|
341
571
|
if (typeof taskId !== 'number' || typeof formId !== 'number') {
|
|
342
572
|
break;
|
|
343
573
|
}
|
|
344
|
-
|
|
345
|
-
if (r && (r instanceof Promise)) {
|
|
346
|
-
r.catch(function(e) {
|
|
347
|
-
console.log(e);
|
|
348
|
-
});
|
|
349
|
-
}
|
|
574
|
+
(boot as any)[eventName](taskId, formId, param1, param2);
|
|
350
575
|
for (const tid in task.list) {
|
|
351
576
|
const t = task.list[tid];
|
|
577
|
+
(t.class as any)?.[eventName](taskId, formId, param1, param2);
|
|
352
578
|
for (const fid in t.forms) {
|
|
353
|
-
|
|
354
|
-
if (r instanceof Promise) {
|
|
355
|
-
r.catch(function(e) {
|
|
356
|
-
console.log(e);
|
|
357
|
-
});
|
|
358
|
-
}
|
|
579
|
+
t.forms[fid].vroot[eventName]?.(taskId, formId, param1, param2);
|
|
359
580
|
}
|
|
360
581
|
}
|
|
361
582
|
break;
|
|
362
583
|
}
|
|
363
584
|
case 'screenResize': {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
r.catch(function(e) {
|
|
367
|
-
console.log(e);
|
|
368
|
-
});
|
|
369
|
-
}
|
|
585
|
+
globalEvents.screenResize();
|
|
586
|
+
(boot as any)[eventName]();
|
|
370
587
|
for (const tid in task.list) {
|
|
371
588
|
const t = task.list[tid];
|
|
589
|
+
(t.class as any)?.[eventName]();
|
|
372
590
|
for (const fid in t.forms) {
|
|
373
|
-
|
|
374
|
-
if (r instanceof Promise) {
|
|
375
|
-
r.catch(function(e) {
|
|
376
|
-
console.log(e);
|
|
377
|
-
});
|
|
378
|
-
}
|
|
591
|
+
t.forms[fid].vroot[eventName]?.();
|
|
379
592
|
}
|
|
380
593
|
}
|
|
381
594
|
break;
|
|
@@ -384,53 +597,38 @@ export function trigger(name: types.TGlobalEvent, taskId: number | string = 0, f
|
|
|
384
597
|
if ((typeof taskId !== 'string') || (typeof formId === 'number')) {
|
|
385
598
|
break;
|
|
386
599
|
}
|
|
387
|
-
|
|
388
|
-
if (r && (r instanceof Promise)) {
|
|
389
|
-
r.catch(function(e) {
|
|
390
|
-
console.log(e);
|
|
391
|
-
});
|
|
392
|
-
}
|
|
600
|
+
(boot as any)[eventName]();
|
|
393
601
|
for (const tid in task.list) {
|
|
394
602
|
const t = task.list[tid];
|
|
603
|
+
(t.class as any)?.[eventName](taskId, formId);
|
|
395
604
|
for (const fid in t.forms) {
|
|
396
|
-
|
|
397
|
-
if (r instanceof Promise) {
|
|
398
|
-
r.catch(function(e) {
|
|
399
|
-
console.log(e);
|
|
400
|
-
});
|
|
401
|
-
}
|
|
605
|
+
t.forms[fid].vroot[eventName]?.(taskId, formId);
|
|
402
606
|
}
|
|
403
607
|
}
|
|
404
608
|
break;
|
|
405
609
|
}
|
|
406
610
|
case 'formCreated':
|
|
407
611
|
case 'formRemoved': {
|
|
408
|
-
(globalEvents as any)[name
|
|
612
|
+
(globalEvents as any)[name]?.(taskId, formId, param1, param2);
|
|
613
|
+
(boot as any)[eventName](taskId, formId, param1, param2);
|
|
409
614
|
for (const tid in task.list) {
|
|
410
615
|
const t = task.list[tid];
|
|
616
|
+
(t.class as any)?.[eventName](taskId, formId, param1, param2);
|
|
411
617
|
for (const fid in t.forms) {
|
|
412
|
-
|
|
413
|
-
if (r instanceof Promise) {
|
|
414
|
-
r.catch(function(e) {
|
|
415
|
-
console.log(e);
|
|
416
|
-
});
|
|
417
|
-
}
|
|
618
|
+
t.forms[fid].vroot[eventName]?.(taskId, formId, param1, param2);
|
|
418
619
|
}
|
|
419
620
|
}
|
|
420
621
|
break;
|
|
421
622
|
}
|
|
422
623
|
case 'formTitleChanged':
|
|
423
624
|
case 'formIconChanged': {
|
|
424
|
-
(globalEvents as any)[name
|
|
625
|
+
(globalEvents as any)[name]?.(taskId, formId, param1);
|
|
626
|
+
(boot as any)[eventName](taskId, formId, param1);
|
|
425
627
|
for (const tid in task.list) {
|
|
426
628
|
const t = task.list[tid];
|
|
629
|
+
(t.class as any)?.[eventName](taskId, formId, param1);
|
|
427
630
|
for (const fid in t.forms) {
|
|
428
|
-
|
|
429
|
-
if (r instanceof Promise) {
|
|
430
|
-
r.catch(function(e) {
|
|
431
|
-
console.log(e);
|
|
432
|
-
});
|
|
433
|
-
}
|
|
631
|
+
t.forms[fid].vroot[eventName]?.(taskId, formId, param1);
|
|
434
632
|
}
|
|
435
633
|
}
|
|
436
634
|
break;
|
|
@@ -438,16 +636,13 @@ export function trigger(name: types.TGlobalEvent, taskId: number | string = 0, f
|
|
|
438
636
|
case 'formStateMinChanged':
|
|
439
637
|
case 'formStateMaxChanged':
|
|
440
638
|
case 'formShowChanged': {
|
|
441
|
-
(globalEvents as any)[name
|
|
639
|
+
(globalEvents as any)[name]?.(taskId, formId, param1);
|
|
640
|
+
(boot as any)[eventName](taskId, formId, param1);
|
|
442
641
|
for (const tid in task.list) {
|
|
443
642
|
const t = task.list[tid];
|
|
643
|
+
(t.class as any)?.[eventName](taskId, formId, param1);
|
|
444
644
|
for (const fid in t.forms) {
|
|
445
|
-
|
|
446
|
-
if (r instanceof Promise) {
|
|
447
|
-
r.catch(function(e) {
|
|
448
|
-
console.log(e);
|
|
449
|
-
});
|
|
450
|
-
}
|
|
645
|
+
t.forms[fid].vroot[eventName]?.(taskId, formId, param1);
|
|
451
646
|
}
|
|
452
647
|
}
|
|
453
648
|
break;
|
|
@@ -455,32 +650,43 @@ export function trigger(name: types.TGlobalEvent, taskId: number | string = 0, f
|
|
|
455
650
|
case 'formFocused':
|
|
456
651
|
case 'formBlurred':
|
|
457
652
|
case 'formFlash': {
|
|
458
|
-
(globalEvents as any)[name
|
|
653
|
+
(globalEvents as any)[name]?.(taskId, formId);
|
|
654
|
+
(boot as any)[eventName](taskId, formId);
|
|
459
655
|
for (const tid in task.list) {
|
|
460
656
|
const t = task.list[tid];
|
|
657
|
+
(t.class as any)?.[eventName](taskId, formId);
|
|
461
658
|
for (const fid in t.forms) {
|
|
462
|
-
|
|
463
|
-
if (r instanceof Promise) {
|
|
464
|
-
r.catch(function(e) {
|
|
465
|
-
console.log(e);
|
|
466
|
-
});
|
|
467
|
-
}
|
|
659
|
+
t.forms[fid].vroot[eventName]?.(taskId, formId);
|
|
468
660
|
}
|
|
469
661
|
}
|
|
470
662
|
break;
|
|
471
663
|
}
|
|
472
664
|
case 'taskStarted':
|
|
473
665
|
case 'taskEnded': {
|
|
474
|
-
(globalEvents as any)[name
|
|
666
|
+
(globalEvents as any)[name]?.(taskId, formId);
|
|
667
|
+
(boot as any)[eventName](taskId, formId);
|
|
475
668
|
for (const tid in task.list) {
|
|
476
669
|
const t = task.list[tid];
|
|
670
|
+
(t.class as any)?.[eventName](taskId);
|
|
477
671
|
for (const fid in t.forms) {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
672
|
+
t.forms[fid].vroot[eventName]?.(taskId);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
break;
|
|
676
|
+
}
|
|
677
|
+
case 'launcherFolderNameChanged': {
|
|
678
|
+
if (typeof formId !== 'string') {
|
|
679
|
+
break;
|
|
680
|
+
}
|
|
681
|
+
if (typeof taskId === 'number') {
|
|
682
|
+
taskId = taskId.toString();
|
|
683
|
+
}
|
|
684
|
+
(boot as any)[eventName](taskId, formId);
|
|
685
|
+
for (const tid in task.list) {
|
|
686
|
+
const t = task.list[tid];
|
|
687
|
+
(t.class as any)?.[eventName](taskId, formId);
|
|
688
|
+
for (const fid in t.forms) {
|
|
689
|
+
t.forms[fid].vroot[eventName]?.(taskId, formId);
|
|
484
690
|
}
|
|
485
691
|
}
|
|
486
692
|
break;
|
|
@@ -489,7 +695,7 @@ export function trigger(name: types.TGlobalEvent, taskId: number | string = 0, f
|
|
|
489
695
|
}
|
|
490
696
|
|
|
491
697
|
/**
|
|
492
|
-
* --- cga
|
|
698
|
+
* --- cga blob 文件解包 ---
|
|
493
699
|
* @param blob blob 对象
|
|
494
700
|
*/
|
|
495
701
|
export async function readApp(blob: Blob): Promise<false | types.IApp> {
|
|
@@ -501,38 +707,30 @@ export async function readApp(blob: Blob): Promise<false | types.IApp> {
|
|
|
501
707
|
}
|
|
502
708
|
// --- 开始读取文件 ---
|
|
503
709
|
const files: Record<string, Blob | string> = {};
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
const config: types.IAppConfig = JSON.parse(configContent);
|
|
510
|
-
for (const file of config.files) {
|
|
511
|
-
const mime = tool.getMimeByPath(file);
|
|
710
|
+
const list = z.readDir('/', {
|
|
711
|
+
'hasChildren': true
|
|
712
|
+
});
|
|
713
|
+
for (const file of list) {
|
|
714
|
+
const mime = tool.getMimeByPath(file.name);
|
|
512
715
|
if (['txt', 'json', 'js', 'css', 'xml', 'html'].includes(mime.ext)) {
|
|
513
|
-
const fab = await z.getContent(file, 'string');
|
|
716
|
+
const fab = await z.getContent(file.path + file.name, 'string');
|
|
514
717
|
if (!fab) {
|
|
515
718
|
continue;
|
|
516
719
|
}
|
|
517
|
-
files[file] = fab.replace(/^\ufeff/, '');
|
|
720
|
+
files[file.path + file.name] = fab.replace(/^\ufeff/, '');
|
|
518
721
|
}
|
|
519
722
|
else {
|
|
520
|
-
const fab = await z.getContent(file, 'arraybuffer');
|
|
723
|
+
const fab = await z.getContent(file.path + file.name, 'arraybuffer');
|
|
521
724
|
if (!fab) {
|
|
522
725
|
continue;
|
|
523
726
|
}
|
|
524
|
-
files[file] = new Blob([fab], {
|
|
727
|
+
files[file.path + file.name] = new Blob([fab], {
|
|
525
728
|
'type': mime.mime
|
|
526
729
|
});
|
|
527
730
|
}
|
|
528
731
|
}
|
|
529
|
-
if (!config) {
|
|
530
|
-
return false;
|
|
531
|
-
}
|
|
532
732
|
return {
|
|
533
|
-
'type': 'app',
|
|
534
733
|
'icon': icon,
|
|
535
|
-
'config': config,
|
|
536
734
|
'files': files
|
|
537
735
|
};
|
|
538
736
|
}
|
|
@@ -540,9 +738,12 @@ export async function readApp(blob: Blob): Promise<false | types.IApp> {
|
|
|
540
738
|
/**
|
|
541
739
|
* --- 从网址下载应用,App 模式下本方法不可用 ---
|
|
542
740
|
* @param url 对于当前网页的相对、绝对路径,以 / 结尾的目录或 .cga 结尾的文件 ---
|
|
543
|
-
* @param opt,notifyId:显示进度条的 notify id,current
|
|
741
|
+
* @param opt,notifyId:显示进度条的 notify id,current:设置则以设置的为准,不以 / 结尾,否则以 location 为准 ---
|
|
544
742
|
*/
|
|
545
|
-
export async function fetchApp(
|
|
743
|
+
export async function fetchApp(
|
|
744
|
+
url: string,
|
|
745
|
+
opt: types.ICoreFetchAppOptions = {}
|
|
746
|
+
): Promise<null | types.IApp> {
|
|
546
747
|
/** --- 若是 cga 文件,则是 cga 的文件名,含 .cga --- */
|
|
547
748
|
let cga: string = '';
|
|
548
749
|
if (!url.endsWith('/')) {
|
|
@@ -555,18 +756,14 @@ export async function fetchApp(url: string, opt: types.ICoreFetchAppOptions = {}
|
|
|
555
756
|
|
|
556
757
|
let current = '';
|
|
557
758
|
if (opt.current) {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
}
|
|
561
|
-
if (!url.startsWith('/')) {
|
|
562
|
-
url = '/current/' + url;
|
|
563
|
-
}
|
|
759
|
+
current = opt.current.endsWith('/') ? opt.current.slice(0, -1) : opt.current;
|
|
760
|
+
url = tool.urlResolve('/current/', url);
|
|
564
761
|
}
|
|
565
762
|
else {
|
|
566
763
|
if (!url.startsWith('/clickgo/') && !url.startsWith('/storage/') && !url.startsWith('/mounted/')) {
|
|
567
764
|
current = tool.urlResolve(window.location.href, url);
|
|
568
765
|
if (cga) {
|
|
569
|
-
current = current.slice(0, -cga.length);
|
|
766
|
+
current = current.slice(0, -cga.length - 1);
|
|
570
767
|
url = '/current/' + cga;
|
|
571
768
|
}
|
|
572
769
|
else {
|
|
@@ -601,75 +798,52 @@ export async function fetchApp(url: string, opt: types.ICoreFetchAppOptions = {}
|
|
|
601
798
|
return null;
|
|
602
799
|
}
|
|
603
800
|
}
|
|
604
|
-
// ---
|
|
605
|
-
|
|
606
|
-
let
|
|
607
|
-
// ---
|
|
608
|
-
const files
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
fs.getContent(url + file.slice(1), {
|
|
622
|
-
'current': current
|
|
623
|
-
}).then(async function(blob) {
|
|
624
|
-
if (blob === null || typeof blob === 'string') {
|
|
625
|
-
clickgo.form.notify({
|
|
626
|
-
'title': 'File not found',
|
|
627
|
-
'content': url + file.slice(1),
|
|
628
|
-
'type': 'danger'
|
|
629
|
-
});
|
|
630
|
-
return;
|
|
631
|
-
}
|
|
632
|
-
const mime = tool.getMimeByPath(file);
|
|
633
|
-
if (['txt', 'json', 'js', 'css', 'xml', 'html'].includes(mime.ext)) {
|
|
634
|
-
files[file] = (await tool.blob2Text(blob)).replace(/^\ufeff/, '');
|
|
635
|
-
}
|
|
636
|
-
else {
|
|
637
|
-
files[file] = blob;
|
|
638
|
-
}
|
|
639
|
-
++loaded;
|
|
640
|
-
opt.progress?.(loaded, total) as unknown;
|
|
641
|
-
if (opt.notifyId) {
|
|
642
|
-
form.notifyProgress(opt.notifyId, loaded / total);
|
|
643
|
-
}
|
|
644
|
-
if (loaded < total) {
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
resolve();
|
|
648
|
-
}).catch(function() {
|
|
649
|
-
++loaded;
|
|
650
|
-
opt.progress?.(loaded, total) as unknown;
|
|
651
|
-
if (opt.notifyId) {
|
|
652
|
-
form.notifyProgress(opt.notifyId, loaded / total);
|
|
653
|
-
}
|
|
654
|
-
if (loaded < total) {
|
|
655
|
-
return;
|
|
656
|
-
}
|
|
657
|
-
resolve();
|
|
658
|
-
});
|
|
801
|
+
// --- 从网络嗅探 ---
|
|
802
|
+
let loaded = 0;
|
|
803
|
+
let total = 30;
|
|
804
|
+
// --- 网络嗅探,不知道文件总数,先暂定 30,不过超出 30 文件的建议打包为 cga ---
|
|
805
|
+
const files = await loader.sniffFiles(url + 'app.js', {
|
|
806
|
+
'dir': '/',
|
|
807
|
+
adapter: async (url) => {
|
|
808
|
+
const r = await fs.getContent(url, {
|
|
809
|
+
'encoding': 'utf8',
|
|
810
|
+
'current': current
|
|
811
|
+
});
|
|
812
|
+
return r;
|
|
813
|
+
},
|
|
814
|
+
'loaded': () => {
|
|
815
|
+
++loaded;
|
|
816
|
+
if (loaded === total) {
|
|
817
|
+
++total;
|
|
659
818
|
}
|
|
660
|
-
|
|
819
|
+
if (opt.notifyId) {
|
|
820
|
+
form.notifyProgress(opt.notifyId, (loaded / total) / 2);
|
|
821
|
+
}
|
|
822
|
+
if (opt.progress) {
|
|
823
|
+
opt.progress(loaded, total) as unknown;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
});
|
|
827
|
+
// --- net 模式此处加载完只算到 50%,因为还有 app 类当中 config 中的静态部分,暂定预留 50% ---
|
|
828
|
+
if (opt.notifyId) {
|
|
829
|
+
form.notifyProgress(opt.notifyId, 0.5);
|
|
661
830
|
}
|
|
662
|
-
|
|
831
|
+
if (Object.keys(files).length === 0) {
|
|
663
832
|
return null;
|
|
664
833
|
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
834
|
+
const ul = url.length - 1;
|
|
835
|
+
for (const fn in files) {
|
|
836
|
+
files[fn.slice(ul)] = files[fn];
|
|
837
|
+
delete files[fn];
|
|
668
838
|
}
|
|
669
839
|
return {
|
|
670
|
-
'
|
|
671
|
-
|
|
672
|
-
|
|
840
|
+
'net': {
|
|
841
|
+
'current': current,
|
|
842
|
+
'notify': opt.notifyId,
|
|
843
|
+
'url': url,
|
|
844
|
+
'progress': opt.progress
|
|
845
|
+
},
|
|
846
|
+
'icon': '',
|
|
673
847
|
'files': files
|
|
674
848
|
};
|
|
675
849
|
}
|