Bug 1327675 - Correctly hightlight nodes for inherited rules. r=pbro

--HG--
extra : rebase_source : 1df369d9b5e07beaf9d66d017122f1f76afd9faf
This commit is contained in:
Sébastien Blin 2017-02-01 06:13:00 -05:00
Родитель 89c63a086b
Коммит ae30e668fa
15 изменённых файлов: 455 добавлений и 690 удалений

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

@ -212,6 +212,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
[browser_rules_selector-highlighter_02.js]
[browser_rules_selector-highlighter_03.js]
[browser_rules_selector-highlighter_04.js]
[browser_rules_selector-highlighter_05.js]
[browser_rules_selector_highlight.js]
[browser_rules_strict-search-filter-computed-list_01.js]
[browser_rules_strict-search-filter_01.js]

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

@ -22,6 +22,7 @@ add_task(function* () {
let testActor = yield getTestActorWithoutToolbox(tab);
let inspector = yield clickOnInspectMenuItem(testActor, "span");
yield getRuleViewSelectorHighlighterIcon(inspector.ruleview.view, "element", 3);
checkRuleViewContent(inspector.ruleview.view);
});

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

@ -33,7 +33,7 @@ function* testSelectorHighlight(view, name) {
info("Test creating selector highlighter");
info("Clicking on a selector icon");
let icon = getRuleViewSelectorHighlighterIcon(view, name);
let icon = yield getRuleViewSelectorHighlighterIcon(view, name);
let onToggled = view.once("ruleview-selectorhighlighter-toggled");
EventUtils.synthesizeMouseAtCenter(icon, {}, view.styleWindow);

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

@ -18,6 +18,7 @@ add_task(function* () {
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
let {inspector, view} = yield openRuleView();
yield selectNode("#test1", inspector);
yield getRuleViewSelectorHighlighterIcon(view, "element", 1);
yield elementStyleInherit(inspector, view);
});

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

@ -20,6 +20,7 @@ add_task(function* () {
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
let {inspector, view} = yield openRuleView();
yield selectNode("a", inspector);
yield getRuleViewSelectorHighlighterIcon(view, "element", 2);
yield elementStyleInherit(inspector, view);
});

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

@ -23,7 +23,7 @@ add_task(function* () {
let highlighters = view.highlighters;
info("Clicking on a selector icon");
let icon = getRuleViewSelectorHighlighterIcon(view, "body, p, td");
let icon = yield getRuleViewSelectorHighlighterIcon(view, "body, p, td");
let onToggled = view.once("ruleview-selectorhighlighter-toggled");
EventUtils.synthesizeMouseAtCenter(icon, {}, view.styleWindow);

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

@ -24,7 +24,7 @@ add_task(function* () {
"No selectorhighlighter exist in the rule-view");
info("Clicking on a selector icon");
let icon = getRuleViewSelectorHighlighterIcon(view, "body, p, td");
let icon = yield getRuleViewSelectorHighlighterIcon(view, "body, p, td");
let onToggled = view.once("ruleview-selectorhighlighter-toggled");
EventUtils.synthesizeMouseAtCenter(icon, {}, view.styleWindow);

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

@ -46,7 +46,7 @@ add_task(function* () {
// Inject the mock highlighter in the rule-view
view.selectorHighlighter = HighlighterFront;
let icon = getRuleViewSelectorHighlighterIcon(view, "body");
let icon = yield getRuleViewSelectorHighlighterIcon(view, "body");
info("Checking that the HighlighterFront's show/hide methods are called");
@ -60,7 +60,7 @@ add_task(function* () {
info("Checking that the right NodeFront reference and options are passed");
yield selectNode("p", inspector);
icon = getRuleViewSelectorHighlighterIcon(view, "p");
icon = yield getRuleViewSelectorHighlighterIcon(view, "p");
yield clickSelectorIcon(icon, view);
is(HighlighterFront.nodeFront.tagName, "P",
@ -69,7 +69,7 @@ add_task(function* () {
"The right selector option is passed to the highlighter (1)");
yield selectNode("body", inspector);
icon = getRuleViewSelectorHighlighterIcon(view, "body");
icon = yield getRuleViewSelectorHighlighterIcon(view, "body");
yield clickSelectorIcon(icon, view);
is(HighlighterFront.nodeFront.tagName, "BODY",
"The right NodeFront is passed to the highlighter (2)");

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

@ -39,7 +39,7 @@ add_task(function* () {
info("Select .node-1 and click on the .node-1 selector icon");
yield selectNode(".node-1", inspector);
let icon = getRuleViewSelectorHighlighterIcon(view, ".node-1");
let icon = yield getRuleViewSelectorHighlighterIcon(view, ".node-1");
yield clickSelectorIcon(icon, view);
ok(HighlighterFront.isShown, "The highlighter is shown");
@ -48,12 +48,12 @@ add_task(function* () {
ok(!HighlighterFront.isShown, "The highlighter is now hidden");
info("With .node-1 still selected, click on the div selector icon");
icon = getRuleViewSelectorHighlighterIcon(view, "div");
icon = yield getRuleViewSelectorHighlighterIcon(view, "div");
yield clickSelectorIcon(icon, view);
ok(HighlighterFront.isShown, "The highlighter is shown again");
info("With .node-1 still selected, click again on the .node-1 selector icon");
icon = getRuleViewSelectorHighlighterIcon(view, ".node-1");
icon = yield getRuleViewSelectorHighlighterIcon(view, ".node-1");
yield clickSelectorIcon(icon, view);
ok(HighlighterFront.isShown,
"The highlighter is shown again since the clicked selector was different");
@ -64,14 +64,14 @@ add_task(function* () {
"The highlighter is still shown after selection");
info("With .node-2 selected, click on the div selector icon");
icon = getRuleViewSelectorHighlighterIcon(view, "div");
icon = yield getRuleViewSelectorHighlighterIcon(view, "div");
yield clickSelectorIcon(icon, view);
ok(HighlighterFront.isShown,
"The highlighter is shown still since the selected was different");
info("Switching back to .node-1 and clicking on the div selector");
yield selectNode(".node-1", inspector);
icon = getRuleViewSelectorHighlighterIcon(view, "div");
icon = yield getRuleViewSelectorHighlighterIcon(view, "div");
yield clickSelectorIcon(icon, view);
ok(!HighlighterFront.isShown,
"The highlighter is hidden now that the same selector was clicked");

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

@ -39,7 +39,7 @@ add_task(function* () {
info("Checking that the right NodeFront reference and options are passed");
yield selectNode("p", inspector);
let icon = getRuleViewSelectorHighlighterIcon(view, "element");
let icon = yield getRuleViewSelectorHighlighterIcon(view, "element");
yield clickSelectorIcon(icon, view);
is(HighlighterFront.nodeFront.tagName, "P",

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

@ -0,0 +1,63 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the selector highlighter is correctly shown when clicking on a
// inherited element
// Note that in this test, we mock the highlighter front, merely testing the
// behavior of the style-inspector UI for now
const TEST_URI = `
<div style="cursor:pointer">
A
<div style="cursor:pointer">
B<a>Cursor</a>
</div>
</div>
`;
add_task(function* () {
yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
let {inspector, view} = yield openRuleView();
// Mock the highlighter front to get the reference of the NodeFront
let HighlighterFront = {
isShown: false,
nodeFront: null,
options: null,
show: function (nodeFront, options) {
this.nodeFront = nodeFront;
this.options = options;
this.isShown = true;
},
hide: function () {
this.nodeFront = null;
this.options = null;
this.isShown = false;
}
};
// Inject the mock highlighter in the rule-view
view.selectorHighlighter = HighlighterFront;
info("Checking that the right NodeFront reference and options are passed");
yield selectNode("a", inspector);
let icon = yield getRuleViewSelectorHighlighterIcon(view, "element");
yield clickSelectorIcon(icon, view);
is(HighlighterFront.options.selector,
"body > div:nth-child(1) > div:nth-child(1) > a:nth-child(1)",
"The right selector option is passed to the highlighter (1)");
icon = yield getRuleViewSelectorHighlighterIcon(view, "element", 1);
yield clickSelectorIcon(icon, view);
is(HighlighterFront.options.selector, "body > div:nth-child(1) > div:nth-child(1)",
"The right selector option is passed to the highlighter (1)");
icon = yield getRuleViewSelectorHighlighterIcon(view, "element", 2);
yield clickSelectorIcon(icon, view);
is(HighlighterFront.options.selector, "body > div:nth-child(1)",
"The right selector option is passed to the highlighter (1)");
});

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

@ -44,76 +44,6 @@ addTab = function (url) {
});
};
/**
* Wait for a content -> chrome message on the message manager (the window
* messagemanager is used).
*
* @param {String} name
* The message name
* @return {Promise} A promise that resolves to the response data when the
* message has been received
*/
function waitForContentMessage(name) {
info("Expecting message " + name + " from content");
let mm = gBrowser.selectedBrowser.messageManager;
let def = defer();
mm.addMessageListener(name, function onMessage(msg) {
mm.removeMessageListener(name, onMessage);
def.resolve(msg.data);
});
return def.promise;
}
/**
* Send an async message to the frame script (chrome -> content) and wait for a
* response message with the same name (content -> chrome).
*
* @param {String} name
* The message name. Should be one of the messages defined
* in doc_frame_script.js
* @param {Object} data
* Optional data to send along
* @param {Object} objects
* Optional CPOW objects to send along
* @param {Boolean} expectResponse
* If set to false, don't wait for a response with the same name
* from the content script. Defaults to true.
* @return {Promise} Resolves to the response data if a response is expected,
* immediately resolves otherwise
*/
function executeInContent(name, data = {}, objects = {},
expectResponse = true) {
info("Sending message " + name + " to content");
let mm = gBrowser.selectedBrowser.messageManager;
mm.sendAsyncMessage(name, data, objects);
if (expectResponse) {
return waitForContentMessage(name);
}
return promise.resolve();
}
/**
* Send an async message to the frame script and get back the requested
* computed style property.
*
* @param {String} selector
* The selector used to obtain the element.
* @param {String} pseudo
* pseudo id to query, or null.
* @param {String} name
* name of the property.
*/
function* getComputedStyleProperty(selector, pseudo, propName) {
return yield executeInContent("Test:GetComputedStylePropertyValue",
{selector,
pseudo,
name: propName});
}
/**
* Get an element's inline style property value.
* @param {TestActor} testActor
@ -129,49 +59,6 @@ function getStyle(testActor, selector, propName) {
`);
}
/**
* Send an async message to the frame script and wait until the requested
* computed style property has the expected value.
*
* @param {String} selector
* The selector used to obtain the element.
* @param {String} pseudo
* pseudo id to query, or null.
* @param {String} prop
* name of the property.
* @param {String} expected
* expected value of property
* @param {String} name
* the name used in test message
*/
function* waitForComputedStyleProperty(selector, pseudo, name, expected) {
return yield executeInContent("Test:WaitForComputedStylePropertyValue",
{selector,
pseudo,
expected,
name});
}
/**
* Given an inplace editable element, click to switch it to edit mode, wait for
* focus
*
* @return a promise that resolves to the inplace-editor element when ready
*/
var focusEditableField = Task.async(function* (ruleView, editable, xOffset = 1,
yOffset = 1, options = {}) {
let onFocus = once(editable.parentNode, "focus", true);
info("Clicking on editable field to turn to edit mode");
EventUtils.synthesizeMouse(editable, xOffset, yOffset, options,
editable.ownerDocument.defaultView);
yield onFocus;
info("Editable field gained focus, returning the input field now");
let onEdit = inplaceEditor(editable.ownerDocument.activeElement);
return onEdit;
});
/**
* When a tooltip is closed, this ends up "commiting" the value changed within
* the tooltip (e.g. the color in case of a colorpicker) which, in turn, ends up
@ -219,109 +106,6 @@ var waitForSuccess = Task.async(function* (validatorFn, desc = "untitled") {
}
});
/**
* Get the DOMNode for a css rule in the rule-view that corresponds to the given
* selector
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view for which the rule
* object is wanted
* @return {DOMNode}
*/
function getRuleViewRule(view, selectorText) {
let rule;
for (let r of view.styleDocument.querySelectorAll(".ruleview-rule")) {
let selector = r.querySelector(".ruleview-selectorcontainer, " +
".ruleview-selector-matched");
if (selector && selector.textContent === selectorText) {
rule = r;
break;
}
}
return rule;
}
/**
* Get references to the name and value span nodes corresponding to a given
* selector and property name in the rule-view
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view to look for the property in
* @param {String} propertyName
* The name of the property
* @return {Object} An object like {nameSpan: DOMNode, valueSpan: DOMNode}
*/
function getRuleViewProperty(view, selectorText, propertyName) {
let prop;
let rule = getRuleViewRule(view, selectorText);
if (rule) {
// Look for the propertyName in that rule element
for (let p of rule.querySelectorAll(".ruleview-property")) {
let nameSpan = p.querySelector(".ruleview-propertyname");
let valueSpan = p.querySelector(".ruleview-propertyvalue");
if (nameSpan.textContent === propertyName) {
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
break;
}
}
}
return prop;
}
/**
* Get the text value of the property corresponding to a given selector and name
* in the rule-view
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view to look for the property in
* @param {String} propertyName
* The name of the property
* @return {String} The property value
*/
function getRuleViewPropertyValue(view, selectorText, propertyName) {
return getRuleViewProperty(view, selectorText, propertyName)
.valueSpan.textContent;
}
/**
* Get a reference to the selector DOM element corresponding to a given selector
* in the rule-view
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view to look for
* @return {DOMNode} The selector DOM element
*/
function getRuleViewSelector(view, selectorText) {
let rule = getRuleViewRule(view, selectorText);
return rule.querySelector(".ruleview-selector, .ruleview-selector-matched");
}
/**
* Get a reference to the selectorhighlighter icon DOM element corresponding to
* a given selector in the rule-view
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view to look for
* @return {DOMNode} The selectorhighlighter icon DOM element
*/
function getRuleViewSelectorHighlighterIcon(view, selectorText) {
let rule = getRuleViewRule(view, selectorText);
return rule.querySelector(".ruleview-selectorhighlighter");
}
/**
* Simulate a color change in a given color picker tooltip, and optionally wait
* for a given element in the page to have its style changed as a result.
@ -452,34 +236,6 @@ var openCubicBezierAndChangeCoords = Task.async(function* (view, ruleIndex,
return {propEditor, swatch, bezierTooltip};
});
/**
* Get a rule-link from the rule-view given its index
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {Number} index
* The index of the link to get
* @return {DOMNode} The link if any at this index
*/
function getRuleViewLinkByIndex(view, index) {
let links = view.styleDocument.querySelectorAll(".ruleview-rule-source");
return links[index];
}
/**
* Get rule-link text from the rule-view given its index
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {Number} index
* The index of the link to get
* @return {String} The string at this index
*/
function getRuleViewLinkTextByIndex(view, index) {
let link = getRuleViewLinkByIndex(view, index);
return link.querySelector(".ruleview-rule-source-label").textContent;
}
/**
* Simulate adding a new property in an existing rule in the rule-view.
*
@ -625,74 +381,6 @@ var togglePropStatus = Task.async(function* (view, textProp) {
yield onRuleViewRefreshed;
});
/**
* Click on a rule-view's close brace to focus a new property name editor
*
* @param {RuleEditor} ruleEditor
* An instance of RuleEditor that will receive the new property
* @return a promise that resolves to the newly created editor when ready and
* focused
*/
var focusNewRuleViewProperty = Task.async(function* (ruleEditor) {
info("Clicking on a close ruleEditor brace to start editing a new property");
// Use bottom alignment to avoid scrolling out of the parent element area.
ruleEditor.closeBrace.scrollIntoView(false);
let editor = yield focusEditableField(ruleEditor.ruleView,
ruleEditor.closeBrace);
is(inplaceEditor(ruleEditor.newPropSpan), editor,
"Focused editor is the new property editor.");
return editor;
});
/**
* Create a new property name in the rule-view, focusing a new property editor
* by clicking on the close brace, and then entering the given text.
* Keep in mind that the rule-view knows how to handle strings with multiple
* properties, so the input text may be like: "p1:v1;p2:v2;p3:v3".
*
* @param {RuleEditor} ruleEditor
* The instance of RuleEditor that will receive the new property(ies)
* @param {String} inputValue
* The text to be entered in the new property name field
* @return a promise that resolves when the new property name has been entered
* and once the value field is focused
*/
var createNewRuleViewProperty = Task.async(function* (ruleEditor, inputValue) {
info("Creating a new property editor");
let editor = yield focusNewRuleViewProperty(ruleEditor);
info("Entering the value " + inputValue);
editor.input.value = inputValue;
info("Submitting the new value and waiting for value field focus");
let onFocus = once(ruleEditor.element, "focus", true);
EventUtils.synthesizeKey("VK_RETURN", {},
ruleEditor.element.ownerDocument.defaultView);
yield onFocus;
});
/**
* Set the search value for the rule-view filter styles search box.
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} searchValue
* The filter search value
* @return a promise that resolves when the rule-view is filtered for the
* search term
*/
var setSearchFilter = Task.async(function* (view, searchValue) {
info("Setting filter text to \"" + searchValue + "\"");
let win = view.styleWindow;
let searchField = view.searchField;
searchField.focus();
synthesizeKeys(searchValue, win);
yield view.inspector.once("ruleview-filtered");
});
/**
* Reload the current page and wait for the inspector to be initialized after
* the navigation
@ -778,26 +466,6 @@ function* sendKeysAndWaitForFocus(view, element, keys) {
yield onFocus;
}
/**
* Open the style editor context menu and return all of it's items in a flat array
* @param {CssRuleView} view
* The instance of the rule-view panel
* @return An array of MenuItems
*/
function openStyleContextMenuAndGetAllItems(view, target) {
let menu = view._contextmenu._openMenu({target: target});
// Flatten all menu items into a single array to make searching through it easier
let allItems = [].concat.apply([], menu.items.map(function addItem(item) {
if (item.submenu) {
return addItem(item.submenu.items);
}
return item;
}));
return allItems;
}
/**
* Wait for a markupmutation event on the inspector that is for a style modification.
* @param {InspectorPanel} inspector

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

@ -149,19 +149,34 @@ RuleEditor.prototype = {
}
if (this.rule.domRule.type !== CSSRule.KEYFRAME_RULE) {
let selector = this.rule.domRule.selectors
? this.rule.domRule.selectors.join(", ")
: this.ruleView.inspector.selectionCssSelector;
Task.spawn(function* () {
let selector;
let selectorHighlighter = createChild(header, "span", {
class: "ruleview-selectorhighlighter" +
(this.ruleView.highlighters.selectorHighlighterShown === selector ?
" highlighted" : ""),
title: l10n("rule.selectorHighlighter.tooltip")
});
selectorHighlighter.addEventListener("click", () => {
this.ruleView.toggleSelectorHighlighter(selectorHighlighter, selector);
});
if (this.rule.domRule.selectors) {
// This is a "normal" rule with a selector.
selector = this.rule.domRule.selectors.join(", ");
} else if (this.rule.inherited) {
// This is an inline style from an inherited rule. Need to resolve the unique
// selector from the node which rule this is inherited from.
selector = yield this.rule.inherited.getUniqueSelector();
} else {
// This is an inline style from the current node.
selector = this.ruleView.inspector.selectionCssSelector;
}
let selectorHighlighter = createChild(header, "span", {
class: "ruleview-selectorhighlighter" +
(this.ruleView.highlighters.selectorHighlighterShown === selector ?
" highlighted" : ""),
title: l10n("rule.selectorHighlighter.tooltip")
});
selectorHighlighter.addEventListener("click", () => {
this.ruleView.toggleSelectorHighlighter(selectorHighlighter, selector);
});
this.uniqueSelector = selector;
this.emit("selector-icon-created");
}.bind(this));
}
this.openBrace = createChild(header, "span", {

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

@ -88,123 +88,6 @@ addTab = function (url) {
});
};
/**
* Wait for a content -> chrome message on the message manager (the window
* messagemanager is used).
*
* @param {String} name
* The message name
* @return {Promise} A promise that resolves to the response data when the
* message has been received
*/
function waitForContentMessage(name) {
info("Expecting message " + name + " from content");
let mm = gBrowser.selectedBrowser.messageManager;
let def = defer();
mm.addMessageListener(name, function onMessage(msg) {
mm.removeMessageListener(name, onMessage);
def.resolve(msg.data);
});
return def.promise;
}
/**
* Send an async message to the frame script (chrome -> content) and wait for a
* response message with the same name (content -> chrome).
*
* @param {String} name
* The message name. Should be one of the messages defined
* in doc_frame_script.js
* @param {Object} data
* Optional data to send along
* @param {Object} objects
* Optional CPOW objects to send along
* @param {Boolean} expectResponse
* If set to false, don't wait for a response with the same name
* from the content script. Defaults to true.
* @return {Promise} Resolves to the response data if a response is expected,
* immediately resolves otherwise
*/
function executeInContent(name, data = {}, objects = {},
expectResponse = true) {
info("Sending message " + name + " to content");
let mm = gBrowser.selectedBrowser.messageManager;
mm.sendAsyncMessage(name, data, objects);
if (expectResponse) {
return waitForContentMessage(name);
}
return promise.resolve();
}
/**
* Send an async message to the frame script and get back the requested
* computed style property.
*
* @param {String} selector
* The selector used to obtain the element.
* @param {String} pseudo
* pseudo id to query, or null.
* @param {String} name
* name of the property.
*/
function* getComputedStyleProperty(selector, pseudo, propName) {
let data = {
selector,
pseudo,
name: propName
};
return yield executeInContent("Test:GetComputedStylePropertyValue", data);
}
/**
* Send an async message to the frame script and wait until the requested
* computed style property has the expected value.
*
* @param {String} selector
* The selector used to obtain the element.
* @param {String} pseudo
* pseudo id to query, or null.
* @param {String} prop
* name of the property.
* @param {String} expected
* expected value of property
* @param {String} name
* the name used in test message
*/
function* waitForComputedStyleProperty(selector, pseudo, name, expected) {
let data = {
selector,
pseudo,
expected,
name
};
return yield executeInContent("Test:WaitForComputedStylePropertyValue", data);
}
/**
* Given an inplace editable element, click to switch it to edit mode, wait for
* focus
*
* @return a promise that resolves to the inplace-editor element when ready
*/
var focusEditableField = Task.async(function* (ruleView, editable, xOffset = 1,
yOffset = 1, options = {}) {
let onFocus = once(editable.parentNode, "focus", true);
info("Clicking on editable field to turn to edit mode");
EventUtils.synthesizeMouse(editable, xOffset, yOffset, options,
editable.ownerDocument.defaultView);
yield onFocus;
info("Editable field gained focus, returning the input field now");
let onEdit = inplaceEditor(editable.ownerDocument.activeElement);
return onEdit;
});
/**
* Polls a given function waiting for it to return true.
*
@ -258,109 +141,6 @@ var getFontFamilyDataURL = Task.async(function* (font, nodeFront) {
* This object contains functions to get rules, get properties, ...
*/
/**
* Get the DOMNode for a css rule in the rule-view that corresponds to the given
* selector
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view for which the rule
* object is wanted
* @return {DOMNode}
*/
function getRuleViewRule(view, selectorText) {
let rule;
for (let r of view.styleDocument.querySelectorAll(".ruleview-rule")) {
let selector = r.querySelector(".ruleview-selectorcontainer, " +
".ruleview-selector-matched");
if (selector && selector.textContent === selectorText) {
rule = r;
break;
}
}
return rule;
}
/**
* Get references to the name and value span nodes corresponding to a given
* selector and property name in the rule-view
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view to look for the property in
* @param {String} propertyName
* The name of the property
* @return {Object} An object like {nameSpan: DOMNode, valueSpan: DOMNode}
*/
function getRuleViewProperty(view, selectorText, propertyName) {
let prop;
let rule = getRuleViewRule(view, selectorText);
if (rule) {
// Look for the propertyName in that rule element
for (let p of rule.querySelectorAll(".ruleview-property")) {
let nameSpan = p.querySelector(".ruleview-propertyname");
let valueSpan = p.querySelector(".ruleview-propertyvalue");
if (nameSpan.textContent === propertyName) {
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
break;
}
}
}
return prop;
}
/**
* Get the text value of the property corresponding to a given selector and name
* in the rule-view
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view to look for the property in
* @param {String} propertyName
* The name of the property
* @return {String} The property value
*/
function getRuleViewPropertyValue(view, selectorText, propertyName) {
return getRuleViewProperty(view, selectorText, propertyName)
.valueSpan.textContent;
}
/**
* Get a reference to the selector DOM element corresponding to a given selector
* in the rule-view
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view to look for
* @return {DOMNode} The selector DOM element
*/
function getRuleViewSelector(view, selectorText) {
let rule = getRuleViewRule(view, selectorText);
return rule.querySelector(".ruleview-selector, .ruleview-selector-matched");
}
/**
* Get a reference to the selectorhighlighter icon DOM element corresponding to
* a given selector in the rule-view
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view to look for
* @return {DOMNode} The selectorhighlighter icon DOM element
*/
function getRuleViewSelectorHighlighterIcon(view, selectorText) {
let rule = getRuleViewRule(view, selectorText);
return rule.querySelector(".ruleview-selectorhighlighter");
}
/**
* Simulate a color change in a given color picker tooltip, and optionally wait
* for a given element in the page to have its style changed as a result
@ -400,100 +180,6 @@ var simulateColorPickerChange = Task.async(function* (ruleView, colorPicker,
}
});
/**
* Get a rule-link from the rule-view given its index
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {Number} index
* The index of the link to get
* @return {DOMNode} The link if any at this index
*/
function getRuleViewLinkByIndex(view, index) {
let links = view.styleDocument.querySelectorAll(".ruleview-rule-source");
return links[index];
}
/**
* Get rule-link text from the rule-view given its index
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {Number} index
* The index of the link to get
* @return {String} The string at this index
*/
function getRuleViewLinkTextByIndex(view, index) {
let link = getRuleViewLinkByIndex(view, index);
return link.querySelector(".ruleview-rule-source-label").textContent;
}
/**
* Click on a rule-view's close brace to focus a new property name editor
*
* @param {RuleEditor} ruleEditor
* An instance of RuleEditor that will receive the new property
* @return a promise that resolves to the newly created editor when ready and
* focused
*/
var focusNewRuleViewProperty = Task.async(function* (ruleEditor) {
info("Clicking on a close ruleEditor brace to start editing a new property");
ruleEditor.closeBrace.scrollIntoView();
let editor = yield focusEditableField(ruleEditor.ruleView,
ruleEditor.closeBrace);
is(inplaceEditor(ruleEditor.newPropSpan), editor,
"Focused editor is the new property editor.");
return editor;
});
/**
* Create a new property name in the rule-view, focusing a new property editor
* by clicking on the close brace, and then entering the given text.
* Keep in mind that the rule-view knows how to handle strings with multiple
* properties, so the input text may be like: "p1:v1;p2:v2;p3:v3".
*
* @param {RuleEditor} ruleEditor
* The instance of RuleEditor that will receive the new property(ies)
* @param {String} inputValue
* The text to be entered in the new property name field
* @return a promise that resolves when the new property name has been entered
* and once the value field is focused
*/
var createNewRuleViewProperty = Task.async(function* (ruleEditor, inputValue) {
info("Creating a new property editor");
let editor = yield focusNewRuleViewProperty(ruleEditor);
info("Entering the value " + inputValue);
editor.input.value = inputValue;
info("Submitting the new value and waiting for value field focus");
let onFocus = once(ruleEditor.element, "focus", true);
EventUtils.synthesizeKey("VK_RETURN", {},
ruleEditor.element.ownerDocument.defaultView);
yield onFocus;
});
/**
* Set the search value for the rule-view filter styles search box.
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} searchValue
* The filter search value
* @return a promise that resolves when the rule-view is filtered for the
* search term
*/
var setSearchFilter = Task.async(function* (view, searchValue) {
info("Setting filter text to \"" + searchValue + "\"");
let win = view.styleWindow;
let searchField = view.searchField;
searchField.focus();
synthesizeKeys(searchValue, win);
yield view.inspector.once("ruleview-filtered");
});
/* *********************************************
* COMPUTED-VIEW
* *********************************************
@ -539,23 +225,3 @@ function getComputedViewPropertyValue(view, name, propertyName) {
return getComputedViewProperty(view, name, propertyName)
.valueSpan.textContent;
}
/**
* Open the style editor context menu and return all of it's items in a flat array
* @param {CssRuleView} view
* The instance of the rule-view panel
* @return An array of MenuItems
*/
function openStyleContextMenuAndGetAllItems(view, target) {
let menu = view._contextmenu._openMenu({target: target});
// Flatten all menu items into a single array to make searching through it easier
let allItems = [].concat.apply([], menu.items.map(function addItem(item) {
if (item.submenu) {
return addItem(item.submenu.items);
}
return item;
}));
return allItems;
}

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

@ -184,3 +184,352 @@ function manualThrottle() {
return throttle;
}
/**
* Wait for a content -> chrome message on the message manager (the window
* messagemanager is used).
*
* @param {String} name
* The message name
* @return {Promise} A promise that resolves to the response data when the
* message has been received
*/
function waitForContentMessage(name) {
info("Expecting message " + name + " from content");
let mm = gBrowser.selectedBrowser.messageManager;
let def = defer();
mm.addMessageListener(name, function onMessage(msg) {
mm.removeMessageListener(name, onMessage);
def.resolve(msg.data);
});
return def.promise;
}
/**
* Send an async message to the frame script (chrome -> content) and wait for a
* response message with the same name (content -> chrome).
*
* @param {String} name
* The message name. Should be one of the messages defined
* in doc_frame_script.js
* @param {Object} data
* Optional data to send along
* @param {Object} objects
* Optional CPOW objects to send along
* @param {Boolean} expectResponse
* If set to false, don't wait for a response with the same name
* from the content script. Defaults to true.
* @return {Promise} Resolves to the response data if a response is expected,
* immediately resolves otherwise
*/
function executeInContent(name, data = {}, objects = {},
expectResponse = true) {
info("Sending message " + name + " to content");
let mm = gBrowser.selectedBrowser.messageManager;
mm.sendAsyncMessage(name, data, objects);
if (expectResponse) {
return waitForContentMessage(name);
}
return promise.resolve();
}
/**
* Send an async message to the frame script and get back the requested
* computed style property.
*
* @param {String} selector
* The selector used to obtain the element.
* @param {String} pseudo
* pseudo id to query, or null.
* @param {String} name
* name of the property.
*/
function* getComputedStyleProperty(selector, pseudo, propName) {
return yield executeInContent("Test:GetComputedStylePropertyValue",
{selector,
pseudo,
name: propName});
}
/**
* Send an async message to the frame script and wait until the requested
* computed style property has the expected value.
*
* @param {String} selector
* The selector used to obtain the element.
* @param {String} pseudo
* pseudo id to query, or null.
* @param {String} prop
* name of the property.
* @param {String} expected
* expected value of property
* @param {String} name
* the name used in test message
*/
function* waitForComputedStyleProperty(selector, pseudo, name, expected) {
return yield executeInContent("Test:WaitForComputedStylePropertyValue",
{selector,
pseudo,
expected,
name});
}
/**
* Given an inplace editable element, click to switch it to edit mode, wait for
* focus
*
* @return a promise that resolves to the inplace-editor element when ready
*/
var focusEditableField = Task.async(function* (ruleView, editable, xOffset = 1,
yOffset = 1, options = {}) {
let onFocus = once(editable.parentNode, "focus", true);
info("Clicking on editable field to turn to edit mode");
EventUtils.synthesizeMouse(editable, xOffset, yOffset, options,
editable.ownerDocument.defaultView);
yield onFocus;
info("Editable field gained focus, returning the input field now");
let onEdit = inplaceEditor(editable.ownerDocument.activeElement);
return onEdit;
});
/**
* Get the DOMNode for a css rule in the rule-view that corresponds to the given
* selector.
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view for which the rule
* object is wanted
* @param {Number} index
* If there are more than 1 rule with the same selector, you may pass a
* index to determine which of the rules you want.
* @return {DOMNode}
*/
function getRuleViewRule(view, selectorText, index = 0) {
let rule;
let pos = 0;
for (let r of view.styleDocument.querySelectorAll(".ruleview-rule")) {
let selector = r.querySelector(".ruleview-selectorcontainer, " +
".ruleview-selector-matched");
if (selector && selector.textContent === selectorText) {
if (index == pos) {
rule = r;
break;
}
pos ++;
}
}
return rule;
}
/**
* Get references to the name and value span nodes corresponding to a given
* selector and property name in the rule-view
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view to look for the property in
* @param {String} propertyName
* The name of the property
* @return {Object} An object like {nameSpan: DOMNode, valueSpan: DOMNode}
*/
function getRuleViewProperty(view, selectorText, propertyName) {
let prop;
let rule = getRuleViewRule(view, selectorText);
if (rule) {
// Look for the propertyName in that rule element
for (let p of rule.querySelectorAll(".ruleview-property")) {
let nameSpan = p.querySelector(".ruleview-propertyname");
let valueSpan = p.querySelector(".ruleview-propertyvalue");
if (nameSpan.textContent === propertyName) {
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
break;
}
}
}
return prop;
}
/**
* Get the text value of the property corresponding to a given selector and name
* in the rule-view
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view to look for the property in
* @param {String} propertyName
* The name of the property
* @return {String} The property value
*/
function getRuleViewPropertyValue(view, selectorText, propertyName) {
return getRuleViewProperty(view, selectorText, propertyName)
.valueSpan.textContent;
}
/**
* Get a reference to the selector DOM element corresponding to a given selector
* in the rule-view
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view to look for
* @return {DOMNode} The selector DOM element
*/
function getRuleViewSelector(view, selectorText) {
let rule = getRuleViewRule(view, selectorText);
return rule.querySelector(".ruleview-selector, .ruleview-selector-matched");
}
/**
* Get a reference to the selectorhighlighter icon DOM element corresponding to
* a given selector in the rule-view
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} selectorText
* The selector in the rule-view to look for
* @param {Number} index
* If there are more than 1 rule with the same selector, use this index
* to determine which one should be retrieved. Defaults to 0
* @return {DOMNode} The selectorhighlighter icon DOM element
*/
var getRuleViewSelectorHighlighterIcon = Task.async(function* (view,
selectorText, index = 0) {
let rule = getRuleViewRule(view, selectorText, index);
let editor = rule._ruleEditor;
if (!editor.uniqueSelector) {
yield once(editor, "selector-icon-created");
}
return rule.querySelector(".ruleview-selectorhighlighter");
});
/**
* Get a rule-link from the rule-view given its index
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {Number} index
* The index of the link to get
* @return {DOMNode} The link if any at this index
*/
function getRuleViewLinkByIndex(view, index) {
let links = view.styleDocument.querySelectorAll(".ruleview-rule-source");
return links[index];
}
/**
* Get rule-link text from the rule-view given its index
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {Number} index
* The index of the link to get
* @return {String} The string at this index
*/
function getRuleViewLinkTextByIndex(view, index) {
let link = getRuleViewLinkByIndex(view, index);
return link.querySelector(".ruleview-rule-source-label").textContent;
}
/**
* Click on a rule-view's close brace to focus a new property name editor
*
* @param {RuleEditor} ruleEditor
* An instance of RuleEditor that will receive the new property
* @return a promise that resolves to the newly created editor when ready and
* focused
*/
var focusNewRuleViewProperty = Task.async(function* (ruleEditor) {
info("Clicking on a close ruleEditor brace to start editing a new property");
// Use bottom alignment to avoid scrolling out of the parent element area.
ruleEditor.closeBrace.scrollIntoView(false);
let editor = yield focusEditableField(ruleEditor.ruleView,
ruleEditor.closeBrace);
is(inplaceEditor(ruleEditor.newPropSpan), editor,
"Focused editor is the new property editor.");
return editor;
});
/**
* Create a new property name in the rule-view, focusing a new property editor
* by clicking on the close brace, and then entering the given text.
* Keep in mind that the rule-view knows how to handle strings with multiple
* properties, so the input text may be like: "p1:v1;p2:v2;p3:v3".
*
* @param {RuleEditor} ruleEditor
* The instance of RuleEditor that will receive the new property(ies)
* @param {String} inputValue
* The text to be entered in the new property name field
* @return a promise that resolves when the new property name has been entered
* and once the value field is focused
*/
var createNewRuleViewProperty = Task.async(function* (ruleEditor, inputValue) {
info("Creating a new property editor");
let editor = yield focusNewRuleViewProperty(ruleEditor);
info("Entering the value " + inputValue);
editor.input.value = inputValue;
info("Submitting the new value and waiting for value field focus");
let onFocus = once(ruleEditor.element, "focus", true);
EventUtils.synthesizeKey("VK_RETURN", {},
ruleEditor.element.ownerDocument.defaultView);
yield onFocus;
});
/**
* Set the search value for the rule-view filter styles search box.
*
* @param {CssRuleView} view
* The instance of the rule-view panel
* @param {String} searchValue
* The filter search value
* @return a promise that resolves when the rule-view is filtered for the
* search term
*/
var setSearchFilter = Task.async(function* (view, searchValue) {
info("Setting filter text to \"" + searchValue + "\"");
let win = view.styleWindow;
let searchField = view.searchField;
searchField.focus();
synthesizeKeys(searchValue, win);
yield view.inspector.once("ruleview-filtered");
});
/**
* Open the style editor context menu and return all of it's items in a flat array
* @param {CssRuleView} view
* The instance of the rule-view panel
* @return An array of MenuItems
*/
function openStyleContextMenuAndGetAllItems(view, target) {
let menu = view._contextmenu._openMenu({target: target});
// Flatten all menu items into a single array to make searching through it easier
let allItems = [].concat.apply([], menu.items.map(function addItem(item) {
if (item.submenu) {
return addItem(item.submenu.items);
}
return item;
}));
return allItems;
}