1
0
mirror of https://github.com/s427/MARL.git synced 2025-01-31 11:34:46 +01:00

1231 lines
30 KiB
JavaScript

// stores definitions
const filesStore = {
resetState() {
this.raw = {};
this.actor = {};
this.outbox = {};
this.toots = [];
this.likes = [];
this.bookmarks = [];
this.avatar = {};
this.header = {};
this.sortAsc = true;
this.pageSize = 10;
this.currentPage = 1;
this.loading = false;
this.loaded = {
actor: false,
avatar: false,
banner: false,
outbox: false,
likes: false,
bookmarks: false,
};
this.languages = {};
this.boostsAuthors = {};
this.filters = {};
this.filtersDefault = {
fullText: "",
hashtagText: "",
mentionText: "",
externalLink: "",
summary: "",
isEdited: false,
noStartingAt: false,
hasExternalLink: false,
hasHashtags: false,
hasMentions: false,
hasSummary: false,
isSensitive: false,
visibilityPublic: true,
visibilityUnlisted: true,
visibilityFollowers: true,
visibilityMentioned: true,
typeOriginal: true,
typeBoost: true,
attachmentAny: false,
attachmentImage: false,
attachmentVideo: false,
attachmentSound: false,
attachmentNoAltText: false,
attachmentWithAltText: false,
// automatically generated (see loadJsonFile()):
// langs_en: true,
// langs_fr: true,
// langs_de: true,
// etc
};
this.filtersActive = false;
this.tagsFilters = {
hashtags: "",
mentions: "",
boostsAuthors: "",
};
},
setFilter() {
this.checkPagingValue();
scrollTootsToTop();
pagingUpdated();
if (JSON.stringify(this.filters) === JSON.stringify(this.filtersDefault)) {
this.filtersActive = false;
} else {
this.filtersActive = true;
}
const self = this;
setTimeout(() => {
self.checkPagingValue();
}, 50);
},
filterByTag(filter, value, id) {
if (value) {
if (value === this.filters[filter]) {
this.filters[filter] = "";
} else {
this.filters[filter] = value;
}
}
// "boosted users" group
// in this case let's also (un)check the 'boost type' filters
if (filter == "fullText") {
if (this.filters[filter] === "") {
this.filters.typeBoost = true;
this.filters.typeOriginal = true;
} else {
this.filters.typeBoost = true;
this.filters.typeOriginal = false;
}
}
this.setFilter();
// keyboard focus may be lost when tags list changes
setTimeout(() => {
document.getElementById(id).focus();
}, 100);
},
resetFilters(userAction) {
this.filters = JSON.parse(JSON.stringify(this.filtersDefault));
if (userAction) {
this.currentPage = 1;
this.filtersActive = false;
scrollTootsToTop();
pagingUpdated();
}
},
get filteredToots() {
const f = this.filters;
const fa = this.filtersActive;
return this.toots.filter((t) => {
if (!fa) {
return true;
}
if (f.fullText) {
let show = false;
if (t._marl.textContent) {
const filterValue = f.fullText.toLowerCase();
if (
filterValue &&
t._marl.textContent &&
t._marl.textContent.indexOf(filterValue) >= 0
) {
show = true;
}
}
if (!show) {
return show;
}
}
if (f.hashtagText) {
if (typeof t.object === "object" && t.object !== null && t.object.tag) {
const filterValue = f.hashtagText.toLowerCase();
if (
!t.object.tag.some((t) => {
return (
t.type === "Hashtag" &&
t.name.toLowerCase().indexOf(filterValue) > -1
);
})
) {
return false;
}
} else {
return false;
}
}
if (f.mentionText) {
if (typeof t.object === "object" && t.object !== null && t.object.tag) {
const filterValue = f.mentionText.toLowerCase();
if (
!t.object.tag.some((t) => {
return (
t.type === "Mention" &&
t.name.toLowerCase().indexOf(filterValue) > -1
);
})
) {
return false;
}
} else {
return false;
}
}
if (f.summary) {
if (t._marl.summary) {
const filterValue = f.summary.toLowerCase();
if (t._marl.summary.indexOf(filterValue) === -1) {
return false;
}
} else {
return false;
}
}
if (f.isEdited) {
if (
!(
typeof t.object === "object" &&
t.object !== null &&
t.object.updated
)
) {
return false;
}
}
if (f.noStartingAt) {
if (!t._marl.textContent || t._marl.textContent.indexOf("@") === 0) {
return false;
}
}
if (f.hasExternalLink) {
if (!t._marl.externalLinks || !t._marl.externalLinks.length) {
return false;
}
}
if (f.hasHashtags) {
if (typeof t.object === "object" && t.object !== null && t.object.tag) {
if (
!t.object.tag.some((t) => {
return t.type === "Hashtag";
})
) {
return false;
}
} else {
return false;
}
}
if (f.hasMentions) {
if (typeof t.object === "object" && t.object !== null && t.object.tag) {
if (
!t.object.tag.some((t) => {
return t.type === "Mention";
})
) {
return false;
}
} else {
return false;
}
}
if (f.hasSummary) {
if (typeof t.object === "object" && t.object !== null) {
if (!t.object.summary) {
return false;
}
} else {
return false;
}
}
if (f.isSensitive) {
if (typeof t.object === "object" && t.object !== null) {
if (!t.object.sensitive) {
return false;
}
} else {
return false;
}
}
if (f.externalLink) {
let show = false;
if (t._marl.externalLinks && t._marl.externalLinks.length) {
const filterValue = f.externalLink.toLowerCase();
show = t._marl.externalLinks.some((link) => {
return (
link.href.indexOf(filterValue) > -1 ||
link.text.indexOf(filterValue) > -1
);
});
}
if (!show) {
return false;
}
}
if (!f.visibilityPublic && t._marl.visibility[0] === "public") {
return false;
}
if (!f.visibilityUnlisted && t._marl.visibility[0] === "unlisted") {
return false;
}
if (!f.visibilityFollowers && t._marl.visibility[0] === "followers") {
return false;
}
if (!f.visibilityMentioned && t._marl.visibility[0] === "mentioned") {
return false;
}
if (!f.typeOriginal && t.type === "Create") {
return false;
}
if (!f.typeBoost && t.type === "Announce") {
return false;
}
if (f.attachmentAny) {
if (!t._marl.hasAttachments) {
return false;
}
}
if (f.attachmentImage) {
if (t._marl.hasAttachments) {
if (
!t.object.attachment.some((att) => {
return attachmentIsImage(att);
})
) {
return false;
}
} else {
return false;
}
}
if (f.attachmentVideo) {
if (t._marl.hasAttachments) {
if (
!t.object.attachment.some((att) => {
return attachmentIsVideo(att);
})
) {
return false;
}
} else {
return false;
}
}
if (f.attachmentSound) {
if (t._marl.hasAttachments) {
if (
!t.object.attachment.some((att) => {
return attachmentIsSound(att);
})
) {
return false;
}
} else {
return false;
}
}
if (f.attachmentNoAltText) {
if (t._marl.hasAttachments) {
if (
!t.object.attachment.some((att) => {
return att.name === null;
})
) {
return false;
}
} else {
return false;
}
}
if (f.attachmentWithAltText) {
if (t._marl.hasAttachments) {
if (
!t.object.attachment.some((att) => {
return att.name;
})
) {
return false;
}
} else {
return false;
}
}
for (let lang in this.languages) {
if (f.hasOwnProperty("langs_" + lang) && f["langs_" + lang] === false) {
if (t.type === "Create") {
if (t.object.contentMap.hasOwnProperty(lang)) {
return false;
}
} else {
return false;
}
}
}
return true;
});
},
get listHashtags() {
return this.listTags("Hashtag");
},
get listMentions() {
return this.listTags("Mention");
},
listTags(type) {
let filterSource = "";
switch (type) {
case "Mention":
filterSource = "mentions";
break;
case "Hashtag":
filterSource = "hashtags";
break;
}
let h = this.filteredToots.reduce((accu, toot) => {
if (tootHasTags(toot)) {
for (const key in toot.object.tag) {
const tag = toot.object.tag[key];
if (
tag.type &&
tag.type === type &&
tag.name &&
tag.name
.toLowerCase()
.indexOf(this.tagsFilters[filterSource].toLowerCase()) >= 0
) {
if (
accu.some((item) => {
return item.name === tag.name;
})
) {
accu.map((item) => {
if (item.name === tag.name) {
item.nb++;
}
});
} else {
accu.push({
name: tag.name,
href: tag.href,
nb: 1,
});
}
}
}
}
return accu;
}, []);
h.sort((a, b) => {
if (a.nb === b.nb) {
return a.name.localeCompare(b.name);
} else {
return b.nb - a.nb;
}
});
return h;
},
get listBoostsAuthors() {
let r = this.boostsAuthors.reduce((accu, item) => {
if (
item.name
.toLowerCase()
.indexOf(this.tagsFilters.boostsAuthors.toLowerCase()) >= 0
) {
accu.push(item);
}
return accu;
}, []);
r.sort((a, b) => {
if (a.nb === b.nb) {
let aHasNoName = a.name.indexOf("? ") === 0;
let bHasNoName = b.name.indexOf("? ") === 0;
if (aHasNoName && bHasNoName) {
return a.name.localeCompare(b.name);
} else if (aHasNoName) {
return 1;
} else if (bHasNoName) {
return -1;
} else {
return a.name.localeCompare(b.name);
}
} else {
if (a.nb === b.nb) {
return a.name.localeCompare(b.name);
} else {
return b.nb - a.nb;
}
}
});
return r;
},
get allLoaded() {
return (
this.loaded.actor &&
this.loaded.avatar &&
this.loaded.banner &&
this.loaded.outbox &&
this.loaded.likes &&
this.loaded.bookmarks
);
},
get totalPages() {
return Math.ceil(this.filteredToots.length / this.pageSize);
},
get pagedToots() {
if (this.filteredToots) {
return this.filteredToots.filter((toot, index) => {
let start = (this.currentPage - 1) * this.pageSize;
let end = this.currentPage * this.pageSize;
if (index >= start && index < end) return true;
});
} else {
return [];
}
},
toggleTootsOrder() {
this.sortAsc = !this.sortAsc;
this.toots.sort((a, b) => {
if (this.sortAsc) {
return a.published.localeCompare(b.published);
} else {
return b.published.localeCompare(a.published);
}
});
scrollTootsToTop();
pagingUpdated();
},
checkPagingValue() {
if (this.currentPage < 1) {
this.currentPage = 1;
} else if (
(this.currentPage - 1) * this.pageSize >
this.filteredToots.length
) {
this.currentPage = this.totalPages;
}
},
nextPage(setFocusTo) {
if (this.currentPage * this.pageSize < this.filteredToots.length) {
this.currentPage++;
scrollTootsToTop(setFocusTo);
pagingUpdated();
}
},
prevPage(setFocusTo) {
if (this.currentPage > 1) {
this.currentPage--;
scrollTootsToTop(setFocusTo);
pagingUpdated();
}
},
firstPage(setFocusTo) {
this.currentPage = 1;
scrollTootsToTop(setFocusTo);
pagingUpdated();
},
lastPage(setFocusTo) {
this.currentPage = this.totalPages;
scrollTootsToTop(setFocusTo);
pagingUpdated();
},
};
const lightboxStore = {
resetState() {
this.show = false;
this.data = [];
this.index = 0;
this.source = "";
},
open(att, index, source) {
this.data = att;
this.show = true;
this.index = index;
this.source = source;
document.getElementById("main-section-inner").setAttribute("inert", true);
setTimeout(() => {
document.getElementById("lightbox").focus();
}, 50);
},
openProfileImg(name, source) {
const data = [
{
name: name,
url: name,
mediaType: Alpine.store("files")[name].type,
},
];
this.open(data, 0, source);
},
close() {
const source = this.source;
this.data = [];
this.index = 0;
this.show = false;
this.source = "";
document.getElementById("main-section-inner").removeAttribute("inert");
document.getElementById(source).focus();
},
showNext() {
this.index++;
if (this.index >= this.data.length) {
this.index = 0;
}
if (!attachmentIsImage(this.data[this.index])) {
this.showNext();
}
},
showPrev() {
this.index--;
if (this.index < 0) {
this.index = this.data.length - 1;
}
if (!attachmentIsImage(this.data[this.index])) {
this.showPrev();
}
},
};
const uiStore = {
resetState() {
this.pagingOptionsVisible = false;
this.openMenu = "";
this.menuIsActive = false;
},
togglePagingOptions() {
this.pagingOptionsVisible = !this.pagingOptionsVisible;
if (this.pagingOptionsVisible) {
setTimeout(() => {
document.getElementById("paging-options").focus();
}, 100);
}
},
get pagingOptionsClass() {
return this.pagingOptionsVisible ? "open" : "";
},
menuClose() {
const name = this.openMenu;
this.openMenu = "";
this.setInert();
// bring focus back to where it was before the panel was opened
document
.querySelector("#main-section-inner .mobile-menu .menu-" + name)
.focus();
},
menuOpen(name) {
this.openMenu = name;
this.resetPanels();
this.setInert();
setTimeout(() => {
document.getElementById("panel-" + name).focus();
}, 100);
},
menuToggle(name) {
switch (name) {
case "actor":
case "filters":
case "tags":
if (this.openMenu === name) {
this.menuClose();
} else {
this.menuOpen(name);
}
break;
}
},
resetPanels() {
const name = this.openMenu;
document.querySelectorAll(`#panel-${name} details[open]`).forEach((e) => {
e.removeAttribute("open");
});
setTimeout(() => {
document.getElementById("panel-" + name).scrollTop = 0;
}, 250);
},
checkMenuState() {
const menu = document.getElementById("mobile-menu");
if (window.getComputedStyle(menu, null).display === "none") {
this.menuIsActive = false;
} else {
this.menuIsActive = true;
}
this.setInert();
},
setInert() {
// set the 'inert' state on the side panels (actor, filters, tags)
// depending on whether they are hidden or not, AND whether the
// mobile menu is active
document.querySelectorAll("#main-section-inner > *").forEach((e) => {
e.removeAttribute("inert");
});
if (this.menuIsActive) {
if (this.openMenu) {
document
.querySelectorAll(
"#main-section-inner > *:not(.mobile-menu, .panel-backdrop, #panel-" +
this.openMenu
)
.forEach((e) => {
e.setAttribute("inert", true);
});
} else {
document
.querySelectorAll("#panel-actor, #panel-filters, #panel-tags")
.forEach((e) => {
e.setAttribute("inert", true);
});
}
}
},
get appClasses() {
let classes = [];
if (this.openMenu) {
classes.push("menu-open menu-open-" + this.openMenu);
} else {
classes.push("menu-closed");
}
return classes;
},
};
// utils
function unZip(file) {
resetStores();
Alpine.store("files").loading = true;
JSZip.loadAsync(file[0]).then(function (content) {
Alpine.store("files").raw = content.files;
loadJsonFile("actor");
loadJsonFile("outbox");
loadJsonFile("likes");
loadJsonFile("bookmarks");
});
}
function resetStores() {
Alpine.store("files").resetState();
Alpine.store("lightbox").resetState();
Alpine.store("ui").resetState();
}
function loadJsonFile(name) {
const content = Alpine.store("files").raw;
if (content[name + ".json"] === undefined) {
if (name === "likes" || name === "bookmarks") {
// we can still run the app without those files
console.warn(`File ${name}.json not found in archive.`);
Alpine.store("files").loaded[name] = true;
} else {
// this should NOT happen and will prevent the app from running
console.error(`File ${name}.json not found in archive.`);
}
return;
}
content[name + ".json"].async("text").then(function (txt) {
if (name === "actor") {
Alpine.store("files").actor = JSON.parse(txt);
loadActorImages();
Alpine.store("files").loaded.actor = true;
} // actor.json
if (name === "outbox") {
let data = JSON.parse(txt);
let toots = data.orderedItems.map(preprocessToots);
Alpine.store("files").toots = toots;
let infos = toots.reduce(
(accu, toot) => {
if (toot.type === "Create") {
const map = toot.object.contentMap;
for (let lang in map) {
if (!accu.langs[lang]) {
accu.langs[lang] = 1;
} else {
accu.langs[lang]++;
}
}
} else if (toot.type === "Announce") {
// since Mastodon doesn't allow (yet?) cross-origin requests to
// retrieve post data (for boosts), we try to at least extract the
// user names for all the boosts contained in the archive
// [ISSUE] "object" value is a string most of the times, but
// sometimes it's a complex object similar to type "Create"
if (typeof toot.object === "object" && toot.object !== null) {
// let's ignore this case for now...
// [TODO], but not clear how it should be handled
} else if (toot.object) {
// if it's not an object and it has a value, then it's simply a
// url (string) pointing to the original (boosted) post.
// [ISSUE] URL format not always consistent... (esp. in the case
// of non-Mastodon instances) - e.g:
// https://craftopi.art/objects/[...]
// https://firefish.city/notes/[...]
// https://bsky.brid.gy/convert/ap/at://did:plc:[...]/app.bsky.feed.post/[...]
// -> the user name is not always present in URL
const url = toot.object.split("/");
let name;
let user;
let domain;
if (url.length > 2) {
domain = url[2];
if (
url[0] === "https:" &&
url[3] === "users" &&
url[5] === "statuses"
) {
// Mastodon URL format -> user name
name = url[4];
user = `https://${url[2]}/users/${url[4]}/`;
} else {
// other URL format -> domain name
name = `? ${url[2]}`;
user = `https://${url[2]}/`;
}
if (!accu.boosts[name]) {
accu.boosts[name] = {
nb: 1,
name: name,
url: user,
domain: domain,
};
} else {
accu.boosts[name].nb++;
}
}
}
}
return accu;
},
{ langs: {}, boosts: {} }
);
let boosts = [];
for (var key in infos.boosts) {
boosts.push(infos.boosts[key]);
}
Alpine.store("files").languages = infos.langs;
Alpine.store("files").boostsAuthors = boosts;
for (let lang in infos.langs) {
Alpine.store("files").filtersDefault["langs_" + lang] = true;
}
delete data.orderedItems;
Alpine.store("files").outbox = data;
Alpine.store("files").resetFilters(false);
Alpine.store("files").loaded.outbox = true;
} // outbox.json
if (name === "likes" || name === "bookmarks") {
const tmp = JSON.parse(txt);
Alpine.store("files")[name] = tmp.orderedItems;
Alpine.store("files").loaded[name] = true;
} // likes.json || bookmarks.json
});
}
function preprocessToots(t) {
let marl = {};
if (typeof t.object === "object" && t.object !== null) {
if (t.object.contentMap) {
let langs = [];
for (let lang in t.object.contentMap) {
langs.push(lang);
}
marl.langs = langs;
}
if (t.object.content) {
const content = t.object.content.toLowerCase();
marl.textContent = stripHTML(content);
marl.externalLinks = extractExternalLinks(content);
}
if (t.object.summary) {
marl.summary = t.object.summary.toLowerCase();
}
if (t.object.attachment && t.object.attachment.length) {
marl.hasAttachments = true;
}
} else if (t.object) {
marl.textContent = t.object.toLowerCase();
}
marl.visibility = tootVisibility(t);
const id = t.id.split("/");
marl.id = id[id.length - 2];
t._marl = marl;
return t;
}
function loadActorImages() {
const actor = Alpine.store("files").actor;
const content = Alpine.store("files").raw;
if (actor.icon && actor.icon.type === "Image" && actor.icon.url) {
const image = actor.icon;
content[image.url].async("base64").then(function (content) {
Alpine.store("files").avatar = {
type: image.mediaType,
content: content,
noImg: false,
};
Alpine.store("files").loaded.avatar = true;
});
} else {
Alpine.store("files").avatar = { noImg: true };
Alpine.store("files").loaded.avatar = true;
}
if (actor.image && actor.image.type === "Image" && actor.image.url) {
const image = actor.image;
content[image.url].async("base64").then(function (content) {
Alpine.store("files").header = {
type: image.mediaType,
content: content,
noImg: false,
};
Alpine.store("files").loaded.banner = true;
});
} else {
Alpine.store("files").header = { noImg: true };
Alpine.store("files").loaded.banner = true;
}
}
function loadAttachedMedia(att) {
if (
attachmentIsImage(att) ||
attachmentIsVideo(att) ||
attachmentIsSound(att)
) {
const data = Alpine.store("files").raw;
let url = att.url;
if (url.indexOf("/") === 0) {
url = url.slice(1);
}
data[url].async("base64").then((content) => {
Alpine.store("files")[att.url] = {
type: att.mediaType,
content: content,
};
});
}
}
function checkAllLoaded(ok) {
if (ok) {
cleanUpRaw();
document.getElementById("main-section").focus();
Alpine.store("ui").checkMenuState();
}
}
function cleanUpRaw() {
const content = Alpine.store("files").raw;
const actor = Alpine.store("files").actor;
if (actor.image && actor.image.url) {
delete content[actor.image.url];
}
if (actor.icon && actor.icon.url) {
delete content[actor.icon.url];
}
delete content["actor.json"];
delete content["outbox.json"];
delete content["likes.json"];
delete content["bookmarks.json"];
Alpine.store("files").raw = content;
}
function pagingUpdated() {
document.querySelectorAll(`#toots details[open]`).forEach((e) => {
e.removeAttribute("open");
});
}
function scrollTootsToTop(setFocusTo) {
setTimeout(() => {
document.getElementById("toots").scrollTop = 0;
if (setFocusTo) {
// for keyboard users: we transfer the focus to the corresponding button
// in the upper paging module; or, in the cases where said button is
// disabled, we set the focus on the list of posts.
document.getElementById(setFocusTo).focus();
}
}, 50);
}
function contentType(data) {
let r = "";
switch (data) {
case "Create":
r = "Post";
break;
case "Announce":
r = "Boost";
break;
}
return r;
}
function tootVisibility(data) {
if (data.to.includes("https://www.w3.org/ns/activitystreams#Public")) {
return ["public", "Public"];
}
if (
data.to.some((x) => x.indexOf("/followers") > -1) &&
!data.to.includes("https://www.w3.org/ns/activitystreams#Public") &&
data.cc.includes("https://www.w3.org/ns/activitystreams#Public")
) {
return ["unlisted", "Unlisted"];
}
if (
data.to.some((x) => x.indexOf("/followers") > -1) &&
!data.to.includes("https://www.w3.org/ns/activitystreams#Public") &&
!data.cc.includes("https://www.w3.org/ns/activitystreams#Public")
) {
return ["followers", "Followers only"];
}
if (
!data.to.some((x) => x.indexOf("/followers") > -1) &&
!data.to.includes("https://www.w3.org/ns/activitystreams#Public") &&
!data.cc.includes("https://www.w3.org/ns/activitystreams#Public")
) {
return ["mentioned", "Mentioned people only"];
}
}
function tootHasTags(toot) {
return (
typeof toot.object === "object" &&
toot.object !== null &&
toot.object.tag &&
toot.object.tag.length
);
}
function formatJson(data) {
let r = data;
if (r._marl) {
// not a part of the source data; let's hide it to avoid confusion
r = JSON.parse(JSON.stringify(data));
delete r._marl;
}
return JSON.stringify(r, null, 4);
}
function formatAuthor(author, plainText) {
if (plainText) {
return author.split("/").pop();
} else {
return `<a href="${author}" target="_blank">${author.split("/").pop()}</a>`;
}
}
function formatDateTime(data) {
let date = new Date(data);
const dateOptions = {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "2-digit",
second: "2-digit",
};
return date.toLocaleDateString(undefined, dateOptions);
}
function formatDate(data) {
let date = new Date(data);
const dateOptions = {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
};
return date.toLocaleDateString(undefined, dateOptions);
}
function formatNumber(nb) {
return nb.toLocaleString();
}
function stripHTML(str) {
let doc = new DOMParser().parseFromString(str, "text/html");
return doc.body.textContent || "";
}
function extractExternalLinks(str) {
const doc = new DOMParser().parseFromString(str, "text/html");
const nodes = doc.querySelectorAll("a[href]:not(.mention)");
let links = [];
nodes.forEach((link) => {
links.push({
href: link.href,
text: link.textContent,
});
});
return links;
}
function attachmentIsImage(att) {
return att.mediaType === "image/jpeg" || att.mediaType === "image/png";
}
function attachmentIsVideo(att) {
return att.mediaType === "video/mp4";
}
function attachmentIsSound(att) {
return att.mediaType === "audio/mpeg";
}
function attachmentWrapperClass(att) {
let r = [];
if (attachmentIsImage(att)) {
r.push("att-img");
} else if (attachmentIsSound(att)) {
r.push("att-sound");
} else if (attachmentIsVideo(att)) {
r.push("att-video");
}
if (!att.name) {
r.push("no-alt-text");
}
return r;
}
function isFilterActive(name) {
return (
Alpine.store("files").filters[name] !==
Alpine.store("files").filtersDefault[name]
);
}
function startOver() {
if (confirm("Discard current data and load a new archive file?")) {
location.reload();
}
}
// drag'n'drop over entire page
const drag = {
el: null,
init(el) {
this.dropArea = document.getElementById(el);
["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => {
this.dropArea.addEventListener(
eventName,
(e) => this.preventDragDefaults(e),
false
);
});
["dragenter", "dragover"].forEach((eventName) => {
this.dropArea.addEventListener(
eventName,
() => this.highlightDrag(),
false
);
});
["dragleave", "drop"].forEach((eventName) => {
this.dropArea.addEventListener(
eventName,
() => this.unhighlightDrag(),
false
);
});
this.dropArea.addEventListener("drop", (e) => this.handleDrop(e), false);
},
preventDragDefaults(e) {
e.preventDefault();
e.stopPropagation();
},
highlightDrag() {
this.dropArea.classList.add("highlight-drag");
},
unhighlightDrag() {
this.dropArea.classList.remove("highlight-drag");
},
handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
unZip(files);
},
};
// initialization
document.addEventListener("alpine:init", () => {
Alpine.store("files", filesStore);
Alpine.store("lightbox", lightboxStore);
Alpine.store("ui", uiStore);
resetStores();
});
drag.init("app");