mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 950915 - Watch for changes to CSS files on disk for source mapped files; r=dcamp
This commit is contained in:
parent
fb7f12c413
commit
cf4c251429
@ -14,6 +14,7 @@ const Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/PluralForm.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.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/gDevTools.jsm");
|
||||
@ -227,6 +228,7 @@ StyleEditorUI.prototype = {
|
||||
sources.forEach((source) => {
|
||||
// set so the first sheet will be selected, even if it's a source
|
||||
source.styleSheetIndex = styleSheet.styleSheetIndex;
|
||||
source.relatedStyleSheet = styleSheet;
|
||||
|
||||
this._addStyleSheetEditor(source);
|
||||
});
|
||||
@ -250,6 +252,8 @@ StyleEditorUI.prototype = {
|
||||
|
||||
editor.on("property-change", this._summaryChange.bind(this, editor));
|
||||
editor.on("style-applied", this._summaryChange.bind(this, editor));
|
||||
editor.on("linked-css-file", this._summaryChange.bind(this, editor));
|
||||
editor.on("linked-css-file-error", this._summaryChange.bind(this, editor));
|
||||
editor.on("error", this._onError);
|
||||
|
||||
this.editors.push(editor);
|
||||
@ -557,9 +561,13 @@ StyleEditorUI.prototype = {
|
||||
if (!summary) {
|
||||
return;
|
||||
}
|
||||
let ruleCount = "-";
|
||||
if (editor.styleSheet.ruleCount !== undefined) {
|
||||
ruleCount = editor.styleSheet.ruleCount;
|
||||
|
||||
let ruleCount = editor.styleSheet.ruleCount;
|
||||
if (editor.styleSheet.relatedStyleSheet) {
|
||||
ruleCount = editor.styleSheet.relatedStyleSheet.ruleCount;
|
||||
}
|
||||
if (ruleCount === undefined) {
|
||||
ruleCount = "-";
|
||||
}
|
||||
|
||||
var flags = [];
|
||||
@ -569,15 +577,22 @@ StyleEditorUI.prototype = {
|
||||
if (editor.unsaved) {
|
||||
flags.push("unsaved");
|
||||
}
|
||||
if (editor.linkedCSSFileError) {
|
||||
flags.push("linked-file-error");
|
||||
}
|
||||
this._view.setItemClassName(summary, flags.join(" "));
|
||||
|
||||
let label = summary.querySelector(".stylesheet-name > label");
|
||||
label.setAttribute("value", editor.friendlyName);
|
||||
|
||||
let linkedCSSFile = "";
|
||||
if (editor.linkedCSSFile) {
|
||||
linkedCSSFile = OS.Path.basename(editor.linkedCSSFile);
|
||||
}
|
||||
text(summary, ".stylesheet-linked-file", linkedCSSFile);
|
||||
text(summary, ".stylesheet-title", editor.styleSheet.title || "");
|
||||
text(summary, ".stylesheet-rule-count",
|
||||
PluralForm.get(ruleCount, _("ruleCount.label")).replace("#1", ruleCount));
|
||||
text(summary, ".stylesheet-error-message", editor.errorMessage);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
|
@ -34,6 +34,13 @@ const UPDATE_STYLESHEET_THROTTLE_DELAY = 500;
|
||||
// Pref which decides if CSS autocompletion is enabled in Style Editor or not.
|
||||
const AUTOCOMPLETION_PREF = "devtools.styleeditor.autocompletion-enabled";
|
||||
|
||||
// How long to wait to update linked CSS file after original source was saved
|
||||
// to disk. Time in ms.
|
||||
const CHECK_LINKED_SHEET_DELAY=500;
|
||||
|
||||
// How many times to check for linked file changes
|
||||
const MAX_CHECK_COUNT=10;
|
||||
|
||||
/**
|
||||
* StyleSheetEditor controls the editor linked to a particular StyleSheet
|
||||
* object.
|
||||
@ -59,28 +66,18 @@ function StyleSheetEditor(styleSheet, win, file, isNew, walker) {
|
||||
|
||||
this.styleSheet = styleSheet;
|
||||
this._inputElement = null;
|
||||
this._sourceEditor = null;
|
||||
this.sourceEditor = null;
|
||||
this._window = win;
|
||||
this._isNew = isNew;
|
||||
this.savedFile = file;
|
||||
this.walker = walker;
|
||||
|
||||
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: readOnly,
|
||||
topIndex: 0, // the first visible line
|
||||
topIndex: 0 // the first visible line
|
||||
};
|
||||
|
||||
this._styleSheetFilePath = null;
|
||||
@ -91,11 +88,20 @@ function StyleSheetEditor(styleSheet, win, file, isNew, walker) {
|
||||
|
||||
this._onPropertyChange = this._onPropertyChange.bind(this);
|
||||
this._onError = this._onError.bind(this);
|
||||
this.checkLinkedFileForChanges = this.checkLinkedFileForChanges.bind(this);
|
||||
this.markLinkedFileBroken = this.markLinkedFileBroken.bind(this);
|
||||
|
||||
this._focusOnSourceEditorReady = false;
|
||||
|
||||
let relatedSheet = this.styleSheet.relatedStyleSheet;
|
||||
if (relatedSheet) {
|
||||
relatedSheet.on("property-change", this._onPropertyChange);
|
||||
}
|
||||
this.styleSheet.on("property-change", this._onPropertyChange);
|
||||
this.styleSheet.on("error", this._onError);
|
||||
|
||||
this.savedFile = file;
|
||||
this.linkCSSFile();
|
||||
}
|
||||
|
||||
StyleSheetEditor.prototype = {
|
||||
@ -114,6 +120,16 @@ StyleSheetEditor.prototype = {
|
||||
return this._isNew;
|
||||
},
|
||||
|
||||
get savedFile() {
|
||||
return this._savedFile;
|
||||
},
|
||||
|
||||
set savedFile(name) {
|
||||
this._savedFile = name;
|
||||
|
||||
this.linkCSSFile();
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a user-friendly name for the style sheet.
|
||||
*
|
||||
@ -145,6 +161,48 @@ StyleSheetEditor.prototype = {
|
||||
return this._friendlyName;
|
||||
},
|
||||
|
||||
/**
|
||||
* If this is an original source, get the path of the CSS file it generated.
|
||||
*/
|
||||
linkCSSFile: function() {
|
||||
if (!this.styleSheet.isOriginalSource) {
|
||||
return;
|
||||
}
|
||||
|
||||
let relatedSheet = this.styleSheet.relatedStyleSheet;
|
||||
|
||||
let path;
|
||||
var uri = NetUtil.newURI(relatedSheet.href);
|
||||
|
||||
if (uri.scheme == "file") {
|
||||
var file = uri.QueryInterface(Ci.nsIFileURL).file;
|
||||
path = file.path;
|
||||
}
|
||||
else if (this.savedFile) {
|
||||
let origUri = NetUtil.newURI(this.styleSheet.href);
|
||||
path = findLinkedFilePath(uri, origUri, this.savedFile);
|
||||
}
|
||||
else {
|
||||
// we can't determine path to generated file on disk
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.linkedCSSFile == path) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.linkedCSSFile = path;
|
||||
|
||||
this.linkedCSSFileError = null;
|
||||
|
||||
// save last file change time so we can compare when we check for changes.
|
||||
OS.File.stat(path).then((info) => {
|
||||
this._fileModDate = info.lastModificationDate.getTime();
|
||||
}, this.markLinkedFileBroken);
|
||||
|
||||
this.emit("linked-css-file");
|
||||
},
|
||||
|
||||
/**
|
||||
* Start fetching the full text source for this editor's sheet.
|
||||
*/
|
||||
@ -196,7 +254,7 @@ StyleSheetEditor.prototype = {
|
||||
value: this._state.text,
|
||||
lineNumbers: true,
|
||||
mode: Editor.modes.css,
|
||||
readOnly: this._state.readOnly,
|
||||
readOnly: false,
|
||||
autoCloseBrackets: "{}()[]",
|
||||
extraKeys: this._getKeyBindings(),
|
||||
contextMenu: "sourceEditorContextMenu"
|
||||
@ -212,9 +270,11 @@ StyleSheetEditor.prototype = {
|
||||
this.saveToFile();
|
||||
});
|
||||
|
||||
sourceEditor.on("change", () => {
|
||||
this.updateStyleSheet();
|
||||
});
|
||||
if (this.styleSheet.update) {
|
||||
sourceEditor.on("change", () => {
|
||||
this.updateStyleSheet();
|
||||
});
|
||||
}
|
||||
|
||||
this.sourceEditor = sourceEditor;
|
||||
|
||||
@ -255,8 +315,8 @@ StyleSheetEditor.prototype = {
|
||||
* Focus the Style Editor input.
|
||||
*/
|
||||
focus: function() {
|
||||
if (this._sourceEditor) {
|
||||
this._sourceEditor.focus();
|
||||
if (this.sourceEditor) {
|
||||
this.sourceEditor.focus();
|
||||
} else {
|
||||
this._focusOnSourceEditorReady = true;
|
||||
}
|
||||
@ -266,8 +326,8 @@ StyleSheetEditor.prototype = {
|
||||
* Event handler for when the editor is shown.
|
||||
*/
|
||||
onShow: function() {
|
||||
if (this._sourceEditor) {
|
||||
this._sourceEditor.setFirstVisibleLine(this._state.topIndex);
|
||||
if (this.sourceEditor) {
|
||||
this.sourceEditor.setFirstVisibleLine(this._state.topIndex);
|
||||
}
|
||||
this.focus();
|
||||
},
|
||||
@ -343,8 +403,8 @@ StyleSheetEditor.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._sourceEditor) {
|
||||
this._state.text = this._sourceEditor.getText();
|
||||
if (this.sourceEditor) {
|
||||
this._state.text = this.sourceEditor.getText();
|
||||
}
|
||||
|
||||
let ostream = FileUtils.openSafeFileOutputStream(returnFile);
|
||||
@ -362,16 +422,12 @@ StyleSheetEditor.prototype = {
|
||||
return;
|
||||
}
|
||||
FileUtils.closeSafeFileOutputStream(ostream);
|
||||
// remember filename for next save if any
|
||||
this._friendlyName = null;
|
||||
this.savedFile = returnFile;
|
||||
|
||||
this.onFileSaved(returnFile);
|
||||
|
||||
if (callback) {
|
||||
callback(returnFile);
|
||||
}
|
||||
this.sourceEditor.setClean();
|
||||
|
||||
this.emit("property-change");
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
@ -381,7 +437,81 @@ StyleSheetEditor.prototype = {
|
||||
}
|
||||
showFilePicker(file || this._styleSheetFilePath, true, this._window,
|
||||
onFile, defaultName);
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when this source has been successfully saved to disk.
|
||||
*/
|
||||
onFileSaved: function(returnFile) {
|
||||
this._friendlyName = null;
|
||||
this.savedFile = returnFile;
|
||||
|
||||
this.sourceEditor.setClean();
|
||||
|
||||
this.emit("property-change");
|
||||
|
||||
// TODO: replace with file watching
|
||||
this._modCheckCount = 0;
|
||||
this._window.clearTimeout(this._timeout);
|
||||
|
||||
if (this.linkedCSSFile && !this.linkedCSSFileError) {
|
||||
this._timeout = this._window.setTimeout(this.checkLinkedFileForChanges,
|
||||
CHECK_LINKED_SHEET_DELAY);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check to see if our linked CSS file has changed on disk, and
|
||||
* if so, update the live style sheet.
|
||||
*/
|
||||
checkLinkedFileForChanges: function() {
|
||||
OS.File.stat(this.linkedCSSFile).then((info) => {
|
||||
let lastChange = info.lastModificationDate.getTime();
|
||||
|
||||
if (this._fileModDate && lastChange != this._fileModDate) {
|
||||
this._fileModDate = lastChange;
|
||||
this._modCheckCount = 0;
|
||||
|
||||
this.updateLinkedStyleSheet();
|
||||
return;
|
||||
}
|
||||
|
||||
if (++this._modCheckCount > MAX_CHECK_COUNT) {
|
||||
this.updateLinkedStyleSheet();
|
||||
return;
|
||||
}
|
||||
|
||||
// try again in a bit
|
||||
this._timeout = this._window.setTimeout(this.checkLinkedFileForChanges,
|
||||
CHECK_LINKED_SHEET_DELAY);
|
||||
}, this.markLinkedFileBroken);
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify that the linked CSS file (if this is an original source)
|
||||
* doesn't exist on disk in the place we think it does.
|
||||
*
|
||||
* @param string error
|
||||
* The error we got when trying to access the file.
|
||||
*/
|
||||
markLinkedFileBroken: function(error) {
|
||||
this.linkedCSSFileError = error || true;
|
||||
this.emit("linked-css-file-error");
|
||||
},
|
||||
|
||||
/**
|
||||
* For original sources (e.g. Sass files). Fetch contents of linked CSS
|
||||
* file from disk and live update the stylesheet object with the contents.
|
||||
*/
|
||||
updateLinkedStyleSheet: function() {
|
||||
OS.File.read(this.linkedCSSFile).then((array) => {
|
||||
let decoder = new TextDecoder();
|
||||
let text = decoder.decode(array);
|
||||
|
||||
let relatedSheet = this.styleSheet.relatedStyleSheet;
|
||||
relatedSheet.update(text, true);
|
||||
}, this.markLinkedFileBroken);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve custom key bindings objects as expected by Editor.
|
||||
@ -482,3 +612,73 @@ function prettifyCSS(text)
|
||||
return parts.join(LINE_SEPARATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a path on disk for a file given it's hosted uri, the uri of the
|
||||
* original resource that generated it (e.g. Sass file), and the location of the
|
||||
* local file for that source.
|
||||
*/
|
||||
function findLinkedFilePath(uri, origUri, file) {
|
||||
let project = findProjectPath(origUri, file);
|
||||
let branch = findUnsharedBranch(origUri, uri);
|
||||
|
||||
let parts = project.concat(branch);
|
||||
let path = OS.Path.join.apply(this, parts);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the path of a project given a file in the project and the uri
|
||||
* of that resource. e.g.:
|
||||
* "http://localhost/src/a.css" and "/Users/moz/proj/src/a.css"
|
||||
* would yeild ["Users", "moz", "proj"]
|
||||
*
|
||||
* @param {nsIURI} uri
|
||||
* uri of hosted resource
|
||||
* @param {nsIFile} file
|
||||
* file for that resource on disk
|
||||
* @return {array}
|
||||
* array of path parts
|
||||
*/
|
||||
function findProjectPath(uri, file) {
|
||||
let uri = OS.Path.split(uri.path).components;
|
||||
let path = OS.Path.split(file.path).components;
|
||||
|
||||
// don't care about differing leaf names
|
||||
uri.pop();
|
||||
path.pop();
|
||||
|
||||
let dir = path.pop();
|
||||
while(dir) {
|
||||
let serverDir = uri.pop();
|
||||
if (serverDir != dir) {
|
||||
return path.concat([dir]);
|
||||
}
|
||||
dir = path.pop();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the part of a uri past the root it shares with another uri. e.g:
|
||||
* "http://localhost/built/a.scss" and "http://localhost/src/a.css"
|
||||
* would yeild ["built", "a.scss"];
|
||||
*
|
||||
* @param {nsIURI} origUri
|
||||
* uri to find unshared branch of
|
||||
* @param {nsIURI} origUri
|
||||
* uri to compare against to get a shared root
|
||||
* @return {array}
|
||||
* array of path parts for branch
|
||||
*/
|
||||
function findUnsharedBranch(origUri, uri) {
|
||||
origUri = OS.Path.split(origUri.path).components;
|
||||
uri = OS.Path.split(uri.path).components;
|
||||
|
||||
for (var i = 0; i < uri.length - 1; i++) {
|
||||
if (uri[i] != origUri[i]) {
|
||||
return uri.slice(i);
|
||||
}
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
@ -136,7 +136,6 @@ StyleEditorPanel.prototype = {
|
||||
this._toolbox = null;
|
||||
this._panelDoc = null;
|
||||
|
||||
this._debuggee.destroy();
|
||||
this.UI.destroy();
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,22 @@ li.unsaved > hgroup > h1 > .stylesheet-name:before {
|
||||
content: "*";
|
||||
}
|
||||
|
||||
li.linked-file-error .stylesheet-linked-file {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
li.linked-file-error .stylesheet-linked-file:after {
|
||||
content: " ✘";
|
||||
}
|
||||
|
||||
li.linked-file-error .stylesheet-rule-count {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.stylesheet-linked-file:not(:empty):before {
|
||||
content: " ↳ ";
|
||||
}
|
||||
|
||||
.stylesheet-enabled {
|
||||
display: -moz-box;
|
||||
cursor: pointer;
|
||||
|
@ -111,8 +111,8 @@
|
||||
<h1><a class="stylesheet-name" tabindex="0"><xul:label crop="start"/></a></h1>
|
||||
<div class="stylesheet-more">
|
||||
<h3 class="stylesheet-title"></h3>
|
||||
<h3 class="stylesheet-linked-file"></h3>
|
||||
<h3 class="stylesheet-rule-count"></h3>
|
||||
<h3 class="stylesheet-error-message"></h3>
|
||||
<xul:spacer/>
|
||||
<h3><xul:label class="stylesheet-saveButton"
|
||||
tooltiptext="&saveButton.tooltip;"
|
||||
|
@ -49,3 +49,4 @@ skip-if = true
|
||||
[browser_styleeditor_sv_resize.js]
|
||||
[browser_styleeditor_selectstylesheet.js]
|
||||
[browser_styleeditor_sourcemaps.js]
|
||||
[browser_styleeditor_sourcemap_watching.js]
|
||||
|
@ -0,0 +1,182 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
let promise = devtools.require("sdk/core/promise");
|
||||
|
||||
const TESTCASE_URI_HTML = TEST_BASE + "sourcemaps.html";
|
||||
const TESTCASE_URI_CSS = TEST_BASE + "sourcemaps.css";
|
||||
const TESTCASE_URI_REG_CSS = TEST_BASE + "simple.css";
|
||||
const TESTCASE_URI_SCSS = TEST_BASE + "sourcemaps.scss";
|
||||
const TESTCASE_URI_MAP = TEST_BASE + "sourcemaps.css.map";
|
||||
|
||||
const PREF = "devtools.styleeditor.source-maps-enabled";
|
||||
|
||||
const CSS_TEXT = "* { color: blue }";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
let tempScope = {};
|
||||
Components.utils.import("resource://gre/modules/FileUtils.jsm", tempScope);
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm", tempScope);
|
||||
let FileUtils = tempScope.FileUtils;
|
||||
let NetUtil = tempScope.NetUtil;
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
|
||||
Task.spawn(function() {
|
||||
// copy all our files over so we don't screw them up for other tests
|
||||
let HTMLFile = yield copy(TESTCASE_URI_HTML, "sourcemaps.html");
|
||||
let CSSFile = yield copy(TESTCASE_URI_CSS, "sourcemaps.css");
|
||||
yield copy(TESTCASE_URI_SCSS, "sourcemaps.scss");
|
||||
yield copy(TESTCASE_URI_MAP, "sourcemaps.css.map");
|
||||
yield copy(TESTCASE_URI_REG_CSS, "simple.css");
|
||||
|
||||
let uri = Services.io.newFileURI(HTMLFile);
|
||||
let testcaseURI = uri.resolve("");
|
||||
|
||||
let editor = yield openEditor(testcaseURI);
|
||||
|
||||
let element = content.document.querySelector("div");
|
||||
let style = content.getComputedStyle(element, null);
|
||||
|
||||
is(style.color, "rgb(255, 0, 102)", "div is red before saving file");
|
||||
|
||||
editor.styleSheet.relatedStyleSheet.once("style-applied", function() {
|
||||
is(style.color, "rgb(0, 0, 255)", "div is blue after saving file");
|
||||
finishUp();
|
||||
});
|
||||
|
||||
yield pauseForTimeChange();
|
||||
|
||||
// Edit and save Sass in the editor. This will start off a file-watching
|
||||
// process waiting for the CSS file to change.
|
||||
yield editSCSS(editor);
|
||||
|
||||
// We can't run Sass or another compiler, so we fake it by just
|
||||
// directly changing the CSS file.
|
||||
yield editCSSFile(CSSFile);
|
||||
|
||||
info("wrote to CSS file");
|
||||
})
|
||||
}
|
||||
|
||||
function openEditor(testcaseURI) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
addTabAndOpenStyleEditor((panel) => {
|
||||
info("style editor panel opened");
|
||||
|
||||
let UI = panel.UI;
|
||||
let count = 0;
|
||||
|
||||
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.
|
||||
let editor = UI.editors[1];
|
||||
|
||||
let link = getStylesheetNameLinkFor(editor);
|
||||
link.click();
|
||||
|
||||
editor.getSourceEditor().then(deferred.resolve);
|
||||
}
|
||||
});
|
||||
})
|
||||
content.location = testcaseURI;
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function editSCSS(editor) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
let pos = {line: 0, ch: 0};
|
||||
editor.sourceEditor.replaceText(CSS_TEXT, pos, pos);
|
||||
|
||||
editor.saveToFile(null, function (file) {
|
||||
ok(file, "Scss file should be saved");
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function editCSSFile(CSSFile) {
|
||||
return write(CSS_TEXT, CSSFile);
|
||||
}
|
||||
|
||||
function pauseForTimeChange() {
|
||||
let deferred = promise.defer();
|
||||
|
||||
// We have to wait for the system time to turn over > 1000 ms so that
|
||||
// our file's last change time will show a change. This reflects what
|
||||
// would happen in real life with a user manually saving the file.
|
||||
setTimeout(deferred.resolve, 2000);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
finish();
|
||||
}
|
||||
|
||||
/* Helpers */
|
||||
|
||||
function getStylesheetNameLinkFor(editor) {
|
||||
return editor.summary.querySelector(".stylesheet-name");
|
||||
}
|
||||
|
||||
function copy(aSrcChromeURL, aDestFileName)
|
||||
{
|
||||
let destFile = FileUtils.getFile("ProfD", [aDestFileName]);
|
||||
return write(read(aSrcChromeURL), destFile);
|
||||
}
|
||||
|
||||
function read(aSrcChromeURL)
|
||||
{
|
||||
let scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
|
||||
.getService(Ci.nsIScriptableInputStream);
|
||||
|
||||
let channel = Services.io.newChannel(aSrcChromeURL, null, null);
|
||||
let input = channel.open();
|
||||
scriptableStream.init(input);
|
||||
|
||||
let data = scriptableStream.read(input.available());
|
||||
scriptableStream.close();
|
||||
input.close();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function write(aData, aFile)
|
||||
{
|
||||
let deferred = promise.defer();
|
||||
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
|
||||
converter.charset = "UTF-8";
|
||||
|
||||
let istream = converter.convertToInputStream(aData);
|
||||
let ostream = FileUtils.openSafeFileOutputStream(aFile);
|
||||
|
||||
NetUtil.asyncCopy(istream, ostream, function(status) {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
info("Coudln't write to " + aFile.path);
|
||||
return;
|
||||
}
|
||||
deferred.resolve(aFile);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
@ -18,6 +18,7 @@
|
||||
}
|
||||
|
||||
.theme-dark .stylesheet-rule-count,
|
||||
.theme-dark .stylesheet-linked-file,
|
||||
.theme-dark .stylesheet-saveButton {
|
||||
color: #b6babf;
|
||||
}
|
||||
@ -28,6 +29,7 @@
|
||||
}
|
||||
|
||||
.theme-light .stylesheet-rule-count,
|
||||
.theme-light .stylesheet-linked-file,
|
||||
.theme-light .stylesheet-saveButton {
|
||||
color: #18191a;
|
||||
}
|
||||
@ -40,6 +42,7 @@
|
||||
.splitview-active .stylesheet-title,
|
||||
.splitview-active .stylesheet-name,
|
||||
.theme-light .splitview-active .stylesheet-rule-count,
|
||||
.theme-light .splitview-active .stylesheet-linked-file,
|
||||
.theme-light .splitview-active .stylesheet-saveButton {
|
||||
color: #f5f7fa;
|
||||
}
|
||||
@ -85,8 +88,16 @@
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.stylesheet-error-message {
|
||||
color: red;
|
||||
.stylesheet-linked-file:not(:empty){
|
||||
-moz-margin-end: 0.4em;
|
||||
}
|
||||
|
||||
.stylesheet-linked-file:not(:empty):before {
|
||||
-moz-margin-start: 0.4em;
|
||||
}
|
||||
|
||||
li.linked-file-error .stylesheet-linked-file:after {
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
.stylesheet-more > h3 {
|
||||
|
@ -547,7 +547,7 @@ let StyleSheetActor = protocol.ActorClass({
|
||||
*/
|
||||
_setSourceMapRoot: function(aSourceMap, aAbsSourceMapURL, aScriptURL) {
|
||||
const base = dirname(
|
||||
aAbsSourceMapURL.indexOf("data:") === 0
|
||||
aAbsSourceMapURL.startsWith("data:")
|
||||
? aScriptURL
|
||||
: aAbsSourceMapURL);
|
||||
aSourceMap.sourceRoot = aSourceMap.sourceRoot
|
||||
@ -700,9 +700,9 @@ let StyleSheetActor = protocol.ActorClass({
|
||||
},
|
||||
|
||||
/**
|
||||
* This cleans up class and rule added for transition effect and then
|
||||
* notifies that the style has been applied.
|
||||
*/
|
||||
* This cleans up class and rule added for transition effect and then
|
||||
* notifies that the style has been applied.
|
||||
*/
|
||||
_onTransitionEnd: function()
|
||||
{
|
||||
if (--this._transitionRefCount == 0) {
|
||||
@ -718,8 +718,8 @@ let StyleSheetActor = protocol.ActorClass({
|
||||
* StyleSheetFront is the client-side counterpart to a StyleSheetActor.
|
||||
*/
|
||||
var StyleSheetFront = protocol.FrontClass(StyleSheetActor, {
|
||||
initialize: function(conn, form, ctx, detail) {
|
||||
protocol.Front.prototype.initialize.call(this, conn, form, ctx, detail);
|
||||
initialize: function(conn, form) {
|
||||
protocol.Front.prototype.initialize.call(this, conn, form);
|
||||
|
||||
this._onPropertyChange = this._onPropertyChange.bind(this);
|
||||
events.on(this, "property-change", this._onPropertyChange);
|
||||
@ -775,7 +775,7 @@ let OriginalSourceActor = protocol.ActorClass({
|
||||
return {
|
||||
actor: this.actorID, // actorID is set when it's added to a pool
|
||||
url: this.url,
|
||||
parentSource: this.parentActor.actorID
|
||||
relatedStyleSheet: this.parentActor.form()
|
||||
};
|
||||
},
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user