mirror of
https://github.com/GoogleChrome/chrome-extensions-samples.git
synced 2026-03-29 13:49:41 +07:00
708 lines
23 KiB
JavaScript
708 lines
23 KiB
JavaScript
/* vim:ts=4:sts=4:sw=4:
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Ajax.org Code Editor (ACE).
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Ajax.org B.V.
|
|
* Portions created by the Initial Developer are Copyright (C) 2010
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Harutyun Amirjanyan <amirjanyan AT gmail DOT com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
define(function(require, exports, module) {
|
|
|
|
var RangeList = require("./range_list").RangeList;
|
|
var Range = require("./range").Range;
|
|
var Selection = require("./selection").Selection;
|
|
var onMouseDown = require("./mouse/multi_select_handler").onMouseDown;
|
|
exports.commands = require("./commands/multi_select_commands");
|
|
|
|
// Todo: session.find or editor.findVolatile that returns range
|
|
var Search = require("./search").Search;
|
|
var search = new Search();
|
|
|
|
function find(session, needle, dir) {
|
|
search.$options.wrap = true;
|
|
search.$options.needle = needle;
|
|
search.$options.backwards = dir == -1;
|
|
return search.find(session);
|
|
}
|
|
|
|
// extend EditSession
|
|
var EditSession = require("./edit_session").EditSession;
|
|
(function() {
|
|
this.getSelectionMarkers = function() {
|
|
return this.$selectionMarkers;
|
|
};
|
|
}).call(EditSession.prototype);
|
|
|
|
// extend Selection
|
|
(function() {
|
|
// list of ranges in reverse addition order
|
|
this.ranges = null;
|
|
|
|
// automatically sorted list of ranges
|
|
this.rangeList = null;
|
|
|
|
/**
|
|
* Selection.addRange(Range) -> Void
|
|
*
|
|
* adds a range to selection entering multiselect mode if necessary
|
|
**/
|
|
this.addRange = function(range, $blockChangeEvents) {
|
|
if (!range)
|
|
return;
|
|
|
|
if (!this.inMultiSelectMode && this.rangeCount == 0) {
|
|
var oldRange = this.toOrientedRange();
|
|
if (range.intersects(oldRange))
|
|
return $blockChangeEvents || this.fromOrientedRange(range);
|
|
|
|
this.rangeList.add(oldRange);
|
|
this.$onAddRange(oldRange);
|
|
}
|
|
|
|
if (!range.cursor)
|
|
range.cursor = range.end;
|
|
|
|
var removed = this.rangeList.add(range);
|
|
|
|
this.$onAddRange(range);
|
|
|
|
if (removed.length)
|
|
this.$onRemoveRange(removed);
|
|
|
|
if (this.rangeCount > 1 && !this.inMultiSelectMode) {
|
|
this._emit("multiSelect");
|
|
this.inMultiSelectMode = true;
|
|
this.session.$undoSelect = false;
|
|
this.rangeList.attach(this.session);
|
|
}
|
|
|
|
return $blockChangeEvents || this.fromOrientedRange(range);
|
|
};
|
|
|
|
this.toSingleRange = function(range) {
|
|
range = range || this.ranges[0];
|
|
var removed = this.rangeList.removeAll();
|
|
if (removed.length)
|
|
this.$onRemoveRange(removed);
|
|
|
|
range && this.fromOrientedRange(range);
|
|
};
|
|
|
|
/**
|
|
* Selection.addRange(pos) -> Range
|
|
* pos: {row, column}
|
|
*
|
|
* removes range containing pos (if exists)
|
|
**/
|
|
this.substractPoint = function(pos) {
|
|
var removed = this.rangeList.substractPoint(pos);
|
|
if (removed) {
|
|
this.$onRemoveRange(removed);
|
|
return removed[0];
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Selection.mergeOverlappingRanges() -> Void
|
|
*
|
|
* merges overlapping ranges ensuring consistency after changes
|
|
**/
|
|
this.mergeOverlappingRanges = function() {
|
|
var removed = this.rangeList.merge();
|
|
if (removed.length)
|
|
this.$onRemoveRange(removed);
|
|
else if(this.ranges[0])
|
|
this.fromOrientedRange(this.ranges[0]);
|
|
};
|
|
|
|
this.$onAddRange = function(range) {
|
|
this.rangeCount = this.rangeList.ranges.length;
|
|
this.ranges.unshift(range);
|
|
this._emit("addRange", {range: range});
|
|
};
|
|
|
|
this.$onRemoveRange = function(removed) {
|
|
this.rangeCount = this.rangeList.ranges.length;
|
|
if (this.rangeCount == 1 && this.inMultiSelectMode) {
|
|
var lastRange = this.rangeList.ranges.pop();
|
|
removed.push(lastRange);
|
|
this.rangeCount = 0;
|
|
}
|
|
|
|
for (var i = removed.length; i--; ) {
|
|
var index = this.ranges.indexOf(removed[i]);
|
|
this.ranges.splice(index, 1);
|
|
}
|
|
|
|
this._emit("removeRange", {ranges: removed});
|
|
|
|
if (this.rangeCount == 0 && this.inMultiSelectMode) {
|
|
this.inMultiSelectMode = false;
|
|
this._emit("singleSelect");
|
|
this.session.$undoSelect = true;
|
|
this.rangeList.detach(this.session);
|
|
}
|
|
|
|
lastRange = lastRange || this.ranges[0];
|
|
if (lastRange && !lastRange.isEqual(this.getRange()))
|
|
this.fromOrientedRange(lastRange);
|
|
};
|
|
|
|
// adds multicursor support to selection
|
|
this.$initRangeList = function() {
|
|
if (this.rangeList)
|
|
return;
|
|
|
|
this.rangeList = new RangeList();
|
|
this.ranges = [];
|
|
this.rangeCount = 0;
|
|
};
|
|
|
|
this.getAllRanges = function() {
|
|
return this.rangeList.ranges.concat();
|
|
};
|
|
|
|
this.splitIntoLines = function () {
|
|
if (this.rangeCount > 1) {
|
|
var ranges = this.rangeList.ranges;
|
|
var lastRange = ranges[ranges.length - 1];
|
|
var range = Range.fromPoints(ranges[0].start, lastRange.end);
|
|
|
|
this.toSingleRange();
|
|
this.setSelectionRange(range, lastRange.cursor == lastRange.start);
|
|
} else {
|
|
var cursor = this.session.documentToScreenPosition(this.selectionLead);
|
|
var anchor = this.session.documentToScreenPosition(this.selectionAnchor);
|
|
|
|
var rectSel = this.rectangularRangeBlock(cursor, anchor);
|
|
rectSel.forEach(this.addRange, this);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Selection.rectangularRangeBlock(screenCursor, screenAnchor, includeEmptyLines) -> [Range]
|
|
* gets list of ranges composing rectangular block on the screen
|
|
* @includeEmptyLines if true includes ranges inside the block which
|
|
* are empty becuase of the clipping
|
|
*/
|
|
this.rectangularRangeBlock = function(screenCursor, screenAnchor, includeEmptyLines) {
|
|
var rectSel = [];
|
|
|
|
var xBackwards = screenCursor.column < screenAnchor.column;
|
|
if (xBackwards) {
|
|
var startColumn = screenCursor.column;
|
|
var endColumn = screenAnchor.column;
|
|
} else {
|
|
var startColumn = screenAnchor.column;
|
|
var endColumn = screenCursor.column;
|
|
}
|
|
|
|
var yBackwards = screenCursor.row < screenAnchor.row;
|
|
if (yBackwards) {
|
|
var startRow = screenCursor.row;
|
|
var endRow = screenAnchor.row;
|
|
} else {
|
|
var startRow = screenAnchor.row;
|
|
var endRow = screenCursor.row;
|
|
}
|
|
|
|
if (startColumn < 0)
|
|
startColumn = 0;
|
|
if (startRow < 0)
|
|
startRow = 0;
|
|
|
|
if (startRow == endRow)
|
|
includeEmptyLines = true;
|
|
|
|
for (var row = startRow; row <= endRow; row++) {
|
|
var range = Range.fromPoints(
|
|
this.session.screenToDocumentPosition(row, startColumn),
|
|
this.session.screenToDocumentPosition(row, endColumn)
|
|
);
|
|
if (range.isEmpty()) {
|
|
if (docEnd && isSamePoint(range.end, docEnd))
|
|
break;
|
|
var docEnd = range.end;
|
|
}
|
|
range.cursor = xBackwards ? range.start : range.end;
|
|
rectSel.push(range);
|
|
}
|
|
|
|
if (yBackwards)
|
|
rectSel.reverse();
|
|
|
|
if (!includeEmptyLines) {
|
|
var end = rectSel.length - 1;
|
|
while (rectSel[end].isEmpty() && end > 0)
|
|
end--;
|
|
if (end > 0) {
|
|
var start = 0;
|
|
while (rectSel[start].isEmpty())
|
|
start++;
|
|
}
|
|
for (var i = end; i >= start; i--) {
|
|
if (rectSel[i].isEmpty())
|
|
rectSel.splice(i, 1);
|
|
}
|
|
}
|
|
|
|
return rectSel;
|
|
};
|
|
}).call(Selection.prototype);
|
|
|
|
// extend Editor
|
|
var Editor = require("./editor").Editor;
|
|
(function() {
|
|
/**
|
|
* Editor.updateSelectionMarkers() -> Void
|
|
*
|
|
* updates cursor and marker layers
|
|
**/
|
|
this.updateSelectionMarkers = function() {
|
|
this.renderer.updateCursor();
|
|
this.renderer.updateBackMarkers();
|
|
};
|
|
|
|
/**
|
|
* Editor.addSelectionMarker(orientedRange) -> Range
|
|
* - orientedRange: range with cursor
|
|
*
|
|
* adds selection and cursor
|
|
**/
|
|
this.addSelectionMarker = function(orientedRange) {
|
|
if (!orientedRange.cursor)
|
|
orientedRange.cursor = orientedRange.end;
|
|
|
|
var style = this.getSelectionStyle();
|
|
orientedRange.marker = this.session.addMarker(orientedRange, "ace_selection", style);
|
|
|
|
this.session.$selectionMarkers.push(orientedRange);
|
|
this.session.selectionMarkerCount = this.session.$selectionMarkers.length;
|
|
return orientedRange;
|
|
};
|
|
|
|
/**
|
|
* Editor.removeSelectionMarker(range) -> Void
|
|
* - range: selection range added with addSelectionMarker
|
|
*
|
|
* removes selection marker
|
|
**/
|
|
this.removeSelectionMarker = function(range) {
|
|
if (!range.marker)
|
|
return;
|
|
this.session.removeMarker(range.marker);
|
|
var index = this.session.$selectionMarkers.indexOf(range);
|
|
if (index != -1)
|
|
this.session.$selectionMarkers.splice(index, 1);
|
|
this.session.selectionMarkerCount = this.session.$selectionMarkers.length;
|
|
};
|
|
|
|
this.removeSelectionMarkers = function(ranges) {
|
|
var markerList = this.session.$selectionMarkers;
|
|
for (var i = ranges.length; i--; ) {
|
|
var range = ranges[i];
|
|
if (!range.marker)
|
|
continue;
|
|
this.session.removeMarker(range.marker);
|
|
var index = markerList.indexOf(range);
|
|
if (index != -1)
|
|
markerList.splice(index, 1);
|
|
}
|
|
this.session.selectionMarkerCount = markerList.length;
|
|
};
|
|
|
|
this.$onAddRange = function(e) {
|
|
this.addSelectionMarker(e.range);
|
|
this.renderer.updateCursor();
|
|
this.renderer.updateBackMarkers();
|
|
};
|
|
|
|
this.$onRemoveRange = function(e) {
|
|
this.removeSelectionMarkers(e.ranges);
|
|
this.renderer.updateCursor();
|
|
this.renderer.updateBackMarkers();
|
|
};
|
|
|
|
this.$onMultiSelect = function(e) {
|
|
if (this.inMultiSelectMode)
|
|
return;
|
|
this.inMultiSelectMode = true;
|
|
|
|
this.setStyle("multiselect");
|
|
this.keyBinding.addKeyboardHandler(exports.commands.keyboardHandler);
|
|
this.commands.on("exec", this.$onMultiSelectExec);
|
|
|
|
this.renderer.updateCursor();
|
|
this.renderer.updateBackMarkers();
|
|
};
|
|
|
|
this.$onSingleSelect = function(e) {
|
|
if (this.session.multiSelect.inVirtualMode)
|
|
return;
|
|
this.inMultiSelectMode = false;
|
|
|
|
this.unsetStyle("multiselect");
|
|
this.keyBinding.removeKeyboardHandler(exports.commands.keyboardHandler);
|
|
|
|
this.commands.removeEventListener("exec", this.$onMultiSelectExec);
|
|
this.renderer.updateCursor();
|
|
this.renderer.updateBackMarkers();
|
|
};
|
|
|
|
this.$onMultiSelectExec = function(e) {
|
|
var command = e.command;
|
|
var editor = e.editor;
|
|
if (!command.multiSelectAction) {
|
|
command.exec(editor, e.args || {});
|
|
editor.multiSelect.addRange(editor.multiSelect.toOrientedRange());
|
|
editor.multiSelect.mergeOverlappingRanges();
|
|
} else if (command.multiSelectAction == "forEach") {
|
|
editor.forEachSelection(command, e.args);
|
|
} else if (command.multiSelectAction == "single") {
|
|
editor.exitMultiSelectMode();
|
|
command.exec(editor, e.args || {});
|
|
} else {
|
|
command.multiSelectAction(editor, e.args || {});
|
|
}
|
|
e.preventDefault();
|
|
};
|
|
|
|
/**
|
|
* Editor.forEachSelection(cmd, args) -> Void
|
|
* - cmd: command to execute
|
|
* - args: arguments to the command
|
|
*
|
|
* executes command for each selection range
|
|
**/
|
|
this.forEachSelection = function(cmd, args) {
|
|
if (this.inVirtualSelectionMode)
|
|
return;
|
|
|
|
var session = this.session;
|
|
var selection = this.selection;
|
|
var rangeList = selection.rangeList;
|
|
|
|
var reg = selection._eventRegistry;
|
|
selection._eventRegistry = {};
|
|
|
|
var tmpSel = new Selection(session);
|
|
this.inVirtualSelectionMode = true;
|
|
for (var i = rangeList.ranges.length; i--;) {
|
|
tmpSel.fromOrientedRange(rangeList.ranges[i]);
|
|
this.selection = session.selection = tmpSel;
|
|
cmd.exec(this, args || {});
|
|
tmpSel.toOrientedRange(rangeList.ranges[i]);
|
|
}
|
|
tmpSel.detach();
|
|
|
|
this.selection = session.selection = selection;
|
|
this.inVirtualSelectionMode = false;
|
|
selection._eventRegistry = reg;
|
|
selection.mergeOverlappingRanges();
|
|
|
|
this.onCursorChange();
|
|
this.onSelectionChange();
|
|
};
|
|
|
|
/**
|
|
* Editor.exitMultiSelectMode() -> Void
|
|
*
|
|
* removes all selections except the last added one.
|
|
**/
|
|
this.exitMultiSelectMode = function() {
|
|
if (this.inVirtualSelectionMode)
|
|
return;
|
|
this.multiSelect.toSingleRange();
|
|
};
|
|
|
|
this.getCopyText = function() {
|
|
var text = "";
|
|
if (this.inMultiSelectMode) {
|
|
var ranges = this.multiSelect.rangeList.ranges;
|
|
text = [];
|
|
for (var i = 0; i < ranges.length; i++) {
|
|
text.push(this.session.getTextRange(ranges[i]));
|
|
}
|
|
text = text.join(this.session.getDocument().getNewLineCharacter());
|
|
} else if (!this.selection.isEmpty()) {
|
|
text = this.session.getTextRange(this.getSelectionRange());
|
|
}
|
|
|
|
return text;
|
|
};
|
|
|
|
/**
|
|
* Editor.findAll(dir, options) -> Number
|
|
* - needle: text to find
|
|
* - options: search options
|
|
* - additive: keeps
|
|
*
|
|
* finds and selects all the occurencies of needle
|
|
* returns number of found ranges
|
|
**/
|
|
this.findAll = function(needle, options, additive) {
|
|
options = options || {};
|
|
options.needle = needle || options.needle;
|
|
this.$search.set(options);
|
|
|
|
var ranges = this.$search.findAll(this.session);
|
|
if (!ranges.length)
|
|
return 0;
|
|
|
|
this.$blockScrolling += 1;
|
|
var selection = this.multiSelect;
|
|
|
|
if (!additive)
|
|
selection.toSingleRange(ranges[0]);
|
|
|
|
for (var i = ranges.length; i--; )
|
|
selection.addRange(ranges[i], true);
|
|
|
|
this.$blockScrolling -= 1;
|
|
|
|
return ranges.length;
|
|
};
|
|
|
|
// commands
|
|
/**
|
|
* Editor.selectMoreLines(dir, skip) -> Void
|
|
* - dir: -1 up, 1 down
|
|
* - skip: remove active selection range if true
|
|
*
|
|
* adds cursor above or bellow active cursor
|
|
**/
|
|
this.selectMoreLines = function(dir, skip) {
|
|
var range = this.selection.toOrientedRange();
|
|
var isBackwards = range.cursor == range.end;
|
|
|
|
var screenLead = this.session.documentToScreenPosition(range.cursor);
|
|
if (this.selection.$desiredColumn)
|
|
screenLead.column = this.selection.$desiredColumn;
|
|
|
|
var lead = this.session.screenToDocumentPosition(screenLead.row + dir, screenLead.column);
|
|
|
|
if (!range.isEmpty()) {
|
|
var screenAnchor = this.session.documentToScreenPosition(isBackwards ? range.end : range.start);
|
|
var anchor = this.session.screenToDocumentPosition(screenAnchor.row + dir, screenAnchor.column);
|
|
} else {
|
|
var anchor = lead;
|
|
}
|
|
|
|
if (isBackwards) {
|
|
var newRange = Range.fromPoints(lead, anchor);
|
|
newRange.cursor = newRange.start;
|
|
} else {
|
|
var newRange = Range.fromPoints(anchor, lead);
|
|
newRange.cursor = newRange.end;
|
|
}
|
|
|
|
newRange.desiredColumn = screenLead.column;
|
|
if (!this.selection.inMultiSelectMode) {
|
|
this.selection.addRange(range);
|
|
} else {
|
|
if (skip)
|
|
var toRemove = range.cursor;
|
|
}
|
|
|
|
this.selection.addRange(newRange);
|
|
if (toRemove)
|
|
this.selection.substractPoint(toRemove);
|
|
};
|
|
|
|
/**
|
|
* Editor.transposeSelections(dir) -> Void
|
|
* - dir: direction to rotate selections
|
|
*
|
|
* contents
|
|
* empty ranges are expanded to word
|
|
**/
|
|
this.transposeSelections = function(dir) {
|
|
var session = this.session;
|
|
var sel = session.multiSelect;
|
|
var all = sel.ranges;
|
|
|
|
for (var i = all.length; i--; ) {
|
|
var range = all[i];
|
|
if (range.isEmpty()) {
|
|
var tmp = session.getWordRange(range.start.row, range.start.column);
|
|
range.start.row = tmp.start.row;
|
|
range.start.column = tmp.start.column;
|
|
range.end.row = tmp.end.row;
|
|
range.end.column = tmp.end.column;
|
|
}
|
|
}
|
|
sel.mergeOverlappingRanges();
|
|
|
|
var words = [];
|
|
for (var i = all.length; i--; ) {
|
|
var range = all[i];
|
|
words.unshift(session.getTextRange(range));
|
|
}
|
|
|
|
if (dir < 0)
|
|
words.unshift(words.pop());
|
|
else
|
|
words.push(words.shift());
|
|
|
|
for (var i = all.length; i--; ) {
|
|
var range = all[i];
|
|
var tmp = range.clone();
|
|
session.replace(range, words[i]);
|
|
range.start.row = tmp.start.row;
|
|
range.start.column = tmp.start.column;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Editor.selectMore(dir, skip) -> Void
|
|
* - dir: 1 next, -1 previous
|
|
* - skip: remove active selection range if true
|
|
*
|
|
* finds next occurence of text in active selection
|
|
* and adds it to the selections
|
|
**/
|
|
this.selectMore = function (dir, skip) {
|
|
var session = this.session;
|
|
var sel = session.multiSelect;
|
|
|
|
var range = sel.toOrientedRange();
|
|
if (range.isEmpty()) {
|
|
var range = session.getWordRange(range.start.row, range.start.column);
|
|
range.cursor = range.end;
|
|
this.multiSelect.addRange(range);
|
|
}
|
|
var needle = session.getTextRange(range);
|
|
|
|
var newRange = find(session, needle, dir);
|
|
if (newRange) {
|
|
newRange.cursor = dir == -1 ? newRange.start : newRange.end;
|
|
this.multiSelect.addRange(newRange);
|
|
}
|
|
if (skip)
|
|
this.multiSelect.substractPoint(range.cursor);
|
|
};
|
|
}).call(Editor.prototype);
|
|
|
|
|
|
function isSamePoint(p1, p2) {
|
|
return p1.row == p2.row && p1.column == p2.column;
|
|
}
|
|
|
|
// patch
|
|
// adds multicursor support to a session
|
|
exports.onSessionChange = function(e) {
|
|
var session = e.session;
|
|
if (!session.multiSelect) {
|
|
session.$selectionMarkers = [];
|
|
session.selection.$initRangeList();
|
|
session.multiSelect = session.selection;
|
|
}
|
|
this.multiSelect = session.multiSelect;
|
|
|
|
var oldSession = e.oldSession;
|
|
if (oldSession) {
|
|
// todo use events
|
|
if (oldSession.multiSelect && oldSession.multiSelect.editor == this)
|
|
oldSession.multiSelect.editor = null;
|
|
|
|
session.multiSelect.removeEventListener("addRange", this.$onAddRange);
|
|
session.multiSelect.removeEventListener("removeRange", this.$onRemoveRange);
|
|
session.multiSelect.removeEventListener("multiSelect", this.$onMultiSelect);
|
|
session.multiSelect.removeEventListener("singleSelect", this.$onSingleSelect);
|
|
}
|
|
|
|
session.multiSelect.on("addRange", this.$onAddRange);
|
|
session.multiSelect.on("removeRange", this.$onRemoveRange);
|
|
session.multiSelect.on("multiSelect", this.$onMultiSelect);
|
|
session.multiSelect.on("singleSelect", this.$onSingleSelect);
|
|
|
|
// this.$onSelectionChange = this.onSelectionChange.bind(this);
|
|
|
|
if (this.inMultiSelectMode != session.selection.inMultiSelectMode) {
|
|
if (session.selection.inMultiSelectMode)
|
|
this.$onMultiSelect();
|
|
else
|
|
this.$onSingleSelect();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* MultiSelect(editor) -> Void
|
|
*
|
|
* adds multiple selection support to the editor
|
|
* (note: should be called only once for each editor instance)
|
|
**/
|
|
function MultiSelect(editor) {
|
|
editor.$onAddRange = editor.$onAddRange.bind(editor);
|
|
editor.$onRemoveRange = editor.$onRemoveRange.bind(editor);
|
|
editor.$onMultiSelect = editor.$onMultiSelect.bind(editor);
|
|
editor.$onSingleSelect = editor.$onSingleSelect.bind(editor);
|
|
|
|
exports.onSessionChange.call(editor, editor);
|
|
editor.on("changeSession", exports.onSessionChange.bind(editor));
|
|
|
|
editor.on("mousedown", onMouseDown);
|
|
editor.commands.addCommands(exports.commands.defaultCommands);
|
|
|
|
addAltCursorListeners(editor);
|
|
}
|
|
|
|
function addAltCursorListeners(editor){
|
|
var el = editor.textInput.getElement();
|
|
var altCursor = false;
|
|
var contentEl = editor.renderer.content;
|
|
el.addEventListener("keydown", function(e) {
|
|
if (e.keyCode == 18 && !(e.ctrlKey || e.shiftKey || e.metaKey)) {
|
|
if (!altCursor) {
|
|
contentEl.style.cursor = "crosshair";
|
|
altCursor = true;
|
|
}
|
|
} else if (altCursor) {
|
|
contentEl.style.cursor = "";
|
|
}
|
|
});
|
|
|
|
el.addEventListener("keyup", reset);
|
|
el.addEventListener("blur", reset);
|
|
function reset() {
|
|
if (altCursor) {
|
|
contentEl.style.cursor = "";
|
|
altCursor = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
exports.MultiSelect = MultiSelect;
|
|
|
|
});
|