@tmagic/editor 1.8.0-beta.16 → 1.8.0-beta.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.
@@ -50,6 +50,7 @@ var Editor_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCom
50
50
  containerHighlightClassName: {},
51
51
  containerHighlightDuration: {},
52
52
  containerHighlightType: {},
53
+ containerHighlightAddOnly: { type: Boolean },
53
54
  stageRect: {},
54
55
  codeOptions: {},
55
56
  disabledDragStart: { type: Boolean },
@@ -120,6 +121,7 @@ var Editor_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineCom
120
121
  containerHighlightClassName: props.containerHighlightClassName,
121
122
  containerHighlightDuration: props.containerHighlightDuration,
122
123
  containerHighlightType: props.containerHighlightType,
124
+ containerHighlightAddOnly: props.containerHighlightAddOnly,
123
125
  disabledDragStart: props.disabledDragStart,
124
126
  renderType: props.renderType,
125
127
  guidesOptions: props.guidesOptions,
@@ -16,6 +16,7 @@ var defaultEditorProps = {
16
16
  containerHighlightClassName: CONTAINER_HIGHLIGHT_CLASS_NAME,
17
17
  containerHighlightDuration: 800,
18
18
  containerHighlightType: ContainerHighlightType.DEFAULT,
19
+ containerHighlightAddOnly: false,
19
20
  disabledShowSrc: false,
20
21
  disabledDataSource: false,
21
22
  disabledCodeBlock: false,
@@ -3,7 +3,7 @@ import { getCompActionAllowedValues, getCompActionOptions, getEventNameAllowedVa
3
3
  import { MContainer, MPanel, MTable, defineFormItem } from "@tmagic/form";
4
4
  import { TMagicButton } from "@tmagic/design";
5
5
  import { ActionType } from "@tmagic/core";
6
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, openBlock, renderList, toDisplayString, unref, withCtx } from "vue";
6
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, openBlock, renderList, unref, withCtx } from "vue";
7
7
  import { has } from "lodash-es";
8
8
  import { Delete, Plus } from "@element-plus/icons-vue";
9
9
  //#region packages/editor/src/fields/EventSelect.vue?vue&type=script&setup=true&lang.ts
@@ -14,7 +14,6 @@ var _hoisted_2 = {
14
14
  };
15
15
  var _hoisted_3 = { class: "event-select-header" };
16
16
  var _hoisted_4 = { class: "event-item-header" };
17
- var _hoisted_5 = { class: "event-item-title" };
18
17
  var EventSelect_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
19
18
  name: "MFieldsEventSelect",
20
19
  __name: "EventSelect",
@@ -95,6 +94,12 @@ var EventSelect_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
95
94
  typeMatch: true,
96
95
  trigger: "blur"
97
96
  }],
97
+ onChange: (_mForm, _v, { setModel }) => {
98
+ setModel("to", "");
99
+ setModel("method", "");
100
+ setModel("codeId", "");
101
+ setModel("dataSourceMethod", []);
102
+ },
98
103
  ...props.config.actionTypeConfig
99
104
  };
100
105
  });
@@ -105,7 +110,7 @@ var EventSelect_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
105
110
  type: "ui-select",
106
111
  labelPosition: "left",
107
112
  display: (_mForm, { model }) => model.actionType === ActionType.COMP,
108
- onChange: (_MForm, _v, { setModel }) => {
113
+ onChange: (_mForm, _v, { setModel }) => {
109
114
  setModel("method", "");
110
115
  },
111
116
  rules: [{
@@ -312,46 +317,42 @@ var EventSelect_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
312
317
  model: entry.cardItem,
313
318
  "last-values": entry.lastCardItem,
314
319
  "is-compare": isCompareMode.value,
315
- "hide-expand": true,
320
+ "hide-expand": false,
316
321
  "label-width": __props.config.labelWidth || "100px",
317
322
  onChange: onChangeHandler
318
323
  }, {
319
- header: withCtx(() => [createElementVNode("div", _hoisted_4, [
320
- createElementVNode("div", _hoisted_5, "事件" + toDisplayString(Number(entry.index) + 1), 1),
321
- createVNode(unref(MContainer), {
322
- class: "fullWidth",
323
- config: eventNameConfig.value,
324
- model: entry.cardItem,
325
- "last-values": entry.lastCardItem,
326
- "is-compare": isCompareMode.value,
327
- disabled: __props.disabled,
328
- size: __props.size,
329
- prop: `${__props.prop}.${entry.index}`,
330
- onChange: eventNameChangeHandler
331
- }, null, 8, [
332
- "config",
333
- "model",
334
- "last-values",
335
- "is-compare",
336
- "disabled",
337
- "size",
338
- "prop"
339
- ]),
340
- !isCompareMode.value ? (openBlock(), createBlock(unref(TMagicButton), {
341
- key: 0,
342
- class: "event-item-delete-button",
343
- link: "",
344
- icon: unref(Delete),
345
- disabled: __props.disabled,
346
- size: __props.size,
347
- onClick: ($event) => removeEvent(Number(entry.index))
348
- }, null, 8, [
349
- "icon",
350
- "disabled",
351
- "size",
352
- "onClick"
353
- ])) : createCommentVNode("v-if", true)
354
- ])]),
324
+ header: withCtx(() => [createElementVNode("div", _hoisted_4, [createVNode(unref(MContainer), {
325
+ class: "fullWidth",
326
+ config: eventNameConfig.value,
327
+ model: entry.cardItem,
328
+ "last-values": entry.lastCardItem,
329
+ "is-compare": isCompareMode.value,
330
+ disabled: __props.disabled,
331
+ size: __props.size,
332
+ prop: `${__props.prop}.${entry.index}`,
333
+ onChange: eventNameChangeHandler
334
+ }, null, 8, [
335
+ "config",
336
+ "model",
337
+ "last-values",
338
+ "is-compare",
339
+ "disabled",
340
+ "size",
341
+ "prop"
342
+ ]), !isCompareMode.value ? (openBlock(), createBlock(unref(TMagicButton), {
343
+ key: 0,
344
+ class: "event-item-delete-button",
345
+ link: "",
346
+ icon: unref(Delete),
347
+ disabled: __props.disabled,
348
+ size: __props.size,
349
+ onClick: ($event) => removeEvent(Number(entry.index))
350
+ }, null, 8, [
351
+ "icon",
352
+ "disabled",
353
+ "size",
354
+ "onClick"
355
+ ])) : createCommentVNode("v-if", true)])]),
355
356
  _: 2
356
357
  }, 1032, [
357
358
  "disabled",
@@ -22,6 +22,7 @@ var useStage = (stageOptions) => {
22
22
  containerHighlightClassName: stageOptions.containerHighlightClassName,
23
23
  containerHighlightDuration: stageOptions.containerHighlightDuration,
24
24
  containerHighlightType: stageOptions.containerHighlightType,
25
+ containerHighlightAddOnly: stageOptions.containerHighlightAddOnly,
25
26
  disabledDragStart: stageOptions.disabledDragStart,
26
27
  renderType: stageOptions.renderType,
27
28
  canSelect: (el, event, stop) => {
@@ -110,15 +110,15 @@ var initServiceEvents = (props, emit, { editorService, codeBlockService, dataSou
110
110
  return pageId;
111
111
  };
112
112
  const collectIdle = (nodes, deep, type) => Promise.all(nodes.map((node) => {
113
- if (node.type === NodeType.ROOT) return Promise.resolve();
113
+ if (node.type === NodeType.ROOT) return Promise.resolve(true);
114
114
  return depService.collectIdle([node], { pageId: getPageIdByNode(node) }, deep, type);
115
- }));
115
+ })).then((results) => results.every(Boolean));
116
116
  watch(() => editorService.get("stage"), (stage) => {
117
117
  if (!stage) return;
118
118
  stage.on("rerender", async () => {
119
119
  const node = editorService.get("node");
120
120
  if (!node) return;
121
- await collectIdle([node], true, DepTargetType.DATA_SOURCE);
121
+ if (!await collectIdle([node], true, DepTargetType.DATA_SOURCE)) return;
122
122
  updateStageNode(node);
123
123
  });
124
124
  });
@@ -205,8 +205,8 @@ var initServiceEvents = (props, emit, { editorService, codeBlockService, dataSou
205
205
  })();
206
206
  };
207
207
  const nodeAddHandler = (nodes) => {
208
- collectIdle(nodes, true).then(() => {
209
- updateStageNodes(nodes);
208
+ collectIdle(nodes, true).then((completed) => {
209
+ if (completed) updateStageNodes(nodes);
210
210
  });
211
211
  };
212
212
  const nodeUpdateHandler = (data) => {
@@ -235,8 +235,8 @@ var initServiceEvents = (props, emit, { editorService, codeBlockService, dataSou
235
235
  else normalNodes.push(newNode);
236
236
  if (needRecollectNodes.length) {
237
237
  const handler = async () => {
238
- await collectIdle(needRecollectNodes, true, DepTargetType.DATA_SOURCE);
239
- await collectIdle(needRecollectNodes, true, DepTargetType.DATA_SOURCE_COND);
238
+ if (!await collectIdle(needRecollectNodes, true, DepTargetType.DATA_SOURCE)) return;
239
+ if (!await collectIdle(needRecollectNodes, true, DepTargetType.DATA_SOURCE_COND)) return;
240
240
  updateStageNodes(needRecollectNodes);
241
241
  };
242
242
  handler();
@@ -249,8 +249,8 @@ var initServiceEvents = (props, emit, { editorService, codeBlockService, dataSou
249
249
  depService.clear(nodes);
250
250
  };
251
251
  const historyChangeHandler = (page) => {
252
- collectIdle([page], true).then(() => {
253
- updateStageNode(page);
252
+ collectIdle([page], true).then((completed) => {
253
+ if (completed) updateStageNode(page);
254
254
  });
255
255
  };
256
256
  editorService.on("history-change", historyChangeHandler);
@@ -310,7 +310,13 @@ var initServiceEvents = (props, emit, { editorService, codeBlockService, dataSou
310
310
  depService.addTarget(createDataSourceMethodTarget(config, reactive({})));
311
311
  collectIdlePromises = [collectIdle(root.items, true, DepTargetType.DATA_SOURCE_METHOD)];
312
312
  }
313
- Promise.all(collectIdlePromises).then(() => updateDataSourceSchema()).then(() => updateDsData()).then(() => updateStageNodes(root.items));
313
+ const handler = async () => {
314
+ if (!(await Promise.all(collectIdlePromises)).every(Boolean)) return;
315
+ updateDataSourceSchema();
316
+ await updateDsData();
317
+ updateStageNodes(root.items);
318
+ };
319
+ handler();
314
320
  }
315
321
  } else if (root?.dataSources) updateDsData();
316
322
  };
@@ -324,11 +330,11 @@ var initServiceEvents = (props, emit, { editorService, codeBlockService, dataSou
324
330
  if (!root) return;
325
331
  const handler = async () => {
326
332
  const nodes = getNodes(Object.keys(root.dataSourceDeps?.[id] || {}), root.items);
327
- await Promise.all([
333
+ if (!(await Promise.all([
328
334
  collectIdle(nodes, false, DepTargetType.DATA_SOURCE),
329
335
  collectIdle(nodes, false, DepTargetType.DATA_SOURCE_COND),
330
336
  collectIdle(nodes, false, DepTargetType.DATA_SOURCE_METHOD)
331
- ]);
337
+ ])).every(Boolean)) return;
332
338
  updateDataSourceSchema();
333
339
  (await getTMagicApp())?.dataSourceManager?.removeDataSource(id);
334
340
  updateStageNodes(nodes);
@@ -70,7 +70,7 @@ var ComponentListPanel_vue_vue_type_script_setup_true_lang_default = /*@__PURE__
70
70
  return;
71
71
  }
72
72
  if (timeout || !stage.value) return;
73
- timeout = stage.value.delayedMarkContainer(e);
73
+ timeout = stage.value.delayedMarkContainer(e, [], true);
74
74
  };
75
75
  return (_ctx, _cache) => {
76
76
  return openBlock(), createBlock(unref(TMagicScrollbar), null, {
@@ -15,6 +15,9 @@ var Dep = class extends BaseService {
15
15
  idleTask = new IdleTask();
16
16
  watcher = new Watcher({ initialTargets: reactive({}) });
17
17
  waitingWorker;
18
+ resolveWaitingWorker;
19
+ workerGeneration = 0;
20
+ activeBatches = /* @__PURE__ */ new Set();
18
21
  constructor() {
19
22
  super();
20
23
  this.idleTask.on("update-task-length", throttle(({ length }) => {
@@ -64,33 +67,36 @@ var Dep = class extends BaseService {
64
67
  }
65
68
  async collectIdle(nodes, depExtendedData = {}, deep = false, type) {
66
69
  if (this.waitingWorker) await this.waitingWorker;
67
- this.set("collecting", true);
68
- let startTask = false;
70
+ const batch = {
71
+ nodes,
72
+ deep,
73
+ pending: 0,
74
+ dsPending: 0,
75
+ collectedEmitted: false,
76
+ dsSettled: false,
77
+ resolve: () => {}
78
+ };
69
79
  this.watcher.collectByCallback(nodes, type, ({ node, target }) => {
70
- startTask = true;
71
- this.enqueueTask(node, target, depExtendedData, deep);
80
+ this.enqueueTask(node, target, depExtendedData, deep, batch);
72
81
  });
82
+ if (batch.pending === 0) {
83
+ this.emit("collected", nodes, deep);
84
+ this.updateCollectingState();
85
+ return true;
86
+ }
87
+ this.activeBatches.add(batch);
88
+ this.set("collecting", true);
73
89
  return new Promise((resolve) => {
74
- if (!startTask) {
75
- this.emit("collected", nodes, deep);
76
- this.set("collecting", false);
77
- resolve();
78
- return;
79
- }
80
- this.idleTask.once("finish", () => {
81
- this.emit("collected", nodes, deep);
82
- this.set("collecting", false);
83
- });
84
- this.idleTask.once("hight-level-finish", () => {
85
- this.emit("ds-collected", nodes, deep);
86
- resolve();
87
- });
90
+ batch.resolve = resolve;
88
91
  });
89
92
  }
90
93
  collectByWorker(dsl) {
91
94
  this.set("collecting", true);
95
+ this.workerGeneration += 1;
96
+ const generation = this.workerGeneration;
92
97
  const { promise, resolve: waitingResolve } = Promise.withResolvers();
93
98
  this.waitingWorker = promise;
99
+ this.resolveWaitingWorker = waitingResolve;
94
100
  return new Promise((resolve) => {
95
101
  const worker = new WorkerWrapper();
96
102
  worker.postMessage({ dsl: serialize(dsl) });
@@ -101,6 +107,10 @@ var Dep = class extends BaseService {
101
107
  resolve({});
102
108
  };
103
109
  }).then((depsData) => {
110
+ if (generation !== this.workerGeneration) {
111
+ waitingResolve();
112
+ return depsData;
113
+ }
104
114
  traverseTarget(this.watcher.getTargetsList(), (target) => {
105
115
  if (depsData[target.type]?.[target.id]) {
106
116
  target.deps = reactive(depsData[target.type][target.id]);
@@ -113,6 +123,10 @@ var Dep = class extends BaseService {
113
123
  this.emit("collected", dsl.items, true);
114
124
  this.emit("ds-collected", dsl.items, true);
115
125
  waitingResolve();
126
+ if (this.waitingWorker === promise) {
127
+ this.waitingWorker = void 0;
128
+ this.resolveWaitingWorker = void 0;
129
+ }
116
130
  return depsData;
117
131
  });
118
132
  }
@@ -134,6 +148,7 @@ var Dep = class extends BaseService {
134
148
  return this.watcher.hasSpecifiedTypeTarget(type);
135
149
  }
136
150
  clearIdleTasks() {
151
+ this.abortActiveBatches();
137
152
  this.idleTask.clearTasks();
138
153
  }
139
154
  on(eventName, listener) {
@@ -143,6 +158,11 @@ var Dep = class extends BaseService {
143
158
  return super.once(eventName, listener);
144
159
  }
145
160
  reset() {
161
+ this.abortActiveBatches();
162
+ this.workerGeneration += 1;
163
+ this.resolveWaitingWorker?.();
164
+ this.resolveWaitingWorker = void 0;
165
+ this.waitingWorker = void 0;
146
166
  this.idleTask.clearTasks();
147
167
  for (const type of Object.keys(this.watcher.getTargetsList())) this.removeTargets(type);
148
168
  this.set("collecting", false);
@@ -167,18 +187,63 @@ var Dep = class extends BaseService {
167
187
  if (dep.data?.pageId && dep.data.pageId === depExtendedData.pageId) delete target.deps[depKey];
168
188
  }
169
189
  }
170
- enqueueTask(node, target, depExtendedData, deep) {
190
+ enqueueTask(node, target, depExtendedData, deep, batch) {
191
+ const isDataSource = target.type === DepTargetType.DATA_SOURCE;
192
+ batch.pending += 1;
193
+ if (isDataSource) batch.dsPending += 1;
171
194
  this.idleTask.enqueueTask(({ node, deep, target }) => {
172
- this.collectNode(node, target, depExtendedData, deep);
195
+ try {
196
+ this.collectNode(node, target, depExtendedData, deep);
197
+ } finally {
198
+ this.onBatchTaskDone(batch, isDataSource);
199
+ }
173
200
  }, {
174
201
  node,
175
202
  deep: false,
176
203
  target
177
- }, target.type === DepTargetType.DATA_SOURCE);
204
+ }, isDataSource);
178
205
  if (deep && Array.isArray(node.items) && node.items.length) node.items.forEach((item) => {
179
- this.enqueueTask(item, target, depExtendedData, deep);
206
+ this.enqueueTask(item, target, depExtendedData, deep, batch);
180
207
  });
181
208
  }
209
+ onBatchTaskDone(batch, isDataSource) {
210
+ if (isDataSource) {
211
+ batch.dsPending -= 1;
212
+ if (batch.dsPending === 0) this.settleBatchDs(batch);
213
+ }
214
+ batch.pending -= 1;
215
+ if (batch.pending === 0) this.finishBatch(batch);
216
+ }
217
+ settleBatchDs(batch) {
218
+ if (batch.dsSettled) return;
219
+ batch.dsSettled = true;
220
+ this.emit("ds-collected", batch.nodes, batch.deep);
221
+ batch.resolve(true);
222
+ }
223
+ finishBatch(batch) {
224
+ if (!batch.collectedEmitted) {
225
+ batch.collectedEmitted = true;
226
+ this.emit("collected", batch.nodes, batch.deep);
227
+ }
228
+ this.settleBatchDs(batch);
229
+ this.activeBatches.delete(batch);
230
+ this.updateCollectingState();
231
+ }
232
+ /**
233
+ * idleTask 被清空时,在途批次的任务不会再执行,必须主动结算,
234
+ * 否则对应的 collectIdle Promise 永远不会 resolve(collecting 卡在 true、once 监听器泄漏)。
235
+ * 收集被中断(通常紧跟一次全量重新收集),因此不再 emit collected/ds-collected,仅结算 Promise。
236
+ */
237
+ abortActiveBatches() {
238
+ if (!this.activeBatches.size) return;
239
+ const batches = [...this.activeBatches];
240
+ this.activeBatches.clear();
241
+ for (const batch of batches) batch.resolve(false);
242
+ this.updateCollectingState();
243
+ }
244
+ updateCollectingState() {
245
+ this.set("collecting", this.activeBatches.size > 0);
246
+ }
182
247
  };
183
248
  var dep_default = new Dep();
184
249
  //#endregion
package/dist/es/style.css CHANGED
@@ -59,6 +59,9 @@
59
59
  border-radius: 0;
60
60
  border-bottom: 0;
61
61
  }
62
+ .tmagic-design-card.tmagic-design-card--flat.m-flat-hide-body .el-card__header {
63
+ border-bottom: 0 !important;
64
+ }
62
65
  .tmagic-design-card.tmagic-design-card--flat.m-fields-group-list-item {
63
66
  margin-bottom: 0;
64
67
  }
@@ -74,6 +77,10 @@
74
77
  box-shadow: none;
75
78
  cursor: default;
76
79
  }
80
+ .tmagic-design-card.tmagic-design-card--flat .m-fields-group-list-footer {
81
+ margin-bottom: 4px;
82
+ margin-top: 4px;
83
+ }
77
84
  .tmagic-design-card.tmagic-design-card--flat .el-card__body {
78
85
  padding: 0 16px 0 16px;
79
86
  }
@@ -95,7 +102,7 @@
95
102
  }
96
103
  .m-split-title-card-container > .tmagic-design-card.tmagic-design-card--flat > .el-card__body {
97
104
  background-color: #fff;
98
- padding-top: 16px;
105
+ padding-top: 8px;
99
106
  }
100
107
 
101
108
  .tmagic-design-color-picker-input {
@@ -434,12 +441,16 @@ fieldset.m-fieldset .m-form-tip {
434
441
  gap: 8px;
435
442
  }
436
443
  .m-fields-group-list .m-fields-group-list-footer {
437
- display: flex;
438
444
  justify-content: space-between;
439
445
  margin-top: 10px;
440
446
  margin-bottom: 16px;
441
447
  }
442
448
 
449
+ /** 最外层的groupList需要每个item需要增加空白区域界限时,增加outer-gorup_list可以实现 */
450
+ .m-container-group-list.outer-gorup_list > .m-fields-group-list > .m-fields-group-list-item {
451
+ margin-bottom: 10px;
452
+ }
453
+
443
454
  .m-form-panel .el-card__header:hover {
444
455
  background: #f2f6fc;
445
456
  }
@@ -1924,7 +1935,7 @@ fieldset.m-fieldset .m-form-tip {
1924
1935
  border: 0 !important;
1925
1936
  }
1926
1937
  .m-fields-code-select .el-card__body .tmagic-design-form-item {
1927
- margin-bottom: 18px;
1938
+ margin-bottom: 16px;
1928
1939
  }
1929
1940
  .m-fields-code-select .code-select-content > .m-fields-group-list > .tmagic-design-card--flat > .el-card__header {
1930
1941
  padding: 16px 0;
@@ -1941,6 +1952,12 @@ fieldset.m-fieldset .m-form-tip {
1941
1952
  width: 100%;
1942
1953
  box-sizing: border-box;
1943
1954
  }
1955
+ .m-fields-event-select .fullWidth.create-button {
1956
+ width: 100%;
1957
+ }
1958
+ .m-fields-event-select .fullWidth.m-container-ui-event {
1959
+ width: calc(100% - 32px);
1960
+ }
1944
1961
  .m-fields-event-select .event-select-container {
1945
1962
  padding: 0 16px;
1946
1963
  }
@@ -2008,18 +2025,19 @@ fieldset.m-fieldset .m-form-tip {
2008
2025
  .event-item-header {
2009
2026
  position: relative;
2010
2027
  width: 100%;
2028
+ display: flex;
2029
+ align-items: center;
2030
+ justify-content: space-between;
2011
2031
  }
2012
2032
  .event-item-header .event-item-title {
2013
2033
  color: #0f1113;
2014
2034
  font-size: 16px;
2015
2035
  font-weight: 500;
2016
2036
  line-height: 24px;
2017
- margin-bottom: 16px;
2037
+ margin-bottom: 8px;
2018
2038
  }
2019
2039
  .event-item-header .event-item-delete-button {
2020
- position: absolute;
2021
- right: 0;
2022
- top: 0;
2040
+ color: #0f1113;
2023
2041
  }
2024
2042
  .event-item-header .el-form-item .el-form-item.is-error {
2025
2043
  margin-bottom: 18px;
@@ -1,3 +1,4 @@
1
+ import { error } from "../logger.js";
1
2
  import { EventEmitter } from "events";
2
3
  //#region packages/editor/src/utils/dep/idle-task.ts
3
4
  globalThis.requestIdleCallback = globalThis.requestIdleCallback || function(cb) {
@@ -11,6 +12,9 @@ globalThis.requestIdleCallback = globalThis.requestIdleCallback || function(cb)
11
12
  });
12
13
  }, 1);
13
14
  };
15
+ globalThis.cancelIdleCallback = globalThis.cancelIdleCallback || function(handle) {
16
+ clearTimeout(handle);
17
+ };
14
18
  var IdleTask = class extends EventEmitter {
15
19
  taskList = [];
16
20
  hightLevelTaskList = [];
@@ -32,7 +36,7 @@ var IdleTask = class extends EventEmitter {
32
36
  this.taskList = [];
33
37
  this.taskHandle = null;
34
38
  this.emit("update-task-length", {
35
- length: this.taskList.length + this.hightLevelTaskList.length,
39
+ length: this.getTaskLength(),
36
40
  hightLevelLength: this.hightLevelTaskList.length
37
41
  });
38
42
  }
@@ -46,30 +50,51 @@ var IdleTask = class extends EventEmitter {
46
50
  return super.emit(eventName, ...args);
47
51
  }
48
52
  runTaskQueue(deadline) {
49
- const { hightLevelTaskList, taskList } = this;
50
- while (deadline.timeRemaining() > 0 && (taskList.length || hightLevelTaskList.length)) {
51
- const timeRemaining = deadline.timeRemaining();
52
- let times = 0;
53
- if (timeRemaining <= 5) times = 10;
54
- else if (timeRemaining <= 10) times = 100;
55
- else if (timeRemaining <= 15) times = 300;
56
- else times = 600;
57
- for (let i = 0; i < times; i++) {
58
- const task = hightLevelTaskList.length > 0 ? hightLevelTaskList.shift() : taskList.shift();
59
- if (task) task.handler(task.data);
60
- if (hightLevelTaskList.length === 0 && taskList.length === 0) break;
53
+ this.taskHandle = null;
54
+ try {
55
+ while (deadline.timeRemaining() > 0 && this.getTaskLength()) {
56
+ const timeRemaining = deadline.timeRemaining();
57
+ let times = 0;
58
+ if (timeRemaining <= 5) times = 10;
59
+ else if (timeRemaining <= 10) times = 100;
60
+ else if (timeRemaining <= 15) times = 300;
61
+ else times = 600;
62
+ for (let i = 0; i < times; i++) {
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
+ }
61
67
  }
68
+ } finally {
69
+ this.finishRun();
62
70
  }
63
- if (!hightLevelTaskList.length) this.emit("hight-level-finish");
64
- if (hightLevelTaskList.length || taskList.length) this.taskHandle = globalThis.requestIdleCallback(this.runTaskQueue.bind(this), { timeout: 300 });
65
- else {
66
- this.taskHandle = 0;
67
- this.emit("finish");
71
+ }
72
+ /**
73
+ * 单个任务失败不能中断整个队列,否则后续任务永远不会被执行,
74
+ * 依赖收集会停在半路(收集中状态与剩余任务数都不再变化)
75
+ */
76
+ runTask(task) {
77
+ try {
78
+ task.handler(task.data);
79
+ } catch (e) {
80
+ error("magic editor: 空闲任务执行失败", e);
68
81
  }
69
- this.emit("update-task-length", {
70
- length: taskList.length + hightLevelTaskList.length,
71
- hightLevelLength: hightLevelTaskList.length
72
- });
82
+ }
83
+ finishRun() {
84
+ try {
85
+ if (!this.hightLevelTaskList.length) this.emit("hight-level-finish");
86
+ } finally {
87
+ if (this.getTaskLength()) {
88
+ if (!this.taskHandle) this.taskHandle = globalThis.requestIdleCallback(this.runTaskQueue.bind(this), { timeout: 300 });
89
+ } else this.emit("finish");
90
+ this.emit("update-task-length", {
91
+ length: this.getTaskLength(),
92
+ hightLevelLength: this.hightLevelTaskList.length
93
+ });
94
+ }
95
+ }
96
+ getTaskLength() {
97
+ return this.taskList.length + this.hightLevelTaskList.length;
73
98
  }
74
99
  };
75
100
  //#endregion