WebKit Bugzilla
Attachment 360192 Details for
Bug 193803
: Web Inspector: Add Changes panel to Elements tab
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
patch.txt (text/plain), 34.17 KB, created by
Nikita Vasilyev
on 2019-01-25 16:56:24 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Nikita Vasilyev
Created:
2019-01-25 16:56:24 PST
Size:
34.17 KB
patch
obsolete
>diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog >index 44053a80022..3bf1c2e12b6 100644 >--- a/Source/WebInspectorUI/ChangeLog >+++ b/Source/WebInspectorUI/ChangeLog >@@ -1,3 +1,88 @@ >+2019-01-25 Nikita Vasilyev <nvasilyev@apple.com> >+ >+ Web Inspector: Add Changes panel to Elements tab >+ https://bugs.webkit.org/show_bug.cgi?id=193803 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Introduce the new experimental Changes Panel. It shows a list of CSS changes >+ made via Web Inspector, so the changes could be copied to the source files. >+ >+ * Localizations/en.lproj/localizedStrings.js: >+ * UserInterface/Base/Setting.js: >+ * UserInterface/Controllers/CSSManager.js: >+ (WI.CSSManager): >+ (WI.CSSManager.prototype.getModifiedCSSRules): >+ (WI.CSSManager.prototype.addModifiedCSSRule): >+ (WI.CSSManager.prototype.removeModifiedCSSRule): >+ (WI.CSSManager.prototype._mainResourceDidChange): >+ * UserInterface/Main.html: >+ >+ * UserInterface/Models/CSSProperty.js: >+ (WI.CSSProperty): >+ (WI.CSSProperty.prototype.update): >+ (WI.CSSProperty.prototype.remove): >+ (WI.CSSProperty.prototype.replaceWithText): >+ (WI.CSSProperty.prototype.commentOut): >+ (WI.CSSProperty.prototype.set text): >+ (WI.CSSProperty.prototype.get modified): >+ (WI.CSSProperty.prototype.set name): >+ (WI.CSSProperty.prototype.set rawValue): >+ (WI.CSSProperty.prototype.get initialState): >+ (WI.CSSProperty.prototype._markModified): >+ (WI.CSSProperty.prototype._saveInitialState): >+ >+ * UserInterface/Models/CSSRule.js: >+ (WI.CSSRule): >+ (WI.CSSRule.prototype.get initialState): >+ (WI.CSSRule.prototype.markModified): >+ (WI.CSSRule.prototype._saveInitialState): >+ >+ * UserInterface/Models/CSSStyleDeclaration.js: >+ (WI.CSSStyleDeclaration): >+ (WI.CSSStyleDeclaration.prototype.markModified): >+ (WI.CSSStyleDeclaration.prototype.get enabledProperties): >+ (WI.CSSStyleDeclaration.prototype.get properties): >+ (WI.CSSStyleDeclaration.prototype.set properties): >+ (WI.CSSStyleDeclaration.prototype.get initialState): >+ (WI.CSSStyleDeclaration.prototype.propertyForName): >+ (WI.CSSStyleDeclaration.prototype.newBlankProperty): >+ (WI.CSSStyleDeclaration.prototype._saveInitialState): >+ >+ * UserInterface/Views/ChangesDetailsSidebarPanel.css: Added. >+ (.sidebar > .panel.changes-panel): >+ (.sidebar > .panel.changes-panel:not(.empty)): >+ (.sidebar > .panel.changes-panel.empty): >+ (.changes-panel ins): >+ (.changes-panel del): >+ (.changes-panel del.css-property::before): >+ (.changes-panel ins.css-property::before): >+ (@media (prefers-color-scheme: dark)): >+ >+ * UserInterface/Views/ChangesDetailsSidebarPanel.js: Added. >+ (WI.ChangesDetailsSidebarPanel): >+ (WI.ChangesDetailsSidebarPanel.prototype.inspect): >+ (WI.ChangesDetailsSidebarPanel.prototype.shown): >+ (WI.ChangesDetailsSidebarPanel.prototype.hidden): >+ (WI.ChangesDetailsSidebarPanel.prototype.supportsDOMNode): >+ (WI.ChangesDetailsSidebarPanel.prototype.initialLayout): >+ (WI.ChangesDetailsSidebarPanel.prototype.layout): >+ (WI.ChangesDetailsSidebarPanel.prototype._diff): >+ >+ * UserInterface/Views/ElementsTabContentView.js: >+ (WI.ElementsTabContentView): >+ >+ * UserInterface/Views/SettingsTabContentView.js: >+ (WI.SettingsTabContentView.prototype._createExperimentalSettingsView): >+ >+ * UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css: >+ (.spreadsheet-style-declaration-editor .property): >+ (.spreadsheet-style-declaration-editor .property.modified): >+ (.spreadsheet-style-declaration-editor .property.selected): >+ (@media (prefers-color-scheme: dark)): >+ * UserInterface/Views/SpreadsheetStyleProperty.js: >+ (WI.SpreadsheetStyleProperty.prototype.updateStatus): >+ > 2019-01-23 Nikita Vasilyev <nvasilyev@apple.com> > > Web Inspector: Refactor WI.CSSStyleDeclaration.prototype.update >diff --git a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >index a6ac3b2ca2d..eaf50ff06ef 100644 >--- a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >+++ b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >@@ -166,6 +166,7 @@ localizedStrings["CSP Hash"] = "CSP Hash"; > localizedStrings["CSS"] = "CSS"; > localizedStrings["CSS Canvas"] = "CSS Canvas"; > localizedStrings["CSS canvas \u201C%s\u201D"] = "CSS canvas \u201C%s\u201D"; >+localizedStrings["CSS hasn't been modified."] = "CSS hasn't been modified."; > localizedStrings["Cached"] = "Cached"; > localizedStrings["Call Frames Truncated"] = "Call Frames Truncated"; > localizedStrings["Call Stack"] = "Call Stack"; >@@ -184,6 +185,7 @@ localizedStrings["Capturing"] = "Capturing"; > localizedStrings["Catch Variables"] = "Catch Variables"; > localizedStrings["Categories"] = "Categories"; > localizedStrings["Certificate"] = "Certificate"; >+localizedStrings["Changes"] = "Changes"; > localizedStrings["Character Data"] = "Character Data"; > localizedStrings["Charge \u201C%s\u201D to Callers"] = "Charge \u201C%s\u201D to Callers"; > localizedStrings["Checked"] = "Checked"; >@@ -360,6 +362,7 @@ localizedStrings["Elements"] = "Elements"; > localizedStrings["Enable Audit Tab"] = "Enable Audit Tab"; > localizedStrings["Enable Breakpoint"] = "Enable Breakpoint"; > localizedStrings["Enable Breakpoints"] = "Enable Breakpoints"; >+localizedStrings["Enable Changes Panel"] = "Enable Changes Panel"; > localizedStrings["Enable Computed Style Cascades"] = "Enable Computed Style Cascades"; > localizedStrings["Enable Event Listener"] = "Enable Event Listener"; > localizedStrings["Enable Layers Tab"] = "Enable Layers Tab"; >diff --git a/Source/WebInspectorUI/UserInterface/Base/Setting.js b/Source/WebInspectorUI/UserInterface/Base/Setting.js >index c9d5140f191..76ed42737fc 100644 >--- a/Source/WebInspectorUI/UserInterface/Base/Setting.js >+++ b/Source/WebInspectorUI/UserInterface/Base/Setting.js >@@ -146,6 +146,7 @@ WI.settings = { > > // Experimental > experimentalEnableComputedStyleCascades: new WI.Setting("experimental-enable-computed-style-cascades", false), >+ experimentalEnableChangesPanel: new WI.Setting("experimental-enable-changes-panel", false), > experimentalEnableLayersTab: new WI.Setting("experimental-enable-layers-tab", false), > experimentalEnableNewTabBar: new WI.Setting("experimental-enable-new-tab-bar", false), > experimentalEnableAuditTab: new WI.Setting("experimental-enable-audit-tab", false), >diff --git a/Source/WebInspectorUI/UserInterface/Controllers/CSSManager.js b/Source/WebInspectorUI/UserInterface/Controllers/CSSManager.js >index 743220c8c47..e15b2487d0b 100644 >--- a/Source/WebInspectorUI/UserInterface/Controllers/CSSManager.js >+++ b/Source/WebInspectorUI/UserInterface/Controllers/CSSManager.js >@@ -45,6 +45,7 @@ WI.CSSManager = class CSSManager extends WI.Object > this._styleSheetIdentifierMap = new Map; > this._styleSheetFrameURLMap = new Map; > this._nodeStylesMap = {}; >+ this._modifiedCSSRules = new Map; > this._defaultAppearance = null; > this._forcedAppearance = null; > >@@ -348,6 +349,25 @@ WI.CSSManager = class CSSManager extends WI.Object > this.dispatchEventToListeners(WI.CSSManager.Event.DefaultAppearanceDidChange, {appearance}); > } > >+ getModifiedCSSRules() >+ { >+ let cssRules = []; >+ this._modifiedCSSRules.forEach((value) => { cssRules.push(value) }); >+ return cssRules; >+ } >+ >+ addModifiedCSSRule(cssRule) >+ { >+ let key = cssRule.id.styleSheetId + "/" + cssRule.id.ordinal; >+ this._modifiedCSSRules.set(key, cssRule); >+ } >+ >+ removeModifiedCSSRule(cssRule) >+ { >+ let key = cssRule.id.styleSheetId + "/" + cssRule.id.ordinal; >+ this._modifiedCSSRules.delete(key); >+ } >+ > // Protected > > mediaQueryResultChanged() >@@ -445,6 +465,8 @@ WI.CSSManager = class CSSManager extends WI.Object > this._fetchedInitialStyleSheets = InspectorBackend.domains.CSS.hasEvent("styleSheetAdded"); > this._styleSheetIdentifierMap.clear(); > this._styleSheetFrameURLMap.clear(); >+ this._modifiedCSSRules.clear(); >+ > this._nodeStylesMap = {}; > } > >diff --git a/Source/WebInspectorUI/UserInterface/Main.html b/Source/WebInspectorUI/UserInterface/Main.html >index c55125bc184..ff1bfd4c136 100644 >--- a/Source/WebInspectorUI/UserInterface/Main.html >+++ b/Source/WebInspectorUI/UserInterface/Main.html >@@ -51,6 +51,7 @@ > <link rel="stylesheet" href="Views/CanvasOverviewContentView.css"> > <link rel="stylesheet" href="Views/CanvasSidebarPanel.css"> > <link rel="stylesheet" href="Views/CanvasTabContentView.css"> >+ <link rel="stylesheet" href="Views/ChangesDetailsSidebarPanel.css"> > <link rel="stylesheet" href="Views/ChartDetailsSectionRow.css"> > <link rel="stylesheet" href="Views/CheckboxNavigationItem.css"> > <link rel="stylesheet" href="Views/CircleChart.css"> >@@ -586,6 +587,7 @@ > <script src="Views/CanvasOverviewContentView.js"></script> > <script src="Views/CanvasSidebarPanel.js"></script> > <script src="Views/CanvasTreeElement.js"></script> >+ <script src="Views/ChangesDetailsSidebarPanel.js"></script> > <script src="Views/ChartDetailsSectionRow.js"></script> > <script src="Views/CheckboxNavigationItem.js"></script> > <script src="Views/CircleChart.js"></script> >diff --git a/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js b/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js >index 172a1345e1c..b01e6b88a4d 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js >+++ b/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js >@@ -31,6 +31,7 @@ WI.CSSProperty = class CSSProperty extends WI.Object > > this._ownerStyle = null; > this._index = index; >+ this._initialState = null; > > this.update(text, name, value, priority, enabled, overridden, implicit, anonymous, valid, styleSheetTextRange, true); > } >@@ -99,6 +100,9 @@ WI.CSSProperty = class CSSProperty extends WI.Object > else > this._overridden = overridden; > >+ if (typeof this._text !== "undefined" && this._text !== text) >+ this._markModified(); >+ > this._text = text; > this._name = name; > this._rawValue = value; >@@ -125,6 +129,8 @@ WI.CSSProperty = class CSSProperty extends WI.Object > > remove() > { >+ this._markModified(); >+ > // Setting name or value to an empty string removes the entire CSSProperty. > this._name = ""; > const forceRemove = true; >@@ -133,6 +139,8 @@ WI.CSSProperty = class CSSProperty extends WI.Object > > replaceWithText(text) > { >+ this._markModified(); >+ > this._updateOwnerStyleText(this._text, text, true); > } > >@@ -142,6 +150,7 @@ WI.CSSProperty = class CSSProperty extends WI.Object > if (this._enabled === !disabled) > return; > >+ this._markModified(); > this._enabled = !disabled; > > if (disabled) >@@ -160,6 +169,7 @@ WI.CSSProperty = class CSSProperty extends WI.Object > if (this._text === newText) > return; > >+ this._markModified(); > this._updateOwnerStyleText(this._text, newText); > this._text = newText; > } >@@ -172,6 +182,11 @@ WI.CSSProperty = class CSSProperty extends WI.Object > return `${this._name}: ${this._rawValue};`; > } > >+ get modified() >+ { >+ return !!this._initialState; >+ } >+ > get name() > { > return this._name; >@@ -182,6 +197,7 @@ WI.CSSProperty = class CSSProperty extends WI.Object > if (name === this._name) > return; > >+ this._markModified(); > this._name = name; > this._updateStyleText(); > } >@@ -215,6 +231,8 @@ WI.CSSProperty = class CSSProperty extends WI.Object > if (value === this._rawValue) > return; > >+ this._markModified(); >+ > this._rawValue = value; > this._value = undefined; > this._updateStyleText(); >@@ -272,6 +290,11 @@ WI.CSSProperty = class CSSProperty extends WI.Object > get variable() { return this._variable; } > get styleSheetTextRange() { return this._styleSheetTextRange; } > >+ get initialState() >+ { >+ return this._initialState; >+ } >+ > get editable() > { > return !!(this._styleSheetTextRange && this._ownerStyle && this._ownerStyle.styleSheetTextRange); >@@ -403,6 +426,33 @@ WI.CSSProperty = class CSSProperty extends WI.Object > break; > } > } >+ >+ _markModified() >+ { >+ this._saveInitialState(); >+ if (this._ownerStyle) { >+ this._ownerStyle.markModified(); >+ this._initialState.ownerStyle = this._ownerStyle.initialState; >+ } >+ } >+ >+ _saveInitialState() >+ { >+ if (!this._initialState) { >+ this._initialState = new WI.CSSProperty( >+ this._index, >+ this._text, >+ this._name, >+ this._rawValue, >+ this._priority, >+ this._enabled, >+ this._overridden, >+ this._implicit, >+ this._anonymous, >+ this._valid, >+ this._styleSheetTextRange); >+ } >+ } > }; > > WI.CSSProperty.Event = { >diff --git a/Source/WebInspectorUI/UserInterface/Models/CSSRule.js b/Source/WebInspectorUI/UserInterface/Models/CSSRule.js >index fc5dd5859dd..0c2e8ba3cb2 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/CSSRule.js >+++ b/Source/WebInspectorUI/UserInterface/Models/CSSRule.js >@@ -35,6 +35,7 @@ WI.CSSRule = class CSSRule extends WI.Object > this._ownerStyleSheet = ownerStyleSheet || null; > this._id = id || null; > this._type = type || null; >+ this._initialState = null; > > this.update(sourceCodeLocation, selectorText, selectors, matchedSelectorIndices, style, mediaList, true); > } >@@ -139,6 +140,11 @@ WI.CSSRule = class CSSRule extends WI.Object > return this._mediaList; > } > >+ get initialState() >+ { >+ return this._initialState; >+ } >+ > isEqualTo(rule) > { > if (!rule) >@@ -147,6 +153,12 @@ WI.CSSRule = class CSSRule extends WI.Object > return Object.shallowEqual(this._id, rule.id); > } > >+ markModified() >+ { >+ this._saveInitialState(); >+ WI.cssManager.addModifiedCSSRule(this); >+ } >+ > // Protected > > get nodeStyles() >@@ -165,6 +177,26 @@ WI.CSSRule = class CSSRule extends WI.Object > { > this.dispatchEventToListeners(WI.CSSRule.Event.SelectorChanged, {valid: !!rulePayload}); > } >+ >+ _saveInitialState() >+ { >+ if (!this._initialState) { >+ let initialStyle = this._style.initialState || this._style; >+ this._initialState = new WI.CSSRule( >+ this._nodeStyles, >+ this._ownerStyleSheet, >+ this._id, >+ this._type, >+ this._sourceCodeLocation, >+ this._selectorText, >+ this._selectors, >+ this._matchedSelectorIndices, >+ initialStyle, >+ this._mediaList); >+ } >+ >+ return this._initialState; >+ } > }; > > WI.CSSRule.Event = { >diff --git a/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js b/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js >index 99780b9b139..9829ad28f75 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js >+++ b/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js >@@ -40,12 +40,13 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > this._node = node || null; > this._inherited = inherited || false; > >+ this._initialState = null; > this._locked = false; > this._pendingProperties = []; > this._propertyNameMap = {}; > > this._properties = []; >- this._enabledProperties = []; >+ this._enabledProperties = null; > this._visibleProperties = null; > > this.update(text, properties, styleSheetTextRange, {dontFireEvents: true}); >@@ -53,6 +54,13 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > > // Public > >+ markModified() >+ { >+ this._saveInitialState(); >+ if (this._ownerRule) >+ this._ownerRule.markModified(); >+ } >+ > get id() > { > return this._id; >@@ -116,11 +124,11 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > > this._text = text; > this._properties = properties; >- this._enabledProperties = properties.filter((property) => property.enabled); > > this._styleSheetTextRange = styleSheetTextRange; > this._propertyNameMap = {}; > >+ this._enabledProperties = null; > this._visibleProperties = null; > > let editable = this.editable; >@@ -141,7 +149,7 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > } > > for (let oldProperty of oldProperties) { >- if (this._enabledProperties.includes(oldProperty)) >+ if (this.enabledProperties.includes(oldProperty)) > continue; > > // Clear the index, since it is no longer valid. >@@ -205,10 +213,26 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > > get enabledProperties() > { >+ if (!this._enabledProperties) >+ this._enabledProperties = this._properties.filter((property) => property.enabled); >+ > return this._enabledProperties; > } > >- get properties() { return this._properties; } >+ get properties() >+ { >+ return this._properties; >+ } >+ >+ set properties(properties) >+ { >+ if (properties === this._properties) >+ return; >+ >+ this._properties = properties; >+ this._enabledProperties = null; >+ this._visibleProperties = null; >+ } > > get visibleProperties() > { >@@ -242,6 +266,11 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > return this._node.appropriateSelectorFor(true); > } > >+ get initialState() >+ { >+ return this._initialState; >+ } >+ > propertyForName(name, dontCreateIfMissing) > { > console.assert(name); >@@ -268,7 +297,7 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > > var bestMatchProperty = null; > >- findMatch(this._enabledProperties); >+ findMatch(this.enabledProperties); > > if (bestMatchProperty) > return bestMatchProperty; >@@ -296,6 +325,7 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > let valid = false; > let styleSheetTextRange = this._rangeAfterPropertyAtIndex(propertyIndex - 1); > >+ this.markModified(); > let property = new WI.CSSProperty(propertyIndex, text, name, value, priority, enabled, overridden, implicit, anonymous, valid, styleSheetTextRange); > > this._properties.insertAtIndex(property, propertyIndex); >@@ -358,6 +388,26 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > let property = this.visibleProperties[index]; > return property.styleSheetTextRange.collapseToEnd(); > } >+ >+ _saveInitialState() >+ { >+ let properties = this._initialState ? this._initialState.properties : this._properties; >+ >+ if (!this._initialState) { >+ this._initialState = new WI.CSSStyleDeclaration( >+ this._nodeStyles, >+ this._ownerStyleSheet, >+ this._id, >+ this._type, >+ this._node, >+ this._inherited, >+ this._text, >+ [], // Passing CSS properties here would change their ownerStyle. >+ this._styleSheetTextRange); >+ } >+ >+ this._initialState.properties = properties.map((property) => { return property.initialState || property }); >+ } > }; > > WI.CSSStyleDeclaration.Event = { >diff --git a/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.css b/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.css >new file mode 100644 >index 00000000000..7e279186bda >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.css >@@ -0,0 +1,74 @@ >+/* >+ * Copyright (C) 2019 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. >+ */ >+ >+.sidebar > .panel.changes-panel { >+ padding: 8px 10px; >+ white-space: pre-wrap; >+ overflow-y: auto; >+} >+ >+.sidebar > .panel.changes-panel:not(.empty) { >+ font: 11px Menlo, monospace; >+ -webkit-user-select: text; >+} >+ >+.sidebar > .panel.changes-panel.empty { >+ text-align: center; >+} >+ >+.changes-panel ins { >+ color: hsl(90, 61%, 25%); >+ background-color: hsl(70, 65%, 85%); >+ text-decoration: none; >+} >+ >+.changes-panel del { >+ color: hsl(0, 100%, 35%); >+ background-color: hsl(5, 78%, 91%); >+ text-decoration: none; >+} >+ >+.changes-panel del.css-property::before { >+ content: "- "; >+ position: absolute; >+ pointer-events: none; >+} >+ >+.changes-panel ins.css-property::before { >+ content: "+ "; >+ position: absolute; >+ pointer-events: none; >+} >+ >+@media (prefers-color-scheme: dark) { >+ .changes-panel ins { >+ color: hsl(70, 64%, 70%); >+ background-color: hsl(89, 40%, 19%); >+ } >+ .changes-panel del { >+ color: hsl(0, 84%, 75%); >+ background-color: hsl(5, 40%, 25%); >+ } >+} >diff --git a/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.js b/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.js >new file mode 100644 >index 00000000000..40ee65cf92d >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.js >@@ -0,0 +1,192 @@ >+/* >+ * Copyright (C) 2019 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. >+ */ >+ >+WI.ChangesDetailsSidebarPanel = class ChangesDetailsSidebarPanel extends WI.DetailsSidebarPanel >+{ >+ constructor() >+ { >+ super("changes-details", WI.UIString("Changes")); >+ >+ this.element.classList.add("changes-panel"); >+ } >+ >+ // Public >+ >+ inspect(objects) >+ { >+ return true; >+ } >+ >+ shown() >+ { >+ if (this.didInitialLayout) >+ this.needsLayout(); >+ >+ super.shown(); >+ } >+ >+ hidden() >+ { >+ super.hidden(); >+ } >+ >+ supportsDOMNode(nodeToInspect) >+ { >+ // Display Changes panel regardless of the selected DOM node. >+ return true; >+ } >+ >+ // Protected >+ >+ initialLayout() >+ { >+ super.initialLayout(); >+ >+ WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this); >+ } >+ >+ layout() >+ { >+ super.layout(); >+ this.element.removeChildren(); >+ >+ let cssRules = WI.cssManager.getModifiedCSSRules(); >+ >+ this.element.classList.toggle("empty", cssRules.length === 0); >+ if (!cssRules.length) { >+ this.element.textContent = WI.UIString("CSS hasn't been modified."); >+ return; >+ } >+ >+ for (let cssRule of cssRules) { >+ let selectorElement = document.createElement("span"); >+ selectorElement.append(cssRule.selectorText, " {\n"); >+ this.element.append(selectorElement); >+ >+ let initialCSSProperties = cssRule.initialState.style.visibleProperties; >+ let cssProperties = cssRule.style.visibleProperties; >+ const indent = " "; >+ >+ this._diff(initialCSSProperties, cssProperties, (cssProperty, action) => { >+ if (action === "equal" || action === "moved") { >+ if (!cssProperty.modified) { >+ let propertyElement = document.createElement("span"); >+ propertyElement.classList.add("css-property"); >+ propertyElement.append(indent, cssProperty.formattedText); >+ this.element.append(propertyElement, "\n"); >+ return; >+ } >+ >+ let delElement = document.createElement("del"); >+ delElement.classList.add("css-property", "initial"); >+ delElement.append(indent, cssProperty._initialState.formattedText); >+ this.element.append(delElement, "\n"); >+ >+ let insElement = document.createElement("ins"); >+ insElement.classList.add("css-property", "current"); >+ insElement.append(indent, cssProperty.formattedText); >+ this.element.append(insElement, "\n"); >+ >+ } else if (action === "added") { >+ let currentTextElement = document.createElement("ins"); >+ currentTextElement.classList.add("css-property", "current"); >+ currentTextElement.append(indent, cssProperty.formattedText); >+ this.element.append(currentTextElement, "\n"); >+ } else if (action === "removed") { >+ let currentTextElement = document.createElement("del"); >+ currentTextElement.classList.add("css-property", "initial"); >+ currentTextElement.append(indent, cssProperty.formattedText); >+ this.element.append(currentTextElement, "\n"); >+ } >+ }); >+ >+ this.element.append("}\n\n"); >+ } >+ } >+ >+ // Private >+ >+ _mainResourceDidChange(event) >+ { >+ if (!event.target.isMainFrame()) >+ return; >+ >+ this.needsLayout(); >+ } >+ >+ _diff(listA, listB, onEach) >+ { >+ let setA = new Set(listA); >+ let setB = new Set(listB); >+ let indexA = 0; >+ let indexB = 0; >+ let deltaA = 0; >+ let deltaB = 0; >+ let shortListLength = Math.min(listA.length, listB.length); >+ >+ let i = 0; >+ while (true) { >+ if (i >= shortListLength) >+ break; >+ >+ if (indexA >= listA.length || indexB >= listB.length) >+ break; >+ >+ let a = listA[indexA]; >+ let b = listB[indexB]; >+ >+ if (a === b) >+ onEach(b, "equal"); >+ else if (setB.has(a)) { >+ if (setA.has(b)) >+ onEach(b, "moved"); >+ else { >+ onEach(b, "added"); >+ --i; >+ ++deltaB; >+ } >+ } else { >+ onEach(a, "removed"); >+ if (!setA.has(b)) >+ onEach(b, "added"); >+ else { >+ --i; >+ ++deltaA; >+ } >+ } >+ >+ ++i; >+ indexA = i + deltaA; >+ indexB = i + deltaB; >+ } >+ >+ for (let i = indexA; i < listA.length; ++i) >+ onEach(listA[i], "removed"); >+ >+ for (let i = indexB; i < listB.length; ++i) >+ onEach(listB[i], "added"); >+ } >+ >+}; >diff --git a/Source/WebInspectorUI/UserInterface/Views/ElementsTabContentView.js b/Source/WebInspectorUI/UserInterface/Views/ElementsTabContentView.js >index 8ce29eeb29c..824ae09ac13 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/ElementsTabContentView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/ElementsTabContentView.js >@@ -28,8 +28,12 @@ WI.ElementsTabContentView = class ElementsTabContentView extends WI.ContentBrows > constructor(identifier) > { > let tabBarItem = WI.GeneralTabBarItem.fromTabInfo(WI.ElementsTabContentView.tabInfo()); >- let detailsSidebarPanelConstructors = [WI.RulesStyleDetailsSidebarPanel, WI.ComputedStyleDetailsSidebarPanel, WI.DOMNodeDetailsSidebarPanel]; > >+ let detailsSidebarPanelConstructors = [WI.RulesStyleDetailsSidebarPanel, WI.ComputedStyleDetailsSidebarPanel]; >+ if (WI.settings.experimentalEnableChangesPanel.value) >+ detailsSidebarPanelConstructors.push(WI.ChangesDetailsSidebarPanel); >+ >+ detailsSidebarPanelConstructors.push(WI.DOMNodeDetailsSidebarPanel); > if (window.LayerTreeAgent) > detailsSidebarPanelConstructors.push(WI.LayerTreeDetailsSidebarPanel); > >diff --git a/Source/WebInspectorUI/UserInterface/Views/SettingsTabContentView.js b/Source/WebInspectorUI/UserInterface/Views/SettingsTabContentView.js >index d123dc00b75..98f2fbd29a4 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/SettingsTabContentView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/SettingsTabContentView.js >@@ -256,6 +256,7 @@ WI.SettingsTabContentView = class SettingsTabContentView extends WI.TabContentVi > if (window.CSSAgent) { > let group = experimentalSettingsView.addGroup(WI.UIString("Styles Sidebar:")); > group.addSetting(WI.settings.experimentalEnableComputedStyleCascades, WI.UIString("Enable Computed Style Cascades")); >+ group.addSetting(WI.settings.experimentalEnableChangesPanel, WI.UIString("Enable Changes Panel")); > experimentalSettingsView.addSeparator(); > } > >@@ -295,6 +296,7 @@ WI.SettingsTabContentView = class SettingsTabContentView extends WI.TabContentVi > } > > listenForChange(WI.settings.experimentalEnableComputedStyleCascades); >+ listenForChange(WI.settings.experimentalEnableChangesPanel); > listenForChange(WI.settings.experimentalEnableLayersTab); > listenForChange(WI.settings.experimentalEnableAuditTab); > listenForChange(WI.settings.experimentalEnableNewTabBar); >diff --git a/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css b/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css >index 17f508ad42d..5c992d5f72e 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css >+++ b/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css >@@ -38,6 +38,7 @@ > .spreadsheet-style-declaration-editor .property { > padding-right: var(--css-declaration-horizontal-padding); > padding-left: calc(var(--css-declaration-horizontal-padding) + 17px); >+ border-right: 2px solid transparent; > border-left: 1px solid transparent; > outline: none; > } >@@ -129,8 +130,13 @@ > -webkit-clip-path: polygon(0% 50%, 6px 0%, 100% 0%, 100% 100%, 6px 100%); > } > >+.spreadsheet-style-declaration-editor .property.modified { >+ border-right-color: hsl(120, 100%, 40%); >+ background-color: hsl(90, 100%, 93%); >+} >+ > .spreadsheet-style-declaration-editor .property.selected { >- background-color: var(--background-color-selected); >+ background-color: var(--background-color-selected) !important; > } > > body:matches(.window-docked-inactive, .window-inactive) .spreadsheet-style-declaration-editor .property.selected { >@@ -188,4 +194,8 @@ body:matches(.window-docked-inactive, .window-inactive) .spreadsheet-style-decla > .spreadsheet-style-declaration-editor :matches(.name, .value).editing { > outline-color: var(--background-color-secondary) !important; > } >+ >+ .spreadsheet-style-declaration-editor .property.modified { >+ background-color: hsl(106, 13%, 25%); >+ } > } >diff --git a/Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js b/Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js >index 611d816f907..4411e99a931 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js >+++ b/Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js >@@ -295,6 +295,9 @@ WI.SpreadsheetStyleProperty = class SpreadsheetStyleProperty extends WI.Object > if (!this._property.enabled) > classNames.push("disabled"); > >+ if (this._property.modified) >+ classNames.push("modified"); >+ > if (this._selected) > classNames.push("selected"); >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
hi
:
review-
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193803
:
360059
|
360065
|
360068
|
360073
|
360091
|
360192
|
360200
|
360207
|
360274
|
360324