Merge pull request #422 from dermotduffy/stop-prop

Don't trigger card-wide actions on card controls
This commit is contained in:
Dermot Duffy
2022-02-27 11:22:38 -08:00
committed by GitHub
8 changed files with 61 additions and 24 deletions
+5 -4
View File
@@ -697,10 +697,11 @@ specific overriding the less specific (see example below).
**Note:** The card itself relies on user interactions to function (e.g. `tap` on
the menu should activate that button, `tap` on a gallery thumbnail should open
that piece of media, etc). These internal actions are executed _also_, which
means that a card-wide `tap` action probably isn't that useful as it may be
disorienting to the user and will trigger on all kinds of basic interaction on
the card (e.g. tapping/clicking a menu button).
that piece of media, etc). Efforts are taken to de-duplicate interactions (e.g.
card-wide actions will not be activated through interaction with menu buttons,
next/previous controls, thumbnails, etc), but in some cases this is not possible
(e.g. embedded WebRTC card controls) -- in these cases duplicate actions may
occur with certain configurations (e.g. `tap`).
## Menu Modes
+17 -7
View File
@@ -1,11 +1,17 @@
import { noChange } from 'lit';
import { AttributePart, directive, Directive, DirectiveParameters } from 'lit/directive.js';
import {
AttributePart,
directive,
Directive,
DirectiveParameters,
} from 'lit/directive.js';
import type {
ActionHandlerDetail,
ActionHandlerOptions,
} from 'custom-card-helpers/dist/types.d.js';
import { fireEvent } from 'custom-card-helpers';
import { stopEventFromActivatingCardWideActions } from './common';
interface ActionHandler extends HTMLElement {
holdTime: number;
@@ -31,7 +37,6 @@ class ActionHandler extends HTMLElement implements ActionHandler {
private dblClickTimeout?: number;
public connectedCallback(): void {
[
'touchcancel',
'mouseout',
@@ -89,12 +94,17 @@ class ActionHandler extends HTMLElement implements ActionHandler {
};
const end = (ev: Event): void => {
// This will ensure only 1 actionHandler is invoked for a given interaction.
stopEventFromActivatingCardWideActions(ev);
const options = element.actionHandlerOptions;
if (['touchend', 'touchcancel'].includes(ev.type)
// This action handler by default relies on synthetic click events for
// touch devices, in order to ensure that embedded cards (e.g. WebRTC)
// can use stock click handlers. The exception is for hold events.
&& !(options?.hasHold && this.held)) {
if (
['touchend', 'touchcancel'].includes(ev.type) &&
// This action handler by default relies on synthetic click events for
// touch devices, in order to ensure that embedded cards (e.g. WebRTC)
// can use stock click handlers. The exception is for hold events.
!(options?.hasHold && this.held)
) {
return;
}
if (options?.hasHold) {
+7
View File
@@ -583,3 +583,10 @@ export const frigateCardHasAction = (
}
return hasAction(config);
};
/**
* Stop an event from activating card wide actions.
*/
export const stopEventFromActivatingCardWideActions = (ev: Event): void => {
ev.stopPropagation();
}
+7 -3
View File
@@ -13,6 +13,7 @@ import {
import { BrowseMediaUtil } from '../browse-media-util.js';
import { View } from '../view.js';
import { renderProgressIndicator } from './message.js';
import { stopEventFromActivatingCardWideActions } from '../common.js';
import galleryStyle from '../scss/gallery.scss';
@@ -161,10 +162,11 @@ export class FrigateCardGalleryCore extends LitElement {
<div class="mdc-image-list__image-aspect-container">
<div class="mdc-image-list__image">
<ha-card
@click=${() => {
@click=${(ev) => {
if (this.view && this.view.previous) {
this.view.previous.dispatchChangeEvent(this);
}
stopEventFromActivatingCardWideActions(ev);
}}
outlined=""
class="frigate-card-gallery-folder"
@@ -182,7 +184,7 @@ export class FrigateCardGalleryCore extends LitElement {
${child.can_expand
? html`<div class="mdc-image-list__image">
<ha-card
@click=${() => {
@click=${(ev) => {
if (this.hass && this.view) {
BrowseMediaUtil.fetchChildMediaAndDispatchViewChange(
this,
@@ -191,6 +193,7 @@ export class FrigateCardGalleryCore extends LitElement {
child,
);
}
stopEventFromActivatingCardWideActions(ev);
}}
outlined=""
class="frigate-card-gallery-folder"
@@ -204,7 +207,7 @@ export class FrigateCardGalleryCore extends LitElement {
class="mdc-image-list__image"
src="${child.thumbnail}"
title="${child.title}"
@click=${() => {
@click=${(ev) => {
if (this.view) {
this.view
.evolve({
@@ -214,6 +217,7 @@ export class FrigateCardGalleryCore extends LitElement {
})
.dispatchChangeEvent(this);
}
stopEventFromActivatingCardWideActions(ev);
}}
/>`
: ``}
+5 -2
View File
@@ -50,6 +50,7 @@ import {
getCameraIcon,
getCameraTitle,
homeAssistantSignPath,
stopEventFromActivatingCardWideActions,
} from '../common.js';
import { renderProgressIndicator } from '../components/message.js';
@@ -550,8 +551,9 @@ export class FrigateCardLiveCarousel extends FrigateCardMediaCarousel {
.label=${getCameraTitle(this.hass, prev)}
.icon=${getCameraIcon(this.hass, prev)}
?disabled=${prev == null}
@click=${() => {
@click=${(ev) => {
this._nextPreviousHandler('previous');
stopEventFromActivatingCardWideActions(ev);
}}
>
</frigate-card-next-previous-control>
@@ -565,8 +567,9 @@ export class FrigateCardLiveCarousel extends FrigateCardMediaCarousel {
.label=${getCameraTitle(this.hass, next)}
.icon=${getCameraIcon(this.hass, next)}
?disabled=${next == null}
@click=${() => {
@click=${(ev) => {
this._nextPreviousHandler('next');
stopEventFromActivatingCardWideActions(ev);
}}
>
</frigate-card-next-previous-control>
+12 -4
View File
@@ -2,7 +2,11 @@ import type { Corner, Menu } from '@material/mwc-menu';
import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit';
import { HomeAssistant } from 'custom-card-helpers';
import { customElement, property, query } from 'lit/decorators';
import { frigateCardHasAction, refreshDynamicStateParameters } from '../common.js';
import {
frigateCardHasAction,
refreshDynamicStateParameters,
stopEventFromActivatingCardWideActions,
} from '../common.js';
import { ifDefined } from 'lit/directives/if-defined';
import { styleMap } from 'lit/directives/style-map';
@@ -68,7 +72,10 @@ export class FrigateCardSubmenu extends LitElement {
protected _getFixedRoot(): HTMLElement | null {
let n = this as Node | null;
while (n) {
if (n.nodeType === Node.ELEMENT_NODE && (n as Element).tagName === 'HA-APP-LAYOUT') {
if (
n.nodeType === Node.ELEMENT_NODE &&
(n as Element).tagName === 'HA-APP-LAYOUT'
) {
return n as HTMLElement;
}
n = n.parentNode
@@ -93,7 +100,7 @@ export class FrigateCardSubmenu extends LitElement {
hasHold: frigateCardHasAction(this.submenu.hold_action),
hasDoubleClick: frigateCardHasAction(this.submenu.double_tap_action),
})}
@click=${() => {
@click=${(ev) => {
if (this._menu) {
// Hack: This insanity is brought about by lack of MWCMenu playing
// nicely with the Home Assistant view/sidepanel. The menu must be
@@ -116,12 +123,13 @@ export class FrigateCardSubmenu extends LitElement {
}
this._menu.show();
}
stopEventFromActivatingCardWideActions(ev);
}}
>
<ha-icon icon="${this.submenu.icon}"></ha-icon>
</ha-icon-button>
<mwc-menu
.corner=${this.corner || "BOTTOM_LEFT"}
.corner=${this.corner || 'BOTTOM_LEFT'}
fixed
@closed=${
// Prevent the submenu closing from closing anything upstream (e.g.
+3 -2
View File
@@ -5,7 +5,7 @@ import { customElement, property } from 'lit/decorators.js';
import type { BrowseMediaSource, ThumbnailsControlConfig } from '../types.js';
import { FrigateCardCarousel } from './carousel.js';
import { dispatchFrigateCardEvent } from '../common.js';
import { dispatchFrigateCardEvent, stopEventFromActivatingCardWideActions } from '../common.js';
import thumbnailCarouselStyle from '../scss/thumbnail-carousel.scss';
@@ -111,7 +111,7 @@ export class FrigateCardThumbnailCarousel extends FrigateCardCarousel {
return html`<div
class="embla__slide"
@click=${() => {
@click=${(ev) => {
if (this._carousel && this._carousel.clickAllowed()) {
dispatchFrigateCardEvent<ThumbnailCarouselTap>(this, 'carousel:tap', {
slideIndex: slideIndex,
@@ -119,6 +119,7 @@ export class FrigateCardThumbnailCarousel extends FrigateCardCarousel {
childIndex: childIndex,
});
}
stopEventFromActivatingCardWideActions(ev);
}}
>
<img
+5 -2
View File
@@ -38,6 +38,7 @@ import {
contentsChanged,
createMediaShowInfo,
dispatchErrorMessageEvent,
stopEventFromActivatingCardWideActions,
} from '../common.js';
import { renderProgressIndicator } from '../components/message.js';
@@ -655,8 +656,9 @@ export class FrigateCardViewerCarousel extends FrigateCardMediaCarousel {
.thumbnail=${prev && prev.thumbnail ? prev.thumbnail : undefined}
.label=${prev ? prev.title : ''}
?disabled=${!prev}
@click=${() => {
@click=${(ev) => {
this._nextPreviousHandler('previous');
stopEventFromActivatingCardWideActions(ev);
}}
></frigate-card-next-previous-control>
<div class="embla__viewport">
@@ -669,8 +671,9 @@ export class FrigateCardViewerCarousel extends FrigateCardMediaCarousel {
.thumbnail=${next && next.thumbnail ? next.thumbnail : undefined}
.label=${next ? next.title : ''}
?disabled=${!next}
@click=${() => {
@click=${(ev) => {
this._nextPreviousHandler('next');
stopEventFromActivatingCardWideActions(ev);
}}
></frigate-card-next-previous-control>
</div>