Bug 208283

Summary: Web Inspector: AXI: disabled buttons shouldn't be focusable
Product: WebKit Reporter: Nikita Vasilyev <nvasilyev>
Component: Web InspectorAssignee: Nikita Vasilyev <nvasilyev>
Status: RESOLVED FIXED    
Severity: Normal CC: hi, inspector-bugzilla-changes, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: All   
OS: All   
Attachments:
Description Flags
Patch
none
Patch
none
Patch
hi: review+
Patch none

Description Nikita Vasilyev 2020-02-26 18:54:58 PST
When pressing Tab/Shift-Tab, it shouldn't focus on disabled buttons.
Comment 1 Radar WebKit Bug Importer 2020-02-26 18:55:15 PST
<rdar://problem/59832150>
Comment 2 Nikita Vasilyev 2020-02-26 18:57:39 PST
Created attachment 391831 [details]
Patch
Comment 3 Devin Rousso 2020-02-26 21:03:57 PST
Comment on attachment 391831 [details]
Patch

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

> Source/WebInspectorUI/UserInterface/Views/ButtonNavigationItem.js:44
> +        if (this._role === "button")

Do we ever actually pass in anything that isn't `"button"`?  I see this type of logic all over the place with navigation related things and I don't remember it ever actually being used anywhere.  Perhaps we can just remove the `role` parameter entirely and always use `"button"`?

> Source/WebInspectorUI/UserInterface/Views/ButtonNavigationItem.js:208
> +        if (this._role === "button")

Shouldn't we `this.element.removeAttribute("tabindex")` in the `else`?
Comment 4 Nikita Vasilyev 2020-02-27 00:03:29 PST
Comment on attachment 391831 [details]
Patch

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

>> Source/WebInspectorUI/UserInterface/Views/ButtonNavigationItem.js:44
>> +        if (this._role === "button")
> 
> Do we ever actually pass in anything that isn't `"button"`?  I see this type of logic all over the place with navigation related things and I don't remember it ever actually being used anywhere.  Perhaps we can just remove the `role` parameter entirely and always use `"button"`?

WI.RadioButtonNavigationItem passes "tab".
(Perhaps WI.RadioButtonNavigationItem should be renamed to something like WI.TabButtonNavigationItem. This is out of the scope of this bug.)

>> Source/WebInspectorUI/UserInterface/Views/ButtonNavigationItem.js:208
>> +        if (this._role === "button")
> 
> Shouldn't we `this.element.removeAttribute("tabindex")` in the `else`?

It wouldn't make a difference. It would only run for WI.RadioButtonNavigationItem during the class instantiation, and RadioButtonNavigationItem doesn't have any tabIndex set at that time.
RadioButtonNavigationItem is never disabled so _updateTabIndex would never get called from there.
Comment 5 Nikita Vasilyev 2020-02-27 00:09:41 PST
I don't want to do this in this patch, but perhaps it's worth refactoring RadioButtonNavigationItem.

Currently, RadioButtonNavigationItem extends ButtonNavigationItem, which extends NavigationItem.
Perhaps it would be less confusing if RadioButtonNavigationItem extended NavigationItem directly.
Comment 6 Devin Rousso 2020-03-05 16:24:40 PST
Comment on attachment 391831 [details]
Patch

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

>>> Source/WebInspectorUI/UserInterface/Views/ButtonNavigationItem.js:208
>>> +        if (this._role === "button")
>> 
>> Shouldn't we `this.element.removeAttribute("tabindex")` in the `else`?
> 
> It wouldn't make a difference. It would only run for WI.RadioButtonNavigationItem during the class instantiation, and RadioButtonNavigationItem doesn't have any tabIndex set at that time.
> RadioButtonNavigationItem is never disabled so _updateTabIndex would never get called from there.

What about if an instance of `WI.RadioButtonNavigationItem` called `.enabled = false;` and then `.enabled = true`?  It would get called then, and the `tabIndex` wouldn't be reset.
Comment 7 Nikita Vasilyev 2020-03-06 19:11:31 PST
Created attachment 392838 [details]
Patch
Comment 8 Devin Rousso 2020-03-06 20:22:46 PST
Comment on attachment 392838 [details]
Patch

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

> Source/WebInspectorUI/UserInterface/Views/ButtonNavigationItem.js:164
> +        if (this._role === "button")
> +            this.element.tabIndex = 0;
> +        else
> +            this.element.tabIndex = -1;

Why not just inline this `this.element.tabIndex = (this._role === "button") ? 0 : -1;`?

> Source/WebInspectorUI/UserInterface/Views/RadioButtonNavigationItem.js:72
> +        if (!this._enabled) {

Style: in subclasses, we shouldn't use the private variables of superclasses, so please use `this.enabled`

> Source/WebInspectorUI/UserInterface/Views/RadioButtonNavigationItem.js:80
> +        if (this.selected)
> +            this.element.tabIndex = 0;
> +        else
> +            this.element.tabIndex = -1;

Why not just have this as part of the `if` in `super.updateTabIndex`?  All basic `WI.ButtonNavigationItem` will already pass `this._role === "button"`, and everyone else should only be tabbabale if they're selected.

At the very least, this deserves an explanation (or at least a warning) that you're not calling `super.updateTabIndex`.  I'd really prefer it if you changed it so that it doesn't completely override `super.updateTabIndex`, as that can make it harder to adjust things in the future as someone reading the base class won't necessarily know about the fact that this was overriding it and would therefore not be affected by any of the aforementioned changes.
Comment 9 Nikita Vasilyev 2020-03-06 20:43:12 PST
Comment on attachment 392838 [details]
Patch

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

>> Source/WebInspectorUI/UserInterface/Views/RadioButtonNavigationItem.js:72
>> +        if (!this._enabled) {
> 
> Style: in subclasses, we shouldn't use the private variables of superclasses, so please use `this.enabled`

Right, thanks.

>> Source/WebInspectorUI/UserInterface/Views/RadioButtonNavigationItem.js:80
>> +            this.element.tabIndex = -1;
> 
> Why not just have this as part of the `if` in `super.updateTabIndex`?  All basic `WI.ButtonNavigationItem` will already pass `this._role === "button"`, and everyone else should only be tabbabale if they're selected.
> 
> At the very least, this deserves an explanation (or at least a warning) that you're not calling `super.updateTabIndex`.  I'd really prefer it if you changed it so that it doesn't completely override `super.updateTabIndex`, as that can make it harder to adjust things in the future as someone reading the base class won't necessarily know about the fact that this was overriding it and would therefore not be affected by any of the aforementioned changes.

Only selected radio button should be tabbable.

I can call super.updateTabIndex for consistency. It would make no difference here.
Comment 10 Nikita Vasilyev 2020-03-06 20:54:14 PST
Created attachment 392847 [details]
Patch
Comment 11 Devin Rousso 2020-03-11 10:25:45 PDT
Comment on attachment 392847 [details]
Patch

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

r=me

> Source/WebInspectorUI/UserInterface/Views/RadioButtonNavigationItem.js:74
> +        if (!this.enabled) {

It'd be nice to avoid doing this check twice.  Right now, we also could potentially end up setting the `tabIndex` twice in this function, which is also unfortunate.  Perhaps we could create a protected `get tabbable` that _can_ be overridden by subclasses.

ButtonNavigationItem.js
```
    updateTabIndex()
    {
        if (!this._enabled) {
            this.element.tabIndex = -1;
            return;
        }

        this.element.tabIndex = this.tabbable ? 0 : -1;
    }

    get tabbable()
    {
        // Can be overridden by subclasses.
        return this._role === "button";
    }
```

RadioButtonNavigationItem.js
```
    get tabbable()
    {
        return this.selected;
    }
```

I guess if you do end up removing `WI.ButtonNavigationItem` as a superclass of `WI.RadioButtonNavigationItem`, then this would kinda have to be needed tho.
Comment 12 Nikita Vasilyev 2020-03-19 13:34:35 PDT
Comment on attachment 392847 [details]
Patch

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

>> Source/WebInspectorUI/UserInterface/Views/RadioButtonNavigationItem.js:74
>> +        if (!this.enabled) {
> 
> It'd be nice to avoid doing this check twice.  Right now, we also could potentially end up setting the `tabIndex` twice in this function, which is also unfortunate.  Perhaps we could create a protected `get tabbable` that _can_ be overridden by subclasses.
> 
> ButtonNavigationItem.js
> ```
>     updateTabIndex()
>     {
>         if (!this._enabled) {
>             this.element.tabIndex = -1;
>             return;
>         }
> 
>         this.element.tabIndex = this.tabbable ? 0 : -1;
>     }
> 
>     get tabbable()
>     {
>         // Can be overridden by subclasses.
>         return this._role === "button";
>     }
> ```
> 
> RadioButtonNavigationItem.js
> ```
>     get tabbable()
>     {
>         return this.selected;
>     }
> ```
> 
> I guess if you do end up removing `WI.ButtonNavigationItem` as a superclass of `WI.RadioButtonNavigationItem`, then this would kinda have to be needed tho.

I like the `tabbable` getter!
Comment 13 Nikita Vasilyev 2020-03-19 13:35:04 PDT
Created attachment 394014 [details]
Patch
Comment 14 EWS 2020-03-19 14:41:38 PDT
Committed r258730: <https://trac.webkit.org/changeset/258730>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 394014 [details].
Comment 15 Devin Rousso 2020-03-19 20:43:53 PDT
Comment on attachment 394014 [details]
Patch

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

> Source/WebInspectorUI/UserInterface/Views/ButtonNavigationItem.js:179
> +        return this._role === "button";

NIT: this probably could've had a `// Can be overridden by subclasses.` comment :P