/* Редактор markdown: панель кнопок применяется к textarea по data-md-target. Плюс переключение статьи в режим правки прямо на странице (без модального окна). */ (function () { var dirty = false; function target(toolbar) { return document.querySelector(toolbar.getAttribute('data-md-target')); } function replaceSelection(area, before, after, placeholder) { var start = area.selectionStart, end = area.selectionEnd; var selected = area.value.slice(start, end) || placeholder || ''; var text = before + selected + after; area.setRangeText(text, start, end, 'end'); if (!area.selectionEnd || selected === placeholder) { // оставляем курсор внутри вставленного фрагмента area.selectionStart = start + before.length; area.selectionEnd = start + before.length + selected.length; } area.focus(); area.dispatchEvent(new Event('input', { bubbles: true })); } function prefixLines(area, prefix, numbered) { var start = area.selectionStart, end = area.selectionEnd; var value = area.value; var lineStart = value.lastIndexOf('\n', start - 1) + 1; var lineEnd = value.indexOf('\n', end); if (lineEnd === -1) lineEnd = value.length; var block = value.slice(lineStart, lineEnd); var lines = block.split('\n'); var changed = lines.map(function (line, index) { if (line.trim() === '') return line; return (numbered ? (index + 1) + '. ' : prefix) + line; }).join('\n'); area.setRangeText(changed, lineStart, lineEnd, 'end'); area.focus(); area.dispatchEvent(new Event('input', { bubbles: true })); } function insertBlock(area, text, cursorOffset) { var start = area.selectionStart; var value = area.value; var atLineStart = start === 0 || value[start - 1] === '\n'; var prefix = atLineStart ? '' : '\n'; var insert = prefix + text + '\n'; area.setRangeText(insert, start, area.selectionEnd, 'end'); var pos = area.selectionStart - 1 - (text.length - (cursorOffset || 0)); area.selectionStart = area.selectionEnd = start + prefix.length + (cursorOffset || 0); area.focus(); area.dispatchEvent(new Event('input', { bubbles: true })); } function apply(action, area) { switch (action) { case 'bold': replaceSelection(area, '**', '**', 'текст'); break; case 'italic': replaceSelection(area, '*', '*', 'текст'); break; case 'code': replaceSelection(area, '`', '`', 'код'); break; case 'h2': prefixLines(area, '## '); break; case 'ul': prefixLines(area, '- '); break; case 'ol': prefixLines(area, '', true); break; case 'quote': prefixLines(area, '> '); break; case 'link': replaceSelection(area, '[', '](https://)', 'ссылка'); break; case 'codeblock': replaceSelection(area, '```c\n', '\n```', 'int main(void)\n{\n return 0;\n}'); break; case 'table': insertBlock(area, '| Столбец | Столбец |\n|---|---|\n| значение | значение |', 2); break; case 'figure': replaceSelection(area, ':::figure assets/', ' | Рис. 1. Подпись', 'имя.svg'); break; case 'video': replaceSelection(area, ':::video assets/', ' | Подпись к видео', 'имя.mp4'); break; case 'spoiler': replaceSelection(area, ':::spoiler Решение\n', '\n:::', 'решение'); break; } } document.addEventListener('click', function (event) { var button = event.target.closest('.md-btn'); if (!button) return; var toolbar = button.closest('.md-toolbar'); if (!toolbar) return; var area = target(toolbar); if (!area) return; event.preventDefault(); apply(button.getAttribute('data-md'), area); }); /* --- режим правки статьи на странице --- */ window.startArticleEdit = function () { var view = document.getElementById('article-view'); var form = document.getElementById('article-edit'); if (!view || !form) return; view.hidden = true; form.hidden = false; dirty = false; var area = document.getElementById('article-body'); if (area) area.focus(); }; window.cancelArticleEdit = function () { if (dirty && !confirm('Выйти из редактирования без сохранения?')) return; var view = document.getElementById('article-view'); var form = document.getElementById('article-edit'); if (!view || !form) return; form.hidden = true; view.hidden = false; dirty = false; }; document.addEventListener('input', function (event) { var id = event.target && event.target.id; if (id === 'article-body' || id === 'article-title') dirty = true; }); /* Сохранение — это осознанный уход со страницы, подтверждение не нужно */ document.addEventListener('submit', function (event) { if (event.target && event.target.id === 'article-edit') dirty = false; }, true); window.addEventListener('beforeunload', function (event) { var form = document.getElementById('article-edit'); if (dirty && form && !form.hidden) { event.preventDefault(); event.returnValue = ''; } }); document.addEventListener('DOMContentLoaded', function () { if (window.location.search.indexOf('edit=1') >= 0) window.startArticleEdit(); }); })();