diff --git a/browser/devtools/scratchpad/scratchpad.xul b/browser/devtools/scratchpad/scratchpad.xul index d57cdf95c624..b686dbb43095 100644 --- a/browser/devtools/scratchpad/scratchpad.xul +++ b/browser/devtools/scratchpad/scratchpad.xul @@ -24,6 +24,7 @@ - Rob Campbell (original author) - Mihai Sucan - Erik Vold + - Mark Capella - - 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 diff --git a/browser/devtools/sourceeditor/orion/Makefile.dryice.js b/browser/devtools/sourceeditor/orion/Makefile.dryice.js index 552c3e423ca0..9e0fdb5015d4 100755 --- a/browser/devtools/sourceeditor/orion/Makefile.dryice.js +++ b/browser/devtools/sourceeditor/orion/Makefile.dryice.js @@ -53,6 +53,7 @@ copy({ ORION_EDITOR + "/orion/textview/rulers.js", ORION_EDITOR + "/orion/textview/undoStack.js", ORION_EDITOR + "/orion/textview/textModel.js", + ORION_EDITOR + "/orion/textview/projectionTextModel.js", ORION_EDITOR + "/orion/textview/tooltip.js", ORION_EDITOR + "/orion/textview/textView.js", ORION_EDITOR + "/orion/textview/textDND.js", diff --git a/browser/devtools/sourceeditor/orion/README b/browser/devtools/sourceeditor/orion/README index 1d767835c914..c7669099cbfb 100644 --- a/browser/devtools/sourceeditor/orion/README +++ b/browser/devtools/sourceeditor/orion/README @@ -22,6 +22,10 @@ Orion version: git clone from 2012-01-26 http://git.eclipse.org/c/orion/org.eclipse.orion.client.git/commit/?id=27177e9a3dc70c20b4877e3eab3adfff1d56e342 see https://bugs.eclipse.org/bugs/show_bug.cgi?id=370606 + + patch for Mozilla Bug 730532 - remove CSS2Properties aliases for MozOpacity + and MozOutline* + see https://bugzilla.mozilla.org/show_bug.cgi?id=730532#c3 + # License The following files are licensed according to the contents in the LICENSE diff --git a/browser/devtools/sourceeditor/orion/orion.js b/browser/devtools/sourceeditor/orion/orion.js index bd237e73acef..c9643dba7251 100644 --- a/browser/devtools/sourceeditor/orion/orion.js +++ b/browser/devtools/sourceeditor/orion/orion.js @@ -2563,6 +2563,590 @@ define("orion/textview/textModel", ['orion/textview/eventTarget'], function(mEve return {TextModel: TextModel}; });/******************************************************************************* + * @license + * Copyright (c) 2010, 2011 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials are made + * available under the terms of the Eclipse Public License v1.0 + * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution + * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). + * + * Contributors: + * Felipe Heidrich (IBM Corporation) - initial API and implementation + * Silenio Quarti (IBM Corporation) - initial API and implementation + ******************************************************************************/ + +/*global define */ + +define("orion/textview/projectionTextModel", ['orion/textview/textModel', 'orion/textview/eventTarget'], function(mTextModel, mEventTarget) { + + /** + * @class This object represents a projection range. A projection specifies a + * range of text and the replacement text. The range of text is relative to the + * base text model associated to a projection model. + *

+ * See:
+ * {@link orion.textview.ProjectionTextModel}
+ * {@link orion.textview.ProjectionTextModel#addProjection}
+ *

+ * @name orion.textview.Projection + * + * @property {Number} start The start offset of the projection range. + * @property {Number} end The end offset of the projection range. This offset is exclusive. + * @property {String|orion.textview.TextModel} [text=""] The projection text to be inserted + */ + /** + * Constructs a new ProjectionTextModel based on the specified TextModel. + * + * @param {orion.textview.TextModel} baseModel The base text model. + * + * @name orion.textview.ProjectionTextModel + * @class The ProjectionTextModel represents a projection of its base text + * model. Projection ranges can be added to the projection text model to hide and/or insert + * ranges to the base text model. + *

+ * The contents of the projection text model is modified when changes occur in the base model, + * projection model or by calls to {@link #addProjection} and {@link #removeProjection}. + *

+ *

+ * See:
+ * {@link orion.textview.TextView}
+ * {@link orion.textview.TextModel} + * {@link orion.textview.TextView#setModel} + *

+ * @borrows orion.textview.EventTarget#addEventListener as #addEventListener + * @borrows orion.textview.EventTarget#removeEventListener as #removeEventListener + * @borrows orion.textview.EventTarget#dispatchEvent as #dispatchEvent + */ + function ProjectionTextModel(baseModel) { + this._model = baseModel; /* Base Model */ + this._projections = []; + } + + ProjectionTextModel.prototype = /** @lends orion.textview.ProjectionTextModel.prototype */ { + /** + * Adds a projection range to the model. + *

+ * The model must notify the listeners before and after the the text is + * changed by calling {@link #onChanging} and {@link #onChanged} respectively. + *

+ * @param {orion.textview.Projection} projection The projection range to be added. + * + * @see #removeProjection + */ + addProjection: function(projection) { + if (!projection) {return;} + //start and end can't overlap any exist projection + var model = this._model, projections = this._projections; + projection._lineIndex = model.getLineAtOffset(projection.start); + projection._lineCount = model.getLineAtOffset(projection.end) - projection._lineIndex; + var text = projection.text; + if (!text) { text = ""; } + if (typeof text === "string") { + projection._model = new mTextModel.TextModel(text, model.getLineDelimiter()); + } else { + projection._model = text; + } + var eventStart = this.mapOffset(projection.start, true); + var removedCharCount = projection.end - projection.start; + var removedLineCount = projection._lineCount; + var addedCharCount = projection._model.getCharCount(); + var addedLineCount = projection._model.getLineCount() - 1; + var modelChangingEvent = { + type: "Changing", + text: projection._model.getText(), + start: eventStart, + removedCharCount: removedCharCount, + addedCharCount: addedCharCount, + removedLineCount: removedLineCount, + addedLineCount: addedLineCount + }; + this.onChanging(modelChangingEvent); + var index = this._binarySearch(projections, projection.start); + projections.splice(index, 0, projection); + var modelChangedEvent = { + type: "Changed", + start: eventStart, + removedCharCount: removedCharCount, + addedCharCount: addedCharCount, + removedLineCount: removedLineCount, + addedLineCount: addedLineCount + }; + this.onChanged(modelChangedEvent); + }, + /** + * Returns all projection ranges of this model. + * + * @return {orion.textview.Projection[]} The projection ranges. + * + * @see #addProjection + */ + getProjections: function() { + return this._projections.slice(0); + }, + /** + * Gets the base text model. + * + * @return {orion.textview.TextModel} The base text model. + */ + getBaseModel: function() { + return this._model; + }, + /** + * Maps offsets between the projection model and its base model. + * + * @param {Number} offset The offset to be mapped. + * @param {Boolean} [baseOffset=false] true if offset is in base model and + * should be mapped to the projection model. + * @return {Number} The mapped offset + */ + mapOffset: function(offset, baseOffset) { + var projections = this._projections, delta = 0, i, projection; + if (baseOffset) { + for (i = 0; i < projections.length; i++) { + projection = projections[i]; + if (projection.start > offset) { break; } + if (projection.end > offset) { return -1; } + delta += projection._model.getCharCount() - (projection.end - projection.start); + } + return offset + delta; + } + for (i = 0; i < projections.length; i++) { + projection = projections[i]; + if (projection.start > offset - delta) { break; } + var charCount = projection._model.getCharCount(); + if (projection.start + charCount > offset - delta) { + return -1; + } + delta += charCount - (projection.end - projection.start); + } + return offset - delta; + }, + /** + * Removes a projection range from the model. + *

+ * The model must notify the listeners before and after the the text is + * changed by calling {@link #onChanging} and {@link #onChanged} respectively. + *

+ * + * @param {orion.textview.Projection} projection The projection range to be removed. + * + * @see #addProjection + */ + removeProjection: function(projection) { + //TODO remove listeners from model + var i, delta = 0; + for (i = 0; i < this._projections.length; i++) { + var p = this._projections[i]; + if (p === projection) { + projection = p; + break; + } + delta += p._model.getCharCount() - (p.end - p.start); + } + if (i < this._projections.length) { + var model = this._model; + var eventStart = projection.start + delta; + var addedCharCount = projection.end - projection.start; + var addedLineCount = projection._lineCount; + var removedCharCount = projection._model.getCharCount(); + var removedLineCount = projection._model.getLineCount() - 1; + var modelChangingEvent = { + type: "Changing", + text: model.getText(projection.start, projection.end), + start: eventStart, + removedCharCount: removedCharCount, + addedCharCount: addedCharCount, + removedLineCount: removedLineCount, + addedLineCount: addedLineCount + }; + this.onChanging(modelChangingEvent); + this._projections.splice(i, 1); + var modelChangedEvent = { + type: "Changed", + start: eventStart, + removedCharCount: removedCharCount, + addedCharCount: addedCharCount, + removedLineCount: removedLineCount, + addedLineCount: addedLineCount + }; + this.onChanged(modelChangedEvent); + } + }, + /** @ignore */ + _binarySearch: function (array, offset) { + var high = array.length, low = -1, index; + while (high - low > 1) { + index = Math.floor((high + low) / 2); + if (offset <= array[index].start) { + high = index; + } else { + low = index; + } + } + return high; + }, + /** + * @see orion.textview.TextModel#getCharCount + */ + getCharCount: function() { + var count = this._model.getCharCount(), projections = this._projections; + for (var i = 0; i < projections.length; i++) { + var projection = projections[i]; + count += projection._model.getCharCount() - (projection.end - projection.start); + } + return count; + }, + /** + * @see orion.textview.TextModel#getLine + */ + getLine: function(lineIndex, includeDelimiter) { + if (lineIndex < 0) { return null; } + var model = this._model, projections = this._projections; + var delta = 0, result = [], offset = 0, i, lineCount, projection; + for (i = 0; i < projections.length; i++) { + projection = projections[i]; + if (projection._lineIndex >= lineIndex - delta) { break; } + lineCount = projection._model.getLineCount() - 1; + if (projection._lineIndex + lineCount >= lineIndex - delta) { + var projectionLineIndex = lineIndex - (projection._lineIndex + delta); + if (projectionLineIndex < lineCount) { + return projection._model.getLine(projectionLineIndex, includeDelimiter); + } else { + result.push(projection._model.getLine(lineCount)); + } + } + offset = projection.end; + delta += lineCount - projection._lineCount; + } + offset = Math.max(offset, model.getLineStart(lineIndex - delta)); + for (; i < projections.length; i++) { + projection = projections[i]; + if (projection._lineIndex > lineIndex - delta) { break; } + result.push(model.getText(offset, projection.start)); + lineCount = projection._model.getLineCount() - 1; + if (projection._lineIndex + lineCount > lineIndex - delta) { + result.push(projection._model.getLine(0, includeDelimiter)); + return result.join(""); + } + result.push(projection._model.getText()); + offset = projection.end; + delta += lineCount - projection._lineCount; + } + var end = model.getLineEnd(lineIndex - delta, includeDelimiter); + if (offset < end) { + result.push(model.getText(offset, end)); + } + return result.join(""); + }, + /** + * @see orion.textview.TextModel#getLineAtOffset + */ + getLineAtOffset: function(offset) { + var model = this._model, projections = this._projections; + var delta = 0, lineDelta = 0; + for (var i = 0; i < projections.length; i++) { + var projection = projections[i]; + if (projection.start > offset - delta) { break; } + var charCount = projection._model.getCharCount(); + if (projection.start + charCount > offset - delta) { + var projectionOffset = offset - (projection.start + delta); + lineDelta += projection._model.getLineAtOffset(projectionOffset); + delta += projectionOffset; + break; + } + lineDelta += projection._model.getLineCount() - 1 - projection._lineCount; + delta += charCount - (projection.end - projection.start); + } + return model.getLineAtOffset(offset - delta) + lineDelta; + }, + /** + * @see orion.textview.TextModel#getLineCount + */ + getLineCount: function() { + var model = this._model, projections = this._projections; + var count = model.getLineCount(); + for (var i = 0; i < projections.length; i++) { + var projection = projections[i]; + count += projection._model.getLineCount() - 1 - projection._lineCount; + } + return count; + }, + /** + * @see orion.textview.TextModel#getLineDelimiter + */ + getLineDelimiter: function() { + return this._model.getLineDelimiter(); + }, + /** + * @see orion.textview.TextModel#getLineEnd + */ + getLineEnd: function(lineIndex, includeDelimiter) { + if (lineIndex < 0) { return -1; } + var model = this._model, projections = this._projections; + var delta = 0, offsetDelta = 0; + for (var i = 0; i < projections.length; i++) { + var projection = projections[i]; + if (projection._lineIndex > lineIndex - delta) { break; } + var lineCount = projection._model.getLineCount() - 1; + if (projection._lineIndex + lineCount > lineIndex - delta) { + var projectionLineIndex = lineIndex - (projection._lineIndex + delta); + return projection._model.getLineEnd (projectionLineIndex, includeDelimiter) + projection.start + offsetDelta; + } + offsetDelta += projection._model.getCharCount() - (projection.end - projection.start); + delta += lineCount - projection._lineCount; + } + return model.getLineEnd(lineIndex - delta, includeDelimiter) + offsetDelta; + }, + /** + * @see orion.textview.TextModel#getLineStart + */ + getLineStart: function(lineIndex) { + if (lineIndex < 0) { return -1; } + var model = this._model, projections = this._projections; + var delta = 0, offsetDelta = 0; + for (var i = 0; i < projections.length; i++) { + var projection = projections[i]; + if (projection._lineIndex >= lineIndex - delta) { break; } + var lineCount = projection._model.getLineCount() - 1; + if (projection._lineIndex + lineCount >= lineIndex - delta) { + var projectionLineIndex = lineIndex - (projection._lineIndex + delta); + return projection._model.getLineStart (projectionLineIndex) + projection.start + offsetDelta; + } + offsetDelta += projection._model.getCharCount() - (projection.end - projection.start); + delta += lineCount - projection._lineCount; + } + return model.getLineStart(lineIndex - delta) + offsetDelta; + }, + /** + * @see orion.textview.TextModel#getText + */ + getText: function(start, end) { + if (start === undefined) { start = 0; } + var model = this._model, projections = this._projections; + var delta = 0, result = [], i, projection, charCount; + for (i = 0; i < projections.length; i++) { + projection = projections[i]; + if (projection.start > start - delta) { break; } + charCount = projection._model.getCharCount(); + if (projection.start + charCount > start - delta) { + if (end !== undefined && projection.start + charCount > end - delta) { + return projection._model.getText(start - (projection.start + delta), end - (projection.start + delta)); + } else { + result.push(projection._model.getText(start - (projection.start + delta))); + start = projection.end + delta + charCount - (projection.end - projection.start); + } + } + delta += charCount - (projection.end - projection.start); + } + var offset = start - delta; + if (end !== undefined) { + for (; i < projections.length; i++) { + projection = projections[i]; + if (projection.start > end - delta) { break; } + result.push(model.getText(offset, projection.start)); + charCount = projection._model.getCharCount(); + if (projection.start + charCount > end - delta) { + result.push(projection._model.getText(0, end - (projection.start + delta))); + return result.join(""); + } + result.push(projection._model.getText()); + offset = projection.end; + delta += charCount - (projection.end - projection.start); + } + result.push(model.getText(offset, end - delta)); + } else { + for (; i < projections.length; i++) { + projection = projections[i]; + result.push(model.getText(offset, projection.start)); + result.push(projection._model.getText()); + offset = projection.end; + } + result.push(model.getText(offset)); + } + return result.join(""); + }, + /** @ignore */ + _onChanging: function(text, start, removedCharCount, addedCharCount, removedLineCount, addedLineCount) { + var model = this._model, projections = this._projections, i, projection, delta = 0, lineDelta; + var end = start + removedCharCount; + for (; i < projections.length; i++) { + projection = projections[i]; + if (projection.start > start) { break; } + delta += projection._model.getCharCount() - (projection.end - projection.start); + } + /*TODO add stuff saved by setText*/ + var mapStart = start + delta, rangeStart = i; + for (; i < projections.length; i++) { + projection = projections[i]; + if (projection.start > end) { break; } + delta += projection._model.getCharCount() - (projection.end - projection.start); + lineDelta += projection._model.getLineCount() - 1 - projection._lineCount; + } + /*TODO add stuff saved by setText*/ + var mapEnd = end + delta, rangeEnd = i; + this.onChanging(mapStart, mapEnd - mapStart, addedCharCount/*TODO add stuff saved by setText*/, removedLineCount + lineDelta/*TODO add stuff saved by setText*/, addedLineCount/*TODO add stuff saved by setText*/); + projections.splice(projections, rangeEnd - rangeStart); + var count = text.length - (mapEnd - mapStart); + for (; i < projections.length; i++) { + projection = projections[i]; + projection.start += count; + projection.end += count; + projection._lineIndex = model.getLineAtOffset(projection.start); + } + }, + /** + * @see orion.textview.TextModel#onChanging + */ + onChanging: function(modelChangingEvent) { + return this.dispatchEvent(modelChangingEvent); + }, + /** + * @see orion.textview.TextModel#onChanged + */ + onChanged: function(modelChangedEvent) { + return this.dispatchEvent(modelChangedEvent); + }, + /** + * @see orion.textview.TextModel#setLineDelimiter + */ + setLineDelimiter: function(lineDelimiter) { + this._model.setLineDelimiter(lineDelimiter); + }, + /** + * @see orion.textview.TextModel#setText + */ + setText: function(text, start, end) { + if (text === undefined) { text = ""; } + if (start === undefined) { start = 0; } + var eventStart = start, eventEnd = end; + var model = this._model, projections = this._projections; + var delta = 0, lineDelta = 0, i, projection, charCount, startProjection, endProjection, startLineDelta = 0; + for (i = 0; i < projections.length; i++) { + projection = projections[i]; + if (projection.start > start - delta) { break; } + charCount = projection._model.getCharCount(); + if (projection.start + charCount > start - delta) { + if (end !== undefined && projection.start + charCount > end - delta) { + projection._model.setText(text, start - (projection.start + delta), end - (projection.start + delta)); + //TODO events - special case + return; + } else { + startLineDelta = projection._model.getLineCount() - 1 - projection._model.getLineAtOffset(start - (projection.start + delta)); + startProjection = { + projection: projection, + start: start - (projection.start + delta) + }; + start = projection.end + delta + charCount - (projection.end - projection.start); + } + } + lineDelta += projection._model.getLineCount() - 1 - projection._lineCount; + delta += charCount - (projection.end - projection.start); + } + var mapStart = start - delta, rangeStart = i, startLine = model.getLineAtOffset(mapStart) + lineDelta - startLineDelta; + if (end !== undefined) { + for (; i < projections.length; i++) { + projection = projections[i]; + if (projection.start > end - delta) { break; } + charCount = projection._model.getCharCount(); + if (projection.start + charCount > end - delta) { + lineDelta += projection._model.getLineAtOffset(end - (projection.start + delta)); + charCount = end - (projection.start + delta); + end = projection.end + delta; + endProjection = { + projection: projection, + end: charCount + }; + break; + } + lineDelta += projection._model.getLineCount() - 1 - projection._lineCount; + delta += charCount - (projection.end - projection.start); + } + } else { + for (; i < projections.length; i++) { + projection = projections[i]; + lineDelta += projection._model.getLineCount() - 1 - projection._lineCount; + delta += projection._model.getCharCount() - (projection.end - projection.start); + } + end = eventEnd = model.getCharCount() + delta; + } + var mapEnd = end - delta, rangeEnd = i, endLine = model.getLineAtOffset(mapEnd) + lineDelta; + + //events + var removedCharCount = eventEnd - eventStart; + var removedLineCount = endLine - startLine; + var addedCharCount = text.length; + var addedLineCount = 0; + var cr = 0, lf = 0, index = 0; + while (true) { + if (cr !== -1 && cr <= index) { cr = text.indexOf("\r", index); } + if (lf !== -1 && lf <= index) { lf = text.indexOf("\n", index); } + if (lf === -1 && cr === -1) { break; } + if (cr !== -1 && lf !== -1) { + if (cr + 1 === lf) { + index = lf + 1; + } else { + index = (cr < lf ? cr : lf) + 1; + } + } else if (cr !== -1) { + index = cr + 1; + } else { + index = lf + 1; + } + addedLineCount++; + } + + var modelChangingEvent = { + type: "Changing", + text: text, + start: eventStart, + removedCharCount: removedCharCount, + addedCharCount: addedCharCount, + removedLineCount: removedLineCount, + addedLineCount: addedLineCount + }; + this.onChanging(modelChangingEvent); + +// var changeLineCount = model.getLineAtOffset(mapEnd) - model.getLineAtOffset(mapStart) + addedLineCount; + model.setText(text, mapStart, mapEnd); + if (startProjection) { + projection = startProjection.projection; + projection._model.setText("", startProjection.start); + } + if (endProjection) { + projection = endProjection.projection; + projection._model.setText("", 0, endProjection.end); + projection.start = projection.end; + projection._lineCount = 0; + } + projections.splice(rangeStart, rangeEnd - rangeStart); + var changeCount = text.length - (mapEnd - mapStart); + for (i = rangeEnd; i < projections.length; i++) { + projection = projections[i]; + projection.start += changeCount; + projection.end += changeCount; +// if (projection._lineIndex + changeLineCount !== model.getLineAtOffset(projection.start)) { +// log("here"); +// } + projection._lineIndex = model.getLineAtOffset(projection.start); +// projection._lineIndex += changeLineCount; + } + + var modelChangedEvent = { + type: "Changed", + start: eventStart, + removedCharCount: removedCharCount, + addedCharCount: addedCharCount, + removedLineCount: removedLineCount, + addedLineCount: addedLineCount + }; + this.onChanged(modelChangedEvent); + } + }; + mEventTarget.EventTarget.addMixin(ProjectionTextModel.prototype); + + return {ProjectionTextModel: ProjectionTextModel}; +}); +/******************************************************************************* * @license * Copyright (c) 2010, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials are made diff --git a/browser/devtools/sourceeditor/source-editor-orion.jsm b/browser/devtools/sourceeditor/source-editor-orion.jsm index fa0408c7c3ce..e4d78b884135 100644 --- a/browser/devtools/sourceeditor/source-editor-orion.jsm +++ b/browser/devtools/sourceeditor/source-editor-orion.jsm @@ -908,7 +908,8 @@ SourceEditor.prototype = { * * @private * @param string aType - * The annotation type to filter annotations for. + * The annotation type to filter annotations for. Use one of the keys + * in ORION_ANNOTATION_TYPES. * @param number aStart * Offset from where to start finding the annotations. * @param number aEnd diff --git a/browser/devtools/sourceeditor/source-editor.jsm b/browser/devtools/sourceeditor/source-editor.jsm index 3f1598012566..54dde40b66c0 100644 --- a/browser/devtools/sourceeditor/source-editor.jsm +++ b/browser/devtools/sourceeditor/source-editor.jsm @@ -268,24 +268,24 @@ SourceEditor.EVENTS = { BLUR: "Blur", /** - * The MouseMove event is sent when the user moves the mouse over a line - * annotation. The event object properties: + * The MouseMove event is sent when the user moves the mouse over a line. + * The event object properties: * - event - the DOM mousemove event object. * - x and y - the mouse coordinates relative to the document being edited. */ MOUSE_MOVE: "MouseMove", /** - * The MouseOver event is sent when the mouse pointer enters a line - * annotation. The event object properties: + * The MouseOver event is sent when the mouse pointer enters a line. + * The event object properties: * - event - the DOM mouseover event object. * - x and y - the mouse coordinates relative to the document being edited. */ MOUSE_OVER: "MouseOver", /** - * This MouseOut event is sent when the mouse pointer exits a line - * annotation. The event object properties: + * This MouseOut event is sent when the mouse pointer exits a line. + * The event object properties: * - event - the DOM mouseout event object. * - x and y - the mouse coordinates relative to the document being edited. */