mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Bug 1356415 - move devtools helper findCssSelector to shared module in toolkit;r=mixedpuppy
MozReview-Commit-ID: 2KOeij1oJnT --HG-- rename : devtools/shared/tests/mochitest/test_css-logic.html => toolkit/modules/tests/chrome/test_findCssSelector.html extra : rebase_source : 940ee1fb814bc33836c1be8e569ed57a6c62ab2e
This commit is contained in:
parent
59ac4a80a5
commit
d86bd44c46
@ -51,11 +51,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebNavigationFrames",
|
||||
"resource://gre/modules/WebNavigationFrames.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Feeds",
|
||||
"resource:///modules/Feeds.jsm");
|
||||
XPCOMUtils.defineLazyGetter(this, "findCssSelector", () => {
|
||||
let { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
let { findCssSelector } = require("devtools/shared/inspector/css-logic");
|
||||
return findCssSelector;
|
||||
});
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "findCssSelector",
|
||||
"resource://gre/modules/css-selector.js");
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
|
||||
|
@ -44,6 +44,9 @@ const { getTabPrefs } = require("devtools/shared/indentation");
|
||||
*/
|
||||
|
||||
const Services = require("Services");
|
||||
|
||||
loader.lazyImporter(this, "findCssSelector", "resource://gre/modules/css-selector.js");
|
||||
|
||||
const CSSLexer = require("devtools/shared/css/lexer");
|
||||
const {LocalizationHelper} = require("devtools/shared/l10n");
|
||||
const styleInspectorL10N =
|
||||
@ -344,85 +347,11 @@ function prettifyCSS(text, ruleCount) {
|
||||
|
||||
exports.prettifyCSS = prettifyCSS;
|
||||
|
||||
/**
|
||||
* Find the position of [element] in [nodeList].
|
||||
* @returns an index of the match, or -1 if there is no match
|
||||
*/
|
||||
function positionInNodeList(element, nodeList) {
|
||||
for (let i = 0; i < nodeList.length; i++) {
|
||||
if (element === nodeList[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a unique CSS selector for a given element
|
||||
* @returns a string such that ele.ownerDocument.querySelector(reply) === ele
|
||||
* and ele.ownerDocument.querySelectorAll(reply).length === 1
|
||||
*/
|
||||
function findCssSelector(ele) {
|
||||
ele = getRootBindingParent(ele);
|
||||
let document = ele.ownerDocument;
|
||||
if (!document || !document.contains(ele)) {
|
||||
throw new Error("findCssSelector received element not inside document");
|
||||
}
|
||||
|
||||
// document.querySelectorAll("#id") returns multiple if elements share an ID
|
||||
if (ele.id &&
|
||||
document.querySelectorAll("#" + CSS.escape(ele.id)).length === 1) {
|
||||
return "#" + CSS.escape(ele.id);
|
||||
}
|
||||
|
||||
// Inherently unique by tag name
|
||||
let tagName = ele.localName;
|
||||
if (tagName === "html") {
|
||||
return "html";
|
||||
}
|
||||
if (tagName === "head") {
|
||||
return "head";
|
||||
}
|
||||
if (tagName === "body") {
|
||||
return "body";
|
||||
}
|
||||
|
||||
// We might be able to find a unique class name
|
||||
let selector, index, matches;
|
||||
if (ele.classList.length > 0) {
|
||||
for (let i = 0; i < ele.classList.length; i++) {
|
||||
// Is this className unique by itself?
|
||||
selector = "." + CSS.escape(ele.classList.item(i));
|
||||
matches = document.querySelectorAll(selector);
|
||||
if (matches.length === 1) {
|
||||
return selector;
|
||||
}
|
||||
// Maybe it's unique with a tag name?
|
||||
selector = tagName + selector;
|
||||
matches = document.querySelectorAll(selector);
|
||||
if (matches.length === 1) {
|
||||
return selector;
|
||||
}
|
||||
// Maybe it's unique using a tag name and nth-child
|
||||
index = positionInNodeList(ele, ele.parentNode.children) + 1;
|
||||
selector = selector + ":nth-child(" + index + ")";
|
||||
matches = document.querySelectorAll(selector);
|
||||
if (matches.length === 1) {
|
||||
return selector;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not unique enough yet. As long as it's not a child of the document,
|
||||
// continue recursing up until it is unique enough.
|
||||
if (ele.parentNode !== document) {
|
||||
index = positionInNodeList(ele, ele.parentNode.children) + 1;
|
||||
selector = findCssSelector(ele.parentNode) + " > " +
|
||||
tagName + ":nth-child(" + index + ")";
|
||||
}
|
||||
|
||||
return selector;
|
||||
}
|
||||
exports.findCssSelector = findCssSelector;
|
||||
|
||||
/**
|
||||
|
@ -3,7 +3,6 @@ tags = devtools
|
||||
skip-if = os == 'android'
|
||||
|
||||
[test_css-logic-getCssPath.html]
|
||||
[test_css-logic.html]
|
||||
[test_devtools_extensions.html]
|
||||
[test_dom_matrix_2d.html]
|
||||
[test_eventemitter_basic.html]
|
||||
|
114
toolkit/modules/css-selector.js
Normal file
114
toolkit/modules/css-selector.js
Normal file
@ -0,0 +1,114 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["findCssSelector"];
|
||||
|
||||
/**
|
||||
* Traverse getBindingParent until arriving upon the bound element
|
||||
* responsible for the generation of the specified node.
|
||||
* See https://developer.mozilla.org/en-US/docs/XBL/XBL_1.0_Reference/DOM_Interfaces#getBindingParent.
|
||||
*
|
||||
* @param {DOMNode} node
|
||||
* @return {DOMNode}
|
||||
* If node is not anonymous, this will return node. Otherwise,
|
||||
* it will return the bound element
|
||||
*
|
||||
*/
|
||||
function getRootBindingParent(node) {
|
||||
let parent;
|
||||
let doc = node.ownerDocument;
|
||||
if (!doc) {
|
||||
return node;
|
||||
}
|
||||
while ((parent = doc.getBindingParent(node))) {
|
||||
node = parent;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the position of [element] in [nodeList].
|
||||
* @returns an index of the match, or -1 if there is no match
|
||||
*/
|
||||
function positionInNodeList(element, nodeList) {
|
||||
for (let i = 0; i < nodeList.length; i++) {
|
||||
if (element === nodeList[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a unique CSS selector for a given element
|
||||
* @returns a string such that ele.ownerDocument.querySelector(reply) === ele
|
||||
* and ele.ownerDocument.querySelectorAll(reply).length === 1
|
||||
*/
|
||||
const findCssSelector = function(ele) {
|
||||
ele = getRootBindingParent(ele);
|
||||
let document = ele.ownerDocument;
|
||||
if (!document || !document.contains(ele)) {
|
||||
throw new Error("findCssSelector received element not inside document");
|
||||
}
|
||||
|
||||
let cssEscape = ele.ownerGlobal.CSS.escape;
|
||||
|
||||
// document.querySelectorAll("#id") returns multiple if elements share an ID
|
||||
if (ele.id &&
|
||||
document.querySelectorAll("#" + cssEscape(ele.id)).length === 1) {
|
||||
return "#" + cssEscape(ele.id);
|
||||
}
|
||||
|
||||
// Inherently unique by tag name
|
||||
let tagName = ele.localName;
|
||||
if (tagName === "html") {
|
||||
return "html";
|
||||
}
|
||||
if (tagName === "head") {
|
||||
return "head";
|
||||
}
|
||||
if (tagName === "body") {
|
||||
return "body";
|
||||
}
|
||||
|
||||
// We might be able to find a unique class name
|
||||
let selector, index, matches;
|
||||
if (ele.classList.length > 0) {
|
||||
for (let i = 0; i < ele.classList.length; i++) {
|
||||
// Is this className unique by itself?
|
||||
selector = "." + cssEscape(ele.classList.item(i));
|
||||
matches = document.querySelectorAll(selector);
|
||||
if (matches.length === 1) {
|
||||
return selector;
|
||||
}
|
||||
// Maybe it's unique with a tag name?
|
||||
selector = tagName + selector;
|
||||
matches = document.querySelectorAll(selector);
|
||||
if (matches.length === 1) {
|
||||
return selector;
|
||||
}
|
||||
// Maybe it's unique using a tag name and nth-child
|
||||
index = positionInNodeList(ele, ele.parentNode.children) + 1;
|
||||
selector = selector + ":nth-child(" + index + ")";
|
||||
matches = document.querySelectorAll(selector);
|
||||
if (matches.length === 1) {
|
||||
return selector;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not unique enough yet. As long as it's not a child of the document,
|
||||
// continue recursing up until it is unique enough.
|
||||
if (ele.parentNode !== document) {
|
||||
index = positionInNodeList(ele, ele.parentNode.children) + 1;
|
||||
selector = findCssSelector(ele.parentNode) + " > " +
|
||||
tagName + ":nth-child(" + index + ")";
|
||||
}
|
||||
|
||||
return selector;
|
||||
}
|
@ -183,6 +183,7 @@ EXTRA_JS_MODULES += [
|
||||
'ClientID.jsm',
|
||||
'Color.jsm',
|
||||
'Console.jsm',
|
||||
'css-selector.js',
|
||||
'DateTimePickerHelper.jsm',
|
||||
'debug.js',
|
||||
'DeferredTask.jsm',
|
||||
|
@ -1,3 +1,4 @@
|
||||
[DEFAULT]
|
||||
|
||||
[test_bug544442_checkCert.xul]
|
||||
[test_findCssSelector.html]
|
@ -12,8 +12,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=
|
||||
<script type="application/javascript">
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
let { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const CssLogic = require("devtools/shared/inspector/css-logic");
|
||||
/* globals findCssSelector */
|
||||
Cu.import("resource://gre/modules/css-selector.js", this);
|
||||
|
||||
var _tests = [];
|
||||
function addTest(test) {
|
||||
@ -34,13 +34,13 @@ window.onload = function() {
|
||||
}
|
||||
|
||||
addTest(function findAllCssSelectors() {
|
||||
var nodes = document.querySelectorAll('*');
|
||||
var nodes = document.querySelectorAll("*");
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
var selector = CssLogic.findCssSelector(nodes[i]);
|
||||
var selector = findCssSelector(nodes[i]);
|
||||
var matches = document.querySelectorAll(selector);
|
||||
|
||||
is(matches.length, 1, 'There is a single match: ' + selector);
|
||||
is(matches[0], nodes[i], 'The selector matches the correct node: ' + selector);
|
||||
is(matches.length, 1, "There is a single match: " + selector);
|
||||
is(matches[0], nodes[i], "The selector matches the correct node: " + selector);
|
||||
}
|
||||
|
||||
runNextTest();
|
||||
@ -51,33 +51,33 @@ addTest(function findCssSelectorNotContainedInDocument() {
|
||||
var unattached = document.createElement("div");
|
||||
unattached.id = "unattached";
|
||||
try {
|
||||
CssLogic.findCssSelector(unattached);
|
||||
ok (false, "Unattached node did not throw")
|
||||
} catch(e) {
|
||||
findCssSelector(unattached);
|
||||
ok(false, "Unattached node did not throw")
|
||||
} catch (e) {
|
||||
ok(e, "Unattached node throws an exception");
|
||||
}
|
||||
|
||||
var unattachedChild = document.createElement("div");
|
||||
unattached.appendChild(unattachedChild);
|
||||
try {
|
||||
CssLogic.findCssSelector(unattachedChild);
|
||||
ok (false, "Unattached child node did not throw")
|
||||
} catch(e) {
|
||||
findCssSelector(unattachedChild);
|
||||
ok(false, "Unattached child node did not throw")
|
||||
} catch (e) {
|
||||
ok(e, "Unattached child node throws an exception");
|
||||
}
|
||||
|
||||
var unattachedBody = document.createElement("body");
|
||||
try {
|
||||
CssLogic.findCssSelector(unattachedBody);
|
||||
ok (false, "Unattached body node did not throw")
|
||||
} catch(e) {
|
||||
findCssSelector(unattachedBody);
|
||||
ok(false, "Unattached body node did not throw")
|
||||
} catch (e) {
|
||||
ok(e, "Unattached body node throws an exception");
|
||||
}
|
||||
|
||||
runNextTest();
|
||||
});
|
||||
|
||||
addTest(function findCssSelector() {
|
||||
addTest(function findCssSelectorBasic() {
|
||||
|
||||
let data = [
|
||||
"#one",
|
||||
@ -97,11 +97,11 @@ addTest(function findCssSelector() {
|
||||
];
|
||||
|
||||
let container = document.querySelector("#find-css-selector");
|
||||
is (container.children.length, data.length, "Container has correct number of children.");
|
||||
is(container.children.length, data.length, "Container has correct number of children.");
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let node = container.children[i];
|
||||
is (CssLogic.findCssSelector(node), data[i], "matched id for index " + (i-1));
|
||||
is(findCssSelector(node), data[i], "matched id for index " + (i - 1));
|
||||
}
|
||||
|
||||
runNextTest();
|
Loading…
Reference in New Issue
Block a user