UX: Restore scroll position in albums & labels #896

This commit is contained in:
Michael Mayer 2021-01-16 12:41:17 +01:00
parent bc0bde4771
commit 67e655f6d0
6 changed files with 122 additions and 33 deletions

View file

@ -111,6 +111,19 @@ const router = new Router({
routes: Routes,
mode: "history",
saveScrollPosition: true,
scrollBehavior: (to, from, savedPosition) => {
if (savedPosition) {
return new Promise((resolve) => {
Notify.ajaxWait().then(() => {
setTimeout(() => {
resolve(savedPosition);
}, 200);
});
});
} else {
return { x: 0, y: 0 };
}
},
});
router.beforeEach((to, from, next) => {

View file

@ -31,6 +31,9 @@ https://docs.photoprism.org/developer-guide/
import Event from "pubsub-js";
import { $gettext } from "./vm";
let ajaxPending = 0;
let ajaxCallbacks = [];
const Notify = {
info: function (message) {
Event.publish("notify.info", { message });
@ -49,10 +52,34 @@ const Notify = {
Event.publish("session.logout", { message });
},
ajaxStart: function () {
ajaxPending++;
Event.publish("ajax.start");
},
ajaxEnd: function () {
ajaxPending--;
Event.publish("ajax.end");
if (!this.ajaxBusy()) {
ajaxCallbacks.forEach((resolve) => {
resolve();
});
}
},
ajaxBusy: function () {
if (ajaxPending < 0) {
ajaxPending = 0;
}
return ajaxPending > 0;
},
ajaxWait: function () {
return new Promise((resolve) => {
if (this.ajaxBusy()) {
ajaxCallbacks.push(resolve);
} else {
resolve();
}
});
},
blockUI: function () {
const el = document.getElementById("busy-overlay");

View file

@ -283,6 +283,19 @@ export default {
}
},
methods: {
searchCount() {
const offset = parseInt(window.localStorage.getItem("albums_offset"));
if(this.offset > 0 || !offset) {
return this.batchSize;
}
return offset + this.batchSize;
},
setOffset(offset) {
this.offset = offset;
window.localStorage.setItem("albums_offset", offset);
},
share(album) {
this.model = album;
this.dialog.share = true;
@ -382,19 +395,19 @@ export default {
Object.assign(params, this.staticFilter);
}
Album.search(params).then(response => {
this.results = this.dirty ? response.models : this.results.concat(response.models);
Album.search(params).then(resp => {
this.results = this.dirty ? resp.models : this.results.concat(resp.models);
this.scrollDisabled = (response.models.length < count);
this.scrollDisabled = (resp.count < resp.limit);
if (this.scrollDisabled) {
this.offset = offset;
this.setOffset(resp.offset);
if (this.results.length > 1) {
this.$notify.info(this.$gettextInterpolate(this.$gettext("All %{n} albums loaded"), {n: this.results.length}));
}
} else {
this.offset = offset + count;
this.setOffset(resp.offset + resp.limit);
this.page++;
this.$nextTick(() => {
@ -434,7 +447,7 @@ export default {
},
searchParams() {
const params = {
count: this.batchSize,
count: this.searchCount(),
offset: this.offset,
};
@ -464,12 +477,11 @@ export default {
const params = this.searchParams();
Album.search(params).then(response => {
this.offset = this.batchSize;
Album.search(params).then(resp => {
this.offset = resp.limit;
this.results = resp.models;
this.results = response.models;
this.scrollDisabled = (response.models.length < this.batchSize);
this.scrollDisabled = (resp.count < resp.limit);
if (this.scrollDisabled) {
if (!this.results.length) {

View file

@ -196,6 +196,19 @@ export default {
}
},
methods: {
searchCount() {
const offset = parseInt(window.localStorage.getItem("labels_offset"));
if(this.offset > 0 || !offset) {
return this.batchSize;
}
return offset + this.batchSize;
},
setOffset(offset) {
this.offset = offset;
window.localStorage.setItem("labels_offset", offset);
},
selectRange(rangeEnd, models) {
if (!models || !models[rangeEnd] || !(models[rangeEnd] instanceof RestModel)) {
console.warn("selectRange() - invalid arguments:", rangeEnd, models);
@ -332,18 +345,18 @@ export default {
Object.assign(params, this.staticFilter);
}
Label.search(params).then(response => {
this.results = this.dirty ? response.models : this.results.concat(response.models);
Label.search(params).then(resp => {
this.results = this.dirty ? resp.models : this.results.concat(resp.models);
this.scrollDisabled = (response.models.length < count);
this.scrollDisabled = (resp.count < resp.limit);
if (this.scrollDisabled) {
this.offset = offset;
this.setOffset(resp.offset);
if (this.results.length > 1) {
this.$notify.info(this.$gettextInterpolate(this.$gettext("All %{n} labels loaded"), {n: this.results.length}));
}
} else {
this.offset = offset + count;
this.setOffset(resp.offset + resp.limit);
this.page++;
this.$nextTick(() => {
@ -383,7 +396,7 @@ export default {
},
searchParams() {
const params = {
count: this.batchSize,
count: this.searchCount(),
offset: this.offset,
};
@ -421,12 +434,11 @@ export default {
const params = this.searchParams();
Label.search(params).then(response => {
this.offset = this.batchSize;
Label.search(params).then(resp => {
this.offset = resp.limit;
this.results = resp.models;
this.results = response.models;
this.scrollDisabled = (response.models.length < this.batchSize);
this.scrollDisabled = (resp.count < resp.limit);
if (this.scrollDisabled) {
this.$notify.info(this.$gettextInterpolate(this.$gettext("%{n} labels found"), {n: this.results.length}));

View file

@ -110,6 +110,19 @@ const router = new Router({
routes: Routes,
mode: "history",
saveScrollPosition: true,
scrollBehavior: (to, from, savedPosition) => {
if (savedPosition) {
return new Promise((resolve) => {
Notify.ajaxWait().then(() => {
setTimeout(() => {
resolve(savedPosition);
}, 200);
});
});
} else {
return { x: 0, y: 0 };
}
},
});
router.beforeEach((to, from, next) => {

View file

@ -195,6 +195,19 @@ export default {
}
},
methods: {
searchCount() {
const offset = parseInt(window.localStorage.getItem("share_albums_offset"));
if(this.offset > 0 || !offset) {
return this.batchSize;
}
return offset + this.batchSize;
},
setOffset(offset) {
this.offset = offset;
window.localStorage.setItem("share_albums_offset", offset);
},
showUpload() {
Event.publish("dialog.upload");
},
@ -282,19 +295,19 @@ export default {
Object.assign(params, this.staticFilter);
}
Album.search(params).then(response => {
this.results = this.dirty ? response.models : this.results.concat(response.models);
Album.search(params).then(resp => {
this.results = this.dirty ? resp.models : this.results.concat(resp.models);
this.scrollDisabled = (response.models.length < count);
this.scrollDisabled = (resp.count < resp.limit);
if (this.scrollDisabled) {
this.offset = offset;
this.setOffset(resp.offset);
if (this.results.length > 1) {
this.$notify.info(this.$gettextInterpolate(this.$gettext("All %{n} albums loaded"), {n: this.results.length}));
}
} else {
this.offset = offset + count;
this.setOffset(resp.offset + resp.limit);
this.page++;
this.$nextTick(() => {
@ -334,7 +347,7 @@ export default {
},
searchParams() {
const params = {
count: this.batchSize,
count: this.searchCount(),
offset: this.offset,
};
@ -364,12 +377,11 @@ export default {
const params = this.searchParams();
Album.search(params).then(response => {
this.offset = this.batchSize;
Album.search(params).then(resp => {
this.offset = resp.limit;
this.results = resp.models;
this.results = response.models;
this.scrollDisabled = (response.models.length < this.batchSize);
this.scrollDisabled = (resp.count < resp.limit);
if (this.scrollDisabled) {
if (!this.results.length) {