preserve vote/fave status on navigation (fixes philomena-dev/philomena#82)

This commit is contained in:
byte[] 2020-12-09 00:04:37 -05:00
parent c1ec2b3df2
commit 0cf48f0eab
2 changed files with 39 additions and 0 deletions

View file

@ -3,6 +3,7 @@
*/ */
import { fetchJson } from './utils/requests'; import { fetchJson } from './utils/requests';
import { $ } from './utils/dom';
const endpoints = { const endpoints = {
vote(imageId) { return `/images/${imageId}/vote` }, vote(imageId) { return `/images/${imageId}/vote` },
@ -19,6 +20,34 @@ function onImage(id, selector, cb) {
document.querySelectorAll(`${selector}[data-image-id="${id}"]`), cb); document.querySelectorAll(`${selector}[data-image-id="${id}"]`), cb);
} }
/* Since JS modifications to webpages, except form inputs, are not stored
* in the browser navigation history, we store a cache of the changes in a
* form to allow interactions to persist on navigation. */
function getCache() {
const cacheEl = $('.js-interaction-cache');
return Object.values(JSON.parse(cacheEl.value));
}
function modifyCache(callback) {
const cacheEl = $('.js-interaction-cache');
cacheEl.value = JSON.stringify(callback(JSON.parse(cacheEl.value)));
}
function cacheStatus(image_id, interaction_type, value) {
modifyCache(cache => {
cache[`${image_id}${interaction_type}`] = { image_id, interaction_type, value };
return cache;
});
}
function uncacheStatus(image_id, interaction_type) {
modifyCache(cache => {
delete cache[`${image_id}${interaction_type}`];
return cache;
});
}
function setScore(imageId, data) { function setScore(imageId, data) {
onImage(imageId, '.score', onImage(imageId, '.score',
el => el.textContent = data.score); el => el.textContent = data.score);
@ -34,26 +63,32 @@ function setScore(imageId, data) {
* Their classes also effect their behavior due to event delegation. */ * Their classes also effect their behavior due to event delegation. */
function showUpvoted(imageId) { function showUpvoted(imageId) {
cacheStatus(imageId, 'voted', 'up');
onImage(imageId, '.interaction--upvote', onImage(imageId, '.interaction--upvote',
el => el.classList.add('active')); el => el.classList.add('active'));
} }
function showDownvoted(imageId) { function showDownvoted(imageId) {
cacheStatus(imageId, 'voted', 'down');
onImage(imageId, '.interaction--downvote', onImage(imageId, '.interaction--downvote',
el => el.classList.add('active')); el => el.classList.add('active'));
} }
function showFaved(imageId) { function showFaved(imageId) {
cacheStatus(imageId, 'faved', '');
onImage(imageId, '.interaction--fave', onImage(imageId, '.interaction--fave',
el => el.classList.add('active')); el => el.classList.add('active'));
} }
function showHidden(imageId) { function showHidden(imageId) {
cacheStatus(imageId, 'hidden', '');
onImage(imageId, '.interaction--hide', onImage(imageId, '.interaction--hide',
el => el.classList.add('active')); el => el.classList.add('active'));
} }
function resetVoted(imageId) { function resetVoted(imageId) {
uncacheStatus(imageId, 'voted');
onImage(imageId, '.interaction--upvote', onImage(imageId, '.interaction--upvote',
el => el.classList.remove('active')); el => el.classList.remove('active'));
@ -62,11 +97,13 @@ function resetVoted(imageId) {
} }
function resetFaved(imageId) { function resetFaved(imageId) {
uncacheStatus(imageId, 'faved');
onImage(imageId, '.interaction--fave', onImage(imageId, '.interaction--fave',
el => el.classList.remove('active')); el => el.classList.remove('active'));
} }
function resetHidden(imageId) { function resetHidden(imageId) {
uncacheStatus(imageId, 'hidden');
onImage(imageId, '.interaction--hide', onImage(imageId, '.interaction--hide',
el => el.classList.remove('active')); el => el.classList.remove('active'));
} }
@ -97,6 +134,7 @@ function loadInteractions() {
/* Set up the actual interactions */ /* Set up the actual interactions */
displayInteractionSet(window.booru.interactions); displayInteractionSet(window.booru.interactions);
displayInteractionSet(getCache());
/* Next part is only for image index pages /* Next part is only for image index pages
* TODO: find a better way to do this */ * TODO: find a better way to do this */

View file

@ -29,4 +29,5 @@ html lang="en"
main#content class=layout_class(@conn) main#content class=layout_class(@conn)
= @inner_content = @inner_content
= render PhilomenaWeb.LayoutView, "_footer.html", assigns = render PhilomenaWeb.LayoutView, "_footer.html", assigns
form.hidden: input.js-interaction-cache type="hidden" value="{}"
= clientside_data(@conn) = clientside_data(@conn)