Bug 158035 - Web Inspector: resource tree elements should provide "Download File" context menu items
Summary: Web Inspector: resource tree elements should provide "Download File" context ...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Web Inspector (show other bugs)
Version: WebKit Nightly Build
Hardware: All All
: P2 Normal
Assignee: Devin Rousso
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2016-05-24 11:53 PDT by BJ Burg
Modified: 2016-08-23 15:25 PDT (History)
8 users (show)

See Also:


Attachments
Patch (2.39 KB, patch)
2016-08-13 23:57 PDT, Devin Rousso
no flags Details | Formatted Diff | Diff
Patch (2.73 KB, patch)
2016-08-14 12:46 PDT, Devin Rousso
no flags Details | Formatted Diff | Diff
Patch (4.12 KB, patch)
2016-08-14 14:19 PDT, Devin Rousso
no flags Details | Formatted Diff | Diff
Patch (5.79 KB, patch)
2016-08-15 00:13 PDT, Devin Rousso
no flags Details | Formatted Diff | Diff
Patch (7.04 KB, patch)
2016-08-16 23:54 PDT, Devin Rousso
no flags Details | Formatted Diff | Diff
Patch (6.99 KB, patch)
2016-08-22 23:17 PDT, Devin Rousso
no flags Details | Formatted Diff | Diff
Patch (8.34 KB, patch)
2016-08-23 00:18 PDT, Devin Rousso
no flags Details | Formatted Diff | Diff
Patch (7.16 KB, patch)
2016-08-23 08:52 PDT, Devin Rousso
joepeck: review+
Details | Formatted Diff | Diff
Patch (8.63 KB, patch)
2016-08-23 12:35 PDT, Devin Rousso
joepeck: commit-queue-
Details | Formatted Diff | Diff
Patch (8.64 KB, patch)
2016-08-23 14:22 PDT, Devin Rousso
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description BJ Burg 2016-05-24 11:53:30 PDT
It's strange that we don't have this.
Comment 1 BJ Burg 2016-05-27 07:18:15 PDT
Ping for import.
Comment 2 Radar WebKit Bug Importer 2016-05-27 07:20:36 PDT
<rdar://problem/26516684>
Comment 3 Devin Rousso 2016-08-13 23:57:53 PDT
Created attachment 286022 [details]
Patch
Comment 4 Nikita Vasilyev 2016-08-14 11:50:27 PDT
Comment on attachment 286022 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=286022&action=review

Works as described!

You should add "Download File" to localizedStrings.js.

> Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js:201
> +            return;

Why is this needed?
Comment 5 Devin Rousso 2016-08-14 12:44:42 PDT
Comment on attachment 286022 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=286022&action=review

>> Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js:201
>> +            return;
> 
> Why is this needed?

I don't actually think it is needed.  I think I just copied more than I should have :P
Comment 6 Devin Rousso 2016-08-14 12:46:33 PDT
Created attachment 286025 [details]
Patch
Comment 7 Matt Baker 2016-08-14 14:03:24 PDT
Comment on attachment 286025 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=286025&action=review

In the Resources tab, the main resource tree element doesn't have a context menu.

> Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js:94
> +        this.element.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this));

It would be nice to add this to ResourceTimelineDataGridNode too, so it would work for the entire row (and in the Network timeline view).

> Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js:202
> +        contextMenu.appendItem(WebInspector.UIString("Download File"), () => {

Maybe we should use "Save File" instead, since this also operates on local files. Chrome uses "Save".

> Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js:205
> +                content: this._resource.content

WebInspector.saveDataToFile asserts for blob content (image files), doesn't save:

Main.js:806:
console.assert(typeof saveData.content === "string");

FWIW, Chrome dev tools doesn't show a context menu item for blob file types.
Comment 8 Devin Rousso 2016-08-14 14:19:36 PDT
Created attachment 286032 [details]
Patch
Comment 9 Matt Baker 2016-08-14 18:37:10 PDT
Comment on attachment 286032 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=286032&action=review

This still needs to work for frame resources in the Resources tab. It looks like we don't get a context menu b/c FrameTreeElement overrides TreeElement.onattach, and skips the base class (intentionally, according to comment).

> Source/WebInspectorUI/ChangeLog:7
> +

Add a short description. I'd mention that this is for text resources only.

> Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js:209
> +        }

It would be nice to break all this out into a helper function that both the data grid node and tree element use.
Comment 10 Devin Rousso 2016-08-15 00:13:02 PDT
Created attachment 286051 [details]
Patch
Comment 11 Joseph Pecoraro 2016-08-15 17:31:05 PDT
Comment on attachment 286051 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=286051&action=review

r- if we can't handle images. We should be able to write some tests too.

> Source/WebInspectorUI/UserInterface/Models/Resource.js:685
> +    isTextWithUrl() {
> +        return this.url && typeof this._resource.content === "string";
> +    }

This function looks dangerous. The contents of resources (any WebInspector.SourceCode) are downloaded asynchronously, so a text file might not have been downloaded yet and so could fail this "content" check.

I'd expect something more like:

    canDownloadResource()
    {
        // Is there any reason we wouldn't want to download?
        return true;
    }

> Source/WebInspectorUI/UserInterface/Models/Resource.js:696
> +    saveContentsToFile()
> +    {
> +        if (!this.isTextWithUrl())
> +            return;
> +
> +        WebInspector.saveDataToFile({
> +            url: this.url,
> +            content: this.content
> +        });
> +    }

We should be able to handle binary data just fine! WebInspector.saveDataToFile calls InspectorFrontendHost.save currently always passes "false" for the base64 parameter. However, if hooked up properly it looks like it should just work. Implementations of InspectorFrontendHost.save looks like they would be able to handle converting base64 data to binary data when saving, and the filename should do the rest. For example WebInspectorProxy::platformSave in Source/WebKit2/UIProcess/mac/WebInspectorProxyMac.mm.

This should be testable!

Also, the URL we are passing in seems poor. The URL is the suggested save dialog URL to use, which doesn't make much sense with the full URL of the resource. Other ContentViews get the display name which roughly matches the last path component. For example:

    get saveData()
    {
        var url = "web-inspector:///" + encodeURI(WebInspector.UIString("Untitled")) + ".txt";
        return {url, content: this._textEditor.string, forceSaveAs: true};
    }

Maybe we should do something like that here, using the URL's last path component.

And finally, to handle any resource, this should download the contents if it hasn't already downloaded the contents.
Comment 12 Devin Rousso 2016-08-16 23:54:24 PDT
Created attachment 286284 [details]
Patch
Comment 13 Joseph Pecoraro 2016-08-22 20:22:44 PDT
Comment on attachment 286284 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=286284&action=review

r- for a few things that should be easy to update. Also some open questions.

> Source/WebInspectorUI/ChangeLog:9
> +        Add a context menu item to elements representing text resources that
> +        allows initiates a download of that resource.

Grammaro: "allows initiates a"
Nit: This says "text resources" but supports non-text. Needs an update.

> Source/WebInspectorUI/UserInterface/Base/Main.js:813
> +    let url = parseURL(saveData.url).lastPathComponent;

Nit: This variable name is misleading. It should be lastPathComponent.

> Source/WebInspectorUI/UserInterface/Base/Main.js:815
> +    if (typeof saveData.content === "string") {

What does this do for a data URL? For example the data URL resources on:
<http://dopiaza.org/tools/datauri/examples/index.php>

I suspect the content in that case will be a string. Does this properly save an image, or a text file? And what is the suggested save name?

> Source/WebInspectorUI/UserInterface/Base/Main.js:823
> +        let base64 = parseDataURL(fileReader.result);

Nit: This variable name is poor. It should be something like dataURLComponents.

> Source/WebInspectorUI/UserInterface/Base/Main.js:824
> +        InspectorFrontendHost.save(url || "data", base64.data, true, forceSaveAs || saveData.forceSaveAs);

Nit: The `true` and `false` in these call sites should be nicely named locals, like: `const base64Encoded = false;`

I feel like there should be a better suggested name than "data", heh. Maybe we need a mapping from common mime types to extensions? E.g. "image/jpeg" => "jpg" to better support some cases like dataURLs?

> Source/WebInspectorUI/UserInterface/Models/Resource.js:686
> +    saveContentsToFile()
> +    {
> +        this.requestContent().then(() => {
> +            WebInspector.saveDataToFile({

It feels like a layering violation to have the Resource model object know about WebInspector.saveDataToFile. Lets do this at the callsites.

> Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js:161
> +    _handleContextMenuEvent(event)

Ugh seems we should have some shared place that adds context menu items for a resource. Having this code duplicated (and different, since one has cURL the other doesn't) kinda stinks.
Comment 14 Devin Rousso 2016-08-22 23:16:25 PDT
(In reply to comment #13)
> > Source/WebInspectorUI/UserInterface/Base/Main.js:815
> > +    if (typeof saveData.content === "string") {
> 
> What does this do for a data URL? For example the data URL resources on:
> <http://dopiaza.org/tools/datauri/examples/index.php>
> 
> I suspect the content in that case will be a string. Does this properly save
> an image, or a text file? And what is the suggested save name?

Yes it works for both data objects.  It suggests "null" for both since there is no lastPathComponent.

> > Source/WebInspectorUI/UserInterface/Base/Main.js:824
> > +        InspectorFrontendHost.save(url || "data", base64.data, true, forceSaveAs || saveData.forceSaveAs);
> 
> I feel like there should be a better suggested name than "data", heh. Maybe
> we need a mapping from common mime types to extensions? E.g. "image/jpeg" =>
> "jpg" to better support some cases like dataURLs?

Good idea (☞゚ヮ゚)☞

> > Source/WebInspectorUI/UserInterface/Views/ResourceTreeElement.js:161
> > +    _handleContextMenuEvent(event)
> 
> Ugh seems we should have some shared place that adds context menu items for
> a resource. Having this code duplicated (and different, since one has cURL
> the other doesn't) kinda stinks.

Other than creating a utility/static function somewhere that adds these items to a context menu, I'm not really sure how to solve this.  ¯\_(ツ)_/¯  I do agree that it is annoying though.
Comment 15 Devin Rousso 2016-08-22 23:17:55 PDT
Created attachment 286681 [details]
Patch
Comment 16 Devin Rousso 2016-08-23 00:18:54 PDT
Created attachment 286685 [details]
Patch
Comment 17 WebKit Commit Bot 2016-08-23 00:21:14 PDT
Attachment 286685 [details] did not pass style-queue:


ERROR: Source/WebInspectorUI/ChangeLog:1:  ChangeLog entry has no bug number  [changelog/bugnumber] [5]
Total errors found: 1 in 5 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 18 Devin Rousso 2016-08-23 08:52:26 PDT
Created attachment 286714 [details]
Patch
Comment 19 Joseph Pecoraro 2016-08-23 11:19:01 PDT
Comment on attachment 286714 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=286714&action=review

r=me, but you may want to put up a follow-up to fix the file extension handling for data URLs. At least file a bugzilla bug for it if you do not address it.

> Source/WebInspectorUI/UserInterface/Base/Main.js:817
> +        let dataURLTypeMatch = /^data:([^\/]+)\/([^;]+)/.exec(saveData.url);
> +        if (dataURLTypeMatch)
> +            suggestedName = `${dataURLTypeMatch[1]}.${dataURLTypeMatch[2]}`;

This might work okay for image types, but it won't work well for text mime types:

    text/plain
    text/javascript
    application/javascript

Turns out we already have a reasonable mapping from File Extension to MIME Type in MIMETypeUtilities.js. Can we flip that and create a WebInspector.fileExtensionForMIMEType(mimeType)?

> Source/WebInspectorUI/UserInterface/Base/Main.js:819
> +            suggestedName = "untitled";

Nit: On macOS the default is normally capitalized, "Untitled".
Comment 20 Joseph Pecoraro 2016-08-23 11:19:40 PDT
Comment on attachment 286714 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=286714&action=review

>> Source/WebInspectorUI/UserInterface/Base/Main.js:819
>> +            suggestedName = "untitled";
> 
> Nit: On macOS the default is normally capitalized, "Untitled".

And maybe this should be localized.
Comment 21 Devin Rousso 2016-08-23 12:35:27 PDT
Created attachment 286756 [details]
Patch
Comment 22 Joseph Pecoraro 2016-08-23 12:53:44 PDT
Comment on attachment 286756 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=286756&action=review

> Source/WebInspectorUI/UserInterface/Base/MIMETypeUtilities.js:82
> +WebInspector.fileExtensionForMIMEType = function(mimeType)

cq-. Shouldn't include the '.' in all of these. Should just add it at the end if not undefined.
Comment 23 Joseph Pecoraro 2016-08-23 12:54:50 PDT
Comment on attachment 286756 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=286756&action=review

> Source/WebInspectorUI/UserInterface/Base/Main.js:819
> +        if (dataURLTypeMatch) {
> +            suggestedName += WebInspector.fileExtensionForMIMEType(dataURLTypeMatch[1]) || "";
> +        }

Style: No braces for single statement blocks.
Comment 24 Devin Rousso 2016-08-23 14:22:00 PDT
Created attachment 286775 [details]
Patch
Comment 25 WebKit Commit Bot 2016-08-23 15:25:13 PDT
Comment on attachment 286775 [details]
Patch

Clearing flags on attachment: 286775

Committed r204862: <http://trac.webkit.org/changeset/204862>
Comment 26 WebKit Commit Bot 2016-08-23 15:25:19 PDT
All reviewed patches have been landed.  Closing bug.