mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
3ea000b341
@ -1004,6 +1004,7 @@ pref("devtools.errorconsole.enabled", false);
|
||||
|
||||
// Enable the Inspector
|
||||
pref("devtools.inspector.enabled", true);
|
||||
pref("devtools.inspector.htmlHeight", 112);
|
||||
|
||||
// Enable the style inspector
|
||||
pref("devtools.styleinspector.enabled", true);
|
||||
|
@ -1063,6 +1063,10 @@
|
||||
<svg:rect x="0" y="0" width="1" height="1" fill="white"/>
|
||||
<svg:circle cx="-0.41" cy="0.5" r="0.65"/>
|
||||
</svg:mask>
|
||||
<svg:mask id="pinstripe-urlbar-back-button-mask" maskContentUnits="userSpaceOnUse">
|
||||
<svg:rect x="0" y="-5" width="10000" height="55" fill="white"/>
|
||||
<svg:circle cx="-9" cy="11" r="15"/>
|
||||
</svg:mask>
|
||||
<svg:mask id="pinstripe-tab-ontop-left-curve-mask" maskContentUnits="userSpaceOnUse">
|
||||
<svg:circle cx="9" cy="3" r="3" fill="white"/>
|
||||
<svg:rect x="9" y="0" width="3" height="3" fill="white"/>
|
||||
|
@ -227,7 +227,14 @@ TreePanel.prototype = {
|
||||
treeBox = this.document.createElement("vbox");
|
||||
treeBox.id = "inspector-tree-box";
|
||||
treeBox.state = "open"; // for the registerTools API.
|
||||
treeBox.minHeight = 10;
|
||||
try {
|
||||
treeBox.height =
|
||||
Services.prefs.getIntPref("devtools.inspector.htmlHeight");
|
||||
} catch(e) {
|
||||
treeBox.height = 112;
|
||||
}
|
||||
|
||||
treeBox.minHeight = 64;
|
||||
treeBox.flex = 1;
|
||||
toolbarParent.insertBefore(treeBox, toolbar);
|
||||
|
||||
@ -262,6 +269,7 @@ TreePanel.prototype = {
|
||||
this.IUI.toolbar.removeAttribute("treepanel-open");
|
||||
|
||||
let treeBox = this.container;
|
||||
Services.prefs.setIntPref("devtools.inspector.htmlHeight", treeBox.height);
|
||||
let treeBoxParent = treeBox.parentNode;
|
||||
treeBoxParent.removeChild(treeBox);
|
||||
} else {
|
||||
@ -577,6 +585,7 @@ TreePanel.prototype = {
|
||||
this.editingContext.attrObj.innerHTML = editorInput.value;
|
||||
|
||||
this.IUI.isDirty = true;
|
||||
this.IUI.nodeChanged(this.registrationObject);
|
||||
|
||||
// event notification
|
||||
Services.obs.notifyObservers(null, this.IUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED,
|
||||
|
@ -1158,6 +1158,19 @@ InspectorUI.prototype = {
|
||||
this.toolsSelect(aScroll);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the highlighted node is changed by a tool.
|
||||
*
|
||||
* @param object aUpdater
|
||||
* The tool that triggered the update (if any), that tool's
|
||||
* onChanged will not be called.
|
||||
*/
|
||||
nodeChanged: function IUI_nodeChanged(aUpdater)
|
||||
{
|
||||
this.highlighter.highlight();
|
||||
this.toolsOnChanged(aUpdater);
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//// Event Handling
|
||||
|
||||
@ -1336,10 +1349,28 @@ InspectorUI.prototype = {
|
||||
openRuleView: function IUI_openRuleView()
|
||||
{
|
||||
let iframe = this.getToolIframe(this.ruleViewObject);
|
||||
if (iframe.getAttribute("src")) {
|
||||
// We're already loading this tool, let it finish.
|
||||
return;
|
||||
}
|
||||
|
||||
let boundLoadListener = function() {
|
||||
iframe.removeEventListener("load", boundLoadListener, true);
|
||||
let doc = iframe.contentDocument;
|
||||
this.ruleView = new CssRuleView(doc);
|
||||
|
||||
let winID = this.winID;
|
||||
let ruleViewStore = this.store.getValue(winID, "ruleView");
|
||||
if (!ruleViewStore) {
|
||||
ruleViewStore = {};
|
||||
this.store.setValue(winID, "ruleView", ruleViewStore);
|
||||
}
|
||||
|
||||
this.ruleView = new CssRuleView(doc, ruleViewStore);
|
||||
|
||||
this.boundRuleViewChanged = this.ruleViewChanged.bind(this);
|
||||
this.ruleView.element.addEventListener("CssRuleViewChanged",
|
||||
this.boundRuleViewChanged);
|
||||
|
||||
doc.documentElement.appendChild(this.ruleView.element);
|
||||
this.ruleView.highlight(this.selection);
|
||||
Services.obs.notifyObservers(null,
|
||||
@ -1370,6 +1401,12 @@ InspectorUI.prototype = {
|
||||
this.ruleView.highlight(aNode);
|
||||
},
|
||||
|
||||
ruleViewChanged: function IUI_ruleViewChanged()
|
||||
{
|
||||
this.isDirty = true;
|
||||
this.nodeChanged(this.ruleViewObject);
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroy the rule view.
|
||||
*/
|
||||
@ -1379,6 +1416,9 @@ InspectorUI.prototype = {
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
|
||||
if (this.ruleView) {
|
||||
this.ruleView.element.removeEventListener("CssRuleViewChanged",
|
||||
this.boundRuleViewChanged);
|
||||
delete boundRuleViewChanged;
|
||||
this.ruleView.clear();
|
||||
delete this.ruleView;
|
||||
}
|
||||
@ -1685,8 +1725,6 @@ InspectorUI.prototype = {
|
||||
*/
|
||||
toolShow: function IUI_toolShow(aTool)
|
||||
{
|
||||
aTool.show.call(aTool.context, this.selection);
|
||||
|
||||
let btn = this.chromeDoc.getElementById(this.getToolbarButtonId(aTool.id));
|
||||
btn.setAttribute("checked", "true");
|
||||
if (aTool.sidebar) {
|
||||
@ -1697,6 +1735,8 @@ InspectorUI.prototype = {
|
||||
this.getToolbarButtonId(other.id)).removeAttribute("checked");
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
aTool.show.call(aTool.context, this.selection);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1848,13 +1888,29 @@ InspectorUI.prototype = {
|
||||
*/
|
||||
toolsDim: function IUI_toolsDim(aState)
|
||||
{
|
||||
this.toolsDo(function IUI_toolsOnSelect(aTool) {
|
||||
this.toolsDo(function IUI_toolsDim(aTool) {
|
||||
if (aTool.isOpen && "dim" in aTool) {
|
||||
aTool.dim.call(aTool.context, aState);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify registered tools of changes to the highlighted element.
|
||||
*
|
||||
* @param object aUpdater
|
||||
* The tool that triggered the update (if any), that tool's
|
||||
* onChanged will not be called.
|
||||
*/
|
||||
toolsOnChanged: function IUI_toolsChanged(aUpdater)
|
||||
{
|
||||
this.toolsDo(function IUI_toolsOnChanged(aTool) {
|
||||
if (aTool.isOpen && ("onChanged" in aTool) && aTool != aUpdater) {
|
||||
aTool.onChanged.call(aTool.context);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Loop through all registered tools and pass each into the provided function
|
||||
* @param aFunction The function to which each tool is to be passed
|
||||
@ -2062,8 +2118,13 @@ InspectorProgressListener.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip non-start states.
|
||||
if (!(aFlag & Ci.nsIWebProgressListener.STATE_START)) {
|
||||
let isStart = aFlag & Ci.nsIWebProgressListener.STATE_START;
|
||||
let isDocument = aFlag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
|
||||
let isNetwork = aFlag & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
|
||||
let isRequest = aFlag & Ci.nsIWebProgressListener.STATE_IS_REQUEST;
|
||||
|
||||
// Skip non-interesting states.
|
||||
if (!isStart || !isDocument || !isRequest || !isNetwork) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -65,6 +65,10 @@ _BROWSER_FILES = \
|
||||
browser_inspector_keybindings.js \
|
||||
browser_inspector_breadcrumbs.html \
|
||||
browser_inspector_breadcrumbs.js \
|
||||
browser_inspector_bug_699308_iframe_navigation.js \
|
||||
browser_inspector_changes.js \
|
||||
browser_inspector_ruleviewstore.js \
|
||||
browser_inspector_duplicate_ruleview.js \
|
||||
$(NULL)
|
||||
|
||||
# Disabled due to constant failures
|
||||
|
@ -0,0 +1,77 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let iframe;
|
||||
let iframeLoads = 0;
|
||||
let checksAfterLoads = false;
|
||||
|
||||
function startTest() {
|
||||
ok(window.InspectorUI, "InspectorUI variable exists");
|
||||
Services.obs.addObserver(runInspectorTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, null);
|
||||
InspectorUI.toggleInspectorUI();
|
||||
}
|
||||
|
||||
function runInspectorTests() {
|
||||
Services.obs.removeObserver(runInspectorTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, null);
|
||||
|
||||
iframe = content.document.querySelector("iframe");
|
||||
ok(iframe, "found the iframe element");
|
||||
|
||||
ok(InspectorUI.inspecting, "Inspector is highlighting");
|
||||
ok(InspectorUI.isInspectorOpen, "Inspector is open");
|
||||
|
||||
Services.obs.addObserver(finishTest,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
|
||||
|
||||
iframe.addEventListener("load", onIframeLoad, false);
|
||||
|
||||
executeSoon(function() {
|
||||
iframe.contentWindow.location = "javascript:location.reload()";
|
||||
});
|
||||
}
|
||||
|
||||
function onIframeLoad() {
|
||||
if (++iframeLoads != 2) {
|
||||
executeSoon(function() {
|
||||
iframe.contentWindow.location = "javascript:location.reload()";
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
iframe.removeEventListener("load", onIframeLoad, false);
|
||||
|
||||
ok(InspectorUI.inspecting, "Inspector is highlighting after iframe nav");
|
||||
ok(InspectorUI.isInspectorOpen, "Inspector Panel is open after iframe nav");
|
||||
|
||||
checksAfterLoads = true;
|
||||
|
||||
InspectorUI.closeInspectorUI();
|
||||
}
|
||||
|
||||
function finishTest() {
|
||||
Services.obs.removeObserver(finishTest,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
|
||||
|
||||
is(iframeLoads, 2, "iframe loads");
|
||||
ok(checksAfterLoads, "the Inspector tests got the chance to run after iframe reloads");
|
||||
ok(!InspectorUI.isInspectorOpen, "Inspector Panel is not open");
|
||||
|
||||
iframe = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
executeSoon(finish);
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onBrowserLoad() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onBrowserLoad, true);
|
||||
waitForFocus(startTest, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,<p>bug 699308 - test iframe navigation" +
|
||||
"<iframe src='data:text/html,hello world'></iframe>";
|
||||
}
|
158
browser/devtools/highlighter/test/browser_inspector_changes.js
Normal file
158
browser/devtools/highlighter/test/browser_inspector_changes.js
Normal file
@ -0,0 +1,158 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Inspect Tests.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
* Rob Campbell <rcampbell@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
let doc;
|
||||
let testDiv;
|
||||
|
||||
function createDocument()
|
||||
{
|
||||
doc.body.innerHTML = '<div id="testdiv">Test div!</div>';
|
||||
doc.title = "Inspector Change Test";
|
||||
startInspectorTests();
|
||||
}
|
||||
|
||||
|
||||
function getInspectorProp(aName)
|
||||
{
|
||||
for each (let view in InspectorUI.stylePanel.cssHtmlTree.propertyViews) {
|
||||
if (view.name == aName) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function startInspectorTests()
|
||||
{
|
||||
ok(InspectorUI, "InspectorUI variable exists");
|
||||
Services.obs.addObserver(runInspectorTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
InspectorUI.toggleInspectorUI();
|
||||
}
|
||||
|
||||
function runInspectorTests()
|
||||
{
|
||||
Services.obs.removeObserver(runInspectorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
|
||||
testDiv = doc.getElementById("testdiv");
|
||||
|
||||
testDiv.style.fontSize = "10px";
|
||||
|
||||
InspectorUI.inspectNode(testDiv);
|
||||
InspectorUI.stopInspecting();
|
||||
|
||||
// Start up the style inspector panel...
|
||||
Services.obs.addObserver(stylePanelTests, "StyleInspector-populated", false);
|
||||
|
||||
executeSoon(function() {
|
||||
InspectorUI.showSidebar();
|
||||
document.getElementById(InspectorUI.getToolbarButtonId("styleinspector")).click();
|
||||
});
|
||||
}
|
||||
|
||||
function stylePanelTests()
|
||||
{
|
||||
Services.obs.removeObserver(stylePanelTests, "StyleInspector-populated");
|
||||
|
||||
ok(InspectorUI.isSidebarOpen, "Inspector Sidebar is open");
|
||||
ok(InspectorUI.stylePanel.cssHtmlTree, "Style Panel has a cssHtmlTree");
|
||||
|
||||
let propView = getInspectorProp("font-size");
|
||||
is(propView.value, "10px", "Style inspector should be showing the correct font size.");
|
||||
|
||||
Services.obs.addObserver(stylePanelAfterChange, "StyleInspector-populated", false);
|
||||
|
||||
testDiv.style.fontSize = "15px";
|
||||
InspectorUI.nodeChanged();
|
||||
}
|
||||
|
||||
function stylePanelAfterChange()
|
||||
{
|
||||
Services.obs.removeObserver(stylePanelAfterChange, "StyleInspector-populated");
|
||||
|
||||
let propView = getInspectorProp("font-size");
|
||||
is(propView.value, "15px", "Style inspector should be showing the new font size.");
|
||||
|
||||
stylePanelNotActive();
|
||||
}
|
||||
|
||||
function stylePanelNotActive()
|
||||
{
|
||||
// Tests changes made while the style panel is not active.
|
||||
InspectorUI.ruleButton.click();
|
||||
executeSoon(function() {
|
||||
testDiv.style.fontSize = "20px";
|
||||
Services.obs.addObserver(stylePanelAfterSwitch, "StyleInspector-populated", false);
|
||||
document.getElementById(InspectorUI.getToolbarButtonId("styleinspector")).click();
|
||||
});
|
||||
}
|
||||
|
||||
function stylePanelAfterSwitch()
|
||||
{
|
||||
Services.obs.removeObserver(stylePanelAfterSwitch, "StyleInspector-populated");
|
||||
|
||||
let propView = getInspectorProp("font-size");
|
||||
is(propView.value, "20px", "Style inspector should be showing the newest font size.");
|
||||
|
||||
Services.obs.addObserver(finishTest, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
|
||||
executeSoon(function() {
|
||||
InspectorUI.closeInspectorUI(true);
|
||||
});
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
Services.obs.removeObserver(finishTest,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
doc = content.document;
|
||||
waitForFocus(createDocument, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,basic tests for inspector";
|
||||
}
|
||||
|
@ -0,0 +1,126 @@
|
||||
/* 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 div;
|
||||
let tab1;
|
||||
let tab2;
|
||||
let tab1window;
|
||||
|
||||
function inspectorTabOpen1()
|
||||
{
|
||||
ok(window.InspectorUI, "InspectorUI variable exists");
|
||||
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
|
||||
ok(InspectorUI.store.isEmpty(), "Inspector.store is empty");
|
||||
|
||||
Services.obs.addObserver(inspectorUIOpen1,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
InspectorUI.openInspectorUI();
|
||||
}
|
||||
|
||||
function inspectorUIOpen1()
|
||||
{
|
||||
Services.obs.removeObserver(inspectorUIOpen1,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
|
||||
// Make sure the inspector is open.
|
||||
ok(InspectorUI.inspecting, "Inspector is highlighting");
|
||||
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
|
||||
ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is not open");
|
||||
ok(!InspectorUI.store.isEmpty(), "InspectorUI.store is not empty");
|
||||
is(InspectorUI.store.length, 1, "Inspector.store.length = 1");
|
||||
|
||||
// Highlight a node.
|
||||
div = content.document.getElementsByTagName("div")[0];
|
||||
InspectorUI.inspectNode(div);
|
||||
is(InspectorUI.selection, div, "selection matches the div element");
|
||||
|
||||
Services.obs.addObserver(inspectorRuleViewOpened,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, false);
|
||||
|
||||
InspectorUI.showSidebar();
|
||||
InspectorUI.openRuleView();
|
||||
}
|
||||
|
||||
function inspectorRuleViewOpened() {
|
||||
Services.obs.removeObserver(inspectorRuleViewOpened,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.RULEVIEWREADY);
|
||||
|
||||
// Open the second tab.
|
||||
tab2 = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab2;
|
||||
|
||||
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee,
|
||||
true);
|
||||
waitForFocus(inspectorTabOpen2, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,<p>tab 2: the inspector should close now";
|
||||
}
|
||||
|
||||
function inspectorTabOpen2()
|
||||
{
|
||||
// Make sure the inspector is closed.
|
||||
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
|
||||
ok(!InspectorUI.treePanel, "Inspector Tree Panel is closed");
|
||||
ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is not open");
|
||||
is(InspectorUI.store.length, 1, "Inspector.store.length = 1");
|
||||
|
||||
Services.obs.addObserver(inspectorFocusTab1,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, false);
|
||||
// Switch back to tab 1.
|
||||
executeSoon(function() {
|
||||
gBrowser.selectedTab = tab1;
|
||||
});
|
||||
}
|
||||
|
||||
function inspectorFocusTab1()
|
||||
{
|
||||
Services.obs.removeObserver(inspectorFocusTab1,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, false);
|
||||
Services.obs.addObserver(inspectorRuleTrap,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, false);
|
||||
|
||||
// Make sure the inspector is open.
|
||||
ok(InspectorUI.inspecting, "Inspector is highlighting");
|
||||
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
|
||||
is(InspectorUI.store.length, 1, "Inspector.store.length = 1");
|
||||
is(InspectorUI.selection, div, "selection matches the div element");
|
||||
ok(InspectorUI.isSidebarOpen, "sidebar is open");
|
||||
ok(InspectorUI.isRuleViewOpen(), "rule view is open");
|
||||
is(InspectorUI.ruleView.doc.documentElement.children.length, 1, "RuleView elements.length == 1");
|
||||
|
||||
requestLongerTimeout(4);
|
||||
executeSoon(function() {
|
||||
InspectorUI.closeInspectorUI();
|
||||
gBrowser.removeCurrentTab(); // tab 1
|
||||
gBrowser.removeCurrentTab(); // tab 2
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
function inspectorRuleTrap()
|
||||
{
|
||||
Services.obs.removeObserver(inspectorRuleTrap,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, false);
|
||||
is(InspectorUI.ruleView.doc.documentElement.children.length, 1, "RuleView elements.length == 1");
|
||||
}
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
||||
tab1 = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab1;
|
||||
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee,
|
||||
true);
|
||||
waitForFocus(inspectorTabOpen1, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,<p>tab switching tests for inspector" +
|
||||
"<div>tab 1</div>";
|
||||
}
|
||||
|
@ -0,0 +1,152 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Inspector Tab Switch Tests.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Rob Campbell <rcampbell@mozilla.com>
|
||||
* Mihai Șucan <mihai.sucan@gmail.com>
|
||||
* Dave Camp <dcamp@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Tests that properties disabled in the rule view survive a tab switch.
|
||||
*/
|
||||
|
||||
let div;
|
||||
let tab1;
|
||||
|
||||
function waitForRuleView(aCallback)
|
||||
{
|
||||
if (InspectorUI.ruleView) {
|
||||
aCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
let ruleViewFrame = InspectorUI.getToolIframe(InspectorUI.ruleViewObject);
|
||||
ruleViewFrame.addEventListener("load", function(evt) {
|
||||
ruleViewFrame.removeEventListener(evt.type, arguments.callee, true);
|
||||
executeSoon(function() {
|
||||
aCallback();
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
function inspectorTabOpen1()
|
||||
{
|
||||
Services.obs.addObserver(inspectorUIOpen1,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
InspectorUI.openInspectorUI();
|
||||
}
|
||||
|
||||
function inspectorUIOpen1()
|
||||
{
|
||||
Services.obs.removeObserver(inspectorUIOpen1,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
|
||||
// Highlight a node.
|
||||
div = content.document.getElementsByTagName("div")[0];
|
||||
InspectorUI.inspectNode(div);
|
||||
|
||||
// Open the rule view sidebar.
|
||||
waitForRuleView(ruleViewOpened1);
|
||||
|
||||
InspectorUI.showSidebar();
|
||||
InspectorUI.ruleButton.click();
|
||||
}
|
||||
|
||||
function ruleViewOpened1()
|
||||
{
|
||||
let prop = InspectorUI.ruleView._elementStyle.rules[0].textProps[0];
|
||||
is(prop.name, "background-color", "First prop is the background color prop.");
|
||||
prop.setEnabled(false);
|
||||
|
||||
// Open second tab and switch to it
|
||||
tab2 = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab2;
|
||||
|
||||
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee,
|
||||
true);
|
||||
waitForFocus(inspectorTabOpen2, content);
|
||||
}, true);
|
||||
content.location = "data:text/html,<p>tab 2: the inspector should close now";
|
||||
}
|
||||
|
||||
function inspectorTabOpen2()
|
||||
{
|
||||
// Switch back to tab 1.
|
||||
executeSoon(function() {
|
||||
Services.obs.addObserver(inspectorFocusTab1,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
gBrowser.removeCurrentTab();
|
||||
gBrowser.selectedTab = tab1;
|
||||
});
|
||||
}
|
||||
|
||||
function inspectorFocusTab1()
|
||||
{
|
||||
Services.obs.removeObserver(inspectorFocusTab1,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
|
||||
// Now wait for the rule view to load again...
|
||||
waitForRuleView(ruleViewOpened2);
|
||||
}
|
||||
|
||||
function ruleViewOpened2()
|
||||
{
|
||||
let prop = InspectorUI.ruleView._elementStyle.rules[0].textProps[0];
|
||||
is(prop.name, "background-color", "First prop is the background color prop.");
|
||||
ok(!prop.enabled, "First prop should be disabled.");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
InspectorUI.closeInspectorUI();
|
||||
finish();
|
||||
}
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
||||
tab1 = gBrowser.addTab();
|
||||
gBrowser.selectedTab = tab1;
|
||||
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee,
|
||||
true);
|
||||
waitForFocus(inspectorTabOpen1, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,<p>tab switching tests for inspector" +
|
||||
'<div style="background-color: green;">tab 1</div>';
|
||||
}
|
||||
|
@ -0,0 +1,144 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Inspector Tests.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Rob Campbell <rcampbell@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
let doc;
|
||||
let salutation;
|
||||
let closing;
|
||||
|
||||
const NEWHEIGHT = 226;
|
||||
|
||||
function createDocument()
|
||||
{
|
||||
doc.body.innerHTML = '<div id="first" style="{ margin: 10em; ' +
|
||||
'font-size: 14pt; font-family: helvetica, sans-serif; color: #AAA}">\n' +
|
||||
'<h1>Some header text</h1>\n' +
|
||||
'<p id="salutation" style="{font-size: 12pt}">hi.</p>\n' +
|
||||
'<p id="body" style="{font-size: 12pt}">I am a test-case. This text exists ' +
|
||||
'solely to provide some things to test the inspector initialization.</p>\n' +
|
||||
'If you are reading this, you should go do something else instead. Maybe ' +
|
||||
'read a book. Or better yet, write some test-cases for another bit of code. ' +
|
||||
'<span style="{font-style: italic}">Maybe more inspector test-cases!</span></p>\n' +
|
||||
'<p id="closing">end transmission</p>\n' +
|
||||
'</div>';
|
||||
doc.title = "Inspector Initialization Test";
|
||||
startInspectorTests();
|
||||
}
|
||||
|
||||
function startInspectorTests()
|
||||
{
|
||||
ok(InspectorUI, "InspectorUI variable exists");
|
||||
Services.obs.addObserver(runInspectorTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
InspectorUI.toggleInspectorUI();
|
||||
}
|
||||
|
||||
function runInspectorTests()
|
||||
{
|
||||
Services.obs.removeObserver(runInspectorTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
|
||||
|
||||
if (InspectorUI.treePanelEnabled) {
|
||||
Services.obs.addObserver(treePanelTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
|
||||
|
||||
InspectorUI.stopInspecting();
|
||||
|
||||
InspectorUI.treePanel.open();
|
||||
} else
|
||||
finishInspectorTests();
|
||||
}
|
||||
|
||||
function treePanelTests()
|
||||
{
|
||||
Services.obs.removeObserver(treePanelTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
|
||||
Services.obs.addObserver(treePanelTests2,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
|
||||
|
||||
ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
|
||||
|
||||
let height = Services.prefs.getIntPref("devtools.inspector.htmlHeight");
|
||||
|
||||
is(InspectorUI.treePanel.container.height, height,
|
||||
"Container height is " + height);
|
||||
|
||||
InspectorUI.treePanel.container.height = NEWHEIGHT;
|
||||
|
||||
executeSoon(function() {
|
||||
InspectorUI.treePanel.close();
|
||||
InspectorUI.treePanel.open();
|
||||
});
|
||||
}
|
||||
|
||||
function treePanelTests2()
|
||||
{
|
||||
Services.obs.removeObserver(treePanelTests2,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
|
||||
|
||||
ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
|
||||
|
||||
let height = Services.prefs.getIntPref("devtools.inspector.htmlHeight");
|
||||
|
||||
is(InspectorUI.treePanel.container.height, NEWHEIGHT,
|
||||
"Container height is now " + height);
|
||||
|
||||
InspectorUI.treePanel.close();
|
||||
executeSoon(function() {
|
||||
finishInspectorTests()
|
||||
});
|
||||
}
|
||||
|
||||
function finishInspectorTests()
|
||||
{
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
doc = content.document;
|
||||
waitForFocus(createDocument, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,basic tests for inspector";
|
||||
}
|
||||
|
@ -43,6 +43,9 @@
|
||||
const Cu = Components.utils;
|
||||
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";
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/PluralForm.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
@ -51,6 +54,94 @@ Cu.import("resource:///modules/devtools/Templater.jsm");
|
||||
|
||||
var EXPORTED_SYMBOLS = ["CssHtmlTree", "PropertyView"];
|
||||
|
||||
/**
|
||||
* Helper for long-running processes that should yield occasionally to
|
||||
* the mainloop.
|
||||
*
|
||||
* @param {Window} aWin
|
||||
* Timeouts will be set on this window when appropriate.
|
||||
* @param {Generator} aGenerator
|
||||
* Will iterate this generator.
|
||||
* @param {object} aOptions
|
||||
* Options for the update process:
|
||||
* onItem {function} Will be called with the value of each iteration.
|
||||
* onBatch {function} Will be called after each batch of iterations,
|
||||
* before yielding to the main loop.
|
||||
* onDone {function} Will be called when iteration is complete.
|
||||
* onCancel {function} Will be called if the process is canceled.
|
||||
* threshold {int} How long to process before yielding, in ms.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function UpdateProcess(aWin, aGenerator, aOptions)
|
||||
{
|
||||
this.win = aWin;
|
||||
this.iter = Iterator(aGenerator);
|
||||
this.onItem = aOptions.onItem || function() {};
|
||||
this.onBatch = aOptions.onBatch || function () {};
|
||||
this.onDone = aOptions.onDone || function() {};
|
||||
this.onCancel = aOptions.onCancel || function() {};
|
||||
this.threshold = aOptions.threshold || 45;
|
||||
|
||||
this.canceled = false;
|
||||
}
|
||||
|
||||
UpdateProcess.prototype = {
|
||||
/**
|
||||
* Schedule a new batch on the main loop.
|
||||
*/
|
||||
schedule: function UP_schedule()
|
||||
{
|
||||
if (this.cancelled) {
|
||||
return;
|
||||
}
|
||||
this._timeout = this.win.setTimeout(this._timeoutHandler.bind(this), 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancel the running process. onItem will not be called again,
|
||||
* and onCancel will be called.
|
||||
*/
|
||||
cancel: function UP_cancel()
|
||||
{
|
||||
if (this._timeout) {
|
||||
this.win.clearTimeout(this._timeout);
|
||||
this._timeout = 0;
|
||||
}
|
||||
this.canceled = true;
|
||||
this.onCancel();
|
||||
},
|
||||
|
||||
_timeoutHandler: function UP_timeoutHandler() {
|
||||
this._timeout = null;
|
||||
try {
|
||||
this._runBatch();
|
||||
this.schedule();
|
||||
} catch(e) {
|
||||
if (e instanceof StopIteration) {
|
||||
this.onBatch();
|
||||
this.onDone();
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
|
||||
_runBatch: function Y_runBatch()
|
||||
{
|
||||
let time = Date.now();
|
||||
while(!this.cancelled) {
|
||||
// Continue until iter.next() throws...
|
||||
let next = this.iter.next();
|
||||
this.onItem(next[1]);
|
||||
if ((Date.now() - time) > this.threshold) {
|
||||
this.onBatch();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* CssHtmlTree is a panel that manages the display of a table sorted by style.
|
||||
* There should be one instance of CssHtmlTree per style display (of which there
|
||||
@ -74,13 +165,13 @@ function CssHtmlTree(aStyleInspector)
|
||||
|
||||
// Nodes used in templating
|
||||
this.root = this.styleDocument.getElementById("root");
|
||||
this.path = this.styleDocument.getElementById("path");
|
||||
this.templateRoot = this.styleDocument.getElementById("templateRoot");
|
||||
this.templatePath = this.styleDocument.getElementById("templatePath");
|
||||
this.propertyContainer = this.styleDocument.getElementById("propertyContainer");
|
||||
this.templateProperty = this.styleDocument.getElementById("templateProperty");
|
||||
this.panel = aStyleInspector.panel;
|
||||
|
||||
// No results text.
|
||||
this.noResults = this.styleDocument.getElementById("noResults");
|
||||
|
||||
// The element that we're inspecting, and the document that it comes from.
|
||||
this.viewedElement = null;
|
||||
this.createStyleViews();
|
||||
@ -132,6 +223,10 @@ CssHtmlTree.processTemplate = function CssHtmlTree_processTemplate(aTemplate,
|
||||
XPCOMUtils.defineLazyGetter(CssHtmlTree, "_strings", function() Services.strings
|
||||
.createBundle("chrome://browser/locale/devtools/styleinspector.properties"));
|
||||
|
||||
XPCOMUtils.defineLazyGetter(CssHtmlTree, "HELP_LINK_TITLE", function() {
|
||||
return CssHtmlTree.HELP_LINK_TITLE = CssHtmlTree.l10n("helpLinkTitle");
|
||||
});
|
||||
|
||||
CssHtmlTree.prototype = {
|
||||
// Cache the list of properties that have matched and unmatched properties.
|
||||
_matchedProperties: null,
|
||||
@ -154,6 +249,9 @@ CssHtmlTree.prototype = {
|
||||
// Toggle for zebra striping
|
||||
_darkStripe: true,
|
||||
|
||||
// Number of visible properties
|
||||
numVisibleProperties: 0,
|
||||
|
||||
get showOnlyUserStyles()
|
||||
{
|
||||
return this.onlyUserStylesCheckbox.checked;
|
||||
@ -166,55 +264,45 @@ CssHtmlTree.prototype = {
|
||||
*/
|
||||
highlight: function CssHtmlTree_highlight(aElement)
|
||||
{
|
||||
if (this.viewedElement == aElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.viewedElement = aElement;
|
||||
this._unmatchedProperties = null;
|
||||
this._matchedProperties = null;
|
||||
|
||||
CssHtmlTree.processTemplate(this.templatePath, this.path, this);
|
||||
|
||||
if (this.htmlComplete) {
|
||||
this.refreshPanel();
|
||||
} else {
|
||||
if (this._panelRefreshTimeout) {
|
||||
this.win.clearTimeout(this._panelRefreshTimeout);
|
||||
if (this._refreshProcess) {
|
||||
this._refreshProcess.cancel();
|
||||
}
|
||||
|
||||
CssHtmlTree.processTemplate(this.templateRoot, this.root, this);
|
||||
|
||||
// We use a setTimeout loop to display the properties in batches of 15 at a
|
||||
// time. This results in a perceptibly more responsive UI.
|
||||
let i = 0;
|
||||
let batchSize = 15;
|
||||
let max = CssHtmlTree.propertyNames.length - 1;
|
||||
function displayProperties() {
|
||||
if (this.viewedElement == aElement && this.styleInspector.isOpen()) {
|
||||
// Display the next 15 properties
|
||||
for (let step = i + batchSize; i < step && i <= max; i++) {
|
||||
let name = CssHtmlTree.propertyNames[i];
|
||||
let propView = new PropertyView(this, name);
|
||||
CssHtmlTree.processTemplate(this.templateProperty,
|
||||
this.propertyContainer, propView, true);
|
||||
propView.refreshAllSelectors();
|
||||
this.propertyViews.push(propView);
|
||||
this.numVisibleProperties = 0;
|
||||
let fragment = this.doc.createDocumentFragment();
|
||||
this._refreshProcess = new UpdateProcess(this.win, CssHtmlTree.propertyNames, {
|
||||
onItem: function(aPropertyName) {
|
||||
// Per-item callback.
|
||||
if (this.viewedElement != aElement || !this.styleInspector.isOpen()) {
|
||||
return false;
|
||||
}
|
||||
if (i < max) {
|
||||
// There are still some properties to display. We loop here to display
|
||||
// the next batch of 15.
|
||||
this._panelRefreshTimeout =
|
||||
this.win.setTimeout(displayProperties.bind(this), 15);
|
||||
} else {
|
||||
this.htmlComplete = true;
|
||||
this._panelRefreshTimeout = null;
|
||||
Services.obs.notifyObservers(null, "StyleInspector-populated", null);
|
||||
let propView = new PropertyView(this, aPropertyName);
|
||||
fragment.appendChild(propView.build());
|
||||
if (propView.visible) {
|
||||
this.numVisibleProperties++;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._panelRefreshTimeout =
|
||||
this.win.setTimeout(displayProperties.bind(this), 15);
|
||||
propView.refreshAllSelectors();
|
||||
this.propertyViews.push(propView);
|
||||
}.bind(this),
|
||||
onDone: function() {
|
||||
// Completed callback.
|
||||
this.htmlComplete = true;
|
||||
this.propertyContainer.appendChild(fragment);
|
||||
this.noResults.hidden = this.numVisibleProperties > 0;
|
||||
this._refreshProcess = null;
|
||||
Services.obs.notifyObservers(null, "StyleInspector-populated", null);
|
||||
}.bind(this)});
|
||||
|
||||
this._refreshProcess.schedule();
|
||||
}
|
||||
},
|
||||
|
||||
@ -223,47 +311,30 @@ CssHtmlTree.prototype = {
|
||||
*/
|
||||
refreshPanel: function CssHtmlTree_refreshPanel()
|
||||
{
|
||||
if (this._panelRefreshTimeout) {
|
||||
this.win.clearTimeout(this._panelRefreshTimeout);
|
||||
if (this._refreshProcess) {
|
||||
this._refreshProcess.cancel();
|
||||
}
|
||||
|
||||
this.noResults.hidden = true;
|
||||
|
||||
// Reset visible property count
|
||||
this.numVisibleProperties = 0;
|
||||
|
||||
// Reset zebra striping.
|
||||
this._darkStripe = true;
|
||||
|
||||
// We use a setTimeout loop to display the properties in batches of 15 at a
|
||||
// time. This results in a perceptibly more responsive UI.
|
||||
let i = 0;
|
||||
let batchSize = 15;
|
||||
let max = this.propertyViews.length - 1;
|
||||
function refreshView() {
|
||||
// Refresh the next 15 property views
|
||||
for (let step = i + batchSize; i < step && i <= max; i++) {
|
||||
this.propertyViews[i].refresh();
|
||||
}
|
||||
if (i < max) {
|
||||
// There are still some property views to refresh. We loop here to
|
||||
// display the next batch of 15.
|
||||
this._panelRefreshTimeout = this.win.setTimeout(refreshView.bind(this), 15);
|
||||
} else {
|
||||
this._panelRefreshTimeout = null;
|
||||
let display = this.propertyContainer.style.display;
|
||||
this._refreshProcess = new UpdateProcess(this.win, this.propertyViews, {
|
||||
onItem: function(aPropView) {
|
||||
aPropView.refresh();
|
||||
}.bind(this),
|
||||
onDone: function() {
|
||||
this._refreshProcess = null;
|
||||
this.noResults.hidden = this.numVisibleProperties > 0
|
||||
Services.obs.notifyObservers(null, "StyleInspector-populated", null);
|
||||
}
|
||||
}
|
||||
this._panelRefreshTimeout = this.win.setTimeout(refreshView.bind(this), 15);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the user clicks on a parent element in the "current element"
|
||||
* path.
|
||||
*
|
||||
* @param {Event} aEvent the DOM Event object.
|
||||
*/
|
||||
pathClick: function CssHtmlTree_pathClick(aEvent)
|
||||
{
|
||||
aEvent.preventDefault();
|
||||
if (aEvent.target && this.viewedElement != aEvent.target.pathElement) {
|
||||
this.styleInspector.selectFromPath(aEvent.target.pathElement);
|
||||
}
|
||||
}.bind(this)
|
||||
});
|
||||
this._refreshProcess.schedule();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -303,18 +374,6 @@ CssHtmlTree.prototype = {
|
||||
this.refreshPanel();
|
||||
},
|
||||
|
||||
/**
|
||||
* Provide access to the path to get from document.body to the selected
|
||||
* element.
|
||||
*
|
||||
* @return {array} the array holding the path from document.body to the
|
||||
* selected element.
|
||||
*/
|
||||
get pathElements()
|
||||
{
|
||||
return CssLogic.getShortNamePath(this.viewedElement);
|
||||
},
|
||||
|
||||
/**
|
||||
* The CSS as displayed by the UI.
|
||||
*/
|
||||
@ -408,10 +467,7 @@ CssHtmlTree.prototype = {
|
||||
|
||||
// Nodes used in templating
|
||||
delete this.root;
|
||||
delete this.path;
|
||||
delete this.templatePath;
|
||||
delete this.propertyContainer;
|
||||
delete this.templateProperty;
|
||||
delete this.panel;
|
||||
|
||||
// The document in which we display the results (csshtmltree.xul).
|
||||
@ -444,7 +500,6 @@ function PropertyView(aTree, aName)
|
||||
this.link = "https://developer.mozilla.org/en/CSS/" + aName;
|
||||
|
||||
this.templateMatchedSelectors = aTree.styleDocument.getElementById("templateMatchedSelectors");
|
||||
this.templateUnmatchedSelectors = aTree.styleDocument.getElementById("templateUnmatchedSelectors");
|
||||
}
|
||||
|
||||
PropertyView.prototype = {
|
||||
@ -514,7 +569,7 @@ PropertyView.prototype = {
|
||||
*/
|
||||
get hasMatchedSelectors()
|
||||
{
|
||||
return this.tree.matchedProperties[this.name];
|
||||
return this.name in this.tree.matchedProperties;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -522,7 +577,7 @@ PropertyView.prototype = {
|
||||
*/
|
||||
get hasUnmatchedSelectors()
|
||||
{
|
||||
return this.tree.hasUnmatchedSelectors(this.name);
|
||||
return this.name in this.tree.hasUnmatchedSelectors;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -559,6 +614,50 @@ PropertyView.prototype = {
|
||||
return "property-view-hidden";
|
||||
},
|
||||
|
||||
build: function PropertyView_build()
|
||||
{
|
||||
let doc = this.tree.doc;
|
||||
this.element = doc.createElementNS(HTML_NS, "div");
|
||||
this.element.setAttribute("class", this.className);
|
||||
|
||||
this.propertyHeader = doc.createElementNS(XUL_NS, "hbox");
|
||||
this.element.appendChild(this.propertyHeader);
|
||||
this.propertyHeader.setAttribute("class", "property-header");
|
||||
this.propertyHeader.addEventListener("click", this.propertyHeaderClick.bind(this), false);
|
||||
|
||||
this.matchedExpander = doc.createElementNS(HTML_NS, "div");
|
||||
this.propertyHeader.appendChild(this.matchedExpander);
|
||||
this.matchedExpander.setAttribute("class", "match expander");
|
||||
|
||||
let name = doc.createElementNS(HTML_NS, "div");
|
||||
this.propertyHeader.appendChild(name);
|
||||
name.setAttribute("class", "property-name");
|
||||
name.textContent = this.name;
|
||||
|
||||
let helpcontainer = doc.createElementNS(HTML_NS, "div");
|
||||
this.propertyHeader.appendChild(helpcontainer);
|
||||
helpcontainer.setAttribute("class", "helplink-container");
|
||||
|
||||
let helplink = doc.createElementNS(HTML_NS, "a");
|
||||
helpcontainer.appendChild(helplink);
|
||||
helplink.setAttribute("class", "helplink");
|
||||
helplink.setAttribute("title", CssHtmlTree.HELP_LINK_TITLE);
|
||||
helplink.textContent = CssHtmlTree.HELP_LINK_TITLE;
|
||||
helplink.addEventListener("click", this.mdnLinkClick.bind(this), false);
|
||||
|
||||
this.valueNode = doc.createElementNS(HTML_NS, "div");
|
||||
this.propertyHeader.appendChild(this.valueNode);
|
||||
this.valueNode.setAttribute("class", "property-value");
|
||||
this.valueNode.setAttribute("dir", "ltr");
|
||||
this.valueNode.textContent = this.value;
|
||||
|
||||
this.matchedSelectorsContainer = doc.createElementNS(HTML_NS, "div");
|
||||
this.element.appendChild(this.matchedSelectorsContainer);
|
||||
this.matchedSelectorsContainer.setAttribute("class", "rulelink");
|
||||
|
||||
return this.element;
|
||||
},
|
||||
|
||||
/**
|
||||
* Refresh the panel's CSS property value.
|
||||
*/
|
||||
@ -575,14 +674,12 @@ PropertyView.prototype = {
|
||||
if (!this.tree.viewedElement || !this.visible) {
|
||||
this.valueNode.innerHTML = "";
|
||||
this.matchedSelectorsContainer.hidden = true;
|
||||
this.unmatchedSelectorsContainer.hidden = true;
|
||||
this.unmatchedSelectorTable.innerHTML = "";
|
||||
this.matchedSelectorsContainer.innerHTML = "";
|
||||
this.matchedExpander.removeAttribute("open");
|
||||
this.unmatchedExpander.removeAttribute("open");
|
||||
return;
|
||||
}
|
||||
|
||||
this.tree.numVisibleProperties++;
|
||||
this.valueNode.innerHTML = this.propertyInfo.value;
|
||||
this.refreshAllSelectors();
|
||||
},
|
||||
@ -595,7 +692,7 @@ PropertyView.prototype = {
|
||||
let hasMatchedSelectors = this.hasMatchedSelectors;
|
||||
this.matchedSelectorsContainer.hidden = !hasMatchedSelectors;
|
||||
|
||||
if (hasMatchedSelectors || this.hasUnmatchedSelectors) {
|
||||
if (hasMatchedSelectors) {
|
||||
this.propertyHeader.classList.add("expandable");
|
||||
} else {
|
||||
this.propertyHeader.classList.remove("expandable");
|
||||
@ -654,7 +751,6 @@ PropertyView.prototype = {
|
||||
refreshAllSelectors: function PropertyView_refreshAllSelectors()
|
||||
{
|
||||
this.refreshMatchedSelectors();
|
||||
this.refreshUnmatchedSelectors();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -702,9 +798,6 @@ PropertyView.prototype = {
|
||||
{
|
||||
if (aEvent.target.className != "helplink") {
|
||||
this.matchedExpanded = !this.matchedExpanded;
|
||||
if (!this.hasMatchedSelectors && this.hasUnmatchedSelectors) {
|
||||
this.unmatchedExpanded = !this.unmatchedExpanded;
|
||||
}
|
||||
this.refreshAllSelectors();
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
|
@ -604,15 +604,19 @@ CssLogic.prototype = {
|
||||
|
||||
this._matchedRules.some(function(aValue) {
|
||||
let rule = aValue[0];
|
||||
let status = aValue[1];
|
||||
aProperties = aProperties.filter(function(aProperty) {
|
||||
if (rule.getPropertyValue(aProperty)) {
|
||||
// We just need to find if a rule has this property while it matches
|
||||
// the viewedElement (or its parents).
|
||||
// We just need to find if a rule has this property while it matches
|
||||
// the viewedElement (or its parents).
|
||||
if (rule.getPropertyValue(aProperty) &&
|
||||
(status == CssLogic.STATUS.MATCHED ||
|
||||
(status == CssLogic.STATUS.PARENT_MATCH &&
|
||||
this.domUtils.isInheritedProperty(aProperty)))) {
|
||||
result[aProperty] = true;
|
||||
return false;
|
||||
}
|
||||
return true; // Keep the property for the next rule.
|
||||
});
|
||||
}.bind(this));
|
||||
return aProperties.length == 0;
|
||||
}, this);
|
||||
|
||||
@ -1660,7 +1664,10 @@ CssPropertyInfo.prototype = {
|
||||
{
|
||||
let cssRule = aSelector._cssRule;
|
||||
let value = cssRule.getPropertyValue(this.property);
|
||||
if (value) {
|
||||
if (value &&
|
||||
(aStatus == CssLogic.STATUS.MATCHED ||
|
||||
(aStatus == CssLogic.STATUS.PARENT_MATCH &&
|
||||
this._cssLogic.domUtils.isInheritedProperty(this.property)))) {
|
||||
let selectorInfo = new CssSelectorInfo(aSelector, this.property, value,
|
||||
aStatus);
|
||||
this._matchedSelectors.push(selectorInfo);
|
||||
|
@ -89,11 +89,25 @@ var EXPORTED_SYMBOLS = ["CssRuleView",
|
||||
/**
|
||||
* ElementStyle maintains a list of Rule objects for a given element.
|
||||
*
|
||||
* @param Element aElement
|
||||
* The element whose style we are viewing.
|
||||
* @param object aStore
|
||||
* The ElementStyle can use this object to store metadata
|
||||
* that might outlast the rule view, particularly the current
|
||||
* set of disabled properties.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function ElementStyle(aElement)
|
||||
function ElementStyle(aElement, aStore)
|
||||
{
|
||||
this.element = aElement;
|
||||
this.store = aStore || {};
|
||||
if (this.store.disabled) {
|
||||
this.store.disabled = aStore.disabled;
|
||||
} else {
|
||||
this.store.disabled = WeakMap();
|
||||
}
|
||||
|
||||
let doc = aElement.ownerDocument;
|
||||
|
||||
// To figure out how shorthand properties are interpreted by the
|
||||
@ -117,6 +131,17 @@ ElementStyle.prototype = {
|
||||
|
||||
domUtils: Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils),
|
||||
|
||||
/**
|
||||
* Called by the Rule object when it has been changed through the
|
||||
* setProperty* methods.
|
||||
*/
|
||||
_changed: function ElementStyle_changed()
|
||||
{
|
||||
if (this.onChanged) {
|
||||
this.onChanged();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Refresh the list of rules to be displayed for the active element.
|
||||
* Upon completion, this.rules[] will hold a list of Rule objects.
|
||||
@ -372,12 +397,20 @@ Rule.prototype = {
|
||||
|
||||
/**
|
||||
* Reapply all the properties in this rule, and update their
|
||||
* computed styles. Will re-mark overridden properties.
|
||||
* computed styles. Store disabled properties in the element
|
||||
* style's store. Will re-mark overridden properties.
|
||||
*/
|
||||
applyProperties: function Rule_applyProperties()
|
||||
{
|
||||
let disabledProps = [];
|
||||
|
||||
for each (let prop in this.textProps) {
|
||||
if (!prop.enabled) {
|
||||
disabledProps.push({
|
||||
name: prop.name,
|
||||
value: prop.value,
|
||||
priority: prop.priority
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -388,6 +421,11 @@ Rule.prototype = {
|
||||
prop.priority = this.style.getPropertyPriority(prop.name);
|
||||
prop.updateComputed();
|
||||
}
|
||||
this.elementStyle._changed();
|
||||
|
||||
// Store disabled properties in the disabled store.
|
||||
let disabled = this.elementStyle.store.disabled;
|
||||
disabled.set(this.style, disabledProps);
|
||||
|
||||
this.elementStyle.markOverridden();
|
||||
},
|
||||
@ -477,6 +515,19 @@ Rule.prototype = {
|
||||
let prop = new TextProperty(this, name, matches[2], matches[3] || "");
|
||||
this.textProps.push(prop);
|
||||
}
|
||||
|
||||
// Include properties from the disabled property store, if any.
|
||||
let disabledProps = this.elementStyle.store.disabled.get(this.style);
|
||||
if (!disabledProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
for each (let prop in disabledProps) {
|
||||
let textProp = new TextProperty(this, prop.name,
|
||||
prop.value, prop.priority);
|
||||
textProp.enabled = false;
|
||||
this.textProps.push(textProp);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@ -593,15 +644,24 @@ TextProperty.prototype = {
|
||||
*
|
||||
* @param Document aDocument
|
||||
* The document that will contain the rule view.
|
||||
* @param object aStore
|
||||
* The CSS rule view can use this object to store metadata
|
||||
* that might outlast the rule view, particularly the current
|
||||
* set of disabled properties.
|
||||
* @constructor
|
||||
*/
|
||||
function CssRuleView(aDoc)
|
||||
function CssRuleView(aDoc, aStore)
|
||||
{
|
||||
this.doc = aDoc;
|
||||
this.store = aStore;
|
||||
|
||||
this.element = this.doc.createElementNS(HTML_NS, "div");
|
||||
this.element.setAttribute("tabindex", "0");
|
||||
this.element.classList.add("ruleview");
|
||||
|
||||
// Give a relative position for the inplace editor's measurement
|
||||
// span to be placed absolutely against.
|
||||
this.element.style.position = "relative";
|
||||
}
|
||||
|
||||
CssRuleView.prototype = {
|
||||
@ -627,7 +687,15 @@ CssRuleView.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
this._elementStyle = new ElementStyle(aElement);
|
||||
if (this._elementStyle) {
|
||||
delete this._elementStyle.onChanged;
|
||||
}
|
||||
|
||||
this._elementStyle = new ElementStyle(aElement, this.store);
|
||||
this._elementStyle.onChanged = function() {
|
||||
this._changed();
|
||||
}.bind(this);
|
||||
|
||||
this._createEditors();
|
||||
},
|
||||
|
||||
@ -643,6 +711,17 @@ CssRuleView.prototype = {
|
||||
this._elementStyle = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the user has made changes to the ElementStyle.
|
||||
* Emits an event that clients can listen to.
|
||||
*/
|
||||
_changed: function CssRuleView_changed()
|
||||
{
|
||||
var evt = this.doc.createEvent("Events");
|
||||
evt.initEvent("CssRuleViewChanged", true, false);
|
||||
this.element.dispatchEvent(evt);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates editor UI for each of the rules in _elementStyle.
|
||||
*/
|
||||
@ -1003,10 +1082,12 @@ TextPropertyEditor.prototype = {
|
||||
*/
|
||||
_parseValue: function TextPropertyEditor_parseValue(aValue)
|
||||
{
|
||||
let [value, priority] = aValue.split("!", 2);
|
||||
let pieces = aValue.split("!", 2);
|
||||
let value = pieces[0];
|
||||
let priority = pieces.length > 1 ? pieces[1] : "";
|
||||
return {
|
||||
value: value.trim(),
|
||||
priority: (priority ? priority.trim() : "")
|
||||
value: pieces[0].trim(),
|
||||
priority: (pieces.length > 1 ? pieces[1].trim() : "")
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -87,6 +87,7 @@ StyleInspector.prototype = {
|
||||
context: this,
|
||||
get isOpen() isOpen(),
|
||||
onSelect: this.selectNode,
|
||||
onChanged: this.updateNode,
|
||||
show: this.open,
|
||||
hide: this.close,
|
||||
dim: this.dimTool,
|
||||
@ -247,6 +248,17 @@ StyleInspector.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the display for the currently-selected node.
|
||||
*/
|
||||
updateNode: function SI_updateNode()
|
||||
{
|
||||
if (this.isOpen() && !this.dimmed) {
|
||||
this.cssLogic.highlight(this.selectedNode);
|
||||
this.cssHtmlTree.refreshPanel();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Dim or undim a panel by setting or removing a dimmed attribute.
|
||||
* @param aState
|
||||
|
@ -19,9 +19,10 @@
|
||||
- the Initial Developer. All Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- Joe Walker (jwalker@mozilla.com) (original author)
|
||||
- Joe Walker <jwalker@mozilla.com> (original author)
|
||||
- Mihai Șucan <mihai.sucan@gmail.com>
|
||||
- Michael Ratcliffe <mratcliffe@mozilla.com>
|
||||
- Dão Gottwald <dao@mozilla.com>
|
||||
-
|
||||
- Alternatively, the contents of this file may be used under the terms of
|
||||
- either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -36,8 +37,10 @@
|
||||
- the terms of any one of the MPL, the GPL or the LGPL.
|
||||
-
|
||||
- ***** END LICENSE BLOCK ***** -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/csshtmltree.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % inspectorDTD SYSTEM "chrome://browser/locale/devtools/styleinspector.dtd">
|
||||
%inspectorDTD;
|
||||
@ -53,14 +56,16 @@
|
||||
<!ATTLIST loop if CDATA #IMPLIED>
|
||||
<!ATTLIST tr if CDATA #IMPLIED>
|
||||
]>
|
||||
|
||||
<xul:window xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<!-- The output from #templateRoot (below) is inserted here. -->
|
||||
<div id="root"></div>
|
||||
|
||||
<!-- The output from #templatePath (below) is inserted here. -->
|
||||
<div id="path">
|
||||
<!-- When no properties are found the following block is displayed. -->
|
||||
<div id="noResults" hidden="">
|
||||
&noPropertiesFound;
|
||||
</div>
|
||||
|
||||
<!-- The output from #templateProperty (below) is appended here. -->
|
||||
@ -71,9 +76,6 @@
|
||||
<xul:label class="legendKey bestmatch">&bestMatch;</xul:label>
|
||||
<xul:label class="legendKey matched">&matched;</xul:label>
|
||||
<xul:label class="legendKey parentmatch">&parentMatch;</xul:label>
|
||||
<xul:label class="legendKey unmatched">&unmatched;</xul:label>
|
||||
<xul:spacer flex="1"/>
|
||||
<xul:resizer dir="bottomright"/>
|
||||
</xul:hbox>
|
||||
<!--
|
||||
To visually debug the templates without running firefox, alter the display:none
|
||||
@ -84,68 +86,16 @@ To visually debug the templates without running firefox, alter the display:none
|
||||
styles" checkbox. For data it needs an instance of CssHtmlTree.
|
||||
-->
|
||||
<div id="templateRoot">
|
||||
<xul:hbox class="header" flex="1">
|
||||
<label class="userStylesLabel">
|
||||
<input class="onlyuserstyles" save="${onlyUserStylesCheckbox}"
|
||||
type="checkbox" onchange="${onlyUserStylesChanged}" checked=""/>
|
||||
&userStylesLabel;
|
||||
</label>
|
||||
<xul:hbox class="headerControls" flex="1" align="center">
|
||||
<xul:checkbox class="onlyuserstyles" save="${onlyUserStylesCheckbox}"
|
||||
oncommand="${onlyUserStylesChanged}" checked="true"
|
||||
label="&userStylesLabel;"/>
|
||||
<xul:textbox class="searchfield" type="search" save="${searchField}"
|
||||
placeholder="&userStylesSearch;"
|
||||
oncommand="${filterChanged}"/>
|
||||
placeholder="&userStylesSearch;" flex="1"
|
||||
oncommand="${filterChanged}"/>
|
||||
</xul:hbox>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
templatePath sits just below the top of the window showing what we're looking
|
||||
at. For data it needs an instance of CssHtmlTree.
|
||||
-->
|
||||
<div id="templatePath">
|
||||
<span class="selectedElementLabel">
|
||||
&selectedElementLabel;
|
||||
</span>
|
||||
<!-- following broken in RTL mode, see bug 699900 -->
|
||||
<ol>
|
||||
<li foreach="item in ${pathElements}">
|
||||
<a href="#" onclick="${pathClick}" __pathElement="${item.element}">
|
||||
${__element.pathElement = item.element; item.display}
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
TemplateProperty lists the properties themselves. Each needs data like this:
|
||||
{
|
||||
property: ... // PropertyView from CssHtmlTree.jsm
|
||||
}
|
||||
-->
|
||||
<div id="templateProperty">
|
||||
<div class="${className}" save="${element}">
|
||||
<div class="property-header" save="${propertyHeader}"
|
||||
onclick="${propertyHeaderClick}">
|
||||
<div save="${matchedExpander}" class="match expander"/>
|
||||
<div class="property-name">${name}</div>
|
||||
<div class="helplink-container">
|
||||
<a href="${link}" class="helplink" title="&helpLinkTitle;" onclick="${mdnLinkClick}">
|
||||
&helpLinkTitle;
|
||||
</a>
|
||||
</div>
|
||||
<div save="${valueNode}" class="property-value" dir="ltr">${value}</div>
|
||||
</div>
|
||||
|
||||
<div save="${matchedSelectorsContainer}" class="rulelink">
|
||||
</div>
|
||||
<div save="${unmatchedSelectorsContainer}" class="rulelink">
|
||||
<div save="${unmatchedTitleBlock}" onclick="${unmatchedSelectorsClick}"
|
||||
class="rule-unmatched">
|
||||
<div save="${unmatchedExpander}" class="expander"/>
|
||||
<div save="${unmatchedSelectorsTitleNode}">&unmatchedSelectors;</div>
|
||||
</div>
|
||||
<div save="${unmatchedSelectorTable}" class="unmatchedSelectorTable"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
A templateMatchedSelectors sits inside each templateProperties showing the
|
||||
@ -165,32 +115,7 @@ To visually debug the templates without running firefox, alter the display:none
|
||||
</td>
|
||||
<td class="rule-link">
|
||||
<a target="_blank" href="view-source:${selector.selectorInfo.href}" class="link"
|
||||
title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</loop>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
A templateUnmatchedSelectors sits inside each templateProperties showing the
|
||||
list of selectors that do not affect that property. Each needs data like this:
|
||||
{
|
||||
unmatchedSelectorViews: ..., // from cssHtmlTree.propertyViews[name].unmatchedSelectorViews
|
||||
}
|
||||
This is a template so the parent does not need to be a table, except that
|
||||
using a div as the parent causes the DOM to muck with the tr elements
|
||||
-->
|
||||
<div id="templateUnmatchedSelectors">
|
||||
<table>
|
||||
<loop foreach="selector in ${unmatchedSelectorViews}">
|
||||
<tr>
|
||||
<td dir="ltr" class="rule-text ${selector.statusClass}">
|
||||
${selector.humanReadableText(__element)}
|
||||
</td>
|
||||
<td class="rule-link">
|
||||
<a target="_blank" href="view-source:${selector.selectorInfo.href}" class="link"
|
||||
title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
|
||||
title="${selector.selectorInfo.href}">${selector.selectorInfo.source}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</loop>
|
||||
|
@ -51,7 +51,9 @@ _BROWSER_TEST_FILES = \
|
||||
browser_bug683672.js \
|
||||
browser_styleinspector_bug_672746_default_styles.js \
|
||||
browser_styleinspector_bug_672744_search_filter.js \
|
||||
browser_styleinspector_bug_689759_no_results_placeholder.js \
|
||||
browser_bug_692400_element_style.js \
|
||||
browser_csslogic_inherited.js \
|
||||
browser_ruleview_editor.js \
|
||||
browser_ruleview_inherit.js \
|
||||
browser_ruleview_manipulation.js \
|
||||
|
@ -38,7 +38,7 @@ function runTests()
|
||||
ok(stylePanel.isOpen(), "style inspector is open");
|
||||
|
||||
testMatchedSelectors();
|
||||
testUnmatchedSelectors();
|
||||
//testUnmatchedSelectors();
|
||||
|
||||
info("finishing up");
|
||||
Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
|
||||
|
@ -0,0 +1,46 @@
|
||||
/* 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/ */
|
||||
|
||||
// Test that inherited properties are treated correctly.
|
||||
|
||||
Cu.import("resource:///modules/devtools/CssLogic.jsm");
|
||||
|
||||
let doc;
|
||||
|
||||
function createDocument()
|
||||
{
|
||||
doc.body.innerHTML = '<div style="margin-left:10px; font-size: 5px"><div id="innerdiv">Inner div</div></div>';
|
||||
doc.title = "Style Inspector Inheritance Test";
|
||||
|
||||
let cssLogic = new CssLogic();
|
||||
cssLogic.highlight(doc.getElementById("innerdiv"));
|
||||
|
||||
let marginProp = cssLogic.getPropertyInfo("margin-left");
|
||||
is(marginProp.matchedRuleCount, 0, "margin-left should not be included in matched selectors.");
|
||||
|
||||
let fontSizeProp = cssLogic.getPropertyInfo("font-size");
|
||||
is(fontSizeProp.matchedRuleCount, 1, "font-size should be included in matched selectors.");
|
||||
|
||||
finishUp();
|
||||
}
|
||||
|
||||
function finishUp()
|
||||
{
|
||||
doc = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
|
||||
doc = content.document;
|
||||
waitForFocus(createDocument, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,selector text test, bug 692400";
|
||||
}
|
@ -32,6 +32,18 @@ function waitForEditorBlur(aEditor, aCallback)
|
||||
}, false);
|
||||
}
|
||||
|
||||
var gRuleViewChanged = false;
|
||||
function ruleViewChanged()
|
||||
{
|
||||
gRuleViewChanged = true;
|
||||
}
|
||||
|
||||
function expectChange()
|
||||
{
|
||||
ok(gRuleViewChanged, "Rule view should have fired a change event.");
|
||||
gRuleViewChanged = false;
|
||||
}
|
||||
|
||||
function startTest()
|
||||
{
|
||||
let style = '' +
|
||||
@ -54,6 +66,7 @@ function startTest()
|
||||
let doc = ruleDialog.document;
|
||||
ruleView = new CssRuleView(doc);
|
||||
doc.documentElement.appendChild(ruleView.element);
|
||||
ruleView.element.addEventListener("CssRuleViewChanged", ruleViewChanged, false);
|
||||
ruleView.highlight(testElement);
|
||||
waitForFocus(testCancelNew, ruleDialog);
|
||||
}, true);
|
||||
@ -69,6 +82,7 @@ function testCancelNew()
|
||||
is(elementRuleEditor.newPropSpan.inplaceEditor, aEditor, "Next focused editor should be the new property editor.");
|
||||
let input = aEditor.input;
|
||||
waitForEditorBlur(aEditor, function () {
|
||||
ok(!gRuleViewChanged, "Shouldn't get a change event after a cancel.");
|
||||
is(elementRuleEditor.rule.textProps.length, 0, "Should have canceled creating a new text property.");
|
||||
ok(!elementRuleEditor.propertyList.hasChildNodes(), "Should not have any properties.");
|
||||
testCreateNew();
|
||||
@ -91,6 +105,7 @@ function testCreateNew()
|
||||
input.value = "background-color";
|
||||
|
||||
waitForEditorFocus(elementRuleEditor.element, function onNewValue(aEditor) {
|
||||
expectChange();
|
||||
is(elementRuleEditor.rule.textProps.length, 1, "Should have created a new text property.");
|
||||
is(elementRuleEditor.propertyList.children.length, 1, "Should have created a property editor.");
|
||||
let textProp = elementRuleEditor.rule.textProps[0];
|
||||
@ -98,6 +113,7 @@ function testCreateNew()
|
||||
|
||||
aEditor.input.value = "purple";
|
||||
waitForEditorBlur(aEditor, function() {
|
||||
expectChange();
|
||||
is(textProp.value, "purple", "Text prop should have been changed.");
|
||||
testEditProperty();
|
||||
});
|
||||
@ -120,10 +136,12 @@ function testEditProperty()
|
||||
is(propEditor.nameSpan.inplaceEditor, aEditor, "Next focused editor should be the name editor.");
|
||||
let input = aEditor.input;
|
||||
waitForEditorFocus(propEditor.element, function onNewName(aEditor) {
|
||||
expectChange();
|
||||
input = aEditor.input;
|
||||
is(propEditor.valueSpan.inplaceEditor, aEditor, "Focus should have moved to the value.");
|
||||
|
||||
waitForEditorBlur(aEditor, function() {
|
||||
expectChange();
|
||||
is(idRuleEditor.rule.style.getPropertyValue("border-color"), "red",
|
||||
"border-color should have been set.");
|
||||
testDisableProperty();
|
||||
@ -150,14 +168,20 @@ function testDisableProperty()
|
||||
|
||||
propEditor.enable.click();
|
||||
is(idRuleEditor.rule.style.getPropertyValue("border-color"), "", "Border-color should have been unset.");
|
||||
expectChange();
|
||||
|
||||
propEditor.enable.click();
|
||||
is(idRuleEditor.rule.style.getPropertyValue("border-color"), "red",
|
||||
"Border-color should have been reset.");
|
||||
expectChange();
|
||||
|
||||
finishTest();
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
ruleView.element.removeEventListener("CssRuleViewChanged", ruleViewChanged, false);
|
||||
ruleView.clear();
|
||||
ruleDialog.close();
|
||||
ruleDialog = ruleView = null;
|
||||
doc = null;
|
||||
|
@ -64,7 +64,7 @@ function SI_CheckProperty()
|
||||
let cssLogic = stylePanel.cssLogic;
|
||||
let propertyInfo = cssLogic.getPropertyInfo("color");
|
||||
ok(propertyInfo.matchedRuleCount > 0, "color property has matching rules");
|
||||
ok(propertyInfo.unmatchedRuleCount > 0, "color property has unmatched rules");
|
||||
//ok(propertyInfo.unmatchedRuleCount > 0, "color property has unmatched rules");
|
||||
}
|
||||
|
||||
function finishUp()
|
||||
|
@ -0,0 +1,118 @@
|
||||
/* 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/ */
|
||||
|
||||
// Tests that the no results placeholder works properly.
|
||||
|
||||
let doc;
|
||||
let stylePanel;
|
||||
|
||||
function createDocument()
|
||||
{
|
||||
doc.body.innerHTML = '<style type="text/css"> ' +
|
||||
'.matches {color: #F00;}</style>' +
|
||||
'<span id="matches" class="matches">Some styled text</span>';
|
||||
doc.title = "Tests that the no results placeholder works properly";
|
||||
ok(window.StyleInspector, "StyleInspector exists");
|
||||
stylePanel = new StyleInspector(window);
|
||||
Services.obs.addObserver(runStyleInspectorTests, "StyleInspector-opened", false);
|
||||
stylePanel.createPanel(false, function() {
|
||||
stylePanel.open(doc.body);
|
||||
});
|
||||
}
|
||||
|
||||
function runStyleInspectorTests()
|
||||
{
|
||||
Services.obs.removeObserver(runStyleInspectorTests, "StyleInspector-opened", false);
|
||||
|
||||
ok(stylePanel.isOpen(), "style inspector is open");
|
||||
|
||||
Services.obs.addObserver(SI_AddFilterText, "StyleInspector-populated", false);
|
||||
|
||||
let span = doc.querySelector("#matches");
|
||||
ok(span, "captain, we have the matches span");
|
||||
|
||||
let htmlTree = stylePanel.cssHtmlTree;
|
||||
stylePanel.selectNode(span);
|
||||
|
||||
is(span, htmlTree.viewedElement,
|
||||
"style inspector node matches the selected node");
|
||||
is(htmlTree.viewedElement, stylePanel.cssLogic.viewedElement,
|
||||
"cssLogic node matches the cssHtmlTree node");
|
||||
}
|
||||
|
||||
function SI_AddFilterText()
|
||||
{
|
||||
Services.obs.removeObserver(SI_AddFilterText, "StyleInspector-populated", false);
|
||||
|
||||
let iframe = stylePanel.iframe;
|
||||
let searchbar = stylePanel.cssHtmlTree.searchField;
|
||||
let searchTerm = "xxxxx";
|
||||
|
||||
Services.obs.addObserver(SI_checkPlaceholderVisible, "StyleInspector-populated", false);
|
||||
info("setting filter text to \"" + searchTerm + "\"");
|
||||
searchbar.focus();
|
||||
for each (let c in searchTerm) {
|
||||
EventUtils.synthesizeKey(c, {}, iframe.contentWindow);
|
||||
}
|
||||
}
|
||||
|
||||
function SI_checkPlaceholderVisible()
|
||||
{
|
||||
Services.obs.removeObserver(SI_checkPlaceholderVisible, "StyleInspector-populated", false);
|
||||
info("SI_checkPlaceholderVisible called");
|
||||
let placeholder = stylePanel.cssHtmlTree.noResults;
|
||||
let iframe = stylePanel.iframe;
|
||||
let display = iframe.contentWindow.getComputedStyle(placeholder).display;
|
||||
|
||||
is(display, "block", "placeholder is visible");
|
||||
|
||||
SI_ClearFilterText();
|
||||
}
|
||||
|
||||
function SI_ClearFilterText()
|
||||
{
|
||||
let iframe = stylePanel.iframe;
|
||||
let searchbar = stylePanel.cssHtmlTree.searchField;
|
||||
|
||||
Services.obs.addObserver(SI_checkPlaceholderHidden, "StyleInspector-populated", false);
|
||||
info("clearing filter text");
|
||||
searchbar.focus();
|
||||
searchbar.value = "";
|
||||
EventUtils.synthesizeKey("c", {}, iframe.contentWindow);
|
||||
}
|
||||
|
||||
function SI_checkPlaceholderHidden()
|
||||
{
|
||||
Services.obs.removeObserver(SI_checkPlaceholderHidden, "StyleInspector-populated", false);
|
||||
let placeholder = stylePanel.cssHtmlTree.noResults;
|
||||
let iframe = stylePanel.iframe;
|
||||
let display = iframe.contentWindow.getComputedStyle(placeholder).display;
|
||||
|
||||
is(display, "none", "placeholder is hidden");
|
||||
|
||||
Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
|
||||
stylePanel.close();
|
||||
}
|
||||
|
||||
function finishUp()
|
||||
{
|
||||
Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
|
||||
ok(!stylePanel.isOpen(), "style inspector is closed");
|
||||
doc = stylePanel = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
|
||||
doc = content.document;
|
||||
waitForFocus(createDocument, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,no results placeholder test";
|
||||
}
|
@ -12,11 +12,10 @@
|
||||
- tree. -->
|
||||
<!ENTITY selectedElementLabel "Selected element:">
|
||||
|
||||
<!-- LOCALIZATION NOTE (helpLinkTitle): For each style property
|
||||
- the user can hover it and get a help link button which allows one to
|
||||
- quickly jump to the documentation from the Mozilla Developer Network site.
|
||||
- This is the link title shown in the hover tooltip. -->
|
||||
<!ENTITY helpLinkTitle "Read the documentation for this property">
|
||||
<!-- LOCALIZATION NOTE (noPropertiesFound): In the case where there are no CSS
|
||||
- properties to display e.g. due to search criteria this message is
|
||||
- displayed. -->
|
||||
<!ENTITY noPropertiesFound "No CSS properties found.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (unmatchedSelectors): For each style property
|
||||
- the panel shows whether there are any selectors that do not match the
|
||||
|
@ -41,3 +41,8 @@ style.highlighter.button.label1=Properties
|
||||
style.highlighter.accesskey1=P
|
||||
style.highlighter.button.tooltip=Inspect element styles
|
||||
|
||||
# LOCALIZATION NOTE (helpLinkTitle): For each style property
|
||||
# the user can hover it and get a help link button which allows one to
|
||||
# quickly jump to the documentation from the Mozilla Developer Network site.
|
||||
# This is the link title shown in the hover tooltip.
|
||||
helpLinkTitle=Read the documentation for this property
|
||||
|
@ -22,6 +22,7 @@
|
||||
* Joe Walker <jwalker@mozilla.com> (original author)
|
||||
* Mihai Șucan <mihai.sucan@gmail.com>
|
||||
* Michael Ratcliffe <mratcliffe@mozilla.com>
|
||||
* Dão Gottwald <dao@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -47,35 +48,6 @@
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
#path {
|
||||
font-size: 11px;
|
||||
word-spacing: -1px;
|
||||
margin-bottom: 0;
|
||||
color: -moz-dialogtext;
|
||||
background-color: -moz-dialog;
|
||||
padding: 4px 5px 0;
|
||||
}
|
||||
#path ol {
|
||||
list-style: none outside none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#path li {
|
||||
border-radius: 3px;
|
||||
padding: 2px 3px;
|
||||
font-size: 11px;
|
||||
display: inline-block;
|
||||
}
|
||||
#path li:after {
|
||||
content: " > ";
|
||||
}
|
||||
#path li:last-child {
|
||||
font-weight: bold;
|
||||
color: #0091ff;
|
||||
}
|
||||
#path li:last-child:after {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.property-header {
|
||||
padding: 4px;
|
||||
@ -83,13 +55,13 @@
|
||||
-moz-padding-end: 5px;
|
||||
}
|
||||
|
||||
.rule-unmatched {
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
-moz-padding-start: 4px;
|
||||
-moz-padding-end: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.rule-unmatched {
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
-moz-padding-start: 4px;
|
||||
-moz-padding-end: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Take away these two :visited rules to get a core dumper */
|
||||
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
|
||||
@ -107,21 +79,20 @@
|
||||
.helplink-container {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.helplink {
|
||||
display: block;
|
||||
height: 0;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
padding-top: 14px;
|
||||
-moz-padding-start: 14px;
|
||||
background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
|
||||
-moz-margin-end: 2px;
|
||||
}
|
||||
|
||||
.property-header:hover > .helplink-container {
|
||||
visibility: visible;
|
||||
.property-header:not(:hover) > .helplink-container {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.unmatchedSelectorTable {
|
||||
@ -134,22 +105,13 @@
|
||||
}
|
||||
|
||||
.expander {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
float: left;
|
||||
-moz-margin-start: 15px;
|
||||
-moz-appearance: treetwisty;
|
||||
-moz-margin-start: 10px;
|
||||
-moz-margin-end: 5px;
|
||||
margin-top: 3px;
|
||||
background: url("chrome://browser/skin/devtools/arrows.png") 48px 0;
|
||||
}
|
||||
|
||||
.expander:-moz-locale-dir(rtl) {
|
||||
float: right;
|
||||
background-position: 40px 0;
|
||||
}
|
||||
|
||||
.expander[open] {
|
||||
background-position: 32px 0;
|
||||
-moz-appearance: treetwistyopen;
|
||||
}
|
||||
|
||||
.expandable {
|
||||
@ -161,7 +123,6 @@
|
||||
}
|
||||
|
||||
.expandable > .match {
|
||||
margin-top: 5px;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@ -170,13 +131,11 @@
|
||||
}
|
||||
|
||||
.property-name {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
color: -moz-FieldText;
|
||||
width: 220px;
|
||||
}
|
||||
.property-value {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
color: grey;
|
||||
}
|
||||
@ -216,41 +175,29 @@
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.selectedElementLabel {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.darkrow {
|
||||
background-color: rgba(0,0,0,.022);
|
||||
}
|
||||
|
||||
.header {
|
||||
#noResults {
|
||||
font-size: 18px;
|
||||
margin-top: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.headerControls {
|
||||
color: -moz-dialogtext;
|
||||
background-color: -moz-dialog;
|
||||
padding: 5px 0 0;
|
||||
}
|
||||
|
||||
.onlyuserstyles,
|
||||
.userStylesLabel {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.userStylesLabel {
|
||||
display: -moz-box;
|
||||
white-space: nowrap;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.onlyuserstyles {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
font-family: sans-serif;
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.searchfield {
|
||||
display: -moz-box;
|
||||
-moz-box-flex: 1;
|
||||
margin-left: 10px;
|
||||
-moz-margin-start: 10px;
|
||||
}
|
||||
|
||||
.styleinspector-legend {
|
||||
|
@ -47,6 +47,10 @@
|
||||
@import url("chrome://global/skin/");
|
||||
|
||||
%include shared.inc
|
||||
%filter substitution
|
||||
%define forwardTransitionLength 150ms
|
||||
%define conditionalForwardWithUrlbar window:not([chromehidden~=toolbar]) #navigator-toolbox[iconsize=large][mode=icons] > :-moz-any(#nav-bar[currentset*="unified-back-forward-button,urlbar-container"],#nav-bar:not([currentset])) > #unified-back-forward-button
|
||||
%define conditionalForwardWithUrlbarWidth 27
|
||||
|
||||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
@namespace html url("http://www.w3.org/1999/xhtml");
|
||||
@ -531,6 +535,71 @@ toolbar[mode="icons"] #forward-button {
|
||||
mask: url(chrome://browser/content/browser.xul#pinstripe-keyhole-forward-mask);
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #forward-button:not(:-moz-lwtheme) {
|
||||
-moz-appearance: none;
|
||||
-moz-padding-start: 2px;
|
||||
background: -moz-linear-gradient(hsl(0,0%,99%), hsl(0,0%,67%)) padding-box;
|
||||
border: 1px solid;
|
||||
border-color: hsl(0,0%,31%) hsla(0,0%,29%,.6) hsl(0,0%,27%);
|
||||
box-shadow: inset 0 1px 0 hsla(0,0%,100%,.35),
|
||||
0 1px 0 hsla(0,0%,100%,.2);
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #forward-button {
|
||||
border-radius: 0;
|
||||
-moz-margin-end: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #forward-button:-moz-lwtheme {
|
||||
-moz-padding-start: 2px;
|
||||
-moz-padding-end: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
|
||||
-moz-transition: opacity @forwardTransitionLength@ ease-out;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #forward-button:hover:active:not(:-moz-lwtheme) {
|
||||
background-image: -moz-linear-gradient(hsl(0,0%,74%), hsl(0,0%,61%));
|
||||
box-shadow: inset rgba(0,0,0,.3) 0 -6px 10px,
|
||||
inset #000 0 1px 3px,
|
||||
inset rgba(0,0,0,.2) 0 1px 3px,
|
||||
0 1px 0 hsla(0,0%,100%,.2);
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #forward-button:-moz-window-inactive:not(:-moz-lwtheme) {
|
||||
border-color: hsl(0,0%,64%) hsl(0,0%,65%) hsl(0,0%,66%);
|
||||
background-image: -moz-linear-gradient(hsl(0,0%,99%), hsl(0,0%,82%));
|
||||
box-shadow: inset 0 1px 0 hsla(0,0%,100%,.35);
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@media (-moz-mac-lion-theme) {
|
||||
@conditionalForwardWithUrlbar@ > #forward-button:not(:-moz-lwtheme) {
|
||||
background-image: -moz-linear-gradient(hsla(0,0%,100%,.73), hsla(0,0%,100%,.05) 85%);
|
||||
border-color: hsla(0,0%,0%,.35) hsla(0,0%,0%,.25) hsla(0,0%,0%,.2);
|
||||
box-shadow: inset 0 1px 0 hsla(0,0%,100%,.2),
|
||||
inset 0 0 1px hsla(0,0%,100%,.1),
|
||||
0 1px 0 hsla(0,0%,100%,.2);
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #forward-button:hover:active:not(:-moz-lwtheme) {
|
||||
background-image: -moz-linear-gradient(hsla(0,0%,60%,.37), hsla(0,0%,100%,.35) 95%);
|
||||
border-color: hsla(0,0%,0%,.43) hsla(0,0%,0%,.25) hsla(0,0%,0%,.37);
|
||||
box-shadow: inset 0 1px 0 hsla(0,0%,0%,.02),
|
||||
inset 0 1px 2px hsla(0,0%,0%,.2),
|
||||
0 1px 0 hsla(0,0%,100%,.2);
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ > #forward-button:-moz-window-inactive:not(:-moz-lwtheme) {
|
||||
background-image: none;
|
||||
border-color: hsla(0,0%,0%,.2);
|
||||
}
|
||||
}
|
||||
|
||||
#navigator-toolbox[iconsize="small"][mode="icons"] > #nav-bar #forward-button {
|
||||
width: 27px;
|
||||
}
|
||||
@ -842,6 +911,57 @@ toolbar[mode="icons"] #zoom-in-button {
|
||||
border-radius: @toolbarbuttonCornerRadius@;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ + #urlbar-container {
|
||||
padding-left: @conditionalForwardWithUrlbarWidth@px;
|
||||
-moz-margin-start: -@conditionalForwardWithUrlbarWidth@px;
|
||||
position: relative;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar {
|
||||
-moz-border-start: none;
|
||||
margin-left: 0;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@:not([switchingtabs]) + #urlbar-container > #urlbar {
|
||||
-moz-transition: margin-left @forwardTransitionLength@ ease-out;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(ltr) {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container {
|
||||
mask: url("chrome://browser/content/browser.xul#pinstripe-urlbar-back-button-mask");
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar {
|
||||
margin-left: -@conditionalForwardWithUrlbarWidth@px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar {
|
||||
/* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
|
||||
-moz-transition-delay: 100s;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar {
|
||||
/* when not hovered anymore, trigger a new transition to hide the forward button immediately */
|
||||
margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ + #urlbar-container:-moz-locale-dir(rtl),
|
||||
@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
|
||||
/* let pinstripe-urlbar-back-button-mask clip the urlbar's right side for RTL */
|
||||
-moz-transform: scaleX(-1);
|
||||
}
|
||||
|
||||
#identity-box {
|
||||
background-image: -moz-linear-gradient(hsl(0,0%,98%), hsl(0,0%,92%));
|
||||
box-shadow: 0 1px 0 hsla(0,0%,0%,.05) inset;
|
||||
@ -860,6 +980,38 @@ toolbar[mode="icons"] #zoom-in-button {
|
||||
border-bottom-right-radius: 2px;
|
||||
}
|
||||
|
||||
#notification-popup-box:not([hidden]) + #identity-box {
|
||||
-moz-padding-start: 10px;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar > #identity-box {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
|
||||
-moz-transition: 0s padding-left;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
|
||||
-moz-transition: 0s padding-right;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box {
|
||||
/* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
|
||||
-moz-transition-delay: 100s;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
|
||||
padding-left: 10.01px;
|
||||
}
|
||||
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
|
||||
padding-right: 10.01px;
|
||||
}
|
||||
|
||||
#identity-box:active:hover,
|
||||
#identity-box[open="true"] {
|
||||
background-image: -moz-linear-gradient(hsl(0,0%,93%), hsl(0,0%,80%));
|
||||
@ -2155,9 +2307,8 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
||||
-moz-margin-end: -8px;
|
||||
}
|
||||
|
||||
#notification-popup-box:not([hidden]) + #identity-box {
|
||||
-moz-padding-start: 10px;
|
||||
border-radius: 0;
|
||||
@conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar > #notification-popup-box {
|
||||
padding-left: 7px;
|
||||
}
|
||||
|
||||
#notification-popup-box:-moz-locale-dir(rtl),
|
||||
|
@ -22,6 +22,7 @@
|
||||
* Joe Walker <jwalker@mozilla.com> (original author)
|
||||
* Mihai Șucan <mihai.sucan@gmail.com>
|
||||
* Michael Ratcliffe <mratcliffe@mozilla.com>
|
||||
* Dão Gottwald <dao@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -47,35 +48,6 @@
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
#path {
|
||||
font-size: 11px;
|
||||
word-spacing: -1px;
|
||||
margin-bottom: 0;
|
||||
color: -moz-dialogtext;
|
||||
background-color: -moz-dialog;
|
||||
padding: 4px 5px 0;
|
||||
}
|
||||
#path ol {
|
||||
list-style: none outside none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#path li {
|
||||
border-radius: 3px;
|
||||
padding: 2px 3px;
|
||||
font-size: 11px;
|
||||
display: inline-block;
|
||||
}
|
||||
#path li:after {
|
||||
content: " > ";
|
||||
}
|
||||
#path li:last-child {
|
||||
font-weight: bold;
|
||||
color: #0091ff;
|
||||
}
|
||||
#path li:last-child:after {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.property-header {
|
||||
padding: 4px;
|
||||
@ -83,13 +55,13 @@
|
||||
-moz-padding-end: 5px;
|
||||
}
|
||||
|
||||
.rule-unmatched {
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
-moz-padding-start: 4px;
|
||||
-moz-padding-end: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.rule-unmatched {
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
-moz-padding-start: 4px;
|
||||
-moz-padding-end: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Take away these two :visited rules to get a core dumper */
|
||||
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
|
||||
@ -107,21 +79,20 @@
|
||||
.helplink-container {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.helplink {
|
||||
display: block;
|
||||
height: 0;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
padding-top: 14px;
|
||||
-moz-padding-start: 14px;
|
||||
background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
|
||||
-moz-margin-end: 2px;
|
||||
}
|
||||
|
||||
.property-header:hover > .helplink-container {
|
||||
visibility: visible;
|
||||
.property-header:not(:hover) > .helplink-container {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.unmatchedSelectorTable {
|
||||
@ -137,15 +108,10 @@
|
||||
-moz-appearance: treetwisty;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
float: left;
|
||||
-moz-margin-start: 5px;
|
||||
-moz-margin-end: 5px;
|
||||
}
|
||||
|
||||
.expander:-moz-locale-dir(rtl) {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.expander[open] {
|
||||
-moz-appearance: treetwistyopen;
|
||||
}
|
||||
@ -159,7 +125,6 @@
|
||||
}
|
||||
|
||||
.expandable > .match {
|
||||
margin-top: 5px;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@ -168,13 +133,11 @@
|
||||
}
|
||||
|
||||
.property-name {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
color: -moz-FieldText;
|
||||
width: 220px;
|
||||
}
|
||||
.property-value {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
color: grey;
|
||||
}
|
||||
@ -214,41 +177,29 @@
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.selectedElementLabel {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.darkrow {
|
||||
background-color: rgba(0,0,0,.022);
|
||||
}
|
||||
|
||||
.header {
|
||||
#noResults {
|
||||
font-size: 18px;
|
||||
margin-top: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.headerControls {
|
||||
color: -moz-dialogtext;
|
||||
background-color: -moz-dialog;
|
||||
padding: 5px 0 0;
|
||||
}
|
||||
|
||||
.onlyuserstyles,
|
||||
.userStylesLabel {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.userStylesLabel {
|
||||
display: -moz-box;
|
||||
white-space: nowrap;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.onlyuserstyles {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
font-family: sans-serif;
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.searchfield {
|
||||
display: -moz-box;
|
||||
-moz-box-flex: 1;
|
||||
margin-left: 10px;
|
||||
-moz-margin-start: 10px;
|
||||
}
|
||||
|
||||
.styleinspector-legend {
|
||||
|
@ -22,6 +22,7 @@
|
||||
* Joe Walker <jwalker@mozilla.com> (original author)
|
||||
* Mihai Șucan <mihai.sucan@gmail.com>
|
||||
* Michael Ratcliffe <mratcliffe@mozilla.com>
|
||||
* Dão Gottwald <dao@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
@ -47,49 +48,19 @@
|
||||
display: -moz-box;
|
||||
}
|
||||
|
||||
#path {
|
||||
font-size: 11px;
|
||||
word-spacing: -1px;
|
||||
margin-bottom: 0;
|
||||
color: -moz-dialogtext;
|
||||
background-color: -moz-dialog;
|
||||
padding: 4px 5px 0;
|
||||
}
|
||||
#path ol {
|
||||
list-style: none outside none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#path li {
|
||||
border-radius: 3px;
|
||||
padding: 2px 3px;
|
||||
font-size: 11px;
|
||||
display: inline-block;
|
||||
}
|
||||
#path li:after {
|
||||
content: " > ";
|
||||
}
|
||||
#path li:last-child {
|
||||
font-weight: bold;
|
||||
color: #0091ff;
|
||||
}
|
||||
#path li:last-child:after {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.property-header {
|
||||
padding: 4px;
|
||||
-moz-padding-start: 0;
|
||||
-moz-padding-end: 5px;
|
||||
}
|
||||
|
||||
.rule-unmatched {
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
-moz-padding-start: 4px;
|
||||
-moz-padding-end: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.rule-unmatched {
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
-moz-padding-start: 4px;
|
||||
-moz-padding-end: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Take away these two :visited rules to get a core dumper */
|
||||
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
|
||||
@ -107,21 +78,20 @@
|
||||
.helplink-container {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.helplink {
|
||||
display: block;
|
||||
height: 0;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
padding-top: 14px;
|
||||
-moz-padding-start: 14px;
|
||||
background-image: url("chrome://browser/skin/devtools/goto-mdn.png");
|
||||
-moz-margin-end: 2px;
|
||||
}
|
||||
|
||||
.property-header:hover > .helplink-container {
|
||||
visibility: visible;
|
||||
.property-header:not(:hover) > .helplink-container {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.unmatchedSelectorTable {
|
||||
@ -136,15 +106,9 @@
|
||||
.expander {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
float: left;
|
||||
margin-top: 1px;
|
||||
-moz-margin-start: 5px;
|
||||
-moz-margin-end: 5px;
|
||||
background-image: url("chrome://global/skin/tree/twisty-clsd.png");
|
||||
}
|
||||
|
||||
.expander:-moz-locale-dir(rtl) {
|
||||
float: right;
|
||||
background: url("chrome://global/skin/tree/twisty-clsd.png") center center no-repeat;
|
||||
}
|
||||
|
||||
.expander[open] {
|
||||
@ -160,7 +124,6 @@
|
||||
}
|
||||
|
||||
.expandable > .match {
|
||||
margin-top: 5px;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@ -169,13 +132,11 @@
|
||||
}
|
||||
|
||||
.property-name {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
color: -moz-FieldText;
|
||||
width: 220px;
|
||||
}
|
||||
.property-value {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
color: grey;
|
||||
}
|
||||
@ -215,41 +176,29 @@
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.selectedElementLabel {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.darkrow {
|
||||
background-color: rgba(0,0,0,.022);
|
||||
}
|
||||
|
||||
.header {
|
||||
#noResults {
|
||||
font-size: 18px;
|
||||
margin-top: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.headerControls {
|
||||
color: -moz-dialogtext;
|
||||
background-color: -moz-dialog;
|
||||
padding: 5px 0 0;
|
||||
}
|
||||
|
||||
.onlyuserstyles,
|
||||
.userStylesLabel {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.userStylesLabel {
|
||||
display: -moz-box;
|
||||
white-space: nowrap;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.onlyuserstyles {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
font-family: sans-serif;
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.searchfield {
|
||||
display: -moz-box;
|
||||
-moz-box-flex: 1;
|
||||
margin-left: 10px;
|
||||
-moz-margin-start: 10px;
|
||||
}
|
||||
|
||||
.styleinspector-legend {
|
||||
|
@ -62,6 +62,7 @@
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include <io.h>
|
||||
#include <propvarutil.h>
|
||||
#include <propkey.h>
|
||||
@ -274,6 +275,28 @@ WinTaskbar::~WinTaskbar() {
|
||||
// static
|
||||
bool
|
||||
WinTaskbar::GetAppUserModelID(nsAString & aDefaultGroupId) {
|
||||
// If marked as such in prefs, use a hash of the profile path for the id
|
||||
// instead of the install path hash setup by the installer.
|
||||
bool useProfile =
|
||||
Preferences::GetBool("taskbar.grouping.useprofile", false);
|
||||
if (useProfile) {
|
||||
nsCOMPtr<nsIFile> profileDir;
|
||||
NS_GetSpecialDirectory(NS_APP_PROFILE_DEFAULTS_50_DIR,
|
||||
getter_AddRefs(profileDir));
|
||||
bool exists = false;
|
||||
if (profileDir && NS_SUCCEEDED(profileDir->Exists(&exists)) && exists) {
|
||||
nsCAutoString path;
|
||||
if (NS_SUCCEEDED(profileDir->GetNativePath(path))) {
|
||||
nsAutoString id;
|
||||
id.AppendInt(HashString(path));
|
||||
if (!id.IsEmpty()) {
|
||||
aDefaultGroupId.Assign(id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The default value is set by the installer and is stored in the registry
|
||||
// under (HKLM||HKCU)/Software/Mozilla/Firefox/TaskBarIDs. If for any reason
|
||||
// hash generation operation fails, the installer will not store a value in
|
||||
|
Loading…
Reference in New Issue
Block a user