diff options
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/CSSStyleDeclaration.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/CSSStyleDeclaration.js | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/CSSStyleDeclaration.js b/Source/WebInspectorUI/UserInterface/CSSStyleDeclaration.js new file mode 100644 index 000000000..eaab18787 --- /dev/null +++ b/Source/WebInspectorUI/UserInterface/CSSStyleDeclaration.js @@ -0,0 +1,310 @@ +/* + * 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; |