Инструменты пользователя

Инструменты сайта


tmp_teh_zadanie_2_23.07.26_18:04

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слеваПредыдущая версия
Следующая версия
Предыдущая версия
tmp_teh_zadanie_2_23.07.26_18:04 [2026/07/23 18:26] – [local.php] VladPolskiytmp_teh_zadanie_2_23.07.26_18:04 [2026/07/23 18:36] (текущий) – [local.php] VladPolskiy
Строка 1426: Строка 1426:
 </code> </code>
  
-===== local.php ===== +===== toolbar.php ===== 
-<code php local.php>+<file html toolbar.php
 +<?php 
 +/** 
 + * Системный компонент редактора: Монолитный Toolbar с горизонтальными пикерами DokuWiki 
 + */ 
 +if (!defined('WIKI_ROOT')) die();  
 +?> 
 +<div class="doku-toolbar-container"> 
 +    <div class="doku-toolbar-group"> 
 +        <!-- Текст --> 
 +        <button type="button" class="doku-btn-ico" title="Жирный (Ctrl+B)" onclick="insertTags('**', '**', 'жирный текст')"><strong>B</strong></button> 
 +        <button type="button" class="doku-btn-ico" title="Курсив (Ctrl+I)" onclick="insertTags('//', '//', 'курсив')"><em>I</em></button> 
 +        <button type="button" class="doku-btn-ico" title="Подчеркнутый (Ctrl+U)" onclick="insertTags('__', '__', 'подчеркнутый текст')"><u>U</u></button> 
 +        <button type="button" class="doku-btn-ico" title="Моноширинный" onclick="insertTags('\'\'', '\'\'', 'код')"><small>TT</small></button> 
 +        <button type="button" class="doku-btn-ico" title="Зачеркнутый" onclick="insertTags('<del>', '</del>', 'зачеркнутый текст')"><del>S</del></button> 
 +    </div> 
 + 
 +    <!-- ВЫПАДАЮЩЕЕ МЕНЮ ЗАГОЛОВКОВ (ГОРИЗОНТАЛЬНЫЙ ПИКЕР) --> 
 +    <div class="doku-toolbar-group"> 
 +        <div class="doku-dropdown"> 
 +            <button type="button" class="doku-btn-ico" id="dokuBtnH" title="Выбрать заголовок"> 
 +                <strong>H</strong><span class="doku-arrow"></span> 
 +            </button> 
 +            <div class="doku-dropdown-content" id="dokuDropH"> 
 +                <div class="doku-sub-toolbar"> 
 +                    <!-- Ластик / Очистка стиля --> 
 +                    <button type="button" class="doku-sub-btn" title="Очистить стиль" onclick="insertTags('', '', '')"> 
 +                        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg> 
 +                    </button> 
 +                    <!-- Кнопки уровней H1-H5 --> 
 +                    <button type="button" class="doku-sub-btn" title="Заголовок H1" onclick="insertTags('====== ', ' ======\n', 'Заголовок 1')"><strong>H₁</strong></button> 
 +                    <button type="button" class="doku-sub-btn" title="Заголовок H2" onclick="insertTags('===== ', ' =====\n', 'Заголовок 2')"><strong>H₂</strong></button> 
 +                    <button type="button" class="doku-sub-btn" title="Заголовок H3" onclick="insertTags('==== ', ' ====\n', 'Заголовок 3')"><strong>H₃</strong></button> 
 +                    <button type="button" class="doku-sub-btn" title="Заголовок H4" onclick="insertTags('=== ', ' ===\n', 'Заголовок 4')"><strong>H₄</strong></button> 
 +                    <button type="button" class="doku-sub-btn" title="Заголовок H5" onclick="insertTags('== ', ' ==\n', 'Заголовок 5')"><strong>H₅</strong></button> 
 +                </div> 
 +            </div> 
 +        </div> 
 +    </div> 
 + 
 +    <div class="doku-toolbar-group"> 
 +        <!-- Списки и таблицы --> 
 +        <button type="button" class="doku-btn-ico" title="Маркированный список" onclick="insertTags('  * ', '\n', 'Элемент списка')"> 
 +            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><circle cx="4" cy="6" r="1"/><line x1="9" y1="6" x2="20" y2="6"/><circle cx="4" cy="12" r="1"/><line x1="9" y1="12" x2="20" y2="12"/><circle cx="4" cy="18" r="1"/><line x1="9" y1="18" x2="20" y2="18"/></svg> 
 +        </button> 
 +        <button type="button" class="doku-btn-ico" title="Нумерованный список" onclick="insertTags('  - ', '\n', 'Элемент списка')"> 
 +            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="10" y1="6" x2="21" y2="6"/><line x1="10" y1="12" x2="21" y2="12"/><line x1="10" y1="18" x2="21" y2="18"/><path d="M4 6h1v4M4 10h2M4 14h2v2H4v2h2"/></svg> 
 +        </button> 
 +        <button type="button" class="doku-btn-ico" title="Вставить таблицу" onclick="insertTags('^ Заголовок 1 ^ Заголовок 2 ^\n| Элемент 1   | Элемент 2   |\n', '', '')"> 
 +            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="12" y1="3" x2="12" y2="21"/></svg> 
 +        </button> 
 +         
 +        <!-- ИСПРАВЛЕНО: Кнопка кода теперь обернута в блок dropdown с корректным ID и стрелочкой --> 
 +        <div class="doku-dropdown"> 
 +            <button type="button" class="doku-btn-ico" id="dokuBtnCode" title="Вставить блок кода"> 
 +                &lt;&gt;<span class="doku-arrow"></span> 
 +            </button> 
 +            <div class="doku-dropdown-content" id="dokuDropCode"> 
 +                <div class="doku-sub-toolbar"> 
 +                    <!-- Обычный код --> 
 +                    <button type="button" class="doku-sub-btn" title="Простой код" onclick="insertTags('<code>\n', '\n</code>', 'текст кода')"> 
 +                        <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="#444" stroke-width="2.5"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg> 
 +                    </button> 
 +                    <!-- HTML --> 
 +                    <button type="button" class="doku-sub-btn" title="Code HTML" onclick="insertTags('<code html>\n', '\n</code>', '<!-- HTML код -->')"> 
 +                        <div class="file-ico css-html">HTM</div> 
 +                    </button> 
 +                    <!-- PHP --> 
 +                    <button type="button" class="doku-sub-btn" title="Code PHP" onclick="insertTags('<code php>\n', '\n</code>', '// PHP код')"> 
 +                        <div class="file-ico css-php">PHP</div> 
 +                    </button> 
 +                    <!-- CSS --> 
 +                    <button type="button" class="doku-sub-btn" title="Code CSS" onclick="insertTags('<code css>\n', '\n</code>', '/* CSS стили */')"> 
 +                        <div class="file-ico css-css">CSS</div> 
 +                    </button> 
 +                    <!-- JS --> 
 +                    <button type="button" class="doku-sub-btn" title="Code JavaScript" onclick="insertTags('<code javascript>\n', '\n</code>', '// JS код')"> 
 +                        <div class="file-ico css-js">JS</div> 
 +                    </button> 
 +                    <!-- SQL --> 
 +                    <button type="button" class="doku-sub-btn" title="Code SQL" onclick="insertTags('<code sql>\n', '\n</code>', 'SELECT * FROM table;')"> 
 +                        <div class="file-ico css-sql">SQL</div> 
 +                    </button> 
 +                    <!-- BASH --> 
 +                    <button type="button" class="doku-sub-btn" title="Code Bash" onclick="insertTags('<code bash>\n', '\n</code>', '#!/bin/bash')"> 
 +                        <div class="file-ico css-bash">BSH</div> 
 +                    </button> 
 +                </div> 
 +            </div> 
 +        </div> 
 +    </div> 
 + 
 +    <div class="doku-toolbar-group"> 
 +        <!-- Ссылки --> 
 +        <button type="button" class="doku-btn-ico" title="Внутренняя ссылка" onclick="insertTags('[[:пространство:имя_файла|%sel%', ']]', 'разметка')"> 
 +            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg> 
 +        </button> 
 +        <button type="button" class="doku-btn-ico" title="Вставить изображение" onclick="openMediaModal()"> 
 +            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg> 
 +        </button> 
 +    </div> 
 +</div> 
 + 
 +<!-- Каркас модального окна скрыт ниже, без изменений --> 
 +<div id="mediaModal" style="display:none; position:fixed; z-index:9999; left:0; top:0; width:100%; height:100%; background-color:rgba(0,0,0,0.5); align-items:center; justify-content:center;"> 
 +    <div style="background:#fff; padding:25px; border-radius:6px; width:500px; max-width:90%; box-shadow:0 4px 20px rgba(0,0,0,0.2); position:relative;"> 
 +        <span onclick="closeMediaModal()" style="position:absolute; right:15px; top:10px; font-size:24px; font-weight:bold; cursor:pointer; color:#aaa;">&times;</span> 
 +        <h3 style="margin-top:0; color:#2b5e8f; margin-bottom:20px; font-family: sans-serif;">Загрузка и вставка изображения</h3> 
 +        <div id="modalUploadContainer"> 
 +            <div style="border:2px dashed #ccc; padding:30px; text-align:center; background:#fafafa; border-radius:4px; margin-bottom:15px; cursor:pointer; position:relative;"> 
 +                <input type="file" id="modalFileInp" name="uploadfile" accept="image/*" style="position:absolute; left:0; top:0; width:100%; height:100%; opacity:0; cursor:pointer;"> 
 +                <span id="uploadPrompt" style="color:#666; font-size:14px; font-family: sans-serif;">📄 Кликните сюда для выбора картинки</span> 
 +            </div> 
 +            <div style="text-align:right; font-family: sans-serif;"> 
 +                <span onclick="closeMediaModal()" style="display:inline-block; padding:8px 15px; background:#eee; border:1px solid #ccc; border-radius:4px; cursor:pointer; margin-right:10px; font-size:14px; color:#333;">Отмена</span> 
 +                <span onclick="sendModalFile(event)" style="display:inline-block; padding:8px 20px; background:#2b5e8f; color:#fff; border-radius:4px; cursor:pointer; font-weight:bold; font-size:14px;">Загрузить и вставить</span> 
 +            </div> 
 +        </div> 
 +    </div> 
 +</div> 
 +</file> 
 + 
 +===== toolbar.js ===== 
 +<code js toolbar.js> 
 +/** 
 + * Функция вставки вики-тегов в поле редактора 
 + */ 
 +function insertTags(openTag, closeTag, defaultText) { 
 +    var txtarea = document.getElementById("wikiEditor"); 
 +    if (!txtarea) return; 
 + 
 +    var start = txtarea.selectionStart; 
 +    var end = txtarea.selectionEnd; 
 +    var selText = txtarea.value.substring(start, end); 
 +     
 +    if (!selText) {  
 +        selText = defaultText;  
 +    } 
 +     
 +    var replacement = ''; 
 +    var newCursorStart = start; 
 +    var newCursorEnd = end; 
 + 
 +    if (openTag.indexOf('%sel%') !== -1) { 
 +        replacement = openTag.replace('%sel%', selText) + closeTag; 
 +        txtarea.value = txtarea.value.substring(0, start) + replacement + txtarea.value.substring(end, txtarea.value.length); 
 +        newCursorStart = start + 3;  
 +        newCursorEnd = start + 3; 
 +    } else { 
 +        replacement = openTag + selText + closeTag; 
 +        txtarea.value = txtarea.value.substring(0, start) + replacement + txtarea.value.substring(end, txtarea.value.length); 
 +        newCursorStart = start; 
 +        newCursorEnd = start + replacement.length; 
 +    } 
 +     
 +    txtarea.focus(); 
 +    txtarea.selectionStart = newCursorStart; 
 +    txtarea.selectionEnd = newCursorEnd; 
 +
 + 
 +/** 
 + * Инициализация горячих клавиш 
 + */ 
 +document.addEventListener("DOMContentLoaded", function() { 
 +    var editor = document.getElementById("wikiEditor"); 
 +    if (!editor) return; 
 + 
 +    editor.addEventListener("keydown", function(e) { 
 +        var isCtrl = e.ctrlKey || e.metaKey; 
 +        if (isCtrl) { 
 +            if (e.key.toLowerCase() === 'b') { e.preventDefault(); insertTags('**', '**', 'жирный текст');
 +            if (e.key.toLowerCase() === 'i') { e.preventDefault(); insertTags('//', '//', 'курсив');
 +            if (e.key.toLowerCase() === 'u') { e.preventDefault(); insertTags('__', '__', 'подчеркнутый текст');
 +        } 
 +    }); 
 +}); 
 + 
 +/** 
 + * Асинхронный движок предпросмотра текста в стиле DokuWiki 
 + */ 
 +function runLivePreview() { 
 +    var editor = document.getElementById("wikiEditor"); 
 +    var previewBlock = document.getElementById("previewBlock"); 
 +    var previewContent = document.getElementById("previewContent"); 
 +     
 +    if (!editor || !previewBlock || !previewContent) return; 
 +     
 +    var textValue = editor.value; 
 +     
 +    var formData = new FormData(); 
 +    formData.append("wikitext", textValue); 
 +     
 +    var urlParams = new URLSearchParams(window.location.search); 
 +    var pageId = urlParams.get('id') || 'start'; 
 +     
 +    previewContent.innerHTML = "<span style='color:#666; font-style:italic;'>Генерация предпросмотра...</span>"; 
 +    previewBlock.style.display = "block"; 
 +     
 +    previewBlock.scrollIntoView({ behavior: 'smooth' }); 
 + 
 +    // Отправляем запрос на бэкенд 
 +    fetch('?id=' + encodeURIComponent(pageId) + '&do=api_preview',
 +        method: 'POST', 
 +        body: formData 
 +    }) 
 +    .then(function(response) { 
 +        if (!response.ok) { 
 +            throw new Error("Сервер вернул статус " + response.status); 
 +        } 
 +        // ИСПРАВЛЕНО: Ждем чистый текст/HTML, а не JSON! 
 +        return response.text();  
 +    }) 
 +    .then(function(htmlResult) { 
 +        // Мгновенно отрисовываем HTML в блоке превью 
 +        previewContent.innerHTML = htmlResult; 
 +    }) 
 +    .catch(function(error) { 
 +        console.error('Preview Error:', error); 
 +        previewContent.innerHTML = "<span style='color:red;'>Не удалось загрузить предпросмотр: " + error.message + "</span>"; 
 +    }); 
 +
 + 
 +// Добавьте этот код в самый конец файла assets/js/toolbar.js: 
 + 
 +/** 
 + * Управление выпадающими горизонтальными пикерами Toolbar 
 + */ 
 +document.addEventListener("DOMContentLoaded", function() { 
 +    var btnH = document.getElementById("dokuBtnH"); 
 +    var btnCode = document.getElementById("dokuBtnCode"); 
 +     
 +    var dropH = document.getElementById("dokuDropH"); 
 +    var dropCode = document.getElementById("dokuDropCode"); 
 + 
 +    if (btnH && dropH) { 
 +        btnH.addEventListener("click", function(e) { 
 +            e.stopPropagation(); 
 +            if (dropCode) dropCode.classList.remove("doku-dropdown-show"); 
 +            dropH.classList.toggle("doku-dropdown-show"); 
 +        }); 
 +    } 
 + 
 +    if (btnCode && dropCode) { 
 +        btnCode.addEventListener("click", function(e) { 
 +            e.stopPropagation(); 
 +            if (dropH) dropH.classList.remove("doku-dropdown-show"); 
 +            dropCode.classList.toggle("doku-dropdown-show"); 
 +        }); 
 +    } 
 + 
 +    document.addEventListener("click", function() { 
 +        if (dropH) dropH.classList.remove("doku-dropdown-show"); 
 +        if (dropCode) dropCode.classList.remove("doku-dropdown-show"); 
 +    }); 
 +});
 </code> </code>
  
-===== local.php ===== +===== media-modal.js ===== 
-<code php local.php>+<code js media-modal.js> 
 +/** 
 + * Системный компонент: Управление модальным окном Медиа-менеджера и AJAX загрузкой 
 + */ 
 + 
 +function openMediaModal() { 
 +    var modal = document.getElementById("mediaModal"); 
 +    if (modal) { 
 +        modal.style.display = "flex"; 
 +        document.getElementById("uploadPrompt").innerText = "📄 Кликните сюда для выбора картинки"; 
 +        document.getElementById("modalFileInp").value = "";  
 +    } 
 +
 + 
 +function closeMediaModal() { 
 +    var modal = document.getElementById("mediaModal"); 
 +    if (modal) modal.style.display = "none"; 
 +
 + 
 +/** 
 + * Асинхронная отправка файла на бэкенд без перезагрузки страницы 
 + */ 
 +function sendModalFile(event) { 
 +    // Жестко глушим любые системные события браузера, чтобы предотвратить submit формы редактора 
 +    if (event) { 
 +        event.preventDefault(); 
 +        event.stopPropagation(); 
 +    } 
 + 
 +    var fileInp = document.getElementById("modalFileInp"); 
 +    if (!fileInp || !fileInp.files || fileInp.files.length === 0) { 
 +        alert("Пожалуйста, выберите файл для загрузки."); 
 +        return; 
 +    } 
 + 
 +    var urlParams = new URLSearchParams(window.location.search); 
 +    var pageId = urlParams.get('id') || 'start'; 
 + 
 +    var targetFile = fileInp.files.item(0); 
 + 
 +    var formData = new FormData(); 
 +    formData.append("uploadfile", targetFile); 
 + 
 +    // Выполняем асинхронный фоновый запрос к бэкенду 
 +    fetch('?id=' + encodeURIComponent(pageId) + '&do=api_upload',
 +        method: 'POST', 
 +        body: formData 
 +    }) 
 +    .then(function(response) { 
 +        if (!response.ok) { 
 +            throw new Error("Ошибка сети: сервер вернул статус " + response.status); 
 +        } 
 +        return response.json(); 
 +    }) 
 +    .then(function(data) { 
 +        if (data.success) { 
 +            // Вставляем полученный тег в поле редактора 
 +            insertTags(data.tag, '', ''); 
 +            closeMediaModal(); 
 +        } else { 
 +            alert("Ошибка сервера: " + data.error); 
 +        } 
 +    }) 
 +    .catch(function(error) { 
 +        console.error('AJAX Error:', error); 
 +        alert("Критическая ошибка при фоновой отправке файла: " + error.message); 
 +    }); 
 +
 + 
 +document.addEventListener("DOMContentLoaded", function() { 
 +    var fileInp = document.getElementById("modalFileInp"); 
 +    if (fileInp) { 
 +        fileInp.addEventListener("change", function() { 
 +            if (this.files && this.files.length > 0) { 
 +                var currentFile = this.files.item(0); 
 +                document.getElementById("uploadPrompt").innerText = "✅ Выбран файл: " + currentFile.name; 
 +            } 
 +        }); 
 +    } 
 +});
 </code> </code>
  
  
tmp_teh_zadanie_2_23.07.26_18/04.1784820366.txt.gz · Последнее изменение: VladPolskiy

Если не указано иное, содержимое этой вики предоставляется на условиях следующей лицензии: Public Domain
Public Domain Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki