Skip to content
Merged
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
85 changes: 85 additions & 0 deletions packages/dashboard/src/public/js/selection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// DEV: This file was generated by Claude Sonnet 4.5 and it works :)
// Honestly, I didn't want to write this myself because it's boring af

let savedSelection = null;

// Function to save selection
window.saveSelection = function saveSelection() {
const selection = window.getSelection();
if (selection.rangeCount > 0 && selection.toString().length > 0) {
const range = selection.getRangeAt(0);

savedSelection = {
text: selection.toString(),
startOffset: range.startOffset,
endOffset: range.endOffset,
startContainerPath: getNodePath(range.startContainer),
endContainerPath: getNodePath(range.endContainer),
};
}
};

// Function to get path to a node for later reconstruction
function getNodePath(node) {
const path = [];
let current = node;
const root = document.body; // Use body as the root instead of job-details

while (current && current !== root && current !== document.documentElement) {
const parent = current.parentNode;
if (!parent) break;

const siblings = Array.from(parent.childNodes);
const index = siblings.indexOf(current);
path.unshift({ index, nodeType: current.nodeType });
current = parent;
}

return path;
}

// Function to get node from path
function getNodeFromPath(path) {
const root = document.body; // Use body as the root instead of job-details
if (!root || !path) return null;

let current = root;
for (const step of path) {
const children = Array.from(current.childNodes);
if (step.index >= children.length) return null;
current = children[step.index];
if (current.nodeType !== step.nodeType) return null;
}

return current;
}

// Function to restore selection
window.restoreSelection = function restoreSelection() {
if (!savedSelection) return;

try {
const startContainer = getNodeFromPath(savedSelection.startContainerPath);
const endContainer = getNodeFromPath(savedSelection.endContainerPath);

if (startContainer && endContainer) {
const range = document.createRange();
range.setStart(startContainer, savedSelection.startOffset);
range.setEnd(endContainer, savedSelection.endOffset);

const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
} catch (e) {
// Selection restoration failed, try fallback with text search
console.debug("Could not restore selection:", e);
}

savedSelection = null;
};

// We don't do a htmx:afterSwap restore here because we do it in layout.ejs after hljs.highlightAll()
document.addEventListener("htmx:beforeSwap", () => {
window.saveSelection();
});
8 changes: 7 additions & 1 deletion packages/dashboard/src/views/layout.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<script src="/public/js/highlight.js"></script>
<script src="/public/js/chart.js"></script>
<script src="/public/js/scroll.js"></script>
<script src="/public/js/selection.js"></script>
</head>
<body class="h-full bg-base-100 text-base-content">
<div class="flex h-full">
Expand All @@ -28,7 +29,6 @@
v0.1.0 — OSS Edition
</div>
</aside>


<!-- Main content -->
<main id="main-section" class="flex-1 p-6 overflow-y-auto"><%- body %></main>
Expand All @@ -37,7 +37,13 @@
<script>
function loadLibs() {
feather.replace();

// Save selection before highlighting (which destroys DOM nodes)
window.saveSelection();
// Highlights all code blocks
hljs.highlightAll();
// Restore selection after highlighting
window.restoreSelection();
}

document.addEventListener("htmx:afterSwap", loadLibs);
Expand Down
Loading