WebKit Bugzilla
Attachment 369999 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), 20.66 KB, created by
Nikita Vasilyev
on 2019-05-15 15:41:16 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Nikita Vasilyev
Created:
2019-05-15 15:41:16 PDT
Size:
20.66 KB
patch
obsolete
>diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 24b7d8c6f58..6a776d4b131 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,16 @@ >+2019-05-15 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-04-03 Myles C. Maxfield <mmaxfield@apple.com> > > -apple-trailing-word is needed for browser detection >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 6809f8dab28..a854271daf8 100644 >--- a/Source/WebInspectorUI/ChangeLog >+++ b/Source/WebInspectorUI/ChangeLog >@@ -1,3 +1,47 @@ >+2019-05-15 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-04-03 Devin Rousso <drousso@apple.com> > > Web Inspector: Single click on links in non-read-only TextEditors should not follow links >diff --git a/Source/WebInspectorUI/UserInterface/Base/Utilities.js b/Source/WebInspectorUI/UserInterface/Base/Utilities.js >index 174faabfad3..8d2e9772c15 100644 >--- a/Source/WebInspectorUI/UserInterface/Base/Utilities.js >+++ b/Source/WebInspectorUI/UserInterface/Base/Utilities.js >@@ -501,62 +501,85 @@ 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; >+ value(initialArray, currentArray, onEach, comparator = (initial, current) => initial === current) >+ { >+ function findShortestEdit(initialArray, currentArray) { >+ 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; >+ if (comparator(initialArray[i], currentArray[j])) { >+ if (newEditCount < editCount) { >+ editCount = newEditCount; >+ deletionCount = i; >+ additionCount = j; >+ } >+ break; >+ } > } > } >+ return [deletionCount, additionCount]; >+ } > >- ++i; >- indexInitial = i + deltaInitial; >- indexCurrent = i + deltaCurrent; >+ function commonPrefixSize(listA, listB) { >+ let shortListLength = Math.min(listA.length, listB.length); >+ let i = 0; >+ for (; i < shortListLength; ++i) { >+ if (!comparator(listA[i], listB[i])) >+ break; >+ } >+ return i; > } > >- for (let i = indexInitial; i < initialArray.length; ++i) { >- // Removed. >- onEach(initialArray[i], -1); >+ function commonSuffixSize(listA, listB) { >+ let aLength = listA.length; >+ let bLength = listB.length; >+ let shortListLength = Math.min(aLength, bLength); >+ let i = 0; >+ for (; i < shortListLength; ++i) { >+ let a = listA[aLength - i - 1]; >+ let b = listB[bLength - i - 1]; >+ if (!comparator(a, b)) >+ break; >+ } >+ return i; >+ } >+ >+ function callOnEach(count, action, array) { >+ for (let i = 0; i < count; ++i) >+ onEach(array[i], action); > } > >- for (let i = indexCurrent; i < currentArray.length; ++i) { >- // Added. >- onEach(currentArray[i], 1); >+ // Remove common suffix. >+ let suffixLength = commonSuffixSize(initialArray, currentArray); >+ let suffix = []; >+ if (suffixLength) { >+ suffix = initialArray.slice(-suffixLength); >+ initialArray = initialArray.slice(0, -suffixLength); >+ currentArray = currentArray.slice(0, -suffixLength); >+ } >+ >+ while (initialArray.length || currentArray.length) { >+ // Remove common prefix. >+ let prefixLength = commonPrefixSize(initialArray, currentArray); >+ if (prefixLength) { >+ callOnEach(prefixLength, 0, initialArray); >+ initialArray = initialArray.slice(prefixLength); >+ currentArray = currentArray.slice(prefixLength); >+ } >+ >+ let [deletionCount, additionCount] = findShortestEdit(initialArray, currentArray); >+ callOnEach(deletionCount, -1, initialArray); >+ callOnEach(additionCount, 1, currentArray); >+ initialArray = initialArray.slice(deletionCount); >+ currentArray = currentArray.slice(additionCount); > } > >+ callOnEach(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..fd618b22681 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) >@@ -437,6 +478,7 @@ WI.CSSProperty = class CSSProperty extends WI.Object > > let propertyWasRemoved = !newText; > this._ownerStyle.shiftPropertiesAfter(this, lineDelta, columnDelta, propertyWasRemoved); >+ this._ownerStyle.updatePropertiesModifiedState(); > } > > _prependSemicolonIfNeeded() >@@ -456,30 +498,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