summaryrefslogtreecommitdiff
path: root/Source/WebInspectorUI/UserInterface/DOMNodeStyles.js
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/DOMNodeStyles.js')
-rw-r--r--Source/WebInspectorUI/UserInterface/DOMNodeStyles.js1050
1 files changed, 0 insertions, 1050 deletions
diff --git a/Source/WebInspectorUI/UserInterface/DOMNodeStyles.js b/Source/WebInspectorUI/UserInterface/DOMNodeStyles.js
deleted file mode 100644
index d5c5801b5..000000000
--- a/Source/WebInspectorUI/UserInterface/DOMNodeStyles.js
+++ /dev/null
@@ -1,1050 +0,0 @@
-/*
- * 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.DOMNodeStyles = function(node)
-{
- WebInspector.Object.call(this);
-
- console.assert(node);
- this._node = node || null;
-
- this._rulesMap = {};
- this._styleDeclarationsMap = {};
-
- this._matchedRules = [];
- this._inheritedRules = [];
- this._pseudoElements = {};
- this._inlineStyle = null;
- this._attributesStyle = null;
- this._computedStyle = null;
- this._orderedStyles = [];
- this._stylesNeedingTextCommited = [];
-
- this._propertyNameToEffectivePropertyMap = {};
-
- this.refresh();
-};
-
-WebInspector.Object.addConstructorFunctions(WebInspector.DOMNodeStyles);
-
-WebInspector.DOMNodeStyles.Event = {
- NeedsRefresh: "dom-node-styles-needs-refresh",
- Refreshed: "dom-node-styles-refreshed"
-};
-
-WebInspector.DOMNodeStyles.prototype = {
- constructor: WebInspector.DOMNodeStyles,
-
- // Public
-
- get node()
- {
- return this._node;
- },
-
- get needsRefresh()
- {
- return this._refreshPending || this._needsRefresh;
- },
-
- refreshIfNeeded: function()
- {
- if (!this._needsRefresh)
- return;
- this.refresh();
- },
-
- refresh: function()
- {
- if (this._refreshPending)
- return;
-
- this._needsRefresh = false;
- this._refreshPending = true;
-
- function parseRuleMatchArrayPayload(matchArray, node, inherited)
- {
- var result = [];
-
- var ruleOccurrences = {};
-
- // Iterate in reverse order to match the cascade order.
- for (var i = matchArray.length - 1; i >= 0; --i) {
- // COMPATIBILITY (iOS 6): This was just an array of rules, now it is an array of matches that have
- // a 'rule' property. Support both here. And 'matchingSelectors' does not exist on iOS 6.
- var matchedSelectorIndices = matchArray[i].matchingSelectors || [];
- var rule = this._parseRulePayload(matchArray[i].rule || matchArray[i], matchedSelectorIndices, node, inherited, ruleOccurrences);
- if (!rule)
- continue;
- result.push(rule);
- }
-
- return result;
- }
-
- function fetchedMatchedStyles(error, matchedRulesPayload, pseudoElementRulesPayload, inheritedRulesPayload)
- {
- matchedRulesPayload = matchedRulesPayload || [];
- pseudoElementRulesPayload = pseudoElementRulesPayload || [];
- inheritedRulesPayload = inheritedRulesPayload || [];
-
- // Move the current maps to previous.
- this._previousRulesMap = this._rulesMap;
- this._previousStyleDeclarationsMap = this._styleDeclarationsMap;
-
- // Clear the current maps.
- this._rulesMap = {};
- this._styleDeclarationsMap = {};
-
- this._matchedRules = parseRuleMatchArrayPayload.call(this, matchedRulesPayload, this._node);
-
- this._pseudoElements = {};
- for (var i = 0; i < pseudoElementRulesPayload.length; ++i) {
- var pseudoElementRulePayload = pseudoElementRulesPayload[i];
-
- // COMPATIBILITY (iOS 6): The entry payload had a 'rules' property, now it has a 'matches' property. Support both here.
- var pseudoElementRules = parseRuleMatchArrayPayload.call(this, pseudoElementRulePayload.matches || pseudoElementRulePayload.rules, this._node);
- this._pseudoElements[pseudoElementRulePayload.pseudoId] = {matchedRules: pseudoElementRules};
- }
-
- this._inheritedRules = [];
-
- var i = 0;
- var currentNode = this._node.parentNode;
- while (currentNode && i < inheritedRulesPayload.length) {
- var inheritedRulePayload = inheritedRulesPayload[i];
-
- var inheritedRuleInfo = {node: currentNode};
- inheritedRuleInfo.inlineStyle = inheritedRulePayload.inlineStyle ? this._parseStyleDeclarationPayload(inheritedRulePayload.inlineStyle, currentNode, true, WebInspector.CSSStyleDeclaration.Type.Inline) : null;
- inheritedRuleInfo.matchedRules = inheritedRulePayload.matchedCSSRules ? parseRuleMatchArrayPayload.call(this, inheritedRulePayload.matchedCSSRules, currentNode, true) : [];
-
- if (inheritedRuleInfo.inlineStyle || inheritedRuleInfo.matchedRules.length)
- this._inheritedRules.push(inheritedRuleInfo);
-
- currentNode = currentNode.parentNode;
- ++i;
- }
- }
-
- function fetchedInlineStyles(error, inlineStylePayload, attributesStylePayload)
- {
- this._inlineStyle = inlineStylePayload ? this._parseStyleDeclarationPayload(inlineStylePayload, this._node, false, WebInspector.CSSStyleDeclaration.Type.Inline) : null;
- this._attributesStyle = attributesStylePayload ? this._parseStyleDeclarationPayload(attributesStylePayload, this._node, false, WebInspector.CSSStyleDeclaration.Type.Attribute) : null;
-
- this._updateStyleCascade();
- }
-
- function fetchedComputedStyle(error, computedPropertiesPayload)
- {
- var properties = [];
- for (var i = 0; computedPropertiesPayload && i < computedPropertiesPayload.length; ++i) {
- var propertyPayload = computedPropertiesPayload[i];
-
- var canonicalName = WebInspector.cssStyleManager.canonicalNameForPropertyName(propertyPayload.name);
- propertyPayload.implicit = !this._propertyNameToEffectivePropertyMap[canonicalName];
-
- var property = this._parseStylePropertyPayload(propertyPayload, NaN, this._computedStyle);
- properties.push(property);
- }
-
- if (this._computedStyle)
- this._computedStyle.update(null, properties);
- else
- this._computedStyle = new WebInspector.CSSStyleDeclaration(this, null, null, WebInspector.CSSStyleDeclaration.Type.Computed, this._node, false, null, properties);
-
- this._refreshPending = false;
-
- var significantChange = this._previousSignificantChange || false;
- if (!significantChange) {
- for (var key in this._styleDeclarationsMap) {
- // Check if the same key exists in the previous map and has the same style objects.
- if (key in this._previousStyleDeclarationsMap && Object.shallowEqual(this._styleDeclarationsMap[key], this._previousStyleDeclarationsMap[key]))
- continue;
-
- if (!this._includeUserAgentRulesOnNextRefresh) {
- // We can assume all the styles with the same key are from the same stylesheet and rule, so we only check the first.
- var firstStyle = this._styleDeclarationsMap[key][0];
- if (firstStyle && firstStyle.ownerRule && firstStyle.ownerRule.type === WebInspector.CSSRule.Type.UserAgent) {
- // User Agent styles get different identifiers after some edits. This would cause us to fire a significant refreshed
- // event more than it is helpful. And since the user agent stylesheet is static it shouldn't match differently
- // between refreshes for the same node. This issue is tracked by: https://webkit.org/b/110055
- continue;
- }
- }
-
- // This key is new or has different style objects than before. This is a significant change.
- significantChange = true;
- break;
- }
- }
-
- if (!significantChange) {
- for (var key in this._previousStyleDeclarationsMap) {
- // Check if the same key exists in current map. If it does exist it was already checked for equality above.
- if (key in this._styleDeclarationsMap)
- continue;
-
- if (!this._includeUserAgentRulesOnNextRefresh) {
- // See above for why we skip user agent style rules.
- var firstStyle = this._previousStyleDeclarationsMap[key][0];
- if (firstStyle && firstStyle.ownerRule && firstStyle.ownerRule.type === WebInspector.CSSRule.Type.UserAgent)
- continue;
- }
-
- // This key no longer exists. This is a significant change.
- significantChange = true;
- break;
- }
- }
-
- delete this._includeUserAgentRulesOnNextRefresh;
-
- // Delete the previous maps now that any reused rules and style have been moved over.
- delete this._previousRulesMap;
- delete this._previousStyleDeclarationsMap;
-
- var styleToCommit = this._stylesNeedingTextCommited.shift();
- if (styleToCommit) {
- // Remember the significant change flag so we can pass it along when the pending style
- // changes trigger a refresh. If we wait to scan later we might not find a significant change
- // and fail to tell listeners about it.
- this._previousSignificantChange = significantChange;
-
- this.changeStyleText(styleToCommit, styleToCommit.__pendingText);
-
- return;
- }
-
- // Delete the previous saved significant change flag so we rescan for a significant change next time.
- delete this._previousSignificantChange;
-
- this.dispatchEventToListeners(WebInspector.DOMNodeStyles.Event.Refreshed, {significantChange: significantChange});
- }
-
- CSSAgent.getMatchedStylesForNode.invoke({nodeId: this._node.id, includePseudo: true, includeInherited: true}, fetchedMatchedStyles.bind(this));
- CSSAgent.getInlineStylesForNode.invoke({nodeId: this._node.id}, fetchedInlineStyles.bind(this));
- CSSAgent.getComputedStyleForNode.invoke({nodeId: this._node.id}, fetchedComputedStyle.bind(this));
- },
-
- addRule: function(selector)
- {
- function addedRule(error, rulePayload)
- {
- if (error)
- return;
-
- DOMAgent.markUndoableState();
-
- this.refresh();
- }
-
- selector = selector || this._node.appropriateSelectorFor(true);
-
- CSSAgent.addRule.invoke({contextNodeId: this._node.id, selector: selector}, addedRule.bind(this));
- },
-
- get matchedRules()
- {
- return this._matchedRules;
- },
-
- get inheritedRules()
- {
- return this._inheritedRules;
- },
-
- get inlineStyle()
- {
- return this._inlineStyle;
- },
-
- get attributesStyle()
- {
- return this._attributesStyle;
- },
-
- get pseudoElements()
- {
- return this._pseudoElements;
- },
-
- get computedStyle()
- {
- return this._computedStyle;
- },
-
- get orderedStyles()
- {
- return this._orderedStyles;
- },
-
- effectivePropertyForName: function(name)
- {
- var canonicalName = WebInspector.cssStyleManager.canonicalNameForPropertyName(name);
- return this._propertyNameToEffectivePropertyMap[canonicalName] || null;
- },
-
- // Protected
-
- mediaQueryResultDidChange: function()
- {
- this._markAsNeedsRefresh();
- },
-
- pseudoClassesDidChange: function(node)
- {
- this._includeUserAgentRulesOnNextRefresh = true;
- this._markAsNeedsRefresh();
- },
-
- attributeDidChange: function(node, attributeName)
- {
- // Ignore the attribute we know we just changed and handled above.
- if (this._ignoreNextStyleAttributeDidChangeEvent && node === this._node && attributeName === "style") {
- delete this._ignoreNextStyleAttributeDidChangeEvent;
- return;
- }
-
- this._markAsNeedsRefresh();
- },
-
- changeRuleSelector: function(rule, selector)
- {
- selector = selector || "";
-
- function ruleSelectorChanged(error, rulePayload)
- {
- DOMAgent.markUndoableState();
-
- // Do a full refresh incase the rule no longer matches the node or the
- // matched selector indices changed.
- this.refresh();
- }
-
- this._needsRefresh = true;
- this._ignoreNextContentDidChangeForStyleSheet = rule.ownerStyleSheet;
-
- CSSAgent.setRuleSelector(rule.id, selector, ruleSelectorChanged.bind(this));
- },
-
- changeStyleText: function(style, text)
- {
- if (!style.ownerStyleSheet || !style.styleSheetTextRange)
- return;
-
- text = text || "";
-
- if (CSSAgent.setStyleText) {
- function styleChanged(error, stylePayload)
- {
- if (error)
- return;
- this.refresh();
- }
-
- CSSAgent.setStyleText(style.id, text, styleChanged.bind(this));
- return;
- }
-
- // COMPATIBILITY (iOS 6): CSSAgent.setStyleText was not available in iOS 6.
-
- // Setting the text on CSSStyleSheet for inline styles causes a crash. https://webkit.org/b/110359
- // So we just set the style attribute to get the same affect. This also avoids SourceCodeRevisions.
- if (style.type === WebInspector.CSSStyleDeclaration.Type.Inline) {
- text = text.trim();
-
- function attributeChanged(error)
- {
- if (error)
- return;
- this.refresh();
- }
-
- this._ignoreNextStyleAttributeDidChangeEvent = true;
-
- if (text)
- style.node.setAttributeValue("style", text, attributeChanged.bind(this));
- else
- style.node.removeAttribute("style", attributeChanged.bind(this));
-
- return;
- }
-
- if (this._needsRefresh || this._refreshPending) {
- // If we need refreshed then it is not safe to use the styleSheetTextRange since the range likely has
- // changed and we need updated ranges. Store the text and remember the style so we can commit it after
- // the next refresh.
-
- style.__pendingText = text;
-
- if (!this._stylesNeedingTextCommited.contains(style))
- this._stylesNeedingTextCommited.push(style);
-
- return;
- }
-
- function fetchedStyleSheetContent(styleSheet, content)
- {
- console.assert(style.styleSheetTextRange);
- if (!style.styleSheetTextRange)
- return;
-
- var startOffset = style.styleSheetTextRange.startOffset;
- var endOffset = style.styleSheetTextRange.endOffset;
-
- if (isNaN(startOffset) || isNaN(endOffset)) {
- style.styleSheetTextRange.resolveOffsets(content);
-
- startOffset = style.styleSheetTextRange.startOffset;
- endOffset = style.styleSheetTextRange.endOffset;
- }
-
- console.assert(!isNaN(startOffset));
- console.assert(!isNaN(endOffset));
- if (isNaN(startOffset) || isNaN(endOffset))
- return;
-
- function contentDidChange()
- {
- style.ownerStyleSheet.removeEventListener(WebInspector.CSSStyleSheet.Event.ContentDidChange, contentDidChange, this);
-
- this.refresh();
- }
-
- style.ownerStyleSheet.addEventListener(WebInspector.CSSStyleSheet.Event.ContentDidChange, contentDidChange, this);
-
- var newContent = content.substring(0, startOffset) + text + content.substring(endOffset);
-
- WebInspector.branchManager.currentBranch.revisionForRepresentedObject(style.ownerStyleSheet).content = newContent;
- }
-
- this._stylesNeedingTextCommited.remove(style);
- delete style.__pendingText;
-
- this._needsRefresh = true;
- this._ignoreNextContentDidChangeForStyleSheet = style.ownerStyleSheet;
-
- style.ownerStyleSheet.requestContent(fetchedStyleSheetContent.bind(this));
- },
-
- changeProperty: function(property, name, value, priority)
- {
- var text = name ? name + ": " + value + (priority ? " !" + priority : "") + ";" : "";
- this.changePropertyText(property, text);
- },
-
- changePropertyText: function(property, text)
- {
- text = text || "";
-
- var index = property.index;
- var newProperty = isNaN(index);
- var overwrite = true;
-
- // If this is a new property, then give it an index at the end of the current properties.
- // Also don't overwrite, which will cause the property to be added at that index.
- if (newProperty) {
- index = property.ownerStyle.properties.length;
- overwrite = false;
- }
-
- if (text && text.charAt(text.length - 1) !== ";")
- text += ";";
-
- this._needsRefresh = true;
- this._ignoreNextContentDidChangeForStyleSheet = property.ownerStyle.ownerStyleSheet;
-
- CSSAgent.setPropertyText(property.ownerStyle.id, index, text, overwrite, this._handlePropertyChange.bind(this, property));
- },
-
- changePropertyEnabledState: function(property, enabled)
- {
- enabled = !!enabled;
-
- // Can't change a pending property with a NaN index.
- if (isNaN(property.index))
- return;
-
- this._ignoreNextContentDidChangeForStyleSheet = property.ownerStyle.ownerStyleSheet;
-
- CSSAgent.toggleProperty(property.ownerStyle.id, property.index, !enabled, this._handlePropertyChange.bind(this, property));
- },
-
- addProperty: function(property)
- {
- // Can't add a property unless it has a NaN index.
- if (!isNaN(property.index))
- return;
-
- // Adding is done by setting the text.
- this.changePropertyText(property, property.text);
- },
-
- removeProperty: function(property)
- {
- // Can't remove a pending property with a NaN index.
- if (isNaN(property.index))
- return;
-
- // Removing is done by setting text to an empty string.
- this.changePropertyText(property, "");
- },
-
- // Private
-
- _handlePropertyChange: function(property, error, stylePayload)
- {
- if (error)
- return;
-
- DOMAgent.markUndoableState();
-
- // Do a refresh instead of handling stylePayload so computed style is updated and we get valid
- // styleSheetTextRange values for all the rules after this change.
- this.refresh();
- },
-
- _createSourceCodeLocation: function(sourceURL, sourceLine, sourceColumn)
- {
- if (!sourceURL)
- return null;
-
- var sourceCode;
-
- // Try to use the node to find the frame which has the correct resource first.
- if (this._node.ownerDocument) {
- var mainResource = WebInspector.frameResourceManager.resourceForURL(this._node.ownerDocument.documentURL);
- if (mainResource) {
- var parentFrame = mainResource.parentFrame;
- sourceCode = parentFrame.resourceForURL(sourceURL);
- }
- }
-
- // If that didn't find the resource, then search all frames.
- if (!sourceCode)
- sourceCode = WebInspector.frameResourceManager.resourceForURL(sourceURL);
-
- if (!sourceCode)
- return null;
-
- return sourceCode.createSourceCodeLocation(sourceLine || 0, sourceColumn || 0);
- },
-
- _parseSourceRangePayload: function(payload, text)
- {
- if (!payload)
- return null;
-
- // COMPATIBILITY (iOS 6): The range use to only contain start and end offsets. Now it
- // has line and column for the start and end position. Support both here.
- if ("start" in payload && "end" in payload) {
- var textRange = new WebInspector.TextRange(payload.start, payload.end);
- if (typeof text === "string")
- textRange.resolveLinesAndColumns(text);
- return textRange;
- }
-
- return new WebInspector.TextRange(payload.startLine, payload.startColumn, payload.endLine, payload.endColumn);
- },
-
- _parseStylePropertyPayload: function(payload, index, styleDeclaration, styleText)
- {
- var text = payload.text || "";
- var name = payload.name;
- var value = (payload.value || "").replace(/\s*!important\s*$/, "");
- var priority = payload.priority || "";
-
- var enabled = true;
- var overridden = false;
- var implicit = payload.implicit || false;
- var anonymous = false;
- var valid = "parsedOk" in payload ? payload.parsedOk : true;
-
- switch (payload.status || "style") {
- case "active":
- enabled = true;
- break;
- case "inactive":
- overridden = true;
- enabled = true;
- break;
- case "disabled":
- enabled = false;
- break;
- case "style":
- anonymous = true;
- break;
- }
-
- var styleSheetTextRange = null;
- var styleDeclarationTextRange = null;
-
- // COMPATIBILITY (iOS 6): The range is in the style text, not the whole stylesheet.
- // Later the range was changed to be in the whole stylesheet.
- if (payload.range && "start" in payload.range && "end" in payload.range)
- styleDeclarationTextRange = this._parseSourceRangePayload(payload.range, styleText);
- else
- styleSheetTextRange = this._parseSourceRangePayload(payload.range);
-
- if (styleDeclaration) {
- // Use propertyForName when the index is NaN since propertyForName is fast in that case.
- var property = isNaN(index) ? styleDeclaration.propertyForName(name, true) : styleDeclaration.properties[index];
-
- // Reuse a property if the index and name matches. Otherwise it is a different property
- // and should be created from scratch. This works in the simple cases where only existing
- // properties change in place and no properties are inserted or deleted at the beginning.
- // FIXME: This could be smarter by ignoring index and just go by name. However, that gets
- // tricky for rules that have more than one property with the same name.
- if (property && property.name === name && (property.index === index || (isNaN(property.index) && isNaN(index)))) {
- property.update(text, name, value, priority, enabled, overridden, implicit, anonymous, valid, styleSheetTextRange, styleDeclarationTextRange);
- return property;
- }
-
- // Reuse a pending property with the same name. These properties are pending being committed,
- // so if we find a match that likely means it got committed and we should use it.
- var pendingProperties = styleDeclaration.pendingProperties;
- for (var i = 0; i < pendingProperties.length; ++i) {
- var pendingProperty = pendingProperties[i];
- if (pendingProperty.name === name && isNaN(pendingProperty.index)) {
- pendingProperty.index = index;
- pendingProperty.update(text, name, value, priority, enabled, overridden, implicit, anonymous, valid, styleSheetTextRange, styleDeclarationTextRange);
- return pendingProperty;
- }
- }
- }
-
- return new WebInspector.CSSProperty(index, text, name, value, priority, enabled, overridden, implicit, anonymous, valid, styleSheetTextRange, styleDeclarationTextRange);
- },
-
- _parseStyleDeclarationPayload: function(payload, node, inherited, type, rule, updateAllStyles)
- {
- if (!payload)
- return null;
-
- rule = rule || null;
- inherited = inherited || false;
-
- var id = payload.styleId;
- var mapKey = id ? id.styleSheetId + ":" + id.ordinal : null;
-
- var styleDeclaration = rule ? rule.style : null;
- var styleDeclarations = [];
-
- // Look for existing styles in the previous map if there is one, otherwise use the current map.
- var previousStyleDeclarationsMap = this._previousStyleDeclarationsMap || this._styleDeclarationsMap;
- if (mapKey && mapKey in previousStyleDeclarationsMap) {
- styleDeclarations = previousStyleDeclarationsMap[mapKey];
-
- // If we need to update all styles, then stop here and call _parseStyleDeclarationPayload for each style.
- // We need to parse multiple times so we reuse the right properties from each style.
- if (updateAllStyles && styleDeclarations.length) {
- for (var i = 0; i < styleDeclarations.length; ++i) {
- var styleDeclaration = styleDeclarations[i];
- this._parseStyleDeclarationPayload(payload, styleDeclaration.node, styleDeclaration.inherited, styleDeclaration.type, styleDeclaration.ownerRule);
- }
-
- return;
- }
-
- if (!styleDeclaration) {
- var filteredStyleDeclarations = styleDeclarations.filter(function(styleDeclaration) {
- // This case only applies for styles that are not part of a rule.
- if (styleDeclaration.ownerRule) {
- console.assert(!rule);
- return false;
- }
-
- if (styleDeclaration.node !== node)
- return false;
-
- if (styleDeclaration.inherited !== inherited)
- return false;
-
- return true;
- });
-
- console.assert(filteredStyleDeclarations.length <= 1);
- styleDeclaration = filteredStyleDeclarations[0] || null;
- }
- }
-
- if (previousStyleDeclarationsMap !== this._styleDeclarationsMap) {
- // If the previous and current maps differ then make sure the found styleDeclaration is added to the current map.
- styleDeclarations = mapKey && mapKey in this._styleDeclarationsMap ? this._styleDeclarationsMap[mapKey] : [] ;
-
- if (styleDeclaration && !styleDeclarations.contains(styleDeclaration)) {
- styleDeclarations.push(styleDeclaration);
- this._styleDeclarationsMap[mapKey] = styleDeclarations;
- }
- }
-
- var shorthands = {};
- for (var i = 0; payload.shorthandEntries && i < payload.shorthandEntries.length; ++i) {
- var shorthand = payload.shorthandEntries[i];
- shorthands[shorthand.name] = shorthand.value;
- }
-
- var text = payload.cssText;
-
- var inheritedPropertyCount = 0;
-
- var properties = [];
- for (var i = 0; payload.cssProperties && i < payload.cssProperties.length; ++i) {
- var propertyPayload = payload.cssProperties[i];
-
- if (inherited && propertyPayload.name in WebInspector.CSSKeywordCompletions.InheritedProperties)
- ++inheritedPropertyCount;
-
- var property = this._parseStylePropertyPayload(propertyPayload, i, styleDeclaration, text);
- properties.push(property);
- }
-
- if (inherited && !inheritedPropertyCount)
- return null;
-
- var styleSheetTextRange = this._parseSourceRangePayload(payload.range);
-
- if (styleDeclaration) {
- styleDeclaration.update(text, properties, styleSheetTextRange);
- return styleDeclaration;
- }
-
- var styleSheet = id ? WebInspector.cssStyleManager.styleSheetForIdentifier(id.styleSheetId) : null;
- if (styleSheet)
- styleSheet.addEventListener(WebInspector.CSSStyleSheet.Event.ContentDidChange, this._styleSheetContentDidChange, this);
-
- styleDeclaration = new WebInspector.CSSStyleDeclaration(this, styleSheet, id, type, node, inherited, text, properties, styleSheetTextRange);
-
- if (mapKey) {
- styleDeclarations.push(styleDeclaration);
- this._styleDeclarationsMap[mapKey] = styleDeclarations;
- }
-
- return styleDeclaration;
- },
-
- _parseRulePayload: function(payload, matchedSelectorIndices, node, inherited, ruleOccurrences)
- {
- if (!payload)
- return null;
-
- // User and User Agent rules don't have 'ruleId' in the payload. However, their style's have 'styleId' and
- // 'styleId' is the same identifier the backend uses for Author rule identifiers, so do the same here.
- // They are excluded by the backend because they are not editable, however our front-end does not determine
- // editability solely based on the existence of the id like the open source front-end does.
- var id = payload.ruleId || payload.style.styleId;
-
- var mapKey = id ? id.styleSheetId + ":" + id.ordinal + ":" + (inherited ? "I" : "N") + ":" + node.id : null;
-
- // Rules can match multiple times if they have multiple selectors or because of inheritance. We keep a count
- // of occurrences so we have unique rules per occurrence, that way properties will be correctly marked as overridden.
- var occurrence = 0;
- if (mapKey) {
- if (mapKey in ruleOccurrences)
- occurrence = ++ruleOccurrences[mapKey];
- else
- ruleOccurrences[mapKey] = occurrence;
- }
-
- // Append the occurrence number to the map key for lookup in the rules map.
- mapKey += ":" + occurrence;
-
- var rule = null;
-
- // Look for existing rules in the previous map if there is one, otherwise use the current map.
- var previousRulesMap = this._previousRulesMap || this._rulesMap;
- if (mapKey && mapKey in previousRulesMap) {
- rule = previousRulesMap[mapKey];
-
- if (previousRulesMap !== this._rulesMap) {
- // If the previous and current maps differ then make sure the found rule is added to the current map.
- this._rulesMap[mapKey] = rule;
- }
- }
-
- var style = this._parseStyleDeclarationPayload(payload.style, node, inherited, WebInspector.CSSStyleDeclaration.Type.Rule, rule);
- if (!style)
- return null;
-
- // COMPATIBILITY (iOS 6): The payload had 'selectorText' as a property,
- // now it has 'selectorList' with a 'text' property. Support both here.
- var selectorText = payload.selectorList ? payload.selectorList.text : payload.selectorText;
- var selectors = payload.selectorList ? payload.selectorList.selectors : [];
-
- // COMPATIBILITY (iOS 6): The payload did not have 'selectorList'.
- // Fallback to using 'sourceLine' without column information.
- if (payload.selectorList && payload.selectorList.range) {
- var sourceRange = payload.selectorList.range;
- var sourceCodeLocation = this._createSourceCodeLocation(payload.sourceURL, sourceRange.startLine, sourceRange.startColumn);
- } else
- var sourceCodeLocation = this._createSourceCodeLocation(payload.sourceURL, payload.sourceLine);
-
- var type;
- switch (payload.origin) {
- case "regular":
- type = WebInspector.CSSRule.Type.Author;
- break;
- case "user":
- type = WebInspector.CSSRule.Type.User;
- break;
- case "user-agent":
- type = WebInspector.CSSRule.Type.UserAgent;
- break;
- case "inspector":
- type = WebInspector.CSSRule.Type.Inspector;
- break;
- }
-
- var mediaList = [];
- for (var i = 0; payload.media && i < payload.media.length; ++i) {
- var mediaItem = payload.media[i];
-
- var mediaType;
- switch (mediaItem.source) {
- case "mediaRule":
- mediaType = WebInspector.CSSMedia.Type.MediaRule;
- break;
- case "importRule":
- mediaType = WebInspector.CSSMedia.Type.ImportRule;
- break;
- case "linkedSheet":
- mediaType = WebInspector.CSSMedia.Type.LinkedStyleSheet;
- break;
- case "inlineSheet":
- mediaType = WebInspector.CSSMedia.Type.InlineStyleSheet;
- break;
- }
-
- var mediaText = mediaItem.text;
- var mediaSourceCodeLocation = this._createSourceCodeLocation(mediaItem.sourceURL, mediaItem.sourceLine);
-
- mediaList.push(new WebInspector.CSSMedia(mediaType, mediaText, mediaSourceCodeLocation));
- }
-
- if (rule) {
- rule.update(sourceCodeLocation, selectorText, selectors, matchedSelectorIndices, style, mediaList);
- return rule;
- }
-
- var styleSheet = id ? WebInspector.cssStyleManager.styleSheetForIdentifier(id.styleSheetId) : null;
- if (styleSheet)
- styleSheet.addEventListener(WebInspector.CSSStyleSheet.Event.ContentDidChange, this._styleSheetContentDidChange, this);
-
- rule = new WebInspector.CSSRule(this, styleSheet, id, type, sourceCodeLocation, selectorText, selectors, matchedSelectorIndices, style, mediaList);
-
- if (mapKey)
- this._rulesMap[mapKey] = rule;
-
- return rule;
- },
-
- _markAsNeedsRefresh: function()
- {
- this._needsRefresh = true;
- this.dispatchEventToListeners(WebInspector.DOMNodeStyles.Event.NeedsRefresh);
- },
-
- _styleSheetContentDidChange: function(event)
- {
- var styleSheet = event.target;
- console.assert(styleSheet);
- if (!styleSheet)
- return;
-
- // Ignore the stylesheet we know we just changed and handled above.
- if (styleSheet === this._ignoreNextContentDidChangeForStyleSheet) {
- delete this._ignoreNextContentDidChangeForStyleSheet;
- return;
- }
-
- this._markAsNeedsRefresh();
- },
-
- _updateStyleCascade: function()
- {
- var cascadeOrderedStyleDeclarations = this._collectStylesInCascadeOrder(this._matchedRules, this._inlineStyle, this._attributesStyle);
-
- for (var i = 0; i < this._inheritedRules.length; ++i) {
- var inheritedStyleInfo = this._inheritedRules[i];
- var inheritedCascadeOrder = this._collectStylesInCascadeOrder(inheritedStyleInfo.matchedRules, inheritedStyleInfo.inlineStyle, null);
- cascadeOrderedStyleDeclarations = cascadeOrderedStyleDeclarations.concat(inheritedCascadeOrder);
- }
-
- this._orderedStyles = cascadeOrderedStyleDeclarations;
-
- this._propertyNameToEffectivePropertyMap = {};
-
- this._markOverriddenProperties(cascadeOrderedStyleDeclarations, this._propertyNameToEffectivePropertyMap);
- this._associateRelatedProperties(cascadeOrderedStyleDeclarations, this._propertyNameToEffectivePropertyMap);
-
- for (var pseudoIdentifier in this._pseudoElements) {
- var pseudoElementInfo = this._pseudoElements[pseudoIdentifier];
- pseudoElementInfo.orderedStyles = this._collectStylesInCascadeOrder(pseudoElementInfo.matchedRules, null, null);
- this._markOverriddenProperties(pseudoElementInfo.orderedStyles);
- this._associateRelatedProperties(pseudoElementInfo.orderedStyles);
- }
- },
-
- _collectStylesInCascadeOrder: function(matchedRules, inlineStyle, attributesStyle)
- {
- var result = [];
-
- // Inline style has the greatest specificity. So it goes first in the cascade order.
- if (inlineStyle)
- result.push(inlineStyle);
-
- var userAndUserAgentStyles = [];
-
- for (var i = 0; i < matchedRules.length; ++i) {
- var rule = matchedRules[i];
-
- // Only append to the result array here for author and inspector rules since attribute
- // styles come between author rules and user/user agent rules.
- switch (rule.type) {
- case WebInspector.CSSRule.Type.Inspector:
- case WebInspector.CSSRule.Type.Author:
- result.push(rule.style);
- break;
-
- case WebInspector.CSSRule.Type.User:
- case WebInspector.CSSRule.Type.UserAgent:
- userAndUserAgentStyles.push(rule.style);
- break;
- }
- }
-
- // Style properties from HTML attributes are next.
- if (attributesStyle)
- result.push(attributesStyle);
-
- // Finally add the user and user stylesheet's matched style rules we collected earlier.
- result = result.concat(userAndUserAgentStyles);
-
- return result;
- },
-
- _markOverriddenProperties: function(styles, propertyNameToEffectiveProperty)
- {
- propertyNameToEffectiveProperty = propertyNameToEffectiveProperty || {};
-
- for (var i = 0; i < styles.length; ++i) {
- var style = styles[i];
- var properties = style.properties;
-
- for (var j = 0; j < properties.length; ++j) {
- var property = properties[j];
- if (!property.enabled || property.anonymous || !property.valid) {
- property.overridden = false;
- continue;
- }
-
- if (style.inherited && !property.inherited) {
- property.overridden = false;
- continue;
- }
-
- var canonicalName = property.canonicalName;
- if (canonicalName in propertyNameToEffectiveProperty) {
- var effectiveProperty = propertyNameToEffectiveProperty[canonicalName];
-
- if (effectiveProperty.ownerStyle === property.ownerStyle) {
- if (effectiveProperty.important && !property.important) {
- property.overridden = true;
- continue;
- }
- } else if (effectiveProperty.important || !property.important || effectiveProperty.ownerStyle.node !== property.ownerStyle.node) {
- property.overridden = true;
- continue;
- }
-
- effectiveProperty.overridden = true;
- }
-
- property.overridden = false;
-
- propertyNameToEffectiveProperty[canonicalName] = property;
- }
- }
- },
-
- _associateRelatedProperties: function(styles, propertyNameToEffectiveProperty)
- {
- for (var i = 0; i < styles.length; ++i) {
- var properties = styles[i].properties;
-
- var knownShorthands = {};
-
- for (var j = 0; j < properties.length; ++j) {
- var property = properties[j];
-
- if (!property.valid)
- continue;
-
- if (!WebInspector.CSSCompletions.cssNameCompletions.isShorthandPropertyName(property.name))
- continue;
-
- if (knownShorthands[property.canonicalName] && !knownShorthands[property.canonicalName].overridden) {
- console.assert(property.overridden);
- continue;
- }
-
- knownShorthands[property.canonicalName] = property;
- }
-
- for (var j = 0; j < properties.length; ++j) {
- var property = properties[j];
-
- if (!property.valid)
- continue;
-
- var shorthandProperty = null;
-
- if (!isEmptyObject(knownShorthands)) {
- var possibleShorthands = WebInspector.CSSCompletions.cssNameCompletions.shorthandsForLonghand(property.canonicalName);
- for (var k = 0; k < possibleShorthands.length; ++k) {
- if (possibleShorthands[k] in knownShorthands) {
- shorthandProperty = knownShorthands[possibleShorthands[k]];
- break;
- }
- }
- }
-
- if (!shorthandProperty || shorthandProperty.overridden !== property.overridden) {
- property.relatedShorthandProperty = null;
- property.clearRelatedLonghandProperties();
- continue;
- }
-
- shorthandProperty.addRelatedLonghandProperty(property);
- property.relatedShorthandProperty = shorthandProperty;
-
- if (propertyNameToEffectiveProperty && propertyNameToEffectiveProperty[shorthandProperty.canonicalName] === shorthandProperty)
- propertyNameToEffectiveProperty[property.canonicalName] = property;
- }
- }
- }
-};
-
-WebInspector.DOMNodeStyles.prototype.__proto__ = WebInspector.Object.prototype;