{% if not editing %} -
{{ post['content'] | safe }}
+
{{ post['content'] | safe }}
{% if render_sig and post['signature_rendered'] %}

diff --git a/data/static/js/thread.js b/data/static/js/thread.js index 1884f58..e3409fc 100644 --- a/data/static/js/thread.js +++ b/data/static/js/thread.js @@ -8,6 +8,125 @@ ta.focus(); }) } + + 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) { + removePopover(); + return; + } + + const selection = document.getSelection(); + const selectionStr = selection.toString().trim(); + if (selection.isCollapsed || selectionStr === "") { + removePopover(); + return; + } + + showPopover(); + }, 50) + } + + function removePopover() { + quotePopover?.hidePopover(); + } + + function createPopover() { + 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 showPopover() { + if (!quotePopover) { + const quoteButton = createPopover(); + 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 += `[url=${postPermalink}]${authorUsername} said:[/url]\n[quote]${document.getSelection().toString()}[/quote]\n`; + ta.scrollIntoView() + ta.focus(); + + document.getSelection().empty(); + removePopover(); + }) + } + + 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"); diff --git a/data/static/style.css b/data/static/style.css index d39f3b2..2f533f7 100644 --- a/data/static/style.css +++ b/data/static/style.css @@ -310,6 +310,10 @@ button:active, input[type=submit]:active, .linkbutton:active { button:disabled, input[type=submit]:disabled, .linkbutton:disabled { background-color: rgb(209.535, 211.565, 211.46); } +button.reduced, input[type=submit].reduced, .linkbutton.reduced { + margin: 0; + padding: 5px; +} button.critical, input[type=submit].critical, .linkbutton.critical { color: white; background-color: red; @@ -323,6 +327,10 @@ button.critical:active, input[type=submit].critical:active, .linkbutton.critical button.critical:disabled, input[type=submit].critical:disabled, .linkbutton.critical:disabled { background-color: rgb(174.675, 156.825, 156.825); } +button.critical.reduced, input[type=submit].critical.reduced, .linkbutton.critical.reduced { + margin: 0; + padding: 5px; +} button.warn, input[type=submit].warn, .linkbutton.warn { background-color: #fbfb8d; } @@ -335,6 +343,10 @@ button.warn:active, input[type=submit].warn:active, .linkbutton.warn:active { button.warn:disabled, input[type=submit].warn:disabled, .linkbutton.warn:disabled { background-color: rgb(217.55, 217.55, 209.85); } +button.warn.reduced, input[type=submit].warn.reduced, .linkbutton.warn.reduced { + margin: 0; + padding: 5px; +} input[type=file]::file-selector-button { background-color: rgb(177, 206, 204.5); @@ -349,6 +361,10 @@ input[type=file]::file-selector-button:active { input[type=file]::file-selector-button:disabled { background-color: rgb(209.535, 211.565, 211.46); } +input[type=file]::file-selector-button.reduced { + margin: 0; + padding: 5px; +} p { margin: 15px 0; @@ -371,6 +387,10 @@ p { .pagebutton:disabled { background-color: rgb(209.535, 211.565, 211.46); } +.pagebutton.reduced { + margin: 0; + padding: 5px; +} .currentpage { border: none; @@ -632,6 +652,10 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus .tab-button:disabled { background-color: rgb(209.535, 211.565, 211.46); } +.tab-button.reduced { + margin: 0; + padding: 5px; +} .tab-button.active { background-color: #beb1ce; padding-top: 8px; @@ -737,3 +761,13 @@ ul, ol { .babycode-button > * { font-size: 1rem; } + +.quote-popover { + position: absolute; + transform: translateX(-50%); + margin: 0; + border: none; + border-radius: 4px; + background-color: rgba(0, 0, 0, 0.5019607843); + padding: 5px 10px; +} diff --git a/sass/style.scss b/sass/style.scss index b922111..0f598b3 100644 --- a/sass/style.scss +++ b/sass/style.scss @@ -75,6 +75,11 @@ $accordion_color: color.adjust($accent_color, $hue: 140, $lightness: -10%, $satu &:disabled { background-color: color.scale($color, $lightness: 30%, $saturation: -90%); } + + &.reduced { + margin: 0; + padding: 5px; + } } @mixin navbar($color) { @@ -746,3 +751,13 @@ ul, ol { font-size: 1rem; } } + +.quote-popover { + position: absolute; + transform: translateX(-50%); + margin: 0; + border: none; + border-radius: 4px; + background-color: #00000080; + padding: 5px 10px; +}