Diff
Modified: trunk/LayoutTests/ChangeLog (240558 => 240559)
--- trunk/LayoutTests/ChangeLog 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/LayoutTests/ChangeLog 2019-01-28 09:29:20 UTC (rev 240559)
@@ -1,3 +1,16 @@
+2019-01-28 Nikita Vasilyev <[email protected]>
+
+ 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-26 Simon Fraser <[email protected]>
Have composited RenderIFrame layers make FrameHosting scrolling tree nodes to parent the iframe's scrolling node
Modified: trunk/LayoutTests/inspector/unit-tests/array-utilities-expected.txt (240558 => 240559)
--- trunk/LayoutTests/inspector/unit-tests/array-utilities-expected.txt 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/LayoutTests/inspector/unit-tests/array-utilities-expected.txt 2019-01-28 09:29:20 UTC (rev 240559)
@@ -70,6 +70,20 @@
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.
Modified: trunk/LayoutTests/inspector/unit-tests/array-utilities.html (240558 => 240559)
--- trunk/LayoutTests/inspector/unit-tests/array-utilities.html 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/LayoutTests/inspector/unit-tests/array-utilities.html 2019-01-28 09:29:20 UTC (rev 240559)
@@ -152,6 +152,35 @@
});
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() {
let object1 = {};
Modified: trunk/Source/WebInspectorUI/ChangeLog (240558 => 240559)
--- trunk/Source/WebInspectorUI/ChangeLog 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/Source/WebInspectorUI/ChangeLog 2019-01-28 09:29:20 UTC (rev 240559)
@@ -1,3 +1,91 @@
+2019-01-28 Nikita Vasilyev <[email protected]>
+
+ 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-26 Devin Rousso <[email protected]>
Web Inspector: handle CSS Color 4 color syntaxes
Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (240558 => 240559)
--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2019-01-28 09:29:20 UTC (rev 240559)
@@ -169,6 +169,7 @@
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";
@@ -187,6 +188,7 @@
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";
@@ -366,6 +368,7 @@
localizedStrings["Elements"] = "Elements";
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";
Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Setting.js (240558 => 240559)
--- trunk/Source/WebInspectorUI/UserInterface/Base/Setting.js 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Setting.js 2019-01-28 09:29:20 UTC (rev 240559)
@@ -153,6 +153,7 @@
// 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),
Modified: trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js (240558 => 240559)
--- trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/Source/WebInspectorUI/UserInterface/Base/Utilities.js 2019-01-28 09:29:20 UTC (rev 240559)
@@ -489,6 +489,67 @@
}
});
+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()
Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/CSSManager.js (240558 => 240559)
--- trunk/Source/WebInspectorUI/UserInterface/Controllers/CSSManager.js 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/CSSManager.js 2019-01-28 09:29:20 UTC (rev 240559)
@@ -45,6 +45,7 @@
this._styleSheetIdentifierMap = new Map;
this._styleSheetFrameURLMap = new Map;
this._nodeStylesMap = {};
+ this._modifiedCSSRules = new Map;
this._defaultAppearance = null;
this._forcedAppearance = null;
@@ -348,6 +349,21 @@
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 @@
this._fetchedInitialStyleSheets = InspectorBackend.domains.CSS.hasEvent("styleSheetAdded");
this._styleSheetIdentifierMap.clear();
this._styleSheetFrameURLMap.clear();
+ this._modifiedCSSRules.clear();
+
this._nodeStylesMap = {};
}
Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (240558 => 240559)
--- trunk/Source/WebInspectorUI/UserInterface/Main.html 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html 2019-01-28 09:29:20 UTC (rev 240559)
@@ -54,6 +54,7 @@
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
+ <link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
<link rel="stylesheet" href=""
@@ -595,6 +596,7 @@
<script src=""
<script src=""
<script src=""
+ <script src=""
<script src=""
<script src=""
<script src=""
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js (240558 => 240559)
--- trunk/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/CSSProperty.js 2019-01-28 09:29:20 UTC (rev 240559)
@@ -31,6 +31,7 @@
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 @@
remove()
{
+ this._markModified();
+
// Setting name or value to an empty string removes the entire CSSProperty.
this._name = "";
const forceRemove = true;
@@ -133,6 +136,8 @@
replaceWithText(text)
{
+ this._markModified();
+
this._updateOwnerStyleText(this._text, text, true);
}
@@ -142,6 +147,7 @@
if (this._enabled === !disabled)
return;
+ this._markModified();
this._enabled = !disabled;
if (disabled)
@@ -160,6 +166,7 @@
if (this._text === newText)
return;
+ this._markModified();
this._updateOwnerStyleText(this._text, newText);
this._text = newText;
}
@@ -172,6 +179,11 @@
return `${this._name}: ${this._rawValue};`;
}
+ get modified()
+ {
+ return !!this._initialState;
+ }
+
get name()
{
return this._name;
@@ -182,6 +194,7 @@
if (name === this._name)
return;
+ this._markModified();
this._name = name;
this._updateStyleText();
}
@@ -215,6 +228,8 @@
if (value === this._rawValue)
return;
+ this._markModified();
+
this._rawValue = value;
this._value = undefined;
this._updateStyleText();
@@ -272,6 +287,11 @@
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 @@
_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 @@
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 = {
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/CSSRule.js (240558 => 240559)
--- trunk/Source/WebInspectorUI/UserInterface/Models/CSSRule.js 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/CSSRule.js 2019-01-28 09:29:20 UTC (rev 240559)
@@ -35,6 +35,7 @@
this._ownerStyleSheet = ownerStyleSheet || null;
this._id = id || null;
this._type = type || null;
+ this._initialState = null;
this.update(sourceCodeLocation, selectorText, selectors, matchedSelectorIndices, style, mediaList, true);
}
@@ -41,9 +42,13 @@
// 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 @@
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()
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js (240558 => 240559)
--- trunk/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/CSSStyleDeclaration.js 2019-01-28 09:29:20 UTC (rev 240559)
@@ -40,12 +40,13 @@
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 @@
// Public
+ get initialState() { return this._initialState; }
+
get id()
{
return this._id;
@@ -116,11 +119,11 @@
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 @@
}
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,11 +208,27 @@
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()
{
if (!this._visibleProperties)
@@ -268,7 +287,7 @@
var bestMatchProperty = null;
- findMatch(this._enabledProperties);
+ findMatch(this.enabledProperties);
if (bestMatchProperty)
return bestMatchProperty;
@@ -296,6 +315,7 @@
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 @@
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.
Added: trunk/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.css (0 => 240559)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.css (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.css 2019-01-28 09:29:20 UTC (rev 240559)
@@ -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%);
+ }
+}
Added: trunk/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.js (0 => 240559)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.js (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ChangesDetailsSidebarPanel.js 2019-01-28 09:29:20 UTC (rev 240559)
@@ -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();
+ }
+};
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ElementsTabContentView.js (240558 => 240559)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ElementsTabContentView.js 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ElementsTabContentView.js 2019-01-28 09:29:20 UTC (rev 240559)
@@ -28,8 +28,11 @@
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);
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/SettingsTabContentView.js (240558 => 240559)
--- trunk/Source/WebInspectorUI/UserInterface/Views/SettingsTabContentView.js 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/SettingsTabContentView.js 2019-01-28 09:29:20 UTC (rev 240559)
@@ -256,6 +256,7 @@
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();
}
@@ -290,6 +291,7 @@
}
listenForChange(WI.settings.experimentalEnableComputedStyleCascades);
+ listenForChange(WI.settings.experimentalEnableChangesPanel);
listenForChange(WI.settings.experimentalEnableLayersTab);
listenForChange(WI.settings.experimentalEnableNewTabBar);
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css (240558 => 240559)
--- trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationEditor.css 2019-01-28 09:29:20 UTC (rev 240559)
@@ -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 @@
.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%);
+ }
}
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js (240558 => 240559)
--- trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js 2019-01-28 03:03:31 UTC (rev 240558)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetStyleProperty.js 2019-01-28 09:29:20 UTC (rev 240559)
@@ -295,6 +295,9 @@
if (!this._property.enabled)
classNames.push("disabled");
+ if (this._property.modified)
+ classNames.push("modified");
+
if (this._selected)
classNames.push("selected");