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/control.ts
DELETED
|
@@ -1,751 +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 core from './core';
|
|
18
|
-
import * as zip from './zip';
|
|
19
|
-
import * as tool from './tool';
|
|
20
|
-
import * as task from './task';
|
|
21
|
-
import * as dom from './dom';
|
|
22
|
-
import * as form from './form';
|
|
23
|
-
import * as fs from './fs';
|
|
24
|
-
|
|
25
|
-
/** --- 窗体的抽象类 --- */
|
|
26
|
-
export abstract class AbstractControl {
|
|
27
|
-
|
|
28
|
-
/** --- 当前 js 文件在包内的完整路径 --- */
|
|
29
|
-
public get filename(): string {
|
|
30
|
-
// --- require 时系统自动在继承类中重写本函数 ---
|
|
31
|
-
return '';
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** --- 当前控件的名字 --- */
|
|
35
|
-
public get controlName(): string {
|
|
36
|
-
// --- init 中系统自动去重写本函数 ---
|
|
37
|
-
return '';
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** --- 当前组件所在的任务 ID --- */
|
|
41
|
-
public get taskId(): number {
|
|
42
|
-
// --- init/require 中系统自动重写本函数 ---
|
|
43
|
-
return 0;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** --- 当前组件所在的窗体 ID --- */
|
|
47
|
-
public get formId(): number {
|
|
48
|
-
// --- buildComponents 时会重写本函数 ---
|
|
49
|
-
return 0;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/** --- root form --- */
|
|
53
|
-
private _rootForm: (form.AbstractForm & Record<string, any>) | null = null;
|
|
54
|
-
|
|
55
|
-
/** --- 当前控件所在窗体的窗体对象 --- */
|
|
56
|
-
public get rootForm(): form.AbstractForm & Record<string, any> {
|
|
57
|
-
if (!this._rootForm) {
|
|
58
|
-
this._rootForm = this.parentByName('root') as any;
|
|
59
|
-
if (!this._rootForm) {
|
|
60
|
-
form.notify({
|
|
61
|
-
'title': 'Error',
|
|
62
|
-
'content': `The "rootForm" is not ready yet.\nFile: "${this.controlName}".`,
|
|
63
|
-
'type': 'danger'
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return this._rootForm!;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** --- 当前组件是否是别的组件的子组件,仅仅是包裹在组件的 layout 初始化中的才算 --- */
|
|
71
|
-
private readonly _rootControl: (AbstractControl & Record<string, any>) | null = null;
|
|
72
|
-
|
|
73
|
-
/** --- 当前组件如果在开发控件层面被包裹了,则可以获取到包裹他的组件对象 --- */
|
|
74
|
-
public get rootControl(): (AbstractControl & Record<string, any>) | null {
|
|
75
|
-
return this._rootControl;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* --- 当前窗体是否有焦点 ---
|
|
80
|
-
*/
|
|
81
|
-
public get formFocus(): boolean {
|
|
82
|
-
return this.rootForm?.formFocus ?? false;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** --- 当前控件所在运行窗体的包内路径不以 / 结尾 --- */
|
|
86
|
-
public get path(): string {
|
|
87
|
-
// --- buildComponents 时会重写本函数 ---
|
|
88
|
-
return '';
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/** --- 样式独占前缀 --- */
|
|
92
|
-
public get prep(): string {
|
|
93
|
-
// --- init 时会重写本函数 ---
|
|
94
|
-
return '';
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/** --- 获取当前语言名 --- */
|
|
98
|
-
public get locale(): string {
|
|
99
|
-
return task.list[this.taskId].locale.lang || core.config.locale;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* --- 获取语言内容 ---
|
|
104
|
-
*/
|
|
105
|
-
public get l(): (key: string, data?: string[]) => string {
|
|
106
|
-
return (key: string, data?: string[]): string => {
|
|
107
|
-
const loc = (this as any).localeData?.[this.locale][key] ?? '[LocaleError]' + key;
|
|
108
|
-
if (!data) {
|
|
109
|
-
return loc;
|
|
110
|
-
}
|
|
111
|
-
let i: number = -1;
|
|
112
|
-
return loc.replace(/\?/g, function() {
|
|
113
|
-
++i;
|
|
114
|
-
if (!data[i]) {
|
|
115
|
-
return '';
|
|
116
|
-
}
|
|
117
|
-
return data[i];
|
|
118
|
-
});
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/** --- layout 中 :class 的转义 --- */
|
|
123
|
-
public get classPrepend(): (cla: any) => string {
|
|
124
|
-
return (cla: any): string => {
|
|
125
|
-
if (typeof cla !== 'string') {
|
|
126
|
-
return cla;
|
|
127
|
-
}
|
|
128
|
-
// --- 控件没有样式表,则除了主题样式外,class 将不进行设置 ---
|
|
129
|
-
return `cg-theme-task${this.taskId}-${this.controlName}_${cla}${this.prep ? (' ' + this.prep + cla) : ''}`;
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** --- 获取 alignH 的 css 属性模式,请确保 props.alignH 存在 --- */
|
|
134
|
-
public get alignHComp(): string | undefined {
|
|
135
|
-
if (!(this.props as any).alignH) {
|
|
136
|
-
return undefined;
|
|
137
|
-
}
|
|
138
|
-
switch ((this.props as any).alignH) {
|
|
139
|
-
case 'center': {
|
|
140
|
-
return 'center';
|
|
141
|
-
}
|
|
142
|
-
case 'left':
|
|
143
|
-
case 'start': {
|
|
144
|
-
return 'flex-start';
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return 'flex-end';
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/** --- 获取 alignH 的 css 属性模式,请确保 props.alignH 存在 --- */
|
|
151
|
-
public get alignVComp(): string | undefined {
|
|
152
|
-
if (!(this.props as any).alignV) {
|
|
153
|
-
return undefined;
|
|
154
|
-
}
|
|
155
|
-
switch ((this.props as any).alignV) {
|
|
156
|
-
case 'center': {
|
|
157
|
-
return 'center';
|
|
158
|
-
}
|
|
159
|
-
case 'top':
|
|
160
|
-
case 'start': {
|
|
161
|
-
return 'flex-start';
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return 'flex-end';
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* --- 监视变动 ---
|
|
169
|
-
* @param name 监视的属性或 prop 值
|
|
170
|
-
* @param cb 回调
|
|
171
|
-
* @param opt 参数
|
|
172
|
-
*/
|
|
173
|
-
public watch<T extends this & this['props'], TK extends keyof T, TR>(
|
|
174
|
-
name: TK | (() => TR),
|
|
175
|
-
cb: (val: T[TK] & TR, old: T[TK] & TR) => void | Promise<void>,
|
|
176
|
-
opt: {
|
|
177
|
-
'immediate'?: boolean;
|
|
178
|
-
'deep'?: boolean;
|
|
179
|
-
} = {}
|
|
180
|
-
): () => void {
|
|
181
|
-
return (this as any).$watch(name, cb, opt);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* --- 获取 refs 情况 ---
|
|
186
|
-
*/
|
|
187
|
-
public get refs(): Record<string, HTMLElement & AbstractControl & Record<string, any>> {
|
|
188
|
-
return (this as any).$refs;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* --- 等待渲染 ---
|
|
193
|
-
*/
|
|
194
|
-
public get nextTick(): () => Promise<void> {
|
|
195
|
-
return (this as any).$nextTick;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* --- 判断当前事件可否执行 ---
|
|
200
|
-
* @param e 鼠标、触摸、键盘事件
|
|
201
|
-
*/
|
|
202
|
-
public allowEvent(e: MouseEvent | TouchEvent | KeyboardEvent): boolean {
|
|
203
|
-
return dom.allowEvent(e);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* --- 触发系统方法 ---
|
|
208
|
-
* @param name 方法名
|
|
209
|
-
* @param param1 参数1
|
|
210
|
-
* @param param2 参数2
|
|
211
|
-
*/
|
|
212
|
-
public trigger(name: types.TGlobalEvent, param1: boolean | Error | string = '', param2: string = ''): void {
|
|
213
|
-
if (!['formTitleChanged', 'formIconChanged', 'formStateMinChanged', 'formStateMaxChanged', 'formShowChanged'].includes(name)) {
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
core.trigger(name, this.taskId, this.formId, param1, param2);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// --- 以下为 control 有,但窗体没有 ---
|
|
220
|
-
|
|
221
|
-
/** --- 组件内部文件,由系统重写 --- */
|
|
222
|
-
public readonly packageFiles: Record<string, Blob | string> = {};
|
|
223
|
-
|
|
224
|
-
/** --- 组件参数,由用户定义重写 --- */
|
|
225
|
-
public readonly props = {};
|
|
226
|
-
|
|
227
|
-
/** --- 组件参数,由用户定义重写 --- */
|
|
228
|
-
public readonly emits: Record<string, null | ((payload: any) => boolean)> = {};
|
|
229
|
-
|
|
230
|
-
/** --- 组件的子插槽 --- */
|
|
231
|
-
public readonly slots: Record<string, () => any[]> = {};
|
|
232
|
-
|
|
233
|
-
/** --- 获取某插槽所有子类 --- */
|
|
234
|
-
public get slotsAll() {
|
|
235
|
-
return (name: string): any[] => {
|
|
236
|
-
if (!this.slots[name]) {
|
|
237
|
-
return [];
|
|
238
|
-
}
|
|
239
|
-
const ls = this.slots[name]();
|
|
240
|
-
const rtn: any[] = [];
|
|
241
|
-
for (const slot of ls) {
|
|
242
|
-
if (!slot.props) {
|
|
243
|
-
if ((typeof slot.children !== 'string') && slot.children.length) {
|
|
244
|
-
for (const item of slot.children) {
|
|
245
|
-
rtn.push(item);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
continue;
|
|
249
|
-
}
|
|
250
|
-
rtn.push(slot);
|
|
251
|
-
}
|
|
252
|
-
return rtn;
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/** --- 获取 props 中的 boolean 类型的值 --- */
|
|
257
|
-
public get propBoolean() {
|
|
258
|
-
return (name: keyof this['props']): boolean => {
|
|
259
|
-
return tool.getBoolean((this.props as any)[name]);
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/** --- 获取 props 中的 number 类型的值 --- */
|
|
264
|
-
public get propNumber() {
|
|
265
|
-
return (name: keyof this['props']): number => {
|
|
266
|
-
return tool.getNumber((this.props as any)[name]);
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/** --- 获取 props 中的 int 类型的值 --- */
|
|
271
|
-
public get propInt() {
|
|
272
|
-
return (name: keyof this['props']): number => {
|
|
273
|
-
return Math.round(this.propNumber(name));
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/** --- 获取 props 中的 array 类型的值 --- */
|
|
278
|
-
public get propArray() {
|
|
279
|
-
return (name: keyof this['props']): any[] => {
|
|
280
|
-
return tool.getArray((this.props as any)[name]);
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/** --- 获取当前的 HTML DOM --- */
|
|
285
|
-
public get element(): HTMLElement {
|
|
286
|
-
return (this as any).$el;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* --- 向上反应事件 ---
|
|
291
|
-
* @param name 事件名
|
|
292
|
-
* @param v 事件值
|
|
293
|
-
*/
|
|
294
|
-
public emit(name: string, ...v: string | any): void {
|
|
295
|
-
(this as any).$emit(name, ...v);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* --- 获取上层控件 ---
|
|
300
|
-
*/
|
|
301
|
-
public get parent(): AbstractControl & form.AbstractForm & Record<string, any> {
|
|
302
|
-
return (this as any).$parent;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* --- 根据 control name 查询上层控件 ---
|
|
307
|
-
*/
|
|
308
|
-
public get parentByName() {
|
|
309
|
-
return (controlName: string): (AbstractControl & Record<string, any>) | null => {
|
|
310
|
-
let parent = (this as any).$parent;
|
|
311
|
-
while (true) {
|
|
312
|
-
if (!parent) {
|
|
313
|
-
return null;
|
|
314
|
-
}
|
|
315
|
-
if (parent.controlName === controlName) {
|
|
316
|
-
return parent;
|
|
317
|
-
}
|
|
318
|
-
parent = parent.$parent;
|
|
319
|
-
}
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* --- 根据 control access 查询上层控件 ---
|
|
325
|
-
*/
|
|
326
|
-
public get parentByAccess() {
|
|
327
|
-
return (name: string, val: string): (AbstractControl & Record<string, any>) | null => {
|
|
328
|
-
let parent = (this as any).$parent;
|
|
329
|
-
while (true) {
|
|
330
|
-
if (!parent) {
|
|
331
|
-
return null;
|
|
332
|
-
}
|
|
333
|
-
if (!parent.access) {
|
|
334
|
-
parent = parent.$parent;
|
|
335
|
-
continue;
|
|
336
|
-
}
|
|
337
|
-
if (parent.access[name] === val) {
|
|
338
|
-
return parent;
|
|
339
|
-
}
|
|
340
|
-
parent = parent.$parent;
|
|
341
|
-
}
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// --- 控件响应事件,都可由用户重写 ---
|
|
346
|
-
|
|
347
|
-
public onBeforeCreate(): void | Promise<void> {
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
public onCreated(): void | Promise<void> {
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
public onBeforeMount(): void | Promise<void> {
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
public onMounted(): void | Promise<void> {
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
public onBeforeUpdate(): void | Promise<void> {
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
public onUpdated(): void | Promise<void> {
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
public onBeforeUnmount(): void | Promise<void> {
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
public onUnmounted(): void | Promise<void> {
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* --- 将 cgc 文件 blob 转换为 control 对象 ---
|
|
383
|
-
* @param blob 文件 blob
|
|
384
|
-
*/
|
|
385
|
-
export async function read(blob: Blob): Promise<false | types.TControlPackage> {
|
|
386
|
-
const z = await zip.get(blob);
|
|
387
|
-
if (!z) {
|
|
388
|
-
return false;
|
|
389
|
-
}
|
|
390
|
-
/** --- 要返回的 control pkg 对象 --- */
|
|
391
|
-
const controlPkg: types.TControlPackage = {};
|
|
392
|
-
|
|
393
|
-
// --- 读取包 ---
|
|
394
|
-
const list = z.readDir('/');
|
|
395
|
-
for (const sub of list) {
|
|
396
|
-
if (sub.isFile) {
|
|
397
|
-
continue;
|
|
398
|
-
}
|
|
399
|
-
const configContent = await z.getContent('/' + sub.name + '/config.json');
|
|
400
|
-
if (!configContent) {
|
|
401
|
-
form.notify({
|
|
402
|
-
'title': 'Error',
|
|
403
|
-
'content': `Control file not found.\nFile: "${'/' + sub.name + '/config.json'}".`,
|
|
404
|
-
'type': 'danger'
|
|
405
|
-
});
|
|
406
|
-
continue;
|
|
407
|
-
}
|
|
408
|
-
// --- 读取本条控件内容 ---
|
|
409
|
-
const config: types.IControlConfig = JSON.parse(configContent);
|
|
410
|
-
controlPkg[config.name] = {
|
|
411
|
-
'type': 'control',
|
|
412
|
-
'config': config,
|
|
413
|
-
'files': {}
|
|
414
|
-
};
|
|
415
|
-
// --- 读取控件包文件 ---
|
|
416
|
-
const list = z.readDir('/' + sub.name + '/', {
|
|
417
|
-
'hasChildren': true
|
|
418
|
-
});
|
|
419
|
-
for (const file of list) {
|
|
420
|
-
const pre = file.path.slice(config.name.length + 1);
|
|
421
|
-
const mime = tool.getMimeByPath(file.name);
|
|
422
|
-
if (['txt', 'json', 'js', 'css', 'xml', 'html'].includes(mime.ext)) {
|
|
423
|
-
const fab = await z.getContent(file.path + file.name, 'string');
|
|
424
|
-
if (!fab) {
|
|
425
|
-
continue;
|
|
426
|
-
}
|
|
427
|
-
controlPkg[config.name].files[pre + file.name] = fab.replace(/^\ufeff/, '');
|
|
428
|
-
}
|
|
429
|
-
else {
|
|
430
|
-
const fab = await z.getContent(file.path + file.name, 'arraybuffer');
|
|
431
|
-
if (!fab) {
|
|
432
|
-
continue;
|
|
433
|
-
}
|
|
434
|
-
controlPkg[config.name].files[pre + file.name] = new Blob([fab], {
|
|
435
|
-
'type': mime.mime
|
|
436
|
-
});
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
return controlPkg;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
/**
|
|
444
|
-
* --- 任务创建过程中,需要对 control 进行先行初始化,并将样式表插入到实际的任务 DOM 中 ---
|
|
445
|
-
* @param taskId 要处理的任务 ID
|
|
446
|
-
*/
|
|
447
|
-
export async function init(
|
|
448
|
-
taskId: number,
|
|
449
|
-
invoke: Record<string, any>,
|
|
450
|
-
cache?: string
|
|
451
|
-
): Promise<number> {
|
|
452
|
-
const t = task.list[taskId];
|
|
453
|
-
if (!t) {
|
|
454
|
-
return -1;
|
|
455
|
-
}
|
|
456
|
-
for (let path of t.app.config.controls) {
|
|
457
|
-
if (!path.endsWith('.cgc')) {
|
|
458
|
-
path += '.cgc';
|
|
459
|
-
}
|
|
460
|
-
path = tool.urlResolve('/', path);
|
|
461
|
-
const file = await fs.getContent(path, {
|
|
462
|
-
'cache': cache
|
|
463
|
-
}, taskId);
|
|
464
|
-
if (file && typeof file !== 'string') {
|
|
465
|
-
const c = await read(file);
|
|
466
|
-
if (c) {
|
|
467
|
-
for (const name in c) {
|
|
468
|
-
/** --- 控件组件中的单项 --- */
|
|
469
|
-
const item = c[name];
|
|
470
|
-
/** --- 样式唯一前缀 --- */
|
|
471
|
-
let prep: string = '';
|
|
472
|
-
// --- 组装预加载 control 对象 ---
|
|
473
|
-
t.controls[name] = {
|
|
474
|
-
'layout': '',
|
|
475
|
-
|
|
476
|
-
'files': item.files,
|
|
477
|
-
'props': {},
|
|
478
|
-
'emits': {},
|
|
479
|
-
'data': {},
|
|
480
|
-
'access': {},
|
|
481
|
-
'methods': {},
|
|
482
|
-
'computed': {}
|
|
483
|
-
};
|
|
484
|
-
// --- 要创建的控件的 layout ---
|
|
485
|
-
t.controls[name].layout = item.files[item.config.layout + '.html'] as string;
|
|
486
|
-
if (t.controls[name].layout === undefined) {
|
|
487
|
-
// --- 控件没有 layout 那肯定不能用 ---
|
|
488
|
-
return -2;
|
|
489
|
-
}
|
|
490
|
-
// --- 给 layout 增加 data-cg-control-xxx ---
|
|
491
|
-
t.controls[name].layout = t.controls[name].layout.replace(/^(<[a-zA-Z0-9-]+)( |>)/, '$1 data-cg-control="' + name + '"$2');
|
|
492
|
-
/** --- 样式表 --- */
|
|
493
|
-
const style = item.files[item.config.style + '.css'] as string;
|
|
494
|
-
if (style) {
|
|
495
|
-
// --- 有样式表,给样式表内的项增加唯一前缀(scope) ---
|
|
496
|
-
const r = tool.stylePrepend(style);
|
|
497
|
-
prep = r.prep;
|
|
498
|
-
dom.pushStyle(t.id, await tool.styleUrl2DataUrl(item.config.style, r.style, item.files), 'control', name);
|
|
499
|
-
}
|
|
500
|
-
// --- 给控件的 layout 的 class 增加前置 ---
|
|
501
|
-
const prepList = [
|
|
502
|
-
'cg-theme-task' + t.id.toString() + '-' + name + '_'
|
|
503
|
-
];
|
|
504
|
-
if (prep !== '') {
|
|
505
|
-
prepList.push(prep);
|
|
506
|
-
}
|
|
507
|
-
// --- 增加 class 为 tag-xxx ---
|
|
508
|
-
t.controls[name].layout = tool.layoutAddTagClassAndReTagName(t.controls[name].layout, false);
|
|
509
|
-
// --- 给 layout 的 class 增加前置 ---
|
|
510
|
-
t.controls[name].layout = tool.layoutClassPrepend(t.controls[name].layout, prepList);
|
|
511
|
-
// --- 给 cg 对象增加 :form-focus 传递 ---
|
|
512
|
-
/*
|
|
513
|
-
if (t.controls[name].layout.includes('<cg-')) {
|
|
514
|
-
t.controls[name].layout = tool.layoutInsertAttr(t.controls[name].layout, ':form-focus=\'formFocus\'', {
|
|
515
|
-
'include': [/^cg-.+/]
|
|
516
|
-
});
|
|
517
|
-
}
|
|
518
|
-
*/
|
|
519
|
-
// --- 给 event 增加包裹 ---
|
|
520
|
-
t.controls[name].layout = tool.eventsAttrWrap(t.controls[name].layout);
|
|
521
|
-
// --- 给 teleport 做处理 ---
|
|
522
|
-
if (t.controls[name].layout.includes('<teleport')) {
|
|
523
|
-
t.controls[name].layout = tool.teleportGlue(t.controls[name].layout, '{{{formId}}}');
|
|
524
|
-
}
|
|
525
|
-
// --- 添加父子组件的映射关系 ---
|
|
526
|
-
t.controls[name].access['cgPCMap'] = tool.random(8, tool.RANDOM_LUNS, '"<>$');
|
|
527
|
-
t.controls[name].layout = t.controls[name].layout.replace(/(<cg-[a-zA-Z0-9-_]+)/g, `$1 data-cg-rootcontrol="${t.controls[name].access['cgPCMap']}"`);
|
|
528
|
-
// --- 检测是否有 js ---
|
|
529
|
-
let cls: any;
|
|
530
|
-
if (item.files[item.config.code + '.js']) {
|
|
531
|
-
item.files['/invoke/clickgo.js'] = `module.exports = invokeClickgo;`;
|
|
532
|
-
let expo: any = [];
|
|
533
|
-
try {
|
|
534
|
-
expo = loader.require(item.config.code, item.files, {
|
|
535
|
-
'dir': '/',
|
|
536
|
-
'invoke': invoke,
|
|
537
|
-
'preprocess': function(code: string, path: string): string {
|
|
538
|
-
// --- 屏蔽 eval 函数 ---
|
|
539
|
-
const exec = /eval\W/.exec(code);
|
|
540
|
-
if (exec) {
|
|
541
|
-
form.notify({
|
|
542
|
-
'title': 'Error',
|
|
543
|
-
'content': `The "eval" is prohibited.\nFile: "${path}".`,
|
|
544
|
-
'type': 'danger'
|
|
545
|
-
});
|
|
546
|
-
return '';
|
|
547
|
-
}
|
|
548
|
-
// --- 给 control 的 class 增加 filename 的 get ---
|
|
549
|
-
code = code.replace(/extends[\s\S]+?\.\s*AbstractControl\s*{/, (t: string) => {
|
|
550
|
-
return t + 'get filename() {return __filename;}';
|
|
551
|
-
});
|
|
552
|
-
return code;
|
|
553
|
-
},
|
|
554
|
-
'map': {
|
|
555
|
-
'clickgo': '/invoke/clickgo'
|
|
556
|
-
}
|
|
557
|
-
})[0];
|
|
558
|
-
}
|
|
559
|
-
catch (e: any) {
|
|
560
|
-
core.trigger('error', taskId, 0, e, e.message + '(-4)');
|
|
561
|
-
return -3;
|
|
562
|
-
}
|
|
563
|
-
if (!expo?.default) {
|
|
564
|
-
const msg = '"default" not found on "' + item.config.code + '" of "' + name + '" control.';
|
|
565
|
-
core.trigger('error', taskId, 0, new Error(msg), msg);
|
|
566
|
-
return -4;
|
|
567
|
-
}
|
|
568
|
-
cls = new expo.default();
|
|
569
|
-
}
|
|
570
|
-
else {
|
|
571
|
-
// --- 没有 js 文件 ---
|
|
572
|
-
cls = new (class extends AbstractControl {
|
|
573
|
-
public get taskId(): number {
|
|
574
|
-
return taskId;
|
|
575
|
-
}
|
|
576
|
-
})();
|
|
577
|
-
}
|
|
578
|
-
if (cls.props) {
|
|
579
|
-
for (const key in cls.props) {
|
|
580
|
-
t.controls[name].props[key] = {
|
|
581
|
-
'default': cls.props[key]
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
if (cls.emits) {
|
|
586
|
-
for (const key in cls.emits) {
|
|
587
|
-
t.controls[name].emits[key] = cls.emits[key];
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
// --- DATA ---
|
|
591
|
-
const cdata = Object.entries(cls);
|
|
592
|
-
for (const item of cdata) {
|
|
593
|
-
if (item[0] === 'files') {
|
|
594
|
-
continue;
|
|
595
|
-
}
|
|
596
|
-
if (item[0] === 'access') {
|
|
597
|
-
// --- access 属性不放在 data 当中 ---
|
|
598
|
-
t.controls[name].access = item[1] as any;
|
|
599
|
-
continue;
|
|
600
|
-
}
|
|
601
|
-
t.controls[name].data[item[0]] = item[1];
|
|
602
|
-
}
|
|
603
|
-
const prot = tool.getClassPrototype(cls);
|
|
604
|
-
t.controls[name].methods = prot.method;
|
|
605
|
-
Object.assign(t.controls[name].computed, prot.access);
|
|
606
|
-
t.controls[name].computed.controlName = {
|
|
607
|
-
get: function() {
|
|
608
|
-
return name;
|
|
609
|
-
},
|
|
610
|
-
set: function() {
|
|
611
|
-
form.notify({
|
|
612
|
-
'title': 'Error',
|
|
613
|
-
'content': `The software tries to modify the system variable "controlName".\nControl: ${name}`,
|
|
614
|
-
'type': 'danger'
|
|
615
|
-
});
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
};
|
|
619
|
-
t.controls[name].computed.prep = {
|
|
620
|
-
get: function() {
|
|
621
|
-
return prep;
|
|
622
|
-
},
|
|
623
|
-
set: function() {
|
|
624
|
-
form.notify({
|
|
625
|
-
'title': 'Error',
|
|
626
|
-
'content': `The software tries to modify the system variable "prep".\nControl: ${name}`,
|
|
627
|
-
'type': 'danger'
|
|
628
|
-
});
|
|
629
|
-
return;
|
|
630
|
-
}
|
|
631
|
-
};
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
else {
|
|
635
|
-
form.notify({
|
|
636
|
-
'title': 'Error',
|
|
637
|
-
'content': 'Control failed to load.\nTask id: ' + t.id.toString() + '\nPath: ' + path,
|
|
638
|
-
'type': 'danger'
|
|
639
|
-
});
|
|
640
|
-
return -5;
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
return 1;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
/**
|
|
648
|
-
* --- 初始化获取新窗体的控件 component ---
|
|
649
|
-
* @param taskId 任务 id
|
|
650
|
-
* @param formId 窗体 id
|
|
651
|
-
* @param path 窗体路径基准(包内路径)不以 / 结尾
|
|
652
|
-
*/
|
|
653
|
-
export function buildComponents(
|
|
654
|
-
taskId: number,
|
|
655
|
-
formId: number,
|
|
656
|
-
path: string
|
|
657
|
-
): false | Record<string, any> {
|
|
658
|
-
const t = task.list[taskId];
|
|
659
|
-
if (!t) {
|
|
660
|
-
return false;
|
|
661
|
-
}
|
|
662
|
-
/** --- 要返回的控件列表 --- */
|
|
663
|
-
const components: Record<string, any> = {};
|
|
664
|
-
for (const name in t.controls) {
|
|
665
|
-
const control = t.controls[name];
|
|
666
|
-
// --- 准备相关变量 ---
|
|
667
|
-
const computed: Record<string, any> = Object.assign({}, control.computed);
|
|
668
|
-
computed.formId = {
|
|
669
|
-
get: function(): number {
|
|
670
|
-
return formId;
|
|
671
|
-
},
|
|
672
|
-
set: function(): void {
|
|
673
|
-
form.notify({
|
|
674
|
-
'title': 'Error',
|
|
675
|
-
'content': `The control tries to modify the system variable "formId".\nControl: ${name}`,
|
|
676
|
-
'type': 'danger'
|
|
677
|
-
});
|
|
678
|
-
}
|
|
679
|
-
};
|
|
680
|
-
computed.path = {
|
|
681
|
-
get: function(): string {
|
|
682
|
-
return path;
|
|
683
|
-
},
|
|
684
|
-
set: function(): void {
|
|
685
|
-
form.notify({
|
|
686
|
-
'title': 'Error',
|
|
687
|
-
'content': `The control tries to modify the system variable "path".\nControl: ${name}`,
|
|
688
|
-
'type': 'danger'
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
};
|
|
692
|
-
components['cg-' + name] = {
|
|
693
|
-
'template': control.layout.replace(/{{{formId}}}/g, formId.toString()),
|
|
694
|
-
'props': control.props,
|
|
695
|
-
'emits': control.emits,
|
|
696
|
-
|
|
697
|
-
'data': function() {
|
|
698
|
-
const data = tool.clone(control.data);
|
|
699
|
-
if (data.props) {
|
|
700
|
-
delete data.props;
|
|
701
|
-
}
|
|
702
|
-
if (data.emits) {
|
|
703
|
-
delete data.emits;
|
|
704
|
-
}
|
|
705
|
-
return data;
|
|
706
|
-
},
|
|
707
|
-
'methods': control.methods,
|
|
708
|
-
'computed': computed,
|
|
709
|
-
|
|
710
|
-
beforeCreate: control.methods.onBeforeCreate,
|
|
711
|
-
created: function() {
|
|
712
|
-
this.props = this.$props;
|
|
713
|
-
this.slots = this.$slots;
|
|
714
|
-
this.access = tool.clone(control.access);
|
|
715
|
-
this.packageFiles = {};
|
|
716
|
-
for (const fname in control.files) {
|
|
717
|
-
this.packageFiles[fname] = control.files[fname];
|
|
718
|
-
}
|
|
719
|
-
this.onCreated();
|
|
720
|
-
},
|
|
721
|
-
beforeMount: function() {
|
|
722
|
-
this.onBeforeMount();
|
|
723
|
-
},
|
|
724
|
-
mounted: async function() {
|
|
725
|
-
if (this.element.dataset?.cgRootcontrol !== undefined) {
|
|
726
|
-
const rc = this.parentByAccess('cgPCMap', this.element.dataset.cgRootcontrol);
|
|
727
|
-
if (rc) {
|
|
728
|
-
this._rootControl = rc;
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
await this.$nextTick();
|
|
732
|
-
this.onMounted();
|
|
733
|
-
},
|
|
734
|
-
beforeUpdate: function() {
|
|
735
|
-
this.onBeforeUpdate();
|
|
736
|
-
},
|
|
737
|
-
updated: async function() {
|
|
738
|
-
await this.$nextTick();
|
|
739
|
-
this.onUpdated();
|
|
740
|
-
},
|
|
741
|
-
beforeUnmount: function() {
|
|
742
|
-
this.onBeforeUnmount();
|
|
743
|
-
},
|
|
744
|
-
unmounted: async function() {
|
|
745
|
-
await this.$nextTick();
|
|
746
|
-
this.onUnmounted();
|
|
747
|
-
}
|
|
748
|
-
};
|
|
749
|
-
}
|
|
750
|
-
return components;
|
|
751
|
-
}
|