mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-09 19:01:41 +00:00
added select all option for library items
This commit is contained in:
parent
140544ba77
commit
9baca4f16c
7 changed files with 169 additions and 10 deletions
|
|
@ -499,6 +499,70 @@ export default {
|
|||
} else {
|
||||
console.error('Error socket not initialized')
|
||||
}
|
||||
},
|
||||
selectAllItems() {
|
||||
console.log('BookShelfCategorized: selectAllItems called!')
|
||||
console.log('BookShelfCategorized: shelves:', this.shelves)
|
||||
|
||||
// Get all visible items from shelves
|
||||
const allVisibleEntities = []
|
||||
this.shelves.forEach((shelf) => {
|
||||
console.log('BookShelfCategorized: processing shelf:', shelf.label, 'type:', shelf.type, 'entities:', shelf.entities.length)
|
||||
if (shelf.type === 'book' || shelf.type === 'podcast') {
|
||||
allVisibleEntities.push(...shelf.entities)
|
||||
}
|
||||
})
|
||||
|
||||
// Check if all visible items are already selected
|
||||
const selectedMediaItems = this.$store.state.globals.selectedMediaItems
|
||||
const visibleEntityIds = allVisibleEntities.map((e) => e.id)
|
||||
const selectedVisibleCount = selectedMediaItems.filter((item) => visibleEntityIds.includes(item.id)).length
|
||||
const shouldDeselect = selectedVisibleCount === visibleEntityIds.length && selectedVisibleCount > 0
|
||||
|
||||
console.log('BookShelfCategorized: visible entities:', visibleEntityIds.length, 'selected visible:', selectedVisibleCount, 'shouldDeselect:', shouldDeselect)
|
||||
|
||||
if (shouldDeselect) {
|
||||
// Deselect all visible items
|
||||
this.shelves.forEach((shelf) => {
|
||||
console.log('BookShelfCategorized: processing shelf for deselection:', shelf.label, 'type:', shelf.type, 'entities:', shelf.entities.length)
|
||||
if (shelf.type === 'book' || shelf.type === 'podcast') {
|
||||
shelf.entities.forEach((entity) => {
|
||||
console.log('BookShelfCategorized: deselecting entity:', entity.id, entity.mediaType)
|
||||
// Create the media item object the same way the individual deselect does
|
||||
const mediaItem = {
|
||||
id: entity.id,
|
||||
mediaType: entity.mediaType,
|
||||
hasTracks: entity.mediaType === 'podcast' || entity.media.audioFile || entity.media.numTracks || (entity.media.tracks && entity.media.tracks.length)
|
||||
}
|
||||
|
||||
// Remove the item from selection
|
||||
this.$store.commit('globals/setMediaItemSelected', { item: mediaItem, selected: false })
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// Select all visible items
|
||||
this.shelves.forEach((shelf) => {
|
||||
if (shelf.type === 'book' || shelf.type === 'podcast') {
|
||||
shelf.entities.forEach((entity) => {
|
||||
// Create the media item object the same way the individual select does
|
||||
const mediaItem = {
|
||||
id: entity.id,
|
||||
mediaType: entity.mediaType,
|
||||
hasTracks: entity.mediaType === 'podcast' || entity.media.audioFile || entity.media.numTracks || (entity.media.tracks && entity.media.tracks.length)
|
||||
}
|
||||
|
||||
// Use the existing store mutation to mark the item as selected
|
||||
this.$store.commit('globals/setMediaItemSelected', { item: mediaItem, selected: true })
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Trigger a single UI update after all items are selected/deselected
|
||||
this.$nextTick(() => {
|
||||
this.$eventBus.$emit('item-selected')
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
|
|
|||
|
|
@ -328,6 +328,13 @@ export default {
|
|||
})
|
||||
}
|
||||
|
||||
if (!this.isBatchSelecting && (!this.page || this.page === 'search')) {
|
||||
items.push({
|
||||
text: 'Select All',
|
||||
action: 'select-all'
|
||||
})
|
||||
}
|
||||
|
||||
this.addSubtitlesMenuItem(items)
|
||||
this.addCollapseSeriesMenuItem(items)
|
||||
|
||||
|
|
@ -426,12 +433,19 @@ export default {
|
|||
if (action === 'export-opml') {
|
||||
this.exportOPML()
|
||||
return
|
||||
} else if (action === 'select-all') {
|
||||
this.selectAllItems()
|
||||
return
|
||||
} else if (this.handleSubtitlesAction(action)) {
|
||||
return
|
||||
} else if (this.handleCollapseSeriesAction(action)) {
|
||||
return
|
||||
}
|
||||
},
|
||||
selectAllItems() {
|
||||
// Emit an event to the parent component to handle selecting all items
|
||||
this.$emit('select-all-items')
|
||||
},
|
||||
exportOPML() {
|
||||
this.$downloadFile(`/api/libraries/${this.currentLibraryId}/opml?token=${this.$store.getters['user/getToken']}`, null, true)
|
||||
},
|
||||
|
|
@ -644,9 +658,8 @@ export default {
|
|||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
#toolbar {
|
||||
box-shadow: 0px 8px 6px #111111aa;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
@ -880,6 +880,64 @@ export default {
|
|||
const shelfOffsetY = this.shelfPaddingHeight * this.sizeMultiplier
|
||||
const shelfOffsetX = (entityIndex - 1) * this.totalEntityCardWidth + this.bookshelfMarginLeft
|
||||
return `translate3d(${shelfOffsetX}px, ${shelfOffsetY}px, 0px)`
|
||||
},
|
||||
selectAllItems() {
|
||||
// Check if all visible items are already selected
|
||||
const selectedMediaItems = this.$store.state.globals.selectedMediaItems
|
||||
const visibleEntityIds = this.entities.filter((e) => e).map((e) => e.id)
|
||||
const selectedVisibleCount = selectedMediaItems.filter((item) => visibleEntityIds.includes(item.id)).length
|
||||
const shouldDeselect = selectedVisibleCount === visibleEntityIds.length && selectedVisibleCount > 0
|
||||
|
||||
if (shouldDeselect) {
|
||||
// Deselect all visible items
|
||||
this.entities.forEach((entity) => {
|
||||
if (entity) {
|
||||
// Create the media item object the same way the individual deselect does
|
||||
const mediaItem = {
|
||||
id: entity.id,
|
||||
mediaType: entity.mediaType,
|
||||
hasTracks: entity.mediaType === 'podcast' || entity.media.audioFile || entity.media.numTracks || (entity.media.tracks && entity.media.tracks.length)
|
||||
}
|
||||
|
||||
// Remove the item from selection
|
||||
this.$store.commit('globals/setMediaItemSelected', { item: mediaItem, selected: false })
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// Select all visible items
|
||||
this.entities.forEach((entity) => {
|
||||
if (entity) {
|
||||
// Create the media item object the same way the individual select does
|
||||
const mediaItem = {
|
||||
id: entity.id,
|
||||
mediaType: entity.mediaType,
|
||||
hasTracks: entity.mediaType === 'podcast' || entity.media.audioFile || entity.media.numTracks || (entity.media.tracks && entity.media.tracks.length)
|
||||
}
|
||||
|
||||
// Use the existing store mutation to mark the item as selected
|
||||
this.$store.commit('globals/setMediaItemSelected', { item: mediaItem, selected: true })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Force update all card components to reflect the selection state
|
||||
this.$nextTick(() => {
|
||||
this.updateBookSelectionMode(true)
|
||||
|
||||
// Also update the selected property of each card component
|
||||
const updatedSelectedItems = this.$store.state.globals.selectedMediaItems
|
||||
|
||||
for (const key in this.entityComponentRefs) {
|
||||
if (this.entityIndexesMounted.includes(Number(key))) {
|
||||
const component = this.entityComponentRefs[key]
|
||||
const entity = this.entities[key]
|
||||
if (component && entity) {
|
||||
const isSelected = updatedSelectedItems.some((item) => item.id === entity.id)
|
||||
component.selected = isSelected
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue