Ver código fonte

Share UI and minor styling fixes

isundil 1 ano atrás
pai
commit
88c7665833

+ 30 - 5
static/public/css/style.css

@@ -12,7 +12,7 @@ body.overlay-visible #fullScreenOverlay {
     margin: 0;
     padding: 0;
     background-color: rgba(0, 0, 0, .75);
-    z-index: 1040;
+    z-index: 2000;
 }
 
 #pch-navbar .dropdown-menu[data-bs-popper] {
@@ -28,6 +28,22 @@ body.overlay-visible #fullScreenOverlay {
     display: none;
 }
 
+#pch-navbar .navbar-nav {
+    flex-direction: row;
+}
+
+#pch-navbar .navbar-nav .nav-item, #pch-navbar .navbar-nav .nav-item > a {
+    display: inline-block;
+}
+
+#pch-navbar .navbar-nav .nav-item > a {
+    padding: 0 var(--bs-navbar-nav-link-padding-x) 0 var(--bs-navbar-nav-link-padding-x);
+}
+
+.fixed-top {
+    z-index: 1050;
+}
+
 body.filter-active #pch-navbar .bt-filter-active {
     display: initial;
 }
@@ -66,17 +82,24 @@ body.filter-active #pch-navbar .bt-filter-inactive {
 }
 
 #pch-mediaList .medialist-year {
-    z-index: 1022;
+    z-index: 1042;
     margin-top: -2.5em;
     padding-top: 2.5em;
 }
 #pch-mediaList .medialist-month {
+    z-index: 1040;
     border-bottom: 2px dashed;
     margin-top: -4.5em;
     padding-top: 4.5em;
     padding-bottom: 0.5em;
 }
-#pch-mediaList .medialist-year, #pch-mediaList .medialist-month {
+#pch-mediaList .medialist-month > div {
+    margin-top: -1em;
+    padding-top: 1em;
+    margin-bottom: -0.5em;
+    padding-bottom: 0.5em;
+}
+#pch-mediaList .medialist-year, #pch-mediaList .medialist-month > div {
     background-color: var(--bs-body-bg);
 }
 
@@ -90,6 +113,8 @@ body.filter-active #pch-navbar .bt-filter-inactive {
     min-width: 450px;
     justify-content: center;
     padding: 1em;
+    margin-bottom: 0.5em;
+    z-index: 1030;
 }
 
 #pch-mediaList > .pch-image img {
@@ -170,7 +195,7 @@ body.filter-active #pch-navbar .bt-filter-inactive {
     overflow: hidden;
     height: auto;
     width: auto;
-    z-index: 1050;
+    z-index: 2050;
 }
 
 #pch-fullPageMedia > div {
@@ -272,7 +297,7 @@ body.filter-active #pch-navbar .bt-filter-inactive {
     justify-content: center;
     align-items: center;
     text-align: center;
-    z-index: 1050;
+    z-index: 2050;
     top: 0;
     bottom: 0;
     left: 0;

+ 4 - 0
static/public/js/medias.js

@@ -291,10 +291,14 @@ class MediaStorage extends EventTarget
     }
 
     getMediaLocal(md5sum) {
+        if (!md5sum)
+            return null;
         return this.medias.find(x => x.fixedSum === md5sum);
     }
 
     async getMedia(md5sum) {
+        if (!md5sum)
+            return null;
         let media = this.medias.find(x => x.fixedSum === md5sum);
         if (media)
             return media;

+ 3 - 1
static/public/js/uiMedia.js

@@ -127,7 +127,9 @@ $(() => {
     function buildMonth(date) {
         let result = document.createElement('h4');
         result.className = "col-12 sticky-top medialist-month";
-        result.textContent = date.toLocaleString('default', { month: 'long' });
+        let container = document.createElement("div");
+        container.textContent = date.toLocaleString('default', { month: 'long' });
+        result.appendChild(container);
         return result;
     }
 

+ 166 - 20
static/public/js/uiShare.js

@@ -4,6 +4,12 @@ $(() => {
 var windowDisplayed = false;
 var data = null;
 
+const GRANT_TEXT = ["None", "Read Access", "Write Access", "Read Access (Strip meta)"];
+const GRANT_ICON = ["", "bi-eye", "bi-pencil", "bi-eye-slash"];
+const ACCESS_ICON = ["bi-question-lg", "bi-database", "bi-envelope-at", "bi-link-45deg", "bi-people"];
+const TYPE_ICON = ["bi-question-lg", "bi-diagram-2", "bi-tags", "bi-braces-asterisk", "bi-images", "bi-gear"];
+const TYPE_TEXT = ["Unknown", "Single photo", "Tags", "Meta", "Everything", "Admin access"];
+
 class ShareData {
     dbId = 0;
     typeId = "";
@@ -21,6 +27,17 @@ class ShareData {
         this.grant = [ "none", "read", "write", "read without meta"].indexOf(data.grant);
     }
 
+    objectify() {
+        return {
+            id: this.dbId,
+            type: [ "unknown", "ldapAccount", "email", "link", "every one" ][this.typeId],
+            typeData: this.typeData,
+            accessTo: [ "unknown", "item", "tag", "meta", "everything", "admin"][this.accessToId],
+            accessToData: this.accessToData,
+            grant: [ "none", "read", "write", "read without meta"][this.grant]
+        };
+    }
+
     compare(b) {
         if (this.typeId != b.typeId) return b.typeId - this.typeId;
         if (this.accessToId != b.accessToId) return b.accessToId - this.accessToId;
@@ -34,12 +51,50 @@ function getData() {
         if (data)
             return ok(data);
         $.get("/api/accessAdmin/list", {}, okData => {
-            data = okData;
-            ok(okData);
+            data = (okData || []).map(x => new ShareData(x)).sort((a, b) => a.compare(b));
+            ok(data);
         });
     });
 }
 
+function updateData(data) {
+    console.log("request to update", data.objectify());
+}
+
+function revokeData(dbId) {
+    console.log("Request to revoke", dbId);
+}
+
+async function buildTypeDepandentDiv(htmlElement, data) {
+    htmlElement.textContent = "";
+    let input = document.createElement("input");
+    input.type = "text";
+    if (data.accessToId === 1) {
+        input.value = data.accessToData;
+        htmlElement.appendChild(input);
+        let span = document.createElement("span");
+        span.textContent = " (" +((await MediaStorage.Instance.getMedia(data.accessToData))?.fileName || "File not found") + ")";
+        htmlElement.appendChild(span);
+        input.addEventListener("change", async () => {
+            span.textContent = " (" +((await MediaStorage.Instance.getMedia(input.value))?.fileName || "File not found") + ")";
+        });
+    }
+    else if (data.accessToId === 2) {
+        input.value = data.accessToData;
+        htmlElement.appendChild(input);
+    }
+    else if (data.accessToId === 3) {
+        input.value = data.accessToData;
+        htmlElement.appendChild(input);
+    }
+    if (htmlElement.children.length) {
+        input.addEventListener("change", () => {
+            data.accessToData = input.value;
+            updateData(data);
+        });
+    }
+}
+
 async function buildShareItem(data) {
     const htmlId = `collapseShareItem${data.dbId}`;
     let container = document.createElement("li");
@@ -47,7 +102,7 @@ async function buildShareItem(data) {
     let header = document.createElement("h2");
     header.className = "accordion-header";
     let headerButton = document.createElement("button");
-    headerButton.className = "accordion-button bi " + (["bi-question-lg", "bi-database", "bi-envelope-at", "bi-link-45deg", "bi-people"][data.typeId]);
+    headerButton.className = `accordion-button bi ${ACCESS_ICON[data.typeId]}`;
     headerButton.type = "button";
     headerButton.dataset.bsToggle = "collapse";
     headerButton.dataset.bsTarget = `#${htmlId}`;
@@ -62,22 +117,109 @@ async function buildShareItem(data) {
     accordionBody.className = "accordion-body";
     let typeDivRow = document.createElement("div");
     typeDivRow.className = "row";
-    let typeDiv = document.createElement("div");
-    typeDiv.className = "bi";
-    typeDiv.classList.add(["bi-question-lg", "bi-diagram-2", "bi-tags", "bi-braces-asterisk", "bi-people", "bi-gear"][data.accessToId]);
-    typeDiv.textContent = ["Unknown", "Single photo", "Tags", "Meta", "Everything", "Admin access"][data.accessToId];
-    if (data.accessToId === 1)
-        typeDiv.textContent += " (" +((await MediaStorage.Instance.getMedia(data.accessToData))?.fileName || "File not found") + ")";
-    else if (data.accessToId === 2)
-        typeDiv.textContent += ` (${data.accessToData})`;
-    else if (data.accessToId === 3)
-        typeDiv.textContent += ` (${data.accessToData})`;
-    if (data.accessToId !== 5) {
-        let grantDiv = document.createElement("div");
-        grantDiv.textContent = ["None", "Read Access", "Write Access", "Read Access (Strip meta)"][data.grant];
-        typeDiv.appendChild(grantDiv);
+    let typeDepandentDiv = document.createElement("div");
+    let grantDiv = document.createElement("div");
+
+    {
+        let typeDiv = document.createElement("div");
+        typeDiv.className = "dropdown";
+        typeDiv.id = `pch-share-${data.dbId}-typeDropdown`
+        let button = document.createElement("button");
+        button.className = "btn btn-secondary dropdown-toggle bi";
+        button.classList.add(TYPE_ICON[data.accessToId]);
+        button.textContent = TYPE_TEXT[data.accessToId];
+        button.type = "button";
+        button.setAttribute("data-bs-toggle", "dropdown");
+        button.setAttribute("aria-expanded", false);
+        button.id = `${typeDiv.id}-button`;
+        let dropdownMenu = document.createElement("ul");
+        dropdownMenu.className = "dropdown-menu";
+
+        for (let i =1; i <= TYPE_TEXT.length; ++i) {
+            let li = document.createElement("li");
+            let a = document.createElement("a");
+            a.className = "dropdown-item bi";
+            if (i === data.grant)
+                a.classList.add("active");
+            a.href="#";
+            a.classList.add(TYPE_ICON[i]);
+            a.textContent = TYPE_TEXT[i];
+            a.addEventListener("click", async () => {
+                let dbData = await getData();
+                let dataIdx = dbData.findIndex(item => item.dbId === data.dbId);
+                if (dataIdx === -1 || dbData[dataIdx].accessToId === i)
+                    return;
+                dbData[dataIdx].accessToId = i;
+                button.className = "btn btn-secondary dropdown-toggle bi";
+                button.textContent = TYPE_TEXT[data.accessToId];
+                button.classList.add(TYPE_ICON[data.accessToId]);
+                button.setAttribute("aria-expanded", false);
+                dropdownMenu.classList.remove("show");
+                dropdownMenu.querySelectorAll(".active").forEach(i => i.classList.remove("active"));
+                a.classList.add("active");
+                if (dbData[dataIdx].accessToId === 5)
+                    grantDiv.classList.add("hidden");
+                else
+                    grantDiv.classList.remove("hidden");
+                await buildTypeDepandentDiv(typeDepandentDiv, dbData[dataIdx]);
+                updateData(dbData[dataIdx]);
+            });
+            li.appendChild(a);
+            dropdownMenu.appendChild(li);
+        }
+
+        typeDiv.appendChild(button);
+        typeDiv.appendChild(dropdownMenu);
+        typeDivRow.appendChild(typeDiv);
+        await buildTypeDepandentDiv(typeDepandentDiv, data);
+        typeDivRow.appendChild(typeDepandentDiv);
     }
 
+    grantDiv.className = "dropdown";
+    if (data.accessToId === 5)
+        grantDiv.classList.add("hidden");
+    grantDiv.id = `pch-share-${data.dbId}-grantDropdown`;
+    let button = document.createElement("button");
+    button.className = "btn btn-secondary dropdown-toggle bi";
+    button.type = "button";
+    button.setAttribute("data-bs-toggle", "dropdown");
+    button.setAttribute("aria-expanded", false);
+    button.id = `${grantDiv.id}-button`;
+    button.textContent = GRANT_TEXT[data.grant];
+    button.classList.add(GRANT_ICON[data.grant]);
+    let dropdownMenu = document.createElement("ul");
+    dropdownMenu.className = "dropdown-menu";
+    for (let i =1; i <= GRANT_TEXT.length; ++i) {
+        let li = document.createElement("li");
+        let a = document.createElement("a");
+        a.className = "dropdown-item bi";
+        if (i === data.grant)
+            a.classList.add("active");
+        a.href="#";
+        a.classList.add(GRANT_ICON[i]);
+        a.textContent = GRANT_TEXT[i];
+        a.addEventListener("click", async () => {
+            let dbData = await getData();
+            let dataIdx = dbData.findIndex(item => item.dbId === data.dbId);
+            if (dataIdx === -1 || dbData[dataIdx].grant === i)
+                return;
+            dbData[dataIdx].grant = i;
+            button.className = "btn btn-secondary dropdown-toggle bi";
+            button.textContent = GRANT_TEXT[data.grant];
+            button.classList.add(GRANT_ICON[data.grant]);
+            button.setAttribute("aria-expanded", false);
+            dropdownMenu.classList.remove("show");
+            dropdownMenu.querySelectorAll(".active").forEach(i => i.classList.remove("active"));
+            a.classList.add("active");
+            updateData(dbData[dataIdx]);
+        });
+        li.appendChild(a);
+        dropdownMenu.appendChild(li);
+    }
+    grantDiv.appendChild(button);
+    grantDiv.appendChild(dropdownMenu);
+    typeDivRow.appendChild(grantDiv);
+
     let deleteButtonRow = document.createElement("div");
     let deleteButtonDiv = document.createElement("div");
     let deleteButton = document.createElement("button");
@@ -88,13 +230,12 @@ async function buildShareItem(data) {
     deleteButtonRow.appendChild(deleteButtonDiv);
     deleteButtonDiv.appendChild(deleteButton);
     deleteButton.addEventListener("click", () => {
-        console.log("Request to revoke " +data.dbId); // FIXME
+        revokeData(data.dbId);
     });
 
     header.appendChild(headerButton);
     container.appendChild(header);
     accordionBody.appendChild(typeDivRow);
-    typeDivRow.appendChild(typeDiv);
     accordionBody.appendChild(deleteButtonRow);
     accordionBodyContainer.appendChild(accordionBody);
     container.appendChild(accordionBodyContainer);
@@ -114,7 +255,7 @@ window.showShareUi = async () => {
     document.getElementById("pch-share-wrapper").classList.remove("hidden");
     document.Title.pushTitle("Share");
     document.body.classList.add("overlay-visible");
-    const data = ((await getData()) || []).map(x => new ShareData(x)).sort((a, b) => a.compare(b));
+    const data = await getData();
     document.getElementById('pch-share-loading').classList.add("hidden");
     const container = document.getElementById('pch-share-container');
     container.innerHTML = "";
@@ -134,6 +275,11 @@ window.closeShareUi = () => {
 document.onClosePopinRequested(() => { window.closeShareUi(); });
 document.getElementById("pch-share-closeBt").addEventListener("click", window.closeShareUi);
 
+document.getElementById("pch-share-addLdap").addEventListener("click", () => {});
+document.getElementById("pch-share-addEmail").addEventListener("click", () => {});
+document.getElementById("pch-share-addLink").addEventListener("click", () => {});
+document.getElementById("pch-share-addEveryone").addEventListener("click", () => {});
+
 setTimeout(() => LoadingTasks.push(window.showShareUi), 1500);
 });
 

+ 7 - 1
templates/_uiShare.js

@@ -16,7 +16,13 @@ module.exports = `
             </div>
         </div>
         <div class="modal-footer">
-            <button type="button" class="btn btn-success">Add</button>
+            <div class="row"><div class="col">
+                <button type="button" id="pch-share-addLdap" class="btn btn-success bi bi-database">Add LDAP</button>
+                <button type="button" id="pch-share-addEmail" class="btn btn-success bi bi-envelope-at">Add Email</button>
+            </div></div><div class="row"><div class="col">
+                <button type="button" id="pch-share-addLink" class="btn btn-success bi bi-link-45deg">Add Link</button>
+                <button type="button" id="pch-share-addEveryone" class="btn btn-success bi bi-people">Add For Everyone</button>
+            </div></div>
         </div>
     </div>
 </div>