Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.

Commit 444ae4d

Browse files
committed
Merge pull request #1769 from DennisKehrig/dk/issue-1256
Fixes #1256
2 parents ae3fc3f + 4b9a6ed commit 444ae4d

4 files changed

Lines changed: 81 additions & 18 deletions

File tree

src/document/TextRange.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ define(function (require, exports, module) {
4545
* - lostSync -- When the backing Document changes in such a way that the range can no longer
4646
* accurately be maintained. Generally, occurs whenever an edit spans a range boundary.
4747
* After this, startLine & endLine will be unusable (set to null).
48+
* Also occurs when the document is deleted, though startLine & endLine won't be modified
4849
* These events only ever occur in response to Document changes, so if you are already listening
4950
* to the Document, you could ignore the TextRange events and just read its updated value in your
5051
* own Document change handler.
@@ -59,16 +60,19 @@ define(function (require, exports, module) {
5960

6061
this.document = document;
6162
document.addRef();
62-
// store this-bound version of listener so we can remove them later
63+
// store this-bound versions of listeners so we can remove them later
6364
this._handleDocumentChange = this._handleDocumentChange.bind(this);
65+
this._handleDocumentDeleted = this._handleDocumentDeleted.bind(this);
6466
$(document).on("change", this._handleDocumentChange);
67+
$(document).on("deleted", this._handleDocumentDeleted);
6568
}
6669

6770
/** Detaches from the Document. The TextRange will no longer update or send change events */
6871
TextRange.prototype.dispose = function (editor, change) {
6972
// Disconnect from Document
7073
this.document.releaseRef();
7174
$(this.document).off("change", this._handleDocumentChange);
75+
$(this.document).off("deleted", this._handleDocumentDeleted);
7276
};
7377

7478

@@ -167,6 +171,10 @@ define(function (require, exports, module) {
167171
this._applyChangesToRange(changeList);
168172
};
169173

174+
TextRange.prototype._handleDocumentDeleted = function (event) {
175+
$(this).triggerHandler("lostSync");
176+
};
177+
170178

171179
/* (pretty toString(), to aid debugging) */
172180
TextRange.prototype.toString = function () {

src/editor/Editor.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -571,8 +571,9 @@ define(function (require, exports, module) {
571571
* Responds to the Document's underlying file being deleted. The Document is now basically dead,
572572
* so we must close.
573573
*/
574-
Editor.prototype._handleDocumentDeleted = function () {
575-
$(this).triggerHandler("lostContent");
574+
Editor.prototype._handleDocumentDeleted = function (event) {
575+
// Pass the delete event along as the cause (needed in MultiRangeInlineEditor)
576+
$(this).triggerHandler("lostContent", [event]);
576577
};
577578

578579

src/editor/InlineTextEditor.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,9 @@ define(function (require, exports, module) {
247247
$lineNumber.text(inlineInfo.editor.getFirstVisibleLine() + 1);
248248
});
249249

250-
// If Document's file is deleted, or Editor loses sync with Document, just close
250+
// If Document's file is deleted, or Editor loses sync with Document, delegate to this._onLostContent()
251251
$(inlineInfo.editor).on("lostContent", function () {
252-
// Note: this closes the entire inline widget if any one Editor loses sync. This seems
253-
// better than leaving it open but suddenly removing one rule from the result list.
254-
self.close();
252+
self._onLostContent.apply(self, arguments);
255253
});
256254

257255
// set dirty indicator state
@@ -285,6 +283,14 @@ define(function (require, exports, module) {
285283
});
286284
};
287285

286+
/**
287+
* If Document's file is deleted, or Editor loses sync with Document, just close
288+
*/
289+
InlineTextEditor.prototype._onLostContent = function () {
290+
// Note: this closes the entire inline widget if any one Editor loses sync. This seems
291+
// better than leaving it open but suddenly removing one rule from the result list.
292+
this.close();
293+
};
288294

289295
// consolidate all dirty document updates
290296
$(DocumentManager).on("dirtyFlagChange", _dirtyFlagChangeHandler);

src/editor/MultiRangeInlineEditor.js

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -146,25 +146,24 @@ define(function (require, exports, module) {
146146

147147
// create range list & add listeners for range textrange changes
148148
var rangeItemText;
149-
this._ranges.forEach(function (range, i) {
149+
this._ranges.forEach(function (range) {
150150
// Create list item UI
151151
var $rangeItem = $(window.document.createElement("li")).appendTo($rangeList);
152152
_updateRangeLabel($rangeItem, range);
153153
$rangeItem.mousedown(function () {
154-
self.setSelectedIndex(i);
154+
self.setSelectedIndex(self._ranges.indexOf(range));
155155
});
156156

157-
self._ranges[i].$listItem = $rangeItem;
157+
range.$listItem = $rangeItem;
158158

159159
// Update list item as TextRange changes
160-
$(self._ranges[i].textRange).on("change", function () {
160+
$(range.textRange).on("change", function () {
161161
_updateRangeLabel($rangeItem, range);
162162
});
163163

164-
// If TextRange lost sync, react just as we do for an inline Editor's lostContent event:
165-
// close the whole inline widget
166-
$(self._ranges[i].textRange).on("lostSync", function () {
167-
self.close();
164+
// If TextRange lost sync, remove it from the list (and close the widget if no other ranges are left)
165+
$(range.textRange).on("lostSync", function () {
166+
self._removeRange(range);
168167
});
169168
});
170169

@@ -207,10 +206,10 @@ define(function (require, exports, module) {
207206
}
208207

209208
// Remove selected class(es)
210-
var previousItem = (this._selectedRangeIndex >= 0) ? this._ranges[this._selectedRangeIndex].$listItem : null;
209+
var $previousItem = (this._selectedRangeIndex >= 0) ? this._ranges[this._selectedRangeIndex].$listItem : null;
211210

212-
if (previousItem) {
213-
previousItem.toggleClass("selected", false);
211+
if ($previousItem) {
212+
$previousItem.toggleClass("selected", false);
214213
}
215214

216215
this._selectedRangeIndex = newIndex;
@@ -249,6 +248,44 @@ define(function (require, exports, module) {
249248
this.sizeInlineWidgetToContents(true, false);
250249
this._updateRelatedContainer();
251250

251+
this._updateSelectedMarker();
252+
};
253+
254+
MultiRangeInlineEditor.prototype._removeRange = function (range) {
255+
// If this is the last range, just close the whole widget
256+
if (this._ranges.length <= 1) {
257+
this.close();
258+
return;
259+
}
260+
261+
// Now we know there is at least one other range -> found out which one this is
262+
var index = this._ranges.indexOf(range);
263+
264+
// If the range to be removed is the selected one, first switch to another one
265+
if (index === this._selectedRangeIndex) {
266+
// If possible, select the one below, else select the one above
267+
if (index + 1 < this._ranges.length) {
268+
this.setSelectedIndex(index + 1);
269+
} else {
270+
this.setSelectedIndex(index - 1);
271+
}
272+
}
273+
274+
// Now we can remove this range
275+
range.$listItem.remove();
276+
range.textRange.dispose();
277+
this._ranges.splice(index, 1);
278+
279+
// If the selected range is below, we need to update the index
280+
if (index < this._selectedRangeIndex) {
281+
this._selectedRangeIndex--;
282+
this._updateSelectedMarker();
283+
}
284+
};
285+
286+
MultiRangeInlineEditor.prototype._updateSelectedMarker = function () {
287+
var $rangeItem = this._ranges[this._selectedRangeIndex].$listItem;
288+
252289
// scroll the selection to the rangeItem, use setTimeout to wait for DOM updates
253290
var self = this;
254291
window.setTimeout(function () {
@@ -429,6 +466,17 @@ define(function (require, exports, module) {
429466
this._ensureCursorVisible();
430467
};
431468

469+
/**
470+
* Overwrite InlineTextEditor's _onLostContent to do nothing if the document's file is deleted
471+
* (deletes are handled via TextRange's lostSync).
472+
*/
473+
MultiRangeInlineEditor.prototype._onLostContent = function (event, cause) {
474+
// Ignore when the editor's content got lost due to a deleted file
475+
if (cause && cause.type === "deleted") { return; }
476+
// Else yield to the parent's implementation
477+
return this.parentClass._onLostContent.apply(this, arguments);
478+
};
479+
432480
/**
433481
* @return {Array.<SearchResultItem>}
434482
*/

0 commit comments

Comments
 (0)