Bug 886039 - Port the computed view to the styles actor. r=mratcliffe

This commit is contained in:
Dave Camp 2013-08-08 08:44:57 -07:00
parent 44b8744a8c
commit ccb9162455
17 changed files with 363 additions and 432 deletions

View File

@ -40,7 +40,7 @@ function test() {
testDiv.style.fontSize = "10px";
// Start up the style inspector panel...
Services.obs.addObserver(stylePanelTests, "StyleInspector-populated", false);
inspector.once("computed-view-refreshed", stylePanelTests);
inspector.selection.setNode(testDiv);
});
@ -48,15 +48,13 @@ function test() {
function stylePanelTests()
{
Services.obs.removeObserver(stylePanelTests, "StyleInspector-populated");
let computedview = inspector.sidebar.getWindowForTab("computedview").computedview;
ok(computedview, "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);
inspector.once("computed-view-refreshed", stylePanelAfterChange);
testDiv.style.fontSize = "15px";
inspector.emit("layout-change");
@ -64,8 +62,6 @@ function test() {
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.");
@ -78,7 +74,7 @@ function test() {
inspector.sidebar.select("ruleview");
executeSoon(function() {
Services.obs.addObserver(stylePanelAfterSwitch, "StyleInspector-populated", false);
inspector.once("computed-view-refreshed", stylePanelAfterSwitch);
testDiv.style.fontSize = "20px";
inspector.sidebar.select("computedview");
});
@ -86,8 +82,6 @@ function test() {
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.");

View File

@ -53,45 +53,39 @@ function test() {
instance.setSize(500, 500);
openInspector(onInspectorUIOpen);
openComputedView(onInspectorUIOpen);
}
function onInspectorUIOpen(aInspector) {
function onInspectorUIOpen(aInspector, aComputedView) {
inspector = aInspector;
ok(inspector, "Got inspector instance");
inspector.sidebar.select("computedview");
let div = content.document.getElementsByTagName("div")[0];
inspector.sidebar.once("computedview-ready", function() {
Services.obs.addObserver(testShrink, "StyleInspector-populated", false);
inspector.selection.setNode(div);
});
inspector.selection.setNode(div);
inspector.once("inspector-updated", testShrink);
}
function testShrink() {
Services.obs.removeObserver(testShrink, "StyleInspector-populated");
computedView = inspector.sidebar.getWindowForTab("computedview").computedview.view;
ok(computedView, "We have access to the Computed View object");
is(computedWidth(), "500px", "Should show 500px initially.");
Services.obs.addObserver(function onShrink() {
Services.obs.removeObserver(onShrink, "StyleInspector-populated");
inspector.once("computed-view-refreshed", function onShrink() {
is(computedWidth(), "100px", "div should be 100px after shrinking.");
testGrow();
}, "StyleInspector-populated", false);
});
instance.setSize(100, 100);
}
function testGrow() {
Services.obs.addObserver(function onGrow() {
Services.obs.removeObserver(onGrow, "StyleInspector-populated");
inspector.once("computed-view-refreshed", function onGrow() {
is(computedWidth(), "500px", "Should be 500px after growing.");
finishUp();
}, "StyleInspector-populated", false);
});
instance.setSize(500, 500);
}

View File

@ -18,6 +18,16 @@ function openInspector(callback)
});
}
function openComputedView(callback)
{
openInspector(inspector => {
inspector.sidebar.once("computedview-ready", () => {
inspector.sidebar.select("computedview");
let ruleView = inspector.sidebar.getWindowForTab("computedview").computedview.view;
callback(inspector, ruleView);
})
});
}
function openRuleView(callback)
{
openInspector(inspector => {

View File

@ -8,6 +8,9 @@ const {Cc, Ci, Cu} = require("chrome");
let ToolDefinitions = require("main").Tools;
let {CssLogic} = require("devtools/styleinspector/css-logic");
let {ELEMENT_STYLE} = require("devtools/server/actors/styles");
let promise = require("sdk/core/promise");
let {EventEmitter} = require("devtools/shared/event-emitter");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PluralForm.jsm");
@ -90,6 +93,7 @@ UpdateProcess.prototype = {
this.onDone();
return;
}
console.error(e);
throw e;
}
},
@ -115,14 +119,18 @@ UpdateProcess.prototype = {
* will generally only be one).
*
* @params {StyleInspector} aStyleInspector The owner of this CssHtmlTree
* @param {PageStyleFront} aPageStyle
* Front for the page style actor that will be providing
* the style information.
*
* @constructor
*/
function CssHtmlTree(aStyleInspector)
function CssHtmlTree(aStyleInspector, aPageStyle)
{
this.styleWindow = aStyleInspector.window;
this.styleDocument = aStyleInspector.window.document;
this.styleInspector = aStyleInspector;
this.cssLogic = aStyleInspector.cssLogic;
this.pageStyle = aPageStyle;
this.propertyViews = [];
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].
@ -144,6 +152,8 @@ function CssHtmlTree(aStyleInspector)
// No results text.
this.noResults = this.styleDocument.getElementById("noResults");
CssHtmlTree.processTemplate(this.templateRoot, this.root, this);
// The element that we're inspecting, and the document that it comes from.
this.viewedElement = null;
this.createStyleViews();
@ -207,8 +217,6 @@ CssHtmlTree.prototype = {
// Cache the list of properties that match the selected element.
_matchedProperties: null,
htmlComplete: false,
// Used for cancelling timeouts in the style filter.
_filterChangedTimeout: null,
@ -227,6 +235,10 @@ CssHtmlTree.prototype = {
// Number of visible properties
numVisibleProperties: 0,
setPageStyle: function(pageStyle) {
this.pageStyle = pageStyle;
},
get includeBrowserStyles()
{
return this.includeBrowserStylesCheckbox.checked;
@ -236,65 +248,65 @@ CssHtmlTree.prototype = {
* Update the highlighted element. The CssHtmlTree panel will show the style
* information for the given element.
* @param {nsIDOMElement} aElement The highlighted node to get styles for.
*
* @returns a promise that will be resolved when highlighting is complete.
*/
highlight: function CssHtmlTree_highlight(aElement)
{
this.viewedElement = aElement;
this._matchedProperties = null;
highlight: function(aElement) {
if (!aElement) {
if (this._refreshProcess) {
this._refreshProcess.cancel();
}
return;
return promise.resolve(undefined)
}
if (this.htmlComplete) {
this.refreshSourceFilter();
this.refreshPanel();
} else {
if (this._refreshProcess) {
this._refreshProcess.cancel();
if (aElement === this.viewedElement) {
return promise.resolve(undefined);
}
this.viewedElement = aElement;
this.refreshSourceFilter();
return this.refreshPanel();
},
_createPropertyViews: function()
{
if (this._createViewsPromise) {
return this._createViewsPromise;
}
let deferred = promise.defer();
this._createViewsPromise = deferred.promise;
this.refreshSourceFilter();
this.numVisibleProperties = 0;
let fragment = this.styleDocument.createDocumentFragment();
this._createViewsProcess = new UpdateProcess(this.styleWindow, CssHtmlTree.propertyNames, {
onItem: (aPropertyName) => {
// Per-item callback.
let propView = new PropertyView(this, aPropertyName);
fragment.appendChild(propView.buildMain());
fragment.appendChild(propView.buildSelectorContainer());
if (propView.visible) {
this.numVisibleProperties++;
}
this.propertyViews.push(propView);
},
onCancel: () => {
deferred.reject("_createPropertyViews cancelled");
},
onDone: () => {
// Completed callback.
this.propertyContainer.appendChild(fragment);
this.noResults.hidden = this.numVisibleProperties > 0;
deferred.resolve(undefined);
}
});
CssHtmlTree.processTemplate(this.templateRoot, this.root, this);
// Refresh source filter ... this must be done after templateRoot has been
// processed.
this.refreshSourceFilter();
this.numVisibleProperties = 0;
let fragment = this.styleDocument.createDocumentFragment();
this._refreshProcess = new UpdateProcess(this.styleWindow, CssHtmlTree.propertyNames, {
onItem: function(aPropertyName) {
// Per-item callback.
let propView = new PropertyView(this, aPropertyName);
fragment.appendChild(propView.buildMain());
fragment.appendChild(propView.buildSelectorContainer());
if (propView.visible) {
this.numVisibleProperties++;
}
propView.refreshMatchedSelectors();
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;
// If a refresh was scheduled during the building, complete it.
if (this._needsRefresh) {
delete this._needsRefresh;
this.refreshPanel();
} else {
Services.obs.notifyObservers(null, "StyleInspector-populated", null);
}
}.bind(this)});
this._refreshProcess.schedule();
}
this._createViewsProcess.schedule();
return deferred.promise;
},
/**
@ -302,39 +314,54 @@ CssHtmlTree.prototype = {
*/
refreshPanel: function CssHtmlTree_refreshPanel()
{
// If we're still in the process of creating the initial layout,
// leave it alone.
if (!this.htmlComplete) {
if (this._refreshProcess) {
this._needsRefresh = true;
return promise.all([
this._createPropertyViews(),
this.pageStyle.getComputed(this.viewedElement, {
filter: this._sourceFilter,
onlyMatched: !this.includeBrowserStyles,
markMatched: true
})
]).then(([createViews, computed]) => {
this._matchedProperties = new Set;
for (let name in computed) {
if (computed[name].matched) {
this._matchedProperties.add(name);
}
}
return;
}
this._computed = computed;
if (this._refreshProcess) {
this._refreshProcess.cancel();
}
if (this._refreshProcess) {
this._refreshProcess.cancel();
}
this.noResults.hidden = true;
this.noResults.hidden = true;
// Reset visible property count
this.numVisibleProperties = 0;
// Reset visible property count
this.numVisibleProperties = 0;
// Reset zebra striping.
this._darkStripe = true;
// Reset zebra striping.
this._darkStripe = true;
let display = this.propertyContainer.style.display;
this._refreshProcess = new UpdateProcess(this.styleWindow, 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);
}.bind(this)
});
this._refreshProcess.schedule();
let display = this.propertyContainer.style.display;
let deferred = promise.defer();
this._refreshProcess = new UpdateProcess(this.styleWindow, this.propertyViews, {
onItem: (aPropView) => {
aPropView.refresh();
},
onCancel: () => {
deferred.reject("refresh cancelled");
},
onDone: () => {
this._refreshProcess = null;
this.noResults.hidden = this.numVisibleProperties > 0;
this.styleInspector.inspector.emit("computed-view-refreshed");
deferred.resolve(undefined);
}
});
this._refreshProcess.schedule();
return deferred.promise;
}).then(null, (err) => console.error(err));
},
/**
@ -377,7 +404,7 @@ CssHtmlTree.prototype = {
refreshSourceFilter: function CssHtmlTree_setSourceFilter()
{
this._matchedProperties = null;
this.cssLogic.sourceFilter = this.includeBrowserStyles ?
this._sourceFilter = this.includeBrowserStyles ?
CssLogic.FILTER.UA :
CssLogic.FILTER.USER;
},
@ -409,21 +436,18 @@ CssHtmlTree.prototype = {
CssHtmlTree.propertyNames.sort();
CssHtmlTree.propertyNames.push.apply(CssHtmlTree.propertyNames,
mozProps.sort());
this._createPropertyViews();
},
/**
* Get a list of properties that have matched selectors.
* Get a set of properties that have matched selectors.
*
* @return {object} the object maps property names (keys) to booleans (values)
* that tell if the given property has matched selectors or not.
* @return {Set} If a property name is in the set, it has matching selectors.
*/
get matchedProperties()
{
if (!this._matchedProperties) {
this._matchedProperties =
this.cssLogic.hasMatchedSelectors(CssHtmlTree.propertyNames);
}
return this._matchedProperties;
return this._matchedProperties || new Set;
},
/**
@ -473,6 +497,9 @@ CssHtmlTree.prototype = {
this.searchField.removeEventListener("command", this.filterChanged);
// Cancel tree construction
if (this._createViewsProcess) {
this._createViewsProcess.cancel();
}
if (this._refreshProcess) {
this._refreshProcess.cancel();
}
@ -517,11 +544,18 @@ CssHtmlTree.prototype = {
delete this.propertyViews;
delete this.styleWindow;
delete this.styleDocument;
delete this.cssLogic;
delete this.styleInspector;
},
};
function PropertyInfo(aTree, aName) {
this.tree = aTree;
this.name = aName;
}
PropertyInfo.prototype = {
get value() this.tree._computed ? this.tree._computed[this.name].value : ""
}
/**
* A container to give easy access to property data from the template engine.
*
@ -539,6 +573,7 @@ function PropertyView(aTree, aName)
this.link = "https://developer.mozilla.org/CSS/" + aName;
this.templateMatchedSelectors = aTree.styleDocument.getElementById("templateMatchedSelectors");
this._propertyInfo = new PropertyInfo(aTree, aName);
}
PropertyView.prototype = {
@ -585,7 +620,7 @@ PropertyView.prototype = {
*/
get propertyInfo()
{
return this.tree.cssLogic.getPropertyInfo(this.name);
return this._propertyInfo;
},
/**
@ -593,7 +628,7 @@ PropertyView.prototype = {
*/
get hasMatchedSelectors()
{
return this.name in this.tree.matchedProperties;
return this.tree.matchedProperties.has(this.name);
},
/**
@ -738,15 +773,29 @@ PropertyView.prototype = {
}
if (this.matchedExpanded && hasMatchedSelectors) {
CssHtmlTree.processTemplate(this.templateMatchedSelectors,
this.matchedSelectorsContainer, this);
this.matchedExpander.setAttribute("open", "");
return this.tree.pageStyle.getMatchedSelectors(this.tree.viewedElement, this.name).then(matched => {
if (!this.matchedExpanded) {
return;
}
this._matchedSelectorResponse = matched;
CssHtmlTree.processTemplate(this.templateMatchedSelectors,
this.matchedSelectorsContainer, this);
this.matchedExpander.setAttribute("open", "");
this.tree.styleInspector.inspector.emit("computed-view-property-expanded");
}).then(null, console.error);
} else {
this.matchedSelectorsContainer.innerHTML = "";
this.matchedExpander.removeAttribute("open");
return promise.resolve(undefined);
}
},
get matchedSelectors()
{
return this._matchedSelectorResponse;
},
/**
* Provide access to the matched SelectorViews that we are currently
* displaying.
@ -755,7 +804,7 @@ PropertyView.prototype = {
{
if (!this._matchedSelectorViews) {
this._matchedSelectorViews = [];
this.propertyInfo.matchedSelectors.forEach(
this._matchedSelectorResponse.forEach(
function matchedSelectorViews_convert(aSelectorInfo) {
this._matchedSelectorViews.push(new SelectorView(this.tree, aSelectorInfo));
}, this);
@ -802,6 +851,15 @@ function SelectorView(aTree, aSelectorInfo)
this.tree = aTree;
this.selectorInfo = aSelectorInfo;
this._cacheStatusNames();
let rule = this.selectorInfo.rule;
if (rule && rule.parentStyleSheet) {
this.sheet = rule.parentStyleSheet;
this.source = CssLogic.shortSource(this.sheet) + ":" + rule.line;
} else {
this.source = CssLogic.l10n("rule.sourceElement");
this.href = "#";
}
}
/**
@ -859,24 +917,25 @@ SelectorView.prototype = {
return SelectorView.CLASS_NAMES[this.selectorInfo.status - 1];
},
/**
* A localized Get localized human readable info
*/
text: function SelectorView_text(aElement) {
let result = this.selectorInfo.selector.text;
if (this.selectorInfo.elementStyle) {
let source = this.selectorInfo.sourceElement;
let inspector = this.tree.styleInspector.inspector;
if (inspector.selection.node == source) {
result = "this";
} else {
result = CssLogic.getShortName(source);
}
result += ".style";
get href()
{
if (this._href) {
return this._href;
}
let sheet = this.selectorInfo.rule.parentStyleSheet;
this._href = sheet ? sheet.href : "#";
return this._href;
},
return result;
get sourceText()
{
return this.selectorInfo.sourceText;
},
get value()
{
return this.selectorInfo.value;
},
maybeOpenStyleEditor: function(aEvent)
@ -900,12 +959,8 @@ SelectorView.prototype = {
openStyleEditor: function(aEvent)
{
let inspector = this.tree.styleInspector.inspector;
let contentDoc = inspector.selection.document;
let cssSheet = this.selectorInfo.selector.cssRule._cssSheet;
let line = this.selectorInfo.ruleLine || 0;
let contentSheet = false;
let styleSheet;
let styleSheets;
let rule = this.selectorInfo.rule;
let line = rule.line || 0;
// The style editor can only display stylesheets coming from content because
// chrome stylesheets are not listed in the editor's stylesheet selector.
@ -913,40 +968,28 @@ SelectorView.prototype = {
// If the stylesheet is a content stylesheet we send it to the style
// editor else we display it in the view source window.
//
// We check if cssSheet exists in case of inline styles (which contain no
// sheet)
if (cssSheet) {
styleSheet = cssSheet.domSheet;
styleSheets = contentDoc.styleSheets;
// Array.prototype.indexOf always returns -1 here so we loop through
// the styleSheets array instead.
for each (let sheet in styleSheets) {
if (sheet == styleSheet) {
contentSheet = true;
break;
}
}
}
if (contentSheet) {
let href = rule.href;
let sheet = rule.parentStyleSheet;
if (sheet && href && !sheet.isSystem) {
let target = inspector.target;
if (ToolDefinitions.styleEditor.isTargetSupported(target)) {
gDevTools.showToolbox(target, "styleeditor").then(function(toolbox) {
toolbox.getCurrentPanel().selectStyleSheet(styleSheet.href, line);
toolbox.getCurrentPanel().selectStyleSheet(href, line);
});
}
} else {
let href = styleSheet ? styleSheet.href : "";
let viewSourceUtils = inspector.viewSourceUtils;
if (this.selectorInfo.sourceElement) {
href = this.selectorInfo.sourceElement.ownerDocument.location.href;
}
viewSourceUtils.viewSource(href, null, contentDoc, line);
return;
}
},
let contentDoc = null;
let rawNode = this.tree.viewedElement.rawNode();
if (rawNode) {
contentDoc = rawNode.ownerDocument;
}
let viewSourceUtils = inspector.viewSourceUtils;
viewSourceUtils.viewSource(href, null, contentDoc, line);
}
};
exports.CssHtmlTree = CssHtmlTree;

View File

@ -98,12 +98,12 @@
<a target="_blank" class="link theme-link"
onclick="${selector.openStyleEditor}"
onkeydown="${selector.maybeOpenStyleEditor}"
title="${selector.selectorInfo.href}"
tabindex="0">${selector.selectorInfo.source}</a>
title="${selector.href}"
tabindex="0">${selector.source}</a>
</span>
<span dir="ltr" class="rule-text ${selector.statusClass} theme-fg-color3" title="${selector.statusText}">
${selector.text(__element)}
<span class="other-property-value theme-fg-color1">${selector.selectorInfo.value}</span>
${selector.sourceText}
<span class="other-property-value theme-fg-color1">${selector.value}</span>
</span>
</p>
</loop>

View File

@ -15,7 +15,6 @@ loader.lazyGetter(this, "RuleView", () => require("devtools/styleinspector/rule-
loader.lazyGetter(this, "ComputedView", () => require("devtools/styleinspector/computed-view"));
loader.lazyGetter(this, "_strings", () => Services.strings
.createBundle("chrome://browser/locale/devtools/styleinspector.properties"));
loader.lazyGetter(this, "CssLogic", () => require("devtools/styleinspector/css-logic").CssLogic);
// This module doesn't currently export any symbols directly, it only
// registers inspector tools.
@ -171,21 +170,20 @@ function ComputedViewTool(aInspector, aWindow, aIFrame)
this.window = aWindow;
this.document = aWindow.document;
this.outerIFrame = aIFrame;
this.cssLogic = new CssLogic();
this.view = new ComputedView.CssHtmlTree(this);
this.view = new ComputedView.CssHtmlTree(this, aInspector.pageStyle);
this._onSelect = this.onSelect.bind(this);
this.inspector.selection.on("detached", this._onSelect);
this.inspector.selection.on("new-node", this._onSelect);
this.inspector.selection.on("new-node-front", this._onSelect);
if (this.inspector.highlighter) {
this.inspector.highlighter.on("locked", this._onSelect);
}
this.refresh = this.refresh.bind(this);
this.inspector.on("layout-change", this.refresh);
this.inspector.sidebar.on("computedview-selected", this.refresh);
this.inspector.selection.on("pseudoclass", this.refresh);
this.panelSelected = this.panelSelected.bind(this);
this.inspector.sidebar.on("computedview-selected", this.panelSelected);
this.cssLogic.highlight(null);
this.view.highlight(null);
this.onSelect();
@ -196,24 +194,35 @@ exports.ComputedViewTool = ComputedViewTool;
ComputedViewTool.prototype = {
onSelect: function CVT_onSelect(aEvent)
{
if (!this.isActive()) {
// We'll try again when we're selected.
return;
}
this.view.setPageStyle(this.inspector.pageStyle);
if (!this.inspector.selection.isConnected() ||
!this.inspector.selection.isElementNode()) {
this.view.highlight(null);
return;
}
if (!aEvent || aEvent == "new-node") {
if (!aEvent || aEvent == "new-node-front") {
if (this.inspector.selection.reason == "highlighter") {
// FIXME: We should hide view's content
} else {
this.cssLogic.highlight(this.inspector.selection.node);
this.view.highlight(this.inspector.selection.node);
let done = this.inspector.updating("computed-view");
this.view.highlight(this.inspector.selection.nodeFront).then(() => {
done();
});
}
}
if (aEvent == "locked") {
this.cssLogic.highlight(this.inspector.selection.node);
this.view.highlight(this.inspector.selection.node);
if (aEvent == "locked" && this.inspector.selection.nodeFront != this.view.viewedElement) {
let done = this.inspector.updating("computed-view");
this.view.highlight(this.inspector.selection.nodeFront).then(() => {
done();
});
}
},
@ -223,17 +232,24 @@ ComputedViewTool.prototype = {
refresh: function CVT_refresh() {
if (this.isActive()) {
this.cssLogic.highlight(this.inspector.selection.node);
this.view.refreshPanel();
}
},
panelSelected: function() {
if (this.inspector.selection.nodeFront === this.view.viewedElement) {
this.view.refreshPanel();
} else {
this.onSelect();
}
},
destroy: function CVT_destroy(aContext)
{
this.inspector.off("layout-change", this.refresh);
this.inspector.sidebar.off("computedview-selected", this.refresh);
this.inspector.selection.off("pseudoclass", this.refresh);
this.inspector.selection.off("new-node", this._onSelect);
this.inspector.selection.off("new-node-front", this._onSelect);
if (this.inspector.highlighter) {
this.inspector.highlighter.off("locked", this._onSelect);
}

View File

@ -12,7 +12,6 @@ relativesrcdir = @relativesrcdir@
include $(DEPTH)/config/autoconf.mk
MOCHITEST_BROWSER_FILES = \
browser_styleinspector.js \
browser_bug683672.js \
browser_styleinspector_bug_672746_default_styles.js \
browser_styleinspector_bug_672744_search_filter.js \

View File

@ -13,6 +13,7 @@ const TEST_URI = "http://example.com/browser/browser/devtools/styleinspector/tes
let tempScope = {};
let {CssHtmlTree, PropertyView} = devtools.require("devtools/styleinspector/computed-view");
let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
function test()
{
@ -25,49 +26,49 @@ function tabLoaded()
{
browser.removeEventListener("load", tabLoaded, true);
doc = content.document;
openInspector(selectNode);
openComputedView(selectNode);
}
function selectNode(aInspector)
function selectNode(aInspector, aComputedView)
{
inspector = aInspector;
computedView = aComputedView;
div = content.document.getElementById("test");
ok(div, "captain, we have the div");
inspector.selection.setNode(div);
inspector.sidebar.once("computedview-ready", function() {
computedView = getComputedView(inspector);
inspector.sidebar.select("computedview");
runTests();
});
inspector.once("inspector-updated", runTests);
}
function runTests()
{
testMatchedSelectors();
info("finishing up");
finishUp();
testMatchedSelectors().then(() => {
info("finishing up");
finishUp();
});
}
function testMatchedSelectors()
{
info("checking selector counts, matched rules and titles");
is(div, computedView.viewedElement,
is(div, computedView.viewedElement.rawNode(),
"style inspector node matches the selected node");
let propertyView = new PropertyView(computedView, "color");
let numMatchedSelectors = propertyView.propertyInfo.matchedSelectors.length;
propertyView.buildMain();
propertyView.buildSelectorContainer();
propertyView.matchedExpanded = true;
return propertyView.refreshMatchedSelectors().then(() => {
let numMatchedSelectors = propertyView.matchedSelectors.length;
is(numMatchedSelectors, 6,
"CssLogic returns the correct number of matched selectors for div");
is(numMatchedSelectors, 6,
"CssLogic returns the correct number of matched selectors for div");
is(propertyView.hasMatchedSelectors, true,
"hasMatchedSelectors returns true");
is(propertyView.hasMatchedSelectors, true,
"hasMatchedSelectors returns true");
}).then(null, (err) => console.error(err));
}
function finishUp()

View File

@ -11,6 +11,9 @@ let computedView;
const TEST_URI = "http://example.com/browser/browser/devtools/styleinspector/" +
"test/browser_bug722196_identify_media_queries.html";
let {PropertyView} = devtools.require("devtools/styleinspector/computed-view");
let {CssLogic} = devtools.require("devtools/styleinspector/css-logic");
function test()
{
waitForExplicitFinish();
@ -23,26 +26,24 @@ function docLoaded()
browser.removeEventListener("load", docLoaded, true);
doc = content.document;
openInspector(selectNode);
openComputedView(selectNode);
}
function selectNode(aInspector)
function selectNode(aInspector, aComputedView)
{
computedView = aComputedView;
var div = doc.querySelector("div");
ok(div, "captain, we have the div");
aInspector.selection.setNode(div);
aInspector.sidebar.once("computedview-ready", function() {
aInspector.sidebar.select("computedview");
computedView = getComputedView(aInspector);
checkSheets();
});
aInspector.once("inspector-updated", checkCssLogic);
}
function checkSheets()
function checkCssLogic()
{
let cssLogic = computedView.cssLogic;
let cssLogic = new CssLogic();
cssLogic.highlight(doc.querySelector("div"));
cssLogic.processMatchedSelectors();
let _strings = Services.strings
@ -57,7 +58,26 @@ function checkSheets()
is(cssLogic._matchedRules[1][0].source, source2,
"rule.source gives correct output for rule 2");
finishUp();
checkPropertyView();
}
function checkPropertyView()
{
let propertyView = new PropertyView(computedView, "width");
propertyView.buildMain();
propertyView.buildSelectorContainer();
propertyView.matchedExpanded = true;
return propertyView.refreshMatchedSelectors().then(() => {
let numMatchedSelectors = propertyView.matchedSelectors.length;
is(numMatchedSelectors, 2,
"Property view has the correct number of matched selectors for div");
is(propertyView.hasMatchedSelectors, true,
"hasMatchedSelectors returns true");
finishUp();
}).then(null, (err) => console.error(err));
}
function finishUp()

View File

@ -13,29 +13,23 @@ function createDocument()
doc.title = "Style Inspector Selector Text Test";
openInspector(openComputedView);
openComputedView(startTests);
}
function openComputedView(aInspector)
function startTests(aInspector, aComputedView)
{
computedView = aComputedView;
let div = doc.querySelector("div");
ok(div, "captain, we have the test div");
aInspector.selection.setNode(div);
aInspector.sidebar.once("computedview-ready", function() {
aInspector.sidebar.select("computedview");
computedView = getComputedView(aInspector);
Services.obs.addObserver(SI_checkText, "StyleInspector-populated", false);
});
aInspector.once("inspector-updated", SI_checkText);
}
function SI_checkText()
{
Services.obs.removeObserver(SI_checkText, "StyleInspector-populated");
let propertyView = null;
computedView.propertyViews.some(function(aView) {
if (aView.name == "color") {
@ -50,15 +44,16 @@ function SI_checkText()
is(propertyView.hasMatchedSelectors, true, "hasMatchedSelectors is true");
propertyView.matchedExpanded = true;
propertyView.refreshMatchedSelectors();
propertyView.refreshMatchedSelectors().then(() => {
let span = propertyView.matchedSelectorsContainer.querySelector("span.rule-text");
ok(span, "found the first table row");
let span = propertyView.matchedSelectorsContainer.querySelector("span.rule-text");
ok(span, "found the first table row");
let selector = propertyView.matchedSelectorViews[0];
ok(selector, "found the first matched selector view");
let selector = propertyView.matchedSelectorViews[0];
ok(selector, "found the first matched selector view");
finishUp();
finishUp();
});
}
function finishUp()

View File

@ -42,29 +42,20 @@ const DOCUMENT_URL = "data:text/html,"+encodeURIComponent(
function selectNode(aInspector)
function selectNode(aInspector, aComputedView)
{
inspector = aInspector;
computedView = aComputedView;
let span = doc.querySelector("span");
ok(span, "captain, we have the span");
aInspector.selection.setNode(span);
aInspector.sidebar.once("computedview-ready", function() {
aInspector.sidebar.select("computedview");
computedView = getComputedView(aInspector);
Services.obs.addObserver(testInlineStyle, "StyleInspector-populated", false);
});
inspector.selection.setNode(span);
inspector.once("inspector-updated", testInlineStyle);
}
function testInlineStyle()
{
Services.obs.removeObserver(testInlineStyle, "StyleInspector-populated");
info("expanding property");
expandProperty(0, function propertyExpanded() {
Services.ww.registerNotification(function onWindow(aSubject, aTopic) {
if (aTopic != "domwindowopened") {
@ -137,12 +128,13 @@ function validateStyleEditorSheet(aEditor, aExpectedSheetIndex)
function expandProperty(aIndex, aCallback)
{
info("expanding property " + aIndex);
let contentDoc = computedView.styleDocument;
let expando = contentDoc.querySelectorAll(".expandable")[aIndex];
expando.click();
// We use executeSoon to give the property time to expand.
executeSoon(aCallback);
inspector.once("computed-view-property-expanded", aCallback);
}
function getLinkByIndex(aIndex)
@ -168,7 +160,7 @@ function test()
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee,
true);
doc = content.document;
waitForFocus(function () { openInspector(selectNode); }, content);
waitForFocus(function () { openComputedView(selectNode); }, content);
}, true);
content.location = DOCUMENT_URL;

View File

@ -32,33 +32,24 @@ function createDocument()
'</div>';
doc.title = "Computed view context menu test";
openInspector(selectNode)
openComputedView(selectNode)
}
function selectNode(aInspector)
function selectNode(aInspector, aComputedView)
{
computedView = aComputedView;
win = aInspector.sidebar.getWindowForTab("computedview");
let span = doc.querySelector("span");
ok(span, "captain, we have the span");
aInspector.selection.setNode(span);
aInspector.sidebar.once("computedview-ready", function() {
aInspector.sidebar.select("computedview");
computedView = getComputedView(aInspector);
win = aInspector.sidebar.getWindowForTab("computedview");
Services.obs.addObserver(runStyleInspectorTests,
"StyleInspector-populated", false);
});
aInspector.once("inspector-updated", runStyleInspectorTests);
}
function runStyleInspectorTests()
{
Services.obs.removeObserver(runStyleInspectorTests,
"StyleInspector-populated", false);
let contentDocument = computedView.styleDocument;
let prop = contentDocument.querySelector(".property-view");
ok(prop, "captain, we have the property-view node");

View File

@ -1,89 +0,0 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the style inspector works properly
let doc;
let inspector;
let computedView;
function createDocument()
{
doc.body.innerHTML = '<style type="text/css"> ' +
'span { font-variant: small-caps; color: #000000; } ' +
'.nomatches {color: #ff0000;}</style> <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 <span style="color: yellow">' +
'highlight</span> and <span style="font-weight: bold">count</span> ' +
'style list-items in the box at right. 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' +
'<p>Inspect using inspectstyle(document.querySelectorAll("span")[0])</p>' +
'</div>';
doc.title = "Style Inspector Test";
openInspector(openComputedView);
}
function openComputedView(aInspector)
{
inspector = aInspector;
inspector.sidebar.once("computedview-ready", function() {
computedView = getComputedView(inspector);
inspector.sidebar.select("computedview");
runStyleInspectorTests();
});
}
function runStyleInspectorTests()
{
var spans = doc.querySelectorAll("span");
ok(spans, "captain, we have the spans");
for (var i = 0, numSpans = spans.length; i < numSpans; i++) {
inspector.selection.setNode(spans[i]);
is(spans[i], computedView.viewedElement,
"style inspector node matches the selected node");
is(computedView.viewedElement, computedView.cssLogic.viewedElement,
"cssLogic node matches the cssHtmlTree node");
}
SI_CheckProperty();
finishUp();
}
function SI_CheckProperty()
{
let cssLogic = computedView.cssLogic;
let propertyInfo = cssLogic.getPropertyInfo("color");
ok(propertyInfo.matchedRuleCount > 0, "color property has matching rules");
}
function finishUp()
{
doc = computedView = null;
gBrowser.removeCurrentTab();
finish();
}
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
doc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = "data:text/html,basic style inspector tests";
}

View File

@ -16,24 +16,14 @@ function createDocument()
'</div>';
doc.title = "Style Inspector Search Filter Test";
openInspector(openComputedView);
openComputedView(runStyleInspectorTests);
}
function openComputedView(aInspector)
function runStyleInspectorTests(aInspector, aComputedView)
{
inspector = aInspector;
computedView = aComputedView;
inspector.sidebar.once("computedview-ready", function() {
inspector.sidebar.select("computedview");
computedView = getComputedView(inspector);
runStyleInspectorTests();
});
}
function runStyleInspectorTests()
{
Services.obs.addObserver(SI_toggleDefaultStyles, "StyleInspector-populated", false);
SI_inspectNode();
}
@ -43,32 +33,28 @@ function SI_inspectNode()
ok(span, "captain, we have the matches span");
inspector.selection.setNode(span);
is(span, computedView.viewedElement,
"style inspector node matches the selected node");
is(computedView.viewedElement, computedView.cssLogic.viewedElement,
"cssLogic node matches the cssHtmlTree node");
inspector.once("inspector-updated", () => {
is(span, computedView.viewedElement.rawNode(),
"style inspector node matches the selected node");
SI_toggleDefaultStyles();
}).then(null, (err) => console.error(err));
}
function SI_toggleDefaultStyles()
{
Services.obs.removeObserver(SI_toggleDefaultStyles, "StyleInspector-populated");
info("checking \"Browser styles\" checkbox");
let doc = computedView.styleDocument;
let checkbox = doc.querySelector(".includebrowserstyles");
Services.obs.addObserver(SI_AddFilterText, "StyleInspector-populated", false);
inspector.once("computed-view-refreshed", SI_AddFilterText);
checkbox.click();
}
function SI_AddFilterText()
{
Services.obs.removeObserver(SI_AddFilterText, "StyleInspector-populated");
let doc = computedView.styleDocument;
let searchbar = doc.querySelector(".devtools-searchinput");
Services.obs.addObserver(SI_checkFilter, "StyleInspector-populated", false);
inspector.once("computed-view-refreshed", SI_checkFilter);
info("setting filter text to \"color\"");
searchbar.focus();
@ -82,7 +68,6 @@ function SI_AddFilterText()
function SI_checkFilter()
{
Services.obs.removeObserver(SI_checkFilter, "StyleInspector-populated");
let propertyViews = computedView.propertyViews;
info("check that the correct properties are visible");

View File

@ -16,43 +16,27 @@ function createDocument()
'</div>';
doc.title = "Style Inspector Default Styles Test";
openInspector(openComputedView);
openComputedView(SI_inspectNode);
}
function openComputedView(aInspector)
function SI_inspectNode(aInspector, aComputedView)
{
inspector = aInspector;
computedView = aComputedView;
inspector.sidebar.once("computedview-ready", function() {
inspector.sidebar.select("computedview");
computedView = getComputedView(inspector);
runStyleInspectorTests();
});
}
function runStyleInspectorTests()
{
Services.obs.addObserver(SI_check, "StyleInspector-populated", false);
SI_inspectNode();
}
function SI_inspectNode()
{
let span = doc.querySelector("#matches");
ok(span, "captain, we have the matches span");
inspector.selection.setNode(span);
is(span, computedView.viewedElement,
"style inspector node matches the selected node");
is(computedView.viewedElement, computedView.cssLogic.viewedElement,
"cssLogic node matches the cssHtmlTree node");
inspector.once("inspector-updated", () => {
is(span, computedView.viewedElement.rawNode(),
"style inspector node matches the selected node");
SI_check();
});
}
function SI_check()
{
Services.obs.removeObserver(SI_check, "StyleInspector-populated");
is(propertyVisible("color"), true,
"span #matches color property is visible");
is(propertyVisible("background-color"), false,
@ -66,14 +50,13 @@ function SI_toggleDefaultStyles()
// Click on the checkbox.
let doc = computedView.styleDocument;
let checkbox = doc.querySelector(".includebrowserstyles");
Services.obs.addObserver(SI_checkDefaultStyles, "StyleInspector-populated", false);
inspector.once("computed-view-refreshed", SI_checkDefaultStyles);
checkbox.click();
}
function SI_checkDefaultStyles()
{
Services.obs.removeObserver(SI_checkDefaultStyles, "StyleInspector-populated");
// Check that the default styles are now applied.
is(propertyVisible("color"), true,
"span color property is visible");

View File

@ -15,45 +15,33 @@ function createDocument()
'<span id="matches" class="matches">Some styled text</span>';
doc.title = "Tests that the no results placeholder works properly";
openInspector(openComputedView);
openComputedView(runStyleInspectorTests);
}
function openComputedView(aInspector)
function runStyleInspectorTests(aInspector, aComputedView)
{
inspector = aInspector;
inspector.sidebar.once("computedview-ready", function() {
inspector.sidebar.select("computedview");
computedView = getComputedView(inspector);
runStyleInspectorTests();
});
}
function runStyleInspectorTests()
{
Services.obs.addObserver(SI_AddFilterText, "StyleInspector-populated", false);
computedView = aComputedView;
let span = doc.querySelector("#matches");
ok(span, "captain, we have the matches span");
inspector.selection.setNode(span);
inspector.once("inspector-updated", () => {
is(span, computedView.viewedElement.rawNode(),
"style inspector node matches the selected node");
SI_AddFilterText();
});
is(span, computedView.viewedElement,
"style inspector node matches the selected node");
is(computedView.viewedElement, computedView.cssLogic.viewedElement,
"cssLogic node matches the cssHtmlTree node");
}
function SI_AddFilterText()
{
Services.obs.removeObserver(SI_AddFilterText, "StyleInspector-populated");
let searchbar = computedView.searchField;
let searchTerm = "xxxxx";
Services.obs.addObserver(SI_checkPlaceholderVisible, "StyleInspector-populated", false);
inspector.once("computed-view-refreshed", SI_checkPlaceholderVisible);
info("setting filter text to \"" + searchTerm + "\"");
searchbar.focus();
for each (let c in searchTerm) {
@ -63,7 +51,6 @@ function SI_AddFilterText()
function SI_checkPlaceholderVisible()
{
Services.obs.removeObserver(SI_checkPlaceholderVisible, "StyleInspector-populated");
info("SI_checkPlaceholderVisible called");
let placeholder = computedView.noResults;
let win = computedView.styleWindow;
@ -78,7 +65,7 @@ function SI_ClearFilterText()
{
let searchbar = computedView.searchField;
Services.obs.addObserver(SI_checkPlaceholderHidden, "StyleInspector-populated", false);
inspector.once("computed-view-refreshed", SI_checkPlaceholderHidden);
info("clearing filter text");
searchbar.focus();
searchbar.value = "";
@ -87,7 +74,6 @@ function SI_ClearFilterText()
function SI_checkPlaceholderHidden()
{
Services.obs.removeObserver(SI_checkPlaceholderHidden, "StyleInspector-populated");
let placeholder = computedView.noResults;
let win = computedView.styleWindow;
let display = win.getComputedStyle(placeholder).display;

View File

@ -59,6 +59,17 @@ function openRuleView(callback)
});
}
function openComputedView(callback)
{
openInspector(inspector => {
inspector.sidebar.once("computedview-ready", () => {
inspector.sidebar.select("computedview");
let ruleView = inspector.sidebar.getWindowForTab("computedview").computedview.view;
callback(inspector, ruleView);
})
});
}
function addStyle(aDocument, aString)
{
let node = aDocument.createElement('style');