Форум

Отзывы и предолжения к софту от AleXStam
Поговорим о...
AleXStamДата: Понедельник, 2025-06-23, 11:21 | Сообщение # 76
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
// В функции обработки поиска:
function handleSearch(query) {
// ... ваш существующий код ...

// Добавьте этот вызов:
if (window.manageTreeSearch) {
window.manageTreeSearch(query);
}
}

// Для мгновенного поиска при вводе
const searchInput = document.querySelector('.search-input');
if (searchInput) {
searchInput.addEventListener('input', function(e) {
if (window.manageTreeSearch) {
window.manageTreeSearch(e.target.value);
}
});
}
AleXStamДата: Понедельник, 2025-06-23, 11:29 | Сообщение # 77
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
<div class="tree-container">
{{ $level := .level | default 1 }}
<ul class="tree-ul level-{{ $level }}">
{{ range .nodes }}
<li class="tree-item {{ if .children }}has-children{{ end }} {{ .state | default "closed" }}"
data-search-text="{{ lower .name }}">
<div class="tree-line">
{{ if .children }}
<span class="tree-arrow">›</span>
{{ else }}
<span class="tree-dot">•</span>
{{ end }}
<span class="tree-name">{{ .name }}</span>
</div>
{{ if .children }}
{{ partial "tree" (dict "nodes" .children "level" (add $level 1)) }}
{{ end }}
</li>
{{ end }}
</ul>
</div>

<script>
(function() {
// Инициализация дерева
function initTree() {
// Закрываем все узлы по умолчанию
document.querySelectorAll('.tree-item.has-children').forEach(item => {
if (!item.classList.contains('open')) {
item.querySelector('.tree-ul').style.display = 'none';
}
});

// Обработчики кликов
document.querySelectorAll('.tree-line').forEach(line => {
line.addEventListener('click', function() {
const item = this.parentElement;
if (item.classList.contains('has-children')) {
const isOpen = item.classList.contains('open');
item.classList.toggle('open', !isOpen);
item.querySelector('.tree-ul').style.display = isOpen ? 'none' : 'block';
}
});
});
}

// Поиск по дереву
function searchTree(query) {
const term = query.toLowerCase().trim();

// Сбрасываем предыдущие результаты
document.querySelectorAll('.tree-item').forEach(item => {
item.classList.remove('highlighted');
});

if (!term) return;

// Ищем совпадения
document.querySelectorAll('.tree-item').forEach(item => {
const text = item.getAttribute('data-search-text');
if (text.includes(term)) {
item.classList.add('highlighted');

// Раскрываем родителей
let parent = item.parentElement.closest('.tree-item');
while (parent) {
parent.classList.add('open');
parent.querySelector('.tree-ul').style.display = 'block';
parent = parent.parentElement.closest('.tree-item');
}

// Прокрутка к первому найденному элементу
const firstMatch = document.querySelector('.tree-item.highlighted');
if (firstMatch) {
firstMatch.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}
});
}

// Инициализация при загрузке
document.addEventListener('DOMContentLoaded', function() {
initTree();

// Обработчики для поиска
const searchInput = document.getElementById('tree-search-input');
const clearButton = document.getElementById('tree-search-clear');

searchInput.addEventListener('input', function() {
searchTree(this.value);
});

clearButton.addEventListener('click', function() {
searchInput.value = '';
searchTree('');
});
});
})();
</script>

<style>
/* Ваши существующие стили дерева */
.tree-container { font-family: sans-serif; font-size: 14px; }
.tree-ul { list-style: none; padding-left: 20px; margin: 0; }
.tree-item { margin: 2px 0; }
.tree-line { display: flex; align-items: center; cursor: pointer; padding: 2px 0; }
.tree-arrow, .tree-dot { width: 16px; margin-right: 4px; }
.tree-arrow { transition: transform 0.2s; }
.tree-item.open > .tree-line > .tree-arrow { transform: rotate(90deg); }
.tree-item > .tree-ul { display: none; }
.tree-item.open > .tree-ul { display: block; }

/* Подсветка найденных элементов */
.tree-item.highlighted > .tree-line > .tree-name {
background-color: #fff8c5;
border-radius: 3px;
padding: 0 2px;
}
</style>
AleXStamДата: Понедельник, 2025-06-23, 11:30 | Сообщение # 78
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
<div class="tree-search-box">
<input type="text" id="tree-search-input" placeholder="Поиск в дереве..." class="tree-search-input">
<button id="tree-search-clear" class="tree-search-clear">×</button>
</div>

<style>
.tree-search-box {
position: relative;
margin-bottom: 15px;
max-width: 300px;
}

.tree-search-input {
width: 100%;
padding: 8px 30px 8px 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}

.tree-search-clear {
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
font-size: 16px;
color: #999;
}
</style>
AleXStamДата: Понедельник, 2025-06-23, 11:37 | Сообщение # 79
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
<div class="tree-search-panel">
<div class="tree-search-box">
<input type="text" id="tree-search-input" placeholder="Поиск в дереве..." class="tree-search-input">
<button id="tree-search-btn" class="tree-search-btn">Найти</button>
<button id="tree-search-clear" class="tree-search-clear">×</button>
</div>
<div class="search-modes">
<label><input type="radio" name="search-mode" value="instant" checked> Мгновенный поиск</label>
<label><input type="radio" name="search-mode" value="button"> Поиск по кнопке</label>
</div>
</div>

<style>
.tree-search-panel {
margin-bottom: 15px;
max-width: 400px;
}

.tree-search-box {
position: relative;
display: flex;
margin-bottom: 8px;
}

.tree-search-input {
flex: 1;
padding: 8px 35px 8px 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}

.tree-search-btn {
margin-left: 8px;
padding: 0 12px;
background: #f0f0f0;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
}

.tree-search-clear {
position: absolute;
right: 90px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
font-size: 16px;
color: #999;
}

.search-modes {
font-size: 13px;
color: #666;
}

.search-modes label {
margin-right: 10px;
cursor: pointer;
}
</style>
AleXStamДата: Понедельник, 2025-06-23, 11:38 | Сообщение # 80
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
(function() {
// Инициализация дерева
function initTree() {
// Закрываем все узлы по умолчанию
document.querySelectorAll('.tree-item.has-children').forEach(item => {
if (!item.classList.contains('open')) {
item.querySelector('.tree-ul').style.display = 'none';
}
});

// Обработчики кликов
document.querySelectorAll('.tree-line').forEach(line => {
line.addEventListener('click', function() {
const item = this.parentElement;
if (item.classList.contains('has-children')) {
const isOpen = item.classList.contains('open');
item.classList.toggle('open', !isOpen);
item.querySelector('.tree-ul').style.display = isOpen ? 'none' : 'block';
}
});
});
}

// Поиск по дереву
function searchTree(query) {
const term = query.toLowerCase().trim();

// Сбрасываем предыдущие результаты
document.querySelectorAll('.tree-item').forEach(item => {
item.classList.remove('highlighted');
});

if (!term) return;

// Ищем совпадения
let foundItems = [];
document.querySelectorAll('.tree-item').forEach(item => {
const text = item.getAttribute('data-search-text');
if (text.includes(term)) {
item.classList.add('highlighted');
foundItems.push(item);

// Раскрываем родителей
let parent = item.parentElement.closest('.tree-item');
while (parent) {
parent.classList.add('open');
parent.querySelector('.tree-ul').style.display = 'block';
parent = parent.parentElement.closest('.tree-item');
}
}
});

// Прокрутка к первому найденному элементу
if (foundItems.length > 0) {
foundItems[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}

// Инициализация при загрузке
document.addEventListener('DOMContentLoaded', function() {
initTree();

// Элементы управления
const searchInput = document.getElementById('tree-search-input');
const searchBtn = document.getElementById('tree-search-btn');
const clearBtn = document.getElementById('tree-search-clear');
const instantMode = document.querySelector('input[value="instant"]');

// Обработка URL параметра
const urlParams = new URLSearchParams(window.location.search);
const urlSearch = urlParams.get('q');
if (urlSearch) {
searchInput.value = urlSearch;
searchTree(urlSearch);
}

// Обработчики событий
let searchTimeout;

searchInput.addEventListener('input', function() {
if (instantMode.checked) {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
searchTree(this.value);
}, 300);
}
});

searchInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
searchTree(this.value);
}
});

searchBtn.addEventListener('click', function() {
searchTree(searchInput.value);
});

clearBtn.addEventListener('click', function() {
searchInput.value = '';
searchTree('');
});
});
})();
AleXStamДата: Понедельник, 2025-06-23, 11:45 | Сообщение # 81
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
(function() {
// Сохраняем изначальное состояние дерева
let initialTreeState = [];

// Инициализация дерева
function initTree() {
// Запоминаем изначальное состояние
document.querySelectorAll('.tree-item.has-children').forEach((item, index) => {
initialTreeState[index] = item.classList.contains('open');
});

// Обработчики кликов
document.querySelectorAll('.tree-line').forEach(line => {
line.addEventListener('click', function() {
const item = this.parentElement;
if (item.classList.contains('has-children')) {
const isOpen = item.classList.contains('open');
item.classList.toggle('open', !isOpen);
item.querySelector('.tree-ul').style.display = isOpen ? 'none' : 'block';
}
});
});
}

// Сброс дерева в исходное состояние
function resetTreeState() {
document.querySelectorAll('.tree-item.has-children').forEach((item, index) => {
const shouldBeOpen = initialTreeState[index];
item.classList.toggle('open', shouldBeOpen);
item.querySelector('.tree-ul').style.display = shouldBeOpen ? 'block' : 'none';
item.classList.remove('highlighted');
});
}

// Поиск по дереву
function searchTree(query) {
const term = query.toLowerCase().trim();

// Сбрасываем к исходному состоянию
resetTreeState();

// Если поиск пустой - оставляем как есть
if (!term) return;

// Ищем совпадения
let foundItems = [];
document.querySelectorAll('.tree-item').forEach(item => {
const text = item.getAttribute('data-search-text');
if (text.includes(term)) {
item.classList.add('highlighted');
foundItems.push(item);

// Раскрываем родителей
let parent = item.parentElement.closest('.tree-item');
while (parent) {
parent.classList.add('open');
parent.querySelector('.tree-ul').style.display = 'block';
parent = parent.parentElement.closest('.tree-item');
}
}
});

// Если ничего не найдено - сворачиваем всё
if (foundItems.length === 0) {
document.querySelectorAll('.tree-item.has-children').forEach(item => {
item.classList.remove('open');
item.querySelector('.tree-ul').style.display = 'none';
});
} else {
// Прокрутка к первому найденному элементу
foundItems[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}

// Инициализация при загрузке
document.addEventListener('DOMContentLoaded', function() {
initTree();

// Элементы управления
const searchInput = document.getElementById('tree-search-input');
const searchBtn = document.getElementById('tree-search-btn');
const clearBtn = document.getElementById('tree-search-clear');
const instantMode = document.querySelector('input[value="instant"]');

// Обработка URL параметра
const urlParams = new URLSearchParams(window.location.search);
const urlSearch = urlParams.get('q');
if (urlSearch) {
searchInput.value = urlSearch;
searchTree(urlSearch);
}

// Обработчики событий
searchBtn.addEventListener('click', function() {
searchTree(searchInput.value);
});

searchInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
searchTree(this.value);
}
});

clearBtn.addEventListener('click', function() {
searchInput.value = '';
searchTree('');
});

// Для мгновенного поиска (если переключили режим)
instantMode.addEventListener('change', function() {
if (this.checked) {
searchInput.addEventListener('input', handleInstantSearch);
} else {
searchInput.removeEventListener('input', handleInstantSearch);
}
});

let searchTimeout;
function handleInstantSearch() {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
searchTree(this.value);
}, 300);
}
});
})();
AleXStamДата: Понедельник, 2025-06-23, 11:48 | Сообщение # 82
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
<div class="tree-container">
{{ $level := .level | default 1 }}
<ul class="tree-ul level-{{ $level }}">
{{ range .nodes }}
<li class="tree-item {{ if .children }}has-children{{ end }} {{ if eq (.state | default "closed") "open" }}open{{ else }}closed{{ end }}"
data-search-text="{{ lower .name }}">
<div class="tree-line">
{{ if .children }}<span class="tree-arrow">›</span>{{ else }}<span class="tree-dot">•</span>{{ end }}
<span class="tree-name">{{ .name }}</span>
</div>
{{ if .children }}
{{ partial "tree" (dict "nodes" .children "level" (add $level 1)) }}
{{ end }}
</li>
{{ end }}
</ul>
</div>

<script>
(function() {
// Сохраняем изначальное состояние
const initialTreeState = new Map();

// Инициализация дерева
function initTree() {
document.querySelectorAll('.tree-item.has-children').forEach(item => {
// Явно закрываем все узлы, кроме тех, что помечены как open
if (!item.classList.contains('open')) {
item.querySelector('.tree-ul').style.display = 'none';
}
// Запоминаем исходное состояние
initialTreeState.set(item, item.classList.contains('open'));
});

// Обработчики кликов
document.querySelectorAll('.tree-line').forEach(line => {
line.addEventListener('click', function() {
const item = this.parentElement;
if (item.classList.contains('has-children')) {
const isOpen = item.classList.contains('open');
item.classList.toggle('open', !isOpen);
item.querySelector('.tree-ul').style.display = isOpen ? 'none' : 'block';
}
});
});
}

// Сброс к исходному состоянию
function resetTreeState() {
document.querySelectorAll('.tree-item.has-children').forEach(item => {
const shouldBeOpen = initialTreeState.get(item);
item.classList.toggle('open', shouldBeOpen);
item.querySelector('.tree-ul').style.display = shouldBeOpen ? 'block' : 'none';
item.classList.remove('highlighted');
});
}

// Поиск по дереву
function searchTree(query) {
const term = query.toLowerCase().trim();

// Сбрасываем к исходному состоянию
resetTreeState();

// Если поиск пустой - оставляем как есть
if (!term) return;

// Ищем совпадения
let foundItems = [];
document.querySelectorAll('.tree-item').forEach(item => {
const text = item.getAttribute('data-search-text');
if (text.includes(term)) {
item.classList.add('highlighted');
foundItems.push(item);

// Раскрываем родителей
let parent = item.parentElement.closest('.tree-item');
while (parent) {
parent.classList.add('open');
parent.querySelector('.tree-ul').style.display = 'block';
parent = parent.parentElement.closest('.tree-item');
}
}
});

// Если ничего не найдено - сворачиваем всё
if (foundItems.length === 0) {
document.querySelectorAll('.tree-item.has-children').forEach(item => {
item.classList.remove('open');
item.querySelector('.tree-ul').style.display = 'none';
});
} else {
// Прокрутка к первому найденному элементу
foundItems[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}

// Инициализация при загрузке
document.addEventListener('DOMContentLoaded', function() {
initTree();

// Обработка URL параметра
const urlParams = new URLSearchParams(window.location.search);
const urlSearch = urlParams.get('q');
if (urlSearch) {
document.getElementById('tree-search-input').value = urlSearch;
searchTree(urlSearch);
}
});

// Экспортируем функцию поиска
window.searchTree = searchTree;
})();
</script>

<style>
/* Ваши существующие стили дерева */
.tree-container { font-family: sans-serif; font-size: 14px; }
.tree-ul { list-style: none; padding-left: 20px; margin: 0; }
.tree-item { margin: 2px 0; }
.tree-line { display: flex; align-items: center; cursor: pointer; padding: 2px 0; }
.tree-arrow, .tree-dot { width: 16px; margin-right: 4px; }
.tree-arrow { transition: transform 0.2s; }
.tree-item.open > .tree-line > .tree-arrow { transform: rotate(90deg); }
.tree-item > .tree-ul { display: none; }
.tree-item.open > .tree-ul { display: block; }
.tree-item.highlighted > .tree-line > .tree-name {
background-color: #fff8c5;
border-radius: 3px;
padding: 0 2px;
}
</style>
AleXStamДата: Понедельник, 2025-06-23, 11:49 | Сообщение # 83
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
<div class="tree-search-panel">
<div class="tree-search-box">
<input type="text" id="tree-search-input" placeholder="Поиск в дереве..." class="tree-search-input">
<button id="tree-search-btn" class="tree-search-btn">Найти</button>
<button id="tree-search-clear" class="tree-search-clear">×</button>
</div>
<div class="search-modes">
<label><input type="radio" name="search-mode" value="instant"> Мгновенный поиск</label>
<label><input type="radio" name="search-mode" value="button" checked> Поиск по кнопке</label>
</div>
</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.getElementById('tree-search-input');
const searchBtn = document.getElementById('tree-search-btn');
const clearBtn = document.getElementById('tree-search-clear');
const instantMode = document.querySelector('input[value="instant"]');

// Обработчики событий
searchBtn.addEventListener('click', function() {
if (window.searchTree) window.searchTree(searchInput.value);
});

searchInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter' && window.searchTree) {
window.searchTree(this.value);
}
});

clearBtn.addEventListener('click', function() {
searchInput.value = '';
if (window.searchTree) window.searchTree('');
});

// Для мгновенного поиска
instantMode.addEventListener('change', function() {
if (this.checked) {
searchInput.addEventListener('input', handleInstantSearch);
} else {
searchInput.removeEventListener('input', handleInstantSearch);
}
});

let searchTimeout;
function handleInstantSearch() {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
if (window.searchTree) window.searchTree(this.value);
}, 300);
}
});
</script>
AleXStamДата: Понедельник, 2025-06-23, 11:58 | Сообщение # 84
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
<div class="tree-container">
<!-- Добавляем панель поиска -->
<div class="tree-search-panel">
<div class="tree-search-box">
<input type="text" id="tree-search-input" placeholder="Поиск в дереве..." class="tree-search-input"
value="{{ with .Page.Params.searchQuery }}{{ . }}{{ end }}">
<button id="tree-search-btn" class="tree-search-btn">Найти</button>
<button id="tree-search-clear" class="tree-search-clear">×</button>
</div>
</div>

{{ $level := .level | default 1 }}
<ul class="tree-ul level-{{ $level }}">
{{ range .nodes }}
<li class="tree-item {{ if .children }}has-children{{ end }} {{ .state | default "closed" }}"
data-search-text="{{ lower .name }}">
<div class="tree-line">
{{ if .children }}<span class="tree-arrow">›</span>{{ else }}<span class="tree-dot">•</span>{{ end }}
<span class="tree-name">{{ .name }}</span>
</div>
{{ if .children }}
{{ partial "tree" (dict "nodes" .children "level" (add $level 1)) }}
{{ end }}
</li>
{{ end }}
</ul>
</div>

<script>
(function() {
// Сохраняем изначальное состояние
const initialTreeState = new Map();

// Инициализация дерева
function initTree() {
document.querySelectorAll('.tree-item.has-children').forEach(item => {
// Явно закрываем все узлы, кроме помеченных как open
const isOpen = item.classList.contains('open');
if (!isOpen) {
item.querySelector('.tree-ul').style.display = 'none';
}
initialTreeState.set(item, isOpen);
});

// Обработчики кликов
document.querySelectorAll('.tree-line').forEach(line => {
line.addEventListener('click', function() {
const item = this.parentElement;
if (item.classList.contains('has-children')) {
const isOpen = item.classList.contains('open');
item.classList.toggle('open', !isOpen);
item.querySelector('.tree-ul').style.display = isOpen ? 'none' : 'block';
}
});
});
}

// Функция поиска по дереву
window.searchTree = function(query) {
const term = query.toLowerCase().trim();
const searchInput = document.getElementById('tree-search-input');
if (searchInput) searchInput.value = term;

// Сброс к исходному состоянию
document.querySelectorAll('.tree-item').forEach(item => {
item.classList.remove('highlighted');
if (initialTreeState.get(item)) {
item.classList.add('open');
item.querySelector('.tree-ul').style.display = 'block';
} else {
item.classList.remove('open');
item.querySelector('.tree-ul').style.display = 'none';
}
});

if (!term) return;

// Поиск и раскрытие
let foundItems = [];
document.querySelectorAll('.tree-item').forEach(item => {
const text = item.getAttribute('data-search-text');
if (text.includes(term)) {
item.classList.add('highlighted');
foundItems.push(item);

// Раскрываем родителей
let parent = item.parentElement.closest('.tree-item');
while (parent) {
parent.classList.add('open');
parent.querySelector('.tree-ul').style.display = 'block';
parent = parent.parentElement.closest('.tree-item');
}
}
});

if (foundItems.length > 0) {
foundItems[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
};

// Инициализация
document.addEventListener('DOMContentLoaded', function() {
initTree();

// Обработчики для панели поиска
const searchInput = document.getElementById('tree-search-input');
const searchBtn = document.getElementById('tree-search-btn');
const clearBtn = document.getElementById('tree-search-clear');

if (searchBtn) {
searchBtn.addEventListener('click', function() {
if (window.searchTree) window.searchTree(searchInput.value);
});
}

if (searchInput) {
searchInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter' && window.searchTree) {
window.searchTree(this.value);
}
});
}

if (clearBtn) {
clearBtn.addEventListener('click', function() {
searchInput.value = '';
if (window.searchTree) window.searchTree('');
});
}

// Проверяем URL параметр
const urlParams = new URLSearchParams(window.location.search);
const urlSearch = urlParams.get('q');
if (urlSearch && window.searchTree) {
window.searchTree(urlSearch);
}
});
})();
</script>
AleXStamДата: Понедельник, 2025-06-23, 11:58 | Сообщение # 85
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
// В функции displayResults:
function displayResults(results, query) {
// ... существующий код ...

// Добавляем интеграцию с деревом
if (window.searchTree) {
window.searchTree(query);

// Заполняем поле поиска в дереве
const treeSearchInput = document.getElementById('tree-search-input');
if (treeSearchInput) {
treeSearchInput.value = query;
}
}
}
AleXStamДата: Понедельник, 2025-06-23, 11:58 | Сообщение # 86
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
{{ define "main" }}
{{ .Scratch.Set "searchQuery" (.Params.searchQuery | default "") }}
{{ partial "tree" (dict "nodes" .Params.tree "searchQuery" (.Scratch.Get "searchQuery")) }}
{{ end }}
AleXStamДата: Понедельник, 2025-06-23, 12:09 | Сообщение # 87
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
(function() {
// Сохраняем изначальное состояние
const initialTreeState = new Map();
let currentSearchMode = 'button'; // По умолчанию поиск по кнопке

// Инициализация дерева
function initTree() {
document.querySelectorAll('.tree-item.has-children').forEach(item => {
// Явно закрываем все узлы, кроме тех, что помечены как open
if (!item.classList.contains('open')) {
item.querySelector('.tree-ul').style.display = 'none';
}
// Запоминаем исходное состояние
initialTreeState.set(item, item.classList.contains('open'));
});

// Обработчики кликов
document.querySelectorAll('.tree-line').forEach(line => {
line.addEventListener('click', function() {
const item = this.parentElement;
if (item.classList.contains('has-children')) {
const isOpen = item.classList.contains('open');
item.classList.toggle('open', !isOpen);
item.querySelector('.tree-ul').style.display = isOpen ? 'none' : 'block';
}
});
});
}

// Сброс к исходному состоянию
function resetTreeState() {
document.querySelectorAll('.tree-item.has-children').forEach(item => {
const shouldBeOpen = initialTreeState.get(item);
item.classList.toggle('open', shouldBeOpen);
item.querySelector('.tree-ul').style.display = shouldBeOpen ? 'block' : 'none';
item.classList.remove('highlighted');
});
}

// Поиск по дереву
function searchTree(query) {
const term = query.toLowerCase().trim();

// Сбрасываем к исходному состоянию
resetTreeState();

// Если поиск пустой - оставляем как есть
if (!term) return;

// Ищем совпадения
let foundItems = [];
document.querySelectorAll('.tree-item').forEach(item => {
const text = item.getAttribute('data-search-text');
if (text.includes(term)) {
item.classList.add('highlighted');
foundItems.push(item);

// Раскрываем родителей
let parent = item.parentElement.closest('.tree-item');
while (parent) {
parent.classList.add('open');
parent.querySelector('.tree-ul').style.display = 'block';
parent = parent.parentElement.closest('.tree-item');
}
}
});

// Если ничего не найдено - сворачиваем всё
if (foundItems.length === 0) {
document.querySelectorAll('.tree-item.has-children').forEach(item => {
item.classList.remove('open');
item.querySelector('.tree-ul').style.display = 'none';
});
} else {
// Прокрутка к первому найденному элементу
foundItems[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}

// Инициализация при загрузке
document.addEventListener('DOMContentLoaded', function() {
initTree();

// Обработка URL параметра
const urlParams = new URLSearchParams(window.location.search);
const urlSearch = urlParams.get('q');
if (urlSearch) {
document.getElementById('tree-search-input').value = urlSearch;
searchTree(urlSearch);
}
});

// Экспортируем функции
window.searchTree = searchTree;
window.setSearchMode = function(mode) {
currentSearchMode = mode;
};
})();
AleXStamДата: Понедельник, 2025-06-23, 12:09 | Сообщение # 88
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
<div class="tree-search-panel">
<div class="tree-search-box">
<input type="text" id="tree-search-input" placeholder="Поиск в дереве..." class="tree-search-input">
<button id="tree-search-btn" class="tree-search-btn">Найти</button>
<button id="tree-search-clear" class="tree-search-clear">×</button>
</div>
<div class="search-modes">
<label><input type="radio" name="search-mode" value="instant"> Мгновенный поиск</label>
<label><input type="radio" name="search-mode" value="button" checked> Поиск по кнопке</label>
</div>
</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
const searchInput = document.getElementById('tree-search-input');
const searchBtn = document.getElementById('tree-search-btn');
const clearBtn = document.getElementById('tree-search-clear');
const modeRadios = document.querySelectorAll('input[name="search-mode"]');

let searchTimeout;

// Обработчик мгновенного поиска
function handleInstantSearch() {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
if (window.searchTree) window.searchTree(this.value);
}, 300);
}

// Инициализация режима поиска
function initSearchMode() {
const selectedMode = document.querySelector('input[name="search-mode"]:checked').value;

// Удаляем все обработчики
searchInput.removeEventListener('input', handleInstantSearch);
searchBtn.style.display = 'block';

if (selectedMode === 'instant') {
searchInput.addEventListener('input', handleInstantSearch);
searchBtn.style.display = 'none';
}

if (window.setSearchMode) {
window.setSearchMode(selectedMode);
}
}

// Инициализация
initSearchMode();

// Обработчики событий
searchBtn.addEventListener('click', function() {
if (window.searchTree) window.searchTree(searchInput.value);
});

searchInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter' && window.searchTree) {
window.searchTree(this.value);
}
});

clearBtn.addEventListener('click', function() {
searchInput.value = '';
if (window.searchTree) window.searchTree('');
});

// Переключение режимов
modeRadios.forEach(radio => {
radio.addEventListener('change', initSearchMode);
});
});
</script>
AleXStamДата: Понедельник, 2025-06-23, 12:35 | Сообщение # 89
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
.tree-search-panel {
margin-bottom: 15px;
max-width: 400px;
}

.tree-search-box {
position: relative;
display: flex;
margin-bottom: 8px;
}

.tree-search-input {
flex: 1;
padding: 8px 30px 8px 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
transition: padding 0.2s;
}

/* Когда кнопка скрыта - увеличиваем отступ для крестика */
.tree-search-input.no-button {
padding-right: 30px;
}

.tree-search-btn {
margin-left: 8px;
padding: 0 12px;
background: #f0f0f0;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
transition: opacity 0.2s, margin 0.2s;
}

.tree-search-btn.hidden {
opacity: 0;
margin-left: 0;
width: 0;
padding: 0;
border: none;
overflow: hidden;
}

.tree-search-clear {
position: absolute;
right: 10px; /* Базовое положение */
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
font-size: 16px;
color: #999;
transition: right 0.2s;
}

/* Когда кнопка видна - смещаем крестик */
.tree-search-box:not(.no-button) .tree-search-clear {
right: 90px;
}

.search-modes {
font-size: 13px;
color: #666;
}

.search-modes label {
margin-right: 10px;
cursor: pointer;
}
AleXStamДата: Понедельник, 2025-06-23, 12:35 | Сообщение # 90
AleXStam
Генералиссимус
Группа: Администраторы
Сообщений: 200
Награды: 1
Репутация: 10003
Статус: Оффлайн
// В функции initSearchMode:
function initSearchMode() {
const selectedMode = document.querySelector('input[name="search-mode"]:checked').value;
const searchBox = document.querySelector('.tree-search-box');
const searchInput = document.getElementById('tree-search-input');
const searchBtn = document.getElementById('tree-search-btn');

// Удаляем все обработчики
searchInput.removeEventListener('input', handleInstantSearch);

if (selectedMode === 'instant') {
// Мгновенный поиск
searchInput.addEventListener('input', handleInstantSearch);
searchBtn.classList.add('hidden');
searchBox.classList.add('no-button');
searchInput.classList.add('no-button');
} else {
// Поиск по кнопке
searchBtn.classList.remove('hidden');
searchBox.classList.remove('no-button');
searchInput.classList.remove('no-button');
}

if (window.setSearchMode) {
window.setSearchMode(selectedMode);
}
}
Поиск:
Новый ответ
Имя:
Текст сообщения: