| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- /* ***** BEGIN LICENSE BLOCK *****
- * Distributed under the BSD license:
- *
- * Copyright (c) 2010, Ajax.org B.V.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Ajax.org B.V. nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * ***** END LICENSE BLOCK ***** */
- define(function(require, exports, module) {
- "use strict";
- var Range = require("./range").Range;
- var EventEmitter = require("./lib/event_emitter").EventEmitter;
- var oop = require("./lib/oop");
- /**
- * @class PlaceHolder
- *
- **/
- /**
- * - session (Document): The document to associate with the anchor
- * - length (Number): The starting row position
- * - pos (Number): The starting column position
- * - others (String):
- * - mainClass (String):
- * - othersClass (String):
- *
- * @constructor
- **/
- var PlaceHolder = function(session, length, pos, others, mainClass, othersClass) {
- var _self = this;
- this.length = length;
- this.session = session;
- this.doc = session.getDocument();
- this.mainClass = mainClass;
- this.othersClass = othersClass;
- this.$onUpdate = this.onUpdate.bind(this);
- this.doc.on("change", this.$onUpdate);
- this.$others = others;
-
- this.$onCursorChange = function() {
- setTimeout(function() {
- _self.onCursorChange();
- });
- };
-
- this.$pos = pos;
- // Used for reset
- var undoStack = session.getUndoManager().$undoStack || session.getUndoManager().$undostack || {length: -1};
- this.$undoStackDepth = undoStack.length;
- this.setup();
- session.selection.on("changeCursor", this.$onCursorChange);
- };
- (function() {
- oop.implement(this, EventEmitter);
- /**
- * PlaceHolder.setup()
- *
- * TODO
- *
- **/
- this.setup = function() {
- var _self = this;
- var doc = this.doc;
- var session = this.session;
- var pos = this.$pos;
-
- this.selectionBefore = session.selection.toJSON();
- if (session.selection.inMultiSelectMode)
- session.selection.toSingleRange();
- this.pos = doc.createAnchor(pos.row, pos.column);
- this.markerId = session.addMarker(new Range(pos.row, pos.column, pos.row, pos.column + this.length), this.mainClass, null, false);
- this.pos.on("change", function(event) {
- session.removeMarker(_self.markerId);
- _self.markerId = session.addMarker(new Range(event.value.row, event.value.column, event.value.row, event.value.column+_self.length), _self.mainClass, null, false);
- });
- this.others = [];
- this.$others.forEach(function(other) {
- var anchor = doc.createAnchor(other.row, other.column);
- _self.others.push(anchor);
- });
- session.setUndoSelect(false);
- };
-
- /**
- * PlaceHolder.showOtherMarkers()
- *
- * TODO
- *
- **/
- this.showOtherMarkers = function() {
- if(this.othersActive) return;
- var session = this.session;
- var _self = this;
- this.othersActive = true;
- this.others.forEach(function(anchor) {
- anchor.markerId = session.addMarker(new Range(anchor.row, anchor.column, anchor.row, anchor.column+_self.length), _self.othersClass, null, false);
- anchor.on("change", function(event) {
- session.removeMarker(anchor.markerId);
- anchor.markerId = session.addMarker(new Range(event.value.row, event.value.column, event.value.row, event.value.column+_self.length), _self.othersClass, null, false);
- });
- });
- };
-
- /**
- * PlaceHolder.hideOtherMarkers()
- *
- * Hides all over markers in the [[EditSession `EditSession`]] that are not the currently selected one.
- *
- **/
- this.hideOtherMarkers = function() {
- if(!this.othersActive) return;
- this.othersActive = false;
- for (var i = 0; i < this.others.length; i++) {
- this.session.removeMarker(this.others[i].markerId);
- }
- };
- /**
- * PlaceHolder@onUpdate(e)
- *
- * Emitted when the place holder updates.
- *
- **/
- this.onUpdate = function(delta) {
- var range = delta;
- if(range.start.row !== range.end.row) return;
- if(range.start.row !== this.pos.row) return;
- if (this.$updating) return;
- this.$updating = true;
- var lengthDiff = delta.action === "insert" ? range.end.column - range.start.column : range.start.column - range.end.column;
-
- if(range.start.column >= this.pos.column && range.start.column <= this.pos.column + this.length + 1) {
- var distanceFromStart = range.start.column - this.pos.column;
- this.length += lengthDiff;
- if(!this.session.$fromUndo) {
- if(delta.action === 'insert') {
- for (var i = this.others.length - 1; i >= 0; i--) {
- var otherPos = this.others[i];
- var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart};
- if(otherPos.row === range.start.row && range.start.column < otherPos.column)
- newPos.column += lengthDiff;
- this.doc.insertMergedLines(newPos, delta.lines);
- }
- } else if(delta.action === 'remove') {
- for (var i = this.others.length - 1; i >= 0; i--) {
- var otherPos = this.others[i];
- var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart};
- if(otherPos.row === range.start.row && range.start.column < otherPos.column)
- newPos.column += lengthDiff;
- this.doc.remove(new Range(newPos.row, newPos.column, newPos.row, newPos.column - lengthDiff));
- }
- }
- // Special case: insert in beginning
- if(range.start.column === this.pos.column && delta.action === 'insert') {
- setTimeout(function() {
- this.pos.setPosition(this.pos.row, this.pos.column - lengthDiff);
- for (var i = 0; i < this.others.length; i++) {
- var other = this.others[i];
- var newPos = {row: other.row, column: other.column - lengthDiff};
- if(other.row === range.start.row && range.start.column < other.column)
- newPos.column += lengthDiff;
- other.setPosition(newPos.row, newPos.column);
- }
- }.bind(this), 0);
- }
- else if(range.start.column === this.pos.column && delta.action === 'remove') {
- setTimeout(function() {
- for (var i = 0; i < this.others.length; i++) {
- var other = this.others[i];
- if(other.row === range.start.row && range.start.column < other.column) {
- other.setPosition(other.row, other.column - lengthDiff);
- }
- }
- }.bind(this), 0);
- }
- }
- this.pos._emit("change", {value: this.pos});
- for (var i = 0; i < this.others.length; i++) {
- this.others[i]._emit("change", {value: this.others[i]});
- }
- }
- this.$updating = false;
- };
-
- /**
- * PlaceHolder@onCursorChange(e)
- *
- * Emitted when the cursor changes.
- *
- **/
- this.onCursorChange = function(event) {
- if (this.$updating || !this.session) return;
- var pos = this.session.selection.getCursor();
- if (pos.row === this.pos.row && pos.column >= this.pos.column && pos.column <= this.pos.column + this.length) {
- this.showOtherMarkers();
- this._emit("cursorEnter", event);
- } else {
- this.hideOtherMarkers();
- this._emit("cursorLeave", event);
- }
- };
-
- /**
- * PlaceHolder.detach()
- *
- * TODO
- *
- **/
- this.detach = function() {
- this.session.removeMarker(this.markerId);
- this.hideOtherMarkers();
- this.doc.removeEventListener("change", this.$onUpdate);
- this.session.selection.removeEventListener("changeCursor", this.$onCursorChange);
- this.pos.detach();
- for (var i = 0; i < this.others.length; i++) {
- this.others[i].detach();
- }
- this.session.setUndoSelect(true);
- this.session = null;
- };
-
- /**
- * PlaceHolder.cancel()
- *
- * TODO
- *
- **/
- this.cancel = function() {
- if(this.$undoStackDepth === -1)
- throw Error("Canceling placeholders only supported with undo manager attached to session.");
- var undoManager = this.session.getUndoManager();
- var undosRequired = (undoManager.$undoStack || undoManager.$undostack).length - this.$undoStackDepth;
- for (var i = 0; i < undosRequired; i++) {
- undoManager.undo(true);
- }
- if (this.selectionBefore)
- this.session.selection.fromJSON(this.selectionBefore);
- };
- }).call(PlaceHolder.prototype);
- exports.PlaceHolder = PlaceHolder;
- });
|