1
0

uiMediaFullpage.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. $(() => {
  2. let fullPageMediaDisplayed = false;
  3. function serializeFileSize(size) {
  4. let units = [ 'o', 'Ko', 'Mo', 'Go', 'To' ];
  5. let idx = 0;
  6. while (size >= 800 && idx < units.length) {
  7. ++idx;
  8. size /= 1024;
  9. }
  10. size = Math.floor(size * 100) / 100;
  11. return `${size} ${units[idx]}`;
  12. }
  13. function displayMeta(key, value, isRo) {
  14. let li = document.createElement("li");
  15. let type = value?.type || null;
  16. let val = (value?.value !== undefined ? value.value : value);
  17. if (!val && val !== '')
  18. return null;
  19. if (type === 'date')
  20. val = val.toLocaleString();
  21. if (["dimension", "height", "width"].indexOf(key) >= 0)
  22. val += ' px';
  23. if (["fileSize"].indexOf(key) >= 0)
  24. val = serializeFileSize(val);
  25. if (key == 'fNumber')
  26. val = `f/ ${val}`;
  27. let keyTranslate = {
  28. fileSize: "File Size",
  29. photochamberImport: "Photochamber Imported",
  30. lensModel: "Lens Model",
  31. exposureTimeStr: "Exposure Time"
  32. };
  33. let keySpan = document.createElement('span');
  34. let valSpan = document.createElement('div');
  35. li.classList.add("row");
  36. keySpan.className = "metaKey col-xl-12 col-4";
  37. valSpan.className = "metaVal col-xl-12 col-8";
  38. let inputGroup = document.createElement('form');
  39. valSpan.appendChild(inputGroup);
  40. inputGroup.classList.add('input-group');
  41. keySpan.innerText = (keyTranslate[key] || (key[0].toUpperCase()+key.substr(1))) + ':';
  42. let valInput = document.createElement("input");
  43. valInput.classList.add("form-control");
  44. valInput.value = val;
  45. valInput.disabled = isRo;
  46. valInput.addEventListener('keyup', evt => evt.stopPropagation());
  47. valInput.addEventListener('keydown', evt => evt.stopPropagation());
  48. inputGroup.appendChild(valInput);
  49. if (!isRo) {
  50. let bt = document.createElement('button');
  51. bt.className = 'btn btn-outline-secondary';
  52. bt.type = 'button';
  53. bt.innerHTML = '<i class="bi bi-pen"></i>';
  54. inputGroup.appendChild(bt);
  55. bt.addEventListener('click', () => MediaStorage.Instance.setMetaValue(fullPageMediaDisplayed.fixedSum, key, valInput.value));
  56. inputGroup.addEventListener('submit', evt => {
  57. evt.preventDefault();
  58. MediaStorage.Instance.setMetaValue(fullPageMediaDisplayed.fixedSum, key, valInput.value);
  59. });
  60. }
  61. li.appendChild(keySpan);
  62. li.appendChild(valSpan);
  63. return li;
  64. }
  65. function displayMap(geo) {
  66. let jsonGeo = geo;
  67. try {
  68. geo = JSON.parse(geo);
  69. }
  70. catch(err) { return null; }
  71. let outerHTML = document.createElement("li");
  72. outerHTML.className = "row";
  73. let container = document.createElement("div");
  74. container.className = "leaflet-container container";
  75. outerHTML.appendChild(container);
  76. let innerHTML = document.createElement("div");
  77. container.appendChild(innerHTML);
  78. let map = L.map(innerHTML, { scrollWheelZoom: false }).setView(geo, 13);
  79. L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
  80. attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
  81. }).addTo(map);
  82. L.marker(geo).addTo(map);
  83. setTimeout(function () {
  84. map.invalidateSize();
  85. }, 0);
  86. let a = document.createElement("a");
  87. a.href = `https://www.openstreetmap.org/?mlat=${geo[0]}&mlon=${geo[1]}`;
  88. a.target = "_blank";
  89. a.innerHTML = jsonGeo;
  90. container.appendChild(a);
  91. return outerHTML;
  92. }
  93. function displayMetas(metaData, isRo) {
  94. let metaList = document.createElement("ul");
  95. metaData.libraryPath = null;
  96. metaData.tags = metaData.fixedTags = null;
  97. if (metaData.exposureTime && metaData.exposureTimeStr)
  98. metaData.exposureTime = null;
  99. if (metaData.date && metaData.dateTime)
  100. metaData.dateTime = null;
  101. if (metaData.height && metaData.width) {
  102. metaData.dimension = { type: "string", value: `${metaData.width.value} x ${metaData.height.value}` }
  103. metaData.height = metaData.width = null;
  104. }
  105. for (let i of [ "date", "dimension", "height", "width", "fileSize" ]) {
  106. let metaItem = displayMeta(i, metaData[i], true);
  107. metaItem && metaList.appendChild(metaItem);
  108. metaData[i] = null;
  109. }
  110. for (let i of Object.keys(metaData).sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))) {
  111. if (i === 'gpsLocation') {
  112. let dom = displayMap(metaData[i].value);
  113. dom && metaList.appendChild(dom);
  114. continue;
  115. }
  116. let metaItem = displayMeta(i, metaData[i], isRo || !MediaStorage.Instance.allMetaTypes[i]?.canWrite);
  117. metaItem && metaList.appendChild(metaItem);
  118. }
  119. if (!isRo)
  120. for (let i of ['geoCountry', 'geoCity', 'geoAdmin']) {
  121. if (!metaData[i]) {
  122. let metaItem = displayMeta(i, "", false);
  123. metaItem && metaList.appendChild(metaItem);
  124. }
  125. }
  126. return metaList;
  127. }
  128. function reloadCurrentMedia() {
  129. window.displayMediaFullPage(fullPageMediaDisplayed);
  130. }
  131. function displayTags(fixedTagList, tagList, writeAccess) {
  132. let tagListUi = document.createElement("ul");
  133. tagListUi.className = "taglist";
  134. let createTagUiItem = (i, roTag) => {
  135. let uiItem = document.createElement("li");
  136. uiItem.className = "badge text-bg-light";
  137. let textItem = document.createElement("span");
  138. textItem.textContent = i;
  139. uiItem.appendChild(textItem);
  140. if (!roTag) {
  141. let btItem = document.createElement("a");
  142. btItem.className = "border-start bi bi-x removeBt";
  143. btItem.href = '#';
  144. btItem.addEventListener('click', async e => {
  145. e.preventDefault();
  146. await MediaStorage.Instance.removeTag(fullPageMediaDisplayed.fixedSum, i);
  147. reloadCurrentMedia();
  148. });
  149. uiItem.appendChild(btItem);
  150. }
  151. tagListUi.appendChild(uiItem);
  152. };
  153. for (let i of fixedTagList)
  154. createTagUiItem(i, true);
  155. for (let i of tagList)
  156. createTagUiItem(i, !writeAccess);
  157. if (writeAccess) {
  158. let inputGroup = document.createElement('form');
  159. tagListUi.appendChild(inputGroup);
  160. inputGroup.classList.add('input-group');
  161. let valInput = document.createElement("input");
  162. valInput.classList.add("form-control");
  163. valInput.addEventListener('keyup', evt => evt.stopPropagation());
  164. valInput.addEventListener('keydown', evt => evt.stopPropagation());
  165. inputGroup.appendChild(valInput);
  166. let bt = document.createElement('button');
  167. bt.className = 'btn btn-outline-secondary';
  168. bt.type = 'button';
  169. bt.innerHTML = '<i class="bi bi-tags"></i>';
  170. inputGroup.appendChild(bt);
  171. bt.addEventListener('click', async () => { await MediaStorage.Instance.addTag(fullPageMediaDisplayed.fixedSum, valInput.value); reloadCurrentMedia(); });
  172. inputGroup.addEventListener('submit', async evt => {
  173. evt.preventDefault();
  174. await MediaStorage.Instance.addTag(fullPageMediaDisplayed.fixedSum, valInput.value);
  175. reloadCurrentMedia();
  176. });
  177. }
  178. return tagListUi;
  179. }
  180. function displayDownloadBt(downloadLink) {
  181. let bt = document.createElement("button");
  182. bt.type = "button";
  183. bt.className = "btn btn-primary";
  184. bt.textContent = "Download";
  185. bt.addEventListener("click", (evt) => {
  186. let link = document.createElement('a');
  187. link.target='_blank';
  188. link.setAttribute("download", "");
  189. link.href = downloadLink;
  190. link.click();
  191. });
  192. return bt;
  193. }
  194. function _displayMediaFullPage(fileName, imgUrl, metaData, downloadLink, writeAccess) {
  195. return new Promise(ok => {
  196. document.getElementById("pch-fullPagePreviewContainer").classList.add("loading");
  197. document.getElementById("pch-fullPageMedia-title").innerText = fileName;
  198. document.getElementById("pch-fullPagePreview").onceLoaded = ok;
  199. document.getElementById("pch-fullPagePreview").src = imgUrl ?? "";
  200. document.getElementById("pch-fullPageDetail").innerText = "";
  201. if (downloadLink)
  202. document.getElementById("pch-fullPageDetail").appendChild(displayDownloadBt(downloadLink));
  203. document.getElementById("pch-fullPageDetail").appendChild(displayTags(metaData?.fixedTags || [], metaData?.tags || [], writeAccess));
  204. document.getElementById("pch-fullPageDetail").appendChild(displayMetas(Object.assign({}, metaData || {}), !writeAccess));
  205. });
  206. }
  207. function LoadPreviousMedia() {
  208. let i = fullPageMediaDisplayed;
  209. while (i = MediaStorage.Instance.previousMedia(i)) {
  210. if (window.FilterManager.match(i)) {
  211. window.displayMediaFullPage(i);
  212. break;
  213. }
  214. }
  215. }
  216. function LoadNextMedia() {
  217. let i = fullPageMediaDisplayed;
  218. while (i = MediaStorage.Instance.nextMedia(i)) {
  219. if (window.FilterManager.match(i)) {
  220. window.displayMediaFullPage(i);
  221. break;
  222. }
  223. }
  224. }
  225. function CloseFullpageMedia() {
  226. if (fullPageMediaDisplayed !== false)
  227. document.body.classList.remove("overlay-visible");
  228. document.getElementById("pch-fullPageMedia").classList.add("hidden");
  229. fullPageMediaDisplayed = false;
  230. history.pushState({}, '', '#');
  231. document.Title.pop();
  232. }
  233. window.displayMediaFullPage = function(mediaItem) {
  234. document.getElementById("pch-fullPageMedia").classList.remove("hidden");
  235. if (fullPageMediaDisplayed)
  236. document.Title.replaceTitle(mediaItem.fixedSum);
  237. else
  238. document.Title.pushTitle(mediaItem.fixedSum);
  239. fullPageMediaDisplayed = mediaItem ?? null;
  240. document.body.classList.add("overlay-visible");
  241. if (!mediaItem)
  242. return _displayMediaFullPage("Error", null, {}, null, false);
  243. let containerSize = document.getElementById("pch-fullPageMedia").getBoundingClientRect();
  244. let requestSize = mediaItem.resize(containerSize.width, containerSize.height);
  245. document.getElementById("pch-fullPagePreview").parentNode.style.maxWidth = "100%";
  246. document.getElementById("pch-fullPagePreview").parentNode.style.maxHeight = "100%";
  247. let meta = {
  248. ...mediaItem.meta,
  249. date: { type: 'date', value: mediaItem.date } || undefined,
  250. filename: mediaItem.filename ? { type: 'string', value: mediaItem.fileName } : undefined,
  251. fixedTags: mediaItem.fixedTags,
  252. tags: mediaItem.tags
  253. };
  254. if (document.location.hash != `#${mediaItem.fixedSum}`)
  255. history.pushState({}, '', `#${mediaItem.fixedSum}`);
  256. const requestSizeQuery = requestSize ? `&w=${requestSize.width}&h=${requestSize.height}` : "";
  257. return _displayMediaFullPage(mediaItem.fileName, `${mediaItem.thumbnail}?q=6${requestSizeQuery}`, meta, `${mediaItem.original}?trim`, mediaItem.writeAccess);
  258. }
  259. document.getElementById("pch-fullPageMedia-closeBt")
  260. .addEventListener("click", () => CloseFullpageMedia());
  261. document.getElementById("pch-fullPagePreview").addEventListener("load", () => {
  262. document.getElementById("pch-fullPagePreviewContainer").classList.remove("loading");
  263. let domItem = document.getElementById("pch-fullPagePreview");
  264. domItem.onceLoaded && domItem.onceLoaded();
  265. domItem.onceLoaded = null;
  266. });
  267. document.addEventListener("keydown", evt => {
  268. if (!fullPageMediaDisplayed)
  269. return;
  270. if (evt.keyCode === 37 || evt.keyCode === 38)
  271. LoadPreviousMedia();
  272. else if (evt.keyCode === 39 || evt.keyCode === 40)
  273. LoadNextMedia();
  274. });
  275. document.onClosePopinRequested(() => { CloseFullpageMedia(); });
  276. });