130 lines
7.4 KiB
JavaScript
130 lines
7.4 KiB
JavaScript
/*
|
|
* Custom LightGallery plugin to add some buttons for administration
|
|
*
|
|
* This file is part of photo21
|
|
* Copyright (C) 2022 Amicale des élèves de l'ENS Paris-Saclay
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
class lgAdmin {
|
|
constructor(instance, $LG) {
|
|
this.core = instance;
|
|
this.$LG = $LG;
|
|
this.isStaff = document.querySelector('[name=is_staff]').value === "true";
|
|
this.userId = document.querySelector('[name=user_id]').value;
|
|
this.csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
|
|
this.photoId = 0;
|
|
return this;
|
|
}
|
|
|
|
init() {
|
|
const adminIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" fill=\"currentColor\" class=\"bi bi-gear-fill\" viewBox=\"0 0 16 16\"><path d=\"M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872l-.1-.34zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z\"/></svg>";
|
|
const deleteIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" fill=\"currentColor\" class=\"bi\" viewBox=\"0 0 16 16\"><path d=\"M11 1.5v1h3.5a.5.5 0 0 1 0 1h-.538l-.853 10.66A2 2 0 0 1 11.115 16h-6.23a2 2 0 0 1-1.994-1.84L2.038 3.5H1.5a.5.5 0 0 1 0-1H5v-1A1.5 1.5 0 0 1 6.5 0h3A1.5 1.5 0 0 1 11 1.5Zm-5 0v1h4v-1a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5ZM4.5 5.029l.5 8.5a.5.5 0 1 0 .998-.06l-.5-8.5a.5.5 0 1 0-.998.06Zm6.53-.528a.5.5 0 0 0-.528.47l-.5 8.5a.5.5 0 0 0 .998.058l.5-8.5a.5.5 0 0 0-.47-.528ZM8 4.5a.5.5 0 0 0-.5.5v8.5a.5.5 0 0 0 1 0V5a.5.5 0 0 0-.5-.5Z\"/></svg>";;
|
|
const reportIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" fill=\"currentColor\" class=\"bi\" viewBox=\"0 0 16 16\"><path d=\"M11.46.146A.5.5 0 0 0 11.107 0H4.893a.5.5 0 0 0-.353.146L.146 4.54A.5.5 0 0 0 0 4.893v6.214a.5.5 0 0 0 .146.353l4.394 4.394a.5.5 0 0 0 .353.146h6.214a.5.5 0 0 0 .353-.146l4.394-4.394a.5.5 0 0 0 .146-.353V4.893a.5.5 0 0 0-.146-.353L11.46.146zM8 4c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995A.905.905 0 0 1 8 4zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z\"/></svg>";
|
|
|
|
// Add button linking to Django admin page
|
|
this.core.$toolbar.append(`<a href="#" target="_blank" id="lg-admin" title="Go to admin" class="lg-icon lg-bi-icon">${adminIcon}</a>`);
|
|
document.getElementById("lg-admin").style.display = this.isStaff ? 'block' : 'none';
|
|
|
|
// Add button to delete photo
|
|
this.core.$toolbar.append(`<a href="#" id="lg-delete" title="Remove this photo" class="lg-icon lg-bi-icon">${deleteIcon}</a>`);
|
|
document.getElementById("lg-delete").style.display = 'none';
|
|
document.getElementById("lg-delete").addEventListener('click', this.onDelete.bind(this));
|
|
|
|
// Add button to report photo
|
|
this.core.$toolbar.append(`<a href="#" id="lg-report" title="Notify abuse" class="lg-icon lg-bi-icon">${reportIcon}</a>`);
|
|
document.getElementById("lg-report").addEventListener('click', this.onReport.bind(this));
|
|
|
|
this.core.LGel.on("lgAfterSlide.admin", this.onAfterSlide.bind(this));
|
|
}
|
|
|
|
// Event called when showing a new slide
|
|
onAfterSlide(event) {
|
|
this.photoId = this.core.galleryItems[event.detail.index].slideName;
|
|
document.getElementById("lg-admin").href = `/admin/photologue/photo/${this.photoId}/change/`;
|
|
const el = document.querySelector(`[data-slide-name='${this.photoId}']`);
|
|
const ownerId = el ? el.dataset.ownerId : null;
|
|
const canDelete = this.isStaff || (ownerId && ownerId === this.userId);
|
|
document.getElementById("lg-delete").style.display = canDelete ? 'block' : 'none';
|
|
}
|
|
|
|
// Navigate away from a photo that was just deleted/hidden.
|
|
// We slide first (while the item still exists), then remove and reindex after the
|
|
// animation so lightgallery's internal index/counter stays consistent.
|
|
_navigateAfterRemove(photoId, currentIndex) {
|
|
const total = this.core.galleryItems.length;
|
|
if (total <= 1) {
|
|
const el = document.querySelector(`[data-slide-name='${photoId}']`);
|
|
if (el) el.remove();
|
|
this.core.refresh();
|
|
this.core.closeGallery();
|
|
return;
|
|
}
|
|
const goingForward = currentIndex < total - 1;
|
|
const targetIndex = goingForward ? currentIndex + 1 : currentIndex - 1;
|
|
this.core.LGel.on('lgAfterSlide.adminRemove', () => {
|
|
this.core.LGel.off('lgAfterSlide.adminRemove');
|
|
const thumb = document.querySelector(`[data-slide-name='${photoId}']`);
|
|
if (thumb) thumb.remove();
|
|
const lgId = this.core.lgId;
|
|
const deletedItem = document.getElementById(`lg-item-${lgId}-${currentIndex}`);
|
|
if (deletedItem) deletedItem.remove();
|
|
document.querySelectorAll(`[id^="lg-item-${lgId}-"]`).forEach(item => {
|
|
const idx = parseInt(item.id.split('-').pop(), 10);
|
|
if (idx > currentIndex) item.id = `lg-item-${lgId}-${idx - 1}`;
|
|
});
|
|
this.core.refresh();
|
|
if (goingForward) {
|
|
this.core.index = currentIndex;
|
|
this.core.updateCurrentCounter(currentIndex);
|
|
}
|
|
});
|
|
this.core.slide(targetIndex, false, false, false);
|
|
}
|
|
|
|
// Event called when user click on delete button
|
|
onDelete(event) {
|
|
event.preventDefault();
|
|
if(confirm("Are you sure to delete this photo?")) {
|
|
// Build form request
|
|
const photoId = this.photoId;
|
|
const currentIndex = this.core.index;
|
|
let data = new FormData();
|
|
data.append('csrfmiddlewaretoken', this.csrfToken);
|
|
fetch(`/photo/${photoId}/delete/`, {
|
|
method: "POST",
|
|
redirect: "manual", // do not load gallery again
|
|
body: data,
|
|
credentials: 'same-origin',
|
|
}).then(() => this._navigateAfterRemove(photoId, currentIndex));
|
|
}
|
|
}
|
|
|
|
// Event called when user click on report button
|
|
onReport(event) {
|
|
event.preventDefault();
|
|
if(confirm("Are you sure to report this photo?")) {
|
|
// Build form request
|
|
const photoId = this.photoId;
|
|
const currentIndex = this.core.index;
|
|
let data = new FormData();
|
|
data.append('csrfmiddlewaretoken', this.csrfToken);
|
|
fetch(`/photo/${photoId}/report/`, {
|
|
method: "POST",
|
|
redirect: "manual", // do not load gallery again
|
|
body: data,
|
|
credentials: 'same-origin',
|
|
}).then(() => {
|
|
const thumbnail = document.querySelector(`[data-slide-name='${photoId}']`);
|
|
if (!this.isStaff) {
|
|
this._navigateAfterRemove(photoId, currentIndex);
|
|
} else {
|
|
location.reload();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// Plugins must have destroy prototype
|
|
destroy() { }
|
|
}
|