Bug 202016 - Web Inspector: Local Resource Overrides: UI for overriding image and font resource content
Summary: Web Inspector: Local Resource Overrides: UI for overriding image and font res...
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: Joseph Pecoraro
URL:
Keywords: InRadar
Depends on: 202000
Blocks:
  Show dependency treegraph
 
Reported: 2019-09-19 17:20 PDT by Joseph Pecoraro
Modified: 2019-10-11 13:44 PDT (History)
5 users (show)

See Also:


Attachments
[PATCH] Proposed Fix (41.29 KB, patch)
2019-09-19 17:56 PDT, Joseph Pecoraro
no flags Details | Formatted Diff | Diff
[IMAGE] Light Mode (Old) (489.53 KB, image/png)
2019-09-19 17:56 PDT, Joseph Pecoraro
no flags Details
[IMAGE] Dark Mode (Old) (464.41 KB, image/png)
2019-09-19 17:56 PDT, Joseph Pecoraro
no flags Details
[PATCH] Proposed Fix (47.05 KB, patch)
2019-09-20 14:00 PDT, Joseph Pecoraro
no flags Details | Formatted Diff | Diff
[Image] suggested drop UI (957.98 KB, image/png)
2019-09-24 15:46 PDT, Devin Rousso
no flags Details
[PATCH] Proposed Fix (77.16 KB, patch)
2019-10-10 14:12 PDT, Joseph Pecoraro
hi: review+
Details | Formatted Diff | Diff
[IMAGE] Light Mode (1.42 MB, image/png)
2019-10-10 14:12 PDT, Joseph Pecoraro
no flags Details
[IMAGE] Dark Mode (1.45 MB, image/png)
2019-10-10 14:13 PDT, Joseph Pecoraro
no flags Details
[PATCH] For Landing (79.45 KB, patch)
2019-10-10 21:35 PDT, Joseph Pecoraro
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Joseph Pecoraro 2019-09-19 17:20:13 PDT
Web Inspector: Local Resource Overrides: UI for overriding image resource content

The backend allows overriding image content, but the UI doesn't allow creating overrides for Image resources. Provide a UI.
Comment 1 Radar WebKit Bug Importer 2019-09-19 17:20:28 PDT Comment hidden (obsolete)
Comment 2 Radar WebKit Bug Importer 2019-09-19 17:20:43 PDT
<rdar://problem/55541482>
Comment 3 Joseph Pecoraro 2019-09-19 17:56:23 PDT
Created attachment 379180 [details]
[PATCH] Proposed Fix

Blocked so bots will not build.
Comment 4 Joseph Pecoraro 2019-09-19 17:56:38 PDT
Created attachment 379181 [details]
[IMAGE] Light Mode (Old)
Comment 5 Joseph Pecoraro 2019-09-19 17:56:54 PDT
Created attachment 379182 [details]
[IMAGE] Dark Mode (Old)
Comment 6 Joseph Pecoraro 2019-09-19 17:57:30 PDT
Node there is actually a green (+) on the cursor but I was unable to capture that in simple screenshots, without going to a video.
Comment 7 Joseph Pecoraro 2019-09-19 18:00:45 PDT
Comment on attachment 379180 [details]
[PATCH] Proposed Fix

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

> Source/WebInspectorUI/UserInterface/Views/DropZoneView.css:49
> +.drop-zone > .box {
> +    width: 70%;
> +    height: 70%;
> +    border: 3px dashed hsl(0, 0%, 70%, 0.8);
> +    border-radius: 3px;
> +    pointer-events: none;
> +}

This UI is totally up for debate. I just made a simple drop box, but it doesn't look great in many cases depending on the image underneath.
Comment 8 Joseph Pecoraro 2019-09-20 14:00:36 PDT
Created attachment 379267 [details]
[PATCH] Proposed Fix
Comment 9 Devin Rousso 2019-09-24 15:46:16 PDT
Created attachment 379508 [details]
[Image] suggested drop UI

How about something like this for the drop zone UI?

I think we should completely cover (edge-to-edge) the entire drop zone with an indicator so that developers know where they can drop the new image/file.

```
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    left: 0;
    font-size: 80px;
    color: white;
    text-shadow: 0 1px black;
    background-color: hsla(0, 0%, 50%, 0.7);
    -webkit-backdrop-filter: blur(10px);
    border: 10px dashed white;
```
Comment 10 Nikita Vasilyev 2019-09-24 15:54:45 PDT
(In reply to Joseph Pecoraro from comment #4)
> Created attachment 379181 [details]
> [IMAGE] Light Mode

What is "#" doing at the bottom right side of the content view?
Comment 11 Joseph Pecoraro 2019-09-24 22:07:50 PDT
(In reply to Nikita Vasilyev from comment #10)
> (In reply to Joseph Pecoraro from comment #4)
> > Created attachment 379181 [details]
> > [IMAGE] Light Mode
> 
> What is "#" doing at the bottom right side of the content view?

That is the image being dragged over the current image.
Comment 12 Devin Rousso 2019-09-27 15:09:27 PDT Comment hidden (obsolete)
Comment 13 Joseph Pecoraro 2019-10-09 16:55:04 PDT Comment hidden (obsolete)
Comment 14 Devin Rousso 2019-10-09 21:27:51 PDT
Comment on attachment 379267 [details]
[PATCH] Proposed Fix

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

>>> Source/WebInspectorUI/UserInterface/Models/SourceCodeRevision.js:62
>>> +    updateRevisionContent(content, base64Encoded, mimeType, blobContent)
>> 
>> It seems like everything other than `content` is optional, so can we move them into an optional POD parameter?
>> ```
>>     updateRevisionContent(content, {base64Encoded, mimeType, blobContent} = {})
>> ```
> 
> Done.
> 
> Aside: What do you mean by an "optional POD parameter"? Do you mean an "optional object parameter"?

POD as in "plain old data" like a JavaScript object, not like some special model object.  So yes, "optional object parameter".

>>> Source/WebInspectorUI/UserInterface/Views/DropZoneView.js:81
>>> +        console.assert(this._targetElement);
>> 
>> How does the `this._targetElement` relate to `this.element`?  Should it be a parent/child/sibling?
>> 
>> It seems like this class really should be more of a controller, not a view, as it really just listens for events on a target and adds/removes styles depending on them.
> 
> Indeed, DropZone is kind of both, hence the delegate. The DropZone view is displayed based on external conditions, but once appearing it has its own event handlers, over the content.

I suppose this is a bit like `WI.Popover`, so yeah I'm fine with it being a `WI.View` subclass.  My question was more about how `this._targetElement` relates to `this.element`, in that should we have some sort of assertion that they have the same parent or something like that.

>>> Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js:52
>>> +                this._dropZoneView = new WI.DropZoneView(this);
>> 
>> Should we also allow drag/drop for text resource content?
> 
> My initial reaction was no. But that is not a strong opinion. Most text editors inline text content or a file path when a file is dropped, not replace contents. So I thought it was a bit weird for text content.

Aaahhh good point!  I'm on the fence about that, especially since paths are pretty uncommon on the web, especially for local paths.  I'm leaning more towards allowing text drag/drop.

>>> Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js:189
>>> +            this._imageElement.src = dataURL;
>> 
>> NIT: I'm not actually sure if this matters, but since image decoding is async, perhaps we should move this above the other stuff.
> 
> Do you mean to encourage it to happen faster?

Yes, that's my thought process.  As I said, I'm not sure if it matters, but it couldn't hurt.
Comment 15 Joseph Pecoraro 2019-10-10 14:12:13 PDT
Created attachment 380679 [details]
[PATCH] Proposed Fix
Comment 16 Joseph Pecoraro 2019-10-10 14:12:55 PDT
Created attachment 380681 [details]
[IMAGE] Light Mode
Comment 17 Joseph Pecoraro 2019-10-10 14:13:12 PDT
Created attachment 380682 [details]
[IMAGE] Dark Mode
Comment 18 Devin Rousso 2019-10-10 20:11:38 PDT
Comment on attachment 380679 [details]
[PATCH] Proposed Fix

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

r=me, awesome work!

> LayoutTests/inspector/unit-tests/mimetype-utilities.html:13
> +            InspectorTest.expectEqual(WI.fileExtensionForFilename(null), null, `File extension for null filename should be null.`);

NIT: `InspectorTest.expectNull`

> Source/WebInspectorUI/UserInterface/Base/BlobUtilities.js:26
> +WI.BlobUtilities = class BlobUtilities {

NICE =D

> Source/WebInspectorUI/UserInterface/Base/BlobUtilities.js:39
> +        var byteCharacters = atob(base64Data);

Optional: while we're moving this code, why not update the `var` too =D

> Source/WebInspectorUI/UserInterface/Base/BlobUtilities.js:50
> +                bytes[i] = byteCharacters[offset].charCodeAt(0);

Optional: you could also use `offset - begin` instead of `i`

> Source/WebInspectorUI/UserInterface/Base/FileUtilities.js:174
> +    static async readDataURL(fileOrList, callback)

This doesn't appear to be used.

> Source/WebInspectorUI/UserInterface/Base/MIMETypeUtilities.js:39
> +}

Style: missing semicolon

> Source/WebInspectorUI/UserInterface/Base/Utilities.js:-1702
> -function textToBlob(text, mimeType)

It looks like you missed:
 - http/tests/inspector/network/fetch-response-body.html
 - http/tests/inspector/network/xhr-response-body.html

> Source/WebInspectorUI/UserInterface/Base/Utilities.js:-1707
> -function blobAsText(blob, callback)

Ditto

> Source/WebInspectorUI/UserInterface/Models/SourceCodeRevision.js:61
> +    updateRevisionContent(content, {base64Encoded, mimeType, blobContent} = {})

NIT: I'd probably call this `update` or `updateContent` (given that this class already has "revision" in the name), but I understand if you'd rather keep it this way for better code searching

> Source/WebInspectorUI/UserInterface/Views/DropZoneView.css:40
> +    text-align: center;

NIT: here's the order I'd use so the styles order from content inside/foreground to outside/background:
```
    font-size: 60px;
    text-align: center;
    color: white;
    text-shadow: 0 1px black;
    background-color: hsla(0, 0%, 50%, 0.5);
    border: 3px dashed hsla(0, 0%, 100%, 0.9);
    -webkit-backdrop-filter: blur(10px);
```

> Source/WebInspectorUI/UserInterface/Views/DropZoneView.css:51
> +        background-color: hsla(0, 0%, 30%, 0.5);

Ditto:
```
    color: hsl(0, 0%, 80%);
    text-shadow: 0 1px hsl(0, 0%, 20%);
    background-color: hsla(0, 0%, 30%, 0.5);
    border: 3px dashed hsla(0, 0%, 65%, 0.9);
```

> Source/WebInspectorUI/UserInterface/Views/DropZoneView.js:109
> +        if (this._activelyHandlingDrag)

We should assert that this view is attached to the DOM tree, so that this UI is shown.
```
    console.assert(this.isAttached);
```

> Source/WebInspectorUI/UserInterface/Views/FontResourceContentView.css:31
>  

might as well remove this too =D

> Source/WebInspectorUI/UserInterface/Views/FontResourceContentView.js:37
> +        if (this.showingLocalResourceOverride)
> +            this._dropZoneView = new WI.DropZoneView(this, {text: WI.UIString("Drop Font")});

NIT: should we do this inside an `initialLayout`?

> Source/WebInspectorUI/UserInterface/Views/FontResourceContentView.js:78
> +    {

I know this was just moved ,but please add `super.shown();`

> Source/WebInspectorUI/UserInterface/Views/FontResourceContentView.js:89
> +    }

I know this was just moved ,but please add `super.hidden();`

> Source/WebInspectorUI/UserInterface/Views/FontResourceContentView.js:99
> +    }

I know this was just moved ,but please add `super.closed();`

> Source/WebInspectorUI/UserInterface/Views/FontResourceContentView.js:130
> +            let dataURL = fileReader.result;

Should we inline this?

> Source/WebInspectorUI/UserInterface/Views/FontResourceContentView.js:181
> +        let lines = WI.FontResourceContentView.PreviewLines;

Ditto (this could also be `const`)

> Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.css:31
> +

Can we remove these extra newlines?

> Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js:44
> +        if (this.showingLocalResourceOverride)
> +            this._dropZoneView = new WI.DropZoneView(this, {text: WI.UIString("Drop Image")});

Ditto (FontResourceContentView.js:36)

> Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js:52
> +

I'd personally remove these newlines, but I'm fine either way

> Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js:82
> +        this._draggingInternalImageElement = false;

Should we define this in the constructor instead?

> Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js:129
> +        // Do not appear if the drag is the current image inside this view.
> +        if (this._draggingInternalImageElement)

Good thinking!

> Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js:154
> +            let {base64, data, mimeType} = parseDataURL(dataURL);

Should we also attempt to derive the `mimeType` if `FileReader` doesn't give a MIME type for some reason, or do you think that that's unlikely?

> Source/WebInspectorUI/UserInterface/Views/ResourceContentView.js:95
> +

Ditto (ImageResourceContentView.js:52)

> Source/WebInspectorUI/UserInterface/Views/ResourceContentView.js:120
> +    {

We should add a `// Implemented by subclasses if needed.`

> Source/WebInspectorUI/UserInterface/Views/ResourceContentView.js:121
> +        return undefined;

Can we use `null` instead?

> Source/WebInspectorUI/UserInterface/Views/TextResourceContentView.js:78
>  

Ditto (ImageResourceContentView.js:52)
Comment 19 Joseph Pecoraro 2019-10-10 21:26:45 PDT
Comment on attachment 380679 [details]
[PATCH] Proposed Fix

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

>> Source/WebInspectorUI/UserInterface/Base/FileUtilities.js:174
>> +    static async readDataURL(fileOrList, callback)
> 
> This doesn't appear to be used.

Oops, I meant to remove this. Yeah I decided against it.

>> Source/WebInspectorUI/UserInterface/Base/Utilities.js:-1702
>> -function textToBlob(text, mimeType)
> 
> It looks like you missed:
>  - http/tests/inspector/network/fetch-response-body.html
>  - http/tests/inspector/network/xhr-response-body.html

Thanks!

>> Source/WebInspectorUI/UserInterface/Models/SourceCodeRevision.js:61
>> +    updateRevisionContent(content, {base64Encoded, mimeType, blobContent} = {})
> 
> NIT: I'd probably call this `update` or `updateContent` (given that this class already has "revision" in the name), but I understand if you'd rather keep it this way for better code searching

Precisely, I like the unique name for code searching.

>> Source/WebInspectorUI/UserInterface/Views/DropZoneView.js:109
>> +        if (this._activelyHandlingDrag)
> 
> We should assert that this view is attached to the DOM tree, so that this UI is shown.
> ```
>     console.assert(this.isAttached);
> ```

Good idea.

>> Source/WebInspectorUI/UserInterface/Views/FontResourceContentView.js:37
>> +            this._dropZoneView = new WI.DropZoneView(this, {text: WI.UIString("Drop Font")});
> 
> NIT: should we do this inside an `initialLayout`?

I had the same thought. Done.

>> Source/WebInspectorUI/UserInterface/Views/FontResourceContentView.js:181
>> +        let lines = WI.FontResourceContentView.PreviewLines;
> 
> Ditto (this could also be `const`)

I just inlined it.

>> Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js:82
>> +        this._draggingInternalImageElement = false;
> 
> Should we define this in the constructor instead?

Done!

>> Source/WebInspectorUI/UserInterface/Views/ImageResourceContentView.js:154
>> +            let {base64, data, mimeType} = parseDataURL(dataURL);
> 
> Should we also attempt to derive the `mimeType` if `FileReader` doesn't give a MIME type for some reason, or do you think that that's unlikely?

I like that idea.

>> Source/WebInspectorUI/UserInterface/Views/ResourceContentView.js:121
>> +        return undefined;
> 
> Can we use `null` instead?

Unfortunately no, because createLocalResourceOverride looked for `undefined`. I will move this all to an empty object instead.
Comment 20 Joseph Pecoraro 2019-10-10 21:35:45 PDT
Created attachment 380720 [details]
[PATCH] For Landing
Comment 21 Joseph Pecoraro 2019-10-11 13:44:40 PDT
https://trac.webkit.org/r251024