When I try to use the CSS.toggleProperty method defined in the Chrome Debugger Protocol Viewer docs, I get an error:
>>> CSS.toggleProperty({ 'styleId': { 'styleSheetId': '56219.1', 'ordinal': 1 }, 'propertyIndex': 1, 'disable': true })
TypeError: CSS.toggleProperty is not a function
at repl:1:5
at REPLServer.defaultEval (repl.js:250:27)
at bound (domain.js:280:14)
at REPLServer.runBound [as eval] (domain.js:293:12)
at REPLServer.<anonymous> (repl.js:412:12)
at emitOne (events.js:82:20)
at REPLServer.emit (events.js:169:7)
at REPLServer.Interface._onLine (readline.js:210:10)
at REPLServer.Interface._line (readline.js:549:8)
at REPLServer.Interface._ttyWrite (readline.js:826:14)
The same happens for DOM.setInspectModeEnabled.
>>> DOM.setInspectModeEnabled({ 'enabled': true })
TypeError: DOM.setInspectModeEnabled is not a function
at repl:1:5
at REPLServer.defaultEval (repl.js:250:27)
at bound (domain.js:280:14)
at REPLServer.runBound [as eval] (domain.js:293:12)
at REPLServer.<anonymous> (repl.js:412:12)
at emitOne (events.js:82:20)
at REPLServer.emit (events.js:169:7)
at REPLServer.Interface._onLine (readline.js:210:10)
at REPLServer.Interface._line (readline.js:549:8)
at REPLServer.Interface._ttyWrite (readline.js:826:14)
Looks like both of these methods have changed now.. The 1.1 isn't well supported unfortunately, so you'll have to use the tot protocol.
CSS.togglePropertyI'm not sure what your usecase is, but this is a bit harder now. AFAICT, it now looks something like this:
var ruleEdit = {
styleSheetId: "28841.6",
range: {
startLine: 0,
startColumn: 7990,
endLine: 0,
endColumn: 8060
},
// this edit toggles off the font-size property
text: "display:block;/* font-size:14px; */margin:16px 0;padding:12px 24px 12px 60px;"
};
CSS.setStyleTexts({edits: [ruleEdit]});
DOM.setInspectModeEnabledI think you'll want to use this now:
DOM.setInspectMode({mode: 'searchForNode'})
// ...
DOM.setInspectMode({mode: 'none'})
cc @aslushnikov to verify
Thanks! I sniffed the protocol to try and figure out what was happening. Am I correct that the range object in the CSS.setStyleTexts response reflects the updated stylesheet range, including the additional /* ... */? Should I just regex the comments out to restore the property?
Also, does this mean the CSSStyleId type is now deprecated? I was confused about the difference between CSSStyleId.ordinal and propertyIndex, but I guess that's a moot distinction now that stylesheet text ranges seem to be the preferred method of indexing.
@sarahlim as a side note you should have noticed that there is no completion available for those methods; this is a quick way to figure out what is available in the currently used protocol.
$ chrome-remote-interface inspect uses the protocol.json bundled with this module by default. But since 195d6fd9d25389e3f170426c04489f47fe7742ca you can use the --remote option to fetch the updated tip-of-tree protocol. The same goes for the API.
@cyrus-and yup, thanks! I misunderstood and thought I could use the 1.1 protocol by importing my own protocol.json, which got autocompletions to work, but the methods still weren't found when I tried to actually invoke them. Looks from @paulirish's answer that it's just a lack of support for 1.1 in general. Thanks to both of you!
@sarahlim you're welcome! So I'm closing this, feel free to continue the discussion if you need though.
@sarahlim yes, the CSS domain in 1.1 is not supported; we moved to textrange-based editing operations since then. And yes, @paulirish was perfectly correct in showcasing the new approach :)
While I have the chance to ask --
Page.loadEventFired(close); line means in the API usage demo. I can't seem to find documentation for Page.loadEventFired taking a callback -- does this mean that the protocol disconnects after the page loads?Is it possible to instrument full-page screenshots via the tot protocol?
Yup, using Page.captureScreenshot. There's a nice usage example here. Not sure about the _full-page_ part, though.
I can't seem to find documentation for Page.loadEventFired taking a callback -- does this mean that the protocol disconnects after the page loads?
Yes exactly, but that was just for the sake of the example. Strictly speaking no protocol method/event takes a callback as an argument; only JSON data can be exchanged with Chrome. Callbacks are used by this module to report the outcome of method invocations and events.
Basically Page.loadEventFired(close) is equivalent to:
chrome.on('Page.loadEventFired', (params) => {
chrome.close();
});
@paulirish @aslushnikov I keep getting the following error when I try to use CSS.setStyleTexts:
{ code: -32000,
message: 'Failed applying edit #0: NotFoundError Source range didn\'t match existing style source range' }
Any ideas? When I log the result of CSS.getStyleSheetText at the substring specified by my range field, it looks correct to me.
@sarahlim since I'm reading this anyway, here's my two cents...
The fact is that figuring out the proper source range can be tricky and AFAIK there is no protocol method that aids you in figuring out the range given a CSS rule selector; you need to first walk the matched CSS rules for a given a NodeId with CSS.getMatchedStylesForNode. Which seems to be what DevTools does when you toggle the checkbox of a CSS rule (if you inspect its WebSocket).
I don't know about your use case, but another approach would be: fetch the whole style sheet text with CSS.getStyleSheetText, perform the desired modifications and replace the original one with CSS.setStyleSheetText.
@sarahlim which range are you sending? The style range should start right after the rule's { and end before rule's ending }.
here's the inspector-protocol test which exercises this method: link
@cyrus-and sorry to bring this thread back up again! I don't think I understand how the DOM.setChildNodes event works. I'm trying to recursively walk a subtree of the DOM and manipulate CSS style rules on each descendant element, and I'm not sure how to implement this using the event interface for requesting children. Is there an example or test somewhere that would clarify this?
@sarahlim no worries! Feel free to drop me an email if this is going off-topic.
The most straightforward way to obtain the (full) DOM tree should be DOM.getDocument:
chrome.DOM.getDocument({depth: -1}, (error, response) => {
const tree = response.root;
console.log(JSON.stringify(tree, null, 4));
});
You can just walk root and apply your CSS modifications only for those nodes which satisfy some condition.
I cannot really try this one because my version of Chrome (54) does not support the depth option of DOM.getDocument (you can test it with chrome-remote-interface inspect -r).
Otherwise you may want to fetch the root of your subtree using a selector with DOM.querySelector, you'll need a starting nodeId, you can use DOM.getDocument to obtain the root node id (it seems that you really have to call this method, i.e., you cannot guess it, see #37):
chrome.DOM.setChildNodes((params) => {
const parentId = params.parentId;
const nodes = params.nodes;
console.log('---', parentId);
console.log(JSON.stringify(nodes, null, 4));
});
chrome.DOM.getDocument((error, response) => {
const rootNodeId = response.root.nodeId;
const options = {
nodeId: rootNodeId,
selector: 'body' // <-- your selector here
};
chrome.DOM.querySelector(options, (error, response) => {
const nodeId = response.nodeId;
chrome.DOM.requestChildNodes({nodeId: nodeId, depth: -1});
});
});
Note that DOM.setChildNodes can be triggered more than once, I guess you'll have to perform some consolidation.
[cc @paulirish]
I noticed some weird behaviors though, some nodes are consistently missing, i.e., childNodeCount is correct but there is no children field. Also sometimes just a couple of nodes are returned.