Skip to content

Commit 283712d

Browse files
authored
Merge pull request #1120 from Patternslib/pat-sortable-clone
fix(pat-sortable): Initialize sorting on cloned elements.
2 parents 7197d37 + d7abbc0 commit 283712d

File tree

5 files changed

+242
-100
lines changed

5 files changed

+242
-100
lines changed

src/core/events.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,20 @@ const submit_event = () => {
192192
});
193193
};
194194

195+
const dragstart_event = () => {
196+
return new Event("dragstart", {
197+
bubbles: true,
198+
cancelable: true,
199+
});
200+
};
201+
202+
const dragend_event = () => {
203+
return new Event("dragend", {
204+
bubbles: true,
205+
cancelable: true,
206+
});
207+
};
208+
195209
export default {
196210
add_event_listener: add_event_listener,
197211
remove_event_listener: remove_event_listener,
@@ -206,4 +220,6 @@ export default {
206220
mouseup_event: mouseup_event,
207221
scroll_event: scroll_event,
208222
submit_event: submit_event,
223+
dragstart_event: dragstart_event,
224+
dragend_event: dragend_event,
209225
};

src/core/events.test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,24 @@ describe("core.events tests", () => {
254254
await utils.timeout(1);
255255
expect(catched).toBe("outer");
256256
});
257+
258+
it("dragstart event", async () => {
259+
outer.addEventListener("dragstart", () => {
260+
catched = "outer";
261+
});
262+
inner.dispatchEvent(events.dragstart_event());
263+
await utils.timeout(1);
264+
expect(catched).toBe("outer");
265+
});
266+
267+
it("dragend event", async () => {
268+
outer.addEventListener("dragend", () => {
269+
catched = "outer";
270+
});
271+
inner.dispatchEvent(events.dragend_event());
272+
await utils.timeout(1);
273+
expect(catched).toBe("outer");
274+
});
257275
});
258276

259277
describe("3 - jQuery vs native", () => {

src/pat/sortable/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
<script src="/bundle.min.js"></script>
88
</head>
99
<body>
10+
11+
<h2>Vertical sorting</h2>
1012
<ul class="pat-sortable">
1113
<li class="sortable-item">Item 3</li>
1214
<li class="sortable-item">Item 5</li>
@@ -16,6 +18,7 @@
1618
<li class="sortable-item">Item 2</li>
1719
</ul>
1820

21+
<h2>Horizontal sorting</h2>
1922
<ul class="pat-sortable vertical">
2023
<li class="sortable-item">Item 3</li>
2124
<li class="sortable-item">Item 5</li>
@@ -25,6 +28,15 @@
2528
<li class="sortable-item">Item 2</li>
2629
</ul>
2730

31+
<h2>Vertical sorting with pat-clone</h2>
32+
<button class="clone-trigger-1">Add item</button>
33+
<ul class="pat-sortable pat-clone"
34+
data-pat-clone="template: .clone-template-1; trigger-element: .clone-trigger-1">
35+
</ul>
36+
<template class="clone-template-1">
37+
<li class="sortable-item">Item #{1}</li>
38+
</template>
39+
2840

2941
<style>
3042
.sortable-item {

src/pat/sortable/sortable.js

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import $ from "jquery";
22
import Base from "../../core/base";
3+
import events from "../../core/events";
34
import Parser from "../../core/parser";
45

56
export const parser = new Parser("sortable");
@@ -28,12 +29,25 @@ export default Base.extend({
2829
/* Handler which gets called when pat-update is triggered within
2930
* the .pat-sortable element.
3031
*/
31-
if (data?.pattern == "clone") {
32-
this.recordPositions();
33-
data.$el.on("dragstart", this.onDragStart.bind(this));
34-
data.$el.on("dragend", this.onDragEnd.bind(this));
32+
if (data?.pattern !== "clone" || data?.action !== "added" || !data?.dom) {
33+
// Nothing to do.
34+
return;
3535
}
36-
return true;
36+
37+
this.recordPositions();
38+
39+
events.add_event_listener(
40+
data.dom,
41+
"dragstart",
42+
"pat-sortable--dragstart",
43+
this.onDragStart.bind(this)
44+
);
45+
events.add_event_listener(
46+
data.dom,
47+
"dragend",
48+
"pat-sortable--dragend",
49+
this.onDragEnd.bind(this)
50+
);
3751
},
3852

3953
recordPositions: function () {
@@ -49,22 +63,37 @@ export default Base.extend({
4963
},
5064

5165
addHandles: function () {
52-
var $sortables_without_handles = this.$sortables.filter(function () {
53-
return $(this).find(".sortable-handle").length === 0;
54-
});
55-
var $handles = $('<a href="#" class="sortable-handle">⇕</a>').appendTo(
56-
$sortables_without_handles
57-
);
58-
if ("draggable" in document.createElement("span")) {
59-
$handles.attr("draggable", true);
60-
} else {
61-
$handles.on("selectstart", function (ev) {
62-
ev.preventDefault();
66+
for (const sortable of [...this.$sortables].filter(
67+
(it) => !it.querySelector(".sortable-handle")
68+
)) {
69+
// TODO: we should change to a <button>.
70+
const handle = document.createElement("a");
71+
handle.textContent = "⇕";
72+
handle.classList.add("sortable-handle");
73+
handle.setAttribute("draggable", "true");
74+
handle.setAttribute("href", "#");
75+
handle.setAttribute("title", "Drag to reorder");
76+
handle.setAttribute("aria-label", "Drag to reorder");
77+
sortable.insertBefore(handle, sortable.firstChild);
78+
79+
// TODO: remove when element is a button.
80+
events.add_event_listener(handle, "click", "pat-sortable--click", (e) => {
81+
e.preventDefault();
6382
});
83+
84+
events.add_event_listener(
85+
handle,
86+
"dragstart",
87+
"pat-sortable--dragstart",
88+
this.onDragStart.bind(this)
89+
);
90+
events.add_event_listener(
91+
handle,
92+
"dragend",
93+
"pat-sortable--dragend",
94+
this.onDragEnd.bind(this)
95+
);
6496
}
65-
$handles.on("dragstart", this.onDragStart.bind(this));
66-
$handles.on("dragend", this.onDragEnd.bind(this));
67-
return this;
6897
},
6998

7099
initScrolling: function () {
@@ -140,12 +169,12 @@ export default Base.extend({
140169
},
141170

142171
onDragStart: function (ev) {
143-
var $handle = $(ev.target),
144-
$dragged = $handle.parent(),
145-
that = this;
146-
if (typeof ev.originalEvent !== "undefined") {
172+
var $handle = $(ev.target);
173+
var $dragged = $handle.parent();
174+
var that = this;
175+
if (ev.originalEvent?.dataTransfer) {
147176
// Firefox seems to need this set to any value
148-
ev.originalEvent.dataTransfer.setData("Text", "");
177+
ev.originalEvent.dataTransfer?.setData("Text", "");
149178
ev.originalEvent.dataTransfer.effectAllowed = ["move"];
150179
if ("setDragImage" in ev.originalEvent.dataTransfer) {
151180
ev.originalEvent.dataTransfer.setDragImage($dragged[0], 0, 0);

0 commit comments

Comments
 (0)