This commit is contained in:
Tim Taubert 2012-02-18 02:03:47 +01:00
Родитель f58ce433db f5740f3cb0
Коммит 015ecf1d5c
34 изменённых файлов: 755 добавлений и 85 удалений

Просмотреть файл

@ -9053,7 +9053,14 @@ XPCOMUtils.defineLazyGetter(Scratchpad, "ScratchpadManager", function() {
var StyleEditor = {
prefEnabledName: "devtools.styleeditor.enabled",
openChrome: function SE_openChrome()
/**
* Opens the style editor. If the UI is already open, it will be focused.
*
* @param {CSSStyleSheet} [aSelectedStyleSheet] default Stylesheet.
* @param {Number} [aLine] Line to which the caret should be moved (one-indexed).
* @param {Number} [aCol] Column to which the caret should be moved (one-indexed).
*/
openChrome: function SE_openChrome(aSelectedStyleSheet, aLine, aCol)
{
const CHROME_URL = "chrome://browser/content/styleeditor.xul";
const CHROME_WINDOW_TYPE = "Tools:StyleEditor";
@ -9067,14 +9074,23 @@ var StyleEditor = {
while (enumerator.hasMoreElements()) {
var win = enumerator.getNext();
if (win.styleEditorChrome.contentWindowID == contentWindowID) {
if (aSelectedStyleSheet) {
win.styleEditorChrome.selectStyleSheet(aSelectedStyleSheet, aLine, aCol);
}
win.focus();
return win;
}
}
let args = {
contentWindow: contentWindow,
selectedStyleSheet: aSelectedStyleSheet,
line: aLine,
col: aCol
};
args.wrappedJSObject = args;
let chromeWindow = Services.ww.openWindow(null, CHROME_URL, "_blank",
CHROME_WINDOW_FLAGS,
contentWindow);
CHROME_WINDOW_FLAGS, args);
chromeWindow.focus();
return chromeWindow;
}

Просмотреть файл

@ -1371,7 +1371,8 @@
// pretend the user typed this so it'll be available till
// the document successfully loads
b.userTypedValue = aURI;
if (!isBlankPageURL(aURI))
b.userTypedValue = aURI;
let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
if (aAllowThirdPartyFixup)
@ -1563,15 +1564,26 @@
<parameter name="aCloseWindowFastpath"/>
<body>
<![CDATA[
if (aTab.closing || this._windowIsClosing)
if (aTab.closing ||
aTab._pendingPermitUnload ||
this._windowIsClosing)
return false;
var browser = this.getBrowserForTab(aTab);
if (!aTabWillBeMoved) {
let ds = browser.docShell;
if (ds && ds.contentViewer && !ds.contentViewer.permitUnload())
return false;
if (ds && ds.contentViewer) {
// We need to block while calling permitUnload() because it
// processes the event queue and may lead to another removeTab()
// call before permitUnload() even returned.
aTab._pendingPermitUnload = true;
let permitUnload = ds.contentViewer.permitUnload();
delete aTab._pendingPermitUnload;
if (!permitUnload)
return false;
}
}
var closeWindow = false;

Просмотреть файл

@ -72,6 +72,7 @@ _BROWSER_TEST_FILES = \
browser_dbg_pause-resume.js \
browser_dbg_update-editor-mode.js \
browser_dbg_select-line.js \
browser_dbg_clean-exit.js \
head.js \
$(NULL)

Просмотреть файл

@ -0,0 +1,42 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Test that closing a tab with the debugger in a paused state exits cleanly.
var gPane = null;
var gTab = null;
var gDebuggee = null;
var gDebugger = null;
const DEBUGGER_TAB_URL = "http://example.com/browser/browser/devtools/" +
"debugger/test/" +
"browser_dbg_debuggerstatement.html";
function test() {
debug_tab_pane(DEBUGGER_TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gDebuggee = aDebuggee;
gPane = aPane;
gDebugger = gPane.debuggerWindow;
testCleanExit();
});
}
function testCleanExit() {
gPane.activeThread.addOneTimeListener("framesadded", function() {
Services.tm.currentThread.dispatch({ run: function() {
is(gDebugger.StackFrames.activeThread.paused, true,
"Should be paused after the debugger statement.");
gPane._client.addOneTimeListener("tabDetached", function () {
finish();
});
removeTab(gTab);
}}, 0);
});
gTab.linkedBrowser.contentWindow.wrappedJSObject.runDebuggerStatement();
}

Просмотреть файл

@ -763,6 +763,9 @@ InspectorUI.prototype = {
this.boundRuleViewChanged = this.ruleViewChanged.bind(this);
this.ruleView.element.addEventListener("CssRuleViewChanged",
this.boundRuleViewChanged);
this.cssRuleViewBoundCSSLinkClicked = this.ruleViewCSSLinkClicked.bind(this);
this.ruleView.element.addEventListener("CssRuleViewCSSLinkClicked",
this.cssRuleViewBoundCSSLinkClicked);
doc.documentElement.appendChild(this.ruleView.element);
this.ruleView.highlight(this.selection);
@ -800,6 +803,30 @@ InspectorUI.prototype = {
this.nodeChanged(this.ruleViewObject);
},
/**
* When a css link is clicked this method is called in order to either:
* 1. Open the link in view source (for element style attributes)
* 2. Open the link in the style editor
*
* @param aEvent The event containing the style rule to act on
*/
ruleViewCSSLinkClicked: function(aEvent)
{
if (!this.chromeWin) {
return;
}
let rule = aEvent.detail.rule;
let styleSheet = rule.sheet;
if (styleSheet) {
this.chromeWin.StyleEditor.openChrome(styleSheet, rule.ruleLine);
} else {
let href = rule.elementStyle.element.ownerDocument.location.href;
this.chromeWin.openUILinkIn("view-source:" + href, "window");
}
},
/**
* Destroy the rule view.
*/
@ -811,6 +838,8 @@ InspectorUI.prototype = {
if (this.ruleView) {
this.ruleView.element.removeEventListener("CssRuleViewChanged",
this.boundRuleViewChanged);
this.ruleView.element.removeEventListener("CssRuleViewCSSLinkClicked",
this.cssRuleViewBoundCSSLinkClicked);
delete boundRuleViewChanged;
this.ruleView.clear();
delete this.ruleView;

Просмотреть файл

@ -78,6 +78,9 @@ const ORION_EVENTS = {
Selection: "Selection",
Focus: "Focus",
Blur: "Blur",
MouseOver: "MouseOver",
MouseOut: "MouseOut",
MouseMove: "MouseMove",
};
/**

Просмотреть файл

@ -161,6 +161,30 @@ SourceEditor.EVENTS = {
* The blur event is fired when the editor goes out of focus.
*/
BLUR: "Blur",
/**
* The MouseMove event is sent when the user moves the mouse over a line
* annotation. The event object properties:
* - event - the DOM mousemove event object.
* - x and y - the mouse coordinates relative to the document being edited.
*/
MOUSE_MOVE: "MouseMove",
/**
* The MouseOver event is sent when the mouse pointer enters a line
* annotation. The event object properties:
* - event - the DOM mouseover event object.
* - x and y - the mouse coordinates relative to the document being edited.
*/
MOUSE_OVER: "MouseOver",
/**
* This MouseOut event is sent when the mouse pointer exits a line
* annotation. The event object properties:
* - event - the DOM mouseout event object.
* - x and y - the mouse coordinates relative to the document being edited.
*/
MOUSE_OUT: "MouseOut",
};
/**

Просмотреть файл

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

Просмотреть файл

@ -0,0 +1,97 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let tempScope = {};
Cu.import("resource:///modules/source-editor.jsm", tempScope);
let SourceEditor = tempScope.SourceEditor;
let testWin;
let editor;
function test()
{
waitForExplicitFinish();
const windowUrl = "data:text/xml,<?xml version='1.0'?>" +
"<window xmlns='http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'" +
" title='Test for bug 725388' width='600' height='500'><hbox flex='1'/></window>";
const windowFeatures = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
testWin = Services.ww.openWindow(null, windowUrl, "_blank", windowFeatures, null);
testWin.addEventListener("load", function onWindowLoad() {
testWin.removeEventListener("load", onWindowLoad, false);
waitForFocus(initEditor, testWin);
}, false);
}
function initEditor()
{
let hbox = testWin.document.querySelector("hbox");
editor = new SourceEditor();
editor.init(hbox, {}, editorLoaded);
}
function editorLoaded()
{
let text = "BrowserBug - 725388";
editor.setText(text);
let target = editor.editorElement;
let targetWin = target.ownerDocument.defaultView;
let mMoveHandler = function(aEvent) {
editor.removeEventListener(SourceEditor.EVENTS.MOUSE_MOVE, mMoveHandler);
is(aEvent.event.type, "mousemove", "MouseMove event fired.");
editor.addEventListener(SourceEditor.EVENTS.MOUSE_OVER, mOverHandler);
waitForFocus(function() {
EventUtils.synthesizeMouse(target, 10, 10, {type: "mouseover"},
targetWin);
});
};
let mOverHandler = function(aEvent) {
editor.removeEventListener(SourceEditor.EVENTS.MOUSE_OVER, mOverHandler);
is(aEvent.event.type, "mouseover", "MouseOver event fired.");
editor.addEventListener(SourceEditor.EVENTS.MOUSE_OUT, mOutHandler);
waitForFocus(function() {
EventUtils.synthesizeMouse(target, -10, -10, {type: "mouseout"},
targetWin);
}, targetWin);
};
let mOutHandler = function(aEvent) {
editor.removeEventListener(SourceEditor.EVENTS.MOUSE_OUT, mOutHandler);
is(aEvent.event.type, "mouseout", "MouseOut event fired.");
executeSoon(testEnd);
};
editor.addEventListener(SourceEditor.EVENTS.MOUSE_MOVE, mMoveHandler);
editor.focus();
waitForFocus(function() {
EventUtils.synthesizeMouse(target, 1, 1, {type: "mousemove"},
targetWin);
}, targetWin);
}
function testEnd()
{
if (editor) {
editor.destroy();
}
if (testWin) {
testWin.close();
}
testWin = editor = null;
waitForFocus(finish, window);
}

Просмотреть файл

@ -146,7 +146,7 @@ StyleEditor.prototype = {
*/
get styleSheet()
{
assert(this._styleSheet, "StyleSheet must be loaded first.")
assert(this._styleSheet, "StyleSheet must be loaded first.");
return this._styleSheet;
},
@ -921,9 +921,11 @@ StyleEditor.prototype = {
aArgs.unshift(this);
}
// copy the list of listeners to allow adding/removing listeners in handlers
let listeners = this._actionListeners.concat();
// trigger all listeners that have this action handler
for (let i = 0; i < this._actionListeners.length; ++i) {
let listener = this._actionListeners[i];
for (let i = 0; i < listeners.length; ++i) {
let listener = listeners[i];
let actionHandler = listener["on" + aName];
if (actionHandler) {
actionHandler.apply(listener, aArgs);

Просмотреть файл

@ -270,9 +270,11 @@ StyleEditorChrome.prototype = {
aArgs.unshift(this);
}
// trigger all listeners that have this named handler
for (let i = 0; i < this._listeners.length; ++i) {
let listener = this._listeners[i];
// copy the list of listeners to allow adding/removing listeners in handlers
let listeners = this._listeners.concat();
// trigger all listeners that have this named handler.
for (let i = 0; i < listeners.length; i++) {
let listener = listeners[i];
let handler = listener["on" + aName];
if (handler) {
handler.apply(listener, aArgs);
@ -329,10 +331,10 @@ StyleEditorChrome.prototype = {
{
this._resetChrome();
this._document.title = _("chromeWindowTitle",
this.contentDocument.title || this.contentDocument.location.href);
let document = this.contentDocument;
this._document.title = _("chromeWindowTitle",
document.title || document.location.href);
for (let i = 0; i < document.styleSheets.length; ++i) {
let styleSheet = document.styleSheets[i];
@ -352,6 +354,79 @@ StyleEditorChrome.prototype = {
}, this);
},
/**
* selects a stylesheet and optionally moves the cursor to a selected line
*
* @param {CSSStyleSheet} [aSheet]
* Stylesheet that should be selected. If a stylesheet is not passed
* and the editor is not initialized we focus the first stylesheet. If
* a stylesheet is not passed and the editor is initialized we ignore
* the call.
* @param {Number} [aLine]
* Line to which the caret should be moved (one-indexed).
* @param {Number} [aCol]
* Column to which the caret should be moved (one-indexed).
*/
selectStyleSheet: function SEC_selectSheet(aSheet, aLine, aCol)
{
let select = function DEC_select(aEditor) {
let summary = aSheet ? this.getSummaryElementForEditor(aEditor)
: this._view.getSummaryElementByOrdinal(0);
let setCaret = false;
if (aLine || aCol) {
aLine = aLine || 1;
aCol = aCol || 1;
setCaret = true;
}
if (!aEditor.sourceEditor) {
// If a line or column was specified we move the caret appropriately.
if (setCaret) {
aEditor.addActionListener({
onAttach: function SEC_selectSheet_onAttach()
{
aEditor.removeActionListener(this);
aEditor.sourceEditor.setCaretPosition(aLine - 1, aCol - 1);
}
});
}
this._view.activeSummary = summary;
} else {
this._view.activeSummary = summary;
// If a line or column was specified we move the caret appropriately.
if (setCaret) {
aEditor.sourceEditor.setCaretPosition(aLine - 1, aCol - 1);
}
}
}.bind(this);
if (!this.editors.length) {
// We are in the main initialization phase so we wait for the editor
// containing the target stylesheet to be added and select the target
// stylesheet, optionally moving the cursor to a selected line.
this.addChromeListener({
onEditorAdded: function SEC_selectSheet_onEditorAdded(aChrome, aEditor) {
if ((!aSheet && aEditor.styleSheetIndex == 0) ||
aEditor.styleSheet == aSheet) {
aChrome.removeChromeListener(this);
select(aEditor);
}
}
});
} else if (aSheet) {
// We are already initialized and a stylesheet has been specified. Here
// we iterate through the editors and select the one containing the target
// stylesheet, optionally moving the cursor to a selected line.
for each (let editor in this.editors) {
if (editor.styleSheet == aSheet) {
select(editor);
break;
}
}
}
},
/**
* Disable all UI, effectively making editors read-only.
* This is automatically called when no content window is attached.
@ -455,9 +530,8 @@ StyleEditorChrome.prototype = {
}
}, false);
// autofocus the first or new stylesheet
if (editor.styleSheetIndex == 0 ||
editor.hasFlag(StyleEditorFlags.NEW)) {
// autofocus new stylesheets
if (editor.hasFlag(StyleEditorFlags.NEW)) {
this._view.activeSummary = aSummary;
}

Просмотреть файл

@ -132,8 +132,10 @@
<xul:script type="application/javascript"><![CDATA[
Components.utils.import("resource:///modules/devtools/StyleEditorChrome.jsm");
let chromeRoot = document.getElementById("style-editor-chrome");
let contentWindow = window.arguments[0];
let args = window.arguments[0].wrappedJSObject;
let contentWindow = args.contentWindow;
let chrome = new StyleEditorChrome(chromeRoot, contentWindow);
chrome.selectStyleSheet(args.selectedStyleSheet, args.line, args.col);
window.styleEditorChrome = chrome;
]]></xul:script>
</xul:window>

Просмотреть файл

@ -51,6 +51,7 @@ _BROWSER_TEST_FILES = \
browser_styleeditor_init.js \
browser_styleeditor_loading.js \
browser_styleeditor_new.js \
browser_styleeditor_passedinsheet.js \
browser_styleeditor_pretty.js \
browser_styleeditor_readonly.js \
browser_styleeditor_reopen.js \

Просмотреть файл

@ -0,0 +1,61 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const TESTCASE_URI = TEST_BASE + "simple.html";
const LINE = 6;
const COL = 2;
let editor = null;
let sheet = null;
function test()
{
waitForExplicitFinish();
gBrowser.selectedBrowser.addEventListener("load", function () {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
run();
}, true);
content.location = TESTCASE_URI;
}
function run()
{
sheet = content.document.styleSheets[1];
launchStyleEditorChrome(function attachListeners(aChrome) {
aChrome.addChromeListener({
onEditorAdded: checkSourceEditor
});
}, sheet, LINE, COL);
}
function checkSourceEditor(aChrome, aEditor)
{
if (!aEditor.sourceEditor) {
aEditor.addActionListener({
onAttach: function (aEditor) {
aEditor.removeActionListener(this);
validate(aEditor);
}
});
} else {
validate(aEditor);
}
}
function validate(aEditor)
{
info("validating style editor");
let sourceEditor = aEditor.sourceEditor;
let caretPosition = sourceEditor.getCaretPosition();
is(caretPosition.line, LINE - 1, "caret row is correct"); // index based
is(caretPosition.col, COL - 1, "caret column is correct");
is(aEditor.styleSheet, sheet, "loaded stylesheet matches document stylesheet");
finishUp();
}
function finishUp()
{
editor = sheet = null;
finish();
}

Просмотреть файл

@ -19,9 +19,9 @@ function cleanup()
}
}
function launchStyleEditorChrome(aCallback)
function launchStyleEditorChrome(aCallback, aSheet, aLine, aCol)
{
gChromeWindow = StyleEditor.openChrome();
gChromeWindow = StyleEditor.openChrome(aSheet, aLine, aCol);
if (gChromeWindow.document.readyState != "complete") {
gChromeWindow.addEventListener("load", function onChromeLoad() {
gChromeWindow.removeEventListener("load", onChromeLoad, true);
@ -34,12 +34,12 @@ function launchStyleEditorChrome(aCallback)
}
}
function addTabAndLaunchStyleEditorChromeWhenLoaded(aCallback)
function addTabAndLaunchStyleEditorChromeWhenLoaded(aCallback, aSheet, aLine, aCol)
{
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
launchStyleEditorChrome(aCallback);
launchStyleEditorChrome(aCallback, aSheet, aLine, aCol);
}, true);
}

Просмотреть файл

@ -273,6 +273,7 @@ CssHtmlTree.prototype = {
this._matchedProperties = null;
if (this.htmlComplete) {
this.refreshSourceFilter();
this.refreshPanel();
} else {
if (this._refreshProcess) {
@ -281,6 +282,9 @@ CssHtmlTree.prototype = {
CssHtmlTree.processTemplate(this.templateRoot, this.root, this);
// Refresh source filter ... this must be done after templateRoot has been
// processed.
this.refreshSourceFilter();
this.numVisibleProperties = 0;
let fragment = this.doc.createDocumentFragment();
this._refreshProcess = new UpdateProcess(this.win, CssHtmlTree.propertyNames, {
@ -362,21 +366,28 @@ CssHtmlTree.prototype = {
},
/**
* The change event handler for the onlyUserStyles checkbox. When
* onlyUserStyles.checked is true we do not display properties that have no
* matched selectors, and we do not display UA styles. If .checked is false we
* do display even properties with no matched selectors, and we include the UA
* styles.
* The change event handler for the onlyUserStyles checkbox.
*
* @param {Event} aEvent the DOM Event object.
*/
onlyUserStylesChanged: function CssHtmltree_onlyUserStylesChanged(aEvent)
{
this.refreshSourceFilter();
this.refreshPanel();
},
/**
* When onlyUserStyles.checked is true we only display properties that have
* matched selectors and have been included by the document or one of the
* document's stylesheets. If .checked is false we display all properties
* including those that come from UA stylesheets.
*/
refreshSourceFilter: function CssHtmlTree_setSourceFilter()
{
this._matchedProperties = null;
this.cssLogic.sourceFilter = this.showOnlyUserStyles ?
CssLogic.FILTER.ALL :
CssLogic.FILTER.UA;
this.refreshPanel();
},
/**
@ -974,4 +985,24 @@ SelectorView.prototype = {
return result;
},
/**
* When a css link is clicked this method is called in order to either:
* 1. Open the link in view source (for element style attributes).
* 2. Open the link in the style editor.
*
* @param aEvent The click event
*/
openStyleEditor: function(aEvent)
{
if (this.selectorInfo.selector._cssRule._cssSheet) {
let styleSheet = this.selectorInfo.selector._cssRule._cssSheet.domSheet;
let line = this.selectorInfo.ruleLine;
this.tree.win.StyleEditor.openChrome(styleSheet, line);
} else {
let href = this.selectorInfo.sourceElement.ownerDocument.location.href;
this.tree.win.openUILinkIn("view-source:" + href, "window");
}
},
};

Просмотреть файл

@ -232,7 +232,7 @@ CssLogic.prototype = {
// Update the CssSheet objects.
this.forEachSheet(function(aSheet) {
aSheet._sheetAllowed = -1;
if (!aSheet.systemSheet && aSheet.sheetAllowed) {
if (aSheet.contentSheet && aSheet.sheetAllowed) {
ruleCount += aSheet.ruleCount;
}
}, this);
@ -345,7 +345,7 @@ CssLogic.prototype = {
let sheets = [];
this.forEachSheet(function (aSheet) {
if (!aSheet.systemSheet) {
if (aSheet.contentSheet) {
sheets.push(aSheet);
}
}, this);
@ -395,7 +395,7 @@ CssLogic.prototype = {
}
sheet = new CssSheet(this, aDomSheet, aIndex);
if (sheet.sheetAllowed && !sheet.systemSheet) {
if (sheet.sheetAllowed && sheet.contentSheet) {
this._ruleCount += sheet.ruleCount;
}
@ -569,7 +569,7 @@ CssLogic.prototype = {
this.forEachSheet(function (aSheet) {
// We do not show unmatched selectors from system stylesheets
if (aSheet.systemSheet || aSheet.disabled || !aSheet.mediaMatches) {
if (!aSheet.contentSheet || aSheet.disabled || !aSheet.mediaMatches) {
return;
}
@ -664,7 +664,7 @@ CssLogic.prototype = {
sheet._passId = this._passId;
}
if (filter !== CssLogic.FILTER.UA && sheet.systemSheet) {
if (filter === CssLogic.FILTER.ALL && !sheet.contentSheet) {
continue;
}
@ -710,7 +710,7 @@ CssLogic.prototype = {
let result = {};
this.forSomeSheets(function (aSheet) {
if (aSheet.systemSheet || aSheet.disabled || !aSheet.mediaMatches) {
if (!aSheet.contentSheet || aSheet.disabled || !aSheet.mediaMatches) {
return false;
}
@ -865,29 +865,23 @@ XPCOMUtils.defineLazyGetter(CssLogic, "_strings", function() Services.strings
.createBundle("chrome://browser/locale/devtools/styleinspector.properties"));
/**
* Is the given property sheet a system (user agent) stylesheet?
* Is the given property sheet a content stylesheet?
*
* @param {CSSStyleSheet} aSheet a stylesheet
* @return {boolean} true if the given stylesheet is a system stylesheet or
* @return {boolean} true if the given stylesheet is a content stylesheet,
* false otherwise.
*/
CssLogic.isSystemStyleSheet = function CssLogic_isSystemStyleSheet(aSheet)
CssLogic.isContentStylesheet = function CssLogic_isContentStylesheet(aSheet)
{
if (!aSheet) {
// All sheets with owner nodes have been included by content.
if (aSheet.ownerNode) {
return true;
}
let url = aSheet.href;
if (!url) return false;
if (url.length === 0) return true;
// Check for http[s]
if (url[0] === 'h') return false;
if (url.substr(0, 9) === "resource:") return true;
if (url.substr(0, 7) === "chrome:") return true;
if (url === "XPCSafeJSObjectWrapper.cpp") return true;
if (url.substr(0, 6) === "about:") return true;
// If the sheet has a CSSImportRule we need to check the parent stylesheet.
if (aSheet.ownerRule instanceof Ci.nsIDOMCSSImportRule) {
return CssLogic.isContentStylesheet(aSheet.parentStyleSheet);
}
return false;
};
@ -942,7 +936,7 @@ function CssSheet(aCssLogic, aDomSheet, aIndex)
{
this._cssLogic = aCssLogic;
this.domSheet = aDomSheet;
this.index = this.systemSheet ? -100 * aIndex : aIndex;
this.index = this.contentSheet ? aIndex : -100 * aIndex;
// Cache of the sheets href. Cached by the getter.
this._href = null;
@ -960,21 +954,21 @@ function CssSheet(aCssLogic, aDomSheet, aIndex)
CssSheet.prototype = {
_passId: null,
_systemSheet: null,
_contentSheet: null,
_mediaMatches: null,
/**
* Tells if the stylesheet is provided by the browser or not.
*
* @return {boolean} true if this is a browser-provided stylesheet, or false
* @return {boolean} false if this is a browser-provided stylesheet, or true
* otherwise.
*/
get systemSheet()
get contentSheet()
{
if (this._systemSheet === null) {
this._systemSheet = CssLogic.isSystemStyleSheet(this.domSheet);
if (this._contentSheet === null) {
this._contentSheet = CssLogic.isContentStylesheet(this.domSheet);
}
return this._systemSheet;
return this._contentSheet;
},
/**
@ -1048,7 +1042,7 @@ CssSheet.prototype = {
this._sheetAllowed = true;
let filter = this._cssLogic.sourceFilter;
if (filter === CssLogic.FILTER.ALL && this.systemSheet) {
if (filter === CssLogic.FILTER.ALL && !this.contentSheet) {
this._sheetAllowed = false;
}
if (filter !== CssLogic.FILTER.ALL && filter !== CssLogic.FILTER.UA) {
@ -1202,13 +1196,13 @@ function CssRule(aCssSheet, aDomRule, aElement)
this.line = this._cssSheet._cssLogic.domUtils.getRuleLine(this._domRule);
this.source = this._cssSheet.shortSource + ":" + this.line;
this.href = this._cssSheet.href;
this.systemRule = this._cssSheet.systemSheet;
this.contentRule = this._cssSheet.contentSheet;
} else if (aElement) {
this._selectors = [ new CssSelector(this, "@element.style") ];
this.line = -1;
this.source = CssLogic.l10n("rule.sourceElement");
this.href = "#";
this.systemRule = false;
this.contentRule = true;
this.sourceElement = aElement;
}
}
@ -1396,12 +1390,12 @@ CssSelector.prototype = {
/**
* Check if the selector comes from a browser-provided stylesheet.
*
* @return {boolean} true if the selector comes from a browser-provided
* @return {boolean} true if the selector comes from a content-provided
* stylesheet, or false otherwise.
*/
get systemRule()
get contentRule()
{
return this._cssRule.systemRule;
return this._cssRule.contentRule;
},
/**
@ -1794,12 +1788,12 @@ function CssSelectorInfo(aSelector, aProperty, aValue, aStatus)
4 important
5 inline important
*/
let scorePrefix = this.systemRule ? 0 : 2;
let scorePrefix = this.contentRule ? 2 : 0;
if (this.elementStyle) {
scorePrefix++;
}
if (this.important) {
scorePrefix += this.systemRule ? 1 : 2;
scorePrefix += this.contentRule ? 2 : 1;
}
this.specificityScore = "" + scorePrefix + this.specificity.ids +
@ -1902,9 +1896,9 @@ CssSelectorInfo.prototype = {
* @return {boolean} true if the selector comes from a browser-provided
* stylesheet, or false otherwise.
*/
get systemRule()
get contentRule()
{
return this.selector.systemRule;
return this.selector.contentRule;
},
/**
@ -1916,8 +1910,8 @@ CssSelectorInfo.prototype = {
*/
compareTo: function CssSelectorInfo_compareTo(aThat)
{
if (this.systemRule && !aThat.systemRule) return 1;
if (!this.systemRule && aThat.systemRule) return -1;
if (!this.contentRule && aThat.contentRule) return 1;
if (this.contentRule && !aThat.contentRule) return -1;
if (this.elementStyle && !aThat.elementStyle) {
if (!this.important && aThat.important) return 1;

Просмотреть файл

@ -38,7 +38,7 @@
*
* ***** END LICENSE BLOCK ***** */
"use strict"
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
@ -181,8 +181,8 @@ ElementStyle.prototype = {
let domRule = domRules.GetElementAt(i);
// XXX: Optionally provide access to system sheets.
let systemSheet = CssLogic.isSystemStyleSheet(domRule.parentStyleSheet);
if (systemSheet) {
let contentSheet = CssLogic.isContentStylesheet(domRule.parentStyleSheet);
if (!contentSheet) {
continue;
}
@ -324,7 +324,7 @@ ElementStyle.prototype = {
aProp.overridden = overridden;
return dirty;
}
}
};
/**
* A single style rule or declaration.
@ -358,11 +358,9 @@ Rule.prototype = {
if (this._title) {
return this._title;
}
let sheet = this.domRule ? this.domRule.parentStyleSheet : null;
this._title = CssLogic.shortSource(sheet);
this._title = CssLogic.shortSource(this.sheet);
if (this.domRule) {
let line = this.elementStyle.domUtils.getRuleLine(this.domRule);
this._title += ":" + line;
this._title += ":" + this.ruleLine;
}
if (this.inherited) {
@ -378,6 +376,26 @@ Rule.prototype = {
return this._title;
},
/**
* The rule's stylesheet.
*/
get sheet()
{
return this.domRule ? this.domRule.parentStyleSheet : null;
},
/**
* The rule's line within a stylesheet
*/
get ruleLine()
{
if (!this.sheet) {
// No stylesheet, no ruleLine
return null;
}
return this.elementStyle.domUtils.getRuleLine(this.domRule);
},
/**
* Create a new TextProperty to include in the rule.
*
@ -530,7 +548,7 @@ Rule.prototype = {
this.textProps.push(textProp);
}
},
}
};
/**
* A single property in a rule's cssText.
@ -618,7 +636,7 @@ TextProperty.prototype = {
{
this.rule.removeProperty(this);
}
}
};
/**
@ -643,7 +661,7 @@ TextProperty.prototype = {
* apply to a given element. After construction, the 'element'
* property will be available with the user interface.
*
* @param Document aDocument
* @param Document aDoc
* The document that will contain the rule view.
* @param object aStore
* The CSS rule view can use this object to store metadata
@ -655,7 +673,6 @@ function CssRuleView(aDoc, aStore)
{
this.doc = aDoc;
this.store = aStore;
this.element = this.doc.createElementNS(XUL_NS, "vbox");
this.element.setAttribute("tabindex", "0");
this.element.classList.add("ruleview");
@ -768,6 +785,14 @@ RuleEditor.prototype = {
class: "ruleview-rule-source",
textContent: this.rule.title
});
source.addEventListener("click", function() {
let rule = this.rule;
let evt = this.doc.createEvent("CustomEvent");
evt.initCustomEvent("CssRuleViewCSSLinkClicked", true, false, {
rule: rule,
});
this.element.dispatchEvent(evt);
}.bind(this));
let code = createChild(this.element, "div", {
class: "ruleview-code"
@ -1094,8 +1119,6 @@ TextPropertyEditor.prototype = {
_parseValue: function TextPropertyEditor_parseValue(aValue)
{
let pieces = aValue.split("!", 2);
let value = pieces[0];
let priority = pieces.length > 1 ? pieces[1] : "";
return {
value: pieces[0].trim(),
priority: (pieces.length > 1 ? pieces[1].trim() : "")

Просмотреть файл

@ -114,7 +114,7 @@ To visually debug the templates without running firefox, alter the display:none
${selector.humanReadableText(__element)}
</td>
<td class="rule-link">
<a target="_blank" href="view-source:${selector.selectorInfo.href}" class="link"
<a target="_blank" onclick="${selector.openStyleEditor}" class="link"
title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
</td>
</tr>

Просмотреть файл

@ -59,11 +59,19 @@ _BROWSER_TEST_FILES = \
browser_ruleview_manipulation.js \
browser_ruleview_override.js \
browser_ruleview_ui.js \
browser_bug705707_is_content_stylesheet.js \
head.js \
$(NULL)
_BROWSER_TEST_PAGES = \
browser_bug683672.html \
browser_bug705707_is_content_stylesheet.html \
browser_bug705707_is_content_stylesheet_imported.css \
browser_bug705707_is_content_stylesheet_imported2.css \
browser_bug705707_is_content_stylesheet_linked.css \
browser_bug705707_is_content_stylesheet_script.css \
browser_bug705707_is_content_stylesheet.xul \
browser_bug705707_is_content_stylesheet_xul.css \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)

Просмотреть файл

@ -0,0 +1,33 @@
<html>
<head>
<title>test</title>
<link href="./browser_bug705707_is_content_stylesheet_linked.css" rel="stylesheet" type="text/css">
<script>
// Load script.css
function loadCSS() {
var link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = "./browser_bug705707_is_content_stylesheet_script.css";
document.getElementsByTagName('head')[0].appendChild(link);
}
</script>
<style>
table {
border: 1px solid #000;
}
</style>
</head>
<body onload="loadCSS();">
<table id="target">
<tr>
<td>
<h3>Simple test</h3>
</td>
</tr>
</table>
</body>
</html>

Просмотреть файл

@ -0,0 +1,100 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the correct stylesheets origins are identified in HTML & XUL
// stylesheets
let doc;
const TEST_URI = "http://example.com/browser/browser/devtools/styleinspector/" +
"test/browser_bug705707_is_content_stylesheet.html";
const TEST_URI2 = "http://example.com/browser/browser/devtools/styleinspector/" +
"test/browser_bug705707_is_content_stylesheet.xul";
const XUL_URI = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService)
.newURI(TEST_URI2, null, null);
let tempScope = {};
Cu.import("resource:///modules/devtools/CssLogic.jsm", tempScope);
let CssLogic = tempScope.CssLogic;
function test()
{
waitForExplicitFinish();
addTab(TEST_URI);
browser.addEventListener("load", htmlLoaded, true);
}
function htmlLoaded()
{
browser.removeEventListener("load", htmlLoaded, true);
doc = content.document;
testFromHTML()
}
function testFromHTML()
{
let target = doc.querySelector("#target");
executeSoon(function() {
checkSheets(target);
gBrowser.removeCurrentTab();
openXUL();
});
}
function openXUL()
{
Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager)
.add(XUL_URI, 'allowXULXBL', Ci.nsIPermissionManager.ALLOW_ACTION);
addTab(TEST_URI2);
browser.addEventListener("load", xulLoaded, true);
}
function xulLoaded()
{
browser.removeEventListener("load", xulLoaded, true);
doc = content.document;
testFromXUL()
}
function testFromXUL()
{
let target = doc.querySelector("#target");
executeSoon(function() {
checkSheets(target);
finishUp();
});
}
function checkSheets(aTarget)
{
let domUtils = Cc["@mozilla.org/inspector/dom-utils;1"]
.getService(Ci.inIDOMUtils);
let domRules = domUtils.getCSSStyleRules(aTarget);
for (let i = 0, n = domRules.Count(); i < n; i++) {
let domRule = domRules.GetElementAt(i);
let sheet = domRule.parentStyleSheet;
let isContentSheet = CssLogic.isContentStylesheet(sheet);
if (!sheet.href ||
/browser_bug705707_is_content_stylesheet_/.test(sheet.href)) {
ok(isContentSheet, sheet.href + " identified as content stylesheet");
} else {
ok(!isContentSheet, sheet.href + " identified as non-content stylesheet");
}
}
}
function finishUp()
{
info("finishing up");
Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager)
.add(XUL_URI, 'allowXULXBL', Ci.nsIPermissionManager.DENY_ACTION);
doc = null;
gBrowser.removeCurrentTab();
finish();
}

Просмотреть файл

@ -0,0 +1,9 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/xul.css" type="text/css"?>
<?xml-stylesheet href="./browser_bug705707_is_content_stylesheet_xul.css"
type="text/css"?>
<!DOCTYPE window>
<window id="testwindow" xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<label id="target" value="Simple XUL document" />
</window>

Просмотреть файл

@ -0,0 +1,5 @@
@import url("./browser_bug705707_is_content_stylesheet_imported2.css");
#target {
text-decoration: underline;
}

Просмотреть файл

@ -0,0 +1,3 @@
#target {
text-decoration: underline;
}

Просмотреть файл

@ -0,0 +1,3 @@
table {
border-collapse: collapse;
}

Просмотреть файл

@ -0,0 +1,5 @@
@import url("./browser_bug705707_is_content_stylesheet_imported.css");
table {
opacity: 1;
}

Просмотреть файл

@ -0,0 +1,3 @@
#target {
font-size: 200px;
}

Просмотреть файл

@ -126,6 +126,40 @@ gcli.addCommand({
}
});
/**
* 'edit' command
*/
gcli.addCommand({
name: "edit",
description: gcli.lookup("editDesc"),
manual: gcli.lookup("editManual"),
params: [
{
name: 'resource',
type: {
name: 'resource',
include: 'text/css'
},
description: gcli.lookup("editResourceDesc")
},
{
name: "line",
defaultValue: 1,
type: {
name: "number",
min: 1,
step: 10
},
description: gcli.lookup("editLineToJumpToDesc")
}
],
exec: function(args, context) {
let hud = HUDService.getHudReferenceById(context.environment.hudId);
let StyleEditor = hud.gcliterm.document.defaultView.StyleEditor;
StyleEditor.openChrome(args.resource.element, args.line);
}
});
let breakpoints = [];
/**

Просмотреть файл

@ -129,3 +129,23 @@ breakdelRemoved=Breakpoint removed
# 'console close' command. This string is designed to be shown in a menu
# alongside the command name, which is why it should be as short as possible.
consolecloseDesc=Close the console
# LOCALIZATION NOTE (editDesc) A very short description of the 'edit'
# command. See editManual for a fuller description of what it does. This
# string is designed to be shown in a menu alongside the command name, which
# is why it should be as short as possible.
editDesc=Tweak a page resource
# LOCALIZATION NOTE (editManual) A fuller description of the 'edit' command,
# displayed when the user asks for help on what it does.
editManual=Edit one of the resources that is part of this page (or maybe any generic web resource?)
# LOCALIZATION NOTE (editResourceDesc) A very short string to describe the
# 'resource' parameter to the 'edit' command, which is displayed in a dialog
# when the user is using this command.
editResourceDesc=URL to edit
# LOCALIZATION NOTE (editLineToJumpToDesc) A very short string to describe the
# 'line' parameter to the 'edit' command, which is displayed in a dialog
# when the user is using this command.
editLineToJumpToDesc=Line to jump to

Просмотреть файл

@ -68,6 +68,9 @@
.helplink:visited {
text-decoration: none;
}
.link:hover {
text-decoration: underline;
}
.helplink {
display: block;
@ -135,6 +138,7 @@
.rule-link {
text-align: end;
-moz-padding-start: 10px;
cursor: pointer;
}
/* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
@ -200,7 +204,13 @@
.ruleview-rule-source {
background-color: -moz-dialog;
color: #0091ff;
padding: 2px 5px;
cursor: pointer;
}
.ruleview-rule-source:hover {
text-decoration: underline;
}
.ruleview-code {

Просмотреть файл

@ -68,6 +68,9 @@
.helplink:visited {
text-decoration: none;
}
.link:hover {
text-decoration: underline;
}
.helplink {
display: block;
@ -137,6 +140,7 @@
.rule-link {
text-align: end;
-moz-padding-start: 10px;
cursor: pointer;
}
/* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
@ -202,7 +206,13 @@
.ruleview-rule-source {
background-color: -moz-dialog;
color: #0091ff;
padding: 2px 5px;
cursor: pointer;
}
.ruleview-rule-source:hover {
text-decoration: underline;
}
.ruleview-code {

Просмотреть файл

@ -67,6 +67,9 @@
.helplink:visited {
text-decoration: none;
}
.link:hover {
text-decoration: underline;
}
.helplink {
display: block;
@ -135,6 +138,7 @@
.rule-link {
text-align: end;
-moz-padding-start: 10px;
cursor: pointer;
}
/* This rule is necessary because Templater.jsm breaks LTR TDs in RTL docs */
@ -200,7 +204,13 @@
.ruleview-rule-source {
background-color: -moz-dialog;
color: #0091ff;
padding: 2px 5px;
cursor: pointer;
}
.ruleview-rule-source:hover {
text-decoration: underline;
}
.ruleview-code {

Просмотреть файл

@ -120,6 +120,10 @@ ThreadActor.prototype = {
},
disconnect: function TA_disconnect() {
if (this._state == "paused") {
this.onResume();
}
this._state = "exited";
if (this.dbg) {
this.dbg.enabled = false;