2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * @extends {WebInspector.SDKModel}
34 * @param {!WebInspector.Target} target
36 WebInspector.CSSStyleModel = function(target)
38 WebInspector.SDKModel.call(this, WebInspector.CSSStyleModel, target);
39 this._domModel = target.domModel;
40 this._agent = target.cssAgent();
41 this._pendingCommandsMajorState = [];
42 this._styleLoader = new WebInspector.CSSStyleModel.ComputedStyleLoader(this);
43 this._domModel.addEventListener(WebInspector.DOMModel.Events.UndoRedoRequested, this._undoRedoRequested, this);
44 this._domModel.addEventListener(WebInspector.DOMModel.Events.UndoRedoCompleted, this._undoRedoCompleted, this);
45 target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameNavigated, this);
46 target.registerCSSDispatcher(new WebInspector.CSSDispatcher(this));
47 this._agent.enable(this._wasEnabled.bind(this));
48 /** @type {!Map.<string, !WebInspector.CSSStyleSheetHeader>} */
49 this._styleSheetIdToHeader = new Map();
50 /** @type {!Map.<string, !Object.<!PageAgent.FrameId, !Array.<!CSSAgent.StyleSheetId>>>} */
51 this._styleSheetIdsForURL = new Map();
54 WebInspector.CSSStyleModel.PseudoStatePropertyName = "pseudoState";
57 * @param {!WebInspector.CSSStyleModel} cssModel
58 * @param {!Array.<!CSSAgent.RuleMatch>|undefined} matchArray
59 * @return {!Array.<!WebInspector.CSSRule>}
61 WebInspector.CSSStyleModel.parseRuleMatchArrayPayload = function(cssModel, matchArray)
67 for (var i = 0; i < matchArray.length; ++i)
68 result.push(WebInspector.CSSRule.parsePayload(cssModel, matchArray[i].rule, matchArray[i].matchingSelectors));
72 WebInspector.CSSStyleModel.Events = {
73 ModelWasEnabled: "ModelWasEnabled",
74 StyleSheetAdded: "StyleSheetAdded",
75 StyleSheetChanged: "StyleSheetChanged",
76 StyleSheetRemoved: "StyleSheetRemoved",
77 MediaQueryResultChanged: "MediaQueryResultChanged",
80 WebInspector.CSSStyleModel.MediaTypes = ["all", "braille", "embossed", "handheld", "print", "projection", "screen", "speech", "tty", "tv"];
82 WebInspector.CSSStyleModel.prototype = {
83 suspendModel: function()
85 this._agent.disable();
86 this._isEnabled = false;
87 this._resetStyleSheets();
90 resumeModel: function()
92 this._agent.enable(this._wasEnabled.bind(this));
96 * @param {function(!Array.<!WebInspector.CSSMedia>)} userCallback
98 getMediaQueries: function(userCallback)
101 * @param {?Protocol.Error} error
102 * @param {?Array.<!CSSAgent.CSSMedia>} payload
103 * @this {!WebInspector.CSSStyleModel}
105 function callback(error, payload)
108 if (!error && payload)
109 models = WebInspector.CSSMedia.parseMediaArrayPayload(this, payload);
110 userCallback(models);
112 this._agent.getMediaQueries(callback.bind(this));
118 isEnabled: function()
120 return this._isEnabled;
123 _wasEnabled: function()
125 this._isEnabled = true;
126 this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.ModelWasEnabled);
130 * @param {!DOMAgent.NodeId} nodeId
131 * @param {boolean} excludePseudo
132 * @param {boolean} excludeInherited
133 * @param {function(?*)} userCallback
135 getMatchedStylesAsync: function(nodeId, excludePseudo, excludeInherited, userCallback)
138 * @param {function(?*)} userCallback
139 * @param {?Protocol.Error} error
140 * @param {!Array.<!CSSAgent.RuleMatch>=} matchedPayload
141 * @param {!Array.<!CSSAgent.PseudoIdMatches>=} pseudoPayload
142 * @param {!Array.<!CSSAgent.InheritedStyleEntry>=} inheritedPayload
143 * @this {WebInspector.CSSStyleModel}
145 function callback(userCallback, error, matchedPayload, pseudoPayload, inheritedPayload)
154 result.matchedCSSRules = WebInspector.CSSStyleModel.parseRuleMatchArrayPayload(this, matchedPayload);
156 result.pseudoElements = [];
158 for (var i = 0; i < pseudoPayload.length; ++i) {
159 var entryPayload = pseudoPayload[i];
160 result.pseudoElements.push({ pseudoId: entryPayload.pseudoId, rules: WebInspector.CSSStyleModel.parseRuleMatchArrayPayload(this, entryPayload.matches) });
164 result.inherited = [];
165 if (inheritedPayload) {
166 for (var i = 0; i < inheritedPayload.length; ++i) {
167 var entryPayload = inheritedPayload[i];
169 if (entryPayload.inlineStyle)
170 entry.inlineStyle = WebInspector.CSSStyleDeclaration.parsePayload(this, entryPayload.inlineStyle);
171 if (entryPayload.matchedCSSRules)
172 entry.matchedCSSRules = WebInspector.CSSStyleModel.parseRuleMatchArrayPayload(this, entryPayload.matchedCSSRules);
173 result.inherited.push(entry);
178 userCallback(result);
181 this._agent.getMatchedStylesForNode(nodeId, excludePseudo, excludeInherited, callback.bind(this, userCallback));
185 * @param {!DOMAgent.NodeId} nodeId
186 * @param {function(?WebInspector.CSSStyleDeclaration)} userCallback
188 getComputedStyleAsync: function(nodeId, userCallback)
190 this._styleLoader.getComputedStyle(nodeId, userCallback);
194 * @param {number} nodeId
195 * @param {function(?string, ?Array.<!CSSAgent.PlatformFontUsage>)} callback
197 getPlatformFontsForNode: function(nodeId, callback)
199 function platformFontsCallback(error, cssFamilyName, fonts)
202 callback(null, null);
204 callback(cssFamilyName, fonts);
206 this._agent.getPlatformFontsForNode(nodeId, platformFontsCallback);
210 * @return {!Array.<!WebInspector.CSSStyleSheetHeader>}
212 allStyleSheets: function()
214 var values = this._styleSheetIdToHeader.valuesArray();
216 * @param {!WebInspector.CSSStyleSheetHeader} a
217 * @param {!WebInspector.CSSStyleSheetHeader} b
220 function styleSheetComparator(a, b)
222 if (a.sourceURL < b.sourceURL)
224 else if (a.sourceURL > b.sourceURL)
226 return a.startLine - b.startLine || a.startColumn - b.startColumn;
228 values.sort(styleSheetComparator);
234 * @param {!DOMAgent.NodeId} nodeId
235 * @param {function(?WebInspector.CSSStyleDeclaration, ?WebInspector.CSSStyleDeclaration)} userCallback
237 getInlineStylesAsync: function(nodeId, userCallback)
240 * @param {function(?WebInspector.CSSStyleDeclaration, ?WebInspector.CSSStyleDeclaration)} userCallback
241 * @param {?Protocol.Error} error
242 * @param {?CSSAgent.CSSStyle=} inlinePayload
243 * @param {?CSSAgent.CSSStyle=} attributesStylePayload
244 * @this {WebInspector.CSSStyleModel}
246 function callback(userCallback, error, inlinePayload, attributesStylePayload)
248 if (error || !inlinePayload)
249 userCallback(null, null);
251 userCallback(WebInspector.CSSStyleDeclaration.parsePayload(this, inlinePayload), attributesStylePayload ? WebInspector.CSSStyleDeclaration.parsePayload(this, attributesStylePayload) : null);
254 this._agent.getInlineStylesForNode(nodeId, callback.bind(this, userCallback));
258 * @param {!WebInspector.DOMNode} node
259 * @param {string} pseudoClass
260 * @param {boolean} enable
263 forcePseudoState: function(node, pseudoClass, enable)
265 var pseudoClasses = node.getUserProperty(WebInspector.CSSStyleModel.PseudoStatePropertyName) || [];
267 if (pseudoClasses.indexOf(pseudoClass) >= 0)
269 pseudoClasses.push(pseudoClass);
270 node.setUserProperty(WebInspector.CSSStyleModel.PseudoStatePropertyName, pseudoClasses);
272 if (pseudoClasses.indexOf(pseudoClass) < 0)
274 pseudoClasses.remove(pseudoClass);
275 if (!pseudoClasses.length)
276 node.removeUserProperty(WebInspector.CSSStyleModel.PseudoStatePropertyName);
279 this._agent.forcePseudoState(node.id, pseudoClasses);
284 * @param {!CSSAgent.CSSRule} rule
285 * @param {!DOMAgent.NodeId} nodeId
286 * @param {string} newSelector
287 * @param {function(!WebInspector.CSSRule)} successCallback
288 * @param {function()} failureCallback
290 setRuleSelector: function(rule, nodeId, newSelector, successCallback, failureCallback)
293 * @param {!DOMAgent.NodeId} nodeId
294 * @param {function(!WebInspector.CSSRule)} successCallback
295 * @param {function()} failureCallback
296 * @param {?Protocol.Error} error
297 * @param {string} newSelector
298 * @param {!CSSAgent.CSSRule} rulePayload
299 * @this {WebInspector.CSSStyleModel}
301 function callback(nodeId, successCallback, failureCallback, newSelector, error, rulePayload)
303 this._pendingCommandsMajorState.pop();
308 this._domModel.markUndoableState();
309 this._computeMatchingSelectors(rulePayload, nodeId, successCallback, failureCallback);
312 if (!rule.styleSheetId)
313 throw "No rule stylesheet id";
314 this._pendingCommandsMajorState.push(true);
315 this._agent.setRuleSelector(rule.styleSheetId, rule.selectorRange, newSelector, callback.bind(this, nodeId, successCallback, failureCallback, newSelector));
319 * @param {!CSSAgent.CSSRule} rulePayload
320 * @param {!DOMAgent.NodeId} nodeId
321 * @param {function(!WebInspector.CSSRule)} successCallback
322 * @param {function()} failureCallback
324 _computeMatchingSelectors: function(rulePayload, nodeId, successCallback, failureCallback)
326 var ownerDocumentId = this._ownerDocumentId(nodeId);
327 if (!ownerDocumentId) {
331 var rule = WebInspector.CSSRule.parsePayload(this, rulePayload);
332 var matchingSelectors = [];
333 var allSelectorsBarrier = new CallbackBarrier();
334 for (var i = 0; i < rule.selectors.length; ++i) {
335 var selector = rule.selectors[i];
336 var boundCallback = allSelectorsBarrier.createCallback(selectorQueried.bind(null, i, nodeId, matchingSelectors));
337 this._domModel.querySelectorAll(ownerDocumentId, selector.value, boundCallback);
339 allSelectorsBarrier.callWhenDone(function() {
340 rule.matchingSelectors = matchingSelectors;
341 successCallback(rule);
345 * @param {number} index
346 * @param {!DOMAgent.NodeId} nodeId
347 * @param {!Array.<number>} matchingSelectors
348 * @param {!Array.<!DOMAgent.NodeId>=} matchingNodeIds
350 function selectorQueried(index, nodeId, matchingSelectors, matchingNodeIds)
352 if (!matchingNodeIds)
354 if (matchingNodeIds.indexOf(nodeId) !== -1)
355 matchingSelectors.push(index);
360 * @param {!CSSAgent.StyleSheetId} styleSheetId
361 * @param {!WebInspector.DOMNode} node
362 * @param {string} ruleText
363 * @param {!WebInspector.TextRange} ruleLocation
364 * @param {function(!WebInspector.CSSRule)} successCallback
365 * @param {function()} failureCallback
367 addRule: function(styleSheetId, node, ruleText, ruleLocation, successCallback, failureCallback)
369 this._pendingCommandsMajorState.push(true);
370 this._agent.addRule(styleSheetId, ruleText, ruleLocation, callback.bind(this));
373 * @param {?Protocol.Error} error
374 * @param {!CSSAgent.CSSRule} rulePayload
375 * @this {WebInspector.CSSStyleModel}
377 function callback(error, rulePayload)
379 this._pendingCommandsMajorState.pop();
381 // Invalid syntax for a selector
384 this._domModel.markUndoableState();
385 this._computeMatchingSelectors(rulePayload, node.id, successCallback, failureCallback);
391 * @param {!WebInspector.DOMNode} node
392 * @param {function(?WebInspector.CSSStyleSheetHeader)} callback
394 requestViaInspectorStylesheet: function(node, callback)
396 var frameId = node.frameId() || this.target().resourceTreeModel.mainFrame.id;
397 var headers = this._styleSheetIdToHeader.valuesArray();
398 for (var i = 0; i < headers.length; ++i) {
399 var styleSheetHeader = headers[i];
400 if (styleSheetHeader.frameId === frameId && styleSheetHeader.isViaInspector()) {
401 callback(styleSheetHeader);
407 * @this {WebInspector.CSSStyleModel}
408 * @param {?Protocol.Error} error
409 * @param {!CSSAgent.StyleSheetId} styleSheetId
411 function innerCallback(error, styleSheetId)
414 console.error(error);
418 callback(this._styleSheetIdToHeader.get(styleSheetId) || null);
421 this._agent.createStyleSheet(frameId, innerCallback.bind(this));
424 mediaQueryResultChanged: function()
426 this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.MediaQueryResultChanged);
430 * @param {!CSSAgent.StyleSheetId} id
431 * @return {?WebInspector.CSSStyleSheetHeader}
433 styleSheetHeaderForId: function(id)
435 return this._styleSheetIdToHeader.get(id) || null;
439 * @return {!Array.<!WebInspector.CSSStyleSheetHeader>}
441 styleSheetHeaders: function()
443 return this._styleSheetIdToHeader.valuesArray();
447 * @param {!DOMAgent.NodeId} nodeId
448 * @return {?DOMAgent.NodeId}
450 _ownerDocumentId: function(nodeId)
452 var node = this._domModel.nodeForId(nodeId);
455 return node.ownerDocument ? node.ownerDocument.id : null;
459 * @param {!CSSAgent.StyleSheetId} styleSheetId
461 _fireStyleSheetChanged: function(styleSheetId)
463 if (!this._pendingCommandsMajorState.length)
466 var majorChange = this._pendingCommandsMajorState[this._pendingCommandsMajorState.length - 1];
468 if (!styleSheetId || !this.hasEventListeners(WebInspector.CSSStyleModel.Events.StyleSheetChanged))
471 this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetChanged, { styleSheetId: styleSheetId, majorChange: majorChange });
475 * @param {!CSSAgent.CSSStyleSheetHeader} header
477 _styleSheetAdded: function(header)
479 console.assert(!this._styleSheetIdToHeader.get(header.styleSheetId));
480 var styleSheetHeader = new WebInspector.CSSStyleSheetHeader(this, header);
481 this._styleSheetIdToHeader.set(header.styleSheetId, styleSheetHeader);
482 var url = styleSheetHeader.resourceURL();
483 if (!this._styleSheetIdsForURL.get(url))
484 this._styleSheetIdsForURL.set(url, {});
485 var frameIdToStyleSheetIds = this._styleSheetIdsForURL.get(url);
486 var styleSheetIds = frameIdToStyleSheetIds[styleSheetHeader.frameId];
487 if (!styleSheetIds) {
489 frameIdToStyleSheetIds[styleSheetHeader.frameId] = styleSheetIds;
491 styleSheetIds.push(styleSheetHeader.id);
492 this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetAdded, styleSheetHeader);
496 * @param {!CSSAgent.StyleSheetId} id
498 _styleSheetRemoved: function(id)
500 var header = this._styleSheetIdToHeader.get(id);
501 console.assert(header);
504 this._styleSheetIdToHeader.remove(id);
505 var url = header.resourceURL();
506 var frameIdToStyleSheetIds = /** @type {!Object.<!PageAgent.FrameId, !Array.<!CSSAgent.StyleSheetId>>} */ (this._styleSheetIdsForURL.get(url));
507 console.assert(frameIdToStyleSheetIds, "No frameId to styleSheetId map is available for given style sheet URL.");
508 frameIdToStyleSheetIds[header.frameId].remove(id);
509 if (!frameIdToStyleSheetIds[header.frameId].length) {
510 delete frameIdToStyleSheetIds[header.frameId];
511 if (!Object.keys(frameIdToStyleSheetIds).length)
512 this._styleSheetIdsForURL.remove(url);
514 this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, header);
518 * @param {string} url
519 * @return {!Array.<!CSSAgent.StyleSheetId>}
521 styleSheetIdsForURL: function(url)
523 var frameIdToStyleSheetIds = this._styleSheetIdsForURL.get(url);
524 if (!frameIdToStyleSheetIds)
528 for (var frameId in frameIdToStyleSheetIds)
529 result = result.concat(frameIdToStyleSheetIds[frameId]);
534 * @param {string} url
535 * @return {!Object.<!PageAgent.FrameId, !Array.<!CSSAgent.StyleSheetId>>}
537 styleSheetIdsByFrameIdForURL: function(url)
539 var styleSheetIdsForFrame = this._styleSheetIdsForURL.get(url);
540 if (!styleSheetIdsForFrame)
542 return styleSheetIdsForFrame;
546 * @param {!CSSAgent.StyleSheetId} styleSheetId
547 * @param {string} newText
548 * @param {boolean} majorChange
549 * @param {function(?Protocol.Error)} userCallback
551 setStyleSheetText: function(styleSheetId, newText, majorChange, userCallback)
553 var header = this._styleSheetIdToHeader.get(styleSheetId);
554 console.assert(header);
555 this._pendingCommandsMajorState.push(majorChange);
556 header.setContent(newText, callback.bind(this));
559 * @param {?Protocol.Error} error
560 * @this {WebInspector.CSSStyleModel}
562 function callback(error)
564 this._pendingCommandsMajorState.pop();
565 if (!error && majorChange)
566 this._domModel.markUndoableState();
568 if (!error && userCallback)
573 _undoRedoRequested: function()
575 this._pendingCommandsMajorState.push(true);
578 _undoRedoCompleted: function()
580 this._pendingCommandsMajorState.pop();
583 _mainFrameNavigated: function()
585 this._resetStyleSheets();
588 _resetStyleSheets: function()
590 var headers = this._styleSheetIdToHeader.valuesArray();
591 this._styleSheetIdsForURL.clear();
592 this._styleSheetIdToHeader.clear();
593 for (var i = 0; i < headers.length; ++i)
594 this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, headers[i]);
597 __proto__: WebInspector.SDKModel.prototype
602 * @extends {WebInspector.SDKObject}
603 * @param {!WebInspector.Target} target
604 * @param {?CSSAgent.StyleSheetId} styleSheetId
605 * @param {string} url
606 * @param {number} lineNumber
607 * @param {number=} columnNumber
609 WebInspector.CSSLocation = function(target, styleSheetId, url, lineNumber, columnNumber)
611 WebInspector.SDKObject.call(this, target);
612 this.styleSheetId = styleSheetId;
614 this.lineNumber = lineNumber;
615 this.columnNumber = columnNumber || 0;
618 WebInspector.CSSLocation.prototype = {
619 __proto__: WebInspector.SDKObject.prototype
624 * @param {!WebInspector.CSSStyleModel} cssModel
625 * @param {!CSSAgent.CSSStyle} payload
627 WebInspector.CSSStyleDeclaration = function(cssModel, payload)
629 this._cssModel = cssModel;
630 this.styleSheetId = payload.styleSheetId;
631 this.range = payload.range ? WebInspector.TextRange.fromObject(payload.range) : null;
632 this._shorthandValues = WebInspector.CSSStyleDeclaration.buildShorthandValueMap(payload.shorthandEntries);
633 this._livePropertyMap = {}; // LIVE properties (source-based or style-based) : { name -> CSSProperty }
634 this._allProperties = []; // ALL properties: [ CSSProperty ]
635 this.__disabledProperties = {}; // DISABLED properties: { index -> CSSProperty }
636 var payloadPropertyCount = payload.cssProperties.length;
639 for (var i = 0; i < payloadPropertyCount; ++i) {
640 var property = WebInspector.CSSProperty.parsePayload(this, i, payload.cssProperties[i]);
641 this._allProperties.push(property);
644 this._computeActiveProperties();
646 var propertyIndex = 0;
647 for (var i = 0; i < this._allProperties.length; ++i) {
648 var property = this._allProperties[i];
649 if (property.disabled)
650 this.__disabledProperties[i] = property;
651 if (!property.active && !property.styleBased)
653 var name = property.name;
654 this[propertyIndex] = name;
655 this._livePropertyMap[name] = property;
658 this.length = propertyIndex;
659 if ("cssText" in payload)
660 this.cssText = payload.cssText;
664 * @param {!Array.<!CSSAgent.ShorthandEntry>} shorthandEntries
667 WebInspector.CSSStyleDeclaration.buildShorthandValueMap = function(shorthandEntries)
670 for (var i = 0; i < shorthandEntries.length; ++i)
671 result[shorthandEntries[i].name] = shorthandEntries[i].value;
676 * @param {!WebInspector.CSSStyleModel} cssModel
677 * @param {!CSSAgent.CSSStyle} payload
678 * @return {!WebInspector.CSSStyleDeclaration}
680 WebInspector.CSSStyleDeclaration.parsePayload = function(cssModel, payload)
682 return new WebInspector.CSSStyleDeclaration(cssModel, payload);
686 * @param {!WebInspector.CSSStyleModel} cssModel
687 * @param {!Array.<!CSSAgent.CSSComputedStyleProperty>} payload
688 * @return {!WebInspector.CSSStyleDeclaration}
690 WebInspector.CSSStyleDeclaration.parseComputedStylePayload = function(cssModel, payload)
692 var newPayload = /** @type {!CSSAgent.CSSStyle} */ ({ cssProperties: [], shorthandEntries: [], width: "", height: "" });
694 newPayload.cssProperties = /** @type {!Array.<!CSSAgent.CSSProperty>} */ (payload);
696 return new WebInspector.CSSStyleDeclaration(cssModel, newPayload);
699 WebInspector.CSSStyleDeclaration.prototype = {
701 * @return {!WebInspector.Target}
705 return this._cssModel.target();
709 * @param {string} styleSheetId
710 * @param {!WebInspector.TextRange} oldRange
711 * @param {!WebInspector.TextRange} newRange
713 sourceStyleSheetEdited: function(styleSheetId, oldRange, newRange)
715 if (this.styleSheetId !== styleSheetId)
718 this.range = this.range.rebaseAfterTextEdit(oldRange, newRange);
719 for (var i = 0; i < this._allProperties.length; ++i)
720 this._allProperties[i].sourceStyleSheetEdited(styleSheetId, oldRange, newRange);
723 _computeActiveProperties: function()
725 var activeProperties = {};
726 for (var i = this._allProperties.length - 1; i >= 0; --i) {
727 var property = this._allProperties[i];
728 if (property.styleBased || property.disabled)
730 property._setActive(false);
731 if (!property.parsedOk)
733 var canonicalName = WebInspector.CSSMetadata.canonicalPropertyName(property.name);
734 var activeProperty = activeProperties[canonicalName];
735 if (!activeProperty || (!activeProperty.important && property.important))
736 activeProperties[canonicalName] = property;
738 for (var propertyName in activeProperties) {
739 var property = activeProperties[propertyName];
740 property._setActive(true);
746 return this._allProperties;
750 * @param {string} name
751 * @return {?WebInspector.CSSProperty}
753 getLiveProperty: function(name)
755 return this._livePropertyMap[name] || null;
759 * @param {string} name
762 getPropertyValue: function(name)
764 var property = this._livePropertyMap[name];
765 return property ? property.value : "";
769 * @param {string} name
772 isPropertyImplicit: function(name)
774 var property = this._livePropertyMap[name];
775 return property ? property.implicit : "";
779 * @param {string} name
780 * @return {!Array.<!WebInspector.CSSProperty>}
782 longhandProperties: function(name)
784 var longhands = WebInspector.CSSMetadata.cssPropertiesMetainfo.longhands(name);
786 for (var i = 0; longhands && i < longhands.length; ++i) {
787 var property = this._livePropertyMap[longhands[i]];
789 result.push(property);
795 * @param {string} shorthandProperty
798 shorthandValue: function(shorthandProperty)
800 return this._shorthandValues[shorthandProperty];
804 * @param {number} index
805 * @return {?WebInspector.CSSProperty}
807 propertyAt: function(index)
809 return (index < this.allProperties.length) ? this.allProperties[index] : null;
815 pastLastSourcePropertyIndex: function()
817 for (var i = this.allProperties.length - 1; i >= 0; --i) {
818 if (this.allProperties[i].range)
825 * @param {number} index
826 * @return {!WebInspector.TextRange}
828 _insertionRange: function(index)
830 var property = this.propertyAt(index);
831 return property && property.range ? property.range.collapseToStart() : this.range.collapseToEnd();
835 * @param {number=} index
836 * @return {!WebInspector.CSSProperty}
838 newBlankProperty: function(index)
840 index = (typeof index === "undefined") ? this.pastLastSourcePropertyIndex() : index;
841 var property = new WebInspector.CSSProperty(this, index, "", "", false, false, true, false, "", this._insertionRange(index));
842 property._setActive(true);
847 * @param {number} index
848 * @param {string} name
849 * @param {string} value
850 * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
852 insertPropertyAt: function(index, name, value, userCallback)
855 * @param {?string} error
856 * @param {!CSSAgent.CSSStyle} payload
857 * @this {!WebInspector.CSSStyleDeclaration}
859 function callback(error, payload)
861 this._cssModel._pendingCommandsMajorState.pop();
866 console.error(error);
869 userCallback(WebInspector.CSSStyleDeclaration.parsePayload(this._cssModel, payload));
872 if (!this.styleSheetId)
873 throw "No stylesheet id";
875 this._cssModel._pendingCommandsMajorState.push(true);
876 this._cssModel._agent.setPropertyText(this.styleSheetId, this._insertionRange(index), name + ": " + value + ";", callback.bind(this));
880 * @param {string} name
881 * @param {string} value
882 * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
884 appendProperty: function(name, value, userCallback)
886 this.insertPropertyAt(this.allProperties.length, name, value, userCallback);
892 * @param {!CSSAgent.Selector} payload
894 WebInspector.CSSRuleSelector = function(payload)
896 this.value = payload.value;
898 this.range = WebInspector.TextRange.fromObject(payload.range);
902 * @param {!CSSAgent.Selector} payload
903 * @return {!WebInspector.CSSRuleSelector}
905 WebInspector.CSSRuleSelector.parsePayload = function(payload)
907 return new WebInspector.CSSRuleSelector(payload)
910 WebInspector.CSSRuleSelector.prototype = {
912 * @param {!WebInspector.TextRange} oldRange
913 * @param {!WebInspector.TextRange} newRange
915 sourceStyleRuleEdited: function(oldRange, newRange)
919 this.range = this.range.rebaseAfterTextEdit(oldRange, newRange);
925 * @param {!WebInspector.CSSStyleModel} cssModel
926 * @param {!CSSAgent.CSSRule} payload
927 * @param {!Array.<number>=} matchingSelectors
929 WebInspector.CSSRule = function(cssModel, payload, matchingSelectors)
931 this._cssModel = cssModel;
932 this.styleSheetId = payload.styleSheetId;
933 if (matchingSelectors)
934 this.matchingSelectors = matchingSelectors;
936 /** @type {!Array.<!WebInspector.CSSRuleSelector>} */
938 for (var i = 0; i < payload.selectorList.selectors.length; ++i) {
939 var selectorPayload = payload.selectorList.selectors[i];
940 this.selectors.push(WebInspector.CSSRuleSelector.parsePayload(selectorPayload));
942 this.selectorText = this.selectors.select("value").join(", ");
944 var firstRange = this.selectors[0].range;
946 var lastRange = this.selectors.peekLast().range;
947 this.selectorRange = new WebInspector.TextRange(firstRange.startLine, firstRange.startColumn, lastRange.endLine, lastRange.endColumn);
949 if (this.styleSheetId) {
950 var styleSheetHeader = cssModel.styleSheetHeaderForId(this.styleSheetId);
951 this.sourceURL = styleSheetHeader.sourceURL;
953 this.origin = payload.origin;
954 this.style = WebInspector.CSSStyleDeclaration.parsePayload(this._cssModel, payload.style);
955 this.style.parentRule = this;
957 this.media = WebInspector.CSSMedia.parseMediaArrayPayload(cssModel, payload.media);
962 * @param {!WebInspector.CSSStyleModel} cssModel
963 * @param {!CSSAgent.CSSRule} payload
964 * @param {!Array.<number>=} matchingIndices
965 * @return {!WebInspector.CSSRule}
967 WebInspector.CSSRule.parsePayload = function(cssModel, payload, matchingIndices)
969 return new WebInspector.CSSRule(cssModel, payload, matchingIndices);
972 WebInspector.CSSRule.prototype = {
974 * @param {string} styleSheetId
975 * @param {!WebInspector.TextRange} oldRange
976 * @param {!WebInspector.TextRange} newRange
978 sourceStyleSheetEdited: function(styleSheetId, oldRange, newRange)
980 if (this.styleSheetId === styleSheetId) {
981 if (this.selectorRange)
982 this.selectorRange = this.selectorRange.rebaseAfterTextEdit(oldRange, newRange);
983 for (var i = 0; i < this.selectors.length; ++i)
984 this.selectors[i].sourceStyleRuleEdited(oldRange, newRange);
987 for (var i = 0; i < this.media.length; ++i)
988 this.media[i].sourceStyleSheetEdited(styleSheetId, oldRange, newRange);
990 this.style.sourceStyleSheetEdited(styleSheetId, oldRange, newRange);
993 _setFrameId: function()
995 if (!this.styleSheetId)
997 var styleSheetHeader = this._cssModel.styleSheetHeaderForId(this.styleSheetId);
998 this.frameId = styleSheetHeader.frameId;
1004 resourceURL: function()
1006 if (!this.styleSheetId)
1008 var styleSheetHeader = this._cssModel.styleSheetHeaderForId(this.styleSheetId);
1009 return styleSheetHeader.resourceURL();
1013 * @param {number} selectorIndex
1016 lineNumberInSource: function(selectorIndex)
1018 var selector = this.selectors[selectorIndex];
1019 if (!selector || !selector.range || !this.styleSheetId)
1021 var styleSheetHeader = this._cssModel.styleSheetHeaderForId(this.styleSheetId);
1022 return styleSheetHeader.lineNumberInSource(selector.range.startLine);
1026 * @param {number} selectorIndex
1027 * @return {number|undefined}
1029 columnNumberInSource: function(selectorIndex)
1031 var selector = this.selectors[selectorIndex];
1032 if (!selector || !selector.range || !this.styleSheetId)
1034 var styleSheetHeader = this._cssModel.styleSheetHeaderForId(this.styleSheetId);
1035 console.assert(styleSheetHeader);
1036 return styleSheetHeader.columnNumberInSource(selector.range.startLine, selector.range.startColumn);
1040 * @param {number} index
1041 * @return {!WebInspector.CSSLocation}
1043 rawSelectorLocation: function(index)
1045 var lineNumber = this.lineNumberInSource(index);
1046 var columnNumber = this.columnNumberInSource(index);
1047 return new WebInspector.CSSLocation(this._cssModel.target(), this.styleSheetId || null, this.resourceURL(), lineNumber, columnNumber);
1052 return this.origin === "user-agent";
1057 return this.origin === "user";
1060 get isViaInspector()
1062 return this.origin === "inspector";
1067 return this.origin === "regular";
1073 * @param {?WebInspector.CSSStyleDeclaration} ownerStyle
1074 * @param {number} index
1075 * @param {string} name
1076 * @param {string} value
1077 * @param {boolean} important
1078 * @param {boolean} disabled
1079 * @param {boolean} parsedOk
1080 * @param {boolean} implicit
1081 * @param {?string=} text
1082 * @param {!CSSAgent.SourceRange=} range
1084 WebInspector.CSSProperty = function(ownerStyle, index, name, value, important, disabled, parsedOk, implicit, text, range)
1086 this.ownerStyle = ownerStyle;
1090 this.important = important;
1091 this.disabled = disabled;
1092 this.parsedOk = parsedOk;
1093 this.implicit = implicit;
1095 this.range = range ? WebInspector.TextRange.fromObject(range) : null;
1099 * @param {?WebInspector.CSSStyleDeclaration} ownerStyle
1100 * @param {number} index
1101 * @param {!CSSAgent.CSSProperty} payload
1102 * @return {!WebInspector.CSSProperty}
1104 WebInspector.CSSProperty.parsePayload = function(ownerStyle, index, payload)
1106 // The following default field values are used in the payload:
1111 var result = new WebInspector.CSSProperty(
1112 ownerStyle, index, payload.name, payload.value, payload.important || false, payload.disabled || false, ("parsedOk" in payload) ? !!payload.parsedOk : true, !!payload.implicit, payload.text, payload.range);
1116 WebInspector.CSSProperty.prototype = {
1118 * @param {string} styleSheetId
1119 * @param {!WebInspector.TextRange} oldRange
1120 * @param {!WebInspector.TextRange} newRange
1122 sourceStyleSheetEdited: function(styleSheetId, oldRange, newRange)
1124 if (this.ownerStyle.styleSheetId !== styleSheetId)
1127 this.range = this.range.rebaseAfterTextEdit(oldRange, newRange);
1131 * @param {boolean} active
1133 _setActive: function(active)
1135 this._active = active;
1140 if (this.text !== undefined)
1143 if (this.name === "")
1145 return this.name + ": " + this.value + (this.important ? " !important" : "") + ";";
1150 return this.active || this.styleBased;
1155 return typeof this._active === "boolean" && this._active;
1165 return typeof this._active === "boolean" && !this._active;
1169 * @param {string} propertyText
1170 * @param {boolean} majorChange
1171 * @param {boolean} overwrite
1172 * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
1174 setText: function(propertyText, majorChange, overwrite, userCallback)
1177 * @param {?WebInspector.CSSStyleDeclaration} style
1179 function enabledCallback(style)
1182 userCallback(style);
1186 * @param {?string} error
1187 * @param {!CSSAgent.CSSStyle} stylePayload
1188 * @this {WebInspector.CSSProperty}
1190 function callback(error, stylePayload)
1192 this.ownerStyle._cssModel._pendingCommandsMajorState.pop();
1195 this.ownerStyle._cssModel._domModel.markUndoableState();
1196 var style = WebInspector.CSSStyleDeclaration.parsePayload(this.ownerStyle._cssModel, stylePayload);
1197 var newProperty = style.allProperties[this.index];
1199 if (newProperty && this.disabled && !propertyText.match(/^\s*$/)) {
1200 newProperty.setDisabled(false, enabledCallback);
1204 userCallback(style);
1211 if (!this.ownerStyle)
1212 throw "No ownerStyle for property";
1214 if (!this.ownerStyle.styleSheetId)
1215 throw "No owner style id";
1217 // An index past all the properties adds a new property to the style.
1218 var cssModel = this.ownerStyle._cssModel;
1219 cssModel._pendingCommandsMajorState.push(majorChange);
1220 var range = /** @type {!WebInspector.TextRange} */ (this.range);
1221 cssModel._agent.setPropertyText(this.ownerStyle.styleSheetId, overwrite ? range : range.collapseToStart(), propertyText, callback.bind(this));
1225 * @param {string} newValue
1226 * @param {boolean} majorChange
1227 * @param {boolean} overwrite
1228 * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
1230 setValue: function(newValue, majorChange, overwrite, userCallback)
1232 var text = this.name + ": " + newValue + (this.important ? " !important" : "") + ";"
1233 this.setText(text, majorChange, overwrite, userCallback);
1237 * @param {boolean} disabled
1238 * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
1240 setDisabled: function(disabled, userCallback)
1242 if (!this.ownerStyle && userCallback)
1244 if (disabled === this.disabled) {
1246 userCallback(this.ownerStyle);
1250 this.setText("/* " + this.text + " */", true, true, userCallback);
1252 this.setText(this.text.substring(2, this.text.length - 2).trim(), true, true, userCallback);
1258 * @param {!CSSAgent.MediaQuery} payload
1260 WebInspector.CSSMediaQuery = function(payload)
1262 this._active = payload.active;
1263 this._expressions = [];
1264 for (var j = 0; j < payload.expressions.length; ++j)
1265 this._expressions.push(WebInspector.CSSMediaQueryExpression.parsePayload(payload.expressions[j]));
1269 * @param {!CSSAgent.MediaQuery} payload
1270 * @return {!WebInspector.CSSMediaQuery}
1272 WebInspector.CSSMediaQuery.parsePayload = function(payload)
1274 return new WebInspector.CSSMediaQuery(payload);
1277 WebInspector.CSSMediaQuery.prototype = {
1283 return this._active;
1287 * @return {!Array.<!WebInspector.CSSMediaQueryExpression>}
1289 expressions: function()
1291 return this._expressions;
1297 * @param {!CSSAgent.MediaQueryExpression} payload
1299 WebInspector.CSSMediaQueryExpression = function(payload)
1301 this._value = payload.value;
1302 this._unit = payload.unit;
1303 this._feature = payload.feature;
1304 this._valueRange = payload.valueRange ? WebInspector.TextRange.fromObject(payload.valueRange) : null;
1305 this._computedLength = payload.computedLength || null;
1309 * @param {!CSSAgent.MediaQueryExpression} payload
1310 * @return {!WebInspector.CSSMediaQueryExpression}
1312 WebInspector.CSSMediaQueryExpression.parsePayload = function(payload)
1314 return new WebInspector.CSSMediaQueryExpression(payload);
1317 WebInspector.CSSMediaQueryExpression.prototype = {
1339 return this._feature;
1343 * @return {?WebInspector.TextRange}
1345 valueRange: function()
1347 return this._valueRange;
1353 computedLength: function()
1355 return this._computedLength;
1362 * @param {!WebInspector.CSSStyleModel} cssModel
1363 * @param {!CSSAgent.CSSMedia} payload
1365 WebInspector.CSSMedia = function(cssModel, payload)
1367 this._cssModel = cssModel
1368 this.text = payload.text;
1369 this.source = payload.source;
1370 this.sourceURL = payload.sourceURL || "";
1371 this.range = payload.range ? WebInspector.TextRange.fromObject(payload.range) : null;
1372 this.parentStyleSheetId = payload.parentStyleSheetId;
1373 this.mediaList = null;
1374 if (payload.mediaList) {
1375 this.mediaList = [];
1376 for (var i = 0; i < payload.mediaList.length; ++i)
1377 this.mediaList.push(WebInspector.CSSMediaQuery.parsePayload(payload.mediaList[i]));
1381 WebInspector.CSSMedia.Source = {
1382 LINKED_SHEET: "linkedSheet",
1383 INLINE_SHEET: "inlineSheet",
1384 MEDIA_RULE: "mediaRule",
1385 IMPORT_RULE: "importRule"
1389 * @param {!WebInspector.CSSStyleModel} cssModel
1390 * @param {!CSSAgent.CSSMedia} payload
1391 * @return {!WebInspector.CSSMedia}
1393 WebInspector.CSSMedia.parsePayload = function(cssModel, payload)
1395 return new WebInspector.CSSMedia(cssModel, payload);
1399 * @param {!WebInspector.CSSStyleModel} cssModel
1400 * @param {!Array.<!CSSAgent.CSSMedia>} payload
1401 * @return {!Array.<!WebInspector.CSSMedia>}
1403 WebInspector.CSSMedia.parseMediaArrayPayload = function(cssModel, payload)
1406 for (var i = 0; i < payload.length; ++i)
1407 result.push(WebInspector.CSSMedia.parsePayload(cssModel, payload[i]));
1411 WebInspector.CSSMedia.prototype = {
1413 * @param {string} styleSheetId
1414 * @param {!WebInspector.TextRange} oldRange
1415 * @param {!WebInspector.TextRange} newRange
1417 sourceStyleSheetEdited: function(styleSheetId, oldRange, newRange)
1419 if (this.parentStyleSheetId !== styleSheetId)
1422 this.range = this.range.rebaseAfterTextEdit(oldRange, newRange);
1426 * @return {number|undefined}
1428 lineNumberInSource: function()
1432 var header = this.header();
1435 return header.lineNumberInSource(this.range.startLine);
1439 * @return {number|undefined}
1441 columnNumberInSource: function()
1445 var header = this.header();
1448 return header.columnNumberInSource(this.range.startLine, this.range.startColumn);
1452 * @return {?WebInspector.CSSStyleSheetHeader}
1456 return this.parentStyleSheetId ? this._cssModel.styleSheetHeaderForId(this.parentStyleSheetId) : null;
1460 * @return {?WebInspector.CSSLocation}
1462 rawLocation: function()
1464 if (!this.header() || this.lineNumberInSource() === undefined)
1466 var lineNumber = Number(this.lineNumberInSource());
1467 return new WebInspector.CSSLocation(this._cssModel.target(), this.header().id, this.sourceURL, lineNumber, this.columnNumberInSource());
1473 * @implements {WebInspector.ContentProvider}
1474 * @param {!WebInspector.CSSStyleModel} cssModel
1475 * @param {!CSSAgent.CSSStyleSheetHeader} payload
1477 WebInspector.CSSStyleSheetHeader = function(cssModel, payload)
1479 this._cssModel = cssModel;
1480 this.id = payload.styleSheetId;
1481 this.frameId = payload.frameId;
1482 this.sourceURL = payload.sourceURL;
1483 this.hasSourceURL = !!payload.hasSourceURL;
1484 this.sourceMapURL = payload.sourceMapURL;
1485 this.origin = payload.origin;
1486 this.title = payload.title;
1487 this.disabled = payload.disabled;
1488 this.isInline = payload.isInline;
1489 this.startLine = payload.startLine;
1490 this.startColumn = payload.startColumn;
1493 WebInspector.CSSStyleSheetHeader.prototype = {
1495 * @return {!WebInspector.Target}
1499 return this._cssModel.target();
1505 resourceURL: function()
1507 return this.isViaInspector() ? this._viaInspectorResourceURL() : this.sourceURL;
1513 _viaInspectorResourceURL: function()
1515 var frame = this._cssModel.target().resourceTreeModel.frameForId(this.frameId);
1516 console.assert(frame);
1517 var parsedURL = new WebInspector.ParsedURL(frame.url);
1518 var fakeURL = "inspector://" + parsedURL.host + parsedURL.folderPathComponents;
1519 if (!fakeURL.endsWith("/"))
1521 fakeURL += "inspector-stylesheet";
1526 * @param {number} lineNumberInStyleSheet
1529 lineNumberInSource: function(lineNumberInStyleSheet)
1531 return this.startLine + lineNumberInStyleSheet;
1535 * @param {number} lineNumberInStyleSheet
1536 * @param {number} columnNumberInStyleSheet
1537 * @return {number|undefined}
1539 columnNumberInSource: function(lineNumberInStyleSheet, columnNumberInStyleSheet)
1541 return (lineNumberInStyleSheet ? 0 : this.startColumn) + columnNumberInStyleSheet;
1548 contentURL: function()
1550 return this.resourceURL();
1555 * @return {!WebInspector.ResourceType}
1557 contentType: function()
1559 return WebInspector.resourceTypes.Stylesheet;
1563 * @param {string} text
1566 _trimSourceURL: function(text)
1568 var sourceURLRegex = /\n[\040\t]*\/\*[#@][\040\t]sourceURL=[\040\t]*([^\s]*)[\040\t]*\*\/[\040\t]*$/mg;
1569 return text.replace(sourceURLRegex, "");
1574 * @param {function(string)} callback
1576 requestContent: function(callback)
1578 this._cssModel._agent.getStyleSheetText(this.id, textCallback.bind(this));
1581 * @this {WebInspector.CSSStyleSheetHeader}
1583 function textCallback(error, text)
1586 WebInspector.console.error("Failed to get text for stylesheet " + this.id + ": " + error);
1590 text = this._trimSourceURL(text);
1598 searchInContent: function(query, caseSensitive, isRegex, callback)
1600 function performSearch(content)
1602 callback(WebInspector.ContentProvider.performSearchInContent(content, query, caseSensitive, isRegex));
1605 // searchInContent should call back later.
1606 this.requestContent(performSearch);
1610 * @param {string} newText
1611 * @param {function(?Protocol.Error)} callback
1613 setContent: function(newText, callback)
1615 newText = this._trimSourceURL(newText);
1616 if (this.hasSourceURL)
1617 newText += "\n/*# sourceURL=" + this.sourceURL + " */";
1618 this._cssModel._agent.setStyleSheetText(this.id, newText, callback);
1624 isViaInspector: function()
1626 return this.origin === "inspector";
1632 * @implements {CSSAgent.Dispatcher}
1633 * @param {!WebInspector.CSSStyleModel} cssModel
1635 WebInspector.CSSDispatcher = function(cssModel)
1637 this._cssModel = cssModel;
1640 WebInspector.CSSDispatcher.prototype = {
1641 mediaQueryResultChanged: function()
1643 this._cssModel.mediaQueryResultChanged();
1647 * @param {!CSSAgent.StyleSheetId} styleSheetId
1649 styleSheetChanged: function(styleSheetId)
1651 this._cssModel._fireStyleSheetChanged(styleSheetId);
1655 * @param {!CSSAgent.CSSStyleSheetHeader} header
1657 styleSheetAdded: function(header)
1659 this._cssModel._styleSheetAdded(header);
1663 * @param {!CSSAgent.StyleSheetId} id
1665 styleSheetRemoved: function(id)
1667 this._cssModel._styleSheetRemoved(id);
1673 * @param {!WebInspector.CSSStyleModel} cssModel
1675 WebInspector.CSSStyleModel.ComputedStyleLoader = function(cssModel)
1677 this._cssModel = cssModel;
1678 /** @type {!Object.<*, !Array.<function(?WebInspector.CSSStyleDeclaration)>>} */
1679 this._nodeIdToCallbackData = {};
1682 WebInspector.CSSStyleModel.ComputedStyleLoader.prototype = {
1684 * @param {!DOMAgent.NodeId} nodeId
1685 * @param {function(?WebInspector.CSSStyleDeclaration)} userCallback
1687 getComputedStyle: function(nodeId, userCallback)
1689 if (this._nodeIdToCallbackData[nodeId]) {
1690 this._nodeIdToCallbackData[nodeId].push(userCallback);
1694 this._nodeIdToCallbackData[nodeId] = [userCallback];
1696 this._cssModel._agent.getComputedStyleForNode(nodeId, resultCallback.bind(this, nodeId));
1699 * @param {!DOMAgent.NodeId} nodeId
1700 * @param {?Protocol.Error} error
1701 * @param {!Array.<!CSSAgent.CSSComputedStyleProperty>} computedPayload
1702 * @this {WebInspector.CSSStyleModel.ComputedStyleLoader}
1704 function resultCallback(nodeId, error, computedPayload)
1706 var computedStyle = (error || !computedPayload) ? null : WebInspector.CSSStyleDeclaration.parseComputedStylePayload(this._cssModel, computedPayload);
1707 var callbacks = this._nodeIdToCallbackData[nodeId];
1709 // The loader has been reset.
1713 delete this._nodeIdToCallbackData[nodeId];
1714 for (var i = 0; i < callbacks.length; ++i)
1715 callbacks[i](computedStyle);
1721 * @type {!WebInspector.CSSStyleModel}
1723 WebInspector.cssModel;