218 lines
6.1 KiB
JavaScript
218 lines
6.1 KiB
JavaScript
export const b = {
|
|
babycodePreviewEndpoint: '/api/babycode-preview/',
|
|
init: 'babycodeEditorCharCountInit',
|
|
}
|
|
|
|
const getThreadId = () => {
|
|
const scheme = window.location.pathname.split("/");
|
|
if (scheme[1] !== 'threads' || scheme[2] === 'new') {
|
|
return -1;
|
|
}
|
|
return parseInt(scheme[2]);
|
|
}
|
|
|
|
export function setTab(_, sender, el) {
|
|
if (sender.ariaSelected === 'true') {
|
|
return;
|
|
}
|
|
if (!el.contains(sender)) {
|
|
return;
|
|
}
|
|
const tabIndex = parseInt(sender.dataset.tabIndex);
|
|
const tabPanels = el.querySelectorAll('.tab-content');
|
|
const tabButtons = el.querySelectorAll('.tab-bar button');
|
|
|
|
for (let i = 0; i < tabPanels.length; i++) {
|
|
const tabPanel = tabPanels[i];
|
|
const tabButton = tabButtons[i];
|
|
if (i === tabIndex) {
|
|
tabPanel.classList.remove('hidden');
|
|
tabButton.ariaSelected = 'true';
|
|
} else if (!tabPanel.classList.contains('hidden')) {
|
|
tabPanel.classList.add('hidden');
|
|
tabButton.ariaSelected = 'false';
|
|
}
|
|
}
|
|
}
|
|
|
|
export function insertBabycode(_, sender, el) {
|
|
if (!el.parentNode.contains(sender)) {
|
|
return;
|
|
}
|
|
|
|
const tagStart = sender.dataset.babycodeTag;
|
|
const breakLine = 'breakLine' in sender.dataset;
|
|
const prefill = 'prefill' in sender.dataset ? 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.substring(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();
|
|
b.send({ sender: el }, 'babycodeEditorCharCount');
|
|
}
|
|
|
|
export function babycodeEditorCharCount(evOrPayload, sender, el) {
|
|
if (!sender) { // sent from bitty, not input
|
|
sender = evOrPayload.sender;
|
|
}
|
|
|
|
if (!sender.parentNode.contains(el)) {
|
|
return;
|
|
}
|
|
|
|
const maxLength = sender.maxLength;
|
|
const currentLength = sender.value.length;
|
|
|
|
el.innerText = `${currentLength}/${maxLength}`;
|
|
|
|
const threadId = getThreadId();
|
|
|
|
if (threadId !== -1) {
|
|
localStorage.setItem(`thread-${threadId}`, sender.value);
|
|
}
|
|
}
|
|
|
|
export function clearThreadDraft(_, __, ___) {
|
|
const threadId = getThreadId();
|
|
localStorage.removeItem(`thread-${threadId}`);
|
|
}
|
|
|
|
export function babycodeEditorCharCountInit(_, __, el) {
|
|
if (el === undefined) { // no editors on page
|
|
return;
|
|
}
|
|
|
|
const threadId = getThreadId();
|
|
if (threadId !== -1) {
|
|
el.value = localStorage.getItem(`thread-${threadId}`) || '';
|
|
}
|
|
b.send({ sender: el }, 'babycodeEditorCharCount');
|
|
}
|
|
|
|
export function babycodePreviewInit(ev, sender, el) {
|
|
if (!sender.parentNode.parentNode.contains(el)) { // tab container > tab bar > button
|
|
return;
|
|
}
|
|
|
|
b.send({ text: el.value, sender: sender, bannedTags: JSON.parse(el.dataset.bannedTags) }, 'babycodePreview');
|
|
}
|
|
|
|
export async function babycodePreview(payload, _, el) {
|
|
if (!payload.sender.parentNode.parentNode.contains(el)) {
|
|
return;
|
|
}
|
|
|
|
if (!payload.text.trim()) {
|
|
b.send({ plain: 'Type something to get a preview.', sender: el }, 'showBabycodePreview');
|
|
return;
|
|
}
|
|
const options = {
|
|
method: 'POST',
|
|
headers: {
|
|
'content-type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
markup: payload.text,
|
|
banned_tags: payload.bannedTags,
|
|
}),
|
|
}
|
|
|
|
const f = await fetch(b.babycodePreviewEndpoint, options);
|
|
try {
|
|
if (!f.ok) {
|
|
console.error(f);
|
|
let msg = '';
|
|
switch (f.status) {
|
|
case 429:
|
|
return;
|
|
default:
|
|
msg = '(Something went wrong. Try again later.)'
|
|
}
|
|
b.send({ plain: msg, sender: el }, 'showBabycodePreview');
|
|
return;
|
|
}
|
|
b.send({ ...(await f.json()), sender: el }, 'showBabycodePreview');
|
|
} catch (error) {
|
|
b.send({ plain: '(Something went wrong. Try again later.)', sender: el }, 'showBabycodePreview');
|
|
console.error(error);
|
|
return;
|
|
}
|
|
}
|
|
|
|
export function showBabycodePreview(payload, _, el) {
|
|
if (!payload.sender.parentNode.contains(el)) {
|
|
return;
|
|
}
|
|
if (payload.plain) {
|
|
el.innerHTML = `<p>${payload.plain}</p>`;
|
|
} else {
|
|
el.innerHTML = payload.html;
|
|
}
|
|
}
|
|
|
|
export function babycodeEditorQuote(ev, sender, el) {
|
|
console.log(sender.dataset.quote);
|
|
const newline = el.value.length === 0 ? '' : '\n'
|
|
el.value += `${newline}[quote=${sender.dataset.posterName}]\n${sender.dataset.quote}\n[/quote]\n\n`
|
|
b.send({ sender: el }, 'babycodeEditorCharCount');
|
|
el.focus();
|
|
}
|
|
|
|
export async function copyCode(ev, sender, el) {
|
|
if (!el.contains(sender)) {
|
|
return;
|
|
}
|
|
|
|
const originalText = sender.textContent;
|
|
const doneText = 'Copied!';
|
|
const code = el.dataset.code;
|
|
|
|
try {
|
|
await navigator.clipboard.writeText(code);
|
|
sender.textContent = doneText;
|
|
setTimeout(() => { sender.textContent = originalText }, 2000);
|
|
} catch (error) {
|
|
console.log(error);
|
|
}
|
|
}
|