Skip to content

Instantly share code, notes, and snippets.

@sebjwallace
Last active July 13, 2025 09:04
Show Gist options
  • Select an option

  • Save sebjwallace/fff139a7a64f118d167960b5eb0ef6a6 to your computer and use it in GitHub Desktop.

Select an option

Save sebjwallace/fff139a7a64f118d167960b5eb0ef6a6 to your computer and use it in GitHub Desktop.
drawio navigation plugin
/**
* Navigation Plus Plugin (Standalone)
* Enhances navigation: back/forward history, Command+Click page jump, and key bindings.
* Fully self-contained—no reliance on ElectronApp.js or main app navigation code.
*/
(function() {
function initPlugin() {
if (typeof Draw !== 'undefined' && Draw.loadPlugin) {
Draw.loadPlugin(function(ui) {
var graph = ui.editor.graph;
// --- Standalone navigation history ---
var navHistory = [];
var forwardStack = [];
var isNavigating = false;
// Helper to get current page
function getCurrentPage() {
return ui.currentPage || (ui.editor && ui.editor.currentPage);
}
// Helper to get all pages
function getPages() {
return ui.pages || (ui.editor && ui.editor.pages);
}
// Helper to get page id
function getPageId(page) {
return page && page.getId ? page.getId() : null;
}
// Listen for page changes to update history
if (ui && ui.editor && ui.editor.addListener) {
ui.editor.addListener('pageSelected', function(sender, evt) {
if (isNavigating) {
isNavigating = false;
return;
}
var current = getCurrentPage();
if (current) {
var currentId = getPageId(current);
if (navHistory.length === 0 || navHistory[navHistory.length - 1] !== currentId) {
navHistory.push(currentId);
}
}
// Clear forward stack on new navigation
forwardStack = [];
});
}
// --- Command+Click to navigate to page/tab links ---
graph.addListener(mxEvent.CLICK, function(sender, evt) {
var me = evt.getProperty('event'); // Mouse event
var cell = evt.getProperty('cell');
if (!cell || !me) return;
// Only trigger on Command+Click (metaKey on Mac)
if (me.metaKey) {
var link = graph.getLinkForCell(cell);
if (link && Graph.isPageLink && Graph.isPageLink(link)) {
// Find the page/tab by ID or name
var pageId = null;
var pageName = null;
if (link.charAt(0) === '#') {
pageId = link.substring(1);
} else if (link.indexOf('data:page/id,') === 0) {
pageId = link.substring('data:page/id,'.length);
} else if (link.indexOf('data:page/name,') === 0) {
pageName = decodeURIComponent(link.substring('data:page/name,'.length));
}
var foundPage = null;
var pages = getPages();
if (pageId && pages) {
for (var i = 0; i < pages.length; i++) {
if (pages[i].getId && pages[i].getId() == pageId) {
foundPage = pages[i];
break;
}
}
} else if (pageName && pages) {
for (var i = 0; i < pages.length; i++) {
if (pages[i].getName && pages[i].getName() == pageName) {
foundPage = pages[i];
break;
}
}
}
if (foundPage) {
var current = getCurrentPage();
if (current) {
var currentId = getPageId(current);
if (navHistory.length === 0 || navHistory[navHistory.length - 1] !== currentId) {
navHistory.push(currentId);
}
}
isNavigating = true;
ui.selectPage(foundPage);
// Clear forward stack on new navigation
forwardStack = [];
mxEvent.consume(me);
console.log('Navigated to page:', foundPage.getName ? foundPage.getName() : foundPage.getId());
} else {
console.log('Page not found for link:', link);
}
}
}
});
// --- Standalone back/forward navigation ---
function goBack() {
var current = getCurrentPage();
var currentId = getPageId(current);
if (navHistory.length > 1) {
// Pop current page
navHistory.pop();
var prevId = navHistory[navHistory.length - 1];
var pages = getPages();
var prevPage = null;
for (var i = 0; i < pages.length; i++) {
if (getPageId(pages[i]) === prevId) {
prevPage = pages[i];
break;
}
}
if (prevPage) {
// Push current to forward stack
if (currentId) forwardStack.push(currentId);
isNavigating = true;
ui.selectPage(prevPage);
console.log('Back navigation triggered');
}
} else {
console.log('Back navigation not available');
}
}
function goForward() {
var pages = getPages();
if (forwardStack.length > 0) {
var nextId = forwardStack.pop();
var nextPage = null;
for (var i = 0; i < pages.length; i++) {
if (getPageId(pages[i]) === nextId) {
nextPage = pages[i];
break;
}
}
if (nextPage) {
var current = getCurrentPage();
var currentId = getPageId(current);
if (currentId) navHistory.push(currentId);
isNavigating = true;
ui.selectPage(nextPage);
console.log('Forward navigation triggered');
}
} else {
console.log('Forward navigation not available');
}
}
// Keydown listener for back (Alt+Left) and forward (Alt+Right) and ⌘,
document.addEventListener('keydown', function(e) {
// Back: Alt + Left Arrow
if (e.altKey && !e.metaKey && !e.shiftKey && !e.ctrlKey && e.key === 'ArrowLeft') {
e.preventDefault();
goBack();
}
// Forward: Alt + Right Arrow
if (e.altKey && !e.metaKey && !e.shiftKey && !e.ctrlKey && e.key === 'ArrowRight') {
e.preventDefault();
goForward();
}
// Command+, (⌘,) for back navigation
if (e.metaKey && !e.shiftKey && !e.altKey && !e.ctrlKey && e.key === ',') {
e.preventDefault();
goBack();
}
});
// Log availability
console.log('Navigation Plus plugin loaded! (standalone)');
console.log('Features: Command+Click page jump, Alt+Left/Right for back/forward, ⌘, for back.');
});
} else {
setTimeout(initPlugin, 100);
}
}
initPlugin();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment