uiShare.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. $(() => {
  2. var windowDisplayed = false;
  3. var data = null;
  4. const GRANT_TEXT = ["None", "Read Access", "Write Access", "Read Access (Strip meta)"];
  5. const GRANT_ICON = ["", "bi-eye", "bi-pencil", "bi-eye-slash"];
  6. const ACCESS_ICON = ["bi-question-lg", "bi-database", "bi-envelope-at", "bi-link-45deg", "bi-people"];
  7. const TYPE_ICON = ["bi-question-lg", "bi-diagram-2", "bi-tags", "bi-braces-asterisk", "bi-images", "bi-gear"];
  8. const TYPE_TEXT = ["Unknown", "Single photo", "Tags", "Meta", "Everything", "Admin access"];
  9. class ShareData {
  10. dbId = 0;
  11. typeId = "";
  12. typeData = "";
  13. accessToId = 0;
  14. accessToData = "";
  15. grant = 0;
  16. constructor(data) {
  17. this.dbId = data.id;
  18. this.typeId = [ "unknown", "ldapAccount", "email", "link", "every one" ].indexOf(data.type);
  19. this.typeData = data.typeData;
  20. this.accessToId = [ "unknown", "item", "tag", "meta", "everything", "admin"].indexOf(data.accessTo);
  21. this.accessToData = data.accessToData;
  22. this.grant = [ "none", "read", "write", "read without meta"].indexOf(data.grant);
  23. }
  24. objectify() {
  25. return {
  26. id: this.dbId,
  27. type: [ "unknown", "ldapAccount", "email", "link", "every one" ][this.typeId],
  28. typeData: this.typeData,
  29. accessTo: [ "unknown", "item", "tag", "meta", "everything", "admin"][this.accessToId],
  30. accessToData: this.accessToData,
  31. grant: [ "none", "read", "write", "read without meta"][this.grant]
  32. };
  33. }
  34. compare(b) {
  35. if (this.typeId != b.typeId) return b.typeId - this.typeId;
  36. if (this.accessToId != b.accessToId) return b.accessToId - this.accessToId;
  37. if (this.grant != b.grant) return b.grant - this.grant;
  38. return 0;
  39. }
  40. }
  41. function getData() {
  42. return new Promise((ok) => {
  43. if (data)
  44. return ok(data);
  45. $.get("/api/accessAdmin/list", {}, okData => {
  46. data = (okData || []).map(x => new ShareData(x)).sort((a, b) => a.compare(b));
  47. ok(data);
  48. });
  49. });
  50. }
  51. function updateData(data) {
  52. return new Promise(ok => {
  53. $.ajax({
  54. url: `/api/accessAdmin/${data.dbId}`,
  55. type: "POST",
  56. data: data,
  57. success: allData => {
  58. ok(true);
  59. },
  60. error: err => ok(false),
  61. });
  62. });
  63. }
  64. function revokeData(dbId) {
  65. return new Promise(ok => {
  66. $.ajax({
  67. url: `/api/accessAdmin/${dbId}`,
  68. type: "DELETE",
  69. success: allData => {
  70. ok(true);
  71. },
  72. error: err => ok(false),
  73. });
  74. });
  75. }
  76. async function buildTypeDepandentDiv(htmlElement, data) {
  77. htmlElement.textContent = "";
  78. let input = document.createElement("input");
  79. input.type = "text";
  80. if (data.accessToId === 1) {
  81. input.value = data.accessToData;
  82. htmlElement.appendChild(input);
  83. let span = document.createElement("span");
  84. span.textContent = " (" +((await MediaStorage.Instance.getMedia(data.accessToData))?.fileName || "File not found") + ")";
  85. htmlElement.appendChild(span);
  86. input.addEventListener("change", async () => {
  87. span.textContent = " (" +((await MediaStorage.Instance.getMedia(input.value))?.fileName || "File not found") + ")";
  88. });
  89. }
  90. else if (data.accessToId === 2) {
  91. input.value = data.accessToData;
  92. htmlElement.appendChild(input);
  93. }
  94. else if (data.accessToId === 3) {
  95. input.value = data.accessToData;
  96. htmlElement.appendChild(input);
  97. }
  98. if (htmlElement.children.length) {
  99. input.addEventListener("change", async () => {
  100. data.accessToData = input.value;
  101. await updateData(data);
  102. });
  103. }
  104. }
  105. async function buildShareItem(data) {
  106. const htmlId = `collapseShareItem${data.dbId}`;
  107. let container = document.createElement("li");
  108. container.className = "accordion-item";
  109. let header = document.createElement("h2");
  110. header.className = "accordion-header";
  111. let headerButton = document.createElement("button");
  112. headerButton.className = `accordion-button bi ${ACCESS_ICON[data.typeId]}`;
  113. headerButton.type = "button";
  114. headerButton.dataset.bsToggle = "collapse";
  115. headerButton.dataset.bsTarget = `#${htmlId}`;
  116. headerButton.textContent = data.typeData;
  117. headerButton.ariaExpanded = false;
  118. headerButton.ariaControls = htmlId;
  119. let accordionBodyContainer = document.createElement("div");
  120. accordionBodyContainer.className = "accordion-collapse collapse";
  121. accordionBodyContainer.dataset.bsParent = "#pch-share-container";
  122. accordionBodyContainer.id = htmlId;
  123. let accordionBody = document.createElement("div");
  124. accordionBody.className = "accordion-body";
  125. let typeDivRow = document.createElement("div");
  126. typeDivRow.className = "row";
  127. let typeDepandentDiv = document.createElement("div");
  128. let grantDiv = document.createElement("div");
  129. {
  130. let typeDiv = document.createElement("div");
  131. typeDiv.className = "dropdown";
  132. typeDiv.id = `pch-share-${data.dbId}-typeDropdown`
  133. let button = document.createElement("button");
  134. button.className = "btn btn-secondary dropdown-toggle bi";
  135. button.classList.add(TYPE_ICON[data.accessToId]);
  136. button.textContent = TYPE_TEXT[data.accessToId];
  137. button.type = "button";
  138. button.setAttribute("data-bs-toggle", "dropdown");
  139. button.setAttribute("aria-expanded", false);
  140. button.id = `${typeDiv.id}-button`;
  141. let dropdownMenu = document.createElement("ul");
  142. dropdownMenu.className = "dropdown-menu";
  143. for (let i =1; i <= TYPE_TEXT.length; ++i) {
  144. let li = document.createElement("li");
  145. let a = document.createElement("a");
  146. a.className = "dropdown-item bi";
  147. if (i === data.accessToId)
  148. a.classList.add("active");
  149. a.href="#";
  150. a.classList.add(TYPE_ICON[i]);
  151. a.textContent = TYPE_TEXT[i];
  152. a.addEventListener("click", async () => {
  153. let dbData = await getData();
  154. let dataIdx = dbData.findIndex(item => item.dbId === data.dbId);
  155. if (dataIdx === -1 || dbData[dataIdx].accessToId === i)
  156. return;
  157. dbData[dataIdx].accessToId = i;
  158. button.className = "btn btn-secondary dropdown-toggle bi";
  159. button.textContent = TYPE_TEXT[data.accessToId];
  160. button.classList.add(TYPE_ICON[data.accessToId]);
  161. button.setAttribute("aria-expanded", false);
  162. dropdownMenu.classList.remove("show");
  163. dropdownMenu.querySelectorAll(".active").forEach(i => i.classList.remove("active"));
  164. a.classList.add("active");
  165. if (dbData[dataIdx].accessToId === 5)
  166. grantDiv.classList.add("hidden");
  167. else
  168. grantDiv.classList.remove("hidden");
  169. await buildTypeDepandentDiv(typeDepandentDiv, dbData[dataIdx]);
  170. await updateData(dbData[dataIdx]);
  171. });
  172. li.appendChild(a);
  173. dropdownMenu.appendChild(li);
  174. }
  175. typeDiv.appendChild(button);
  176. typeDiv.appendChild(dropdownMenu);
  177. typeDivRow.appendChild(typeDiv);
  178. await buildTypeDepandentDiv(typeDepandentDiv, data);
  179. typeDivRow.appendChild(typeDepandentDiv);
  180. }
  181. grantDiv.className = "dropdown";
  182. if (data.accessToId === 5)
  183. grantDiv.classList.add("hidden");
  184. grantDiv.id = `pch-share-${data.dbId}-grantDropdown`;
  185. let button = document.createElement("button");
  186. button.className = "btn btn-secondary dropdown-toggle bi";
  187. button.type = "button";
  188. button.setAttribute("data-bs-toggle", "dropdown");
  189. button.setAttribute("aria-expanded", false);
  190. button.id = `${grantDiv.id}-button`;
  191. button.textContent = GRANT_TEXT[data.grant];
  192. button.classList.add(GRANT_ICON[data.grant]);
  193. let dropdownMenu = document.createElement("ul");
  194. dropdownMenu.className = "dropdown-menu";
  195. for (let i =1; i <= GRANT_TEXT.length; ++i) {
  196. let li = document.createElement("li");
  197. let a = document.createElement("a");
  198. a.className = "dropdown-item bi";
  199. if (i === data.grant)
  200. a.classList.add("active");
  201. a.href="#";
  202. a.classList.add(GRANT_ICON[i]);
  203. a.textContent = GRANT_TEXT[i];
  204. a.addEventListener("click", async () => {
  205. let dbData = await getData();
  206. let dataIdx = dbData.findIndex(item => item.dbId === data.dbId);
  207. if (dataIdx === -1 || dbData[dataIdx].grant === i)
  208. return;
  209. dbData[dataIdx].grant = i;
  210. button.className = "btn btn-secondary dropdown-toggle bi";
  211. button.textContent = GRANT_TEXT[data.grant];
  212. button.classList.add(GRANT_ICON[data.grant]);
  213. button.setAttribute("aria-expanded", false);
  214. dropdownMenu.classList.remove("show");
  215. dropdownMenu.querySelectorAll(".active").forEach(i => i.classList.remove("active"));
  216. a.classList.add("active");
  217. await updateData(dbData[dataIdx]);
  218. });
  219. li.appendChild(a);
  220. dropdownMenu.appendChild(li);
  221. }
  222. grantDiv.appendChild(button);
  223. grantDiv.appendChild(dropdownMenu);
  224. typeDivRow.appendChild(grantDiv);
  225. let deleteButtonRow = document.createElement("div");
  226. let deleteButtonDiv = document.createElement("div");
  227. let deleteButton = document.createElement("button");
  228. deleteButtonRow.className = "row";
  229. deleteButtonDiv.className = "col align-self-end";
  230. deleteButton.className = "btn btn-danger";
  231. deleteButton.textContent = "Revoke";
  232. deleteButtonRow.appendChild(deleteButtonDiv);
  233. deleteButtonDiv.appendChild(deleteButton);
  234. deleteButton.addEventListener("click", async () => {
  235. revokeData(data.dbId).then(success => {
  236. if (success) {
  237. container.remove();
  238. }
  239. });
  240. });
  241. header.appendChild(headerButton);
  242. container.appendChild(header);
  243. accordionBody.appendChild(typeDivRow);
  244. accordionBody.appendChild(deleteButtonRow);
  245. accordionBodyContainer.appendChild(accordionBody);
  246. container.appendChild(accordionBodyContainer);
  247. return container;
  248. }
  249. async function buildShareItems(data) {
  250. let container = document.createElement("ul");
  251. for (let i of data)
  252. container.appendChild(await buildShareItem(i));
  253. return container;
  254. }
  255. window.showShareUi = async () => {
  256. if (windowDisplayed)
  257. return;
  258. document.getElementById("pch-share-wrapper").classList.remove("hidden");
  259. document.Title.pushTitle("Share");
  260. document.body.classList.add("overlay-visible");
  261. const data = await getData();
  262. document.getElementById('pch-share-loading').classList.add("hidden");
  263. const container = document.getElementById('pch-share-container');
  264. container.innerHTML = "";
  265. container.appendChild(await buildShareItems(data));
  266. windowDisplayed = true;
  267. }
  268. window.closeShareUi = () => {
  269. if (!windowDisplayed)
  270. return;
  271. document.getElementById("pch-share-wrapper").classList.add("hidden");
  272. document.body.classList.remove("overlay-visible");
  273. windowDisplayed = false;
  274. document.Title.pop();
  275. }
  276. document.onClosePopinRequested(() => { window.closeShareUi(); });
  277. document.getElementById("pch-share-closeBt").addEventListener("click", window.closeShareUi);
  278. document.getElementById("pch-share-addLdap").addEventListener("click", () => {});
  279. document.getElementById("pch-share-addEmail").addEventListener("click", () => {});
  280. document.getElementById("pch-share-addLink").addEventListener("click", () => {});
  281. document.getElementById("pch-share-addEveryone").addEventListener("click", () => {});
  282. setTimeout(() => LoadingTasks.push(window.showShareUi), 1500);
  283. });