Pārlūkot izejas kodu

Fixes #28 remove lost items from local IndexedStorage
Make year and month sticky top

isundil 1 gadu atpakaļ
vecāks
revīzija
0b6be404f0

+ 12 - 2
model/mediaService.js

@@ -201,8 +201,13 @@ function fetchMediasBuildSubQuery(startTs, count, access, maxVersion) {
     }
 
     // order and limit
-    query += whereClause + " order by date desc limit ?";
-    args.push(count);
+    query += whereClause + " order by date desc ";
+
+    if (count > 0) {
+        query += "limit ?";
+        args.push(count);
+    }
+
     return {
         query: query,
         args: args
@@ -226,6 +231,11 @@ module.exports.fetchMedias = async function(app, startTs, count, access, maxVers
     return result;
 };
 
+module.exports.fetchMediasSumWithAccess = async function(app, access) {
+    const subQuery = fetchMediasBuildSubQuery(0, -1, await buildAccessList(app, access), 0);
+    return (await app.databaseHelper.runSql(subQuery.query, subQuery.args)).map(x => x.fixedSum);
+};
+
 module.exports.fetchMediasWithAccess = async function(app, startTs, count, access, maxVersion) {
     let result = [];
     let lastTs = startTs;

+ 8 - 0
router/api.js

@@ -162,6 +162,14 @@ module.exports = { register: app => {
             maxVersion: maxVersion
         });
     });
+    app.router.get("/api/media/sumlist", async (req, res) => {
+        app.routerUtils.onApiRequest(req, res);
+        app.routerUtils.jsonResponse(res, {
+            data: await MediaService.fetchMediasSumWithAccess(
+                app,
+                req.sessionObj?.accessList)
+        });
+    });
     app.router.get("/api/media/:md5sum", async (req, res) => {
         app.routerUtils.onApiRequest(req, res);
         let data = MediaToJson(await MediaService.fetchOne(app, req.params.md5sum, req.sessionObj?.accessList, 0));

+ 16 - 1
static/public/css/style.css

@@ -45,7 +45,7 @@ body.filter-active #pch-navbar .bt-filter-inactive {
 }
 
 #pch-page {
-    margin-top: 6rem;
+    margin-top: 3rem;
     padding: 1em 3em;
 }
 
@@ -65,6 +65,21 @@ body.filter-active #pch-navbar .bt-filter-inactive {
     justify-content: center;
 }
 
+#pch-mediaList .medialist-year {
+    z-index: 1022;
+    margin-top: -2.5em;
+    padding-top: 2.5em;
+}
+#pch-mediaList .medialist-month {
+    border-bottom: 2px dashed;
+    margin-top: -4.5em;
+    padding-top: 4.5em;
+    padding-bottom: 0.5em;
+}
+#pch-mediaList .medialist-year, #pch-mediaList .medialist-month {
+    background-color: var(--bs-body-bg);
+}
+
 #pch-mediaList > .pch-image.loading {
     height: 250px;
 }

+ 52 - 2
static/public/js/indexedCache.js

@@ -30,8 +30,10 @@
                     this.onDbReady(evt.target.result);
                 };
             });
-            MediaStorage.Instance.addEventListener("doneLoading", (evt) => {
-                this.pushMedias(MediaStorage.Instance.medias, MediaStorage.Instance.getDbVersion());
+            MediaStorage.Instance.addEventListener("doneLoading", async evt => {
+                await this.pushMedias(MediaStorage.Instance.medias, MediaStorage.Instance.getDbVersion());
+                let removed = await this.removeObsolete();
+                removed.length && MediaStorage.Instance.removeMedia(removed);
             });
         }
 
@@ -87,6 +89,54 @@
             return { medias: data, version: data.length ? this.#version : 0 };
         }
 
+        allKeyCount() {
+            return new Promise(async ok => {
+                let count = 0;
+                let transaction = this.#db.transaction([INDEXEDCACHE_DATABASE_NAME], IDBTransaction.READ);
+                transaction.oncomplete = () => ok(count);
+                transaction.onerror = () => ok(count);
+                count = (await (new Promise(okKey => {
+                    let req = transaction.objectStore(INDEXEDCACHE_DATABASE_NAME).getAllKeys();
+                    req.onsuccess = evt => {
+                        okKey(req?.result || []);
+                    }
+                }))).length;
+            });
+        }
+
+        #getObsoleteKeys() {
+            return new Promise((ok, ko) => {
+                $.get(`/api/media/sumlist`, async srvKeys => {
+                    let transaction = this.#db.transaction([INDEXEDCACHE_DATABASE_NAME], IDBTransaction.READ);
+                    let obsoleteIndexes = [];
+                    transaction.oncomplete = () => ok(obsoleteIndexes);
+                    transaction.onerror = () => ok(obsoleteIndexes);
+                    obsoleteIndexes = (await (new Promise((okLocalKey) => {
+                        let req = transaction.objectStore(INDEXEDCACHE_DATABASE_NAME).getAllKeys();
+                        req.onsuccess = evt => {
+                            okLocalKey(req?.result || []);
+                        }
+                    }))).filter(i => srvKeys.data.indexOf(i) === -1);
+                });
+            });
+        }
+
+        async removeObsolete() {
+            await this.#openReq;
+            if (!this.#db)
+                return;
+
+            let obsoleteIndexes = await this.#getObsoleteKeys();
+            for (let i of obsoleteIndexes)
+                await new Promise((ok, ko) => {
+                    let transaction = this.#db.transaction([INDEXEDCACHE_DATABASE_NAME], IDBTransaction.READ_WRITE);
+                    transaction.oncomplete = ok;
+                    transaction.onerror = ko;
+                    transaction.objectStore(INDEXEDCACHE_DATABASE_NAME).delete(i);
+                });
+            return obsoleteIndexes;
+        }
+
         async pushMedias(mediaArr, version) {
             await this.#openReq;
             if (!this.#db)

+ 9 - 1
static/public/js/medias.js

@@ -129,6 +129,7 @@ class MediaStorage extends EventTarget
     async restoreMetaList() {
         if (this.isLoading())
             return;
+        this.#reset();
         this.#isLoading = true;
         document.getElementById("pch-infiniteScrollLoading").classList.remove("hidden");
         let hasData = false;
@@ -155,7 +156,7 @@ class MediaStorage extends EventTarget
                 let oldest = isUpdate !== true ? (this.oldest?.getDateTs() || 0) : 0;
                 let oldestArg = oldest ? `&from=${oldest}` : "";
                 let requestCount = 300;
-                $.get(`/api/media/list?count=${requestCount}${chronology}${oldestArg}&version=${this.#dbVersion}`, data => {
+                $.get(`/api/media/list?count=${requestCount}${chronology}${oldestArg}&version=${this.#dbVersion}`, async data => {
                     this.pushAll(data.data.map(i => new Media(i)));
                     if (data.first || data.last)
                         window.chronology.rebuildRange(data.first, data.last);
@@ -282,6 +283,13 @@ class MediaStorage extends EventTarget
         return this.getMediaBetweenIndexes(aIndex, bIndex);
     }
 
+    removeMedia(md5sums) {
+        let medias = this.medias.filter(x => md5sums.indexOf(x.fixedSum) >= 0);
+        this.medias = this.medias.filter(x => md5sums.indexOf(x.fixedSum) === -1);
+        for (let i of medias)
+            i.ui.root.remove();
+    }
+
     getMediaLocal(md5sum) {
         return this.medias.find(x => x.fixedSum === md5sum);
     }

+ 2 - 2
static/public/js/uiMedia.js

@@ -119,14 +119,14 @@ $(() => {
 
     function buildYear(date) {
         let result = document.createElement('h3');
-        result.className = "col-12";
+        result.className = "col-12 sticky-top medialist-year";
         result.textContent = date.getUTCFullYear();
         return result;
     }
 
     function buildMonth(date) {
         let result = document.createElement('h4');
-        result.className = "col-12";
+        result.className = "col-12 sticky-top medialist-month";
         result.textContent = date.toLocaleString('default', { month: 'long' });
         return result;
     }