Web Inspector: Canvas Tab initial user experience is poor when no canvases exist
authormattbaker@apple.com <mattbaker@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 6 Dec 2017 20:28:26 +0000 (20:28 +0000)
committermattbaker@apple.com <mattbaker@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 6 Dec 2017 20:28:26 +0000 (20:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=179329
<rdar://problem/35842036>

Reviewed by Timothy Hatcher.

This patch adds a new method, WI.createNavigationItemHelp, for creating command
help to display in a message text view. The method accepts a format string and
NavigationItem, and returns a DOM element. For example,

    WI.createNavigationItemHelp("Press %s to do X.", navigationItem)

returns:

    <div class="navigation-item-help">
        Press <div class="navigation-bar"><div class="item">...</div></div> to do X.
    </div>

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Base/Main.js:

* UserInterface/Controllers/CanvasManager.js:
(WI.CanvasManager.prototype.importRecording):
Importing a recording should be a manager command with a corresponding
event, so that it's decoupled from any specific location in the UI.

* UserInterface/Views/CanvasOverviewContentView.js:
(WI.CanvasOverviewContentView):

* UserInterface/Views/CanvasTabContentView.js:
(WI.CanvasTabContentView):
(WI.CanvasTabContentView.prototype.attached):
(WI.CanvasTabContentView.prototype._recordingImportedOrStopped):
(WI.CanvasTabContentView.prototype._recordingStopped): Deleted.
(WI.CanvasTabContentView.prototype._navigationSidebarImport): Deleted.

* UserInterface/Views/Main.css:
(.message-text-view .navigation-item-help):
(.message-text-view .navigation-item-help .navigation-bar):
(.message-text-view .navigation-item-help .navigation-bar > .item):
New styles for a NavigationItem appearing inline as part of descriptive
text. Wrapped in a fake navigation bar so navigation item styles are picked up.

* UserInterface/Views/RecordingNavigationSidebarPanel.js:
(WI.RecordingNavigationSidebarPanel.prototype.initialLayout):
(WI.RecordingNavigationSidebarPanel.prototype._importNavigationItemClicked): Deleted.
Moved import code to CanvasManager.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225587 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Base/Main.js
Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js
Source/WebInspectorUI/UserInterface/Views/CanvasOverviewContentView.js
Source/WebInspectorUI/UserInterface/Views/CanvasTabContentView.js
Source/WebInspectorUI/UserInterface/Views/Main.css
Source/WebInspectorUI/UserInterface/Views/RecordingNavigationSidebarPanel.js

index 12287be..a4f2abf 100644 (file)
@@ -1,3 +1,53 @@
+2017-12-06  Matt Baker  <mattbaker@apple.com>
+
+        Web Inspector: Canvas Tab initial user experience is poor when no canvases exist
+        https://bugs.webkit.org/show_bug.cgi?id=179329
+        <rdar://problem/35842036>
+
+        Reviewed by Timothy Hatcher.
+
+        This patch adds a new method, WI.createNavigationItemHelp, for creating command
+        help to display in a message text view. The method accepts a format string and
+        NavigationItem, and returns a DOM element. For example,
+
+            WI.createNavigationItemHelp("Press %s to do X.", navigationItem)
+
+        returns:
+
+            <div class="navigation-item-help">
+                Press <div class="navigation-bar"><div class="item">...</div></div> to do X.
+            </div>
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Base/Main.js:
+
+        * UserInterface/Controllers/CanvasManager.js:
+        (WI.CanvasManager.prototype.importRecording):
+        Importing a recording should be a manager command with a corresponding
+        event, so that it's decoupled from any specific location in the UI.
+
+        * UserInterface/Views/CanvasOverviewContentView.js:
+        (WI.CanvasOverviewContentView):
+
+        * UserInterface/Views/CanvasTabContentView.js:
+        (WI.CanvasTabContentView):
+        (WI.CanvasTabContentView.prototype.attached):
+        (WI.CanvasTabContentView.prototype._recordingImportedOrStopped):
+        (WI.CanvasTabContentView.prototype._recordingStopped): Deleted.
+        (WI.CanvasTabContentView.prototype._navigationSidebarImport): Deleted.
+
+        * UserInterface/Views/Main.css:
+        (.message-text-view .navigation-item-help):
+        (.message-text-view .navigation-item-help .navigation-bar):
+        (.message-text-view .navigation-item-help .navigation-bar > .item):
+        New styles for a NavigationItem appearing inline as part of descriptive
+        text. Wrapped in a fake navigation bar so navigation item styles are picked up.
+
+        * UserInterface/Views/RecordingNavigationSidebarPanel.js:
+        (WI.RecordingNavigationSidebarPanel.prototype.initialLayout):
+        (WI.RecordingNavigationSidebarPanel.prototype._importNavigationItemClicked): Deleted.
+        Moved import code to CanvasManager.
+
 2017-12-06  Devin Rousso  <webkit@devinrousso.com>
 
         Web Inspector: REGRESSION(r225569): CSSStyleDetailsSidebarPanel no longer exists
index 64cb40e..ffbd416 100644 (file)
@@ -702,6 +702,7 @@ localizedStrings["Position X"] = "Position X";
 localizedStrings["Position Y"] = "Position Y";
 localizedStrings["Prefer indent using:"] = "Prefer indent using:";
 localizedStrings["Preserve Log"] = "Preserve Log";
+localizedStrings["Press %s to load a recording from file."] = "Press %s to load a recording from file.";
 localizedStrings["Pressed"] = "Pressed";
 localizedStrings["Pretty print"] = "Pretty print";
 localizedStrings["Preview"] = "Preview";
index 1377301..f06e964 100644 (file)
@@ -2250,6 +2250,28 @@ WI.createMessageTextView = function(message, isError)
     return messageElement;
 };
 
+WI.createNavigationItemHelp = function(formatString, navigationItem)
+{
+    console.assert(typeof formatString === "string");
+    console.assert(navigationItem instanceof WI.NavigationItem);
+
+    function append(a, b) {
+        a.append(b);
+        return a;
+    }
+
+    let containerElement = document.createElement("div");
+    containerElement.className = "navigation-item-help";
+    containerElement.__navigationItem = navigationItem;
+
+    let wrapperElement = document.createElement("div");
+    wrapperElement.className = "navigation-bar";
+    wrapperElement.appendChild(navigationItem.element);
+
+    String.format(formatString, [wrapperElement], String.standardFormatters, containerElement, append);
+    return containerElement;
+};
+
 WI.createGoToArrowButton = function()
 {
     var button = document.createElement("button");
index 7c7eb5d..d224b4e 100644 (file)
@@ -55,6 +55,35 @@ WI.CanvasManager = class CanvasManager extends WI.Object
 
     get recordingCanvas() { return this._recordingCanvas; }
 
+    importRecording()
+    {
+        WI.loadDataFromFile((data, filename) => {
+            if (!data)
+                return;
+
+            let payload = null;
+            try {
+                payload = JSON.parse(data);
+            } catch (e) {
+                WI.Recording.synthesizeError(e);
+                return;
+            }
+
+            let recording = WI.Recording.fromPayload(payload);
+            if (!recording) {
+                WI.Recording.synthesizeError(WI.UIString("unsupported version."));
+                return;
+            }
+
+            let extensionStart = filename.lastIndexOf(".");
+            if (extensionStart !== -1)
+                filename = filename.substring(0, extensionStart);
+            recording.createDisplayName(filename);
+
+            this.dispatchEventToListeners(WI.CanvasManager.Event.RecordingImported, {recording});
+        });
+    }
+
     startRecording(canvas, singleFrame)
     {
         console.assert(!this._recordingCanvas, "Recording already started.");
@@ -271,6 +300,7 @@ WI.CanvasManager = class CanvasManager extends WI.Object
 WI.CanvasManager.Event = {
     CanvasAdded: "canvas-manager-canvas-was-added",
     CanvasRemoved: "canvas-manager-canvas-was-removed",
+    RecordingImported: "canvas-manager-recording-imported",
     RecordingStarted: "canvas-manager-recording-started",
     RecordingProgress: "canvas-manager-recording-progress",
     RecordingStopped: "canvas-manager-recording-stopped",
index 2533f47..d49e292 100644 (file)
@@ -34,6 +34,13 @@ WI.CanvasOverviewContentView = class CanvasOverviewContentView extends WI.Collec
         descriptionElement.className = "description";
         descriptionElement.textContent = WI.UIString("Waiting for canvas contexts created by script or CSS.");
 
+        let importNavigationItem = new WI.ButtonNavigationItem("import-recording", WI.UIString("Import"), "Images/Import.svg", 15, 15);
+        importNavigationItem.buttonStyle = WI.ButtonNavigationItem.Style.ImageAndText;
+        importNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, () => { WI.canvasManager.importRecording(); });
+
+        let importHelpElement = WI.createNavigationItemHelp(WI.UIString("Press %s to load a recording from file."), importNavigationItem);
+        contentPlaceholder.appendChild(importHelpElement);
+
         super(representedObject, WI.CanvasContentView, contentPlaceholder);
 
         this.element.classList.add("canvas-overview");
index 29cfa83..8d0c4e5 100644 (file)
@@ -54,7 +54,6 @@ WI.CanvasTabContentView = class CanvasTabContentView extends WI.ContentBrowserTa
         this.contentBrowser.navigationBar.insertNavigationItem(this._overviewNavigationItem, 2);
         this.contentBrowser.navigationBar.insertNavigationItem(new WI.DividerNavigationItem, 3);
 
-        this.navigationSidebarPanel.addEventListener(WI.RecordingNavigationSidebarPanel.Event.Import, this._navigationSidebarImport, this);
         this.navigationSidebarPanel.contentTreeOutline.addEventListener(WI.TreeOutline.Event.SelectionDidChange, this._navigationSidebarTreeOutlineSelectionChanged, this);
     }
 
@@ -141,7 +140,8 @@ WI.CanvasTabContentView = class CanvasTabContentView extends WI.ContentBrowserTa
 
         WI.canvasManager.addEventListener(WI.CanvasManager.Event.CanvasAdded, this._handleCanvasAdded, this);
         WI.canvasManager.addEventListener(WI.CanvasManager.Event.CanvasRemoved, this._handleCanvasRemoved, this);
-        WI.canvasManager.addEventListener(WI.CanvasManager.Event.RecordingStopped, this._recordingStopped, this);
+        WI.canvasManager.addEventListener(WI.CanvasManager.Event.RecordingImported, this._recordingImportedOrStopped, this);
+        WI.canvasManager.addEventListener(WI.CanvasManager.Event.RecordingStopped, this._recordingImportedOrStopped, this);
         WI.RecordingContentView.addEventListener(WI.RecordingContentView.Event.RecordingActionIndexChanged, this._recordingActionIndexChanged, this);
 
         let canvases = new Set(Array.from(this._canvasCollection.items).concat(WI.canvasManager.canvases));
@@ -233,37 +233,17 @@ WI.CanvasTabContentView = class CanvasTabContentView extends WI.ContentBrowserTa
         console.assert(false, "Unexpected representedObject.", representedObject);
     }
 
-    _recordingStopped(event)
+    _recordingImportedOrStopped(event)
     {
         let recording = event.data.recording;
-        if (!recording) {
-            // FIXME: <https://webkit.org/b/178185> Web Inspector: Canvas tab: show detailed status during canvas recording
+        if (!recording)
             return;
-        }
 
         this._recordingAdded(recording, {
             suppressShowRecording: event.data.fromConsole,
         });
     }
 
-    _navigationSidebarImport(event)
-    {
-        let {filename, payload} = event.data;
-        let recording = WI.Recording.fromPayload(payload);
-        if (!recording) {
-            WI.Recording.synthesizeError(WI.UIString("unsupported version."));
-            return;
-        }
-
-        let extensionStart = filename.lastIndexOf(".");
-        if (extensionStart !== -1)
-            filename = filename.substring(0, extensionStart);
-
-        recording.createDisplayName(filename);
-
-        this._recordingAdded(recording);
-    }
-
     _navigationSidebarTreeOutlineSelectionChanged(event)
     {
         if (!event.data.selectedElement)
index 2130203..69ddb49 100644 (file)
@@ -189,6 +189,29 @@ body.docked:matches(.right, .left) #navigation-sidebar.collapsed > .resizer {
     font-size: var(--message-text-view-font-size);
 }
 
+.message-text-view .navigation-item-help {
+    display: inline-flex;
+    padding: 10px 0;
+}
+
+.message-text-view .navigation-item-help .navigation-bar {
+    height: auto;
+    padding: 0 4px;
+    border-bottom: none;
+    overflow: visible;
+}
+
+.message-text-view .navigation-item-help .navigation-bar > .item {
+    /* Adjust button top by the border thickness, to keep button text on the baseline. */
+    position: relative;
+    top: -1px;
+
+    padding: 1px 4px;
+    font-size: 11px;
+    border-radius: 4px;
+    border: solid 1px var(--border-color);
+}
+
 .message-text-view.error {
     color: var(--error-text-color);
 }
index 86ba06a..ee21753 100644 (file)
@@ -134,7 +134,7 @@ WI.RecordingNavigationSidebarPanel = class RecordingNavigationSidebarPanel exten
 
         this._importButton = importNavigationItem.element.appendChild(document.createElement("button"));
         this._importButton.textContent = importLabel;
-        this._importButton.addEventListener("click", this._importNavigationItemClicked.bind(this));
+        this._importButton.addEventListener("click", () => { WI.canvasManager.importRecording(); });
 
         const exportLabel = WI.UIString("Export");
         let exportNavigationItem = new WI.NavigationItem("recording-export", role, exportLabel);
@@ -171,24 +171,6 @@ WI.RecordingNavigationSidebarPanel = class RecordingNavigationSidebarPanel exten
 
     // Private
 
-    _importNavigationItemClicked(event)
-    {
-        WI.loadDataFromFile((data, filename) => {
-            if (!data)
-                return;
-
-            let payload = null;
-            try {
-                payload = JSON.parse(data);
-            } catch (e) {
-                WI.Recording.synthesizeError(e);
-                return;
-            }
-
-            this.dispatchEventToListeners(WI.RecordingNavigationSidebarPanel.Event.Import, {payload, filename});
-        });
-    }
-
     _exportNavigationItemClicked(event)
     {
         if (!this._recording || !this.contentBrowser || !this.contentBrowser.currentContentView || !this.contentBrowser.currentContentView.supportsSave)