2369 lines
90 KiB
JavaScript
2369 lines
90 KiB
JavaScript
/**
|
||
* @file editor.js
|
||
* @brief Основной файл редактора, содержит базовые функции и переменные для работы с элементами страницы
|
||
*/
|
||
|
||
function pluginFun(action, side) {
|
||
if (action === 'add') {
|
||
jsonrpcRequest('getFolders', { folder: 'plugin' })
|
||
.then(folders => {
|
||
let pluginAddSideName = document.getElementById('pluginAdd' + (side === 'left' ? 'Left' : 'Right') + 'Name');
|
||
pluginAddSideName.innerHTML = '';
|
||
folders.forEach(folder => {
|
||
let option = document.createElement('option');
|
||
option.value = folder;
|
||
option.textContent = folder;
|
||
pluginAddSideName.appendChild(option);
|
||
});
|
||
});
|
||
}
|
||
}
|
||
|
||
addEventListener("LoadeditorJs", function()
|
||
{
|
||
/* movementMenu("basis3"); */
|
||
addEventListener("scroll", del);
|
||
|
||
let view=document.getElementById("view"); // Ссылка на элементы окна просмотра
|
||
let bas=document.getElementById("bas").style;
|
||
let pict=document.getElementById("pict");
|
||
|
||
/* view.addEventListener("click", del); */
|
||
|
||
function del() // Функция закрытия окна просмотра
|
||
{
|
||
if (view) {
|
||
view.style.visibility="hidden";
|
||
}
|
||
bas.visibility="hidden";
|
||
}
|
||
|
||
|
||
}, { once: true });
|
||
|
||
/** @brief Список редактируемых элементов */
|
||
let editableElements;
|
||
/** @brief Режим редактирования: -1 = выключен */
|
||
let editMode = -1;
|
||
/** @brief Массив ID кнопок редактирования */
|
||
let editId = ['pluginDelete', 'titleEdit', 'pluginMove', 'elementEdit',
|
||
'editTableButtonAddLine', 'editTableButtonDeleteLine', 'editTableButtonAddColumn', 'editTableButtonDeleteColumn'] ;
|
||
|
||
/** @brief Переключает видимость и редактируемость элементов */
|
||
function basisVis() {
|
||
editableElementsFun();
|
||
let basis3 = document.getElementById('basis3');
|
||
let sideFloatClass = basis3 ? basis3.querySelectorAll('[style*="visibility: visible;"]') : null;
|
||
if (!basis3 || !sideFloatClass || !window.editableElements || window.editableElements.length === 0) return;
|
||
let elementsСhecked = [basis3, ...sideFloatClass, ...window.editableElements];
|
||
|
||
if (basis3.style.visibility === "visible") {
|
||
basis3.style.visibility = "hidden";
|
||
sessionStorage.setItem('basis3_visibility', 'hidden');
|
||
window.editableElements.forEach(function(element) {
|
||
if (element) {
|
||
element.setAttribute("contenteditable", false);
|
||
}
|
||
});
|
||
document.querySelector('#mainTitle').setAttribute('contenteditable', 'false');
|
||
sideFloatClass.forEach(function(element) {
|
||
element.style.visibility = "hidden";
|
||
});
|
||
for (let i = 0; i < editId.length; i++) {
|
||
editMode = -1;
|
||
if (document.getElementById(editId[i])) {
|
||
document.getElementById(editId[i]).classList.remove('active');
|
||
}
|
||
}
|
||
document.getElementById('bcbody').style.top = '0px';
|
||
document.querySelectorAll('.bfloat').forEach(e => e.style.fontSize = '')
|
||
} else {
|
||
basis3.style.visibility = "visible";
|
||
sessionStorage.setItem('basis3_visibility', 'visible');
|
||
window.editableElements.forEach(function(element) {
|
||
if (element) {
|
||
element.setAttribute("contenteditable", true);
|
||
}
|
||
});
|
||
document.querySelector('#mainTitle').setAttribute('contenteditable', 'true');
|
||
basis3.style.left = '10px';
|
||
basis3.style.top = '20%';
|
||
basis3.style.transform = 'translate(0%, -20%)';
|
||
document.getElementById('bcbody').style.top = '30px';
|
||
document.querySelectorAll('.bfloat').forEach(e => e.style.fontSize = '1em')
|
||
}
|
||
}
|
||
window.basisVis = basisVis;
|
||
|
||
/** @brief Сбор всех редактируемых элементов */
|
||
function editableElementsFun() {
|
||
window.editableElements = [];
|
||
let contents = document.querySelectorAll('.content');
|
||
let pluginEls = document.querySelectorAll('.pluginEditable');
|
||
pluginEls = Array.from(pluginEls);
|
||
window.editableElements.push(...pluginEls, ...contents);
|
||
|
||
window.editableElements.forEach(function(element) {
|
||
if (!element) {
|
||
console.log("Element " + element + " not found.");
|
||
return;
|
||
}
|
||
});
|
||
}
|
||
|
||
addEventListener("LoadeditorJs", function()
|
||
{
|
||
|
||
let te=document.getElementById("tex"); // Ссылка на текстовое поле
|
||
let tex=document.getElementById("tex"); // Ссылка на стили текстового поля
|
||
|
||
// Передаём содержимое пустых блоков в поле
|
||
document.querySelectorAll('.content').forEach(el => {
|
||
if (!el.innerHTML) te.value = el.innerHTML;
|
||
});
|
||
|
||
// Символы клавиш со знаками препинания или перевода строки
|
||
let symb = ["Enter", "!", "?", ";", ":", ",", ".", " ", "-", "'", "\"", "(", ")", "{", "}", "[", "]", "_", "&", "/", "\\", "*"];
|
||
|
||
// Запись в память введенного текста при нажатии клавиши со знаком препинания или перевода строки
|
||
document.querySelectorAll('.content').forEach(el => {
|
||
el.addEventListener('keyup', ev => {
|
||
for (let i = 0; i < symb.length; i++) {
|
||
if (symb[i] == ev.key) inter();
|
||
}
|
||
});
|
||
});
|
||
|
||
let sel = document.getSelection();
|
||
function selInContenteditable(insertType) {
|
||
if (!sel.rangeCount) {
|
||
messageFunction("{{cursor_not_in_editable_field}}");
|
||
return 0;
|
||
}
|
||
function isInContenteditable(node) {
|
||
while (node) {
|
||
if (node.nodeType === Node.ELEMENT_NODE && node.getAttribute('contenteditable') === 'true') {
|
||
return true;
|
||
}
|
||
node = node.parentNode;
|
||
}
|
||
return false;
|
||
}
|
||
let range = sel.getRangeAt(0);
|
||
if (!isInContenteditable(range.startContainer) || !isInContenteditable(range.endContainer)) {
|
||
messageFunction("{{cursor_or_selection_not_in_editable_field}}");
|
||
return 0;
|
||
}
|
||
if (insertType == "element") {
|
||
range.deleteContents();
|
||
} else if (insertType == "editText") {
|
||
if (sel.isCollapsed) {
|
||
messageFunction("{{no_text_selected}}");
|
||
return 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Функция открытия окон среднего редактирования
|
||
let s=document.querySelectorAll(".swit");
|
||
for(let i=0; i<s.length; i++)
|
||
{
|
||
let idc=s[i].id;
|
||
let nid=idc+"_d";
|
||
document.getElementById(idc).addEventListener("click", ins.bind(null, nid));
|
||
}
|
||
|
||
/* функция вставок элементов */
|
||
document.querySelectorAll('.align-dropdown-oneImg').forEach(dropdown => {
|
||
const list = dropdown.querySelector('.align-list');
|
||
dropdown.addEventListener('click', e => {
|
||
if (e.target.closest('.align-list')) {
|
||
const cmd = e.target.closest('li').dataset.cmd;
|
||
handleImageAction(cmd);
|
||
list.style.display = 'none';
|
||
return;
|
||
}
|
||
list.style.display = list.style.display === 'block' ? 'none' : 'block';
|
||
});
|
||
document.addEventListener('click', e => {
|
||
if (!dropdown.contains(e.target)) {
|
||
list.style.display = 'none';
|
||
}
|
||
});
|
||
});
|
||
|
||
async function handleImageAction(id) {
|
||
var sel = window.getSelection();
|
||
if (sel.rangeCount) {
|
||
var node = sel.anchorNode.nodeType === 1 ? sel.anchorNode : sel.anchorNode.parentElement;
|
||
if (!node.closest('[contenteditable="true"]')) {
|
||
return;
|
||
}
|
||
}
|
||
switch (id) {
|
||
case "imgLink":
|
||
messageQueue.push("Enter image URL")
|
||
;(async () => {
|
||
const url = await messageCreateInput()
|
||
if (url) {
|
||
const img = document.createElement("img")
|
||
img.src = url
|
||
img.style.cssText = "float: left; margin: 10px; width: 250px; border: 0; overflow: hidden;"
|
||
insertNodeAtSelection(img)
|
||
}
|
||
})()
|
||
break
|
||
case "imgPc":
|
||
var input = document.createElement("input");
|
||
input.type = "file";
|
||
input.accept = "image/*";
|
||
input.style.display = "none";
|
||
document.body.appendChild(input);
|
||
|
||
input.addEventListener("change", function() {
|
||
if (input.files.length > 0) {
|
||
var reader = new FileReader();
|
||
reader.onload = function(e) {
|
||
var base64Data = e.target.result.split(',')[1];
|
||
jsonrpcRequest('uploadImage', { userImgBase64: base64Data, userImgName: input.files[0].name })
|
||
.then(response => {
|
||
if (response) {
|
||
try {
|
||
var img = document.createElement("img");
|
||
img.src = response;
|
||
img.setAttribute("style", "float: left; margin: 10px; width: 250px; border: 0px solid rgb(0, 0, 0); overflow: hidden;");
|
||
insertNodeAtSelection(img);
|
||
} catch (e) {
|
||
messageFunction("{{img_upload_error}}");
|
||
}
|
||
} else {
|
||
messageFunction("{{img_upload_error}}");
|
||
}
|
||
})
|
||
.catch(() => messageFunction("{{img_upload_error}}"));
|
||
};
|
||
reader.readAsDataURL(input.files[0]);
|
||
}
|
||
document.body.removeChild(input);
|
||
});
|
||
input.click();
|
||
break;
|
||
case "imgManager":
|
||
window.managerDataAction = "selectImgForm";
|
||
let userName = getCookie('User');
|
||
if (userName) {
|
||
await includePlugin("manager");
|
||
managerData("/img/users_img/" + userName);
|
||
managerDiv.style.visibility = "visible";
|
||
document.getElementById("settingsMain_d").style.visibility = "hidden";
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
function insertHR() {
|
||
const hr = document.createElement("hr")
|
||
hr.style.cssText = "height: 5px; width: 50%; background: rgb(0, 0, 0); border: 0;"
|
||
insertNodeAtSelection(hr)
|
||
}
|
||
document.getElementById("hr").addEventListener("click", insertHR)
|
||
|
||
function insertTable() {
|
||
const table = document.createElement("table")
|
||
table.style.cssText = "width: 50%; margin: 1px; float: left; border: 1px solid rgb(0, 0, 0); background-color: rgb(255, 255, 255); border-collapse: collapse;"
|
||
for (let i = 0; i < 4; i++) {
|
||
const tr = document.createElement("tr")
|
||
for (let j = 0; j < 4; j++) {
|
||
const td = document.createElement("td")
|
||
td.style.cssText = "padding: 1px; border: 1px solid rgb(0, 0, 0);"
|
||
tr.appendChild(td)
|
||
}
|
||
table.appendChild(tr)
|
||
}
|
||
insertNodeAtSelection(table)
|
||
}
|
||
document.getElementById("tabl").addEventListener("click", insertTable)
|
||
|
||
function insertNodeAtSelection(node) {
|
||
var sel = window.getSelection();
|
||
if (!sel.rangeCount) return;
|
||
var range = sel.getRangeAt(0);
|
||
range.deleteContents();
|
||
range.insertNode(node);
|
||
}
|
||
|
||
/*let t=document.querySelectorAll(".cldiv");
|
||
for(let i=0; i<t.length; i++) // Регистрация обработчиков для закрытия вкладок с настройками сложного редактирования
|
||
{
|
||
|
||
let idc=t[i].id;
|
||
let nid=idc.replace("_i", "_d");
|
||
document.getElementById(idc).addEventListener("click", clo.bind(null, nid));
|
||
}*/
|
||
|
||
let q=document.querySelectorAll(".sym");
|
||
for(let i=0; i<q.length; i++) // Регистрация обработчиков для вставки символов в текст
|
||
{
|
||
let idc=q[i].id;
|
||
let smb=q[i].value;
|
||
document.getElementById(idc).addEventListener("click", sign.bind(null, smb));
|
||
}
|
||
|
||
function sign(s) // Функция вставки символов в текст
|
||
{
|
||
if (selInContenteditable("element") == 0) {
|
||
return;
|
||
}
|
||
let rng=sel.getRangeAt(0);
|
||
let elm=document.createTextNode(s);
|
||
rng.insertNode(elm);
|
||
|
||
clo("copyr_d");
|
||
inter();
|
||
}
|
||
|
||
// Изменение пространственной ориентации у редактора
|
||
let coup = false;
|
||
let basis3 = document.getElementById("basis3");
|
||
let editi = Array.from(document.getElementsByClassName("editi"));
|
||
let edits = Array.from(document.getElementsByClassName("edits"));
|
||
let editb = editi.concat(edits);
|
||
let indentb = Array.from(document.getElementsByClassName("indent"));
|
||
let custb = Array.from(document.getElementsByClassName("cust"));
|
||
/* document.getElementById("coup").addEventListener("click", function() {
|
||
if (coup === false) {
|
||
coup = true;
|
||
let basis3Top = parseInt(basis3.style.top, 10);
|
||
basis3.style.top = (basis3Top - 1055) + 'px';
|
||
let basis3Left = parseInt(basis3.style.left, 10);
|
||
basis3.style.left = (basis3Left + 1176) + 'px';
|
||
|
||
editb.forEach(function(element) {
|
||
element.style.display = 'block';
|
||
element.style.position = 'relative';
|
||
element.style.marginBottom = '4px';
|
||
element.style.right = '0px';
|
||
});
|
||
indentb.forEach(function(element) {
|
||
element.style.width = '0px';
|
||
element.style.height = '8px';
|
||
});
|
||
document.getElementById("equaj").style.marginBottom = '';
|
||
document.getElementById("ff").style.width = '28px';
|
||
document.getElementById("fs").style.width = '28px';
|
||
document.getElementById("list").style.width = '28px';
|
||
document.getElementById("coup").style.backgroundPosition = '-397px 1663px';
|
||
|
||
document.getElementById("tex").style.left = '45px';
|
||
custb.forEach(function(element) {
|
||
element.style.left = '45px';
|
||
element.style.top = '0px';
|
||
element.style.width = '764px';
|
||
});
|
||
|
||
} else {
|
||
coup = false;
|
||
let basis3Top = parseInt(basis3.style.top, 10);
|
||
basis3.style.top = (basis3Top + 1055) + 'px';
|
||
let basis3Left = parseInt(basis3.style.left, 10);
|
||
basis3.style.left = (basis3Left - 1176) + 'px';
|
||
|
||
editb.forEach(function(element) {
|
||
element.style.display = 'inline-block';
|
||
element.style.position = '';
|
||
element.style.marginBottom = '';
|
||
});
|
||
indentb.forEach(function(element) {
|
||
element.style.width = '5px';
|
||
element.style.height = '0px';
|
||
});
|
||
document.getElementById("ff").style.width = '136px';
|
||
document.getElementById("fs").style.width = '38px';
|
||
document.getElementById("list").style.width = '62px';
|
||
document.getElementById("coup").style.backgroundPosition = '-357px 1662px';
|
||
|
||
document.getElementById("tex").style.left = '0px';
|
||
custb.forEach(function(element) {
|
||
element.style.left = '';
|
||
element.style.top = '45px';
|
||
element.style.width = '1189px';
|
||
});
|
||
}
|
||
}); */
|
||
|
||
let sbe=document.getElementsByClassName("sb");
|
||
for(let i=0; i<sbe.length; i++) {
|
||
sbe[i].style.visibility="hidden";
|
||
}
|
||
function ins(k) // Функция открытия вкладок с настройками для сложного редактирования текста
|
||
{
|
||
let sbe=document.getElementsByClassName("sb");
|
||
for(let i=0; i<sbe.length; i++) {
|
||
if (sbe[i] != document.getElementById(k))
|
||
sbe[i].style.visibility="hidden";
|
||
}
|
||
if (document.getElementById(k).style.visibility=="hidden") {
|
||
document.getElementById(k).style.visibility="visible";
|
||
} else {
|
||
document.getElementById(k).style.visibility="hidden";
|
||
}
|
||
}
|
||
|
||
function clo(c) // Функция закрытия вкладок с настройками для сложного редактирования текста
|
||
{
|
||
document.getElementById(c).style.visibility="hidden";
|
||
}
|
||
|
||
// действия блока плагинов
|
||
/* let pluginDropdownContentId = document.getElementById("pluginDropdownContent");
|
||
pluginDropdownContentId.addEventListener('click', function () {
|
||
let targetElement = document.getElementById(this.value);
|
||
if (targetElement) {
|
||
targetElement.click();
|
||
} else {
|
||
console.log("{{action_not_defined}}");
|
||
}
|
||
let activeOption = pluginDropdownContentId.querySelector('option.active');
|
||
let options = pluginDropdownContentId.querySelectorAll('option');
|
||
options.forEach(option => {
|
||
option.style.backgroundColor = '#efefef';
|
||
});
|
||
if (activeOption) {
|
||
pluginDropdownContentId.style.backgroundColor = '#d8d8d8';
|
||
} else {
|
||
pluginDropdownContentId.style.backgroundColor = '';
|
||
}
|
||
if (editMode == -1) {
|
||
pluginDropdownContentId.style.backgroundColor = '';
|
||
}
|
||
}); */
|
||
|
||
// действия блока элементов
|
||
/* let elementDropdownContentId = document.getElementById("elementDropdownContent");
|
||
elementDropdownContentId.addEventListener('click', function () {
|
||
let targetElement = document.getElementById(this.value);
|
||
if (targetElement) {
|
||
targetElement.click();
|
||
} else {
|
||
console.log("{{action_not_defined}}2");
|
||
}
|
||
}); */
|
||
|
||
// действия блока главных действий
|
||
/* let mainActionsId = document.getElementById("mainActions");
|
||
mainActionsId.addEventListener('click', function () {
|
||
switch (this.value) {
|
||
case "save":
|
||
saveChanges();
|
||
break;fshowHtmlCode
|
||
case "saveHow":
|
||
saveChangesHow();
|
||
break;
|
||
case "htm":
|
||
showHtmlCode();
|
||
break;
|
||
default:
|
||
console.log("{{action_not_defined}}");
|
||
}
|
||
}); */
|
||
|
||
document.getElementById("save").addEventListener("click", saveChanges);
|
||
|
||
// Загрузка изменений как
|
||
document.getElementById("saveHow").addEventListener("click", saveChangesHow);
|
||
async function saveChangesHow() {
|
||
await includePlugin("manager");
|
||
window.managerDataAction = "saveHow";
|
||
managerData("/content");
|
||
managerDiv.style.visibility = "visible";
|
||
document.getElementById("settingsMain_d").style.visibility = "hidden";
|
||
}
|
||
|
||
// Открытие страницы
|
||
document.getElementById("getPage").addEventListener("click", openPageFun);
|
||
async function openPageFun() {
|
||
await includePlugin("manager");
|
||
window.managerDataAction = "getPage";
|
||
managerData("/content");
|
||
managerDiv.style.visibility = "visible";
|
||
document.getElementById("settingsMain_d").style.visibility="hidden";
|
||
}
|
||
|
||
// Создание новой страницы
|
||
document.getElementById("newPage").addEventListener("click", newPageFun);
|
||
function newPageFun() {
|
||
document.getElementById("right-float").innerHTML = "";
|
||
document.getElementById("left-float").innerHTML = "";
|
||
document.querySelectorAll('.content').forEach(el => el.innerHTML = "");
|
||
document.getElementById("mainTitle").innerHTML = "<i>{{new_file}}!</i>";
|
||
window.newPageFunValue = "newPage";
|
||
document.getElementById("settingsMain_d").style.visibility="hidden";
|
||
}
|
||
|
||
// Сохранение выделение
|
||
document.addEventListener('selectionchange', () => {
|
||
const contents = document.querySelectorAll('.content');
|
||
if (!contents || contents.length === 0) return;
|
||
const sel = window.getSelection();
|
||
if (!sel.rangeCount) return;
|
||
const range = sel.getRangeAt(0);
|
||
const startNode = range.startContainer;
|
||
for (let content of contents) {
|
||
if (content.contains(startNode)) {
|
||
saveSelection();
|
||
break;
|
||
}
|
||
}
|
||
});
|
||
|
||
let savedSel = null;
|
||
|
||
function saveSelection() {
|
||
const contents = document.querySelectorAll('.content');
|
||
const sel = window.getSelection();
|
||
if (!sel.rangeCount) return;
|
||
const range = sel.getRangeAt(0);
|
||
for (let content of contents) {
|
||
if (content.contains(range.commonAncestorContainer)) {
|
||
const pre = range.cloneRange();
|
||
pre.selectNodeContents(content);
|
||
pre.setEnd(range.startContainer, range.startOffset);
|
||
const start = pre.toString().length;
|
||
const end = start + range.toString().length;
|
||
savedSel = { start, end };
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
function restoreSelection() {
|
||
if (!savedSel) return;
|
||
const contents = document.querySelectorAll('.content');
|
||
const { start, end } = savedSel;
|
||
let charIndex = 0;
|
||
const range = document.createRange();
|
||
try {
|
||
for (const content of contents) {
|
||
range.setStart(content, 0);
|
||
range.collapse(true);
|
||
(function traverse(node) {
|
||
if (node.nodeType === Node.TEXT_NODE) {
|
||
const next = charIndex + node.length;
|
||
if (charIndex <= start && next >= start) range.setStart(node, start - charIndex);
|
||
if (charIndex <= end && next >= end) {
|
||
range.setEnd(node, end - charIndex);
|
||
throw 'done';
|
||
}
|
||
charIndex = next;
|
||
} else node.childNodes.forEach(traverse);
|
||
})(content);
|
||
}
|
||
} catch (e) {}
|
||
const sel = window.getSelection();
|
||
sel.removeAllRanges();
|
||
sel.addRange(range);
|
||
}
|
||
|
||
/* плагины для центра */
|
||
document.getElementById('pluginAddCenter').onclick = function pluginFunCenter() {
|
||
jsonrpcRequest('getPluginBlocks', {})
|
||
.then(folders => {
|
||
const pluginAddSideName = document.getElementById('pluginAddCenterName');
|
||
pluginAddSideName.innerHTML = '';
|
||
folders.forEach(folder => {
|
||
const option = document.createElement('option');
|
||
option.value = folder;
|
||
option.textContent = folder;
|
||
pluginAddSideName.appendChild(option);
|
||
});
|
||
});
|
||
};
|
||
document.getElementById('pluginAddCenterFun_d').addEventListener('click', function() {
|
||
const select = document.getElementById('pluginAddCenterName');
|
||
const pluginName = select.value;
|
||
if (!pluginName) return;
|
||
if (document.querySelector('.' + pluginName)) return;
|
||
|
||
includePluginBlock(pluginName).then(fragment => {
|
||
const centerFloat = document.querySelector('.center-float');
|
||
if (!centerFloat) return;
|
||
|
||
const wrapper = document.createElement('div');
|
||
wrapper.setAttribute('pluginblock', pluginName);
|
||
wrapper.appendChild(document.createElement('br'));
|
||
|
||
const scripts = [];
|
||
Array.from(fragment.childNodes).forEach(node => {
|
||
if (node.tagName === 'SCRIPT') {
|
||
const s = document.createElement('script');
|
||
if (node.src) {
|
||
s.src = node.src;
|
||
s.async = false;
|
||
scripts.push(new Promise(res => s.onload = res));
|
||
} else {
|
||
s.textContent = node.textContent;
|
||
}
|
||
document.body.appendChild(s);
|
||
} else {
|
||
wrapper.appendChild(node);
|
||
}
|
||
});
|
||
|
||
centerFloat.appendChild(wrapper);
|
||
|
||
Promise.all(scripts).then(() => {
|
||
const event = new Event("Load" + pluginName + "Js");
|
||
document.dispatchEvent(event);
|
||
window.dispatchEvent(event);
|
||
});
|
||
});
|
||
});
|
||
|
||
// Пример изменения includePlugin
|
||
function includePluginBlock(plugin) {
|
||
return jsonrpcRequest("includePlugin", { plugin })
|
||
.then(html => {
|
||
const frag = document.createDocumentFragment();
|
||
const temp = document.createElement('div');
|
||
temp.innerHTML = html;
|
||
|
||
Array.from(temp.childNodes).forEach(node => {
|
||
if (node.nodeType === 1) node.setAttribute('plugin', plugin);
|
||
frag.appendChild(node);
|
||
});
|
||
|
||
return frag;
|
||
});
|
||
}
|
||
|
||
// Взаимодействие с плагинами
|
||
/* document.getElementById('pluginCreateLeft').onclick = function() { pluginFun('create', 'left'); };
|
||
document.getElementById('pluginCreateRight').onclick = function() { pluginFun('create', 'right'); }; */
|
||
document.getElementById('pluginAddLeft').onclick = function() { pluginFun('add', 'left'); };
|
||
document.getElementById('pluginAddRight').onclick = function() { pluginFun('add', 'right'); };
|
||
/* document.getElementById('pluginRulesButton1').onclick = function() { pluginRulesFun('pluginRulesBlock1'); };
|
||
document.getElementById('pluginRulesButton2').onclick = function() { pluginRulesFun('pluginRulesBlock2'); }; */
|
||
|
||
function pluginRulesFun(id) {
|
||
let element = document.getElementById(id);
|
||
if (element.classList.contains('show')) {
|
||
element.classList.remove('show');
|
||
} else {
|
||
element.classList.add('show');
|
||
/* jsonrpcRequest('funcEditor', { action: 'add', side: '', pluginName: '' }).then(pluginsText => {
|
||
let plugins = pluginsText.trim().split("\n");
|
||
element.innerHTML = `<div>{{plugin_name_guidelines}}</div><hr><div>{{used_plugin_names}}</div>`;
|
||
plugins.forEach(plugin => {
|
||
let div = document.createElement('div');
|
||
div.innerHTML = plugin;
|
||
element.appendChild(div);
|
||
});
|
||
}); */
|
||
}
|
||
}
|
||
|
||
document.getElementById('pluginCreateLeftFun_d').onclick = function() { pluginFun_d('pluginCreateLeftName', 'left-float', 'pluginCreateLeftTitle', ' {{plugin_created_left_suffix}}', 'create', 'pluginCreateLeft_d'); };
|
||
document.getElementById('pluginAddLeftFun_d').onclick = function() { pluginFun_d('pluginAddLeftName', 'left-float', 'pluginAddLeftTitle', ' {{plugin_added_left_suffix}}', 'add', 'pluginAddLeft_d'); };
|
||
document.getElementById('pluginCreateRightFun_d').onclick = function() { pluginFun_d('pluginCreateRightName', 'right-float', 'pluginCreateRightTitle', ' {{plugin_created_right_suffix}}', 'create', 'pluginCreateRight_d'); };
|
||
document.getElementById('pluginAddRightFun_d').onclick = function() { pluginFun_d('pluginAddRightName', 'right-float', 'pluginAddRightTitle', ' {{plugin_added_right_suffix}}', 'add', 'pluginAddRight_d'); };
|
||
|
||
function pluginFun_d(inputIdName, side_float, inputIdTitle, pluginText, action, pluginAddSide_d) {
|
||
let pluginName = document.getElementById(inputIdName).value.trim();
|
||
let pluginTitle = document.getElementById(inputIdTitle).value.trim();
|
||
|
||
if (pluginName === "") {
|
||
messageFunction(action === 'create' ? "{{plugin_name_empty_error}}" : "{{plugin_not_selected_error}}")
|
||
return;
|
||
}
|
||
|
||
let allowedCharacters = /^[a-zA-Z0-9 _]*$/;
|
||
if (!allowedCharacters.test(pluginName)) {
|
||
messageFunction("{{plugin_name_guidelines}}")
|
||
return;
|
||
}
|
||
|
||
if (action === 'create') {
|
||
jsonrpcRequest('checkFile', { path: 'plugin', nameFile: pluginName })
|
||
.then(response => {
|
||
if (response.trim() === "true") {
|
||
messageFunction(pluginName + "{{plugin_name_exists_suffix}}");
|
||
} else {
|
||
sendRequest('create', side_float, pluginName, pluginTitle, pluginText);
|
||
}
|
||
});
|
||
} else {
|
||
pluginHtml('add', pluginName, side_float, pluginTitle);
|
||
inter();
|
||
}
|
||
document.getElementById(pluginAddSide_d).style.visibility = "hidden";
|
||
}
|
||
/* if (pluginTitle === "") {
|
||
messageFunction("{{plugin_title_empty_error}}");
|
||
return;
|
||
} */
|
||
|
||
function sendRequest(action, side_float, pluginName, pluginTitle, pluginText) {
|
||
jsonrpcRequest('createPlugin', { pluginName, side: side_float, pluginTitle, pluginText }).then(response => {
|
||
if (response.trim() === "Plugin created: " + pluginName) {
|
||
pluginHtml('create', pluginName, side_float, pluginTitle);
|
||
inter();
|
||
}
|
||
});
|
||
}
|
||
function pluginHtml(action, pluginName, side_float, pluginTitle) {
|
||
let sideFloat = document.getElementById(side_float);
|
||
let sideFloatElement = sideFloat;
|
||
|
||
let pluginUrl = document.createElement("div");
|
||
pluginUrl.classList.add('plugin-url');
|
||
pluginUrl.pluginUrl = '/plugin/' + pluginName + '/';
|
||
|
||
let br = document.createElement("br");
|
||
let tclass = null;
|
||
if (pluginTitle != "") {
|
||
tclass = document.createElement("div");
|
||
tclass.setAttribute("tclass", 'tclass');
|
||
tclass.setAttribute("plugin-title", 'pluginTitle');
|
||
tclass.className = 'btitle';
|
||
tclass.textContent = pluginTitle;
|
||
}
|
||
|
||
let bclass = document.createElement("div");
|
||
bclass.setAttribute("bclass", 'bclass');
|
||
bclass.className = 'bfloat';
|
||
|
||
let bcont = document.createElement("div");
|
||
bcont.className = 'bcont';
|
||
|
||
sideFloatElement.appendChild(pluginUrl);
|
||
if (tclass) {
|
||
pluginUrl.appendChild(tclass);
|
||
}
|
||
pluginUrl.appendChild(bclass);
|
||
pluginUrl.appendChild(br);
|
||
bclass.appendChild(bcont);
|
||
|
||
if (action === 'add') {
|
||
jsonrpcRequest('getPlugin', { pluginName2: pluginName }).then(pluginContent => {
|
||
bcont.innerHTML = pluginContent;
|
||
});
|
||
} else {
|
||
let pluginEditable = document.createElement("div");
|
||
pluginEditable.className = 'pluginEditable';
|
||
pluginEditable.contentEditable = 'true';
|
||
bcont.appendChild(pluginEditable);
|
||
}
|
||
}
|
||
|
||
for (let i = 0; i < editId.length; i++) {
|
||
if (document.getElementById(editId[i])) {
|
||
document.getElementById(editId[i]).onclick = function() { editFun(editId[i]); };
|
||
}
|
||
}
|
||
|
||
function editFun(whichEditId) {
|
||
for (let i = 0; i < editId.length; i++) {
|
||
if (whichEditId === editId[i]) {
|
||
if (editMode != i) {
|
||
editFun1_1(i);
|
||
} else {
|
||
editFun1_2(i);
|
||
}
|
||
|
||
} else {
|
||
editFun3(i);
|
||
}
|
||
|
||
if (i == 3 && editMode != 3) {
|
||
editFun4(i);
|
||
}
|
||
if (editMode != 0 && editMode != 2 && editMode != 3) {
|
||
editFun5(i);
|
||
}
|
||
}
|
||
}
|
||
|
||
function editFun1_1(i) {
|
||
editMode = i;
|
||
document.getElementById(editId[i]).classList.add('active');
|
||
}
|
||
function editFun1_2(i) {
|
||
editMode = -1;
|
||
document.getElementById(editId[i]).classList.remove('active');
|
||
}
|
||
/* function editFun2_1(i) {
|
||
let pluginElements = document.querySelectorAll('[plugin-url]');
|
||
for (let i = 0; i < pluginElements.length; i++) {
|
||
let pluginTitleElement = pluginElements[i].querySelector('[plugin-title]');
|
||
if (pluginTitleElement) {
|
||
let pluginUrl = pluginElements[i].getAttribute('plugin-url');
|
||
let newDiv = document.createElement('div');
|
||
newDiv.className = 'pluginTitleUrl';
|
||
newDiv.textContent = pluginUrl;
|
||
pluginTitleElement.insertAdjacentElement('afterbegin', newDiv);
|
||
}
|
||
}
|
||
} */
|
||
function editFun3(i) {
|
||
/* document.getElementById(editId[i]).classList.remove('active'); */
|
||
}
|
||
function editFun4(i) {
|
||
}
|
||
function editFun5(i) {
|
||
/* pluginDropdownContentId.style.backgroundColor = ''; */
|
||
}
|
||
|
||
let pluginTakeCheck = 0;
|
||
let targetElement;
|
||
document.onclick = function(event) {
|
||
if (editMode === 0) {
|
||
yourFunction(event);
|
||
}
|
||
|
||
async function yourFunction(event) {
|
||
let target = event.target;
|
||
let pluginElement = target.closest('.plugin-url');
|
||
if (pluginElement) {
|
||
messageQueue.push("{{delete_plugin_confirm}}");
|
||
if (await messageCreateQuestion()) {
|
||
pluginElement.remove();
|
||
|
||
/* let floatElements = [document.querySelector('.right-float'), document.querySelector('.left-float')];
|
||
floatElements.forEach(element => {
|
||
if (element && element.children.length === 0 && element.textContent.trim() === "") {
|
||
element.remove();
|
||
}
|
||
}); */
|
||
|
||
inter();
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
if (editMode === 1) {
|
||
/* let target = event.target;
|
||
let pluginTitle = target.closest('[plugin-title]');
|
||
let mainTitle = target.closest('#mainTitle');
|
||
|
||
let secondDiv = pluginTitle ? pluginTitle.closest('div').parentElement.closest('div') : null;
|
||
let thirdDiv = secondDiv ? secondDiv.parentElement.closest('div') : null;
|
||
let allDivsInParent = secondDiv ? Array.from(secondDiv.parentElement.children).filter(child => child.tagName === 'DIV') : [];
|
||
let indexOfSecondDiv = secondDiv ? allDivsInParent.indexOf(secondDiv) : null;
|
||
let classOfThirdDiv = thirdDiv ? thirdDiv.className.replace(/-float/g, '') : null;
|
||
|
||
if (pluginTitle || mainTitle) {
|
||
let editTitle = mainTitle ? mainTitle : pluginTitle;
|
||
let whichTitle = mainTitle ? "mainTitle" : "pluginTitle";
|
||
console.log(whichTitle+" "+functionOpenPage);
|
||
|
||
if (whichTitle === "mainTitle" && functionOpenPage === true) {
|
||
messageFunction("{{open_page}}");
|
||
} else {
|
||
let title = prompt("{{enter_new_title}}", editTitle.textContent.trim());
|
||
if (title !== null) {
|
||
let newTitle = title.trim();
|
||
|
||
if (newTitle !== "") {
|
||
jsonrpcRequest('newTitle', { newTitle, whichTitle, side: classOfThirdDiv, pluginNumber: indexOfSecondDiv }).then(response => {
|
||
console.log(response);
|
||
editTitle.innerHTML = newTitle;
|
||
messageFunction("{{title_saved}}")
|
||
inter();
|
||
});
|
||
} else {
|
||
messageFunction("{{plugin_title_empty_error}}");
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
} */
|
||
}
|
||
|
||
if (editMode === 2 && pluginTakeCheck == 0) {
|
||
let pluginElement = event.target.closest('.plugin-url');
|
||
|
||
if (pluginElement) {
|
||
pluginElement.style.border = '3px dashed #000000';
|
||
pluginElement.classList.add('pluginElementl');
|
||
|
||
let indicator = document.createElement("div");
|
||
indicator.style.width = '20px';
|
||
indicator.style.height = '20px';
|
||
indicator.style.position = 'absolute';
|
||
indicator.style.left = (event.clientX - 10) + 'px';
|
||
indicator.style.top = (event.clientY - 10) + 'px';
|
||
indicator.style.backgroundImage = "url(../../img/pict/b_iconslyb.svg)";
|
||
indicator.style.backgroundPosition = "0px -80px";
|
||
indicator.style.pointerEvents = "none";
|
||
document.body.appendChild(indicator);
|
||
|
||
function pointerMove(event) {
|
||
indicator.style.left = (event.clientX - 10) + 'px';
|
||
indicator.style.top = (event.clientY - 10) + 'px';
|
||
|
||
let dropTarget = document.elementFromPoint(event.clientX, event.clientY);
|
||
let leftFloatElement = document.getElementById('left-float');
|
||
let rightFloatElement = document.getElementById('right-float');
|
||
let isLeftFloat = leftFloatElement ? leftFloatElement.contains(dropTarget) : false;
|
||
let isRightFloat = rightFloatElement ? rightFloatElement.contains(dropTarget) : false;
|
||
|
||
if (isLeftFloat || isRightFloat) {
|
||
let targetCheck = document.elementFromPoint(event.clientX, event.clientY).closest('.plugin-url');
|
||
let floatElement = isLeftFloat ? leftFloatElement : rightFloatElement;
|
||
|
||
if (pluginElement !== targetCheck) {
|
||
pluginTakeCheck = 1;
|
||
}
|
||
|
||
pluginElement.classList.remove('pluginElementl');
|
||
|
||
if (targetCheck) {
|
||
let side = getTargetSide(targetCheck, event.clientY);
|
||
|
||
if (side === 0) {
|
||
if (targetCheck.parentNode === floatElement) {
|
||
floatElement.insertBefore(pluginElement, targetCheck.nextSibling);
|
||
} else {
|
||
floatElement.appendChild(pluginElement);
|
||
}
|
||
indicator.style.backgroundPosition = "-40px -80px";
|
||
} else if (side === 1) {
|
||
if (targetCheck.parentNode === floatElement) {
|
||
floatElement.insertBefore(pluginElement, targetCheck);
|
||
} else {
|
||
floatElement.appendChild(pluginElement);
|
||
}
|
||
indicator.style.backgroundPosition = "0px -80px";
|
||
}
|
||
} else {
|
||
floatElement.appendChild(pluginElement);
|
||
}
|
||
|
||
/* let floatElements = [document.querySelector('.right-float'), document.querySelector('.left-float')];
|
||
floatElements.forEach(element => {
|
||
if (element && element.children.length === 0 && element.textContent.trim() === "") {
|
||
element.remove();
|
||
}
|
||
}); */
|
||
}
|
||
}
|
||
|
||
document.addEventListener('pointermove', pointerMove);
|
||
document.addEventListener('pointerup', function pointerup() {
|
||
document.removeEventListener('pointermove', pointerMove);
|
||
document.removeEventListener('pointerup', pointerup);
|
||
|
||
pluginElement.style.border = '';
|
||
pluginElement.style.padding = '';
|
||
indicator.remove();
|
||
inter();
|
||
});
|
||
}
|
||
}
|
||
pluginTakeCheck = 0;
|
||
|
||
if (editMode === 3) {
|
||
}
|
||
|
||
let table = event.target.closest('table');
|
||
if (table) {
|
||
let rowIndex, cellIndex;
|
||
let targetRow = event.target.closest('tr');
|
||
let targetCell = event.target.closest('td');
|
||
|
||
if (targetRow) {
|
||
rowIndex = Array.from(targetRow.parentNode.children).indexOf(targetRow);
|
||
}
|
||
|
||
if (targetCell) {
|
||
cellIndex = Array.from(targetCell.parentNode.children).indexOf(targetCell);
|
||
}
|
||
|
||
if (editMode === 4 && targetRow) {
|
||
let row = table.insertRow(rowIndex + 1);
|
||
let cellCount = targetRow.cells.length;
|
||
for (let i = 0; i < cellCount; i++) {
|
||
let newCell = row.insertCell(i);
|
||
if (targetRow.cells.length > 0) {
|
||
let referenceCell = targetRow.cells[i];
|
||
newCell.style.cssText = referenceCell.style.cssText;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (editMode === 5 && targetRow) {
|
||
if (table.rows.length > 1) {
|
||
table.deleteRow(rowIndex);
|
||
}
|
||
}
|
||
|
||
if (editMode === 6 && targetCell) {
|
||
for (let i = 0; i < table.rows.length; i++) {
|
||
let row = table.rows[i];
|
||
let newCell = row.insertCell(cellIndex + 1);
|
||
if (row.cells.length > cellIndex) {
|
||
let referenceCell = row.cells[cellIndex];
|
||
newCell.style.cssText = referenceCell.style.cssText;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (editMode === 7 && targetCell) {
|
||
if (targetCell.parentNode.cells.length > 1) {
|
||
for (let i = 0; i < table.rows.length; i++) {
|
||
let row = table.rows[i];
|
||
if (row.cells.length > cellIndex) {
|
||
row.deleteCell(cellIndex);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
inter();
|
||
}
|
||
|
||
};
|
||
|
||
function getTargetSide(targetCheck, mouseY) {
|
||
if (targetCheck) {
|
||
let targetRect = targetCheck.getBoundingClientRect();
|
||
let targetY = targetRect.top + targetRect.height / 2;
|
||
return mouseY < targetY ? 1 : 0;
|
||
} else {
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
/* выделение элементов */
|
||
let clipboard = ['', '']
|
||
let selectedElement = null
|
||
let selectedElementOriginalOutline = ''
|
||
let selectedElementCut = ''
|
||
|
||
document.addEventListener('contextmenu',editingElements)
|
||
function editingElements(event) {
|
||
var editable = event.target.closest('[contenteditable="true"]')
|
||
if (!editable) return
|
||
event.preventDefault()
|
||
var menu = document.getElementById('editingMenuItems')
|
||
var copy = document.getElementById('editingMenuItemsCopy')
|
||
var cut = document.getElementById('editingMenuItemsCut')
|
||
var paste = document.getElementById('editingMenuItemsPaste')
|
||
copy.style.display = 'none'
|
||
cut.style.display = 'none'
|
||
paste.style.display = 'none'
|
||
var element = event.target.closest('hr, img, table')
|
||
|
||
if (editable && element) {
|
||
if (selectedElement && selectedElement !== element) {
|
||
selectedElement.style.outline = selectedElementOriginalOutline
|
||
}
|
||
selectedElementOriginalOutline = element.style.outline || ''
|
||
element.style.outline = '1px dashed black'
|
||
selectedElement = element
|
||
menu.style.visibility = 'visible'
|
||
copy.style.display = ''
|
||
cut.style.display = ''
|
||
if (clipboard[0]) paste.style.display = ''
|
||
} else if (editable && clipboard[0]) {
|
||
if (selectedElement) {
|
||
selectedElement.style.outline = selectedElementOriginalOutline
|
||
selectedElement = null
|
||
}
|
||
menu.style.visibility = 'visible'
|
||
paste.style.display = ''
|
||
} else {
|
||
if (selectedElement) {
|
||
selectedElement.style.outline = selectedElementOriginalOutline
|
||
selectedElement = null
|
||
}
|
||
menu.style.visibility = 'hidden'
|
||
}
|
||
|
||
targetElement = null
|
||
if (element) {
|
||
targetElement = element
|
||
var sel = window.getSelection()
|
||
var range = document.createRange()
|
||
range.selectNode(targetElement)
|
||
sel.removeAllRanges()
|
||
sel.addRange(range)
|
||
}
|
||
document.querySelectorAll('.elementEditPanelElement').forEach(function(panel) {
|
||
panel.style.display = 'none'
|
||
document.getElementById('editingMenuItemsHr').style.display = 'none'
|
||
})
|
||
if (targetElement !== null && event.target.closest('[contenteditable="true"]')) {
|
||
editElement()
|
||
}
|
||
|
||
const pad=10
|
||
const menuRect=menu.getBoundingClientRect()
|
||
let x=(event.clientX!==undefined?event.clientX:touchX)
|
||
let y=(event.clientY!==undefined?event.clientY:touchY)
|
||
let left=Math.min(x,window.innerWidth-menuRect.width-pad)
|
||
let top=Math.min(y,window.innerHeight-menuRect.height-pad)
|
||
if (!isPhone) {
|
||
menu.style.left = `${Math.max(pad, left)}px`
|
||
menu.style.top = `${Math.max(pad, top)}px`
|
||
} else {
|
||
menu.style.top = '30%'
|
||
menu.style.left = '0'
|
||
menu.style.right = '0'
|
||
menu.style.marginLeft = 'auto'
|
||
menu.style.marginRight = 'auto'
|
||
menu.style.width = 'calc(100% - 20px)'
|
||
menu.style.maxWidth = 'max-content'
|
||
}
|
||
}
|
||
|
||
function editElement() {
|
||
var panelMap = {
|
||
'HR': 'elementEditPanelHr',
|
||
'IMG': 'elementEditPanelImg',
|
||
'TABLE': 'elementEditPanelTable'
|
||
}
|
||
var panelId = panelMap[targetElement.tagName]
|
||
if (panelId) {
|
||
var panel = document.getElementById(panelId)
|
||
if (panel) {
|
||
panel.style.display = ''
|
||
document.getElementById('editingMenuItemsHr').style.display = ''
|
||
}
|
||
}
|
||
if (panelId === 'elementEditPanelHr') {
|
||
document.getElementById('hr1Edit').value = parseInt(targetElement.style.height, 10) || 1
|
||
document.getElementById('hr2Edit').value = targetElement.style.width || '95%'
|
||
document.getElementById('hr3cEdit').value = targetElement.style.backgroundColor
|
||
? rgbToHex(targetElement.style.backgroundColor)
|
||
: '#000000'
|
||
document.getElementById('hrMarginTopEdit').value = parseInt(targetElement.style.marginTop, 10) || 0
|
||
document.getElementById('hrMarginRightEdit').value = parseInt(targetElement.style.marginRight, 10) || 0
|
||
document.getElementById('hrMarginBottomEdit').value = parseInt(targetElement.style.marginBottom, 10) || 0
|
||
document.getElementById('hrMarginLeftEdit').value = parseInt(targetElement.style.marginLeft, 10) || 0
|
||
var m = targetElement.style.margin
|
||
if (m === '0.5em auto 0.5em 0px') {
|
||
document.getElementById('hr4Edit').value = 'left_clear'
|
||
} else if (m === '0.5em 0px 0.5em auto') {
|
||
document.getElementById('hr4Edit').value = 'right_clear'
|
||
} else if (targetElement.style.display === 'inline-block'
|
||
&& targetElement.style.verticalAlign === 'middle') {
|
||
document.getElementById('hr4Edit').value = 'left_text'
|
||
} else {
|
||
document.getElementById('hr4Edit').value = 'center_clear'
|
||
}
|
||
}
|
||
if (panelId === 'elementEditPanelImg') {
|
||
document.getElementById('ima1Edit').value = targetElement.src || ''
|
||
document.getElementById('ima6Edit').value = parseInt(targetElement.style.width, 10) || 250
|
||
document.getElementById('ima6aEdit').value = parseInt(targetElement.style.height, 10) || ''
|
||
document.getElementById('ima7Edit').value = parseInt(targetElement.style.borderWidth, 10) || 0
|
||
document.getElementById('ima8cEdit').value = targetElement.style.borderColor
|
||
? rgbToHex(targetElement.style.borderColor)
|
||
: '#000000'
|
||
document.getElementById('imaMarginTopEdit').value = parseInt(targetElement.style.marginTop, 10) || 0
|
||
document.getElementById('imaMarginRightEdit').value = parseInt(targetElement.style.marginRight, 10) || 0
|
||
document.getElementById('imaMarginBottomEdit').value = parseInt(targetElement.style.marginBottom, 10) || 0
|
||
document.getElementById('imaMarginLeftEdit').value = parseInt(targetElement.style.marginLeft, 10) || 0
|
||
document.getElementById('ima4Edit').value = targetElement.style.float
|
||
? (targetElement.style.float === 'left' ? 'left_clear'
|
||
: 'right_clear')
|
||
: 'center_clear'
|
||
var link = targetElement.closest('a')
|
||
document.getElementById('imaLinkEdit').value = link ? link.href : ''
|
||
var captionEl = targetElement.nextElementSibling
|
||
}
|
||
if (panelId === 'elementEditPanelTable') {
|
||
document.getElementById('tab1Edit').value = targetElement.style.width || '50%'
|
||
document.getElementById('tabMarginTopEdit').value = parseInt(targetElement.style.marginTop, 10) || 0
|
||
document.getElementById('tabMarginRightEdit').value = parseInt(targetElement.style.marginRight, 10) || 0
|
||
document.getElementById('tabMarginBottomEdit').value = parseInt(targetElement.style.marginBottom, 10) || 0
|
||
document.getElementById('tabMarginLeftEdit').value = parseInt(targetElement.style.marginLeft, 10) || 0
|
||
document.getElementById('tab9Edit').value = parseInt(targetElement.style.borderWidth, 10) || 1
|
||
document.getElementById('tab11cEdit').value = targetElement.style.backgroundColor
|
||
? rgbToHex(targetElement.style.backgroundColor)
|
||
: '#000000'
|
||
var firstCell = targetElement.querySelector('td')
|
||
document.getElementById('tab4Edit').value = firstCell
|
||
? parseInt(firstCell.style.padding, 10) || 1
|
||
: 1
|
||
document.getElementById('tab10cEdit').value = firstCell
|
||
? rgbToHex(firstCell.style.borderColor)
|
||
: '#000000'
|
||
document.getElementById('tab6Edit').value = targetElement.style.float
|
||
? (targetElement.style.float === 'left' ? 'left_clear'
|
||
: 'right_clear')
|
||
: 'center_clear'
|
||
}
|
||
}
|
||
|
||
/* меню изменение элемнтов */
|
||
document.addEventListener('pointerdown', clearMenu)
|
||
document.addEventListener('keydown', clearMenu)
|
||
function clearMenu(event) {
|
||
if (event.type === 'pointerdown' && event.button !== 0) {
|
||
return;
|
||
}
|
||
if (event.target.closest('#editingMenuItems')) {
|
||
return;
|
||
}
|
||
var menu = document.getElementById("editingMenuItems");
|
||
if (selectedElement) {
|
||
selectedElement.style.outline = selectedElementOriginalOutline;
|
||
selectedElement = null;
|
||
}
|
||
if (menu) menu.style.visibility = "hidden";
|
||
}
|
||
|
||
document.getElementById("editingMenuItemsCopy").addEventListener('click', function() {
|
||
if (selectedElement) {
|
||
clipboard = [selectedElement.cloneNode(true), 'copy'];
|
||
}
|
||
});
|
||
|
||
document.getElementById("editingMenuItemsCut").addEventListener('click', function() {
|
||
if (selectedElement) {
|
||
clipboard = [selectedElement.cloneNode(true), 'cut'];
|
||
selectedElementCut = selectedElement;
|
||
}
|
||
});
|
||
|
||
document.getElementById("editingMenuItemsPaste").addEventListener('click', function() {
|
||
if (clipboard && clipboard[0]) {
|
||
var sel = window.getSelection();
|
||
if (!sel.rangeCount) return;
|
||
var range = sel.getRangeAt(0);
|
||
range.collapse(false);
|
||
range.insertNode(clipboard[0]);
|
||
if (clipboard[1] == 'cut' && selectedElementCut) {
|
||
selectedElementCut.remove();
|
||
selectedElementCut = null;
|
||
}
|
||
clipboard[0] = clipboard[0].cloneNode(true);
|
||
document.getElementById("editingMenuItems").style.visibility = "hidden";
|
||
}
|
||
});
|
||
|
||
//редактирования меню страниц
|
||
/* document.getElementById("contentPageCreateFun_d").addEventListener("click", function() {
|
||
inter();
|
||
});
|
||
document.getElementById("contentPageMove").addEventListener("click", function() {
|
||
inter();
|
||
});
|
||
document.getElementById("contentPageSettingsFun_d").addEventListener("click", function() {
|
||
inter();
|
||
}); */
|
||
|
||
// панель редактирования для элементов
|
||
document.getElementById("buthrEdit").addEventListener("click", function() {
|
||
let hr1_v = document.getElementById("hr1Edit").value
|
||
let hr2_v = document.getElementById("hr2Edit").value
|
||
let hr3_v = document.getElementById("hr3cEdit").value
|
||
let hr4_v = document.getElementById("hr4Edit").value
|
||
let mt = document.getElementById("hrMarginTopEdit").value
|
||
let mr = document.getElementById("hrMarginRightEdit").value
|
||
let mb = document.getElementById("hrMarginBottomEdit").value
|
||
let ml = document.getElementById("hrMarginLeftEdit").value
|
||
|
||
let style = ""
|
||
style += "height: " + (hr1_v || 1) + "px; "
|
||
if (hr2_v) style += "width: " + hr2_v + "; "
|
||
style += "background: " + hr3_v + "; "
|
||
style += "margin: " + (mt||0) + "px " + (mr||0) + "px " + (mb||0) + "px " + (ml||0) + "px; "
|
||
|
||
switch (hr4_v) {
|
||
case "left_clear": style += "margin-left: 0; "; break
|
||
case "right_clear": style += "margin-right: 0; "; break
|
||
case "center_clear": style += "position: relative; left: 50%; transform: translateX(-50%); "; break
|
||
case "left_text": style += "display: inline-block; vertical-align: middle; float: left; "; break
|
||
case "right_text": style += "display: inline-block; vertical-align: middle; float: right; "; break
|
||
case "text": style += "display: inline-block; vertical-align: middle; "; break
|
||
}
|
||
|
||
style += "border: 0;"
|
||
change(targetElement, style, "")
|
||
inter()
|
||
})
|
||
|
||
document.getElementById("butimaEdit").addEventListener("click", function() {
|
||
let url = document.getElementById("ima1Edit").value
|
||
let pos = document.getElementById("ima4Edit").value
|
||
let mt = document.getElementById("imaMarginTopEdit").value
|
||
let mr = document.getElementById("imaMarginRightEdit").value
|
||
let mb = document.getElementById("imaMarginBottomEdit").value
|
||
let ml = document.getElementById("imaMarginLeftEdit").value
|
||
let w = document.getElementById("ima6Edit").value
|
||
let h = document.getElementById("ima6aEdit").value
|
||
let bw = document.getElementById("ima7Edit").value
|
||
let bc = document.getElementById("ima8cEdit").value
|
||
let link = document.getElementById("imaLinkEdit").value
|
||
|
||
if (!url) {
|
||
messageFunction("{{insert_url}}")
|
||
return
|
||
}
|
||
|
||
let style = ""
|
||
if (pos === "left_clear") style += "float: left; "
|
||
if (pos === "right_clear") style += "float: right; "
|
||
if (pos === "center_clear") style += "position: relative; left: 50%; transform: translateX(-50%); margin-top: " + (mt||0) + "px; display: block; "
|
||
if (pos === "left_text") style += "float: left; display: inline-block; vertical-align: middle; "
|
||
if (pos === "right_text") style += "float: right; display: inline-block; vertical-align: middle; "
|
||
if (pos === "text") style += "vertical-align: middle; display: inline-block; "
|
||
if (pos !== "center_clear") style += "margin: " + (mt||0) + "px " + (mr||0) + "px " + (mb||0) + "px " + (ml||0) + "px; "
|
||
|
||
if (w) style += "width: " + w + "px; "
|
||
if (h) style += "height: " + h + "px; "
|
||
if (bw) style += "border: " + bw + "px solid " + bc + "; "
|
||
|
||
change(targetElement, style, url)
|
||
|
||
if (link) {
|
||
let a = document.createElement("a")
|
||
a.href = link
|
||
targetElement.parentNode.insertBefore(a, targetElement)
|
||
a.appendChild(targetElement)
|
||
}
|
||
|
||
inter()
|
||
})
|
||
|
||
|
||
document.getElementById("butabEdit").addEventListener("click", function() {
|
||
let width_v = document.getElementById("tab1Edit").value
|
||
let mt = document.getElementById("tabMarginTopEdit").value
|
||
let mr = document.getElementById("tabMarginRightEdit").value
|
||
let mb = document.getElementById("tabMarginBottomEdit").value
|
||
let ml = document.getElementById("tabMarginLeftEdit").value
|
||
let pad_i_v = document.getElementById("tab4Edit").value
|
||
let float_v = document.getElementById("tab6Edit").value
|
||
let border_v = document.getElementById("tab9Edit").value
|
||
let bc_v = document.getElementById("tab10cEdit").value
|
||
let bg_v = document.getElementById("tab11cEdit").value
|
||
|
||
let style = ""
|
||
if (width_v) style += "width: " + width_v + "; "
|
||
if (float_v === "left_clear") style += "float: left; "
|
||
if (float_v === "right_clear") style += "float: right; "
|
||
if (float_v === "center_clear") style += "position: relative; left: 50%; transform: translateX(-50%); "
|
||
if (float_v === "left_text") style += "float: left; display: inline-table; vertical-align: middle; "
|
||
if (float_v === "right_text") style += "float: right; display: inline-table; vertical-align: middle; "
|
||
if (float_v === "text") style += "display: inline-table; vertical-align: middle; "
|
||
if (float_v !== "center_clear") style += "margin: " + (mt||0) + "px " + (mr||0) + "px " + (mb||0) + "px " + (ml||0) + "px; "
|
||
|
||
if (border_v) style += "border: " + border_v + "px solid " + bc_v + "; "
|
||
if (bg_v) style += "background-color: " + bg_v + "; "
|
||
style += "border-collapse: collapse;"
|
||
|
||
change(targetElement, style, "")
|
||
|
||
let cells = targetElement.querySelectorAll("td")
|
||
cells.forEach(function(cell) {
|
||
let cellStyle = ""
|
||
if (pad_i_v) cellStyle += "padding: " + pad_i_v + "px; "
|
||
if (border_v) cellStyle += "border: " + border_v + "px solid " + bc_v + "; "
|
||
cell.style.cssText = cellStyle
|
||
})
|
||
|
||
inter()
|
||
})
|
||
|
||
function change(element, style, src) {
|
||
if (element) {
|
||
if (style) element.style.cssText = style
|
||
if (src) element.src = src
|
||
}
|
||
}
|
||
|
||
function rgbToHex(rgb) {
|
||
let rgbArray = rgb.match(/\d+/g);
|
||
return "#" + rgbArray.map(x => {
|
||
let hex = parseInt(x).toString(16);
|
||
return hex.length === 1 ? "0" + hex : hex;
|
||
}).join('');
|
||
}
|
||
|
||
/* const visibility = sessionStorage.getItem('basis3_visibility');
|
||
if (visibility === "visible" && document.getElementById("siteSettingsButton")) {
|
||
basisVis();
|
||
} */
|
||
}, { once: true }); //addEventListener("LoadeditorJs", function()'
|
||
|
||
/** @brief Список редактируемых элементов */
|
||
let editableElduyjements;
|
||
|
||
addEventListener("LoadeditorJs", function()
|
||
{
|
||
|
||
document.querySelectorAll('.swit').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
const target = document.getElementById(btn.id + '_d');
|
||
if (!target) return;
|
||
target.style.display =
|
||
(getComputedStyle(target).display === 'none') ? '' : 'none';
|
||
});
|
||
});
|
||
|
||
const container = document.querySelector('.toolbar-container');
|
||
const panel = document.getElementById('panel');
|
||
const arrowLeft = document.getElementById('arrow-left');
|
||
const arrowRight = document.getElementById('arrow-right');
|
||
let interval;
|
||
let offset = 0;
|
||
|
||
function getBounds() {
|
||
const containerWidth = container.scrollWidth;
|
||
const panelWidth = panel.clientWidth;
|
||
const arrowWidth = arrowLeft.clientWidth;
|
||
const extra = arrowWidth;
|
||
const maxOffset = 24;
|
||
const minOffset = panelWidth - containerWidth - extra;
|
||
return { containerWidth, panelWidth, maxOffset, minOffset };
|
||
}
|
||
|
||
function updateArrowsVisibility() {
|
||
const { containerWidth, panelWidth, minOffset, maxOffset } = getBounds();
|
||
|
||
if (containerWidth <= panelWidth) {
|
||
arrowLeft.style.display = 'none';
|
||
arrowRight.style.display = 'none';
|
||
panel.style.overflowX = 'visible';
|
||
offset = 0;
|
||
container.style.transform = 'translateX(0px)';
|
||
} else {
|
||
arrowLeft.style.display = 'inline-flex';
|
||
arrowRight.style.display = 'inline-flex';
|
||
panel.style.overflowX = 'clip';
|
||
if (offset > maxOffset) offset = maxOffset;
|
||
if (offset < minOffset) offset = minOffset;
|
||
}
|
||
}
|
||
|
||
const events = ['resize', 'scroll', 'pointerdown', 'pointerup', 'pointermove', 'keydown', 'touchstart'];
|
||
events.forEach(evt => {
|
||
window.addEventListener(evt, updateArrowsVisibility, { passive: true });
|
||
document.addEventListener(evt, updateArrowsVisibility, { passive: true });
|
||
});
|
||
if (window.visualViewport) {
|
||
window.visualViewport.addEventListener('resize', updateArrowsVisibility);
|
||
}
|
||
|
||
updateArrowsVisibility();
|
||
|
||
function startScroll(direction) {
|
||
const { maxOffset, minOffset } = getBounds();
|
||
interval = setInterval(() => {
|
||
if (direction === 'left') {
|
||
offset += 10;
|
||
} else {
|
||
offset -= 10;
|
||
}
|
||
if (offset > maxOffset) offset = maxOffset;
|
||
if (offset < minOffset) offset = minOffset;
|
||
container.style.transform = `translateX(${offset}px)`;
|
||
}, 16);
|
||
}
|
||
|
||
function stopScroll() {
|
||
clearInterval(interval);
|
||
}
|
||
|
||
arrowLeft.addEventListener('pointerdown', e => {
|
||
if (e.pointerType === 'touch') e.preventDefault();
|
||
startScroll('left');
|
||
});
|
||
arrowLeft.addEventListener('pointerup', stopScroll);
|
||
arrowLeft.addEventListener('pointerleave', stopScroll);
|
||
arrowLeft.addEventListener('pointercancel', stopScroll);
|
||
arrowLeft.addEventListener('contextmenu', e => {
|
||
if (e.pointerType === 'touch') e.preventDefault();
|
||
});
|
||
|
||
arrowRight.addEventListener('pointerdown', e => {
|
||
if (e.pointerType === 'touch') e.preventDefault();
|
||
startScroll('right');
|
||
});
|
||
arrowRight.addEventListener('pointerup', stopScroll);
|
||
arrowRight.addEventListener('pointerleave', stopScroll);
|
||
arrowRight.addEventListener('pointercancel', stopScroll);
|
||
arrowRight.addEventListener('contextmenu', e => {
|
||
if (e.pointerType === 'touch') e.preventDefault();
|
||
});
|
||
|
||
|
||
}, { once: true });
|
||
|
||
|
||
/** @brief Простые стили текста */
|
||
const simpleFormats = [
|
||
{ id: 'bol', style: { fontWeight: 'bold' }, prop: 'font-weight', test: v => (parseInt(v) >= 700 || v === 'bold') },
|
||
{ id: 'ital', style: { fontStyle: 'italic' }, prop: 'font-style', test: v => v === 'italic' },
|
||
{ id: 'under', style: { textDecorationLine: 'underline' },prop: 'text-decoration-line', test: v => v.split(' ').includes('underline') },
|
||
{ id: 'strik', style: { textDecorationLine: 'line-through' },prop: 'text-decoration-line', test: v => v.split(' ').includes('line-through') },
|
||
{ id: 'sup', style: { verticalAlign: 'super' }, prop: 'vertical-align', test: v => v === 'super' },
|
||
{ id: 'sub', style: { verticalAlign: 'sub' }, prop: 'vertical-align', test: v => v === 'sub' }
|
||
];
|
||
/** @brief Стили выравнивания для блоков */
|
||
const divFormats = [
|
||
{ id: 'equal', style: { textAlign: 'left' } },
|
||
{ id: 'equac', style: { textAlign: 'center' } },
|
||
{ id: 'equar', style: { textAlign: 'right' } },
|
||
{ id: 'equaj', style: { textAlign: 'justify'} }
|
||
];
|
||
/** @brief Стили списков */
|
||
const listFormats = [
|
||
{ id: 'listNone', style: { listStyleType: 'none' } },
|
||
{ id: 'listDots', style: { listStyleType: 'disc' } },
|
||
{ id: 'listNumbers', style: { listStyleType: 'decimal' } },
|
||
{ id: 'listLetters', style: { listStyleType: 'lower-alpha'} }
|
||
];
|
||
/** @brief Отдельные свойства текста */
|
||
const singleFormats = [
|
||
{ id: 'ff', prop: 'font-family'},
|
||
{ id: 'fs', prop: 'font-size'}
|
||
];
|
||
/** @brief Специальные форматы */
|
||
const specialFormats = ['butlink', 'linkdel', 'forma', 'col', 'backgr'];
|
||
|
||
addEventListener("LoadeditorJs", function() {
|
||
const content = document.querySelectorAll('.content');
|
||
|
||
simpleFormats.forEach(f => {
|
||
document.getElementById(f.id).addEventListener('click', () => {
|
||
const sel = window.getSelection();
|
||
if (!sel.rangeCount) return;
|
||
const range = sel.getRangeAt(0);
|
||
if (![...document.querySelectorAll('.content')].some(c => c.contains(range.commonAncestorContainer))) return;
|
||
let all = true;
|
||
const it = document.createNodeIterator(
|
||
range.commonAncestorContainer,
|
||
NodeFilter.SHOW_ALL,
|
||
{ acceptNode: n => range.intersectsNode(n) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT }
|
||
);
|
||
let n;
|
||
while (n = it.nextNode()) {
|
||
if (n.nodeType === Node.TEXT_NODE && n.textContent.trim()) {
|
||
let cur = n.parentElement, ok = false;
|
||
while (cur) {
|
||
const v = getComputedStyle(cur)[f.prop] || '';
|
||
if (f.test(v)) { ok = true; break; }
|
||
cur = cur.parentElement;
|
||
}
|
||
if (!ok) { all = false; break; }
|
||
}
|
||
}
|
||
all ? simpleUnformat(range, f) : simpleApplyformat(range, f);
|
||
sel.removeAllRanges();
|
||
sel.addRange(range);
|
||
inter();
|
||
});
|
||
});
|
||
|
||
divFormats.forEach(f => {
|
||
document.getElementById(f.id).addEventListener('click', () => {
|
||
const sel = window.getSelection();
|
||
if (!sel.rangeCount) return;
|
||
const range = sel.getRangeAt(0);
|
||
if (![...document.querySelectorAll('.content')].some(c => c.contains(range.commonAncestorContainer))) return;
|
||
divApplyformat(range, f);
|
||
inter();
|
||
});
|
||
});
|
||
|
||
listFormats.forEach(f => {
|
||
document.getElementById(f.id).addEventListener('click', () => {
|
||
const sel = window.getSelection();
|
||
if (!sel.rangeCount) return;
|
||
const range = sel.getRangeAt(0);
|
||
if (![...document.querySelectorAll('.content')].some(c => c.contains(range.commonAncestorContainer))) return;
|
||
listApplyformat(range, f);
|
||
inter();
|
||
});
|
||
});
|
||
|
||
singleFormats.forEach(f => {
|
||
const el = document.getElementById(f.id)
|
||
el.addEventListener('click', e => {
|
||
const list = el.querySelector('.align-list')
|
||
if (!list || getComputedStyle(list).display === 'none') return
|
||
const cmdEl = e.target.closest('[data-cmd]')
|
||
if (!cmdEl) return
|
||
f.value = cmdEl.dataset.cmd
|
||
const sel = window.getSelection()
|
||
if (!sel.rangeCount) return
|
||
const range = sel.getRangeAt(0)
|
||
if (![...document.querySelectorAll('.content')].some(c => c.contains(range.commonAncestorContainer))) return;
|
||
singleApplyformat(range, f)
|
||
inter()
|
||
})
|
||
})
|
||
|
||
specialFormats.forEach(f => {
|
||
document.getElementById(f).addEventListener('click', () => {
|
||
const sel = window.getSelection();
|
||
if (!sel.rangeCount) return;
|
||
const range = sel.getRangeAt(0);
|
||
if (![...content].some(c => c.contains(range.commonAncestorContainer))) return;
|
||
if (typeof document[f + 'Fun'] === 'function') document[f + 'Fun'](range);
|
||
else window[f + 'Fun'](range);
|
||
inter();
|
||
});
|
||
});
|
||
|
||
const events = ['pointerup','keyup','input','focus','blur','click'];
|
||
events.forEach(evt => {
|
||
const contents = document.querySelectorAll('.content');
|
||
if (!contents || contents.length === 0) return;
|
||
contents.forEach(content => {
|
||
content.addEventListener(evt, () => {
|
||
updateToolbarStyles();
|
||
updateSingleSelectors();
|
||
});
|
||
});
|
||
});
|
||
|
||
}, { once: true });
|
||
|
||
/////////////////// Начало блока, выполняющего навигацию по внесенным изменениям ====================
|
||
|
||
/** @brief История изменений контента */
|
||
let arr = []
|
||
/** @brief Текущий индекс в истории изменений */
|
||
let currentIndex = 0
|
||
|
||
/** @brief Сохраняет текущее состояние контента, если оно изменилось */
|
||
function inter() {
|
||
const editables = document.querySelectorAll(".content")
|
||
editables.forEach(editable => {
|
||
if (editable) {
|
||
let currentContent = editable.innerHTML
|
||
if (currentContent !== arr[currentIndex]) {
|
||
currentIndex++
|
||
arr = arr.slice(0, currentIndex)
|
||
arr.push(currentContent)
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
document.querySelectorAll(".content").forEach((editable, i) => {
|
||
if (i === 0) arr[0] = editable.innerHTML
|
||
})
|
||
|
||
document.getElementById("forw").addEventListener("click", function() {
|
||
if (currentIndex < arr.length - 1) {
|
||
currentIndex++
|
||
const editables = document.querySelectorAll(".content")
|
||
editables.forEach(editable => {
|
||
editable.innerHTML = arr[currentIndex]
|
||
editable.setAttribute("contenteditable", "true")
|
||
})
|
||
}
|
||
})
|
||
|
||
document.getElementById("bac").addEventListener("click", function() {
|
||
if (currentIndex > 0) {
|
||
currentIndex--
|
||
const editables = document.querySelectorAll(".content")
|
||
editables.forEach(editable => {
|
||
editable.innerHTML = arr[currentIndex]
|
||
editable.setAttribute("contenteditable", "true")
|
||
})
|
||
}
|
||
})
|
||
|
||
/////////////////// Конец блока, выполняющего навигацию по внесенным изменениям ====================
|
||
|
||
/**
|
||
* @brief Применяет форматирование к выделенному диапазону текста
|
||
* @param range Диапазон выделения текста
|
||
* @param createElement Функция создания нового элемента для форматирования
|
||
*/
|
||
function applyformat(range, createElement) {
|
||
const arr = [], it = document.createNodeIterator(
|
||
range.commonAncestorContainer,
|
||
NodeFilter.SHOW_TEXT,
|
||
n => range.intersectsNode(n) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT
|
||
);
|
||
let n;
|
||
while (n = it.nextNode()) arr.push(n);
|
||
let firstEl, lastEl;
|
||
arr.forEach((tn, i) => {
|
||
const p = tn.parentNode;
|
||
const start = tn === range.startContainer ? range.startOffset : 0;
|
||
const end = tn === range.endContainer ? range.endOffset : tn.textContent.length;
|
||
let newEl;
|
||
if (tn === range.startContainer && tn === range.endContainer) {
|
||
const b = tn.splitText(start), m = b.splitText(end - start);
|
||
newEl = createElement();
|
||
newEl.textContent = b.textContent;
|
||
p.replaceChild(newEl, b);
|
||
p.insertBefore(m, newEl.nextSibling);
|
||
} else if (tn === range.startContainer) {
|
||
const aNode = tn.splitText(start);
|
||
newEl = createElement();
|
||
newEl.textContent = aNode.textContent;
|
||
p.replaceChild(newEl, aNode);
|
||
} else if (tn === range.endContainer) {
|
||
const b = tn.splitText(end);
|
||
newEl = createElement();
|
||
newEl.textContent = tn.textContent;
|
||
p.replaceChild(newEl, tn);
|
||
p.insertBefore(b, newEl.nextSibling);
|
||
} else {
|
||
newEl = createElement();
|
||
newEl.textContent = tn.textContent;
|
||
p.replaceChild(newEl, tn);
|
||
}
|
||
if (i === 0) firstEl = newEl;
|
||
if (i === arr.length - 1) lastEl = newEl;
|
||
});
|
||
if (firstEl && lastEl) {
|
||
range.setStartBefore(firstEl);
|
||
range.setEndAfter(lastEl);
|
||
}
|
||
mergeTextNodes(range.commonAncestorContainer);
|
||
}
|
||
|
||
/**
|
||
* @brief Применяет простой стиль (bold, italic и т.д.) к диапазону текста
|
||
* @param range Диапазон выделения текста
|
||
* @param format Объект с описанием формата
|
||
*/
|
||
function simpleApplyformat(range, format) {
|
||
const span = document.createElement('span');
|
||
Object.assign(span.style, format.style);
|
||
applyformat(range, () => span.cloneNode());
|
||
}
|
||
|
||
/**
|
||
* @brief Убирает простой стиль (bold, italic и т.д.) из диапазона текста
|
||
* @param range Диапазон выделения текста
|
||
* @param format Объект с описанием формата
|
||
*/
|
||
function simpleUnformat(range, format) {
|
||
const { prop, test } = format;
|
||
|
||
const spans = new Set();
|
||
const it = document.createNodeIterator(
|
||
range.commonAncestorContainer,
|
||
NodeFilter.SHOW_TEXT,
|
||
n => {
|
||
if (!range.intersectsNode(n)) return NodeFilter.FILTER_REJECT;
|
||
let node = n.parentNode;
|
||
while (node && node !== range.commonAncestorContainer) {
|
||
if (node.tagName === 'SPAN' && test(node.style.getPropertyValue(prop) || '')) {
|
||
return NodeFilter.FILTER_ACCEPT;
|
||
}
|
||
node = node.parentNode;
|
||
}
|
||
return NodeFilter.FILTER_REJECT;
|
||
}
|
||
);
|
||
|
||
let tn;
|
||
while (tn = it.nextNode()) {
|
||
let node = tn.parentNode;
|
||
while (node && node !== range.commonAncestorContainer) {
|
||
if (node.tagName === 'SPAN' && test(node.style.getPropertyValue(prop) || '')) {
|
||
if (range.intersectsNode(node)) {
|
||
spans.add(node);
|
||
}
|
||
}
|
||
node = node.parentNode;
|
||
}
|
||
}
|
||
|
||
spans.forEach(span => {
|
||
const full = span.textContent;
|
||
let total = 0, startAbs = 0, endAbs = full.length;
|
||
const walker = document.createTreeWalker(span, NodeFilter.SHOW_TEXT, null);
|
||
let t;
|
||
while (walker.nextNode()) {
|
||
t = walker.currentNode;
|
||
if (t === range.startContainer) startAbs = total + range.startOffset;
|
||
if (t === range.endContainer) endAbs = total + range.endOffset;
|
||
total += t.textContent.length;
|
||
}
|
||
if (startAbs >= endAbs) return;
|
||
|
||
const bef = full.slice(0, startAbs);
|
||
const sel = full.slice(startAbs, endAbs);
|
||
const aft = full.slice(endAbs);
|
||
|
||
const p = span.parentNode;
|
||
if (!p) return;
|
||
|
||
function cloneWithText(node, text) {
|
||
const clone = node.cloneNode(false);
|
||
for (let child of node.childNodes) {
|
||
if (text.length === 0) break;
|
||
if (child.nodeType === Node.TEXT_NODE) {
|
||
const len = child.textContent.length;
|
||
const take = text.slice(0, len);
|
||
clone.appendChild(document.createTextNode(take));
|
||
text = text.slice(len);
|
||
} else {
|
||
const sub = child.textContent;
|
||
const taken = text.slice(0, sub.length);
|
||
clone.appendChild(cloneWithText(child, taken));
|
||
text = text.slice(sub.length);
|
||
}
|
||
}
|
||
return clone;
|
||
}
|
||
|
||
if (bef) p.insertBefore(cloneWithText(span, bef), span);
|
||
if (sel) {
|
||
const unwrapped = document.createDocumentFragment();
|
||
const mid = cloneWithText(span, sel);
|
||
while (mid.firstChild) unwrapped.appendChild(mid.firstChild);
|
||
p.insertBefore(unwrapped, span);
|
||
}
|
||
if (aft) p.insertBefore(cloneWithText(span, aft), span);
|
||
span.remove();
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @brief Объединяет соседние текстовые узлы
|
||
* @param node Элемент, внутри которого объединяются текстовые узлы
|
||
*/
|
||
function mergeTextNodes(node) {
|
||
let c = node.firstChild;
|
||
while (c) {
|
||
let nx = c.nextSibling;
|
||
if (c.nodeType === Node.TEXT_NODE) {
|
||
while (nx && nx.nodeType === Node.TEXT_NODE) {
|
||
c.textContent += nx.textContent;
|
||
const next = nx.nextSibling;
|
||
if (nx.parentNode) nx.parentNode.removeChild(nx);
|
||
nx = next;
|
||
}
|
||
} else if (c.nodeType === Node.ELEMENT_NODE) {
|
||
mergeTextNodes(c);
|
||
}
|
||
c = nx;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Применяет стиль выравнивания к блочным элементам
|
||
* @param range Диапазон выделения текста
|
||
* @param format Объект с описанием формата
|
||
*/
|
||
function divApplyformat(range, format) {
|
||
const style = format.style;
|
||
if (!style || !style.textAlign) return;
|
||
const externals = new Set();
|
||
const intersects = element => {
|
||
const er = document.createRange();
|
||
er.selectNodeContents(element);
|
||
return range.compareBoundaryPoints(Range.END_TO_START, er) < 0 &&
|
||
range.compareBoundaryPoints(Range.START_TO_END, er) > 0;
|
||
};
|
||
|
||
Array.from(document.querySelectorAll('.content')).forEach(content => {
|
||
Array.from(content.children).forEach(child => {
|
||
if (intersects(child)) externals.add(child);
|
||
});
|
||
});
|
||
|
||
externals.forEach(div => {
|
||
div.style.textAlign = style.textAlign;
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @brief Применяет стиль списка к выделенным элементам
|
||
* @param range Диапазон выделения текста
|
||
* @param format Объект с описанием формата
|
||
*/
|
||
function listApplyformat(range, format) {
|
||
const intersects = el => {
|
||
const er = document.createRange();
|
||
er.selectNodeContents(el);
|
||
return range.compareBoundaryPoints(Range.END_TO_START, er) < 0 &&
|
||
range.compareBoundaryPoints(Range.START_TO_END, er) > 0;
|
||
};
|
||
|
||
const type = format.id;
|
||
|
||
if (type === 'listNone') {
|
||
const lists = new Set();
|
||
Array.from(document.querySelectorAll('.content')).forEach(content => {
|
||
Array.from(content.querySelectorAll('li')).forEach(li => {
|
||
if (intersects(li)) lists.add(li.parentNode);
|
||
});
|
||
});
|
||
|
||
lists.forEach(list => {
|
||
const parent = list.parentNode;
|
||
const lis = Array.from(list.children);
|
||
const selected = lis.filter(li => intersects(li));
|
||
if (!selected.length) return;
|
||
|
||
const firstIdx = lis.indexOf(selected[0]);
|
||
const lastIdx = lis.indexOf(selected[selected.length - 1]);
|
||
const before = lis.slice(0, firstIdx);
|
||
const after = lis.slice(lastIdx + 1);
|
||
|
||
if (before.length) {
|
||
const ul1 = list.cloneNode(false);
|
||
before.forEach(li => ul1.appendChild(li));
|
||
parent.insertBefore(ul1, list);
|
||
}
|
||
|
||
selected.forEach(li => {
|
||
const wrapper = li.firstElementChild && li.firstElementChild.cloneNode(true) || document.createElement('div');
|
||
if (!li.firstElementChild) {
|
||
while (li.firstChild) wrapper.appendChild(li.firstChild);
|
||
}
|
||
parent.insertBefore(wrapper, list);
|
||
});
|
||
|
||
if (after.length) {
|
||
const ul2 = list.cloneNode(false);
|
||
after.forEach(li => ul2.appendChild(li));
|
||
parent.insertBefore(ul2, list);
|
||
}
|
||
|
||
parent.removeChild(list);
|
||
});
|
||
} else {
|
||
Array.from(document.querySelectorAll('.content')).forEach(content => {
|
||
const items = Array.from(content.children).filter(child => intersects(child));
|
||
if (!items.length) return;
|
||
|
||
let listEl;
|
||
if (type === 'listNumbers' || type === 'listLetters') {
|
||
listEl = document.createElement('ol');
|
||
listEl.style.listStyleType = format.style.listStyleType;
|
||
} else {
|
||
listEl = document.createElement('ul');
|
||
listEl.style.listStyleType = format.style.listStyleType;
|
||
}
|
||
content.insertBefore(listEl, items[0]);
|
||
|
||
items.forEach(node => {
|
||
if (node.tagName === 'UL' || node.tagName === 'OL') {
|
||
Array.from(node.children).forEach(li => {
|
||
listEl.appendChild(li);
|
||
});
|
||
content.removeChild(node);
|
||
} else {
|
||
const li = document.createElement('li');
|
||
content.removeChild(node);
|
||
li.appendChild(node);
|
||
listEl.appendChild(li);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Применяет одиночный стиль к диапазону текста
|
||
* @param range Диапазон выделения текста
|
||
* @param f Объект с описанием формата
|
||
* @return span Элемент span с применённым стилем
|
||
*/
|
||
function singleApplyformat(range, f) {
|
||
const val = f.value;
|
||
if (!val) return;
|
||
applyformat(range, () => {
|
||
const span = document.createElement('span');
|
||
span.style[f.prop] = val;
|
||
return span;
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @brief Применяет ссылку к диапазону текста
|
||
* @param range Диапазон выделения текста
|
||
* @return a Элемент a с применёнными атрибутами и стилем
|
||
*/
|
||
function butlinkFun(range) {
|
||
const url = document.getElementById('link2').value;
|
||
const targetBlank = document.getElementById('link3').value === 'yes';
|
||
const underline = document.getElementById('link5').value === 'yes';
|
||
const color = document.getElementById('link6c').value;
|
||
applyformat(range, () => {
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
if (targetBlank) a.target = '_blank';
|
||
if (underline) a.style.textDecoration = 'underline';
|
||
if (color) a.style.color = color;
|
||
return a;
|
||
});
|
||
inter();
|
||
}
|
||
|
||
/**
|
||
* @brief Удаляет все ссылки из диапазона текста
|
||
* @param range Диапазон выделения текста
|
||
* @return frag Фрагмент документа без ссылок
|
||
*/
|
||
function linkdelFun(range) {
|
||
const frag = range.extractContents();
|
||
const cleaned = unwrapAllLinks(frag);
|
||
range.insertNode(cleaned);
|
||
|
||
function unwrapAllLinks(node) {
|
||
const frag = document.createDocumentFragment();
|
||
Array.from(node.childNodes).forEach(ch => {
|
||
if (ch.nodeType === Node.ELEMENT_NODE && ch.tagName === 'A') {
|
||
frag.appendChild(unwrapAllLinks(ch));
|
||
} else if (ch.nodeType === Node.ELEMENT_NODE) {
|
||
const copy = ch.cloneNode(false);
|
||
copy.appendChild(unwrapAllLinks(ch));
|
||
frag.appendChild(copy);
|
||
} else {
|
||
frag.appendChild(ch.cloneNode(true));
|
||
}
|
||
});
|
||
return frag;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Убирает все спаны и ссылки из диапазона текста
|
||
* @param range Диапазон выделения текста
|
||
* @return frag Фрагмент документа без span и a
|
||
*/
|
||
function formaFun(range) {
|
||
const frag = range.extractContents();
|
||
const cleaned = unwrapAllSpansAndLinks(frag);
|
||
range.insertNode(cleaned);
|
||
|
||
const externals = new Set();
|
||
const intersects = element => {
|
||
const er = document.createRange();
|
||
er.selectNodeContents(element);
|
||
return range.compareBoundaryPoints(Range.END_TO_START, er) < 0
|
||
&& range.compareBoundaryPoints(Range.START_TO_END, er) > 0;
|
||
};
|
||
Array.from(document.querySelectorAll('.content')).forEach(content => {
|
||
Array.from(content.children).forEach(child => {
|
||
if (intersects(child)) externals.add(child);
|
||
});
|
||
});
|
||
externals.forEach(el => {
|
||
el.style.textAlign = '';
|
||
});
|
||
|
||
Array.from(document.querySelectorAll('.content')).forEach(content => {
|
||
const itList = document.createNodeIterator(
|
||
content,
|
||
NodeFilter.SHOW_ELEMENT,
|
||
{
|
||
acceptNode: n =>
|
||
(n.tagName === 'UL' || n.tagName === 'OL') &&
|
||
range.intersectsNode(n)
|
||
? NodeFilter.FILTER_ACCEPT
|
||
: NodeFilter.FILTER_REJECT
|
||
}
|
||
);
|
||
let listEl;
|
||
while (listEl = itList.nextNode()) {
|
||
const parent = listEl.parentNode;
|
||
Array.from(listEl.children).forEach(li => {
|
||
while (li.firstChild) parent.insertBefore(li.firstChild, listEl);
|
||
});
|
||
parent.removeChild(listEl);
|
||
}
|
||
});
|
||
|
||
function unwrapAllSpansAndLinks(node) {
|
||
const frag = document.createDocumentFragment();
|
||
Array.from(node.childNodes).forEach(ch => {
|
||
if (
|
||
ch.nodeType === Node.ELEMENT_NODE &&
|
||
(ch.tagName === 'SPAN' || ch.tagName === 'A')
|
||
) {
|
||
frag.appendChild(unwrapAllSpansAndLinks(ch));
|
||
} else if (ch.nodeType === Node.ELEMENT_NODE) {
|
||
const copy = ch.cloneNode(false);
|
||
copy.appendChild(unwrapAllSpansAndLinks(ch));
|
||
frag.appendChild(copy);
|
||
} else {
|
||
frag.appendChild(ch.cloneNode(true));
|
||
}
|
||
});
|
||
return frag;
|
||
}
|
||
}
|
||
|
||
/** @brief Текущий формат для применения */
|
||
let currentFormat = null;
|
||
/** @brief Текущий диапазон выделения */
|
||
let currentRange = null;
|
||
/**
|
||
* @brief Открывает палитру выбора цвета текста
|
||
* @param range Диапазон выделения текста
|
||
*/
|
||
window.colFun = function(range) {
|
||
currentFormat = { prop: 'color', test: v => !!v };
|
||
currentRange = range;
|
||
const app = document.querySelector('.pcr-app');
|
||
app.style.marginLeft = '-61px';
|
||
app.style.left = '';
|
||
app.classList.remove('hide');
|
||
}
|
||
/**
|
||
* @brief Открывает палитру выбора фона текста
|
||
* @param range Диапазон выделения текста
|
||
*/
|
||
window.backgrFun = function(range) {
|
||
currentFormat = { prop: 'background-color', test: v => !!v };
|
||
currentRange = range;
|
||
const app = document.querySelector('.pcr-app');
|
||
app.style.marginLeft = '-29px';
|
||
app.style.left = '';
|
||
app.classList.remove('hide');
|
||
}
|
||
/**
|
||
* @brief Применяет выбранный цвет текста или фона
|
||
*/
|
||
function setColorFun() {
|
||
const input = document.querySelector('.pcr-result');
|
||
const val = input.value;
|
||
if (!currentRange || !currentFormat) return;
|
||
if (!val) {
|
||
simpleUnformat(currentRange, currentFormat);
|
||
} else {
|
||
applyformat(currentRange, () => {
|
||
const span = document.createElement('span');
|
||
span.style[currentFormat.prop] = val;
|
||
return span;
|
||
});
|
||
}
|
||
const app = document.querySelector('.pcr-app');
|
||
app.classList.add('hide');
|
||
}
|
||
document.addEventListener('LoadeditorJs', () => {
|
||
document.addEventListener('pointerdown', e => {
|
||
if (document.querySelector('.pcr-app') && !e.target.closest('.pcr-app') && !e.target.closest('#col') && !e.target.closest('#backgr')) {
|
||
setColorFun();
|
||
}
|
||
});
|
||
}, { once: true });
|
||
|
||
/** @brief Кнопки панели инструментов */
|
||
const toolbarButtons = ['bol','ital','under','strik','sup','sub'];
|
||
/** @brief Цвета фона кнопок панели инструментов */
|
||
const bgColors = {
|
||
none: 'rgb(255 255 255)',
|
||
partial: 'rgb(231 231 231)',
|
||
full: 'rgb(203 203 203)'
|
||
};
|
||
|
||
/**
|
||
* @brief Определяет текущее состояние формата (выделено/не выделено/частично)
|
||
* @param format Идентификатор формата
|
||
* @return string Состояние формата: 'none', 'partial', 'full'
|
||
*/
|
||
function detectFormatState(format) {
|
||
const sel = window.getSelection();
|
||
if (!sel.rangeCount) return 'none';
|
||
const range = sel.getRangeAt(0);
|
||
if (![...document.querySelectorAll('.content')].some(c => c.contains(range.commonAncestorContainer))) return 'none';
|
||
const it = document.createNodeIterator(
|
||
range.commonAncestorContainer,
|
||
NodeFilter.SHOW_TEXT,
|
||
{ acceptNode: n => range.intersectsNode(n) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT }
|
||
);
|
||
let node, total = 0, styled = 0;
|
||
while (node = it.nextNode()) {
|
||
const text = node.textContent.trim();
|
||
if (!text) continue;
|
||
total++;
|
||
let cur = node.parentElement, ok = false;
|
||
while (cur && ![...document.querySelectorAll('.content')].includes(cur)) {
|
||
const fmt = simpleFormats.find(f => f.id === format);
|
||
const v = fmt ? getComputedStyle(cur)[fmt.prop] || '' : '';
|
||
if (fmt && fmt.test(v)) { ok = true; break; }
|
||
cur = cur.parentElement;
|
||
}
|
||
if (ok) styled++;
|
||
}
|
||
if (total === 0) return 'none';
|
||
if (styled === 0) return 'none';
|
||
if (styled === total) return 'full';
|
||
return 'partial';
|
||
}
|
||
|
||
/**
|
||
* @brief Обновляет стили кнопок панели инструментов в зависимости от состояния форматирования
|
||
*/
|
||
function updateToolbarStyles() {
|
||
toolbarButtons.forEach(id => {
|
||
const btn = document.getElementById(id);
|
||
const state = detectFormatState(id);
|
||
btn.style.backgroundColor = bgColors[state];
|
||
});
|
||
}
|
||
|
||
/** @brief Одиночные селекторы панели инструментов */
|
||
const singleSelectors = ['ff','fs'];
|
||
|
||
/**
|
||
* @brief Определяет текущее состояние одиночного селектора (шрифт, размер)
|
||
* @param format Идентификатор селектора
|
||
* @return string Текущее значение или пустая строка
|
||
*/
|
||
function detectSingleState(format) {
|
||
const sel = window.getSelection();
|
||
if (!sel.rangeCount) return '';
|
||
const range = sel.getRangeAt(0);
|
||
if (![...document.querySelectorAll('.content')].some(c => c.contains(range.commonAncestorContainer))) return '';
|
||
const it = document.createNodeIterator(
|
||
range.commonAncestorContainer,
|
||
NodeFilter.SHOW_TEXT,
|
||
{ acceptNode: n => range.intersectsNode(n) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT }
|
||
);
|
||
let node, values = [], uniform = true;
|
||
while (node = it.nextNode()) {
|
||
const text = node.textContent.trim();
|
||
if (!text) continue;
|
||
const cur = node.parentElement;
|
||
const fmt = singleFormats.find(f => f.id === format);
|
||
const v = getComputedStyle(cur)[fmt.prop] || '';
|
||
values.push(v);
|
||
}
|
||
if (values.length === 0) return '';
|
||
const first = values[0];
|
||
for (let i = 1; i < values.length; i++) {
|
||
if (values[i] !== first) { uniform = false; break; }
|
||
}
|
||
return uniform ? values[0] : '';
|
||
}
|
||
|
||
/**
|
||
* @brief Обновляет отображение одиночных селекторов на панели инструментов
|
||
*/
|
||
function updateSingleSelectors() {
|
||
singleSelectors.forEach(id => {
|
||
const dropdown = document.getElementById(id);
|
||
const current = dropdown.querySelector('.current');
|
||
const list = dropdown.querySelectorAll('li');
|
||
let value = detectSingleState(id);
|
||
if (!value) return;
|
||
let cmd = id === 'ff'
|
||
? value.replace(/["']/g, '')
|
||
: value;
|
||
if (id === 'fs') {
|
||
const num = parseFloat(cmd);
|
||
const unit = (cmd.match(/[a-z%]+$/) || [''])[0];
|
||
cmd = num.toFixed(1) + unit;
|
||
}
|
||
let found = Array.from(list).some(li => li.dataset.cmd === cmd);
|
||
if (!found && id === 'ff') {
|
||
const li = document.createElement('li');
|
||
li.dataset.cmd = cmd;
|
||
const div = document.createElement('div');
|
||
div.textContent = cmd.split(',')[0].trim();
|
||
li.appendChild(div);
|
||
dropdown.querySelector('.align-list').appendChild(li);
|
||
}
|
||
current.textContent = id === 'ff'
|
||
? cmd.split(',')[0].trim()
|
||
: cmd;
|
||
current.dataset.cmd = cmd;
|
||
});
|
||
}
|
||
|
||
addEventListener("LoadeditorJs", function()
|
||
{
|
||
document.querySelectorAll("#panel .toolbar-group").forEach(g => {
|
||
const btn = g.querySelector(".toolbar-group-button");
|
||
const content = g.querySelector(".toolbar-group-content");
|
||
|
||
const toggle = () => {
|
||
const isHidden = content.style.display === "none";
|
||
content.style.display = isHidden ? "" : "none";
|
||
const hidden = content.style.display === "none";
|
||
g.classList.toggle("open", !hidden);
|
||
};
|
||
if (btn && content) {
|
||
btn.addEventListener("click", e => {
|
||
toggle();
|
||
});
|
||
g.addEventListener("click", e => {
|
||
if (e.target === g) toggle();
|
||
});
|
||
const isHidden = content.style.display === "none";
|
||
g.classList.toggle("open", !isHidden);
|
||
}
|
||
});
|
||
|
||
document.querySelectorAll('.swit').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
const target = document.getElementById(btn.id + '_d');
|
||
if (!target) return;
|
||
target.style.display =
|
||
(getComputedStyle(target).display === 'none') ? '' : 'none';
|
||
});
|
||
});
|
||
|
||
document.querySelectorAll('.align-dropdown').forEach(dropdown => {
|
||
const current = dropdown.querySelector('.current');
|
||
const list = dropdown.querySelector('.align-list');
|
||
current.addEventListener('click', () => {
|
||
list.style.display = list.style.display === 'block' ? 'none' : 'block';
|
||
if (list.style.display === 'none' && current.dataset.cmd) {
|
||
const cmd = current.dataset.cmd;
|
||
const iconEl = document.getElementById(cmd);
|
||
if (iconEl) iconEl.click();
|
||
}
|
||
});
|
||
document.addEventListener('click', e => {
|
||
if (!dropdown.contains(e.target)) list.style.display = 'none';
|
||
});
|
||
list.querySelectorAll('li').forEach(li => {
|
||
li.addEventListener('click', () => {
|
||
const icon = li.firstElementChild;
|
||
const cmd = icon.id;
|
||
current.dataset.cmd = cmd;
|
||
current.removeAttribute('style');
|
||
current.className = 'current editi editib pers';
|
||
current.classList.add(cmd);
|
||
list.style.display = 'none';
|
||
});
|
||
});
|
||
});
|
||
|
||
document.querySelectorAll('.align-dropdown-text').forEach(dropdown => {
|
||
const current = dropdown.querySelector('.current')
|
||
const list = dropdown.querySelector('.align-list')
|
||
dropdown.addEventListener('click', e => {
|
||
if (e.target.closest('.align-list')) return
|
||
list.style.display = list.style.display === 'block' ? 'none' : 'block'
|
||
})
|
||
document.addEventListener('click', e => {
|
||
if (!dropdown.contains(e.target)) list.style.display = 'none'
|
||
})
|
||
list.querySelectorAll('li').forEach(li => {
|
||
li.addEventListener('click', () => {
|
||
const cmd = li.dataset.cmd
|
||
current.innerHTML = li.querySelector('img')?.outerHTML || li.textContent
|
||
current.dataset.cmd = cmd
|
||
list.style.display = 'none'
|
||
const f = singleFormats.find(ff => ff.id === dropdown.id)
|
||
f.value = cmd
|
||
const sel = window.getSelection()
|
||
if (sel.rangeCount) {
|
||
const range = sel.getRangeAt(0)
|
||
if ([...document.querySelectorAll('.content')].some(c => c.contains(range.commonAncestorContainer))) {
|
||
singleApplyformat(range, f)
|
||
inter()
|
||
}
|
||
}
|
||
})
|
||
})
|
||
})
|
||
|
||
}, { once: true }); |