f7cloud_client/apps/photos/js/FilesSelectionMixin-JLsUiKnU.chunk.mjs.map
root 8b6a0139db f7cloud_client
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 22:59:26 +00:00

1 line
34 KiB
Plaintext

{"version":3,"file":"FilesSelectionMixin-JLsUiKnU.chunk.mjs","sources":["../src/services/TiledLayout.ts","../src/components/TiledLayout/TiledLayout.vue","../src/components/VirtualScrolling.vue","../src/components/FilesListViewer.vue","../src/mixins/FilesSelectionMixin.ts"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nexport type TiledItem = {\n\tid: string // Unique id for the item.\n\twidth: number // Real width of the item.\n\theight: number // Real height of the item.\n\tratio: number // The aspect ratio of the item.\n}\n\nexport type Section = {\n\tid: string // Unique id for the section.\n\titems: TiledItem[] // Real width of the item.\n}\n\nexport type TiledRow = {\n\titems: TiledItem[] // List of item in the row.\n\theight: number // Height of the row.\n\tkey: string // Unique key for the row.\n}\n\nexport type TiledSection = Section & {\n\tkey: string // Unique key for the section.\n\trows: TiledRow[] // Real width of the item.\n\theight: number // Height of the section.\n}\n\n/**\n * Split items in rows of equal width.\n * The last row will not be forced to match containerWidth.\n *\n * @param items\n * @param containerWidth\n * @param baseHeight\n */\nexport function splitItemsInRows(items: TiledItem[], containerWidth: number, baseHeight: number = 200): TiledRow[] {\n\tif (containerWidth === 0) {\n\t\treturn []\n\t}\n\n\tconst rows: TiledRow[] = []\n\tlet rowNumber = 0\n\tlet currentItem = 0\n\n\twhile (currentItem < items.length) {\n\t\tconst rowItems: TiledItem[] = []\n\n\t\t// Fill the row with new items as long as the width is less than containerWidth.\n\t\tdo {\n\t\t\trowItems.push(items[currentItem++])\n\t\t} while (\n\t\t\tcurrentItem < items.length\n\t\t\t&& computeRowWidth([...rowItems, items[currentItem]], baseHeight) <= containerWidth\n\t\t)\n\n\t\tconst rowHeight = computeRowHeight(\n\t\t\trowItems,\n\t\t\tcontainerWidth,\n\t\t\titems.length === currentItem,\n\t\t\tbaseHeight,\n\t\t)\n\n\t\trows[rowNumber] = {\n\t\t\titems: rowItems.map((item) => ({ ...item, width: rowHeight * item.ratio, height: rowHeight })),\n\t\t\t// Key to help vue to keep track of the row in VirtualScrolling.\n\t\t\theight: rowHeight,\n\t\t\tkey: rowItems.map((item) => item.id).join('-'),\n\t\t}\n\n\t\trowNumber += 1\n\t}\n\n\treturn rows\n}\n\n/**\n *\n * @param items\n * @param baseHeight\n */\nfunction computeRowWidth(items: TiledItem[], baseHeight: number): number {\n\treturn items\n\t\t.map((item) => baseHeight * item.ratio)\n\t\t.reduce((sum, itemWidth) => sum + itemWidth)\n}\n\n/**\n * Compute the row height based on its items and on the container's width.\n *\n * Math time !\n * With Rn the aspect ratio of item n\n * Wn the width of item n\n * Hn the height of item n\n * Wc the width of the container\n * Hr the height of the row\n * For n items we want: Wc = W1 + W2 + ... + Wn\n * We know Rn = Wn / Hn\n * So Wn = Rn * Hn\n * So Wc = (R1 * H1) + (R2 * H2) + ... + (Rn * Hn)\n * But we also want Hr === H1 === H2 === ... === Hn\n * So Wc = (R1 * Hr) + (R2 * Hr) + ... + (Rn * Hr)\n * So Wc = Hr * (R1 + R2 + ... + Rn)\n * So Hr = Wc / (R1 + R2 + ... + Rn)\n *\n * @param items\n * @param containerWidth\n * @param isLastRow\n * @param baseHeight\n */\nfunction computeRowHeight(items: TiledItem[], containerWidth: number, isLastRow: boolean, baseHeight: number): number {\n\tconst sumOfItemsRatio = items\n\t\t.map((item) => item.ratio)\n\t\t.reduce((sum, itemRatio) => sum + itemRatio)\n\n\tlet rowHeight = containerWidth / sumOfItemsRatio\n\n\t// Exception 1: there is only one item which is larger than containerWidth.\n\t// Limit its height so that itemWidth === containerWidth\n\tif (items.length === 1 && items[0].width > containerWidth) {\n\t\trowHeight = containerWidth / items[0].ratio\n\t}\n\n\t// Exception 2: we reached the last row.\n\t// Force the items width to match containerWidth, and limit their height to baseHeight + 20.\n\tif (isLastRow) {\n\t\trowHeight = Math.min(baseHeight + 20, rowHeight)\n\t}\n\n\treturn rowHeight\n}\n","<!--\n - SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<div\n\t\tref=\"tiledLayoutContainer\"\n\t\tclass=\"tiled-container\">\n\t\t<!-- Slot to allow changing the rows before passing them to TiledRows -->\n\t\t<!-- Useful for partially rendering rows like with VirtualScrolling -->\n\t\t<slot :tiled-sections=\"tiledSections\">\n\t\t\t<!-- Default rendering -->\n\t\t\t<TiledRows :rows=\"tiledSections\" />\n\t\t</slot>\n\t</div>\n</template>\n\n<script lang='ts'>\nimport type { PropType } from 'vue'\n\nimport TiledRows from './TiledRows.vue'\nimport logger from '../../services/logger.js'\nimport {\n\ttype Section, type TiledSection,\n\n\tsplitItemsInRows,\n} from '../../services/TiledLayout.js'\n\nexport default {\n\tname: 'TiledLayout',\n\n\tcomponents: {\n\t\tTiledRows,\n\t},\n\n\tprops: {\n\t\tsections: {\n\t\t\ttype: Array as PropType<Section[]>,\n\t\t\trequired: true,\n\t\t},\n\n\t\tbaseHeight: {\n\t\t\ttype: Number,\n\t\t\tdefault: 200,\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tcontainerWidth: 0,\n\t\t\tresizeObserver: null as ResizeObserver | null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\ttiledSections(): TiledSection[] {\n\t\t\tlogger.debug('[TiledLayout] Computing rows', { items: this.sections })\n\n\t\t\treturn this.sections.map((section) => {\n\t\t\t\tconst rows = splitItemsInRows(section.items, this.containerWidth, this.baseHeight)\n\t\t\t\treturn {\n\t\t\t\t\t...section,\n\t\t\t\t\tkey: section.id,\n\t\t\t\t\trows: rows.map((row) => ({ ...row, sectionKey: section.id })),\n\t\t\t\t\theight: rows.reduce((totalHeight, row) => totalHeight + row.height, 0),\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.resizeObserver = new ResizeObserver((entries) => {\n\t\t\tfor (const entry of entries) {\n\t\t\t\tconst cr = entry.contentRect\n\t\t\t\tif (entry.target.classList.contains('tiled-container')) {\n\t\t\t\t\tthis.containerWidth = cr.width\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\n\t\tthis.resizeObserver.observe(this.$refs.tiledLayoutContainer as Element)\n\t},\n\n\tbeforeDestroy() {\n\t\tthis.resizeObserver?.disconnect()\n\t},\n}\n</script>\n\n<style scoped lang=\"scss\">\n.tiled-container {\n\theight: 100%;\n\n\t.tiled-row {\n\t\tdisplay: flex;\n\t}\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<div v-if=\"!useWindow && containerElement === null\" ref=\"container\" class=\"vs-container\">\n\t\t<div\n\t\t\tref=\"rowsContainer\"\n\t\t\tclass=\"vs-rows-container\"\n\t\t\t:style=\"rowsContainerStyle\">\n\t\t\t<slot :visible-sections=\"visibleSections\" />\n\t\t\t<slot name=\"loader\" />\n\t\t</div>\n\t</div>\n\t<div\n\t\tv-else\n\t\tref=\"rowsContainer\"\n\t\tclass=\"vs-rows-container\"\n\t\t:style=\"rowsContainerStyle\">\n\t\t<slot :visible-sections=\"visibleSections\" />\n\t\t<slot name=\"loader\" />\n\t</div>\n</template>\n\n<script lang='ts'>\nimport type { PropType } from 'vue'\n\nimport logger from '../services/logger.js'\n\nexport type Row = {\n\tkey: string // Unique key for the row.\n\theight: number // The height of the row.\n\tsectionKey: string // Unique key for the row.\n}\n\nexport type VisibleRow = Row & {\n\tdistance: number // The distance from the visible viewport\n}\n\nexport type Section = {\n\tid: string // Unique key for the section.\n\trows: Row[] // The height of the row.\n\theight: number // Height of the section, excluding the header.\n}\n\nexport type VisibleSection = Section & {\n\trows: VisibleRow[] // The height of the row.\n}\n\nexport default {\n\tname: 'VirtualScrolling',\n\n\tprops: {\n\t\tsections: {\n\t\t\ttype: Array as PropType<Section[]>,\n\t\t\trequired: true,\n\t\t},\n\n\t\tcontainerElement: {\n\t\t\ttype: HTMLElement,\n\t\t\tdefault: null,\n\t\t},\n\n\t\tuseWindow: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\theaderHeight: {\n\t\t\ttype: Number,\n\t\t\tdefault: 75,\n\t\t},\n\n\t\trenderDistance: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0.5,\n\t\t},\n\n\t\tbottomBufferRatio: {\n\t\t\ttype: Number,\n\t\t\tdefault: 2,\n\t\t},\n\n\t\tscrollToKey: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tscrollPosition: 0,\n\t\t\tcontainerHeight: 0,\n\t\t\trowsContainerHeight: 0,\n\t\t\tresizeObserver: null as ResizeObserver | null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tvisibleSections(): VisibleSection[] {\n\t\t\tlogger.debug('[VirtualScrolling] Computing visible section', { sections: this.sections })\n\n\t\t\t// Optimisation: get those computed properties once to not go through vue's internal every time we need them.\n\t\t\tconst containerHeight = this.containerHeight\n\t\t\tconst containerTop = this.scrollPosition\n\t\t\tconst containerBottom = containerTop + containerHeight\n\n\t\t\tlet currentRowTop = 0\n\t\t\tlet currentRowBottom = 0\n\n\t\t\t// Compute whether a row should be included in the DOM (shouldRender)\n\t\t\t// And how visible the row is.\n\t\t\tconst visibleSections = this.sections\n\t\t\t\t.map((section) => {\n\t\t\t\t\tcurrentRowBottom += this.headerHeight\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...section,\n\t\t\t\t\t\trows: section.rows.reduce((visibleRows, row) => {\n\t\t\t\t\t\t\tcurrentRowTop = currentRowBottom\n\t\t\t\t\t\t\tcurrentRowBottom += row.height\n\n\t\t\t\t\t\t\tlet distance = 0\n\n\t\t\t\t\t\t\tif (currentRowBottom < containerTop) {\n\t\t\t\t\t\t\t\tdistance = (containerTop - currentRowBottom) / containerHeight\n\t\t\t\t\t\t\t} else if (currentRowTop > containerBottom) {\n\t\t\t\t\t\t\t\tdistance = (currentRowTop - containerBottom) / containerHeight\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (distance > this.renderDistance) {\n\t\t\t\t\t\t\t\treturn visibleRows\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\t\t...visibleRows,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t...row,\n\t\t\t\t\t\t\t\t\tdistance,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}, [] as VisibleRow[]),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.filter((section) => section.rows.length > 0)\n\n\t\t\t// To allow vue to recycle the DOM elements instead of adding and deleting new ones,\n\t\t\t// we assign a random key to each items. When a item removed, we recycle its key for new items,\n\t\t\t// so vue can replace the content of removed DOM elements with the content of new items, but keep the other DOM elements untouched.\n\t\t\tconst visibleItems = visibleSections\n\t\t\t\t.flatMap(({ rows }) => rows)\n\t\t\t\t.flatMap(({ items }) => items)\n\n\t\t\tvisibleItems.forEach((item) => (item.key = this.rowIdToKeyMap[item.id]))\n\n\t\t\tconst usedTokens = visibleItems\n\t\t\t\t.map(({ key }) => key)\n\t\t\t\t.filter((key) => key !== undefined)\n\n\t\t\tconst unusedTokens = Object.values(this.rowIdToKeyMap).filter((key) => !usedTokens.includes(key))\n\n\t\t\tvisibleItems\n\t\t\t\t.filter(({ key }) => key === undefined)\n\t\t\t\t.forEach((item) => (item.key = unusedTokens.pop() ?? Math.random().toString(36).substr(2)))\n\n\t\t\t// this.rowIdToKeyMap is created in the beforeCreate hook, so value changes are not tracked.\n\t\t\t// Therefore, we wont trigger the computation of visibleSections again if we alter the value of this.rowIdToKeyMap.\n\t\t\t// eslint-disable-next-line vue/no-side-effects-in-computed-properties\n\t\t\tthis.rowIdToKeyMap = visibleItems.reduce((finalMapping, { id, key }) => ({ ...finalMapping, [`${id}`]: key }), {})\n\n\t\t\treturn visibleSections\n\t\t},\n\n\t\t/**\n\t\t * Total height of all the rows + some room for the loader.\n\t\t */\n\t\ttotalHeight(): number {\n\t\t\tconst loaderHeight = 200\n\n\t\t\treturn this.sections\n\t\t\t\t.map((section) => this.headerHeight + section.height)\n\t\t\t\t.reduce((totalHeight, sectionHeight) => totalHeight + sectionHeight, 0) + loaderHeight\n\t\t},\n\n\t\tpaddingTop(): number {\n\t\t\tif (this.visibleSections.length === 0) {\n\t\t\t\treturn 0\n\t\t\t}\n\n\t\t\tlet paddingTop = 0\n\n\t\t\tfor (const section of this.sections) {\n\t\t\t\tif (section.key !== this.visibleSections[0].rows[0].sectionKey) {\n\t\t\t\t\tpaddingTop += this.headerHeight + section.height\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tfor (const row of section.rows) {\n\t\t\t\t\tif (row.key === this.visibleSections[0].rows[0].key) {\n\t\t\t\t\t\treturn paddingTop\n\t\t\t\t\t}\n\n\t\t\t\t\tpaddingTop += row.height\n\t\t\t\t}\n\n\t\t\t\tpaddingTop += this.headerHeight\n\t\t\t}\n\n\t\t\treturn paddingTop\n\t\t},\n\n\t\t/**\n\t\t * padding-top is used to replace not included item in the container.\n\t\t */\n\t\trowsContainerStyle(): { height: string, paddingTop: string } {\n\t\t\treturn {\n\t\t\t\theight: `${this.totalHeight}px`,\n\t\t\t\tpaddingTop: `${this.paddingTop}px`,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether the user is near the bottom.\n\t\t * If true, then the need-content event will be emitted.\n\t\t */\n\t\tisNearBottom(): boolean {\n\t\t\tconst buffer = this.containerHeight * this.bottomBufferRatio\n\t\t\treturn this.scrollPosition + this.containerHeight >= this.totalHeight - buffer\n\t\t},\n\n\t\tcontainer(): HTMLElement | Window {\n\t\t\tlogger.debug('[VirtualScrolling] Computing container')\n\t\t\tif (this.containerElement !== null) {\n\t\t\t\treturn this.containerElement\n\t\t\t} else if (this.useWindow) {\n\t\t\t\treturn window\n\t\t\t} else {\n\t\t\t\treturn this.$refs.container as HTMLElement\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\tisNearBottom(value) {\n\t\t\tlogger.debug('[VirtualScrolling] isNearBottom changed', { value })\n\t\t\tif (value) {\n\t\t\t\tthis.$emit('need-content')\n\t\t\t}\n\t\t},\n\n\t\tvisibleSections() {\n\t\t\t// Re-emit need-content when rows is updated and isNearBottom is still true.\n\t\t\t// If the height of added rows is under `bottomBufferRatio`, `isNearBottom` will still be true so we need more content.\n\t\t\tif (this.isNearBottom) {\n\t\t\t\tthis.$emit('need-content')\n\t\t\t}\n\t\t},\n\n\t\tscrollToKey(key) {\n\t\t\tlet currentRowTopDistanceFromTop = 0\n\n\t\t\tfor (const section of this.sections) {\n\t\t\t\tif (section.key !== key) {\n\t\t\t\t\tcurrentRowTopDistanceFromTop += this.headerHeight + section.height\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tlogger.debug('[VirtualScrolling] Scrolling to', { currentRowTopDistanceFromTop })\n\t\t\t;(this.$refs.container as Element).scrollTo({ top: currentRowTopDistanceFromTop, behavior: 'smooth' })\n\t\t},\n\t},\n\n\tbeforeCreate() {\n\t\tthis.rowIdToKeyMap = {}\n\t},\n\n\tmounted() {\n\t\tthis.resizeObserver = new ResizeObserver((entries) => {\n\t\t\tfor (const entry of entries) {\n\t\t\t\tconst cr = entry.contentRect\n\t\t\t\tif (entry.target === this.container) {\n\t\t\t\t\tthis.containerHeight = cr.height\n\t\t\t\t}\n\t\t\t\tif (entry.target.classList.contains('vs-rows-container')) {\n\t\t\t\t\tthis.rowsContainerHeight = cr.height\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\n\t\tif (this.useWindow) {\n\t\t\twindow.addEventListener('resize', this.updateContainerSize, { passive: true })\n\t\t\tthis.containerHeight = window.innerHeight\n\t\t} else {\n\t\t\tthis.resizeObserver.observe(this.container as Element)\n\t\t}\n\n\t\tthis.resizeObserver.observe(this.$refs.rowsContainer as Element)\n\t\tthis.container?.addEventListener('scroll', this.updateScrollPosition, { passive: true })\n\t},\n\n\tbeforeDestroy() {\n\t\tif (this.useWindow) {\n\t\t\twindow.removeEventListener('resize', this.updateContainerSize)\n\t\t}\n\n\t\tthis.resizeObserver?.disconnect()\n\t\tthis.container?.removeEventListener('scroll', this.updateScrollPosition)\n\t},\n\n\tmethods: {\n\t\tupdateScrollPosition() {\n\t\t\tthis._onScrollHandle ??= requestAnimationFrame(() => {\n\t\t\t\tthis._onScrollHandle = null\n\t\t\t\tif (this.useWindow) {\n\t\t\t\t\tthis.scrollPosition = (this.container as Window).scrollY\n\t\t\t\t} else {\n\t\t\t\t\tthis.scrollPosition = (this.container as HTMLElement).scrollTop\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\tupdateContainerSize() {\n\t\t\tthis.containerHeight = window.innerHeight\n\t\t},\n\t},\n}\n</script>\n\n<style scoped lang=\"scss\">\n.vs-container {\n\toverflow-y: scroll;\n\theight: 100%;\n}\n\n.vs-rows-container {\n\tbox-sizing: border-box;\n\twill-change: scroll-position, padding;\n\tcontain: layout paint style;\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<div class=\"files-list-viewer\">\n\t\t<NcEmptyContent\n\t\t\tv-if=\"emptyMessage !== '' && photosCount === 0 && !loading\"\n\t\t\tkey=\"emptycontent\"\n\t\t\t:name=\"emptyMessage\">\n\t\t\t<PackageVariant slot=\"icon\" />\n\t\t</NcEmptyContent>\n\n\t\t<TiledLayout :base-height=\"baseHeight\" :sections=\"itemsBySections\">\n\t\t\t<VirtualScrolling\n\t\t\t\tslot-scope=\"{ tiledSections }\"\n\t\t\t\t:use-window=\"useWindow\"\n\t\t\t\t:container-element=\"containerElement\"\n\t\t\t\t:sections=\"tiledSections\"\n\t\t\t\t:scroll-to-key=\"scrollToSection\"\n\t\t\t\t:header-height=\"sectionHeaderHeight\"\n\t\t\t\t@need-content=\"needContent\">\n\t\t\t\t<template slot-scope=\"{ visibleSections }\">\n\t\t\t\t\t<div v-for=\"section of visibleSections\" :key=\"section.id\">\n\t\t\t\t\t\t<template v-if=\"section.id !== ''\">\n\t\t\t\t\t\t\t<!-- Placeholder when initial loading -->\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tv-if=\"showPlaceholders\"\n\t\t\t\t\t\t\t\tclass=\"files-list-viewer__placeholder\"\n\t\t\t\t\t\t\t\t:style=\"{ 'flex-basis': '100%', height: `${sectionHeaderHeight}px` }\" />\n\t\t\t\t\t\t\t<!-- Real file. -->\n\t\t\t\t\t\t\t<slot\n\t\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\t\t:file=\"{ id: section.id }\"\n\t\t\t\t\t\t\t\t:is-header=\"true\"\n\t\t\t\t\t\t\t\tclass=\"files-list-viewer__section-header\"\n\t\t\t\t\t\t\t\t:style=\"{ 'flex-basis': '100%', height: `${sectionHeaderHeight}px` }\" />\n\t\t\t\t\t\t</template>\n\n\t\t\t\t\t\t<ul>\n\t\t\t\t\t\t\t<template v-for=\"(row, rowIndex) of section.rows\">\n\t\t\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\t\t\tWe are subtracting 1 from flex-basis to compensate for rounding issues.\n\t\t\t\t\t\t\t\t\tThe flex algo will then compensate with flex-grow.\n\t\t\t\t\t\t\t\t\t'last-tiled-row' prevents the last row's items from growing.\n\t\t\t\t\t\t\t\t-->\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tv-for=\"item of row.items\"\n\t\t\t\t\t\t\t\t\t:key=\"item.key\"\n\t\t\t\t\t\t\t\t\t:class=\"{ 'last-tiled-rows': rowIndex === section.rows.length - 1 }\"\n\t\t\t\t\t\t\t\t\t:style=\"{ 'flex-basis': `${item.width - 1}px`, height: `${item.height}px` }\">\n\t\t\t\t\t\t\t\t\t<!-- Placeholder when initial loading -->\n\t\t\t\t\t\t\t\t\t<div v-if=\"showPlaceholders\" class=\"files-list-viewer__placeholder\" />\n\t\t\t\t\t\t\t\t\t<!-- Real file. -->\n\t\t\t\t\t\t\t\t\t<slot v-else :file=\"item\" :distance=\"row.distance\" />\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</div>\n\t\t\t\t</template>\n\t\t\t\t<NcLoadingIcon v-if=\"loading && !showPlaceholders\" slot=\"loader\" class=\"files-list-viewer__loader\" />\n\t\t\t</VirtualScrolling>\n\t\t</TiledLayout>\n\t</div>\n</template>\n\n<script lang='ts'>\nimport type { File } from '@nextcloud/files'\nimport type { PropType } from 'vue'\nimport type { TiledItem } from '../services/TiledLayout.ts'\nimport type { PhotoFile } from '../store/files.ts'\n\nimport { subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'\nimport NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'\nimport PackageVariant from 'vue-material-design-icons/PackageVariant.vue'\nimport TiledLayout from '../components/TiledLayout/TiledLayout.vue'\nimport VirtualScrolling from '../components/VirtualScrolling.vue'\nimport { fetchFile } from '../services/fileFetcher.ts'\n\nexport default {\n\tname: 'FilesListViewer',\n\n\tcomponents: {\n\t\tPackageVariant,\n\t\tNcEmptyContent,\n\t\tNcLoadingIcon,\n\t\tTiledLayout,\n\t\tVirtualScrolling,\n\t},\n\n\tprops: {\n\t\t// Array of file ids that should be rendered.\n\t\tfileIds: {\n\t\t\ttype: Array as PropType<string[]>,\n\t\t\tdefault: undefined,\n\t\t},\n\n\t\t// An object mapping a list of section to a list of fileIds.\n\t\tfileIdsBySection: {\n\t\t\ttype: Object as PropType<Record<string, string[]>>,\n\t\t\tdefault: undefined,\n\t\t},\n\n\t\t// The list of sorted sections.\n\t\tsections: {\n\t\t\ttype: Array as PropType<string[]>,\n\t\t\tdefault: undefined,\n\t\t},\n\n\t\t// Whether we should display a loading indicator.\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t// Message to display when there is no files.\n\t\temptyMessage: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t// The base height to forward to TileLayout.\n\t\tbaseHeight: {\n\t\t\ttype: Number,\n\t\t\tdefault: 200,\n\t\t},\n\n\t\t// The height to use for section headers.\n\t\tsectionHeaderHeight: {\n\t\t\ttype: Number,\n\t\t\tdefault: 75,\n\t\t},\n\n\t\t// Instruct VirtualScrolling to scroll to the given section id.\n\t\tscrollToSection: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t// The containerElement props to forward to TileLayout.\n\t\tcontainerElement: {\n\t\t\ttype: [HTMLElement, null],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t// The useWindow props to forward to TileLayout.\n\t\tuseWindow: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tplaceholderFiles: Array(20).fill(0).map((_, index) => {\n\t\t\t\tconst height = 200\n\t\t\t\tconst width = this.croppedLayout ? height : height * (1 + Math.random() * 2)\n\t\t\t\treturn {\n\t\t\t\t\tid: index.toString(),\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\tratio: width / height,\n\t\t\t\t}\n\t\t\t}),\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tfiles(): Record<string, PhotoFile> {\n\t\t\treturn this.$store.state.files.files\n\t\t},\n\n\t\tshowPlaceholders(): boolean {\n\t\t\treturn this.loading && (this.fileIds?.length === 0 || this.sections?.length === 0)\n\t\t},\n\n\t\titemsBySections(): { id: string, items: TiledItem[] }[] {\n\t\t\tif (this.fileIds !== undefined) {\n\t\t\t\tif (this.showPlaceholders) {\n\t\t\t\t\treturn [{ id: '', items: this.placeholderFiles }]\n\t\t\t\t}\n\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: '',\n\t\t\t\t\t\titems: this.fileIds\n\t\t\t\t\t\t\t.filter((fileId) => this.files[fileId])\n\t\t\t\t\t\t\t.map(this.mapFileToItem),\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t}\n\n\t\t\tif (this.sections !== undefined) {\n\t\t\t\tif (this.showPlaceholders) {\n\t\t\t\t\treturn [{ id: 'placeholder', items: this.placeholderFiles }]\n\t\t\t\t}\n\n\t\t\t\treturn this.sections.map((sectionId) => {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tid: sectionId,\n\t\t\t\t\t\titems: this.fileIdsBySection[sectionId]\n\t\t\t\t\t\t\t.filter((fileId) => this.files[fileId])\n\t\t\t\t\t\t\t.map(this.mapFileToItem),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\n\t\t\treturn []\n\t\t},\n\n\t\tphotosCount(): number {\n\t\t\treturn this.itemsBySections.map(({ items }) => items.length).reduce((total, length) => total + length, 0)\n\t\t},\n\n\t\tshowLoader(): boolean {\n\t\t\treturn this.loading && (this.fileIds?.length !== 0 || this.sections?.length !== 0)\n\t\t},\n\n\t\tcroppedLayout(): boolean {\n\t\t\treturn this.$store.state.userConfig.croppedLayout\n\t\t},\n\t},\n\n\tmounted() {\n\t\tsubscribe('files:node:updated', this.handleFileUpdated)\n\t\tsubscribe('files:node:deleted', this.handleFileDeleted)\n\t},\n\n\tdestroyed() {\n\t\tunsubscribe('files:node:updated', this.handleFileUpdated)\n\t\tunsubscribe('files:node:deleted', this.handleFileDeleted)\n\t},\n\n\tmethods: {\n\t\t// Ask the parent for more content.\n\t\tneedContent(): void {\n\t\t\tthis.$emit('need-content')\n\t\t},\n\n\t\tmapFileToItem(fileId: string): TiledItem {\n\t\t\tconst file = this.files[fileId] as File\n\t\t\treturn {\n\t\t\t\tid: file.fileid?.toString() as string,\n\t\t\t\twidth: file.attributes['metadata-photos-size'].width,\n\t\t\t\theight: file.attributes['metadata-photos-size'].height,\n\t\t\t\tratio: this.croppedLayout ? 1 : file.attributes['metadata-photos-size'].width / file.attributes['metadata-photos-size'].height,\n\t\t\t}\n\t\t},\n\n\t\tasync handleFileUpdated({ fileid }: File): Promise<void> {\n\t\t\tconst fetchedFile = await fetchFile(this.files[fileid as number].path)\n\t\t\tthis.$store.dispatch('appendFiles', [fetchedFile])\n\t\t},\n\n\t\thandleFileDeleted({ fileid }: File) {\n\t\t\tthis.$store.commit('deleteFile', fileid)\n\t\t},\n\t},\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.files-list-viewer {\n\theight: 100%;\n\tposition: relative;\n\n\t&__placeholder {\n\t\tbackground: var(--color-primary-element-light);\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tborder: 2px solid var(--color-main-background); // Use border so create a separation between images.\n\t}\n\n\t.tiled-container {\n\t\tflex-basis: 0;\n\t}\n\n\tul {\n\t\tdisplay: flex;\n\t\tflex-wrap: wrap;\n\n\t\tli:not(.last-tiled-rows) {\n\t\t\tflex-grow: 1;\n\t\t}\n\t}\n\n\t&__section-header {\n\t\tposition: sticky;\n\t\ttop: 0;\n\t\tz-index: 3;\n\t\tbackground: var(--color-main-background);\n\t}\n\n\t&__loader {\n\t\tmargin: 50px 0;\n\t}\n}\n</style>\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { defineComponent } from 'vue'\n\nexport default defineComponent({\n\tname: 'FilesSelectionMixin',\n\n\tdata() {\n\t\treturn {\n\t\t\tselection: {} as Record<string, boolean>,\n\t\t}\n\t},\n\n\twatch: {\n\t\t$route() {\n\t\t\tthis.resetSelection()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tonFileSelectToggle({ id, value }): void {\n\t\t\tthis.$set(this.selection, id, value)\n\t\t},\n\n\t\tonUncheckFiles(filesIds: string[]): void {\n\t\t\tfilesIds.forEach((filesId: string) => this.$set(this.selection, filesId, false))\n\t\t},\n\n\t\tresetSelection(): void {\n\t\t\tthis.selection = {}\n\t\t},\n\t},\n\n\tcomputed: {\n\t\tselectedFileIds(): string[] {\n\t\t\treturn Object.keys(this.selection).filter((fileId) => this.selection[fileId])\n\t\t},\n\t},\n})\n"],"names":["splitItemsInRows","items","containerWidth","baseHeight","rows","rowNumber","currentItem","rowItems","computeRowWidth","rowHeight","computeRowHeight","item","sum","itemWidth","isLastRow","sumOfItemsRatio","itemRatio","_sfc_main$2","TiledRows","logger","section","row","totalHeight","entries","entry","cr","_sfc_main$1","containerHeight","containerTop","containerBottom","currentRowTop","currentRowBottom","visibleSections","visibleRows","distance","visibleItems","usedTokens","key","unusedTokens","finalMapping","id","sectionHeight","paddingTop","buffer","value","currentRowTopDistanceFromTop","_sfc_main","PackageVariant","NcEmptyContent","NcLoadingIcon","TiledLayout","VirtualScrolling","_","index","width","fileId","sectionId","total","length","subscribe","unsubscribe","file","fileid","fetchedFile","fetchFile","FilesSelectionMixin","defineComponent","filesIds","filesId"],"mappings":"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"}