| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564 |
- document.addEventListener('DOMContentLoaded', function() {
- tinymce.init({
- license_key: 'gpl',
- remove_script_host: false,
- relative_urls: false,
- entity_encoding: 'raw', // Записывает символы как есть
- valid_elements: '*[*]', // Разрешает любые элементы и атрибуты
- content_css: false, // Отключает внешнюю CSS-стилизацию
- force_br_newlines: true,
- //force_p_newlines: true,
- entities: '160,nbsp', // Мини
- remove_linebreaks: false,
- selector: '.secondary-content', // Ваши текстовые области
- encoding: 'UTF-8', // Указывает кодировку
- plugins: 'image link media code table lists', // Подключены плагины для изображений, таблиц, списков
- toolbar: 'undo redo | styleselect | bold italic | bullist numlist | alignleft aligncenter alignright alignjustify | outdent indent | link image media table | code', // Добавлены кнопки для списков
- menubar: 'file edit view insert format tools table help', // Включаем меню с таблицами
- contextmenu: 'table', // Контекстное меню для работы с таблицами
- images_upload_url: '/admin/upload.php', // URL для загрузки изображений
- automatic_uploads: true, // Автоматическая загрузка изображений
- file_picker_types: 'image', // Включаем выбор файлов
- images_reuse_filename: true, // Сохраняем оригинальное название файла
- paste_as_text: true,
- setup: function (editor) {
- // Обработка перед сохранением
- editor.on('SaveContent', function (e) {
- e.content = e.content.replace(/<img([^>]*?)src=/g, '<img$1class="lazy" data-src=');
- });
-
- // Обработка контента при загрузке в редактор
- editor.on('BeforeSetContent', function (e) {
- e.content = e.content.replace(/<img([^>]*?)src=/g, '<img$1class="lazy" data-src=');
- });
- },
- table_default_attributes: {
- border: '1', // Граница таблицы по умолчанию
- },
- table_default_styles: {
- width: '100%', // Ширина таблицы по умолчанию
- borderCollapse: 'collapse', // Границы объединяются
- },
- file_picker_callback: function(callback, value, meta) {
- // Если это изображение, открываем стандартный файловый выбор
- if (meta.filetype === 'image') {
- const input = document.createElement('input');
- input.setAttribute('type', 'file');
- input.setAttribute('accept', 'image/*');
- input.onchange = function() {
- const file = this.files[0];
- const formData = new FormData();
- formData.append('file', file);
-
- fetch('/admin/upload.php', {
- method: 'POST',
- body: formData
- })
- .then(response => response.json())
- .then(result => {
- callback(result.location); // URL изображения
- })
- .catch(() => alert('Ошибка при загрузке изображения.'));
- };
- input.click();
- }
- },
- content_style: `
- body { font-family: Arial, sans-serif; font-size: 14px; }
- table { border-collapse: collapse; width: 100%; }
- th, td { border: 1px solid #ddd; padding: 8px; }
- th { background-color: #f2f2f2; text-align: left; }
- ` // Добавлены стили для таблиц
- });
- });
- // Выбор цвета-------------------------
- document.addEventListener('DOMContentLoaded', function () {
- // Получаем все элементы input с классами inp-color и inp-color-text
- const colorPickers = document.querySelectorAll('.inp-color');
- const textInputs = document.querySelectorAll('.inp-color-text');
- // Синхронизация inp-color -> inp-color-text
- colorPickers.forEach(colorPicker => {
- colorPicker.addEventListener('input', function () {
- const textInput = this.nextElementSibling;
- if (textInput && textInput.classList.contains('inp-color-text')) {
- textInput.value = this.value;
- }
- });
- });
- // Синхронизация inp-color-text -> inp-color
- textInputs.forEach(textInput => {
- textInput.addEventListener('input', function () {
- const colorPicker = this.previousElementSibling;
- if (colorPicker && colorPicker.classList.contains('inp-color')) {
- // Проверяем, что введенное значение является валидным цветом в формате HEX
- if (/^#([0-9A-F]{3}|[0-9A-F]{6})$/i.test(this.value)) {
- colorPicker.value = this.value;
- }
- }
- });
- // Проверяем и синхронизируем значение при загрузке страницы
- const colorPicker = textInput.previousElementSibling;
- if (colorPicker && colorPicker.classList.contains('inp-color')) {
- // Проверяем, что значение в текстовом поле валидное
- if (/^#([0-9A-F]{3}|[0-9A-F]{6})$/i.test(textInput.value)) {
- colorPicker.value = textInput.value;
- }
- }
- });
- });
- // function addRepeaterItem(type) {
- // const container = document.getElementById(`${type}-items`);
- // const index = container.children.length;
- // const html = `
- // <div class="repeater-item">
- // <input type="text" name="items[${index}][question]" placeholder="Question">
- // <input type="text" name="items[${index}][answer]" placeholder="Answer">
- // <button type="button" onclick="this.parentElement.remove()">Remove</button>
- // </div>`;
- // container.insertAdjacentHTML('beforeend', html);
- // }
- function addCasinoItem() {
- const container = document.getElementById('casinoRepeater');
- const tpl = document.getElementById('casinoTemplate').content.cloneNode(true);
- container.appendChild(tpl);
- }
- function uploadImage(input, wrapper) {
- const file = input.files[0];
- const formData = new FormData();
- formData.append('image', file);
- fetch('upload_repeater_image.php', {
- method: 'POST',
- body: formData
- })
- .then(resp => resp.json())
- .then(data => {
- if (data.success) {
- wrapper.querySelector('.image').value = data.path;
- } else {
- alert('Ошибка загрузки изображения: ' + data.message);
- }
- });
- }
- function saveRepeater() {
- const items = [];
- document.querySelectorAll('#casinoRepeater .casino-item').forEach((item, index) => {
- items.push({
- id: item.dataset.id || null,
- sort_order: index,
- image: item.querySelector('.image').value,
- alt: item.querySelector('.alt').value,
- title: item.querySelector('.title').value,
- heading: item.querySelector('.heading').value,
- text: item.querySelector('.text').value,
- button: item.querySelector('.button').value,
- keitaro: item.querySelector('.keitaro').value,
- });
- });
- document.getElementById('casinoRepeaterData').value = JSON.stringify(items);
- return true;
- }
- // Drag and Drop functionality for casino items
- document.addEventListener('DOMContentLoaded', function() {
- const container = document.getElementById('casinoRepeater');
- if (!container) return;
- let draggedElement = null;
- let placeholder = null;
- function updateOrderNumbers() {
- const items = container.querySelectorAll('.casino-item');
- items.forEach((item, index) => {
- const numberElement = item.querySelector('.casino-order-number');
- if (numberElement) {
- numberElement.textContent = index + 1;
- }
- });
- }
- function createPlaceholder() {
- const div = document.createElement('div');
- div.className = 'drag-placeholder';
- div.style.cssText = 'height: 60px; margin: 10px 0; border: 2px dashed #007bff; background: #f0f8ff; opacity: 0.5;';
- return div;
- }
- // Accordion functionality
- function initAccordion() {
- const items = container.querySelectorAll('.casino-item');
- items.forEach(item => {
- const header = item.querySelector('.casino-item-header');
- const toggleBtn = item.querySelector('.toggle-accordion');
- const content = item.querySelector('.casino-item-content');
- const dragHandle = item.querySelector('.drag-handle');
- if (!header || !toggleBtn || !content) return;
- // Toggle accordion
- const toggleAccordion = (e) => {
- // Не закрывать если клик по drag handle
- if (e.target.closest('.drag-handle')) {
- return;
- }
- const isOpen = content.style.display !== 'none' && content.style.display !== '';
- if (isOpen) {
- content.style.display = 'none';
- toggleBtn.textContent = '▼';
- } else {
- content.style.display = 'flex';
- toggleBtn.textContent = '▲';
- }
- };
- header.addEventListener('click', toggleAccordion);
- // Запрет на перетаскивание при клике на header (кроме drag-handle)
- header.addEventListener('mousedown', (e) => {
- if (!e.target.closest('.drag-handle')) {
- item.setAttribute('draggable', 'false');
- }
- });
- header.addEventListener('mouseup', () => {
- item.setAttribute('draggable', 'true');
- });
- // Drag только за handle
- dragHandle.addEventListener('mousedown', (e) => {
- e.stopPropagation();
- item.setAttribute('draggable', 'true');
- });
- // Обновление заголовка при изменении Casino title
- const headingInput = item.querySelector('.heading');
- if (headingInput) {
- headingInput.addEventListener('input', function() {
- const titleElement = item.querySelector('.casino-item-title');
- if (titleElement) {
- titleElement.textContent = this.value || 'New Casino Item';
- }
- });
- }
- });
- }
- function initDragAndDrop() {
- const items = container.querySelectorAll('.casino-item');
- items.forEach(item => {
- item.setAttribute('draggable', 'true');
- const dragHandle = item.querySelector('.drag-handle');
- // Drag только при клике на handle
- dragHandle.addEventListener('mousedown', function(e) {
- item.setAttribute('draggable', 'true');
- });
- item.addEventListener('dragstart', function(e) {
- // Проверяем что перетаскивание началось с drag-handle
- if (!e.target.querySelector('.drag-handle')) {
- e.preventDefault();
- return;
- }
- draggedElement = this;
- this.classList.add('dragging');
- e.dataTransfer.effectAllowed = 'move';
- e.dataTransfer.setData('text/html', '');
- setTimeout(() => {
- this.style.display = 'none';
- }, 0);
- });
- item.addEventListener('dragend', function(e) {
- this.style.display = '';
- this.classList.remove('dragging');
- if (placeholder && placeholder.parentNode) {
- placeholder.parentNode.removeChild(placeholder);
- }
- placeholder = null;
- draggedElement = null;
- updateOrderNumbers();
- });
- });
- }
- container.addEventListener('dragover', function(e) {
- e.preventDefault();
- e.dataTransfer.dropEffect = 'move';
- if (!draggedElement) return;
- const afterElement = getDragAfterElement(container, e.clientY);
- const currentItems = [...container.querySelectorAll('.casino-item:not(.dragging)')];
- if (!placeholder) {
- placeholder = createPlaceholder();
- }
- if (afterElement == null) {
- container.appendChild(placeholder);
- } else {
- container.insertBefore(placeholder, afterElement);
- }
- });
- container.addEventListener('drop', function(e) {
- e.preventDefault();
- if (!draggedElement || !placeholder) return;
- if (placeholder.parentNode) {
- placeholder.parentNode.insertBefore(draggedElement, placeholder);
- placeholder.parentNode.removeChild(placeholder);
- }
- draggedElement.style.display = '';
- placeholder = null;
- });
- function getDragAfterElement(container, y) {
- const draggableElements = [...container.querySelectorAll('.casino-item:not(.dragging)')];
- return draggableElements.reduce((closest, child) => {
- const box = child.getBoundingClientRect();
- const offset = y - box.top - box.height / 2;
- if (offset < 0 && offset > closest.offset) {
- return { offset: offset, element: child };
- } else {
- return closest;
- }
- }, { offset: Number.NEGATIVE_INFINITY }).element;
- }
- // Инициализация при загрузке
- initAccordion();
- initDragAndDrop();
- updateOrderNumbers();
- // Слушаем событие удаления элемента
- container.addEventListener('itemRemoved', function() {
- updateOrderNumbers();
- });
- // Переопределяем addCasinoItem для инициализации drag&drop на новых элементах
- window.originalAddCasinoItem = window.addCasinoItem;
- window.addCasinoItem = function() {
- if (window.originalAddCasinoItem) {
- window.originalAddCasinoItem();
- } else {
- const container = document.getElementById('casinoRepeater');
- const tpl = document.getElementById('casinoTemplate').content.cloneNode(true);
- container.appendChild(tpl);
- }
- setTimeout(() => {
- initAccordion();
- initDragAndDrop();
- updateOrderNumbers();
- }, 10);
- };
- });
- const pageSelect = document.getElementById('page-select');
- if (pageSelect) {
- pageSelect.addEventListener('change', function () {
- const selected = this.value;
- const blocks = document.querySelectorAll('.page-block');
- blocks.forEach(block => {
- if (block.classList.contains(selected)) {
- block.style.display = 'block';
- } else {
- block.style.display = 'none';
- }
- });
- });
- }
- // Tab switching functionality for new admin interface
- function switchTab(tabName) {
- // Hide all tab contents
- const contents = document.querySelectorAll('.tab-content');
- contents.forEach(content => content.classList.remove('active'));
-
- // Remove active class from all tabs
- const tabs = document.querySelectorAll('.tab');
- tabs.forEach(tab => tab.classList.remove('active'));
-
- // Show selected tab content
- document.getElementById(tabName + '-tab').classList.add('active');
-
- // Add active class to clicked tab
- event.target.classList.add('active');
- }
- // Repeater functionality for new admin interface
- function addRepeaterItem(type) {
- const container = document.getElementById(`${type}-items`);
- const index = container.children.length;
- const html = `
- <div class="repeater-item" style="margin-bottom: 15px; padding: 15px; border: 1px solid #ddd;">
- ${type === 'menu' ? `
- <input type="text" name="repeaters[${type}][${index}][title]" placeholder="Menu Title" style="width: 100%; margin-bottom: 10px;">
- <input type="text" name="repeaters[${type}][${index}][anchor]" placeholder="Anchor Link (#id)" style="width: 100%; margin-bottom: 10px;">
- ` : `
- <input type="text" name="repeaters[${type}][${index}][question]" placeholder="Question" style="width: 100%; margin-bottom: 10px;">
- <textarea name="repeaters[${type}][${index}][answer]" placeholder="Answer" style="width: 100%; margin-bottom: 10px;"></textarea>
- `}
- <button type="button" onclick="removeRepeaterItem(this)" style="background: #dc3545; color: white; border: none; padding: 5px 10px;">Remove</button>
- </div>`;
- container.insertAdjacentHTML('beforeend', html);
- }
- function removeRepeaterItem(button) {
- button.parentElement.remove();
- }
- function addCasinoItem() {
- const container = document.getElementById('casino-items');
- const index = container.children.length;
- const html = `
- <div class="casino-item" style="margin-bottom: 20px; padding: 15px; border: 1px solid #ddd;">
- <h4>Casino Item #${index + 1}</h4>
- <input type="text" name="repeaters[casino_list][${index}][heading]" placeholder="Casino Name" style="width: 100%; margin-bottom: 10px;">
- <input type="text" name="repeaters[casino_list][${index}][text]" placeholder="Bonus Text" style="width: 100%; margin-bottom: 10px;">
- <input type="text" name="repeaters[casino_list][${index}][button]" placeholder="Button Text" style="width: 100%; margin-bottom: 10px;">
- <input type="file" name="casino_image_${index}" style="margin-bottom: 10px;">
- <button type="button" onclick="removeRepeaterItem(this)" style="background: #dc3545; color: white; border: none; padding: 5px 10px;">Remove</button>
- </div>`;
- container.insertAdjacentHTML('beforeend', html);
- }
- function addHreflangItem() {
- const container = document.getElementById('hreflang-items');
- const index = container.children.length;
- const html = `
- <div style="margin-bottom: 15px; padding: 15px; border: 1px solid #ddd;">
- <div style="display: grid; grid-template-columns: 1fr 1fr auto; gap: 15px; align-items: center;">
- <div>
- <label style="display: block; margin-bottom: 5px; font-weight: bold;">Hreflang</label>
- <input type="text" name="seo[hreflang][${index}][hreflang]" placeholder="en, es, fr, etc." style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;">
- </div>
- <div>
- <label style="display: block; margin-bottom: 5px; font-weight: bold;">Href URL</label>
- <input type="text" name="seo[hreflang][${index}][href]" placeholder="https://example.com/en/" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;">
- </div>
- <button type="button" onclick="removeRepeaterItem(this)" style="background: #dc3545; color: white; border: none; padding: 8px 12px; border-radius: 4px; margin-top: 25px;">Remove</button>
- </div>
- </div>`;
- container.insertAdjacentHTML('beforeend', html);
- }
- // Load existing data for new admin interface
- function loadExistingData() {
- const menuItems = window.menuItems || [];
- const faqItems = window.faqItems || [];
- const casinoItems = window.casinoItems || [];
- const hreflangItems = window.hreflangItems || [];
- // Load existing menu items
- menuItems.forEach((item, index) => {
- if (item && item.title) {
- const container = document.getElementById('menu-items');
- if (container) {
- const html = `
- <div class="repeater-item" style="margin-bottom: 15px; padding: 15px; border: 1px solid #ddd;">
- <input type="text" name="repeaters[menu][${index}][title]" value="${item.title}" placeholder="Menu Title" style="width: 100%; margin-bottom: 10px;">
- <input type="text" name="repeaters[menu][${index}][anchor]" value="${item.anchor || ''}" placeholder="Anchor Link (#id)" style="width: 100%; margin-bottom: 10px;">
- <button type="button" onclick="removeRepeaterItem(this)" style="background: #dc3545; color: white; border: none; padding: 5px 10px;">Remove</button>
- </div>`;
- container.insertAdjacentHTML('beforeend', html);
- }
- }
- });
- // Load existing FAQ items
- faqItems.forEach((item, index) => {
- if (item && item.question) {
- const container = document.getElementById('faq-items');
- if (container) {
- const html = `
- <div class="repeater-item" style="margin-bottom: 15px; padding: 15px; border: 1px solid #ddd;">
- <input type="text" name="repeaters[faq][${index}][question]" value="${item.question}" placeholder="Question" style="width: 100%; margin-bottom: 10px;">
- <textarea name="repeaters[faq][${index}][answer]" placeholder="Answer" style="width: 100%; margin-bottom: 10px;">${item.answer || ''}</textarea>
- <button type="button" onclick="removeRepeaterItem(this)" style="background: #dc3545; color: white; border: none; padding: 5px 10px;">Remove</button>
- </div>`;
- container.insertAdjacentHTML('beforeend', html);
- }
- }
- });
- // Load existing casino items
- casinoItems.forEach((item, index) => {
- if (item && item.heading) {
- const container = document.getElementById('casino-items');
- if (container) {
- const html = `
- <div class="casino-item" style="margin-bottom: 20px; padding: 15px; border: 1px solid #ddd;">
- <h4>${item.heading}</h4>
- <input type="text" name="repeaters[casino_list][${index}][heading]" value="${item.heading}" placeholder="Casino Name" style="width: 100%; margin-bottom: 10px;">
- <input type="text" name="repeaters[casino_list][${index}][text]" value="${item.text || ''}" placeholder="Bonus Text" style="width: 100%; margin-bottom: 10px;">
- <input type="text" name="repeaters[casino_list][${index}][button]" value="${item.button || ''}" placeholder="Button Text" style="width: 100%; margin-bottom: 10px;">
- <button type="button" onclick="removeRepeaterItem(this)" style="background: #dc3545; color: white; border: none; padding: 5px 10px;">Remove</button>
- </div>`;
- container.insertAdjacentHTML('beforeend', html);
- }
- }
- });
- // Load existing hreflang items
- hreflangItems.forEach((item, index) => {
- if (item && (item.hreflang || item.href)) {
- const container = document.getElementById('hreflang-items');
- if (container) {
- const html = `
- <div style="margin-bottom: 15px; padding: 15px; border: 1px solid #ddd;">
- <div style="display: grid; grid-template-columns: 1fr 1fr auto; gap: 15px; align-items: center;">
- <div>
- <label style="display: block; margin-bottom: 5px; font-weight: bold;">Hreflang</label>
- <input type="text" name="seo[hreflang][${index}][hreflang]" value="${item.hreflang || ''}" placeholder="en, es, fr, etc." style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;">
- </div>
- <div>
- <label style="display: block; margin-bottom: 5px; font-weight: bold;">Href URL</label>
- <input type="text" name="seo[hreflang][${index}][href]" value="${item.href || ''}" placeholder="https://example.com/en/" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;">
- </div>
- <button type="button" onclick="removeRepeaterItem(this)" style="background: #dc3545; color: white; border: none; padding: 8px 12px; border-radius: 4px; margin-top: 25px;">Remove</button>
- </div>
- </div>`;
- container.insertAdjacentHTML('beforeend', html);
- }
- }
- });
- }
- // Initialize on DOM ready (for new admin interface)
- if (document.readyState === 'loading') {
- document.addEventListener('DOMContentLoaded', loadExistingData);
- } else {
- loadExistingData();
- }
|