WebKit Bugzilla
Attachment 360324 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), 36.85 KB, created by
Nikita Vasilyev
on 2019-01-28 00:52:04 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Nikita Vasilyev
Created:
2019-01-28 00:52:04 PST
Size:
36.85 KB
patch
obsolete
>diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index a8c8f6ea2e7..5e08b26907d 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,16 @@ >+2019-01-28 Nikita Vasilyev <nvasilyev@apple.com> >+ >+ Web Inspector: Add Changes panel to Elements tab >+ https://bugs.webkit.org/show_bug.cgi?id=193803 >+ >+ Reviewed by Devin Rousso. >+ >+ Test newly added Array.diffArrays. >+ >+ * inspector/unit-tests/array-utilities-expected.txt: >+ * inspector/unit-tests/array-utilities.html: >+ Use the old `InspectorTest.log` method since it shows diffs for actual and expected text. >+ > 2019-01-24 Wenson Hsieh <wenson_hsieh@apple.com> > > [iOS] Unable to make a selection in jsfiddle.net using arrow keys when requesting desktop site >diff --git a/LayoutTests/inspector/unit-tests/array-utilities-expected.txt b/LayoutTests/inspector/unit-tests/array-utilities-expected.txt >index 0b24225a40d..e196911bbf1 100644 >--- a/LayoutTests/inspector/unit-tests/array-utilities-expected.txt >+++ b/LayoutTests/inspector/unit-tests/array-utilities-expected.txt >@@ -70,6 +70,20 @@ PASS: shallowEqual of a typed-array and non-array should be false. > PASS: shallowEqual of a non-array with itself should be false. > PASS: shallowEqual of non-arrays should be false. > >+-- Running test case: Array.diffArrays >+["a"], [] => [["a",-1]] >+[], ["a"] => [["a",1]] >+["a"], ["b"] => [["a",-1],["b",1]] >+["a"], ["a"] => [["a",0]] >+["a"], ["a","b"] => [["a",0],["b",1]] >+["a"], ["b","a"] => [["b",1],["a",0]] >+["a","b"], ["a"] => [["a",0],["b",-1]] >+["b","a"], ["a"] => [["b",-1],["a",0]] >+["b","a"], ["a","c"] => [["b",-1],["a",0],["c",1]] >+["b","a"], ["a","c"] => [["b",-1],["a",0],["c",1]] >+["b","a"], ["a","b"] => [["a",0],["b",0]] >+["a","b","c"], ["a","d","c"] => [["a",0],["b",-1],["d",1],["c",0]] >+ > -- Running test case: Array.prototype.lastValue > PASS: lastValue of a nonempty array should be the last value. > PASS: lastValue of an empty array should be undefined. >diff --git a/LayoutTests/inspector/unit-tests/array-utilities.html b/LayoutTests/inspector/unit-tests/array-utilities.html >index ca9c58f6de2..01d8de1cccd 100644 >--- a/LayoutTests/inspector/unit-tests/array-utilities.html >+++ b/LayoutTests/inspector/unit-tests/array-utilities.html >@@ -151,6 +151,35 @@ function test() > } > }); > >+ suite.addTestCase({ >+ name: "Array.diffArrays", >+ test() { >+ function diff(initial, current) { >+ let actual = []; >+ Array.diffArrays(initial, current, (value, changed) => { >+ actual.push([value, changed]); >+ }); >+ >+ InspectorTest.log(JSON.stringify(initial) + ", " + JSON.stringify(current) + " => " + JSON.stringify(actual)); >+ } >+ >+ diff(["a"], []); >+ diff([], ["a"]); >+ diff(["a"], ["b"]); >+ diff(["a"], ["a"]); >+ diff(["a"], ["a", "b"]); >+ diff(["a"], ["b", "a"]); >+ diff(["a", "b"], ["a"]); >+ diff(["b", "a"], ["a"]); >+ diff(["b", "a"], ["a", "c"]); >+ diff(["b", "a"], ["a", "c"]); >+ diff(["b", "a"], ["a", "b"]); >+ diff(["a", "b", "c"], ["a", "d", "c"]); >+ >+ return true; >+ } >+ }); >+ > suite.addTestCase({ > name: "Array.prototype.lastValue", > test() { >diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog >index 44053a80022..51d8436d22b 100644 >--- a/Source/WebInspectorUI/ChangeLog >+++ b/Source/WebInspectorUI/ChangeLog >@@ -1,3 +1,91 @@ >+2019-01-28 Nikita Vasilyev <nvasilyev@apple.com> >+ >+ Web Inspector: Add Changes panel to Elements tab >+ https://bugs.webkit.org/show_bug.cgi?id=193803 >+ >+ Reviewed by Devin Rousso. >+ >+ 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/Base/Utilities.js: >+ (Array.diffArrays): Added. >+ >+ * UserInterface/Controllers/CSSManager.js: >+ (WI.CSSManager): >+ (WI.CSSManager.prototype.get modifiedCSSRules): >+ (WI.CSSManager.prototype.addModifiedCSSRule): >+ (WI.CSSManager.prototype.removeModifiedCSSRule): >+ (WI.CSSManager.prototype._mainResourceDidChange): >+ >+ * UserInterface/Main.html: >+ * UserInterface/Models/CSSProperty.js: >+ (WI.CSSProperty): >+ (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._updateOwnerStyleText): >+ (WI.CSSProperty.prototype._markModified): >+ Mark CSSProperty modified *before* making any changes to copy its initial state. >+ >+ * UserInterface/Models/CSSRule.js: >+ (WI.CSSRule): >+ (WI.CSSRule.prototype.get id): >+ (WI.CSSRule.prototype.get initialState): >+ (WI.CSSRule.prototype.get stringId): >+ (WI.CSSRule.prototype.markModified): >+ >+ * UserInterface/Models/CSSStyleDeclaration.js: >+ (WI.CSSStyleDeclaration): >+ (WI.CSSStyleDeclaration.prototype.get initialState): >+ (WI.CSSStyleDeclaration.prototype.get enabledProperties): >+ (WI.CSSStyleDeclaration.prototype.get properties): >+ (WI.CSSStyleDeclaration.prototype.set properties): >+ (WI.CSSStyleDeclaration.prototype.propertyForName): >+ (WI.CSSStyleDeclaration.prototype.newBlankProperty): >+ (WI.CSSStyleDeclaration.prototype.markModified): >+ >+ * 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.supportsDOMNode): >+ (WI.ChangesDetailsSidebarPanel.prototype.shown): >+ (WI.ChangesDetailsSidebarPanel.prototype.detached): >+ (WI.ChangesDetailsSidebarPanel.prototype.layout): >+ (WI.ChangesDetailsSidebarPanel.prototype._mainResourceDidChange): >+ >+ * 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.modified:not(.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/Base/Utilities.js b/Source/WebInspectorUI/UserInterface/Base/Utilities.js >index 9bf08943dc7..c1dded53139 100644 >--- a/Source/WebInspectorUI/UserInterface/Base/Utilities.js >+++ b/Source/WebInspectorUI/UserInterface/Base/Utilities.js >@@ -489,6 +489,67 @@ Object.defineProperty(Array, "shallowEqual", > } > }); > >+Object.defineProperty(Array, "diffArrays", >+{ >+ value(initialArray, currentArray, onEach) >+ { >+ let initialSet = new Set(initialArray); >+ let currentSet = new Set(currentArray); >+ let indexInitial = 0; >+ let indexCurrent = 0; >+ let deltaInitial = 0; >+ let deltaCurrent = 0; >+ >+ let i = 0; >+ while (true) { >+ if (indexInitial >= initialArray.length || indexCurrent >= currentArray.length) >+ break; >+ >+ let initial = initialArray[indexInitial]; >+ let current = currentArray[indexCurrent]; >+ >+ if (initial === current) >+ onEach(current, 0); >+ else if (currentSet.has(initial)) { >+ if (initialSet.has(current)) { >+ // Moved. >+ onEach(current, 0); >+ } else { >+ // Added. >+ onEach(current, 1); >+ --i; >+ ++deltaCurrent; >+ } >+ } else { >+ // Removed. >+ onEach(initial, -1); >+ if (!initialSet.has(current)) { >+ // Added. >+ onEach(current, 1); >+ } else { >+ --i; >+ ++deltaInitial; >+ } >+ } >+ >+ ++i; >+ indexInitial = i + deltaInitial; >+ indexCurrent = i + deltaCurrent; >+ } >+ >+ for (let i = indexInitial; i < initialArray.length; ++i) { >+ // Removed. >+ onEach(initialArray[i], -1); >+ } >+ >+ for (let i = indexCurrent; i < currentArray.length; ++i) { >+ // Added. >+ onEach(currentArray[i], 1); >+ } >+ >+ } >+}); >+ > Object.defineProperty(Array.prototype, "lastValue", > { > get() >diff --git a/Source/WebInspectorUI/UserInterface/Controllers/CSSManager.js b/Source/WebInspectorUI/UserInterface/Controllers/CSSManager.js >index 743220c8c47..c00cda2eaf7 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,21 @@ WI.CSSManager = class CSSManager extends WI.Object > this.dispatchEventToListeners(WI.CSSManager.Event.DefaultAppearanceDidChange, {appearance}); > } > >+ get modifiedCSSRules() >+ { >+ return Array.from(this._modifiedCSSRules.values()); >+ } >+ >+ addModifiedCSSRule(cssRule) >+ { >+ this._modifiedCSSRules.set(cssRule.stringId, cssRule); >+ } >+ >+ removeModifiedCSSRule(cssRule) >+ { >+ this._modifiedCSSRules.delete(cssRule.stringId); >+ } >+ > // Protected > > mediaQueryResultChanged() >@@ -445,6 +461,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..1be38e5d5fe 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); > } >@@ -125,6 +126,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 +136,8 @@ WI.CSSProperty = class CSSProperty extends WI.Object > > replaceWithText(text) > { >+ this._markModified(); >+ > this._updateOwnerStyleText(this._text, text, true); > } > >@@ -142,6 +147,7 @@ WI.CSSProperty = class CSSProperty extends WI.Object > if (this._enabled === !disabled) > return; > >+ this._markModified(); > this._enabled = !disabled; > > if (disabled) >@@ -160,6 +166,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 +179,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 +194,7 @@ WI.CSSProperty = class CSSProperty extends WI.Object > if (name === this._name) > return; > >+ this._markModified(); > this._name = name; > this._updateStyleText(); > } >@@ -215,6 +228,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 +287,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); >@@ -349,6 +369,8 @@ WI.CSSProperty = class CSSProperty extends WI.Object > > _updateOwnerStyleText(oldText, newText, forceRemove = false) > { >+ console.assert(this.modified, "CSSProperty was modified without saving initial state."); >+ > if (oldText === newText) { > if (forceRemove) { > const lineDelta = 0; >@@ -403,6 +425,30 @@ WI.CSSProperty = class CSSProperty extends WI.Object > break; > } > } >+ >+ _markModified() >+ { >+ if (this.modified) >+ return; >+ >+ 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); >+ >+ if (this._ownerStyle) { >+ this._ownerStyle.markModified(); >+ this._initialState.ownerStyle = this._ownerStyle.initialState; >+ } >+ } > }; > > WI.CSSProperty.Event = { >diff --git a/Source/WebInspectorUI/UserInterface/Models/CSSRule.js b/Source/WebInspectorUI/UserInterface/Models/CSSRule.js >index fc5dd5859dd..375845b8df6 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/CSSRule.js >+++ b/Source/WebInspectorUI/UserInterface/Models/CSSRule.js >@@ -35,15 +35,20 @@ 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); > } > > // Public > >- get id() >+ get id() { return this._id; } >+ get initialState() { return this._initialState; } >+ >+ get stringId() > { >- return this._id; >+ if (this._id) >+ return this._id.styleSheetId + "/" + this._id.ordinal; > } > > get ownerStyleSheet() >@@ -147,6 +152,27 @@ WI.CSSRule = class CSSRule extends WI.Object > return Object.shallowEqual(this._id, rule.id); > } > >+ markModified() >+ { >+ if (this._initialState) >+ return; >+ >+ 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); >+ >+ WI.cssManager.addModifiedCSSRule(this); >+ } >+ > // Protected > > get nodeStyles() >diff --git a/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js b/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js >index 99780b9b139..56c10677f8a 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,8 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > > // Public > >+ get initialState() { return this._initialState; } >+ > get id() > { > return this._id; >@@ -116,11 +119,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 +144,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 +208,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() > { >@@ -268,7 +287,7 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > > var bestMatchProperty = null; > >- findMatch(this._enabledProperties); >+ findMatch(this.enabledProperties); > > if (bestMatchProperty) > return bestMatchProperty; >@@ -296,6 +315,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); >@@ -307,6 +327,29 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > return property; > } > >+ markModified() >+ { >+ 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 }); >+ >+ if (this._ownerRule) >+ this._ownerRule.markModified(); >+ } >+ > shiftPropertiesAfter(cssProperty, lineDelta, columnDelta, propertyWasRemoved) > { > // cssProperty.index could be set to NaN by WI.CSSStyleDeclaration.prototype.update. >diff --git a/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.css b/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.css >new file mode 100644 >index 00000000000..8dabd97c782 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.css >@@ -0,0 +1,75 @@ >+/* >+ * 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..3f8ba419e83 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.js >@@ -0,0 +1,126 @@ >+/* >+ * 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; >+ } >+ >+ supportsDOMNode(nodeToInspect) >+ { >+ // Display Changes panel regardless of the selected DOM node. >+ return true; >+ } >+ >+ shown() >+ { >+ // `shown` may get called before initialLayout when Elements tab is opened. >+ // When Changes panel is selected, `shown` is called and this time it's after initialLayout. >+ if (this.didInitialLayout) { >+ this.needsLayout(); >+ WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this); >+ } >+ >+ super.shown(); >+ } >+ >+ detached() >+ { >+ super.detached(); >+ >+ WI.Frame.removeEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this); >+ } >+ >+ // Protected >+ >+ layout() >+ { >+ super.layout(); >+ >+ this.element.removeChildren(); >+ >+ let cssRules = WI.cssManager.modifiedCSSRules; >+ >+ this.element.classList.toggle("empty", !cssRules.length); >+ if (!cssRules.length) { >+ this.element.textContent = WI.UIString("CSS hasn't been modified."); >+ return; >+ } >+ >+ let indent = WI.indentString(); >+ >+ let appendPropertyElement = (tagName, text) => { >+ let propertyElement = document.createElement(tagName); >+ propertyElement.className = "css-property"; >+ propertyElement.append(indent, text); >+ this.element.append(propertyElement, "\n"); >+ }; >+ >+ 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; >+ >+ Array.diffArrays(initialCSSProperties, cssProperties, (cssProperty, action) => { >+ if (action === 0) { >+ if (cssProperty.modified) { >+ appendPropertyElement("del", cssProperty.initialState.formattedText); >+ appendPropertyElement("ins", cssProperty.formattedText); >+ } else >+ appendPropertyElement("span", cssProperty.formattedText); >+ } else if (action === 1) >+ appendPropertyElement("ins", cssProperty.formattedText); >+ else if (action === -1) >+ appendPropertyElement("del", cssProperty.formattedText); >+ }); >+ >+ this.element.append("}\n\n"); >+ } >+ } >+ >+ // Private >+ >+ _mainResourceDidChange(event) >+ { >+ if (!event.target.isMainFrame()) >+ return; >+ >+ this.needsLayout(); >+ } >+}; >diff --git a/Source/WebInspectorUI/UserInterface/Views/ElementsTabContentView.js b/Source/WebInspectorUI/UserInterface/Views/ElementsTabContentView.js >index 8ce29eeb29c..2eb912ab40f 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/ElementsTabContentView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/ElementsTabContentView.js >@@ -28,8 +28,11 @@ 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..98b74988b75 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,6 +130,14 @@ > -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%); >+} >+ >+.spreadsheet-style-declaration-editor .property.modified:not(.selected) { >+ background-color: hsl(90, 100%, 93%); >+} >+ > .spreadsheet-style-declaration-editor .property.selected { > background-color: var(--background-color-selected); > } >@@ -188,4 +197,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:not(.selected) { >+ 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
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193803
:
360059
|
360065
|
360068
|
360073
|
360091
|
360192
|
360200
|
360207
|
360274
| 360324