WebKit Bugzilla
Attachment 370376 Details for
Bug 195264
: Web Inspector: CSS Changes: modifications aren't shared for rules that match multiple elements
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
patch.txt (text/plain), 21.60 KB, created by
Nikita Vasilyev
on 2019-05-21 20:27:35 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Nikita Vasilyev
Created:
2019-05-21 20:27:35 PDT
Size:
21.60 KB
patch
obsolete
>diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 60a6b0287a3..4ab847fc6a2 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,16 @@ >+2019-05-21 Nikita Vasilyev <nvasilyev@apple.com> >+ >+ Web Inspector: CSS Changes: modifications aren't shared for rules that match multiple elements >+ https://bugs.webkit.org/show_bug.cgi?id=195264 >+ <rdar://problem/48550023> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Test arrays with repeating items for Array.diffArrays. >+ >+ * inspector/unit-tests/array-utilities-expected.txt: >+ * inspector/unit-tests/array-utilities.html: >+ > 2019-05-17 Joonghun Park <pjh0718@gmail.com> > > Implement CSS `display: flow-root` (modern clearfix) >diff --git a/LayoutTests/inspector/unit-tests/array-utilities-expected.txt b/LayoutTests/inspector/unit-tests/array-utilities-expected.txt >index f52c69c9544..e8c1e0ef75b 100644 >--- a/LayoutTests/inspector/unit-tests/array-utilities-expected.txt >+++ b/LayoutTests/inspector/unit-tests/array-utilities-expected.txt >@@ -81,8 +81,18 @@ PASS: shallowEqual of non-arrays should be false. > ["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]] >+["b","a"], ["a","b"] => [["a",1],["b",0],["a",-1]] > ["a","b","c"], ["a","d","c"] => [["a",0],["b",-1],["d",1],["c",0]] >+["a","b","c"], ["c","b","a"] => [["c",1],["b",1],["a",0],["b",-1],["c",-1]] >+ >+Repeating items: >+["a"], ["a","a"] => [["a",1],["a",0]] >+["a","a"], ["a"] => [["a",-1],["a",0]] >+["a","a"], ["a","a"] => [["a",0],["a",0]] >+["b","a","b"], ["a","b","a"] => [["a",1],["b",0],["a",0],["b",-1]] >+["a","b","b","c"], ["c","b","b","b","a"] => [["a",-1],["c",1],["b",0],["b",0],["c",-1],["b",1],["a",1]] >+["a","b","b","b","c"], ["c","b","b","a"] => [["a",-1],["c",1],["b",0],["b",0],["b",-1],["c",-1],["a",1]] >+["a","a","b","b","c","c"], ["b","b","c","c","a","a"] => [["a",-1],["a",-1],["b",0],["b",0],["c",0],["c",0],["a",1],["a",1]] > > -- Running test case: Array.prototype.lastValue > PASS: lastValue of a nonempty array should be the last value. >diff --git a/LayoutTests/inspector/unit-tests/array-utilities.html b/LayoutTests/inspector/unit-tests/array-utilities.html >index d15afecee7d..c3282a778c0 100644 >--- a/LayoutTests/inspector/unit-tests/array-utilities.html >+++ b/LayoutTests/inspector/unit-tests/array-utilities.html >@@ -175,6 +175,16 @@ function test() > diff(["b", "a"], ["a", "c"]); > diff(["b", "a"], ["a", "b"]); > diff(["a", "b", "c"], ["a", "d", "c"]); >+ diff(["a", "b", "c"], ["c", "b", "a"]); >+ >+ InspectorTest.log("\nRepeating items:"); >+ diff(["a"], ["a", "a"]); >+ diff(["a", "a"], ["a"]); >+ diff(["a", "a"], ["a", "a"]); >+ diff(["b", "a", "b"], ["a", "b", "a"]); >+ diff(["a", "b", "b", "c"], ["c", "b", "b", "b", "a"]); >+ diff(["a", "b", "b", "b", "c"], ["c", "b", "b", "a"]); >+ diff(["a", "a", "b", "b", "c", "c"], ["b", "b", "c", "c", "a", "a"]); > > return true; > } >diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog >index d76efb6430c..02e9cdb4c91 100644 >--- a/Source/WebInspectorUI/ChangeLog >+++ b/Source/WebInspectorUI/ChangeLog >@@ -1,3 +1,47 @@ >+2019-05-21 Nikita Vasilyev <nvasilyev@apple.com> >+ >+ Web Inspector: CSS Changes: modifications aren't shared for rules that match multiple elements >+ https://bugs.webkit.org/show_bug.cgi?id=195264 >+ <rdar://problem/48550023> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch fixes several cases when the diff was incorrect. >+ >+ 1. Perform diff based on CSSProperty content (name, value, and enabled property) instead >+ of strict equality of CSSProperty instances. >+ >+ 2. Copy all initial CSSProperty instances of CSSStyleDeclaration on 1st edit. >+ This removes the need to update `properties` on every single edit. >+ >+ 3. Do full diff to display modified property markers (green background) in Rules panel. >+ This fixes a few cases when the markers were inaccurate. E.g. a newly added property >+ matches removed property - no need to show the green background. >+ >+ * UserInterface/Base/Utilities.js: >+ (Array.diffArrays): >+ Allow repeating items in the arrays. >+ >+ * UserInterface/Controllers/CSSManager.js: >+ (WI.CSSManager.prototype.getModifiedStyle): >+ (WI.CSSManager.prototype.removeModifiedStyle): >+ * UserInterface/Models/CSSProperty.js: >+ (WI.CSSProperty): >+ (WI.CSSProperty.prototype.get modified): >+ (WI.CSSProperty.prototype.set modified): >+ (WI.CSSProperty.prototype.equals): >+ (WI.CSSProperty.prototype.clone): >+ (WI.CSSProperty.prototype._updateOwnerStyleText): >+ (WI.CSSProperty.prototype._markModified): >+ * UserInterface/Models/CSSStyleDeclaration.js: >+ (WI.CSSStyleDeclaration.prototype.markModified): >+ (WI.CSSStyleDeclaration.prototype.updatePropertiesModifiedState): >+ * UserInterface/Views/ChangesDetailsSidebarPanel.js: >+ (WI.ChangesDetailsSidebarPanel.prototype._createRuleElement): >+ * UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.js: >+ (WI.SpreadsheetCSSStyleDeclarationEditor.prototype.layout): >+ * UserInterface/Views/SpreadsheetStyleProperty.js: >+ > 2019-05-17 Devin Rousso <drousso@apple.com> > > Web Inspector: Timelines: CPU/memory timeline bars sometimes don't draw correctly and jump around on scrolling >diff --git a/Source/WebInspectorUI/UserInterface/Base/Utilities.js b/Source/WebInspectorUI/UserInterface/Base/Utilities.js >index 2bd4fad60cf..72ade8156a7 100644 >--- a/Source/WebInspectorUI/UserInterface/Base/Utilities.js >+++ b/Source/WebInspectorUI/UserInterface/Base/Utilities.js >@@ -509,62 +509,102 @@ Object.defineProperty(Array, "shallowEqual", > > Object.defineProperty(Array, "diffArrays", > { >- value(initialArray, currentArray, onEach) >+ value(initialArray, currentArray, onEach, comparator) > { >- let initialSet = new Set(initialArray); >- let currentSet = new Set(currentArray); >- let indexInitial = 0; >- let indexCurrent = 0; >- let deltaInitial = 0; >- let deltaCurrent = 0; >+ "use strict"; > >- 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; >+ function defaultComparator(initial, current) { >+ return initial === current; >+ } >+ comparator = comparator || defaultComparator; >+ >+ // Find the first shortest edit. In the another words, find the prefix of the first longest common sequence. >+ // >+ // initialArray = ["a", "b", "b", "c"] >+ // currentArray = ["c", "b", "b", "a"] >+ // findShortestEdit() // [1, 1] >+ // >+ function findShortestEdit() { >+ let deletionCount = initialArray.length; >+ let additionCount = currentArray.length; >+ let editCount = deletionCount + additionCount; >+ for (let i = 0; i < initialArray.length; ++i) { >+ for (let j = 0; j < currentArray.length; ++j) { >+ let newEditCount = i + j; >+ if (newEditCount > editCount) { >+ // Break since any possible edits at this point are going to be longer than the one already found. >+ break; >+ } >+ >+ if (comparator(initialArray[i], currentArray[j])) { >+ // A candidate for the shortest edit found. >+ if (newEditCount < editCount) { >+ editCount = newEditCount; >+ deletionCount = i; >+ additionCount = j; >+ } >+ break; >+ } > } > } >+ return [deletionCount, additionCount]; >+ } > >- ++i; >- indexInitial = i + deltaInitial; >- indexCurrent = i + deltaCurrent; >+ function commonPrefixLength(listA, listB) { >+ let shorterListLength = Math.min(listA.length, listB.length); >+ let i = 0; >+ while (i < shorterListLength) { >+ if (!comparator(listA[i], listB[i])) >+ break; >+ ++i; >+ } >+ return i; >+ } >+ >+ function commonSuffixLength(listA, listB) { >+ let shorterListLength = Math.min(listA.length, listB.length); >+ let i = 0; >+ while (i < shorterListLength) { >+ let a = listA[listA.length - i - 1]; >+ let b = listB[listB.length - i - 1]; >+ if (!comparator(a, b)) >+ break; >+ ++i; >+ } >+ return i; >+ } >+ >+ function fireOnEach(count, diffAction, array) { >+ for (let i = 0; i < count; ++i) >+ onEach(array[i], diffAction); > } > >- for (let i = indexInitial; i < initialArray.length; ++i) { >- // Removed. >- onEach(initialArray[i], -1); >+ // Remove common suffix. >+ let suffix = []; >+ let suffixLength = commonSuffixLength(initialArray, currentArray); >+ if (suffixLength) { >+ suffix = initialArray.slice(-suffixLength); >+ initialArray = initialArray.slice(0, -suffixLength); >+ currentArray = currentArray.slice(0, -suffixLength); > } > >- for (let i = indexCurrent; i < currentArray.length; ++i) { >- // Added. >- onEach(currentArray[i], 1); >+ while (initialArray.length || currentArray.length) { >+ // Remove common prefix. >+ let prefixLength = commonPrefixLength(initialArray, currentArray); >+ if (prefixLength) { >+ fireOnEach(prefixLength, 0, initialArray); >+ initialArray = initialArray.slice(prefixLength); >+ currentArray = currentArray.slice(prefixLength); >+ } >+ >+ let [deletionCount, additionCount] = findShortestEdit(); >+ fireOnEach(deletionCount, -1, initialArray); >+ fireOnEach(additionCount, 1, currentArray); >+ initialArray = initialArray.slice(deletionCount); >+ currentArray = currentArray.slice(additionCount); > } > >+ fireOnEach(suffix.length, 0, suffix); > } > }); > >diff --git a/Source/WebInspectorUI/UserInterface/Controllers/CSSManager.js b/Source/WebInspectorUI/UserInterface/Controllers/CSSManager.js >index a622d0e5296..a2fbe91eac2 100644 >--- a/Source/WebInspectorUI/UserInterface/Controllers/CSSManager.js >+++ b/Source/WebInspectorUI/UserInterface/Controllers/CSSManager.js >@@ -431,6 +431,16 @@ WI.CSSManager = class CSSManager extends WI.Object > this._modifiedStyles.set(style.stringId, style); > } > >+ getModifiedStyle(style) >+ { >+ return this._modifiedStyles.get(style.stringId); >+ } >+ >+ removeModifiedStyle(style) >+ { >+ this._modifiedStyles.delete(style.stringId); >+ } >+ > // Protected > > mediaQueryResultChanged() >diff --git a/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js b/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js >index 2c10895cc78..82082cfc153 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js >+++ b/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js >@@ -33,6 +33,7 @@ WI.CSSProperty = class CSSProperty extends WI.Object > this._index = index; > this._overridingProperty = null; > this._initialState = null; >+ this._modified = false; > > this.update(text, name, value, priority, enabled, overridden, implicit, anonymous, valid, styleSheetTextRange, true); > } >@@ -184,7 +185,16 @@ WI.CSSProperty = class CSSProperty extends WI.Object > > get modified() > { >- return !!this._initialState; >+ return this._modified; >+ } >+ >+ set modified(value) >+ { >+ if (this._modified === value) >+ return; >+ >+ this._modified = value; >+ this.dispatchEventToListeners(WI.CSSProperty.Event.ModifiedChanged); > } > > get name() >@@ -377,6 +387,37 @@ WI.CSSProperty = class CSSProperty extends WI.Object > return this._hasOtherVendorNameOrKeyword; > } > >+ equals(property) >+ { >+ if (property === this) >+ return true; >+ >+ if (!property) >+ return false; >+ >+ return this._name === property.name && this._rawValue === property.rawValue && this._enabled === property.enabled; >+ } >+ >+ clone() >+ { >+ let cssProperty = 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); >+ >+ cssProperty.ownerStyle = this._ownerStyle; >+ >+ return cssProperty; >+ } >+ > // Private > > _updateStyleText(forceRemove = false) >@@ -393,8 +434,6 @@ 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; >@@ -437,6 +476,7 @@ WI.CSSProperty = class CSSProperty extends WI.Object > > let propertyWasRemoved = !newText; > this._ownerStyle.shiftPropertiesAfter(this, lineDelta, columnDelta, propertyWasRemoved); >+ this._ownerStyle.updatePropertiesModifiedState(); > } > > _prependSemicolonIfNeeded() >@@ -456,30 +496,13 @@ WI.CSSProperty = class CSSProperty extends WI.Object > > _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) { >+ if (this._ownerStyle) > this._ownerStyle.markModified(); >- this._initialState.ownerStyle = this._ownerStyle.initialState; >- } > } > }; > > WI.CSSProperty.Event = { > Changed: "css-property-changed", >+ ModifiedChanged: "css-property-modified-changed", > OverriddenStatusChanged: "css-property-overridden-status-changed" > }; >diff --git a/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js b/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js >index 74b694f2212..f4159e28bb8 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js >+++ b/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js >@@ -365,9 +365,11 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > > markModified() > { >- let properties = this._initialState ? this._initialState.properties : this._properties; >- > if (!this._initialState) { >+ let visibleProperties = this.visibleProperties.map((property) => { >+ return property.clone(); >+ }); >+ > this._initialState = new WI.CSSStyleDeclaration( > this._nodeStyles, > this._ownerStyleSheet, >@@ -376,12 +378,10 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > this._node, > this._inherited, > this._text, >- [], // Passing CSS properties here would change their ownerStyle. >+ visibleProperties, > this._styleSheetTextRange); > } > >- this._initialState.properties = properties.map((property) => { return property.initialState || property }); >- > WI.cssManager.addModifiedStyle(this); > } > >@@ -417,6 +417,29 @@ WI.CSSStyleDeclaration = class CSSStyleDeclaration extends WI.Object > this._visibleProperties = null; > } > >+ updatePropertiesModifiedState() >+ { >+ if (!this._initialState) >+ return; >+ >+ if (this._type === WI.CSSStyleDeclaration.Type.Computed) >+ return; >+ >+ let initialCSSProperties = this._initialState.visibleProperties; >+ let cssProperties = this.visibleProperties; >+ >+ let hasModified = false; >+ Array.diffArrays(initialCSSProperties, cssProperties, (property, action) => { >+ if (action !== 0) >+ hasModified = true; >+ >+ property.modified = action === 1; >+ }, (a, b) => a.equals(b)); >+ >+ if (!hasModified) >+ WI.cssManager.removeModifiedStyle(this); >+ } >+ > // Protected > > get nodeStyles() >diff --git a/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.js b/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.js >index 8fef7aff5a6..4b7dda4b3d6 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.js >+++ b/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.js >@@ -149,28 +149,25 @@ WI.ChangesDetailsSidebarPanel = class ChangesDetailsSidebarPanel extends WI.DOMD > > selectorLineElement.append(" {\n"); > >- let appendProperty = (cssProperty, className) => { >- let propertyLineElement = ruleElement.appendChild(document.createElement("div")); >- propertyLineElement.classList.add("css-property-line", className); >- let stylePropertyView = new WI.SpreadsheetStyleProperty(null, cssProperty, {readOnly: true}); >- propertyLineElement.append(WI.indentString(), stylePropertyView.element, "\n"); >- }; >- > let initialCSSProperties = style.initialState.visibleProperties; > let cssProperties = style.visibleProperties; > > Array.diffArrays(initialCSSProperties, cssProperties, (cssProperty, action) => { >- if (action === 0) { >- if (cssProperty.modified) { >- appendProperty(cssProperty.initialState, "removed"); >- appendProperty(cssProperty, "added"); >- } else >- appendProperty(cssProperty, "unchanged"); >- } else if (action === 1) >- appendProperty(cssProperty, "added"); >+ let className = ""; >+ if (action === 1) >+ className = "added"; > else if (action === -1) >- appendProperty(cssProperty, "removed"); >- }); >+ className = "removed"; >+ else >+ className = "unchanged"; >+ >+ let propertyLineElement = ruleElement.appendChild(document.createElement("div")); >+ propertyLineElement.classList.add("css-property-line", className); >+ >+ const delegate = null; >+ let stylePropertyView = new WI.SpreadsheetStyleProperty(delegate, cssProperty, {readOnly: true}); >+ propertyLineElement.append(WI.indentString(), stylePropertyView.element, "\n"); >+ }, (a, b) => a.equals(b)); > > let closeBraceElement = document.createElement("span"); > closeBraceElement.className = "close-brace"; >diff --git a/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.js b/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.js >index 4361f8892bf..e82da88c485 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.js >+++ b/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.js >@@ -82,6 +82,9 @@ WI.SpreadsheetCSSStyleDeclarationEditor = class SpreadsheetCSSStyleDeclarationEd > > this.element.removeChildren(); > >+ if (this._style) >+ this._style.updatePropertiesModifiedState(); >+ > let properties = this.propertiesToRender; > this.element.classList.toggle("no-properties", !properties.length); > >diff --git a/Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js b/Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js >index 93d4d16b295..6cbc629b264 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js >+++ b/Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js >@@ -53,6 +53,7 @@ WI.SpreadsheetStyleProperty = class SpreadsheetStyleProperty extends WI.Object > > if (!this._readOnly) { > this._element.tabIndex = -1; >+ property.addEventListener(WI.CSSProperty.Event.ModifiedChanged, this.updateStatus, this); > > this._element.addEventListener("blur", (event) => { > // Keep selection after tabbing out of Web Inspector window and back.
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 195264
:
366548
|
366552
|
366558
|
366561
|
366564
|
366568
|
366569
|
366672
|
366678
|
366683
|
368625
|
369076
|
369077
|
369201
|
369999
|
370198
|
370376
|
370902
|
371081