{ "version": 3, "sources": ["src/app/cards/bulk-selection.service.ts"], "sourcesContent": ["import {Injectable} from '@angular/core';\nimport {NavigationStart, Router} from '@angular/router';\nimport {ReplaySubject} from 'rxjs';\nimport {filter} from 'rxjs/operators';\nimport {Action, ActionFactoryService, ActionItem} from '../_services/action-factory.service';\n\ntype DataSource = 'volume' | 'chapter' | 'special' | 'series' | 'bookmark' | 'sideNavStream' | 'collection' | 'readingList';\n\n/**\n * Responsible for handling selections on cards. Can handle multiple card sources next to each other in different loops.\n * This will clear selections between pages.\n *\n * Remarks: Page which renders cards is responsible for listening for shift keydown/keyup and updating our state variable.\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class BulkSelectionService {\n\n private debug: boolean = false;\n private prevIndex: number = 0;\n private prevDataSource!: DataSource;\n private selectedCards: { [key: string]: {[key: number]: boolean} } = {};\n private dataSourceMax: { [key: string]: number} = {};\n public isShiftDown: boolean = false;\n\n private actionsSource = new ReplaySubject[]>(1);\n public actions$ = this.actionsSource.asObservable();\n\n private selectionsSource = new ReplaySubject(1);\n /**\n * Number of active selections\n */\n public selections$ = this.selectionsSource.asObservable();\n\n constructor(router: Router, private actionFactory: ActionFactoryService) {\n router.events\n .pipe(filter(event => event instanceof NavigationStart))\n .subscribe(() => {\n this.deselectAll();\n this.dataSourceMax = {};\n this.prevIndex = 0;\n });\n }\n\n handleCardSelection(dataSource: DataSource, index: number, maxIndex: number, wasSelected: boolean) {\n if (this.isShiftDown) {\n\n if (dataSource === this.prevDataSource) {\n this.debugLog('Selecting ' + dataSource + ' cards from ' + this.prevIndex + ' to ' + index + ' as ' + !wasSelected);\n this.selectCards(dataSource, this.prevIndex, index, !wasSelected);\n } else {\n const isForwardSelection = index > this.prevIndex;\n\n if (isForwardSelection) {\n this.debugLog('Selecting ' + this.prevDataSource + ' cards from ' + this.prevIndex + ' to ' + this.dataSourceMax[this.prevDataSource]);\n this.selectCards(this.prevDataSource, this.prevIndex, this.dataSourceMax[this.prevDataSource], !wasSelected);\n this.debugLog('Selecting ' + dataSource + ' cards from ' + 0 + ' to ' + index);\n this.selectCards(dataSource, 0, index, !wasSelected);\n } else {\n this.debugLog('Selecting ' + this.prevDataSource + ' cards from ' + 0 + ' to ' + this.prevIndex);\n this.selectCards(this.prevDataSource, this.prevIndex, 0, !wasSelected);\n this.debugLog('Selecting ' + dataSource + ' cards from ' + index + ' to ' + maxIndex);\n this.selectCards(dataSource, index, maxIndex, !wasSelected);\n }\n }\n } else {\n this.debugLog('Selecting ' + dataSource + ' cards at ' + index);\n this.selectCards(dataSource, index, index, !wasSelected);\n }\n this.prevIndex = index;\n this.prevDataSource = dataSource;\n this.dataSourceMax[dataSource] = maxIndex;\n this.actionsSource.next(this.getActions(() => {}));\n }\n\n isCardSelected(dataSource: DataSource, index: number) {\n if (this.selectedCards.hasOwnProperty(dataSource) && this.selectedCards[dataSource].hasOwnProperty(index)) {\n return this.selectedCards[dataSource][index];\n }\n return false;\n }\n\n selectCards(dataSource: DataSource, from: number, to: number, value: boolean) {\n if (!this.selectedCards.hasOwnProperty(dataSource)) {\n this.selectedCards[dataSource] = {};\n }\n\n if (from === to) {\n this.selectedCards[dataSource][to] = value;\n this.selectionsSource.next(this.totalSelections());\n return;\n }\n\n if (from > to) {\n for (let i = to; i <= from; i++) {\n this.selectedCards[dataSource][i] = value;\n }\n }\n\n for (let i = from; i <= to; i++) {\n this.selectedCards[dataSource][i] = value;\n }\n this.selectionsSource.next(this.totalSelections());\n }\n\n deselectAll() {\n this.selectedCards = {};\n this.selectionsSource.next(0);\n }\n\n hasSelections() {\n const keys = Object.keys(this.selectedCards);\n return keys.filter(key => {\n return Object.values(this.selectedCards[key]).filter(item => item).length > 0;\n }).length > 0;\n }\n\n totalSelections() {\n let sum = 0;\n const keys = Object.keys(this.selectedCards);\n keys.forEach(key => {\n sum += Object.values(this.selectedCards[key]).filter(item => item).length;\n });\n return sum;\n }\n\n getSelectedCardsForSource(dataSource: DataSource) {\n if (!this.selectedCards.hasOwnProperty(dataSource)) return [];\n\n const ret = [];\n for(let k in this.selectedCards[dataSource]) {\n if (this.selectedCards[dataSource][k]) {\n ret.push(k);\n }\n }\n\n return ret;\n }\n\n /**\n * Returns the appropriate set of supported actions for the given mix of cards\n * @param callback\n */\n getActions(callback: (action: ActionItem, data: any) => void) {\n const allowedActions = [Action.AddToReadingList, Action.MarkAsRead, Action.MarkAsUnread, Action.AddToCollection,\n Action.Delete, Action.AddToWantToReadList, Action.RemoveFromWantToReadList];\n\n if (Object.keys(this.selectedCards).filter(item => item === 'series').length > 0) {\n return this.applyFilterToList(this.actionFactory.getSeriesActions(callback), allowedActions);\n }\n\n if (Object.keys(this.selectedCards).filter(item => item === 'bookmark').length > 0) {\n return this.actionFactory.getBookmarkActions(callback);\n }\n\n if (Object.keys(this.selectedCards).filter(item => item === 'sideNavStream').length > 0) {\n return this.applyFilterToList(this.actionFactory.getSideNavStreamActions(callback), [Action.MarkAsInvisible, Action.MarkAsVisible]);\n }\n\n if (Object.keys(this.selectedCards).filter(item => item === 'collection').length > 0) {\n return this.applyFilterToList(this.actionFactory.getCollectionTagActions(callback), [Action.Promote, Action.UnPromote, Action.Delete]);\n }\n\n if (Object.keys(this.selectedCards).filter(item => item === 'readingList').length > 0) {\n return this.applyFilterToList(this.actionFactory.getReadingListActions(callback), [Action.Promote, Action.UnPromote, Action.Delete]);\n }\n\n // Chapter/Volume\n return this.applyFilterToList(this.actionFactory.getVolumeActions(callback), [...allowedActions, Action.SendTo]);\n }\n\n private debugLog(message: string, extraData?: any) {\n if (!this.debug) return;\n\n if (extraData !== undefined) {\n console.log(message, extraData);\n } else {\n console.log(message);\n }\n }\n\n private applyFilter(action: ActionItem, allowedActions: Array) {\n let hasValidAction = false;\n\n // Check if the current action is valid or a submenu\n if (action.action === Action.Submenu || allowedActions.includes(action.action)) {\n hasValidAction = true;\n }\n\n // If the action has children, filter them recursively\n if (action.children && action.children.length > 0) {\n action.children = action.children.filter((childAction) => this.applyFilter(childAction, allowedActions));\n\n // If no valid children remain, the parent submenu should not be considered valid\n if (action.children.length === 0 && action.action === Action.Submenu) {\n hasValidAction = false;\n }\n }\n\n // Return whether this action or its children are valid\n return hasValidAction;\n }\n\n\tprivate applyFilterToList(list: Array>, allowedActions: Array): Array> {\n\t\tconst actions = list.map((a) => {\n\t\t\treturn { ...a };\n\t\t});\n return actions.filter(action => this.applyFilter(action, allowedActions));\n\t}\n}\n"], "mappings": "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", "names": ["BulkSelectionService", "constructor", "router", "actionFactory", "debug", "prevIndex", "selectedCards", "dataSourceMax", "isShiftDown", "actionsSource", "ReplaySubject", "actions$", "asObservable", "selectionsSource", "selections$", "events", "pipe", "filter", "event", "NavigationStart", "subscribe", "deselectAll", "handleCardSelection", "dataSource", "index", "maxIndex", "wasSelected", "prevDataSource", "debugLog", "selectCards", "next", "getActions", "isCardSelected", "hasOwnProperty", "from", "to", "value", "totalSelections", "i", "hasSelections", "Object", "keys", "key", "values", "item", "length", "sum", "forEach", "getSelectedCardsForSource", "ret", "k", "push", "callback", "allowedActions", "Action", "AddToReadingList", "MarkAsRead", "MarkAsUnread", "AddToCollection", "Delete", "AddToWantToReadList", "RemoveFromWantToReadList", "applyFilterToList", "getSeriesActions", "getBookmarkActions", "getSideNavStreamActions", "MarkAsInvisible", "MarkAsVisible", "getCollectionTagActions", "Promote", "UnPromote", "getReadingListActions", "getVolumeActions", "SendTo", "message", "extraData", "undefined", "console", "log", "applyFilter", "action", "hasValidAction", "Submenu", "includes", "children", "childAction", "list", "map", "a", "__spreadValues", "\u0275\u0275inject", "Router", "ActionFactoryService", "factory", "\u0275fac", "providedIn"] }