blob: 022fe4ca607697f1ad77ae3c2f30987aa05485c1 [file] [log] [blame]
// Copyright (c) 2015 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.
/**
* @extends {WebInspector.Object}
* @constructor
*/
WebInspector.ComputedStyleModel = function()
{
WebInspector.Object.call(this);
this._node = WebInspector.context.flavor(WebInspector.DOMNode);
WebInspector.context.addFlavorChangeListener(WebInspector.DOMNode, this._onNodeChanged, this);
}
WebInspector.ComputedStyleModel.Events = {
ComputedStyleChanged: "ComputedStyleChanged"
}
WebInspector.ComputedStyleModel.prototype = {
/**
* @return {?WebInspector.DOMNode}
*/
node: function()
{
return this._node;
},
/**
* @return {?WebInspector.CSSModel}
*/
cssModel: function()
{
return this._cssModel && this._cssModel.isEnabled() ? this._cssModel : null;
},
/**
* @param {!WebInspector.Event} event
*/
_onNodeChanged: function(event)
{
this._node = /** @type {?WebInspector.DOMNode} */(event.data);
this._updateTarget(this._node ? this._node.target() : null);
this._onComputedStyleChanged(null);
},
/**
* @param {?WebInspector.Target} target
*/
_updateTarget: function(target)
{
if (this._target === target)
return;
if (this._targetEvents) {
WebInspector.EventTarget.removeEventListeners(this._targetEvents);
this._targetEvents = null;
}
this._target = target;
var domModel = null;
var resourceTreeModel = null;
if (target) {
this._cssModel = WebInspector.CSSModel.fromTarget(target);
domModel = WebInspector.DOMModel.fromTarget(target);
resourceTreeModel = target.resourceTreeModel;
}
if (this._cssModel && domModel && resourceTreeModel) {
this._targetEvents = [
this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, this._onComputedStyleChanged, this),
this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, this._onComputedStyleChanged, this),
this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetChanged, this._onComputedStyleChanged, this),
this._cssModel.addEventListener(WebInspector.CSSModel.Events.MediaQueryResultChanged, this._onComputedStyleChanged, this),
this._cssModel.addEventListener(WebInspector.CSSModel.Events.PseudoStateForced, this._onComputedStyleChanged, this),
this._cssModel.addEventListener(WebInspector.CSSModel.Events.ModelWasEnabled, this._onComputedStyleChanged, this),
domModel.addEventListener(WebInspector.DOMModel.Events.DOMMutated, this._onDOMModelChanged, this),
resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameResized, this._onFrameResized, this),
];
}
},
/**
* @param {?WebInspector.Event} event
*/
_onComputedStyleChanged: function(event)
{
delete this._computedStylePromise;
this.dispatchEventToListeners(WebInspector.ComputedStyleModel.Events.ComputedStyleChanged, event ? event.data : null);
},
/**
* @param {!WebInspector.Event} event
*/
_onDOMModelChanged: function(event)
{
// Any attribute removal or modification can affect the styles of "related" nodes.
var node = /** @type {!WebInspector.DOMNode} */ (event.data);
if (!this._node || this._node !== node && node.parentNode !== this._node.parentNode && !node.isAncestor(this._node))
return;
this._onComputedStyleChanged(null);
},
/**
* @param {!WebInspector.Event} event
*/
_onFrameResized: function(event)
{
/**
* @this {WebInspector.ComputedStyleModel}
*/
function refreshContents()
{
this._onComputedStyleChanged(null);
delete this._frameResizedTimer;
}
if (this._frameResizedTimer)
clearTimeout(this._frameResizedTimer);
this._frameResizedTimer = setTimeout(refreshContents.bind(this), 100);
},
/**
* @return {?WebInspector.DOMNode}
*/
_elementNode: function()
{
return this.node() ? this.node().enclosingElementOrSelf() : null;
},
/**
* @return {!Promise.<?WebInspector.ComputedStyleModel.ComputedStyle>}
*/
fetchComputedStyle: function()
{
var elementNode = this._elementNode();
var cssModel = this.cssModel();
if (!elementNode || !cssModel)
return Promise.resolve(/** @type {?WebInspector.ComputedStyleModel.ComputedStyle} */(null));
if (!this._computedStylePromise)
this._computedStylePromise = cssModel.computedStylePromise(elementNode.id).then(verifyOutdated.bind(this, elementNode));
return this._computedStylePromise;
/**
* @param {!WebInspector.DOMNode} elementNode
* @param {?Map.<string, string>} style
* @return {?WebInspector.ComputedStyleModel.ComputedStyle}
* @this {WebInspector.ComputedStyleModel}
*/
function verifyOutdated(elementNode, style)
{
return elementNode === this._elementNode() && style ? new WebInspector.ComputedStyleModel.ComputedStyle(elementNode, style) : /** @type {?WebInspector.ComputedStyleModel.ComputedStyle} */(null);
}
},
__proto__: WebInspector.Object.prototype
}
/**
* @constructor
* @param {!WebInspector.DOMNode} node
* @param {!Map.<string, string>} computedStyle
*/
WebInspector.ComputedStyleModel.ComputedStyle = function(node, computedStyle)
{
this.node = node;
this.computedStyle = computedStyle;
}