@fc3/mmcadi 0.1.50 → 0.1.52
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/.last-compile-time +1 -1
- package/dist/.last-publish-time +1 -1
- package/dist/client.js +343 -742
- package/dist/src/client/helper/interaction.d.ts +24 -41
- package/dist/src/client/helper/interaction.js +291 -645
- package/dist/src/client/helper/interaction.js.map +1 -1
- package/dist/src/client/page/cursor.d.ts +3 -1
- package/dist/src/client/page/cursor.js +46 -19
- package/dist/src/client/page/cursor.js.map +1 -1
- package/dist/src/server/serializer/base.js +23 -13
- package/dist/src/server/serializer/base.js.map +1 -1
- package/dist/src/server/serializer/block/audio.js +1 -1
- package/dist/src/server/serializer/block.js +31 -15
- package/dist/src/server/serializer/block.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -3,634 +3,361 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const time_1 = require("@fc3/time");
|
|
6
7
|
const errors_1 = require("@fc3/errors");
|
|
7
8
|
const action_type_1 = __importDefault(require("./../../enum/action-type.js"));
|
|
8
|
-
const emoji_1 = __importDefault(require("./../../enum/emoji.js"));
|
|
9
9
|
const get_index_path_for_element_1 = __importDefault(require("./../utility/get-index-path-for-element.js"));
|
|
10
10
|
class InteractionHelper {
|
|
11
11
|
constructor() {
|
|
12
|
-
this.
|
|
13
|
-
this.
|
|
14
|
-
this.drag_placeholder = null;
|
|
15
|
-
this.drag_ghost = null;
|
|
16
|
-
this.drag_start_y = null;
|
|
17
|
-
this.drag_pointer_offset_y = null;
|
|
18
|
-
this.drag_press_timer = null;
|
|
19
|
-
this.swipe_active = false;
|
|
20
|
-
this.swipe_block = null;
|
|
21
|
-
this.swipe_start_x = null;
|
|
22
|
-
this.swipe_start_y = null;
|
|
23
|
-
this.swipe_content = null;
|
|
24
|
-
this.swipe_menu_width = 0;
|
|
25
|
-
this.open_swipe_block = null;
|
|
26
|
-
this.open_swipe_content = null;
|
|
12
|
+
this.drag_start_coordinate = null;
|
|
13
|
+
this.drag_delay_timer = null;
|
|
27
14
|
}
|
|
28
15
|
attach() {
|
|
29
|
-
document.addEventListener('
|
|
30
|
-
this.
|
|
31
|
-
}, true);
|
|
32
|
-
document.addEventListener('
|
|
33
|
-
this.
|
|
16
|
+
document.addEventListener('pointerdown', (event) => {
|
|
17
|
+
this.handlePointerDown(event);
|
|
18
|
+
}, { capture: true });
|
|
19
|
+
document.addEventListener('pointermove', (event) => {
|
|
20
|
+
this.handlePointerMove(event);
|
|
34
21
|
}, { capture: true, passive: false });
|
|
35
|
-
document.addEventListener('
|
|
36
|
-
this.
|
|
37
|
-
}, true);
|
|
38
|
-
document.addEventListener('
|
|
39
|
-
this.
|
|
40
|
-
}, { capture: true
|
|
41
|
-
document.addEventListener('mouseup', (event) => {
|
|
42
|
-
this.onPressEnd(event);
|
|
43
|
-
}, true);
|
|
44
|
-
document.addEventListener('touchend', (event) => {
|
|
45
|
-
this.onPressEnd(event);
|
|
46
|
-
}, true);
|
|
47
|
-
// Close any open swipe when touching outside
|
|
48
|
-
document.addEventListener('touchstart', (event) => {
|
|
49
|
-
this.onGlobalTouchStart(event);
|
|
50
|
-
}, { capture: true, passive: true });
|
|
51
|
-
// Prevent native browser drag for anchors/images inside blocks so our
|
|
52
|
-
// custom drag logic receives mousemove events instead of dragover.
|
|
22
|
+
document.addEventListener('pointerup', (event) => {
|
|
23
|
+
this.handlePointerUp(event);
|
|
24
|
+
}, { capture: true });
|
|
25
|
+
document.addEventListener('pointercancel', (event) => {
|
|
26
|
+
this.handlePointerCancel(event);
|
|
27
|
+
}, { capture: true });
|
|
53
28
|
document.addEventListener('dragstart', (event) => {
|
|
54
|
-
this.
|
|
55
|
-
}, true);
|
|
29
|
+
this.handleNativeDragStart(event);
|
|
30
|
+
}, { capture: true });
|
|
56
31
|
}
|
|
57
32
|
isDragging() {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
getBlockElements() {
|
|
61
|
-
const elements = document.querySelectorAll('section.block');
|
|
62
|
-
return Array.from(elements);
|
|
63
|
-
}
|
|
64
|
-
getSiblingBlocks(container, exclude) {
|
|
65
|
-
const children = Array.from(container.children);
|
|
66
|
-
return children.filter((element) => {
|
|
67
|
-
if (element === exclude) {
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
return element.classList.contains('block');
|
|
71
|
-
});
|
|
33
|
+
const elements = Array.from(document.querySelectorAll('.dragging'));
|
|
34
|
+
return elements.length > 0;
|
|
72
35
|
}
|
|
73
|
-
|
|
74
|
-
const target = event
|
|
36
|
+
handlePointerDown(event) {
|
|
37
|
+
const { target } = event;
|
|
75
38
|
if (target === null) {
|
|
76
39
|
return;
|
|
77
40
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
41
|
+
const target_element = target;
|
|
42
|
+
let current_element = target_element;
|
|
43
|
+
while (current_element) {
|
|
44
|
+
const attribute = current_element.getAttribute('data-role');
|
|
45
|
+
if (attribute === 'block_activation') {
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
// Tricky. Bail out early if we detect an anchor element in the event
|
|
49
|
+
// ancestry that is NOT an all-block-encompassing link (eg, a folder block).
|
|
50
|
+
if (current_element instanceof HTMLAnchorElement) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
current_element = current_element.parentNode;
|
|
54
|
+
if (!(current_element instanceof HTMLElement)) {
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
82
57
|
}
|
|
83
|
-
const block =
|
|
58
|
+
const block = target_element.closest('section.block');
|
|
84
59
|
if (block === null) {
|
|
85
60
|
return;
|
|
86
61
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const anchor = target.closest('a[href]');
|
|
90
|
-
if (anchor) {
|
|
91
|
-
event.preventDefault();
|
|
92
|
-
}
|
|
62
|
+
if (target_element.closest('button, input, textarea, select, label, form')) {
|
|
63
|
+
return;
|
|
93
64
|
}
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
const point = this.getEventPoint(event);
|
|
97
|
-
if (point === null) {
|
|
65
|
+
const coordinate = this.getEventCoordinate(event);
|
|
66
|
+
if (coordinate === null) {
|
|
98
67
|
return;
|
|
99
68
|
}
|
|
100
|
-
this.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
69
|
+
this.drag_start_coordinate = coordinate;
|
|
70
|
+
block.classList.add('drag-candidate');
|
|
71
|
+
this.scheduleDelayedDrag();
|
|
72
|
+
}
|
|
73
|
+
scheduleDelayedDrag() {
|
|
74
|
+
this.cancelDelayedDrag();
|
|
75
|
+
const delay = time_1.TimeInterval.ONE_SECOND;
|
|
76
|
+
this.drag_delay_timer = setTimeout(this.beginDelayedDrag.bind(this), delay);
|
|
77
|
+
}
|
|
78
|
+
cancelDelayedDrag() {
|
|
79
|
+
if (this.drag_delay_timer !== null) {
|
|
80
|
+
clearTimeout(this.drag_delay_timer);
|
|
106
81
|
}
|
|
107
|
-
const threshold_ms = is_touch ? 350 : 200;
|
|
108
|
-
this.clearPressTimer();
|
|
109
|
-
this.drag_press_timer = window.setTimeout(() => {
|
|
110
|
-
this.beginDrag(point.clientY);
|
|
111
|
-
}, threshold_ms);
|
|
112
82
|
}
|
|
113
|
-
|
|
83
|
+
removeClassFromAllElements(class_name) {
|
|
84
|
+
const raw_elements = document.querySelectorAll(`.${class_name}`);
|
|
85
|
+
const elements = Array.from(raw_elements);
|
|
86
|
+
elements.forEach((element) => {
|
|
87
|
+
element.classList.remove(class_name);
|
|
88
|
+
});
|
|
89
|
+
return elements;
|
|
90
|
+
}
|
|
91
|
+
beginDelayedDrag() {
|
|
92
|
+
const raw_candidates = document.querySelectorAll('.drag-candidate');
|
|
93
|
+
const candidates = Array.from(raw_candidates);
|
|
94
|
+
candidates.forEach((candidate) => {
|
|
95
|
+
const ghost = candidate.cloneNode(true);
|
|
96
|
+
const index_path = (0, get_index_path_for_element_1.default)(candidate);
|
|
97
|
+
ghost.classList.add('ghost');
|
|
98
|
+
ghost.setAttribute('data-for', index_path);
|
|
99
|
+
candidate.classList.remove('drag-candidate');
|
|
100
|
+
const { parentNode } = candidate;
|
|
101
|
+
if (parentNode === null) {
|
|
102
|
+
throw new errors_1.InvariantViolation(`
|
|
103
|
+
Expected drag candidate to be located in a parent, but it was null
|
|
104
|
+
`);
|
|
105
|
+
}
|
|
106
|
+
const rect = candidate.getBoundingClientRect();
|
|
107
|
+
Object.assign(candidate.style, {
|
|
108
|
+
top: `${rect.top}px`,
|
|
109
|
+
left: `${rect.left}px`,
|
|
110
|
+
width: `${rect.width}px`,
|
|
111
|
+
height: `${rect.height}px`
|
|
112
|
+
});
|
|
113
|
+
candidate.setAttribute('data-drag-start-x', rect.left.toString());
|
|
114
|
+
candidate.setAttribute('data-drag-start-y', rect.top.toString());
|
|
115
|
+
candidate.classList.add('dragging');
|
|
116
|
+
parentNode.insertBefore(ghost, candidate);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
handleNativeDragStart(event) {
|
|
114
120
|
const target = event.target;
|
|
115
121
|
if (!target) {
|
|
116
122
|
return;
|
|
117
123
|
}
|
|
118
|
-
|
|
124
|
+
const closest_block = target.closest('section.block');
|
|
125
|
+
if (closest_block !== null) {
|
|
119
126
|
event.preventDefault();
|
|
120
127
|
}
|
|
121
128
|
}
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
129
|
+
handlePointerMove(event) {
|
|
130
|
+
const current_coordinate = this.getEventCoordinate(event);
|
|
131
|
+
const start_coordinate = this.getDragStartCoordinate();
|
|
132
|
+
if (start_coordinate === null || current_coordinate === null) {
|
|
125
133
|
return;
|
|
126
134
|
}
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
const start_x = this.swipe_start_x;
|
|
136
|
-
const start_y = this.swipe_start_y;
|
|
137
|
-
const delta_x = point.clientX - start_x;
|
|
138
|
-
const delta_y = point.clientY - start_y;
|
|
139
|
-
if (!this.swipe_active) {
|
|
140
|
-
const abs_x = Math.abs(delta_x);
|
|
141
|
-
const abs_y = Math.abs(delta_y);
|
|
142
|
-
// Initiate swipe if horizontal dominates and exceeds threshold
|
|
143
|
-
if (abs_x > 12 && abs_x > abs_y) {
|
|
144
|
-
// Cancel pending drag long-press
|
|
145
|
-
this.clearPressTimer();
|
|
146
|
-
// Close any previously open swipe on another block
|
|
147
|
-
this.closeOpenSwipeMenu(this.swipe_block);
|
|
148
|
-
this.swipe_active = true;
|
|
149
|
-
this.beginSwipe(this.swipe_block);
|
|
135
|
+
const { target } = event;
|
|
136
|
+
if (target !== null) {
|
|
137
|
+
const target_element = target;
|
|
138
|
+
const block = target_element.closest('section.block');
|
|
139
|
+
if (block) {
|
|
140
|
+
if (!block.classList.contains('dragging')) {
|
|
141
|
+
block.classList.add('drag-candidate');
|
|
150
142
|
}
|
|
151
143
|
}
|
|
152
|
-
if (this.swipe_active) {
|
|
153
|
-
event.preventDefault();
|
|
154
|
-
const content_element = this.swipe_content;
|
|
155
|
-
const menu_width = this.swipe_menu_width;
|
|
156
|
-
// Only allow left swipe (negative delta_x)
|
|
157
|
-
const translate_x = Math.max(-menu_width, Math.min(0, delta_x));
|
|
158
|
-
content_element.style.transition = '';
|
|
159
|
-
content_element.style.transform = `translateX(${translate_x}px)`;
|
|
160
|
-
// Don't fall through to drag while swiping:
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
if (!this.drag_active && this.drag_origin_block && this.drag_start_y !== null) {
|
|
165
|
-
const delta_y = Math.abs(point.clientY - this.drag_start_y);
|
|
166
|
-
if (delta_y > 8 && this.drag_press_timer !== null) {
|
|
167
|
-
this.beginDrag(point.clientY);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
if (!this.drag_active) {
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
event.preventDefault();
|
|
174
|
-
// FLIP: capture positions before DOM change (within current container)
|
|
175
|
-
const origin = this.drag_origin_block;
|
|
176
|
-
let container = null;
|
|
177
|
-
if (this.drag_placeholder !== null) {
|
|
178
|
-
container = this.drag_placeholder.parentElement;
|
|
179
|
-
}
|
|
180
|
-
if (container === null && origin !== null) {
|
|
181
|
-
container = origin.parentElement;
|
|
182
144
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
145
|
+
const { x: start_x, y: start_y } = start_coordinate;
|
|
146
|
+
const { x: current_x, y: current_y } = current_coordinate;
|
|
147
|
+
const distance = Math.hypot(current_x - start_x, current_y - start_y);
|
|
148
|
+
if (distance > 25) {
|
|
149
|
+
this.removeClassFromAllElements('drag-candidate');
|
|
150
|
+
}
|
|
151
|
+
this.scheduleDelayedDrag();
|
|
152
|
+
const raw_targets = document.querySelectorAll('.dragging');
|
|
153
|
+
const drag_target_blocks = Array.from(raw_targets);
|
|
154
|
+
drag_target_blocks.forEach((target_block) => {
|
|
155
|
+
this.translateDragTargetBlock(target_block, current_coordinate);
|
|
191
156
|
});
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
// Update ghost to follow pointer (glued to finger/mouse)
|
|
195
|
-
if (this.drag_ghost && this.drag_pointer_offset_y !== null) {
|
|
196
|
-
const top_position = point.clientY - this.drag_pointer_offset_y;
|
|
197
|
-
this.drag_ghost.style.top = `${top_position}px`;
|
|
157
|
+
if (drag_target_blocks.length > 0) {
|
|
158
|
+
event.preventDefault();
|
|
198
159
|
}
|
|
199
|
-
// Capture last positions and animate
|
|
200
|
-
const blocks_after = this.getSiblingBlocks(container, origin);
|
|
201
|
-
this.animateWithFlip(preceding_rects, blocks_after);
|
|
202
160
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
161
|
+
translateDragTargetBlock(block, current_coordinate) {
|
|
162
|
+
const x_attribute = block.getAttribute('data-drag-start-x');
|
|
163
|
+
const y_attribute = block.getAttribute('data-drag-start-y');
|
|
164
|
+
if (x_attribute === null || y_attribute === null) {
|
|
165
|
+
throw new errors_1.InvariantViolation(`
|
|
166
|
+
Drag coordinate attributes were invalid:
|
|
167
|
+
x: ${x_attribute}
|
|
168
|
+
y: ${y_attribute}
|
|
169
|
+
`);
|
|
170
|
+
}
|
|
171
|
+
const parsed_x = parseInt(x_attribute);
|
|
172
|
+
const parsed_y = parseInt(y_attribute);
|
|
173
|
+
if (isNaN(parsed_x) || isNaN(parsed_y)) {
|
|
174
|
+
throw new errors_1.InvariantViolation(`
|
|
175
|
+
Drag coordinate attributes were invalid:
|
|
176
|
+
x: ${x_attribute}
|
|
177
|
+
y: ${y_attribute}
|
|
178
|
+
`);
|
|
179
|
+
}
|
|
180
|
+
const start_coordinate = this.getDragStartCoordinate();
|
|
181
|
+
if (start_coordinate === null) {
|
|
182
|
+
throw new errors_1.InvariantViolation(`
|
|
183
|
+
Tried to translate drag target, but drag start coordinate was null
|
|
184
|
+
`);
|
|
185
|
+
}
|
|
186
|
+
const { x: start_x, y: start_y } = start_coordinate;
|
|
187
|
+
const { x: current_x, y: current_y } = current_coordinate;
|
|
188
|
+
const x_delta = current_x - start_x;
|
|
189
|
+
const y_delta = current_y - start_y;
|
|
190
|
+
const new_x = parsed_x + x_delta;
|
|
191
|
+
const new_y = parsed_y + y_delta;
|
|
192
|
+
block.style.left = `${new_x}px`;
|
|
193
|
+
block.style.top = `${new_y}px`;
|
|
194
|
+
const block_rect = block.getBoundingClientRect();
|
|
195
|
+
const previous_block = this.getPreviousBlock(block);
|
|
196
|
+
const next_block = this.getNextBlock(block);
|
|
197
|
+
const ghost = this.getGhostForBlock(block);
|
|
198
|
+
let swapped = false;
|
|
199
|
+
if (previous_block !== null) {
|
|
200
|
+
const previous_rect = previous_block.getBoundingClientRect();
|
|
201
|
+
const previous_block_y_threshold = previous_rect.top + (previous_rect.height * 0.4);
|
|
202
|
+
if (block_rect.top < previous_block_y_threshold) {
|
|
203
|
+
swapped = true;
|
|
204
|
+
const next_sibling = ghost.nextElementSibling;
|
|
205
|
+
previous_block.replaceWith(ghost);
|
|
206
|
+
if (next_sibling) {
|
|
207
|
+
next_sibling.before(previous_block);
|
|
218
208
|
}
|
|
219
209
|
}
|
|
220
|
-
const width = this.swipe_menu_width;
|
|
221
|
-
const open = Math.abs(current_x) > width / 2;
|
|
222
|
-
content.style.transition = 'transform 150ms ease';
|
|
223
|
-
content.style.transform = open ? `translateX(${-width}px)` : 'translateX(0)';
|
|
224
|
-
if (!open) {
|
|
225
|
-
this.teardownSwipe();
|
|
226
|
-
}
|
|
227
|
-
if (open) {
|
|
228
|
-
this.open_swipe_block = this.swipe_block;
|
|
229
|
-
this.open_swipe_content = content;
|
|
230
|
-
}
|
|
231
|
-
this.swipe_active = false;
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
if (!this.drag_active) {
|
|
235
|
-
this.resetDragState();
|
|
236
|
-
return;
|
|
237
210
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
const editing = new URL(window.location.href).searchParams.get('editing') === 'true';
|
|
249
|
-
this.postReposition(source_index_path, target_index_path, editing)
|
|
250
|
-
.then((new_index_path) => {
|
|
251
|
-
if (new_index_path) {
|
|
252
|
-
const url = new URL(window.location.href);
|
|
253
|
-
url.searchParams.set('index_path', new_index_path);
|
|
254
|
-
history.replaceState({}, '', url.toString());
|
|
255
|
-
}
|
|
256
|
-
const blocks = this.getBlockElements();
|
|
257
|
-
blocks.forEach((element) => {
|
|
258
|
-
element.classList.remove('selected');
|
|
259
|
-
});
|
|
260
|
-
origin.classList.add('selected');
|
|
261
|
-
// Rewrite data-index-path for all top-level blocks to reflect new order
|
|
262
|
-
this.updateTopLevelIndexPaths();
|
|
263
|
-
})
|
|
264
|
-
.finally(() => {
|
|
265
|
-
this.resetDragState();
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
beginSwipe(block) {
|
|
269
|
-
// Ensure wrapper and actions exist
|
|
270
|
-
const result = this.ensureSwipeUI(block);
|
|
271
|
-
const target = result.target;
|
|
272
|
-
const menu = result.menu;
|
|
273
|
-
const menu_width = result.menu_width;
|
|
274
|
-
this.swipe_content = target;
|
|
275
|
-
this.swipe_menu_width = menu_width;
|
|
276
|
-
if (menu) {
|
|
277
|
-
menu.style.display = 'flex';
|
|
278
|
-
menu.style.opacity = '1';
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
closeOpenSwipeMenu(except) {
|
|
282
|
-
if (!this.open_swipe_content) {
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
if (except && this.open_swipe_block === except) {
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
const content = this.open_swipe_content;
|
|
289
|
-
content.style.transition = 'transform 150ms ease';
|
|
290
|
-
content.style.transform = 'translateX(0)';
|
|
291
|
-
const clear_callback = () => {
|
|
292
|
-
content.removeEventListener('transitionend', clear_callback);
|
|
293
|
-
if (this.open_swipe_block) {
|
|
294
|
-
const menu_element = this.getSwipeMenuFor(this.open_swipe_block);
|
|
295
|
-
if (menu_element && menu_element.parentElement) {
|
|
296
|
-
menu_element.parentElement.removeChild(menu_element);
|
|
211
|
+
if (next_block !== null && swapped === false) {
|
|
212
|
+
const next_rect = next_block.getBoundingClientRect();
|
|
213
|
+
const next_block_y_threshold = next_rect.top + (next_rect.height * 0.6);
|
|
214
|
+
if (block_rect.bottom > next_block_y_threshold) {
|
|
215
|
+
const next_sibling = ghost.nextElementSibling === next_block ? ghost : ghost.nextElementSibling;
|
|
216
|
+
next_block.replaceWith(ghost);
|
|
217
|
+
if (next_sibling) {
|
|
218
|
+
next_sibling.before(next_block);
|
|
297
219
|
}
|
|
298
220
|
}
|
|
299
|
-
this.open_swipe_block = null;
|
|
300
|
-
this.open_swipe_content = null;
|
|
301
|
-
};
|
|
302
|
-
content.addEventListener('transitionend', clear_callback);
|
|
303
|
-
}
|
|
304
|
-
teardownSwipe() {
|
|
305
|
-
if (!this.swipe_block || !this.swipe_content) {
|
|
306
|
-
this.resetSwipeState();
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
this.swipe_content.style.transition = '';
|
|
310
|
-
this.swipe_content.style.transform = 'translateX(0)';
|
|
311
|
-
const menu = this.getSwipeMenuFor(this.swipe_block);
|
|
312
|
-
if (menu && menu.parentElement) {
|
|
313
|
-
menu.parentElement.removeChild(menu);
|
|
314
221
|
}
|
|
315
|
-
this.resetSwipeState();
|
|
316
222
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
const menu = this.getSwipeMenuFor(this.open_swipe_block);
|
|
327
|
-
const closest_block = target.closest('section.block');
|
|
328
|
-
const swipe_actions = target.closest('.swipe-actions');
|
|
329
|
-
if (closest_block === this.open_swipe_block || swipe_actions === menu) {
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
this.closeOpenSwipeMenu();
|
|
223
|
+
getGhostForBlock(block) {
|
|
224
|
+
const index_path = (0, get_index_path_for_element_1.default)(block);
|
|
225
|
+
const ghost = document.querySelector(`[data-for="${index_path}"]`);
|
|
226
|
+
if (ghost === null) {
|
|
227
|
+
throw new errors_1.InvariantViolation(`
|
|
228
|
+
Unable to find ghost for block with index path ${index_path}
|
|
229
|
+
`);
|
|
230
|
+
}
|
|
231
|
+
return ghost;
|
|
333
232
|
}
|
|
334
|
-
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
233
|
+
getPreviousBlock(block) {
|
|
234
|
+
const parent_node = block.parentNode;
|
|
235
|
+
const siblings = Array.from(parent_node.children);
|
|
236
|
+
const ghost = this.getGhostForBlock(block);
|
|
237
|
+
let index = siblings.indexOf(ghost);
|
|
238
|
+
if (index === -1) {
|
|
239
|
+
throw new errors_1.InvariantViolation('Unable to locate ghost within siblings');
|
|
240
|
+
}
|
|
241
|
+
while (index--) {
|
|
242
|
+
const sibling = siblings[index];
|
|
243
|
+
if (sibling === block) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
const { classList } = sibling;
|
|
247
|
+
if (!classList.contains('block')) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (classList.contains('ghost')) {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
return sibling;
|
|
338
254
|
}
|
|
339
|
-
return
|
|
255
|
+
return null;
|
|
340
256
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
target.style.zIndex = '1';
|
|
355
|
-
const wrapper = block.closest('main .section-wrapper');
|
|
356
|
-
let menu = null;
|
|
357
|
-
if (wrapper) {
|
|
358
|
-
if (getComputedStyle(wrapper).position === 'static') {
|
|
359
|
-
wrapper.style.position = 'relative';
|
|
257
|
+
getNextBlock(block) {
|
|
258
|
+
const parent_node = block.parentNode;
|
|
259
|
+
const siblings = Array.from(parent_node.children);
|
|
260
|
+
const ghost = this.getGhostForBlock(block);
|
|
261
|
+
let index = siblings.indexOf(ghost);
|
|
262
|
+
if (index === -1) {
|
|
263
|
+
throw new errors_1.InvariantViolation('Unable to locate ghost within siblings');
|
|
264
|
+
}
|
|
265
|
+
while (index < siblings.length) {
|
|
266
|
+
index++;
|
|
267
|
+
const sibling = siblings[index];
|
|
268
|
+
if (sibling === block) {
|
|
269
|
+
continue;
|
|
360
270
|
}
|
|
361
|
-
|
|
362
|
-
if (!
|
|
363
|
-
|
|
364
|
-
existing.className = 'swipe-actions';
|
|
365
|
-
existing.setAttribute('data-for', block.id);
|
|
366
|
-
existing.style.position = 'absolute';
|
|
367
|
-
existing.style.right = '0';
|
|
368
|
-
existing.style.display = 'none';
|
|
369
|
-
existing.style.opacity = '0';
|
|
370
|
-
existing.style.gap = '8px';
|
|
371
|
-
existing.style.alignItems = 'stretch';
|
|
372
|
-
existing.style.padding = '0 8px';
|
|
373
|
-
existing.style.background = 'transparent';
|
|
374
|
-
existing.style.zIndex = '0';
|
|
375
|
-
const edit_button = document.createElement('button');
|
|
376
|
-
const delete_button = document.createElement('button');
|
|
377
|
-
const add_button = document.createElement('button');
|
|
378
|
-
edit_button.textContent = emoji_1.default.GEAR;
|
|
379
|
-
edit_button.setAttribute('aria-label', 'Edit');
|
|
380
|
-
edit_button.style.background = '#f0ad4e';
|
|
381
|
-
edit_button.style.color = '#000';
|
|
382
|
-
edit_button.style.border = 'none';
|
|
383
|
-
edit_button.style.padding = '0';
|
|
384
|
-
edit_button.style.fontSize = '20px';
|
|
385
|
-
edit_button.style.width = '48px';
|
|
386
|
-
edit_button.style.minWidth = '48px';
|
|
387
|
-
edit_button.style.display = 'flex';
|
|
388
|
-
edit_button.style.alignItems = 'center';
|
|
389
|
-
edit_button.style.justifyContent = 'center';
|
|
390
|
-
edit_button.style.cursor = 'pointer';
|
|
391
|
-
delete_button.textContent = emoji_1.default.RED_X;
|
|
392
|
-
delete_button.setAttribute('aria-label', 'Delete');
|
|
393
|
-
delete_button.style.background = '#e74c3c';
|
|
394
|
-
delete_button.style.color = '#fff';
|
|
395
|
-
delete_button.style.border = 'none';
|
|
396
|
-
delete_button.style.padding = '0';
|
|
397
|
-
delete_button.style.fontSize = '20px';
|
|
398
|
-
delete_button.style.width = '48px';
|
|
399
|
-
delete_button.style.minWidth = '48px';
|
|
400
|
-
delete_button.style.display = 'flex';
|
|
401
|
-
delete_button.style.alignItems = 'center';
|
|
402
|
-
delete_button.style.justifyContent = 'center';
|
|
403
|
-
delete_button.style.cursor = 'pointer';
|
|
404
|
-
add_button.textContent = emoji_1.default.PLUS_SIGN;
|
|
405
|
-
add_button.setAttribute('aria-label', 'Add After');
|
|
406
|
-
add_button.style.background = '#27ae60';
|
|
407
|
-
add_button.style.color = '#fff';
|
|
408
|
-
add_button.style.border = 'none';
|
|
409
|
-
add_button.style.padding = '0';
|
|
410
|
-
add_button.style.fontSize = '20px';
|
|
411
|
-
add_button.style.width = '48px';
|
|
412
|
-
add_button.style.minWidth = '48px';
|
|
413
|
-
add_button.style.display = 'flex';
|
|
414
|
-
add_button.style.alignItems = 'center';
|
|
415
|
-
add_button.style.justifyContent = 'center';
|
|
416
|
-
add_button.style.cursor = 'pointer';
|
|
417
|
-
existing.appendChild(edit_button);
|
|
418
|
-
existing.appendChild(delete_button);
|
|
419
|
-
existing.appendChild(add_button);
|
|
420
|
-
wrapper.appendChild(existing);
|
|
421
|
-
const edit_handler = (event) => {
|
|
422
|
-
event.preventDefault();
|
|
423
|
-
event.stopPropagation();
|
|
424
|
-
this.navigateToBlockLink(block, 'edit');
|
|
425
|
-
};
|
|
426
|
-
const delete_handler = (event) => {
|
|
427
|
-
event.preventDefault();
|
|
428
|
-
event.stopPropagation();
|
|
429
|
-
this.navigateToBlockLink(block, 'delete');
|
|
430
|
-
};
|
|
431
|
-
const add_handler = (event) => {
|
|
432
|
-
event.preventDefault();
|
|
433
|
-
event.stopPropagation();
|
|
434
|
-
this.navigateToAddAfter(block);
|
|
435
|
-
};
|
|
436
|
-
// Prevent global touchstart from closing when interacting with menu
|
|
437
|
-
existing.addEventListener('touchstart', (event) => {
|
|
438
|
-
event.stopPropagation();
|
|
439
|
-
});
|
|
440
|
-
existing.addEventListener('mousedown', (event) => {
|
|
441
|
-
event.stopPropagation();
|
|
442
|
-
});
|
|
443
|
-
edit_button.addEventListener('click', edit_handler);
|
|
444
|
-
edit_button.addEventListener('touchend', edit_handler);
|
|
445
|
-
delete_button.addEventListener('click', delete_handler);
|
|
446
|
-
delete_button.addEventListener('touchend', delete_handler);
|
|
447
|
-
add_button.addEventListener('click', add_handler);
|
|
448
|
-
add_button.addEventListener('touchend', add_handler);
|
|
271
|
+
const { classList } = sibling;
|
|
272
|
+
if (!classList.contains('block')) {
|
|
273
|
+
continue;
|
|
449
274
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
menu.style.top = `${top}px`;
|
|
455
|
-
menu.style.height = `${height}px`;
|
|
456
|
-
}
|
|
457
|
-
let menu_width = 160;
|
|
458
|
-
if (menu) {
|
|
459
|
-
const prevDisplay = menu.style.display;
|
|
460
|
-
const prevOpacity = menu.style.opacity;
|
|
461
|
-
menu.style.display = 'flex';
|
|
462
|
-
menu.style.opacity = '0';
|
|
463
|
-
menu_width = menu.offsetWidth || 160;
|
|
464
|
-
menu.style.display = prevDisplay;
|
|
465
|
-
menu.style.opacity = prevOpacity;
|
|
275
|
+
if (classList.contains('ghost')) {
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
return sibling;
|
|
466
279
|
}
|
|
467
|
-
|
|
468
|
-
return {
|
|
469
|
-
target,
|
|
470
|
-
menu,
|
|
471
|
-
menu_width
|
|
472
|
-
};
|
|
280
|
+
return null;
|
|
473
281
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
282
|
+
handlePointerUp(event) {
|
|
283
|
+
this.stopDragging();
|
|
284
|
+
}
|
|
285
|
+
handlePointerCancel(event) {
|
|
286
|
+
this.stopDragging();
|
|
287
|
+
}
|
|
288
|
+
stopDragging() {
|
|
289
|
+
this.showFullscreenBlockingOverlay();
|
|
290
|
+
this.stopDraggingAsync().then(() => {
|
|
291
|
+
this.hideFullscreenBlockingOverlay();
|
|
482
292
|
});
|
|
483
|
-
if (parts.length === 0 || has_invalid_number) {
|
|
484
|
-
throw new errors_1.InvariantViolation('Invalid index_path for Add After');
|
|
485
|
-
}
|
|
486
|
-
const last = parts.pop();
|
|
487
|
-
if (last === undefined) {
|
|
488
|
-
throw new errors_1.InvariantViolation('Unable to compute next index for Add After');
|
|
489
|
-
}
|
|
490
|
-
parts.push(last + 1);
|
|
491
|
-
const index_path = parts.join('.');
|
|
492
|
-
const url = new URL(window.location.href);
|
|
493
|
-
const editing = url.searchParams.get('editing') === 'true';
|
|
494
|
-
const path = window.location.pathname;
|
|
495
|
-
const actionUrl = new URL('/actions', window.location.origin);
|
|
496
|
-
actionUrl.searchParams.set('path', path);
|
|
497
|
-
actionUrl.searchParams.set('editing', String(editing));
|
|
498
|
-
actionUrl.searchParams.set('action_type', 'add_block');
|
|
499
|
-
actionUrl.searchParams.set('index_path', index_path);
|
|
500
|
-
window.location.href = actionUrl.toString();
|
|
501
293
|
}
|
|
502
|
-
|
|
503
|
-
const shows_time = block.classList.contains('with-time');
|
|
504
|
-
const time_element = block.querySelector(':scope time');
|
|
505
|
-
if (!time_element) {
|
|
506
|
-
return;
|
|
507
|
-
}
|
|
508
|
-
if (!shows_time) {
|
|
509
|
-
time_element.style.display = 'none';
|
|
510
|
-
}
|
|
511
|
-
else {
|
|
512
|
-
time_element.style.display = '';
|
|
513
|
-
}
|
|
294
|
+
showFullscreenBlockingOverlay() {
|
|
514
295
|
}
|
|
515
|
-
|
|
516
|
-
const block_id = block.id;
|
|
517
|
-
const link_id = `${block_id}-${type}`;
|
|
518
|
-
const link_element = document.getElementById(link_id);
|
|
519
|
-
if (!link_element) {
|
|
520
|
-
return;
|
|
521
|
-
}
|
|
522
|
-
const href = link_element.getAttribute('href');
|
|
523
|
-
if (href) {
|
|
524
|
-
window.location.href = href;
|
|
525
|
-
}
|
|
296
|
+
hideFullscreenBlockingOverlay() {
|
|
526
297
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
ghost.style.boxShadow = '0 8px 16px rgba(0,0,0,0.2)';
|
|
548
|
-
ghost.style.zIndex = '9999';
|
|
549
|
-
// No transition on top; keep glued to pointer
|
|
550
|
-
document.body.appendChild(ghost);
|
|
551
|
-
this.drag_ghost = ghost;
|
|
552
|
-
// Record pointer offset within the element so the ghost aligns under finger
|
|
553
|
-
this.drag_pointer_offset_y = current_y - rect.top;
|
|
554
|
-
// Replace the original block's layout with a placeholder in the same spot
|
|
555
|
-
const placeholder = document.createElement('div');
|
|
556
|
-
placeholder.style.height = `${rect.height}px`;
|
|
557
|
-
placeholder.style.margin = getComputedStyle(block).margin;
|
|
558
|
-
placeholder.style.border = '2px dashed #888';
|
|
559
|
-
placeholder.style.borderRadius = '4px';
|
|
560
|
-
placeholder.style.boxSizing = 'border-box';
|
|
561
|
-
if (block.parentElement !== null) {
|
|
562
|
-
block.parentElement.insertBefore(placeholder, block);
|
|
298
|
+
async stopDraggingAsync() {
|
|
299
|
+
this.cancelDelayedDrag();
|
|
300
|
+
this.removeClassFromAllElements('drag-candidate');
|
|
301
|
+
const dragging_elements = this.removeClassFromAllElements('dragging');
|
|
302
|
+
let index = 0;
|
|
303
|
+
while (index < dragging_elements.length) {
|
|
304
|
+
const element = dragging_elements[index++];
|
|
305
|
+
const ghost = this.getGhostForBlock(element);
|
|
306
|
+
const source_index_path = (0, get_index_path_for_element_1.default)(element);
|
|
307
|
+
const target_index_path = this.getIndexPathForGhost(ghost);
|
|
308
|
+
await this.submitReposition(source_index_path, target_index_path);
|
|
309
|
+
ghost.replaceWith(element);
|
|
310
|
+
Object.assign(element.style, {
|
|
311
|
+
left: '',
|
|
312
|
+
top: '',
|
|
313
|
+
right: '',
|
|
314
|
+
bottom: '',
|
|
315
|
+
width: '',
|
|
316
|
+
height: ''
|
|
317
|
+
});
|
|
563
318
|
}
|
|
564
|
-
this.drag_placeholder = placeholder;
|
|
565
|
-
// Remove original from layout so we don't keep extra blank space
|
|
566
|
-
block.style.display = 'none';
|
|
567
|
-
this.updatePlaceholderPosition(current_y);
|
|
568
319
|
}
|
|
569
|
-
|
|
570
|
-
const
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
|
-
const container = placeholder.parentElement;
|
|
576
|
-
const blocks = this.getSiblingBlocks(container, origin);
|
|
577
|
-
let inserted = false;
|
|
578
|
-
for (let i = 0; i < blocks.length; i++) {
|
|
579
|
-
const element = blocks[i];
|
|
580
|
-
const rect = element.getBoundingClientRect();
|
|
581
|
-
const midpoint = rect.top + rect.height / 2;
|
|
582
|
-
if (cursor_y < midpoint) {
|
|
583
|
-
const parent = element.parentElement;
|
|
584
|
-
if (parent) {
|
|
585
|
-
parent.insertBefore(placeholder, element);
|
|
586
|
-
}
|
|
587
|
-
inserted = true;
|
|
588
|
-
break;
|
|
589
|
-
}
|
|
320
|
+
getIndexPathSafe(element) {
|
|
321
|
+
const is_block = element.classList.contains('block');
|
|
322
|
+
if (!is_block) {
|
|
323
|
+
return null;
|
|
590
324
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
const parent = last_element.parentElement;
|
|
595
|
-
if (parent) {
|
|
596
|
-
parent.appendChild(placeholder);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
325
|
+
const is_ghost = element.classList.contains('ghost');
|
|
326
|
+
if (is_ghost) {
|
|
327
|
+
return null;
|
|
599
328
|
}
|
|
329
|
+
return (0, get_index_path_for_element_1.default)(element);
|
|
600
330
|
}
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
331
|
+
getIndexPathForGhost(ghost) {
|
|
332
|
+
let current_child = ghost;
|
|
333
|
+
while (current_child) {
|
|
334
|
+
const index_path = this.getIndexPathSafe(current_child);
|
|
335
|
+
if (index_path !== null) {
|
|
336
|
+
return index_path;
|
|
606
337
|
}
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
338
|
+
current_child = current_child.nextElementSibling;
|
|
339
|
+
}
|
|
340
|
+
current_child = ghost;
|
|
341
|
+
while (current_child) {
|
|
342
|
+
const index_path = this.getIndexPathSafe(current_child);
|
|
343
|
+
if (index_path !== null) {
|
|
344
|
+
// TODO: This will need to change when I implement drag-reordering of
|
|
345
|
+
// multicolumn layouts.
|
|
346
|
+
const index_major_version = parseInt(index_path);
|
|
347
|
+
const next_version = index_major_version + 1;
|
|
348
|
+
return next_version.toString();
|
|
611
349
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
// Play
|
|
616
|
-
void element.getBoundingClientRect();
|
|
617
|
-
element.style.transition = 'transform 120ms ease';
|
|
618
|
-
element.style.transform = 'translateY(0)';
|
|
619
|
-
const cleanup = () => {
|
|
620
|
-
element.style.transition = '';
|
|
621
|
-
element.style.transform = '';
|
|
622
|
-
element.removeEventListener('transitionend', cleanup);
|
|
623
|
-
};
|
|
624
|
-
element.addEventListener('transitionend', cleanup);
|
|
625
|
-
});
|
|
350
|
+
current_child = current_child.previousElementSibling;
|
|
351
|
+
}
|
|
352
|
+
return '0';
|
|
626
353
|
}
|
|
627
|
-
async
|
|
354
|
+
async submitReposition(source_index_path, target_index_path) {
|
|
628
355
|
const form = new FormData();
|
|
629
356
|
form.set('path', window.location.pathname);
|
|
630
357
|
form.set('action_type', action_type_1.default.REPOSITION_BLOCK);
|
|
631
358
|
form.set('source_index_path', source_index_path);
|
|
632
359
|
form.set('target_index_path', target_index_path);
|
|
633
|
-
const response = await fetch(`/actions
|
|
360
|
+
const response = await fetch(`/actions`, {
|
|
634
361
|
method: 'POST',
|
|
635
362
|
body: form,
|
|
636
363
|
credentials: 'same-origin',
|
|
@@ -644,96 +371,15 @@ class InteractionHelper {
|
|
|
644
371
|
return null;
|
|
645
372
|
}
|
|
646
373
|
}
|
|
647
|
-
|
|
648
|
-
if (!placeholder) {
|
|
649
|
-
return null;
|
|
650
|
-
}
|
|
651
|
-
const parent = placeholder.parentElement;
|
|
652
|
-
if (!parent) {
|
|
653
|
-
return null;
|
|
654
|
-
}
|
|
655
|
-
let index = 0;
|
|
656
|
-
const children_elements = Array.from(parent.children);
|
|
657
|
-
for (let i = 0; i < children_elements.length; i++) {
|
|
658
|
-
const child_element = children_elements[i];
|
|
659
|
-
if (child_element === placeholder) {
|
|
660
|
-
break;
|
|
661
|
-
}
|
|
662
|
-
if (child_element.classList.contains('block')) {
|
|
663
|
-
index += 1;
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
return index.toString();
|
|
667
|
-
}
|
|
668
|
-
updateTopLevelIndexPaths() {
|
|
669
|
-
// Top-level blocks are rendered inside main > .section-wrapper
|
|
670
|
-
const wrapper = document.querySelector('main .section-wrapper');
|
|
671
|
-
let blocks;
|
|
672
|
-
if (wrapper) {
|
|
673
|
-
const node_list = wrapper.querySelectorAll(':scope > section.block');
|
|
674
|
-
blocks = Array.from(node_list);
|
|
675
|
-
}
|
|
676
|
-
else {
|
|
677
|
-
// Fallback: direct children of main if wrapper is not present
|
|
678
|
-
const node_list = document.querySelectorAll('main > section.block');
|
|
679
|
-
blocks = Array.from(node_list);
|
|
680
|
-
}
|
|
681
|
-
for (let i = 0; i < blocks.length; i++) {
|
|
682
|
-
blocks[i].setAttribute('data-index-path', i.toString());
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
cleanupDragElements() {
|
|
686
|
-
if (this.drag_ghost && this.drag_ghost.parentElement) {
|
|
687
|
-
this.drag_ghost.parentElement.removeChild(this.drag_ghost);
|
|
688
|
-
}
|
|
689
|
-
if (this.drag_placeholder && this.drag_placeholder.parentElement) {
|
|
690
|
-
// Move the real element into the placeholder's final position
|
|
691
|
-
if (this.drag_origin_block) {
|
|
692
|
-
this.drag_placeholder.parentElement.insertBefore(this.drag_origin_block, this.drag_placeholder);
|
|
693
|
-
}
|
|
694
|
-
this.drag_placeholder.parentElement.removeChild(this.drag_placeholder);
|
|
695
|
-
}
|
|
696
|
-
if (this.drag_origin_block) {
|
|
697
|
-
this.drag_origin_block.style.display = '';
|
|
698
|
-
}
|
|
699
|
-
this.drag_ghost = null;
|
|
700
|
-
this.drag_placeholder = null;
|
|
701
|
-
// Restore global styles
|
|
702
|
-
document.body.style.userSelect = '';
|
|
703
|
-
document.body.style.cursor = '';
|
|
704
|
-
}
|
|
705
|
-
resetDragState() {
|
|
706
|
-
this.cleanupDragElements();
|
|
707
|
-
this.drag_active = false;
|
|
708
|
-
this.drag_origin_block = null;
|
|
709
|
-
this.drag_start_y = null;
|
|
710
|
-
this.drag_pointer_offset_y = null;
|
|
711
|
-
}
|
|
712
|
-
clearPressTimer() {
|
|
713
|
-
if (this.drag_press_timer !== null) {
|
|
714
|
-
window.clearTimeout(this.drag_press_timer);
|
|
715
|
-
this.drag_press_timer = null;
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
getEventPoint(event) {
|
|
719
|
-
const touch_event = event;
|
|
720
|
-
const has_touches = touch_event.touches !== undefined;
|
|
721
|
-
if (has_touches) {
|
|
722
|
-
const primary_touch = touch_event.touches[0] || touch_event.changedTouches[0];
|
|
723
|
-
if (!primary_touch) {
|
|
724
|
-
return null;
|
|
725
|
-
}
|
|
726
|
-
return {
|
|
727
|
-
clientX: primary_touch.clientX,
|
|
728
|
-
clientY: primary_touch.clientY
|
|
729
|
-
};
|
|
730
|
-
}
|
|
731
|
-
const mouse_event = event;
|
|
374
|
+
getEventCoordinate(event) {
|
|
732
375
|
return {
|
|
733
|
-
|
|
734
|
-
|
|
376
|
+
x: event.clientX,
|
|
377
|
+
y: event.clientY
|
|
735
378
|
};
|
|
736
379
|
}
|
|
380
|
+
getDragStartCoordinate() {
|
|
381
|
+
return this.drag_start_coordinate;
|
|
382
|
+
}
|
|
737
383
|
}
|
|
738
384
|
exports.default = InteractionHelper;
|
|
739
385
|
//# sourceMappingURL=interaction.js.map
|