| /* |
| * Copyright (C) 2013 Apple 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: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. 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. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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. |
| */ |
| |
| WebInspector.CSSStyleDeclaration = function(nodeStyles, ownerStyleSheet, id, type, node, inherited, text, properties, styleSheetTextRange) |
| { |
| WebInspector.Object.call(this); |
| |
| console.assert(nodeStyles); |
| this._nodeStyles = nodeStyles; |
| |
| this._ownerRule = null; |
| |
| this._ownerStyleSheet = ownerStyleSheet || null; |
| this._id = id || null; |
| this._type = type || null; |
| this._node = node || null; |
| this._inherited = inherited || false; |
| |
| this._pendingProperties = []; |
| this._propertyNameMap = {}; |
| |
| this.update(text, properties, styleSheetTextRange, true); |
| }; |
| |
| WebInspector.Object.addConstructorFunctions(WebInspector.CSSStyleDeclaration); |
| |
| WebInspector.CSSStyleDeclaration.Event = { |
| PropertiesChanged: "css-style-declaration-properties-changed" |
| }; |
| |
| WebInspector.CSSStyleDeclaration.Type = { |
| Rule: "css-style-declaration-type-rule", |
| Inline: "css-style-declaration-type-inline", |
| Attribute: "css-style-declaration-type-attribute", |
| Computed: "css-style-declaration-type-computed" |
| }; |
| |
| WebInspector.CSSStyleDeclaration.prototype = { |
| constructor: WebInspector.CSSStyleDeclaration, |
| |
| // Public |
| |
| get id() |
| { |
| return this._id; |
| }, |
| |
| get ownerStyleSheet() |
| { |
| return this._ownerStyleSheet; |
| }, |
| |
| get type() |
| { |
| return this._type; |
| }, |
| |
| get inherited() |
| { |
| return this._inherited; |
| }, |
| |
| get node() |
| { |
| return this._node; |
| }, |
| |
| get editable() |
| { |
| return !!this._id && ((this._type === WebInspector.CSSStyleDeclaration.Type.Rule && this._ownerRule && this._ownerRule.editable) || this._type === WebInspector.CSSStyleDeclaration.Type.Inline); |
| }, |
| |
| update: function(text, properties, styleSheetTextRange, dontFireEvents) |
| { |
| text = text || ""; |
| properties = properties || []; |
| |
| var oldProperties = this._properties || []; |
| var oldText = this._text; |
| |
| this._text = text; |
| this._properties = properties; |
| this._styleSheetTextRange = styleSheetTextRange; |
| this._propertyNameMap = {}; |
| |
| delete this._visibleProperties; |
| |
| var editable = this.editable; |
| |
| for (var i = 0; i < this._properties.length; ++i) { |
| var property = this._properties[i]; |
| property.ownerStyle = this; |
| |
| // Store the property in a map if we arn't editable. This |
| // allows for quick lookup for computed style. Editable |
| // styles don't use the map since they need to account for |
| // overridden properties. |
| if (!editable) |
| this._propertyNameMap[property.name] = property; |
| else { |
| // Remove from pendingProperties (if it was pending). |
| this._pendingProperties.remove(property); |
| } |
| } |
| |
| var removedProperties = []; |
| for (var i = 0; i < oldProperties.length; ++i) { |
| var oldProperty = oldProperties[i]; |
| |
| if (!this._properties.contains(oldProperty)) { |
| // Clear the index, since it is no longer valid. |
| oldProperty.index = NaN; |
| |
| removedProperties.push(oldProperty); |
| |
| // Keep around old properties in pending in case they |
| // are needed again during editing. |
| if (editable) |
| this._pendingProperties.push(oldProperty); |
| } |
| } |
| |
| if (dontFireEvents) |
| return; |
| |
| var addedProperties = []; |
| for (var i = 0; i < this._properties.length; ++i) { |
| if (!oldProperties.contains(this._properties[i])) |
| addedProperties.push(this._properties[i]); |
| } |
| |
| // Don't fire the event if there is text and it hasn't changed. |
| if (oldText && this._text && oldText === this._text) { |
| // We shouldn't have any added or removed properties in this case. |
| console.assert(!addedProperties.length && !removedProperties.length); |
| if (!addedProperties.length && !removedProperties.length) |
| return; |
| } |
| |
| function delayed() |
| { |
| this.dispatchEventToListeners(WebInspector.CSSStyleDeclaration.Event.PropertiesChanged, {addedProperties: addedProperties, removedProperties: removedProperties}); |
| } |
| |
| // Delay firing the PropertiesChanged event so DOMNodeStyles has a chance to mark overridden and associated properties. |
| setTimeout(delayed.bind(this), 0); |
| }, |
| |
| get ownerRule() |
| { |
| return this._ownerRule; |
| }, |
| |
| set ownerRule(rule) |
| { |
| this._ownerRule = rule || null; |
| }, |
| |
| get text() |
| { |
| return this._text; |
| }, |
| |
| set text(text) |
| { |
| if (this._text === text) |
| return; |
| |
| this._nodeStyles.changeStyleText(this, text); |
| }, |
| |
| get properties() |
| { |
| return this._properties; |
| }, |
| |
| get visibleProperties() |
| { |
| if (this._visibleProperties) |
| return this._visibleProperties; |
| |
| this._visibleProperties = this._properties.filter(function(property) { |
| return !!property.styleDeclarationTextRange; |
| }); |
| |
| return this._visibleProperties; |
| }, |
| |
| get pendingProperties() |
| { |
| return this._pendingProperties; |
| }, |
| |
| get styleSheetTextRange() |
| { |
| return this._styleSheetTextRange; |
| }, |
| |
| propertyForName: function(name, dontCreateIfMissing) |
| { |
| console.assert(name); |
| if (!name) |
| return null; |
| |
| if (!this.editable) |
| return this._propertyNameMap[name] || null; |
| |
| // Editable styles don't use the map since they need to |
| // account for overridden properties. |
| |
| function findMatch(properties) |
| { |
| for (var i = 0; i < properties.length; ++i) { |
| var property = properties[i]; |
| if (property.canonicalName !== name && property.name !== name) |
| continue; |
| if (bestMatchProperty && !bestMatchProperty.overridden && property.overridden) |
| continue; |
| bestMatchProperty = property; |
| } |
| } |
| |
| var bestMatchProperty = null; |
| |
| findMatch(this._properties); |
| |
| if (bestMatchProperty) |
| return bestMatchProperty; |
| |
| if (dontCreateIfMissing || !this.editable) |
| return null; |
| |
| findMatch(this._pendingProperties, true); |
| |
| if (bestMatchProperty) |
| return bestMatchProperty; |
| |
| var newProperty = new WebInspector.CSSProperty(NaN, null, name); |
| newProperty.ownerStyle = this; |
| |
| this._pendingProperties.push(newProperty); |
| |
| return newProperty; |
| }, |
| |
| addProperty: function(property) |
| { |
| console.assert(property); |
| if (!property) |
| return; |
| |
| console.assert(property.ownerStyle === this); |
| if (property.ownerStyle !== this) |
| return; |
| |
| console.assert(this.editable); |
| if (!this.editable) |
| return; |
| |
| this._nodeStyles.addProperty(property); |
| }, |
| |
| removeProperty: function(property) |
| { |
| console.assert(property); |
| if (!property) |
| return; |
| |
| console.assert(property.ownerStyle === this); |
| if (property.ownerStyle !== this) |
| return; |
| |
| console.assert(this.editable); |
| if (!this.editable) |
| return; |
| |
| this._nodeStyles.removeProperty(property); |
| }, |
| |
| // Protected |
| |
| get nodeStyles() |
| { |
| return this._nodeStyles; |
| } |
| }; |
| |
| WebInspector.CSSStyleDeclaration.prototype.__proto__ = WebInspector.Object.prototype; |