blob: aa6cda5bc9a2c59c107b6ccbbbb64b4f788c7d29 [file] [log] [blame]
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @constructor
* @extends {WebInspector.SDKModel}
* @param {!WebInspector.Target} target
*/
WebInspector.CSSModel = function(target)
{
WebInspector.SDKModel.call(this, WebInspector.CSSModel, target);
this._domModel = WebInspector.DOMModel.fromTarget(target);
this._agent = target.cssAgent();
this._styleLoader = new WebInspector.CSSModel.ComputedStyleLoader(this);
target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameNavigated, this);
target.registerCSSDispatcher(new WebInspector.CSSDispatcher(this));
this._agent.enable().then(this._wasEnabled.bind(this));
/** @type {!Map.<string, !WebInspector.CSSStyleSheetHeader>} */
this._styleSheetIdToHeader = new Map();
/** @type {!Map.<string, !Object.<!PageAgent.FrameId, !Array.<!CSSAgent.StyleSheetId>>>} */
this._styleSheetIdsForURL = new Map();
}
WebInspector.CSSModel.Events = {
LayoutEditorChange: "LayoutEditorChange",
MediaQueryResultChanged: "MediaQueryResultChanged",
ModelWasEnabled: "ModelWasEnabled",
PseudoStateForced: "PseudoStateForced",
StyleSheetAdded: "StyleSheetAdded",
StyleSheetChanged: "StyleSheetChanged",
StyleSheetRemoved: "StyleSheetRemoved"
}
WebInspector.CSSModel.MediaTypes = ["all", "braille", "embossed", "handheld", "print", "projection", "screen", "speech", "tty", "tv"];
WebInspector.CSSModel.PseudoStateMarker = "pseudo-state-marker";
/**
* @constructor
* @param {!CSSAgent.StyleSheetId} styleSheetId
* @param {!WebInspector.TextRange} oldRange
* @param {string} newText
* @param {?Object} payload
*/
WebInspector.CSSModel.Edit = function(styleSheetId, oldRange, newText, payload)
{
this.styleSheetId = styleSheetId;
this.oldRange = oldRange;
this.newRange = WebInspector.TextRange.fromEdit(oldRange, newText);
this.payload = payload;
}
WebInspector.CSSModel.prototype = {
/**
* @return {!WebInspector.DOMModel}
*/
domModel: function()
{
return /** @type {!WebInspector.DOMModel} */(this._domModel);
},
/**
* @param {!Array<!CSSAgent.StyleSheetId>} styleSheetIds
* @param {!Array<!WebInspector.TextRange>} ranges
* @param {!Array<string>} texts
* @param {boolean} majorChange
* @return {!Promise<boolean>}
*/
setStyleTexts: function(styleSheetIds, ranges, texts, majorChange)
{
/**
* @param {?Protocol.Error} error
* @param {?Array<!CSSAgent.CSSStyle>} stylePayloads
* @return {boolean}
* @this {WebInspector.CSSModel}
*/
function parsePayload(error, stylePayloads)
{
if (error || !stylePayloads || stylePayloads.length !== ranges.length)
return false;
if (majorChange)
this._domModel.markUndoableState();
for (var i = 0; i < ranges.length; ++i) {
var edit = new WebInspector.CSSModel.Edit(styleSheetIds[i], ranges[i], texts[i], stylePayloads[i]);
this._fireStyleSheetChanged(styleSheetIds[i], edit);
}
return true;
}
console.assert(styleSheetIds.length === ranges.length && ranges.length === texts.length, "Array lengths must be equal");
var edits = [];
for (var i = 0; i < styleSheetIds.length; ++i) {
edits.push({
styleSheetId: styleSheetIds[i],
range: ranges[i].serializeToObject(),
text: texts[i]
});
}
return this._agent.setStyleTexts(edits, parsePayload.bind(this))
.catchException(false);
},
/**
* @param {!CSSAgent.StyleSheetId} styleSheetId
* @param {!WebInspector.TextRange} range
* @param {string} text
* @return {!Promise<boolean>}
*/
setSelectorText: function(styleSheetId, range, text)
{
/**
* @param {?Protocol.Error} error
* @param {?CSSAgent.SelectorList} selectorPayload
* @return {boolean}
* @this {WebInspector.CSSModel}
*/
function callback(error, selectorPayload)
{
if (error || !selectorPayload)
return false;
this._domModel.markUndoableState();
var edit = new WebInspector.CSSModel.Edit(styleSheetId, range, text, selectorPayload);
this._fireStyleSheetChanged(styleSheetId, edit);
return true;
}
WebInspector.userMetrics.actionTaken(WebInspector.UserMetrics.Action.StyleRuleEdited);
return this._agent.setRuleSelector(styleSheetId, range, text, callback.bind(this))
.catchException(false);
},
/**
* @param {!CSSAgent.StyleSheetId} styleSheetId
* @param {!WebInspector.TextRange} range
* @param {string} text
* @return {!Promise<boolean>}
*/
setKeyframeKey: function(styleSheetId, range, text)
{
/**
* @param {?Protocol.Error} error
* @param {!CSSAgent.Value} payload
* @return {boolean}
* @this {WebInspector.CSSModel}
*/
function callback(error, payload)
{
if (error || !payload)
return false;
this._domModel.markUndoableState();
var edit = new WebInspector.CSSModel.Edit(styleSheetId, range, text, payload);
this._fireStyleSheetChanged(styleSheetId, edit);
return true;
}
WebInspector.userMetrics.actionTaken(WebInspector.UserMetrics.Action.StyleRuleEdited);
return this._agent.setKeyframeKey(styleSheetId, range, text, callback.bind(this))
.catchException(false);
},
/**
* @return {!Promise.<!Array.<!WebInspector.CSSMedia>>}
*/
mediaQueriesPromise: function()
{
/**
* @param {?Protocol.Error} error
* @param {?Array.<!CSSAgent.CSSMedia>} payload
* @return {!Array.<!WebInspector.CSSMedia>}
* @this {!WebInspector.CSSModel}
*/
function parsePayload(error, payload)
{
return !error && payload ? WebInspector.CSSMedia.parseMediaArrayPayload(this, payload) : [];
}
return this._agent.getMediaQueries(parsePayload.bind(this));
},
/**
* @return {boolean}
*/
isEnabled: function()
{
return this._isEnabled;
},
/**
* @param {?Protocol.Error} error
*/
_wasEnabled: function(error)
{
if (error) {
console.error("Failed to enabled CSS agent: " + error);
return;
}
this._isEnabled = true;
this.dispatchEventToListeners(WebInspector.CSSModel.Events.ModelWasEnabled);
},
/**
* @param {!DOMAgent.NodeId} nodeId
* @return {!Promise.<?WebInspector.CSSMatchedStyles>}
*/
matchedStylesPromise: function(nodeId)
{
/**
* @param {?Protocol.Error} error
* @param {?CSSAgent.CSSStyle=} inlinePayload
* @param {?CSSAgent.CSSStyle=} attributesPayload
* @param {!Array.<!CSSAgent.RuleMatch>=} matchedPayload
* @param {!Array.<!CSSAgent.PseudoElementMatches>=} pseudoPayload
* @param {!Array.<!CSSAgent.InheritedStyleEntry>=} inheritedPayload
* @param {!Array.<!CSSAgent.CSSKeyframesRule>=} animationsPayload
* @return {?WebInspector.CSSMatchedStyles}
* @this {WebInspector.CSSModel}
*/
function callback(error, inlinePayload, attributesPayload, matchedPayload, pseudoPayload, inheritedPayload, animationsPayload)
{
if (error)
return null;
var node = this._domModel.nodeForId(nodeId);
if (!node)
return null;
return new WebInspector.CSSMatchedStyles(this, node, inlinePayload || null, attributesPayload || null, matchedPayload || [], pseudoPayload || [], inheritedPayload || [], animationsPayload || []);
}
return this._agent.getMatchedStylesForNode(nodeId, callback.bind(this));
},
/**
* @param {!DOMAgent.NodeId} nodeId
* @return {!Promise.<?Map.<string, string>>}
*/
computedStylePromise: function(nodeId)
{
return this._styleLoader.computedStylePromise(nodeId);
},
/**
* @param {number} nodeId
* @return {!Promise<?Array<string>>}
*/
backgroundColorsPromise: function(nodeId)
{
/**
* @param {?string} error
* @param {!Array<string>=} backgroundColors
* @return {?Array<string>}
*/
function backgroundColorsCallback(error, backgroundColors) {
return !error && backgroundColors ? backgroundColors : null;
}
return this._agent.getBackgroundColors(nodeId, backgroundColorsCallback);
},
/**
* @param {number} nodeId
* @return {!Promise.<?Array.<!CSSAgent.PlatformFontUsage>>}
*/
platformFontsPromise: function(nodeId)
{
/**
* @param {?Protocol.Error} error
* @param {?Array.<!CSSAgent.PlatformFontUsage>} fonts
* @return {?Array.<!CSSAgent.PlatformFontUsage>}
*/
function platformFontsCallback(error, fonts)
{
return !error && fonts ? fonts : null;
}
return this._agent.getPlatformFontsForNode(nodeId, platformFontsCallback);
},
/**
* @return {!Array.<!WebInspector.CSSStyleSheetHeader>}
*/
allStyleSheets: function()
{
var values = this._styleSheetIdToHeader.valuesArray();
/**
* @param {!WebInspector.CSSStyleSheetHeader} a
* @param {!WebInspector.CSSStyleSheetHeader} b
* @return {number}
*/
function styleSheetComparator(a, b)
{
if (a.sourceURL < b.sourceURL)
return -1;
else if (a.sourceURL > b.sourceURL)
return 1;
return a.startLine - b.startLine || a.startColumn - b.startColumn;
}
values.sort(styleSheetComparator);
return values;
},
/**
* @param {!DOMAgent.NodeId} nodeId
* @return {!Promise.<?WebInspector.CSSModel.InlineStyleResult>}
*/
inlineStylesPromise: function(nodeId)
{
/**
* @param {?Protocol.Error} error
* @param {?CSSAgent.CSSStyle=} inlinePayload
* @param {?CSSAgent.CSSStyle=} attributesStylePayload
* @return {?WebInspector.CSSModel.InlineStyleResult}
* @this {WebInspector.CSSModel}
*/
function callback(error, inlinePayload, attributesStylePayload)
{
if (error || !inlinePayload)
return null;
var inlineStyle = inlinePayload ? new WebInspector.CSSStyleDeclaration(this, null, inlinePayload, WebInspector.CSSStyleDeclaration.Type.Inline) : null;
var attributesStyle = attributesStylePayload ? new WebInspector.CSSStyleDeclaration(this, null, attributesStylePayload, WebInspector.CSSStyleDeclaration.Type.Attributes) : null;
return new WebInspector.CSSModel.InlineStyleResult(inlineStyle, attributesStyle);
}
return this._agent.getInlineStylesForNode(nodeId, callback.bind(this));
},
/**
* @param {!WebInspector.DOMNode} node
* @param {string} pseudoClass
* @param {boolean} enable
* @return {boolean}
*/
forcePseudoState: function(node, pseudoClass, enable)
{
var pseudoClasses = node.marker(WebInspector.CSSModel.PseudoStateMarker) || [];
if (enable) {
if (pseudoClasses.indexOf(pseudoClass) >= 0)
return false;
pseudoClasses.push(pseudoClass);
node.setMarker(WebInspector.CSSModel.PseudoStateMarker, pseudoClasses);
} else {
if (pseudoClasses.indexOf(pseudoClass) < 0)
return false;
pseudoClasses.remove(pseudoClass);
if (!pseudoClasses.length)
node.setMarker(WebInspector.CSSModel.PseudoStateMarker, null);
}
this._agent.forcePseudoState(node.id, pseudoClasses);
this.dispatchEventToListeners(WebInspector.CSSModel.Events.PseudoStateForced, { node: node, pseudoClass: pseudoClass, enable: enable });
return true;
},
/**
* @param {!WebInspector.DOMNode} node
* @return {?Array<string>} state
*/
pseudoState: function(node)
{
return node.marker(WebInspector.CSSModel.PseudoStateMarker) || [];
},
/**
* @param {!WebInspector.CSSMedia} media
* @param {string} newMediaText
* @param {function(?WebInspector.CSSMedia)} userCallback
*/
setMediaText: function(media, newMediaText, userCallback)
{
/**
* @param {?Protocol.Error} error
* @param {!CSSAgent.CSSMedia} mediaPayload
* @return {boolean}
* @this {WebInspector.CSSModel}
*/
function parsePayload(error, mediaPayload)
{
if (!mediaPayload)
return false;
this._domModel.markUndoableState();
var edit = new WebInspector.CSSModel.Edit(media.parentStyleSheetId, media.range, newMediaText, mediaPayload);
this._fireStyleSheetChanged(media.parentStyleSheetId, edit);
return true;
}
console.assert(!!media.parentStyleSheetId);
WebInspector.userMetrics.actionTaken(WebInspector.UserMetrics.Action.StyleRuleEdited);
this._agent.setMediaText(media.parentStyleSheetId, media.range, newMediaText, parsePayload.bind(this))
.catchException(null)
.then(userCallback);
},
/**
* @param {!CSSAgent.StyleSheetId} styleSheetId
* @param {string} ruleText
* @param {!WebInspector.TextRange} ruleLocation
* @return {!Promise<?WebInspector.CSSStyleRule>}
*/
addRule: function(styleSheetId, ruleText, ruleLocation)
{
return this._agent.addRule(styleSheetId, ruleText, ruleLocation, parsePayload.bind(this))
.catchException(/** @type {?WebInspector.CSSStyleRule} */(null))
/**
* @param {?Protocol.Error} error
* @param {?CSSAgent.CSSRule} rulePayload
* @return {?WebInspector.CSSStyleRule}
* @this {WebInspector.CSSModel}
*/
function parsePayload(error, rulePayload)
{
if (error || !rulePayload)
return null;
this._domModel.markUndoableState();
var edit = new WebInspector.CSSModel.Edit(styleSheetId, ruleLocation, ruleText, rulePayload);
this._fireStyleSheetChanged(styleSheetId, edit);
return new WebInspector.CSSStyleRule(this, rulePayload);
}
},
/**
* @param {!WebInspector.DOMNode} node
* @param {function(?WebInspector.CSSStyleSheetHeader)} userCallback
*/
requestViaInspectorStylesheet: function(node, userCallback)
{
var frameId = node.frameId() || this.target().resourceTreeModel.mainFrame.id;
var headers = this._styleSheetIdToHeader.valuesArray();
for (var i = 0; i < headers.length; ++i) {
var styleSheetHeader = headers[i];
if (styleSheetHeader.frameId === frameId && styleSheetHeader.isViaInspector()) {
userCallback(styleSheetHeader);
return;
}
}
/**
* @param {?Protocol.Error} error
* @param {?CSSAgent.StyleSheetId} styleSheetId
* @return {?WebInspector.CSSStyleSheetHeader}
* @this {WebInspector.CSSModel}
*/
function innerCallback(error, styleSheetId)
{
return !error && styleSheetId ? this._styleSheetIdToHeader.get(styleSheetId) || null : null;
}
this._agent.createStyleSheet(frameId, innerCallback.bind(this))
.catchException(null)
.then(userCallback)
},
mediaQueryResultChanged: function()
{
this.dispatchEventToListeners(WebInspector.CSSModel.Events.MediaQueryResultChanged);
},
/**
* @param {!CSSAgent.StyleSheetId} id
* @return {?WebInspector.CSSStyleSheetHeader}
*/
styleSheetHeaderForId: function(id)
{
return this._styleSheetIdToHeader.get(id) || null;
},
/**
* @return {!Array.<!WebInspector.CSSStyleSheetHeader>}
*/
styleSheetHeaders: function()
{
return this._styleSheetIdToHeader.valuesArray();
},
/**
* @param {!CSSAgent.StyleSheetId} styleSheetId
* @param {!WebInspector.CSSModel.Edit=} edit
*/
_fireStyleSheetChanged: function(styleSheetId, edit)
{
this.dispatchEventToListeners(WebInspector.CSSModel.Events.StyleSheetChanged, { styleSheetId: styleSheetId, edit: edit });
},
/**
* @param {!CSSAgent.CSSStyleSheetHeader} header
*/
_styleSheetAdded: function(header)
{
console.assert(!this._styleSheetIdToHeader.get(header.styleSheetId));
var styleSheetHeader = new WebInspector.CSSStyleSheetHeader(this, header);
this._styleSheetIdToHeader.set(header.styleSheetId, styleSheetHeader);
var url = styleSheetHeader.resourceURL();
if (!this._styleSheetIdsForURL.get(url))
this._styleSheetIdsForURL.set(url, {});
var frameIdToStyleSheetIds = this._styleSheetIdsForURL.get(url);
var styleSheetIds = frameIdToStyleSheetIds[styleSheetHeader.frameId];
if (!styleSheetIds) {
styleSheetIds = [];
frameIdToStyleSheetIds[styleSheetHeader.frameId] = styleSheetIds;
}
styleSheetIds.push(styleSheetHeader.id);
this.dispatchEventToListeners(WebInspector.CSSModel.Events.StyleSheetAdded, styleSheetHeader);
},
/**
* @param {!CSSAgent.StyleSheetId} id
*/
_styleSheetRemoved: function(id)
{
var header = this._styleSheetIdToHeader.get(id);
console.assert(header);
if (!header)
return;
this._styleSheetIdToHeader.remove(id);
var url = header.resourceURL();
var frameIdToStyleSheetIds = /** @type {!Object.<!PageAgent.FrameId, !Array.<!CSSAgent.StyleSheetId>>} */ (this._styleSheetIdsForURL.get(url));
console.assert(frameIdToStyleSheetIds, "No frameId to styleSheetId map is available for given style sheet URL.");
frameIdToStyleSheetIds[header.frameId].remove(id);
if (!frameIdToStyleSheetIds[header.frameId].length) {
delete frameIdToStyleSheetIds[header.frameId];
if (!Object.keys(frameIdToStyleSheetIds).length)
this._styleSheetIdsForURL.remove(url);
}
this.dispatchEventToListeners(WebInspector.CSSModel.Events.StyleSheetRemoved, header);
},
/**
* @param {string} url
* @return {!Array.<!CSSAgent.StyleSheetId>}
*/
styleSheetIdsForURL: function(url)
{
var frameIdToStyleSheetIds = this._styleSheetIdsForURL.get(url);
if (!frameIdToStyleSheetIds)
return [];
var result = [];
for (var frameId in frameIdToStyleSheetIds)
result = result.concat(frameIdToStyleSheetIds[frameId]);
return result;
},
/**
* @param {!CSSAgent.StyleSheetId} styleSheetId
* @param {string} newText
* @param {boolean} majorChange
* @return {!Promise.<?Protocol.Error>}
*/
setStyleSheetText: function(styleSheetId, newText, majorChange)
{
var header = this._styleSheetIdToHeader.get(styleSheetId);
console.assert(header);
newText = WebInspector.CSSModel.trimSourceURL(newText);
if (header.hasSourceURL)
newText += "\n/*# sourceURL=" + header.sourceURL + " */";
return this._agent.setStyleSheetText(header.id, newText, callback.bind(this));
/**
* @param {?Protocol.Error} error
* @param {string=} sourceMapURL
* @return {?Protocol.Error}
* @this {WebInspector.CSSModel}
*/
function callback(error, sourceMapURL)
{
header.setSourceMapURL(sourceMapURL);
if (error)
return error;
if (majorChange)
this._domModel.markUndoableState();
this._fireStyleSheetChanged(styleSheetId);
return null;
}
},
/**
* @param {!CSSAgent.StyleSheetId} styleSheetId
* @return {!Promise<string>}
*/
getStyleSheetText: function(styleSheetId)
{
/**
* @param {?Protocol.Error} error
* @param {?string} text
* @return {string}
*/
function textCallback(error, text)
{
if (error || text === null) {
WebInspector.console.error("Failed to get text for stylesheet " + styleSheetId + ": " + error)
text = "";
// Fall through.
}
return WebInspector.CSSModel.trimSourceURL(text);
}
return this._agent.getStyleSheetText(styleSheetId, textCallback)
.catchException(/** @type {string} */(""));
},
_mainFrameNavigated: function()
{
this._resetStyleSheets();
},
_resetStyleSheets: function()
{
var headers = this._styleSheetIdToHeader.valuesArray();
this._styleSheetIdsForURL.clear();
this._styleSheetIdToHeader.clear();
for (var i = 0; i < headers.length; ++i)
this.dispatchEventToListeners(WebInspector.CSSModel.Events.StyleSheetRemoved, headers[i]);
},
/**
* @override
* @return {!Promise}
*/
suspendModel: function()
{
this._isEnabled = false;
return this._agent.disable().then(this._resetStyleSheets.bind(this));
},
/**
* @override
* @return {!Promise}
*/
resumeModel: function()
{
return this._agent.enable().then(this._wasEnabled.bind(this));
},
/**
* @param {!CSSAgent.StyleSheetId} id
* @param {!CSSAgent.SourceRange} range
*/
_layoutEditorChange: function(id, range)
{
this.dispatchEventToListeners(WebInspector.CSSModel.Events.LayoutEditorChange, {id: id, range: range});
},
/**
* @param {number} nodeId
* @param {string} name
* @param {string} value
*/
setEffectivePropertyValueForNode: function(nodeId, name, value)
{
this._agent.setEffectivePropertyValueForNode(nodeId, name, value);
},
__proto__: WebInspector.SDKModel.prototype
}
/**
* @param {string} text
* @return {string}
*/
WebInspector.CSSModel.trimSourceURL = function(text)
{
var sourceURLIndex = text.lastIndexOf("/*# sourceURL=");
if (sourceURLIndex === -1) {
sourceURLIndex = text.lastIndexOf("/*@ sourceURL=");
if (sourceURLIndex === -1)
return text;
}
var sourceURLLineIndex = text.lastIndexOf("\n", sourceURLIndex);
if (sourceURLLineIndex === -1)
return text;
var sourceURLLine = text.substr(sourceURLLineIndex + 1).split("\n", 1)[0];
var sourceURLRegex = /[\040\t]*\/\*[#@] sourceURL=[\040\t]*([^\s]*)[\040\t]*\*\/[\040\t]*$/;
if (sourceURLLine.search(sourceURLRegex) === -1)
return text;
return text.substr(0, sourceURLLineIndex) + text.substr(sourceURLLineIndex + sourceURLLine.length + 1);
}
/**
* @constructor
* @extends {WebInspector.SDKObject}
* @param {!WebInspector.CSSStyleSheetHeader} header
* @param {number} lineNumber
* @param {number=} columnNumber
*/
WebInspector.CSSLocation = function(header, lineNumber, columnNumber)
{
WebInspector.SDKObject.call(this, header.target());
this._header = header;
this.styleSheetId = header.id;
this.url = header.resourceURL();
this.lineNumber = lineNumber;
this.columnNumber = columnNumber || 0;
}
WebInspector.CSSLocation.prototype = {
/**
* @return {!WebInspector.CSSModel}
*/
cssModel: function()
{
return this._header.cssModel();
},
/**
* @return {!WebInspector.CSSStyleSheetHeader}
*/
header: function()
{
return this._header;
},
__proto__: WebInspector.SDKObject.prototype
}
/**
* @constructor
* @implements {CSSAgent.Dispatcher}
* @param {!WebInspector.CSSModel} cssModel
*/
WebInspector.CSSDispatcher = function(cssModel)
{
this._cssModel = cssModel;
}
WebInspector.CSSDispatcher.prototype = {
/**
* @override
*/
mediaQueryResultChanged: function()
{
this._cssModel.mediaQueryResultChanged();
},
/**
* @override
* @param {!CSSAgent.StyleSheetId} styleSheetId
*/
styleSheetChanged: function(styleSheetId)
{
this._cssModel._fireStyleSheetChanged(styleSheetId);
},
/**
* @override
* @param {!CSSAgent.CSSStyleSheetHeader} header
*/
styleSheetAdded: function(header)
{
this._cssModel._styleSheetAdded(header);
},
/**
* @override
* @param {!CSSAgent.StyleSheetId} id
*/
styleSheetRemoved: function(id)
{
this._cssModel._styleSheetRemoved(id);
},
/**
* @override
* @param {!CSSAgent.StyleSheetId} id
* @param {!CSSAgent.SourceRange} range
*/
layoutEditorChange: function(id, range)
{
this._cssModel._layoutEditorChange(id, range);
},
}
/**
* @constructor
* @param {!WebInspector.CSSModel} cssModel
*/
WebInspector.CSSModel.ComputedStyleLoader = function(cssModel)
{
this._cssModel = cssModel;
/** @type {!Map<!DOMAgent.NodeId, !Promise<?Map<string, string>>>} */
this._nodeIdToPromise = new Map();
}
WebInspector.CSSModel.ComputedStyleLoader.prototype = {
/**
* @param {!DOMAgent.NodeId} nodeId
* @return {!Promise<?Map<string, string>>}
*/
computedStylePromise: function(nodeId)
{
if (!this._nodeIdToPromise.has(nodeId))
this._nodeIdToPromise.set(nodeId, this._cssModel._agent.getComputedStyleForNode(nodeId, parsePayload).then(cleanUp.bind(this)));
return /** @type {!Promise.<?Map.<string, string>>} */(this._nodeIdToPromise.get(nodeId));
/**
* @param {?Protocol.Error} error
* @param {!Array.<!CSSAgent.CSSComputedStyleProperty>} computedPayload
* @return {?Map.<string, string>}
*/
function parsePayload(error, computedPayload)
{
if (error || !computedPayload || !computedPayload.length)
return null;
var result = new Map();
for (var property of computedPayload)
result.set(property.name, property.value);
return result;
}
/**
* @param {?Map.<string, string>} computedStyle
* @return {?Map.<string, string>}
* @this {WebInspector.CSSModel.ComputedStyleLoader}
*/
function cleanUp(computedStyle)
{
this._nodeIdToPromise.delete(nodeId);
return computedStyle;
}
}
}
/**
* @param {!WebInspector.Target} target
* @return {?WebInspector.CSSModel}
*/
WebInspector.CSSModel.fromTarget = function(target)
{
if (!target.isPage())
return null;
return /** @type {?WebInspector.CSSModel} */ (target.model(WebInspector.CSSModel));
}
/**
* @param {!WebInspector.DOMNode} node
* @return {!WebInspector.CSSModel}
*/
WebInspector.CSSModel.fromNode = function(node)
{
return /** @type {!WebInspector.CSSModel} */ (WebInspector.CSSModel.fromTarget(node.target()));
}
/**
* @constructor
* @param {?WebInspector.CSSStyleDeclaration} inlineStyle
* @param {?WebInspector.CSSStyleDeclaration} attributesStyle
*/
WebInspector.CSSModel.InlineStyleResult = function(inlineStyle, attributesStyle)
{
this.inlineStyle = inlineStyle;
this.attributesStyle = attributesStyle;
}