Changeset 238198 in webkit


Ignore:
Timestamp:
Nov 14, 2018 2:01:03 PM (5 years ago)
Author:
Devin Rousso
Message:

Web Inspector: add drag+drop for importing Audits and Recordings
https://bugs.webkit.org/show_bug.cgi?id=191566

Reviewed by Joseph Pecoraro.

Reorganize the file loading logic for the Audit and Canvas tabs/managers. Add "drop" event
handlers to the tabs that add and show the corresponding object for the imported data.

  • UserInterface/Views/AuditTabContentView.js:

(WI.AuditTabContentView):
(WI.AuditTabContentView.prototype._handleDragOver): Added.
(WI.AuditTabContentView.prototype._handleDrop): Added.

  • UserInterface/Views/CanvasTabContentView.js:

(WI.CanvasTabContentView):
(WI.CanvasTabContentView.prototype._addCanvas):
(WI.CanvasTabContentView.prototype._recordingImportedOrStopped):
(WI.CanvasTabContentView.prototype._handleDragOver): Added.
(WI.CanvasTabContentView.prototype._handleDrop): Added.

  • UserInterface/Controllers/AuditManager.js:

(WI.AuditManager.prototype.async processJSON): Added.
(WI.AuditManager.prototype.export):
(WI.AuditManager.prototype.import): Deleted.

  • UserInterface/Controllers/CanvasManager.js:

(WI.CanvasManager.prototype.processJSON): Added.
(WI.CanvasManager.prototype.importRecording): Deleted.

  • UserInterface/Views/AuditNavigationSidebarPanel.js:

(WI.AuditNavigationSidebarPanel):
(WI.AuditNavigationSidebarPanel.prototype.showDefaultContentView):
(WI.AuditNavigationSidebarPanel.prototype._handleImportButtonNavigationItemClicked):

  • UserInterface/Views/CanvasSidebarPanel.js:

(WI.CanvasSidebarPanel):
(WI.CanvasSidebarPanel.prototype._handleImportButtonNavigationItemClicked): Added.
(WI.CanvasSidebarPanel.prototype._recordingChanged):
(WI.CanvasSidebarPanel.prototype._updateRecordNavigationItem):

  • UserInterface/Views/CanvasOverviewContentView.js:

(WI.CanvasOverviewContentView):
(WI.CanvasOverviewContentView.prototype._handleImportButtonNavigationItemClicked): Added.

  • UserInterface/Base/FileUtilities.js:

(WI.FileUtilities.save): Added.
(WI.FileUtilities.importText): Added.
(WI.FileUtilities.importJSON): Added.
(WI.FileUtilities.async readText): Added.
(WI.FileUtilities.async readJSON): Added.
(WI.saveDataToFile): Deleted.
(WI.loadDataFromFile): Deleted.

  • UserInterface/Base/Main.js:

(WI._contextMenuRequested):
(WI._save):
(WI._saveAs):

  • UserInterface/Views/ContextMenuUtilities.js:

(WI.appendContextMenuItemsForSourceCode):

  • UserInterface/Views/LogContentView.js:

(WI.LogContentView.prototype._handleContextMenuEvent):

  • UserInterface/Views/NetworkTableContentView.js:

(WI.NetworkTableContentView.prototype._exportHAR):

  • UserInterface/Views/RecordingContentView.js:

(WI.RecordingContentView.prototype._exportRecording):

  • UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js:

(WI.SpreadsheetCSSStyleDeclarationSection.prototype._save):
Move file related functions into a static class container.

  • Localizations/en.lproj/localizedStrings.js:
Location:
trunk/Source/WebInspectorUI
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebInspectorUI/ChangeLog

    r238197 r238198  
     12018-11-14  Devin Rousso  <drousso@apple.com>
     2
     3        Web Inspector: add drag+drop for importing Audits and Recordings
     4        https://bugs.webkit.org/show_bug.cgi?id=191566
     5
     6        Reviewed by Joseph Pecoraro.
     7
     8        Reorganize the file loading logic for the Audit and Canvas tabs/managers. Add "drop" event
     9        handlers to the tabs that add and show the corresponding object for the imported data.
     10
     11        * UserInterface/Views/AuditTabContentView.js:
     12        (WI.AuditTabContentView):
     13        (WI.AuditTabContentView.prototype._handleDragOver): Added.
     14        (WI.AuditTabContentView.prototype._handleDrop): Added.
     15        * UserInterface/Views/CanvasTabContentView.js:
     16        (WI.CanvasTabContentView):
     17        (WI.CanvasTabContentView.prototype._addCanvas):
     18        (WI.CanvasTabContentView.prototype._recordingImportedOrStopped):
     19        (WI.CanvasTabContentView.prototype._handleDragOver): Added.
     20        (WI.CanvasTabContentView.prototype._handleDrop): Added.
     21
     22        * UserInterface/Controllers/AuditManager.js:
     23        (WI.AuditManager.prototype.async processJSON): Added.
     24        (WI.AuditManager.prototype.export):
     25        (WI.AuditManager.prototype.import): Deleted.
     26        * UserInterface/Controllers/CanvasManager.js:
     27        (WI.CanvasManager.prototype.processJSON): Added.
     28        (WI.CanvasManager.prototype.importRecording): Deleted.
     29
     30        * UserInterface/Views/AuditNavigationSidebarPanel.js:
     31        (WI.AuditNavigationSidebarPanel):
     32        (WI.AuditNavigationSidebarPanel.prototype.showDefaultContentView):
     33        (WI.AuditNavigationSidebarPanel.prototype._handleImportButtonNavigationItemClicked):
     34        * UserInterface/Views/CanvasSidebarPanel.js:
     35        (WI.CanvasSidebarPanel):
     36        (WI.CanvasSidebarPanel.prototype._handleImportButtonNavigationItemClicked): Added.
     37        (WI.CanvasSidebarPanel.prototype._recordingChanged):
     38        (WI.CanvasSidebarPanel.prototype._updateRecordNavigationItem):
     39
     40        * UserInterface/Views/CanvasOverviewContentView.js:
     41        (WI.CanvasOverviewContentView):
     42        (WI.CanvasOverviewContentView.prototype._handleImportButtonNavigationItemClicked): Added.
     43
     44        * UserInterface/Base/FileUtilities.js:
     45        (WI.FileUtilities.save): Added.
     46        (WI.FileUtilities.importText): Added.
     47        (WI.FileUtilities.importJSON): Added.
     48        (WI.FileUtilities.async readText): Added.
     49        (WI.FileUtilities.async readJSON): Added.
     50        (WI.saveDataToFile): Deleted.
     51        (WI.loadDataFromFile): Deleted.
     52        * UserInterface/Base/Main.js:
     53        (WI._contextMenuRequested):
     54        (WI._save):
     55        (WI._saveAs):
     56        * UserInterface/Views/ContextMenuUtilities.js:
     57        (WI.appendContextMenuItemsForSourceCode):
     58        * UserInterface/Views/LogContentView.js:
     59        (WI.LogContentView.prototype._handleContextMenuEvent):
     60        * UserInterface/Views/NetworkTableContentView.js:
     61        (WI.NetworkTableContentView.prototype._exportHAR):
     62        * UserInterface/Views/RecordingContentView.js:
     63        (WI.RecordingContentView.prototype._exportRecording):
     64        * UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js:
     65        (WI.SpreadsheetCSSStyleDeclarationSection.prototype._save):
     66        Move file related functions into a static class container.
     67
     68        * Localizations/en.lproj/localizedStrings.js:
     69
    1702018-11-14  Joseph Pecoraro  <pecoraro@apple.com>
    271
  • trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js

    r238192 r238198  
    475475localizedStrings["Immediate Pause Requested"] = "Immediate Pause Requested";
    476476localizedStrings["Import"] = "Import";
    477 localizedStrings["Import recording from file"] = "Import recording from file";
    478477localizedStrings["Imported"] = "Imported";
    479478localizedStrings["Imported Recordings"] = "Imported Recordings";
  • trunk/Source/WebInspectorUI/UserInterface/Base/FileUtilities.js

    r223322 r238198  
    2424 */
    2525
    26 WI.saveDataToFile = function(saveData, forceSaveAs)
    27 {
    28     console.assert(saveData);
    29     if (!saveData)
    30         return;
     26WI.FileUtilities = class FileUtilities {
     27    static save(saveData, forceSaveAs)
     28    {
     29        console.assert(saveData);
     30        if (!saveData)
     31            return;
    3132
    32     if (typeof saveData.customSaveHandler === "function") {
    33         saveData.customSaveHandler(forceSaveAs);
    34         return;
     33        if (typeof saveData.customSaveHandler === "function") {
     34            saveData.customSaveHandler(forceSaveAs);
     35            return;
     36        }
     37
     38        console.assert(saveData.content);
     39        if (!saveData.content)
     40            return;
     41
     42        let url = saveData.url || "";
     43        let suggestedName = parseURL(url).lastPathComponent;
     44        if (!suggestedName) {
     45            suggestedName = WI.UIString("Untitled");
     46            let dataURLTypeMatch = /^data:([^;]+)/.exec(url);
     47            if (dataURLTypeMatch) {
     48                let fileExtension = WI.fileExtensionForMIMEType(dataURLTypeMatch[1]);
     49                if (fileExtension)
     50                    suggestedName += "." + fileExtension;
     51            }
     52        }
     53
     54        if (typeof saveData.content === "string") {
     55            const base64Encoded = saveData.base64Encoded || false;
     56            InspectorFrontendHost.save(suggestedName, saveData.content, base64Encoded, forceSaveAs || saveData.forceSaveAs);
     57            return;
     58        }
     59
     60        let fileReader = new FileReader;
     61        fileReader.readAsDataURL(saveData.content);
     62        fileReader.addEventListener("loadend", () => {
     63            let dataURLComponents = parseDataURL(fileReader.result);
     64
     65            const base64Encoded = true;
     66            InspectorFrontendHost.save(suggestedName, dataURLComponents.data, base64Encoded, forceSaveAs || saveData.forceSaveAs);
     67        });
    3568    }
    3669
    37     console.assert(saveData.content);
    38     if (!saveData.content)
    39         return;
     70    static importText(callback)
     71    {
     72        let inputElement = document.createElement("input");
     73        inputElement.type = "file";
     74        inputElement.multiple = true;
     75        inputElement.addEventListener("change", (event) => {
     76            WI.FileUtilities.readText(inputElement.files, callback);
     77        });
     78        inputElement.click();
     79    }
    4080
    41     let url = saveData.url || "";
    42     let suggestedName = parseURL(url).lastPathComponent;
    43     if (!suggestedName) {
    44         suggestedName = WI.UIString("Untitled");
    45         let dataURLTypeMatch = /^data:([^;]+)/.exec(url);
    46         if (dataURLTypeMatch) {
    47             let fileExtension = WI.fileExtensionForMIMEType(dataURLTypeMatch[1]);
    48             if (fileExtension)
    49                 suggestedName += "." + fileExtension;
     81    static importJSON(callback)
     82    {
     83        let inputElement = document.createElement("input");
     84        inputElement.type = "file";
     85        inputElement.multiple = true;
     86        inputElement.addEventListener("change", (event) => {
     87            WI.FileUtilities.readJSON(inputElement.files, callback);
     88        });
     89        inputElement.click();
     90    }
     91
     92    static async readText(fileOrList, callback)
     93    {
     94        console.assert(fileOrList instanceof File || fileOrList instanceof FileList);
     95
     96        let files = [];
     97        if (fileOrList instanceof File)
     98            files.push(fileOrList);
     99        else if (fileOrList instanceof FileList)
     100            files = Array.from(fileOrList);
     101
     102        for (let file of files) {
     103            let reader = new FileReader;
     104            reader.readAsText(file);
     105
     106            let result = {
     107                filename: file.name,
     108            };
     109
     110            try {
     111                await new Promise((resolve, reject) => {
     112                    reader.addEventListener("loadend", (event) => {
     113                        result.text = reader.result;
     114                        resolve(event);
     115                    });
     116                    reader.addEventListener("error", reject);
     117                });
     118            } catch (e) {
     119                result.error = e;
     120            }
     121
     122            let promise = callback(result);
     123            if (promise)
     124                await promise;
    50125        }
    51126    }
    52127
    53     if (typeof saveData.content === "string") {
    54         const base64Encoded = saveData.base64Encoded || false;
    55         InspectorFrontendHost.save(suggestedName, saveData.content, base64Encoded, forceSaveAs || saveData.forceSaveAs);
    56         return;
     128    static async readJSON(fileOrList, callback)
     129    {
     130        return WI.FileUtilities.readText(fileOrList, (result) => {
     131            if (result.text && !result.error) {
     132                try {
     133                    result.json = JSON.parse(result.text);
     134                } catch (e) {
     135                    result.error = e;
     136                }
     137            }
     138
     139            return callback(result);
     140        });
    57141    }
    58 
    59     let fileReader = new FileReader;
    60     fileReader.readAsDataURL(saveData.content);
    61     fileReader.addEventListener("loadend", () => {
    62         let dataURLComponents = parseDataURL(fileReader.result);
    63 
    64         const base64Encoded = true;
    65         InspectorFrontendHost.save(suggestedName, dataURLComponents.data, base64Encoded, forceSaveAs || saveData.forceSaveAs);
    66     });
    67142};
    68 
    69 WI.loadDataFromFile = function(callback)
    70 {
    71     let inputElement = document.createElement("input");
    72     inputElement.type = "file";
    73     inputElement.addEventListener("change", (event) => {
    74         if (!inputElement.files.length) {
    75             callback(null);
    76             return;
    77         }
    78 
    79         let file = inputElement.files[0];
    80         let reader = new FileReader;
    81         reader.addEventListener("loadend", (event) => {
    82             callback(reader.result, file.name);
    83         });
    84         reader.readAsText(file);
    85     });
    86     inputElement.click();
    87 };
  • trunk/Source/WebInspectorUI/UserInterface/Base/Main.js

    r238192 r238198  
    16031603        protocolSubMenu.appendItem(WI.unlocalizedString("Export Trace\u2026"), () => {
    16041604            const forceSaveAs = true;
    1605             WI.saveDataToFile(InspectorBackend.activeTracer.trace.saveData, forceSaveAs);
     1605            WI.FileUtilities.save(InspectorBackend.activeTracer.trace.saveData, forceSaveAs);
    16061606        }, !isCapturingTraffic);
    16071607    } else {
     
    20702070        return;
    20712071
    2072     WI.saveDataToFile(contentView.saveData);
     2072    WI.FileUtilities.save(contentView.saveData);
    20732073};
    20742074
     
    20792079        return;
    20802080
    2081     WI.saveDataToFile(contentView.saveData, true);
     2081    WI.FileUtilities.save(contentView.saveData, true);
    20822082};
    20832083
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/AuditManager.js

    r237665 r238198  
    9494    }
    9595
    96     import()
     96    async processJSON({json, error})
    9797    {
    98         WI.loadDataFromFile(async (data, filename) => {
    99             if (!data)
    100                 return;
     98        if (error) {
     99            WI.AuditManager.synthesizeError(error);
     100            return;
     101        }
    101102
    102             let payload = null;
    103             try {
    104                 payload = JSON.parse(data);
    105             } catch (e) {
    106                 WI.AuditManager.synthesizeError(e);
     103        let object = await WI.AuditTestGroup.fromPayload(json) || await WI.AuditTestCase.fromPayload(json);
     104        if (!object) {
     105            object = await WI.AuditTestGroupResult.fromPayload(json) || await WI.AuditTestCaseResult.fromPayload(json);
     106            if (!object) {
     107                WI.AuditManager.synthesizeError(WI.UIString("invalid JSON."));
    107108                return;
    108109            }
     110        }
    109111
    110             let object = await WI.AuditTestGroup.fromPayload(payload) || await WI.AuditTestCase.fromPayload(payload);
    111             if (!object) {
    112                 object = await WI.AuditTestGroupResult.fromPayload(payload) || await WI.AuditTestCaseResult.fromPayload(payload);
    113                 if (!object) {
    114                     WI.AuditManager.synthesizeError(WI.UIString("invalid JSON."));
    115                     return;
    116                 }
    117             }
     112        if (object instanceof WI.AuditTestBase) {
     113            this._addTest(object);
     114            WI.objectStores.audits.addObject(object);
     115        } else if (object instanceof WI.AuditTestResultBase)
     116            this._addResult(object);
    118117
    119             if (object instanceof WI.AuditTestBase) {
    120                 this._addTest(object);
    121                 WI.objectStores.audits.addObject(object);
    122             } else if (object instanceof WI.AuditTestResultBase)
    123                 this._addResult(object);
    124         });
     118        WI.showRepresentedObject(object);
    125119    }
    126120
     
    135129        let url = "web-inspector:///" + encodeURI(filename) + ".json";
    136130
    137         WI.saveDataToFile({
     131        WI.FileUtilities.save({
    138132            url,
    139133            content: JSON.stringify(object),
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/CanvasManager.js

    r237670 r238198  
    6868    }
    6969
    70     importRecording()
    71     {
    72         WI.loadDataFromFile((data, filename) => {
    73             if (!data)
    74                 return;
    75 
    76             let payload = null;
    77             try {
    78                 payload = JSON.parse(data);
    79             } catch (e) {
    80                 WI.Recording.synthesizeError(e);
    81                 return;
    82             }
    83 
    84             let recording = WI.Recording.fromPayload(payload);
    85             if (!recording) {
    86                 WI.Recording.synthesizeError(WI.UIString("unsupported version."));
    87                 return;
    88             }
    89 
    90             let extensionStart = filename.lastIndexOf(".");
    91             if (extensionStart !== -1)
    92                 filename = filename.substring(0, extensionStart);
    93             recording.createDisplayName(filename);
    94 
    95             this._importedRecordings.add(recording);
    96 
    97             this.dispatchEventToListeners(WI.CanvasManager.Event.RecordingImported, {recording});
    98         });
     70    processJSON({filename, json, error})
     71    {
     72        if (error) {
     73            WI.Recording.synthesizeError(error);
     74            return;
     75        }
     76
     77        let recording = WI.Recording.fromPayload(json);
     78        if (!recording) {
     79            WI.Recording.synthesizeError(WI.UIString("unsupported version."));
     80            return;
     81        }
     82
     83        let extensionStart = filename.lastIndexOf(".");
     84        if (extensionStart !== -1)
     85            filename = filename.substring(0, extensionStart);
     86        recording.createDisplayName(filename);
     87
     88        this._importedRecordings.add(recording);
     89
     90        this.dispatchEventToListeners(WI.CanvasManager.Event.RecordingImported, {recording, initiatedByUser: true});
    9991    }
    10092
  • trunk/Source/WebInspectorUI/UserInterface/Views/AuditNavigationSidebarPanel.js

    r237831 r238198  
    4242        let importNavigationItem = new WI.ButtonNavigationItem("import-audit", WI.UIString("Import"), "Images/Import.svg", 15, 15);
    4343        importNavigationItem.buttonStyle = WI.ButtonNavigationItem.Style.ImageAndText;
    44         importNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, () => {
    45             WI.auditManager.import();
    46         });
     44        importNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._handleImportButtonNavigationItemClicked, this);
    4745
    4846        let importHelpElement = WI.createNavigationItemHelp(WI.UIString("Press %s to import a test or result file"), importNavigationItem);
     
    196194    _handleImportButtonNavigationItemClicked(event)
    197195    {
    198         WI.auditManager.import();
     196        WI.FileUtilities.importJSON((result) => WI.auditManager.processJSON(result));
    199197    }
    200198};
  • trunk/Source/WebInspectorUI/UserInterface/Views/AuditTabContentView.js

    r237665 r238198  
    3333        this._startStopShortcut.implicitlyPreventsDefault = false;
    3434        this._startStopShortcut.disabled = true;
     35
     36        this.element.addEventListener("dragover", this._handleDragOver.bind(this));
     37        this.element.addEventListener("drop", this._handleDrop.bind(this));
    3538    }
    3639
     
    109112        event.preventDefault();
    110113    }
     114
     115    _handleDragOver(event)
     116    {
     117        if (event.dataTransfer.types.includes("Files"))
     118            event.preventDefault();
     119    }
     120
     121    _handleDrop(event)
     122    {
     123        if (!event.dataTransfer.files || !event.dataTransfer.files.length)
     124            return;
     125
     126        event.preventDefault();
     127
     128        WI.FileUtilities.readJSON(event.dataTransfer.files, (result) => WI.auditManager.processJSON(result))
     129        .then(() => {
     130            event.dataTransfer.clearData();
     131        });
     132    }
    111133};
    112134
  • trunk/Source/WebInspectorUI/UserInterface/Views/CanvasOverviewContentView.js

    r238169 r238198  
    3737        let importNavigationItem = new WI.ButtonNavigationItem("import-recording", WI.UIString("Import"), "Images/Import.svg", 15, 15);
    3838        importNavigationItem.buttonStyle = WI.ButtonNavigationItem.Style.ImageAndText;
    39         importNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, () => { WI.canvasManager.importRecording(); });
    4039
    4140        let importHelpElement = WI.createNavigationItemHelp(WI.UIString("Press %s to load a recording from file."), importNavigationItem);
     
    6564
    6665        this._importButtonNavigationItem = new WI.ButtonNavigationItem("import-recording", WI.UIString("Import"), "Images/Import.svg", 15, 15);
    67         this._importButtonNavigationItem.toolTip = WI.UIString("Import recording from file");
     66        this._importButtonNavigationItem.toolTip = WI.UIString("Import");
    6867        this._importButtonNavigationItem.buttonStyle = WI.ButtonNavigationItem.Style.ImageAndText;
    69         this._importButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, () => { WI.canvasManager.importRecording(); });
    7068
    7169        this._refreshButtonNavigationItem = new WI.ButtonNavigationItem("refresh-all", WI.UIString("Refresh all"), "Images/ReloadFull.svg", 13, 13);
     
    7775        this._showGridButtonNavigationItem.enabled = false;
    7876        this._showGridButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._showGridButtonClicked, this);
     77
     78        importNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._handleImportButtonNavigationItemClicked, this);
     79        this._importButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._handleImportButtonNavigationItemClicked, this);
    7980    }
    8081
     
    257258        this._recordingAutoCaptureFrameCountInputElement.value = WI.settings.canvasRecordingAutoCaptureFrameCount.value;
    258259    }
     260
     261    _handleImportButtonNavigationItemClicked(event)
     262    {
     263        WI.FileUtilities.importJSON((result) => WI.canvasManager.processJSON(result));
     264    }
    259265};
  • trunk/Source/WebInspectorUI/UserInterface/Views/CanvasSidebarPanel.js

    r237593 r238198  
    4141        this._recordButtonNavigationItem = new WI.ToggleButtonNavigationItem("record-start-stop", toolTip, altToolTip, "Images/Record.svg", "Images/Stop.svg", 13, 13);
    4242        this._recordButtonNavigationItem.enabled = false;
     43        this._recordButtonNavigationItem.buttonStyle = WI.ButtonNavigationItem.Style.ImageAndText;
     44        this._recordButtonNavigationItem.label = WI.UIString("Start");
    4345        this._recordButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._toggleRecording, this);
    4446        this._navigationBar.addNavigationItem(this._recordButtonNavigationItem);
     47
     48        this._navigationBar.addNavigationItem(new WI.DividerNavigationItem);
     49
     50        let importButtonNavigationItem = new WI.ButtonNavigationItem("import-recording", WI.UIString("Import"), "Images/Import.svg", 15, 15);
     51        importButtonNavigationItem.buttonStyle = WI.ButtonNavigationItem.Style.ImageAndText;
     52        importButtonNavigationItem.visibilityPriority = WI.NavigationItem.VisibilityPriority.Low;
     53        importButtonNavigationItem.addEventListener(WI.ButtonNavigationItem.Event.Clicked, this._handleImportButtonNavigationItemClicked, this);
     54        this._navigationBar.addNavigationItem(importButtonNavigationItem);
    4555
    4656        this.addSubview(this._navigationBar);
     
    298308    }
    299309
     310    _handleImportButtonNavigationItemClicked(event)
     311    {
     312        WI.FileUtilities.importJSON((result) => WI.canvasManager.processJSON(result));
     313    }
     314
    300315    _treeOutlineSelectionDidChange(event)
    301316    {
     
    360375        this._recordingTreeOutline.removeChildren();
    361376
    362         if (!this._recording) {
    363             if (this._recordingProcessingOptionsContainer) {
    364                 this._recordingProcessingOptionsContainer.remove();
    365                 this._recordingProcessingOptionsContainer = null;
    366             }
    367             return;
    368         }
     377        if (this._recordingProcessingOptionsContainer) {
     378            this._recordingProcessingOptionsContainer.remove();
     379            this._recordingProcessingOptionsContainer = null;
     380        }
     381
     382        if (!this._recording)
     383            return;
    369384
    370385        if (!this._recording.ready) {
     
    453468
    454469        this._recordButtonNavigationItem.toggled = this._canvas.recordingActive;
     470        this._recordButtonNavigationItem.label = this._recordButtonNavigationItem.toggled ? WI.UIString("Stop") : WI.UIString("Start");
    455471    }
    456472
  • trunk/Source/WebInspectorUI/UserInterface/Views/CanvasTabContentView.js

    r237670 r238198  
    5656        this._recordSingleFrameShortcut.implicitlyPreventsDefault = false;
    5757        this._recordSingleFrameShortcut.disabled = true;
     58
     59        this.element.addEventListener("dragover", this._handleDragOver.bind(this));
     60        this.element.addEventListener("drop", this._handleDrop.bind(this));
    5861    }
    5962
     
    181184        this._canvasCollection.add(canvas);
    182185
     186        const options = {
     187            suppressShowRecording: true,
     188        };
     189
    183190        for (let recording of canvas.recordingCollection)
    184             this._addRecording(recording, {suppressShowRecording: true});
     191            this._addRecording(recording, options);
    185192    }
    186193
     
    252259            return;
    253260
    254         this._addRecording(recording, {
    255             suppressShowRecording: !initiatedByUser || this.contentBrowser.currentRepresentedObjects.some((representedObject) => representedObject instanceof WI.Recording),
    256         });
     261        let options = {};
     262
     263        // Always show imported recordings.
     264        if (recording.source)
     265            options.suppressShowRecording = !initiatedByUser || this.contentBrowser.currentRepresentedObjects.some((representedObject) => representedObject instanceof WI.Recording);
     266
     267        this._addRecording(recording, options);
    257268    }
    258269
     
    278289        event.preventDefault();
    279290    }
     291
     292    _handleDragOver(event)
     293    {
     294        if (event.dataTransfer.types.includes("Files"))
     295            event.preventDefault();
     296    }
     297
     298    _handleDrop(event)
     299    {
     300        if (!event.dataTransfer.files || !event.dataTransfer.files.length)
     301            return;
     302
     303        event.preventDefault();
     304
     305        WI.FileUtilities.readJSON(event.dataTransfer.files, (result) => WI.canvasManager.processJSON(result))
     306        .then(() => {
     307            event.dataTransfer.clearData();
     308        });
     309    }
    280310};
    281311
  • trunk/Source/WebInspectorUI/UserInterface/Views/ContextMenuUtilities.js

    r238048 r238198  
    5656        sourceCode.requestContent().then(() => {
    5757            const forceSaveAs = true;
    58             WI.saveDataToFile({
     58            WI.FileUtilities.save({
    5959                url: sourceCode.url || "",
    6060                content: sourceCode.content
     
    239239                ];
    240240                let filename = WI.UIString("Screen Shot %s-%s-%s at %s.%s.%s").format(...values);
    241                 WI.saveDataToFile({
     241                WI.FileUtilities.save({
    242242                    url: encodeURI(`web-inspector:///${filename}.png`),
    243243                    content: parseDataURL(dataURL).data,
  • trunk/Source/WebInspectorUI/UserInterface/Views/LogContentView.js

    r238048 r238198  
    473473            contextMenu.appendItem(WI.UIString("Save Selected"), () => {
    474474                const forceSaveAs = true;
    475                 WI.saveDataToFile({
     475                WI.FileUtilities.save({
    476476                    url: "web-inspector:///Console.txt",
    477477                    content: this._formatMessagesAsData(true),
  • trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js

    r238192 r238198  
    18831883            let archiveName = mainFrame.mainResource.urlComponents.host || mainFrame.mainResource.displayName || "Archive";
    18841884            let url = "web-inspector:///" + encodeURI(archiveName) + ".har";
    1885             WI.saveDataToFile({
     1885            WI.FileUtilities.save({
    18861886                url,
    18871887                content: JSON.stringify(har, null, 2),
  • trunk/Source/WebInspectorUI/UserInterface/Views/RecordingContentView.js

    r237808 r238198  
    184184        let url = "web-inspector:///" + encodeURI(filename) + ".json";
    185185
    186         WI.saveDataToFile({
     186        WI.FileUtilities.save({
    187187            url,
    188188            content: JSON.stringify(this.representedObject.toJSON()),
  • trunk/Source/WebInspectorUI/UserInterface/Views/SpreadsheetCSSStyleDeclarationSection.js

    r237659 r238198  
    457457
    458458        const saveAs = event.shiftKey;
    459         WI.saveDataToFile({url: url, content: sourceCode.content}, saveAs);
     459        WI.FileUtilities.save({url: url, content: sourceCode.content}, saveAs);
    460460    }
    461461
Note: See TracChangeset for help on using the changeset viewer.