Files
utext/main_plugin/editor/editor.js
2025-07-27 18:47:50 +03:00

2189 lines
81 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

addEventListener("load", 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";
pict.src="../../img/img/net.jpg";
}
});
let editableElements;
let editMode = -1;
let editId = ['pluginDelete', 'titleEdit', 'pluginMove', 'elementEdit',
'editTableButtonAddLine', 'editTableButtonDeleteLine', 'editTableButtonAddColumn', 'editTableButtonDeleteColumn'] ;
function basisVis() {
editableElementsFun();
let basis3 = document.getElementById('basis3');
let sideFloatClass = basis3 ? basis3.querySelectorAll('[style*="visibility: visible;"]') : null;
if (!basis3 || !sideFloatClass || !editableElements || editableElements.length === 0) return;
elementsСhecked = [basis3, ...sideFloatClass, ...editableElements];
if (basis3.style.visibility === "hidden") {
basis3.style.visibility = "visible";
sessionStorage.setItem('basis3_visibility', 'visible');
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')
} else {
basis3.style.visibility = "hidden";
sessionStorage.setItem('basis3_visibility', 'hidden');
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='')
}
}
addEventListener("DOMContentLoaded", function()
{
let te=document.getElementById("tex"); // Ссылка на текстовое поле
let tex=document.getElementById("tex"); // Ссылка на стили текстового поля
if (document.getElementById("content") == "") {
te.value=document.getElementById("content").innerHTML; // Передача данных из области контента в текстовое поле
}
// Символы клавиш со знаками препинания или перевода строки
let symb = ["Enter", "!", "?", ";", ":", ",", ".", " ", "-", "'", "\"", "(", ")", "{", "}", "[", "]", "_", "&", "/", "\\", "*"];
// Запись в память введенного текста при нажатии клавиши со знаком препинания или перевода строки
if (document.getElementById("content")) {
document.getElementById("content").addEventListener("keyup", function(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';
}
});
});
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 formData = new FormData();
formData.append('userImg', input.files[0]);
formData.append('handleRequestAction', 'uploadUserImage');
handleJsonRpcRequest('uploadUserImage', formData, 1)
.then(result => {
if (result.error) {
messageFunction("{{img_upload_error}}");
} else {
var img = document.createElement("img");
img.src = result;
img.style.cssText = "float: left; margin: 10px; width: 250px; border: 0; overflow: hidden;";
insertNodeAtSelection(img);
}
})
.catch(() => {
messageFunction("{{img_upload_error}}");
});
}
document.body.removeChild(input);
});
input.click();
break;
case "imgManager":
window.managerDataAction = "selectImgForm";
createAjaxRequest({ handleRequestAction: 'nameUser' }, function(response) {
managerData("/img/users_img/" + response.user);
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;
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);
function saveChangesHow() {
window.managerDataAction = "saveHow";
managerData("/content");
managerDiv.style.visibility = "visible";
document.getElementById("settingsMain_d").style.visibility="hidden";
}
// Открытие страницы
document.getElementById("openPage").addEventListener("click", openPageFun);
function openPageFun() {
window.managerDataAction = "openPage";
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.getElementById("content").innerHTML = "";
document.getElementById("mainTitle").innerHTML = "<i>{{new_file}}!</i>";
window.newPageFunValue = "newPage";
document.getElementById("settingsMain_d").style.visibility="hidden";
}
// Сбор новых элементов
function editableElementsFun() {
let content = document.getElementById('content');
editableElements = document.querySelectorAll('.pluginEditable');
editableElements = Array.from(editableElements);
editableElements.push(content);
editableElements.forEach(function(element) {
if (!element) {
console.log("Element " + element + " not found.");
return;
}
});
}
window.editableElementsFun = editableElementsFun;
// Сохранение выделение
document.addEventListener('selectionchange', () => {
const content = document.getElementById('content');
const sel = window.getSelection();
if (!sel.rangeCount) return;
const range = sel.getRangeAt(0);
const startNode = range.startContainer;
if (content.contains(startNode)) {
saveSelection();
}
});
let savedSel = null;
function saveSelection() {
const content = document.getElementById('content');
const sel = window.getSelection();
if (!sel.rangeCount) return;
const range = sel.getRangeAt(0);
if (!content.contains(range.commonAncestorContainer)) return;
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 };
}
function restoreSelection() {
if (!savedSel) return;
const content = document.getElementById('content');
const { start, end } = savedSel;
let charIndex = 0;
const range = document.createRange();
range.setStart(content, 0);
range.collapse(true);
try {
(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('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'); };
function pluginFun(action, side) {
let data = `action=${encodeURIComponent(action)}&side=${encodeURIComponent(side)}&pluginName=`;
if (action === 'add') {
let xhr = createXHR(function () {
let plugins = xhr.responseText.trim().split("\n");
let pluginAddSideName = document.getElementById('pluginAdd' + (side === 'left' ? 'Left' : 'Right') + 'Name');
pluginAddSideName.innerHTML = '';
plugins.forEach(plugin => {
let option = document.createElement('option');
option.value = plugin;
option.textContent = plugin;
pluginAddSideName.appendChild(option);
});
});
xhr.send(data+'&handleRequestAction=managerPlugin');
}
}
/* 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');
let data = `action=${encodeURIComponent("add")}&side=$&pluginName=`;
let xhr = createXHR(function () {
let plugins = xhr.responseText.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);
});
});
xhr.send(data+'&action=funcEditor');
}
}
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 (pluginTitle === "") {
messageFunction("{{plugin_title_empty_error}}");
return;
} */
if (action === 'create') {
let checkData = `action=check&pluginName=${encodeURIComponent(pluginName)}`;
let checkXHR = createXHR(function () {
if (checkXHR.responseText.trim() === "exists") {
messageFunction(pluginName + "{{plugin_name_exists_suffix}}");
} else {
sendRequest('create', side_float, pluginName, pluginTitle, pluginText);
}
});
checkXHR.send(checkData+'&handleRequestAction=managerPlugin');
} else {
pluginHtml('add', pluginName, side_float, pluginTitle);
inter();
}
document.getElementById(pluginAddSide_d).style.visibility = "hidden";
}
function sendRequest(action, side_float, pluginName, pluginTitle, pluginText) {
let xhr = createXHR(function () {
if (xhr.responseText.trim() === "Plugin created: " + pluginName) {
pluginHtml('create', pluginName, side_float, pluginTitle);
inter();
}
});
let data = `action=${encodeURIComponent(action)}&side=${encodeURIComponent(side_float)}&pluginName=${encodeURIComponent(pluginName)}`;
xhr.send(data+'&handleRequestAction=managerPlugin');
}
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') {
let xhr = createXHR(function () {
let pluginContent = xhr.responseText;
bcont.innerHTML = pluginContent;
});
let data = `pluginName2=${encodeURIComponent(pluginName)}`;
xhr.send(data+'&handleRequestAction=loadPlugin');
} 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) {
let target = event.target;
let pluginElement = target.closest('.plugin-url');
if (pluginElement) {
if (confirm("{{delete_plugin_confirm}}")) {
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 !== "") {
let xhr = createXHR(function () {
let responseText = xhr.responseText;
console.log(responseText);
editTitle.innerHTML = newTitle;
messageFunction("{{title_saved}}");
inter();
});
let data = `newTitle=${encodeURIComponent(newTitle)}&whichTitle=${encodeURIComponent(whichTitle)}
&side=${encodeURIComponent(classOfThirdDiv)}&pluginNumber=${encodeURIComponent(indexOfSecondDiv)}`;
xhr.send(data+'&handleRequestAction=newTitle');
} 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;
}
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();
}
}); //addEventListener("load", function()'
addEventListener("load", 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();
});
});
/* добовление функций */
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' }
];
const divFormats = [
{ id: 'equal', style: { textAlign: 'left' } },
{ id: 'equac', style: { textAlign: 'center' } },
{ id: 'equar', style: { textAlign: 'right' } },
{ id: 'equaj', style: { textAlign: 'justify'} }
];
const listFormats = [
{ id: 'listNone', style: { listStyleType: 'none' } },
{ id: 'listDots', style: { listStyleType: 'disc' } },
{ id: 'listNumbers', style: { listStyleType: 'decimal' } },
{ id: 'listLetters', style: { listStyleType: 'lower-alpha'} }
];
const singleFormats = [
{ id: 'ff', prop: 'font-family'},
{ id: 'fs', prop: 'font-size'}
];
const specialFormats = ['butlink', 'linkdel', 'forma', 'col', 'backgr'];
addEventListener("load", function() {
const content = document.getElementById('content');
simpleFormats.forEach(f => {
document.getElementById(f.id).addEventListener('click', () => {
const sel = window.getSelection();
if (!sel.rangeCount) return;
const range = sel.getRangeAt(0);
if (!content.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 (!content.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 (!content.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 (!content.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.contains(range.commonAncestorContainer)) return;
window[f + 'Fun'](range);
inter();
});
});
const events = ['pointerup','keyup','input','focus','blur','click'];
events.forEach(evt => {
if (!content) return;
content.addEventListener(evt, () => {
updateToolbarStyles();
updateSingleSelectors();
});
});
});
/////////////////// Начало блока, выполняющего навигацию по внесенным изменениям ====================
let arr = []
let currentIndex = 0
function inter() {
const editable = document.getElementById("content")
if (editable) {
let currentContent = editable.innerHTML
if (currentContent !== arr[currentIndex]) {
currentIndex++
arr = arr.slice(0, currentIndex)
arr.push(currentContent)
}
}
}
if (document.getElementById("content")) {
arr[0] = document.getElementById("content").innerHTML
}
document.getElementById("forw").addEventListener("click", function() {
if (currentIndex < arr.length - 1) {
currentIndex++
const editable = document.getElementById("content")
editable.innerHTML = arr[currentIndex]
editable.setAttribute("contenteditable", "true")
}
})
document.getElementById("bac").addEventListener("click", function() {
if (currentIndex > 0) {
currentIndex--
const editable = document.getElementById("content")
editable.innerHTML = arr[currentIndex]
editable.setAttribute("contenteditable", "true")
}
})
/////////////////// Конец блока, выполняющего навигацию по внесенным изменениям ====================
/* общие функции */
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);
}
/* simpleFormats */
function simpleApplyformat(range, format) {
const span = document.createElement('span');
Object.assign(span.style, format.style);
applyformat(range, () => span.cloneNode());
}
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();
});
}
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;
}
}
/* divFormats */
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(content.children).forEach(child => {
if (intersects(child)) externals.add(child);
});
externals.forEach(div => {
div.style.textAlign = style.textAlign;
});
}
/* listApplyformat */
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(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 {
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);
}
});
}
}
/* singleFormats */
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;
});
}
/* specialFormats */
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();
}
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;
}
}
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(content.children).forEach(child => {
if (intersects(child)) externals.add(child);
});
externals.forEach(el => {
el.style.textAlign = '';
});
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;
}
}
let currentFormat = null;
let currentRange = null;
function colFun(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');
}
function backgrFun(range) {
currentFormat = { prop: 'background-color', test: v => !!v };
currentRange = range;
const app = document.querySelector('.pcr-app');
app.style.marginLeft = '-29px';
app.style.left = '';
1,
app.classList.remove('hide');
}
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('DOMContentLoaded', () => {
document.addEventListener('pointerdown', e => {
if (!e.target.closest('.pcr-app') && !e.target.closest('#col') && !e.target.closest('#backgr')) {
setColorFun();
}
});
});
/* определение стилей */
const toolbarButtons = ['bol','ital','under','strik','sup','sub'];
const bgColors = {
none: 'rgb(255 255 255)',
partial: 'rgb(231 231 231)',
full: 'rgb(203 203 203)'
};
function detectFormatState(format) {
const sel = window.getSelection();
if (!sel.rangeCount) return 'none';
const range = sel.getRangeAt(0);
if (!content.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 && cur !== content) {
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';
}
function updateToolbarStyles() {
toolbarButtons.forEach(id => {
const btn = document.getElementById(id);
const state = detectFormatState(id);
btn.style.backgroundColor = bgColors[state];
});
}
const singleSelectors = ['ff','fs'];
function detectSingleState(format) {
const sel = window.getSelection();
if (!sel.rangeCount) return '';
const range = sel.getRangeAt(0);
if (!content.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] : '';
}
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("load", function()
{
document.querySelectorAll("#panel .toolbar-group").forEach(g => {
const btn = g.querySelector(".toolbar-group-button");
const content = g.querySelector(".toolbar-group-content");
if (btn && content) {
btn.addEventListener("click", () => {
const isHidden = content.style.display === "none";
content.style.display = isHidden ? "" : "none";
if (btn && content) {
const isHidden = content.style.display === "none";
g.classList.toggle("open", !isHidden);
}
});
if (btn && content) {
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 (content.contains(range.commonAncestorContainer)) {
singleApplyformat(range, f)
inter()
}
}
})
})
})
});