Bug 707987 - Ability to set breakpoints in the Source Editor (orion); r=rcampbell f=past

This commit is contained in:
Mihai Sucan 2012-02-18 12:58:54 +02:00
parent 05ae442701
commit bf2bd25595
24 changed files with 956 additions and 92 deletions

View File

@ -806,7 +806,7 @@ var Scratchpad = {
let config = {
mode: SourceEditor.MODES.JAVASCRIPT,
showLineNumbers: true,
placeholderText: initialText
initialText: initialText,
};
let editorPlaceholder = document.getElementById("scratchpad-editor");

View File

@ -54,6 +54,8 @@ XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
const ORION_SCRIPT = "chrome://browser/content/orion.js";
const ORION_IFRAME = "data:text/html;charset=utf8,<!DOCTYPE html>" +
"<html style='height:100%' dir='ltr'>" +
"<head><link rel='stylesheet'" +
" href='chrome://browser/skin/devtools/orion-container.css'></head>" +
"<body style='height:100%;margin:0;overflow:hidden'>" +
"<div id='editor' style='height:100%'></div>" +
"</body></html>";
@ -69,8 +71,8 @@ const ORION_THEMES = {
};
/**
* Known editor events you can listen for. This object maps SourceEditor.EVENTS
* to Orion events.
* Known Orion editor events you can listen for. This object maps several of the
* SourceEditor.EVENTS to Orion events.
*/
const ORION_EVENTS = {
ContextMenu: "ContextMenu",
@ -89,6 +91,8 @@ const ORION_EVENTS = {
const ORION_ANNOTATION_TYPES = {
currentBracket: "orion.annotation.currentBracket",
matchingBracket: "orion.annotation.matchingBracket",
breakpoint: "orion.annotation.breakpoint",
task: "orion.annotation.task",
};
/**
@ -127,13 +131,15 @@ var EXPORTED_SYMBOLS = ["SourceEditor"];
function SourceEditor() {
// Update the SourceEditor defaults from user preferences.
SourceEditor.DEFAULTS.TAB_SIZE =
SourceEditor.DEFAULTS.tabSize =
Services.prefs.getIntPref(SourceEditor.PREFS.TAB_SIZE);
SourceEditor.DEFAULTS.EXPAND_TAB =
SourceEditor.DEFAULTS.expandTab =
Services.prefs.getBoolPref(SourceEditor.PREFS.EXPAND_TAB);
this._onOrionSelection = this._onOrionSelection.bind(this);
this._eventTarget = {};
this._eventListenersQueue = [];
this.ui = new SourceEditorUI(this);
}
@ -143,6 +149,8 @@ SourceEditor.prototype = {
_model: null,
_undoStack: null,
_linesRuler: null,
_annotationRuler: null,
_overviewRuler: null,
_styler: null,
_annotationStyler: null,
_annotationModel: null,
@ -151,6 +159,8 @@ SourceEditor.prototype = {
_expandTab: null,
_tabSize: null,
_iframeWindow: null,
_eventTarget: null,
_eventListenersQueue: null,
/**
* The Source Editor user interface manager.
@ -171,30 +181,12 @@ SourceEditor.prototype = {
* @param nsIDOMElement aElement
* The DOM element where you want the editor to show.
* @param object aConfig
* Editor configuration object. Properties:
* - placeholderText - the text you want to be shown by default.
* - theme - the syntax highlighting theme you want. You can use one
* of the predefined themes, or you can point to your CSS file.
* - mode - the editor mode, based on the file type you want to edit.
* You can use one of the predefined modes.
* - tabSize - define how many spaces to use for a tab character.
* - expandTab - tells if you want tab characters to be expanded to
* spaces.
* - readOnly - make the editor read only.
* - showLineNumbers - display the line numbers gutter.
* - undoLimit - how many steps should the undo stack hold.
* - keys - is an array of objects that allows you to define custom
* editor keyboard bindings. Each object can have:
* - action - name of the editor action to invoke.
* - code - keyCode for the shortcut.
* - accel - boolean for the Accel key (cmd/ctrl).
* - shift - boolean for the Shift key.
* - alt - boolean for the Alt key.
* - callback - optional function to invoke, if the action is not
* predefined in the editor.
* Editor configuration object. See SourceEditor.DEFAULTS for the
* available configuration options.
* @param function [aCallback]
* Function you want to execute once the editor is loaded and
* initialized.
* @see SourceEditor.DEFAULTS
*/
init: function SE_init(aElement, aConfig, aCallback)
{
@ -218,7 +210,21 @@ SourceEditor.prototype = {
aElement.appendChild(this._iframe);
this.parentElement = aElement;
this._config = aConfig;
this._config = {};
for (let key in SourceEditor.DEFAULTS) {
this._config[key] = key in aConfig ?
aConfig[key] :
SourceEditor.DEFAULTS[key];
}
// TODO: Bug 725677 - Remove the deprecated placeholderText option from the
// Source Editor initialization.
if (aConfig.placeholderText) {
this._config.initialText = aConfig.placeholderText;
Services.console.logStringMessage("SourceEditor.init() was called with the placeholderText option which is deprecated, please use initialText.");
}
this._onReadyCallback = aCallback;
this.ui.init();
},
@ -238,14 +244,13 @@ SourceEditor.prototype = {
let TextModel = window.require("orion/textview/textModel").TextModel;
let TextView = window.require("orion/textview/textView").TextView;
this._expandTab = typeof config.expandTab != "undefined" ?
config.expandTab : SourceEditor.DEFAULTS.EXPAND_TAB;
this._tabSize = config.tabSize || SourceEditor.DEFAULTS.TAB_SIZE;
this._expandTab = config.expandTab;
this._tabSize = config.tabSize;
let theme = config.theme || SourceEditor.DEFAULTS.THEME;
let theme = config.theme;
let stylesheet = theme in ORION_THEMES ? ORION_THEMES[theme] : theme;
this._model = new TextModel(config.placeholderText);
this._model = new TextModel(config.initialText);
this._view = new TextView({
model: this._model,
parent: "editor",
@ -268,24 +273,56 @@ SourceEditor.prototype = {
let KeyBinding = window.require("orion/textview/keyBinding").KeyBinding;
let TextDND = window.require("orion/textview/textDND").TextDND;
let LineNumberRuler = window.require("orion/textview/rulers").LineNumberRuler;
let Rulers = window.require("orion/textview/rulers");
let LineNumberRuler = Rulers.LineNumberRuler;
let AnnotationRuler = Rulers.AnnotationRuler;
let OverviewRuler = Rulers.OverviewRuler;
let UndoStack = window.require("orion/textview/undoStack").UndoStack;
let AnnotationModel = window.require("orion/textview/annotations").AnnotationModel;
this._annotationModel = new AnnotationModel(this._model);
if (config.showAnnotationRuler) {
this._annotationRuler = new AnnotationRuler(this._annotationModel, "left",
{styleClass: "ruler annotations"});
this._annotationRuler.onClick = this._annotationRulerClick.bind(this);
this._annotationRuler.addAnnotationType(ORION_ANNOTATION_TYPES.breakpoint);
this._annotationRuler.setMultiAnnotation({
html: "<div class='annotationHTML multiple'></div>"
});
this._annotationRuler.setMultiAnnotationOverlay({
html: "<div class='annotationHTML overlay'></div>"
});
this._view.addRuler(this._annotationRuler);
}
if (config.showLineNumbers) {
let rulerClass = this._annotationRuler ?
"ruler lines linesWithAnnotations" :
"ruler lines";
this._linesRuler = new LineNumberRuler(this._annotationModel, "left",
{styleClass: "rulerLines"}, {styleClass: "rulerLine odd"},
{styleClass: "rulerLine even"});
{styleClass: rulerClass}, {styleClass: "rulerLines odd"},
{styleClass: "rulerLines even"});
this._view.addRuler(this._linesRuler);
}
this.setMode(config.mode || SourceEditor.DEFAULTS.MODE);
if (config.showOverviewRuler) {
this._overviewRuler = new OverviewRuler(this._annotationModel, "right",
{styleClass: "ruler overview"});
this._overviewRuler.onClick = this._overviewRulerClick.bind(this);
this._undoStack = new UndoStack(this._view,
config.undoLimit || SourceEditor.DEFAULTS.UNDO_LIMIT);
this._overviewRuler.addAnnotationType(ORION_ANNOTATION_TYPES.matchingBracket);
this._overviewRuler.addAnnotationType(ORION_ANNOTATION_TYPES.currentBracket);
this._overviewRuler.addAnnotationType(ORION_ANNOTATION_TYPES.breakpoint);
this._overviewRuler.addAnnotationType(ORION_ANNOTATION_TYPES.task);
this._view.addRuler(this._overviewRuler);
}
this.setMode(config.mode);
this._undoStack = new UndoStack(this._view, config.undoLimit);
this._dragAndDrop = new TextDND(this._view, this._undoStack);
@ -315,6 +352,43 @@ SourceEditor.prototype = {
this._view.setAction(aKey.action, aKey.callback);
}
}, this);
this._initEventTarget();
},
/**
* Initialize the private Orion EventTarget object. This is used for tracking
* our own event listeners for events outside of Orion's scope.
* @private
*/
_initEventTarget: function SE__initEventTarget()
{
let EventTarget =
this._iframeWindow.require("orion/textview/eventTarget").EventTarget;
EventTarget.addMixin(this._eventTarget);
this._eventListenersQueue.forEach(function(aRequest) {
if (aRequest[0] == "add") {
this.addEventListener(aRequest[1], aRequest[2]);
} else {
this.removeEventListener(aRequest[1], aRequest[2]);
}
}, this);
this._eventListenersQueue = [];
},
/**
* Dispatch an event to the SourceEditor event listeners. This covers only the
* SourceEditor-specific events.
*
* @private
* @param object aEvent
* The event object to dispatch to all listeners.
*/
_dispatchEvent: function SE__dispatchEvent(aEvent)
{
this._eventTarget.dispatchEvent(aEvent);
},
/**
@ -492,6 +566,112 @@ SourceEditor.prototype = {
Ci.nsIClipboard.kSelectionClipboard);
},
/**
* Highlight the Orion annotations. This updates the annotation styler as
* needed.
* @private
*/
_highlightAnnotations: function SE__highlightAnnotations()
{
if (this._annotationStyler) {
this._annotationStyler.destroy();
this._annotationStyler = null;
}
let AnnotationStyler =
this._iframeWindow.require("orion/textview/annotations").AnnotationStyler;
let styler = new AnnotationStyler(this._view, this._annotationModel);
this._annotationStyler = styler;
styler.addAnnotationType(ORION_ANNOTATION_TYPES.matchingBracket);
styler.addAnnotationType(ORION_ANNOTATION_TYPES.currentBracket);
styler.addAnnotationType(ORION_ANNOTATION_TYPES.task);
},
/**
* Retrieve the list of Orion Annotations filtered by type for the given text range.
*
* @private
* @param string aType
* The annotation type to filter annotations for.
* @param number aStart
* Offset from where to start finding the annotations.
* @param number aEnd
* End offset for retrieving the annotations.
* @return array
* The array of annotations, filtered by type, within the given text
* range.
*/
_getAnnotationsByType: function SE__getAnnotationsByType(aType, aStart, aEnd)
{
let annotations = this._annotationModel.getAnnotations(aStart, aEnd);
let annotation, result = [];
while (annotation = annotations.next()) {
if (annotation.type == ORION_ANNOTATION_TYPES[aType]) {
result.push(annotation);
}
}
return result;
},
/**
* The click event handler for the annotation ruler.
*
* @private
* @param number aLineIndex
* The line index where the click event occurred.
* @param object aEvent
* The DOM click event object.
*/
_annotationRulerClick: function SE__annotationRulerClick(aLineIndex, aEvent)
{
if (aLineIndex === undefined || aLineIndex == -1) {
return;
}
let lineStart = this._model.getLineStart(aLineIndex);
let lineEnd = this._model.getLineEnd(aLineIndex);
let annotations = this._getAnnotationsByType("breakpoint", lineStart, lineEnd);
if (annotations.length > 0) {
this.removeBreakpoint(aLineIndex);
} else {
this.addBreakpoint(aLineIndex);
}
},
/**
* The click event handler for the overview ruler. When the user clicks on an
* annotation the editor jumps to the associated line.
*
* @private
* @param number aLineIndex
* The line index where the click event occurred.
* @param object aEvent
* The DOM click event object.
*/
_overviewRulerClick: function SE__overviewRulerClick(aLineIndex, aEvent)
{
if (aLineIndex === undefined || aLineIndex == -1) {
return;
}
let model = this._model;
let lineStart = model.getLineStart(aLineIndex);
let lineEnd = model.getLineEnd(aLineIndex);
let annotations = this._annotationModel.getAnnotations(lineStart, lineEnd);
let annotation = annotations.next();
// Jump to the line where annotation is. If the annotation is specific to
// a substring part of the line, then select the substring.
if (!annotation || lineStart == annotation.start && lineEnd == annotation.end) {
this.setSelection(lineStart, lineStart);
} else {
this.setSelection(annotation.start, annotation.end);
}
},
/**
* Get the editor element.
*
@ -512,14 +692,14 @@ SourceEditor.prototype = {
* @param function aCallback
* The function you want executed when the event is triggered.
*/
addEventListener:
function SE_addEventListener(aEventType, aCallback)
addEventListener: function SE_addEventListener(aEventType, aCallback)
{
if (aEventType in ORION_EVENTS) {
if (this._view && aEventType in ORION_EVENTS) {
this._view.addEventListener(ORION_EVENTS[aEventType], aCallback);
} else if (this._eventTarget.addEventListener) {
this._eventTarget.addEventListener(aEventType, aCallback);
} else {
throw new Error("SourceEditor.addEventListener() unknown event " +
"type " + aEventType);
this._eventListenersQueue.push(["add", aEventType, aCallback]);
}
},
@ -534,14 +714,14 @@ SourceEditor.prototype = {
* @param function aCallback
* The function you have as the event handler.
*/
removeEventListener:
function SE_removeEventListener(aEventType, aCallback)
removeEventListener: function SE_removeEventListener(aEventType, aCallback)
{
if (aEventType in ORION_EVENTS) {
if (this._view && aEventType in ORION_EVENTS) {
this._view.removeEventListener(ORION_EVENTS[aEventType], aCallback);
} else if (this._eventTarget.removeEventListener) {
this._eventTarget.removeEventListener(aEventType, aCallback);
} else {
throw new Error("SourceEditor.removeEventListener() unknown event " +
"type " + aEventType);
this._eventListenersQueue.push(["remove", aEventType, aCallback]);
}
},
@ -841,10 +1021,6 @@ SourceEditor.prototype = {
this._styler.destroy();
this._styler = null;
}
if (this._annotationStyler) {
this._annotationStyler.destroy();
this._annotationStyler = null;
}
let window = this._iframeWindow;
@ -857,16 +1033,6 @@ SourceEditor.prototype = {
this._styler = new TextStyler(this._view, aMode, this._annotationModel);
this._styler.setFoldingEnabled(false);
this._styler.setHighlightCaretLine(true);
let AnnotationStyler =
window.require("orion/textview/annotations").AnnotationStyler;
this._annotationStyler =
new AnnotationStyler(this._view, this._annotationModel);
this._annotationStyler.
addAnnotationType(ORION_ANNOTATION_TYPES.matchingBracket);
this._annotationStyler.
addAnnotationType(ORION_ANNOTATION_TYPES.currentBracket);
break;
case SourceEditor.MODES.HTML:
@ -879,6 +1045,7 @@ SourceEditor.prototype = {
break;
}
this._highlightAnnotations();
this._mode = aMode;
},
@ -915,6 +1082,106 @@ SourceEditor.prototype = {
return this._view.getOptions("readonly");
},
/**
* Add a breakpoint at the given line index.
*
* @param number aLineIndex
* Line index where to add the breakpoint (starts from 0).
* @param string [aCondition]
* Optional breakpoint condition.
*/
addBreakpoint: function SE_addBreakpoint(aLineIndex, aCondition)
{
let lineStart = this._model.getLineStart(aLineIndex);
let lineEnd = this._model.getLineEnd(aLineIndex);
let annotations = this._getAnnotationsByType("breakpoint", lineStart, lineEnd);
if (annotations.length > 0) {
return;
}
let lineText = this._model.getLine(aLineIndex);
let title = SourceEditorUI.strings.
formatStringFromName("annotation.breakpoint.title",
[lineText], 1);
let annotation = {
type: ORION_ANNOTATION_TYPES.breakpoint,
start: lineStart,
end: lineEnd,
breakpointCondition: aCondition,
title: title,
style: {styleClass: "annotation breakpoint"},
html: "<div class='annotationHTML breakpoint'></div>",
overviewStyle: {styleClass: "annotationOverview breakpoint"},
rangeStyle: {styleClass: "annotationRange breakpoint"}
};
this._annotationModel.addAnnotation(annotation);
let event = {
type: SourceEditor.EVENTS.BREAKPOINT_CHANGE,
added: [{line: aLineIndex, condition: aCondition}],
removed: [],
};
this._dispatchEvent(event);
},
/**
* Remove the current breakpoint from the given line index.
*
* @param number aLineIndex
* Line index from where to remove the breakpoint (starts from 0).
* @return boolean
* True if a breakpoint was removed, false otherwise.
*/
removeBreakpoint: function SE_removeBreakpoint(aLineIndex)
{
let lineStart = this._model.getLineStart(aLineIndex);
let lineEnd = this._model.getLineEnd(aLineIndex);
let event = {
type: SourceEditor.EVENTS.BREAKPOINT_CHANGE,
added: [],
removed: [],
};
let annotations = this._getAnnotationsByType("breakpoint", lineStart, lineEnd);
annotations.forEach(function(annotation) {
this._annotationModel.removeAnnotation(annotation);
event.removed.push({line: aLineIndex,
condition: annotation.breakpointCondition});
}, this);
if (event.removed.length > 0) {
this._dispatchEvent(event);
}
return event.removed.length > 0;
},
/**
* Get the list of breakpoints in the Source Editor instance.
*
* @return array
* The array of breakpoints. Each item is an object with two
* properties: line and condition.
*/
getBreakpoints: function SE_getBreakpoints()
{
let annotations = this._getAnnotationsByType("breakpoint", 0,
this.getCharCount());
let breakpoints = [];
annotations.forEach(function(annotation) {
breakpoints.push({line: this._model.getLineAtOffset(annotation.start),
condition: annotation.breakpointCondition});
}, this);
return breakpoints;
},
/**
* Destroy/uninitialize the editor.
*/
@ -936,9 +1203,13 @@ SourceEditor.prototype = {
this._undoStack = null;
this._styler = null;
this._linesRuler = null;
this._annotationRuler = null;
this._overviewRuler = null;
this._dragAndDrop = null;
this._annotationModel = null;
this._annotationStyler = null;
this._eventTarget = null;
this._eventListenersQueue = null;
this._view = null;
this._model = null;
this._config = null;

View File

@ -106,13 +106,93 @@ SourceEditor.THEMES = {
/**
* Source editor configuration defaults.
* @see SourceEditor.init
*/
SourceEditor.DEFAULTS = {
MODE: SourceEditor.MODES.TEXT,
THEME: SourceEditor.THEMES.MOZILLA,
UNDO_LIMIT: 200,
TAB_SIZE: 4, // overriden by pref
EXPAND_TAB: true, // overriden by pref
/**
* The text you want shown when the editor opens up.
* @type string
*/
initialText: "",
/**
* The editor mode, based on the file type you want to edit. You can use one of
* the predefined modes.
*
* @see SourceEditor.MODES
* @type string
*/
mode: SourceEditor.MODES.TEXT,
/**
* The syntax highlighting theme you want. You can use one of the predefined
* themes, or you can point to your CSS file.
*
* @see SourceEditor.THEMES.
* @type string
*/
theme: SourceEditor.THEMES.MOZILLA,
/**
* How many steps should the undo stack hold.
* @type number
*/
undoLimit: 200,
/**
* Define how many spaces to use for a tab character. This value is overridden
* by a user preference, see SourceEditor.PREFS.TAB_SIZE.
*
* @type number
*/
tabSize: 4,
/**
* Tells if you want tab characters to be expanded to spaces. This value is
* overridden by a user preference, see SourceEditor.PREFS.EXPAND_TAB.
* @type boolean
*/
expandTab: true,
/**
* Tells if you want the editor to be read only or not.
* @type boolean
*/
readOnly: false,
/**
* Display the line numbers gutter.
* @type boolean
*/
showLineNumbers: false,
/**
* Display the annotations gutter/ruler. This gutter currently supports
* annotations of breakpoint type.
* @type boolean
*/
showAnnotationRuler: false,
/**
* Display the overview gutter/ruler. This gutter presents an overview of the
* current annotations in the editor, for example the breakpoints.
* @type boolean
*/
showOverviewRuler: false,
/**
* An array of objects that allows you to define custom editor keyboard
* bindings. Each object can have:
* - action - name of the editor action to invoke.
* - code - keyCode for the shortcut.
* - accel - boolean for the Accel key (Cmd on Macs, Ctrl on Linux/Windows).
* - shift - boolean for the Shift key.
* - alt - boolean for the Alt key.
* - callback - optional function to invoke, if the action is not predefined
* in the editor.
* @type array
*/
keys: null,
};
/**
@ -185,6 +265,17 @@ SourceEditor.EVENTS = {
* - x and y - the mouse coordinates relative to the document being edited.
*/
MOUSE_OUT: "MouseOut",
/**
* The BreakpointChange event is fired when a new breakpoint is added or when
* a breakpoint is removed - either through API use or through the editor UI.
* Event object properties:
* - added - array that holds the new breakpoints.
* - removed - array that holds the breakpoints that have been removed.
* Each object in the added/removed arrays holds two properties: line and
* condition.
*/
BREAKPOINT_CHANGE: "BreakpointChange",
};
/**

View File

@ -56,6 +56,7 @@ _BROWSER_TEST_FILES = \
browser_bug650345_find.js \
browser_bug703692_focus_blur.js \
browser_bug725388_mouse_events.js \
browser_bug707987_debugger_breakpoints.js \
head.js \
libs:: $(_BROWSER_TEST_FILES)

View File

@ -48,7 +48,7 @@ function initEditor()
let config = {
showLineNumbers: true,
placeholderText: text,
initialText: text,
};
editor = new SourceEditor();

View File

@ -0,0 +1,169 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
function test() {
let temp = {};
Cu.import("resource:///modules/source-editor.jsm", temp);
let SourceEditor = temp.SourceEditor;
let component = Services.prefs.getCharPref(SourceEditor.PREFS.COMPONENT);
if (component == "textarea") {
ok(true, "skip test for bug 707987: only applicable for non-textarea components");
return;
}
waitForExplicitFinish();
let editor;
const windowUrl = "data:text/xml,<?xml version='1.0'?>" +
"<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'" +
" title='test for bug 707987' width='600' height='500'><hbox flex='1'/></window>";
const windowFeatures = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
let testWin = Services.ww.openWindow(null, windowUrl, "_blank", windowFeatures, null);
testWin.addEventListener("load", function onWindowLoad() {
testWin.removeEventListener("load", onWindowLoad, false);
waitForFocus(initEditor, testWin);
}, false);
function initEditor()
{
let hbox = testWin.document.querySelector("hbox");
editor = new SourceEditor();
editor.init(hbox, {showAnnotationRuler: true}, editorLoaded);
}
function editorLoaded()
{
editor.focus();
editor.setText("line1\nline2\nline3\nline4");
is(editor.getBreakpoints().length, 0, "no breakpoints");
let event = null;
let eventHandler = function(aEvent) {
event = aEvent;
};
editor.addEventListener(SourceEditor.EVENTS.BREAKPOINT_CHANGE, eventHandler);
// Add breakpoint at line 0
editor.addBreakpoint(0);
let breakpoints = editor.getBreakpoints();
is(breakpoints.length, 1, "one breakpoint added");
is(breakpoints[0].line, 0, "breakpoint[0].line is correct");
ok(!breakpoints[0].condition, "breakpoint[0].condition is correct");
ok(event, "breakpoint event fired");
is(event.added.length, 1, "one breakpoint added (confirmed)");
is(event.removed.length, 0, "no breakpoint removed");
is(event.added[0].line, 0, "event added[0].line is correct");
ok(!event.added[0].condition, "event added[0].condition is correct");
// Add breakpoint at line 3
event = null;
editor.addBreakpoint(3, "foo == 'bar'");
breakpoints = editor.getBreakpoints();
is(breakpoints.length, 2, "another breakpoint added");
is(breakpoints[0].line, 0, "breakpoint[0].line is correct");
ok(!breakpoints[0].condition, "breakpoint[0].condition is correct");
is(breakpoints[1].line, 3, "breakpoint[1].line is correct");
is(breakpoints[1].condition, "foo == 'bar'",
"breakpoint[1].condition is correct");
ok(event, "breakpoint event fired");
is(event.added.length, 1, "another breakpoint added (confirmed)");
is(event.removed.length, 0, "no breakpoint removed");
is(event.added[0].line, 3, "event added[0].line is correct");
is(event.added[0].condition, "foo == 'bar'",
"event added[0].condition is correct");
// Try to add another breakpoint at line 0
event = null;
editor.addBreakpoint(0);
is(editor.getBreakpoints().length, 2, "no breakpoint added");
is(event, null, "no breakpoint event fired");
// Try to remove a breakpoint from line 1
is(editor.removeBreakpoint(1), false, "removeBreakpoint(1) returns false");
is(editor.getBreakpoints().length, 2, "no breakpoint removed");
is(event, null, "no breakpoint event fired");
// Remove the breakpoint from line 0
is(editor.removeBreakpoint(0), true, "removeBreakpoint(0) returns true");
breakpoints = editor.getBreakpoints();
is(breakpoints[0].line, 3, "breakpoint[0].line is correct");
is(breakpoints[0].condition, "foo == 'bar'",
"breakpoint[0].condition is correct");
ok(event, "breakpoint event fired");
is(event.added.length, 0, "no breakpoint added");
is(event.removed.length, 1, "one breakpoint removed");
is(event.removed[0].line, 0, "event removed[0].line is correct");
ok(!event.removed[0].condition, "event removed[0].condition is correct");
// Remove the breakpoint from line 3
event = null;
is(editor.removeBreakpoint(3), true, "removeBreakpoint(3) returns true");
is(editor.getBreakpoints().length, 0, "no breakpoints");
ok(event, "breakpoint event fired");
is(event.added.length, 0, "no breakpoint added");
is(event.removed.length, 1, "one breakpoint removed");
is(event.removed[0].line, 3, "event removed[0].line is correct");
is(event.removed[0].condition, "foo == 'bar'",
"event removed[0].condition is correct");
// Add a breakpoint with the mouse
event = null;
EventUtils.synthesizeMouse(editor.editorElement, 10, 10, {}, testWin);
breakpoints = editor.getBreakpoints();
is(breakpoints.length, 1, "one breakpoint added");
is(breakpoints[0].line, 0, "breakpoint[0].line is correct");
ok(!breakpoints[0].condition, "breakpoint[0].condition is correct");
ok(event, "breakpoint event fired");
is(event.added.length, 1, "one breakpoint added (confirmed)");
is(event.removed.length, 0, "no breakpoint removed");
is(event.added[0].line, 0, "event added[0].line is correct");
ok(!event.added[0].condition, "event added[0].condition is correct");
// Remove a breakpoint with the mouse
event = null;
EventUtils.synthesizeMouse(editor.editorElement, 10, 10, {}, testWin);
breakpoints = editor.getBreakpoints();
is(breakpoints.length, 0, "one breakpoint removed");
ok(event, "breakpoint event fired");
is(event.added.length, 0, "no breakpoint added");
is(event.removed.length, 1, "one breakpoint removed (confirmed)");
is(event.removed[0].line, 0, "event removed[0].line is correct");
ok(!event.removed[0].condition, "event removed[0].condition is correct");
editor.destroy();
testWin.close();
testWin = editor = null;
waitForFocus(finish, window);
}
}

View File

@ -37,7 +37,7 @@ function initEditor()
editor = new SourceEditor();
let config = {
showLineNumbers: true,
placeholderText: "foobarbaz",
initialText: "foobarbaz",
tabSize: 7,
expandTab: true,
};
@ -54,7 +54,7 @@ function editorLoaded()
editor.focus();
is(editor.getMode(), SourceEditor.DEFAULTS.MODE, "default editor mode");
is(editor.getMode(), SourceEditor.DEFAULTS.mode, "default editor mode");
// Test general editing methods.

View File

@ -222,7 +222,7 @@ StyleEditor.prototype = {
let sourceEditor = new SourceEditor();
let config = {
placeholderText: this._state.text, //! this is initialText (bug 680371)
initialText: this._state.text,
showLineNumbers: true,
mode: SourceEditor.MODES.CSS,
readOnly: this._state.readOnly,

View File

@ -28,3 +28,8 @@ gotoLineCmd.promptTitle=Go to line…
# the user wants to jump to a specific line number in the code. You can
# access this feature by pressing Ctrl-J on Windows/Linux or Cmd-J on Mac.
gotoLineCmd.promptMessage=Jump to line number:
# LOCALIZATION NOTE (annotation.breakpoint.title): This is the text shown in
# front of any breakpoint annotation when it is displayed as a tooltip in one of
# the editor gutters. This feature is used in the JavaScript Debugger.
annotation.breakpoint.title=Breakpoint: %S

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

View File

@ -0,0 +1,39 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
.viewTooltip {
display: none; /* TODO: add tooltips support, see bug 721752 */
font-family: monospace;
font-size: 13px;
background-color: InfoBackground;
color: InfoText;
padding: 2px;
border-radius: 4px;
border: 1px solid black;
z-index: 100;
position: fixed;
overflow: hidden;
white-space: pre;
}
.viewTooltip em {
font-style: normal;
font-weight: bold;
}
.annotationHTML {
cursor: pointer;
width: 16px;
height: 16px;
display: inline-block;
vertical-align: middle;
background-position: center;
background-repeat: no-repeat;
}
.annotationHTML.task {
background-image: url("chrome://browser/skin/devtools/orion-task.png");
}
.annotationHTML.breakpoint {
background-image: url("chrome://browser/skin/devtools/orion-breakpoint.png");
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

View File

@ -18,16 +18,86 @@
background: #f0f0ff;
}
/* Styles for the line number ruler */
.rulerLines {
border-right: 1px solid #b4c4d3;
.ruler {
background: #cddae5;
color: #7a8a99;
}
.ruler.annotations {
width: 16px;
padding-left: 4px;
}
.ruler.lines {
border-right: 1px solid #b4c4d3;
min-width: 1.4em;
padding-left: 4px;
padding-right: 4px;
text-align: end;
}
.ruler.linesWithAnnotations {
min-width: 0;
padding-left: 0;
}
.ruler.overview {
border-left: 1px solid #b4c4d3;
width: 14px;
text-align: start;
}
/* Styles for the annotation ruler (first line) */
.annotationHTML {
cursor: pointer;
width: 16px;
height: 16px;
display: inline-block;
vertical-align: middle;
background-position: center;
background-repeat: no-repeat;
}
.annotationHTML.task {
background-image: url("chrome://browser/skin/devtools/orion-task.png");
}
.annotationHTML.breakpoint {
background-image: url("chrome://browser/skin/devtools/orion-breakpoint.png");
}
/* Styles for the overview ruler */
.annotationOverview {
cursor: pointer;
border-radius: 2px;
left: 2px;
width: 8px;
}
.annotationOverview.task {
background-color: lightgreen;
border: 1px solid green;
}
.annotationOverview.breakpoint {
background-color: lightblue;
border: 1px solid blue;
}
.annotationOverview.currentBracket {
background-color: lightgray;
border: 1px solid red;
}
.annotationOverview.matchingBracket {
background-color: lightgray;
border: 1px solid red;
}
/* Styles for text range */
.annotationRange {
background-repeat: repeat-x;
background-position: left bottom;
}
.annotationRange.task {
outline: 1px dashed rgba(0, 255, 0, 0.5);
}
.annotationRange.matchingBracket {
outline: 1px solid grey;
}
.token_singleline_comment {
color: #45a946; /* green */
}
@ -110,7 +180,3 @@
color: red;
font-weight: bold;
}
.annotationRange.matchingBracket {
outline: 1px solid grey;
}

View File

@ -95,6 +95,9 @@ browser.jar:
skin/classic/browser/devtools/webconsole.png (devtools/webconsole.png)
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
skin/classic/browser/devtools/orion.css (devtools/orion.css)
skin/classic/browser/devtools/orion-container.css (devtools/orion-container.css)
skin/classic/browser/devtools/orion-task.png (devtools/orion-task.png)
skin/classic/browser/devtools/orion-breakpoint.png (devtools/orion-breakpoint.png)
skin/classic/browser/devtools/breadcrumbs/ltr-end-pressed.png (devtools/breadcrumbs/ltr-end-pressed.png)
skin/classic/browser/devtools/breadcrumbs/ltr-end-selected-pressed.png (devtools/breadcrumbs/ltr-end-selected-pressed.png)
skin/classic/browser/devtools/breadcrumbs/ltr-end-selected.png (devtools/breadcrumbs/ltr-end-selected.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

View File

@ -0,0 +1,39 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
.viewTooltip {
display: none; /* TODO: add tooltips support, see bug 721752 */
font-family: monospace;
font-size: 13px;
background-color: InfoBackground;
color: InfoText;
padding: 2px;
border-radius: 4px;
border: 1px solid black;
z-index: 100;
position: fixed;
overflow: hidden;
white-space: pre;
}
.viewTooltip em {
font-style: normal;
font-weight: bold;
}
.annotationHTML {
cursor: pointer;
width: 16px;
height: 16px;
display: inline-block;
vertical-align: middle;
background-position: center;
background-repeat: no-repeat;
}
.annotationHTML.task {
background-image: url("chrome://browser/skin/devtools/orion-task.png");
}
.annotationHTML.breakpoint {
background-image: url("chrome://browser/skin/devtools/orion-breakpoint.png");
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

View File

@ -18,16 +18,86 @@
background: #f0f0ff;
}
/* Styles for the line number ruler */
.rulerLines {
border-right: 1px solid #b4c4d3;
.ruler {
background: #cddae5;
color: #7a8a99;
}
.ruler.annotations {
width: 16px;
padding-left: 4px;
}
.ruler.lines {
border-right: 1px solid #b4c4d3;
min-width: 1.4em;
padding-left: 4px;
padding-right: 4px;
text-align: end;
}
.ruler.linesWithAnnotations {
min-width: 0;
padding-left: 0;
}
.ruler.overview {
border-left: 1px solid #b4c4d3;
width: 14px;
text-align: start;
}
/* Styles for the annotation ruler (first line) */
.annotationHTML {
cursor: pointer;
width: 16px;
height: 16px;
display: inline-block;
vertical-align: middle;
background-position: center;
background-repeat: no-repeat;
}
.annotationHTML.task {
background-image: url("chrome://browser/skin/devtools/orion-task.png");
}
.annotationHTML.breakpoint {
background-image: url("chrome://browser/skin/devtools/orion-breakpoint.png");
}
/* Styles for the overview ruler */
.annotationOverview {
cursor: pointer;
border-radius: 2px;
left: 2px;
width: 8px;
}
.annotationOverview.task {
background-color: lightgreen;
border: 1px solid green;
}
.annotationOverview.breakpoint {
background-color: lightblue;
border: 1px solid blue;
}
.annotationOverview.currentBracket {
background-color: lightgray;
border: 1px solid red;
}
.annotationOverview.matchingBracket {
background-color: lightgray;
border: 1px solid red;
}
/* Styles for text range */
.annotationRange {
background-repeat: repeat-x;
background-position: left bottom;
}
.annotationRange.task {
outline: 1px dashed rgba(0, 255, 0, 0.5);
}
.annotationRange.matchingBracket {
outline: 1px solid grey;
}
.token_singleline_comment {
color: #45a946; /* green */
}
@ -110,7 +180,3 @@
color: red;
font-weight: bold;
}
.annotationRange.matchingBracket {
outline: 1px solid grey;
}

View File

@ -131,6 +131,9 @@ browser.jar:
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
skin/classic/browser/devtools/orion.css (devtools/orion.css)
skin/classic/browser/devtools/orion-container.css (devtools/orion-container.css)
skin/classic/browser/devtools/orion-task.png (devtools/orion-task.png)
skin/classic/browser/devtools/orion-breakpoint.png (devtools/orion-breakpoint.png)
skin/classic/browser/devtools/toolbarbutton-close.png (devtools/toolbarbutton-close.png)
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

View File

@ -0,0 +1,39 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
.viewTooltip {
display: none; /* TODO: add tooltips support, see bug 721752 */
font-family: monospace;
font-size: 13px;
background-color: InfoBackground;
color: InfoText;
padding: 2px;
border-radius: 4px;
border: 1px solid black;
z-index: 100;
position: fixed;
overflow: hidden;
white-space: pre;
}
.viewTooltip em {
font-style: normal;
font-weight: bold;
}
.annotationHTML {
cursor: pointer;
width: 16px;
height: 16px;
display: inline-block;
vertical-align: middle;
background-position: center;
background-repeat: no-repeat;
}
.annotationHTML.task {
background-image: url("chrome://browser/skin/devtools/orion-task.png");
}
.annotationHTML.breakpoint {
background-image: url("chrome://browser/skin/devtools/orion-breakpoint.png");
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

View File

@ -18,16 +18,86 @@
background: #f0f0ff;
}
/* Styles for the line number ruler */
.rulerLines {
border-right: 1px solid #b4c4d3;
.ruler {
background: #cddae5;
color: #7a8a99;
}
.ruler.annotations {
width: 16px;
padding-left: 4px;
}
.ruler.lines {
border-right: 1px solid #b4c4d3;
min-width: 1.4em;
padding-left: 4px;
padding-right: 4px;
text-align: end;
}
.ruler.linesWithAnnotations {
min-width: 0;
padding-left: 0;
}
.ruler.overview {
border-left: 1px solid #b4c4d3;
width: 14px;
text-align: start;
}
/* Styles for the annotation ruler (first line) */
.annotationHTML {
cursor: pointer;
width: 16px;
height: 16px;
display: inline-block;
vertical-align: middle;
background-position: center;
background-repeat: no-repeat;
}
.annotationHTML.task {
background-image: url("chrome://browser/skin/devtools/orion-task.png");
}
.annotationHTML.breakpoint {
background-image: url("chrome://browser/skin/devtools/orion-breakpoint.png");
}
/* Styles for the overview ruler */
.annotationOverview {
cursor: pointer;
border-radius: 2px;
left: 2px;
width: 8px;
}
.annotationOverview.task {
background-color: lightgreen;
border: 1px solid green;
}
.annotationOverview.breakpoint {
background-color: lightblue;
border: 1px solid blue;
}
.annotationOverview.currentBracket {
background-color: lightgray;
border: 1px solid red;
}
.annotationOverview.matchingBracket {
background-color: lightgray;
border: 1px solid red;
}
/* Styles for text range */
.annotationRange {
background-repeat: repeat-x;
background-position: left bottom;
}
.annotationRange.task {
outline: 1px dashed rgba(0, 255, 0, 0.5);
}
.annotationRange.matchingBracket {
outline: 1px solid grey;
}
.token_singleline_comment {
color: #45a946; /* green */
}
@ -110,7 +180,3 @@
color: red;
font-weight: bold;
}
.annotationRange.matchingBracket {
outline: 1px solid grey;
}

View File

@ -116,6 +116,9 @@ browser.jar:
skin/classic/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
skin/classic/browser/devtools/gcli.css (devtools/gcli.css)
skin/classic/browser/devtools/orion.css (devtools/orion.css)
skin/classic/browser/devtools/orion-container.css (devtools/orion-container.css)
skin/classic/browser/devtools/orion-task.png (devtools/orion-task.png)
skin/classic/browser/devtools/orion-breakpoint.png (devtools/orion-breakpoint.png)
skin/classic/browser/devtools/toolbarbutton-close.png (devtools/toolbarbutton-close.png)
skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
skin/classic/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)
@ -282,6 +285,9 @@ browser.jar:
skin/classic/aero/browser/devtools/csshtmltree.css (devtools/csshtmltree.css)
skin/classic/aero/browser/devtools/gcli.css (devtools/gcli.css)
skin/classic/aero/browser/devtools/orion.css (devtools/orion.css)
skin/classic/aero/browser/devtools/orion-container.css (devtools/orion-container.css)
skin/classic/aero/browser/devtools/orion-task.png (devtools/orion-task.png)
skin/classic/aero/browser/devtools/orion-breakpoint.png (devtools/orion-breakpoint.png)
skin/classic/aero/browser/devtools/toolbarbutton-close.png (devtools/toolbarbutton-close.png)
skin/classic/aero/browser/devtools/webconsole.css (devtools/webconsole.css)
skin/classic/aero/browser/devtools/webconsole_networkpanel.css (devtools/webconsole_networkpanel.css)