Changeset 223322 in webkit


Ignore:
Timestamp:
Oct 14, 2017 12:05:16 PM (7 years ago)
Author:
Matt Baker
Message:

Web Inspector: Canvas tab: recordings should have a unique name
https://bugs.webkit.org/show_bug.cgi?id=178188
<rdar://problem/34943364>

Reviewed by Devin Rousso.

  • Localizations/en.lproj/localizedStrings.js:

New format string "Recording %d".

  • UserInterface/Base/FileUtilities.js:

(WI.loadDataFromFile):
Pass chosen filename to callback.

  • UserInterface/Controllers/CanvasManager.js:

(WI.CanvasManager.prototype.recordingFinished):
Create a unique name for the recording.

  • UserInterface/Models/Recording.js:

(WI.Recording):
(WI.Recording.fromPayload):
(WI.Recording.prototype.get displayName):
(WI.Recording.prototype.createDisplayName):

  • UserInterface/Views/RecordingContentView.js:

(WI.RecordingContentView.prototype.get saveData):
Use encodeURI so that special characters can be used in filenames, and
to be consistent with other saveData implementations.

  • UserInterface/Views/RecordingNavigationSidebarPanel.js:

(WI.RecordingNavigationSidebarPanel.prototype.set recording):
(WI.RecordingNavigationSidebarPanel.prototype._importNavigationItemClicked):
Drive-by fix: wait until actions are resolved before updating UI.

  • UserInterface/Views/RecordingTabContentView.js:

(WI.RecordingTabContentView.prototype._navigationSidebarImport):
Try to use the imported filename as the recording name. If the name
collides with that of another imported recording, append a unique suffix.

Location:
trunk/Source/WebInspectorUI
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebInspectorUI/ChangeLog

    r223321 r223322  
     12017-10-14  Matt Baker  <mattbaker@apple.com>
     2
     3        Web Inspector: Canvas tab: recordings should have a unique name
     4        https://bugs.webkit.org/show_bug.cgi?id=178188
     5        <rdar://problem/34943364>
     6
     7        Reviewed by Devin Rousso.
     8
     9        * Localizations/en.lproj/localizedStrings.js:
     10        New format string "Recording %d".
     11
     12        * UserInterface/Base/FileUtilities.js:
     13        (WI.loadDataFromFile):
     14        Pass chosen filename to callback.
     15
     16        * UserInterface/Controllers/CanvasManager.js:
     17        (WI.CanvasManager.prototype.recordingFinished):
     18        Create a unique name for the recording.
     19
     20        * UserInterface/Models/Recording.js:
     21        (WI.Recording):
     22        (WI.Recording.fromPayload):
     23        (WI.Recording.prototype.get displayName):
     24        (WI.Recording.prototype.createDisplayName):
     25
     26        * UserInterface/Views/RecordingContentView.js:
     27        (WI.RecordingContentView.prototype.get saveData):
     28        Use encodeURI so that special characters can be used in filenames, and
     29        to be consistent with other `saveData` implementations.
     30
     31        * UserInterface/Views/RecordingNavigationSidebarPanel.js:
     32        (WI.RecordingNavigationSidebarPanel.prototype.set recording):
     33        (WI.RecordingNavigationSidebarPanel.prototype._importNavigationItemClicked):
     34        Drive-by fix: wait until actions are resolved before updating UI.
     35
     36        * UserInterface/Views/RecordingTabContentView.js:
     37        (WI.RecordingTabContentView.prototype._navigationSidebarImport):
     38        Try to use the imported filename as the recording name. If the name
     39        collides with that of another imported recording, append a unique suffix.
     40
    1412017-10-14  Devin Rousso  <webkit@devinrousso.com>
    242
  • trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js

    r223321 r223322  
    709709localizedStrings["Recently Closed Tabs"] = "Recently Closed Tabs";
    710710localizedStrings["Recording"] = "Recording";
     711localizedStrings["Recording %d"] = "Recording %d";
    711712localizedStrings["Recording Timeline Data"] = "Recording Timeline Data";
    712713localizedStrings["Recording error: %s"] = "Recording error: %s";
  • trunk/Source/WebInspectorUI/UserInterface/Base/FileUtilities.js

    r221891 r223322  
    7777        }
    7878
     79        let file = inputElement.files[0];
    7980        let reader = new FileReader;
    8081        reader.addEventListener("loadend", (event) => {
    81             callback(reader.result);
     82            callback(reader.result, file.name);
    8283        });
    83         reader.readAsText(inputElement.files[0]);
     84        reader.readAsText(file);
    8485    });
    8586    inputElement.click();
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js

    r223308 r223322  
    159159            return;
    160160
    161         let recording = recordingPayload ? WI.Recording.fromPayload(recordingPayload) : null;
    162         if (recording)
     161        let recording = recordingPayload ? WI.Recording.fromPayload(recordingPayload) : null
     162        if (recording) {
    163163            recording.source = canvas;
     164            recording.createDisplayName();
     165        }
    164166
    165167        this.dispatchEventToListeners(WI.CanvasManager.Event.RecordingStopped, {canvas, recording});
  • trunk/Source/WebInspectorUI/UserInterface/Models/Recording.js

    r222057 r223322  
    3333        this._frames = frames;
    3434        this._data = data;
     35        this._displayName = WI.UIString("Recording");
    3536
    3637        this._swizzle = [];
     
    6465    }
    6566
    66     // Static
    67 
    6867    static fromPayload(payload)
    6968    {
    7069        if (typeof payload !== "object" || payload === null)
    71             payload = {};
     70            return null;
    7271
    7372        if (isNaN(payload.version) || payload.version <= 0)
     
    166165    // Public
    167166
     167    get displayName() { return this._displayName; }
    168168    get type() { return this._type; }
    169169    get initialState() { return this._initialState; }
     
    175175    get source() { return this._source; }
    176176    set source(source) { this._source = source; }
     177
     178    createDisplayName(suggestedName)
     179    {
     180        let recordingNameSet;
     181        if (this._source) {
     182            recordingNameSet = this._source[WI.Recording.CanvasRecordingNamesSymbol];
     183            if (!recordingNameSet)
     184                this._source[WI.Recording.CanvasRecordingNamesSymbol] = recordingNameSet = new Set;
     185        } else
     186            recordingNameSet = WI.Recording._importedRecordingNameSet;
     187
     188        let name;
     189        if (suggestedName) {
     190            name = suggestedName;
     191            let duplicateNumber = 2;
     192            while (recordingNameSet.has(name))
     193                name = `${suggestedName} (${duplicateNumber++})`;
     194        } else {
     195            let recordingNumber = 1;
     196            do {
     197                name = WI.UIString("Recording %d").format(recordingNumber++);
     198            } while (recordingNameSet.has(name));
     199        }
     200
     201        recordingNameSet.add(name);
     202        this._displayName = name;
     203    }
    177204
    178205    async swizzle(index, type)
     
    282309    }
    283310};
     311
     312WI.Recording._importedRecordingNameSet = new Set;
     313
     314WI.Recording.CanvasRecordingNamesSymbol = Symbol("canvas-recording-names");
    284315
    285316WI.Recording.Type = {
  • trunk/Source/WebInspectorUI/UserInterface/Views/RecordingContentView.js

    r223308 r223322  
    149149    get saveData()
    150150    {
     151        let filename = this.representedObject.displayName;
     152        if (!filename.endsWith(".json"))
     153            filename += ".json";
     154
    151155        return {
    152             url: "web-inspector:///Recording.json",
     156            url: "web-inspector:///" + encodeURI(filename),
    153157            content: JSON.stringify(this.representedObject.toJSON()),
    154158            forceSaveAs: true,
  • trunk/Source/WebInspectorUI/UserInterface/Views/RecordingNavigationSidebarPanel.js

    r222057 r223322  
    5757        this._recording = recording;
    5858
    59         if (this._recording) {
    60             this._recording.actions.then((actions) => {
    61                 this.contentTreeOutline.element.dataset.indent = Number.countDigits(actions.length);
    62 
    63                 if (actions[0] instanceof WI.RecordingInitialStateAction)
    64                     this.contentTreeOutline.appendChild(new WI.RecordingActionTreeElement(actions[0], 0, this._recording.type));
    65 
    66                 let cumulativeActionIndex = 1;
    67                 this._recording.frames.forEach((frame, frameIndex) => {
    68                     let folder = new WI.FolderTreeElement(WI.UIString("Frame %d").format((frameIndex + 1).toLocaleString()));
    69                     this.contentTreeOutline.appendChild(folder);
    70 
    71                     for (let i = 0; i < frame.actions.length; ++i)
    72                         folder.appendChild(new WI.RecordingActionTreeElement(frame.actions[i], cumulativeActionIndex + i, this._recording.type));
    73 
    74                     if (frame.incomplete)
    75                         folder.subtitle = WI.UIString("Incomplete");
    76 
    77                     if (this._recording.frames.length === 1)
    78                         folder.expand();
    79 
    80                     cumulativeActionIndex += frame.actions.length;
    81                 });
     59        this.updateEmptyContentPlaceholder(WI.UIString("No Recording Data"));
     60
     61        if (!this._recording) {
     62            if (this._exportButton)
     63                this._exportButton.disabled = true;
     64            return;
     65        }
     66
     67        this._recording.actions.then((actions) => {
     68            this.contentTreeOutline.element.dataset.indent = Number.countDigits(actions.length);
     69
     70            if (actions[0] instanceof WI.RecordingInitialStateAction)
     71                this.contentTreeOutline.appendChild(new WI.RecordingActionTreeElement(actions[0], 0, this._recording.type));
     72
     73            let cumulativeActionIndex = 1;
     74            this._recording.frames.forEach((frame, frameIndex) => {
     75                let folder = new WI.FolderTreeElement(WI.UIString("Frame %d").format((frameIndex + 1).toLocaleString()));
     76                this.contentTreeOutline.appendChild(folder);
     77
     78                for (let i = 0; i < frame.actions.length; ++i)
     79                    folder.appendChild(new WI.RecordingActionTreeElement(frame.actions[i], cumulativeActionIndex + i, this._recording.type));
     80
     81                if (frame.incomplete)
     82                    folder.subtitle = WI.UIString("Incomplete");
     83
     84                if (this._recording.frames.length === 1)
     85                    folder.expand();
     86
     87                cumulativeActionIndex += frame.actions.length;
    8288            });
    83         }
    84 
    85         this.updateEmptyContentPlaceholder(WI.UIString("No Recording Data"));
    86 
    87         if (this._exportButton)
    88             this._exportButton.disabled = !this.contentTreeOutline.children.length;
     89
     90            this._exportButton.disabled = !actions.length;
     91        });
    8992    }
    9093
     
    175178    _importNavigationItemClicked(event)
    176179    {
    177         WI.loadDataFromFile((data) => {
     180        WI.loadDataFromFile((data, filename) => {
    178181            if (!data)
    179182                return;
     
    187190            }
    188191
    189             this.dispatchEventToListeners(WI.RecordingNavigationSidebarPanel.Event.Import, {payload});
     192            this.dispatchEventToListeners(WI.RecordingNavigationSidebarPanel.Event.Import, {payload, filename});
    190193        });
    191194    }
  • trunk/Source/WebInspectorUI/UserInterface/Views/RecordingTabContentView.js

    r222124 r223322  
    163163    _navigationSidebarImport(event)
    164164    {
    165         let recording = WI.Recording.fromPayload(event.data.payload);
     165        let {filename, payload} = event.data;
     166        let recording = WI.Recording.fromPayload(payload);
    166167        if (!recording) {
    167168            WI.Recording.synthesizeError(WI.UIString("unsupported version."));
    168169            return;
    169170        }
     171
     172        let extensionStart = filename.lastIndexOf(".");
     173        if (extensionStart !== -1)
     174            filename = filename.substring(0, extensionStart);
     175
     176        recording.createDisplayName(filename);
    170177
    171178        this.showRepresentedObject(recording);
Note: See TracChangeset for help on using the changeset viewer.