diff --git a/data/static/js/babycode-editor.js b/data/static/js/babycode-editor.js
deleted file mode 100644
index a095c12..0000000
--- a/data/static/js/babycode-editor.js
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- let ta = document.getElementById("babycode-content");
-
- ta.addEventListener("keydown", (e) => {
- if(e.key === "Enter" && e.ctrlKey) {
- if (inThread()) {
- localStorage.removeItem(window.location.pathname);
- }
- e.target.form?.submit();
- }
- })
-
- const inThread = () => {
- const scheme = window.location.pathname.split("/");
- return scheme[1] === "threads" && scheme[2] !== "create";
- }
-
- ta.addEventListener("input", () => {
- if (!inThread()) return;
-
- localStorage.setItem(window.location.pathname, ta.value);
- })
-
- if (inThread()) {
- const form = ta.closest('.post-edit-form');
- if (form){
- form.addEventListener("submit", () => {
- localStorage.removeItem(window.location.pathname);
- })
- }
- }
-
- document.addEventListener("DOMContentLoaded", () => {
- if (!inThread()) return;
- const prevContent = localStorage.getItem(window.location.pathname);
- if (!prevContent) return;
- ta.value = prevContent;
- })
-}
diff --git a/data/static/js/bitties/pyrom-bitty.js b/data/static/js/bitties/pyrom-bitty.js
deleted file mode 100644
index 9ffb006..0000000
--- a/data/static/js/bitties/pyrom-bitty.js
+++ /dev/null
@@ -1,543 +0,0 @@
-const bookmarkMenuHrefTemplate = '/hyperapi/bookmarks-dropdown';
-const badgeEditorEndpoint = '/hyperapi/badge-editor';
-const previewEndpoint = '/api/babycode-preview';
-const userEndpoint = '/api/current-user';
-
-const delay = ms => {return new Promise(resolve => setTimeout(resolve, ms))}
-
-export default class {
- async showBookmarkMenu(ev, el) {
- if ((ev.sender.dataset.bookmarkId === el.prop('bookmarkId')) && el.childElementCount === 0) {
- const searchParams = new URLSearchParams({
- 'id': ev.sender.dataset.conceptId,
- 'require_reload': el.dataset.requireReload,
- });
- const bookmarkMenuHref = `${bookmarkMenuHrefTemplate}/${ev.sender.dataset.bookmarkType}?${searchParams}`;
- const res = await this.api.getHTML(bookmarkMenuHref);
- if (res.error) {
- return;
- }
- const frag = res.value;
- el.appendChild(frag);
- const menu = el.childNodes[0];
- menu.showPopover();
-
- const bRect = el.getBoundingClientRect();
- const menuRect = menu.getBoundingClientRect();
- const preferredLeft = bRect.right - menuRect.width;
- const preferredRight = bRect.right;
- const enoughSpace = preferredLeft >= 0;
- const scrollY = window.scrollY || window.pageYOffset;
- if (enoughSpace) {
- menu.style.left = `${preferredLeft}px`;
- } else {
- menu.style.left = `${bRect.left}px`;
- }
- menu.style.top = `${bRect.bottom + scrollY}px`;
-
- menu.addEventListener('beforetoggle', (e) => {
- if (e.newState === 'closed') {
- // if it's still in the tree, remove it
- // the delay is required to make sure its removed instantly when
- // clicking the button when the menu is open
- setTimeout(() => {menu.remove()}, 100);
- };
- }, { once: true });
-
- } else if (el.childElementCount > 0) {
- el.removeChild(el.childNodes[0]);
- }
- }
-
- selectBookmarkCollection(ev, el) {
- const clicked = ev.sender;
-
- if (ev.sender === el) {
- if (clicked.classList.contains('selected')) {
- clicked.classList.remove('selected');
- } else {
- clicked.classList.add('selected');
- }
- } else {
- el.classList.remove('selected');
- }
- }
-
- async saveBookmarks(ev, el) {
- const bookmarkHref = el.prop('bookmarkEndpoint');
- const collection = el.querySelector('.bookmark-dropdown-item.selected');
- let data = {};
- if (collection) {
- data['operation'] = 'move';
- data['collection_id'] = collection.dataset.collectionId;
- data['memo'] = el.querySelector('.bookmark-memo-input').value;
- } else {
- data['operation'] = 'remove';
- data['collection_id'] = el.prop('originallyContainedIn');
- }
-
- const options = {
- method: 'POST',
- body: JSON.stringify(data),
- headers: {
- 'Content-Type': 'application/json',
- },
- }
- const requireReload = el.propToInt('requireReload') !== 0;
- el.remove();
- await fetch(bookmarkHref, options);
- if (requireReload) {
- window.location.reload();
- }
- }
-
- async copyCode(ev, el) {
- if (!el.isSender) {
- return;
- }
- await navigator.clipboard.writeText(el.value);
- el.textContent = 'Copied!'
- await delay(1000);
- el.textContent = 'Copy';
- }
-
- toggleAccordion(ev, el) {
- const accordion = el;
- const header = accordion.querySelector('.accordion-header');
- if (!header.contains(ev.sender)){
- return;
- }
- const btn = ev.sender;
- const content = el.querySelector('.accordion-content');
- // these are all meant to be in sync
- accordion.classList.toggle('hidden');
- content.classList.toggle('hidden');
- btn.textContent = accordion.classList.contains('hidden') ? '+' : '-';
- }
-
- toggleTab(ev, el) {
- const tabButtonsContainer = el.querySelector('.tab-buttons');
- if (!el.contains(ev.sender)) {
- return;
- }
-
- if (ev.sender.classList.contains('active')) {
- return;
- }
-
- const targetId = ev.sender.prop('targetId');
- const contents = el.querySelectorAll('.tab-content');
- for (let content of contents) {
- if (content.id === targetId) {
- content.classList.add('active');
- } else {
- content.classList.remove('active');
- }
- }
- for (let button of tabButtonsContainer.children) {
- if (button.dataset.targetId === targetId) {
- button.classList.add('active');
- } else {
- button.classList.remove('active');
- }
- }
- }
-
- #previousMarkup = null;
- async babycodePreview(ev, el) {
- if (ev.sender.classList.contains('active')) {
- return;
- }
-
- const previewErrorsContainer = el.querySelector('#babycode-preview-errors-container');
- const previewContainer = el.querySelector('#babycode-preview-container');
- const ta = document.getElementById('babycode-content');
- const markup = ta.value.trim();
- if (markup === '') {
- previewErrorsContainer.textContent = 'Type something!';
- previewContainer.textContent = '';
- this.#previousMarkup = '';
- return;
- }
-
- if (markup === this.#previousMarkup) {
- return;
- }
-
- const bannedTags = JSON.parse(document.getElementById('babycode-banned-tags').value);
- this.#previousMarkup = markup;
-
- const res = await this.api.getJSON(previewEndpoint, [], {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- markup: markup,
- banned_tags: bannedTags,
- }),
- });
- if (res.error) {
- switch (res.error.status) {
- case 429:
- previewErrorsContainer.textContent = '(Old preview, try again in a few seconds.)'
- this.#previousMarkup = '';
- break;
- case 400:
- previewErrorsContainer.textContent = '(Request got malformed.)'
- break;
- case 401:
- previewErrorsContainer.textContent = '(You are not logged in.)'
- break;
- default:
- previewErrorsContainer.textContent = '(Error. Check console.)'
- break;
- }
- } else {
- previewErrorsContainer.textContent = '';
- previewContainer.innerHTML = res.value.html;
- }
- }
-
- insertBabycodeTag(ev, el) {
- const tagStart = ev.sender.prop('tag');
- const breakLine = 'breakLine' in ev.sender.dataset;
- const prefill = 'prefill' in ev.sender.dataset ? ev.sender.dataset.prefill : '';
-
- const hasAttr = tagStart[tagStart.length - 1] === '=';
- let tagEnd = tagStart;
- let tagInsertStart = `[${tagStart}]${breakLine ? '\n' : ''}`;
- if (hasAttr) {
- tagEnd = tagEnd.slice(0, -1);
- }
- const tagInsertEnd = `${breakLine ? '\n' : ''}[/${tagEnd}]`;
- const hasSelection = el.selectionStart !== el.selectionEnd;
- const text = el.value;
-
- if (hasSelection) {
- const realStart = Math.min(el.selectionStart, el.selectionEnd);
- const realEnd = Math.max(el.selectionStart, el.selectionEnd);
- const selectionLength = realEnd - realStart;
-
- const strStart = text.slice(0, realStart);
- const strEnd = text.substring(realEnd);
- const frag = `${tagInsertStart}${text.slice(realStart, realEnd)}${tagInsertEnd}`;
- const reconst = `${strStart}${frag}${strEnd}`;
- el.value = reconst;
- if (!hasAttr) {
- el.setSelectionRange(realStart + tagInsertStart.length, realStart + tagInsertEnd.length + selectionLength - 1);
- } else {
- const attrCursor = realStart + tagInsertEnd.length - (1 + (breakLine ? 1 : 0))
- el.setSelectionRange(attrCursor, attrCursor); // cursor on attr
- }
- } else {
- if (hasAttr) {
- tagInsertStart += prefill;
- }
- const cursor = el.selectionStart;
- const strStart = text.slice(0, cursor);
- const strEnd = text.substr(cursor);
-
- let newCursor = strStart.length + tagInsertStart.length;
- if (hasAttr) {
- newCursor = cursor + tagInsertStart.length - prefill.length - (1 + (breakLine ? 1 : 0)) //cursor on attr
- }
- const reconst = `${strStart}${tagInsertStart}${tagInsertEnd}${strEnd}`;
- el.value = reconst;
- el.setSelectionRange(newCursor, newCursor);
- }
- el.focus();
- }
-
- addQuote(ev, el) {
- el.value += ev.sender.value;
- el.scrollIntoView();
- el.focus();
- }
-
- convertTimestamps(ev, el) {
- const timestamp = el.propToInt('utc');
- if (!isNaN(timestamp)) {
- const date = new Date(timestamp * 1000);
- el.textContent = date.toLocaleString();
- }
- }
-
- #currentUsername = undefined;
- async highlightMentions(ev, el) {
- if (this.#currentUsername === undefined) {
- const userInfo = await this.api.getJSON(userEndpoint);
- if (!userInfo.value) {
- return;
- }
- this.#currentUsername = userInfo.value.user.username;
- }
-
- if (el.prop('username') === this.#currentUsername) {
- el.classList.add('me');
- }
- }
-}
-
-export class BadgeEditorForm {
- #badgeTemplate = undefined;
- async loadBadgeEditor(ev, el) {
- const badges = await this.api.getHTML(badgeEditorEndpoint);
- if (!badges.value) {
- return;
- }
- if (this.#badgeTemplate === undefined){
- this.#badgeTemplate = document.getElementById('badge-editor-template').content.firstElementChild.outerHTML;
- }
- el.replaceChildren();
- const addButton = ``;
- const submitButton = ``;
- const controls = `${addButton} ${submitButton} BADGECOUNT/10`
- const badgeCount = badges.value.querySelectorAll('.settings-badge-container').length;
- const subs = [
- ['BADGECOUNT', badgeCount],
- ['DISABLE_IF_MAX', badgeCount === 10 ? 'disabled' : ''],
- ];
- el.appendChild(this.api.makeHTML(controls, subs));
-
- const listTemplate = document.getElementById('badges-list-template').content.firstElementChild.outerHTML;
- const list = this.api.makeHTML(listTemplate).firstElementChild;
- list.appendChild(badges.value);
- el.appendChild(list);
- }
-
- addBadge(ev, el) {
- if (this.#badgeTemplate === undefined) {
- return;
- }
- const badge = this.api.makeHTML(this.#badgeTemplate).firstElementChild;
- el.appendChild(badge);
- this.api.localTrigger('updateBadgeCount');
- }
-
- deleteBadge(ev, el) {
- if (!el.contains(ev.sender)) {
- return;
- }
- el.remove();
- this.api.localTrigger('updateBadgeCount');
- }
-
- updateBadgeCount(ev, el) {
- const badgeCount = el.parentNode.parentNode.querySelectorAll('.settings-badge-container').length;
- if (el.propToInt('disableIfMax') === 1) {
- el.disabled = badgeCount === 10;
- } else if (el.propToInt('count') === 1) {
- el.textContent = `${badgeCount}/10`;
- }
- }
-
- badgeEditorPrepareSubmit(ev, el) {
- if (ev.type !== 'submit') {
- return;
- }
- ev.preventDefault();
-
- const badges = el.querySelectorAll('.settings-badge-container').length;
-
- const noUploads = el.querySelectorAll('.settings-badge-file-picker.hidden input[type=file]');
- noUploads.forEach(e => {
- e.value = null;
- })
- el.submit();
- }
-}
-
-const validateBase64Img = dataURL => new Promise(resolve => {
- const img = new Image();
- img.onload = () => {
- resolve(img.width === 88 && img.height === 31);
- };
- img.src = dataURL;
-});
-
-export class BadgeEditorBadge {
- #badgeCustomImageData = null;
- badgeUpdatePreview(ev, el) {
- if (ev.type !== 'change') {
- return;
- }
- // TODO: ev.sender doesn't have a bittyParent
- const selectBittyParent = ev.sender.closest('bitty-7-0');
- if (el.bittyParent !== selectBittyParent) {
- return;
- }
-
- if (ev.value === 'custom') {
- if (this.#badgeCustomImageData) {
- el.src = this.#badgeCustomImageData;
- } else {
- el.removeAttribute('src');
- }
- return;
- }
- const option = ev.sender.selectedOptions[0];
- el.src = option.dataset.filePath;
- }
-
- async badgeUpdatePreviewCustom(ev, el) {
- if (ev.type !== 'change') {
- return;
- }
- if (el.bittyParent !== ev.sender.bittyParent) {
- return;
- }
-
- const file = ev.target.files[0];
- if (file.size >= 1000 * 500) {
- this.api.localTrigger('badgeErrorSize');
- this.#badgeCustomImageData = null;
- el.removeAttribute('src');
- return;
- }
-
- const reader = new FileReader();
-
- reader.onload = async e => {
- const dimsValid = await validateBase64Img(e.target.result);
- if (!dimsValid) {
- this.api.localTrigger('badgeErrorDim');
- this.#badgeCustomImageData = null;
- el.removeAttribute('src');
- return;
- }
- this.#badgeCustomImageData = e.target.result;
- el.src = this.#badgeCustomImageData;
- this.api.localTrigger('badgeHideErrors');
- }
-
- reader.readAsDataURL(file);
- }
-
- badgeToggleFilePicker(ev, el) {
- if (ev.type !== 'change') {
- return;
- }
- // TODO: ev.sender doesn't have a bittyParent
- const selectBittyParent = ev.sender.closest('bitty-7-0');
- if (el.bittyParent !== selectBittyParent) {
- return;
- }
- const filePicker = el.querySelector('input[type=file]');
- if (ev.value === 'custom') {
- el.classList.remove('hidden');
- if (filePicker.dataset.validity) {
- filePicker.setCustomValidity(filePicker.dataset.validity);
- }
- filePicker.required = true;
- } else {
- el.classList.add('hidden');
- filePicker.setCustomValidity('');
- filePicker.required = false;
- }
- }
-
- openBadgeFilePicker(ev, el) {
- // TODO: ev.sender doesn't have a bittyParent
- if (ev.sender.parentNode !== el.parentNode) {
- return;
- }
- el.click();
- }
-
- badgeErrorSize(ev, el) {
- const validity = "Image can't be over 500KB."
- el.dataset.validity = validity;
- el.setCustomValidity(validity);
- el.reportValidity();
- }
-
- badgeErrorDim(ev, el) {
- const validity = "Image must be exactly 88x31 pixels."
- el.dataset.validity = validity;
- el.setCustomValidity(validity);
- el.reportValidity();
- }
-
- badgeHideErrors(ev, el) {
- delete el.dataset.validity;
- el.setCustomValidity('');
- }
-}
-
-const getCollectionDataForEl = el => {
- const nameInput = el.querySelector(".collection-name");
- const collectionId = el.dataset.collectionId;
-
- return {
- id: collectionId,
- name: nameInput.value,
- is_new: !('collectionId' in el.dataset),
- };
-}
-
-export class CollectionsEditor {
- #collectionTemplate = undefined;
- #collectionsData = [];
- #removedCollections = [];
- #valid = true;
-
- addCollection(ev, el) {
- if (this.#collectionTemplate === undefined) {
- this.#collectionTemplate = document.getElementById('new-collection-template').content;
- }
- // interesting
- const newCollection = this.api.makeHTML(this.#collectionTemplate.firstElementChild.outerHTML);
- el.appendChild(newCollection);
- }
-
- deleteCollection(ev, el) {
- if (!el.contains(ev.sender)) {
- return;
- }
- if ('collectionId' in el.dataset) {
- this.#removedCollections.push(el.dataset.collectionId);
- }
- el.remove();
- }
-
- async saveCollections(ev, el) {
- this.#valid = true;
- this.api.localTrigger('testValidity');
- if (!this.#valid) {
- return;
- }
- this.#collectionsData = [];
- this.api.localTrigger('getCollectionData');
-
- const data = {
- collections: this.#collectionsData,
- removed_collections: this.#removedCollections,
- };
-
- const res = await this.api.getJSON(el.prop('submitHref'), [], {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(data),
- });
- if (res.error) {
- return;
- }
-
- window.location.reload();
- }
-
- getCollectionData(ev, el) {
- this.#collectionsData.push(getCollectionDataForEl(el));
- }
-
- testValidity(ev, el) {
- const input = el.querySelector('input');
- if (!input.validity.valid) {
- input.reportValidity();
- this.#valid = false;
- }
- }
-}
diff --git a/data/static/js/thread.js b/data/static/js/thread.js
deleted file mode 100644
index 113d5b0..0000000
--- a/data/static/js/thread.js
+++ /dev/null
@@ -1,360 +0,0 @@
-{
- const ta = document.getElementById("babycode-content");
-
- function supportsPopover() {
- return Object.hasOwn(HTMLElement.prototype, "popover");
- }
-
- if (supportsPopover()){
- let quotedPostContainer = null;
- function isQuoteSelectionValid() {
- const selection = document.getSelection();
-
- if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {
- return false;
- }
-
- const range = selection.getRangeAt(0);
- const commonAncestor = range.commonAncestorContainer;
-
- const ancestorElement = commonAncestor.nodeType === Node.TEXT_NODE
- ? commonAncestor.parentNode
- : commonAncestor;
-
- const container = ancestorElement.closest(".post-inner");
- if (!container) {
- return false;
- }
- const success = container.contains(ancestorElement);
- if (success) {
- quotedPostContainer = container;
- }
- return success;
- }
-
- let quotePopover = null;
- let isSelecting = false;
-
- document.addEventListener("mousedown", () => {
- isSelecting = true;
- })
-
- document.addEventListener("mouseup", () => {
- isSelecting = false;
- handlePossibleSelection();
- })
-
- document.addEventListener("keyup", (e) => {
- if (e.shiftKey && (e.key.startsWith('Arrow') || e.key === 'Home' || e.key === 'End')) {
- handlePossibleSelection();
- }
- })
-
- function handlePossibleSelection() {
- setTimeout(() => {
- const valid = isQuoteSelectionValid();
- if (isSelecting || !valid) {
- removeQuotePopover();
- return;
- }
-
- const selection = document.getSelection();
- const selectionStr = selection.toString().trim();
- if (selection.isCollapsed || selectionStr === "") {
- removeQuotePopover();
- return;
- }
-
- showQuotePopover();
- }, 50)
- }
-
- function removeQuotePopover() {
- quotePopover?.hidePopover();
- }
-
- function createQuotePopover() {
- quotePopover = document.createElement("div");
- quotePopover.popover = "auto";
- quotePopover.className = "quote-popover";
-
- const quoteButton = document.createElement("button");
- quoteButton.textContent = "Quote fragment"
- quoteButton.className = "reduced"
- quotePopover.appendChild(quoteButton);
- document.body.appendChild(quotePopover);
- return quoteButton;
- }
-
- function showQuotePopover() {
- if (!quotePopover) {
- const quoteButton = createQuotePopover();
- quoteButton.addEventListener("click", () => {
- console.log("Quoting:", document.getSelection().toString());
- const postPermalink = quotedPostContainer.dataset.postPermalink;
- const authorUsername = quotedPostContainer.dataset.authorUsername;
- console.log(postPermalink, authorUsername);
- if (ta.value.trim() !== "") {
- ta.value += "\n"
- }
- ta.value += `@${authorUsername} [url=${postPermalink}]said:[/url]\n[quote]<:scissors:> ${document.getSelection().toString()} <:scissors:>[/quote]\n`;
- ta.scrollIntoView()
- ta.focus();
-
- document.getSelection().empty();
- removeQuotePopover();
- })
- }
-
- const range = document.getSelection().getRangeAt(0);
- const rect = range.getBoundingClientRect();
- const scrollY = window.scrollY || window.pageYOffset;
-
- quotePopover.style.setProperty("top", `${rect.top + scrollY - 55}px`)
- quotePopover.style.setProperty("left", `${rect.left + rect.width/2}px`)
-
- if (!quotePopover.matches(':popover-open')) {
- quotePopover.showPopover();
- }
- }
- }
-
- const deleteDialog = document.getElementById("delete-dialog");
- const deleteDialogCloseButton = document.getElementById("post-delete-dialog-close");
- let deletionTargetPostContainer;
-
- function closeDeleteDialog() {
- deletionTargetPostContainer.style.removeProperty("background-color");
- deleteDialog.close();
- }
-
- deleteDialogCloseButton.addEventListener("click", (e) => {
- closeDeleteDialog();
- })
- deleteDialog.addEventListener("click", (e) => {
- if (e.target === deleteDialog) {
- closeDeleteDialog();
- }
- })
- for (let button of document.querySelectorAll(".post-delete-button")) {
- button.addEventListener("click", (e) => {
- deleteDialog.showModal();
- const postId = button.value;
- deletionTargetPostContainer = document.getElementById("post-" + postId).querySelector(".post-content-container");
- deletionTargetPostContainer.style.setProperty("background-color", "#fff");
- const form = document.getElementById("post-delete-form");
- form.action = `/post/${postId}/delete`
- })
- }
-
- const threadEndpoint = document.getElementById("thread-subscribe-endpoint").value;
- let now = Math.floor(new Date() / 1000);
- function hideNotification() {
- const notification = document.getElementById('new-post-notification');
- notification.classList.add('hidden');
- }
-
- function showNewPostNotification(url) {
- const notification = document.getElementById("new-post-notification");
-
- notification.classList.remove("hidden");
-
- document.getElementById("dismiss-new-post-button").onclick = () => {
- now = Math.floor(new Date() / 1000);
- hideNotification();
- tryFetchUpdate();
- }
-
- document.getElementById("go-to-new-post-button").href = url;
-
- document.getElementById("unsub-new-post-button").onclick = () => {
- hideNotification();
- }
- }
-
- function tryFetchUpdate() {
- if (!threadEndpoint) return;
- const body = JSON.stringify({'since': now});
- fetch(threadEndpoint, {method: "POST", headers: {"Content-Type": "application/json"}, body: body})
- .then(res => res.json())
- .then(json => {
- if (json.status === "none") {
- setTimeout(tryFetchUpdate, 5000);
- } else if (json.status === "new_post") {
- showNewPostNotification(json.url);
- }
- })
- .catch(error => console.log(error))
- }
- tryFetchUpdate();
-
- if (supportsPopover()){
- const reactionEmoji = document.getElementById("allowed-reaction-emoji").value.split(" ");
- let reactionPopover = null;
- let reactionTargetPostId = null;
-
- function tryAddReaction(emoji, postId = reactionTargetPostId) {
- const body = JSON.stringify({
- "emoji": emoji,
- });
- fetch(`/api/add-reaction/${postId}`, {method: "POST", headers: {"Content-Type": "application/json"}, body: body})
- .then(res => res.json())
- .then(json => {
- if (json.status === "added") {
- const post = document.getElementById(`post-${postId}`);
- const spans = Array.from(post.querySelectorAll(".reaction-count")).filter((span) => {
- return span.dataset.emoji === emoji
- });
- if (spans.length > 0) {
- const currentValue = spans[0].textContent;
- spans[0].textContent = `${parseInt(currentValue) + 1}`;
- const button = spans[0].closest(".reaction-button");
- button.classList.add("active");
- } else {
- const span = document.createElement("span");
- span.classList = "reaction-container";
- span.dataset.emoji = emoji;
-
- const button = document.createElement("button");
- button.type = "button";
- button.className = "reduced reaction-button active";
-
- button.addEventListener("click", () => {
- tryAddReaction(emoji, postId);
- })
-
- const img = document.createElement("img");
- img.src = `/static/emoji/${emoji}.png`;
-
- button.textContent = " x";
-
- const reactionCountSpan = document.createElement("span")
- reactionCountSpan.className = "reaction-count"
- reactionCountSpan.textContent = "1"
-
- button.insertAdjacentElement("afterbegin", img);
- button.appendChild(reactionCountSpan);
-
- span.appendChild(button);
-
- const post = document.getElementById(`post-${postId}`);
- post.querySelector(".post-reactions").insertBefore(span, post.querySelector(".add-reaction-button"));
- }
- } else if (json.error_code === 409) {
- console.log("reaction exists, gonna try and remove");
- tryRemoveReaction(emoji, postId);
- } else {
- console.warn(json)
- }
- })
- .catch(error => console.error(error));
- }
-
- function tryRemoveReaction(emoji, postId = reactionTargetPostId) {
- const body = JSON.stringify({
- "emoji": emoji,
- });
-
- fetch(`/api/remove-reaction/${postId}`, {method: "POST", headers: {"Content-Type": "application/json"}, body: body})
- .then(res => res.json())
- .then(json => {
- if (json.status === "removed") {
- const post = document.getElementById(`post-${postId}`);
- const spans = Array.from(post.querySelectorAll(".reaction-container")).filter((span) => {
- return span.dataset.emoji === emoji
- });
- if (spans.length > 0) {
- const reactionCountSpan = spans[0].querySelector(".reaction-count");
- const currentValue = parseInt(reactionCountSpan.textContent);
- if (currentValue - 1 === 0) {
- spans[0].remove();
- } else {
- reactionCountSpan.textContent = `${parseInt(currentValue) - 1}`;
- const button = reactionCountSpan.closest(".reaction-button");
- button.classList.remove("active");
- }
- }
- } else {
- console.warn(json)
- }
- })
- .catch(error => console.error(error));
- }
-
- function createReactionPopover() {
- reactionPopover = document.createElement("div");
- reactionPopover.className = "reaction-popover";
- reactionPopover.popover = "auto";
-
- const inner = document.createElement("div");
- inner.className = "reaction-popover-inner";
-
- reactionPopover.appendChild(inner);
-
- for (let emoji of reactionEmoji) {
- const img = document.createElement("img");
- img.src = `/static/emoji/${emoji}.png`;
-
- const button = document.createElement("button");
- button.type = "button";
- button.className = "reduced";
- button.appendChild(img);
- button.addEventListener("click", () => {
- tryAddReaction(emoji);
- })
-
- button.dataset.emojiName = emoji;
-
- inner.appendChild(button);
- }
-
- reactionPopover.addEventListener("beforetoggle", (e) => {
- if (e.newState === "closed") {
- reactionTargetPostId = null;
- }
- })
-
- document.body.appendChild(reactionPopover);
- }
-
- function showReactionPopover() {
- if (!reactionPopover) {
- createReactionPopover();
- }
-
- if (!reactionPopover.matches(':popover-open')) {
- reactionPopover.showPopover();
- }
- }
-
- for (let button of document.querySelectorAll(".add-reaction-button")) {
- button.addEventListener("click", (e) => {
- showReactionPopover();
- reactionTargetPostId = e.target.dataset.postId;
-
- const rect = e.target.getBoundingClientRect();
- const popoverRect = reactionPopover.getBoundingClientRect();
- const scrollY = window.scrollY || window.pageYOffset;
-
- reactionPopover.style.setProperty("top", `${rect.top + scrollY + rect.height}px`)
- reactionPopover.style.setProperty("left", `${rect.left + rect.width/2 - popoverRect.width/2}px`)
- })
- }
-
- for (let button of document.querySelectorAll(".reaction-button")) {
- button.addEventListener("click", () => {
- const reactionContainer = button.closest(".reaction-container")
- const emoji = reactionContainer.dataset.emoji;
- const postId = reactionContainer.dataset.postId;
- console.log(reactionContainer);
- tryAddReaction(emoji, postId);
- })
- }
-
- } else {
- for (let button of document.querySelectorAll(".add-reaction-button")) {
- button.disabled = true;
- button.title = "Enable JS to add reactions."
- }
- }
-}
diff --git a/data/static/js/topic.js b/data/static/js/topic.js
deleted file mode 100644
index 6489843..0000000
--- a/data/static/js/topic.js
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- const deleteDialog = document.getElementById("delete-dialog");
- const deleteDialogOpenButton = document.getElementById("topic-delete-dialog-open");
- deleteDialogOpenButton.addEventListener("click", (e) => {
- deleteDialog.showModal();
- });
- const deleteDialogCloseButton = document.getElementById("topic-delete-dialog-close");
- deleteDialogCloseButton.addEventListener("click", (e) => {
- deleteDialog.close();
- })
- deleteDialog.addEventListener("click", (e) => {
- if (e.target === deleteDialog) {
- deleteDialog.close();
- }
- })
-}
diff --git a/data/static/js/ui.js b/data/static/js/ui.js
deleted file mode 100644
index 7f6ed1a..0000000
--- a/data/static/js/ui.js
+++ /dev/null
@@ -1,235 +0,0 @@
-function openLightbox(post, idx) {
- lightboxCurrentPost = post;
- lightboxCurrentIdx = idx;
- lightboxObj.img.src = lightboxImages.get(post)[idx].src;
- lightboxObj.openOriginalAnchor.href = lightboxImages.get(post)[idx].src
- lightboxObj.prevButton.disabled = lightboxImages.get(post).length === 1
- lightboxObj.nextButton.disabled = lightboxImages.get(post).length === 1
- lightboxObj.imageCount.textContent = `Image ${idx + 1} of ${lightboxImages.get(post).length}`
-
- if (!lightboxObj.dialog.open) {
- lightboxObj.dialog.showModal();
- }
-}
-
-const modulo = (n, m) => ((n % m) + m) % m
-
-function lightboxNext() {
- const l = lightboxImages.get(lightboxCurrentPost).length;
- const target = modulo(lightboxCurrentIdx + 1, l);
- openLightbox(lightboxCurrentPost, target);
-}
-
-function lightboxPrev() {
- const l = lightboxImages.get(lightboxCurrentPost).length;
- const target = modulo(lightboxCurrentIdx - 1, l);
- openLightbox(lightboxCurrentPost, target);
-}
-
-function constructLightbox() {
- const dialog = document.createElement("dialog");
- dialog.classList.add("lightbox-dialog");
- dialog.addEventListener("click", (e) => {
- if (e.target === dialog) {
- dialog.close();
- }
- })
- const dialogInner = document.createElement("div");
- dialogInner.classList.add("lightbox-inner");
- dialog.appendChild(dialogInner);
- const img = document.createElement("img");
- img.classList.add("lightbox-image")
- dialogInner.appendChild(img);
- const openOriginalAnchor = document.createElement("a")
- openOriginalAnchor.text = "Open original in new window"
- openOriginalAnchor.target = "_blank"
- openOriginalAnchor.rel = "noopener noreferrer nofollow"
- dialogInner.appendChild(openOriginalAnchor);
-
- const navSpan = document.createElement("span");
- navSpan.classList.add("lightbox-nav");
- const prevButton = document.createElement("button");
- prevButton.type = "button";
- prevButton.textContent = "Previous";
- prevButton.addEventListener("click", lightboxPrev);
- const nextButton = document.createElement("button");
- nextButton.type = "button";
- nextButton.textContent = "Next";
- nextButton.addEventListener("click", lightboxNext);
- const imageCount = document.createElement("span");
- imageCount.textContent = "Image of ";
- navSpan.appendChild(prevButton);
- navSpan.appendChild(imageCount);
- navSpan.appendChild(nextButton);
-
- dialogInner.appendChild(navSpan);
- return {
- img: img,
- dialog: dialog,
- openOriginalAnchor: openOriginalAnchor,
- prevButton: prevButton,
- nextButton: nextButton,
- imageCount: imageCount,
- }
-}
-
-let lightboxImages = new Map(); //.post-inner : Array