scripts.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. document.addEventListener('DOMContentLoaded', function() {
  2. tinymce.init({
  3. license_key: 'gpl',
  4. remove_script_host: false,
  5. relative_urls: false,
  6. entity_encoding: 'raw',
  7. valid_elements: '*[*]',
  8. content_css: false,
  9. force_br_newlines: true,
  10. entities: '160,nbsp',
  11. remove_linebreaks: false,
  12. selector: '.secondary-content',
  13. encoding: 'UTF-8',
  14. plugins: 'image link media code table lists',
  15. toolbar: 'undo redo | styleselect | bold italic | bullist numlist | alignleft aligncenter alignright alignjustify | outdent indent | link image media table | code',
  16. menubar: 'file edit view insert format tools table help',
  17. contextmenu: 'table',
  18. images_upload_url: '/admin/upload.php',
  19. automatic_uploads: true,
  20. file_picker_types: 'image',
  21. images_reuse_filename: true,
  22. paste_as_text: true,
  23. setup: function (editor) {
  24. editor.on('SaveContent', function (e) {
  25. e.content = e.content.replace(/<img([^>]*?)src=/g, '<img$1class="lazy" data-src=');
  26. });
  27. editor.on('BeforeSetContent', function (e) {
  28. e.content = e.content.replace(/<img([^>]*?)src=/g, '<img$1class="lazy" data-src=');
  29. });
  30. },
  31. table_default_attributes: {
  32. border: '1',
  33. },
  34. table_default_styles: {
  35. width: '100%',
  36. borderCollapse: 'collapse',
  37. },
  38. file_picker_callback: function(callback, value, meta) {
  39. if (meta.filetype === 'image') {
  40. const input = document.createElement('input');
  41. input.setAttribute('type', 'file');
  42. input.setAttribute('accept', 'image/*');
  43. input.onchange = function() {
  44. const file = this.files[0];
  45. const formData = new FormData();
  46. formData.append('file', file);
  47. fetch('/admin/upload.php', {
  48. method: 'POST',
  49. body: formData
  50. })
  51. .then(response => response.json())
  52. .then(result => {
  53. callback(result.location);
  54. })
  55. .catch(() => alert('Ошибка при загрузке изображения.'));
  56. };
  57. input.click();
  58. }
  59. },
  60. content_style: `
  61. body { font-family: Arial, sans-serif; font-size: 14px; }
  62. table { border-collapse: collapse; width: 100%; }
  63. th, td { border: 1px solid #ddd; padding: 8px; }
  64. th { background-color: #f2f2f2; text-align: left; }
  65. `
  66. });
  67. });
  68. // Color picker functionality
  69. document.addEventListener('DOMContentLoaded', function () {
  70. const colorPickers = document.querySelectorAll('.inp-color');
  71. const textInputs = document.querySelectorAll('.inp-color-text');
  72. colorPickers.forEach(colorPicker => {
  73. colorPicker.addEventListener('input', function () {
  74. const textInput = this.nextElementSibling;
  75. if (textInput && textInput.classList.contains('inp-color-text')) {
  76. textInput.value = this.value;
  77. }
  78. });
  79. });
  80. textInputs.forEach(textInput => {
  81. textInput.addEventListener('input', function () {
  82. const colorPicker = this.previousElementSibling;
  83. if (colorPicker && colorPicker.classList.contains('inp-color')) {
  84. if (/^#([0-9A-F]{3}|[0-9A-F]{6})$/i.test(this.value)) {
  85. colorPicker.value = this.value;
  86. }
  87. }
  88. });
  89. const colorPicker = textInput.previousElementSibling;
  90. if (colorPicker && colorPicker.classList.contains('inp-color')) {
  91. if (/^#([0-9A-F]{3}|[0-9A-F]{6})$/i.test(textInput.value)) {
  92. colorPicker.value = textInput.value;
  93. }
  94. }
  95. });
  96. });
  97. // Casino repeater functionality
  98. function addCasinoItem() {
  99. const container = document.getElementById('casinoRepeater');
  100. const tpl = document.getElementById('casinoTemplate').content.cloneNode(true);
  101. container.appendChild(tpl);
  102. }
  103. function uploadImage(input, wrapper) {
  104. const file = input.files[0];
  105. const formData = new FormData();
  106. formData.append('image', file);
  107. fetch('upload_repeater_image.php', {
  108. method: 'POST',
  109. body: formData
  110. })
  111. .then(resp => resp.json())
  112. .then(data => {
  113. if (data.success) {
  114. wrapper.querySelector('.image').value = data.path;
  115. } else {
  116. alert('Ошибка загрузки изображения: ' + data.message);
  117. }
  118. });
  119. }
  120. function saveRepeater() {
  121. const items = [];
  122. document.querySelectorAll('#casinoRepeater .casino-item').forEach((item, index) => {
  123. items.push({
  124. id: item.dataset.id || null,
  125. sort_order: index,
  126. image: item.querySelector('.image').value,
  127. alt: item.querySelector('.alt').value,
  128. title: item.querySelector('.title').value,
  129. heading: item.querySelector('.heading').value,
  130. text: item.querySelector('.text').value,
  131. button: item.querySelector('.button').value,
  132. keitaro: item.querySelector('.keitaro').value,
  133. });
  134. });
  135. document.getElementById('casinoRepeaterData').value = JSON.stringify(items);
  136. return true;
  137. }
  138. // Drag and Drop functionality for casino items
  139. document.addEventListener('DOMContentLoaded', function() {
  140. const container = document.getElementById('casinoRepeater');
  141. if (!container) return;
  142. let draggedElement = null;
  143. let placeholder = null;
  144. function updateOrderNumbers() {
  145. const items = container.querySelectorAll('.casino-item');
  146. items.forEach((item, index) => {
  147. const numberElement = item.querySelector('.casino-order-number');
  148. if (numberElement) {
  149. numberElement.textContent = index + 1;
  150. }
  151. });
  152. }
  153. function createPlaceholder() {
  154. const div = document.createElement('div');
  155. div.className = 'drag-placeholder';
  156. div.style.cssText = 'height: 60px; margin: 10px 0; border: 2px dashed #007bff; background: #f0f8ff; opacity: 0.5;';
  157. return div;
  158. }
  159. function initAccordion() {
  160. const items = container.querySelectorAll('.casino-item');
  161. items.forEach(item => {
  162. const header = item.querySelector('.casino-item-header');
  163. const toggleBtn = item.querySelector('.toggle-accordion');
  164. const content = item.querySelector('.casino-item-content');
  165. const dragHandle = item.querySelector('.drag-handle');
  166. if (!header || !toggleBtn || !content) return;
  167. const toggleAccordion = (e) => {
  168. if (e.target.closest('.drag-handle')) {
  169. return;
  170. }
  171. const isOpen = content.style.display !== 'none' && content.style.display !== '';
  172. if (isOpen) {
  173. content.style.display = 'none';
  174. toggleBtn.textContent = '▼';
  175. } else {
  176. content.style.display = 'flex';
  177. toggleBtn.textContent = '▲';
  178. }
  179. };
  180. header.addEventListener('click', toggleAccordion);
  181. header.addEventListener('mousedown', (e) => {
  182. if (!e.target.closest('.drag-handle')) {
  183. item.setAttribute('draggable', 'false');
  184. }
  185. });
  186. header.addEventListener('mouseup', () => {
  187. item.setAttribute('draggable', 'true');
  188. });
  189. dragHandle.addEventListener('mousedown', (e) => {
  190. e.stopPropagation();
  191. item.setAttribute('draggable', 'true');
  192. });
  193. const headingInput = item.querySelector('.heading');
  194. if (headingInput) {
  195. headingInput.addEventListener('input', function() {
  196. const titleElement = item.querySelector('.casino-item-title');
  197. if (titleElement) {
  198. titleElement.textContent = this.value || 'New Casino Item';
  199. }
  200. });
  201. }
  202. });
  203. }
  204. function initDragAndDrop() {
  205. const items = container.querySelectorAll('.casino-item');
  206. items.forEach(item => {
  207. item.setAttribute('draggable', 'true');
  208. const dragHandle = item.querySelector('.drag-handle');
  209. dragHandle.addEventListener('mousedown', function(e) {
  210. item.setAttribute('draggable', 'true');
  211. });
  212. item.addEventListener('dragstart', function(e) {
  213. if (!e.target.querySelector('.drag-handle')) {
  214. e.preventDefault();
  215. return;
  216. }
  217. draggedElement = this;
  218. this.classList.add('dragging');
  219. e.dataTransfer.effectAllowed = 'move';
  220. e.dataTransfer.setData('text/html', '');
  221. setTimeout(() => {
  222. this.style.display = 'none';
  223. }, 0);
  224. });
  225. item.addEventListener('dragend', function(e) {
  226. this.style.display = '';
  227. this.classList.remove('dragging');
  228. if (placeholder && placeholder.parentNode) {
  229. placeholder.parentNode.removeChild(placeholder);
  230. }
  231. placeholder = null;
  232. draggedElement = null;
  233. updateOrderNumbers();
  234. });
  235. });
  236. }
  237. container.addEventListener('dragover', function(e) {
  238. e.preventDefault();
  239. e.dataTransfer.dropEffect = 'move';
  240. if (!draggedElement) return;
  241. const afterElement = getDragAfterElement(container, e.clientY);
  242. const currentItems = [...container.querySelectorAll('.casino-item:not(.dragging)')];
  243. if (!placeholder) {
  244. placeholder = createPlaceholder();
  245. }
  246. if (afterElement == null) {
  247. container.appendChild(placeholder);
  248. } else {
  249. container.insertBefore(placeholder, afterElement);
  250. }
  251. });
  252. container.addEventListener('drop', function(e) {
  253. e.preventDefault();
  254. if (!draggedElement || !placeholder) return;
  255. if (placeholder.parentNode) {
  256. placeholder.parentNode.insertBefore(draggedElement, placeholder);
  257. placeholder.parentNode.removeChild(placeholder);
  258. }
  259. draggedElement.style.display = '';
  260. placeholder = null;
  261. });
  262. function getDragAfterElement(container, y) {
  263. const draggableElements = [...container.querySelectorAll('.casino-item:not(.dragging)')];
  264. return draggableElements.reduce((closest, child) => {
  265. const box = child.getBoundingClientRect();
  266. const offset = y - box.top - box.height / 2;
  267. if (offset < 0 && offset > closest.offset) {
  268. return { offset: offset, element: child };
  269. } else {
  270. return closest;
  271. }
  272. }, { offset: Number.NEGATIVE_INFINITY }).element;
  273. }
  274. initAccordion();
  275. initDragAndDrop();
  276. updateOrderNumbers();
  277. container.addEventListener('itemRemoved', function() {
  278. updateOrderNumbers();
  279. });
  280. window.originalAddCasinoItem = window.addCasinoItem;
  281. window.addCasinoItem = function() {
  282. if (window.originalAddCasinoItem) {
  283. window.originalAddCasinoItem();
  284. } else {
  285. const container = document.getElementById('casinoRepeater');
  286. const tpl = document.getElementById('casinoTemplate').content.cloneNode(true);
  287. container.appendChild(tpl);
  288. }
  289. setTimeout(() => {
  290. initAccordion();
  291. initDragAndDrop();
  292. updateOrderNumbers();
  293. }, 10);
  294. };
  295. });
  296. // Page selector functionality
  297. const pageSelect = document.getElementById('page-select');
  298. if (pageSelect) {
  299. pageSelect.addEventListener('change', function () {
  300. const selected = this.value;
  301. const blocks = document.querySelectorAll('.page-block');
  302. blocks.forEach(block => {
  303. if (block.classList.contains(selected)) {
  304. block.style.display = 'block';
  305. } else {
  306. block.style.display = 'none';
  307. }
  308. });
  309. });
  310. }
  311. // Tab switching functionality
  312. function switchTab(tabName) {
  313. const contents = document.querySelectorAll('.tab-content');
  314. contents.forEach(content => content.classList.remove('active'));
  315. const tabs = document.querySelectorAll('.tab');
  316. tabs.forEach(tab => tab.classList.remove('active'));
  317. document.getElementById(tabName + '-tab').classList.add('active');
  318. event.target.classList.add('active');
  319. }