Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/main/webapp/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>Tree View</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="tree-container"></div>
<script src="script.js"></script>
</body>
</html>
109 changes: 109 additions & 0 deletions src/main/webapp/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@

const treeContainer = document.getElementById('tree-container');

// --- Data Generation ---
function generateRandomTree(maxDepth = 3) {
const tree = [];
const numRootItems = Math.floor(Math.random() * 5) + 3; // 3 to 7 root items

for (let i = 0; i < numRootItems; i++) {
tree.push(generateRandomItem(1, maxDepth));
}

return tree;
}

function generateRandomItem(currentDepth, maxDepth) {
const item = {
label: `Item ${currentDepth}-${Math.random().toString(36).substring(2, 15)} ${'Looooooooong '.repeat(Math.floor(Math.random() * 5))}`,
active: Math.random() < 0.5,
};

if (currentDepth < maxDepth && Math.random() < 0.7) { // 70% chance of having children
item.children = [];
const numChildren = Math.floor(Math.random() * 4) + 1; // 1 to 4 children
for (let i = 0; i < numChildren; i++) {
item.children.push(generateRandomItem(currentDepth + 1, maxDepth));
}
}

return item;
}

// --- Rendering ---
function renderTree(data, parentElement) {
const treeElement = document.createElement('div');
treeElement.classList.add('tree');
parentElement.appendChild(treeElement);

data.forEach(item => {
renderItem(item, treeElement);
});
}

function renderItem(item, parentElement) {
const itemElement = document.createElement('div');
itemElement.classList.add('tree-item');
if (item.active) {
itemElement.classList.add('active');
}

const expandButton = document.createElement('div');
expandButton.classList.add('expand-button');
if (item.children) {
expandButton.textContent = '+';
}
itemElement.appendChild(expandButton);

const label = document.createElement('div');
label.classList.add('tree-label');
label.textContent = item.label;
itemElement.appendChild(label);

const activateButton = document.createElement('button');
activateButton.classList.add('activate-button');
activateButton.textContent = item.active ? 'Deactivate' : 'Activate';
itemElement.appendChild(activateButton);

parentElement.appendChild(itemElement);

if (item.children) {
const childrenContainer = document.createElement('div');
childrenContainer.classList.add('tree-item-children');
childrenContainer.style.display = 'none'; // Initially hidden
parentElement.appendChild(childrenContainer);

item.children.forEach(child => {
renderItem(child, childrenContainer);
});
}
}

// --- Event Listeners ---
treeContainer.addEventListener('click', function(event) {
const target = event.target;

if (target.classList.contains('expand-button') && target.textContent) {
const childrenContainer = target.parentElement.nextElementSibling;
if (childrenContainer && childrenContainer.classList.contains('tree-item-children')) {
if (childrenContainer.style.display === 'none') {
childrenContainer.style.display = 'block';
target.textContent = '-';
} else {
childrenContainer.style.display = 'none';
target.textContent = '+';
}
}
}

if (target.classList.contains('activate-button')) {
const itemElement = target.parentElement;
itemElement.classList.toggle('active');
const isActive = itemElement.classList.contains('active');
target.textContent = isActive ? 'Deactivate' : 'Activate';
}
});

// --- Initial Load ---
const randomTreeData = generateRandomTree();
renderTree(randomTreeData, treeContainer);
62 changes: 62 additions & 0 deletions src/main/webapp/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#tree-container {
max-width: 500px;
overflow-x: auto;
white-space: nowrap;
border: 1px solid #ccc;
padding: 10px;
}

.tree {
min-width: 100%;
display: inline-block;
}

.tree-item {
display: flex;
align-items: center;
padding: 5px;
}

.tree-item.active {
background-color: #e0e0e0;
}

.tree-item-children {
padding-left: 20px;
}

.expand-button {
cursor: pointer;
margin-right: 5px;
width: 16px;
height: 16px;
text-align: center;
line-height: 16px;
border: 1px solid #ccc;
background-color: #f0f0f0;
flex-shrink: 0;
}

.expand-button:empty {
border: none;
background-color: transparent;
cursor: default;
}

.activate-button {
margin-left: auto;
flex-shrink: 0;
position: sticky;
right: 0;
background-color: white; /* Default background */
padding-left: 5px; /* Add some space from the label */
padding-right: 5px;
}

.tree-item.active .activate-button {
background-color: #e0e0e0; /* Match active item background */
}

.tree-label {
/* No flex-grow to prevent pushing the button out */
}