[UI] DropdownItem should emit @input together with @click.

The propagation of the `click` event shouldn't be stopped, as it is
required for the upstream Dropdown event to understand if it needs to
close.

Components should instead listen to `@input` events, so disabled items
will not be triggered.
This commit is contained in:
Fabio Manganiello 2024-07-21 19:54:03 +02:00
parent 2ccf00508d
commit 01aedb5568
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
17 changed files with 115 additions and 83 deletions

View file

@ -38,7 +38,7 @@
<div class="col-2 actions" v-if="fileActions.length">
<Dropdown>
<DropdownItem icon-class="fa fa-play" text="Play"
@click="$emit('play', {type: 'file', url: `file://${file.path}`})"
@input="$emit('play', {type: 'file', url: `file://${file.path}`})"
v-if="hasPlay && file.type !== 'directory'" />
</Dropdown>
</div>

View file

@ -98,9 +98,19 @@ export default {
return parseFloat(getComputedStyle(dropdown).height)
},
onClick() {
onClick(event) {
if (!this.keepOpenOnItemClick)
this.close()
if (event.target.tagName === 'A') {
event.preventDefault()
return false
}
if (event.defaultPrevented) {
event.stopPropagation()
return false
}
},
close() {

View file

@ -1,5 +1,6 @@
<template>
<div class="row item" :class="itemClass" @click="clicked">
<div class="row item" :class="{...itemClass_, disabled: disabled}"
:title="hoverText" @click="clicked">
<div class="col-2 icon" v-if="iconClass?.length || iconUrl?.length">
<Icon :class="iconClass" :url="iconUrl" />
</div>
@ -13,6 +14,7 @@ import { bus } from "@/bus";
export default {
components: {Icon},
emits: ['click', 'input'],
props: {
iconClass: {
type: String,
@ -26,6 +28,11 @@ export default {
type: String,
},
hoverText: {
type: String,
default: null,
},
disabled: {
type: Boolean,
default: false,
@ -34,13 +41,27 @@ export default {
itemClass: {}
},
methods: {
clicked() {
if (this.disabled)
return false
computed: {
itemClass_() {
if (typeof this.itemClass === 'string')
return {[this.itemClass]: true}
return this.itemClass
}
},
methods: {
clicked(event) {
if (!this.$parent.keepOpenOnItemClick)
bus.emit('dropdown-close')
if (this.disabled) {
event.stopPropagation()
event.preventDefault()
return false
}
this.$emit('input', event)
}
}
}
@ -69,7 +90,7 @@ export default {
&.disabled {
color: $dropdown-disabled-color;
cursor: initial;
cursor: initial !important;
}
.text {

View file

@ -44,12 +44,12 @@
<span class="section right">
<Dropdown title="Actions" icon-class="fa fa-ellipsis-h">
<DropdownItem text="Refresh" icon-class="fa fa-sync-alt" @click="refresh(group)" />
<DropdownItem text="Hide" icon-class="fa fa-eye-slash" @click="hideGroup(group)" />
<DropdownItem text="Refresh" icon-class="fa fa-sync-alt" @input="refresh(group)" />
<DropdownItem text="Hide" icon-class="fa fa-eye-slash" @input="hideGroup(group)" />
<DropdownItem text="Collapse" icon-class="fa fa-caret-up"
@click="collapsedGroups[group.name] = true" v-if="!collapsedGroups[group.name]" />
@input="collapsedGroups[group.name] = true" v-if="!collapsedGroups[group.name]" />
<DropdownItem text="Expand" icon-class="fa fa-caret-down"
@click="collapsedGroups[group.name] = false" v-else />
@input="collapsedGroups[group.name] = false" v-else />
</Dropdown>
</span>
</div>

View file

@ -10,15 +10,15 @@
<div class="selector actions-container col-1 pull-right">
<Dropdown title="Actions" icon-class="fas fa-ellipsis">
<DropdownItem icon-class="fas fa-sync-alt" text="Refresh"
@click="$emit('refresh')" />
@input="$emit('refresh')" />
<DropdownItem icon-class="fas fa-square-root-variable"
text="Set Variable" @click="$emit('show-variable-modal')" />
text="Set Variable" @input="$emit('show-variable-modal')" />
<Dropdown title="Group by" text="Group by"
icon-class="fas fa-object-ungroup" ref="groupingSelector">
<DropdownItem v-for="g in visibleGroupings" :key="g" :text="prettifyGroupingName(g)"
:item-class="{selected: value?.grouping === g}"
@click="onGroupingChanged(g)" />
@input="onGroupingChanged(g)" />
</Dropdown>
<Dropdown title="Filter groups" text="Filter groups"

View file

@ -32,19 +32,19 @@
<div class="col-2 right side">
<Dropdown title="Actions" icon-class="fa fa-ellipsis-h" @click="selectedItem = i">
<DropdownItem icon-class="fa fa-play" text="Play"
@click="$emit('play', {url: `file:///${media.path}`})"
@input="$emit('play', {url: `file:///${media.path}`})"
v-if="media.state.toLowerCase() === 'completed'" />
<DropdownItem icon-class="fa fa-pause" text="Pause download" @click="pause(media)"
<DropdownItem icon-class="fa fa-pause" text="Pause download" @input="pause(media)"
v-if="media.state.toLowerCase() === 'downloading' || media.state.toLowerCase() === 'started'" />
<DropdownItem icon-class="fa fa-rotate-left" text="Resume download" @click="resume(media)"
<DropdownItem icon-class="fa fa-rotate-left" text="Resume download" @input="resume(media)"
v-if="media.state.toLowerCase() === 'paused'" />
<DropdownItem icon-class="fa fa-eraser" text="Clear from queue" @click="clear(media)"
<DropdownItem icon-class="fa fa-eraser" text="Clear from queue" @input="clear(media)"
v-if="media.state.toLowerCase() === 'completed'" />
<DropdownItem icon-class="fa fa-stop" text="Cancel" @click="cancel(media)"
<DropdownItem icon-class="fa fa-stop" text="Cancel" @input="cancel(media)"
v-if="media.state.toLowerCase() !== 'completed' && media.state.toLowerCase() !== 'cancelled'" />
<DropdownItem icon-class="fa fa-trash" text="Remove file" @click="onDeleteSelected(media)"
<DropdownItem icon-class="fa fa-trash" text="Remove file" @input="onDeleteSelected(media)"
v-if="media.state.toLowerCase() === 'completed' || media.state.toLowerCase() === 'cancelled'" />
<DropdownItem icon-class="fa fa-info" text="Media info" @click="$refs.mediaInfo.isVisible = true" />
<DropdownItem icon-class="fa fa-info" text="Media info" @input="$refs.mediaInfo.isVisible = true" />
</Dropdown>
</div>
</div>

View file

@ -13,19 +13,19 @@
<div class="col-11 left side" v-text="item.title || item.name" @click="$emit('select')" />
<div class="col-1 right side">
<Dropdown title="Actions" icon-class="fa fa-ellipsis-h" ref="dropdown">
<DropdownItem icon-class="fa fa-play" text="Play" @click="$emit('play')"
<DropdownItem icon-class="fa fa-play" text="Play" @input="$emit('play')"
v-if="item.type !== 'torrent'" />
<DropdownItem icon-class="fa fa-download" text="Download" @click="$emit('download')"
<DropdownItem icon-class="fa fa-download" text="Download" @input="$emit('download')"
v-if="(item.type === 'torrent' || item.type === 'youtube') && item.item_type !== 'channel' && item.item_type !== 'playlist'" />
<DropdownItem icon-class="fa fa-volume-high" text="Download Audio" @click="$emit('download-audio')"
<DropdownItem icon-class="fa fa-volume-high" text="Download Audio" @input="$emit('download-audio')"
v-if="item.type === 'youtube' && item.item_type !== 'channel' && item.item_type !== 'playlist'" />
<DropdownItem icon-class="fa fa-list" text="Add to playlist" @click="$emit('add-to-playlist')"
<DropdownItem icon-class="fa fa-list" text="Add to playlist" @input="$emit('add-to-playlist')"
v-if="item.type === 'youtube'" />
<DropdownItem icon-class="fa fa-trash" text="Remove from playlist" @click="$emit('remove-from-playlist')"
<DropdownItem icon-class="fa fa-trash" text="Remove from playlist" @input="$emit('remove-from-playlist')"
v-if="item.type === 'youtube' && playlist?.length" />
<DropdownItem icon-class="fa fa-window-maximize" text="View in browser" @click="$emit('view')"
<DropdownItem icon-class="fa fa-window-maximize" text="View in browser" @input="$emit('view')"
v-if="item.type === 'file'" />
<DropdownItem icon-class="fa fa-info-circle" text="Info" @click="$emit('select')" />
<DropdownItem icon-class="fa fa-info-circle" text="Info" @input="$emit('select')" />
</Dropdown>
</div>
</div>

View file

@ -21,7 +21,7 @@
<Loading v-if="loading" />
<div class="refresh">
<DropdownItem text="Refresh" icon-class="fa fa-sync-alt" @click="refresh" />
<DropdownItem text="Refresh" icon-class="fa fa-sync-alt" @input="refresh" />
</div>
<div class="no-results" v-if="!players?.length">No players found</div>
@ -29,7 +29,7 @@
<div class="player" v-for="(player, i) in players" :key="i"
:class="{selected: selectedPlayer != null && selectedPlayer.pluginName === player.pluginName
&& selectedPlayer.name === player.name}">
<DropdownItem :text="player.name" :icon-class="player.iconClass" @click="select(player)" />
<DropdownItem :text="player.name" :icon-class="player.iconClass" @input="select(player)" />
</div>
</Dropdown>
</div>

View file

@ -56,10 +56,10 @@
<span class="actions">
<Dropdown title="Actions" icon-class="fa fa-ellipsis-h">
<DropdownItem text="Play" icon-class="fa fa-play" @click="play(i)" />
<DropdownItem text="Add to queue" icon-class="fa fa-plus" @click="load(i)" />
<DropdownItem text="Add to playlist" icon-class="fa fa-list-ul" @click="$emit('add-to-playlist', result)" />
<DropdownItem text="Info" icon-class="fa fa-info" @click="$emit('info', result)" />
<DropdownItem text="Play" icon-class="fa fa-play" @input="play(i)" />
<DropdownItem text="Add to queue" icon-class="fa fa-plus" @input="load(i)" />
<DropdownItem text="Add to playlist" icon-class="fa fa-list-ul" @input="$emit('add-to-playlist', result)" />
<DropdownItem text="Info" icon-class="fa fa-info" @input="$emit('info', result)" />
</Dropdown>
</span>
</div>

View file

@ -20,29 +20,29 @@
</button>
<Dropdown title="Actions" icon-class="fa fa-ellipsis-h">
<DropdownItem text="Add track" icon-class="fa fa-plus" @click="addTrack" />
<DropdownItem text="Refresh status" icon-class="fa fa-sync" @click="$emit('refresh-status')" v-if="devices != null" />
<DropdownItem text="Add track" icon-class="fa fa-plus" @input="addTrack" />
<DropdownItem text="Refresh status" icon-class="fa fa-sync" @input="$emit('refresh-status')" v-if="devices != null" />
<DropdownItem text="Save as playlist" icon-class="fa fa-save" :disabled="!tracks?.length"
@click="playlistSave" v-if="withSave" />
@input="playlistSave" v-if="withSave" />
<DropdownItem text="Swap tracks" icon-class="fa fa-retweet"
v-if="withSwap && selectedTracks?.length === 2"
@click="$emit('swap', selectedTracks)" />
@input="$emit('swap', selectedTracks)" />
<DropdownItem :text="selectionMode ? 'End selection' : 'Start selection'" icon-class="far fa-check-square"
:disabled="!tracks?.length" @click="selectionMode = !selectionMode" />
:disabled="!tracks?.length" @input="selectionMode = !selectionMode" />
<DropdownItem :text="selectedTracks?.length === tracks?.length ? 'Unselect all' : 'Select all'"
icon-class="fa fa-check-double" :disabled="!tracks?.length"
@click="selectedTracks = selectedTracks.length === tracks.length ? [] : [...Array(tracks.length).keys()]" />
@input="selectedTracks = selectedTracks.length === tracks.length ? [] : [...Array(tracks.length).keys()]" />
<DropdownItem :text="'Remove track' + (selectedTracks.length > 1 ? 's' : '')"
icon-class="fa fa-trash" v-if="selectedTracks.length > 0"
@click="$emit('remove', [...(new Set(selectedTracks))])" />
@input="$emit('remove', [...(new Set(selectedTracks))])" />
<DropdownItem text="Clear playlist" icon-class="fa fa-ban"
:disabled="!tracks?.length" @click="$emit('clear')" v-if="withClear" />
:disabled="!tracks?.length" @input="$emit('clear')" v-if="withClear" />
</Dropdown>
<Dropdown title="Players" icon-class="fa fa-volume-up" v-if="Object.keys(devices || {}).length">
<DropdownItem v-for="(device, id) in devices" :key="id" v-text="device.name"
:item-class="{active: activeDevice === id, selected: selectedDevice === id}"
icon-class="fa fa-volume-up" @click="$emit('select-device', id)" />
icon-class="fa fa-volume-up" @input="$emit('select-device', id)" />
</Dropdown>
</div>
</MusicHeader>
@ -87,12 +87,12 @@
<span class="actions">
<Dropdown title="Actions" icon-class="fa fa-ellipsis-h" :ref="'menu' + i">
<DropdownItem text="Play" icon-class="fa fa-play" @click="onMenuPlay(i)" />
<DropdownItem text="Play" icon-class="fa fa-play" @input="onMenuPlay(i)" />
<DropdownItem text="Add to queue" icon-class="fa fa-plus"
@click="$emit('add-to-queue', [...(new Set([...selectedTracks, i]))])" v-if="withAddToQueue" />
<DropdownItem text="Add to playlist" icon-class="fa fa-list-ul" @click="$emit('add-to-playlist', tracks[i])" />
<DropdownItem text="Remove" icon-class="fa fa-trash" @click="$emit('remove', [...(new Set([...selectedTracks, i]))])" />
<DropdownItem text="Info" icon-class="fa fa-info" @click="$emit('info', tracks[i])" />
@input="$emit('add-to-queue', [...(new Set([...selectedTracks, i]))])" v-if="withAddToQueue" />
<DropdownItem text="Add to playlist" icon-class="fa fa-list-ul" @input="$emit('add-to-playlist', tracks[i])" />
<DropdownItem text="Remove" icon-class="fa fa-trash" @input="$emit('remove', [...(new Set([...selectedTracks, i]))])" />
<DropdownItem text="Info" icon-class="fa fa-info" @input="$emit('info', tracks[i])" />
</Dropdown>
</span>
</div>

View file

@ -40,7 +40,7 @@
<Dropdown title="Players" icon-class="fa fa-volume-up" v-if="Object.keys(devices || {}).length">
<DropdownItem v-for="(device, id) in devices" :key="id" v-text="device.name"
:item-class="{active: activeDevice === id, selected: selectedDevice === id}"
icon-class="fa fa-volume-up" @click="$emit('select-device', id)" />
icon-class="fa fa-volume-up" @input="$emit('select-device', id)" />
</Dropdown>
<button title="Refresh status" @click="$emit('refresh-status')" v-if="devices != null">

View file

@ -89,10 +89,10 @@
<span class="actions">
<Dropdown title="Actions" icon-class="fa fa-ellipsis-h">
<DropdownItem text="Play" icon-class="fa fa-play" @click="play(i)" />
<DropdownItem text="Add to queue" icon-class="fa fa-plus" @click="load(i)" />
<DropdownItem text="Add to playlist" icon-class="fa fa-list-ul" @click="$emit('add-to-playlist', result)" />
<DropdownItem text="Info" icon-class="fa fa-info" @click="$emit('info', result)" />
<DropdownItem text="Play" icon-class="fa fa-play" @input="play(i)" />
<DropdownItem text="Add to queue" icon-class="fa fa-plus" @input="load(i)" />
<DropdownItem text="Add to playlist" icon-class="fa fa-list-ul" @input="$emit('add-to-playlist', result)" />
<DropdownItem text="Info" icon-class="fa fa-info" @input="$emit('info', result)" />
</Dropdown>
</span>
</div>

View file

@ -45,9 +45,10 @@
<div class="actions pull-right col-4">
<Dropdown title="User Actions" icon-class="fa fa-ellipsis">
<DropdownItem text="Change Password" :disabled="commandRunning" icon-class="fa fa-key"
@click="showChangePasswordModal(user)" />
<DropdownItem text="Delete User" :disabled="commandRunning" icon-class="fa fa-trash"
@click="selectedUser = user.username; $refs.deleteUserDialog.show()" />
@input="showChangePasswordModal(user)" />
<DropdownItem text="Delete User" :disabled="commandRunning"
icon-class="fa fa-trash" item-class="text-danger"
@input="selectedUser = user.username; $refs.deleteUserDialog.show()" />
</Dropdown>
</div>
</li>

View file

@ -22,13 +22,13 @@
<div class="col-2 right side">
<Dropdown title="Actions" icon-class="fa fa-ellipsis-h" @click="selectedItem = i">
<DropdownItem icon-class="fa fa-pause" text="Pause transfer" @click="$emit('pause', torrent)"
<DropdownItem icon-class="fa fa-pause" text="Pause transfer" @input="$emit('pause', torrent)"
v-if="torrent.state === 'downloading' && !torrent.paused" />
<DropdownItem icon-class="fa fa-play" text="Resume transfer" @click="$emit('resume', torrent)"
<DropdownItem icon-class="fa fa-play" text="Resume transfer" @input="$emit('resume', torrent)"
v-if="torrent.state === 'downloading' && torrent.paused" />
<DropdownItem icon-class="fa fa-trash" text="Remove transfer" @click="$emit('remove', torrent)" />
<DropdownItem icon-class="fa fa-folder" text="View files" @click="$refs.torrentFiles.isVisible = true" />
<DropdownItem icon-class="fa fa-info" text="Torrent info" @click="$refs.torrentInfo.isVisible = true" />
<DropdownItem icon-class="fa fa-trash" text="Remove transfer" @input="$emit('remove', torrent)" />
<DropdownItem icon-class="fa fa-folder" text="View files" @input="$refs.torrentFiles.isVisible = true" />
<DropdownItem icon-class="fa fa-info" text="Torrent info" @input="$refs.torrentInfo.isVisible = true" />
</Dropdown>
</div>
</div>
@ -114,7 +114,7 @@
<div class="col-1 icon">
<Dropdown v-if="isMedia && mediaExtensions.has(file.split('.').pop())">
<DropdownItem icon-class="fa fa-play" text="Play"
@click="$emit('play', {url: `file://${transfers[selectedItem].files[i]}`, type: 'file'})" />
@input="$emit('play', {url: `file://${transfers[selectedItem].files[i]}`, type: 'file'})" />
</Dropdown>
<i class="fa fa-file" v-else />

View file

@ -72,11 +72,11 @@
</button>
<Dropdown ref="networkCommandsDropdown" icon-class="fa fa-cog" title="Network commands">
<DropdownItem text="Network Info" :disabled="loading" @click="$refs.infoModal.show()" />
<DropdownItem text="Permit Join" :disabled="loading" @click="permitJoin(true)"
<DropdownItem text="Network Info" :disabled="loading" @input="$refs.infoModal.show()" />
<DropdownItem text="Permit Join" :disabled="loading" @input="permitJoin(true)"
v-if="!status.info?.permit_join" />
<DropdownItem text="Disable Join" :disabled="loading" @click="permitJoin(false)" v-else/>
<DropdownItem text="Factory Reset" :disabled="loading" @click="factoryReset" />
<DropdownItem text="Disable Join" :disabled="loading" @input="permitJoin(false)" v-else/>
<DropdownItem text="Factory Reset" :disabled="loading" @input="factoryReset" />
</Dropdown>
<button class="btn btn-default" title="Refresh network" :disabled="loading" @click="refresh">

View file

@ -84,7 +84,7 @@
<Dropdown title="Add to scene" icon-class="fa fa-plus">
<DropdownItem v-for="(scene, i) in addValueToSceneItems" :key="i"
:text="scene.label" :disabled="commandRunning"
@click="$emit('add-to-scene', {sceneId: scene.scene_id, valueId: value.id_on_network})" />
@input="$emit('add-to-scene', {sceneId: scene.scene_id, valueId: value.id_on_network})" />
</Dropdown>
</div>
</div>

View file

@ -95,23 +95,23 @@
</button>
<Dropdown title="Network commands" icon-class="fa fa-cog">
<DropdownItem text="Network Info" :disabled="commandRunning" @click="networkInfoModalOpen" />
<DropdownItem text="Start Network" :disabled="commandRunning" @click="startNetwork" />
<DropdownItem text="Stop Network" :disabled="commandRunning" @click="stopNetwork" />
<DropdownItem text="Network Info" :disabled="commandRunning" @input="networkInfoModalOpen" />
<DropdownItem text="Start Network" :disabled="commandRunning" @input="startNetwork" />
<DropdownItem text="Stop Network" :disabled="commandRunning" @input="stopNetwork" />
<DropdownItem text="Add Node" :disabled="commandRunning"
@click="openAddNodeModal()" v-if="selected.view === 'nodes'" />
<DropdownItem text="Remove Node" :disabled="commandRunning" @click="removeNode"
@input="openAddNodeModal()" v-if="selected.view === 'nodes'" />
<DropdownItem text="Remove Node" :disabled="commandRunning" @input="removeNode"
v-if="selected.view === 'nodes'" />
<DropdownItem text="Switch All On" :disabled="commandRunning" @click="switchAll(true)" />
<DropdownItem text="Switch All Off" :disabled="commandRunning" @click="switchAll(false)" />
<DropdownItem text="Cancel Command" :disabled="commandRunning" @click="cancelCommand" />
<DropdownItem text="Kill Command" :disabled="commandRunning" @click="killCommand" />
<DropdownItem text="Receive Configuration" :disabled="commandRunning" @click="receiveConfiguration" />
<DropdownItem text="Create New Primary" :disabled="commandRunning" @click="createNewPrimary" />
<DropdownItem text="Transfer Primary Role" :disabled="commandRunning" @click="transferPrimaryRole" />
<DropdownItem text="Heal Network" :disabled="commandRunning" @click="healNetwork" />
<DropdownItem text="Soft Reset" :disabled="commandRunning" @click="softReset" />
<DropdownItem text="Hard Reset" :disabled="commandRunning" @click="hardReset" />
<DropdownItem text="Switch All On" :disabled="commandRunning" @input="switchAll(true)" />
<DropdownItem text="Switch All Off" :disabled="commandRunning" @input="switchAll(false)" />
<DropdownItem text="Cancel Command" :disabled="commandRunning" @input="cancelCommand" />
<DropdownItem text="Kill Command" :disabled="commandRunning" @input="killCommand" />
<DropdownItem text="Receive Configuration" :disabled="commandRunning" @input="receiveConfiguration" />
<DropdownItem text="Create New Primary" :disabled="commandRunning" @input="createNewPrimary" />
<DropdownItem text="Transfer Primary Role" :disabled="commandRunning" @input="transferPrimaryRole" />
<DropdownItem text="Heal Network" :disabled="commandRunning" @input="healNetwork" />
<DropdownItem text="Soft Reset" :disabled="commandRunning" @input="softReset" />
<DropdownItem text="Hard Reset" :disabled="commandRunning" @input="hardReset" />
</Dropdown>
<button class="btn btn-default" title="Refresh Network" @click="refresh">