зеркало из https://github.com/mozilla/gecko-dev.git
Bug 926014 - Support CSS source maps; r=dcamp
--HG-- rename : browser/devtools/styleeditor/StyleEditorPanel.jsm => browser/devtools/styleeditor/styleeditor-panel.js
This commit is contained in:
Родитель
6a2ff3b70b
Коммит
1d65b9038a
|
@ -1155,7 +1155,7 @@ pref("devtools.scratchpad.recentFilesMax", 10);
|
|||
|
||||
// Enable the Style Editor.
|
||||
pref("devtools.styleeditor.enabled", true);
|
||||
pref("devtools.styleeditor.transitions", true);
|
||||
pref("devtools.styleeditor.source-maps-enabled", false);
|
||||
|
||||
// Enable the Shader Editor.
|
||||
pref("devtools.shadereditor.enabled", false);
|
||||
|
|
|
@ -26,7 +26,7 @@ loader.lazyGetter(this, "OptionsPanel", () => require("devtools/framework/toolbo
|
|||
loader.lazyGetter(this, "InspectorPanel", () => require("devtools/inspector/inspector-panel").InspectorPanel);
|
||||
loader.lazyGetter(this, "WebConsolePanel", () => require("devtools/webconsole/panel").WebConsolePanel);
|
||||
loader.lazyGetter(this, "DebuggerPanel", () => require("devtools/debugger/panel").DebuggerPanel);
|
||||
loader.lazyImporter(this, "StyleEditorPanel", "resource:///modules/devtools/StyleEditorPanel.jsm");
|
||||
loader.lazyGetter(this, "StyleEditorPanel", () => require("devtools/styleeditor/styleeditor-panel").StyleEditorPanel);
|
||||
loader.lazyGetter(this, "ShaderEditorPanel", () => require("devtools/shadereditor/panel").ShaderEditorPanel);
|
||||
loader.lazyGetter(this, "ProfilerPanel", () => require("devtools/profiler/panel"));
|
||||
loader.lazyGetter(this, "NetMonitorPanel", () => require("devtools/netmonitor/panel").NetMonitorPanel);
|
||||
|
|
|
@ -5,4 +5,6 @@
|
|||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
libs::
|
||||
$(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools
|
||||
$(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools/
|
||||
$(NSINSTALL) $(srcdir)/*.js $(FINAL_TARGET)/modules/devtools/styleeditor
|
||||
|
||||
|
|
|
@ -1,346 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["StyleEditorDebuggee", "StyleSheet"];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/devtools/shared/event-emitter.js");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "promise",
|
||||
"resource://gre/modules/commonjs/sdk/core/promise.js", "Promise");
|
||||
|
||||
/**
|
||||
* A StyleEditorDebuggee represents the document the style editor is debugging.
|
||||
* It maintains a list of StyleSheet objects that represent the stylesheets in
|
||||
* the target's document. It wraps remote debugging protocol comunications.
|
||||
*
|
||||
* It emits these events:
|
||||
* 'document-load': debuggee's document is loaded, style sheets are argument
|
||||
* 'stylesheets-cleared': The debuggee's stylesheets have been reset (e.g. the
|
||||
* page navigated)
|
||||
*
|
||||
* @param {Target} target
|
||||
* The target the debuggee is listening to
|
||||
*/
|
||||
let StyleEditorDebuggee = function(target) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this.styleSheets = [];
|
||||
|
||||
this.clear = this.clear.bind(this);
|
||||
this._onNewDocument = this._onNewDocument.bind(this);
|
||||
this._onDocumentLoad = this._onDocumentLoad.bind(this);
|
||||
|
||||
this._target = target;
|
||||
this._actor = this.target.form.styleEditorActor;
|
||||
|
||||
this.client.addListener("documentLoad", this._onDocumentLoad);
|
||||
this._target.on("navigate", this._onNewDocument);
|
||||
|
||||
this._onNewDocument();
|
||||
}
|
||||
|
||||
StyleEditorDebuggee.prototype = {
|
||||
/**
|
||||
* list of StyleSheet objects for this target
|
||||
*/
|
||||
styleSheets: null,
|
||||
|
||||
/**
|
||||
* baseURIObject for the current document
|
||||
*/
|
||||
baseURI: null,
|
||||
|
||||
/**
|
||||
* The target we're debugging
|
||||
*/
|
||||
get target() {
|
||||
return this._target;
|
||||
},
|
||||
|
||||
/**
|
||||
* Client for communicating with server with remote debug protocol.
|
||||
*/
|
||||
get client() {
|
||||
return this._target.client;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the StyleSheet object with the given href.
|
||||
*
|
||||
* @param {string} href
|
||||
* Url of the stylesheet to find
|
||||
* @return {StyleSheet}
|
||||
* StyleSheet with the matching href
|
||||
*/
|
||||
styleSheetFromHref: function(href) {
|
||||
for (let sheet of this.styleSheets) {
|
||||
if (sheet.href == href) {
|
||||
return sheet;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear stylesheets and state.
|
||||
*/
|
||||
clear: function() {
|
||||
this.baseURI = null;
|
||||
this.clearStyleSheets();
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear stylesheets.
|
||||
*/
|
||||
clearStyleSheets: function() {
|
||||
for (let stylesheet of this.styleSheets) {
|
||||
stylesheet.destroy();
|
||||
}
|
||||
this.styleSheets = [];
|
||||
this.emit("stylesheets-cleared");
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when target is created or has navigated.
|
||||
* Clear previous sheets and request new document's
|
||||
*/
|
||||
_onNewDocument: function() {
|
||||
this.clear();
|
||||
|
||||
this._getBaseURI();
|
||||
|
||||
let message = { type: "newDocument" };
|
||||
this._sendRequest(message);
|
||||
},
|
||||
|
||||
/**
|
||||
* request baseURIObject information from the document
|
||||
*/
|
||||
_getBaseURI: function() {
|
||||
let message = { type: "getBaseURI" };
|
||||
this._sendRequest(message, (response) => {
|
||||
this.baseURI = Services.io.newURI(response.baseURI, null, null);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for document load, forward event with
|
||||
* all the stylesheets available on load.
|
||||
*
|
||||
* @param {string} type
|
||||
* Event type
|
||||
* @param {object} request
|
||||
* Object with 'styleSheets' array of actor forms
|
||||
*/
|
||||
_onDocumentLoad: function(type, request) {
|
||||
if (this.styleSheets.length > 0) {
|
||||
this.clearStyleSheets();
|
||||
}
|
||||
let sheets = [];
|
||||
for (let form of request.styleSheets) {
|
||||
let sheet = this._addStyleSheet(form);
|
||||
sheets.push(sheet);
|
||||
}
|
||||
this.emit("document-load", sheets);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new StyleSheet object from the form
|
||||
* and add to our stylesheet list.
|
||||
*
|
||||
* @param {object} form
|
||||
* Initial properties of the stylesheet
|
||||
*/
|
||||
_addStyleSheet: function(form) {
|
||||
let sheet = new StyleSheet(form, this);
|
||||
this.styleSheets.push(sheet);
|
||||
return sheet;
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new stylesheet with the given text
|
||||
* and attach it to the document.
|
||||
*
|
||||
* @param {string} text
|
||||
* Initial text of the stylesheet
|
||||
* @param {function} callback
|
||||
* Function to call when the stylesheet has been added to the document
|
||||
*/
|
||||
createStyleSheet: function(text, callback) {
|
||||
let message = { type: "newStyleSheet", text: text };
|
||||
this._sendRequest(message, (response) => {
|
||||
let sheet = this._addStyleSheet(response.styleSheet);
|
||||
callback(sheet);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Send a request to our actor on the server
|
||||
*
|
||||
* @param {object} message
|
||||
* Message to send to the actor
|
||||
* @param {function} callback
|
||||
* Function to call with reponse from actor
|
||||
*/
|
||||
_sendRequest: function(message, callback) {
|
||||
message.to = this._actor;
|
||||
this.client.request(message, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Clean up and remove listeners
|
||||
*/
|
||||
destroy: function() {
|
||||
this.clear();
|
||||
|
||||
this._target.off("navigate", this._onNewDocument);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A StyleSheet object represents a stylesheet on the debuggee. It wraps
|
||||
* communication with a complimentary StyleSheetActor on the server.
|
||||
*
|
||||
* It emits these events:
|
||||
* 'source-load' - The full text source of the stylesheet has been fetched
|
||||
* 'property-change' - Any property (e.g 'disabled') has changed
|
||||
* 'style-applied' - A change has been applied to the live stylesheet on the server
|
||||
* 'error' - An error occured when loading or saving stylesheet
|
||||
*
|
||||
* @param {object} form
|
||||
* Initial properties of the stylesheet
|
||||
* @param {StyleEditorDebuggee} debuggee
|
||||
* Owner of the stylesheet
|
||||
*/
|
||||
let StyleSheet = function(form, debuggee) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this.debuggee = debuggee;
|
||||
this._client = debuggee.client;
|
||||
this._actor = form.actor;
|
||||
|
||||
this._onSourceLoad = this._onSourceLoad.bind(this);
|
||||
this._onPropertyChange = this._onPropertyChange.bind(this);
|
||||
this._onStyleApplied = this._onStyleApplied.bind(this);
|
||||
|
||||
this._client.addListener("sourceLoad", this._onSourceLoad);
|
||||
this._client.addListener("propertyChange", this._onPropertyChange);
|
||||
this._client.addListener("styleApplied", this._onStyleApplied);
|
||||
|
||||
// Backwards compatibility
|
||||
this._client.addListener("sourceLoad-" + this._actor, this._onSourceLoad);
|
||||
this._client.addListener("propertyChange-" + this._actor, this._onPropertyChange);
|
||||
this._client.addListener("styleApplied-" + this._actor, this._onStyleApplied);
|
||||
|
||||
|
||||
// set initial property values
|
||||
for (let attr in form) {
|
||||
this[attr] = form[attr];
|
||||
}
|
||||
}
|
||||
|
||||
StyleSheet.prototype = {
|
||||
/**
|
||||
* Toggle the disabled attribute of the stylesheet
|
||||
*/
|
||||
toggleDisabled: function() {
|
||||
let message = { type: "toggleDisabled" };
|
||||
this._sendRequest(message);
|
||||
},
|
||||
|
||||
/**
|
||||
* Request that the source of the stylesheet be fetched.
|
||||
* 'source-load' event will be fired when it's been fetched.
|
||||
*/
|
||||
fetchSource: function() {
|
||||
let message = { type: "fetchSource" };
|
||||
this._sendRequest(message);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the stylesheet in place with the given full source.
|
||||
*
|
||||
* @param {string} sheetText
|
||||
* Full text to update the stylesheet with
|
||||
*/
|
||||
update: function(sheetText) {
|
||||
let message = { type: "update", text: sheetText, transition: true };
|
||||
this._sendRequest(message);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle source load event from the client.
|
||||
*
|
||||
* @param {string} type
|
||||
* Event type
|
||||
* @param {object} request
|
||||
* Event details
|
||||
*/
|
||||
_onSourceLoad: function(type, request) {
|
||||
if (request.from == this._actor) {
|
||||
if (request.error) {
|
||||
return this.emit("error", request.error);
|
||||
}
|
||||
this.emit("source-load", request.source);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle a property change on the stylesheet
|
||||
*
|
||||
* @param {string} type
|
||||
* Event type
|
||||
* @param {object} request
|
||||
* Event details
|
||||
*/
|
||||
_onPropertyChange: function(type, request) {
|
||||
if (request.from == this._actor) {
|
||||
this[request.property] = request.value;
|
||||
this.emit("property-change", request.property);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle event when update has been successfully applied and propogate it.
|
||||
*/
|
||||
_onStyleApplied: function(type, request) {
|
||||
if (request.from == this._actor) {
|
||||
this.emit("style-applied");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Send a request to our actor on the server
|
||||
*
|
||||
* @param {object} message
|
||||
* Message to send to the actor
|
||||
* @param {function} callback
|
||||
* Function to call with reponse from actor
|
||||
*/
|
||||
_sendRequest: function(message, callback) {
|
||||
message.to = this._actor;
|
||||
this._client.request(message, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Clean up and remove event listeners
|
||||
*/
|
||||
destroy: function() {
|
||||
this._client.removeListener("sourceLoad", this._onSourceLoad);
|
||||
this._client.removeListener("propertyChange", this._onPropertyChange);
|
||||
this._client.removeListener("styleApplied", this._onStyleApplied);
|
||||
|
||||
this._client.removeListener("sourceLoad-" + this._actor, this._onSourceLoad);
|
||||
this._client.removeListener("propertyChange-" + this._actor, this._onPropertyChange);
|
||||
this._client.removeListener("styleApplied-" + this._actor, this._onStyleApplied);
|
||||
}
|
||||
}
|
|
@ -25,6 +25,8 @@ const LOAD_ERROR = "error-load";
|
|||
|
||||
const STYLE_EDITOR_TEMPLATE = "stylesheet";
|
||||
|
||||
const PREF_ORIG_SOURCES = "devtools.styleeditor.source-maps-enabled";
|
||||
|
||||
/**
|
||||
* StyleEditorUI is controls and builds the UI of the Style Editor, including
|
||||
* maintaining a list of editors for each stylesheet on a debuggee.
|
||||
|
@ -34,15 +36,18 @@ const STYLE_EDITOR_TEMPLATE = "stylesheet";
|
|||
* 'editor-selected': An editor was selected
|
||||
* 'error': An error occured
|
||||
*
|
||||
* @param {StyleEditorDebuggee} debuggee
|
||||
* Debuggee of whose stylesheets should be shown in the UI
|
||||
* @param {StyleEditorFront} debuggee
|
||||
* Client-side front for interacting with the page's stylesheets
|
||||
* @param {Target} target
|
||||
* Interface for the page we're debugging
|
||||
* @param {Document} panelDoc
|
||||
* Document of the toolbox panel to populate UI in.
|
||||
*/
|
||||
function StyleEditorUI(debuggee, panelDoc) {
|
||||
function StyleEditorUI(debuggee, target, panelDoc) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this._debuggee = debuggee;
|
||||
this._target = target;
|
||||
this._panelDoc = panelDoc;
|
||||
this._window = this._panelDoc.defaultView;
|
||||
this._root = this._panelDoc.getElementById("style-editor-chrome");
|
||||
|
@ -51,14 +56,18 @@ function StyleEditorUI(debuggee, panelDoc) {
|
|||
this.selectedEditor = null;
|
||||
|
||||
this._onStyleSheetCreated = this._onStyleSheetCreated.bind(this);
|
||||
this._onStyleSheetsCleared = this._onStyleSheetsCleared.bind(this);
|
||||
this._onDocumentLoad = this._onDocumentLoad.bind(this);
|
||||
this._onNewDocument = this._onNewDocument.bind(this);
|
||||
this._clear = this._clear.bind(this);
|
||||
this._onError = this._onError.bind(this);
|
||||
|
||||
debuggee.on("document-load", this._onDocumentLoad);
|
||||
debuggee.on("stylesheets-cleared", this._onStyleSheetsCleared);
|
||||
|
||||
this.createUI();
|
||||
|
||||
this._debuggee.getStyleSheets().then((styleSheets) => {
|
||||
this._resetStyleSheetList(styleSheets);
|
||||
|
||||
this._target.on("will-navigate", this._clear);
|
||||
this._target.on("navigate", this._onNewDocument);
|
||||
})
|
||||
}
|
||||
|
||||
StyleEditorUI.prototype = {
|
||||
|
@ -101,7 +110,7 @@ StyleEditorUI.prototype = {
|
|||
this._view = new SplitView(viewRoot);
|
||||
|
||||
wire(this._view.rootElement, ".style-editor-newButton", function onNew() {
|
||||
this._debuggee.createStyleSheet(null, this._onStyleSheetCreated);
|
||||
this._debuggee.addStyleSheet(null).then(this._onStyleSheetCreated);
|
||||
}.bind(this));
|
||||
|
||||
wire(this._view.rootElement, ".style-editor-importButton", function onImport() {
|
||||
|
@ -109,6 +118,112 @@ StyleEditorUI.prototype = {
|
|||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Refresh editors to reflect the stylesheets in the document.
|
||||
*
|
||||
* @param {string} event
|
||||
* Event name
|
||||
* @param {StyleSheet} styleSheet
|
||||
* StyleSheet object for new sheet
|
||||
*/
|
||||
_onNewDocument: function() {
|
||||
this._debuggee.getStyleSheets().then((styleSheets) => {
|
||||
this._resetStyleSheetList(styleSheets);
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all editors and add loading indicator.
|
||||
*/
|
||||
_clear: function() {
|
||||
// remember selected sheet and line number for next load
|
||||
if (this.selectedEditor && this.selectedEditor.sourceEditor) {
|
||||
let href = this.selectedEditor.styleSheet.href;
|
||||
let {line, ch} = this.selectedEditor.sourceEditor.getCursor();
|
||||
|
||||
this._styleSheetToSelect = {
|
||||
href: href,
|
||||
line: line,
|
||||
col: ch
|
||||
};
|
||||
}
|
||||
|
||||
this._clearStyleSheetEditors();
|
||||
this._view.removeAll();
|
||||
|
||||
this.selectedEditor = null;
|
||||
|
||||
this._root.classList.add("loading");
|
||||
},
|
||||
|
||||
/**
|
||||
* Add editors for all the given stylesheets to the UI.
|
||||
*
|
||||
* @param {array} styleSheets
|
||||
* Array of StyleSheetFront
|
||||
*/
|
||||
_resetStyleSheetList: function(styleSheets) {
|
||||
this._clear();
|
||||
|
||||
for (let sheet of styleSheets) {
|
||||
this._addStyleSheet(sheet);
|
||||
}
|
||||
|
||||
this._root.classList.remove("loading");
|
||||
|
||||
this.emit("stylesheets-reset");
|
||||
},
|
||||
|
||||
/**
|
||||
* Add an editor for this stylesheet. Add editors for its original sources
|
||||
* instead (e.g. Sass sources), if applicable.
|
||||
*
|
||||
* @param {StyleSheetFront} styleSheet
|
||||
* Style sheet to add to style editor
|
||||
*/
|
||||
_addStyleSheet: function(styleSheet) {
|
||||
let editor = this._addStyleSheetEditor(styleSheet);
|
||||
|
||||
if (!Services.prefs.getBoolPref(PREF_ORIG_SOURCES)) {
|
||||
return;
|
||||
}
|
||||
|
||||
styleSheet.getOriginalSources().then((sources) => {
|
||||
if (sources && sources.length) {
|
||||
this._removeStyleSheetEditor(editor);
|
||||
sources.forEach((source) => {
|
||||
// set so the first sheet will be selected, even if it's a source
|
||||
source.styleSheetIndex = styleSheet.styleSheetIndex;
|
||||
|
||||
this._addStyleSheetEditor(source);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a new editor to the UI for a source.
|
||||
*
|
||||
* @param {StyleSheet} styleSheet
|
||||
* Object representing stylesheet
|
||||
* @param {nsIfile} file
|
||||
* Optional file object that sheet was imported from
|
||||
* @param {Boolean} isNew
|
||||
* Optional if stylesheet is a new sheet created by user
|
||||
*/
|
||||
_addStyleSheetEditor: function(styleSheet, file, isNew) {
|
||||
let editor = new StyleSheetEditor(styleSheet, this._window, file, isNew);
|
||||
|
||||
editor.on("property-change", this._summaryChange.bind(this, editor));
|
||||
editor.on("style-applied", this._summaryChange.bind(this, editor));
|
||||
editor.on("error", this._onError);
|
||||
|
||||
this.editors.push(editor);
|
||||
|
||||
editor.fetchSource(this._sourceLoaded.bind(this, editor));
|
||||
return editor;
|
||||
},
|
||||
|
||||
/**
|
||||
* Import a style sheet from file and asynchronously create a
|
||||
* new stylesheet on the debuggee for it.
|
||||
|
@ -134,7 +249,7 @@ StyleEditorUI.prototype = {
|
|||
let source = NetUtil.readInputStreamToString(stream, stream.available());
|
||||
stream.close();
|
||||
|
||||
this._debuggee.createStyleSheet(source, (styleSheet) => {
|
||||
this._debuggee.addStyleSheet(source).then((styleSheet) => {
|
||||
this._onStyleSheetCreated(styleSheet, file);
|
||||
});
|
||||
});
|
||||
|
@ -144,24 +259,6 @@ StyleEditorUI.prototype = {
|
|||
showFilePicker(file, false, parentWindow, onFileSelected);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for debuggee's 'stylesheets-cleared' event. Remove all editors.
|
||||
*/
|
||||
_onStyleSheetsCleared: function() {
|
||||
// remember selected sheet and line number for next load
|
||||
if (this.selectedEditor && this.selectedEditor.sourceEditor) {
|
||||
let href = this.selectedEditor.styleSheet.href;
|
||||
let {line, ch} = this.selectedEditor.sourceEditor.getCursor();
|
||||
this.selectStyleSheet(href, line, ch);
|
||||
}
|
||||
|
||||
this._clearStyleSheetEditors();
|
||||
this._view.removeAll();
|
||||
|
||||
this.selectedEditor = null;
|
||||
|
||||
this._root.classList.add("loading");
|
||||
},
|
||||
|
||||
/**
|
||||
* When a new or imported stylesheet has been added to the document.
|
||||
|
@ -171,35 +268,6 @@ StyleEditorUI.prototype = {
|
|||
this._addStyleSheetEditor(styleSheet, file, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handler for debuggee's 'document-load' event. Add editors
|
||||
* for all style sheets in the document
|
||||
*
|
||||
* @param {string} event
|
||||
* Event name
|
||||
* @param {StyleSheet} styleSheet
|
||||
* StyleSheet object for new sheet
|
||||
*/
|
||||
_onDocumentLoad: function(event, styleSheets) {
|
||||
if (this._styleSheetToSelect) {
|
||||
// if selected stylesheet from previous load isn't here,
|
||||
// just set first stylesheet to be selected instead
|
||||
let selectedExists = styleSheets.some((sheet) => {
|
||||
return this._styleSheetToSelect.href == sheet.href;
|
||||
})
|
||||
if (!selectedExists) {
|
||||
this._styleSheetToSelect = null;
|
||||
}
|
||||
}
|
||||
for (let sheet of styleSheets) {
|
||||
this._addStyleSheetEditor(sheet);
|
||||
}
|
||||
|
||||
this._root.classList.remove("loading");
|
||||
|
||||
this.emit("document-load");
|
||||
},
|
||||
|
||||
/**
|
||||
* Forward any error from a stylesheet.
|
||||
*
|
||||
|
@ -207,34 +275,35 @@ StyleEditorUI.prototype = {
|
|||
* Event name
|
||||
* @param {string} errorCode
|
||||
* Code represeting type of error
|
||||
* @param {string} message
|
||||
* The full error message
|
||||
*/
|
||||
_onError: function(event, errorCode) {
|
||||
this.emit("error", errorCode);
|
||||
_onError: function(event, errorCode, message) {
|
||||
this.emit("error", errorCode, message);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a new editor to the UI for a stylesheet.
|
||||
* Remove a particular stylesheet editor from the UI
|
||||
*
|
||||
* @param {StyleSheet} styleSheet
|
||||
* Object representing stylesheet
|
||||
* @param {nsIfile} file
|
||||
* Optional file object that sheet was imported from
|
||||
* @param {Boolean} isNew
|
||||
* Optional if stylesheet is a new sheet created by user
|
||||
* @param {StyleSheetEditor} editor
|
||||
* The editor to remove.
|
||||
*/
|
||||
_addStyleSheetEditor: function(styleSheet, file, isNew) {
|
||||
let editor = new StyleSheetEditor(styleSheet, this._window, file, isNew);
|
||||
_removeStyleSheetEditor: function(editor) {
|
||||
if (editor.summary) {
|
||||
this._view.removeItem(editor.summary);
|
||||
}
|
||||
else {
|
||||
let self = this;
|
||||
this.on("editor-added", function onAdd(event, added) {
|
||||
if (editor == added) {
|
||||
self.off("editor-added", onAdd);
|
||||
self._view.removeItem(editor.summary);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
editor.once("source-load", this._sourceLoaded.bind(this, editor));
|
||||
editor.on("property-change", this._summaryChange.bind(this, editor));
|
||||
editor.on("style-applied", this._summaryChange.bind(this, editor));
|
||||
editor.on("error", this._onError);
|
||||
|
||||
this.editors.push(editor);
|
||||
|
||||
// Queue editor loading. This helps responsivity during loading when
|
||||
// there are many heavy stylesheets.
|
||||
this._window.setTimeout(editor.fetchSource.bind(editor), 0);
|
||||
editor.destroy();
|
||||
this.editors.splice(this.editors.indexOf(editor), 1);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -248,8 +317,8 @@ StyleEditorUI.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Handler for an StyleSheetEditor's 'source-load' event.
|
||||
* Create a summary UI for the editor.
|
||||
* Called when a StyleSheetEditor's source has been fetched. Create a
|
||||
* summary UI for the editor.
|
||||
*
|
||||
* @param {StyleSheetEditor} editor
|
||||
* Editor to create UI for.
|
||||
|
@ -310,8 +379,7 @@ StyleEditorUI.prototype = {
|
|||
}
|
||||
|
||||
// If this is the first stylesheet, select it
|
||||
if (this.selectedStyleSheetIndex == -1
|
||||
&& !this._styleSheetToSelect
|
||||
if (!this.selectedEditor
|
||||
&& editor.styleSheet.styleSheetIndex == 0) {
|
||||
this._selectEditor(editor);
|
||||
}
|
||||
|
@ -322,7 +390,6 @@ StyleEditorUI.prototype = {
|
|||
onShow: function(summary, details, data) {
|
||||
let editor = data.editor;
|
||||
this.selectedEditor = editor;
|
||||
this._styleSheetToSelect = null;
|
||||
|
||||
if (!editor.sourceEditor) {
|
||||
// only initialize source editor when we switch to this view
|
||||
|
@ -345,7 +412,8 @@ StyleEditorUI.prototype = {
|
|||
for each (let editor in this.editors) {
|
||||
if (editor.styleSheet.href == sheet.href) {
|
||||
this._selectEditor(editor, sheet.line, sheet.col);
|
||||
break;
|
||||
this._styleSheetToSelect = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -367,7 +435,6 @@ StyleEditorUI.prototype = {
|
|||
editor.getSourceEditor().then(() => {
|
||||
editor.sourceEditor.setCursor({line: line, ch: col});
|
||||
});
|
||||
|
||||
this._view.activeSummary = editor.summary;
|
||||
},
|
||||
|
||||
|
@ -466,8 +533,5 @@ StyleEditorUI.prototype = {
|
|||
|
||||
destroy: function() {
|
||||
this._clearStyleSheetEditors();
|
||||
|
||||
this._debuggee.off("document-load", this._onDocumentLoad);
|
||||
this._debuggee.off("stylesheets-cleared", this._onStyleSheetsCleared);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ const Cu = Components.utils;
|
|||
const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
|
||||
const Editor = require("devtools/sourceeditor/editor");
|
||||
const promise = require("sdk/core/promise");
|
||||
const {CssLogic} = require("devtools/styleinspector/css-logic");
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
|
@ -21,6 +22,7 @@ Cu.import("resource://gre/modules/NetUtil.jsm");
|
|||
Cu.import("resource:///modules/devtools/shared/event-emitter.js");
|
||||
Cu.import("resource:///modules/devtools/StyleEditorUtil.jsm");
|
||||
|
||||
const LOAD_ERROR = "error-load";
|
||||
const SAVE_ERROR = "error-save";
|
||||
|
||||
// max update frequency in ms (avoid potential typing lag and/or flicker)
|
||||
|
@ -32,12 +34,12 @@ const UPDATE_STYLESHEET_THROTTLE_DELAY = 500;
|
|||
* object.
|
||||
*
|
||||
* Emits events:
|
||||
* 'source-load': The source of the stylesheet has been fetched
|
||||
* 'property-change': A property on the underlying stylesheet has changed
|
||||
* 'source-editor-load': The source editor for this editor has been loaded
|
||||
* 'error': An error has occured
|
||||
*
|
||||
* @param {StyleSheet} styleSheet
|
||||
* @param {StyleSheet|OriginalSource} styleSheet
|
||||
* Stylesheet or original source to show
|
||||
* @param {DOMWindow} win
|
||||
* panel window for style editor
|
||||
* @param {nsIFile} file
|
||||
|
@ -57,13 +59,19 @@ function StyleSheetEditor(styleSheet, win, file, isNew) {
|
|||
|
||||
this.errorMessage = null;
|
||||
|
||||
let readOnly = false;
|
||||
if (styleSheet.isOriginalSource) {
|
||||
// live-preview won't work with sources that need compilation
|
||||
readOnly = true;
|
||||
}
|
||||
|
||||
this._state = { // state to use when inputElement attaches
|
||||
text: "",
|
||||
selection: {
|
||||
start: {line: 0, ch: 0},
|
||||
end: {line: 0, ch: 0}
|
||||
},
|
||||
readOnly: false,
|
||||
readOnly: readOnly,
|
||||
topIndex: 0, // the first visible line
|
||||
};
|
||||
|
||||
|
@ -73,30 +81,21 @@ function StyleSheetEditor(styleSheet, win, file, isNew) {
|
|||
this._styleSheetFilePath = this.styleSheet.href;
|
||||
}
|
||||
|
||||
this._onSourceLoad = this._onSourceLoad.bind(this);
|
||||
this._onPropertyChange = this._onPropertyChange.bind(this);
|
||||
this._onError = this._onError.bind(this);
|
||||
|
||||
this._focusOnSourceEditorReady = false;
|
||||
|
||||
this.styleSheet.once("source-load", this._onSourceLoad);
|
||||
this.styleSheet.on("property-change", this._onPropertyChange);
|
||||
this.styleSheet.on("error", this._onError);
|
||||
}
|
||||
|
||||
StyleSheetEditor.prototype = {
|
||||
/**
|
||||
* This editor's source editor
|
||||
*/
|
||||
get sourceEditor() {
|
||||
return this._sourceEditor;
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether there are unsaved changes in the editor
|
||||
*/
|
||||
get unsaved() {
|
||||
return this._sourceEditor && !this._sourceEditor.isClean();
|
||||
return this.sourceEditor && !this.sourceEditor.isClean();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -113,37 +112,23 @@ StyleSheetEditor.prototype = {
|
|||
* @return string
|
||||
*/
|
||||
get friendlyName() {
|
||||
if (this.savedFile) { // reuse the saved filename if any
|
||||
if (this.savedFile) {
|
||||
return this.savedFile.leafName;
|
||||
}
|
||||
|
||||
if (this._isNew) {
|
||||
let index = this.styleSheet.styleSheetIndex + 1; // 0-indexing only works for devs
|
||||
let index = this.styleSheet.styleSheetIndex + 1;
|
||||
return _("newStyleSheet", index);
|
||||
}
|
||||
|
||||
if (!this.styleSheet.href) {
|
||||
let index = this.styleSheet.styleSheetIndex + 1; // 0-indexing only works for devs
|
||||
let index = this.styleSheet.styleSheetIndex + 1;
|
||||
return _("inlineStyleSheet", index);
|
||||
}
|
||||
|
||||
if (!this._friendlyName) {
|
||||
let sheetURI = this.styleSheet.href;
|
||||
let contentURI = this.styleSheet.debuggee.baseURI;
|
||||
let contentURIScheme = contentURI.scheme;
|
||||
let contentURILeafIndex = contentURI.specIgnoringRef.lastIndexOf("/");
|
||||
contentURI = contentURI.specIgnoringRef;
|
||||
|
||||
// get content base URI without leaf name (if any)
|
||||
if (contentURILeafIndex > contentURIScheme.length) {
|
||||
contentURI = contentURI.substring(0, contentURILeafIndex + 1);
|
||||
}
|
||||
|
||||
// avoid verbose repetition of absolute URI when the style sheet URI
|
||||
// is relative to the content URI
|
||||
this._friendlyName = (sheetURI.indexOf(contentURI) == 0)
|
||||
? sheetURI.substring(contentURI.length)
|
||||
: sheetURI;
|
||||
this._friendlyName = CssLogic.shortSource({ href: sheetURI });
|
||||
try {
|
||||
this._friendlyName = decodeURI(this._friendlyName);
|
||||
} catch (ex) {
|
||||
|
@ -155,22 +140,17 @@ StyleSheetEditor.prototype = {
|
|||
/**
|
||||
* Start fetching the full text source for this editor's sheet.
|
||||
*/
|
||||
fetchSource: function() {
|
||||
this.styleSheet.fetchSource();
|
||||
},
|
||||
fetchSource: function(callback) {
|
||||
this.styleSheet.getText().then((longStr) => {
|
||||
longStr.string().then((source) => {
|
||||
this._state.text = prettifyCSS(source);
|
||||
this.sourceLoaded = true;
|
||||
|
||||
/**
|
||||
* Handle source fetched event. Forward source-load event.
|
||||
*
|
||||
* @param {string} event
|
||||
* Event type
|
||||
* @param {string} source
|
||||
* Full-text source of the stylesheet
|
||||
*/
|
||||
_onSourceLoad: function(event, source) {
|
||||
this._state.text = prettifyCSS(source);
|
||||
this.sourceLoaded = true;
|
||||
this.emit("source-load");
|
||||
callback(source);
|
||||
});
|
||||
}, e => {
|
||||
this.emit("error", LOAD_ERROR, this.styleSheet.href);
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -181,8 +161,8 @@ StyleSheetEditor.prototype = {
|
|||
* @param {string} property
|
||||
* Property that has changed on sheet
|
||||
*/
|
||||
_onPropertyChange: function(event, property) {
|
||||
this.emit("property-change", property);
|
||||
_onPropertyChange: function(property, value) {
|
||||
this.emit("property-change", property, value);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -220,7 +200,7 @@ StyleSheetEditor.prototype = {
|
|||
this.updateStyleSheet();
|
||||
});
|
||||
|
||||
this._sourceEditor = sourceEditor;
|
||||
this.sourceEditor = sourceEditor;
|
||||
|
||||
if (this._focusOnSourceEditorReady) {
|
||||
this._focusOnSourceEditorReady = false;
|
||||
|
@ -320,7 +300,7 @@ StyleSheetEditor.prototype = {
|
|||
this._state.text = this.sourceEditor.getText();
|
||||
}
|
||||
|
||||
this.styleSheet.update(this._state.text);
|
||||
this.styleSheet.update(this._state.text, true);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -374,6 +354,8 @@ StyleSheetEditor.prototype = {
|
|||
callback(returnFile);
|
||||
}
|
||||
this.sourceEditor.setClean();
|
||||
|
||||
this.emit("property-change");
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
|
@ -404,7 +386,6 @@ StyleSheetEditor.prototype = {
|
|||
* Clean up for this editor.
|
||||
*/
|
||||
destroy: function() {
|
||||
this.styleSheet.off("source-load", this._onSourceLoad);
|
||||
this.styleSheet.off("property-change", this._onPropertyChange);
|
||||
this.styleSheet.off("error", this._onError);
|
||||
}
|
||||
|
|
|
@ -4,21 +4,19 @@
|
|||
* 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/. */
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["StyleEditorPanel"];
|
||||
const {Cc, Ci, Cu, Cr} = require("chrome");
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
|
||||
Cu.import("resource:///modules/devtools/shared/event-emitter.js");
|
||||
Cu.import("resource:///modules/devtools/StyleEditorDebuggee.jsm");
|
||||
|
||||
let promise = require("sdk/core/promise");
|
||||
let EventEmitter = require("devtools/shared/event-emitter");
|
||||
|
||||
Cu.import("resource:///modules/devtools/StyleEditorUI.jsm");
|
||||
Cu.import("resource:///modules/devtools/StyleEditorUtil.jsm");
|
||||
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "StyleEditorChrome",
|
||||
"resource:///modules/devtools/StyleEditorChrome.jsm");
|
||||
loader.lazyGetter(this, "StyleSheetsFront",
|
||||
() => require("devtools/server/actors/styleeditor").StyleSheetsFront);
|
||||
|
||||
this.StyleEditorPanel = function StyleEditorPanel(panelWin, toolbox) {
|
||||
EventEmitter.decorate(this);
|
||||
|
@ -32,6 +30,8 @@ this.StyleEditorPanel = function StyleEditorPanel(panelWin, toolbox) {
|
|||
this._showError = this._showError.bind(this);
|
||||
}
|
||||
|
||||
exports.StyleEditorPanel = StyleEditorPanel;
|
||||
|
||||
StyleEditorPanel.prototype = {
|
||||
get target() this._toolbox.target,
|
||||
|
||||
|
@ -54,9 +54,9 @@ StyleEditorPanel.prototype = {
|
|||
targetPromise.then(() => {
|
||||
this.target.on("close", this.destroy);
|
||||
|
||||
this._debuggee = new StyleEditorDebuggee(this.target);
|
||||
this._debuggee = StyleSheetsFront(this.target.client, this.target.form);
|
||||
|
||||
this.UI = new StyleEditorUI(this._debuggee, this._panelDoc);
|
||||
this.UI = new StyleEditorUI(this._debuggee, this.target, this._panelDoc);
|
||||
this.UI.on("error", this._showError);
|
||||
|
||||
this.isReady = true;
|
||||
|
@ -99,7 +99,6 @@ StyleEditorPanel.prototype = {
|
|||
if (!this._debuggee || !this.UI) {
|
||||
return;
|
||||
}
|
||||
let stylesheet = this._debuggee.styleSheetFromHref(href);
|
||||
this.UI.selectStyleSheet(href, line - 1, col ? col - 1 : 0);
|
||||
},
|
||||
|
|
@ -19,6 +19,10 @@ support-files =
|
|||
simple.css.gz^headers^
|
||||
simple.gz.html
|
||||
simple.html
|
||||
sourcemaps.css
|
||||
sourcemaps.css.map
|
||||
sourcemaps.scss
|
||||
sourcemaps.html
|
||||
test_private.css
|
||||
test_private.html
|
||||
|
||||
|
@ -42,3 +46,4 @@ skip-if = true
|
|||
[browser_styleeditor_sv_keynav.js]
|
||||
[browser_styleeditor_sv_resize.js]
|
||||
[browser_styleeditor_selectstylesheet.js]
|
||||
[browser_styleeditor_sourcemaps.js]
|
||||
|
|
|
@ -13,7 +13,8 @@ function test() {
|
|||
gUI = panel.UI;
|
||||
gUI.on("editor-added", function(event, editor) {
|
||||
count++;
|
||||
if (count == 2) {
|
||||
if (count == 4) {
|
||||
info("all editors added");
|
||||
runTests();
|
||||
}
|
||||
})
|
||||
|
@ -35,6 +36,8 @@ function getStylesheetNameLinkFor(aEditor) {
|
|||
}
|
||||
|
||||
function onEditor0Attach(aEditor) {
|
||||
info("first editor selected");
|
||||
|
||||
waitForFocus(function () {
|
||||
// left mouse click should focus editor 1
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
|
@ -45,6 +48,8 @@ function onEditor0Attach(aEditor) {
|
|||
}
|
||||
|
||||
function onEditor1Attach(aEditor) {
|
||||
info("second editor selected");
|
||||
|
||||
ok(aEditor.sourceEditor.hasFocus(),
|
||||
"left mouse click has given editor 1 focus");
|
||||
|
||||
|
|
|
@ -19,25 +19,25 @@ function test()
|
|||
|
||||
waitForExplicitFinish();
|
||||
addTabAndOpenStyleEditor(function (aPanel) {
|
||||
let debuggee = aPanel._debuggee;
|
||||
let UI = aPanel.UI;
|
||||
|
||||
// Spam the _onNewDocument callback multiple times before the
|
||||
// StyleEditorActor has a chance to respond to the first one.
|
||||
const SPAM_COUNT = 2;
|
||||
for (let i=0; i<SPAM_COUNT; ++i) {
|
||||
debuggee._onNewDocument();
|
||||
UI._onNewDocument();
|
||||
}
|
||||
|
||||
// Wait for the StyleEditorActor to respond to each "newDocument"
|
||||
// message.
|
||||
let loadCount = 0;
|
||||
debuggee.on("document-load", function () {
|
||||
UI.on("stylesheets-reset", function () {
|
||||
++loadCount;
|
||||
if (loadCount == SPAM_COUNT) {
|
||||
// No matter how large SPAM_COUNT is, the number of style
|
||||
// sheets should never be more than the number of style sheets
|
||||
// in the document.
|
||||
is(debuggee.styleSheets.length, 1, "correct style sheet count");
|
||||
is(UI.editors.length, 1, "correct style sheet count");
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -58,7 +58,7 @@ function testEditorAdded(aEvent, aEditor)
|
|||
}
|
||||
});
|
||||
|
||||
aEditor.styleSheet.on("property-change", function(event, property) {
|
||||
aEditor.styleSheet.on("property-change", function(property) {
|
||||
if (property == "ruleCount") {
|
||||
let ruleCount = aEditor.summary.querySelector(".stylesheet-rule-count").textContent;
|
||||
is(parseInt(ruleCount), 1,
|
||||
|
|
|
@ -15,7 +15,7 @@ function test()
|
|||
// it is loaded until the accompanying content page is loaded.
|
||||
|
||||
addTabAndOpenStyleEditor(function(panel) {
|
||||
panel.UI.once("document-load", testDocumentLoad);
|
||||
panel.UI.once("stylesheets-reset", testDocumentLoad);
|
||||
|
||||
content.location = TESTCASE_URI;
|
||||
});
|
||||
|
|
|
@ -33,12 +33,7 @@ function test() {
|
|||
}
|
||||
|
||||
function onEditorAdded(aEvent, aEditor) {
|
||||
if (aEditor.sourceLoaded) {
|
||||
checkCache();
|
||||
}
|
||||
else {
|
||||
aEditor.on("source-load", checkCache);
|
||||
}
|
||||
aEditor.getSourceEditor().then(checkCache);
|
||||
}
|
||||
|
||||
function testOnWindow(options, callback) {
|
||||
|
|
|
@ -22,6 +22,7 @@ function test()
|
|||
let count = 0;
|
||||
gUI.on("editor-added", function editorAdded(event, editor) {
|
||||
if (++count == 2) {
|
||||
info("all editors added to UI");
|
||||
gUI.off("editor-added", editorAdded);
|
||||
gUI.editors[0].getSourceEditor().then(runTests);
|
||||
}
|
||||
|
@ -41,6 +42,7 @@ function runTests()
|
|||
|
||||
gUI.on("editor-added", function editorAdded(event, editor) {
|
||||
if (++count == 2) {
|
||||
info("all editors added after reload");
|
||||
gUI.off("editor-added", editorAdded);
|
||||
gUI.editors[1].getSourceEditor().then(testRemembered);
|
||||
}
|
||||
|
@ -67,6 +69,7 @@ function testNewPage()
|
|||
gUI.on("editor-added", function editorAdded(event, editor) {
|
||||
info("editor added here")
|
||||
if (++count == 2) {
|
||||
info("all editors added after navigating page");
|
||||
gUI.off("editor-added", editorAdded);
|
||||
gUI.editors[0].getSourceEditor().then(testNotRemembered);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// https rather than chrome to improve coverage
|
||||
const TESTCASE_URI = TEST_BASE_HTTPS + "sourcemaps.html";
|
||||
const PREF = "devtools.styleeditor.source-maps-enabled";
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
|
||||
let count = 0;
|
||||
addTabAndOpenStyleEditor(function(panel) {
|
||||
let UI = panel.UI;
|
||||
UI.on("editor-added", (event, editor) => {
|
||||
if (++count >= 3) {
|
||||
// wait for 3 editors - 1 for first style sheet, 1 for the
|
||||
// generated style sheet, and 1 for original source after it
|
||||
// loads and replaces the generated style sheet.
|
||||
runTests(UI);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
content.location = TESTCASE_URI;
|
||||
}
|
||||
|
||||
function runTests(UI)
|
||||
{
|
||||
is(UI.editors.length, 2);
|
||||
|
||||
let firstEditor = UI.editors[0];
|
||||
testFirstEditor(firstEditor);
|
||||
|
||||
let ScssEditor = UI.editors[1];
|
||||
|
||||
let link = getStylesheetNameLinkFor(ScssEditor);
|
||||
link.click();
|
||||
|
||||
ScssEditor.getSourceEditor().then(() => {
|
||||
testScssEditor(ScssEditor);
|
||||
|
||||
finishUp();
|
||||
});
|
||||
}
|
||||
|
||||
function testFirstEditor(editor) {
|
||||
let name = getStylesheetNameFor(editor);
|
||||
is(name, "simple.css", "First style sheet display name is correct");
|
||||
}
|
||||
|
||||
function testScssEditor(editor) {
|
||||
let name = getStylesheetNameFor(editor);
|
||||
is(name, "sourcemaps.scss", "Original source display name is correct");
|
||||
|
||||
let text = editor.sourceEditor.getText();
|
||||
|
||||
is(text, "\n\
|
||||
$paulrougetpink: #f06;\n\
|
||||
\n\
|
||||
div {\n\
|
||||
color: $paulrougetpink;\n\
|
||||
}\n\
|
||||
\n\
|
||||
span {\n\
|
||||
background-color: #EEE;\n\
|
||||
}", "Original source text is correct");
|
||||
}
|
||||
|
||||
/* Helpers */
|
||||
function getStylesheetNameLinkFor(editor) {
|
||||
return editor.summary.querySelector(".stylesheet-name");
|
||||
}
|
||||
|
||||
function getStylesheetNameFor(editor) {
|
||||
return editor.summary.querySelector(".stylesheet-name > label")
|
||||
.getAttribute("value")
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
finish();
|
||||
}
|
|
@ -46,46 +46,10 @@ function openStyleEditorInWindow(win, callback) {
|
|||
gPanelWindow = panel._panelWin;
|
||||
|
||||
panel.UI._alwaysDisableAnimations = true;
|
||||
|
||||
/*
|
||||
if (aSheet) {
|
||||
panel.selectStyleSheet(aSheet, aLine, aCol);
|
||||
} */
|
||||
|
||||
callback(panel);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
function launchStyleEditorChrome(aCallback, aSheet, aLine, aCol)
|
||||
{
|
||||
launchStyleEditorChromeFromWindow(window, aCallback, aSheet, aLine, aCol);
|
||||
}
|
||||
|
||||
function launchStyleEditorChromeFromWindow(aWindow, aCallback, aSheet, aLine, aCol)
|
||||
{
|
||||
let target = TargetFactory.forTab(aWindow.gBrowser.selectedTab);
|
||||
gDevTools.showToolbox(target, "styleeditor").then(function(toolbox) {
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
gPanelWindow = panel._panelWin;
|
||||
gPanelWindow.styleEditorChrome._alwaysDisableAnimations = true;
|
||||
if (aSheet) {
|
||||
panel.selectStyleSheet(aSheet, aLine, aCol);
|
||||
}
|
||||
aCallback(gPanelWindow.styleEditorChrome);
|
||||
});
|
||||
}
|
||||
|
||||
function addTabAndLaunchStyleEditorChromeWhenLoaded(aCallback, aSheet, aLine, aCol)
|
||||
{
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
|
||||
launchStyleEditorChrome(aCallback, aSheet, aLine, aCol);
|
||||
}, true);
|
||||
}
|
||||
*/
|
||||
|
||||
function checkDiskCacheFor(host, done)
|
||||
{
|
||||
let foundPrivateData = false;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
div {
|
||||
color: #ff0066; }
|
||||
|
||||
span {
|
||||
background-color: #EEE; }
|
||||
|
||||
/*# sourceMappingURL=sourcemaps.css.map */
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"version": 3,
|
||||
"mappings": "AAGA,GAAI;EACF,KAAK,EAHU,OAAI;;AAMrB,IAAK;EACH,gBAAgB,EAAE,IAAI",
|
||||
"sources": ["sourcemaps.scss"],
|
||||
"names": [],
|
||||
"file": "sourcemaps.css"
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>testcase for testing CSS source maps</title>
|
||||
<link rel="stylesheet" type="text/css" href="simple.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="sourcemaps.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div>source maps <span>testcase</span></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
$paulrougetpink: #f06;
|
||||
|
||||
div {
|
||||
color: $paulrougetpink;
|
||||
}
|
||||
|
||||
span {
|
||||
background-color: #EEE;
|
||||
}
|
|
@ -26,6 +26,8 @@ const FILTER_CHANGED_TIMEOUT = 300;
|
|||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
const PREF_ORIG_SOURCES = "devtools.styleeditor.source-maps-enabled";
|
||||
|
||||
/**
|
||||
* Helper for long-running processes that should yield occasionally to
|
||||
* the mainloop.
|
||||
|
@ -1096,6 +1098,25 @@ function SelectorView(aTree, aSelectorInfo)
|
|||
if (rule && rule.parentStyleSheet) {
|
||||
this.sheet = rule.parentStyleSheet;
|
||||
this.source = CssLogic.shortSource(this.sheet) + ":" + rule.line;
|
||||
|
||||
let showOrig = Services.prefs.getBoolPref(PREF_ORIG_SOURCES);
|
||||
if (showOrig && rule.type != ELEMENT_STYLE) {
|
||||
rule.getOriginalLocation().then(({href, line, column}) => {
|
||||
let newSource = CssLogic.shortSource({href: href}) + ":" + line;
|
||||
|
||||
// Really hacky. Setting the 'source' property won't change the
|
||||
// link's text if the link's already been loaded via template, so we
|
||||
// have to retroactively mutate the DOM.
|
||||
if (newSource != this.source && this.tree.propertyContainer) {
|
||||
let selector = '[sourcelocation="' + this.source + '"]';
|
||||
let link = this.tree.propertyContainer.querySelector(selector);
|
||||
if (link) {
|
||||
link.textContent = newSource;
|
||||
}
|
||||
}
|
||||
this.source = newSource;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.source = CssLogic.l10n("rule.sourceElement");
|
||||
this.href = "#";
|
||||
|
@ -1217,37 +1238,42 @@ SelectorView.prototype = {
|
|||
{
|
||||
let inspector = this.tree.styleInspector.inspector;
|
||||
let rule = this.selectorInfo.rule;
|
||||
let line = rule.line || 0;
|
||||
|
||||
// The style editor can only display stylesheets coming from content because
|
||||
// chrome stylesheets are not listed in the editor's stylesheet selector.
|
||||
//
|
||||
// If the stylesheet is a content stylesheet we send it to the style
|
||||
// editor else we display it in the view source window.
|
||||
//
|
||||
|
||||
let href = rule.href;
|
||||
let sheet = rule.parentStyleSheet;
|
||||
if (sheet && href && !sheet.isSystem) {
|
||||
if (!sheet || sheet.isSystem) {
|
||||
let contentDoc = null;
|
||||
if (this.tree.viewedElement.isLocal_toBeDeprecated()) {
|
||||
let rawNode = this.tree.viewedElement.rawNode();
|
||||
if (rawNode) {
|
||||
contentDoc = rawNode.ownerDocument;
|
||||
}
|
||||
}
|
||||
let viewSourceUtils = inspector.viewSourceUtils;
|
||||
viewSourceUtils.viewSource(rule.href, null, contentDoc, rule.line);
|
||||
return;
|
||||
}
|
||||
|
||||
let location = promise.resolve({
|
||||
href: rule.href,
|
||||
line: rule.line
|
||||
});
|
||||
if (rule.href && Services.prefs.getBoolPref(PREF_ORIG_SOURCES)) {
|
||||
location = rule.getOriginalLocation();
|
||||
}
|
||||
|
||||
location.then(({href, line}) => {
|
||||
let target = inspector.target;
|
||||
if (ToolDefinitions.styleEditor.isTargetSupported(target)) {
|
||||
gDevTools.showToolbox(target, "styleeditor").then(function(toolbox) {
|
||||
toolbox.getCurrentPanel().selectStyleSheet(href, line);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let contentDoc = null;
|
||||
if (this.tree.viewedElement.isLocal_toBeDeprecated()) {
|
||||
let rawNode = this.tree.viewedElement.rawNode();
|
||||
if (rawNode) {
|
||||
contentDoc = rawNode.ownerDocument;
|
||||
}
|
||||
}
|
||||
|
||||
let viewSourceUtils = inspector.viewSourceUtils;
|
||||
viewSourceUtils.viewSource(href, null, contentDoc, line);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@
|
|||
onclick="${selector.openStyleEditor}"
|
||||
onkeydown="${selector.maybeOpenStyleEditor}"
|
||||
title="${selector.href}"
|
||||
sourcelocation="${selector.source}"
|
||||
tabindex="0">${selector.source}</a>
|
||||
</span>
|
||||
<span dir="ltr" class="rule-text ${selector.statusClass} theme-fg-color3" title="${selector.statusText}">
|
||||
|
|
|
@ -22,6 +22,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
const PREF_ORIG_SOURCES = "devtools.styleeditor.source-maps-enabled";
|
||||
|
||||
/**
|
||||
* These regular expressions are adapted from firebug's css.js, and are
|
||||
* used to parse CSSStyleDeclaration's cssText attribute.
|
||||
|
@ -487,6 +489,33 @@ Rule.prototype = {
|
|||
return this.domRule ? this.domRule.line : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* The rule's column within a stylesheet
|
||||
*/
|
||||
get ruleColumn()
|
||||
{
|
||||
return this.domRule ? this.domRule.column : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get display name for this rule based on the original source
|
||||
* for this rule's style sheet.
|
||||
*
|
||||
* @return {Promise}
|
||||
* Promise which resolves with location as a string.
|
||||
*/
|
||||
getOriginalSourceString: function Rule_getOriginalSourceString()
|
||||
{
|
||||
if (this._originalSourceString) {
|
||||
return promise.resolve(this._originalSourceString);
|
||||
}
|
||||
return this.domRule.getOriginalLocation().then(({href, line}) => {
|
||||
let string = CssLogic.shortSource({href: href}) + ":" + line;
|
||||
this._originalSourceString = string;
|
||||
return string;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if the rule matches the creation options
|
||||
* specified.
|
||||
|
@ -1586,6 +1615,14 @@ RuleEditor.prototype = {
|
|||
sourceLabel.setAttribute("tooltiptext", this.rule.title);
|
||||
source.appendChild(sourceLabel);
|
||||
|
||||
let showOrig = Services.prefs.getBoolPref(PREF_ORIG_SOURCES);
|
||||
if (showOrig && this.rule.domRule.type != ELEMENT_STYLE) {
|
||||
this.rule.getOriginalSourceString().then((string) => {
|
||||
sourceLabel.setAttribute("value", string);
|
||||
sourceLabel.setAttribute("tooltiptext", string);
|
||||
})
|
||||
}
|
||||
|
||||
let code = createChild(this.element, "div", {
|
||||
class: "ruleview-code"
|
||||
});
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const {Cc, Cu, Ci} = require("chrome");
|
||||
const promise = require("sdk/core/promise");
|
||||
|
||||
let ToolDefinitions = require("main").Tools;
|
||||
|
||||
|
@ -16,6 +17,8 @@ loader.lazyGetter(this, "ComputedView", () => require("devtools/styleinspector/c
|
|||
loader.lazyGetter(this, "_strings", () => Services.strings
|
||||
.createBundle("chrome://global/locale/devtools/styleinspector.properties"));
|
||||
|
||||
const PREF_ORIG_SOURCES = "devtools.styleeditor.source-maps-enabled";
|
||||
|
||||
// This module doesn't currently export any symbols directly, it only
|
||||
// registers inspector tools.
|
||||
|
||||
|
@ -42,29 +45,30 @@ function RuleViewTool(aInspector, aWindow, aIFrame)
|
|||
|
||||
this._cssLinkHandler = (aEvent) => {
|
||||
let rule = aEvent.detail.rule;
|
||||
let line = rule.line || 0;
|
||||
|
||||
// The style editor can only display stylesheets coming from content because
|
||||
// chrome stylesheets are not listed in the editor's stylesheet selector.
|
||||
//
|
||||
// If the stylesheet is a content stylesheet we send it to the style
|
||||
// editor else we display it in the view source window.
|
||||
//
|
||||
let href = rule.href;
|
||||
let sheet = rule.parentStyleSheet;
|
||||
if (sheet && href && !sheet.isSystem) {
|
||||
let target = this.inspector.target;
|
||||
if (ToolDefinitions.styleEditor.isTargetSupported(target)) {
|
||||
gDevTools.showToolbox(target, "styleeditor").then(function(toolbox) {
|
||||
toolbox.getCurrentPanel().selectStyleSheet(href, line);
|
||||
});
|
||||
}
|
||||
|
||||
// Chrome stylesheets are not listed in the style editor, so show
|
||||
// these sheets in the view source window instead.
|
||||
if (!sheet || !rule.href || sheet.isSystem) {
|
||||
let contentDoc = this.inspector.selection.document;
|
||||
let viewSourceUtils = this.inspector.viewSourceUtils;
|
||||
viewSourceUtils.viewSource(rule.href, null, contentDoc, rule.line || 0);
|
||||
return;
|
||||
}
|
||||
|
||||
let contentDoc = this.inspector.selection.document;
|
||||
let viewSourceUtils = this.inspector.viewSourceUtils;
|
||||
viewSourceUtils.viewSource(href, null, contentDoc, line);
|
||||
let location = promise.resolve(rule.location);
|
||||
if (Services.prefs.getBoolPref(PREF_ORIG_SOURCES)) {
|
||||
location = rule.getOriginalLocation();
|
||||
}
|
||||
location.then(({ href, line, column }) => {
|
||||
let target = this.inspector.target;
|
||||
if (ToolDefinitions.styleEditor.isTargetSupported(target)) {
|
||||
gDevTools.showToolbox(target, "styleeditor").then(function(toolbox) {
|
||||
toolbox.getCurrentPanel().selectStyleSheet(href, line, column);
|
||||
});
|
||||
}
|
||||
return;
|
||||
})
|
||||
}
|
||||
|
||||
this.view.element.addEventListener("CssRuleViewCSSLinkClicked",
|
||||
|
|
|
@ -54,3 +54,10 @@ support-files = browser_ruleview_pseudoelement.html
|
|||
[browser_bug765105_background_image_tooltip.js]
|
||||
[browser_bug889638_rule_view_color_picker.js]
|
||||
[browser_bug940500_rule_view_pick_gradient_color.js]
|
||||
[browser_ruleview_original_source_link.js]
|
||||
support-files =
|
||||
sourcemaps.html
|
||||
sourcemaps.css
|
||||
sourcemaps.css.map
|
||||
sourcemaps.scss
|
||||
[browser_computedview_original_source_link.js]
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let win;
|
||||
let doc;
|
||||
let inspector;
|
||||
let computedView;
|
||||
let toolbox;
|
||||
|
||||
const TESTCASE_URI = TEST_BASE_HTTPS + "sourcemaps.html";
|
||||
const PREF = "devtools.styleeditor.source-maps-enabled";
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee,
|
||||
true);
|
||||
doc = content.document;
|
||||
waitForFocus(function () { openComputedView(highlightNode); }, content);
|
||||
}, true);
|
||||
|
||||
content.location = TESTCASE_URI;
|
||||
}
|
||||
|
||||
function highlightNode(aInspector, aComputedView)
|
||||
{
|
||||
inspector = aInspector;
|
||||
computedView = aComputedView;
|
||||
|
||||
// Highlight a node.
|
||||
let div = content.document.getElementsByTagName("div")[0];
|
||||
ok(div, "div to select exists")
|
||||
|
||||
inspector.selection.setNode(div);
|
||||
inspector.once("inspector-updated", () => {
|
||||
is(inspector.selection.node, div, "selection matches the div element");
|
||||
|
||||
expandProperty(0, testComputedViewLink);
|
||||
}).then(null, console.error);
|
||||
}
|
||||
|
||||
function testComputedViewLink() {
|
||||
let link = getLinkByIndex(0);
|
||||
waitForSuccess({
|
||||
name: "link text changed to display original source location",
|
||||
validatorFn: function()
|
||||
{
|
||||
return link.textContent == "sourcemaps.scss:4";
|
||||
},
|
||||
successFn: linkChanged,
|
||||
failureFn: linkChanged,
|
||||
});
|
||||
}
|
||||
|
||||
function linkChanged() {
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
let toolbox = gDevTools.getToolbox(target);
|
||||
|
||||
toolbox.once("styleeditor-ready", function(id, aToolbox) {
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
panel.UI.on("editor-selected", (event, editor) => {
|
||||
// The style editor selects the first sheet at first load before
|
||||
// selecting the desired sheet.
|
||||
if (editor.styleSheet.href.endsWith("scss")) {
|
||||
info("original source editor selected");
|
||||
editor.getSourceEditor().then(editorSelected);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let link = getLinkByIndex(0);
|
||||
|
||||
info("clicking rule view link");
|
||||
link.scrollIntoView();
|
||||
link.click();
|
||||
}
|
||||
|
||||
function editorSelected(editor) {
|
||||
let href = editor.styleSheet.href;
|
||||
ok(href.endsWith("sourcemaps.scss"), "selected stylesheet is correct one");
|
||||
|
||||
let {line, col} = editor.sourceEditor.getCursor();
|
||||
is(line, 3, "cursor is at correct line number in original source");
|
||||
|
||||
finishUp();
|
||||
}
|
||||
|
||||
/* Helpers */
|
||||
function expandProperty(aIndex, aCallback)
|
||||
{
|
||||
info("expanding property " + aIndex);
|
||||
let contentDoc = computedView.styleDocument;
|
||||
let expando = contentDoc.querySelectorAll(".expandable")[aIndex];
|
||||
|
||||
expando.click();
|
||||
|
||||
inspector.once("computed-view-property-expanded", aCallback);
|
||||
}
|
||||
|
||||
function getLinkByIndex(aIndex)
|
||||
{
|
||||
let contentDoc = computedView.styleDocument;
|
||||
let links = contentDoc.querySelectorAll(".rule-link .link");
|
||||
return links[aIndex];
|
||||
}
|
||||
|
||||
function finishUp()
|
||||
{
|
||||
gBrowser.removeCurrentTab();
|
||||
doc = inspector = computedView = toolbox = win = null;
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
finish();
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let win;
|
||||
let doc;
|
||||
let contentWindow;
|
||||
let inspector;
|
||||
let toolbox;
|
||||
|
||||
const TESTCASE_URI = TEST_BASE_HTTPS + "sourcemaps.html";
|
||||
const PREF = "devtools.styleeditor.source-maps-enabled";
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee,
|
||||
true);
|
||||
doc = content.document;
|
||||
waitForFocus(openToolbox, content);
|
||||
}, true);
|
||||
|
||||
content.location = TESTCASE_URI;
|
||||
}
|
||||
|
||||
function openToolbox() {
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
||||
gDevTools.showToolbox(target, "inspector").then(function(aToolbox) {
|
||||
toolbox = aToolbox;
|
||||
inspector = toolbox.getCurrentPanel();
|
||||
inspector.sidebar.select("ruleview");
|
||||
highlightNode();
|
||||
});
|
||||
}
|
||||
|
||||
function highlightNode()
|
||||
{
|
||||
// Highlight a node.
|
||||
let div = content.document.getElementsByTagName("div")[0];
|
||||
|
||||
inspector.selection.setNode(div);
|
||||
inspector.once("inspector-updated", () => {
|
||||
is(inspector.selection.node, div, "selection matches the div element");
|
||||
testRuleViewLink();
|
||||
}).then(null, console.error);
|
||||
}
|
||||
|
||||
function testRuleViewLink() {
|
||||
let label = getLinkByIndex(1).querySelector("label");
|
||||
|
||||
waitForSuccess({
|
||||
name: "link text changed to display original source location",
|
||||
validatorFn: function()
|
||||
{
|
||||
return label.getAttribute("value") == "sourcemaps.scss:4";
|
||||
},
|
||||
successFn: linkChanged,
|
||||
failureFn: linkChanged,
|
||||
});
|
||||
}
|
||||
|
||||
function linkChanged() {
|
||||
toolbox.once("styleeditor-ready", function(id, aToolbox) {
|
||||
let panel = toolbox.getCurrentPanel();
|
||||
panel.UI.on("editor-selected", (event, editor) => {
|
||||
// The style editor selects the first sheet at first load before
|
||||
// selecting the desired sheet.
|
||||
if (editor.styleSheet.href.endsWith("scss")) {
|
||||
info("original source editor selected");
|
||||
editor.getSourceEditor().then(editorSelected);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let link = getLinkByIndex(1);
|
||||
|
||||
info("clicking rule view link");
|
||||
link.scrollIntoView();
|
||||
link.click();
|
||||
}
|
||||
|
||||
function editorSelected(editor) {
|
||||
let href = editor.styleSheet.href;
|
||||
ok(href.endsWith("sourcemaps.scss"), "selected stylesheet is correct one");
|
||||
|
||||
let {line, col} = editor.sourceEditor.getCursor();
|
||||
is(line, 3, "cursor is at correct line number in original source");
|
||||
|
||||
finishUp();
|
||||
}
|
||||
|
||||
function getLinkByIndex(aIndex)
|
||||
{
|
||||
let contentDoc = ruleView().doc;
|
||||
contentWindow = contentDoc.defaultView;
|
||||
let links = contentDoc.querySelectorAll(".ruleview-rule-source");
|
||||
return links[aIndex];
|
||||
}
|
||||
|
||||
function finishUp()
|
||||
{
|
||||
gBrowser.removeCurrentTab();
|
||||
contentWindow = doc = inspector = toolbox = win = null;
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
finish();
|
||||
}
|
|
@ -3,6 +3,9 @@
|
|||
* 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/. */
|
||||
|
||||
const TEST_BASE_HTTP = "http://example.com/browser/browser/devtools/styleinspector/test/";
|
||||
const TEST_BASE_HTTPS = "https://example.com/browser/browser/devtools/styleinspector/test/";
|
||||
|
||||
Services.prefs.setBoolPref("devtools.debugger.log", true);
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("devtools.debugger.log");
|
||||
|
@ -187,6 +190,53 @@ function getComputedPropertyValue(aName)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Polls a given function waiting for it to become true.
|
||||
*
|
||||
* @param object aOptions
|
||||
* Options object with the following properties:
|
||||
* - validatorFn
|
||||
* A validator function that returns a boolean. This is called every few
|
||||
* milliseconds to check if the result is true. When it is true, succesFn
|
||||
* is called and polling stops. If validatorFn never returns true, then
|
||||
* polling timeouts after several tries and a failure is recorded.
|
||||
* - successFn
|
||||
* A function called when the validator function returns true.
|
||||
* - failureFn
|
||||
* A function called if the validator function timeouts - fails to return
|
||||
* true in the given time.
|
||||
* - name
|
||||
* Name of test. This is used to generate the success and failure
|
||||
* messages.
|
||||
* - timeout
|
||||
* Timeout for validator function, in milliseconds. Default is 5000.
|
||||
*/
|
||||
function waitForSuccess(aOptions)
|
||||
{
|
||||
let start = Date.now();
|
||||
let timeout = aOptions.timeout || 5000;
|
||||
|
||||
function wait(validatorFn, successFn, failureFn)
|
||||
{
|
||||
if ((Date.now() - start) > timeout) {
|
||||
// Log the failure.
|
||||
ok(false, "Timed out while waiting for: " + aOptions.name);
|
||||
failureFn(aOptions);
|
||||
return;
|
||||
}
|
||||
|
||||
if (validatorFn(aOptions)) {
|
||||
ok(true, aOptions.name);
|
||||
successFn();
|
||||
}
|
||||
else {
|
||||
setTimeout(function() wait(validatorFn, successFn, failureFn), 100);
|
||||
}
|
||||
}
|
||||
|
||||
wait(aOptions.validatorFn, aOptions.successFn, aOptions.failureFn);
|
||||
}
|
||||
|
||||
registerCleanupFunction(tearDown);
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
div {
|
||||
color: #ff0066; }
|
||||
|
||||
span {
|
||||
background-color: #EEE; }
|
||||
|
||||
/*# sourceMappingURL=sourcemaps.css.map */
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"version": 3,
|
||||
"mappings": "AAGA,GAAI;EACF,KAAK,EAHU,OAAI;;AAMrB,IAAK;EACH,gBAAgB,EAAE,IAAI",
|
||||
"sources": ["sourcemaps.scss"],
|
||||
"names": [],
|
||||
"file": "sourcemaps.css"
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>testcase for testing CSS source maps</title>
|
||||
<link rel="stylesheet" type="text/css" href="simple.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="sourcemaps.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div>source maps <span>testcase</span></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
$paulrougetpink: #f06;
|
||||
|
||||
div {
|
||||
color: $paulrougetpink;
|
||||
}
|
||||
|
||||
span {
|
||||
background-color: #EEE;
|
||||
}
|
|
@ -722,7 +722,7 @@ var NodeListActor = exports.NodeListActor = protocol.ActorClass({
|
|||
/**
|
||||
* Client side of a node list as returned by querySelectorAll()
|
||||
*/
|
||||
var NodeListFront = exports.NodeLIstFront = protocol.FrontClass(NodeListActor, {
|
||||
var NodeListFront = exports.NodeListFront = protocol.FrontClass(NodeListActor, {
|
||||
initialize: function(client, form) {
|
||||
protocol.Front.prototype.initialize.call(this, client, form);
|
||||
},
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -5,11 +5,13 @@
|
|||
"use strict";
|
||||
|
||||
const {Cc, Ci} = require("chrome");
|
||||
const promise = require("sdk/core/promise");
|
||||
const protocol = require("devtools/server/protocol");
|
||||
const {Arg, Option, method, RetVal, types} = protocol;
|
||||
const events = require("sdk/event/core");
|
||||
const object = require("sdk/util/object");
|
||||
const { Class } = require("sdk/core/heritage");
|
||||
const { StyleSheetActor } = require("devtools/server/actors/styleeditor");
|
||||
|
||||
loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
|
||||
loader.lazyGetter(this, "CssLogic", () => require("devtools/styleinspector/css-logic").CssLogic);
|
||||
|
@ -104,7 +106,7 @@ var PageStyleActor = protocol.ActorClass({
|
|||
if (this.refMap.has(sheet)) {
|
||||
return this.refMap.get(sheet);
|
||||
}
|
||||
let actor = StyleSheetActor(this, sheet);
|
||||
let actor = new StyleSheetActor(sheet, this, this.walker.rootWin);
|
||||
this.manage(actor);
|
||||
this.refMap.set(sheet, actor);
|
||||
|
||||
|
@ -253,7 +255,7 @@ var PageStyleActor = protocol.ActorClass({
|
|||
},
|
||||
response: RetVal(types.addDictType("matchedselectorresponse", {
|
||||
rules: "array:domstylerule",
|
||||
sheets: "array:domsheet",
|
||||
sheets: "array:stylesheet",
|
||||
matched: "array:matchedselector"
|
||||
}))
|
||||
}),
|
||||
|
@ -339,7 +341,7 @@ var PageStyleActor = protocol.ActorClass({
|
|||
response: RetVal(types.addDictType("appliedStylesReturn", {
|
||||
entries: "array:appliedstyle",
|
||||
rules: "array:domstylerule",
|
||||
sheets: "array:domsheet"
|
||||
sheets: "array:stylesheet"
|
||||
}))
|
||||
}),
|
||||
|
||||
|
@ -546,73 +548,6 @@ var PageStyleFront = protocol.FrontClass(PageStyleActor, {
|
|||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* Actor representing an nsIDOMCSSStyleSheet.
|
||||
*/
|
||||
var StyleSheetActor = protocol.ActorClass({
|
||||
typeName: "domsheet",
|
||||
|
||||
initialize: function(pageStyle, sheet) {
|
||||
protocol.Front.prototype.initialize.call(this);
|
||||
this.pageStyle = pageStyle;
|
||||
this.rawSheet = sheet;
|
||||
},
|
||||
|
||||
get conn() this.pageStyle.conn,
|
||||
|
||||
form: function(detail) {
|
||||
if (detail === "actorid") {
|
||||
return this.actorID;
|
||||
}
|
||||
|
||||
let href;
|
||||
if (this.rawSheet.ownerNode) {
|
||||
if (this.rawSheet.ownerNode instanceof Ci.nsIDOMHTMLDocument)
|
||||
href = this.rawSheet.ownerNode.location.href;
|
||||
if (this.rawSheet.ownerNode.ownerDocument)
|
||||
href = this.rawSheet.ownerNode.ownerDocument.location.href;
|
||||
}
|
||||
|
||||
return {
|
||||
actor: this.actorID,
|
||||
|
||||
// href stores the uri of the sheet
|
||||
href: this.rawSheet.href,
|
||||
|
||||
// nodeHref stores the URI of the document that
|
||||
// included the sheet.
|
||||
nodeHref: href,
|
||||
|
||||
system: !CssLogic.isContentStylesheet(this.rawSheet),
|
||||
disabled: this.rawSheet.disabled ? true : undefined
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Front for the StyleSheetActor.
|
||||
*/
|
||||
var StyleSheetFront = protocol.FrontClass(StyleSheetActor, {
|
||||
initialize: function(conn, form, ctx, detail) {
|
||||
protocol.Front.prototype.initialize.call(this, conn, form, ctx, detail);
|
||||
},
|
||||
|
||||
form: function(form, detail) {
|
||||
if (detail === "actorid") {
|
||||
this.actorID = form;
|
||||
return;
|
||||
}
|
||||
this.actorID = form.actorID;
|
||||
this._form = form;
|
||||
},
|
||||
|
||||
get href() this._form.href,
|
||||
get nodeHref() this._form.nodeHref,
|
||||
get disabled() !!this._form.disabled,
|
||||
get isSystem() this._form.system
|
||||
});
|
||||
|
||||
|
||||
// Predeclare the domstylerule actor type
|
||||
types.addActorType("domstylerule");
|
||||
|
||||
|
@ -636,6 +571,7 @@ var StyleRuleActor = protocol.ActorClass({
|
|||
this.rawRule = item;
|
||||
if (this.rawRule instanceof Ci.nsIDOMCSSStyleRule && this.rawRule.parentStyleSheet) {
|
||||
this.line = DOMUtils.getRuleLine(this.rawRule);
|
||||
this.column = DOMUtils.getRuleColumn(this.rawRule);
|
||||
}
|
||||
} else {
|
||||
// Fake a rule
|
||||
|
@ -665,6 +601,7 @@ var StyleRuleActor = protocol.ActorClass({
|
|||
actor: this.actorID,
|
||||
type: this.type,
|
||||
line: this.line || undefined,
|
||||
column: this.column
|
||||
};
|
||||
|
||||
if (this.rawRule.parentRule) {
|
||||
|
@ -788,6 +725,7 @@ var StyleRuleFront = protocol.FrontClass(StyleRuleActor, {
|
|||
|
||||
get type() this._form.type,
|
||||
get line() this._form.line || -1,
|
||||
get column() this._form.column || -1,
|
||||
get cssText() {
|
||||
return this._form.cssText;
|
||||
},
|
||||
|
@ -828,6 +766,40 @@ var StyleRuleFront = protocol.FrontClass(StyleRuleActor, {
|
|||
return sheet.href || sheet.nodeHref;
|
||||
},
|
||||
|
||||
get location()
|
||||
{
|
||||
return {
|
||||
href: this.href,
|
||||
line: this.line,
|
||||
column: this.column
|
||||
};
|
||||
},
|
||||
|
||||
getOriginalLocation: function()
|
||||
{
|
||||
if (this._originalLocation) {
|
||||
return promise.resolve(this._originalLocation);
|
||||
}
|
||||
|
||||
let parentSheet = this.parentStyleSheet;
|
||||
if (!parentSheet) {
|
||||
return promise.resolve(this.location);
|
||||
}
|
||||
return parentSheet.getOriginalLocation(this.line, this.column)
|
||||
.then(({ source, line, column }) => {
|
||||
let location = {
|
||||
href: source,
|
||||
line: line,
|
||||
column: column
|
||||
}
|
||||
if (!source) {
|
||||
location.href = this.href;
|
||||
}
|
||||
this._originalLocation = location;
|
||||
return location;
|
||||
})
|
||||
},
|
||||
|
||||
// Only used for testing, please keep it that way.
|
||||
_rawStyle: function() {
|
||||
if (!this.conn._transport._serverConnection) {
|
||||
|
|
|
@ -352,12 +352,12 @@ var DebuggerServer = {
|
|||
if ("nsIProfiler" in Ci)
|
||||
this.addActors("resource://gre/modules/devtools/server/actors/profiler.js");
|
||||
|
||||
this.addActors("resource://gre/modules/devtools/server/actors/styleeditor.js");
|
||||
this.addActors("resource://gre/modules/devtools/server/actors/webapps.js");
|
||||
this.registerModule("devtools/server/actors/inspector");
|
||||
this.registerModule("devtools/server/actors/webgl");
|
||||
this.registerModule("devtools/server/actors/tracer");
|
||||
this.registerModule("devtools/server/actors/device");
|
||||
this.registerModule("devtools/server/actors/styleeditor");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -372,9 +372,9 @@ var DebuggerServer = {
|
|||
this.addActors("resource://gre/modules/devtools/server/actors/script.js");
|
||||
this.addActors("resource://gre/modules/devtools/server/actors/webconsole.js");
|
||||
this.addActors("resource://gre/modules/devtools/server/actors/gcli.js");
|
||||
this.addActors("resource://gre/modules/devtools/server/actors/styleeditor.js");
|
||||
this.registerModule("devtools/server/actors/inspector");
|
||||
this.registerModule("devtools/server/actors/webgl");
|
||||
this.registerModule("devtools/server/actors/styleeditor");
|
||||
}
|
||||
if (!("ContentAppActor" in DebuggerServer)) {
|
||||
this.addActors("resource://gre/modules/devtools/server/actors/childtab.js");
|
||||
|
|
Загрузка…
Ссылка в новой задаче