@tmagic/editor 1.8.0-beta.20 → 1.8.0-beta.21
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/dist/es/fields/EventSelect.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/es/services/events.js +2 -2
- package/dist/es/utils/dep/idle-task.js +28 -5
- package/dist/es/utils/event.js +19 -7
- package/dist/tmagic-editor.umd.cjs +54 -16
- package/package.json +7 -7
- package/src/fields/EventSelect.vue +7 -5
- package/src/services/events.ts +3 -3
- package/src/utils/dep/idle-task.ts +43 -11
- package/src/utils/event.ts +25 -12
- package/types/index.d.ts +11 -2
|
@@ -173,7 +173,7 @@ var EventSelect_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
|
|
|
173
173
|
name: "name",
|
|
174
174
|
label: "事件名",
|
|
175
175
|
type: eventNameConfig.value.type,
|
|
176
|
-
options: (mForm, { formValue }) => eventsService.getEvent(formValue.type).map((option) => ({
|
|
176
|
+
options: (mForm, { formValue }) => eventsService.getEvent(formValue.type, { node: editorService.getNodeById(formValue.id) }).map((option) => ({
|
|
177
177
|
text: option.label,
|
|
178
178
|
value: option.value
|
|
179
179
|
}))
|
|
@@ -190,7 +190,10 @@ var EventSelect_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
|
|
|
190
190
|
options: (mForm, { model }) => {
|
|
191
191
|
const node = editorService.getNodeById(model.to);
|
|
192
192
|
if (!node?.type) return [];
|
|
193
|
-
return eventsService.getMethod(node.type,
|
|
193
|
+
return eventsService.getMethod(node.type, {
|
|
194
|
+
targetId: model.to,
|
|
195
|
+
node
|
|
196
|
+
}).map((option) => ({
|
|
194
197
|
text: option.label,
|
|
195
198
|
value: option.value
|
|
196
199
|
}));
|
|
@@ -32,7 +32,7 @@ var Events = class extends BaseService {
|
|
|
32
32
|
setEvent(type, events) {
|
|
33
33
|
eventMap[toLine(type)] = [...events];
|
|
34
34
|
}
|
|
35
|
-
getEvent(type) {
|
|
35
|
+
getEvent(type, _data = {}) {
|
|
36
36
|
return cloneDeep(eventMap[toLine(type)]) || [];
|
|
37
37
|
}
|
|
38
38
|
setMethods(methods) {
|
|
@@ -43,7 +43,7 @@ var Events = class extends BaseService {
|
|
|
43
43
|
setMethod(type, method) {
|
|
44
44
|
methodMap[toLine(type)] = [...method];
|
|
45
45
|
}
|
|
46
|
-
getMethod(type,
|
|
46
|
+
getMethod(type, _data = {}) {
|
|
47
47
|
return cloneDeep(methodMap[toLine(type)]) || [];
|
|
48
48
|
}
|
|
49
49
|
resetState() {
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { error } from "../logger.js";
|
|
2
2
|
import { EventEmitter } from "events";
|
|
3
3
|
//#region packages/editor/src/utils/dep/idle-task.ts
|
|
4
|
+
/**
|
|
5
|
+
* 回调因 timeout 触发(主线程一直没有空闲)时,单次回调执行任务的时间预算,单位 ms
|
|
6
|
+
* 参考一帧内可让出的余量:既保证队列有进展,又不长时间阻塞主线程
|
|
7
|
+
*/
|
|
8
|
+
var TIMEOUT_RUN_BUDGET = 5;
|
|
9
|
+
/**
|
|
10
|
+
* 回调因 timeout 触发时,每两次读取时钟之间执行的任务数
|
|
11
|
+
* 与空闲时间 <=5ms 时的批量保持一致,避免每个任务都读一次时钟
|
|
12
|
+
*/
|
|
13
|
+
var TIMEOUT_BATCH_SIZE = 10;
|
|
4
14
|
globalThis.requestIdleCallback = globalThis.requestIdleCallback || function(cb) {
|
|
5
15
|
const start = Date.now();
|
|
6
16
|
return setTimeout(() => {
|
|
@@ -52,6 +62,13 @@ var IdleTask = class extends EventEmitter {
|
|
|
52
62
|
runTaskQueue(deadline) {
|
|
53
63
|
this.taskHandle = null;
|
|
54
64
|
try {
|
|
65
|
+
if (deadline.didTimeout) {
|
|
66
|
+
const start = Date.now();
|
|
67
|
+
do
|
|
68
|
+
this.runTaskBatch(TIMEOUT_BATCH_SIZE);
|
|
69
|
+
while (this.getTaskLength() && Date.now() - start < TIMEOUT_RUN_BUDGET);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
55
72
|
while (deadline.timeRemaining() > 0 && this.getTaskLength()) {
|
|
56
73
|
const timeRemaining = deadline.timeRemaining();
|
|
57
74
|
let times = 0;
|
|
@@ -59,17 +76,23 @@ var IdleTask = class extends EventEmitter {
|
|
|
59
76
|
else if (timeRemaining <= 10) times = 100;
|
|
60
77
|
else if (timeRemaining <= 15) times = 300;
|
|
61
78
|
else times = 600;
|
|
62
|
-
|
|
63
|
-
const task = this.hightLevelTaskList.length > 0 ? this.hightLevelTaskList.shift() : this.taskList.shift();
|
|
64
|
-
if (task) this.runTask(task);
|
|
65
|
-
if (!this.getTaskLength()) break;
|
|
66
|
-
}
|
|
79
|
+
this.runTaskBatch(times);
|
|
67
80
|
}
|
|
68
81
|
} finally {
|
|
69
82
|
this.finishRun();
|
|
70
83
|
}
|
|
71
84
|
}
|
|
72
85
|
/**
|
|
86
|
+
* 执行一批任务,队列被清空时提前结束
|
|
87
|
+
*/
|
|
88
|
+
runTaskBatch(times) {
|
|
89
|
+
for (let i = 0; i < times; i++) {
|
|
90
|
+
const task = this.hightLevelTaskList.length > 0 ? this.hightLevelTaskList.shift() : this.taskList.shift();
|
|
91
|
+
if (task) this.runTask(task);
|
|
92
|
+
if (!this.getTaskLength()) break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
73
96
|
* 单个任务失败不能中断整个队列,否则后续任务永远不会被执行,
|
|
74
97
|
* 依赖收集会停在半路(收集中状态与剩余任务数都不再变化)
|
|
75
98
|
*/
|
package/dist/es/utils/event.js
CHANGED
|
@@ -19,7 +19,8 @@ var normalizeCompActionValue = (value) => {
|
|
|
19
19
|
var getEventNameOptions = (src, formValue = {}) => {
|
|
20
20
|
if (!formValue.type) return [];
|
|
21
21
|
if (src === "component") {
|
|
22
|
-
|
|
22
|
+
const sourceNode = editor_default.getNodeById(formValue.id);
|
|
23
|
+
let events = events_default.getEvent(formValue.type, { node: sourceNode }) || [];
|
|
23
24
|
if (formValue.type === "page-fragment-container" && formValue.pageFragmentId) {
|
|
24
25
|
const pageFragment = editor_default.get("root")?.items?.find((page) => page.id === formValue.pageFragmentId);
|
|
25
26
|
if (!pageFragment) return [];
|
|
@@ -28,9 +29,11 @@ var getEventNameOptions = (src, formValue = {}) => {
|
|
|
28
29
|
value: pageFragment.id,
|
|
29
30
|
children: events
|
|
30
31
|
}];
|
|
31
|
-
(pageFragment.items || []).forEach((
|
|
32
|
-
traverseNode(
|
|
33
|
-
|
|
32
|
+
(pageFragment.items || []).forEach((item) => {
|
|
33
|
+
traverseNode(item, (current) => {
|
|
34
|
+
if (!current.type) return;
|
|
35
|
+
const node = editor_default.getNodeById(current.id) || current;
|
|
36
|
+
const nodeEvents = events_default.getEvent(current.type, { node }) || [];
|
|
34
37
|
events.push({
|
|
35
38
|
label: `${current.name}_${current.id}`,
|
|
36
39
|
value: `${current.id}`,
|
|
@@ -89,15 +92,24 @@ var getCompActionOptions = (toId) => {
|
|
|
89
92
|
if (typeof toId === "undefined" || toId === null || toId === "") return [];
|
|
90
93
|
const node = editor_default.getNodeById(toId);
|
|
91
94
|
if (!node?.type) return [];
|
|
92
|
-
let methods = events_default.getMethod(node.type,
|
|
95
|
+
let methods = events_default.getMethod(node.type, {
|
|
96
|
+
targetId: toId,
|
|
97
|
+
node
|
|
98
|
+
}) || [];
|
|
93
99
|
if (node.type === "page-fragment-container" && node.pageFragmentId) {
|
|
94
100
|
const pageFragment = editor_default.get("root")?.items?.find((page) => page.id === node.pageFragmentId);
|
|
95
101
|
if (!pageFragment) return [];
|
|
96
102
|
methods = [];
|
|
97
103
|
(pageFragment.items || []).forEach((item) => {
|
|
98
104
|
traverseNode(item, (current) => {
|
|
99
|
-
const
|
|
100
|
-
if (
|
|
105
|
+
const node = editor_default.getNodeById(current.id) || current;
|
|
106
|
+
if (!current.type) return;
|
|
107
|
+
const nodeMethods = events_default.getMethod(current.type, {
|
|
108
|
+
targetId: current.id,
|
|
109
|
+
node
|
|
110
|
+
}) || [];
|
|
111
|
+
if (!nodeMethods.length) return;
|
|
112
|
+
methods.push({
|
|
101
113
|
label: `${current.name}_${current.id}`,
|
|
102
114
|
value: `${current.id}`,
|
|
103
115
|
children: nodeMethods
|
|
@@ -9647,6 +9647,16 @@
|
|
|
9647
9647
|
};
|
|
9648
9648
|
//#endregion
|
|
9649
9649
|
//#region packages/editor/src/utils/dep/idle-task.ts
|
|
9650
|
+
/**
|
|
9651
|
+
* 回调因 timeout 触发(主线程一直没有空闲)时,单次回调执行任务的时间预算,单位 ms
|
|
9652
|
+
* 参考一帧内可让出的余量:既保证队列有进展,又不长时间阻塞主线程
|
|
9653
|
+
*/
|
|
9654
|
+
var TIMEOUT_RUN_BUDGET = 5;
|
|
9655
|
+
/**
|
|
9656
|
+
* 回调因 timeout 触发时,每两次读取时钟之间执行的任务数
|
|
9657
|
+
* 与空闲时间 <=5ms 时的批量保持一致,避免每个任务都读一次时钟
|
|
9658
|
+
*/
|
|
9659
|
+
var TIMEOUT_BATCH_SIZE = 10;
|
|
9650
9660
|
globalThis.requestIdleCallback = globalThis.requestIdleCallback || function(cb) {
|
|
9651
9661
|
const start = Date.now();
|
|
9652
9662
|
return setTimeout(() => {
|
|
@@ -9698,6 +9708,13 @@
|
|
|
9698
9708
|
runTaskQueue(deadline) {
|
|
9699
9709
|
this.taskHandle = null;
|
|
9700
9710
|
try {
|
|
9711
|
+
if (deadline.didTimeout) {
|
|
9712
|
+
const start = Date.now();
|
|
9713
|
+
do
|
|
9714
|
+
this.runTaskBatch(TIMEOUT_BATCH_SIZE);
|
|
9715
|
+
while (this.getTaskLength() && Date.now() - start < TIMEOUT_RUN_BUDGET);
|
|
9716
|
+
return;
|
|
9717
|
+
}
|
|
9701
9718
|
while (deadline.timeRemaining() > 0 && this.getTaskLength()) {
|
|
9702
9719
|
const timeRemaining = deadline.timeRemaining();
|
|
9703
9720
|
let times = 0;
|
|
@@ -9705,17 +9722,23 @@
|
|
|
9705
9722
|
else if (timeRemaining <= 10) times = 100;
|
|
9706
9723
|
else if (timeRemaining <= 15) times = 300;
|
|
9707
9724
|
else times = 600;
|
|
9708
|
-
|
|
9709
|
-
const task = this.hightLevelTaskList.length > 0 ? this.hightLevelTaskList.shift() : this.taskList.shift();
|
|
9710
|
-
if (task) this.runTask(task);
|
|
9711
|
-
if (!this.getTaskLength()) break;
|
|
9712
|
-
}
|
|
9725
|
+
this.runTaskBatch(times);
|
|
9713
9726
|
}
|
|
9714
9727
|
} finally {
|
|
9715
9728
|
this.finishRun();
|
|
9716
9729
|
}
|
|
9717
9730
|
}
|
|
9718
9731
|
/**
|
|
9732
|
+
* 执行一批任务,队列被清空时提前结束
|
|
9733
|
+
*/
|
|
9734
|
+
runTaskBatch(times) {
|
|
9735
|
+
for (let i = 0; i < times; i++) {
|
|
9736
|
+
const task = this.hightLevelTaskList.length > 0 ? this.hightLevelTaskList.shift() : this.taskList.shift();
|
|
9737
|
+
if (task) this.runTask(task);
|
|
9738
|
+
if (!this.getTaskLength()) break;
|
|
9739
|
+
}
|
|
9740
|
+
}
|
|
9741
|
+
/**
|
|
9719
9742
|
* 单个任务失败不能中断整个队列,否则后续任务永远不会被执行,
|
|
9720
9743
|
* 依赖收集会停在半路(收集中状态与剩余任务数都不再变化)
|
|
9721
9744
|
*/
|
|
@@ -11193,7 +11216,7 @@
|
|
|
11193
11216
|
setEvent(type, events) {
|
|
11194
11217
|
eventMap[(0, _tmagic_utils.toLine)(type)] = [...events];
|
|
11195
11218
|
}
|
|
11196
|
-
getEvent(type) {
|
|
11219
|
+
getEvent(type, _data = {}) {
|
|
11197
11220
|
return cloneDeep$1(eventMap[(0, _tmagic_utils.toLine)(type)]) || [];
|
|
11198
11221
|
}
|
|
11199
11222
|
setMethods(methods) {
|
|
@@ -11204,7 +11227,7 @@
|
|
|
11204
11227
|
setMethod(type, method) {
|
|
11205
11228
|
methodMap[(0, _tmagic_utils.toLine)(type)] = [...method];
|
|
11206
11229
|
}
|
|
11207
|
-
getMethod(type,
|
|
11230
|
+
getMethod(type, _data = {}) {
|
|
11208
11231
|
return cloneDeep$1(methodMap[(0, _tmagic_utils.toLine)(type)]) || [];
|
|
11209
11232
|
}
|
|
11210
11233
|
resetState() {
|
|
@@ -11238,7 +11261,8 @@
|
|
|
11238
11261
|
var getEventNameOptions = (src, formValue = {}) => {
|
|
11239
11262
|
if (!formValue.type) return [];
|
|
11240
11263
|
if (src === "component") {
|
|
11241
|
-
|
|
11264
|
+
const sourceNode = editor_default.getNodeById(formValue.id);
|
|
11265
|
+
let events = events_default.getEvent(formValue.type, { node: sourceNode }) || [];
|
|
11242
11266
|
if (formValue.type === "page-fragment-container" && formValue.pageFragmentId) {
|
|
11243
11267
|
const pageFragment = editor_default.get("root")?.items?.find((page) => page.id === formValue.pageFragmentId);
|
|
11244
11268
|
if (!pageFragment) return [];
|
|
@@ -11247,9 +11271,11 @@
|
|
|
11247
11271
|
value: pageFragment.id,
|
|
11248
11272
|
children: events
|
|
11249
11273
|
}];
|
|
11250
|
-
(pageFragment.items || []).forEach((
|
|
11251
|
-
(0, _tmagic_utils.traverseNode)(
|
|
11252
|
-
|
|
11274
|
+
(pageFragment.items || []).forEach((item) => {
|
|
11275
|
+
(0, _tmagic_utils.traverseNode)(item, (current) => {
|
|
11276
|
+
if (!current.type) return;
|
|
11277
|
+
const node = editor_default.getNodeById(current.id) || current;
|
|
11278
|
+
const nodeEvents = events_default.getEvent(current.type, { node }) || [];
|
|
11253
11279
|
events.push({
|
|
11254
11280
|
label: `${current.name}_${current.id}`,
|
|
11255
11281
|
value: `${current.id}`,
|
|
@@ -11308,15 +11334,24 @@
|
|
|
11308
11334
|
if (typeof toId === "undefined" || toId === null || toId === "") return [];
|
|
11309
11335
|
const node = editor_default.getNodeById(toId);
|
|
11310
11336
|
if (!node?.type) return [];
|
|
11311
|
-
let methods = events_default.getMethod(node.type,
|
|
11337
|
+
let methods = events_default.getMethod(node.type, {
|
|
11338
|
+
targetId: toId,
|
|
11339
|
+
node
|
|
11340
|
+
}) || [];
|
|
11312
11341
|
if (node.type === "page-fragment-container" && node.pageFragmentId) {
|
|
11313
11342
|
const pageFragment = editor_default.get("root")?.items?.find((page) => page.id === node.pageFragmentId);
|
|
11314
11343
|
if (!pageFragment) return [];
|
|
11315
11344
|
methods = [];
|
|
11316
11345
|
(pageFragment.items || []).forEach((item) => {
|
|
11317
11346
|
(0, _tmagic_utils.traverseNode)(item, (current) => {
|
|
11318
|
-
const
|
|
11319
|
-
if (
|
|
11347
|
+
const node = editor_default.getNodeById(current.id) || current;
|
|
11348
|
+
if (!current.type) return;
|
|
11349
|
+
const nodeMethods = events_default.getMethod(current.type, {
|
|
11350
|
+
targetId: current.id,
|
|
11351
|
+
node
|
|
11352
|
+
}) || [];
|
|
11353
|
+
if (!nodeMethods.length) return;
|
|
11354
|
+
methods.push({
|
|
11320
11355
|
label: `${current.name}_${current.id}`,
|
|
11321
11356
|
value: `${current.id}`,
|
|
11322
11357
|
children: nodeMethods
|
|
@@ -23003,7 +23038,7 @@
|
|
|
23003
23038
|
name: "name",
|
|
23004
23039
|
label: "事件名",
|
|
23005
23040
|
type: eventNameConfig.value.type,
|
|
23006
|
-
options: (mForm, { formValue }) => eventsService.getEvent(formValue.type).map((option) => ({
|
|
23041
|
+
options: (mForm, { formValue }) => eventsService.getEvent(formValue.type, { node: editorService.getNodeById(formValue.id) }).map((option) => ({
|
|
23007
23042
|
text: option.label,
|
|
23008
23043
|
value: option.value
|
|
23009
23044
|
}))
|
|
@@ -23020,7 +23055,10 @@
|
|
|
23020
23055
|
options: (mForm, { model }) => {
|
|
23021
23056
|
const node = editorService.getNodeById(model.to);
|
|
23022
23057
|
if (!node?.type) return [];
|
|
23023
|
-
return eventsService.getMethod(node.type,
|
|
23058
|
+
return eventsService.getMethod(node.type, {
|
|
23059
|
+
targetId: model.to,
|
|
23060
|
+
node
|
|
23061
|
+
}).map((option) => ({
|
|
23024
23062
|
text: option.label,
|
|
23025
23063
|
value: option.value
|
|
23026
23064
|
}));
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.8.0-beta.
|
|
2
|
+
"version": "1.8.0-beta.21",
|
|
3
3
|
"name": "@tmagic/editor",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
@@ -58,11 +58,11 @@
|
|
|
58
58
|
"moveable": "^0.53.0",
|
|
59
59
|
"serialize-javascript": "^7.0.0",
|
|
60
60
|
"sortablejs": "^1.15.6",
|
|
61
|
-
"@tmagic/design": "1.8.0-beta.
|
|
62
|
-
"@tmagic/form": "1.8.0-beta.
|
|
63
|
-
"@tmagic/stage": "1.8.0-beta.
|
|
64
|
-
"@tmagic/table": "1.8.0-beta.
|
|
65
|
-
"@tmagic/utils": "1.8.0-beta.
|
|
61
|
+
"@tmagic/design": "1.8.0-beta.21",
|
|
62
|
+
"@tmagic/form": "1.8.0-beta.21",
|
|
63
|
+
"@tmagic/stage": "1.8.0-beta.21",
|
|
64
|
+
"@tmagic/table": "1.8.0-beta.21",
|
|
65
|
+
"@tmagic/utils": "1.8.0-beta.21"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"@types/events": "^3.0.3",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"type-fest": "^5.2.0",
|
|
77
77
|
"typescript": "^6.0.3",
|
|
78
78
|
"vue": "^3.5.40",
|
|
79
|
-
"@tmagic/core": "1.8.0-beta.
|
|
79
|
+
"@tmagic/core": "1.8.0-beta.21"
|
|
80
80
|
},
|
|
81
81
|
"peerDependenciesMeta": {
|
|
82
82
|
"typescript": {
|
|
@@ -311,10 +311,12 @@ const tableConfig = computed(
|
|
|
311
311
|
label: '事件名',
|
|
312
312
|
type: eventNameConfig.value.type,
|
|
313
313
|
options: (mForm: FormState, { formValue }: any) =>
|
|
314
|
-
eventsService
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
314
|
+
eventsService
|
|
315
|
+
.getEvent(formValue.type, { node: editorService.getNodeById(formValue.id) })
|
|
316
|
+
.map((option: any) => ({
|
|
317
|
+
text: option.label,
|
|
318
|
+
value: option.value,
|
|
319
|
+
})),
|
|
318
320
|
},
|
|
319
321
|
{
|
|
320
322
|
name: 'to',
|
|
@@ -329,7 +331,7 @@ const tableConfig = computed(
|
|
|
329
331
|
const node = editorService.getNodeById(model.to);
|
|
330
332
|
if (!node?.type) return [];
|
|
331
333
|
|
|
332
|
-
return eventsService.getMethod(node.type, model.to).map((option: any) => ({
|
|
334
|
+
return eventsService.getMethod(node.type, { targetId: model.to, node }).map((option: any) => ({
|
|
333
335
|
text: option.label,
|
|
334
336
|
value: option.value,
|
|
335
337
|
}));
|
package/src/services/events.ts
CHANGED
|
@@ -20,7 +20,7 @@ import { reactive } from 'vue';
|
|
|
20
20
|
import { cloneDeep } from 'lodash-es';
|
|
21
21
|
import type { Writable } from 'type-fest';
|
|
22
22
|
|
|
23
|
-
import {
|
|
23
|
+
import type { EventOption, Id, MNode } from '@tmagic/core';
|
|
24
24
|
import { toLine } from '@tmagic/utils';
|
|
25
25
|
|
|
26
26
|
import type { AsyncHookPlugin, SyncHookPlugin } from '@editor/type';
|
|
@@ -56,7 +56,7 @@ class Events extends BaseService {
|
|
|
56
56
|
eventMap[toLine(type)] = [...events];
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
public getEvent(type: string): EventOption[] {
|
|
59
|
+
public getEvent(type: string, _data: { node?: MNode | null } = {}): EventOption[] {
|
|
60
60
|
return cloneDeep(eventMap[toLine(type)]) || [];
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -70,7 +70,7 @@ class Events extends BaseService {
|
|
|
70
70
|
methodMap[toLine(type)] = [...method];
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
public getMethod(type: string,
|
|
73
|
+
public getMethod(type: string, _data: { node?: MNode | null; targetId?: Id } = {}) {
|
|
74
74
|
return cloneDeep(methodMap[toLine(type)]) || [];
|
|
75
75
|
}
|
|
76
76
|
|
|
@@ -13,6 +13,18 @@ type TaskList<T> = {
|
|
|
13
13
|
data: T;
|
|
14
14
|
}[];
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* 回调因 timeout 触发(主线程一直没有空闲)时,单次回调执行任务的时间预算,单位 ms
|
|
18
|
+
* 参考一帧内可让出的余量:既保证队列有进展,又不长时间阻塞主线程
|
|
19
|
+
*/
|
|
20
|
+
const TIMEOUT_RUN_BUDGET = 5;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 回调因 timeout 触发时,每两次读取时钟之间执行的任务数
|
|
24
|
+
* 与空闲时间 <=5ms 时的批量保持一致,避免每个任务都读一次时钟
|
|
25
|
+
*/
|
|
26
|
+
const TIMEOUT_BATCH_SIZE = 10;
|
|
27
|
+
|
|
16
28
|
globalThis.requestIdleCallback =
|
|
17
29
|
globalThis.requestIdleCallback ||
|
|
18
30
|
function (cb) {
|
|
@@ -94,6 +106,19 @@ export class IdleTask<T = any> extends EventEmitter {
|
|
|
94
106
|
this.taskHandle = null;
|
|
95
107
|
|
|
96
108
|
try {
|
|
109
|
+
// 主线程一直没有空闲时,回调只会因 timeout 触发,此时 deadline.timeRemaining() 恒为 0(规范行为)。
|
|
110
|
+
// 若仍以它作为循环条件,一个任务都执行不了,而 finishRun 又会接着重新调度,
|
|
111
|
+
// 队列就会无限空转下去:依赖收集永远不结束,collecting 卡在 true,画布也不再更新。
|
|
112
|
+
// 这种情况下改用自有时间预算推进,既保证有进展,又不会像放开循环那样长时间阻塞主线程。
|
|
113
|
+
if (deadline.didTimeout) {
|
|
114
|
+
const start = Date.now();
|
|
115
|
+
do {
|
|
116
|
+
this.runTaskBatch(TIMEOUT_BATCH_SIZE);
|
|
117
|
+
} while (this.getTaskLength() && Date.now() - start < TIMEOUT_RUN_BUDGET);
|
|
118
|
+
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
97
122
|
// 动画会占用空闲时间,当任务一直无法执行时,看看是否有动画正在播放
|
|
98
123
|
// 根据空闲时间的多少来决定执行的任务数,保证页面不卡死的情况下尽量多执行任务,不然当任务数巨大时,执行时间会很久
|
|
99
124
|
// 执行不完不会影响配置,但是会影响画布渲染
|
|
@@ -110,17 +135,7 @@ export class IdleTask<T = any> extends EventEmitter {
|
|
|
110
135
|
times = 600;
|
|
111
136
|
}
|
|
112
137
|
|
|
113
|
-
|
|
114
|
-
// 每次都从实例上取队列,任务执行过程中调用 clearTasks 能立即生效,不会继续消费已被清空的旧队列
|
|
115
|
-
const task = this.hightLevelTaskList.length > 0 ? this.hightLevelTaskList.shift() : this.taskList.shift();
|
|
116
|
-
if (task) {
|
|
117
|
-
this.runTask(task);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (!this.getTaskLength()) {
|
|
121
|
-
break;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
138
|
+
this.runTaskBatch(times);
|
|
124
139
|
}
|
|
125
140
|
} finally {
|
|
126
141
|
// 必须放在 finally 中:一旦这里被跳过,taskHandle 会一直是真值,
|
|
@@ -129,6 +144,23 @@ export class IdleTask<T = any> extends EventEmitter {
|
|
|
129
144
|
}
|
|
130
145
|
}
|
|
131
146
|
|
|
147
|
+
/**
|
|
148
|
+
* 执行一批任务,队列被清空时提前结束
|
|
149
|
+
*/
|
|
150
|
+
private runTaskBatch(times: number) {
|
|
151
|
+
for (let i = 0; i < times; i++) {
|
|
152
|
+
// 每次都从实例上取队列,任务执行过程中调用 clearTasks 能立即生效,不会继续消费已被清空的旧队列
|
|
153
|
+
const task = this.hightLevelTaskList.length > 0 ? this.hightLevelTaskList.shift() : this.taskList.shift();
|
|
154
|
+
if (task) {
|
|
155
|
+
this.runTask(task);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!this.getTaskLength()) {
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
132
164
|
/**
|
|
133
165
|
* 单个任务失败不能中断整个队列,否则后续任务永远不会被执行,
|
|
134
166
|
* 依赖收集会停在半路(收集中状态与剩余任务数都不再变化)
|
package/src/utils/event.ts
CHANGED
|
@@ -56,7 +56,8 @@ export const getEventNameOptions = (
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
if (src === 'component') {
|
|
59
|
-
|
|
59
|
+
const sourceNode = editorService.getNodeById(formValue.id);
|
|
60
|
+
let events: EventOption[] | CascaderOption[] = eventsService.getEvent(formValue.type, { node: sourceNode }) || [];
|
|
60
61
|
|
|
61
62
|
if (formValue.type === 'page-fragment-container' && formValue.pageFragmentId) {
|
|
62
63
|
const pageFragment = editorService.get('root')?.items?.find((page) => page.id === formValue.pageFragmentId);
|
|
@@ -72,9 +73,14 @@ export const getEventNameOptions = (
|
|
|
72
73
|
},
|
|
73
74
|
];
|
|
74
75
|
|
|
75
|
-
(pageFragment.items || []).forEach((
|
|
76
|
-
traverseNode<MComponent | MContainer>(
|
|
77
|
-
|
|
76
|
+
(pageFragment.items || []).forEach((item) => {
|
|
77
|
+
traverseNode<MComponent | MContainer>(item, (current) => {
|
|
78
|
+
if (!current.type) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const node = editorService.getNodeById(current.id) || current;
|
|
83
|
+
const nodeEvents = eventsService.getEvent(current.type, { node }) || [];
|
|
78
84
|
(events as CascaderOption[]).push({
|
|
79
85
|
label: `${current.name}_${current.id}`,
|
|
80
86
|
value: `${current.id}`,
|
|
@@ -176,7 +182,7 @@ export const getCompActionOptions = (toId?: Id): EventNameOption[] => {
|
|
|
176
182
|
return [];
|
|
177
183
|
}
|
|
178
184
|
|
|
179
|
-
let methods: EventOption[] | CascaderOption[] = eventsService.getMethod(node.type, toId) || [];
|
|
185
|
+
let methods: EventOption[] | CascaderOption[] = eventsService.getMethod(node.type, { targetId: toId, node }) || [];
|
|
180
186
|
|
|
181
187
|
if (node.type === 'page-fragment-container' && node.pageFragmentId) {
|
|
182
188
|
const pageFragment = editorService.get('root')?.items?.find((page) => page.id === node.pageFragmentId);
|
|
@@ -187,15 +193,22 @@ export const getCompActionOptions = (toId?: Id): EventNameOption[] => {
|
|
|
187
193
|
methods = [];
|
|
188
194
|
(pageFragment.items || []).forEach((item: MComponent | MContainer) => {
|
|
189
195
|
traverseNode<MComponent | MContainer>(item, (current) => {
|
|
190
|
-
const
|
|
196
|
+
const node = editorService.getNodeById(current.id) || current;
|
|
191
197
|
|
|
192
|
-
if (
|
|
193
|
-
|
|
194
|
-
label: `${current.name}_${current.id}`,
|
|
195
|
-
value: `${current.id}`,
|
|
196
|
-
children: nodeMethods,
|
|
197
|
-
});
|
|
198
|
+
if (!current.type) {
|
|
199
|
+
return;
|
|
198
200
|
}
|
|
201
|
+
|
|
202
|
+
const nodeMethods = eventsService.getMethod(current.type, { targetId: current.id, node }) || [];
|
|
203
|
+
if (!nodeMethods.length) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
(methods as CascaderOption[]).push({
|
|
208
|
+
label: `${current.name}_${current.id}`,
|
|
209
|
+
value: `${current.id}`,
|
|
210
|
+
children: nodeMethods,
|
|
211
|
+
});
|
|
199
212
|
});
|
|
200
213
|
});
|
|
201
214
|
|
package/types/index.d.ts
CHANGED
|
@@ -1023,10 +1023,15 @@ declare class Events extends BaseService {
|
|
|
1023
1023
|
constructor();
|
|
1024
1024
|
setEvents(events: Record<string, EventOption[]>): void;
|
|
1025
1025
|
setEvent(type: string, events: EventOption[]): void;
|
|
1026
|
-
getEvent(type: string
|
|
1026
|
+
getEvent(type: string, _data?: {
|
|
1027
|
+
node?: MNode | null;
|
|
1028
|
+
}): EventOption[];
|
|
1027
1029
|
setMethods(methods: Record<string, EventOption[]>): void;
|
|
1028
1030
|
setMethod(type: string, method: EventOption[]): void;
|
|
1029
|
-
getMethod(type: string,
|
|
1031
|
+
getMethod(type: string, _data?: {
|
|
1032
|
+
node?: MNode | null;
|
|
1033
|
+
targetId?: Id;
|
|
1034
|
+
}): EventOption[];
|
|
1030
1035
|
resetState(): void;
|
|
1031
1036
|
destroy(): void;
|
|
1032
1037
|
usePlugin(options: AsyncHookPlugin<AsyncMethodName$3, Events> & SyncHookPlugin<SyncMethodName$4, Events>): void;
|
|
@@ -3395,6 +3400,10 @@ declare class IdleTask<T = any> extends EventEmitter {
|
|
|
3395
3400
|
once<Name extends keyof IdleTaskEvents, Param extends IdleTaskEvents[Name]>(eventName: Name, listener: (...args: Param) => void | Promise<void>): this;
|
|
3396
3401
|
emit<Name extends keyof IdleTaskEvents, Param extends IdleTaskEvents[Name]>(eventName: Name, ...args: Param): boolean;
|
|
3397
3402
|
private runTaskQueue;
|
|
3403
|
+
/**
|
|
3404
|
+
* 执行一批任务,队列被清空时提前结束
|
|
3405
|
+
*/
|
|
3406
|
+
private runTaskBatch;
|
|
3398
3407
|
/**
|
|
3399
3408
|
* 单个任务失败不能中断整个队列,否则后续任务永远不会被执行,
|
|
3400
3409
|
* 依赖收集会停在半路(收集中状态与剩余任务数都不再变化)
|