$(() => { let fullPageMediaDisplayed = false; function serializeFileSize(size) { let units = [ 'o', 'Ko', 'Mo', 'Go', 'To' ]; let idx = 0; while (size >= 800 && idx < units.length) { ++idx; size /= 1024; } size = Math.floor(size * 100) / 100; return `${size} ${units[idx]}`; } function displayMeta(key, value, isRo) { let li = document.createElement("li"); let type = value?.type || null; let val = (value?.value !== undefined ? value.value : value); if (!val && val !== '') return null; if (type === 'date') val = val.toLocaleString(); if (["dimension", "height", "width"].indexOf(key) >= 0) val += ' px'; if (["fileSize"].indexOf(key) >= 0) val = serializeFileSize(val); if (key == 'fNumber') val = `f/ ${val}`; let keyTranslate = { fileSize: "File Size", photochamberImport: "Photochamber Imported", lensModel: "Lens Model", exposureTimeStr: "Exposure Time" }; let keySpan = document.createElement('span'); let valSpan = document.createElement('div'); li.classList.add("row"); keySpan.className = "metaKey col-xl-12 col-4"; valSpan.className = "metaVal col-xl-12 col-8"; let inputGroup = document.createElement('form'); valSpan.appendChild(inputGroup); inputGroup.classList.add('input-group'); keySpan.innerText = (keyTranslate[key] || (key[0].toUpperCase()+key.substr(1))) + ':'; let valInput = document.createElement("input"); valInput.classList.add("form-control"); valInput.value = val; valInput.disabled = isRo; valInput.addEventListener('keyup', evt => evt.stopPropagation()); valInput.addEventListener('keydown', evt => evt.stopPropagation()); inputGroup.appendChild(valInput); if (!isRo) { let bt = document.createElement('button'); bt.className = 'btn btn-outline-secondary'; bt.type = 'button'; bt.innerHTML = ''; inputGroup.appendChild(bt); bt.addEventListener('click', () => MediaStorage.Instance.setMetaValue(fullPageMediaDisplayed.fixedSum, key, valInput.value)); inputGroup.addEventListener('submit', evt => { evt.preventDefault(); MediaStorage.Instance.setMetaValue(fullPageMediaDisplayed.fixedSum, key, valInput.value); }); } li.appendChild(keySpan); li.appendChild(valSpan); return li; } function displayMap(geo) { let jsonGeo = geo; try { geo = JSON.parse(geo); } catch(err) { return null; } let outerHTML = document.createElement("li"); outerHTML.className = "row"; let container = document.createElement("div"); container.className = "leaflet-container container"; outerHTML.appendChild(container); let innerHTML = document.createElement("div"); container.appendChild(innerHTML); let map = L.map(innerHTML, { scrollWheelZoom: false }).setView(geo, 13); L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(map); L.marker(geo).addTo(map); setTimeout(function () { map.invalidateSize(); }, 0); let a = document.createElement("a"); a.href = `https://www.openstreetmap.org/?mlat=${geo[0]}&mlon=${geo[1]}`; a.target = "_blank"; a.innerHTML = jsonGeo; container.appendChild(a); return outerHTML; } function displayMetas(metaData, isRo) { let metaList = document.createElement("ul"); metaData.libraryPath = null; metaData.tags = metaData.fixedTags = null; if (metaData.exposureTime && metaData.exposureTimeStr) metaData.exposureTime = null; if (metaData.date && metaData.dateTime) metaData.dateTime = null; if (metaData.height && metaData.width) { metaData.dimension = { type: "string", value: `${metaData.width.value} x ${metaData.height.value}` } metaData.height = metaData.width = null; } for (let i of [ "date", "dimension", "height", "width", "fileSize" ]) { let metaItem = displayMeta(i, metaData[i], true); metaItem && metaList.appendChild(metaItem); metaData[i] = null; } for (let i of Object.keys(metaData).sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))) { if (i === 'gpsLocation') { let dom = displayMap(metaData[i].value); dom && metaList.appendChild(dom); continue; } let metaItem = displayMeta(i, metaData[i], isRo || !MediaStorage.Instance.allMetaTypes[i]?.canWrite); metaItem && metaList.appendChild(metaItem); } if (!isRo) for (let i of ['geoCountry', 'geoCity', 'geoAdmin']) { if (!metaData[i]) { let metaItem = displayMeta(i, "", false); metaItem && metaList.appendChild(metaItem); } } return metaList; } function reloadCurrentMedia() { window.displayMediaFullPage(fullPageMediaDisplayed); } function displayTags(fixedTagList, tagList, writeAccess) { let tagListUi = document.createElement("ul"); tagListUi.className = "taglist"; let createTagUiItem = (i, roTag) => { let uiItem = document.createElement("li"); uiItem.className = "badge text-bg-light"; let textItem = document.createElement("span"); textItem.textContent = i; uiItem.appendChild(textItem); if (!roTag) { let btItem = document.createElement("a"); btItem.className = "border-start bi bi-x removeBt"; btItem.href = '#'; btItem.addEventListener('click', async e => { e.preventDefault(); await MediaStorage.Instance.removeTag(fullPageMediaDisplayed.fixedSum, i); reloadCurrentMedia(); }); uiItem.appendChild(btItem); } tagListUi.appendChild(uiItem); }; for (let i of fixedTagList) createTagUiItem(i, true); for (let i of tagList) createTagUiItem(i, !writeAccess); if (writeAccess) { let inputGroup = document.createElement('form'); tagListUi.appendChild(inputGroup); inputGroup.classList.add('input-group'); let valInput = document.createElement("input"); valInput.classList.add("form-control"); valInput.addEventListener('keyup', evt => evt.stopPropagation()); valInput.addEventListener('keydown', evt => evt.stopPropagation()); inputGroup.appendChild(valInput); let bt = document.createElement('button'); bt.className = 'btn btn-outline-secondary'; bt.type = 'button'; bt.innerHTML = ''; inputGroup.appendChild(bt); bt.addEventListener('click', async () => { await MediaStorage.Instance.addTag(fullPageMediaDisplayed.fixedSum, valInput.value); reloadCurrentMedia(); }); inputGroup.addEventListener('submit', async evt => { evt.preventDefault(); await MediaStorage.Instance.addTag(fullPageMediaDisplayed.fixedSum, valInput.value); reloadCurrentMedia(); }); } return tagListUi; } function displayDownloadBt(downloadLink) { let bt = document.createElement("button"); bt.type = "button"; bt.className = "btn btn-primary"; bt.textContent = "Download"; bt.addEventListener("click", (evt) => { let link = document.createElement('a'); link.target='_blank'; link.setAttribute("download", ""); link.href = downloadLink; link.click(); }); return bt; } function _displayMediaFullPage(fileName, imgUrl, metaData, downloadLink, writeAccess) { return new Promise(ok => { document.getElementById("pch-fullPagePreviewContainer").classList.add("loading"); document.getElementById("pch-fullPageMedia-title").innerText = fileName; document.getElementById("pch-fullPagePreview").onceLoaded = ok; document.getElementById("pch-fullPagePreview").src = imgUrl ?? ""; document.getElementById("pch-fullPageDetail").innerText = ""; if (downloadLink) document.getElementById("pch-fullPageDetail").appendChild(displayDownloadBt(downloadLink)); document.getElementById("pch-fullPageDetail").appendChild(displayTags(metaData?.fixedTags || [], metaData?.tags || [], writeAccess)); document.getElementById("pch-fullPageDetail").appendChild(displayMetas(Object.assign({}, metaData || {}), !writeAccess)); }); } function LoadPreviousMedia() { let i = fullPageMediaDisplayed; while (i = MediaStorage.Instance.previousMedia(i)) { if (window.FilterManager.match(i)) { window.displayMediaFullPage(i); break; } } } function LoadNextMedia() { let i = fullPageMediaDisplayed; while (i = MediaStorage.Instance.nextMedia(i)) { if (window.FilterManager.match(i)) { window.displayMediaFullPage(i); break; } } } function CloseFullpageMedia() { if (fullPageMediaDisplayed !== false) document.body.classList.remove("overlay-visible"); document.getElementById("pch-fullPageMedia").classList.add("hidden"); fullPageMediaDisplayed = false; history.pushState({}, '', '#'); document.Title.pop(); } window.displayMediaFullPage = function(mediaItem) { document.getElementById("pch-fullPageMedia").classList.remove("hidden"); if (fullPageMediaDisplayed) document.Title.replaceTitle(mediaItem.fixedSum); else document.Title.pushTitle(mediaItem.fixedSum); fullPageMediaDisplayed = mediaItem ?? null; document.body.classList.add("overlay-visible"); if (!mediaItem) return _displayMediaFullPage("Error", null, {}, null, false); let containerSize = document.getElementById("pch-fullPageMedia").getBoundingClientRect(); let requestSize = mediaItem.resize(containerSize.width, containerSize.height); document.getElementById("pch-fullPagePreview").parentNode.style.maxWidth = "100%"; document.getElementById("pch-fullPagePreview").parentNode.style.maxHeight = "100%"; let meta = { ...mediaItem.meta, date: { type: 'date', value: mediaItem.date } || undefined, filename: mediaItem.filename ? { type: 'string', value: mediaItem.fileName } : undefined, fixedTags: mediaItem.fixedTags, tags: mediaItem.tags }; if (document.location.hash != `#${mediaItem.fixedSum}`) history.pushState({}, '', `#${mediaItem.fixedSum}`); const requestSizeQuery = requestSize ? `&w=${requestSize.width}&h=${requestSize.height}` : ""; return _displayMediaFullPage(mediaItem.fileName, `${mediaItem.thumbnail}?q=6${requestSizeQuery}`, meta, `${mediaItem.original}?trim`, mediaItem.writeAccess); } document.getElementById("pch-fullPageMedia-closeBt") .addEventListener("click", () => CloseFullpageMedia()); document.getElementById("pch-fullPagePreview").addEventListener("load", () => { document.getElementById("pch-fullPagePreviewContainer").classList.remove("loading"); let domItem = document.getElementById("pch-fullPagePreview"); domItem.onceLoaded && domItem.onceLoaded(); domItem.onceLoaded = null; }); document.addEventListener("keydown", evt => { if (!fullPageMediaDisplayed) return; if (evt.keyCode === 37 || evt.keyCode === 38) LoadPreviousMedia(); else if (evt.keyCode === 39 || evt.keyCode === 40) LoadNextMedia(); }); document.onClosePopinRequested(() => { CloseFullpageMedia(); }); });