Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/jmandel/cornell-cfr-bookmarklet
Add nav buttons to cornell cfr
https://github.com/jmandel/cornell-cfr-bookmarklet
Last synced: 19 days ago
JSON representation
Add nav buttons to cornell cfr
- Host: GitHub
- URL: https://github.com/jmandel/cornell-cfr-bookmarklet
- Owner: jmandel
- Created: 2023-04-11T20:26:30.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2023-04-11T20:26:49.000Z (over 1 year ago)
- Last Synced: 2024-10-06T15:43:15.559Z (about 1 month ago)
- Size: 1.95 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# cornell-cfr-bookmarklet
Add nav buttons to cornell cfr```
javascript:(function() {
class TreeNode {
constructor(element) {
this.element = element;
this.id = element.id;
this.children = [];
this.parent = null;
this.next = null;
this.prev = null;
}
}function buildNodeMap() {
const nodes = Array.from(document.querySelectorAll('.enumxml')).map((el) => new TreeNode(el));
return new Map(nodes.map((node) => [node.id, node]));
}function findAncestor(nodeMap, parentId) {
while (parentId) {
const ancestor = nodeMap.get(parentId);
if (ancestor) return ancestor;
parentId = parentId.split('_').slice(0, -1).join('_');
}
return null;
}function parseHierarchy(nodeMap) {
for (const node of nodeMap.values()) {
const parentId = node.id.split('_').slice(0, -1).join('_');
const parent = findAncestor(nodeMap, parentId);
if (parent) {
node.parent = parent;
parent.children.push(node);
}
}
}function updateSiblings(nodeMap) {
for (const node of nodeMap.values()) {
const siblings = node.parent ? node.parent.children : Array.from(nodeMap.values()).filter((n) => n.parent === null);
const index = siblings.indexOf(node);
node.prev = index > 0 ? siblings[index - 1] : null;
node.next = index < siblings.length - 1 ? siblings[index + 1] : null;
}
}function createNavButton(target, indentLevel, onClick) {
const button = document.createElement('button');
button.innerText = target.id;
button.style.marginLeft = `${indentLevel * 20}px`;
button.onclick = onClick;
return button;
}function createNavigationMenu(node) {
const menu = document.createElement('div');
menu.className = 'cfr-navigation-menu';
menu.style.cssText = 'position:absolute;background:#fff;border:1px solid #ccc;padding:10px;display:none';let currentNode = node;
let level = 0;
while (currentNode.parent) {
let target = currentNode.parent;
menu.appendChild(createNavButton(target, level, () => {
target.element.scrollIntoView({ block: 'center', behavior: 'smooth' });
target.element.style.animation = 'highlight 5s';
}));
currentNode = currentNode.parent;
level++;
}[node.prev, node.next].forEach((sibling, i) => {
if (sibling) {
let target = sibling;
menu.appendChild(createNavButton(target, level, () => {
target.element.scrollIntoView({ block: 'center', behavior: 'smooth' });
target.element.style.animation = 'highlight 5s';
}));
}
});return menu;
}function enhanceNode(node) {
const menu = createNavigationMenu(node);
node.element.appendChild(menu);
node.element.addEventListener('click', () => {
menu.style.display = menu.style.display === 'none' ? 'block' : 'none';
});
}function addHighlightAnimationStyle() {
const style = document.createElement('style');
style.innerHTML = '@keyframes highlight { 0% { background-color: yellow; } 100% { background-color: inherit; } }\n.cfr-navigation-menu {display: flex; flex-direction: row;}\n.cfr-navigation-menu button {display: block;}';
document.head.appendChild(style);
}const nodeMap = buildNodeMap();
parseHierarchy(nodeMap);
updateSiblings(nodeMap);
addHighlightAnimationStyle();
nodeMap.forEach(enhanceNode);
})();
```