move over a bunch of ui functionality to bitty
This commit is contained in:
@@ -6,7 +6,7 @@ from pygments.lexers import get_lexer_by_name
|
|||||||
from pygments.util import ClassNotFound as PygmentsClassNotFound
|
from pygments.util import ClassNotFound as PygmentsClassNotFound
|
||||||
import re
|
import re
|
||||||
|
|
||||||
BABYCODE_VERSION = 4
|
BABYCODE_VERSION = 5
|
||||||
|
|
||||||
NAMED_COLORS = [
|
NAMED_COLORS = [
|
||||||
'black', 'silver', 'gray', 'white', 'maroon', 'red',
|
'black', 'silver', 'gray', 'white', 'maroon', 'red',
|
||||||
@@ -61,7 +61,7 @@ def tag_code(children, attr, surrounding):
|
|||||||
return f"<code class=\"inline-code\">{children}</code>"
|
return f"<code class=\"inline-code\">{children}</code>"
|
||||||
else:
|
else:
|
||||||
input_code = children.strip()
|
input_code = children.strip()
|
||||||
button = f"<button type=button class=\"copy-code\" value=\"{input_code}\">Copy</button>"
|
button = f"<button type=button class=\"copy-code\" value=\"{input_code}\" data-send=\"copyCode\" data-receive=\"copyCode\">Copy</button>"
|
||||||
unhighlighted = f"<pre><span class=\"copy-code-container\"><span class=\"code-language-identifier\">code block</span>{button}</span><code>{input_code}</code></pre>"
|
unhighlighted = f"<pre><span class=\"copy-code-container\"><span class=\"code-language-identifier\">code block</span>{button}</span><code>{input_code}</code></pre>"
|
||||||
if not attr:
|
if not attr:
|
||||||
return unhighlighted
|
return unhighlighted
|
||||||
@@ -94,7 +94,7 @@ def tag_color(children, attr, surrounding):
|
|||||||
def tag_spoiler(children, attr, surrounding):
|
def tag_spoiler(children, attr, surrounding):
|
||||||
spoiler_name = attr if attr else "Spoiler"
|
spoiler_name = attr if attr else "Spoiler"
|
||||||
content = f"<div class='accordion-content post-accordion-content hidden'>{children}</div>"
|
content = f"<div class='accordion-content post-accordion-content hidden'>{children}</div>"
|
||||||
container = f"""<div class='accordion hidden'><div class='accordion-header'><button type='button' class='accordion-toggle'>+</button><span>{spoiler_name}</span></div>{content}</div>"""
|
container = f"""<div class='accordion hidden' data-receive='toggleAccordion'><div class='accordion-header'><button type='button' class='accordion-toggle' data-send='toggleAccordion'>+</button><span>{spoiler_name}</span></div>{content}</div>"""
|
||||||
return container
|
return container
|
||||||
|
|
||||||
def tag_image(children, attr, surrounding):
|
def tag_image(children, attr, surrounding):
|
||||||
|
|||||||
@@ -79,26 +79,26 @@
|
|||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{% macro babycode_editor_component(ta_name, ta_placeholder="Post body", optional=False, prefill="", banned_tags=[]) %}
|
{% macro babycode_editor_component(ta_name, ta_placeholder="Post body", optional=False, prefill="", banned_tags=[]) %}
|
||||||
<div class="babycode-editor-container">
|
<div class="babycode-editor-container tab-bar" data-receive="toggleTab">
|
||||||
<input type="hidden" id="babycode-banned-tags" value="{{banned_tags | unique | list | tojson | forceescape}}">
|
<input type="hidden" id="babycode-banned-tags" value="{{banned_tags | unique | list | tojson | forceescape}}">
|
||||||
<div class="tab-buttons">
|
<div class="tab-buttons">
|
||||||
<button type=button class="tab-button active" data-target-id="tab-edit">Write</button>
|
<button data-send="toggleTab" type=button class="tab-button active" data-target-id="tab-edit">Write</button>
|
||||||
<button type=button class="tab-button" data-target-id="tab-preview">Preview</button>
|
<button data-send="babycodePreview toggleTab" type=button class="tab-button" data-target-id="tab-preview">Preview</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content active" id="tab-edit">
|
<div class="tab-content active" id="tab-edit">
|
||||||
<span class="babycode-button-container">
|
<span class="babycode-button-container">
|
||||||
<button class="babycode-button" type=button id="post-editor-bold" title="Insert Bold" {{"disabled" if "b" in banned_tags else ""}}><strong>B</strong></button>
|
<button data-send="insertBabycodeTag" data-tag="b" class="babycode-button" type=button id="post-editor-bold" title="Insert Bold" {{"disabled" if "b" in banned_tags else ""}}><strong>B</strong></button>
|
||||||
<button class="babycode-button" type=button id="post-editor-italics" title="Insert Italics" {{"disabled" if "i" in banned_tags else ""}}><em>I</em></button>
|
<button data-send="insertBabycodeTag" data-tag="i" class="babycode-button" type=button id="post-editor-italics" title="Insert Italics" {{"disabled" if "i" in banned_tags else ""}}><em>I</em></button>
|
||||||
<button class="babycode-button" type=button id="post-editor-strike" title="Insert Strikethrough" {{"disabled" if "s" in banned_tags else ""}}><del>S</del></button>
|
<button data-send="insertBabycodeTag" data-tag="s" class="babycode-button" type=button id="post-editor-strike" title="Insert Strikethrough" {{"disabled" if "s" in banned_tags else ""}}><del>S</del></button>
|
||||||
<button class="babycode-button" type=button id="post-editor-underline" title="Insert Underline" {{"disabled" if "u" in banned_tags else ""}}><u>U</u></button>
|
<button data-send="insertBabycodeTag" data-tag="u" class="babycode-button" type=button id="post-editor-underline" title="Insert Underline" {{"disabled" if "u" in banned_tags else ""}}><u>U</u></button>
|
||||||
<button class="babycode-button" type=button id="post-editor-url" title="Insert Link" {{"disabled" if "url" in banned_tags else ""}}><code>://</code></button>
|
<button data-send="insertBabycodeTag" data-tag="url=" data-prefill="link label" class="babycode-button" type=button id="post-editor-url" title="Insert Link" {{"disabled" if "url" in banned_tags else ""}}><code>://</code></button>
|
||||||
<button class="babycode-button" type=button id="post-editor-code" title="Insert Code block" {{"disabled" if "code" in banned_tags else ""}}><code></></code></button>
|
<button data-send="insertBabycodeTag" data-tag="code=" data-break-line="1" class="babycode-button" type=button id="post-editor-code" title="Insert Code block" {{"disabled" if "code" in banned_tags else ""}}><code></></code></button>
|
||||||
<button class="babycode-button contain-svg" type=button id="post-editor-img" title="Insert Image" {{"disabled" if "img" in banned_tags else ""}}>{{ icn_image() }}</button>
|
<button data-send="insertBabycodeTag" data-tag="img=" data-prefill="alt text" class="babycode-button contain-svg" type=button id="post-editor-img" title="Insert Image" {{"disabled" if "img" in banned_tags else ""}}>{{ icn_image() }}</button>
|
||||||
<button class="babycode-button" type=button id="post-editor-ol" title="Insert Ordered list" {{"disabled" if "ol" in banned_tags else ""}}>1.</button>
|
<button data-send="insertBabycodeTag" data-tag="ol" data-break-line="1" class="babycode-button" type=button id="post-editor-ol" title="Insert Ordered list" {{"disabled" if "ol" in banned_tags else ""}}>1.</button>
|
||||||
<button class="babycode-button" type=button id="post-editor-ul" title="Insert Unordered list" {{"disabled" if "u;" in banned_tags else ""}}>•</button>
|
<button data-send="insertBabycodeTag" data-tag="ul" data-break-line="1" class="babycode-button" type=button id="post-editor-ul" title="Insert Unordered list" {{"disabled" if "u;" in banned_tags else ""}}>•</button>
|
||||||
<button class="babycode-button contain-svg" type=button id="post-editor-spoiler" title="Insert spoiler" {{"disabled" if "spoiler" in banned_tags else ""}}>{{ icn_spoiler() }}</button>
|
<button data-send="insertBabycodeTag" data-tag="spoiler=" data-break-line="1" data-prefill="hidden content" class="babycode-button contain-svg" type=button id="post-editor-spoiler" title="Insert spoiler" {{"disabled" if "spoiler" in banned_tags else ""}}>{{ icn_spoiler() }}</button>
|
||||||
</span>
|
</span>
|
||||||
<textarea class="babycode-editor" name="{{ ta_name }}" id="babycode-content" placeholder="{{ ta_placeholder }}" {{ "required" if not optional else "" }} autocomplete="off">{{ prefill }}</textarea>
|
<textarea class="babycode-editor" name="{{ ta_name }}" id="babycode-content" placeholder="{{ ta_placeholder }}" {{ "required" if not optional else "" }} autocomplete="off" data-receive="insertBabycodeTag addQuote">{{ prefill }}</textarea>
|
||||||
<a href="{{ url_for("app.babycode_guide") }}" target="_blank">babycode guide</a>
|
<a href="{{ url_for("app.babycode_guide") }}" target="_blank">babycode guide</a>
|
||||||
{% if banned_tags %}
|
{% if banned_tags %}
|
||||||
<div>Forbidden tags:</div>
|
<div>Forbidden tags:</div>
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-content" id="tab-preview">
|
<div class="tab-content" id="tab-preview" data-receive="babycodePreview">
|
||||||
<div id="babycode-preview-errors-container">Type something!</div>
|
<div id="babycode-preview-errors-container">Type something!</div>
|
||||||
<div id="babycode-preview-container"></div>
|
<div id="babycode-preview-container"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -207,7 +207,7 @@
|
|||||||
{% if show_reply %}
|
{% if show_reply %}
|
||||||
{% set qtext = "[url=%s]%s said:[/url]" | format(post_permalink, post['username']) %}
|
{% set qtext = "[url=%s]%s said:[/url]" | format(post_permalink, post['username']) %}
|
||||||
{% set reply_text = "%s\n[quote]\n%s\n[/quote]\n" | format(qtext, post['original_markup']) %}
|
{% set reply_text = "%s\n[quote]\n%s\n[/quote]\n" | format(qtext, post['original_markup']) %}
|
||||||
<button value="{{ reply_text }}" class="reply-button">Quote</button>
|
<button data-send="addQuote" value="{{ reply_text }}" class="reply-button">Quote</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% set show_delete = false %}
|
{% set show_delete = false %}
|
||||||
@@ -272,13 +272,13 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro accordion(hidden=false, style="", disabled=false) %}
|
{% macro accordion(hidden=false, disabled=false) %}
|
||||||
{% if disabled %}
|
{% if disabled %}
|
||||||
{% set hidden = true %}
|
{% set hidden = true %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="accordion {{ "hidden" if hidden else ""}}" style="{{style}}">
|
<div class="accordion {{ "hidden" if hidden else ""}}" data-receive="toggleAccordion">
|
||||||
<div class="accordion-header">
|
<div class="accordion-header">
|
||||||
<button type="button" class="accordion-toggle" {{"disabled" if disabled else ""}}>{{ "+" if hidden else "-" }}</button>
|
<button type="button" class="accordion-toggle" {{"disabled" if disabled else ""}} data-send="toggleAccordion">{{ "+" if hidden else "-" }}</button>
|
||||||
{{ caller('header') }}
|
{{ caller('header') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="accordion-content {{ "hidden" if hidden else "" }}">
|
<div class="accordion-content {{ "hidden" if hidden else "" }}">
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
ta.addEventListener("keydown", (e) => {
|
ta.addEventListener("keydown", (e) => {
|
||||||
if(e.key === "Enter" && e.ctrlKey) {
|
if(e.key === "Enter" && e.ctrlKey) {
|
||||||
// console.log(e.target.form)
|
|
||||||
if (inThread()) {
|
if (inThread()) {
|
||||||
localStorage.removeItem(window.location.pathname);
|
localStorage.removeItem(window.location.pathname);
|
||||||
}
|
}
|
||||||
@@ -38,152 +37,4 @@
|
|||||||
if (!prevContent) return;
|
if (!prevContent) return;
|
||||||
ta.value = prevContent;
|
ta.value = prevContent;
|
||||||
})
|
})
|
||||||
|
|
||||||
const buttonBold = document.getElementById("post-editor-bold");
|
|
||||||
const buttonItalics = document.getElementById("post-editor-italics");
|
|
||||||
const buttonStrike = document.getElementById("post-editor-strike");
|
|
||||||
const buttonUnderline = document.getElementById("post-editor-underline");
|
|
||||||
const buttonUrl = document.getElementById("post-editor-url");
|
|
||||||
const buttonCode = document.getElementById("post-editor-code");
|
|
||||||
const buttonImg = document.getElementById("post-editor-img");
|
|
||||||
const buttonOl = document.getElementById("post-editor-ol");
|
|
||||||
const buttonUl = document.getElementById("post-editor-ul");
|
|
||||||
const buttonSpoiler = document.getElementById("post-editor-spoiler");
|
|
||||||
|
|
||||||
function insertTag(tagStart, newline = false, prefill = "") {
|
|
||||||
const hasAttr = tagStart[tagStart.length - 1] === "=";
|
|
||||||
let tagEnd = tagStart;
|
|
||||||
let tagInsertStart = `[${tagStart}]${newline ? "\n" : ""}`;
|
|
||||||
if (hasAttr) {
|
|
||||||
tagEnd = tagEnd.slice(0, -1);
|
|
||||||
}
|
|
||||||
const tagInsertEnd = `${newline ? "\n" : ""}[/${tagEnd}]`;
|
|
||||||
const hasSelection = ta.selectionStart !== ta.selectionEnd;
|
|
||||||
const text = ta.value;
|
|
||||||
if (hasSelection) {
|
|
||||||
const realStart = Math.min(ta.selectionStart, ta.selectionEnd);
|
|
||||||
const realEnd = Math.max(ta.selectionStart, ta.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}`;
|
|
||||||
ta.value = reconst;
|
|
||||||
if (!hasAttr){
|
|
||||||
ta.setSelectionRange(realStart + tagInsertStart.length, realStart + tagInsertStart.length + selectionLength);
|
|
||||||
} else {
|
|
||||||
ta.setSelectionRange(realStart + tagInsertEnd.length - 1, realStart + tagInsertEnd.length - 1); // cursor on attr
|
|
||||||
}
|
|
||||||
ta.focus()
|
|
||||||
} else {
|
|
||||||
if (hasAttr) {
|
|
||||||
tagInsertStart += prefill;
|
|
||||||
}
|
|
||||||
const cursor = ta.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;
|
|
||||||
}
|
|
||||||
const reconst = `${strStart}${tagInsertStart}${tagInsertEnd}${strEnd}`;
|
|
||||||
ta.value = reconst;
|
|
||||||
ta.setSelectionRange(newCursor, newCursor);
|
|
||||||
ta.focus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buttonBold.addEventListener("click", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
insertTag("b")
|
|
||||||
})
|
|
||||||
buttonItalics.addEventListener("click", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
insertTag("i")
|
|
||||||
})
|
|
||||||
buttonStrike.addEventListener("click", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
insertTag("s")
|
|
||||||
})
|
|
||||||
buttonUnderline.addEventListener("click", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
insertTag("u")
|
|
||||||
})
|
|
||||||
buttonUrl.addEventListener("click", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
insertTag("url=", false, "link label");
|
|
||||||
})
|
|
||||||
buttonCode.addEventListener("click", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
insertTag("code", true)
|
|
||||||
})
|
|
||||||
buttonImg.addEventListener("click", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
insertTag("img=", false, "alt text");
|
|
||||||
})
|
|
||||||
buttonOl.addEventListener("click", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
insertTag("ol", true);
|
|
||||||
})
|
|
||||||
buttonUl.addEventListener("click", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
insertTag("ul", true);
|
|
||||||
})
|
|
||||||
buttonSpoiler.addEventListener("click", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
insertTag("spoiler=", true, "hidden content");
|
|
||||||
})
|
|
||||||
|
|
||||||
const previewEndpoint = "/api/babycode-preview";
|
|
||||||
let previousMarkup = "";
|
|
||||||
const previewTab = document.getElementById("tab-preview");
|
|
||||||
previewTab.addEventListener("tab-activated", async () => {
|
|
||||||
const previewContainer = document.getElementById("babycode-preview-container");
|
|
||||||
const previewErrorsContainer = document.getElementById("babycode-preview-errors-container");
|
|
||||||
// previewErrorsContainer.textContent = "";
|
|
||||||
const markup = ta.value.trim();
|
|
||||||
if (markup === "" || markup === previousMarkup) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const bannedTags = JSON.parse(document.getElementById('babycode-banned-tags').value);
|
|
||||||
previousMarkup = markup;
|
|
||||||
const req = await fetch(previewEndpoint, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
markup: markup,
|
|
||||||
banned_tags: bannedTags,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
if (!req.ok) {
|
|
||||||
switch (req.status) {
|
|
||||||
case 429:
|
|
||||||
previewErrorsContainer.textContent = "(Old preview, try again in a few seconds.)"
|
|
||||||
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.)"
|
|
||||||
console.error(req.error);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const json_resp = await req.json();
|
|
||||||
previewContainer.innerHTML = json_resp.html;
|
|
||||||
previewErrorsContainer.textContent = "";
|
|
||||||
|
|
||||||
const accordionRefreshEvt = new CustomEvent("refresh_accordions");
|
|
||||||
document.body.dispatchEvent(accordionRefreshEvt);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
const bookmarkMenuHrefTemplate = '/hyperapi/bookmarks-dropdown'
|
const bookmarkMenuHrefTemplate = '/hyperapi/bookmarks-dropdown';
|
||||||
|
const previewEndpoint = '/api/babycode-preview';
|
||||||
|
|
||||||
|
const delay = ms => {return new Promise(resolve => setTimeout(resolve, ms))}
|
||||||
|
|
||||||
export default class {
|
export default class {
|
||||||
async showBookmarkMenu(ev, el) {
|
async showBookmarkMenu(ev, el) {
|
||||||
@@ -85,4 +88,160 @@ export default class {
|
|||||||
window.location.reload();
|
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.getString('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 = '';
|
||||||
|
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 === '' || 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.getString('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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
{
|
{
|
||||||
const ta = document.getElementById("babycode-content");
|
const ta = document.getElementById("babycode-content");
|
||||||
|
|
||||||
for (let button of document.querySelectorAll(".reply-button")) {
|
|
||||||
button.addEventListener("click", (e) => {
|
|
||||||
ta.value += button.value;
|
|
||||||
ta.scrollIntoView()
|
|
||||||
ta.focus();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function supportsPopover() {
|
function supportsPopover() {
|
||||||
return Object.hasOwn(HTMLElement.prototype, "popover");
|
return Object.hasOwn(HTMLElement.prototype, "popover");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,3 @@
|
|||||||
function activateSelfDeactivateSibs(button) {
|
|
||||||
if (button.classList.contains("active")) return;
|
|
||||||
|
|
||||||
Array.from(button.parentNode.children).forEach(s => {
|
|
||||||
if (s === button){
|
|
||||||
button.classList.add('active');
|
|
||||||
} else {
|
|
||||||
s.classList.remove('active');
|
|
||||||
}
|
|
||||||
const targetId = s.dataset.targetId;
|
|
||||||
const target = document.getElementById(targetId);
|
|
||||||
|
|
||||||
if (!target) return;
|
|
||||||
|
|
||||||
if (s.classList.contains('active')) {
|
|
||||||
target.classList.add('active');
|
|
||||||
target.dispatchEvent(new CustomEvent("tab-activated", {bubbles: false}))
|
|
||||||
} else {
|
|
||||||
target.classList.remove('active');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function openLightbox(post, idx) {
|
function openLightbox(post, idx) {
|
||||||
lightboxCurrentPost = post;
|
lightboxCurrentPost = post;
|
||||||
lightboxCurrentIdx = idx;
|
lightboxCurrentIdx = idx;
|
||||||
@@ -102,43 +79,6 @@ let lightboxCurrentPost = null;
|
|||||||
let lightboxCurrentIdx = -1;
|
let lightboxCurrentIdx = -1;
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
// tabs
|
|
||||||
document.querySelectorAll(".tab-button").forEach(button => {
|
|
||||||
button.addEventListener("click", () => {
|
|
||||||
activateSelfDeactivateSibs(button);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// accordions
|
|
||||||
const handledAccordions = new Set();
|
|
||||||
function attachAccordionHandlers(accordion){
|
|
||||||
if(handledAccordions.has(accordion)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
handledAccordions.add(accordion)
|
|
||||||
const header = accordion.querySelector(".accordion-header");
|
|
||||||
const toggleButton = header.querySelector(".accordion-toggle");
|
|
||||||
const content = accordion.querySelector(".accordion-content");
|
|
||||||
|
|
||||||
const toggle = (e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
accordion.classList.toggle("hidden");
|
|
||||||
content.classList.toggle("hidden");
|
|
||||||
toggleButton.textContent = content.classList.contains("hidden") ? "+" : "-"
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleButton.addEventListener("click", toggle);
|
|
||||||
}
|
|
||||||
|
|
||||||
function refreshAccordions(){
|
|
||||||
const accordions = document.querySelectorAll(".accordion");
|
|
||||||
accordions.forEach(attachAccordionHandlers);
|
|
||||||
}
|
|
||||||
refreshAccordions()
|
|
||||||
|
|
||||||
document.body.addEventListener('refresh_accordions', refreshAccordions)
|
|
||||||
|
|
||||||
//lightboxes
|
//lightboxes
|
||||||
lightboxObj = constructLightbox();
|
lightboxObj = constructLightbox();
|
||||||
document.body.appendChild(lightboxObj.dialog);
|
document.body.appendChild(lightboxObj.dialog);
|
||||||
@@ -192,13 +132,4 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
image.addEventListener("load", () => setImageMaxSize(image));
|
image.addEventListener("load", () => setImageMaxSize(image));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// copy code blocks
|
|
||||||
for (let button of document.querySelectorAll(".copy-code")) {
|
|
||||||
button.addEventListener("click", async () => {
|
|
||||||
await navigator.clipboard.writeText(button.value)
|
|
||||||
button.textContent = "Copied!"
|
|
||||||
setTimeout(() => {button.textContent = "Copy"}, 1000.0)
|
|
||||||
})
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user