(function () { var textarea = document.getElementById('editor'); if (!textarea) return; var form = textarea.closest('form'); // --- DOM helpers --- function wrap(before, after, placeholder) { var start = textarea.selectionStart; var end = textarea.selectionEnd; var selected = textarea.value.slice(start, end) || placeholder; var replacement = before + selected + after; textarea.value = textarea.value.slice(0, start) + replacement + textarea.value.slice(end); if (selected === placeholder) { textarea.selectionStart = start + before.length; textarea.selectionEnd = start + before.length + placeholder.length; } else { textarea.selectionStart = start + replacement.length; textarea.selectionEnd = start + replacement.length; } textarea.focus(); } function linePrefix(prefix) { var start = textarea.selectionStart; var lineStart = textarea.value.lastIndexOf('\n', start - 1) + 1; textarea.value = textarea.value.slice(0, lineStart) + prefix + textarea.value.slice(lineStart); textarea.selectionStart = textarea.selectionEnd = start + prefix.length; textarea.focus(); } function insertAtCursor(s) { var start = textarea.selectionStart; var end = textarea.selectionEnd; textarea.value = textarea.value.slice(0, start) + s + textarea.value.slice(end); textarea.selectionStart = textarea.selectionEnd = start + s.length; textarea.dispatchEvent(new Event('input')); textarea.focus(); } function applyResult(result) { textarea.value = result.text; textarea.selectionStart = textarea.selectionEnd = result.cursor; textarea.dispatchEvent(new Event('input')); textarea.focus(); } function applyTableOp(fn, arg) { var result = arg !== undefined ? fn(textarea.value, textarea.selectionStart, arg) : fn(textarea.value, textarea.selectionStart); if (result) applyResult(result); } // --- Actions --- var T = EditorTables; var L = EditorLists; var D = EditorDates; var actions = { save: function () { form.submit(); }, bold: function () { wrap('**', '**', 'bold text'); }, italic: function () { wrap('*', '*', 'italic text'); }, h1: function () { linePrefix('# '); }, h2: function () { linePrefix('## '); }, h3: function () { linePrefix('### '); }, code: function () { wrap('`', '`', 'code'); }, codeblock: function () { wrap('```\n', '\n```', 'code'); }, quote: function () { linePrefix('> '); }, link: function () { wrap('[', '](url)', 'link text'); }, ul: function () { linePrefix('- '); }, ol: function () { linePrefix('1. '); }, hr: function () { wrap('\n\n---\n\n', '', ''); }, fmttable: function () { applyTableOp(T.formatTableText); }, tblalignleft: function () { applyTableOp(T.setColumnAlignment, 'left'); }, tblaligncenter: function () { applyTableOp(T.setColumnAlignment, 'center'); }, tblalignright: function () { applyTableOp(T.setColumnAlignment, 'right'); }, tblinsertcol: function () { applyTableOp(T.insertColumn); }, tbldeletecol: function () { applyTableOp(T.deleteColumn); }, tblinsertrow: function () { applyTableOp(T.insertRow); }, tbldeleterow: function () { applyTableOp(T.deleteRow); }, dateiso: function () { insertAtCursor(D.isoDate()); }, datelong: function () { insertAtCursor(D.longDate()); }, }; // --- Keyboard shortcut registration --- var keyMap = {}; document.querySelectorAll('[data-action]').forEach(function (btn) { btn.addEventListener('click', function () { var action = actions[btn.dataset.action]; if (action) action(); }); if (btn.dataset.key) { keyMap[btn.dataset.key] = actions[btn.dataset.action]; } }); keyMap['T'] = actions.fmttable; keyMap['D'] = actions.dateiso; keyMap['W'] = actions.datelong; document.addEventListener('keydown', function (e) { if (!e.altKey || !e.shiftKey) return; var action = keyMap[e.key]; if (action) { e.preventDefault(); action(); } }); // --- Textarea key handling --- textarea.addEventListener('keydown', function (e) { if (e.key === 'Delete' && e.shiftKey) { var result = T.deleteRow(textarea.value, textarea.selectionStart) || L.deleteOrderedLine(textarea.value, textarea.selectionStart); if (!result) return; e.preventDefault(); applyResult(result); return; } if (e.key === 'Enter' && e.shiftKey) { var result = T.insertRowBelow(textarea.value, textarea.selectionStart); if (!result) return; e.preventDefault(); applyResult(result); return; } if (e.key !== 'Enter') return; var result = L.handleEnterKey(textarea.value, textarea.selectionStart); if (!result) return; e.preventDefault(); applyResult(result); }); // --- Dropdown helper --- var openMenus = []; function makeDropdown(triggerBtn, items) { var menu = document.createElement('div'); menu.className = 'toolbar-dropdown-menu'; items.forEach(function (item) { var btn = document.createElement('button'); btn.type = 'button'; btn.className = 'btn btn-tool toolbar-dropdown-item'; btn.textContent = item.label; btn.addEventListener('mousedown', function (e) { e.preventDefault(); actions[item.action](); menu.classList.remove('is-open'); }); menu.appendChild(btn); }); triggerBtn.appendChild(menu); openMenus.push(menu); triggerBtn.addEventListener('click', function (e) { if (e.target !== triggerBtn) return; var wasOpen = menu.classList.contains('is-open'); openMenus.forEach(function (m) { m.classList.remove('is-open'); }); if (!wasOpen) menu.classList.add('is-open'); }); } document.addEventListener('click', function (e) { var insideAny = openMenus.some(function (m) { return m.parentElement && m.parentElement.contains(e.target); }); if (!insideAny) openMenus.forEach(function (m) { m.classList.remove('is-open'); }); }); document.addEventListener('keydown', function (e) { if (e.key === 'Escape') openMenus.forEach(function (m) { m.classList.remove('is-open'); }); }); // --- Table dropdown --- var tblDropBtn = document.querySelector('[data-action="tbldrop"]'); if (tblDropBtn) { makeDropdown(tblDropBtn, [ { label: 'Format table', action: 'fmttable' }, { label: 'Align left', action: 'tblalignleft' }, { label: 'Align center', action: 'tblaligncenter' }, { label: 'Align right', action: 'tblalignright' }, { label: 'Insert column', action: 'tblinsertcol' }, { label: 'Delete column', action: 'tbldeletecol' }, { label: 'Insert row', action: 'tblinsertrow' }, { label: 'Delete row', action: 'tbldeleterow' }, ]); } // --- Date dropdown --- var dateDropBtn = document.querySelector('[data-action="datedrop"]'); if (dateDropBtn) { makeDropdown(dateDropBtn, [ { label: 'YYYY-MM-DD', action: 'dateiso' }, { label: 'DE Long', action: 'datelong' }, ]); } })();