2 * $Id: Menus.js,v 1.13 2013-02-20 16:21:29 gaudenz Exp $
3 * Copyright (c) 2006-2012, JGraph Ltd
6 * Constructs a new graph editor
8 Menus = function(editorUi) {
9 this.editorUi = editorUi;
10 this.menus = new Object();
13 // Pre-fetches checkmark image
14 new Image().src = IMAGE_PATH + '/checkmark.gif';
18 * Adds the label menu items to the given menu and parent.
20 Menus.prototype.init = function() {
21 var graph = this.editorUi.editor.graph;
23 this.put('fontFamily', new Menu(mxUtils.bind(this, function(menu, parent) {
24 var fonts = ['Helvetica', 'Verdana', 'Times New Roman', 'Garamond',
26 'Courier New', 'Georgia', 'Lucida Console', 'Tahoma'
29 for (var i = 0; i < fonts.length; i++) {
30 var tr = this.styleChange(menu, fonts[i], [mxConstants.STYLE_FONTFAMILY], [
33 tr.firstChild.nextSibling.style.fontFamily = fonts[i];
36 menu.addSeparator(parent);
37 this.promptChange(menu, mxResources.get('custom'), '', mxConstants.DEFAULT_FONTFAMILY,
38 mxConstants.STYLE_FONTFAMILY, parent);
40 this.put('fontSize', new Menu(mxUtils.bind(this, function(menu, parent) {
41 var sizes = [6, 8, 9, 10, 11, 12, 14, 18, 24, 36, 48, 72];
43 for (var i = 0; i < sizes.length; i++) {
44 this.styleChange(menu, sizes[i], [mxConstants.STYLE_FONTSIZE], [sizes[i]],
48 menu.addSeparator(parent);
49 this.promptChange(menu, mxResources.get('custom'), '(pt)', '12',
50 mxConstants.STYLE_FONTSIZE, parent);
52 this.put('linewidth', new Menu(mxUtils.bind(this, function(menu, parent) {
53 var sizes = [1, 2, 3, 4, 8, 12, 16, 24];
55 for (var i = 0; i < sizes.length; i++) {
56 this.styleChange(menu, sizes[i] + 'px', [mxConstants.STYLE_STROKEWIDTH], [
61 menu.addSeparator(parent);
62 this.promptChange(menu, mxResources.get('custom'), '(px)', '1',
63 mxConstants.STYLE_STROKEWIDTH, parent);
65 this.put('line', new Menu(mxUtils.bind(this, function(menu, parent) {
66 this.styleChange(menu, mxResources.get('straight'), [mxConstants.STYLE_EDGE], [
69 this.styleChange(menu, mxResources.get('entityRelation'), [mxConstants.STYLE_EDGE], [
70 'entityRelationEdgeStyle'
72 menu.addSeparator(parent);
73 this.styleChange(menu, mxResources.get('horizontal'), [mxConstants.STYLE_EDGE,
74 mxConstants.STYLE_ELBOW
75 ], ['elbowEdgeStyle', 'horizontal'], null, parent);
76 this.styleChange(menu, mxResources.get('vertical'), [mxConstants.STYLE_EDGE,
77 mxConstants.STYLE_ELBOW
78 ], ['elbowEdgeStyle', 'vertical'], null, parent);
79 menu.addSeparator(parent);
80 this.styleChange(menu, mxResources.get('manual'), [mxConstants.STYLE_EDGE], [
83 this.styleChange(menu, mxResources.get('automatic'), [mxConstants.STYLE_EDGE], [
87 this.put('lineend', new Menu(mxUtils.bind(this, function(menu, parent) {
88 this.styleChange(menu, mxResources.get('classic'), [mxConstants.STYLE_ENDARROW], [
89 mxConstants.ARROW_CLASSIC
91 this.styleChange(menu, mxResources.get('openArrow'), [mxConstants.STYLE_ENDARROW], [
92 mxConstants.ARROW_OPEN
94 this.styleChange(menu, mxResources.get('block'), [mxConstants.STYLE_ENDARROW], [
95 mxConstants.ARROW_BLOCK
97 menu.addSeparator(parent);
98 this.styleChange(menu, mxResources.get('oval'), [mxConstants.STYLE_ENDARROW], [
99 mxConstants.ARROW_OVAL
101 this.styleChange(menu, mxResources.get('diamond'), [mxConstants.STYLE_ENDARROW], [
102 mxConstants.ARROW_DIAMOND
104 this.styleChange(menu, mxResources.get('diamondThin'), [mxConstants.STYLE_ENDARROW], [
105 mxConstants.ARROW_DIAMOND_THIN
107 menu.addSeparator(parent);
108 this.styleChange(menu, mxResources.get('none'), [mxConstants.STYLE_ENDARROW], [
111 menu.addSeparator(parent);
112 menu.addItem(mxResources.get('transparent'), null, function() {
113 graph.toggleCellStyles('endFill', true);
114 }, parent, null, true);
115 menu.addSeparator(parent);
116 this.promptChange(menu, mxResources.get('size'), '(px)', mxConstants.DEFAULT_MARKERSIZE,
117 mxConstants.STYLE_ENDSIZE, parent);
119 this.put('linestart', new Menu(mxUtils.bind(this, function(menu, parent) {
120 this.styleChange(menu, mxResources.get('classic'), [mxConstants.STYLE_STARTARROW], [
121 mxConstants.ARROW_CLASSIC
123 this.styleChange(menu, mxResources.get('openArrow'), [mxConstants.STYLE_STARTARROW], [
124 mxConstants.ARROW_OPEN
126 this.styleChange(menu, mxResources.get('block'), [mxConstants.STYLE_STARTARROW], [
127 mxConstants.ARROW_BLOCK
129 menu.addSeparator(parent);
130 this.styleChange(menu, mxResources.get('oval'), [mxConstants.STYLE_STARTARROW], [
131 mxConstants.ARROW_OVAL
133 this.styleChange(menu, mxResources.get('diamond'), [mxConstants.STYLE_STARTARROW], [
134 mxConstants.ARROW_DIAMOND
136 this.styleChange(menu, mxResources.get('diamondThin'), [mxConstants.STYLE_STARTARROW], [
137 mxConstants.ARROW_DIAMOND_THIN
139 menu.addSeparator(parent);
140 this.styleChange(menu, mxResources.get('none'), [mxConstants.STYLE_STARTARROW], [
143 menu.addSeparator(parent);
144 menu.addItem(mxResources.get('transparent'), null, function() {
145 graph.toggleCellStyles('startFill', true);
146 }, parent, null, true);
147 menu.addSeparator(parent);
148 this.promptChange(menu, mxResources.get('size'), '(px)', mxConstants.DEFAULT_MARKERSIZE,
149 mxConstants.STYLE_STARTSIZE, parent);
151 this.put('spacing', new Menu(mxUtils.bind(this, function(menu, parent) {
152 // Uses shadow action and line menu to analyze selection
153 var vertexSelected = this.editorUi.actions.get('shadow').enabled;
154 var edgeSelected = this.get('line').enabled;
156 if (vertexSelected || menu.showDisabled) {
157 this.promptChange(menu, mxResources.get('top'), '(px)', '0',
158 mxConstants.STYLE_SPACING_TOP, parent, vertexSelected);
159 this.promptChange(menu, mxResources.get('right'), '(px)', '0',
160 mxConstants.STYLE_SPACING_RIGHT, parent, vertexSelected);
161 this.promptChange(menu, mxResources.get('bottom'), '(px)', '0',
162 mxConstants.STYLE_SPACING_BOTTOM, parent, vertexSelected);
163 this.promptChange(menu, mxResources.get('left'), '(px)', '0',
164 mxConstants.STYLE_SPACING_LEFT, parent, vertexSelected);
165 menu.addSeparator(parent);
166 this.promptChange(menu, mxResources.get('global'), '(px)', '0',
167 mxConstants.STYLE_SPACING, parent, vertexSelected);
168 this.promptChange(menu, mxResources.get('perimeter'), '(px)', '0',
169 mxConstants.STYLE_PERIMETER_SPACING, parent, vertexSelected);
172 if (edgeSelected || menu.showDisabled) {
173 menu.addSeparator(parent);
174 this.promptChange(menu, mxResources.get('sourceSpacing'), '(px)', '0',
175 mxConstants.STYLE_SOURCE_PERIMETER_SPACING, parent, edgeSelected);
176 this.promptChange(menu, mxResources.get('targetSpacing'), '(px)', '0',
177 mxConstants.STYLE_TARGET_PERIMETER_SPACING, parent, edgeSelected);
180 this.put('format', new Menu(mxUtils.bind(this, function(menu, parent) {
181 this.addMenuItem(menu, 'style', parent);
183 this.put('text', new Menu(mxUtils.bind(this, function(menu, parent) {
184 var enabled = this.get('text').enabled;
185 menu.addSeparator(parent);
186 this.addSubmenu('fontFamily', menu, parent);
187 this.addSubmenu('fontSize', menu, parent);
188 this.addMenuItems(menu, ['-', 'bold', 'italic', 'underline', '-'],
190 this.addSubmenu('alignment', menu, parent);
191 this.addMenuItem(menu, 'wordWrap', parent);
192 menu.addSeparator(parent);
193 this.promptChange(menu, mxResources.get('textOpacity'), '(%)', '100',
194 mxConstants.STYLE_TEXT_OPACITY, parent, enabled);
195 menu.addItem(mxResources.get('hide'), null, function() {
196 graph.toggleCellStyles(mxConstants.STYLE_NOLABEL, false);
197 }, parent, null, enabled);
199 this.put('alignment', new Menu(mxUtils.bind(this, function(menu, parent) {
200 this.styleChange(menu, mxResources.get('leftAlign'), [mxConstants.STYLE_ALIGN], [
201 mxConstants.ALIGN_LEFT
203 this.styleChange(menu, mxResources.get('center'), [mxConstants.STYLE_ALIGN], [
204 mxConstants.ALIGN_CENTER
206 this.styleChange(menu, mxResources.get('rightAlign'), [mxConstants.STYLE_ALIGN], [
207 mxConstants.ALIGN_RIGHT
209 menu.addSeparator(parent);
210 this.styleChange(menu, mxResources.get('topAlign'), [mxConstants.STYLE_VERTICAL_ALIGN], [
211 mxConstants.ALIGN_TOP
213 this.styleChange(menu, mxResources.get('middle'), [mxConstants.STYLE_VERTICAL_ALIGN], [
214 mxConstants.ALIGN_MIDDLE
216 this.styleChange(menu, mxResources.get('bottomAlign'), [mxConstants.STYLE_VERTICAL_ALIGN], [
217 mxConstants.ALIGN_BOTTOM
219 menu.addSeparator(parent);
220 this.addSubmenu('position', menu, parent);
221 this.addSubmenu('spacing', menu, parent);
222 menu.addSeparator(parent);
223 var enabled = this.get('text').enabled;
224 menu.addItem(mxResources.get('vertical'), null, function() {
225 graph.toggleCellStyles(mxConstants.STYLE_HORIZONTAL, true);
226 }, parent, null, enabled);
228 this.put('position', new Menu(mxUtils.bind(this, function(menu, parent) {
229 this.styleChange(menu, mxResources.get('left'), [mxConstants.STYLE_LABEL_POSITION,
230 mxConstants.STYLE_ALIGN
231 ], [mxConstants.ALIGN_LEFT, mxConstants.ALIGN_RIGHT], null, parent);
232 this.styleChange(menu, mxResources.get('center'), [mxConstants.STYLE_LABEL_POSITION,
233 mxConstants.STYLE_ALIGN
234 ], [mxConstants.ALIGN_CENTER, mxConstants.ALIGN_CENTER], null, parent);
235 this.styleChange(menu, mxResources.get('right'), [mxConstants.STYLE_LABEL_POSITION,
236 mxConstants.STYLE_ALIGN
237 ], [mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_LEFT], null, parent);
238 menu.addSeparator(parent);
239 this.styleChange(menu, mxResources.get('top'), [mxConstants.STYLE_VERTICAL_LABEL_POSITION,
240 mxConstants.STYLE_VERTICAL_ALIGN
241 ], [mxConstants.ALIGN_TOP, mxConstants.ALIGN_BOTTOM], null, parent);
242 this.styleChange(menu, mxResources.get('middle'), [mxConstants.STYLE_VERTICAL_LABEL_POSITION,
243 mxConstants.STYLE_VERTICAL_ALIGN
244 ], [mxConstants.ALIGN_MIDDLE, mxConstants.ALIGN_MIDDLE], null, parent);
245 this.styleChange(menu, mxResources.get('bottom'), [mxConstants.STYLE_VERTICAL_LABEL_POSITION,
246 mxConstants.STYLE_VERTICAL_ALIGN
247 ], [mxConstants.ALIGN_BOTTOM, mxConstants.ALIGN_TOP], null, parent);
249 this.put('direction', new Menu(mxUtils.bind(this, function(menu, parent) {
250 menu.addItem(mxResources.get('flipH'), null, function() {
251 graph.toggleCellStyles(mxConstants.STYLE_FLIPH, false);
253 menu.addItem(mxResources.get('flipV'), null, function() {
254 graph.toggleCellStyles(mxConstants.STYLE_FLIPV, false);
256 this.addMenuItems(menu, ['-', 'tilt', 'rotation'], parent);
258 this.put('align', new Menu(mxUtils.bind(this, function(menu, parent) {
259 menu.addItem(mxResources.get('leftAlign'), null, function() {
260 graph.alignCells(mxConstants.ALIGN_LEFT);
262 menu.addItem(mxResources.get('center'), null, function() {
263 graph.alignCells(mxConstants.ALIGN_CENTER);
265 menu.addItem(mxResources.get('rightAlign'), null, function() {
266 graph.alignCells(mxConstants.ALIGN_RIGHT);
268 menu.addSeparator(parent);
269 menu.addItem(mxResources.get('topAlign'), null, function() {
270 graph.alignCells(mxConstants.ALIGN_TOP);
272 menu.addItem(mxResources.get('middle'), null, function() {
273 graph.alignCells(mxConstants.ALIGN_MIDDLE);
275 menu.addItem(mxResources.get('bottomAlign'), null, function() {
276 graph.alignCells(mxConstants.ALIGN_BOTTOM);
279 this.put('layout', new Menu(mxUtils.bind(this, function(menu, parent) {
280 // menu.addItem(mxResources.get('horizontalTree'), null, mxUtils.bind(this, function()
282 // if (!graph.isSelectionEmpty())
284 // var layout = new mxCompactTreeLayout(graph, true);
285 // layout.edgeRouting = false;
286 // layout.levelDistance = 30;
287 // this.editorUi.executeLayout(layout, true, true);
290 // menu.addItem(mxResources.get('verticalTree'), null, mxUtils.bind(this, function()
292 // if (!graph.isSelectionEmpty())
294 // var layout = new mxCompactTreeLayout(graph, false);
295 // layout.edgeRouting = false;
296 // layout.levelDistance = 30;
297 // this.editorUi.executeLayout(layout, true, true);
300 // menu.addSeparator(parent);
301 menu.addItem(mxResources.get('horizontalFlow'), null, mxUtils.bind(this,
303 var layout = new mxHierarchicalLayout(graph, mxConstants.DIRECTION_WEST);
304 this.editorUi.executeLayout(layout, true, true);
306 menu.addItem(mxResources.get('verticalFlow'), null, mxUtils.bind(this,
308 var layout = new mxHierarchicalLayout(graph, mxConstants.DIRECTION_NORTH);
309 this.editorUi.executeLayout(layout, true, true);
311 //menu.addSeparator(parent);
312 // menu.addItem(mxResources.get('organic'), null, mxUtils.bind(this, function()
314 // var layout = new mxFastOrganicLayout(graph);
315 // this.editorUi.executeLayout(layout, true, true);
317 // menu.addItem(mxResources.get('circle'), null, mxUtils.bind(this, function()
319 // var layout = new mxCircleLayout(graph);
320 // this.editorUi.executeLayout(layout, true, true, graph.getSelectionCells());
323 this.put('navigation', new Menu(mxUtils.bind(this, function(menu, parent) {
324 this.addMenuItems(menu, ['home', '-', 'exitGroup', 'enterGroup', '-',
328 this.put('arrange', new Menu(mxUtils.bind(this, function(menu, parent) {
329 this.addMenuItems(menu, ['toFront', 'toBack', '-'], parent);
330 //this.addSubmenu('direction', menu, parent);
331 this.addSubmenu('layout', menu, parent);
332 //this.addSubmenu('align', menu, parent);
333 menu.addSeparator(parent);
334 //this.addSubmenu('navigation', menu, parent);
335 this.addMenuItems(menu, ['-', 'group', 'ungroup', 'removeFromGroup'],
337 //this.addMenuItems(menu, ['-', 'group', 'ungroup', 'removeFromGroup', '-', 'autosize'], parent);
339 this.put('view', new Menu(mxUtils.bind(this, function(menu, parent) {
340 this.addMenuItems(menu, ['actualSize'], parent);
342 var scales = [0.25, 0.5, 0.75, 1, 2, 4];
344 for (var i = 0; i < scales.length; i++) {
346 menu.addItem((scale * 100) + '%', null, function() {
352 this.addMenuItems(menu, ['-', 'zoomIn', 'zoomOut', '-', 'fitWindow',
353 'customZoom', '-', 'fitPage', 'fitPageWidth'
356 this.put('file', new Menu(mxUtils.bind(this, function(menu, parent) {
357 this.addMenuItems(menu, ['new', 'open', '-', 'save', 'saveAs', 'publish',
358 '-', 'variable', '-', 'import', 'export', '-', 'editFile', '-',
362 this.put('edit', new Menu(mxUtils.bind(this, function(menu, parent) {
363 this.addMenuItems(menu, ['undo', 'redo', '-', 'cut', 'copy', 'paste',
364 'delete', '-', 'duplicate', '-',
365 'selectVertices', 'selectEdges', 'selectAll'
368 this.put('help', new Menu(mxUtils.bind(this, function(menu, parent) {
369 this.addMenuItems(menu, ['help', '-', 'about']);
374 * Adds the label menu items to the given menu and parent.
376 Menus.prototype.put = function(name, menu) {
377 this.menus[name] = menu;
381 * Adds the label menu items to the given menu and parent.
383 Menus.prototype.get = function(name) {
384 return this.menus[name];
388 * Adds the given submenu.
390 Menus.prototype.addSubmenu = function(name, menu, parent) {
391 var enabled = this.get(name).enabled;
393 if (menu.showDisabled || enabled) {
394 var submenu = menu.addItem(mxResources.get(name), null, null, parent, null,
396 this.addMenu(name, menu, submenu);
401 * Adds the label menu items to the given menu and parent.
403 Menus.prototype.addMenu = function(name, popupMenu, parent) {
404 var menu = this.get(name);
406 if (menu != null && (popupMenu.showDisabled || menu.enabled)) {
407 this.get(name).execute(popupMenu, parent);
412 * Adds a style change item to the given menu.
414 Menus.prototype.styleChange = function(menu, label, keys, values, sprite,
416 return menu.addItem(label, null, mxUtils.bind(this, function() {
417 var graph = this.editorUi.editor.graph;
419 graph.getModel().beginUpdate();
421 for (var i = 0; i < keys.length; i++) {
422 graph.setCellStyles(keys[i], values[i]);
425 graph.getModel().endUpdate();
431 * Adds a style change item with a prompt to the given menu.
433 Menus.prototype.promptChange = function(menu, label, hint, defaultValue, key,
435 return menu.addItem(label, null, mxUtils.bind(this, function() {
436 var graph = this.editorUi.editor.graph;
437 var value = defaultValue;
438 var state = graph.getView().getState(graph.getSelectionCell());
441 value = state.style[key] || value;
444 value = mxUtils.prompt(mxResources.get('enterValue') + ((hint.length > 0) ?
445 (' ' + hint) : ''), value);
447 if (value != null && value.length > 0) {
448 graph.setCellStyles(key, value);
450 }), parent, null, enabled);
454 * Creates the keyboard event handler for the current graph and history.
456 Menus.prototype.addMenuItem = function(menu, key, parent) {
457 var action = this.editorUi.actions.get(key);
459 if (action != null && (menu.showDisabled || action.enabled)) {
460 var item = menu.addItem(action.label, null, action.funct, parent, null,
463 // Adds checkmark image
464 if (action.toggleAction && action.isSelected()) {
465 this.addCheckmark(item);
468 this.addShortcut(item, action);
477 * Adds a checkmark to the given menuitem.
479 Menus.prototype.addShortcut = function(item, action) {
480 if (action.shortcut != null) {
481 var td = item.firstChild.nextSibling.nextSibling;
482 var span = document.createElement('span');
483 span.style.color = 'gray';
484 mxUtils.write(span, action.shortcut);
485 td.appendChild(span);
490 * Adds a checkmark to the given menuitem.
492 Menus.prototype.addCheckmark = function(item) {
493 var td = item.firstChild.nextSibling;
494 td.style.backgroundImage = 'url(' + IMAGE_PATH + '/checkmark.gif)';
495 td.style.backgroundRepeat = 'no-repeat';
496 td.style.backgroundPosition = '2px 50%';
500 * Creates the keyboard event handler for the current graph and history.
502 Menus.prototype.addMenuItems = function(menu, keys, parent) {
503 for (var i = 0; i < keys.length; i++) {
504 if (keys[i] == '-') {
505 menu.addSeparator(parent);
507 this.addMenuItem(menu, keys[i], parent);
513 * Creates the keyboard event handler for the current graph and history.
515 Menus.prototype.createPopupMenu = function(menu, cell, evt) {
516 var graph = this.editorUi.editor.graph;
517 menu.smartSeparators = true;
519 if (graph.isSelectionEmpty()) {
520 this.addMenuItems(menu, ['undo', 'redo', '-', 'paste', '-']);
522 this.addMenuItems(menu, ['delete', '-', 'cut', 'copy', '-', 'duplicate']);
524 if (graph.getSelectionCount() == 1 && graph.getModel().isEdge(graph.getSelectionCell())) {
525 this.addMenuItems(menu, ['setAsDefaultEdge']);
531 if (graph.getSelectionCount() > 0) {
532 this.addMenuItems(menu, ['toFront', 'toBack', '-']);
534 if (graph.getModel().isEdge(graph.getSelectionCell())) {
535 var isWaypoint = false;
536 var cell = graph.getSelectionCell();
538 if (cell != null && graph.getModel().isEdge(cell)) {
539 var handler = graph.selectionCellsHandler.getHandler(cell);
541 if (handler instanceof mxEdgeHandler && handler.bends != null && handler.bends
543 var index = handler.getHandleForEvent(new mxMouseEvent(evt));
545 // Configures removeWaypoint action before execution
546 var rmWaypointAction = this.editorUi.actions.get('removeWaypoint');
547 rmWaypointAction.handler = handler;
548 rmWaypointAction.index = index;
550 isWaypoint = index > 0 && index < handler.bends.length;
554 this.addMenuItems(menu, ['-', (isWaypoint) ? 'removeWaypoint' :
557 } else if (graph.getSelectionCount() > 1) {
559 this.addMenuItems(menu, ['group']);
564 if (graph.getSelectionCount() == 1) {
565 var link = graph.getLinkForCell(graph.getSelectionCell());
568 this.addMenuItems(menu, ['openLink']);
572 this.addMenuItems(menu, ['-', 'selectVertices', 'selectEdges', '-',
579 * Creates the keyboard event handler for the current graph and history.
581 Menus.prototype.createMenubar = function(container) {
582 var menubar = new Menubar(this.editorUi, container);
583 var menus = ['file', 'edit', 'view', 'format', 'text', 'arrange',
587 for (var i = 0; i < menus.length; i++) {
588 menubar.addMenu(mxResources.get(menus[i]), this.get(menus[i]).funct);
595 * Construcs a new menubar for the given editor.
597 function Menubar(editorUi, container) {
598 this.editorUi = editorUi;
599 this.container = container;
601 // Global handler to hide the current menu
602 mxEvent.addGestureListeners(document, mxUtils.bind(this, function(evt) {
608 * Adds the menubar elements.
610 Menubar.prototype.hideMenu = function() {
611 if (this.currentMenu != null) {
612 this.currentMenu.hideMenu();
617 * Adds a submenu to this menubar.
619 Menubar.prototype.addMenu = function(label, funct) {
620 var elt = document.createElement('a');
621 elt.setAttribute('href', 'javascript:void(0);');
622 elt.className = 'geItem';
623 mxUtils.write(elt, label);
625 this.addMenuHandler(elt, funct);
626 this.container.appendChild(elt);
632 * Adds a handler for showing a menu in the given element.
634 Menubar.prototype.addMenuHandler = function(elt, funct) {
638 var clickHandler = mxUtils.bind(this, function(evt) {
639 if (show && elt.enabled == null || elt.enabled) {
640 this.editorUi.editor.graph.panningHandler.hideMenu();
641 var menu = new mxPopupMenu(funct);
642 menu.div.className += ' geMenubarMenu';
643 menu.smartSeparators = true;
644 menu.showDisabled = true;
645 menu.autoExpand = true;
647 // Disables autoexpand and destroys menu when hidden
648 menu.hideMenu = mxUtils.bind(this, function() {
649 mxPopupMenu.prototype.hideMenu.apply(menu, arguments);
651 this.currentMenu = null;
652 this.currentElt = null;
655 // Added width of the page-sidebar
656 var x = elt.offsetLeft + document.getElementById('page-sidebar').offsetWidth +
658 // Added static height of the page-navbar
659 var y = elt.offsetTop + elt.offsetHeight + 140;
661 menu.popup(x, y, null, evt);
663 //menu.popup(elt.offsetLeft + 4, elt.offsetTop + elt.offsetHeight + 4, null, evt);
664 this.currentMenu = menu;
665 this.currentElt = elt;
669 mxEvent.consume(evt);
672 // Shows menu automatically while in expanded state
673 mxEvent.addListener(elt, 'mousemove', mxUtils.bind(this, function(evt) {
674 if (this.currentMenu != null && this.currentElt != elt) {
680 // Hides menu if already showing
681 mxEvent.addListener(elt, 'mousedown', mxUtils.bind(this, function() {
682 show = this.currentElt != elt;
685 mxEvent.addListener(elt, 'click', clickHandler);
690 * Constructs a new action for the given parameters.
692 function Menu(funct, enabled) {
693 mxEventSource.call(this);
695 this.enabled = (enabled != null) ? enabled : true;
698 // Menu inherits from mxEventSource
699 mxUtils.extend(Menu, mxEventSource);
702 * Sets the enabled state of the action and fires a stateChanged event.
704 Menu.prototype.setEnabled = function(value) {
705 if (this.enabled != value) {
706 this.enabled = value;
707 this.fireEvent(new mxEventObject('stateChanged'));
712 * Sets the enabled state of the action and fires a stateChanged event.
714 Menu.prototype.execute = function(menu, parent) {
715 this.funct(menu, parent);