summaryrefslogtreecommitdiff
path: root/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js')
-rw-r--r--Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js362
1 files changed, 362 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js b/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js
new file mode 100644
index 000000000..8a7ba5f8f
--- /dev/null
+++ b/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js
@@ -0,0 +1,362 @@
+/*
+ * 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 = class CSSStyleDeclaration extends WebInspector.Object
+{
+ constructor(nodeStyles, ownerStyleSheet, id, type, node, inherited, text, properties, styleSheetTextRange)
+ {
+ super();
+
+ 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._initialText = text;
+ this._hasModifiedInitialText = false;
+
+ this.update(text, properties, styleSheetTextRange, true);
+ }
+
+ // 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()
+ {
+ if (!this._id)
+ return false;
+
+ if (this._type === WebInspector.CSSStyleDeclaration.Type.Rule)
+ return this._ownerRule && this._ownerRule.editable;
+
+ if (this._type === WebInspector.CSSStyleDeclaration.Type.Inline)
+ return !this._node.isInUserAgentShadowTree();
+
+ return false;
+ }
+
+ update(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.includes(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.includes(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, 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;
+
+ let trimmedText = WebInspector.CSSStyleDeclarationTextEditor.PrefixWhitespace + text.trim();
+ if (this._text === trimmedText)
+ return;
+
+ if (trimmedText === WebInspector.CSSStyleDeclarationTextEditor.PrefixWhitespace || this._type === WebInspector.CSSStyleDeclaration.Type.Inline)
+ text = trimmedText;
+
+ let modified = text !== this._initialText;
+ if (modified !== this._hasModifiedInitialText) {
+ this._hasModifiedInitialText = modified;
+ this.dispatchEventToListeners(WebInspector.CSSStyleDeclaration.Event.InitialTextModified);
+ }
+
+ this._nodeStyles.changeStyleText(this, text);
+ }
+
+ resetText()
+ {
+ this.text = this._initialText;
+ }
+
+ get modified()
+ {
+ return this._hasModifiedInitialText;
+ }
+
+ 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;
+ }
+
+ get mediaList()
+ {
+ if (this._ownerRule)
+ return this._ownerRule.mediaList;
+ return [];
+ }
+
+ get selectorText()
+ {
+ if (this._ownerRule)
+ return this._ownerRule.selectorText;
+ return this._node.appropriateSelectorFor(true);
+ }
+
+ propertyForName(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;
+ }
+
+ generateCSSRuleString()
+ {
+ let indentString = WebInspector.indentString();
+ let styleText = "";
+ let mediaList = this.mediaList;
+ let mediaQueriesCount = mediaList.length;
+ for (let i = mediaQueriesCount - 1; i >= 0; --i)
+ styleText += indentString.repeat(mediaQueriesCount - i - 1) + "@media " + mediaList[i].text + " {\n";
+
+ styleText += indentString.repeat(mediaQueriesCount) + this.selectorText + " {\n";
+
+ for (let property of this._properties) {
+ if (property.anonymous)
+ continue;
+
+ styleText += indentString.repeat(mediaQueriesCount + 1) + property.text.trim();
+
+ if (!styleText.endsWith(";"))
+ styleText += ";";
+
+ styleText += "\n";
+ }
+
+ for (let i = mediaQueriesCount; i > 0; --i)
+ styleText += indentString.repeat(i) + "}\n";
+
+ styleText += "}";
+
+ return styleText;
+ }
+
+ isInspectorRule()
+ {
+ return this._ownerRule && this._ownerRule.type === WebInspector.CSSStyleSheet.Type.Inspector;
+ }
+
+ hasProperties()
+ {
+ return !!this._properties.length;
+ }
+
+ // Protected
+
+ get nodeStyles()
+ {
+ return this._nodeStyles;
+ }
+};
+
+WebInspector.CSSStyleDeclaration.Event = {
+ PropertiesChanged: "css-style-declaration-properties-changed",
+ InitialTextModified: "css-style-declaration-initial-text-modified"
+};
+
+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"
+};