uiMedia.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. let setSelectionCheckboxValue = function(media, value) {
  13. media.ui.checkbox.checked = value;
  14. let indexInSelection = selectedThumbnails.indexOf(media.fixedSum);
  15. if (value && indexInSelection < 0) {
  16. selectedThumbnails.push(media.fixedSum);
  17. onItemSelected(media);
  18. return true;
  19. } else if (!value && indexInSelection >= 0) {
  20. selectedThumbnails.splice(indexInSelection, 1);
  21. onItemDeselected(media);
  22. return true;
  23. }
  24. return false;
  25. }
  26. function buildThumbnail(mediaItem) {
  27. if (mediaItem.ui)
  28. return mediaItem.ui;
  29. let checkbox = document.createElement("input");
  30. let editButton = document.createElement("button");
  31. let img = document.createElement("img");
  32. let container = document.createElement("li");
  33. let loadingImg = document.createElement("div");
  34. checkbox.type = "checkbox";
  35. editButton.type = "button";
  36. if (!mediaItem.writeAccess)
  37. editButton.classList.add("hidden");
  38. let editButtonSpan = document.createElement("span");
  39. editButtonSpan.className = "bi bi-pen";
  40. editButton.appendChild(editButtonSpan);
  41. container.className = "pch-image loading col-12 col-md-6 col-xl-4 align-self-center";
  42. loadingImg.classList.add("spinner");
  43. loadingImg.innerHTML = "<span class='spinner-grow'></span>";
  44. container.dataset.md5sum = mediaItem.fixedSum;
  45. img.loading = "lazy";
  46. let requestSize = mediaItem.resize(450, 450);
  47. requestSize = requestSize ? `w=${requestSize.width}&h=${requestSize.height}&` : "";
  48. img.src = `${mediaItem.thumbnail}?${requestSize}q=4`;
  49. img.classList.add("img-fluid");
  50. img.classList.add("img-thumbnail");
  51. img.addEventListener("load", () => {
  52. container.classList.remove("loading");
  53. container.classList.remove("spinner-grow");
  54. });
  55. container.style.width = `${requestSize.width}px`;
  56. container.appendChild(loadingImg);
  57. container.appendChild(img);
  58. container.appendChild(checkbox);
  59. container.appendChild(editButton);
  60. let cascadeSetSelectionCheckboxValue = function(value) {
  61. if (!setSelectionCheckboxValue(mediaItem, value))
  62. return;
  63. if (window.lastKeyboardEvent?.shiftKey && lastSelection) {
  64. let _lastKeyboardEvent = window.lastKeyboardEvent;
  65. window.lastKeyboardEvent = null;
  66. for (let i of MediaStorage.Instance.getMediaBetween(lastSelection, mediaItem)) {
  67. if (i === mediaItem)
  68. continue;
  69. i.ui.checkbox.setAttribute("checked", value);
  70. i.ui.checkbox.checked = value;
  71. setSelectionCheckboxValue(i, value);
  72. }
  73. window.lastKeyboardEvent = _lastKeyboardEvent;
  74. }
  75. lastSelection = mediaItem;
  76. }
  77. editButton.addEventListener("click", e => {
  78. e.stopPropagation();
  79. if (!checkbox.checked) {
  80. checkbox.checked = true;
  81. setSelectionCheckboxValue(mediaItem, true);
  82. }
  83. let sel = selectedThumbnails.map(x => MediaStorage.Instance.getMediaLocal(x)).filter(x => x && x.writeAccess);
  84. if (sel.length === 1 && sel[0].fixedSum === mediaItem.fixedSum) {
  85. checkbox.checked = false;
  86. setSelectionCheckboxValue(mediaItem, false);
  87. document.location.hash = mediaItem.fixedSum;
  88. return;
  89. }
  90. window.displayMultipleMediaFullPage(sel);
  91. });
  92. container.addEventListener("click", () => {
  93. if (selectedThumbnails.length || window.lastKeyboardEvent?.ctrlKey) {
  94. let value = !checkbox.checked;
  95. checkbox.setAttribute("checked", value);
  96. checkbox.checked = value;
  97. cascadeSetSelectionCheckboxValue(value);
  98. return;
  99. }
  100. document.location.hash = mediaItem.fixedSum;
  101. });
  102. checkbox.addEventListener("click", evt => {
  103. evt.stopPropagation();
  104. });
  105. checkbox.addEventListener("change", evt => {
  106. cascadeSetSelectionCheckboxValue(checkbox.checked);
  107. });
  108. return mediaItem.ui = {
  109. root: container,
  110. img: img,
  111. checkbox: checkbox
  112. };
  113. }
  114. function buildYear(date) {
  115. let result = document.createElement('h3');
  116. result.className = "col-12";
  117. result.textContent = date.getUTCFullYear();
  118. return result;
  119. }
  120. function buildMonth(date) {
  121. let result = document.createElement('h4');
  122. result.className = "col-12";
  123. result.textContent = date.toLocaleString('default', { month: 'long' });
  124. return result;
  125. }
  126. let lastItemDisplayed = null;
  127. let displayedItemCount = 0;
  128. const displayItemBatchCount = 15;
  129. let targetDisplayedItems = displayItemBatchCount;
  130. function redraw(container, media) {
  131. buildThumbnail(media);
  132. if (!media.ui)
  133. return;
  134. let yearUpdated = !container.dataset.lastItemYear || container.dataset.lastItemYear != media.getDate().getUTCFullYear();
  135. const mediaDate = media.getDate();
  136. if (yearUpdated) {
  137. container.appendChild(buildYear(mediaDate));
  138. container.dataset.lastItemYear = mediaDate.getUTCFullYear();
  139. }
  140. if (yearUpdated || container.dataset.lastItemMonth === undefined || container.dataset.lastItemMonth != mediaDate.getUTCMonth()) {
  141. container.appendChild(buildMonth(mediaDate));
  142. container.dataset.lastItemMonth = mediaDate.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?.ui?.setSelectionCheckboxValue(media, 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. });