add js to quote part of a post
This commit is contained in:
		@@ -94,6 +94,7 @@
 | 
				
			|||||||
{% if editing %}
 | 
					{% if editing %}
 | 
				
			||||||
  {% set postclass = postclass + " editing" %}
 | 
					  {% set postclass = postclass + " editing" %}
 | 
				
			||||||
{% endif %}
 | 
					{% endif %}
 | 
				
			||||||
 | 
					{% set post_permalink = url_for("threads.thread", slug = post['thread_slug'], after = post['id'], _anchor = ("post-" + (post['id'] | string))) %}
 | 
				
			||||||
<div class=" {{ postclass }}" id="post-{{ post['id'] }}">
 | 
					<div class=" {{ postclass }}" id="post-{{ post['id'] }}">
 | 
				
			||||||
  <div class="usercard">
 | 
					  <div class="usercard">
 | 
				
			||||||
    <div class="usercard-inner">
 | 
					    <div class="usercard-inner">
 | 
				
			||||||
@@ -109,7 +110,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  <div class="post-content-container" {{ "id=latest-post" if is_latest else "" }}>
 | 
					  <div class="post-content-container" {{ "id=latest-post" if is_latest else "" }}>
 | 
				
			||||||
    <div class="post-info">
 | 
					    <div class="post-info">
 | 
				
			||||||
      {% set post_permalink = url_for("threads.thread", slug = post['thread_slug'], after = post['id'], _anchor = ("post-" + (post['id'] | string))) %}
 | 
					 | 
				
			||||||
      <a href="{{ post_permalink }}" title="Permalink"><i>
 | 
					      <a href="{{ post_permalink }}" title="Permalink"><i>
 | 
				
			||||||
        {% if (post['edited_at'] | int) > (post['created_at'] | int) %}
 | 
					        {% if (post['edited_at'] | int) > (post['created_at'] | int) %}
 | 
				
			||||||
          Edited on {{ timestamp(post['edited_at']) }}
 | 
					          Edited on {{ timestamp(post['edited_at']) }}
 | 
				
			||||||
@@ -157,7 +157,7 @@
 | 
				
			|||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="post-content">
 | 
					    <div class="post-content">
 | 
				
			||||||
      {% if not editing %}
 | 
					      {% if not editing %}
 | 
				
			||||||
        <div class="post-inner">{{ post['content'] | safe }}</div>
 | 
					        <div class="post-inner" data-post-permalink="{{ post_permalink }}" data-author-username="{{ post.username }}">{{ post['content'] | safe }}</div>
 | 
				
			||||||
        {% if render_sig and post['signature_rendered'] %}
 | 
					        {% if render_sig and post['signature_rendered'] %}
 | 
				
			||||||
          <div class="signature-container">
 | 
					          <div class="signature-container">
 | 
				
			||||||
            <hr>
 | 
					            <hr>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,125 @@
 | 
				
			|||||||
      ta.focus();
 | 
					      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 deleteDialog = document.getElementById("delete-dialog");
 | 
				
			||||||
  const deleteDialogCloseButton = document.getElementById("post-delete-dialog-close");
 | 
					  const deleteDialogCloseButton = document.getElementById("post-delete-dialog-close");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -310,6 +310,10 @@ button:active, input[type=submit]:active, .linkbutton:active {
 | 
				
			|||||||
button:disabled, input[type=submit]:disabled, .linkbutton:disabled {
 | 
					button:disabled, input[type=submit]:disabled, .linkbutton:disabled {
 | 
				
			||||||
  background-color: rgb(209.535, 211.565, 211.46);
 | 
					  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 {
 | 
					button.critical, input[type=submit].critical, .linkbutton.critical {
 | 
				
			||||||
  color: white;
 | 
					  color: white;
 | 
				
			||||||
  background-color: red;
 | 
					  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 {
 | 
					button.critical:disabled, input[type=submit].critical:disabled, .linkbutton.critical:disabled {
 | 
				
			||||||
  background-color: rgb(174.675, 156.825, 156.825);
 | 
					  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 {
 | 
					button.warn, input[type=submit].warn, .linkbutton.warn {
 | 
				
			||||||
  background-color: #fbfb8d;
 | 
					  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 {
 | 
					button.warn:disabled, input[type=submit].warn:disabled, .linkbutton.warn:disabled {
 | 
				
			||||||
  background-color: rgb(217.55, 217.55, 209.85);
 | 
					  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 {
 | 
					input[type=file]::file-selector-button {
 | 
				
			||||||
  background-color: rgb(177, 206, 204.5);
 | 
					  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 {
 | 
					input[type=file]::file-selector-button:disabled {
 | 
				
			||||||
  background-color: rgb(209.535, 211.565, 211.46);
 | 
					  background-color: rgb(209.535, 211.565, 211.46);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					input[type=file]::file-selector-button.reduced {
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  padding: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
p {
 | 
					p {
 | 
				
			||||||
  margin: 15px 0;
 | 
					  margin: 15px 0;
 | 
				
			||||||
@@ -371,6 +387,10 @@ p {
 | 
				
			|||||||
.pagebutton:disabled {
 | 
					.pagebutton:disabled {
 | 
				
			||||||
  background-color: rgb(209.535, 211.565, 211.46);
 | 
					  background-color: rgb(209.535, 211.565, 211.46);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					.pagebutton.reduced {
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  padding: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.currentpage {
 | 
					.currentpage {
 | 
				
			||||||
  border: none;
 | 
					  border: none;
 | 
				
			||||||
@@ -632,6 +652,10 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus
 | 
				
			|||||||
.tab-button:disabled {
 | 
					.tab-button:disabled {
 | 
				
			||||||
  background-color: rgb(209.535, 211.565, 211.46);
 | 
					  background-color: rgb(209.535, 211.565, 211.46);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					.tab-button.reduced {
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  padding: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
.tab-button.active {
 | 
					.tab-button.active {
 | 
				
			||||||
  background-color: #beb1ce;
 | 
					  background-color: #beb1ce;
 | 
				
			||||||
  padding-top: 8px;
 | 
					  padding-top: 8px;
 | 
				
			||||||
@@ -737,3 +761,13 @@ ul, ol {
 | 
				
			|||||||
.babycode-button > * {
 | 
					.babycode-button > * {
 | 
				
			||||||
  font-size: 1rem;
 | 
					  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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,6 +75,11 @@ $accordion_color: color.adjust($accent_color, $hue: 140, $lightness: -10%, $satu
 | 
				
			|||||||
  &:disabled {
 | 
					  &:disabled {
 | 
				
			||||||
    background-color: color.scale($color, $lightness: 30%, $saturation: -90%);
 | 
					    background-color: color.scale($color, $lightness: 30%, $saturation: -90%);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.reduced {
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					    padding: 5px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@mixin navbar($color) {
 | 
					@mixin navbar($color) {
 | 
				
			||||||
@@ -746,3 +751,13 @@ ul, ol {
 | 
				
			|||||||
    font-size: 1rem;
 | 
					    font-size: 1rem;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.quote-popover {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  transform: translateX(-50%);
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					  border-radius: 4px;
 | 
				
			||||||
 | 
					  background-color: #00000080;
 | 
				
			||||||
 | 
					  padding: 5px 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user