uiMedia.js 7.9 KB

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