зеркало из https://github.com/mozilla/gecko-dev.git
Bug 886038 - Port the rule view to the styles actor. r=mratcliffe
This commit is contained in:
Родитель
083c360416
Коммит
7b3a1264e1
|
@ -68,14 +68,12 @@ function performTests()
|
|||
// inspector has been told of the pseudoclass lock change.
|
||||
inspector.selection.once("pseudoclass", () => {
|
||||
// Give the rule view time to update.
|
||||
executeSoon(() => {
|
||||
inspector.once("rule-view-refreshed", () => {
|
||||
testAdded();
|
||||
|
||||
// toggle the lock off and wait for the pseudoclass event again.
|
||||
// Change the pseudo class and give the rule view time to update.
|
||||
inspector.togglePseudoClass(pseudo);
|
||||
inspector.selection.once("pseudoclass", () => {
|
||||
// Give the rule view time to update.
|
||||
executeSoon(() => {
|
||||
inspector.once("rule-view-refreshed", () => {
|
||||
testRemoved();
|
||||
testRemovedFromUI();
|
||||
|
||||
|
|
|
@ -48,26 +48,20 @@ function test() {
|
|||
|
||||
instance.setSize(500, 500);
|
||||
|
||||
openInspector(onInspectorUIOpen);
|
||||
openRuleView(onInspectorUIOpen);
|
||||
}
|
||||
|
||||
function onInspectorUIOpen(aInspector) {
|
||||
function onInspectorUIOpen(aInspector, aRuleView) {
|
||||
inspector = aInspector;
|
||||
ruleView = aRuleView;
|
||||
ok(inspector, "Got inspector instance");
|
||||
inspector.sidebar.select("ruleview");
|
||||
|
||||
let div = content.document.getElementsByTagName("div")[0];
|
||||
|
||||
inspector.sidebar.once("ruleview-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");
|
||||
|
||||
ruleView = inspector.sidebar.getWindowForTab("ruleview").ruleview.view;
|
||||
|
||||
is(numberOfRules(), 2, "Should have two rules initially.");
|
||||
|
||||
|
|
|
@ -18,3 +18,13 @@ function openInspector(callback)
|
|||
});
|
||||
}
|
||||
|
||||
function openRuleView(callback)
|
||||
{
|
||||
openInspector(inspector => {
|
||||
inspector.sidebar.once("ruleview-ready", () => {
|
||||
inspector.sidebar.select("ruleview");
|
||||
let ruleView = inspector.sidebar.getWindowForTab("ruleview").ruleview.view;
|
||||
callback(inspector, ruleView);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
"use strict";
|
||||
|
||||
const {Cc, Ci, Cu} = require("chrome");
|
||||
const promise = require("sdk/core/promise");
|
||||
|
||||
let {CssLogic} = require("devtools/styleinspector/css-logic");
|
||||
let {InplaceEditor, editableField, editableItem} = require("devtools/shared/inplace-editor");
|
||||
let {ELEMENT_STYLE} = require("devtools/server/actors/styles");
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
@ -34,6 +36,46 @@ const CSS_RESOURCE_RE = /url\([\'\"]?(.*?)[\'\"]?\)/;
|
|||
const IOService = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
|
||||
function promiseWarn(err) {
|
||||
console.error(err);
|
||||
return promise.reject(err);
|
||||
}
|
||||
|
||||
/**
|
||||
* To figure out how shorthand properties are interpreted by the
|
||||
* engine, we will set properties on a dummy element and observe
|
||||
* how their .style attribute reflects them as computed values.
|
||||
* This function creates the document in which those dummy elements
|
||||
* will be created.
|
||||
*/
|
||||
var gDummyPromise;
|
||||
function createDummyDocument() {
|
||||
if (gDummyPromise) {
|
||||
return gDummyPromise;
|
||||
}
|
||||
const { getDocShell, create: makeFrame } = require("sdk/frame/utils");
|
||||
|
||||
let frame = makeFrame(Services.appShell.hiddenDOMWindow.document, {
|
||||
nodeName: "iframe",
|
||||
namespaceURI: "http://www.w3.org/1999/xhtml",
|
||||
allowJavascript: false,
|
||||
allowPlugins: false,
|
||||
allowAuth: false
|
||||
});
|
||||
let docShell = getDocShell(frame);
|
||||
let eventTarget = docShell.chromeEventHandler;
|
||||
docShell.createAboutBlankContentViewer(Cc["@mozilla.org/nullprincipal;1"].createInstance(Ci.nsIPrincipal));
|
||||
let window = docShell.contentViewer.DOMDocument.defaultView;
|
||||
window.location = "data:text/html,<html></html>";
|
||||
let deferred = promise.defer()
|
||||
eventTarget.addEventListener("DOMContentLoaded", function handler(event) {
|
||||
eventTarget.removeEventListener("DOMContentLoaded", handler, false);
|
||||
deferred.resolve(window.document);
|
||||
}, false);
|
||||
gDummyPromise = deferred.promise;
|
||||
return gDummyPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Our model looks like this:
|
||||
*
|
||||
|
@ -62,13 +104,17 @@ const IOService = Cc["@mozilla.org/network/io-service;1"]
|
|||
* The ElementStyle can use this object to store metadata
|
||||
* that might outlast the rule view, particularly the current
|
||||
* set of disabled properties.
|
||||
* @param {PageStyleFront} aPageStyle
|
||||
* Front for the page style actor that will be providing
|
||||
* the style information.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function ElementStyle(aElement, aStore)
|
||||
function ElementStyle(aElement, aStore, aPageStyle)
|
||||
{
|
||||
this.element = aElement;
|
||||
this.store = aStore || {};
|
||||
this.pageStyle = aPageStyle;
|
||||
|
||||
// We don't want to overwrite this.store.userProperties so we only create it
|
||||
// if it doesn't already exist.
|
||||
|
@ -85,9 +131,12 @@ function ElementStyle(aElement, aStore)
|
|||
// To figure out how shorthand properties are interpreted by the
|
||||
// engine, we will set properties on a dummy element and observe
|
||||
// how their .style attribute reflects them as computed values.
|
||||
this.dummyElement = doc.createElementNS(this.element.namespaceURI,
|
||||
this.element.tagName);
|
||||
this.populate();
|
||||
this.dummyElementPromise = createDummyDocument().then(document => {
|
||||
this.dummyElement = document.createElementNS(this.element.namespaceURI,
|
||||
this.element.tagName);
|
||||
document.documentElement.appendChild(this.dummyElement);
|
||||
return this.dummyElement;
|
||||
}).then(null, promiseWarn);
|
||||
}
|
||||
// We're exporting _ElementStyle for unit tests.
|
||||
exports._ElementStyle = ElementStyle;
|
||||
|
@ -101,6 +150,17 @@ ElementStyle.prototype = {
|
|||
// to figure out how shorthand properties will be parsed.
|
||||
dummyElement: null,
|
||||
|
||||
destroy: function()
|
||||
{
|
||||
this.dummyElement = null;
|
||||
this.dummyElementPromise.then(dummyElement => {
|
||||
if (dummyElement.parentNode) {
|
||||
dummyElement.parentNode.removeChild(dummyElement);
|
||||
}
|
||||
this.dummyElementPromise = null;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Called by the Rule object when it has been changed through the
|
||||
* setProperty* methods.
|
||||
|
@ -115,62 +175,44 @@ ElementStyle.prototype = {
|
|||
/**
|
||||
* Refresh the list of rules to be displayed for the active element.
|
||||
* Upon completion, this.rules[] will hold a list of Rule objects.
|
||||
*
|
||||
* Returns a promise that will be resolved when the elementStyle is
|
||||
* ready.
|
||||
*/
|
||||
populate: function ElementStyle_populate()
|
||||
{
|
||||
// Store the current list of rules (if any) during the population
|
||||
// process. They will be reused if possible.
|
||||
this._refreshRules = this.rules;
|
||||
let populated = this.pageStyle.getApplied(this.element, {
|
||||
inherited: true,
|
||||
matchedSelectors: true
|
||||
}).then(entries => {
|
||||
// Make sure the dummy element has been created before continuing...
|
||||
return this.dummyElementPromise.then(() => {
|
||||
if (this.populated != populated) {
|
||||
// Don't care anymore.
|
||||
return promise.reject("unused");
|
||||
}
|
||||
|
||||
this.rules = [];
|
||||
// Store the current list of rules (if any) during the population
|
||||
// process. They will be reused if possible.
|
||||
this._refreshRules = this.rules;
|
||||
|
||||
let element = this.element;
|
||||
do {
|
||||
this._addElementRules(element);
|
||||
} while ((element = element.parentNode) &&
|
||||
element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
|
||||
this.rules = [];
|
||||
|
||||
// Mark overridden computed styles.
|
||||
this.markOverridden();
|
||||
for (let entry of entries) {
|
||||
this._maybeAddRule(entry);
|
||||
}
|
||||
|
||||
// We're done with the previous list of rules.
|
||||
delete this._refreshRules;
|
||||
},
|
||||
// Mark overridden computed styles.
|
||||
this.markOverridden();
|
||||
|
||||
_addElementRules: function ElementStyle_addElementRules(aElement)
|
||||
{
|
||||
let inherited = aElement !== this.element ? aElement : null;
|
||||
// We're done with the previous list of rules.
|
||||
delete this._refreshRules;
|
||||
|
||||
// Include the element's style first.
|
||||
this._maybeAddRule({
|
||||
style: aElement.style,
|
||||
selectorText: CssLogic.l10n("rule.sourceElement"),
|
||||
inherited: inherited
|
||||
});
|
||||
|
||||
// Get the styles that apply to the element.
|
||||
var domRules = domUtils.getCSSStyleRules(aElement);
|
||||
|
||||
// getCSStyleRules returns ordered from least-specific to
|
||||
// most-specific.
|
||||
for (let i = domRules.Count() - 1; i >= 0; i--) {
|
||||
let domRule = domRules.GetElementAt(i);
|
||||
|
||||
// XXX: Optionally provide access to system sheets.
|
||||
let contentSheet = CssLogic.isContentStylesheet(domRule.parentStyleSheet);
|
||||
if (!contentSheet) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this._maybeAddRule({
|
||||
domRule: domRule,
|
||||
inherited: inherited
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}).then(null, promiseWarn);
|
||||
this.populated = populated;
|
||||
return this.populated;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -186,8 +228,12 @@ ElementStyle.prototype = {
|
|||
{
|
||||
// If we've already included this domRule (for example, when a
|
||||
// common selector is inherited), ignore it.
|
||||
if (aOptions.domRule &&
|
||||
this.rules.some(function(rule) rule.domRule === aOptions.domRule)) {
|
||||
if (aOptions.rule &&
|
||||
this.rules.some(function(rule) rule.domRule === aOptions.rule)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aOptions.system) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -195,11 +241,13 @@ ElementStyle.prototype = {
|
|||
|
||||
// If we're refreshing and the rule previously existed, reuse the
|
||||
// Rule object.
|
||||
for (let r of (this._refreshRules || [])) {
|
||||
if (r.matches(aOptions)) {
|
||||
rule = r;
|
||||
rule.refresh();
|
||||
break;
|
||||
if (this._refreshRules) {
|
||||
for (let r of this._refreshRules) {
|
||||
if (r.matches(aOptions)) {
|
||||
rule = r;
|
||||
rule.refresh(aOptions);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,6 +262,7 @@ ElementStyle.prototype = {
|
|||
}
|
||||
|
||||
this.rules.push(rule);
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -324,11 +373,7 @@ ElementStyle.prototype = {
|
|||
* The ElementStyle to which this rule belongs.
|
||||
* @param {object} aOptions
|
||||
* The information used to construct this rule. Properties include:
|
||||
* domRule: the nsIDOMCSSStyleRule to view, if any.
|
||||
* style: the nsIDOMCSSStyleDeclaration to view. If omitted,
|
||||
* the domRule's style will be used.
|
||||
* selectorText: selector text to display. If omitted, the domRule's
|
||||
* selectorText will be used.
|
||||
* rule: A StyleRuleActor
|
||||
* inherited: An element this rule was inherited from. If omitted,
|
||||
* the rule applies directly to the current element.
|
||||
* @constructor
|
||||
|
@ -336,15 +381,17 @@ ElementStyle.prototype = {
|
|||
function Rule(aElementStyle, aOptions)
|
||||
{
|
||||
this.elementStyle = aElementStyle;
|
||||
this.domRule = aOptions.domRule || null;
|
||||
this.style = aOptions.style || this.domRule.style;
|
||||
this.selectorText = aOptions.selectorText || this.domRule.selectorText;
|
||||
this.domRule = aOptions.rule || null;
|
||||
this.style = aOptions.rule;
|
||||
this.matchedSelectors = aOptions.matchedSelectors || [];
|
||||
|
||||
this.inherited = aOptions.inherited || null;
|
||||
this._modificationDepth = 0;
|
||||
|
||||
if (this.domRule) {
|
||||
let parentRule = this.domRule.parentRule;
|
||||
if (parentRule && parentRule.type == Ci.nsIDOMCSSRule.MEDIA_RULE) {
|
||||
this.mediaText = parentRule.media.mediaText;
|
||||
this.mediaText = parentRule.mediaText;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -363,11 +410,12 @@ Rule.prototype = {
|
|||
return this._title;
|
||||
}
|
||||
this._title = CssLogic.shortSource(this.sheet);
|
||||
if (this.domRule) {
|
||||
if (this.domRule.type !== ELEMENT_STYLE) {
|
||||
this._title += ":" + this.ruleLine;
|
||||
}
|
||||
|
||||
return this._title + (this.mediaText ? " @media " + this.mediaText : "");
|
||||
this._title = this._title + (this.mediaText ? " @media " + this.mediaText : "");
|
||||
return this._title;
|
||||
},
|
||||
|
||||
get inheritedSource()
|
||||
|
@ -387,6 +435,11 @@ Rule.prototype = {
|
|||
return this._inheritedSource;
|
||||
},
|
||||
|
||||
get selectorText()
|
||||
{
|
||||
return this.domRule.selectors ? this.domRule.selectors.join(", ") : CssLogic.l10n("rule.sourceElement");
|
||||
},
|
||||
|
||||
/**
|
||||
* The rule's stylesheet.
|
||||
*/
|
||||
|
@ -400,11 +453,7 @@ Rule.prototype = {
|
|||
*/
|
||||
get ruleLine()
|
||||
{
|
||||
if (!this.sheet) {
|
||||
// No stylesheet, no ruleLine
|
||||
return null;
|
||||
}
|
||||
return domUtils.getRuleLine(this.domRule);
|
||||
return this.domRule ? this.domRule.line : null;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -416,7 +465,7 @@ Rule.prototype = {
|
|||
*/
|
||||
matches: function Rule_matches(aOptions)
|
||||
{
|
||||
return (this.style === (aOptions.style || aOptions.domRule.style));
|
||||
return this.style === aOptions.rule;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -447,12 +496,15 @@ Rule.prototype = {
|
|||
* when calling from setPropertyValue & setPropertyName to signify
|
||||
* that the property should be saved in store.userProperties.
|
||||
*/
|
||||
applyProperties: function Rule_applyProperties(aName)
|
||||
applyProperties: function Rule_applyProperties(aModifications, aName)
|
||||
{
|
||||
if (!aModifications) {
|
||||
aModifications = this.style.startModifyingProperties();
|
||||
}
|
||||
let disabledProps = [];
|
||||
let store = this.elementStyle.store;
|
||||
|
||||
for each (let prop in this.textProps) {
|
||||
for (let prop of this.textProps) {
|
||||
if (!prop.enabled) {
|
||||
disabledProps.push({
|
||||
name: prop.name,
|
||||
|
@ -462,21 +514,11 @@ Rule.prototype = {
|
|||
continue;
|
||||
}
|
||||
|
||||
this.style.setProperty(prop.name, prop.value, prop.priority);
|
||||
aModifications.setProperty(prop.name, prop.value, prop.priority);
|
||||
|
||||
if (aName && prop.name == aName) {
|
||||
store.userProperties.setProperty(
|
||||
this.style, prop.name,
|
||||
this.style.getPropertyValue(prop.name),
|
||||
prop.value);
|
||||
}
|
||||
|
||||
// Refresh the property's priority from the style, to reflect
|
||||
// any changes made during parsing.
|
||||
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;
|
||||
|
@ -486,7 +528,46 @@ Rule.prototype = {
|
|||
disabled.delete(this.style);
|
||||
}
|
||||
|
||||
this.elementStyle.markOverridden();
|
||||
let promise = aModifications.apply().then(() => {
|
||||
let cssProps = {};
|
||||
for (let cssProp of this._parseCSSText(this.style.cssText)) {
|
||||
cssProps[cssProp.name] = cssProp;
|
||||
}
|
||||
|
||||
for (let textProp of this.textProps) {
|
||||
if (!textProp.enabled) {
|
||||
continue;
|
||||
}
|
||||
let cssProp = cssProps[textProp.name];
|
||||
|
||||
if (!cssProp) {
|
||||
cssProp = {
|
||||
name: textProp.name,
|
||||
value: "",
|
||||
priority: ""
|
||||
}
|
||||
}
|
||||
|
||||
if (aName && textProp.name == aName) {
|
||||
store.userProperties.setProperty(
|
||||
this.style, textProp.name,
|
||||
null,
|
||||
cssProp.value,
|
||||
textProp.value);
|
||||
}
|
||||
textProp.priority = cssProp.priority;
|
||||
}
|
||||
|
||||
this.elementStyle.markOverridden();
|
||||
|
||||
if (promise === this._applyingModifications) {
|
||||
this._applyingModifications = null;
|
||||
}
|
||||
|
||||
this.elementStyle._changed();
|
||||
}).then(null, promiseWarn);
|
||||
this._applyingModifications = promise;
|
||||
return promise;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -502,9 +583,10 @@ Rule.prototype = {
|
|||
if (aName === aProperty.name) {
|
||||
return;
|
||||
}
|
||||
this.style.removeProperty(aProperty.name);
|
||||
let modifications = this.style.startModifyingProperties();
|
||||
modifications.removeProperty(aProperty.name);
|
||||
aProperty.name = aName;
|
||||
this.applyProperties(aName);
|
||||
this.applyProperties(modifications, aName);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -524,7 +606,7 @@ Rule.prototype = {
|
|||
}
|
||||
aProperty.value = aValue;
|
||||
aProperty.priority = aPriority;
|
||||
this.applyProperties(aProperty.name);
|
||||
this.applyProperties(null, aProperty.name);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -533,10 +615,11 @@ Rule.prototype = {
|
|||
setPropertyEnabled: function Rule_enableProperty(aProperty, aValue)
|
||||
{
|
||||
aProperty.enabled = !!aValue;
|
||||
let modifications = this.style.startModifyingProperties();
|
||||
if (!aProperty.enabled) {
|
||||
this.style.removeProperty(aProperty.name);
|
||||
modifications.removeProperty(aProperty.name);
|
||||
}
|
||||
this.applyProperties();
|
||||
this.applyProperties(modifications);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -546,10 +629,32 @@ Rule.prototype = {
|
|||
removeProperty: function Rule_removeProperty(aProperty)
|
||||
{
|
||||
this.textProps = this.textProps.filter(function(prop) prop != aProperty);
|
||||
this.style.removeProperty(aProperty);
|
||||
let modifications = this.style.startModifyingProperties();
|
||||
modifications.removeProperty(aProperty.name);
|
||||
// Need to re-apply properties in case removing this TextProperty
|
||||
// exposes another one.
|
||||
this.applyProperties();
|
||||
this.applyProperties(modifications);
|
||||
},
|
||||
|
||||
_parseCSSText: function Rule_parseProperties(aCssText)
|
||||
{
|
||||
let lines = aCssText.match(CSS_LINE_RE);
|
||||
let props = [];
|
||||
|
||||
for (let line of lines) {
|
||||
dump("line: " + line + "\n");
|
||||
let [, name, value, priority] = CSS_PROP_RE.exec(line) || []
|
||||
if (!name || !value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
props.push({
|
||||
name: name,
|
||||
value: value,
|
||||
priority: priority || ""
|
||||
});
|
||||
}
|
||||
return props;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -560,19 +665,15 @@ Rule.prototype = {
|
|||
{
|
||||
let textProps = [];
|
||||
let store = this.elementStyle.store;
|
||||
let lines = this.style.cssText.match(CSS_LINE_RE);
|
||||
for each (let line in lines) {
|
||||
let matches = CSS_PROP_RE.exec(line);
|
||||
if (!matches || !matches[2])
|
||||
continue;
|
||||
|
||||
let name = matches[1];
|
||||
let props = this._parseCSSText(this.style.cssText);
|
||||
for (let prop of props) {
|
||||
let name = prop.name;
|
||||
if (this.inherited && !domUtils.isInheritedProperty(name)) {
|
||||
continue;
|
||||
}
|
||||
let value = store.userProperties.getProperty(this.style, name, matches[2]);
|
||||
let prop = new TextProperty(this, name, value, matches[3] || "");
|
||||
textProps.push(prop);
|
||||
let value = store.userProperties.getProperty(this.style, name, prop.value);
|
||||
let textProp = new TextProperty(this, name, value, prop.priority);
|
||||
textProps.push(textProp);
|
||||
}
|
||||
|
||||
return textProps;
|
||||
|
@ -607,8 +708,9 @@ Rule.prototype = {
|
|||
* Reread the current state of the rules and rebuild text
|
||||
* properties as needed.
|
||||
*/
|
||||
refresh: function Rule_refresh()
|
||||
refresh: function Rule_refresh(aOptions)
|
||||
{
|
||||
this.matchedSelectors = aOptions.matchedSelectors || [];
|
||||
let newTextProps = this._getTextProperties();
|
||||
|
||||
// Update current properties for each property present on the style.
|
||||
|
@ -861,14 +963,15 @@ TextProperty.prototype = {
|
|||
* The CSS rule view can use this object to store metadata
|
||||
* that might outlast the rule view, particularly the current
|
||||
* set of disabled properties.
|
||||
* @param {<iframe>} aOuterIFrame
|
||||
* The iframe containing the ruleview.
|
||||
* @param {PageStyleFront} aPageStyle
|
||||
* The PageStyleFront for communicating with the remote server.
|
||||
* @constructor
|
||||
*/
|
||||
function CssRuleView(aDoc, aStore)
|
||||
function CssRuleView(aDoc, aStore, aPageStyle)
|
||||
{
|
||||
this.doc = aDoc;
|
||||
this.store = aStore;
|
||||
this.pageStyle = aPageStyle;
|
||||
this.element = this.doc.createElementNS(HTML_NS, "div");
|
||||
this.element.className = "ruleview devtools-monospace";
|
||||
this.element.flex = 1;
|
||||
|
@ -892,6 +995,10 @@ CssRuleView.prototype = {
|
|||
// The element that we're inspecting.
|
||||
_viewedElement: null,
|
||||
|
||||
setPageStyle: function(aPageStyle) {
|
||||
this.pageStyle = aPageStyle;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return {bool} true if the rule view currently has an input editor visible.
|
||||
*/
|
||||
|
@ -910,6 +1017,8 @@ CssRuleView.prototype = {
|
|||
this.element.parentNode.removeChild(this.element);
|
||||
}
|
||||
|
||||
this.elementStyle.destroy();
|
||||
|
||||
this.popup.destroy();
|
||||
},
|
||||
|
||||
|
@ -922,7 +1031,7 @@ CssRuleView.prototype = {
|
|||
highlight: function CssRuleView_highlight(aElement)
|
||||
{
|
||||
if (this._viewedElement === aElement) {
|
||||
return;
|
||||
return promise.resolve(undefined);
|
||||
}
|
||||
|
||||
this.clear();
|
||||
|
@ -934,15 +1043,15 @@ CssRuleView.prototype = {
|
|||
this._viewedElement = aElement;
|
||||
if (!this._viewedElement) {
|
||||
this._showEmpty();
|
||||
return;
|
||||
return promise.resolve(undefined);
|
||||
}
|
||||
|
||||
this._elementStyle = new ElementStyle(aElement, this.store);
|
||||
this._elementStyle.onChanged = function() {
|
||||
this._changed();
|
||||
}.bind(this);
|
||||
|
||||
this._createEditors();
|
||||
this._elementStyle = new ElementStyle(aElement, this.store, this.pageStyle);
|
||||
return this._populate().then(() => {
|
||||
this._elementStyle.onChanged = () => {
|
||||
this._changed();
|
||||
};
|
||||
}).then(null, console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -952,21 +1061,29 @@ CssRuleView.prototype = {
|
|||
{
|
||||
// Ignore refreshes during editing or when no element is selected.
|
||||
if (this.isEditing || !this._elementStyle) {
|
||||
return;
|
||||
return promise.resolve(null);
|
||||
}
|
||||
|
||||
this._clearRules();
|
||||
|
||||
// Repopulate the element style.
|
||||
this._elementStyle.populate();
|
||||
return this._populate();
|
||||
},
|
||||
|
||||
// Refresh the rule editors.
|
||||
this._createEditors();
|
||||
_populate: function() {
|
||||
let elementStyle = this._elementStyle;
|
||||
return this._elementStyle.populate().then(() => {
|
||||
if (this._elementStyle != elementStyle) {
|
||||
return promise.reject("element changed");
|
||||
}
|
||||
this._createEditors();
|
||||
|
||||
// Notify anyone that cares that we refreshed.
|
||||
var evt = this.doc.createEvent("Events");
|
||||
evt.initEvent("CssRuleViewRefreshed", true, false);
|
||||
this.element.dispatchEvent(evt);
|
||||
// Notify anyone that cares that we refreshed.
|
||||
var evt = this.doc.createEvent("Events");
|
||||
evt.initEvent("CssRuleViewRefreshed", true, false);
|
||||
this.element.dispatchEvent(evt);
|
||||
return undefined;
|
||||
}).then(null, promiseWarn);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1023,7 +1140,10 @@ CssRuleView.prototype = {
|
|||
// Run through the current list of rules, attaching
|
||||
// their editors in order. Create editors if needed.
|
||||
let lastInheritedSource = "";
|
||||
for each (let rule in this._elementStyle.rules) {
|
||||
for (let rule of this._elementStyle.rules) {
|
||||
if (rule.domRule.system) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let inheritedSource = rule.inheritedSource;
|
||||
if (inheritedSource != lastInheritedSource) {
|
||||
|
@ -1117,7 +1237,7 @@ RuleEditor.prototype = {
|
|||
class: "ruleview-rule-source theme-link"
|
||||
});
|
||||
source.addEventListener("click", function() {
|
||||
let rule = this.rule;
|
||||
let rule = this.rule.domRule;
|
||||
let evt = this.doc.createEvent("CustomEvent");
|
||||
evt.initCustomEvent("CssRuleViewCSSLinkClicked", true, false, {
|
||||
rule: rule,
|
||||
|
@ -1198,11 +1318,10 @@ RuleEditor.prototype = {
|
|||
// If selector text comes from a css rule, highlight selectors that
|
||||
// actually match. For custom selector text (such as for the 'element'
|
||||
// style, just show the text directly.
|
||||
if (this.rule.domRule && this.rule.domRule.selectorText) {
|
||||
let selectors = CssLogic.getSelectors(this.rule.domRule);
|
||||
let element = this.rule.inherited || this.ruleView._viewedElement;
|
||||
for (let i = 0; i < selectors.length; i++) {
|
||||
let selector = selectors[i];
|
||||
if (this.rule.domRule.type === ELEMENT_STYLE) {
|
||||
this.selectorText.textContent = this.rule.selectorText;
|
||||
} else {
|
||||
this.rule.domRule.selectors.forEach((selector, i) => {
|
||||
if (i != 0) {
|
||||
createChild(this.selectorText, "span", {
|
||||
class: "ruleview-selector-separator",
|
||||
|
@ -1210,7 +1329,7 @@ RuleEditor.prototype = {
|
|||
});
|
||||
}
|
||||
let cls;
|
||||
if (domUtils.selectorMatchesElement(element, this.rule.domRule, i)) {
|
||||
if (this.rule.matchedSelectors.indexOf(selector) > -1) {
|
||||
cls = "ruleview-selector-matched";
|
||||
} else {
|
||||
cls = "ruleview-selector-unmatched";
|
||||
|
@ -1219,9 +1338,7 @@ RuleEditor.prototype = {
|
|||
class: cls,
|
||||
textContent: selector
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.selectorText.textContent = this.rule.selectorText;
|
||||
});
|
||||
}
|
||||
|
||||
for (let prop of this.rule.textProps) {
|
||||
|
@ -1339,7 +1456,7 @@ function TextPropertyEditor(aRuleEditor, aProperty)
|
|||
this.browserWindow = this.doc.defaultView.top;
|
||||
|
||||
let sheet = this.prop.rule.sheet;
|
||||
let href = sheet ? CssLogic.href(sheet) : null;
|
||||
let href = sheet ? (sheet.href || sheet.nodeHref) : null;
|
||||
if (href) {
|
||||
this.sheetURI = IOService.newURI(href, null, null);
|
||||
}
|
||||
|
|
|
@ -29,19 +29,21 @@ function RuleViewTool(aInspector, aWindow, aIFrame)
|
|||
this.view = new RuleView.CssRuleView(this.doc, null);
|
||||
this.doc.documentElement.appendChild(this.view.element);
|
||||
|
||||
this._changeHandler = function() {
|
||||
this._changeHandler = () => {
|
||||
this.inspector.markDirty();
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
this.view.element.addEventListener("CssRuleViewChanged", this._changeHandler)
|
||||
this.view.element.addEventListener("CssRuleViewChanged", this._changeHandler);
|
||||
|
||||
this._cssLinkHandler = function(aEvent) {
|
||||
let contentDoc = this.inspector.selection.document;
|
||||
this._refreshHandler = () => {
|
||||
this.inspector.emit("rule-view-refreshed");
|
||||
};
|
||||
|
||||
this.view.element.addEventListener("CssRuleViewRefreshed", this._refreshHandler);
|
||||
|
||||
this._cssLinkHandler = (aEvent) => {
|
||||
let rule = aEvent.detail.rule;
|
||||
let line = rule.ruleLine || 0;
|
||||
let styleSheet = rule.sheet;
|
||||
let styleSheets = contentDoc.styleSheets;
|
||||
let contentSheet = false;
|
||||
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.
|
||||
|
@ -49,42 +51,34 @@ function RuleViewTool(aInspector, aWindow, aIFrame)
|
|||
// If the stylesheet is a content stylesheet we send it to the style
|
||||
// editor else we display it in the view source window.
|
||||
//
|
||||
// Array.prototype.indexOf always returns -1 here so we loop through
|
||||
// the styleSheets object 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 = this.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 : "";
|
||||
if (rule.elementStyle.element) {
|
||||
href = rule.elementStyle.element.ownerDocument.location.href;
|
||||
}
|
||||
let viewSourceUtils = this.inspector.viewSourceUtils;
|
||||
viewSourceUtils.viewSource(href, null, contentDoc, line);
|
||||
return;
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
let contentDoc = this.inspector.selection.document;
|
||||
let viewSourceUtils = this.inspector.viewSourceUtils;
|
||||
viewSourceUtils.viewSource(href, null, contentDoc, line);
|
||||
}
|
||||
|
||||
this.view.element.addEventListener("CssRuleViewCSSLinkClicked",
|
||||
this._cssLinkHandler);
|
||||
|
||||
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);
|
||||
this.refresh = this.refresh.bind(this);
|
||||
this.inspector.on("layout-change", this.refresh);
|
||||
this.inspector.sidebar.on("ruleview-selected", this.refresh);
|
||||
|
||||
this.panelSelected = this.panelSelected.bind(this);
|
||||
this.inspector.sidebar.on("ruleview-selected", this.panelSelected);
|
||||
this.inspector.selection.on("pseudoclass", this.refresh);
|
||||
if (this.inspector.highlighter) {
|
||||
this.inspector.highlighter.on("locked", this._onSelect);
|
||||
|
@ -97,22 +91,30 @@ exports.RuleViewTool = RuleViewTool;
|
|||
|
||||
RuleViewTool.prototype = {
|
||||
onSelect: function RVT_onSelect(aEvent) {
|
||||
if (!this.isActive()) {
|
||||
// We'll update when the panel is 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") {
|
||||
this.view.highlight(null);
|
||||
} else {
|
||||
this.view.highlight(this.inspector.selection.node);
|
||||
let done = this.inspector.updating("rule-view");
|
||||
this.view.highlight(this.inspector.selection.nodeFront).then(done, done);
|
||||
}
|
||||
}
|
||||
|
||||
if (aEvent == "locked") {
|
||||
this.view.highlight(this.inspector.selection.node);
|
||||
let done = this.inspector.updating("rule-view");
|
||||
this.view.highlight(this.inspector.selection.nodeFront).then(done, done);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -126,11 +128,19 @@ RuleViewTool.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
panelSelected: function() {
|
||||
if (this.inspector.selection.nodeFront === this.view.viewedElement) {
|
||||
this.view.nodeChanged();
|
||||
} else {
|
||||
this.onSelect();
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function RVT_destroy() {
|
||||
this.inspector.off("layout-change", this.refresh);
|
||||
this.inspector.sidebar.off("ruleview-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);
|
||||
}
|
||||
|
@ -141,6 +151,9 @@ RuleViewTool.prototype = {
|
|||
this.view.element.removeEventListener("CssRuleViewChanged",
|
||||
this._changeHandler);
|
||||
|
||||
this.view.element.removeEventListener("CssRuleViewRefreshed",
|
||||
this._refreshHandler);
|
||||
|
||||
this.doc.documentElement.removeChild(this.view.element);
|
||||
|
||||
this.view.destroy();
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
// rule view.
|
||||
|
||||
let doc;
|
||||
let inspector = null;
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/styleinspector/" +
|
||||
"test/browser_bug722196_identify_media_queries.html";
|
||||
|
@ -21,7 +22,15 @@ function docLoaded()
|
|||
{
|
||||
browser.removeEventListener("load", docLoaded, true);
|
||||
doc = content.document;
|
||||
checkSheets();
|
||||
openRuleView(selectNode);
|
||||
}
|
||||
|
||||
function selectNode(aInspector, aRuleView)
|
||||
{
|
||||
inspector = aInspector;
|
||||
|
||||
inspector.selection.setNode(doc.querySelector("div"));
|
||||
inspector.once("inspector-updated", checkSheets);
|
||||
}
|
||||
|
||||
function checkSheets()
|
||||
|
@ -29,14 +38,14 @@ function checkSheets()
|
|||
var div = doc.querySelector("div");
|
||||
ok(div, "captain, we have the div");
|
||||
|
||||
let elementStyle = new _ElementStyle(div);
|
||||
is(elementStyle.rules.length, 3, "Should have 3 rules.");
|
||||
let elementStyle = ruleView()._elementStyle;
|
||||
|
||||
let _strings = Services.strings
|
||||
.createBundle("chrome://browser/locale/devtools/styleinspector.properties");
|
||||
|
||||
let inline = _strings.GetStringFromName("rule.sourceInline");
|
||||
|
||||
is(elementStyle.rules.length, 3, "Should have 3 rules.");
|
||||
is(elementStyle.rules[0].title, inline, "check rule 0 title");
|
||||
is(elementStyle.rules[1].title, inline +
|
||||
":15 @media screen and (min-width: 1px)", "check rule 1 title");
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
// arrow keys works correctly.
|
||||
|
||||
let doc;
|
||||
let ruleDialog;
|
||||
let ruleView;
|
||||
let view;
|
||||
let inspector;
|
||||
|
||||
function setUpTests()
|
||||
{
|
||||
|
@ -15,25 +15,22 @@ function setUpTests()
|
|||
'margin-top:0px;' +
|
||||
'padding-top: 0px;' +
|
||||
'color:#000000;' +
|
||||
'background-color: #000000; >"'+
|
||||
'background-color: #000000;" >'+
|
||||
'</div>';
|
||||
let testElement = doc.getElementById("test");
|
||||
ruleDialog = openDialog("chrome://browser/content/devtools/cssruleview.xhtml",
|
||||
"cssruleviewtest",
|
||||
"width=350,height=350");
|
||||
ruleDialog.addEventListener("load", function onLoad(evt) {
|
||||
ruleDialog.removeEventListener("load", onLoad, true);
|
||||
let doc = ruleDialog.document;
|
||||
ruleView = new CssRuleView(doc);
|
||||
doc.documentElement.appendChild(ruleView.element);
|
||||
ruleView.highlight(testElement);
|
||||
waitForFocus(runTests, ruleDialog);
|
||||
}, true);
|
||||
|
||||
openRuleView((aInspector, aRuleView) => {
|
||||
inspector = aInspector;
|
||||
view = aRuleView;
|
||||
inspector.selection.setNode(doc.getElementById("test"));
|
||||
inspector.once("inspector-updated", () => {
|
||||
runTests();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function runTests()
|
||||
{
|
||||
let idRuleEditor = ruleView.element.children[0]._ruleEditor;
|
||||
let idRuleEditor = view.element.children[0]._ruleEditor;
|
||||
let marginPropEditor = idRuleEditor.rule.textProps[0].editor;
|
||||
let paddingPropEditor = idRuleEditor.rule.textProps[1].editor;
|
||||
let hexColorPropEditor = idRuleEditor.rule.textProps[2].editor;
|
||||
|
@ -52,7 +49,7 @@ function runTests()
|
|||
8: { pageDown: true, shift: true, start: "0px", end: "-100px", selectAll: true,
|
||||
nextTest: test2 }
|
||||
});
|
||||
EventUtils.synthesizeMouse(marginPropEditor.valueSpan, 1, 1, {}, ruleDialog);
|
||||
EventUtils.synthesizeMouse(marginPropEditor.valueSpan, 1, 1, {}, view.doc.defaultView);
|
||||
})();
|
||||
|
||||
function test2() {
|
||||
|
@ -69,7 +66,7 @@ function runTests()
|
|||
9: { start: "0ex", end: "1ex", selectAll: true,
|
||||
nextTest: test3 }
|
||||
});
|
||||
EventUtils.synthesizeMouse(paddingPropEditor.valueSpan, 1, 1, {}, ruleDialog);
|
||||
EventUtils.synthesizeMouse(paddingPropEditor.valueSpan, 1, 1, {}, view.doc.defaultView);
|
||||
};
|
||||
|
||||
function test3() {
|
||||
|
@ -83,7 +80,7 @@ function runTests()
|
|||
6: { down: true, shift: true, start: "#000000", end: "#000000", selectAll: true,
|
||||
nextTest: test4 }
|
||||
});
|
||||
EventUtils.synthesizeMouse(hexColorPropEditor.valueSpan, 1, 1, {}, ruleDialog);
|
||||
EventUtils.synthesizeMouse(hexColorPropEditor.valueSpan, 1, 1, {}, view.doc.defaultView);
|
||||
};
|
||||
|
||||
function test4() {
|
||||
|
@ -97,7 +94,7 @@ function runTests()
|
|||
6: { down: true, shift: true, start: "rgb(0,5,0)", end: "rgb(0,0,0)", selection: [6,7],
|
||||
nextTest: test5 }
|
||||
});
|
||||
EventUtils.synthesizeMouse(rgbColorPropEditor.valueSpan, 1, 1, {}, ruleDialog);
|
||||
EventUtils.synthesizeMouse(rgbColorPropEditor.valueSpan, 1, 1, {}, view.doc.defaultView);
|
||||
};
|
||||
|
||||
function test5() {
|
||||
|
@ -111,7 +108,7 @@ function runTests()
|
|||
6: { down: true, shift: true, start: "0px 0px 0px 0px", end: "-10px 0px 0px 0px", selectAll: true,
|
||||
nextTest: test6 }
|
||||
});
|
||||
EventUtils.synthesizeMouse(paddingPropEditor.valueSpan, 1, 1, {}, ruleDialog);
|
||||
EventUtils.synthesizeMouse(paddingPropEditor.valueSpan, 1, 1, {}, view.doc.defaultView);
|
||||
};
|
||||
|
||||
function test6() {
|
||||
|
@ -133,7 +130,7 @@ function runTests()
|
|||
14: { alt: true, start: "url('test--0.1.png')", end: "url('test-0.png')", selection: [10,14],
|
||||
endTest: true }
|
||||
});
|
||||
EventUtils.synthesizeMouse(marginPropEditor.valueSpan, 1, 1, {}, ruleDialog);
|
||||
EventUtils.synthesizeMouse(marginPropEditor.valueSpan, 1, 1, {}, view.doc.defaultView);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -172,14 +169,11 @@ function testIncrement( aEditor, aOptions )
|
|||
key = ( aOptions.pageDown ) ? "VK_PAGE_DOWN" : ( aOptions.pageUp ) ? "VK_PAGE_UP" : key;
|
||||
EventUtils.synthesizeKey(key,
|
||||
{altKey: aOptions.alt, shiftKey: aOptions.shift},
|
||||
ruleDialog);
|
||||
view.doc.defaultView);
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
ruleView.clear();
|
||||
ruleDialog.close();
|
||||
ruleDialog = ruleView = null;
|
||||
doc = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
|
|
|
@ -62,7 +62,7 @@ function openRuleView()
|
|||
let node = content.document.getElementsByTagName("h1")[0];
|
||||
inspector.selection.setNode(node);
|
||||
|
||||
inspector.sidebar.once("ruleview-ready", testCompletion);
|
||||
inspector.once("inspector-updated", testCompletion);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ function openRuleView() {
|
|||
let node = content.document.getElementsByTagName("h1")[0];
|
||||
inspector.selection.setNode(node);
|
||||
|
||||
inspector.sidebar.once("ruleview-ready", testCompletion);
|
||||
inspector.once("inspector-updated", testCompletion);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ function openRuleView()
|
|||
let node = content.document.getElementsByTagName("h1")[0];
|
||||
inspector.selection.setNode(node);
|
||||
|
||||
inspector.sidebar.once("ruleview-ready", testCompletion);
|
||||
inspector.once("inspector-updated", testCompletion);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ function openRuleView() {
|
|||
let node = content.document.getElementsByTagName("h1")[0];
|
||||
inspector.selection.setNode(node);
|
||||
|
||||
inspector.sidebar.once("ruleview-ready", testCompletion);
|
||||
inspector.once("inspector-updated", testCompletion);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -62,42 +62,38 @@ function highlightNode()
|
|||
// Highlight a node.
|
||||
let div = content.document.getElementsByTagName("div")[0];
|
||||
|
||||
inspector.selection.once("new-node", function() {
|
||||
inspector.selection.setNode(div);
|
||||
inspector.once("inspector-updated", () => {
|
||||
is(inspector.selection.node, div, "selection matches the div element");
|
||||
testInlineStyle();
|
||||
});
|
||||
executeSoon(function() {
|
||||
inspector.selection.setNode(div);
|
||||
});
|
||||
}).then(null, console.error);
|
||||
}
|
||||
|
||||
function testInlineStyle()
|
||||
{
|
||||
executeSoon(function() {
|
||||
info("clicking an inline style");
|
||||
info("clicking an inline style");
|
||||
|
||||
Services.ww.registerNotification(function onWindow(aSubject, aTopic) {
|
||||
if (aTopic != "domwindowopened") {
|
||||
return;
|
||||
}
|
||||
Services.ww.registerNotification(function onWindow(aSubject, aTopic) {
|
||||
if (aTopic != "domwindowopened") {
|
||||
return;
|
||||
}
|
||||
|
||||
win = aSubject.QueryInterface(Ci.nsIDOMWindow);
|
||||
win.addEventListener("load", function windowLoad() {
|
||||
win.removeEventListener("load", windowLoad);
|
||||
let windowType = win.document.documentElement.getAttribute("windowtype");
|
||||
is(windowType, "navigator:view-source", "view source window is open");
|
||||
win.close();
|
||||
Services.ww.unregisterNotification(onWindow);
|
||||
executeSoon(() => {
|
||||
testInlineStyleSheet();
|
||||
});
|
||||
win = aSubject.QueryInterface(Ci.nsIDOMWindow);
|
||||
win.addEventListener("load", function windowLoad() {
|
||||
win.removeEventListener("load", windowLoad);
|
||||
let windowType = win.document.documentElement.getAttribute("windowtype");
|
||||
is(windowType, "navigator:view-source", "view source window is open");
|
||||
win.close();
|
||||
Services.ww.unregisterNotification(onWindow);
|
||||
executeSoon(() => {
|
||||
testInlineStyleSheet();
|
||||
});
|
||||
});
|
||||
|
||||
let link = getLinkByIndex(0);
|
||||
link.scrollIntoView();
|
||||
link.click();
|
||||
});
|
||||
|
||||
let link = getLinkByIndex(0);
|
||||
link.scrollIntoView();
|
||||
link.click();
|
||||
}
|
||||
|
||||
function testInlineStyleSheet()
|
||||
|
|
|
@ -45,13 +45,12 @@ function highlightNode()
|
|||
// Highlight a node.
|
||||
let div = content.document.getElementsByTagName("div")[0];
|
||||
|
||||
inspector.selection.once("new-node", function() {
|
||||
inspector.once("inspector-updated", function() {
|
||||
is(inspector.selection.node, div, "selection matches the div element");
|
||||
executeSoon(checkCopySelection);
|
||||
});
|
||||
executeSoon(function() {
|
||||
inspector.selection.setNode(div);
|
||||
});
|
||||
|
||||
inspector.selection.setNode(div);
|
||||
}
|
||||
|
||||
function checkCopySelection()
|
||||
|
|
|
@ -3,20 +3,9 @@
|
|||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let doc;
|
||||
let ruleDialog;
|
||||
let ruleWindow;
|
||||
let ruleView;
|
||||
|
||||
var gRuleViewChanged = false;
|
||||
function ruleViewChanged()
|
||||
{
|
||||
gRuleViewChanged = true;
|
||||
}
|
||||
|
||||
function expectChange()
|
||||
{
|
||||
ok(gRuleViewChanged, "Rule view should have fired a change event.");
|
||||
gRuleViewChanged = false;
|
||||
}
|
||||
let inspector;
|
||||
|
||||
function startTest()
|
||||
{
|
||||
|
@ -32,18 +21,13 @@ function startTest()
|
|||
doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
|
||||
let testElement = doc.getElementById("testid");
|
||||
|
||||
ruleDialog = openDialog("chrome://browser/content/devtools/cssruleview.xhtml",
|
||||
"cssruleviewtest",
|
||||
"width=200,height=350");
|
||||
ruleDialog.addEventListener("load", function onLoad(evt) {
|
||||
ruleDialog.removeEventListener("load", onLoad, true);
|
||||
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);
|
||||
openRuleView((aInspector, aRuleView) => {
|
||||
inspector = aInspector;
|
||||
ruleView = aRuleView;
|
||||
ruleWindow = aRuleView.doc.defaultView;
|
||||
inspector.selection.setNode(testElement);
|
||||
inspector.once("inspector-updated", testCancelNew);
|
||||
});
|
||||
}
|
||||
|
||||
function testCancelNew()
|
||||
|
@ -55,7 +39,7 @@ function testCancelNew()
|
|||
is(inplaceEditor(elementRuleEditor.newPropSpan), 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.");
|
||||
ok(!elementRuleEditor.rule._applyingModifications, "Shouldn't have an outstanding request 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();
|
||||
|
@ -64,7 +48,7 @@ function testCancelNew()
|
|||
});
|
||||
EventUtils.synthesizeMouse(elementRuleEditor.closeBrace, 1, 1,
|
||||
{ },
|
||||
ruleDialog);
|
||||
ruleWindow);
|
||||
}
|
||||
|
||||
function testCreateNew()
|
||||
|
@ -77,26 +61,28 @@ 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];
|
||||
is(aEditor, inplaceEditor(textProp.editor.valueSpan), "Should be editing the value span now.");
|
||||
aEditor.input.value = "#XYZ";
|
||||
waitForEditorBlur(aEditor, function() {
|
||||
expectChange();
|
||||
is(textProp.value, "#XYZ", "Text prop should have been changed.");
|
||||
is(textProp.editor._validate(), false, "#XYZ should not be a valid entry");
|
||||
testEditProperty();
|
||||
});
|
||||
aEditor.input.blur();
|
||||
promiseDone(expectRuleChange(elementRuleEditor.rule).then(() => {
|
||||
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];
|
||||
is(aEditor, inplaceEditor(textProp.editor.valueSpan), "Should be editing the value span now.");
|
||||
aEditor.input.value = "#XYZ";
|
||||
waitForEditorBlur(aEditor, function() {
|
||||
promiseDone(expectRuleChange(elementRuleEditor.rule).then(() => {
|
||||
is(textProp.value, "#XYZ", "Text prop should have been changed.");
|
||||
is(textProp.editor._validate(), false, "#XYZ should not be a valid entry");
|
||||
testEditProperty();
|
||||
}));
|
||||
});
|
||||
aEditor.input.blur();
|
||||
}));
|
||||
});
|
||||
EventUtils.synthesizeKey("VK_RETURN", {}, ruleDialog);
|
||||
EventUtils.synthesizeKey("VK_RETURN", {}, ruleWindow);
|
||||
});
|
||||
|
||||
EventUtils.synthesizeMouse(elementRuleEditor.closeBrace, 1, 1,
|
||||
{ },
|
||||
ruleDialog);
|
||||
ruleWindow);
|
||||
}
|
||||
|
||||
function testEditProperty()
|
||||
|
@ -107,38 +93,37 @@ function testEditProperty()
|
|||
is(inplaceEditor(propEditor.nameSpan), aEditor, "Next focused editor should be the name editor.");
|
||||
let input = aEditor.input;
|
||||
waitForEditorFocus(propEditor.element, function onNewName(aEditor) {
|
||||
expectChange();
|
||||
input = aEditor.input;
|
||||
is(inplaceEditor(propEditor.valueSpan), aEditor, "Focus should have moved to the value.");
|
||||
promiseDone(expectRuleChange(idRuleEditor.rule).then(() => {
|
||||
input = aEditor.input;
|
||||
is(inplaceEditor(propEditor.valueSpan), aEditor, "Focus should have moved to the value.");
|
||||
|
||||
waitForEditorBlur(aEditor, function() {
|
||||
expectChange();
|
||||
let value = idRuleEditor.rule.style.getPropertyValue("border-color");
|
||||
is(value, "red", "border-color should have been set.");
|
||||
is(propEditor._validate(), true, "red should be a valid entry");
|
||||
finishTest();
|
||||
});
|
||||
waitForEditorBlur(aEditor, function() {
|
||||
promiseDone(expectRuleChange(idRuleEditor.rule).then(() => {
|
||||
let value = idRuleEditor.rule.domRule._rawStyle().getPropertyValue("border-color");
|
||||
is(value, "red", "border-color should have been set.");
|
||||
is(propEditor._validate(), true, "red should be a valid entry");
|
||||
finishTest();
|
||||
}));
|
||||
});
|
||||
|
||||
for each (let ch in "red;") {
|
||||
EventUtils.sendChar(ch, ruleDialog);
|
||||
}
|
||||
for (let ch of "red;") {
|
||||
EventUtils.sendChar(ch, ruleWindow);
|
||||
}
|
||||
}));
|
||||
});
|
||||
for each (let ch in "border-color:") {
|
||||
EventUtils.sendChar(ch, ruleDialog);
|
||||
for (let ch of "border-color:") {
|
||||
EventUtils.sendChar(ch, ruleWindow);
|
||||
}
|
||||
});
|
||||
|
||||
EventUtils.synthesizeMouse(propEditor.nameSpan, 32, 1,
|
||||
{ },
|
||||
ruleDialog);
|
||||
ruleWindow);
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
ruleView.element.removeEventListener("CssRuleViewChanged", ruleViewChanged, false);
|
||||
ruleView.clear();
|
||||
ruleDialog.close();
|
||||
ruleDialog = ruleView = null;
|
||||
inspector = ruleWindow = ruleView = null;
|
||||
doc = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
|
|
|
@ -9,18 +9,12 @@ let doc;
|
|||
let inspector;
|
||||
let stylePanel;
|
||||
|
||||
function openRuleView()
|
||||
function selectNode(aInspector, aRuleView)
|
||||
{
|
||||
var target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
|
||||
inspector = toolbox.getCurrentPanel();
|
||||
inspector.sidebar.select("ruleview");
|
||||
|
||||
// Highlight a node.
|
||||
let node = content.document.getElementsByTagName("h1")[0];
|
||||
|
||||
inspector.sidebar.once("ruleview-ready", testFocus);
|
||||
});
|
||||
inspector = aInspector;
|
||||
let node = content.document.getElementsByTagName("h1")[0];
|
||||
inspector.selection.setNode(node);
|
||||
inspector.once("inspector-updated", testFocus);
|
||||
}
|
||||
|
||||
function testFocus()
|
||||
|
@ -64,7 +58,7 @@ function test()
|
|||
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
|
||||
doc = content.document;
|
||||
doc.title = "Rule View Test";
|
||||
waitForFocus(openRuleView, content);
|
||||
waitForFocus(() => openRuleView(selectNode), content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,<h1>Some header text</h1>";
|
||||
|
|
|
@ -4,8 +4,16 @@
|
|||
|
||||
let doc;
|
||||
|
||||
function simpleInherit()
|
||||
let inspector;
|
||||
let view;
|
||||
|
||||
let {ELEMENT_STYLE} = devtools.require("devtools/server/actors/styles");
|
||||
|
||||
function simpleInherit(aInspector, aRuleView)
|
||||
{
|
||||
inspector = aInspector;
|
||||
view = aRuleView;
|
||||
|
||||
let style = '' +
|
||||
'#test2 {' +
|
||||
' background-color: green;' +
|
||||
|
@ -15,23 +23,26 @@ function simpleInherit()
|
|||
let styleNode = addStyle(doc, style);
|
||||
doc.body.innerHTML = '<div id="test2"><div id="test1">Styled Node</div></div>';
|
||||
|
||||
let elementStyle = new _ElementStyle(doc.getElementById("test1"));
|
||||
inspector.selection.setNode(doc.getElementById("test1"));
|
||||
inspector.once("inspector-updated", () => {
|
||||
let elementStyle = view._elementStyle;
|
||||
|
||||
is(elementStyle.rules.length, 2, "Should have 2 rules.");
|
||||
is(elementStyle.rules.length, 2, "Should have 2 rules.");
|
||||
|
||||
let elementRule = elementStyle.rules[0];
|
||||
ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
|
||||
let elementRule = elementStyle.rules[0];
|
||||
ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
|
||||
|
||||
let inheritRule = elementStyle.rules[1];
|
||||
is(inheritRule.selectorText, "#test2", "Inherited rule should be the one that includes inheritable properties.");
|
||||
ok(!!inheritRule.inherited, "Rule should consider itself inherited.");
|
||||
is(inheritRule.textProps.length, 1, "Should only display one inherited style");
|
||||
let inheritProp = inheritRule.textProps[0];
|
||||
is(inheritProp.name, "color", "color should have been inherited.");
|
||||
let inheritRule = elementStyle.rules[1];
|
||||
is(inheritRule.selectorText, "#test2", "Inherited rule should be the one that includes inheritable properties.");
|
||||
ok(!!inheritRule.inherited, "Rule should consider itself inherited.");
|
||||
is(inheritRule.textProps.length, 1, "Should only display one inherited style");
|
||||
let inheritProp = inheritRule.textProps[0];
|
||||
is(inheritProp.name, "color", "color should have been inherited.");
|
||||
|
||||
styleNode.parentNode.removeChild(styleNode);
|
||||
styleNode.parentNode.removeChild(styleNode);
|
||||
|
||||
emptyInherit();
|
||||
emptyInherit();
|
||||
}).then(null, console.error);
|
||||
}
|
||||
|
||||
function emptyInherit()
|
||||
|
@ -45,37 +56,43 @@ function emptyInherit()
|
|||
let styleNode = addStyle(doc, style);
|
||||
doc.body.innerHTML = '<div id="test2"><div id="test1">Styled Node</div></div>';
|
||||
|
||||
let elementStyle = new _ElementStyle(doc.getElementById("test1"));
|
||||
inspector.selection.setNode(doc.getElementById("test1"));
|
||||
inspector.once("inspector-updated", () => {
|
||||
let elementStyle = view._elementStyle;
|
||||
|
||||
is(elementStyle.rules.length, 1, "Should have 1 rule.");
|
||||
is(elementStyle.rules.length, 1, "Should have 1 rule.");
|
||||
|
||||
let elementRule = elementStyle.rules[0];
|
||||
ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
|
||||
let elementRule = elementStyle.rules[0];
|
||||
ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
|
||||
|
||||
styleNode.parentNode.removeChild(styleNode);
|
||||
styleNode.parentNode.removeChild(styleNode);
|
||||
|
||||
elementStyleInherit();
|
||||
elementStyleInherit();
|
||||
}).then(null, console.error);
|
||||
}
|
||||
|
||||
function elementStyleInherit()
|
||||
{
|
||||
doc.body.innerHTML = '<div id="test2" style="color: red"><div id="test1">Styled Node</div></div>';
|
||||
|
||||
let elementStyle = new _ElementStyle(doc.getElementById("test1"));
|
||||
inspector.selection.setNode(doc.getElementById("test1"));
|
||||
inspector.once("inspector-updated", () => {
|
||||
let elementStyle = view._elementStyle;
|
||||
|
||||
is(elementStyle.rules.length, 2, "Should have 2 rules.");
|
||||
is(elementStyle.rules.length, 2, "Should have 2 rules.");
|
||||
|
||||
let elementRule = elementStyle.rules[0];
|
||||
ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
|
||||
let elementRule = elementStyle.rules[0];
|
||||
ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
|
||||
|
||||
let inheritRule = elementStyle.rules[1];
|
||||
ok(!inheritRule.domRule, "Inherited rule should be an element style, not a rule.");
|
||||
ok(!!inheritRule.inherited, "Rule should consider itself inherited.");
|
||||
is(inheritRule.textProps.length, 1, "Should only display one inherited style");
|
||||
let inheritProp = inheritRule.textProps[0];
|
||||
is(inheritProp.name, "color", "color should have been inherited.");
|
||||
let inheritRule = elementStyle.rules[1];
|
||||
is(inheritRule.domRule.type, ELEMENT_STYLE, "Inherited rule should be an element style, not a rule.");
|
||||
ok(!!inheritRule.inherited, "Rule should consider itself inherited.");
|
||||
is(inheritRule.textProps.length, 1, "Should only display one inherited style");
|
||||
let inheritProp = inheritRule.textProps[0];
|
||||
is(inheritProp.name, "color", "color should have been inherited.");
|
||||
|
||||
finishTest();
|
||||
finishTest();
|
||||
}).then(null, console.error);
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
|
@ -92,7 +109,7 @@ function test()
|
|||
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
|
||||
doc = content.document;
|
||||
waitForFocus(simpleInherit, content);
|
||||
waitForFocus(() => openRuleView(simpleInherit), content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,basic style inspector tests";
|
||||
|
|
|
@ -4,47 +4,68 @@
|
|||
|
||||
let doc;
|
||||
|
||||
function simpleOverride()
|
||||
|
||||
|
||||
function simpleOverride(aInspector, aRuleView)
|
||||
{
|
||||
doc.body.innerHTML = '<div id="testid">Styled Node</div>';
|
||||
let element = doc.getElementById("testid");
|
||||
let elementStyle = new _ElementStyle(element);
|
||||
|
||||
let elementRule = elementStyle.rules[0];
|
||||
let firstProp = elementRule.createProperty("background-color", "green", "");
|
||||
let secondProp = elementRule.createProperty("background-color", "blue", "");
|
||||
is(elementRule.textProps[0], firstProp, "Rules should be in addition order.");
|
||||
is(elementRule.textProps[1], secondProp, "Rules should be in addition order.");
|
||||
aInspector.selection.setNode(element);
|
||||
aInspector.once("inspector-updated", () => {
|
||||
let elementStyle = aRuleView._elementStyle;
|
||||
|
||||
is(element.style.getPropertyValue("background-color"), "blue", "Second property should have been used.");
|
||||
let elementRule = elementStyle.rules[0];
|
||||
let firstProp = elementRule.createProperty("background-color", "green", "");
|
||||
let secondProp = elementRule.createProperty("background-color", "blue", "");
|
||||
is(elementRule.textProps[0], firstProp, "Rules should be in addition order.");
|
||||
is(elementRule.textProps[1], secondProp, "Rules should be in addition order.");
|
||||
|
||||
secondProp.remove();
|
||||
is(element.style.getPropertyValue("background-color"), "green", "After deleting second property, first should be used.");
|
||||
promiseDone(elementRule._applyingModifications.then(() => {
|
||||
is(element.style.getPropertyValue("background-color"), "blue", "Second property should have been used.");
|
||||
|
||||
secondProp = elementRule.createProperty("background-color", "blue", "");
|
||||
is(element.style.getPropertyValue("background-color"), "blue", "New property should be used.");
|
||||
secondProp.remove();
|
||||
return elementRule._applyingModifications;
|
||||
}).then(() => {
|
||||
is(element.style.getPropertyValue("background-color"), "green", "After deleting second property, first should be used.");
|
||||
|
||||
is(elementRule.textProps[0], firstProp, "Rules shouldn't have switched places.");
|
||||
is(elementRule.textProps[1], secondProp, "Rules shouldn't have switched places.");
|
||||
secondProp = elementRule.createProperty("background-color", "blue", "");
|
||||
return elementRule._applyingModifications;
|
||||
}).then(() => {
|
||||
is(element.style.getPropertyValue("background-color"), "blue", "New property should be used.");
|
||||
|
||||
secondProp.setEnabled(false);
|
||||
is(element.style.getPropertyValue("background-color"), "green", "After disabling second property, first value should be used");
|
||||
is(elementRule.textProps[0], firstProp, "Rules shouldn't have switched places.");
|
||||
is(elementRule.textProps[1], secondProp, "Rules shouldn't have switched places.");
|
||||
|
||||
firstProp.setEnabled(false);
|
||||
is(element.style.getPropertyValue("background-color"), "", "After disabling both properties, value should be empty.");
|
||||
secondProp.setEnabled(false);
|
||||
return elementRule._applyingModifications;
|
||||
}).then(() => {
|
||||
is(element.style.getPropertyValue("background-color"), "green", "After disabling second property, first value should be used");
|
||||
|
||||
secondProp.setEnabled(true);
|
||||
is(element.style.getPropertyValue("background-color"), "blue", "Value should be set correctly after re-enabling");
|
||||
firstProp.setEnabled(false);
|
||||
return elementRule._applyingModifications;
|
||||
}).then(() => {
|
||||
is(element.style.getPropertyValue("background-color"), "", "After disabling both properties, value should be empty.");
|
||||
|
||||
firstProp.setEnabled(true);
|
||||
is(element.style.getPropertyValue("background-color"), "blue", "Re-enabling an earlier property shouldn't make it override a later property.");
|
||||
is(elementRule.textProps[0], firstProp, "Rules shouldn't have switched places.");
|
||||
is(elementRule.textProps[1], secondProp, "Rules shouldn't have switched places.");
|
||||
secondProp.setEnabled(true);
|
||||
return elementRule._applyingModifications;
|
||||
}).then(() => {
|
||||
is(element.style.getPropertyValue("background-color"), "blue", "Value should be set correctly after re-enabling");
|
||||
|
||||
firstProp.setValue("purple", "");
|
||||
is(element.style.getPropertyValue("background-color"), "blue", "Modifying an earlier property shouldn't override a later property.");
|
||||
firstProp.setEnabled(true);
|
||||
return elementRule._applyingModifications;
|
||||
}).then(() => {
|
||||
is(element.style.getPropertyValue("background-color"), "blue", "Re-enabling an earlier property shouldn't make it override a later property.");
|
||||
is(elementRule.textProps[0], firstProp, "Rules shouldn't have switched places.");
|
||||
is(elementRule.textProps[1], secondProp, "Rules shouldn't have switched places.");
|
||||
|
||||
finishTest();
|
||||
firstProp.setValue("purple", "");
|
||||
return elementRule._applyingModifications;
|
||||
}).then(() => {
|
||||
is(element.style.getPropertyValue("background-color"), "blue", "Modifying an earlier property shouldn't override a later property.");
|
||||
finishTest();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
|
@ -61,7 +82,7 @@ function test()
|
|||
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
|
||||
doc = content.document;
|
||||
waitForFocus(simpleOverride, content);
|
||||
waitForFocus(() => openRuleView(simpleOverride), content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,basic style inspector tests";
|
||||
|
|
|
@ -3,9 +3,13 @@
|
|||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let doc;
|
||||
let inspector;
|
||||
let view;
|
||||
|
||||
function simpleOverride()
|
||||
function simpleOverride(aInspector, aRuleView)
|
||||
{
|
||||
inspector = aInspector;
|
||||
view = aRuleView;
|
||||
let style = '' +
|
||||
'#testid {' +
|
||||
' background-color: blue;' +
|
||||
|
@ -17,31 +21,34 @@ function simpleOverride()
|
|||
let styleNode = addStyle(doc, style);
|
||||
doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
|
||||
|
||||
let elementStyle = new _ElementStyle(doc.getElementById("testid"));
|
||||
inspector.selection.setNode(doc.getElementById("testid"));
|
||||
inspector.once("inspector-updated", () => {
|
||||
let elementStyle = view._elementStyle;
|
||||
|
||||
let idRule = elementStyle.rules[1];
|
||||
let idProp = idRule.textProps[0];
|
||||
is(idProp.name, "background-color", "First ID prop should be background-color");
|
||||
ok(!idProp.overridden, "ID prop should not be overridden.");
|
||||
let idRule = elementStyle.rules[1];
|
||||
let idProp = idRule.textProps[0];
|
||||
is(idProp.name, "background-color", "First ID prop should be background-color");
|
||||
ok(!idProp.overridden, "ID prop should not be overridden.");
|
||||
|
||||
let classRule = elementStyle.rules[2];
|
||||
let classProp = classRule.textProps[0];
|
||||
is(classProp.name, "background-color", "First class prop should be background-color");
|
||||
ok(classProp.overridden, "Class property should be overridden.");
|
||||
let classRule = elementStyle.rules[2];
|
||||
let classProp = classRule.textProps[0];
|
||||
is(classProp.name, "background-color", "First class prop should be background-color");
|
||||
ok(classProp.overridden, "Class property should be overridden.");
|
||||
|
||||
// Override background-color by changing the element style.
|
||||
let elementRule = elementStyle.rules[0];
|
||||
elementRule.createProperty("background-color", "purple", "");
|
||||
let elementProp = elementRule.textProps[0];
|
||||
is(classProp.name, "background-color", "First element prop should now be background-color");
|
||||
// Override background-color by changing the element style.
|
||||
let elementRule = elementStyle.rules[0];
|
||||
elementRule.createProperty("background-color", "purple", "");
|
||||
promiseDone(elementRule._applyingModifications.then(() => {
|
||||
let elementProp = elementRule.textProps[0];
|
||||
is(classProp.name, "background-color", "First element prop should now be background-color");
|
||||
ok(!elementProp.overridden, "Element style property should not be overridden");
|
||||
ok(idProp.overridden, "ID property should be overridden");
|
||||
ok(classProp.overridden, "Class property should be overridden");
|
||||
|
||||
ok(!elementProp.overridden, "Element style property should not be overridden");
|
||||
ok(idProp.overridden, "ID property should be overridden");
|
||||
ok(classProp.overridden, "Class property should be overridden");
|
||||
|
||||
styleNode.parentNode.removeChild(styleNode);
|
||||
|
||||
partialOverride();
|
||||
styleNode.parentNode.removeChild(styleNode);
|
||||
partialOverride();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function partialOverride()
|
||||
|
@ -59,22 +66,25 @@ function partialOverride()
|
|||
let styleNode = addStyle(doc, style);
|
||||
doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
|
||||
|
||||
let elementStyle = new _ElementStyle(doc.getElementById("testid"));
|
||||
inspector.selection.setNode(doc.getElementById("testid"));
|
||||
inspector.once("inspector-updated", () => {
|
||||
let elementStyle = view._elementStyle;
|
||||
|
||||
let classRule = elementStyle.rules[2];
|
||||
let classProp = classRule.textProps[0];
|
||||
ok(!classProp.overridden, "Class prop shouldn't be overridden, some props are still being used.");
|
||||
for each (let computed in classProp.computed) {
|
||||
if (computed.name.indexOf("margin-left") == 0) {
|
||||
ok(computed.overridden, "margin-left props should be overridden.");
|
||||
} else {
|
||||
ok(!computed.overridden, "Non-margin-left props should not be overridden.");
|
||||
let classRule = elementStyle.rules[2];
|
||||
let classProp = classRule.textProps[0];
|
||||
ok(!classProp.overridden, "Class prop shouldn't be overridden, some props are still being used.");
|
||||
for (let computed of classProp.computed) {
|
||||
if (computed.name.indexOf("margin-left") == 0) {
|
||||
ok(computed.overridden, "margin-left props should be overridden.");
|
||||
} else {
|
||||
ok(!computed.overridden, "Non-margin-left props should not be overridden.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
styleNode.parentNode.removeChild(styleNode);
|
||||
styleNode.parentNode.removeChild(styleNode);
|
||||
|
||||
importantOverride();
|
||||
importantOverride();
|
||||
});
|
||||
}
|
||||
|
||||
function importantOverride()
|
||||
|
@ -91,24 +101,29 @@ function importantOverride()
|
|||
let styleNode = addStyle(doc, style);
|
||||
doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
|
||||
|
||||
let elementStyle = new _ElementStyle(doc.getElementById("testid"));
|
||||
inspector.selection.setNode(doc.getElementById("testid"));
|
||||
inspector.once("inspector-updated", () => {
|
||||
let elementStyle = view._elementStyle;
|
||||
|
||||
let idRule = elementStyle.rules[1];
|
||||
let idProp = idRule.textProps[0];
|
||||
ok(idProp.overridden, "Not-important rule should be overridden.");
|
||||
let idRule = elementStyle.rules[1];
|
||||
let idProp = idRule.textProps[0];
|
||||
ok(idProp.overridden, "Not-important rule should be overridden.");
|
||||
|
||||
let classRule = elementStyle.rules[2];
|
||||
let classProp = classRule.textProps[0];
|
||||
ok(!classProp.overridden, "Important rule should not be overridden.");
|
||||
let classRule = elementStyle.rules[2];
|
||||
let classProp = classRule.textProps[0];
|
||||
ok(!classProp.overridden, "Important rule should not be overridden.");
|
||||
|
||||
styleNode.parentNode.removeChild(styleNode);
|
||||
styleNode.parentNode.removeChild(styleNode);
|
||||
|
||||
let elementRule = elementStyle.rules[0];
|
||||
let elementProp = elementRule.createProperty("background-color", "purple", "important");
|
||||
ok(classProp.overridden, "New important prop should override class property.");
|
||||
ok(!elementProp.overridden, "New important prop should not be overriden.");
|
||||
let elementRule = elementStyle.rules[0];
|
||||
let elementProp = elementRule.createProperty("background-color", "purple", "important");
|
||||
promiseDone(elementRule._applyingModifications.then(() => {
|
||||
ok(classProp.overridden, "New important prop should override class property.");
|
||||
ok(!elementProp.overridden, "New important prop should not be overriden.");
|
||||
|
||||
disableOverride();
|
||||
disableOverride();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function disableOverride()
|
||||
|
@ -123,19 +138,23 @@ function disableOverride()
|
|||
let styleNode = addStyle(doc, style);
|
||||
doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
|
||||
|
||||
let elementStyle = new _ElementStyle(doc.getElementById("testid"));
|
||||
inspector.selection.setNode(doc.getElementById("testid"));
|
||||
inspector.once("inspector-updated", () => {
|
||||
let elementStyle = view._elementStyle;
|
||||
|
||||
let idRule = elementStyle.rules[1];
|
||||
let idProp = idRule.textProps[0];
|
||||
idProp.setEnabled(false);
|
||||
let idRule = elementStyle.rules[1];
|
||||
let idProp = idRule.textProps[0];
|
||||
idProp.setEnabled(false);
|
||||
promiseDone(idRule._applyingModifications.then(() => {
|
||||
let classRule = elementStyle.rules[2];
|
||||
let classProp = classRule.textProps[0];
|
||||
ok(!classProp.overridden, "Class prop should not be overridden after id prop was disabled.");
|
||||
|
||||
let classRule = elementStyle.rules[2];
|
||||
let classProp = classRule.textProps[0];
|
||||
ok(!classProp.overridden, "Class prop should not be overridden after id prop was disabled.");
|
||||
styleNode.parentNode.removeChild(styleNode);
|
||||
|
||||
styleNode.parentNode.removeChild(styleNode);
|
||||
|
||||
finishTest();
|
||||
finishTest();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
|
@ -152,7 +171,7 @@ function test()
|
|||
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
|
||||
doc = content.document;
|
||||
waitForFocus(simpleOverride, content);
|
||||
waitForFocus(() => openRuleView(simpleOverride), content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,basic style inspector tests";
|
||||
|
|
|
@ -3,23 +3,15 @@
|
|||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let doc;
|
||||
let ruleDialog;
|
||||
let inspector;
|
||||
let ruleWindow;
|
||||
let ruleView;
|
||||
|
||||
var gRuleViewChanged = false;
|
||||
function ruleViewChanged()
|
||||
{
|
||||
gRuleViewChanged = true;
|
||||
}
|
||||
|
||||
function expectChange()
|
||||
{
|
||||
ok(gRuleViewChanged, "Rule view should have fired a change event.");
|
||||
gRuleViewChanged = false;
|
||||
}
|
||||
|
||||
function startTest()
|
||||
function startTest(aInspector, aRuleView)
|
||||
{
|
||||
inspector = aInspector;
|
||||
ruleWindow = aRuleView.doc.defaultView;
|
||||
ruleView = aRuleView;
|
||||
let style = '' +
|
||||
'#testid {' +
|
||||
' background-color: blue;' +
|
||||
|
@ -30,30 +22,24 @@ function startTest()
|
|||
|
||||
let styleNode = addStyle(doc, style);
|
||||
doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
|
||||
|
||||
let testElement = doc.getElementById("testid");
|
||||
|
||||
ruleDialog = openDialog("chrome://browser/content/devtools/cssruleview.xhtml",
|
||||
"cssruleviewtest",
|
||||
"width=200,height=350");
|
||||
ruleDialog.addEventListener("load", function onLoad(evt) {
|
||||
ruleDialog.removeEventListener("load", onLoad);
|
||||
let doc = ruleDialog.document;
|
||||
ruleView = new CssRuleView(doc);
|
||||
doc.documentElement.appendChild(ruleView.element);
|
||||
ruleView.element.addEventListener("CssRuleViewChanged", ruleViewChanged, false);
|
||||
is(ruleView.element.querySelectorAll("#noResults").length, 1, "Has a no-results element.");
|
||||
ruleView.highlight(testElement);
|
||||
inspector.selection.setNode(testElement);
|
||||
inspector.once("inspector-updated", () => {
|
||||
is(ruleView.element.querySelectorAll("#noResults").length, 0, "After a highlight, no longer has a no-results element.");
|
||||
ruleView.highlight(null);
|
||||
is(ruleView.element.querySelectorAll("#noResults").length, 1, "After highlighting null, has a no-results element again.");
|
||||
ruleView.highlight(testElement);
|
||||
inspector.selection.setNode(null);
|
||||
inspector.once("inspector-updated", () => {
|
||||
is(ruleView.element.querySelectorAll("#noResults").length, 1, "After highlighting null, has a no-results element again.");
|
||||
inspector.selection.setNode(testElement)
|
||||
inspector.once("inspector-updated", () => {
|
||||
let classEditor = ruleView.element.children[2]._ruleEditor;
|
||||
is(classEditor.selectorText.querySelector(".ruleview-selector-matched").textContent, ".testclass", ".textclass should be matched.");
|
||||
is(classEditor.selectorText.querySelector(".ruleview-selector-unmatched").textContent, ".unmatched", ".unmatched should not be matched.");
|
||||
|
||||
let classEditor = ruleView.element.children[2]._ruleEditor;
|
||||
is(classEditor.selectorText.querySelector(".ruleview-selector-matched").textContent, ".testclass", ".textclass should be matched.");
|
||||
is(classEditor.selectorText.querySelector(".ruleview-selector-unmatched").textContent, ".unmatched", ".unmatched should not be matched.");
|
||||
|
||||
waitForFocus(testCancelNew, ruleDialog);
|
||||
}, true);
|
||||
testCancelNew();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testCancelNew()
|
||||
|
@ -66,7 +52,7 @@ function testCancelNew()
|
|||
is(inplaceEditor(elementRuleEditor.newPropSpan), 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.");
|
||||
ok(!elementRuleEditor.rule._applyingModifications, "Shouldn't have an outstanding modification request 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();
|
||||
|
@ -76,7 +62,7 @@ function testCancelNew()
|
|||
|
||||
EventUtils.synthesizeMouse(elementRuleEditor.closeBrace, 1, 1,
|
||||
{ },
|
||||
ruleDialog);
|
||||
ruleWindow);
|
||||
}
|
||||
|
||||
function testCreateNew()
|
||||
|
@ -91,33 +77,35 @@ function testCreateNew()
|
|||
ok(input.selectionStart === 0 && input.selectionEnd === input.value.length, "Editor contents are selected.");
|
||||
|
||||
// Try clicking on the editor's input again, shouldn't cause trouble (see bug 761665).
|
||||
EventUtils.synthesizeMouse(input, 1, 1, { }, ruleDialog);
|
||||
EventUtils.synthesizeMouse(input, 1, 1, { }, ruleWindow);
|
||||
input.select();
|
||||
|
||||
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];
|
||||
is(aEditor, inplaceEditor(textProp.editor.valueSpan), "Should be editing the value span now.");
|
||||
promiseDone(expectRuleChange(elementRuleEditor.rule).then(() => {
|
||||
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];
|
||||
is(aEditor, inplaceEditor(textProp.editor.valueSpan), "Should be editing the value span now.");
|
||||
|
||||
aEditor.input.value = "purple";
|
||||
waitForEditorBlur(aEditor, function() {
|
||||
expectChange();
|
||||
is(textProp.value, "purple", "Text prop should have been changed.");
|
||||
testEditProperty();
|
||||
});
|
||||
aEditor.input.value = "purple";
|
||||
waitForEditorBlur(aEditor, function() {
|
||||
expectRuleChange(elementRuleEditor.rule).then(() => {
|
||||
is(textProp.value, "purple", "Text prop should have been changed.");
|
||||
testEditProperty();
|
||||
});
|
||||
});
|
||||
|
||||
aEditor.input.blur();
|
||||
aEditor.input.blur();
|
||||
}));
|
||||
});
|
||||
EventUtils.sendKey("return", ruleDialog);
|
||||
EventUtils.sendKey("return", ruleWindow);
|
||||
});
|
||||
|
||||
EventUtils.synthesizeMouse(elementRuleEditor.closeBrace, 1, 1,
|
||||
{ },
|
||||
ruleDialog);
|
||||
ruleWindow);
|
||||
}
|
||||
|
||||
function testEditProperty()
|
||||
|
@ -133,48 +121,50 @@ function testEditProperty()
|
|||
ok(input.selectionStart === 0 && input.selectionEnd === input.value.length, "Editor contents are selected.");
|
||||
|
||||
// Try clicking on the editor's input again, shouldn't cause trouble (see bug 761665).
|
||||
EventUtils.synthesizeMouse(input, 1, 1, { }, ruleDialog);
|
||||
EventUtils.synthesizeMouse(input, 1, 1, { }, ruleWindow);
|
||||
input.select();
|
||||
|
||||
waitForEditorFocus(propEditor.element, function onNewName(aEditor) {
|
||||
expectChange();
|
||||
is(inplaceEditor(propEditor.valueSpan), aEditor, "Focus should have moved to the value.");
|
||||
promiseDone(expectRuleChange(idRuleEditor.rule).then(() => {
|
||||
is(inplaceEditor(propEditor.valueSpan), aEditor, "Focus should have moved to the value.");
|
||||
|
||||
input = aEditor.input;
|
||||
input = aEditor.input;
|
||||
|
||||
ok(input.selectionStart === 0 && input.selectionEnd === input.value.length, "Editor contents are selected.");
|
||||
ok(input.selectionStart === 0 && input.selectionEnd === input.value.length, "Editor contents are selected.");
|
||||
|
||||
// Try clicking on the editor's input again, shouldn't cause trouble (see bug 761665).
|
||||
EventUtils.synthesizeMouse(input, 1, 1, { }, ruleDialog);
|
||||
input.select();
|
||||
// Try clicking on the editor's input again, shouldn't cause trouble (see bug 761665).
|
||||
EventUtils.synthesizeMouse(input, 1, 1, { }, ruleWindow);
|
||||
input.select();
|
||||
|
||||
waitForEditorBlur(aEditor, function() {
|
||||
expectChange();
|
||||
is(idRuleEditor.rule.style.getPropertyValue("border-color"), "red",
|
||||
"border-color should have been set.");
|
||||
waitForEditorBlur(aEditor, function() {
|
||||
promiseDone(expectRuleChange(idRuleEditor.rule).then(() => {;
|
||||
is(idRuleEditor.rule.style._rawStyle().getPropertyValue("border-color"), "red",
|
||||
"border-color should have been set.");
|
||||
|
||||
let props = ruleView.element.querySelectorAll(".ruleview-property");
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
is(props[i].hasAttribute("dirty"), i <= 1,
|
||||
"props[" + i + "] marked dirty as appropriate");
|
||||
let props = ruleView.element.querySelectorAll(".ruleview-property");
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
is(props[i].hasAttribute("dirty"), i <= 1,
|
||||
"props[" + i + "] marked dirty as appropriate");
|
||||
}
|
||||
testDisableProperty();
|
||||
}));
|
||||
});
|
||||
|
||||
for (let ch of "red;") {
|
||||
EventUtils.sendChar(ch, ruleWindow);
|
||||
is(propEditor.warning.hidden, ch == "d" || ch == ";",
|
||||
"warning triangle is hidden or shown as appropriate");
|
||||
}
|
||||
testDisableProperty();
|
||||
});
|
||||
|
||||
for each (let ch in "red;") {
|
||||
EventUtils.sendChar(ch, ruleDialog);
|
||||
is(propEditor.warning.hidden, ch == "d" || ch == ";",
|
||||
"warning triangle is hidden or shown as appropriate");
|
||||
}
|
||||
}));
|
||||
});
|
||||
for each (let ch in "border-color:") {
|
||||
EventUtils.sendChar(ch, ruleDialog);
|
||||
for (let ch of "border-color:") {
|
||||
EventUtils.sendChar(ch, ruleWindow);
|
||||
}
|
||||
});
|
||||
|
||||
EventUtils.synthesizeMouse(propEditor.nameSpan, 32, 1,
|
||||
{ },
|
||||
ruleDialog);
|
||||
ruleWindow);
|
||||
}
|
||||
|
||||
function testDisableProperty()
|
||||
|
@ -183,22 +173,22 @@ function testDisableProperty()
|
|||
let propEditor = idRuleEditor.rule.textProps[0].editor;
|
||||
|
||||
propEditor.enable.click();
|
||||
is(idRuleEditor.rule.style.getPropertyValue("border-color"), "", "Border-color should have been unset.");
|
||||
expectChange();
|
||||
promiseDone(expectRuleChange(idRuleEditor.rule).then(() => {
|
||||
is(idRuleEditor.rule.style._rawStyle().getPropertyValue("border-color"), "", "Border-color should have been unset.");
|
||||
|
||||
propEditor.enable.click();
|
||||
is(idRuleEditor.rule.style.getPropertyValue("border-color"), "red",
|
||||
"Border-color should have been reset.");
|
||||
expectChange();
|
||||
propEditor.enable.click();
|
||||
return expectRuleChange(idRuleEditor.rule);
|
||||
}).then(() => {
|
||||
is(idRuleEditor.rule.style._rawStyle().getPropertyValue("border-color"), "red",
|
||||
"Border-color should have been reset.");
|
||||
|
||||
finishTest();
|
||||
finishTest();
|
||||
}));
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
ruleView.clear();
|
||||
ruleDialog.close();
|
||||
ruleDialog = ruleView = null;
|
||||
inspector = ruleWindow = ruleView = null;
|
||||
doc = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
|
@ -211,7 +201,7 @@ function test()
|
|||
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
|
||||
doc = content.document;
|
||||
waitForFocus(startTest, content);
|
||||
waitForFocus(() => openRuleView(startTest), content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,basic style inspector tests";
|
||||
|
|
|
@ -3,12 +3,15 @@
|
|||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let doc;
|
||||
let ruleDialog;
|
||||
|
||||
let inspector;
|
||||
let ruleView;
|
||||
let testElement;
|
||||
|
||||
function startTest()
|
||||
function startTest(aInspector, aRuleView)
|
||||
{
|
||||
inspector = aInspector;
|
||||
ruleView = aRuleView;
|
||||
let style = '' +
|
||||
'#testid {' +
|
||||
' background-color: blue;' +
|
||||
|
@ -19,21 +22,15 @@ function startTest()
|
|||
|
||||
let styleNode = addStyle(doc, style);
|
||||
doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
|
||||
|
||||
testElement = doc.getElementById("testid");
|
||||
|
||||
let elementStyle = 'margin-top: 1px; padding-top: 5px;'
|
||||
testElement.setAttribute("style", elementStyle);
|
||||
|
||||
ruleDialog = openDialog("chrome://browser/content/devtools/cssruleview.xhtml",
|
||||
"cssruleviewtest",
|
||||
"width=200,height=350");
|
||||
ruleDialog.addEventListener("load", function onLoad(evt) {
|
||||
ruleDialog.removeEventListener("load", onLoad);
|
||||
let doc = ruleDialog.document;
|
||||
ruleView = new CssRuleView(doc);
|
||||
doc.documentElement.appendChild(ruleView.element);
|
||||
ruleView.highlight(testElement);
|
||||
waitForFocus(testRuleChanges, ruleDialog);
|
||||
inspector.selection.setNode(testElement);
|
||||
inspector.once("inspector-updated", () => {
|
||||
testRuleChanges();
|
||||
}, true);
|
||||
}
|
||||
|
||||
|
@ -47,24 +44,24 @@ function testRuleChanges()
|
|||
|
||||
// Change the id and refresh.
|
||||
testElement.setAttribute("id", "differentid");
|
||||
ruleView.nodeChanged();
|
||||
promiseDone(ruleView.nodeChanged().then(() => {
|
||||
let selectors = ruleView.doc.querySelectorAll(".ruleview-selector");
|
||||
is(selectors.length, 2, "Two rules visible.");
|
||||
is(selectors[0].textContent.indexOf("element"), 0, "First item is inline style.");
|
||||
is(selectors[1].textContent.indexOf(".testclass"), 0, "Second item is class rule.");
|
||||
|
||||
let selectors = ruleView.doc.querySelectorAll(".ruleview-selector");
|
||||
is(selectors.length, 2, "Three rules visible.");
|
||||
is(selectors[0].textContent.indexOf("element"), 0, "First item is inline style.");
|
||||
is(selectors[1].textContent.indexOf(".testclass"), 0, "Second item is class rule.");
|
||||
testElement.setAttribute("id", "testid");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
// Put the id back.
|
||||
let selectors = ruleView.doc.querySelectorAll(".ruleview-selector");
|
||||
is(selectors.length, 3, "Three rules visible.");
|
||||
is(selectors[0].textContent.indexOf("element"), 0, "First item is inline style.");
|
||||
is(selectors[1].textContent.indexOf("#testid"), 0, "Second item is id rule.");
|
||||
is(selectors[2].textContent.indexOf(".testclass"), 0, "Third item is class rule.");
|
||||
|
||||
testElement.setAttribute("id", "testid");
|
||||
ruleView.nodeChanged();
|
||||
|
||||
// Put the id back.
|
||||
let selectors = ruleView.doc.querySelectorAll(".ruleview-selector");
|
||||
is(selectors.length, 3, "Three rules visible.");
|
||||
is(selectors[0].textContent.indexOf("element"), 0, "First item is inline style.");
|
||||
is(selectors[1].textContent.indexOf("#testid"), 0, "Second item is id rule.");
|
||||
is(selectors[2].textContent.indexOf(".testclass"), 0, "Third item is class rule.");
|
||||
|
||||
testPropertyChanges();
|
||||
testPropertyChanges();
|
||||
}));
|
||||
}
|
||||
|
||||
function validateTextProp(aProp, aEnabled, aName, aValue, aDesc)
|
||||
|
@ -81,59 +78,64 @@ function validateTextProp(aProp, aEnabled, aName, aValue, aDesc)
|
|||
function testPropertyChanges()
|
||||
{
|
||||
// Add a second margin-top value, just to make things interesting.
|
||||
let rule = ruleView._elementStyle.rules[0];
|
||||
let ruleEditor = ruleView._elementStyle.rules[0].editor;
|
||||
ruleEditor.addProperty("margin-top", "5px", "");
|
||||
promiseDone(expectRuleChange(rule).then(() => {
|
||||
// Set the element style back to a 1px margin-top.
|
||||
testElement.setAttribute("style", "margin-top: 1px; padding-top: 5px");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], true, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], false, "margin-top", "5px", "Second margin property disabled");
|
||||
|
||||
let rule = ruleView._elementStyle.rules[0];
|
||||
// Now set it back to 5px, the 5px value should be re-enabled.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 5px;");
|
||||
return ruleView.nodeChanged();
|
||||
|
||||
// Set the element style back to a 1px margin-top.
|
||||
testElement.setAttribute("style", "margin-top: 1px; padding-top: 5px");
|
||||
ruleView.nodeChanged();
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], true, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], false, "margin-top", "5px", "Second margin property disabled");
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], false, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], true, "margin-top", "5px", "Second margin property disabled");
|
||||
|
||||
// Now set it back to 5px, the 5px value should be re-enabled.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 5px;");
|
||||
ruleView.nodeChanged();
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], false, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], true, "margin-top", "5px", "Second margin property disabled");
|
||||
// Set the margin property to a value that doesn't exist in the editor.
|
||||
// Should reuse the currently-enabled element (the second one.)
|
||||
testElement.setAttribute("style", "margin-top: 15px; padding-top: 5px;");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], false, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], true, "margin-top", "15px", "Second margin property disabled");
|
||||
|
||||
// Set the margin property to a value that doesn't exist in the editor.
|
||||
// Should reuse the currently-enabled element (the second one.)
|
||||
testElement.setAttribute("style", "margin-top: 15px; padding-top: 5px;");
|
||||
ruleView.nodeChanged();
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[0], false, "margin-top", "1px", "First margin property re-enabled");
|
||||
validateTextProp(rule.textProps[2], true, "margin-top", "15px", "Second margin property disabled");
|
||||
// Remove the padding-top attribute. Should disable the padding property but not remove it.
|
||||
testElement.setAttribute("style", "margin-top: 5px;");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[1], false, "padding-top", "5px", "Padding property disabled");
|
||||
|
||||
// Remove the padding-top attribute. Should disable the padding property but not remove it.
|
||||
testElement.setAttribute("style", "margin-top: 5px;");
|
||||
ruleView.nodeChanged();
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[1], false, "padding-top", "5px", "Padding property disabled");
|
||||
// Put the padding-top attribute back in, should re-enable the padding property.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 25px");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[1], true, "padding-top", "25px", "Padding property enabled");
|
||||
|
||||
// Put the padding-top attribute back in, should re-enable the padding property.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 25px");
|
||||
ruleView.nodeChanged();
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 3, "Correct number of properties");
|
||||
validateTextProp(rule.textProps[1], true, "padding-top", "25px", "Padding property enabled");
|
||||
// Add an entirely new property.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 25px; padding-left: 20px;");
|
||||
return ruleView.nodeChanged();
|
||||
}).then(() => {
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 4, "Added a property");
|
||||
validateTextProp(rule.textProps[3], true, "padding-left", "20px", "Padding property enabled");
|
||||
|
||||
// Add an entirely new property.
|
||||
testElement.setAttribute("style", "margin-top: 5px; padding-top: 25px; padding-left: 20px;");
|
||||
ruleView.nodeChanged();
|
||||
is(rule.editor.element.querySelectorAll(".ruleview-property").length, 4, "Added a property");
|
||||
validateTextProp(rule.textProps[3], true, "padding-left", "20px", "Padding property enabled");
|
||||
|
||||
finishTest();
|
||||
finishTest();
|
||||
}));
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
ruleView.clear();
|
||||
ruleDialog.close();
|
||||
ruleDialog = ruleView = null;
|
||||
inspector = ruleView = null;
|
||||
doc = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
|
@ -146,7 +148,7 @@ function test()
|
|||
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
|
||||
doc = content.document;
|
||||
waitForFocus(startTest, content);
|
||||
waitForFocus(() => openRuleView(startTest), content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,basic style inspector tests";
|
||||
|
|
|
@ -15,22 +15,11 @@ const TEST_URI = BASE_URL +
|
|||
const TEST_IMAGE = BASE_URL + "test-image.png";
|
||||
const BASE_64_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
|
||||
|
||||
function createDocument()
|
||||
{
|
||||
doc.title = "Style Inspector URL Clickable test";
|
||||
|
||||
openInspector(function(aInspector) {
|
||||
inspector = aInspector;
|
||||
executeSoon(selectNode);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function selectNode(aInspector)
|
||||
function selectNode(aInspector, aRuleView)
|
||||
{
|
||||
inspector = aInspector;
|
||||
let sidebar = inspector.sidebar;
|
||||
let iframe = sidebar._tabbox.querySelector(".iframe-ruleview");
|
||||
let contentDoc = iframe.contentWindow.document;
|
||||
let contentDoc = aRuleView.doc;
|
||||
|
||||
let relative = doc.querySelector(".relative");
|
||||
let absolute = doc.querySelector(".absolute");
|
||||
|
@ -45,35 +34,44 @@ function selectNode(aInspector)
|
|||
ok(noimage, "captain, we have the noimage div");
|
||||
|
||||
inspector.selection.setNode(relative);
|
||||
is(inspector.selection.node, relative, "selection matches the relative element");
|
||||
let relativeLink = contentDoc.querySelector(".ruleview-propertycontainer a");
|
||||
ok (relativeLink, "Link exists for relative node");
|
||||
ok (relativeLink.getAttribute("href"), TEST_IMAGE);
|
||||
inspector.once("inspector-updated", () => {
|
||||
is(inspector.selection.node, relative, "selection matches the relative element");
|
||||
let relativeLink = contentDoc.querySelector(".ruleview-propertycontainer a");
|
||||
ok (relativeLink, "Link exists for relative node");
|
||||
ok (relativeLink.getAttribute("href"), TEST_IMAGE);
|
||||
|
||||
inspector.selection.setNode(absolute);
|
||||
is(inspector.selection.node, absolute, "selection matches the absolute element");
|
||||
let absoluteLink = contentDoc.querySelector(".ruleview-propertycontainer a");
|
||||
ok (absoluteLink, "Link exists for absolute node");
|
||||
ok (absoluteLink.getAttribute("href"), TEST_IMAGE);
|
||||
inspector.selection.setNode(absolute);
|
||||
inspector.once("inspector-updated", () => {
|
||||
is(inspector.selection.node, absolute, "selection matches the absolute element");
|
||||
let absoluteLink = contentDoc.querySelector(".ruleview-propertycontainer a");
|
||||
ok (absoluteLink, "Link exists for absolute node");
|
||||
ok (absoluteLink.getAttribute("href"), TEST_IMAGE);
|
||||
|
||||
inspector.selection.setNode(inline);
|
||||
is(inspector.selection.node, inline, "selection matches the inline element");
|
||||
let inlineLink = contentDoc.querySelector(".ruleview-propertycontainer a");
|
||||
ok (inlineLink, "Link exists for inline node");
|
||||
ok (inlineLink.getAttribute("href"), TEST_IMAGE);
|
||||
inspector.selection.setNode(inline);
|
||||
inspector.once("inspector-updated", () => {
|
||||
is(inspector.selection.node, inline, "selection matches the inline element");
|
||||
let inlineLink = contentDoc.querySelector(".ruleview-propertycontainer a");
|
||||
ok (inlineLink, "Link exists for inline node");
|
||||
ok (inlineLink.getAttribute("href"), TEST_IMAGE);
|
||||
|
||||
inspector.selection.setNode(base64);
|
||||
is(inspector.selection.node, base64, "selection matches the base64 element");
|
||||
let base64Link = contentDoc.querySelector(".ruleview-propertycontainer a");
|
||||
ok (base64Link, "Link exists for base64 node");
|
||||
ok (base64Link.getAttribute("href"), BASE_64_URL);
|
||||
inspector.selection.setNode(base64);
|
||||
inspector.once("inspector-updated", () => {
|
||||
is(inspector.selection.node, base64, "selection matches the base64 element");
|
||||
let base64Link = contentDoc.querySelector(".ruleview-propertycontainer a");
|
||||
ok (base64Link, "Link exists for base64 node");
|
||||
ok (base64Link.getAttribute("href"), BASE_64_URL);
|
||||
|
||||
inspector.selection.setNode(noimage);
|
||||
is(inspector.selection.node, noimage, "selection matches the inline element");
|
||||
let noimageLink = contentDoc.querySelector(".ruleview-propertycontainer a");
|
||||
ok (!noimageLink, "There is no link for the node with no background image");
|
||||
|
||||
finishUp();
|
||||
inspector.selection.setNode(noimage);
|
||||
inspector.once("inspector-updated", () => {
|
||||
is(inspector.selection.node, noimage, "selection matches the inline element");
|
||||
let noimageLink = contentDoc.querySelector(".ruleview-propertycontainer a");
|
||||
ok (!noimageLink, "There is no link for the node with no background image");
|
||||
finishUp();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function finishUp()
|
||||
|
@ -90,7 +88,7 @@ function test()
|
|||
gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
|
||||
doc = content.document;
|
||||
waitForFocus(createDocument, content);
|
||||
waitForFocus(() => openRuleView(selectNode), content);
|
||||
}, true);
|
||||
|
||||
content.location = TEST_URI;
|
||||
|
|
|
@ -3,7 +3,13 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Services.prefs.setBoolPref("devtools.debugger.log", true);
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("devtools.debugger.log");
|
||||
});
|
||||
|
||||
let tempScope = {};
|
||||
|
||||
Cu.import("resource:///modules/devtools/gDevTools.jsm", tempScope);
|
||||
let ConsoleUtils = tempScope.ConsoleUtils;
|
||||
let gDevTools = tempScope.gDevTools;
|
||||
|
@ -16,6 +22,8 @@ let {CssHtmlTree} = devtools.require("devtools/styleinspector/computed-view");
|
|||
let {CssRuleView, _ElementStyle} = devtools.require("devtools/styleinspector/rule-view");
|
||||
let {CssLogic, CssSelector} = devtools.require("devtools/styleinspector/css-logic");
|
||||
|
||||
let promise = devtools.require("sdk/core/promise");
|
||||
|
||||
let {
|
||||
editableField,
|
||||
getInplaceEditorForSpan: inplaceEditor
|
||||
|
@ -40,6 +48,17 @@ function openInspector(callback)
|
|||
});
|
||||
}
|
||||
|
||||
function openRuleView(callback)
|
||||
{
|
||||
openInspector(inspector => {
|
||||
inspector.sidebar.once("ruleview-ready", () => {
|
||||
inspector.sidebar.select("ruleview");
|
||||
let ruleView = inspector.sidebar.getWindowForTab("ruleview").ruleview.view;
|
||||
callback(inspector, ruleView);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function addStyle(aDocument, aString)
|
||||
{
|
||||
let node = aDocument.createElement('style');
|
||||
|
@ -120,6 +139,21 @@ function contextMenuClick(element) {
|
|||
element.dispatchEvent(evt);
|
||||
}
|
||||
|
||||
function expectRuleChange(rule) {
|
||||
return rule._applyingModifications;
|
||||
}
|
||||
|
||||
function promiseDone(promise) {
|
||||
promise.then(null, err => {
|
||||
ok(false, "Promise failed: " + err);
|
||||
if (err.stack) {
|
||||
dump(err.stack);
|
||||
}
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
registerCleanupFunction(tearDown);
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
|
Загрузка…
Ссылка в новой задаче