clickgo 3.0.7-dev8 → 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 +84 -88
- package/dist/app/task/form/bar/bar.xml +4 -5
- 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/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 +313 -228
- package/dist/lib/core.ts +400 -255
- package/dist/lib/dom.ts +1 -3
- package/dist/lib/form.js +398 -928
- package/dist/lib/form.ts +630 -1075
- package/dist/lib/fs.js +42 -39
- package/dist/lib/fs.ts +45 -41
- package/dist/lib/native.ts +3 -0
- package/dist/lib/task.js +705 -182
- package/dist/lib/task.ts +775 -200
- 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 +274 -325
- 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',
|
|
@@ -31,6 +35,8 @@ const configOrigin: types.IConfig = {
|
|
|
31
35
|
'desktop.path': null,
|
|
32
36
|
'launcher.list': []
|
|
33
37
|
};
|
|
38
|
+
|
|
39
|
+
/** --- Config 配置对象 --- */
|
|
34
40
|
export const config: types.IConfig = clickgo.vue.reactive({
|
|
35
41
|
'locale': 'en',
|
|
36
42
|
'task.position': 'bottom',
|
|
@@ -42,7 +48,296 @@ export const config: types.IConfig = clickgo.vue.reactive({
|
|
|
42
48
|
'launcher.list': []
|
|
43
49
|
});
|
|
44
50
|
|
|
45
|
-
|
|
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;
|
|
46
341
|
|
|
47
342
|
clickgo.vue.watch(config, function() {
|
|
48
343
|
// --- 检测有没有缺少的 config key ---
|
|
@@ -101,7 +396,7 @@ const modules: Record<string, { func: () => any | Promise<any>; 'obj': null | an
|
|
|
101
396
|
'monaco': {
|
|
102
397
|
func: async function() {
|
|
103
398
|
return new Promise(function(resolve, reject) {
|
|
104
|
-
fetch(loader.cdn + '/npm/monaco-editor@0.
|
|
399
|
+
fetch(loader.cdn + '/npm/monaco-editor@0.34.1/min/vs/loader.js').then(function(r) {
|
|
105
400
|
return r.blob();
|
|
106
401
|
}).then(function(b) {
|
|
107
402
|
return tool.blob2DataUrl(b);
|
|
@@ -118,7 +413,7 @@ const modules: Record<string, { func: () => any | Promise<any>; 'obj': null | an
|
|
|
118
413
|
};
|
|
119
414
|
|
|
120
415
|
/**
|
|
121
|
-
* ---
|
|
416
|
+
* --- 注册新的外接模块,App 模式下无效 ---
|
|
122
417
|
* @param name 模块名
|
|
123
418
|
* @param func 执行加载函数
|
|
124
419
|
*/
|
|
@@ -220,33 +515,30 @@ export function getModule(name: string): null | any {
|
|
|
220
515
|
return modules[name].obj;
|
|
221
516
|
}
|
|
222
517
|
|
|
223
|
-
/** ---
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
screenResizeHandler: function(): void {
|
|
518
|
+
/** --- 系统要处理的全局响应事件 --- */
|
|
519
|
+
const globalEvents = {
|
|
520
|
+
screenResize: function(): void {
|
|
227
521
|
form.refreshMaxPosition();
|
|
228
522
|
},
|
|
229
|
-
|
|
230
|
-
formCreatedHandler: null,
|
|
231
|
-
formRemovedHandler: function(taskId: number, formId: number): void {
|
|
523
|
+
formRemoved: function(taskId: number, formId: number): void {
|
|
232
524
|
if (!form.simpleSystemTaskRoot.forms[formId]) {
|
|
233
525
|
return;
|
|
234
526
|
}
|
|
235
527
|
delete form.simpleSystemTaskRoot.forms[formId];
|
|
236
528
|
},
|
|
237
|
-
|
|
529
|
+
formTitleChanged: function(taskId: number, formId: number, title: string): void {
|
|
238
530
|
if (!form.simpleSystemTaskRoot.forms[formId]) {
|
|
239
531
|
return;
|
|
240
532
|
}
|
|
241
533
|
form.simpleSystemTaskRoot.forms[formId].title = title;
|
|
242
534
|
},
|
|
243
|
-
|
|
535
|
+
formIconChanged: function(taskId: number, formId: number, icon: string): void {
|
|
244
536
|
if (!form.simpleSystemTaskRoot.forms[formId]) {
|
|
245
537
|
return;
|
|
246
538
|
}
|
|
247
539
|
form.simpleSystemTaskRoot.forms[formId].icon = icon;
|
|
248
540
|
},
|
|
249
|
-
|
|
541
|
+
formStateMinChanged: function(taskId: number, formId: number, state: boolean): void {
|
|
250
542
|
if (task.systemTaskInfo.taskId > 0) {
|
|
251
543
|
return;
|
|
252
544
|
}
|
|
@@ -266,119 +558,37 @@ export const globalEvents: types.IGlobalEvents = {
|
|
|
266
558
|
}
|
|
267
559
|
delete form.simpleSystemTaskRoot.forms[formId];
|
|
268
560
|
}
|
|
269
|
-
},
|
|
270
|
-
formStateMaxChangedHandler: null,
|
|
271
|
-
formShowChangedHandler: null,
|
|
272
|
-
formFocusedHandler: null,
|
|
273
|
-
formBlurredHandler: null,
|
|
274
|
-
formFlashHandler: null,
|
|
275
|
-
taskStartedHandler: null,
|
|
276
|
-
taskEndedHandler: null,
|
|
277
|
-
launcherFolderNameChangedHandler: null
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* --- 设置系统事件监听,一个窗体只能设置一个监听 ---
|
|
282
|
-
* @param name 系统事件名
|
|
283
|
-
* @param func 回调函数
|
|
284
|
-
* @param formId 窗体 id,app 模式下留空为当前窗体
|
|
285
|
-
* @param taskId 任务 id,app 模式下无效
|
|
286
|
-
*/
|
|
287
|
-
export function setSystemEventListener(
|
|
288
|
-
name: types.TGlobalEvent,
|
|
289
|
-
func: (...any: any) => void | Promise<void>,
|
|
290
|
-
formId?: number,
|
|
291
|
-
taskId?: number
|
|
292
|
-
): void {
|
|
293
|
-
if (!taskId) {
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
const t = task.list[taskId];
|
|
297
|
-
if (!t) {
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
if (!formId) {
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
const f = t.forms[formId];
|
|
304
|
-
if (!f) {
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
f.events[name] = func;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* --- 移除系统事件监听,一个窗体只能设置一个监听 ---
|
|
312
|
-
* @param name name 系统事件名
|
|
313
|
-
* @param formId 窗体 id,app 默认为当前窗体
|
|
314
|
-
* @param taskId 任务 id,app 模式下无效
|
|
315
|
-
*/
|
|
316
|
-
export function removeSystemEventListener(
|
|
317
|
-
name: types.TGlobalEvent,
|
|
318
|
-
formId?: number,
|
|
319
|
-
taskId?: number
|
|
320
|
-
): void {
|
|
321
|
-
if (!taskId) {
|
|
322
|
-
return;
|
|
323
561
|
}
|
|
324
|
-
|
|
325
|
-
if (!t) {
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
if (!formId) {
|
|
329
|
-
return;
|
|
330
|
-
}
|
|
331
|
-
const f = t.forms[formId];
|
|
332
|
-
if (!f) {
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
delete f.events[name];
|
|
336
|
-
}
|
|
562
|
+
};
|
|
337
563
|
|
|
338
564
|
/**
|
|
339
|
-
* ---
|
|
565
|
+
* --- 主动触发系统级事件,App 中无效,用 this.trigger 替代 ---
|
|
340
566
|
*/
|
|
341
|
-
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);
|
|
342
569
|
switch (name) {
|
|
343
570
|
case 'error': {
|
|
344
571
|
if (typeof taskId !== 'number' || typeof formId !== 'number') {
|
|
345
572
|
break;
|
|
346
573
|
}
|
|
347
|
-
|
|
348
|
-
if (r && (r instanceof Promise)) {
|
|
349
|
-
r.catch(function(e) {
|
|
350
|
-
console.log(e);
|
|
351
|
-
});
|
|
352
|
-
}
|
|
574
|
+
(boot as any)[eventName](taskId, formId, param1, param2);
|
|
353
575
|
for (const tid in task.list) {
|
|
354
576
|
const t = task.list[tid];
|
|
577
|
+
(t.class as any)?.[eventName](taskId, formId, param1, param2);
|
|
355
578
|
for (const fid in t.forms) {
|
|
356
|
-
|
|
357
|
-
if (r instanceof Promise) {
|
|
358
|
-
r.catch(function(e) {
|
|
359
|
-
console.log(e);
|
|
360
|
-
});
|
|
361
|
-
}
|
|
579
|
+
t.forms[fid].vroot[eventName]?.(taskId, formId, param1, param2);
|
|
362
580
|
}
|
|
363
581
|
}
|
|
364
582
|
break;
|
|
365
583
|
}
|
|
366
584
|
case 'screenResize': {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
r.catch(function(e) {
|
|
370
|
-
console.log(e);
|
|
371
|
-
});
|
|
372
|
-
}
|
|
585
|
+
globalEvents.screenResize();
|
|
586
|
+
(boot as any)[eventName]();
|
|
373
587
|
for (const tid in task.list) {
|
|
374
588
|
const t = task.list[tid];
|
|
589
|
+
(t.class as any)?.[eventName]();
|
|
375
590
|
for (const fid in t.forms) {
|
|
376
|
-
|
|
377
|
-
if (r instanceof Promise) {
|
|
378
|
-
r.catch(function(e) {
|
|
379
|
-
console.log(e);
|
|
380
|
-
});
|
|
381
|
-
}
|
|
591
|
+
t.forms[fid].vroot[eventName]?.();
|
|
382
592
|
}
|
|
383
593
|
}
|
|
384
594
|
break;
|
|
@@ -387,53 +597,38 @@ export function trigger(name: types.TGlobalEvent, taskId: number | string = 0, f
|
|
|
387
597
|
if ((typeof taskId !== 'string') || (typeof formId === 'number')) {
|
|
388
598
|
break;
|
|
389
599
|
}
|
|
390
|
-
|
|
391
|
-
if (r && (r instanceof Promise)) {
|
|
392
|
-
r.catch(function(e) {
|
|
393
|
-
console.log(e);
|
|
394
|
-
});
|
|
395
|
-
}
|
|
600
|
+
(boot as any)[eventName]();
|
|
396
601
|
for (const tid in task.list) {
|
|
397
602
|
const t = task.list[tid];
|
|
603
|
+
(t.class as any)?.[eventName](taskId, formId);
|
|
398
604
|
for (const fid in t.forms) {
|
|
399
|
-
|
|
400
|
-
if (r instanceof Promise) {
|
|
401
|
-
r.catch(function(e) {
|
|
402
|
-
console.log(e);
|
|
403
|
-
});
|
|
404
|
-
}
|
|
605
|
+
t.forms[fid].vroot[eventName]?.(taskId, formId);
|
|
405
606
|
}
|
|
406
607
|
}
|
|
407
608
|
break;
|
|
408
609
|
}
|
|
409
610
|
case 'formCreated':
|
|
410
611
|
case 'formRemoved': {
|
|
411
|
-
(globalEvents as any)[name
|
|
612
|
+
(globalEvents as any)[name]?.(taskId, formId, param1, param2);
|
|
613
|
+
(boot as any)[eventName](taskId, formId, param1, param2);
|
|
412
614
|
for (const tid in task.list) {
|
|
413
615
|
const t = task.list[tid];
|
|
616
|
+
(t.class as any)?.[eventName](taskId, formId, param1, param2);
|
|
414
617
|
for (const fid in t.forms) {
|
|
415
|
-
|
|
416
|
-
if (r instanceof Promise) {
|
|
417
|
-
r.catch(function(e) {
|
|
418
|
-
console.log(e);
|
|
419
|
-
});
|
|
420
|
-
}
|
|
618
|
+
t.forms[fid].vroot[eventName]?.(taskId, formId, param1, param2);
|
|
421
619
|
}
|
|
422
620
|
}
|
|
423
621
|
break;
|
|
424
622
|
}
|
|
425
623
|
case 'formTitleChanged':
|
|
426
624
|
case 'formIconChanged': {
|
|
427
|
-
(globalEvents as any)[name
|
|
625
|
+
(globalEvents as any)[name]?.(taskId, formId, param1);
|
|
626
|
+
(boot as any)[eventName](taskId, formId, param1);
|
|
428
627
|
for (const tid in task.list) {
|
|
429
628
|
const t = task.list[tid];
|
|
629
|
+
(t.class as any)?.[eventName](taskId, formId, param1);
|
|
430
630
|
for (const fid in t.forms) {
|
|
431
|
-
|
|
432
|
-
if (r instanceof Promise) {
|
|
433
|
-
r.catch(function(e) {
|
|
434
|
-
console.log(e);
|
|
435
|
-
});
|
|
436
|
-
}
|
|
631
|
+
t.forms[fid].vroot[eventName]?.(taskId, formId, param1);
|
|
437
632
|
}
|
|
438
633
|
}
|
|
439
634
|
break;
|
|
@@ -441,16 +636,13 @@ export function trigger(name: types.TGlobalEvent, taskId: number | string = 0, f
|
|
|
441
636
|
case 'formStateMinChanged':
|
|
442
637
|
case 'formStateMaxChanged':
|
|
443
638
|
case 'formShowChanged': {
|
|
444
|
-
(globalEvents as any)[name
|
|
639
|
+
(globalEvents as any)[name]?.(taskId, formId, param1);
|
|
640
|
+
(boot as any)[eventName](taskId, formId, param1);
|
|
445
641
|
for (const tid in task.list) {
|
|
446
642
|
const t = task.list[tid];
|
|
643
|
+
(t.class as any)?.[eventName](taskId, formId, param1);
|
|
447
644
|
for (const fid in t.forms) {
|
|
448
|
-
|
|
449
|
-
if (r instanceof Promise) {
|
|
450
|
-
r.catch(function(e) {
|
|
451
|
-
console.log(e);
|
|
452
|
-
});
|
|
453
|
-
}
|
|
645
|
+
t.forms[fid].vroot[eventName]?.(taskId, formId, param1);
|
|
454
646
|
}
|
|
455
647
|
}
|
|
456
648
|
break;
|
|
@@ -458,32 +650,26 @@ export function trigger(name: types.TGlobalEvent, taskId: number | string = 0, f
|
|
|
458
650
|
case 'formFocused':
|
|
459
651
|
case 'formBlurred':
|
|
460
652
|
case 'formFlash': {
|
|
461
|
-
(globalEvents as any)[name
|
|
653
|
+
(globalEvents as any)[name]?.(taskId, formId);
|
|
654
|
+
(boot as any)[eventName](taskId, formId);
|
|
462
655
|
for (const tid in task.list) {
|
|
463
656
|
const t = task.list[tid];
|
|
657
|
+
(t.class as any)?.[eventName](taskId, formId);
|
|
464
658
|
for (const fid in t.forms) {
|
|
465
|
-
|
|
466
|
-
if (r instanceof Promise) {
|
|
467
|
-
r.catch(function(e) {
|
|
468
|
-
console.log(e);
|
|
469
|
-
});
|
|
470
|
-
}
|
|
659
|
+
t.forms[fid].vroot[eventName]?.(taskId, formId);
|
|
471
660
|
}
|
|
472
661
|
}
|
|
473
662
|
break;
|
|
474
663
|
}
|
|
475
664
|
case 'taskStarted':
|
|
476
665
|
case 'taskEnded': {
|
|
477
|
-
(globalEvents as any)[name
|
|
666
|
+
(globalEvents as any)[name]?.(taskId, formId);
|
|
667
|
+
(boot as any)[eventName](taskId, formId);
|
|
478
668
|
for (const tid in task.list) {
|
|
479
669
|
const t = task.list[tid];
|
|
670
|
+
(t.class as any)?.[eventName](taskId);
|
|
480
671
|
for (const fid in t.forms) {
|
|
481
|
-
|
|
482
|
-
if (r instanceof Promise) {
|
|
483
|
-
r.catch(function(e) {
|
|
484
|
-
console.log(e);
|
|
485
|
-
});
|
|
486
|
-
}
|
|
672
|
+
t.forms[fid].vroot[eventName]?.(taskId);
|
|
487
673
|
}
|
|
488
674
|
}
|
|
489
675
|
break;
|
|
@@ -495,21 +681,12 @@ export function trigger(name: types.TGlobalEvent, taskId: number | string = 0, f
|
|
|
495
681
|
if (typeof taskId === 'number') {
|
|
496
682
|
taskId = taskId.toString();
|
|
497
683
|
}
|
|
498
|
-
|
|
499
|
-
if (r && (r instanceof Promise)) {
|
|
500
|
-
r.catch(function(e) {
|
|
501
|
-
console.log(e);
|
|
502
|
-
});
|
|
503
|
-
}
|
|
684
|
+
(boot as any)[eventName](taskId, formId);
|
|
504
685
|
for (const tid in task.list) {
|
|
505
686
|
const t = task.list[tid];
|
|
687
|
+
(t.class as any)?.[eventName](taskId, formId);
|
|
506
688
|
for (const fid in t.forms) {
|
|
507
|
-
|
|
508
|
-
if (r instanceof Promise) {
|
|
509
|
-
r.catch(function(e) {
|
|
510
|
-
console.log(e);
|
|
511
|
-
});
|
|
512
|
-
}
|
|
689
|
+
t.forms[fid].vroot[eventName]?.(taskId, formId);
|
|
513
690
|
}
|
|
514
691
|
}
|
|
515
692
|
break;
|
|
@@ -518,7 +695,7 @@ export function trigger(name: types.TGlobalEvent, taskId: number | string = 0, f
|
|
|
518
695
|
}
|
|
519
696
|
|
|
520
697
|
/**
|
|
521
|
-
* --- cga
|
|
698
|
+
* --- cga blob 文件解包 ---
|
|
522
699
|
* @param blob blob 对象
|
|
523
700
|
*/
|
|
524
701
|
export async function readApp(blob: Blob): Promise<false | types.IApp> {
|
|
@@ -530,38 +707,30 @@ export async function readApp(blob: Blob): Promise<false | types.IApp> {
|
|
|
530
707
|
}
|
|
531
708
|
// --- 开始读取文件 ---
|
|
532
709
|
const files: Record<string, Blob | string> = {};
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const config: types.IAppConfig = JSON.parse(configContent);
|
|
539
|
-
for (const file of config.files) {
|
|
540
|
-
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);
|
|
541
715
|
if (['txt', 'json', 'js', 'css', 'xml', 'html'].includes(mime.ext)) {
|
|
542
|
-
const fab = await z.getContent(file, 'string');
|
|
716
|
+
const fab = await z.getContent(file.path + file.name, 'string');
|
|
543
717
|
if (!fab) {
|
|
544
718
|
continue;
|
|
545
719
|
}
|
|
546
|
-
files[file] = fab.replace(/^\ufeff/, '');
|
|
720
|
+
files[file.path + file.name] = fab.replace(/^\ufeff/, '');
|
|
547
721
|
}
|
|
548
722
|
else {
|
|
549
|
-
const fab = await z.getContent(file, 'arraybuffer');
|
|
723
|
+
const fab = await z.getContent(file.path + file.name, 'arraybuffer');
|
|
550
724
|
if (!fab) {
|
|
551
725
|
continue;
|
|
552
726
|
}
|
|
553
|
-
files[file] = new Blob([fab], {
|
|
727
|
+
files[file.path + file.name] = new Blob([fab], {
|
|
554
728
|
'type': mime.mime
|
|
555
729
|
});
|
|
556
730
|
}
|
|
557
731
|
}
|
|
558
|
-
if (!config) {
|
|
559
|
-
return false;
|
|
560
|
-
}
|
|
561
732
|
return {
|
|
562
|
-
'type': 'app',
|
|
563
733
|
'icon': icon,
|
|
564
|
-
'config': config,
|
|
565
734
|
'files': files
|
|
566
735
|
};
|
|
567
736
|
}
|
|
@@ -569,9 +738,12 @@ export async function readApp(blob: Blob): Promise<false | types.IApp> {
|
|
|
569
738
|
/**
|
|
570
739
|
* --- 从网址下载应用,App 模式下本方法不可用 ---
|
|
571
740
|
* @param url 对于当前网页的相对、绝对路径,以 / 结尾的目录或 .cga 结尾的文件 ---
|
|
572
|
-
* @param opt,notifyId:显示进度条的 notify id,current
|
|
741
|
+
* @param opt,notifyId:显示进度条的 notify id,current:设置则以设置的为准,不以 / 结尾,否则以 location 为准 ---
|
|
573
742
|
*/
|
|
574
|
-
export async function fetchApp(
|
|
743
|
+
export async function fetchApp(
|
|
744
|
+
url: string,
|
|
745
|
+
opt: types.ICoreFetchAppOptions = {}
|
|
746
|
+
): Promise<null | types.IApp> {
|
|
575
747
|
/** --- 若是 cga 文件,则是 cga 的文件名,含 .cga --- */
|
|
576
748
|
let cga: string = '';
|
|
577
749
|
if (!url.endsWith('/')) {
|
|
@@ -584,18 +756,14 @@ export async function fetchApp(url: string, opt: types.ICoreFetchAppOptions = {}
|
|
|
584
756
|
|
|
585
757
|
let current = '';
|
|
586
758
|
if (opt.current) {
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
}
|
|
590
|
-
if (!url.startsWith('/')) {
|
|
591
|
-
url = '/current/' + url;
|
|
592
|
-
}
|
|
759
|
+
current = opt.current.endsWith('/') ? opt.current.slice(0, -1) : opt.current;
|
|
760
|
+
url = tool.urlResolve('/current/', url);
|
|
593
761
|
}
|
|
594
762
|
else {
|
|
595
763
|
if (!url.startsWith('/clickgo/') && !url.startsWith('/storage/') && !url.startsWith('/mounted/')) {
|
|
596
764
|
current = tool.urlResolve(window.location.href, url);
|
|
597
765
|
if (cga) {
|
|
598
|
-
current = current.slice(0, -cga.length);
|
|
766
|
+
current = current.slice(0, -cga.length - 1);
|
|
599
767
|
url = '/current/' + cga;
|
|
600
768
|
}
|
|
601
769
|
else {
|
|
@@ -630,75 +798,52 @@ export async function fetchApp(url: string, opt: types.ICoreFetchAppOptions = {}
|
|
|
630
798
|
return null;
|
|
631
799
|
}
|
|
632
800
|
}
|
|
633
|
-
// ---
|
|
634
|
-
|
|
635
|
-
let
|
|
636
|
-
// ---
|
|
637
|
-
const files
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
fs.getContent(url + file.slice(1), {
|
|
651
|
-
'current': current
|
|
652
|
-
}).then(async function(blob) {
|
|
653
|
-
if (blob === null || typeof blob === 'string') {
|
|
654
|
-
clickgo.form.notify({
|
|
655
|
-
'title': 'File not found',
|
|
656
|
-
'content': url + file.slice(1),
|
|
657
|
-
'type': 'danger'
|
|
658
|
-
});
|
|
659
|
-
return;
|
|
660
|
-
}
|
|
661
|
-
const mime = tool.getMimeByPath(file);
|
|
662
|
-
if (['txt', 'json', 'js', 'css', 'xml', 'html'].includes(mime.ext)) {
|
|
663
|
-
files[file] = (await tool.blob2Text(blob)).replace(/^\ufeff/, '');
|
|
664
|
-
}
|
|
665
|
-
else {
|
|
666
|
-
files[file] = blob;
|
|
667
|
-
}
|
|
668
|
-
++loaded;
|
|
669
|
-
opt.progress?.(loaded, total) as unknown;
|
|
670
|
-
if (opt.notifyId) {
|
|
671
|
-
form.notifyProgress(opt.notifyId, loaded / total);
|
|
672
|
-
}
|
|
673
|
-
if (loaded < total) {
|
|
674
|
-
return;
|
|
675
|
-
}
|
|
676
|
-
resolve();
|
|
677
|
-
}).catch(function() {
|
|
678
|
-
++loaded;
|
|
679
|
-
opt.progress?.(loaded, total) as unknown;
|
|
680
|
-
if (opt.notifyId) {
|
|
681
|
-
form.notifyProgress(opt.notifyId, loaded / total);
|
|
682
|
-
}
|
|
683
|
-
if (loaded < total) {
|
|
684
|
-
return;
|
|
685
|
-
}
|
|
686
|
-
resolve();
|
|
687
|
-
});
|
|
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;
|
|
688
818
|
}
|
|
689
|
-
|
|
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);
|
|
690
830
|
}
|
|
691
|
-
|
|
831
|
+
if (Object.keys(files).length === 0) {
|
|
692
832
|
return null;
|
|
693
833
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
834
|
+
const ul = url.length - 1;
|
|
835
|
+
for (const fn in files) {
|
|
836
|
+
files[fn.slice(ul)] = files[fn];
|
|
837
|
+
delete files[fn];
|
|
697
838
|
}
|
|
698
839
|
return {
|
|
699
|
-
'
|
|
700
|
-
|
|
701
|
-
|
|
840
|
+
'net': {
|
|
841
|
+
'current': current,
|
|
842
|
+
'notify': opt.notifyId,
|
|
843
|
+
'url': url,
|
|
844
|
+
'progress': opt.progress
|
|
845
|
+
},
|
|
846
|
+
'icon': '',
|
|
702
847
|
'files': files
|
|
703
848
|
};
|
|
704
849
|
}
|