uiMedia.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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. let checked = media.ui.checkbox.checked;
  49. let indexInSelection = selectedThumbnails.indexOf(media.md5sum);
  50. if (checked && indexInSelection < 0) {
  51. selectedThumbnails.push(media.md5sum);
  52. onItemSelected(media);
  53. return true;
  54. } else if (!checked && indexInSelection >= 0) {
  55. selectedThumbnails.splice(indexInSelection, 1);
  56. onItemDeselected(media);
  57. return true;
  58. }
  59. return false;
  60. }
  61. let cascadeSetSelectionCheckboxValue = function(value) {
  62. if (!setSelectionCheckboxValue(mediaItem, value))
  63. return;
  64. if (lastKeyboardEvent?.shiftKey && lastSelection) {
  65. let _lastKeyboardEvent = lastKeyboardEvent;
  66. 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. 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.writeAccess);
  85. if (sel.length === 1 && sel[0].md5sum === mediaItem.md5sum) {
  86. checkbox.checked = false;
  87. setSelectionCheckboxValue(mediaItem, false);
  88. document.location.hash = mediaItem.md5sum;
  89. return;
  90. }
  91. console.log(sel);
  92. });
  93. container.addEventListener("click", () => {
  94. if (selectedThumbnails.length || 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.md5sum;
  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.textContent = date.getUTCFullYear();
  118. return result;
  119. }
  120. function buildMonth(date) {
  121. let result = document.createElement('h4');
  122. result.textContent = date.toLocaleString('default', { month: 'long' });
  123. return result;
  124. }
  125. let lastItemDisplayed = null;
  126. let displayedItemCount = 0;
  127. const displayItemBatchCount = 15;
  128. let targetDisplayedItems = displayItemBatchCount;
  129. function redraw(container, media) {
  130. buildThumbnail(media);
  131. if (!media.ui)
  132. return;
  133. let yearUpdated = !container.dataset.lastItemYear || container.dataset.lastItemYear != media.date.getUTCFullYear();
  134. if (yearUpdated) {
  135. container.appendChild(buildYear(media.date));
  136. container.dataset.lastItemYear = media.date.getUTCFullYear();
  137. }
  138. if (yearUpdated || container.dataset.lastItemMonth === undefined || container.dataset.lastItemMonth != media.date.getUTCMonth()) {
  139. container.appendChild(buildMonth(media.date));
  140. container.dataset.lastItemMonth = media.date.getUTCMonth();
  141. }
  142. container.appendChild(media.ui.root);
  143. lastItemDisplayed = media;
  144. displayedItemCount++;
  145. }
  146. MediaStorage.Instance.addEventListener("rebuildMedia", (evt) => {
  147. let newContainer = document.getElementById('pch-mediaList');
  148. newContainer.textContent = '';
  149. newContainer.dataset.lastItemYear = null;
  150. newContainer.dataset.lastItemMonth = null;
  151. lastItemDisplayed = null;
  152. displayedItemCount = 0;
  153. targetDisplayedItems = displayItemBatchCount;
  154. for (let i of MediaStorage.Instance.medias)
  155. if (window.FilterManager.match(i)) {
  156. redraw(newContainer, i);
  157. if (displayedItemCount >= targetDisplayedItems)
  158. break;
  159. }
  160. });
  161. MediaStorage.Instance.addEventListener("newMedia", (evt) => {
  162. if (displayedItemCount < targetDisplayedItems && window.FilterManager.match(evt.detail)) {
  163. let container = document.getElementById('pch-mediaList');
  164. redraw(container, evt.detail);
  165. }
  166. });
  167. window.displayMoreMedia = () => {
  168. targetDisplayedItems += displayItemBatchCount;
  169. let container = document.getElementById('pch-mediaList');
  170. for (let index = lastItemDisplayed ? (MediaStorage.Instance.getMediaIndex(lastItemDisplayed) +1) : 0;
  171. displayedItemCount < targetDisplayedItems; ++index) {
  172. let media = MediaStorage.Instance.medias[index];
  173. if (window.FilterManager.match(media))
  174. redraw(container, media);
  175. }
  176. }
  177. });