@tmagic/editor 1.7.14-beta.1 → 1.7.14-beta.3
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/components/ToolButton.vue_vue_type_script_setup_true_lang.js +6 -2
- package/dist/es/layouts/CodeEditor.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/es/layouts/NavMenu.vue_vue_type_script_setup_true_lang.js +11 -11
- package/dist/es/layouts/NavMenuColumn.js +5 -0
- package/dist/es/layouts/NavMenuColumn.vue_vue_type_script_setup_true_lang.js +201 -0
- package/dist/es/services/editor.js +88 -31
- package/dist/es/services/storage.js +5 -5
- package/dist/es/style.css +51 -0
- package/dist/es/utils/keybinding-config.js +19 -19
- package/dist/style.css +51 -0
- package/dist/tmagic-editor.umd.cjs +353 -93
- package/package.json +8 -8
- package/src/components/ToolButton.vue +7 -1
- package/src/layouts/CodeEditor.vue +18 -10
- package/src/layouts/NavMenu.vue +9 -4
- package/src/layouts/NavMenuColumn.vue +252 -0
- package/src/services/editor.ts +132 -40
- package/src/theme/nav-menu.scss +61 -0
- package/src/type.ts +42 -0
- package/src/utils/undo-redo.ts +2 -0
- package/types/index.d.ts +456 -437
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useServices } from "../hooks/use-services.js";
|
|
2
2
|
import Icon_default from "./Icon.js";
|
|
3
3
|
import { TMagicButton, TMagicDivider, TMagicDropdown, TMagicDropdownItem, TMagicDropdownMenu, TMagicIcon, TMagicTooltip } from "@tmagic/design";
|
|
4
|
-
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, mergeProps, normalizeClass, openBlock, renderList, resolveDynamicComponent, toDisplayString, toHandlers, unref, withCtx } from "vue";
|
|
4
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createSlots, createTextVNode, createVNode, defineComponent, mergeProps, normalizeClass, openBlock, renderList, resolveDynamicComponent, toDisplayString, toHandlers, unref, useTemplateRef, withCtx } from "vue";
|
|
5
5
|
import { ArrowDown } from "@element-plus/icons-vue";
|
|
6
6
|
//#region packages/editor/src/components/ToolButton.vue?vue&type=script&setup=true&lang.ts
|
|
7
7
|
var _hoisted_1 = {
|
|
@@ -19,9 +19,11 @@ var ToolButton_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ def
|
|
|
19
19
|
}) },
|
|
20
20
|
eventType: { default: "click" }
|
|
21
21
|
},
|
|
22
|
-
setup(__props) {
|
|
22
|
+
setup(__props, { expose: __expose }) {
|
|
23
23
|
const props = __props;
|
|
24
24
|
const services = useServices();
|
|
25
|
+
const rootElRef = useTemplateRef("rootEl");
|
|
26
|
+
const getElRef = () => rootElRef;
|
|
25
27
|
const disabled = computed(() => {
|
|
26
28
|
if (typeof props.data === "string") return false;
|
|
27
29
|
if (props.data.type === "component") return false;
|
|
@@ -53,9 +55,11 @@ var ToolButton_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ def
|
|
|
53
55
|
if (props.eventType !== "mouseup") return;
|
|
54
56
|
if (item.type === "button" && event.button === 0) buttonHandler(item, event);
|
|
55
57
|
};
|
|
58
|
+
__expose({ getElRef });
|
|
56
59
|
return (_ctx, _cache) => {
|
|
57
60
|
return display.value ? (openBlock(), createElementBlock("div", {
|
|
58
61
|
key: 0,
|
|
62
|
+
ref: "rootEl",
|
|
59
63
|
class: normalizeClass(["menu-item", `${__props.data.type} ${__props.data.className || ""}`]),
|
|
60
64
|
onClick: _cache[0] || (_cache[0] = ($event) => clickHandler(__props.data, $event)),
|
|
61
65
|
onMousedown: _cache[1] || (_cache[1] = ($event) => mousedownHandler(__props.data, $event)),
|
|
@@ -124,23 +124,23 @@ var CodeEditor_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ def
|
|
|
124
124
|
if (props.type === "diff") {
|
|
125
125
|
const originalModel = monaco.editor.createModel(values.value, "text/javascript");
|
|
126
126
|
const modifiedModel = monaco.editor.createModel(toString(m, props.language), "text/javascript");
|
|
127
|
-
const
|
|
127
|
+
const viewState = vsDiffEditor?.saveViewState();
|
|
128
128
|
const result = vsDiffEditor?.setModel({
|
|
129
129
|
original: originalModel,
|
|
130
130
|
modified: modifiedModel
|
|
131
131
|
});
|
|
132
|
-
if (
|
|
133
|
-
vsDiffEditor?.
|
|
132
|
+
if (viewState) nextTick(() => {
|
|
133
|
+
vsDiffEditor?.restoreViewState(viewState);
|
|
134
134
|
vsDiffEditor?.focus();
|
|
135
|
-
}
|
|
135
|
+
});
|
|
136
136
|
return result;
|
|
137
137
|
}
|
|
138
|
-
const
|
|
138
|
+
const viewState = vsEditor?.saveViewState();
|
|
139
139
|
const result = vsEditor?.setValue(values.value);
|
|
140
|
-
if (
|
|
141
|
-
vsEditor?.
|
|
140
|
+
if (viewState) nextTick(() => {
|
|
141
|
+
vsEditor?.restoreViewState(viewState);
|
|
142
142
|
vsEditor?.focus();
|
|
143
|
-
}
|
|
143
|
+
});
|
|
144
144
|
return result;
|
|
145
145
|
};
|
|
146
146
|
const getEditorValue = () => (props.type === "diff" ? vsDiffEditor?.getModifiedEditor().getValue() : vsEditor?.getValue()) || "";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ColumnLayout } from "../type.js";
|
|
2
2
|
import { useServices } from "../hooks/use-services.js";
|
|
3
|
-
import
|
|
3
|
+
import NavMenuColumn_default from "./NavMenuColumn.js";
|
|
4
4
|
import { NodeType } from "@tmagic/core";
|
|
5
|
-
import { Fragment, computed, createBlock, createElementBlock, defineComponent, markRaw,
|
|
5
|
+
import { Fragment, computed, createBlock, createElementBlock, defineComponent, markRaw, normalizeStyle, onBeforeUnmount, onMounted, openBlock, renderList, unref, useTemplateRef } from "vue";
|
|
6
6
|
import { Back, Delete, FullScreen, Grid, Memo, Right, ScaleToOriginal, ZoomIn, ZoomOut } from "@element-plus/icons-vue";
|
|
7
7
|
//#region packages/editor/src/layouts/NavMenu.vue?vue&type=script&setup=true&lang.ts
|
|
8
8
|
var NavMenu_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
@@ -165,16 +165,16 @@ var NavMenu_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ define
|
|
|
165
165
|
style: normalizeStyle({ height: `${__props.height}px` }),
|
|
166
166
|
ref: "navMenu"
|
|
167
167
|
}, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(keys), (key) => {
|
|
168
|
-
return openBlock(),
|
|
169
|
-
class: normalizeClass(`menu-${key}`),
|
|
168
|
+
return openBlock(), createBlock(NavMenuColumn_default, {
|
|
170
169
|
key,
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
170
|
+
"column-key": key,
|
|
171
|
+
items: buttons.value[key],
|
|
172
|
+
width: columnWidth.value?.[key]
|
|
173
|
+
}, null, 8, [
|
|
174
|
+
"column-key",
|
|
175
|
+
"items",
|
|
176
|
+
"width"
|
|
177
|
+
]);
|
|
178
178
|
}), 128))], 4);
|
|
179
179
|
};
|
|
180
180
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import NavMenuColumn_vue_vue_type_script_setup_true_lang_default from "./NavMenuColumn.vue_vue_type_script_setup_true_lang.js";
|
|
2
|
+
//#region packages/editor/src/layouts/NavMenuColumn.vue
|
|
3
|
+
var NavMenuColumn_default = NavMenuColumn_vue_vue_type_script_setup_true_lang_default;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { NavMenuColumn_default as default };
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import ToolButton_default from "../components/ToolButton.js";
|
|
2
|
+
import { TMagicButton, TMagicPopover } from "@tmagic/design";
|
|
3
|
+
import { Fragment, computed, createBlock, createElementBlock, createElementVNode, createVNode, defineComponent, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, unref, useTemplateRef, watch, withCtx } from "vue";
|
|
4
|
+
import { ArrowDown, ArrowUp } from "@element-plus/icons-vue";
|
|
5
|
+
//#region packages/editor/src/layouts/NavMenuColumn.vue?vue&type=script&setup=true&lang.ts
|
|
6
|
+
var _hoisted_1 = { class: "m-editor-nav-menu-overflow-list" };
|
|
7
|
+
var NavMenuColumn_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
|
|
8
|
+
name: "MEditorNavMenuColumn",
|
|
9
|
+
__name: "NavMenuColumn",
|
|
10
|
+
props: {
|
|
11
|
+
columnKey: {},
|
|
12
|
+
items: { default: () => [] },
|
|
13
|
+
width: {},
|
|
14
|
+
gap: { default: 3 },
|
|
15
|
+
popoverWidth: { default: 180 }
|
|
16
|
+
},
|
|
17
|
+
setup(__props) {
|
|
18
|
+
const props = __props;
|
|
19
|
+
const columnEl = useTemplateRef("columnEl");
|
|
20
|
+
const moreWrapperEl = useTemplateRef("moreWrapperEl");
|
|
21
|
+
const popoverVisible = ref(false);
|
|
22
|
+
const togglePopover = () => {
|
|
23
|
+
popoverVisible.value = !popoverVisible.value;
|
|
24
|
+
};
|
|
25
|
+
const itemInstances = ref([]);
|
|
26
|
+
let slotsRO;
|
|
27
|
+
const observedEls = /* @__PURE__ */ new Set();
|
|
28
|
+
const setItemRef = (inst, index) => {
|
|
29
|
+
itemInstances.value[index] = inst ?? null;
|
|
30
|
+
};
|
|
31
|
+
const itemEls = computed(() => itemInstances.value.map((inst) => inst?.getElRef?.().value ?? null));
|
|
32
|
+
const reobserveSlots = () => {
|
|
33
|
+
if (!slotsRO) return;
|
|
34
|
+
for (const el of observedEls) slotsRO.unobserve(el);
|
|
35
|
+
observedEls.clear();
|
|
36
|
+
for (const el of itemEls.value) if (el) {
|
|
37
|
+
slotsRO.observe(el);
|
|
38
|
+
observedEls.add(el);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const cachedWidths = ref(/* @__PURE__ */ new Map());
|
|
42
|
+
const moreWidth = ref(0);
|
|
43
|
+
const containerWidth = ref(0);
|
|
44
|
+
const hiddenIndexSet = ref(/* @__PURE__ */ new Set());
|
|
45
|
+
const hasOverflow = computed(() => hiddenIndexSet.value.size > 0);
|
|
46
|
+
const overflowItems = computed(() => props.items.filter((_, index) => hiddenIndexSet.value.has(index)));
|
|
47
|
+
const measureAndCompute = () => {
|
|
48
|
+
if (!columnEl.value) return;
|
|
49
|
+
containerWidth.value = columnEl.value.clientWidth;
|
|
50
|
+
const els = itemEls.value;
|
|
51
|
+
for (let i = 0; i < props.items.length; i++) {
|
|
52
|
+
const el = els[i];
|
|
53
|
+
if (!el) {
|
|
54
|
+
cachedWidths.value.delete(i);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const w = el.getBoundingClientRect().width;
|
|
58
|
+
if (w > 0) cachedWidths.value.set(i, w);
|
|
59
|
+
else cachedWidths.value.delete(i);
|
|
60
|
+
}
|
|
61
|
+
if (moreWrapperEl.value) {
|
|
62
|
+
const w = moreWrapperEl.value.getBoundingClientRect().width;
|
|
63
|
+
if (w > 0) moreWidth.value = w;
|
|
64
|
+
}
|
|
65
|
+
const total = props.items.length;
|
|
66
|
+
if (total === 0 || containerWidth.value <= 0) {
|
|
67
|
+
if (hiddenIndexSet.value.size > 0) hiddenIndexSet.value = /* @__PURE__ */ new Set();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
let fullSum = 0;
|
|
71
|
+
let positive = 0;
|
|
72
|
+
for (let i = 0; i < total; i++) {
|
|
73
|
+
const w = cachedWidths.value.get(i) ?? 0;
|
|
74
|
+
if (w > 0) {
|
|
75
|
+
fullSum += w;
|
|
76
|
+
positive += 1;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
fullSum += props.gap * Math.max(0, positive - 1);
|
|
80
|
+
const effectiveMoreWidth = moreWidth.value > 0 ? moreWidth.value : 32;
|
|
81
|
+
const reservedMore = effectiveMoreWidth + (positive > 0 ? props.gap : 0);
|
|
82
|
+
let nextHidden = null;
|
|
83
|
+
if (fullSum + reservedMore <= containerWidth.value + .5) {
|
|
84
|
+
if (hiddenIndexSet.value.size > 0) nextHidden = /* @__PURE__ */ new Set();
|
|
85
|
+
} else {
|
|
86
|
+
const newHidden = /* @__PURE__ */ new Set();
|
|
87
|
+
let used = effectiveMoreWidth;
|
|
88
|
+
let cutoff = -1;
|
|
89
|
+
for (let i = 0; i < total; i++) {
|
|
90
|
+
const w = cachedWidths.value.get(i) ?? 0;
|
|
91
|
+
if (w === 0) continue;
|
|
92
|
+
const need = props.gap + w;
|
|
93
|
+
if (used + need > containerWidth.value) {
|
|
94
|
+
cutoff = i;
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
used += need;
|
|
98
|
+
}
|
|
99
|
+
if (cutoff >= 0) for (let j = cutoff; j < total; j++) newHidden.add(j);
|
|
100
|
+
nextHidden = newHidden;
|
|
101
|
+
}
|
|
102
|
+
if (nextHidden) {
|
|
103
|
+
if (!(nextHidden.size === hiddenIndexSet.value.size && [...nextHidden].every((v) => hiddenIndexSet.value.has(v)))) hiddenIndexSet.value = nextHidden;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
let raf = 0;
|
|
107
|
+
const scheduleMeasure = () => {
|
|
108
|
+
if (raf) cancelAnimationFrame(raf);
|
|
109
|
+
raf = requestAnimationFrame(() => {
|
|
110
|
+
raf = 0;
|
|
111
|
+
measureAndCompute();
|
|
112
|
+
if (hasOverflow.value && moreWidth.value === 0) raf = requestAnimationFrame(() => {
|
|
113
|
+
raf = 0;
|
|
114
|
+
measureAndCompute();
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
watch(hasOverflow, (value) => {
|
|
119
|
+
if (!value) popoverVisible.value = false;
|
|
120
|
+
});
|
|
121
|
+
watch(() => props.items, () => {
|
|
122
|
+
cachedWidths.value = /* @__PURE__ */ new Map();
|
|
123
|
+
hiddenIndexSet.value = /* @__PURE__ */ new Set();
|
|
124
|
+
}, { deep: true });
|
|
125
|
+
watch(itemEls, () => {
|
|
126
|
+
cachedWidths.value = /* @__PURE__ */ new Map();
|
|
127
|
+
reobserveSlots();
|
|
128
|
+
scheduleMeasure();
|
|
129
|
+
});
|
|
130
|
+
watch(() => props.width, () => scheduleMeasure());
|
|
131
|
+
let ro;
|
|
132
|
+
onMounted(() => {
|
|
133
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
134
|
+
if (columnEl.value) {
|
|
135
|
+
ro = new ResizeObserver(() => scheduleMeasure());
|
|
136
|
+
ro.observe(columnEl.value);
|
|
137
|
+
}
|
|
138
|
+
slotsRO = new ResizeObserver(() => scheduleMeasure());
|
|
139
|
+
reobserveSlots();
|
|
140
|
+
}
|
|
141
|
+
scheduleMeasure();
|
|
142
|
+
});
|
|
143
|
+
onBeforeUnmount(() => {
|
|
144
|
+
if (raf) cancelAnimationFrame(raf);
|
|
145
|
+
ro?.disconnect();
|
|
146
|
+
slotsRO?.disconnect();
|
|
147
|
+
slotsRO = void 0;
|
|
148
|
+
observedEls.clear();
|
|
149
|
+
});
|
|
150
|
+
return (_ctx, _cache) => {
|
|
151
|
+
return openBlock(), createElementBlock("div", {
|
|
152
|
+
class: normalizeClass(`menu-${__props.columnKey} m-editor-nav-menu-column`),
|
|
153
|
+
style: normalizeStyle(__props.width != null ? `width: ${__props.width}px` : ""),
|
|
154
|
+
ref_key: "columnEl",
|
|
155
|
+
ref: columnEl
|
|
156
|
+
}, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.items, (item, index) => {
|
|
157
|
+
return openBlock(), createBlock(ToolButton_default, {
|
|
158
|
+
data: item,
|
|
159
|
+
key: `item-${index}`,
|
|
160
|
+
class: normalizeClass({ "m-editor-nav-menu-slot-hidden": hiddenIndexSet.value.has(index) }),
|
|
161
|
+
ref_for: true,
|
|
162
|
+
ref: (comp) => setItemRef(comp, index)
|
|
163
|
+
}, null, 8, ["data", "class"]);
|
|
164
|
+
}), 128)), createElementVNode("div", {
|
|
165
|
+
class: normalizeClass(["m-editor-nav-menu-more-wrapper", { "m-editor-nav-menu-more-wrapper-hidden": !hasOverflow.value }]),
|
|
166
|
+
ref_key: "moreWrapperEl",
|
|
167
|
+
ref: moreWrapperEl
|
|
168
|
+
}, [createVNode(unref(TMagicPopover), {
|
|
169
|
+
placement: "bottom-end",
|
|
170
|
+
"popper-class": "m-editor-nav-menu-popover",
|
|
171
|
+
width: __props.popoverWidth,
|
|
172
|
+
visible: popoverVisible.value
|
|
173
|
+
}, {
|
|
174
|
+
reference: withCtx(() => [createElementVNode("div", {
|
|
175
|
+
class: "menu-item button m-editor-nav-menu-more",
|
|
176
|
+
ref: "referenceEl",
|
|
177
|
+
onClick: togglePopover
|
|
178
|
+
}, [createVNode(unref(TMagicButton), {
|
|
179
|
+
size: "small",
|
|
180
|
+
text: "",
|
|
181
|
+
icon: popoverVisible.value ? unref(ArrowUp) : unref(ArrowDown),
|
|
182
|
+
bg: popoverVisible.value,
|
|
183
|
+
type: popoverVisible.value ? "primary" : ""
|
|
184
|
+
}, null, 8, [
|
|
185
|
+
"icon",
|
|
186
|
+
"bg",
|
|
187
|
+
"type"
|
|
188
|
+
])], 512)]),
|
|
189
|
+
default: withCtx(() => [createElementVNode("div", _hoisted_1, [(openBlock(true), createElementBlock(Fragment, null, renderList(overflowItems.value, (item, index) => {
|
|
190
|
+
return openBlock(), createBlock(ToolButton_default, {
|
|
191
|
+
data: item,
|
|
192
|
+
key: `o-${index}`
|
|
193
|
+
}, null, 8, ["data"]);
|
|
194
|
+
}), 128))])]),
|
|
195
|
+
_: 1
|
|
196
|
+
}, 8, ["width", "visible"])], 2)], 6);
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
//#endregion
|
|
201
|
+
export { NavMenuColumn_vue_vue_type_script_setup_true_lang_default as default };
|
|
@@ -12,6 +12,23 @@ import { NodeType } from "@tmagic/core";
|
|
|
12
12
|
import { reactive, toRaw } from "vue";
|
|
13
13
|
import { cloneDeep, isObject, mergeWith, uniq } from "lodash-es";
|
|
14
14
|
//#region packages/editor/src/services/editor.ts
|
|
15
|
+
/**
|
|
16
|
+
* 经过 BaseService 的插件 / 中间件包装后,源方法的最后一个形参可能被注入为 dispatch 函数
|
|
17
|
+
* 当 options 形参位置被注入为函数(或为 null)时,将其归一为空对象,避免后续逻辑误读
|
|
18
|
+
*/
|
|
19
|
+
var safeOptions = (options) => {
|
|
20
|
+
const empty = {};
|
|
21
|
+
if (!options || typeof options === "function") return empty;
|
|
22
|
+
return options;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* 经过 BaseService 的插件 / 中间件包装后,源方法的形参可能被注入为 dispatch 函数
|
|
26
|
+
* 当 parent 形参位置被注入为函数(或为空值)时,归一为 null,由调用方继续走默认 parent 逻辑
|
|
27
|
+
*/
|
|
28
|
+
var safeParent = (parent) => {
|
|
29
|
+
if (!parent || typeof parent === "function") return null;
|
|
30
|
+
return parent;
|
|
31
|
+
};
|
|
15
32
|
var Editor = class extends BaseService_default {
|
|
16
33
|
state = reactive({
|
|
17
34
|
root: null,
|
|
@@ -222,9 +239,13 @@ var Editor = class extends BaseService_default {
|
|
|
222
239
|
* 向指点容器添加组件节点
|
|
223
240
|
* @param addConfig 将要添加的组件节点配置
|
|
224
241
|
* @param parent 要添加到的容器组件节点配置,如果不设置,默认为当前选中的组件的父节点
|
|
242
|
+
* @param options 可选配置
|
|
243
|
+
* @param options.doNotSelect 添加后是否不更新当前选中节点(默认 false,添加后会选中新增的节点)
|
|
225
244
|
* @returns 添加后的节点
|
|
226
245
|
*/
|
|
227
|
-
async add(addNode, parent) {
|
|
246
|
+
async add(addNode, parent, options) {
|
|
247
|
+
const safeParentNode = safeParent(parent);
|
|
248
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
228
249
|
this.captureSelectionBeforeOp();
|
|
229
250
|
const stage = this.get("stage");
|
|
230
251
|
const addNodes = [];
|
|
@@ -236,19 +257,21 @@ var Editor = class extends BaseService_default {
|
|
|
236
257
|
const newNodes = await Promise.all(addNodes.map((node) => {
|
|
237
258
|
const root = this.get("root");
|
|
238
259
|
if ((isPage(node) || isPageFragment(node)) && root) return this.doAdd(node, root);
|
|
239
|
-
const parentNode =
|
|
260
|
+
const parentNode = safeParentNode ?? getAddParent(node);
|
|
240
261
|
if (!parentNode) throw new Error("未找到父元素");
|
|
241
262
|
return this.doAdd(node, parentNode);
|
|
242
263
|
}));
|
|
243
264
|
if (newNodes.length > 1) {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
265
|
+
if (!doNotSelect) {
|
|
266
|
+
const newNodeIds = newNodes.map((node) => node.id);
|
|
267
|
+
stage?.multiSelect(newNodeIds);
|
|
268
|
+
await this.multiSelect(newNodeIds);
|
|
269
|
+
}
|
|
247
270
|
} else {
|
|
248
|
-
await this.select(newNodes[0]);
|
|
271
|
+
if (!doNotSelect) await this.select(newNodes[0]);
|
|
249
272
|
if (isPage(newNodes[0])) this.state.pageLength += 1;
|
|
250
273
|
else if (isPageFragment(newNodes[0])) this.state.pageFragmentLength += 1;
|
|
251
|
-
else stage?.select(newNodes[0].id);
|
|
274
|
+
else if (!doNotSelect) stage?.select(newNodes[0].id);
|
|
252
275
|
}
|
|
253
276
|
if (!(isPage(newNodes[0]) || isPageFragment(newNodes[0]))) {
|
|
254
277
|
const pageForOp = this.getNodeInfo(newNodes[0].id, false).page;
|
|
@@ -267,7 +290,8 @@ var Editor = class extends BaseService_default {
|
|
|
267
290
|
this.emit("add", newNodes);
|
|
268
291
|
return Array.isArray(addNode) ? newNodes : newNodes[0];
|
|
269
292
|
}
|
|
270
|
-
async doRemove(node) {
|
|
293
|
+
async doRemove(node, options) {
|
|
294
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
271
295
|
const root = this.get("root");
|
|
272
296
|
if (!root) throw new Error("root不能为空");
|
|
273
297
|
const { parent, node: curNode } = this.getNodeInfo(node.id, false);
|
|
@@ -281,6 +305,19 @@ var Editor = class extends BaseService_default {
|
|
|
281
305
|
parentId: parent.id,
|
|
282
306
|
root: cloneDeep(root)
|
|
283
307
|
});
|
|
308
|
+
if (doNotSelect) {
|
|
309
|
+
const selectedNodes = this.get("nodes");
|
|
310
|
+
const removedSelectedIndex = selectedNodes.findIndex((n) => `${n.id}` === `${node.id}`);
|
|
311
|
+
if (removedSelectedIndex !== -1) {
|
|
312
|
+
const nextSelected = [...selectedNodes];
|
|
313
|
+
nextSelected.splice(removedSelectedIndex, 1);
|
|
314
|
+
this.set("nodes", nextSelected);
|
|
315
|
+
}
|
|
316
|
+
if (isPage(node) || isPageFragment(node)) {
|
|
317
|
+
const currentPage = this.get("page");
|
|
318
|
+
if (currentPage && `${currentPage.id}` === `${node.id}`) this.set("page", null);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
284
321
|
const selectDefault = async (pages) => {
|
|
285
322
|
if (pages[0]) {
|
|
286
323
|
await this.select(pages[0]);
|
|
@@ -293,13 +330,15 @@ var Editor = class extends BaseService_default {
|
|
|
293
330
|
const rootItems = root.items || [];
|
|
294
331
|
if (isPage(node)) {
|
|
295
332
|
this.state.pageLength -= 1;
|
|
296
|
-
await selectDefault(rootItems);
|
|
333
|
+
if (!doNotSelect) await selectDefault(rootItems);
|
|
297
334
|
} else if (isPageFragment(node)) {
|
|
298
335
|
this.state.pageFragmentLength -= 1;
|
|
299
|
-
await selectDefault(rootItems);
|
|
336
|
+
if (!doNotSelect) await selectDefault(rootItems);
|
|
300
337
|
} else {
|
|
301
|
-
|
|
302
|
-
|
|
338
|
+
if (!doNotSelect) {
|
|
339
|
+
await this.select(parent);
|
|
340
|
+
stage?.select(parent.id);
|
|
341
|
+
}
|
|
303
342
|
this.addModifiedNodeId(parent.id);
|
|
304
343
|
}
|
|
305
344
|
if (!rootItems.length) {
|
|
@@ -309,9 +348,12 @@ var Editor = class extends BaseService_default {
|
|
|
309
348
|
}
|
|
310
349
|
/**
|
|
311
350
|
* 删除组件
|
|
312
|
-
* @param {Object} node
|
|
351
|
+
* @param {Object} node 要删除的节点或节点集合
|
|
352
|
+
* @param options 可选配置
|
|
353
|
+
* @param options.doNotSelect 删除后是否不更新当前选中节点(默认 false,删除后会选中父节点或首个页面)
|
|
313
354
|
*/
|
|
314
|
-
async remove(nodeOrNodeList) {
|
|
355
|
+
async remove(nodeOrNodeList, options) {
|
|
356
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
315
357
|
this.captureSelectionBeforeOp();
|
|
316
358
|
const nodes = Array.isArray(nodeOrNodeList) ? nodeOrNodeList : [nodeOrNodeList];
|
|
317
359
|
const removedItems = [];
|
|
@@ -331,11 +373,11 @@ var Editor = class extends BaseService_default {
|
|
|
331
373
|
});
|
|
332
374
|
}
|
|
333
375
|
}
|
|
334
|
-
await Promise.all(nodes.map((node) => this.doRemove(node)));
|
|
376
|
+
await Promise.all(nodes.map((node) => this.doRemove(node, { doNotSelect })));
|
|
335
377
|
if (removedItems.length > 0 && pageForOp) this.pushOpHistory("remove", { removedItems }, pageForOp);
|
|
336
378
|
this.emit("remove", nodes);
|
|
337
379
|
}
|
|
338
|
-
async doUpdate(config, { changeRecords = []
|
|
380
|
+
async doUpdate(config, { changeRecords = [] } = {}) {
|
|
339
381
|
const root = this.get("root");
|
|
340
382
|
if (!root) throw new Error("root为空");
|
|
341
383
|
if (!config?.id) throw new Error("没有配置或者配置缺少id值");
|
|
@@ -362,11 +404,11 @@ var Editor = class extends BaseService_default {
|
|
|
362
404
|
const layout = await this.getLayout(node);
|
|
363
405
|
if (Array.isArray(newConfig.items) && newLayout !== layout) newConfig = setChildrenLayout(newConfig, newLayout);
|
|
364
406
|
parentNodeItems[index] = newConfig;
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
this.set("nodes", [...
|
|
407
|
+
const selectedNodes = this.get("nodes");
|
|
408
|
+
const targetIndex = selectedNodes.findIndex((nodeItem) => `${nodeItem.id}` === `${newConfig.id}`);
|
|
409
|
+
if (targetIndex !== -1) {
|
|
410
|
+
selectedNodes.splice(targetIndex, 1, newConfig);
|
|
411
|
+
this.set("nodes", [...selectedNodes]);
|
|
370
412
|
}
|
|
371
413
|
if (isPage(newConfig) || isPageFragment(newConfig)) this.set("page", newConfig);
|
|
372
414
|
this.addModifiedNodeId(newConfig.id);
|
|
@@ -407,9 +449,12 @@ var Editor = class extends BaseService_default {
|
|
|
407
449
|
* 将id为id1的组件移动到id为id2的组件位置上,例如:[1,2,3,4] -> sort(1,3) -> [2,1,3,4]
|
|
408
450
|
* @param id1 组件ID
|
|
409
451
|
* @param id2 组件ID
|
|
452
|
+
* @param options 可选配置
|
|
453
|
+
* @param options.doNotSelect 排序后是否不更新当前选中节点(默认 false)
|
|
410
454
|
* @returns void
|
|
411
455
|
*/
|
|
412
|
-
async sort(id1, id2) {
|
|
456
|
+
async sort(id1, id2, options) {
|
|
457
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
413
458
|
this.captureSelectionBeforeOp();
|
|
414
459
|
const root = this.get("root");
|
|
415
460
|
if (!root) throw new Error("root为空");
|
|
@@ -422,7 +467,7 @@ var Editor = class extends BaseService_default {
|
|
|
422
467
|
const index1 = parent.items.findIndex((node) => `${node.id}` === `${id1}`);
|
|
423
468
|
parent.items.splice(index2, 0, ...parent.items.splice(index1, 1));
|
|
424
469
|
await this.update(parent);
|
|
425
|
-
await this.select(node);
|
|
470
|
+
if (!doNotSelect) await this.select(node);
|
|
426
471
|
this.get("stage")?.update({
|
|
427
472
|
config: cloneDeep(node),
|
|
428
473
|
parentId: parent.id,
|
|
@@ -450,9 +495,13 @@ var Editor = class extends BaseService_default {
|
|
|
450
495
|
/**
|
|
451
496
|
* 从localStorage中获取节点,然后添加到当前容器中
|
|
452
497
|
* @param position 粘贴的坐标
|
|
498
|
+
* @param collectorOptions 可选的依赖收集器配置
|
|
499
|
+
* @param options 可选配置
|
|
500
|
+
* @param options.doNotSelect 粘贴后是否不更新当前选中节点(默认 false)
|
|
453
501
|
* @returns 添加后的组件节点配置
|
|
454
502
|
*/
|
|
455
|
-
async paste(position = {}, collectorOptions) {
|
|
503
|
+
async paste(position = {}, collectorOptions, options) {
|
|
504
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
456
505
|
const config = storage_default.getItem(COPY_STORAGE_KEY);
|
|
457
506
|
if (!Array.isArray(config)) return;
|
|
458
507
|
const node = this.get("node");
|
|
@@ -463,7 +512,7 @@ var Editor = class extends BaseService_default {
|
|
|
463
512
|
}
|
|
464
513
|
const pasteConfigs = await this.doPaste(config, position);
|
|
465
514
|
if (collectorOptions && typeof collectorOptions.isTarget === "function") props_default.replaceRelateId(config, pasteConfigs, collectorOptions);
|
|
466
|
-
return this.add(pasteConfigs, parent);
|
|
515
|
+
return this.add(pasteConfigs, parent, { doNotSelect });
|
|
467
516
|
}
|
|
468
517
|
async doPaste(config, position = {}) {
|
|
469
518
|
props_default.clearRelateId();
|
|
@@ -484,14 +533,17 @@ var Editor = class extends BaseService_default {
|
|
|
484
533
|
/**
|
|
485
534
|
* 将指点节点设置居中
|
|
486
535
|
* @param config 组件节点配置
|
|
536
|
+
* @param options 可选配置
|
|
537
|
+
* @param options.doNotSelect 居中后是否不更新当前选中节点(默认 false)
|
|
487
538
|
* @returns 当前组件节点配置
|
|
488
539
|
*/
|
|
489
|
-
async alignCenter(config) {
|
|
540
|
+
async alignCenter(config, options) {
|
|
541
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
490
542
|
const nodes = Array.isArray(config) ? config : [config];
|
|
491
543
|
const stage = this.get("stage");
|
|
492
544
|
const newNodes = await Promise.all(nodes.map((node) => this.doAlignCenter(node)));
|
|
493
545
|
const newNode = await this.update(newNodes);
|
|
494
|
-
if (newNodes.length > 1) await stage?.multiSelect(newNodes.map((node) => node.id));
|
|
546
|
+
if (!doNotSelect) if (newNodes.length > 1) await stage?.multiSelect(newNodes.map((node) => node.id));
|
|
495
547
|
else await stage?.select(newNodes[0].id);
|
|
496
548
|
return newNode;
|
|
497
549
|
}
|
|
@@ -536,8 +588,11 @@ var Editor = class extends BaseService_default {
|
|
|
536
588
|
* 移动到指定容器中
|
|
537
589
|
* @param config 需要移动的节点
|
|
538
590
|
* @param targetId 容器ID
|
|
591
|
+
* @param options 可选配置
|
|
592
|
+
* @param options.doNotSelect 移动后是否不更新当前选中节点(默认 false)
|
|
539
593
|
*/
|
|
540
|
-
async moveToContainer(config, targetId) {
|
|
594
|
+
async moveToContainer(config, targetId, options) {
|
|
595
|
+
const { doNotSelect = false } = safeOptions(options);
|
|
541
596
|
this.captureSelectionBeforeOp();
|
|
542
597
|
const root = this.get("root");
|
|
543
598
|
const { node, parent, page: pageForOp } = this.getNodeInfo(config.id, false);
|
|
@@ -559,15 +614,17 @@ var Editor = class extends BaseService_default {
|
|
|
559
614
|
});
|
|
560
615
|
newConfig.style = getInitPositionStyle(newConfig.style, layout);
|
|
561
616
|
target.items.push(newConfig);
|
|
562
|
-
await stage.select(targetId);
|
|
617
|
+
if (!doNotSelect) await stage.select(targetId);
|
|
563
618
|
const targetParent = this.getParentById(target.id);
|
|
564
619
|
await stage.update({
|
|
565
620
|
config: cloneDeep(target),
|
|
566
621
|
parentId: targetParent?.id,
|
|
567
622
|
root: cloneDeep(root)
|
|
568
623
|
});
|
|
569
|
-
|
|
570
|
-
|
|
624
|
+
if (!doNotSelect) {
|
|
625
|
+
await this.select(newConfig);
|
|
626
|
+
stage.select(newConfig.id);
|
|
627
|
+
}
|
|
571
628
|
this.addModifiedNodeId(target.id);
|
|
572
629
|
this.addModifiedNodeId(parent.id);
|
|
573
630
|
this.pushOpHistory("update", { updatedItems: [{
|
|
@@ -64,10 +64,10 @@ var WebStorage = class extends BaseService_default {
|
|
|
64
64
|
const { protocol = options.protocol, item } = this.getValueAndProtocol(storage.getItem(`${options.namespace || namespace}:${key}`));
|
|
65
65
|
if (item === null) return null;
|
|
66
66
|
switch (protocol) {
|
|
67
|
-
case
|
|
68
|
-
case
|
|
69
|
-
case
|
|
70
|
-
case
|
|
67
|
+
case "object": return getEditorConfig("parseDSL")(`(${item})`);
|
|
68
|
+
case "json": return JSON.parse(item);
|
|
69
|
+
case "number": return Number(item);
|
|
70
|
+
case "boolean":
|
|
71
71
|
if (item === "true") return true;
|
|
72
72
|
if (item === "false") return false;
|
|
73
73
|
default: return item;
|
|
@@ -95,7 +95,7 @@ var WebStorage = class extends BaseService_default {
|
|
|
95
95
|
const namespace = this.getNamespace();
|
|
96
96
|
let item = value;
|
|
97
97
|
const protocol = options.protocol ? `${options.protocol}:` : "";
|
|
98
|
-
if (typeof value ===
|
|
98
|
+
if (typeof value === "string" || typeof value === "number") item = `${protocol}${value}`;
|
|
99
99
|
else item = `${protocol}${serialize(value)}`;
|
|
100
100
|
storage.setItem(`${options.namespace || namespace}:${key}`, item);
|
|
101
101
|
}
|