yet-another-blog/frontend/views/themes/default/js/richTextEditor.js

89 lines
3.8 KiB
JavaScript
Raw Permalink Normal View History

Generic Theme (#1) * Theme work Signed-off-by: Armored Dragon <publicmail@armoreddragon.com> * User registration. Cleanup CSS. Signed-off-by: Armored Dragon <publicmail@armoreddragon.com> * Post Creation and Manipulation Uploading images now easier. Just drag and drop onto the text area. Signed-off-by: Armored Dragon <publicmail@armoreddragon.com> * Author Page. Edit author page. Author display name. Generic media uploads. Core refactoring. Signed-off-by: Armored Dragon <publicmail@armoreddragon.com> * Texteditor bugfix. PGAdmin docker container for management of database. Signed-off-by: Armored Dragon <publicmail@armoreddragon.com> * Tags. Search by tags. Return tags used by posts. Signed-off-by: Armored Dragon <publicmail@armoreddragon.com> * New post button. Fix index "page" param not being honored. Signed-off-by: Armored Dragon <publicmail@armoreddragon.com> * Post drafts Users can now only have one "unpublished" draft. Improved password handling. Minor cleanup. Admin panel navigation link. Signed-off-by: Armored Dragon <publicmail@armoreddragon.com> * Post visibility flairs Signed-off-by: Armored Dragon <publicmail@armoreddragon.com> * Publish date autofill to now. Fix deleteBlog. Signed-off-by: Armored Dragon <publicmail@armoreddragon.com> * Removed unused function Signed-off-by: Armored Dragon <publicmail@armoreddragon.com> * Media upload pruning. Uploaded media is now pruned automatically every time a post is updated. Minor cleanup. Groundwork for media types other than images. Signed-off-by: Armored Dragon <publicmail@armoreddragon.com> * Updated name. Use the manifest data. Signed-off-by: Armored Dragon <publicmail@armoreddragon.com> --------- Signed-off-by: Armored Dragon <publicmail@armoreddragon.com>
2024-04-30 15:26:35 +00:00
const rich_text_editors = qsa(".rich-text-editor");
let media = [];
function textareaAction(textarea, insert, cursor_position, dual_side = false) {
textarea = textarea.querySelector("textarea");
const selectionStart = textarea.selectionStart;
const selectionEnd = textarea.selectionEnd;
const textBefore = textarea.value.substring(0, selectionStart);
const textAfter = textarea.value.substring(selectionEnd);
const selectedText = textarea.value.substring(selectionStart, selectionEnd);
let updatedText;
if (dual_side) updatedText = `${textBefore}${insert}${selectedText}${insert}${textAfter}`;
else updatedText = `${textBefore}${insert}${selectedText}${textAfter}`;
textarea.value = updatedText;
// Set the cursor position after the custom string
textarea.focus();
const newPosition = selectionStart + (cursor_position || insert.length);
textarea.setSelectionRange(newPosition, newPosition);
}
// Go though rich editors and apply image uploading script
rich_text_editors.forEach((editor) => {
editor.querySelector("#insert-sidebyside").addEventListener("click", () => textareaAction(editor, "{sidebyside}{/sidebyside}", 12));
editor.querySelector("#insert-video").addEventListener("click", () => textareaAction(editor, "{video:}", 7));
editor.querySelector("#insert-h1").addEventListener("click", () => textareaAction(editor, "# "));
editor.querySelector("#insert-h2").addEventListener("click", () => textareaAction(editor, "## "));
editor.querySelector("#insert-h3").addEventListener("click", () => textareaAction(editor, "### "));
editor.querySelector("#insert-h4").addEventListener("click", () => textareaAction(editor, "#### "));
editor.querySelector("#insert-underline").addEventListener("click", () => textareaAction(editor, "_", undefined, true));
editor.querySelector("#insert-italics").addEventListener("click", () => textareaAction(editor, "*", undefined, true));
editor.querySelector("#insert-bold").addEventListener("click", () => textareaAction(editor, "__", undefined, true));
editor.querySelector("#insert-strike").addEventListener("click", () => textareaAction(editor, "~~", undefined, true));
editor.querySelector("#insert-sup").addEventListener("click", () => textareaAction(editor, "^", undefined, true));
editor.addEventListener("drop", async (event) => {
event.preventDefault();
const files = event.dataTransfer.files;
// let image_queue = [];
for (let i = 0; i < files.length; i++) {
// Each dropped image will be stored in this formatted object
const image_object = {
data_blob: new Blob([await files[i].arrayBuffer()]),
content_type: files[i].type,
};
let form_data = {
buffer: await _readFile(image_object.data_blob),
content_type: image_object.content_type,
post_id: window.location.href.split("/")[4],
parent_type: "posts",
};
const image_uploading_request = await request("/api/web/image", "POST", form_data);
if (image_uploading_request.status == 200) {
textareaAction(editor, `{image:${image_uploading_request.body}}`);
media.push(image_uploading_request.body);
}
}
});
let textarea = editor.querySelector("textarea");
textarea.addEventListener("input", (e) => {
textarea.style.height = textarea.scrollHeight + "px";
textarea.style.minHeight = e.target.scrollHeight + "px";
});
// Auto resize on page load
textarea.style.height = textarea.scrollHeight + "px";
textarea.style.minHeight = textarea.scrollHeight + "px";
});
// We need to read the file contents in order to convert it to base64 to send to the server
function _readFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(file);
});
}