diff --git a/scripts/logviewer/index.html b/scripts/logviewer/index.html
index aed67512..2245e7a8 100644
--- a/scripts/logviewer/index.html
+++ b/scripts/logviewer/index.html
@@ -72,6 +72,31 @@
grid-area: nav;
}
+ .timeline li:not(.expanded) > ol {
+ display: none;
+ }
+
+ .timeline li > div {
+ display: flex;
+ }
+
+ .timeline .toggleExpanded {
+ border: none;
+ background: none;
+ width: 24px;
+ height: 24px;
+ margin-right: 4px;
+ cursor: pointer;
+ }
+
+ .timeline .toggleExpanded:before {
+ content: "▶";
+ }
+
+ .timeline li.expanded > div > .toggleExpanded:before {
+ content: "▼";
+ }
+
.timeline ol {
list-style: none;
padding: 0 0 0 20px;
@@ -86,6 +111,13 @@
padding: 2px;
display: flex;
margin: 1px;
+ flex: 1;
+ cursor: pointer;
+ }
+
+
+ .timeline div.item:not(.has-children) {
+ margin-left: calc(24px + 4px + 1px);
}
.timeline div.item .caption {
diff --git a/scripts/logviewer/main.js b/scripts/logviewer/main.js
index 2a805787..5796e6f4 100644
--- a/scripts/logviewer/main.js
+++ b/scripts/logviewer/main.js
@@ -13,21 +13,26 @@ main.addEventListener("click", event => {
selectedItemNode.classList.remove("selected");
selectedItemNode = null;
}
- const itemNode = event.target.closest(".item");
- if (itemNode) {
- selectedItemNode = itemNode;
- selectedItemNode.classList.add("selected");
- const path = selectedItemNode.dataset.path;
- let item = rootItem;
- let parent;
- if (path.length) {
- const indices = path.split("/").map(i => parseInt(i, 10));
- for(const i of indices) {
- parent = item;
- item = itemChildren(item)[i];
+ if (event.target.classList.contains("toggleExpanded")) {
+ const li = event.target.parentElement.parentElement;
+ li.classList.toggle("expanded");
+ } else {
+ const itemNode = event.target.closest(".item");
+ if (itemNode) {
+ selectedItemNode = itemNode;
+ selectedItemNode.classList.add("selected");
+ const path = selectedItemNode.dataset.path;
+ let item = rootItem;
+ let parent;
+ if (path.length) {
+ const indices = path.split("/").map(i => parseInt(i, 10));
+ for(const i of indices) {
+ parent = item;
+ item = itemChildren(item)[i];
+ }
}
+ showItemDetails(item, parent);
}
- showItemDetails(item, parent);
}
});
@@ -96,16 +101,22 @@ function normalizeValueKey(key) {
// returns the node and the total range (recursively) occupied by the node
function itemToNode(item, path) {
+ const hasChildren = !!itemChildren(item)?.length;
const className = {
item: true,
+ "has-children": hasChildren,
error: itemError(item),
[`type-${itemType(item)}`]: !!itemType(item),
[`level-${itemLevel(item)}`]: true,
};
+
const li = t.li([
- t.div({className, "data-path": path.join("/")}, [
- t.span({class: "caption"}, itemCaption(item)),
- t.span({class: "duration"}, `(${itemDuration(item)}ms)`),
+ t.div([
+ hasChildren ? t.button({className: "toggleExpanded"}) : "",
+ t.div({className, "data-path": path.join("/")}, [
+ t.span({class: "caption"}, itemCaption(item)),
+ t.span({class: "duration"}, `(${itemDuration(item)}ms)`),
+ ])
])
]);
if (itemChildren(item) && itemChildren(item).length) {