diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/DOMNodeStyles.js | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/DOMNodeStyles.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/DOMNodeStyles.js | 1050 |
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; |