Files
slava.home/main_plugin/site_tree/site_tree.js

1031 lines
42 KiB
JavaScript
Raw Permalink 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.

/**
* @file site_tree.js
* @brief Основной файл site_tree, управляет древовидной структурой сайта
*/
/** @brief Счетчик для уникальных id элементов дерева */
let idCounter = 0;
siteTreeGeneration();
/** @brief Генерация HTML древа сайта */
function siteTreeGeneration() {
jsonrpcRequest("getSiteTree", {}).then(data => {
let treeContainer = document.getElementById('treeTableDiv');
if (!document.getElementById('treeTableDiv')) return;
treeContainer.innerHTML = generateTreeHtml(data, "");
let firstSpan = document.getElementById('treeTableDiv').querySelector('span');
if (!treeContainer.innerHTML.includes('background-color: #e5f0ff;')) {
firstSpan.style.backgroundColor = '#e5f0ff';
}
});
idCounter = 0;
}
window.siteTreeGeneration = siteTreeGeneration;
/** @brief Выбранный элемент дерева */
let selectedTreeItem = "";
/** @brief Дополнительный выбранный элемент дерева для вставки данных */
let selectedTreeItemAdd = "";
/** @brief Флаг первого <li> для особого выделения */
let firstLi = true;
/** @brief Генерация HTML дерева рекурсивно
* @param items массив объектов страницы
* @param checkChildren флаг проверки дочерних элементов
* @return сгенерированный HTML дерева
*/
function generateTreeHtml(items, checkChildren) {
let html = '<ul style="margin-top: 10px; margin-bottom: 10px; list-style-type: none;">';
items.forEach(item => {
if (!item.name && item.tag == "sitename" && checkChildren == "") {
html += generateTreeHtmlSitename(item, "treeHtmlSitename");
return;
}
if (!item.name && item.tag == "slogan" && checkChildren == "") {
html += generateTreeHtmlSitename(item, "treeHtmlSlogan");
return;
}
let hasChildren = item.children && item.children.length;
let isOpen = (item.isOpen || item.tag === 'index') ? 'block' : 'none';
let markerText = hasChildren ? (isOpen === 'block' ? '▼' : '►') : '■';
let style = item.isOpen ? 'background-color: #e5f0ff;' : '';
id = "";
if (firstLi == true) {
id = 'id="treeHtmlIndex"';
firstLi = false;
}
html += `<li ${id} style="position: relative; margin: 0px 0px 8px -20px;">`;
html += `<span class="tree-item" style="cursor: pointer; ${style} padding: 3px 6px 3px 3px;" onclick="toggleChildren(this)">`;
html += `<span class="tree-marker">${markerText}</span> <span class="tree-text">${item.tag} <span class="tree-text-name">&nbsp;(${item.title})</span></span>`;
html += `<div class="tree-data" style="display: none;">`;
html += `url: ${item.url}<br>`;
html += `title: ${item.title}<br>`;
html += `name: ${item.name}<br>`;
html += `template: ${item.template}<br>`;
html += `PageMenu: ${item.PageMenu}<br>`;
html += `users: ${item.users}<br>`;
html += `group: ${item.group}<br>`;
html += `plugins: ${item.plugins}<br>`;
let now = new Date();
let pad = n => n < 10 ? '0' + n : n;
let nowStr = `${now.getFullYear()}-${pad(now.getMonth()+1)}-${pad(now.getDate())}T${pad(now.getHours())}:${pad(now.getMinutes())}`;
if (item.news) {
let newsData = item.news.split(',');
let range = newsData[0] || '';
let blocks = newsData.slice(1);
html += `news: <div><input type="checkbox" class="news-checkbox" checked>show in news</div>`;
let [start, end] = range.split('/');
let fmt = s => {
let p = s.split('.');
return `${p[0]}-${p[1]}-${p[2]}T${p[3]}:${p[4]}`;
};
html += `<div><input type="datetime-local" class="news-start" value="${fmt(start)}">`;
html += `<input type="datetime-local" class="news-end" value="${fmt(end)}"></div>`;
html += `<div>${['left','center','right'].map(b => `<label><input type="checkbox" value="${b}"${blocks.includes(b)?' checked':''}>${b}</label>`).join(' ')}</div>`;
} else {
html += `news: <div><input type="checkbox" class="news-checkbox">show in news</div>`;
html += `<div><input type="datetime-local" class="news-start" value="${nowStr}">`;
html += `<input type="datetime-local" class="news-end" value="${nowStr}"></div>`;
html += `<div>${['left','center','right'].map(b => `<label><input type="checkbox" value="${b}">${b}</label>`).join(' ')}</div>`;
}
html += `</div>`;
html += `</span>`;
if (hasChildren) {
html += `<div class="details" style="display: ${isOpen};">` + generateTreeHtml(item.children, "children") + `</div>`;
}
html += `</li>`;
if (style) {
selectedTreeItemAdd = `url: ${item.url}<br>title: ${item.title}<br>name: ${item.name}<br>template: ${item.template}<br>PageMenu: ${item.PageMenu}<br>users: ${item.users}<br>group: ${item.group}<br>plugins: ${item.plugins}`;
}
});
html += `</ul>`;
if (checkChildren == "") {
firstLi = true;
}
moveTreePage();
return html;
}
/** @brief Генерация HTML для элементов типа sitename или slogan
* @param item объект элемента
* @param id id для span
* @return HTML строки элемента
*/
function generateTreeHtmlSitename(item, id) {
let html = `<li style="position: relative; margin: 0px 0px 8px -20px;">`;
html += `<span id="${id}" class="tree-item" style="cursor: pointer; padding: 3px 6px 3px 3px;" onclick="toggleChildren(this)">`;
html += `<span class="tree-marker">${item.tag}:</span> <span class="tree-text">${item.content}</span>`;
html += `</span>`;
html += `</li>`;
return html;
}
/* перемещение страниц */
/** @brief Перемещаемый элемент дерева при drag & drop */
let draggedItem = null;
/** @brief Текущий выделенный элемент дерева */
let selectedItem = null;
/** @brief Смещение Y при перетаскивании */
let offsetY = 0;
/** @brief Начальная координата X при перетаскивании */
let startX = 0;
/** @brief Проверка, является ли child потомком parent
* @param parent родительский элемент
* @param child проверяемый элемент
* @return true если child потомок parent
*/
function isDescendant(parent, child) {
while (child) {
if (child === parent) return true;
child = child.parentNode;
}
return false;
}
/** @brief Сброс выделения выбранного элемента */
function clearSelection() {
if (selectedItem) {
selectedItem.style.outline = '';
selectedItem = null;
}
}
/** @brief Обработка нажатия на элемент дерева для начала перемещения
* @param event событие pointerdown
*/
function moveTreePagePointerDown(event) {
if (window.treeSettingsMode != '') return;
let treeTableDiv = document.getElementById('treeTableDiv');
let li = event.target.closest('li');
if (li && event.button === 0) {
if (li.id === 'treeHtmlIndex') return;
let treeItem = event.target.closest('.tree-item');
if (!treeItem) return;
if (selectedItem && selectedItem !== li) {
selectedItem.style.outline = '';
}
selectedItem = li;
selectedItem.style.outline = '1px dashed rgb(0,0,0)';
draggedItem = li;
offsetY = event.clientY - treeItem.getBoundingClientRect().top;
li.style.opacity = '0.5';
event.preventDefault();
} else {
clearSelection();
}
}
/** @brief Обработка нажатия вне дерева для очистки выделения
* @param event событие pointerdown
*/
function moveTreePageDocumentPointerDown(event) {
const treeTableDiv = document.getElementById('treeTableDiv');
if (treeTableDiv && !treeTableDiv.contains(event.target)) {
clearSelection();
}
}
/** @brief Обработка движения мыши для перемещения элементов дерева
* @param event событие pointermove
*/
function moveTreePageDocumentPointerMove(event) {
if (window.treeSettingsMode != '') return;
let treeTableDiv = document.getElementById('treeTableDiv');
if (draggedItem && event.target.tagName !== "LI" && event.target.tagName !== "UL") {
let elemBelow = document.elementFromPoint(event.clientX, event.clientY);
let liBelow = elemBelow ? elemBelow.closest('li') : null;
if (liBelow && liBelow !== draggedItem && !isDescendant(draggedItem, liBelow)) {
let rect = liBelow.getBoundingClientRect();
let isTargetIndex = liBelow.parentElement?.closest('#treeHtmlIndex') !== null && liBelow.parentElement?.closest('#treeTableDiv')?.querySelector('#treeHtmlIndex')?.contains(liBelow.parentElement);
if (isTargetIndex) {
let parentDetails = draggedItem.parentElement.closest('.details');
if (event.clientY < rect.top + rect.height / 2) {
liBelow.parentNode.insertBefore(draggedItem, liBelow);
} else {
liBelow.parentNode.insertBefore(draggedItem, liBelow.nextSibling);
}
if (parentDetails) {
let parentUl = parentDetails.querySelector('ul');
if (parentUl && parentUl.children.length === 0) {
let parentLi = parentDetails.closest('li');
parentDetails.remove();
if (parentLi) {
let marker = parentLi.querySelector('.tree-marker');
if (marker) marker.textContent = '■';
}
}
}
}
}
}
}
/** @brief Обработка отпускания мыши для завершения перемещения
*/
function moveTreePageDocumentPointerUp() {
if (window.treeSettingsMode != '') return;
if (draggedItem) {
draggedItem.style.opacity = '';
draggedItem = null;
}
}
/** @brief Обработка движения мыши внутри дерева для вложения элементов
* @param event событие pointermove
*/
function moveTreePageTreePointerMove(event) {
if (window.treeSettingsMode != '') return;
let li = event.target.closest('li');
if (li && event.button === 0 && draggedItem) {
let treeItem = event.target.closest('.tree-item');
if (!treeItem) return;
startX = event.clientX - treeItem.getBoundingClientRect().left;
let upperLi = draggedItem.previousElementSibling;
if (upperLi) {
if (startX > 60) {
let details = upperLi.querySelector('.details');
if (!details) {
details = document.createElement('div');
details.className = 'details';
let ul = document.createElement('ul');
ul.setAttribute('style', 'margin-top: 10px; margin-bottom: 10px; list-style-type: none;');
details.appendChild(ul);
upperLi.appendChild(details);
} else {
if (details.style.display === 'none') {
details.style.display = 'block';
}
}
let marker = upperLi.querySelector('.tree-marker');
if (marker) {
marker.textContent = '▼';
}
draggedItem._attachedTo = upperLi;
let detailsUl = details.querySelector('ul');
if (detailsUl && draggedItem.parentNode !== detailsUl) {
detailsUl.appendChild(draggedItem);
}
} else if (startX < 20) {
let details = upperLi.querySelector('.details');
if (details && details.contains(draggedItem)) {
let parentUl = upperLi.parentNode;
parentUl.insertBefore(draggedItem, upperLi.nextSibling);
delete draggedItem._attachedTo;
let detailsUl = details.querySelector('ul');
if (detailsUl && detailsUl.children.length === 0) {
details.style.display = 'none';
let marker = upperLi.querySelector('.tree-marker');
if (marker) {
marker.textContent = '►';
}
}
}
}
}
}
}
/** @brief Обработка нажатий клавиш для управления выбранным элементом дерева
* @param event событие keydown
*/
function moveTreePageDocumentKeyDown(event) {
if (!selectedItem || window.treeSettingsMode != '') return;
let treeIndex = document.getElementById('treeHtmlIndex');
if (!treeIndex) return;
if (!treeIndex.contains(selectedItem)) return;
let parentUl = selectedItem.parentNode;
if (!treeIndex.contains(parentUl)) return;
switch (event.key) {
case 'ArrowUp': {
let prev = selectedItem.previousElementSibling;
if (prev && treeIndex.contains(prev)) {
parentUl.insertBefore(selectedItem, prev);
event.preventDefault();
}
break;
}
case 'ArrowDown': {
let next = selectedItem.nextElementSibling;
if (next && treeIndex.contains(next)) {
parentUl.insertBefore(next, selectedItem);
event.preventDefault();
}
break;
}
case 'ArrowRight': {
let prev = selectedItem.previousElementSibling;
if (!prev || !treeIndex.contains(prev)) break;
let details = prev.querySelector('.details');
if (!details) {
details = document.createElement('div');
details.className = 'details';
let ul = document.createElement('ul');
ul.style.marginTop = '10px';
ul.style.marginBottom = '10px';
ul.style.listStyleType = 'none';
details.appendChild(ul);
prev.appendChild(details);
} else if (details.style.display === 'none') {
details.style.display = 'block';
}
let marker = prev.querySelector('.tree-marker');
if (marker) marker.textContent = '▼';
let ul = details.querySelector('ul');
if (ul && selectedItem.parentNode !== ul && treeIndex.contains(ul)) {
ul.appendChild(selectedItem);
event.preventDefault();
}
break;
}
case 'ArrowLeft': {
let parentDetails = selectedItem.parentNode.closest('.details');
if (!parentDetails) break;
let parentLi = parentDetails.closest('li');
if (!parentLi) break;
let grandParentUl = parentLi.parentNode;
if (!treeIndex.contains(grandParentUl)) break;
grandParentUl.insertBefore(selectedItem, parentLi.nextSibling);
let ul = parentDetails.querySelector('ul');
if (ul.children.length === 0) {
parentDetails.remove();
let marker = parentLi.querySelector('.tree-marker');
if (marker) marker.textContent = '■';
}
event.preventDefault();
break;
}
}
}
/** @brief Настройка обработчиков событий для перемещения элементов дерева
*/
function moveTreePage() {
const treeTableDiv = document.getElementById('treeTableDiv');
if (!treeTableDiv) return;
treeTableDiv.removeEventListener('pointerdown', moveTreePagePointerDown);
document.removeEventListener('pointerdown', moveTreePageDocumentPointerDown);
document.removeEventListener('pointermove', moveTreePageDocumentPointerMove);
document.removeEventListener('pointerup', moveTreePageDocumentPointerUp);
treeTableDiv.removeEventListener('pointermove', moveTreePageTreePointerMove);
document.removeEventListener('keydown', moveTreePageDocumentKeyDown);
treeTableDiv.addEventListener('pointerdown', moveTreePagePointerDown);
document.addEventListener('pointerdown', moveTreePageDocumentPointerDown);
document.addEventListener('pointermove', moveTreePageDocumentPointerMove);
document.addEventListener('pointerup', moveTreePageDocumentPointerUp);
treeTableDiv.addEventListener('pointermove', moveTreePageTreePointerMove);
document.addEventListener('keydown', moveTreePageDocumentKeyDown);
}
addEventListener("Loadsite_treeJs", function() {
movementMenu("treeDiv");
movementMenu("treeProperties");
/* сохронения древа */
let treeSettingsSaveId = document.getElementById("treeSettingsSave");
treeSettingsSaveId.addEventListener('click', saveTree);
function saveTree() {
let treeTableDiv = document.getElementById('treeTableDiv');
let ul = treeTableDiv.querySelector('ul');
let treeData = ul ? parseUl(ul) : [];
let siteNameElement = document.getElementById("treeHtmlSitename");
let siteName = siteNameElement ? siteNameElement.querySelector('.tree-text').textContent.trim() : '';
let sloganElement = document.getElementById("treeHtmlSlogan");
let slogan = sloganElement ? sloganElement.querySelector('.tree-text').textContent.trim() : '';
let fullData = { sitename: siteName, slogan: slogan, children: treeData };
jsonrpcRequest("saveSiteTree", { data: fullData }).then(response => {
console.log(response);
});
}
function parseUl(ul) {
let result = [];
let items = ul.children;
for (let item of items) {
let span = item.querySelector('.tree-item .tree-text');
let textName = item.querySelector('.tree-text-name');
let dataDiv = item.querySelector('.tree-data');
let childrenUl = item.querySelector('.details > ul');
if (span && dataDiv) {
let data = parseDataDiv(dataDiv);
let mainText = span.childNodes[0].textContent.trim();
let extraText = textName ? textName.textContent.trim() : "";
data['tag'] = mainText;
data['name'] = mainText + (extraText ? " " + extraText : "");
if (childrenUl) data['children'] = parseUl(childrenUl);
result.push(data);
}
}
return result;
}
function parseDataDiv(div) {
let data = {};
let lines = div.innerHTML.split(/<br\s*\/?>/i);
for (let line of lines) {
let parts = line.split(': ');
if (parts.length === 2) data[parts[0].trim()] = parts[1].trim();
}
let cb = div.querySelector('.news-checkbox');
if (cb) {
if (cb.checked) {
let start = div.querySelector('.news-start').value;
let end = div.querySelector('.news-end').value;
let blocks = Array.from(div.querySelectorAll('input[type="checkbox"][value]:checked'))
.map(x => x.value);
let fmt = s => s.replace(/[-:T]/g, '.');
data.news = `${fmt(start)}/${fmt(end)}${blocks.length ? ',' + blocks.join(',') : ''}`;
} else {
data.news = '';
}
}
return data;
}
/* окно настроек древа */
let targetTreeItem = "";
let treeSettingsDiv = document.getElementById('treeSettings');
function treeSettings() {
const treeDivDiv = document.getElementById('treeDiv');
if (!treeDivDiv) return;
if (window.treeSettingsMode == 'linkFromPage') {
document.getElementById('treeTopTitle').innerHTML = "{{select_page_for_link}}";
document.getElementById('treeSettingsSave').style.display = "none";
} else {
document.getElementById('treeTopTitle').innerHTML = "{{tree_site_title}}";
document.getElementById('treeSettingsSave').style.display = "block";
}
function showTreeSettings(event) {
event.preventDefault();
let treeItem = event.target.closest('.tree-item');
targetTreeItem = treeItem ? treeItem : "";
treeSettingsDiv.style.left = `${touchX}px`;
treeSettingsDiv.style.top = `${touchY}px`;
document.getElementById('treeSettingsAdd').style.display = '';
document.getElementById('treeSettingsPaste').style.display = '';
document.getElementById('treeSettingsCopy').style.display = '';
document.getElementById('treeSettingsRename').style.display = '';
document.getElementById('treeSettingsProperties').style.display = '';
document.getElementById('treeSettingsDelete').style.display = '';
document.getElementById('treeSettingsChoose').style.display = '';
treeSettingsDiv.style.visibility = targetTreeItem ? "visible" : "hidden";
let tag = targetTreeItem instanceof Element
? targetTreeItem.querySelector('.tree-text')?.textContent.trim()
: null;
if (tag == "index" && !targetTreeItem.closest('li li')) {
document.getElementById('treeSettingsRename').style.display = 'none';
document.getElementById('treeSettingsDelete').style.display = 'none';
}
if (targetTreeItem) {
let firstId = targetTreeItem.closest('li')?.firstElementChild?.id;
if (firstId == "treeHtmlSitename" || firstId == "treeHtmlSlogan") {
['Add','Copy','Paste','Delete','Properties','Choose'].forEach(id=>{
document.getElementById('treeSettings'+id).style.display = 'none';
});
}
}
if (selectedTreeItem == "") {
document.getElementById('treeSettingsPaste').style.display = 'none';
}
document.addEventListener('pointerdown', function hideMenu(e) {
if (!treeSettingsDiv.contains(e.target)) {
treeSettingsDiv.style.visibility = "hidden";
document.removeEventListener('pointerdown', hideMenu);
}
});
if (window.treeSettingsMode == 'linkFromPage') {
['Add','Copy','Paste','Delete','Rename','Properties'].forEach(id=>{
document.getElementById('treeSettings'+id).style.display = 'none';
});
} else {
document.getElementById('treeSettingsChoose').style.display = 'none';
}
if ([].slice.call(document.getElementById('treeSettingsDiv').children).every(el=>
getComputedStyle(el).display === 'none'
)) {
treeSettingsDiv.style.visibility = 'hidden';
}
}
function setupTreeSettingsHandler(){
const treeDiv=document.getElementById('treeDiv')
if(!treeDiv) return
treeDiv.removeEventListener('click',showTreeSettings)
treeDiv.oncontextmenu=null
if(isPhone){
touchLong(treeDiv,showTreeSettings)
}else{
treeDiv.oncontextmenu=showTreeSettings
}
}
setupTreeSettingsHandler();
window.addEventListener('resize', setupTreeSettingsHandler);
}
window.treeSettings = treeSettings;
/* кнопки окна настроек древа */
/* кнопки добовление страниц / начало */
let treeSettingsAddId = document.getElementById('treeSettingsAdd');
treeSettingsAddId.addEventListener('click', treeSettingsAddFun);
async function treeSettingsAddFun() {
if (window.newPageFunValue == "newPage") {
document.getElementById("saveHow").click();
messageFunction("{{save_new_page}}");
return;
}
let container = getContainer();
let pageUrl = selectedTreeItemAdd;
messageQueue.push("{{enter_tag_for_new_page}}");
let treeText = await messageCreateInput();
treeText = treeText ? treeText.trim() : "";
if (!/^[A-Za-z0-9]+$/.test(treeText)) {
messageFunction("{{tag_only_english_letters}}");
return;
}
if (treeText !== "") {
let exists = false;
let lis = container.querySelectorAll('li');
lis.forEach(function(li) {
let txt = li.querySelector('.tree-text');
if (txt && txt.textContent.trim() === treeText) {
exists = true;
}
});
if (exists) {
messageFunction("{{tag_already_exists}}");
return;
}
let newItem = createNewTreeItem(pageUrl, treeText);
let newLi = document.createElement('li');
newLi.style.position = 'relative';
newLi.style.margin = '0px 0px 8px -20px';
newLi.appendChild(newItem);
container.appendChild(newLi);
if (targetTreeItem) {
targetTreeItem.querySelector('.tree-marker').textContent = '▼';
}
}
treeSettingsDiv.style.visibility = "hidden";
}
let treeSettingsPasteId = document.getElementById('treeSettingsPaste');
treeSettingsPasteId.addEventListener('click', treeSettingsPasteFun);
async function treeSettingsPasteFun() {
let container = getContainer();
let clonedItem = selectedTreeItem.cloneNode(true);
messageQueue.push("{{enter_tag_for_new_page}}");
let treeText = await messageCreateInput();
treeText = treeText ? treeText.trim() : "";
if (!/^[A-Za-z0-9]+$/.test(treeText)) {
messageFunction("{{tag_only_english_letters}}");
return;
}
if (treeText !== "") {
let exists = false;
let lis = container.querySelectorAll('li');
lis.forEach(function(li) {
let txt = li.querySelector('.tree-text');
if (txt && txt.textContent.trim() === treeText) {
exists = true;
}
});
if (exists) {
messageFunction("{{tag_already_exists}}");
return;
}
let textSpan = clonedItem.querySelector('.tree-text');
let extractedTitle = selectedTreeItem.querySelector('.tree-data').innerHTML.match(/title:\s*([^<]+)/)?.[1].trim();
textSpan.innerHTML = `${treeText} <span class="tree-text-name">&nbsp;(${extractedTitle})</span>`;
let newLi = document.createElement('li');
newLi.style.position = 'relative';
newLi.style.margin = '0px 0px 8px -20px';
newLi.appendChild(clonedItem);
container.appendChild(newLi);
if (targetTreeItem) {
targetTreeItem.querySelector('.tree-marker').textContent = '▼';
}
}
treeSettingsDiv.style.visibility = "hidden";
}
function createNewTreeItem(pageUrl, treeText) {
let newItem = document.createElement('span');
newItem.className = 'tree-item';
newItem.style.cursor = 'pointer';
newItem.style.padding = '3px 6px 3px 3px';
let marker = document.createElement('span');
marker.className = 'tree-marker';
marker.textContent = '■';
let textSpan = document.createElement('span');
textSpan.className = 'tree-text';
let extractedTitle = selectedTreeItemAdd.match(/title:\s*([^<]+)/)?.[1].trim() || "";
textSpan.innerHTML = `${treeText} <span class="tree-text-name">&nbsp;(${extractedTitle})</span>`;
let dataDiv = document.createElement('div');
dataDiv.className = 'tree-data';
dataDiv.style.display = 'none';
dataDiv.innerHTML = `${pageUrl}`;
newItem.appendChild(marker);
newItem.insertAdjacentText('beforeend', ' ');
newItem.appendChild(textSpan);
newItem.appendChild(dataDiv);
newItem.setAttribute('onclick', 'toggleChildren(this)');
return newItem;
}
function getContainer() {
let container;
if (targetTreeItem) {
let li = targetTreeItem.closest('li');
let details = li.querySelector('.details');
if (!details) {
details = document.createElement('div');
details.className = 'details';
details.style.display = 'block';
li.appendChild(details);
}
let detailsUl = details.querySelector('ul');
if (!detailsUl) {
detailsUl = document.createElement('ul');
detailsUl.style.marginTop = '10px';
detailsUl.style.marginBottom = '10px';
detailsUl.style.listStyleType = 'none';
details.appendChild(detailsUl);
}
container = detailsUl;
} else {
let treeTableDiv = document.getElementById('treeTableDiv');
let mainUl = treeTableDiv.querySelector('ul');
if (!mainUl) {
mainUl = document.createElement('ul');
mainUl.style.marginTop = '10px';
mainUl.style.marginBottom = '10px';
mainUl.style.listStyleType = 'none';
treeTableDiv.appendChild(mainUl);
}
container = mainUl;
}
return container;
}
/* кнопки добовление страниц / конец */
let treeSettingsCopyId = document.getElementById('treeSettingsCopy');
treeSettingsCopyId.addEventListener('click', treeSettingsCopyFun);
function treeSettingsCopyFun() {
selectedTreeItem = targetTreeItem.cloneNode(true);
selectedTreeItem.querySelector('.tree-marker').textContent = '■';
if (selectedTreeItem.classList.contains('tree-item')) {
selectedTreeItem.style.backgroundColor = '';
} else {
let treeItem = selectedTreeItem.querySelector('.tree-item');
if (treeItem) treeItem.style.backgroundColor = '';
}
treeSettingsDiv.style.visibility = "hidden";
}
let treeSettingsRenameId = document.getElementById('treeSettingsRename');
treeSettingsRenameId.addEventListener('click', treeSettingsRenameFun);
async function treeSettingsRenameFun() {
if (targetTreeItem) {
let li = targetTreeItem.closest('li');
if (li) {
let treeText = li.querySelector('.tree-text');
if (treeText) {
let firstTextNode = treeText.firstChild;
let currentName = firstTextNode.nodeValue.trim();
messageQueue.push("{{enter_new_name}}");
let newText = await messageCreateInput();
if (newText !== null) {
newText = newText.trim();
if (!/^[A-Za-z0-9]+$/.test(newText)) {
messageFunction("{{name_only_english_letters}}");
return;
}
firstTextNode.nodeValue = newText + ' ';
}
}
}
} else {
messageFunction("{{no_item_selected}}");
}
treeSettingsDiv.style.visibility = "hidden";
}
let treeSettingsDeleteId = document.getElementById('treeSettingsDelete');
treeSettingsDeleteId.addEventListener('click', treeSettingsDeleteFun);
async function treeSettingsDeleteFun() {
if (targetTreeItem) {
let li = targetTreeItem.closest('li');
if (li) {
let parentUl = li.parentElement;
if (li.querySelector('li')) {
messageQueue.push(`{{delete_all_subpages}} ${targetTreeItem.querySelector('.tree-text').textContent}?`);
const userConfirmed = await messageCreateQuestion();
if (userConfirmed) {
li.remove();
}
} else {
li.remove();
}
if (parentUl && parentUl.children.length === 0) {
let detailsDiv = parentUl.parentElement;
if (detailsDiv && detailsDiv.classList.contains('details')) {
let parentLi = detailsDiv.closest('li');
if (parentLi) {
let marker = parentLi.querySelector('.tree-marker');
if (marker) marker.textContent = '■';
}
detailsDiv.remove();
}
}
}
} else {
messageFunction("{{no_item_selected}}");
}
let treeSettingsDiv = document.getElementById('treeSettings');
treeSettingsDiv.style.visibility = "hidden";
}
/* свойтсва страниц */
let treeSettingsPropertiesId = document.getElementById('treeSettingsProperties');;
treeSettingsPropertiesId.onclick = function() {
document.getElementById('treeProperties').style.visibility = 'hidden';
let treePropertiesId = document.getElementById('treeProperties');
let treePropertiesDivId = document.getElementById('treePropertiesDiv');
let treePropertiesTopNameId = document.getElementById('treePropertiesTopName');
let treePropertiesWindowPropertiesId = document.getElementById('treePropertiesWindowProperties');
let treePropertiesWindowRightsId = document.getElementById('treePropertiesWindowRights');
let tableProperties = document.createElement('table');
tableProperties.style.width = "100%";
tableProperties.innerHTML= treePropertiesDiv();
let tableRights = document.createElement('div');
tableRights.innerHTML = `{{no_rights}}`;
treePropertiesTopNameId.textContent = `{{properties}}`;
treePropertiesDivId.innerHTML = '';
treePropertiesWindowPropertiesId.onclick = function() {
treePropertiesDivId.innerHTML = '';
treePropertiesDivId.appendChild(tableProperties);
treePropertiesWindowPropertiesId.style.backgroundColor = "#f3f3f3";
treePropertiesWindowRightsId.style.backgroundColor = "";
};
treePropertiesWindowRightsId.onclick = function() {
treePropertiesDivId.innerHTML = '';
treePropertiesDivId.appendChild(tableRights);
treePropertiesWindowPropertiesId.style.backgroundColor = "";
treePropertiesWindowRightsId.style.backgroundColor = "#f3f3f3";
};
treePropertiesWindowPropertiesId.click();
if (treePropertiesId.style.visibility == 'hidden') {
treePropertiesId.style.visibility = 'visible';
}
let treePropertiesTopCloseId = document.getElementById('treePropertiesTopClose');
let treePropertiesDivButtonOkId = document.getElementById('treePropertiesDivButtonOk');
let treePropertiesDivButtonCancelId = document.getElementById('treePropertiesDivButtonCancel');
treePropertiesTopCloseId.onclick = function() {
treePropertiesId.style.visibility = 'hidden';
if (window.managerDataAction == "propertiesUrl") {
window.managerDataAction = "";
managerDiv.style.visibility = "hidden";
removePluginDom("manager");
}
};
treePropertiesDivButtonOkId.onclick = function() {
saveTreePropertiesDiv();
treePropertiesId.style.visibility = 'hidden';
if (window.managerDataAction == "propertiesUrl") {
window.managerDataAction = "";
managerDiv.style.visibility = "hidden";
removePluginDom("manager");
}
};
treePropertiesDivButtonCancelId.onclick = function() {
treePropertiesId.style.visibility = 'hidden';
if (window.managerDataAction == "propertiesUrl") {
window.managerDataAction = "";
managerDiv.style.visibility = "hidden";
removePluginDom("manager");
}
};
};
function saveTreePropertiesDiv() {
let treeDataDiv = lastRightClickedItem.querySelector('.tree-data');
let rows = document.querySelectorAll('#treePropertiesDiv table tr');
let newData = [];
rows.forEach(row => {
let key = row.querySelector('td:first-child').textContent.trim();
let valueCell = row.querySelector('td:last-child');
let value = '';
if (key.toLowerCase() === 'pagemenu') {
let inputs = valueCell.querySelectorAll('input');
value = Array.from(inputs)
.map(input => input.value.trim())
.filter(v => v)
.join(',');
}
else if (key.toLowerCase() === 'template') {
value = valueCell.querySelector('select').value;
}
else if (key.toLowerCase() === 'url') {
value = document.getElementById('treePropertiesDivUrlValue').textContent;
}
else if (key.toLowerCase() === 'news') {
let cb = valueCell.querySelector('.news-checkbox');
let parts = [];
parts.push(`<div><input type="checkbox" class="news-checkbox"${cb.checked?' checked':''}>show in news</div>`);
let start = valueCell.querySelector('.news-start').value;
let end = valueCell.querySelector('.news-end').value;
parts.push(`<div><input type="datetime-local" class="news-start" value="${start}"><input type="datetime-local" class="news-end" value="${end}"></div>`);
let blocks = Array.from(valueCell.querySelectorAll('input[type="checkbox"][value]'))
.map(x => `<label><input type="checkbox" value="${x.value}"${x.checked?' checked':''}>${x.value}</label>`);
parts.push(`<div>${blocks.join(' ')}</div>`);
value = parts.join('');
}
else if (key.toLowerCase() === 'plugins') {
let cbs = valueCell.querySelectorAll('input[type="checkbox"][value]');
let active = Array.from(cbs)
.filter(cb => cb.checked)
.map(cb => cb.value);
value = active.join(',');
} else {
let input = valueCell.querySelector('input');
value = input ? input.value : valueCell.textContent.trim();
}
newData.push(`${key}: ${value}`);
});
if (treeDataDiv) {
treeDataDiv.innerHTML = newData.join('<br>');
let name = newData.find(d => d.startsWith('name: '))?.split(': ')[1] || '';
let title = newData.find(d => d.startsWith('title: '))?.split(': ')[1] || '';
let textSpan = lastRightClickedItem.querySelector('.tree-text');
if (textSpan) {
textSpan.childNodes[0].textContent = name + ' ';
let nameSpan = textSpan.querySelector('.tree-text-name');
if (nameSpan) nameSpan.innerHTML = `&nbsp;(${title})`;
}
}
}
/* Выбор страницы для ссылки */
let treeSettingsChooseId = document.getElementById('treeSettingsChoose');
treeSettingsChooseId.addEventListener('click', treeSettingsChooseFun);
function treeSettingsChooseFun() {
var parts = [];
var span = targetTreeItem;
var li = span.closest('li');
while (li) {
var itemSpan = li.querySelector(':scope > span.tree-item');
var text = itemSpan.querySelector('.tree-text').firstChild.textContent.trim();
parts.unshift(text);
li = li.parentElement.closest('li');
}
if (parts[0] === 'index') {
parts.shift();
}
var url;
if (parts.length) {
url = 'http://slava.home/' + parts.join('/') + '.html';
} else {
url = 'http://slava.home';
}
document.getElementById('link2').value = url;
document.getElementById("treeDiv").style.visibility = "hidden";
document.getElementById("treeProperties").style.visibility = "hidden";
document.getElementById("treeSettings").style.visibility = "hidden";
removePluginDom("site_tree")
}
function treePropertiesDiv() {
if (!treePropertiesDivElement) return "";
let dataHTML = treePropertiesDivElement.querySelector('.tree-data')?.innerHTML || "";
let lines = dataHTML.split('<br>');
let rows = [];
for (let line of lines) {
if (!line.trim()) continue;
let parts = line.split(':');
let key = parts[0].trim();
let value = parts.slice(1).join(':').trim();
let inputHtml = value;
if (key.toLowerCase() === "url") {
inputHtml = `<span id="treePropertiesDivUrlValue" style="font-size: inherit;">${value}</span> <button id="treePropertiesDivUrl" type="button">{{select}}</button>`;
} else if (key.toLowerCase() === "title") {
inputHtml = `<input type="text" value="${value}" style="font-size: inherit;">`;
} else if (key.toLowerCase() === "name") {
inputHtml = `<input type="text" value="${value}" style="font-size: inherit;" pattern="[A-Za-z0-9]+" oninput="this.value = this.value.replace(/[^A-Za-z0-9]/g, '')">`;
} else if (key.toLowerCase() === "template") {
let defaultTemplate = value;
inputHtml = `<select id="templateSelect" style="font-size: inherit;"><option selected>${defaultTemplate}</option></select>`;
setTimeout(function() {
jsonrpcRequest("getFolders", { folder: "/template" }).then(data => {
let select = document.getElementById('templateSelect');
if (select && data) {
select.innerHTML = '';
data.forEach(folder => {
select.innerHTML += `<option${folder === defaultTemplate ? ' selected' : ''}>${folder}</option>`;
});
}
});
}, 0);
} else if (key.toLowerCase() === "pagemenu") {
let values = value.split(",");
while (values.length < 3) {
values.push("");
}
inputHtml = values.map((val, index) =>
`<input type="text" value="${val}" style="width: 30px; font-size: inherit; text-align: center;"
oninput="this.value = this.value.replace(/[^0-9]/g, '');">`
).join(" , ");
} else if (key.toLowerCase() === "users") {
inputHtml = `<input type="text" value="${value}" style="font-size: inherit;" readonly disabled>`;
} else if (key.toLowerCase() === "group") {
inputHtml = `<input type="text" value="${value}" style="font-size: inherit;" readonly disabled>`;
} else if (key.toLowerCase() === "plugins") {
let plugins = (value || '').split(',');
let allPlugins = ['dgrm','SvgEditorM', 'form_editor'];
inputHtml = allPlugins.map(p =>
`<label><input type="checkbox" value="${p}"${plugins.includes(p)?' checked':''}>${p}</label>`
).join(' ');
}
rows.push(`<tr><td class="managerPropertiesDivDivs">${key}</td><td class="managerPropertiesDivDivs">${inputHtml}</td></tr>`);
}
setTimeout(treePropertiesDivFunc, 0);
return `<table style="width: 100%;">${rows.join('')}</table>`;
}
function treePropertiesDivFunc() {
document.getElementById('treePropertiesDivUrl').onclick = async function() {
await includePlugin("manager");
window.managerDataAction = "propertiesUrl";
managerData("/content");
managerDiv.style.visibility = "visible";
document.getElementById("settingsMain_d").style.visibility = "hidden";
};
}
let lastRightClickedItem = null;
let treePropertiesDivElement = null;
function treeContext(event){
let treeItem=event.target.closest('.tree-item')
if(treeItem){
lastRightClickedItem=treeItem
treePropertiesDivElement=treeItem
}
}
document.addEventListener('contextmenu',treeContext)
touchLong(document,treeContext)
}, { once: true }); /* начало */