Skip to content

Commit ad694e3

Browse files
committed
fix: drag & drop logic breaks when target is after source
1 parent 7f5b85e commit ad694e3

File tree

1 file changed

+96
-26
lines changed

1 file changed

+96
-26
lines changed

src/LiveDevelopment/LivePreviewEdit.js

Lines changed: 96 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -181,41 +181,111 @@ define(function (require, exports, module) {
181181
const sourceText = editor.getTextBetween(sourceRange.from, sourceRange.to);
182182
const targetIndent = editor.getTextBetween({ line: targetRange.from.line, ch: 0 }, targetRange.from);
183183

184-
// creating a batch operation so that undo in live preview works fine
185-
editor.document.batchOperation(function () {
186-
// first, we need to remove the source code from its initial position
187-
editor.replaceRange("", sourceRange.from, sourceRange.to);
184+
// Check if source is before target to determine order of operations
185+
// check if the source is before target or after the target
186+
// we need this because
187+
// If source is before target → we need to insert first, then remove
188+
// If target is before source → remove first, then insert
189+
const sourceBeforeTarget =
190+
sourceRange.from.line < targetRange.from.line ||
191+
(sourceRange.from.line === targetRange.from.line && sourceRange.from.ch < targetRange.from.ch);
192+
193+
// this function is to clean up the empty lines after an element is removed
194+
function cleanupAfterRemoval(range) {
195+
const lineToCheck = range.from.line;
196+
197+
// check if the line where element was removed is now empty
198+
if (lineToCheck < editor.lineCount()) {
199+
const currentLineText = editor.getLine(lineToCheck);
200+
if (currentLineText && currentLineText.trim() === "") {
201+
// remove the empty line
202+
const lineStart = { line: lineToCheck, ch: 0 };
203+
const lineEnd = { line: lineToCheck + 1, ch: 0 };
204+
editor.replaceRange("", lineStart, lineEnd);
205+
}
206+
}
188207

189-
// since we remove content from the source, we want to clear the extra line
190-
if(sourceRange.from.line !== 0) {
191-
const prevLineText = editor.getLine(sourceRange.from.line - 1);
192-
const chPrevLine = prevLineText ? prevLineText.length : 0;
193-
editor.replaceRange("", {line: sourceRange.from.line - 1, ch: chPrevLine}, sourceRange.from);
208+
// also we need to check the previous line if it became empty
209+
if (lineToCheck > 0) {
210+
const prevLineText = editor.getLine(lineToCheck - 1);
211+
if (prevLineText && prevLineText.trim() === "") {
212+
const lineStart = { line: lineToCheck - 1, ch: 0 };
213+
const lineEnd = { line: lineToCheck, ch: 0 };
214+
editor.replaceRange("", lineStart, lineEnd);
215+
}
194216
}
217+
}
218+
219+
// this function is to make sure that we insert elements with proper indentation
220+
function insertElementWithIndentation(insertPos, insertAfterMode, useTargetIndent) {
221+
const indent = useTargetIndent ? targetIndent : targetIndent;
222+
223+
if (insertAfterMode) {
224+
// Insert after the target element
225+
editor.replaceRange("\n" + indent + sourceText, insertPos);
226+
} else {
227+
// Insert before the target element
228+
const insertLine = insertPos.line;
229+
const lineStart = { line: insertLine, ch: 0 };
230+
231+
// Get current line content to preserve any existing indentation structure
232+
const currentLine = editor.getLine(insertLine);
195233

196-
// recalculate the target range, as the source text is not removed
197-
const updatedTargetRange = HTMLInstrumentation.getPositionFromTagId(editor, targetId);
198-
if (!updatedTargetRange) {
199-
return;
234+
if (currentLine && currentLine.trim() === "") {
235+
// the line is empty, replace it entirely
236+
editor.replaceRange(indent + sourceText, lineStart, { line: insertLine, ch: currentLine.length });
237+
} else {
238+
// the line has content, insert before it
239+
editor.replaceRange(indent + sourceText + "\n", lineStart);
240+
}
200241
}
242+
}
201243

202-
if (insertAfter) {
203-
const insertPos = {
204-
line: updatedTargetRange.to.line,
205-
ch: updatedTargetRange.to.ch
206-
};
244+
// creating a batch operation so that undo in live preview works fine
245+
editor.document.batchOperation(function () {
246+
if (sourceBeforeTarget) {
247+
// this handles the case when source is before target: insert first, then remove
248+
if (insertAfter) {
249+
const insertPos = {
250+
line: targetRange.to.line,
251+
ch: targetRange.to.ch
252+
};
253+
insertElementWithIndentation(insertPos, true, true);
254+
} else {
255+
// insert before target
256+
insertElementWithIndentation(targetRange.from, false, true);
257+
}
207258

208-
editor.replaceRange("\n" + targetIndent + sourceText, insertPos);
259+
// Now remove the source element (NOTE: the positions have shifted)
260+
const updatedSourceRange = HTMLInstrumentation.getPositionFromTagId(editor, sourceId);
261+
if (updatedSourceRange) {
262+
editor.replaceRange("", updatedSourceRange.from, updatedSourceRange.to);
263+
cleanupAfterRemoval(updatedSourceRange);
264+
}
209265
} else {
210-
// insert before
211-
const targetText = editor.getTextBetween(updatedTargetRange.from, updatedTargetRange.to);
266+
// This handles the case when target is before source: remove first, then insert
267+
// Store source range before removal
268+
const originalSourceRange = { ...sourceRange };
269+
270+
// Remove the source element first
271+
editor.replaceRange("", sourceRange.from, sourceRange.to);
272+
cleanupAfterRemoval(originalSourceRange);
273+
274+
// Recalculate target range after source removal as the positions have shifted
275+
const updatedTargetRange = HTMLInstrumentation.getPositionFromTagId(editor, targetId);
276+
if (!updatedTargetRange) {
277+
return;
278+
}
212279

213-
// to check if there is only indentation and no text before it
214-
if (targetIndent.trim() === "") {
215-
const finalText = sourceText + '\n' + targetIndent + targetText;
216-
editor.replaceRange(finalText, updatedTargetRange.from, updatedTargetRange.to);
280+
if (insertAfter) {
281+
const insertPos = {
282+
line: updatedTargetRange.to.line,
283+
ch: updatedTargetRange.to.ch
284+
};
285+
insertElementWithIndentation(insertPos, true, true);
217286
} else {
218-
editor.replaceRange(sourceText + targetText, updatedTargetRange.from, updatedTargetRange.to);
287+
// Insert before target
288+
insertElementWithIndentation(updatedTargetRange.from, false, true);
219289
}
220290
}
221291
});

0 commit comments

Comments
 (0)