Commit 3acba91a authored by Joel Einbinder's avatar Joel Einbinder Committed by Commit Bot

DevTools: Add an option to copy element styles

Adds a `Copy styles` menuitem to DOM elements, which copies all active
user-authored styles of the element.

Change-Id: Id78e94eecb506393dfd20f2da4771ece3a72eddc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1665428
Commit-Queue: Joel Einbinder <einbinder@chromium.org>
Reviewed-by: default avatarErik Luo <luoe@chromium.org>
Cr-Commit-Position: refs/heads/master@{#672606}
parent 0328baf6
...@@ -526,6 +526,7 @@ Elements.ElementsTreeElement = class extends UI.TreeElement { ...@@ -526,6 +526,7 @@ Elements.ElementsTreeElement = class extends UI.TreeElement {
section.appendItem(Common.UIString('Copy selector'), this._copyCSSPath.bind(this)); section.appendItem(Common.UIString('Copy selector'), this._copyCSSPath.bind(this));
section.appendItem( section.appendItem(
Common.UIString('Copy JS path'), this._copyJSPath.bind(this), !Elements.DOMPath.canGetJSPath(this._node)); Common.UIString('Copy JS path'), this._copyJSPath.bind(this), !Elements.DOMPath.canGetJSPath(this._node));
section.appendItem(ls`Copy styles`, this._copyStyles.bind(this));
} }
if (!isShadowRoot) { if (!isShadowRoot) {
section.appendItem(Common.UIString('Copy XPath'), this._copyXPath.bind(this)); section.appendItem(Common.UIString('Copy XPath'), this._copyXPath.bind(this));
...@@ -1641,6 +1642,30 @@ Elements.ElementsTreeElement = class extends UI.TreeElement { ...@@ -1641,6 +1642,30 @@ Elements.ElementsTreeElement = class extends UI.TreeElement {
InspectorFrontendHost.copyText(Elements.DOMPath.xPath(this._node, false)); InspectorFrontendHost.copyText(Elements.DOMPath.xPath(this._node, false));
} }
async _copyStyles() {
const node = this._node;
const cssModel = node.domModel().cssModel();
const cascade = await cssModel.cachedMatchedCascadeForNode(node);
if (!cascade)
return;
/** @type {!Array<string>} */
const lines = [];
for (const style of cascade.nodeStyles().reverse()) {
for (const property of style.leadingProperties()) {
if (!property.parsedOk || property.disabled || !property.activeInStyle() || property.implicit)
continue;
if (cascade.isInherited(style) && !SDK.cssMetadata().isPropertyInherited(property.name))
continue;
if (style.parentRule && style.parentRule.isUserAgent())
continue;
if (cascade.propertyState(property) !== SDK.CSSMatchedStyles.PropertyState.Active)
continue;
lines.push(`${property.name}: ${property.value};`);
}
}
InspectorFrontendHost.copyText(lines.join('\n'));
}
_highlightSearchResults() { _highlightSearchResults() {
if (!this._searchQuery || !this._searchHighlightsVisible) if (!this._searchQuery || !this._searchHighlightsVisible)
return; return;
......
...@@ -99,6 +99,9 @@ ...@@ -99,6 +99,9 @@
<message name="IDS_DEVTOOLS_4757fe07fd492a8be0ea6a760d683d6e" desc=""> <message name="IDS_DEVTOOLS_4757fe07fd492a8be0ea6a760d683d6e" desc="">
position position
</message> </message>
<message name="IDS_DEVTOOLS_4a27b8d01ae86c80074e4c57be48f8c6" desc="">
Copy styles
</message>
<message name="IDS_DEVTOOLS_4c1c7d945fcd04d68bd3b3f1d99a55a1" desc=""> <message name="IDS_DEVTOOLS_4c1c7d945fcd04d68bd3b3f1d99a55a1" desc="">
Styles Styles
</message> </message>
......
Tests node xPath construction
<html>​
InspectorFrontendHost.copyText:
<head>​
InspectorFrontendHost.copyText:
<style>​
InspectorFrontendHost.copyText:
button {
color: red;
}
body {
border: 1px solid black;
font-weight: bold;
}
<body>​
InspectorFrontendHost.copyText:
border: 1px solid black;
font-weight: bold;
<div style=​"padding:​ 5px">​ Hello ​</div>​
InspectorFrontendHost.copyText:
font-weight: bold;
padding: 5px;
<button>​ A red button ​</button>​
InspectorFrontendHost.copyText:
color: red;
<button style=​"color:​ green">​ A green button ​</button>​
InspectorFrontendHost.copyText:
color: green;
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(async function() {
TestRunner.addResult(`Tests node xPath construction\n`);
await TestRunner.loadModule('elements_test_runner');
await TestRunner.showPanel('elements');
await TestRunner.loadHTML(`
<style>
button {
color: red;
}
body {
border: 1px solid black;
font-weight: bold;
}
</style>
<div style="padding: 5px"> Hello </div>
<button> A red button </button>
<button style="color: green"> A green button </button>
`);
InspectorFrontendHost.copyText = text => {
TestRunner.addResult('InspectorFrontendHost.copyText:\n' + text)
};
await new Promise(x => ElementsTestRunner.expandElementsTree(x));
const element = ElementsTestRunner.firstElementsTreeOutline().rootElement();
await processElement(element);
TestRunner.completeTest();
async function processElement(element) {
if (element instanceof Elements.ElementsTreeElement && !element.isClosingTag() && element.node().nodeNameInCorrectCase() !== 'base') {
TestRunner.addResult('\n' + element.listItemElement.textContent);
await element._copyStyles();
}
for (const child of element.children()) {
await processElement(child);
}
}
})();
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment