$(() => { var fullPageMediaDisplayed = false; var selectedThumbnails = []; var lastSelection = null; function onItemSelected(mediaItem) { document.getElementById("pch-mediaList").classList.add("selection"); } function onItemDeselected(mediaItem) { if (!selectedThumbnails.length) document.getElementById("pch-mediaList").classList.remove("selection"); } function buildThumbnail(mediaItem) { if (mediaItem.ui) return mediaItem.ui; let checkbox = document.createElement("input"); let editButton = document.createElement("button"); let img = document.createElement("img"); let container = document.createElement("li"); let loadingImg = document.createElement("div"); checkbox.type = "checkbox"; editButton.type = "button"; if (!mediaItem.writeAccess) editButton.classList.add("hidden"); let editButtonSpan = document.createElement("span"); editButtonSpan.className = "bi bi-pen"; editButton.appendChild(editButtonSpan); container.className = "pch-image loading col-12 col-md-6 col-xl-4"; loadingImg.classList.add("spinner"); loadingImg.innerHTML = ""; container.dataset.md5sum = mediaItem.md5sum; img.loading = "lazy"; let requestSize = mediaItem.resize(450, 450); requestSize = requestSize ? `w=${requestSize.width}&h=${requestSize.height}&` : ""; img.src = `${mediaItem.thumbnail}?${requestSize}q=4`; img.classList.add("img-fluid"); img.classList.add("img-thumbnail"); img.addEventListener("load", () => { container.classList.remove("loading"); container.classList.remove("spinner-grow"); }); container.style.width = `${requestSize.width}px`; container.appendChild(loadingImg); container.appendChild(img); container.appendChild(checkbox); container.appendChild(editButton); let setSelectionCheckboxValue = function(media, value) { media.ui.checkbox.checked = value; let indexInSelection = selectedThumbnails.indexOf(media.md5sum); if (value && indexInSelection < 0) { selectedThumbnails.push(media.md5sum); onItemSelected(media); return true; } else if (!value && indexInSelection >= 0) { selectedThumbnails.splice(indexInSelection, 1); onItemDeselected(media); return true; } return false; } mediaItem.setSelectionCheckboxValue = value => setSelectionCheckboxValue(mediaItem, value); let cascadeSetSelectionCheckboxValue = function(value) { if (!setSelectionCheckboxValue(mediaItem, value)) return; if (window.lastKeyboardEvent?.shiftKey && lastSelection) { let _lastKeyboardEvent = window.lastKeyboardEvent; window.lastKeyboardEvent = null; for (let i of MediaStorage.Instance.getMediaBetween(lastSelection, mediaItem)) { if (i === mediaItem) continue; i.ui.checkbox.setAttribute("checked", value); i.ui.checkbox.checked = value; setSelectionCheckboxValue(i, value); } window.lastKeyboardEvent = _lastKeyboardEvent; } lastSelection = mediaItem; } editButton.addEventListener("click", e => { e.stopPropagation(); if (!checkbox.checked) { checkbox.checked = true; setSelectionCheckboxValue(mediaItem, true); } let sel = selectedThumbnails.map(x => MediaStorage.Instance.getMediaLocal(x)).filter(x => x.writeAccess); if (sel.length === 1 && sel[0].md5sum === mediaItem.md5sum) { checkbox.checked = false; setSelectionCheckboxValue(mediaItem, false); document.location.hash = mediaItem.md5sum; return; } console.log(sel); }); container.addEventListener("click", () => { if (selectedThumbnails.length || window.lastKeyboardEvent?.ctrlKey) { let value = !checkbox.checked; checkbox.setAttribute("checked", value); checkbox.checked = value; cascadeSetSelectionCheckboxValue(value); return; } document.location.hash = mediaItem.md5sum; }); checkbox.addEventListener("click", evt => { evt.stopPropagation(); }); checkbox.addEventListener("change", evt => { cascadeSetSelectionCheckboxValue(checkbox.checked); }); return mediaItem.ui = { root: container, img: img, checkbox: checkbox }; } function buildYear(date) { let result = document.createElement('h3'); result.className = "col-12"; result.textContent = date.getUTCFullYear(); return result; } function buildMonth(date) { let result = document.createElement('h4'); result.className = "col-12"; result.textContent = date.toLocaleString('default', { month: 'long' }); return result; } let lastItemDisplayed = null; let displayedItemCount = 0; const displayItemBatchCount = 15; let targetDisplayedItems = displayItemBatchCount; function redraw(container, media) { buildThumbnail(media); if (!media.ui) return; let yearUpdated = !container.dataset.lastItemYear || container.dataset.lastItemYear != media.date.getUTCFullYear(); if (yearUpdated) { container.appendChild(buildYear(media.date)); container.dataset.lastItemYear = media.date.getUTCFullYear(); } if (yearUpdated || container.dataset.lastItemMonth === undefined || container.dataset.lastItemMonth != media.date.getUTCMonth()) { container.appendChild(buildMonth(media.date)); container.dataset.lastItemMonth = media.date.getUTCMonth(); } container.appendChild(media.ui.root); lastItemDisplayed = media; displayedItemCount++; } MediaStorage.Instance.addEventListener("rebuildMedia", (evt) => { let newContainer = document.getElementById('pch-mediaList'); newContainer.textContent = ''; newContainer.dataset.lastItemYear = null; newContainer.dataset.lastItemMonth = null; lastItemDisplayed = null; displayedItemCount = 0; targetDisplayedItems = displayItemBatchCount; for (let i of selectedThumbnails) { let media = MediaStorage.Instance.getMediaLocal(i); media?.setSelectionCheckboxValue(false); } lastSelection = null; for (let i of MediaStorage.Instance.medias) if (window.FilterManager.match(i)) { redraw(newContainer, i); if (displayedItemCount >= targetDisplayedItems) break; } }); MediaStorage.Instance.addEventListener("newMedia", (evt) => { if (displayedItemCount < targetDisplayedItems && window.FilterManager.match(evt.detail)) { let container = document.getElementById('pch-mediaList'); redraw(container, evt.detail); } }); window.displayMoreMedia = () => { targetDisplayedItems += displayItemBatchCount; let container = document.getElementById('pch-mediaList'); for (let index = lastItemDisplayed ? (MediaStorage.Instance.getMediaIndex(lastItemDisplayed) +1) : 0; displayedItemCount < targetDisplayedItems; ++index) { let media = MediaStorage.Instance.medias[index]; if (!media) return; if (window.FilterManager.match(media)) redraw(container, media); } } });