uiMedia.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. $(() => {
  2. var fullPageMediaDisplayed = false;
  3. var selectedThumbnails = [];
  4. var lastSelection = null;
  5. function onItemSelected(mediaItem) {
  6. document.getElementById("pch-mediaList").classList.add("selection");
  7. }
  8. function onItemDeselected(mediaItem) {
  9. if (!selectedThumbnails.length)
  10. document.getElementById("pch-mediaList").classList.remove("selection");
  11. }
  12. function buildThumbnail(mediaItem) {
  13. if (mediaItem.ui)
  14. return mediaItem.ui;
  15. let checkbox = document.createElement("input");
  16. let editButton = document.createElement("button");
  17. let img = document.createElement("img");
  18. let container = document.createElement("li");
  19. let loadingImg = document.createElement("div");
  20. checkbox.type = "checkbox";
  21. editButton.type = "button";
  22. if (!mediaItem.writeAccess)
  23. editButton.classList.add("hidden");
  24. let editButtonSpan = document.createElement("span");
  25. editButtonSpan.className = "bi bi-pen";
  26. editButton.appendChild(editButtonSpan);
  27. container.className = "pch-image loading col-12 col-md-6 col-xl-4 align-self-center";
  28. loadingImg.classList.add("spinner");
  29. loadingImg.innerHTML = "<span class='spinner-grow'></span>";
  30. container.dataset.md5sum = mediaItem.fixedSum;
  31. img.loading = "lazy";
  32. let requestSize = mediaItem.resize(450, 450);
  33. requestSize = requestSize ? `w=${requestSize.width}&h=${requestSize.height}&` : "";
  34. img.src = `${mediaItem.thumbnail}?${requestSize}q=4`;
  35. img.classList.add("img-fluid");
  36. img.classList.add("img-thumbnail");
  37. img.addEventListener("load", () => {
  38. container.classList.remove("loading");
  39. container.classList.remove("spinner-grow");
  40. });
  41. container.style.width = `${requestSize.width}px`;
  42. container.appendChild(loadingImg);
  43. container.appendChild(img);
  44. container.appendChild(checkbox);
  45. container.appendChild(editButton);
  46. let setSelectionCheckboxValue = function(media, value) {
  47. media.ui.checkbox.checked = value;
  48. let indexInSelection = selectedThumbnails.indexOf(media.fixedSum);
  49. if (value && indexInSelection < 0) {
  50. selectedThumbnails.push(media.fixedSum);
  51. onItemSelected(media);
  52. return true;
  53. } else if (!value && indexInSelection >= 0) {
  54. selectedThumbnails.splice(indexInSelection, 1);
  55. onItemDeselected(media);
  56. return true;
  57. }
  58. return false;
  59. }
  60. mediaItem.setSelectionCheckboxValue = value => setSelectionCheckboxValue(mediaItem, value);
  61. let cascadeSetSelectionCheckboxValue = function(value) {
  62. if (!setSelectionCheckboxValue(mediaItem, value))
  63. return;
  64. if (window.lastKeyboardEvent?.shiftKey && lastSelection) {
  65. let _lastKeyboardEvent = window.lastKeyboardEvent;
  66. window.lastKeyboardEvent = null;
  67. for (let i of MediaStorage.Instance.getMediaBetween(lastSelection, mediaItem)) {
  68. if (i === mediaItem)
  69. continue;
  70. i.ui.checkbox.setAttribute("checked", value);
  71. i.ui.checkbox.checked = value;
  72. setSelectionCheckboxValue(i, value);
  73. }
  74. window.lastKeyboardEvent = _lastKeyboardEvent;
  75. }
  76. lastSelection = mediaItem;
  77. }
  78. editButton.addEventListener("click", e => {
  79. e.stopPropagation();
  80. if (!checkbox.checked) {
  81. checkbox.checked = true;
  82. setSelectionCheckboxValue(mediaItem, true);
  83. }
  84. let sel = selectedThumbnails.map(x => MediaStorage.Instance.getMediaLocal(x)).filter(x => x && x.writeAccess);
  85. if (sel.length === 1 && sel[0].fixedSum === mediaItem.fixedSum) {
  86. checkbox.checked = false;
  87. setSelectionCheckboxValue(mediaItem, false);
  88. document.location.hash = mediaItem.fixedSum;
  89. return;
  90. }
  91. window.displayMultipleMediaFullPage(sel);
  92. });
  93. container.addEventListener("click", () => {
  94. if (selectedThumbnails.length || window.lastKeyboardEvent?.ctrlKey) {
  95. let value = !checkbox.checked;
  96. checkbox.setAttribute("checked", value);
  97. checkbox.checked = value;
  98. cascadeSetSelectionCheckboxValue(value);
  99. return;
  100. }
  101. document.location.hash = mediaItem.fixedSum;
  102. });
  103. checkbox.addEventListener("click", evt => {
  104. evt.stopPropagation();
  105. });
  106. checkbox.addEventListener("change", evt => {
  107. cascadeSetSelectionCheckboxValue(checkbox.checked);
  108. });
  109. return mediaItem.ui = {
  110. root: container,
  111. img: img,
  112. checkbox: checkbox
  113. };
  114. }
  115. function buildYear(date) {
  116. let result = document.createElement('h3');
  117. result.className = "col-12";
  118. result.textContent = date.getUTCFullYear();
  119. return result;
  120. }
  121. function buildMonth(date) {
  122. let result = document.createElement('h4');
  123. result.className = "col-12";
  124. result.textContent = date.toLocaleString('default', { month: 'long' });
  125. return result;
  126. }
  127. let lastItemDisplayed = null;
  128. let displayedItemCount = 0;
  129. const displayItemBatchCount = 15;
  130. let targetDisplayedItems = displayItemBatchCount;
  131. function redraw(container, media) {
  132. buildThumbnail(media);
  133. if (!media.ui)
  134. return;
  135. let yearUpdated = !container.dataset.lastItemYear || container.dataset.lastItemYear != media.date.getUTCFullYear();
  136. if (yearUpdated) {
  137. container.appendChild(buildYear(media.date));
  138. container.dataset.lastItemYear = media.date.getUTCFullYear();
  139. }
  140. if (yearUpdated || container.dataset.lastItemMonth === undefined || container.dataset.lastItemMonth != media.date.getUTCMonth()) {
  141. container.appendChild(buildMonth(media.date));
  142. container.dataset.lastItemMonth = media.date.getUTCMonth();
  143. }
  144. container.appendChild(media.ui.root);
  145. lastItemDisplayed = media;
  146. displayedItemCount++;
  147. }
  148. MediaStorage.Instance.addEventListener("rebuildMedia", (evt) => {
  149. let newContainer = document.getElementById('pch-mediaList');
  150. newContainer.textContent = '';
  151. newContainer.dataset.lastItemYear = null;
  152. newContainer.dataset.lastItemMonth = null;
  153. lastItemDisplayed = null;
  154. displayedItemCount = 0;
  155. targetDisplayedItems = displayItemBatchCount;
  156. for (let i of selectedThumbnails) {
  157. let media = MediaStorage.Instance.getMediaLocal(i);
  158. media?.setSelectionCheckboxValue(false);
  159. }
  160. lastSelection = null;
  161. for (let i of MediaStorage.Instance.medias)
  162. if (window.FilterManager.match(i)) {
  163. redraw(newContainer, i);
  164. if (displayedItemCount >= targetDisplayedItems)
  165. break;
  166. }
  167. });
  168. MediaStorage.Instance.addEventListener("newMedia", (evt) => {
  169. if (displayedItemCount < targetDisplayedItems && window.FilterManager.match(evt.detail)) {
  170. let container = document.getElementById('pch-mediaList');
  171. redraw(container, evt.detail);
  172. }
  173. });
  174. window.displayMoreMedia = () => {
  175. targetDisplayedItems += displayItemBatchCount;
  176. let container = document.getElementById('pch-mediaList');
  177. for (let index = lastItemDisplayed ? (MediaStorage.Instance.getMediaIndex(lastItemDisplayed) +1) : 0;
  178. displayedItemCount < targetDisplayedItems; ++index) {
  179. let media = MediaStorage.Instance.medias[index];
  180. if (!media)
  181. return;
  182. if (window.FilterManager.match(media))
  183. redraw(container, media);
  184. }
  185. }
  186. });