/**
* Copyright (c) 2020-2025, JGraph Holdings Ltd
* Copyright (c) 2020-2025, draw.io AG
*/
/**
* Installing theme.
*/
Editor.themes.push('min');
/**
* Testing dockable windows.
*/
EditorUi.windowed = urlParams['windows'] != '0';
/**
* Code for the minimal UI theme.
*/
EditorUi.initMinimalTheme = function()
{
// Disabled in lightbox and chromeless mode
if (urlParams['lightbox'] == '1' || urlParams['chrome'] == '0' || typeof window.Format === 'undefined' || typeof window.Menus === 'undefined')
{
window.uiTheme = null;
return;
}
var iw = 0;
try
{
iw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
}
catch (e)
{
// ignore
}
Menus.prototype.autoPopup = false;
function toggleFormat(ui, visible)
{
if (EditorUi.windowed)
{
var graph = ui.editor.graph;
graph.popupMenuHandler.hideMenu();
if (ui.formatWindow == null)
{
var x = Math.max(10, ui.diagramContainer.clientWidth - 248);
var y = 60;
var h = Math.min(566, graph.container.clientHeight - 10);
ui.formatWindow = new WrapperWindow(ui, '', x, y, 240, h,
function(container)
{
container.className = 'geSidebarContainer geFormatContainer';
var format = ui.createFormat(container);
format.init();
});
ui.dependsOnLanguage(mxUtils.bind(this, function()
{
ui.formatWindow.window.setTitle(mxResources.get('format'));
}));
ui.formatWindow.window.addListener(mxEvent.SHOW, mxUtils.bind(this, function()
{
ui.formatWindow.window.fit();
}));
ui.formatWindow.window.minimumSize = new mxRectangle(0, 0, 240, 80);
}
else
{
ui.formatWindow.window.setVisible((visible != null) ?
visible : !ui.formatWindow.window.isVisible());
}
}
else
{
if (ui.formatElt == null)
{
ui.formatElt = ui.createSidebarContainer();
var format = ui.createFormat(ui.formatElt);
format.init();
ui.formatElt.style.border = 'none';
ui.formatElt.style.width = '240px';
ui.formatElt.style.borderLeftWidth = '1px';
ui.formatElt.style.borderLeftStyle = 'solid';
ui.formatElt.style.right = '0px';
}
var wrapper = ui.diagramContainer.parentNode;
if (ui.formatElt.parentNode != null)
{
ui.formatElt.parentNode.removeChild(ui.formatElt);
wrapper.style.right = '0px';
}
else
{
wrapper.parentNode.appendChild(ui.formatElt);
wrapper.style.right = ui.formatElt.style.width;
}
}
};
function toggleShapes(ui, visible)
{
if (EditorUi.windowed)
{
var graph = ui.editor.graph;
graph.popupMenuHandler.hideMenu();
if (ui.sidebarWindow == null)
{
var w = Math.min(graph.container.clientWidth - 10, 218);
var h = Math.min(graph.container.clientHeight - 40, 650);
ui.sidebarWindow = new WrapperWindow(ui, '', 10, 56, w - 6, h - 6,
function(container)
{
ui.createShapesPanel(container);
});
ui.dependsOnLanguage(mxUtils.bind(this, function()
{
ui.sidebarWindow.window.setTitle(mxResources.get('shapes'));
}));
ui.sidebarWindow.window.addListener(mxEvent.SHOW, mxUtils.bind(this, function()
{
ui.sidebarWindow.window.fit();
}));
ui.sidebarWindow.window.minimumSize = new mxRectangle(0, 0, 90, 90);
ui.sidebarWindow.window.setVisible(true);
if (isLocalStorage)
{
ui.getLocalData('sidebar', function(value)
{
ui.sidebar.showEntries(value, null, true);
});
}
ui.restoreLibraries();
}
else
{
ui.sidebarWindow.window.setVisible((visible != null) ?
visible : !ui.sidebarWindow.window.isVisible());
}
}
else
{
if (ui.sidebarElt == null)
{
ui.sidebarElt = ui.createSidebarContainer();
ui.createShapesPanel(ui.sidebarElt);
ui.sidebarElt.style.border = 'none';
ui.sidebarElt.style.width = '210px';
ui.sidebarElt.style.borderRight = '1px solid gray';
}
var wrapper = ui.diagramContainer.parentNode;
if (ui.sidebarElt.parentNode != null)
{
ui.sidebarElt.parentNode.removeChild(ui.sidebarElt);
wrapper.style.left = '0px';
}
else
{
wrapper.parentNode.appendChild(ui.sidebarElt);
wrapper.style.left = ui.sidebarElt.style.width;
}
}
};
// Changes colors for some UI elements
var fill = '#29b6f2';
mxConstraintHandler.prototype.pointImage = Graph.createSvgImage(5, 5,
'' +
'');
mxOutline.prototype.sizerImage = null;
mxConstants.VERTEX_SELECTION_COLOR = '#C0C0C0';
mxConstants.EDGE_SELECTION_COLOR = '#C0C0C0';
mxConstants.CONNECT_HANDLE_FILLCOLOR = '#cee7ff';
mxConstants.DEFAULT_VALID_COLOR = fill;
mxConstants.GUIDE_COLOR = '#C0C0C0';
mxConstants.OUTLINE_COLOR = '#29b6f2';
mxConstants.OUTLINE_HANDLE_FILLCOLOR = '#29b6f2';
mxConstants.OUTLINE_HANDLE_STROKECOLOR = '#fff';
Graph.prototype.svgShadowColor = '#3D4574';
Graph.prototype.svgShadowOpacity = '0.4';
Graph.prototype.svgShadowSize = '0.6';
Graph.prototype.svgShadowBlur = '1.2';
mxRubberband.prototype.defaultOpacity = 50;
HoverIcons.prototype.inactiveOpacity = 25;
EditorUi.prototype.closableScratchpad = false;
Graph.prototype.editAfterInsert = !mxClient.IS_IOS && !mxClient.IS_ANDROID;
/**
* Sets the XML node for the current diagram.
*/
Editor.prototype.isChromelessView = function()
{
return false;
};
/**
* Sets the XML node for the current diagram.
*/
Graph.prototype.isLightboxView = function()
{
return false;
};
// Overridden to update save menu state
/**
* Updates action states depending on the selection.
*/
var editorUiUpdateActionStates = EditorUi.prototype.updateActionStates;
EditorUi.prototype.updateActionStates = function()
{
editorUiUpdateActionStates.apply(this, arguments);
this.menus.get('save').setEnabled(this.getCurrentFile() != null || urlParams['embed'] == '1');
};
// Hides keyboard shortcuts in menus
var menusAddShortcut = Menus.prototype.addShortcut;
Menus.prototype.addShortcut = function(item, action)
{
if (action.shortcut != null && iw < 900 && !mxClient.IS_IOS)
{
var td = item.firstChild.nextSibling;
td.setAttribute('title', action.shortcut);
}
else
{
menusAddShortcut.apply(this, arguments);
}
};
// Overridden to toggle window instead
EditorUi.prototype.toggleFormatPanel = function(visible)
{
if (this.formatWindow != null)
{
this.formatWindow.window.setVisible((visible != null) ?
visible : !this.formatWindow.window.isVisible());
}
else
{
toggleFormat(this);
}
};
EditorUi.prototype.isFormatPanelVisible = function()
{
return (this.formatWindow != null && this.formatWindow.window.isVisible()) ||
(this.formatWindow == null && this.formatWidth > 0);
};
// Initializes the user interface
var editorUiDestroy = EditorUi.prototype.destroy;
EditorUi.prototype.destroy = function()
{
this.destroyWindows();
editorUiDestroy.apply(this, arguments);
};
// Hides windows when a file is closed
var editorUiSetGraphEnabled = EditorUi.prototype.setGraphEnabled;
EditorUi.prototype.setGraphEnabled = function(enabled)
{
editorUiSetGraphEnabled.apply(this, arguments);
if (!enabled)
{
if (this.sidebarWindow != null)
{
this.sidebarWindow.window.setVisible(false);
}
if (this.formatWindow != null)
{
this.formatWindow.window.setVisible(false);
}
}
else
{
var iw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
if (iw >= 1000 && this.sidebarWindow != null)
{
this.sidebarWindow.window.setVisible(true);
}
if (this.formatWindow != null && iw >= 1000)
{
this.formatWindow.window.setVisible(true);
}
}
};
// Disables centering of graph after iframe resize
EditorUi.prototype.chromelessWindowResize = function() {};
// Installs the format toolbar
EditorUi.prototype.installFormatToolbar = function(container)
{
var graph = this.editor.graph;
var div = document.createElement('div');
div.style.cssText = 'position:absolute;top:10px;z-index:1;border-radius:4px;' +
'box-shadow:0px 0px 3px 1px #d1d1d1;padding:6px;white-space:nowrap;background-color:#fff;' +
'transform:translate(-50%, 0);left:50%;';
graph.getSelectionModel().addListener(mxEvent.CHANGE, mxUtils.bind(this, function(sender, evt)
{
if (graph.getSelectionCount() > 0)
{
container.appendChild(div);
div.innerHTML = 'Selected: ' + graph.getSelectionCount();
}
else if (div.parentNode != null)
{
div.parentNode.removeChild(div);
}
}));
};
var formatWindowInitialized = false;
EditorUi.prototype.initFormatWindow = function()
{
if (!formatWindowInitialized && this.formatWindow != null)
{
formatWindowInitialized = true;
var toggleMinimized = this.formatWindow.window.toggleMinimized;
var w = 240;
this.formatWindow.window.toggleMinimized = function()
{
toggleMinimized.apply(this, arguments);
if (this.minimized)
{
w = parseInt(this.div.style.width);
this.div.style.width = '140px';
this.table.style.width = '140px';
this.div.style.left = (parseInt(this.div.style.left) + w - 140) + 'px';
}
else
{
this.div.style.width = w + 'px';
this.table.style.width = this.div.style.width;
this.div.style.left = (Math.max(0, parseInt(this.div.style.left) - w + 140)) + 'px';
}
this.fit();
};
mxEvent.addListener(this.formatWindow.window.title, 'dblclick', mxUtils.bind(this, function(evt)
{
if (mxEvent.getSource(evt) == this.formatWindow.window.title)
{
this.formatWindow.window.toggleMinimized();
}
}));
}
};
// Initializes the user interface
var editorUiInit = EditorUi.prototype.init;
EditorUi.prototype.init = function()
{
editorUiInit.apply(this, arguments);
var node = (mxUtils.isAncestorNode(document.body, this.container)) ?
this.container : this.editor.graph.container;
if (node != null)
{
node.classList.add('geSimple');
node.classList.add('geMinimal');
node.classList.remove('geClassic');
}
this.sidebar = this.createSidebar(this.sidebarContainer);
if (iw >= 1000 || urlParams['clibs'] != null || urlParams['libs'] != null ||
urlParams['search-shapes'] != null)
{
toggleShapes(this, true);
if (this.sidebar != null && urlParams['search-shapes'] != null && this.sidebar.searchShapes != null)
{
this.sidebar.searchShapes(urlParams['search-shapes']);
this.sidebar.showEntries('search');
}
}
if (EditorUi.windowed && iw >= 1000)
{
toggleFormat(this, true);
this.formatWindow.window.setVisible(true);
}
// Needed for creating elements in Format panel
var ui = this;
var graph = ui.editor.graph;
ui.toolbar = this.createToolbar(ui.createDiv('geToolbar'));
var menubar = document.createElement('div');
menubar.className = 'geMenubarContainer';
var menuObj = new Menubar(ui, menubar);
function addMenu(id, small, img)
{
var menu = ui.menus.get(id);
var elt = menuObj.addMenu(mxResources.get(id), mxUtils.bind(this, function()
{
menu.funct.apply(this, arguments);
}));
elt.className = 'geButton';
elt.setAttribute('title', mxResources.get(id));
ui.menus.menuCreated(menu, elt, 'geButton');
if (img != null)
{
elt.style.backgroundImage = 'url(' + img + ')';
elt.innerText = '';
}
return elt;
};
function addMenuItem(label, fn, small, tooltip, action, img)
{
var btn = document.createElement('a');
btn.className = 'geButton';
menubar.appendChild(btn);
if (img != null)
{
btn.style.backgroundImage = 'url(' + img + ')';
}
else
{
mxUtils.write(btn, label);
}
mxEvent.addListener(btn, 'click', function(evt)
{
if (btn.getAttribute('disabled') != 'disabled')
{
fn(evt);
}
mxEvent.consume(evt);
});
mxEvent.preventDefault(btn);
if (tooltip != null)
{
btn.setAttribute('title', tooltip);
}
if (action != null)
{
function updateState()
{
if (action.isEnabled())
{
btn.removeAttribute('disabled');
}
else
{
btn.setAttribute('disabled', 'disabled');
}
};
action.addListener('stateChanged', updateState);
graph.addListener('enabledChanged', updateState);
updateState();
}
return btn;
};
function createGroup(btns, op, container)
{
var btnGroup = document.createElement('div');
btnGroup.className = 'geButtonGroup';
for (var i = 0; i < btns.length; i++)
{
if (btns[i] != null)
{
btnGroup.appendChild(btns[i]);
}
}
menubar.appendChild(btnGroup);
return btnGroup;
};
function updateTitle()
{
var file = ui.getCurrentFile();
if (file != null && file.getTitle() != null)
{
var mode = file.getMode();
if (mode == 'google')
{
mode = 'googleDrive';
}
else if (mode == 'github')
{
mode = 'gitHub';
}
else if (mode == 'gitlab')
{
mode = 'gitLab';
}
else if (mode == 'onedrive')
{
mode = 'oneDrive';
}
mode = mxResources.get(mode);
menubar.setAttribute('title', file.getTitle() + ((mode != null) ? ' (' + mode + ')' : ''));
}
else
{
menubar.removeAttribute('title');
}
};
// Hides popup menus
var uiHideCurrentMenu = ui.hideCurrentMenu;
ui.hideCurrentMenu = function()
{
uiHideCurrentMenu.apply(this, arguments);
this.editor.graph.popupMenuHandler.hideMenu();
};
// Connects the status bar to the editor status
var uiDescriptorChanged = ui.descriptorChanged;
ui.descriptorChanged = function()
{
uiDescriptorChanged.apply(this, arguments);
updateTitle();
};
ui.setStatusText(ui.editor.getStatus());
menubar.appendChild(ui.statusContainer);
ui.buttonContainer = this.createButtonContainer();
menubar.appendChild(ui.buttonContainer);
// Container for the user element
ui.menubarContainer = ui.buttonContainer;
ui.tabContainer = this.createTabContainer();
// Overrides tab container to append zoom input
var zoomElt = this.createZoomInput(true);
var updateTabContainer = ui.updateTabContainer;
ui.updateTabContainer = function()
{
updateTabContainer.apply(this, arguments);
ui.tabContainer.appendChild(zoomElt);
};
var insertImage = Editor.addBoxImage;
// Hides hover icons if freehand is active
if (ui.hoverIcons != null)
{
var hoverIconsUpdate = ui.hoverIcons.update;
ui.hoverIcons.update = function()
{
if (!graph.freehand.isDrawing())
{
hoverIconsUpdate.apply(this, arguments);
}
};
}
// Removes sketch style from freehand shapes
if (graph.freehand != null)
{
var freehandCreateStyle = graph.freehand.createStyle;
graph.freehand.createStyle = function(stencil)
{
return freehandCreateStyle.apply(this, arguments) + 'sketch=0;';
};
}
// Connects the status bar to the editor status
ui.editor.addListener('statusChanged', mxUtils.bind(this, function()
{
ui.setStatusText(ui.editor.getStatus());
}));
ui.setStatusText(ui.editor.getStatus());
var fitFunction = function(evt)
{
if (mxEvent.isAltDown(evt))
{
ui.hideCurrentMenu();
ui.actions.get('customZoom').funct();
mxEvent.consume(evt);
}
else
{
ui.hideCurrentMenu();
ui.actions.get('smartFit').funct();
mxEvent.consume(evt);
}
};
var zoomInAction = ui.actions.get('zoomIn');
var zoomOutAction = ui.actions.get('zoomOut');
var resetViewAction = ui.actions.get('resetView');
var undoAction = ui.actions.get('undo');
var redoAction = ui.actions.get('redo');
var undoElt = addMenuItem('', undoAction.funct, null, '', undoAction, Editor.undoImage);
var redoElt = addMenuItem('', redoAction.funct, null, '', redoAction, Editor.redoImage);
var fitElt = addMenuItem('', fitFunction, true, '', resetViewAction, Editor.zoomFitImage);
ui.actions.get('toggleShapes').funct = mxUtils.bind(this, function()
{
toggleShapes(ui, null);
});
ui.container.appendChild(ui.tabContainer);
ui.container.appendChild(menubar);
ui.updateTabContainer();
if (!EditorUi.windowed && iw >= 1000)
{
toggleFormat(this, true);
}
function refreshMenu()
{
iw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
menubar.innerHTML = '';
var small = iw < 1000;
var appElt = addMenu('diagram', null, (small) ? Editor.menuImage : null);
createGroup([appElt, addMenuItem(mxResources.get('shapes'), ui.actions.get('toggleShapes').funct, null,
mxResources.get('shapes'), ui.actions.get('image'), (small) ? Editor.shapesImage : null),
addMenuItem(mxResources.get('format'), ui.actions.get('format').funct, null,
mxResources.get('format') + ' (' + ui.actions.get('format').shortcut + ')', ui.actions.get('image'),
(small) ? Editor.formatImage : null)]);
var insertElt = addMenu('insert', true, (small) ? insertImage : null);
createGroup([insertElt, addMenuItem(mxResources.get('delete'), ui.actions.get('delete').funct,
null, mxResources.get('delete'), ui.actions.get('delete'),
(small) ? Editor.trashImage : null)]);
if (!graph.isEnabled())
{
insertElt.setAttribute('disabled', 'disabled');
}
undoElt.setAttribute('title', mxResources.get('undo') +
' (' + undoAction.shortcut + ')');
redoElt.setAttribute('title', mxResources.get('redo') +
' (' + redoAction.shortcut + ')');
fitElt.setAttribute('title', mxResources.get('fit') +
' (' + Editor.ctrlKey + '+H)');
if (iw >= 411)
{
createGroup([undoElt, redoElt]);
if (iw >= 520)
{
createGroup([fitElt,
(iw >= 640) ? addMenuItem('', zoomInAction.funct, true,
mxResources.get('zoomIn') + ' (' + Editor.ctrlKey + ' +)',
zoomInAction, Editor.zoomInImage) : null,
(iw >= 640) ? addMenuItem('', zoomOutAction.funct, true,
mxResources.get('zoomOut') + ' (' + Editor.ctrlKey + ' -)',
zoomOutAction, Editor.zoomOutImage) : null]);
}
}
menubar.appendChild(ui.statusContainer);
menubar.appendChild(ui.buttonContainer);
};
refreshMenu();
ui.addListener('lockedChanged', refreshMenu);
ui.addListener('languageChanged', refreshMenu);
ui.editor.graph.addListener('enabledChanged', refreshMenu);
mxEvent.addListener(window, 'resize', function()
{
refreshMenu();
if (ui.sidebarWindow != null)
{
ui.sidebarWindow.window.fit();
}
if (ui.formatWindow != null)
{
ui.formatWindow.window.fit();
}
if (ui.actions.outlineWindow != null)
{
ui.actions.outlineWindow.window.fit();
}
if (ui.actions.layersWindow != null)
{
ui.actions.layersWindow.window.fit();
}
if (ui.menus.chatWindow != null)
{
ui.menus.chatWindow.window.fit();
}
if (ui.menus.tagsWindow != null)
{
ui.menus.tagsWindow.window.fit();
}
if (ui.menus.findWindow != null)
{
ui.menus.findWindow.window.fit();
}
if (ui.menus.findReplaceWindow != null)
{
ui.menus.findReplaceWindow.window.fit();
}
});
};
};
(function()
{
var initialized = false;
// ChromeApp has async local storage
if (uiTheme == 'min' && !initialized && !mxClient.IS_CHROMEAPP)
{
EditorUi.initMinimalTheme();
initialized = true;
}
var uiInitTheme = EditorUi.initTheme;
// For async startup like chromeos
EditorUi.initTheme = function()
{
uiInitTheme.apply(this, arguments);
if (uiTheme == 'min' && !initialized)
{
this.initMinimalTheme();
initialized = true;
}
};
})();