1
0

uiMedia.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. $(() => {
  2. var fullPageMediaDisplayed = false;
  3. var selectedThumbnails = [];
  4. var lastKeyboardEvent = null;
  5. var lastSelection = null;
  6. function onItemSelected(mediaItem) {
  7. document.getElementById("pch-mediaList").classList.add("selection");
  8. }
  9. function onItemDeselected(mediaItem) {
  10. if (!selectedThumbnails.length)
  11. document.getElementById("pch-mediaList").classList.remove("selection");
  12. }
  13. function buildThumbnail(mediaItem) {
  14. if (mediaItem.ui)
  15. return mediaItem.ui;
  16. let checkbox = document.createElement("input");
  17. let img = document.createElement("img");
  18. let container = document.createElement("li");
  19. let loadingImg = document.createElement("div");
  20. checkbox.type = "checkbox";
  21. container.classList.add("pch-image");
  22. container.classList.add("loading");
  23. loadingImg.classList.add("spinner");
  24. loadingImg.innerHTML = "<span class='spinner-grow'></span>";
  25. container.dataset.md5sum = mediaItem.md5sum;
  26. img.loading = "lazy";
  27. let requestSize = mediaItem.resize(450, 450);
  28. img.src = `${mediaItem.thumbnail}?w=${requestSize.width}&h=${requestSize.height}&q=4`;
  29. img.classList.add("img-fluid");
  30. img.classList.add("img-thumbnail");
  31. img.addEventListener("load", () => {
  32. container.classList.remove("loading");
  33. container.classList.remove("spinner-grow");
  34. });
  35. container.style.width = `${requestSize.width}px`;
  36. container.appendChild(loadingImg);
  37. container.appendChild(img);
  38. container.appendChild(checkbox);
  39. let setSelectionCheckboxValue = function(media, value) {
  40. let checked = media.ui.checkbox.checked;
  41. let indexInSelection = selectedThumbnails.indexOf(media.md5sum);
  42. if (checked && indexInSelection < 0) {
  43. selectedThumbnails.push(media.md5sum);
  44. onItemSelected(media);
  45. return true;
  46. } else if (!checked && indexInSelection >= 0) {
  47. selectedThumbnails.splice(indexInSelection, 1);
  48. onItemDeselected(media);
  49. return true;
  50. }
  51. return false;
  52. }
  53. let cascadeSetSelectionCheckboxValue = function(value) {
  54. if (!setSelectionCheckboxValue(mediaItem, value))
  55. return;
  56. if (lastKeyboardEvent?.shiftKey && lastSelection) {
  57. let _lastKeyboardEvent = lastKeyboardEvent;
  58. lastKeyboardEvent = null;
  59. for (let i of MediaStorage.Instance.getMediaBetween(lastSelection, mediaItem)) {
  60. if (i === mediaItem)
  61. continue;
  62. i.ui.checkbox.setAttribute("checked", value);
  63. i.ui.checkbox.checked = value;
  64. setSelectionCheckboxValue(i, value);
  65. }
  66. lastKeyboardEvent = _lastKeyboardEvent;
  67. }
  68. lastSelection = mediaItem;
  69. console.log(mediaItem);
  70. }
  71. container.addEventListener("click", () => {
  72. if (selectedThumbnails.length || lastKeyboardEvent?.ctrlKey) {
  73. let value = !checkbox.checked;
  74. checkbox.setAttribute("checked", value);
  75. checkbox.checked = value;
  76. cascadeSetSelectionCheckboxValue(value);
  77. return;
  78. }
  79. document.location.hash = mediaItem.md5sum;
  80. });
  81. checkbox.addEventListener("click", evt => {
  82. evt.stopPropagation();
  83. });
  84. checkbox.addEventListener("change", evt => {
  85. cascadeSetSelectionCheckboxValue(checkbox.checked);
  86. });
  87. return mediaItem.ui = {
  88. root: container,
  89. img: img,
  90. checkbox: checkbox
  91. };
  92. }
  93. function buildYear(date) {
  94. let result = document.createElement('h3');
  95. result.textContent = date.getUTCFullYear();
  96. return result;
  97. }
  98. function buildMonth(date) {
  99. let result = document.createElement('h4');
  100. result.textContent = date.toLocaleString('default', { month: 'long' });
  101. return result;
  102. }
  103. function redraw(container, media) {
  104. buildThumbnail(media);
  105. if (!media.ui)
  106. return;
  107. let yearUpdated = !container.dataset.lastItemYear || container.dataset.lastItemYear != media.date.getUTCFullYear();
  108. if (yearUpdated) {
  109. container.appendChild(buildYear(media.date));
  110. container.dataset.lastItemYear = media.date.getUTCFullYear();
  111. }
  112. if (yearUpdated || container.dataset.lastItemMonth === undefined || container.dataset.lastItemMonth != media.date.getUTCMonth()) {
  113. container.appendChild(buildMonth(media.date));
  114. container.dataset.lastItemMonth = media.date.getUTCMonth();
  115. }
  116. container.appendChild(media.ui.root);
  117. }
  118. MediaStorage.Instance.addEventListener("rebuildMedia", (evt) => {
  119. let newContainer = document.getElementById('pch-mediaList');
  120. newContainer.textContent = '';
  121. newContainer.dataset.lastItemYear = null;
  122. newContainer.dataset.lastItemMonth = null;
  123. for (let i of MediaStorage.Instance.medias)
  124. redraw(newContainer, i);
  125. });
  126. MediaStorage.Instance.addEventListener("newMedia", (evt) => {
  127. let container = document.getElementById('pch-mediaList');
  128. redraw(container, evt.detail);
  129. });
  130. function _displayMediaFullPage(fileName, imgUrl, metaData, downloadLink) {
  131. return new Promise(ok => {
  132. document.getElementById("pch-fullPagePreviewContainer").classList.add("loading");
  133. document.getElementById("pch-fullPageMedia-title").innerText = fileName;
  134. document.getElementById("pch-fullPagePreview").onceLoaded = ok;
  135. document.getElementById("pch-fullPagePreview").src = imgUrl;
  136. document.getElementById("pch-fullPageDetail").innerText = "";
  137. let metaList = document.createElement("ul");
  138. for (let i in metaData || {}) {
  139. let li = document.createElement("li");
  140. li.innerText = `${i}: ${metaData[i]}`;
  141. metaList.appendChild(li);
  142. }
  143. document.getElementById("pch-fullPageDetail").appendChild(metaList);
  144. if (downloadLink) {
  145. document.getElementById("pch-fullPageDetail-dlButton").classList.remove("hidden");
  146. document.getElementById("pch-fullPageDetail-dlButton").dataset["link"] = downloadLink;
  147. } else {
  148. document.getElementById("pch-fullPageDetail-dlButton").classList.add("hidden");
  149. }
  150. });
  151. }
  152. function LoadPreviousMedia() {
  153. let media = MediaStorage.Instance.previousMedia(fullPageMediaDisplayed);
  154. if (media)
  155. window.displayMediaFullPage(media);
  156. }
  157. function LoadNextMedia() {
  158. let media = MediaStorage.Instance.nextMedia(fullPageMediaDisplayed);
  159. if (media)
  160. window.displayMediaFullPage(media);
  161. }
  162. window.displayMediaFullPage = function(mediaItem) {
  163. document.getElementById("pch-fullPageMedia").classList.remove("hidden");
  164. fullPageMediaDisplayed = mediaItem;
  165. if (!mediaItem)
  166. return _displayMediaFullPage("Error", null, {}, null);
  167. let containerSize = document.getElementById("pch-fullPageMedia").getBoundingClientRect();
  168. let requestSize = mediaItem.resize(containerSize.width, containerSize.height);
  169. document.getElementById("pch-fullPagePreview").parentNode.style.maxWidth = "100%";
  170. document.getElementById("pch-fullPagePreview").parentNode.style.maxHeight = "100%";
  171. let meta = {
  172. ...mediaItem.meta,
  173. date: mediaItem.date || undefined,
  174. filename: mediaItem.fileName || undefined
  175. };
  176. return _displayMediaFullPage(mediaItem.fileName, `${mediaItem.thumbnail}?w=${requestSize.width}&h=${requestSize.height}&q=6`, meta, mediaItem.original);
  177. }
  178. document.getElementById("pch-fullPageMedia-closeBt")
  179. .addEventListener("click", () => {
  180. document.getElementById("pch-fullPageMedia").classList.add("hidden");
  181. fullPageMediaDisplayed = false;
  182. history.pushState({}, '', '#');
  183. });
  184. document.getElementById("pch-fullPagePreview").addEventListener("load", () => {
  185. document.getElementById("pch-fullPagePreviewContainer").classList.remove("loading");
  186. let domItem = document.getElementById("pch-fullPagePreview");
  187. domItem.onceLoaded && domItem.onceLoaded();
  188. domItem.onceLoaded = null;
  189. });
  190. document.getElementById('pch-fullPageDetail-dlButton').addEventListener("click", (evt) => {
  191. if (!evt.target?.dataset?.link)
  192. return;
  193. let link = document.createElement('a');
  194. link.target='_blank';
  195. link.setAttribute("download", "");
  196. link.href = evt.target.dataset.link;
  197. link.click();
  198. });
  199. document.addEventListener("keyup", evt => {
  200. lastKeyboardEvent = evt;
  201. });
  202. document.addEventListener("keydown", evt => {
  203. lastKeyboardEvent = evt;
  204. if (!fullPageMediaDisplayed)
  205. return;
  206. if (evt.keyCode === 37 || evt.keyCode === 38)
  207. LoadPreviousMedia();
  208. else if (evt.keyCode === 39 || evt.keyCode === 40)
  209. LoadNextMedia();
  210. else {
  211. console.log("Unregistered key event", evt.key, evt.keyCode);
  212. return;
  213. }
  214. evt.preventDefault();
  215. });
  216. });