Initial commit
This commit is contained in:
145
main_plugin/site_tree/func.site_tree.php
Normal file
145
main_plugin/site_tree/func.site_tree.php
Normal file
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
/* перебор файлов и папок */
|
||||
|
||||
function scanDirTree() {
|
||||
global $path, $_SESSION;
|
||||
|
||||
$file = $path . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'filepath.' . $_SESSION['lng'] . '.php';
|
||||
$content = file_get_contents($file);
|
||||
$xml = simplexml_load_string($content);
|
||||
|
||||
function generateArray($xml, $urlParts = [], $isOpen = false) {
|
||||
$result = [];
|
||||
foreach ($xml->children() as $child) {
|
||||
$item = [
|
||||
'name' => (string) $child->attributes()->name,
|
||||
'tag' => $child->getName(),
|
||||
'children' => generateArray($child, $urlParts, $isOpen),
|
||||
'isOpen' => false,
|
||||
|
||||
'url' => (string) $child->attributes()->url,
|
||||
'title' => (string) $child->attributes()->title,
|
||||
'template' => (string) $child->attributes()->template,
|
||||
'PageMenu' => (string) $child->attributes()->PageMenu,
|
||||
'users' => (string) $child->attributes()->users,
|
||||
'group' => (string) $child->attributes()->group,
|
||||
|
||||
'content' => (string)$child
|
||||
];
|
||||
|
||||
if (!empty($urlParts) && $urlParts[0] == $item['tag']) {
|
||||
array_shift($urlParts);
|
||||
if (empty($urlParts)) {
|
||||
if ($item['tag'] !== 'index') {
|
||||
$item['isOpen'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result[] = $item;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
$url = $_SERVER['REQUEST_URI'];
|
||||
$urlParts = array_filter(explode('/', trim($url, '/')));
|
||||
$urlParts = array_map(function($part) {
|
||||
return pathinfo($part, PATHINFO_FILENAME);
|
||||
}, $urlParts);
|
||||
|
||||
$result = generateArray($xml, $urlParts);
|
||||
|
||||
return ['items' => $result];
|
||||
}
|
||||
|
||||
/* сохронения древа */
|
||||
function saveTree($params) {
|
||||
global $path, $_SESSION;
|
||||
|
||||
$file = $path . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'filepath.' . ($_SESSION['lng'] ?? 'en') . '.php';
|
||||
|
||||
if (!isset($params['data']) || !is_array($params['data'])) {
|
||||
return ['status' => 'error', 'message' => 'Invalid data'];
|
||||
}
|
||||
|
||||
$treeData = $params['data'];
|
||||
$siteName = isset($treeData['sitename']) ? htmlspecialchars($treeData['sitename'], ENT_XML1 | ENT_QUOTES, 'UTF-8') : '';
|
||||
$slogan = isset($treeData['slogan']) ? htmlspecialchars($treeData['slogan'], ENT_XML1 | ENT_QUOTES, 'UTF-8') : '';
|
||||
|
||||
$xmlContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".
|
||||
"<site>\n".
|
||||
" <sitename>$siteName</sitename>\n".
|
||||
" <slogan>$slogan</slogan>\n".
|
||||
buildXml($treeData['children'] ?? []).
|
||||
"</site>\n";
|
||||
|
||||
$result = @file_put_contents($file, $xmlContent);
|
||||
|
||||
if ($result === false) {
|
||||
return ['status' => 'error', 'message' => 'Failed to write file'];
|
||||
}
|
||||
|
||||
if (!file_exists($file)) {
|
||||
return ['status' => 'error', 'message' => 'File does not exist after write'];
|
||||
}
|
||||
|
||||
return ['status' => 'success', 'message' => 'File saved successfully'];
|
||||
}
|
||||
|
||||
function buildXml($data, $level = 1) {
|
||||
$xml = "";
|
||||
foreach ($data as $item) {
|
||||
if (!isset($item['name']) || empty($item['name'])) continue;
|
||||
|
||||
$tag = htmlspecialchars(trim(explode(' ', $item['name'])[0]), ENT_XML1 | ENT_QUOTES, 'UTF-8');
|
||||
$nameAttr = htmlspecialchars(trim($tag), ENT_XML1 | ENT_QUOTES, 'UTF-8');
|
||||
|
||||
$attributes = [
|
||||
'url' => isset($item['url']) ? htmlspecialchars($item['url'], ENT_XML1 | ENT_QUOTES, 'UTF-8') : '',
|
||||
'title' => isset($item['title']) ? htmlspecialchars($item['title'], ENT_XML1 | ENT_QUOTES, 'UTF-8') : '',
|
||||
'name' => $nameAttr,
|
||||
'template' => isset($item['template']) ? htmlspecialchars($item['template'], ENT_XML1 | ENT_QUOTES, 'UTF-8') : '',
|
||||
'PageMenu' => isset($item['PageMenu']) ? htmlspecialchars($item['PageMenu'], ENT_XML1 | ENT_QUOTES, 'UTF-8') : '',
|
||||
'users' => isset($item['users']) ? htmlspecialchars($item['users'], ENT_XML1 | ENT_QUOTES, 'UTF-8') : '',
|
||||
'group' => isset($item['group']) ? htmlspecialchars($item['group'], ENT_XML1 | ENT_QUOTES, 'UTF-8') : ''
|
||||
];
|
||||
|
||||
$attrString = "";
|
||||
foreach ($attributes as $key => $value) {
|
||||
$attrString .= " $key='$value'";
|
||||
}
|
||||
|
||||
$xml .= str_repeat(" ", $level) . "<$tag$attrString>\n";
|
||||
if (!empty($item['children'])) {
|
||||
$xml .= buildXml($item['children'], $level + 1);
|
||||
}
|
||||
$xml .= str_repeat(" ", $level) . "</$tag>\n";
|
||||
}
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/* текущий файл страницы */
|
||||
|
||||
function currentPageFile() {
|
||||
global $_SESSION, $path;
|
||||
return ['folders' => $folders];
|
||||
}
|
||||
|
||||
/* текущий файл страницы */
|
||||
function getFolderNames() {
|
||||
global $path;
|
||||
$folder = $path . DIRECTORY_SEPARATOR . $_POST['folder'];
|
||||
$folders = array();
|
||||
if ($folder && is_dir($folder)) {
|
||||
$files = scandir($folder);
|
||||
foreach ($files as $file) {
|
||||
if ($file != '.' && $file != '..' && is_dir($folder . DIRECTORY_SEPARATOR . $file)) {
|
||||
$folders[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ['folders' => $folders];
|
||||
}
|
||||
|
||||
?>
|
||||
8
main_plugin/site_tree/lang.js.php
Normal file
8
main_plugin/site_tree/lang.js.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
$lang = include $path . 'lang.php';
|
||||
$lng = $_GET['lng'] ?? ($_SESSION['lng'] ?? 'en');
|
||||
$placeholders = [];
|
||||
foreach ($lang[$lng] as $key => $value) {
|
||||
$placeholders['{{' . $key . '}}'] = $value;
|
||||
}
|
||||
echo strtr(file_get_contents($path . 'site_tree.js'), $placeholders);
|
||||
83
main_plugin/site_tree/lang.php
Normal file
83
main_plugin/site_tree/lang.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
$lang = [
|
||||
'ru' => [
|
||||
'tree_site_title' => 'Дерево сайта',
|
||||
'save' => 'Сохранить',
|
||||
'add' => 'Добавить',
|
||||
'paste' => 'Вставить',
|
||||
'copy' => 'Копировать',
|
||||
'rename' => 'Переименовать',
|
||||
'properties' => 'Свойства',
|
||||
'delete' => 'Удалить',
|
||||
'choose' => 'Выбрать',
|
||||
'enter_new_name' => 'Введите новое имя',
|
||||
'name_only_english_letters' => 'Имя должно содержать только английские буквы без пробелов и символов.',
|
||||
'no_item_selected' => 'Нет выбранного элемента.',
|
||||
'delete_all_subpages' => 'Удалить все подстраницы страницы',
|
||||
'save_new_page' => 'Сохраните новую страницу!',
|
||||
'enter_tag_for_new_page' => 'Введите тег для новой страницы:',
|
||||
'tag_only_english_letters' => 'Тег должен содержать только английские буквы без пробелов и символов.',
|
||||
'tag_already_exists' => 'Элемент с таким тегом уже существует.',
|
||||
'select_page_for_link' => 'Выбор страницы для ссылки',
|
||||
'rights' => 'Права',
|
||||
'ok' => 'ОК',
|
||||
'cancel' => 'Отмена',
|
||||
'select' => 'Выбрать',
|
||||
'no_rights' => 'Прав пока что нету',
|
||||
'properties' => 'Свойства',
|
||||
],
|
||||
'en' => [
|
||||
'tree_site_title' => 'Site Tree',
|
||||
'save' => 'Save',
|
||||
'add' => 'Add',
|
||||
'paste' => 'Paste',
|
||||
'copy' => 'Copy',
|
||||
'rename' => 'Rename',
|
||||
'properties' => 'Properties',
|
||||
'delete' => 'Delete',
|
||||
'choose' => 'Choose',
|
||||
'enter_new_name' => 'Enter new name',
|
||||
'name_only_english_letters' => 'Name must contain only English letters without spaces and symbols.',
|
||||
'no_item_selected' => 'No item selected.',
|
||||
'delete_all_subpages' => 'Delete all subpages of the page',
|
||||
'save_new_page' => 'Save the new page!',
|
||||
'enter_tag_for_new_page' => 'Enter tag for the new page:',
|
||||
'tag_only_english_letters' => 'Tag must contain only English letters without spaces and symbols.',
|
||||
'tag_already_exists' => 'An element with this tag already exists.',
|
||||
'select_page_for_link' => 'Select page for the link',
|
||||
'rights' => 'Rights',
|
||||
'ok' => 'OK',
|
||||
'cancel' => 'Cancel',
|
||||
'select' => 'Select',
|
||||
'no_rights' => 'No rights yet',
|
||||
'properties' => 'Properties',
|
||||
],
|
||||
'lv' => [
|
||||
'tree_site_title' => 'Saites koks',
|
||||
'save' => 'Saglabāt',
|
||||
'add' => 'Pievienot',
|
||||
'paste' => 'Ielīmēt',
|
||||
'copy' => 'Kopēt',
|
||||
'rename' => 'Pārdēvēt',
|
||||
'properties' => 'Īpašības',
|
||||
'delete' => 'Dzēst',
|
||||
'choose' => 'Izvēlēties',
|
||||
'enter_new_name' => 'Ievadiet jaunu nosaukumu',
|
||||
'name_only_english_letters' => 'Nosaukumam jābūt tikai angļu burtiem bez atstarpēm un simboliem.',
|
||||
'no_item_selected' => 'Nav izvēlēts neviens elements.',
|
||||
'delete_all_subpages' => 'Dzēst visas apakšlapas',
|
||||
'save_new_page' => 'Saglabājiet jauno lapu!',
|
||||
'enter_tag_for_new_page' => 'Ievadiet taga nosaukumu jaunai lapai:',
|
||||
'tag_only_english_letters' => 'Tagam jābūt tikai angļu burtiem bez atstarpēm un simboliem.',
|
||||
'tag_already_exists' => 'Tādā pašā tagā jau pastāv elements.',
|
||||
'select_page_for_link' => 'Izvēlieties lapu saitei',
|
||||
'rights' => 'Tiesības',
|
||||
'ok' => 'Labi',
|
||||
'cancel' => 'Atcelt',
|
||||
'select' => 'Izvēlēties',
|
||||
'no_rights' => 'Nav tiesību vēl',
|
||||
'properties' => 'Īpašības',
|
||||
],
|
||||
];
|
||||
|
||||
return $lang;
|
||||
18
main_plugin/site_tree/plug.php
Normal file
18
main_plugin/site_tree/plug.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
global $path, $_SESSION, $configAdmins;
|
||||
$lang = include $path . 'main_plugin/site_tree/lang.php';
|
||||
$lng = $_SESSION['lng'] ?? 'en';
|
||||
|
||||
if (in_array($_SESSION['username'], $configAdmins, true)) {
|
||||
include_once $path . 'main_plugin/site_tree/func.site_tree.php';
|
||||
|
||||
$Html = file_get_contents($path . 'main_plugin/site_tree/site_tree.php');
|
||||
foreach ($lang[$lng] as $key => $value) {
|
||||
$Html = str_replace('{{' . $key . '}}', $value, $Html);
|
||||
}
|
||||
echo $Html;
|
||||
|
||||
echo '<link rel="stylesheet" href="/main_plugin/site_tree/site_tree.css">';
|
||||
echo '<script type="text/javascript" src="/main_plugin/site_tree/lang.js.php?lng=' . $lng . '"></script>';
|
||||
}
|
||||
?>
|
||||
189
main_plugin/site_tree/site_tree.css
Normal file
189
main_plugin/site_tree/site_tree.css
Normal file
@@ -0,0 +1,189 @@
|
||||
/* основной div */
|
||||
#treeDiv {
|
||||
display: inline-block;
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
user-select: none;
|
||||
background-color: rgba(255, 255, 255, 0.92);
|
||||
border: 1px solid #000000;
|
||||
width: 800px;
|
||||
border-radius: 5px;
|
||||
height: 600px;
|
||||
font-size: 1em;
|
||||
box-shadow: 0px 0px 5px #777;
|
||||
max-width: calc(100% - 20px);
|
||||
}
|
||||
|
||||
/* верхний див */
|
||||
#treeTop {
|
||||
text-align: center;
|
||||
border-bottom: 1px #40464d solid;
|
||||
padding: 5px;
|
||||
background-color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
#treeTopTitle {
|
||||
text-align: center;
|
||||
}
|
||||
#treeCloseFun {
|
||||
float: right;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-position: -159px -121px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* основное древо сайта */
|
||||
|
||||
#treeTableDiv {
|
||||
top: 36px;
|
||||
height: 480px;
|
||||
position: relative;
|
||||
margin: 0px 20px 0px 20px;
|
||||
border: 1px #40464d solid;
|
||||
overflow-y: overlay;
|
||||
border-radius: 5px;
|
||||
width: calc(100% - 40px);
|
||||
}
|
||||
|
||||
li.has-children::marker {
|
||||
content: "► ";
|
||||
}
|
||||
li.has-children.open::marker {
|
||||
content: "▼ ";
|
||||
}
|
||||
li.no-children::marker {
|
||||
content: "□ ";
|
||||
}
|
||||
|
||||
/* окно страницы */
|
||||
|
||||
.tree-details {
|
||||
display: none;
|
||||
background: white;
|
||||
border: 1px solid black;
|
||||
padding: 3px;
|
||||
margin: 3px 0px 10px 0px;
|
||||
z-index: 10;
|
||||
position: relative;
|
||||
width: max-content;
|
||||
}
|
||||
.tree-details div {
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
/* окно настроек */
|
||||
#treeSettings {
|
||||
display: inline-block;
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
user-select: none;
|
||||
background-color: rgba(255, 255, 255, 0.92);
|
||||
border: 1px solid #000000;
|
||||
border-radius: 5px;
|
||||
font-size: 1em;
|
||||
box-shadow: 0px 0px 5px #777;
|
||||
padding: 5px;
|
||||
animation: fadeIn 0.5s ease-in forwards;
|
||||
}
|
||||
|
||||
.treeSettingsButtons {
|
||||
background-color: rgba(255, 255, 255, 1);
|
||||
border-radius: 5px;
|
||||
padding: 2px;
|
||||
margin: 3px;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
}
|
||||
.treeSettingsButtons:hover {
|
||||
color: #787878;
|
||||
}
|
||||
|
||||
#treeSettingsSave {
|
||||
border: 1px #40464d solid;
|
||||
border-radius: 5px;
|
||||
padding: 5px;
|
||||
margin: 44px 20px 0px 10px;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
width: 91px;
|
||||
float: right;
|
||||
}
|
||||
#treeSettingsSave:hover {
|
||||
color: #787878;
|
||||
}
|
||||
|
||||
/* окно свойств */
|
||||
#treeProperties {
|
||||
display: inline-block;
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
user-select: none;
|
||||
background-color: rgba(255, 255, 255, 0.97);
|
||||
border: 1px solid #000000;
|
||||
border-radius: 5px;
|
||||
font-size: 1em;
|
||||
box-shadow: 0px 0px 5px #777;
|
||||
width: 600px;
|
||||
max-width: calc(100% - 20px);
|
||||
}
|
||||
#treePropertiesMiddle {
|
||||
margin: 0px 20px 0px 20px;
|
||||
}
|
||||
|
||||
#treePropertiesTop {
|
||||
border-bottom: 1px solid #000000;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
#treePropertiesTopName {
|
||||
text-align: center;
|
||||
}
|
||||
#treePropertiesTopClose {
|
||||
float: right;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-position: -159px -121px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#treePropertiesWindow {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
}
|
||||
.treePropertiesWindowDiv {
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
width: 50%;
|
||||
display: inline-block;
|
||||
padding: 9px;
|
||||
}
|
||||
.treePropertiesWindowDiv:hover {
|
||||
color: #787878;
|
||||
}
|
||||
|
||||
#treePropertiesDiv {
|
||||
border: 1px solid #000000;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.treePropertiesDivDivs {
|
||||
padding: 6px 8px 6px 8px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#treePropertiesDivButtons {
|
||||
padding: 9px;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
align-items: center;
|
||||
}
|
||||
#treePropertiesDivButtons {
|
||||
text-align: center;
|
||||
}
|
||||
.treePropertiesDivButton {
|
||||
margin: 3px 3px 3px 15px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
.treePropertiesDivButton:hover {
|
||||
color: #787878;
|
||||
}
|
||||
795
main_plugin/site_tree/site_tree.js
Normal file
795
main_plugin/site_tree/site_tree.js
Normal file
@@ -0,0 +1,795 @@
|
||||
/* показ окна древа */
|
||||
let idCounter = 0;
|
||||
siteTreeGeneration();
|
||||
|
||||
/* генерация html древа */
|
||||
function siteTreeGeneration() {
|
||||
handleJsonRpcRequest('scanDirTree', {}, 1).then(data => {
|
||||
if (data && Array.isArray(data.items)) {
|
||||
let treeContainer = document.getElementById('treeTableDiv');
|
||||
treeContainer.innerHTML = generateTreeHtml(data.items, "");
|
||||
|
||||
let firstSpan = treeContainer.querySelector('span');
|
||||
if (!treeContainer.innerHTML.includes('background-color: #e5f0ff;')) {
|
||||
firstSpan.style.backgroundColor = '#e5f0ff';
|
||||
}
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
idCounter = 0;
|
||||
}
|
||||
window.siteTreeGeneration = siteTreeGeneration;
|
||||
|
||||
let selectedTreeItem = "";
|
||||
let selectedTreeItemAdd = "";
|
||||
let firstLi = true;
|
||||
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"> (${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}`;
|
||||
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}`;
|
||||
}
|
||||
|
||||
});
|
||||
html += `</ul>`;
|
||||
if (checkChildren == "") {
|
||||
firstLi = true;
|
||||
}
|
||||
moveTreePage();
|
||||
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;
|
||||
}
|
||||
|
||||
/* перемещение страниц */
|
||||
function moveTreePage() {
|
||||
let treeTableDiv = document.getElementById('treeTableDiv');
|
||||
let draggedItem = null;
|
||||
let offsetY = 0;
|
||||
let startX = 0;
|
||||
|
||||
function isDescendant(parent, child) {
|
||||
while (child) {
|
||||
if (child === parent) return true;
|
||||
child = child.parentNode;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
treeTableDiv.addEventListener('pointerdown', function(event) {
|
||||
if (window.treeSettingsMode != '') return;
|
||||
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;
|
||||
draggedItem = li;
|
||||
offsetY = event.clientY - treeItem.getBoundingClientRect().top;
|
||||
li.style.opacity = '0.5';
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('pointermove', function(event) {
|
||||
if (window.treeSettingsMode != '') return;
|
||||
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 = '■';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('pointerup', function() {
|
||||
if (window.treeSettingsMode != '') return;
|
||||
if (draggedItem) {
|
||||
draggedItem.style.opacity = '';
|
||||
draggedItem = null;
|
||||
}
|
||||
});
|
||||
|
||||
treeTableDiv.addEventListener('pointermove', function(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 = '►';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
addEventListener("load", 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 };
|
||||
|
||||
handleJsonRpcRequest('saveTree', fullData, 1).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();
|
||||
}
|
||||
|
||||
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);
|
||||
function treeSettingsAddFun() {
|
||||
if (window.newPageFunValue == "newPage") {
|
||||
document.getElementById("saveHow").click();
|
||||
messageFunction("{{save_new_page}}");
|
||||
return;
|
||||
}
|
||||
|
||||
let container = getContainer();
|
||||
let pageUrl = selectedTreeItemAdd;
|
||||
let treeText = prompt("{{enter_tag_for_new_page}}");
|
||||
treeText = treeText ? treeText.trim() : "";
|
||||
if (!/^[A-Za-z]+$/.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) {
|
||||
alert("{{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);
|
||||
function treeSettingsPasteFun() {
|
||||
let container = getContainer();
|
||||
let clonedItem = selectedTreeItem.cloneNode(true);
|
||||
let treeText = prompt("{{enter_tag_for_new_page}}");
|
||||
treeText = treeText ? treeText.trim() : "";
|
||||
if (!/^[A-Za-z]+$/.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"> (${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"> (${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);
|
||||
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();
|
||||
let newText = prompt("{{enter_new_name}}", currentName);
|
||||
if (newText !== null) {
|
||||
newText = newText.trim();
|
||||
if (!/^[A-Za-z]+$/.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() {
|
||||
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";
|
||||
}
|
||||
};
|
||||
treePropertiesDivButtonOkId.onclick = function() {
|
||||
saveTreePropertiesDiv();
|
||||
treePropertiesId.style.visibility = 'hidden';
|
||||
if (window.managerDataAction == "propertiesUrl") {
|
||||
window.managerDataAction = "";
|
||||
managerDiv.style.visibility = "hidden";
|
||||
}
|
||||
};
|
||||
treePropertiesDivButtonCancelId.onclick = function() {
|
||||
treePropertiesId.style.visibility = 'hidden';
|
||||
if (window.managerDataAction == "propertiesUrl") {
|
||||
window.managerDataAction = "";
|
||||
managerDiv.style.visibility = "hidden";
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
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 {
|
||||
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 = ` (${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";
|
||||
}
|
||||
|
||||
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-z]+" oninput="this.value = this.value.replace(/[^A-Za-z]/g, '')">`;
|
||||
} else if (key.toLowerCase() === "template") {
|
||||
let defaultTemplate = value;
|
||||
inputHtml = `<select id="templateSelect" style="font-size: inherit;"><option selected>${defaultTemplate}</option></select>`;
|
||||
setTimeout(function() {
|
||||
handleJsonRpcRequest('getFolderNames', { folder: '/template' }, 1).then(data => {
|
||||
let select = document.getElementById('templateSelect');
|
||||
if (select && data && data.folders) {
|
||||
select.innerHTML = '';
|
||||
data.folders.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>`;
|
||||
}
|
||||
|
||||
|
||||
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 = function() {
|
||||
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)
|
||||
|
||||
}); /* начало */
|
||||
39
main_plugin/site_tree/site_tree.php
Normal file
39
main_plugin/site_tree/site_tree.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<div id="treeDiv" style="visibility: hidden; top: 20%; left: 50%; transform: translate(-50%, -20%);">
|
||||
<div id="treeTop">
|
||||
<span id="treeTopTitle">{{tree_site_title}}</span>
|
||||
<span id="treeCloseFun" class="editib"></span>
|
||||
</div>
|
||||
<div id="treeTableDiv"></div>
|
||||
<span id="treeSettingsSave">{{save}}</span>
|
||||
</div>
|
||||
|
||||
<div id="treeSettings" style="visibility: hidden; top: 0px; left: 0px;">
|
||||
<div id="treeSettingsDiv">
|
||||
<span id="treeSettingsAdd" class="treeSettingsButtons">{{add}}</span>
|
||||
<span id="treeSettingsPaste" class="treeSettingsButtons">{{paste}}</span>
|
||||
<span id="treeSettingsCopy" class="treeSettingsButtons">{{copy}}</span>
|
||||
<span id="treeSettingsRename" class="treeSettingsButtons">{{rename}}</span>
|
||||
<span id="treeSettingsProperties" class="treeSettingsButtons">{{properties}}</span>
|
||||
<span id="treeSettingsDelete" class="treeSettingsButtons">{{delete}}</span>
|
||||
<span id="treeSettingsChoose" class="treeSettingsButtons">{{choose}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="treeProperties" style="visibility: hidden; top: 20%; left: 50%; transform: translate(-50%, -20%);">
|
||||
<div id="treePropertiesTop">
|
||||
<span id="treePropertiesTopName" class="treePropertiesTop"></span>
|
||||
<span id="treePropertiesTopClose" class="editib"></span>
|
||||
</div>
|
||||
<div id="treePropertiesMiddle">
|
||||
<div id="treePropertiesWindow">
|
||||
<span id="treePropertiesWindowProperties" class="treePropertiesWindowDiv">{{properties}}</span>
|
||||
<span id="treePropertiesWindowRights" class="treePropertiesWindowDiv">{{rights}}</span>
|
||||
</div>
|
||||
<div id="treePropertiesDiv">
|
||||
</div>
|
||||
<div id="treePropertiesDivButtons">
|
||||
<div id="treePropertiesDivButtonOk" class="treePropertiesDivButton">{{ok}}</div>
|
||||
<div id="treePropertiesDivButtonCancel" class="treePropertiesDivButton">{{cancel}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user