Skip to content

Commit 9fcb504

Browse files
Continuing refactor
1 parent 9c14cac commit 9fcb504

File tree

4 files changed

+112
-86
lines changed

4 files changed

+112
-86
lines changed

src/core/componentStructure.js

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { isTransition as isTransitionName } from "../util/tags";
22

3+
const getHtmlElementFromNode = ({ el }) => el;
4+
const getNodeFromHtmlElement = ({ __vnode: node }) => node;
5+
36
function isTransition(nodes) {
47
if (nodes.length !== 1) {
58
return false;
@@ -8,8 +11,20 @@ function isTransition(nodes) {
811
return !!type && (isTransitionName(type) || isTransitionName(type.name));
912
}
1013

14+
function getRootContainer({ $el, transitionMode }) {
15+
if (!transitionMode) {
16+
return $el;
17+
}
18+
const { children } = $el;
19+
if (children.length !== 1) {
20+
return $el;
21+
}
22+
const firstChild = children.item(0);
23+
return !getNodeFromHtmlElement(firstChild).transition ? firstChild : $el;
24+
}
25+
1126
class ComponentStructure {
12-
constructor({ nodes: { header, default: defaultNodes, footer }, root }) {
27+
constructor({ nodes: { header, default: defaultNodes, footer }, root, $el }) {
1328
this.nodes = { header, default: defaultNodes, footer };
1429
this.children = [...header, ...defaultNodes, ...footer];
1530
this.offsets = {
@@ -21,14 +36,70 @@ class ComponentStructure {
2136
this.tag = root.tag;
2237
this.noneFunctional =
2338
this.externalComponent && typeof this.tag !== "function";
39+
this.setHtmlRoot($el);
40+
this._checkCoherence();
2441
}
2542

26-
checkCoherence() {
43+
_checkCoherence() {
2744
if (this.noneFunctional && this.transitionMode) {
2845
throw new Error(
2946
`Transition-group inside component is not supported. Please alter tag value or remove transition-group. Current tag value: ${this.tag}`
3047
);
3148
}
49+
}
50+
51+
getChildrenNodes() {
52+
const {
53+
noneFunctional,
54+
transitionMode,
55+
nodes: { default: defaultNodes }
56+
} = this;
57+
58+
if (noneFunctional) {
59+
//TODO check problem here
60+
return defaultNodes[0].children;
61+
}
62+
63+
if (!transitionMode) {
64+
return defaultNodes.length === 1 && defaultNodes[0].el.nodeType === 3
65+
? defaultNodes[0].children
66+
: defaultNodes;
67+
}
68+
69+
const [{ children }] = defaultNodes;
70+
if (Array.isArray(children)) {
71+
return children;
72+
}
73+
return [...this.rootContainer.children]
74+
.map(getNodeFromHtmlElement)
75+
.filter(node => !!node.transition);
76+
}
77+
78+
computeIndexes() {
79+
const {
80+
transitionMode,
81+
offsets: { footer: footerOffset }
82+
} = this;
83+
84+
const domChildrenFromNodes = this.getChildrenNodes().map(
85+
getHtmlElementFromNode
86+
);
87+
const domChildren = this.rootContainer.children;
88+
const footerIndex = domChildren.length - footerOffset;
89+
const rawIndexes = [...domChildren].map((elt, idx) =>
90+
idx >= footerIndex
91+
? domChildrenFromNodes.length
92+
: domChildrenFromNodes.indexOf(elt)
93+
);
94+
return transitionMode ? rawIndexes.filter(ind => ind !== -1) : rawIndexes;
95+
}
96+
97+
setHtmlRoot($el) {
98+
if (!$el) {
99+
return;
100+
}
101+
this.$el = $el;
102+
this.rootContainer = getRootContainer(this);
32103
return this;
33104
}
34105
}

src/core/renderHelper.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ function computeNodes(slots) {
1111
const [header, defaultNodes, footer] = [
1212
"header",
1313
"default",
14-
"footer",
15-
].map((name) => getSlot(slots, name));
14+
"footer"
15+
].map(name => getSlot(slots, name));
1616
return {
1717
header,
1818
footer,
19-
default: defaultNodes,
19+
default: defaultNodes
2020
};
2121
}
2222

@@ -28,10 +28,10 @@ function getRootInformation(tag) {
2828
};
2929
}
3030

31-
function computeComponentStructure({ $slots, tag }) {
31+
function computeComponentStructure({ $slots, tag, $el }) {
3232
const nodes = computeNodes($slots);
3333
const root = getRootInformation(tag);
34-
return new ComponentStructure({ nodes, root });
34+
return new ComponentStructure({ nodes, root, $el });
3535
}
3636

3737
export { computeComponentStructure };

src/vuedraggable.js

Lines changed: 14 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,6 @@ function computeVmIndex(vNodes, htmlElement) {
2121
return index;
2222
}
2323

24-
function computeIndexes(
25-
vNodes,
26-
domChildren,
27-
{ transitionMode, offsets: { footer: footerOffset } }
28-
) {
29-
const domChildrenFromNodes = vNodes.map(({ el }) => el);
30-
const footerIndex = domChildren.length - footerOffset;
31-
const rawIndexes = [...domChildren].map((elt, idx) =>
32-
idx >= footerIndex
33-
? domChildrenFromNodes.length
34-
: domChildrenFromNodes.indexOf(elt)
35-
);
36-
return transitionMode ? rawIndexes.filter(ind => ind !== -1) : rawIndexes;
37-
}
38-
3924
function emit(evtName, evtData) {
4025
nextTick(() => this.$emit(evtName.toLowerCase(), evtData));
4126
}
@@ -98,14 +83,10 @@ const draggableComponent = defineComponent({
9883
props,
9984

10085
render() {
101-
const { $slots, $attrs, tag, componentData } = this;
102-
const componentStructure = computeComponentStructure({
103-
$slots,
104-
tag
105-
}).checkCoherence();
86+
const { $slots, $attrs, tag, componentData, $el } = this;
87+
const componentStructure = computeComponentStructure({ $slots, tag, $el });
10688
this.componentStructure = componentStructure;
10789
const attributes = getComponentAttributes({ $attrs, componentData });
108-
10990
return h(componentStructure.tag, attributes, componentStructure.children);
11091
},
11192

@@ -118,7 +99,8 @@ const draggableComponent = defineComponent({
11899
},
119100

120101
mounted() {
121-
const { $attrs, rootContainer } = this;
102+
const { $attrs, $el, componentStructure } = this;
103+
componentStructure.setHtmlRoot($el);
122104

123105
const sortableOptions = createSortableOption({
124106
$attrs,
@@ -128,7 +110,9 @@ const draggableComponent = defineComponent({
128110
manage: event => manage.call(this, event)
129111
}
130112
});
131-
113+
const {
114+
componentStructure: { rootContainer }
115+
} = this;
132116
this._sortable = new Sortable(rootContainer, sortableOptions);
133117
rootContainer.__draggable_component__ = this;
134118
this.computeIndexes();
@@ -139,22 +123,6 @@ const draggableComponent = defineComponent({
139123
},
140124

141125
computed: {
142-
rootContainer() {
143-
const {
144-
$el,
145-
componentStructure: { transitionMode }
146-
} = this;
147-
if (!transitionMode) {
148-
return $el;
149-
}
150-
const { children } = $el;
151-
if (children.length !== 1) {
152-
return $el;
153-
}
154-
const firstChild = children.item(0);
155-
return !!firstChild.__vnode.transition ? $el : firstChild;
156-
},
157-
158126
realList() {
159127
return this.list ? this.list : this.modelValue;
160128
}
@@ -174,58 +142,22 @@ const draggableComponent = defineComponent({
174142
},
175143

176144
methods: {
177-
getIsFunctional() {
178-
return typeof this.mainNode.type === "function";
179-
},
180-
181145
updateOptions(newOptionValue) {
182146
const { _sortable } = this;
183147
getValidSortableEntries(newOptionValue).forEach(([key, value]) => {
184148
_sortable.option(key, value);
185149
});
186150
},
187151

188-
getChildrenNodes() {
189-
const {
190-
componentStructure: {
191-
noneFunctional,
192-
transitionMode,
193-
nodes: { default: defaultNodes }
194-
}
195-
} = this;
196-
if (noneFunctional) {
197-
//TODO check
198-
return defaultNodes[0].children;
199-
//return this.$children[0].$slots.default();
200-
}
201-
202-
if (transitionMode) {
203-
const [{ children }] = defaultNodes;
204-
if (Array.isArray(children)) {
205-
return children;
206-
}
207-
return [...this.rootContainer.children]
208-
.map(c => c.__vnode)
209-
.filter(node => !!node.transition);
210-
}
211-
212-
return defaultNodes.length === 1 && defaultNodes[0].el.nodeType === 3
213-
? defaultNodes[0].children
214-
: defaultNodes;
215-
},
216-
217152
computeIndexes() {
218153
nextTick(() => {
219-
this.visibleIndexes = computeIndexes(
220-
this.getChildrenNodes(),
221-
this.rootContainer.children,
222-
this.componentStructure
223-
);
154+
this.visibleIndexes = this.componentStructure.computeIndexes();
224155
});
225156
},
226157

227158
getUnderlyingVm(htmlElement) {
228-
const index = computeVmIndex(this.getChildrenNodes(), htmlElement);
159+
const childrenNodes = this.componentStructure.getChildrenNodes();
160+
const index = computeVmIndex(childrenNodes, htmlElement);
229161
if (index === -1) {
230162
//Edge case during move callback: related element might be
231163
//an element different from collection
@@ -307,7 +239,10 @@ const draggableComponent = defineComponent({
307239
},
308240

309241
onDragRemove(evt) {
310-
insertNodeAt(this.rootContainer, evt.item, evt.oldIndex);
242+
const {
243+
componentStructure: { rootContainer }
244+
} = this;
245+
insertNodeAt(rootContainer, evt.item, evt.oldIndex);
311246
if (evt.pullMode === "clone") {
312247
removeNode(evt.clone);
313248
return;

tests/unit/vuedraggable.spec.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,26 @@ describe("draggable.vue when initialized with list", () => {
658658
expect(wrapper.emitted().end).toEqual([[endEvt]]);
659659
});
660660
});
661+
662+
describe("when re-rendering", () => {
663+
const updatedRender= "<div><header></header><div>a</div><div>b</div><div>c</div><div>d</div><footer></footer></div>";
664+
beforeEach(async () => {
665+
items.push("d");
666+
wrapper.setProps({
667+
list: [...items]
668+
});
669+
await nextTick();
670+
});
671+
672+
it("updates the rendered elements", () => {
673+
expect(wrapper.html()).toEqual(updatedRender);
674+
});
675+
676+
it("updates indexes", async () => {
677+
await nextTick();
678+
expect(vm.visibleIndexes).toEqual([-1, 0, 1, 2, 3, 4]);
679+
});
680+
});
661681
});
662682

663683
describe("when initiating a drag operation in clone context", () => {

0 commit comments

Comments
 (0)