first commit
This commit is contained in:
		
						commit
						fb9168f700
					
				
							
								
								
									
										867
									
								
								main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										867
									
								
								main.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,867 @@ | |||||||
|  | // ==UserScript==
 | ||||||
|  | // @name         New Userscript
 | ||||||
|  | // @namespace    http://tampermonkey.net/
 | ||||||
|  | // @version      2024-11-18
 | ||||||
|  | // @desc  try to take over the world!
 | ||||||
|  | // @author       You
 | ||||||
|  | // @match        https://rst.runcity.org/msk2025/cp_mgmt/?action=edit&cp_id=88548
 | ||||||
|  | // @icon         https://www.google.com/s2/favicons?sz=64&domain=runcity.org
 | ||||||
|  | // @grant        none
 | ||||||
|  | // @require https://code.jquery.com/jquery-3.7.1.min.js
 | ||||||
|  | // @require https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js
 | ||||||
|  | // @require https://api.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v1.0.1/Leaflet.fullscreen.min.js
 | ||||||
|  | // ==/UserScript==
 | ||||||
|  | 
 | ||||||
|  | (function () { | ||||||
|  |   'use strict'; | ||||||
|  | 
 | ||||||
|  |   class Property { | ||||||
|  |     id; | ||||||
|  |     name; | ||||||
|  |     content; | ||||||
|  |     desc; | ||||||
|  | 
 | ||||||
|  |     constructor(id, row) { | ||||||
|  |       this.id = id | ||||||
|  | 
 | ||||||
|  |       let columns = [...row.querySelectorAll('td, th')].map(el => el.cloneNode(true)) | ||||||
|  |       if (columns.length === 1) { | ||||||
|  |         this.content = columns[0].innerHTML.trim() | ||||||
|  |       } | ||||||
|  |       else if (columns.length >= 2) { | ||||||
|  |         this.name = columns[0].innerHTML.trim() | ||||||
|  |         let elementsToRemove = columns[1].querySelector("input[name=\"read_gps2\"]") | ||||||
|  |         if (elementsToRemove) { | ||||||
|  |           columns[1].removeChild(elementsToRemove) | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         this.content = columns[1].innerHTML | ||||||
|  |           .replaceAll("<br>", "") | ||||||
|  |           .replaceAll(/\s*Перейти к легенде.*$/gs, "") | ||||||
|  |           .replaceAll("для легенды (\"l\")", "") | ||||||
|  |           .replaceAll("общие (\"c\")", "") | ||||||
|  |           .replaceAll("для ист. справки (\"h\")", "") | ||||||
|  |           .replaceAll("Получить координаты КП из картинки", "") | ||||||
|  |           .trim() | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (columns.length === 3) { | ||||||
|  |         this.desc = columns[2].innerHTML.replaceAll("<br>", "").replaceAll(/(\n)\s*/g, "$1").trim() | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     toDiv(altName = null, altDesc = null) { | ||||||
|  |       let div = document.createElement('div') | ||||||
|  |       let desc = altDesc ?? this.desc | ||||||
|  |       desc = desc ? "<span title='" + desc + "'>?</span>" : "" | ||||||
|  |       div.innerHTML = "<label for=''>" + (altName ?? this.name ?? "") + "</label>" + "<div>" + this.content + "</div>" + | ||||||
|  |         desc | ||||||
|  |       return div | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function createFrom(rows, classList, data) { | ||||||
|  |     let container = document.createElement('div') | ||||||
|  |     container.classList.add(...classList.split(" ")) | ||||||
|  |     for (const options of data) { | ||||||
|  |       let prop = new Property(options.index, rows[options.index]) | ||||||
|  |       container.appendChild(prop.toDiv(options.name, options.desc)) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return container | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function addCss(link) { | ||||||
|  |     let css = document.createElement("link") | ||||||
|  |     css.href = link | ||||||
|  |     css.rel = "stylesheet" | ||||||
|  |     document.head.appendChild(css) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function makeDownloadLink(name, href = null) { | ||||||
|  |     let downloadLink = document.createElement("a") | ||||||
|  |     downloadLink.setAttribute("download", name) | ||||||
|  |     downloadLink.textContent = "Скачать" | ||||||
|  |     if (href) | ||||||
|  |       downloadLink.href = href | ||||||
|  | 
 | ||||||
|  |     return downloadLink | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function addDisplayedFile(input, type, file, preview, removeLink) { | ||||||
|  |     if (!input || !file || !removeLink) return | ||||||
|  | 
 | ||||||
|  |     let fileListContainer = input.parentElement.parentElement.querySelector(".file-list-container") | ||||||
|  |     let fileContainer = document.createElement("div") | ||||||
|  |     fileContainer.classList.add("file-container") | ||||||
|  | 
 | ||||||
|  |     const displayedFile = document.createElement(type ?? "a") | ||||||
|  |     displayedFile.classList.add("preview-small") | ||||||
|  | 
 | ||||||
|  |     if (type == "img") { | ||||||
|  |       displayedFile.src = preview | ||||||
|  |       displayedFile.addEventListener("click", () => { | ||||||
|  |         let dialog = document.querySelector("dialog") | ||||||
|  |         let dialogFile = displayedFile.cloneNode(true) | ||||||
|  |         dialogFile.src = file | ||||||
|  |         dialog.appendChild(dialogFile) | ||||||
|  |         dialog.showModal() | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |     else if (type == "audio") { | ||||||
|  |       displayedFile.src = file | ||||||
|  |       displayedFile.setAttribute("controls", "") | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |       displayedFile.href = file | ||||||
|  |       displayedFile.textContent = "Файл" | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     let fileButtonsContainer = document.createElement("div") | ||||||
|  |     fileButtonsContainer.classList.add("file-buttons-container") | ||||||
|  | 
 | ||||||
|  |     fileButtonsContainer.appendChild(makeDownloadLink("test.png", file)) | ||||||
|  | 
 | ||||||
|  |     let deleteButton = document.createElement("button") | ||||||
|  |     deleteButton.type = "button" | ||||||
|  |     deleteButton.classList.add("button-delete") | ||||||
|  |     deleteButton.textContent = "x" | ||||||
|  |     deleteButton.addEventListener("click", e => { | ||||||
|  |       if (!confirm("Точно?")) return | ||||||
|  |       fetch(removeLink) | ||||||
|  |         .then(res => fileListContainer.removeChild(fileContainer)) | ||||||
|  |     }) | ||||||
|  |     fileButtonsContainer.appendChild(deleteButton) | ||||||
|  | 
 | ||||||
|  |     fileContainer.appendChild(displayedFile) | ||||||
|  |     fileContainer.appendChild(fileButtonsContainer) | ||||||
|  | 
 | ||||||
|  |     fileListContainer.appendChild(fileContainer) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function dataURLtoFile(dataurl, filename) { | ||||||
|  |     let arr = dataurl.split(',') | ||||||
|  |     let mime = arr[0].match(/:(.*?);/)[1] | ||||||
|  |     let bstr = atob(arr[arr.length - 1]) | ||||||
|  |     let n = bstr.length | ||||||
|  |     let u8arr = new Uint8Array(n) | ||||||
|  |     while (n--) { | ||||||
|  |       u8arr[n] = bstr.charCodeAt(n) | ||||||
|  |     } | ||||||
|  |     return new File([u8arr], filename, {type:mime}) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function getHtmlElementByFileType(file) { | ||||||
|  |     const htmlElementsForTypes = { | ||||||
|  |       "image/": "img", | ||||||
|  |       "audio/": "audio" | ||||||
|  |     } | ||||||
|  |     let res = "div" | ||||||
|  |     for (const [type, el] of Object.entries(htmlElementsForTypes)) { | ||||||
|  |       if (file.type.startsWith(type)) { | ||||||
|  |         res = el | ||||||
|  |         break | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     let el = document.createElement(res) | ||||||
|  |     if (res == "audio") { | ||||||
|  |       el.setAttribute("controls", "") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return el | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function handleFiles() { | ||||||
|  |     let dt = new DataTransfer() | ||||||
|  | 
 | ||||||
|  |     let storageLabel = `files-${this.dataset.index}` | ||||||
|  | 
 | ||||||
|  |     let storedFiles = localStorage.getItem(storageLabel) | ||||||
|  |     if (storedFiles) { | ||||||
|  |       let oldFiles = JSON.parse(localStorage.getItem(storageLabel)) | ||||||
|  |       for (const oldFile of oldFiles) { | ||||||
|  |         let oldFileObj = dataURLtoFile(oldFile.data, oldFile.name) | ||||||
|  |         dt.items.add(oldFileObj) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (let i = 0; i < this.files.length; i++) { | ||||||
|  |       const file = this.files[i] | ||||||
|  |       dt.items.add(file) | ||||||
|  | 
 | ||||||
|  |       let fileListContainer = this.parentElement.parentElement.querySelector(".file-list-container") | ||||||
|  |       let fileContainer = document.createElement("div") | ||||||
|  |       fileContainer.classList.add("file-container") | ||||||
|  | 
 | ||||||
|  |       const displayedFile = getHtmlElementByFileType(file) | ||||||
|  |       displayedFile.classList.add("preview") | ||||||
|  |       displayedFile.file = file | ||||||
|  |       displayedFile.addEventListener("click", () => { | ||||||
|  |         let dialog = document.querySelector("dialog") | ||||||
|  |         dialog.appendChild(displayedFile.cloneNode(true)) | ||||||
|  |         dialog.showModal() | ||||||
|  |       }) | ||||||
|  | 
 | ||||||
|  |       let fileButtonsContainer = document.createElement("div") | ||||||
|  |       fileButtonsContainer.classList.add("file-buttons-container") | ||||||
|  | 
 | ||||||
|  |       let downloadLink = makeDownloadLink(file.name) | ||||||
|  |       fileButtonsContainer.appendChild(downloadLink) | ||||||
|  | 
 | ||||||
|  |       let deleteButton = document.createElement("button") | ||||||
|  |       deleteButton.classList.add("button-delete") | ||||||
|  |       deleteButton.textContent = "x" | ||||||
|  |       deleteButton.type = "button" | ||||||
|  |       deleteButton.addEventListener("click", e => { | ||||||
|  |         let index = [...fileListContainer.children].indexOf(fileContainer) | ||||||
|  | 
 | ||||||
|  |         if (!confirm("Точно?")) return | ||||||
|  |    | ||||||
|  |         let storedFiles = JSON.parse(localStorage.getItem(storageLabel)) ?? [] | ||||||
|  |         storedFiles.splice(storedFiles.length - this.files.length + index, 1) | ||||||
|  |         localStorage.setItem(storageLabel, JSON.stringify(storedFiles)) | ||||||
|  |          | ||||||
|  |         let rdt = new DataTransfer() | ||||||
|  |         for (const file of this.files) { | ||||||
|  |           rdt.items.add(file) | ||||||
|  |         } | ||||||
|  |         rdt.items.remove(index) | ||||||
|  |         this.files = rdt.files | ||||||
|  |    | ||||||
|  |         fileListContainer.removeChild(fileContainer) | ||||||
|  |       }) | ||||||
|  |       fileButtonsContainer.appendChild(deleteButton) | ||||||
|  | 
 | ||||||
|  |       fileContainer.appendChild(displayedFile) | ||||||
|  |       fileContainer.appendChild(fileButtonsContainer) | ||||||
|  | 
 | ||||||
|  |       fileListContainer.appendChild(fileContainer) | ||||||
|  | 
 | ||||||
|  |       const reader = new FileReader() | ||||||
|  |       reader.onload = (e) => { | ||||||
|  |         displayedFile.src = e.target.result | ||||||
|  |         downloadLink.setAttribute("href", displayedFile.src) | ||||||
|  | 
 | ||||||
|  |         let storedFiles = JSON.parse(localStorage.getItem(storageLabel)) ?? [] | ||||||
|  |         storedFiles.push({data: displayedFile.src, name: file.name}) | ||||||
|  |         localStorage.setItem(storageLabel, JSON.stringify(storedFiles)) | ||||||
|  |       } | ||||||
|  |       reader.readAsDataURL(file) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     this.files = dt.files | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   let prettifyFiles = (function() { | ||||||
|  |     var executed = false | ||||||
|  |     return function(insertedFileRows) { | ||||||
|  |       if (executed) return | ||||||
|  | 
 | ||||||
|  |       executed = true | ||||||
|  |       document.querySelector("#new").querySelectorAll("input[type=file]").forEach((element, index) => { | ||||||
|  |         element.id = `input-file-${index}` | ||||||
|  |         element.setAttribute("multiple", "multiple") | ||||||
|  |         element.dataset.index = index | ||||||
|  |         let pseudoInput = document.createElement("label") | ||||||
|  |         pseudoInput.classList.add("custom-file-upload") | ||||||
|  |         pseudoInput.setAttribute("for", element.id) | ||||||
|  |         pseudoInput.textContent = "+" | ||||||
|  |         element.parentElement.insertBefore(pseudoInput, element) | ||||||
|  |      | ||||||
|  |         let fileListContainer = document.createElement("div") | ||||||
|  |         fileListContainer.classList.add("file-list-container") | ||||||
|  |         element.parentElement.parentElement.appendChild(fileListContainer) | ||||||
|  |      | ||||||
|  |         element.addEventListener("change", handleFiles, false) | ||||||
|  |       }) | ||||||
|  | 
 | ||||||
|  |       moveFileInputValues(insertedFileRows) | ||||||
|  |     } | ||||||
|  |   })() | ||||||
|  | 
 | ||||||
|  |   function saveInputValues(from) { | ||||||
|  |     let fromInputs = [...from.querySelectorAll("input, textarea")] | ||||||
|  |     let result = new Map() | ||||||
|  | 
 | ||||||
|  |     for (const fromEl of fromInputs) { | ||||||
|  |       result.set(fromEl, fromEl.type == "radio" ? fromEl.checked : fromEl.value) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return result | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function setInputValues(to, values) { | ||||||
|  |     let toInputs = [...to.querySelectorAll("input, textarea")] | ||||||
|  | 
 | ||||||
|  |     for (const [fromEl, value] of values) { | ||||||
|  |       let currentToInput = toInputs.find(toEl =>  | ||||||
|  |         toEl.type !== 'file' && | ||||||
|  |         toEl.type === fromEl.type &&  | ||||||
|  |         toEl.name === fromEl.name &&  | ||||||
|  |         toEl.id === fromEl.id &&  | ||||||
|  |         (toEl.type !== "radio" || toEl.value === fromEl.value) | ||||||
|  |       ) | ||||||
|  | 
 | ||||||
|  |       if (currentToInput) { | ||||||
|  |         currentToInput.checked = fromEl.checked | ||||||
|  |         currentToInput.value = fromEl.value | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function moveFileInputValues(insertedFileRows) { | ||||||
|  |     for (const [inputRowIndex, rows] of insertedFileRows) { | ||||||
|  |       for (const row of rows) { | ||||||
|  |         let fileInput = null, type = null, fileUrl = null, deleteUrl = null, preview = null | ||||||
|  |         if (row.querySelector("img")) { | ||||||
|  |           type = "img" | ||||||
|  |           fileUrl = row.querySelector("td:first-child a").href | ||||||
|  |           preview = row.querySelector("img").src | ||||||
|  |         } | ||||||
|  |         else if (row.querySelector("audio")) { | ||||||
|  |           type = "audio" | ||||||
|  |           fileUrl = row.querySelector("audio").src | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |           fileUrl = row.querySelector("td:first-child a").href | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         deleteUrl = row.querySelector("td:nth-child(2) a").href | ||||||
|  | 
 | ||||||
|  |         if (inputRowIndex == 23) { | ||||||
|  |           fileInput = "attachment1" | ||||||
|  |         } | ||||||
|  |         else if (inputRowIndex == 27) { | ||||||
|  |           fileInput = "attachment4" | ||||||
|  |         } | ||||||
|  |         else if (inputRowIndex == 31) { | ||||||
|  |           fileInput = "attachment2" | ||||||
|  |         } | ||||||
|  |         else if (inputRowIndex == 35) { | ||||||
|  |           fileInput = "attachment3" | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |           console.log(inputRowIndex) | ||||||
|  |           return | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         addDisplayedFile(document.querySelector(`input[name="${fileInput}\[\]"]`), type, fileUrl, preview, deleteUrl) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |    | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function hide(elList) { | ||||||
|  |     elList.forEach(el => el.classList.add("hidden")) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function show(elList) { | ||||||
|  |     elList.forEach(el => el.classList.remove("hidden")) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   let styles = ` | ||||||
|  |     #content-wrapper { | ||||||
|  |       display: flex; | ||||||
|  |       gap: 20px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #props { | ||||||
|  |       width: unset !important; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     form { | ||||||
|  |       width: 50%; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #map-wrapper { | ||||||
|  |       width: 50%; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #map { | ||||||
|  |       width: unset !important; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #new { | ||||||
|  |       display: flex; | ||||||
|  |       flex-direction: column; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #new > :not(:first-child) { | ||||||
|  |       padding-top: 5px; | ||||||
|  |       border-top: 1px solid #ddd; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #new > :not(:last-child) { | ||||||
|  |       padding-bottom: 5px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #cps_main { | ||||||
|  |       width: 150px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     input[type=submit] { | ||||||
|  |       width: fit-content; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     button, input[type=submit] { | ||||||
|  |       cursor: pointer; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #new input[type=radio], input[type=checkbox] { | ||||||
|  |       margin: 0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #new input[type="file"] { | ||||||
|  |       display: none; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #new div > input[type="checkbox"] { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .custom-file-upload { | ||||||
|  |       display: block; | ||||||
|  |       width: fit-content; | ||||||
|  |       border: 1px solid black; | ||||||
|  |       padding: 5px 14px; | ||||||
|  |       border-radius: 5px; | ||||||
|  |       box-shadow: 0 1px 3px #ddd; | ||||||
|  |       background: linear-gradient(white, #ddd); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .header > * { | ||||||
|  |       display: flex; | ||||||
|  |       gap: 5px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     :is(.header, .options) input { | ||||||
|  |       width: unset; | ||||||
|  |     } | ||||||
|  |        | ||||||
|  |     .header { | ||||||
|  |       display: flex; | ||||||
|  |       gap: 30px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .options { | ||||||
|  |       display: flex; | ||||||
|  |       flex-wrap: wrap; | ||||||
|  |       gap: 10px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .options > * { | ||||||
|  |       display: flex; | ||||||
|  |       gap: 5px; | ||||||
|  |       align-items: center; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .legend-container { | ||||||
|  |       display: flex; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .legend-container > :not(:last-child) { | ||||||
|  |       padding-right: 15px; | ||||||
|  |       border-right: 1px solid #ddd; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .legend-container > :not(:first-child) { | ||||||
|  |       padding-left: 15px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .legend-container > * { | ||||||
|  |       display: flex; | ||||||
|  |       flex-direction: column; | ||||||
|  |       flex: 0 1 48%; | ||||||
|  |       gap: 5px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .legend-container__desc-header { | ||||||
|  |       display: flex; | ||||||
|  |       gap: 10px; | ||||||
|  |       align-items: center; | ||||||
|  |       justify-content: end; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .legend-desc { | ||||||
|  |       display: flex; | ||||||
|  |       flex-direction: column; | ||||||
|  |       gap: 5px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .collapsed, .hidden { | ||||||
|  |       display: none; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .collapse-button::after { | ||||||
|  |       content: "Свернуть" | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .collapsed + * > .collapse-button::after { | ||||||
|  |       content: "Развернуть" | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     :is(.comment, .legend-desc) > * { | ||||||
|  |       display: flex; | ||||||
|  |       gap: 5px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     :is(.comment, .legend-desc) label { | ||||||
|  |       display: block; | ||||||
|  |       width: 10em; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     :is(.comment, .legend-desc) > * > :nth-child(2) { | ||||||
|  |       flex: 1 1 auto; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     textarea { | ||||||
|  |       width: 100%; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .files-container input[type=radio] { | ||||||
|  |       display: none; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .file-list-container { | ||||||
|  |       display: flex; | ||||||
|  |       flex-wrap: wrap; | ||||||
|  |       gap: 10px; | ||||||
|  |       margin-top: 5px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .file-container { | ||||||
|  |       display: flex; | ||||||
|  |       flex-direction: column; | ||||||
|  |       gap: 5px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     img.preview { | ||||||
|  |       width: 120px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     img.preview-small { | ||||||
|  |       width: 60px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .files-container img.preview { | ||||||
|  |       cursor: zoom-in; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     button.button-delete { | ||||||
|  |       padding: 0; | ||||||
|  |       border: 0; | ||||||
|  |       margin: 0; | ||||||
|  |       background: none; | ||||||
|  |       font-size: 18px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .admin-files-container { | ||||||
|  |       display: flex; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .admin-files-container > :not(:last-child) { | ||||||
|  |       padding-right: 10px; | ||||||
|  |       border-right: 1px solid #ddd; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .admin-files-container > :not(:first-child) { | ||||||
|  |       padding-left: 10px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     dialog img.preview { | ||||||
|  |       width: auto; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .file-buttons-container { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |       gap: 5px; | ||||||
|  |     } | ||||||
|  |   ` | ||||||
|  | 
 | ||||||
|  |   /* HEAD */ | ||||||
|  | 
 | ||||||
|  |   let styleSheet = document.createElement("style") | ||||||
|  |   styleSheet.textContent = styles | ||||||
|  |   document.head.appendChild(styleSheet) | ||||||
|  | 
 | ||||||
|  |   addCss("https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css") | ||||||
|  |   addCss('https://api.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v1.0.1/leaflet.fullscreen.css') | ||||||
|  | 
 | ||||||
|  |   /* NEW DEFALUT VALUES */ | ||||||
|  | 
 | ||||||
|  |   document.querySelector(`#props input[name="new_file_type1"][value="l"]`).click() | ||||||
|  |   document.querySelector(`#props input[name="new_file_type4"][value="l"]`).click() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   /* CONTAINER */ | ||||||
|  | 
 | ||||||
|  |   let form = document.querySelector('form') | ||||||
|  |   let rows = [...document.querySelectorAll('#props > tbody > tr')] | ||||||
|  |   let insertedFileRows = new Map() | ||||||
|  |   let i = 0 | ||||||
|  |   while (i < rows.length) { | ||||||
|  |     if ([23, 27, 31, 35].includes(i) && rows[i].querySelector(`input[type="file"]`) == null) { | ||||||
|  |       if (!insertedFileRows.has(i)) { | ||||||
|  |         insertedFileRows.set(i, [rows[i]]) | ||||||
|  |       } | ||||||
|  |       else { | ||||||
|  |         let savedRows = insertedFileRows.get(i) | ||||||
|  |         savedRows.push(rows[i]) | ||||||
|  |         insertedFileRows.set(i, savedRows) | ||||||
|  |       } | ||||||
|  |       rows.splice(i, 1) | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |       i++ | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   let container = document.createElement('div') | ||||||
|  |   container.id = "new" | ||||||
|  |   let oldTable = document.querySelector("#props") | ||||||
|  | 
 | ||||||
|  |   /* HEADER */ | ||||||
|  | 
 | ||||||
|  |   let headerContainer = createFrom(rows, "header", [ | ||||||
|  |     { index: 2, name: "№" }, | ||||||
|  |     { index: 8, name: "Название" } | ||||||
|  |   ]) | ||||||
|  | 
 | ||||||
|  |   let copyLink = document.createElement("div") | ||||||
|  |   copyLink.innerHTML = new Property(2, rows[2]).desc | ||||||
|  |   headerContainer.append(copyLink) | ||||||
|  | 
 | ||||||
|  |   /* TOP BUTTONS */ | ||||||
|  | 
 | ||||||
|  |   let topButtonsContainer = createFrom(rows, "buttons", [ | ||||||
|  |     { index: 0 } | ||||||
|  |   ]) | ||||||
|  | 
 | ||||||
|  |   let bottomButtonsContainer = topButtonsContainer.cloneNode(true) | ||||||
|  | 
 | ||||||
|  |   document.querySelectorAll("#props tr:is(:first-child, :last-child) th").forEach(el => { | ||||||
|  |     let prettifyButton = document.createElement("button") | ||||||
|  |     prettifyButton.type = "button" | ||||||
|  |     prettifyButton.textContent = "Сделать красиво" | ||||||
|  |     prettifyButton.addEventListener("click", () => { | ||||||
|  |       let inputValues = saveInputValues(oldTable) | ||||||
|  |       form.removeChild(oldTable) | ||||||
|  |       form.appendChild(container) | ||||||
|  |       setInputValues(container, inputValues) | ||||||
|  |       prettifyFiles(insertedFileRows) | ||||||
|  |          | ||||||
|  |       $("#cps_main").select2() | ||||||
|  |     }) | ||||||
|  |     el.appendChild(prettifyButton) | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|  |   ;[topButtonsContainer, bottomButtonsContainer].forEach(el => { | ||||||
|  |     let unglifyButton = document.createElement("button") | ||||||
|  |     unglifyButton.type = "button" | ||||||
|  |     unglifyButton.textContent = "Сделать некрасиво" | ||||||
|  |     unglifyButton.addEventListener("click", () => { | ||||||
|  |       let inputValues = saveInputValues(container) | ||||||
|  |       form.removeChild(container) | ||||||
|  |       form.appendChild(oldTable) | ||||||
|  |       setInputValues(oldTable, inputValues) | ||||||
|  |     }) | ||||||
|  |     el.querySelector("div > div > div").appendChild(unglifyButton) | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|  |   /* OPTIONS */ | ||||||
|  | 
 | ||||||
|  |   let firstContainer = createFrom(rows, "options", [ | ||||||
|  |     { index: 3 }, | ||||||
|  |     { index: 4, name: "КП-загадка" }, | ||||||
|  |     { index: 5, name: "Старт" }, | ||||||
|  |     { index: 6, name: "Финиш" }, | ||||||
|  |     { index: 16, name: "Этапник" }, | ||||||
|  |     { index: 7, name: "Пиктограмма" }, | ||||||
|  |     { index: 12, name: "Нужна ИС" }, | ||||||
|  |     { index: 17, name: "Спрятать ИС" }, | ||||||
|  |     { index: 14, name: "Основной КП" }, | ||||||
|  |     { index: 10, name: "X" }, | ||||||
|  |     { index: 11, name: "Y" }, | ||||||
|  |     { index: 15, name: "Знак" } | ||||||
|  |   ]) | ||||||
|  | 
 | ||||||
|  |   let commentContainer = createFrom(rows, "comment", [ | ||||||
|  |     { index: 9, desc: "" } | ||||||
|  |   ]) | ||||||
|  | 
 | ||||||
|  |   /* LEGEND */ | ||||||
|  | 
 | ||||||
|  |   let legendContainer = document.createElement("div") | ||||||
|  |   legendContainer.classList.add("legend-container") | ||||||
|  | 
 | ||||||
|  |   /* LEGEND DESC */ | ||||||
|  | 
 | ||||||
|  |   let legendDescContainer = document.createElement("div") | ||||||
|  |   legendDescContainer.classList.add("legend-container__desc") | ||||||
|  | 
 | ||||||
|  |   let legendDescHeader = document.createElement("div") | ||||||
|  |   legendDescHeader.classList.add("legend-container__desc-header") | ||||||
|  | 
 | ||||||
|  |   let legendEnSwitchContainer = createFrom(rows, "legend-switch-container", [ | ||||||
|  |     { index: 48 } | ||||||
|  |   ]) | ||||||
|  |   legendEnSwitchContainer.addEventListener("click", event => { | ||||||
|  |     hide([legendRuDescContainer, legendRuHiddenDescContainer, legendEnSwitchContainer]) | ||||||
|  |     show([legendEnDescContainer, legendEnHiddenDescContainer, legendRuSwitchContainer]) | ||||||
|  |   }) | ||||||
|  |   legendDescHeader.appendChild(legendEnSwitchContainer) | ||||||
|  |   let copyDescButton = document.createElement("button") | ||||||
|  |   copyDescButton.type = "button" | ||||||
|  |   copyDescButton.textContent = "Копировать" | ||||||
|  |   copyDescButton.addEventListener("click", () => { | ||||||
|  |     let ruInputs = [...container.querySelectorAll(":is(input, textarea)[name^=\"cp_strings\[ru\]\"]")] | ||||||
|  |     let enInputs = [...container.querySelectorAll(":is(input, textarea)[name^=\"cp_strings\[en\]\"]")] | ||||||
|  |     for (const [i, enInput] of enInputs.entries()) { | ||||||
|  |       enInput.value = ruInputs[i].value | ||||||
|  |     } | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|  |   let legendRuSwitchContainer = createFrom(rows, "legend-switch-container hidden", [ | ||||||
|  |     { index: 39 } | ||||||
|  |   ]) | ||||||
|  |   legendRuSwitchContainer.addEventListener("click", event => { | ||||||
|  |     hide([legendEnDescContainer, legendEnHiddenDescContainer, legendRuSwitchContainer]) | ||||||
|  |     show([legendRuDescContainer, legendRuHiddenDescContainer, legendEnSwitchContainer]) | ||||||
|  |   }) | ||||||
|  |   legendDescHeader.appendChild(legendRuSwitchContainer) | ||||||
|  | 
 | ||||||
|  |   legendDescHeader.appendChild(copyDescButton) | ||||||
|  | 
 | ||||||
|  |   let legendRuDescContainer = createFrom(rows, "legend-desc", [ | ||||||
|  |     { index: 40, desc: "" }, | ||||||
|  |     { index: 41, desc: "" }, | ||||||
|  |     { index: 42, desc: "" }, | ||||||
|  |     { index: 43, desc: "" } | ||||||
|  |   ]) | ||||||
|  | 
 | ||||||
|  |   let legendRuHiddenDescContainer = createFrom(rows, "legend-desc collapsible collapsed", [ | ||||||
|  |     { index: 44, desc: "" }, | ||||||
|  |     { index: 45, desc: "" }, | ||||||
|  |     { index: 46, desc: "" } | ||||||
|  |   ]) | ||||||
|  | 
 | ||||||
|  |   let legendEnDescContainer = createFrom(rows, "legend-desc hidden", [ | ||||||
|  |     { index: 49, desc: "" }, | ||||||
|  |     { index: 50, desc: "" }, | ||||||
|  |     { index: 51, desc: "" }, | ||||||
|  |     { index: 52, desc: "" } | ||||||
|  |   ]) | ||||||
|  | 
 | ||||||
|  |   let legendEnHiddenDescContainer = createFrom(rows, "legend-desc collapsible collapsed hidden", [ | ||||||
|  |     { index: 53, desc: "" }, | ||||||
|  |     { index: 54, desc: "" }, | ||||||
|  |     { index: 55, desc: "" } | ||||||
|  |   ]) | ||||||
|  | 
 | ||||||
|  |   let hider = document.createElement("div") | ||||||
|  |   let hiderButton = document.createElement("button") | ||||||
|  |   hiderButton.classList.add("collapse-button") | ||||||
|  |   hiderButton.setAttribute("type", "button") | ||||||
|  |   hiderButton.addEventListener("click", event => { | ||||||
|  |     container.querySelectorAll(".legend-desc.collapsible").forEach(element => { | ||||||
|  |       element.classList.toggle("collapsed") | ||||||
|  |     }) | ||||||
|  |   }) | ||||||
|  |   hider.appendChild(hiderButton) | ||||||
|  | 
 | ||||||
|  |   legendDescContainer.appendChild(legendDescHeader) | ||||||
|  |   legendDescContainer.appendChild(legendRuDescContainer) | ||||||
|  |   legendDescContainer.appendChild(legendRuHiddenDescContainer) | ||||||
|  |   legendDescContainer.appendChild(legendEnDescContainer) | ||||||
|  |   legendDescContainer.appendChild(legendEnHiddenDescContainer) | ||||||
|  |   legendDescContainer.appendChild(hider) | ||||||
|  |   legendContainer.appendChild(legendDescContainer) | ||||||
|  | 
 | ||||||
|  |   /* LEGEND FILES */ | ||||||
|  |   let legendFilesContainer = document.createElement("div") | ||||||
|  |   legendFilesContainer.classList.add("legend-container__files") | ||||||
|  | 
 | ||||||
|  |   let imagesForLegendContainer = createFrom(rows, "files-container", [ | ||||||
|  |     { index: 23, name: "Фото в легенде" } | ||||||
|  |   ]) | ||||||
|  |   legendFilesContainer.appendChild(imagesForLegendContainer) | ||||||
|  | 
 | ||||||
|  |   let audioForLegendContainer = createFrom(rows, "files-container", [ | ||||||
|  |     { index: 27, name: "Файлы в легенде" } | ||||||
|  |   ]) | ||||||
|  |   legendFilesContainer.appendChild(audioForLegendContainer) | ||||||
|  | 
 | ||||||
|  |   legendContainer.appendChild(legendFilesContainer) | ||||||
|  | 
 | ||||||
|  |   let adminFilesContainer = document.createElement('div') | ||||||
|  |   adminFilesContainer.classList.add('admin-files-container') | ||||||
|  | 
 | ||||||
|  |   let imagesForAdminContainer = createFrom(rows, "files-container", [ | ||||||
|  |     { index: 31, name: "Фото в админке" } | ||||||
|  |   ]) | ||||||
|  |   adminFilesContainer.appendChild(imagesForAdminContainer) | ||||||
|  | 
 | ||||||
|  |   let audioForAdminContainer = createFrom(rows, "files-container", [ | ||||||
|  |     { index: 35, name: "Файлы в админке" } | ||||||
|  |   ]) | ||||||
|  |   adminFilesContainer.appendChild(audioForAdminContainer) | ||||||
|  | 
 | ||||||
|  |   /* BOTTOM OPTIONS */ | ||||||
|  | 
 | ||||||
|  |   let bottomOptionsContainer = createFrom(rows, "options bottom-options", [ | ||||||
|  |     { index: 59 }, | ||||||
|  |     { index: 60 }, | ||||||
|  |     { index: 61 }, | ||||||
|  |     { index: 62 }, | ||||||
|  |     { index: 63 } | ||||||
|  |   ]) | ||||||
|  | 
 | ||||||
|  |   /* APPEND ALL */ | ||||||
|  | 
 | ||||||
|  |   container.appendChild(topButtonsContainer) | ||||||
|  |   container.appendChild(headerContainer) | ||||||
|  |   container.appendChild(firstContainer) | ||||||
|  |   container.appendChild(commentContainer) | ||||||
|  |   container.appendChild(legendContainer) | ||||||
|  |   container.appendChild(adminFilesContainer) | ||||||
|  |   container.appendChild(bottomOptionsContainer) | ||||||
|  |   container.appendChild(bottomButtonsContainer) | ||||||
|  | 
 | ||||||
|  |   /* MAP */ | ||||||
|  |   let content = document.querySelector("#content") | ||||||
|  |   let contentWrapper = document.createElement("div") | ||||||
|  |   contentWrapper.id = "content-wrapper" | ||||||
|  |   contentWrapper.appendChild(document.querySelector("form")) | ||||||
|  |   contentWrapper.appendChild(document.querySelector("#map-wrapper")) | ||||||
|  |   content.appendChild(contentWrapper) | ||||||
|  |   $(() => { | ||||||
|  |     map.addControl(new L.Control.Fullscreen()) | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|  |   let panToCenter = document.createElement("button") | ||||||
|  |   panToCenter.type = "button" | ||||||
|  |   panToCenter.textContent = "В центр" | ||||||
|  |   panToCenter.addEventListener("click", () => { | ||||||
|  |     let lat = document.querySelector("input[name=\"cp\[lattitude\]\"").value | ||||||
|  |     let lon = document.querySelector("input[name=\"cp\[longitude\]\"").value | ||||||
|  |     map.setView(new L.LatLng(parseFloat(lat), parseFloat(lon)), 13) | ||||||
|  |   }) | ||||||
|  |   document.querySelector("#map_controls").appendChild(panToCenter) | ||||||
|  | 
 | ||||||
|  |   /* FILES */ | ||||||
|  |   localStorage.clear() | ||||||
|  | 
 | ||||||
|  |   let dialog = document.createElement("dialog") | ||||||
|  |   dialog.id = "dialog" | ||||||
|  |   document.body.appendChild(dialog) | ||||||
|  | 
 | ||||||
|  |   dialog.addEventListener("click", (e) => { | ||||||
|  |     if (e.target == dialog) { | ||||||
|  |       e.target.close() | ||||||
|  |       e.target.innerHTML = "" | ||||||
|  |     } | ||||||
|  |   }) | ||||||
|  | 
 | ||||||
|  | })(); | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user