/** * Copyright (c) 2006-2012, JGraph Holdings Ltd */ /** * Construcs a new toolbar for the given editor. */ function Toolbar(editorUi, container) { this.editorUi = editorUi; this.container = container; this.init(); // Global handler to hide the current menu this.gestureHandler = mxUtils.bind(this, function(evt) { if (this.editorUi.isHideCurrentMenuEvent(evt)) { this.hideMenu(); } }); mxEvent.addGestureListeners(document, this.gestureHandler); }; /** * Adds the toolbar elements. */ Toolbar.prototype.init = function() { var viewMenu = this.addMenu(this.editorUi.menus.get('viewPanels'), null, Editor.dockRightImage); viewMenu.setAttribute('data-min-width', '720'); this.addSeparator(null, 720); var zoomInput = this.editorUi.createZoomInput(); zoomInput.setAttribute('data-min-width', '580'); this.container.appendChild(zoomInput); this.addSeparator(null, 580); this.addItems(['zoomIn', 'zoomOut'], null, null, [Editor.zoomInImage, Editor.zoomOutImage], 460); this.addSeparator(null, 460); this.addItems(['undo', 'redo'], null, null, [Editor.undoImage, Editor.redoImage]); this.addSeparator(null, 260); this.addItems(['delete'], null, null, [Editor.trashImage], 260); this.addSeparator(null, 300); this.addItems(['toFront', 'toBack'], null, null, [Editor.toFrontImage, Editor.toBackImage], 660); this.addSeparator(null, 660); this.addItems(['fillColor'], null, null, [Editor.fillColorImage], 740); this.addItems(['strokeColor'], null, null, [Editor.strokeColorImage], 780); this.addItems(['shadow'], null, null, [Editor.shadowImage], 820); this.addSeparator(null, 820); this.edgeShapeMenu = this.addMenu(this.editorUi.menus.get('edgeShape')); this.edgeShapeMenu.setAttribute('data-min-width', 440); this.edgeStyleMenu = this.addMenu(this.editorUi.menus.get('edgeStyle')); this.edgeStyleMenu.setAttribute('data-min-width', 480); this.addSeparator(null, 480); var insertMenu = this.addMenu(this.editorUi.menus.get('insert'), null, Editor.plusImage); insertMenu.setAttribute('data-min-width', 300); var shapesElt = insertMenu.cloneNode(true); shapesElt.setAttribute('data-min-width', 330); shapesElt.style.backgroundImage = 'url(' + Editor.shapesImage + ')'; this.editorUi.addShapePicker(shapesElt, true); this.container.appendChild(shapesElt); var tableMenu = this.addTableDropDown(); tableMenu.setAttribute('data-min-width', 360); this.editorUi.dependsOnLanguage(mxUtils.bind(this, function() { if (this.edgeShapeMenu != null) { this.edgeShapeMenu.setAttribute('title', mxResources.get('connection')); } if (this.edgeStyleMenu != null) { this.edgeStyleMenu.setAttribute('title', mxResources.get('waypoints')); } viewMenu.setAttribute('title', mxResources.get('view') + ' (' + mxResources.get('panTooltip') + ')'); insertMenu.setAttribute('title', mxResources.get('insert') + ' (' + mxResources.get('doubleClickTooltip') + ')'); shapesElt.setAttribute('title', mxResources.get('shapes')); tableMenu.setAttribute('title', mxResources.get('table')); })); }; /** * Adds the toolbar elements. */ Toolbar.prototype.appendDropDownImageHtml = function(elt) { elt.style.backgroundImage = 'url(' + Editor.thinExpandImage + ')'; elt.style.backgroundPosition = 'right 0px top 50%'; elt.style.paddingRight = '16px'; }; /** * Adds the toolbar elements. */ Toolbar.prototype.addTableDropDown = function() { var menuElt = this.addMenu(new Menu(mxUtils.bind(this, function(menu) { this.editorUi.menus.addInsertTableCellItem(menu); })), null, Editor.tableImage); // Connects to insert menu enabled state var menu = this.editorUi.menus.get('insert'); // Workaround for possible not a function // when extending HTML objects if (menu != null && typeof menuElt.setEnabled === 'function') { menu.addListener('stateChanged', function() { menuElt.setEnabled(menu.enabled); }); } return menuElt; }; /** * Sets the current font name. */ Toolbar.prototype.setFontName = function(value) { if (this.fontMenu != null) { this.fontMenu.innerText = ''; var div = document.createElement('span'); mxUtils.write(div, value); this.fontMenu.appendChild(div); this.appendDropDownImageHtml(this.fontMenu); } }; /** * Sets the current font name. */ Toolbar.prototype.setFontSize = function(value) { if (this.sizeMenu != null) { this.sizeMenu.innerText = ''; var div = document.createElement('span'); mxUtils.write(div, value); this.sizeMenu.appendChild(div); this.appendDropDownImageHtml(this.sizeMenu); } }; /** * Hides the current menu. */ Toolbar.prototype.createTextToolbar = function() { var ui = this.editorUi; var graph = ui.editor.graph; var styleElt = this.addMenu(this.editorUi.menus.get('formatBlock'), ''); styleElt.style.width = '54px'; styleElt.setAttribute('data-min-width', 360); this.appendDropDownImageHtml(styleElt); this.addSeparator(null, 360); var fontMenu = this.addMenu(this.editorUi.menus.get('fontFamily'), ''); this.fontMenu = fontMenu this.fontMenu.style.width = '82px'; this.fontMenu.setAttribute('data-min-width', 240); this.setFontName(Menus.prototype.defaultFont); this.addSeparator(null, 280); var sizeMenu = this.addMenu(this.editorUi.menus.get('fontSize'), Menus.prototype.defaultFontSize); this.sizeMenu = sizeMenu; this.sizeMenu.style.width = '36px'; this.sizeMenu.setAttribute('data-min-width', 280); this.setFontSize(Menus.prototype.defaultFontSize); this.addItems(['-', 'undo', 'redo'], null, null, [null, Editor.undoImage, Editor.redoImage], 560); this.addItems(['-', 'bold', 'italic', 'underline'], null, null, [null, Editor.boldImage, Editor.italicImage, Editor.underlineImage], 460); // KNOWN: Lost focus after click on submenu with text (not icon) in quirks and IE8. This is because the TD seems // to catch the focus on click in these browsers. NOTE: Workaround in mxPopupMenu for icon items (without text). var alignMenu = this.addMenu(new Menu(mxUtils.bind(this, function(menu) { elt = menu.addItem('', Editor.alignLeftImage, mxUtils.bind(this, function(evt) { graph.cellEditor.alignText(mxConstants.ALIGN_LEFT, evt); ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_ALIGN], 'values', [mxConstants.ALIGN_LEFT], 'cells', [graph.cellEditor.getEditingCell()])); })); elt.setAttribute('title', mxResources.get('left')); elt = menu.addItem('', Editor.alignCenterImage, mxUtils.bind(this, function(evt) { graph.cellEditor.alignText(mxConstants.ALIGN_CENTER, evt); ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_ALIGN], 'values', [mxConstants.ALIGN_CENTER], 'cells', [graph.cellEditor.getEditingCell()])); })); elt.setAttribute('title', mxResources.get('center')); elt = menu.addItem('', Editor.alignRightImage, mxUtils.bind(this, function(evt) { graph.cellEditor.alignText(mxConstants.ALIGN_RIGHT, evt); ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_ALIGN], 'values', [mxConstants.ALIGN_RIGHT], 'cells', [graph.cellEditor.getEditingCell()])); })); elt.setAttribute('title', mxResources.get('right')); elt = menu.addItem('', Editor.alignJustifyImage, mxUtils.bind(this, function() { document.execCommand('justifyfull', false, null); })); elt.setAttribute('title', mxResources.get('justifyfull')); elt = menu.addItem('', Editor.orderedListImage, mxUtils.bind(this, function() { document.execCommand('insertorderedlist', false, null); })); elt.setAttribute('title', mxResources.get('numberedList')); elt = menu.addItem('', Editor.unorderedListImage, mxUtils.bind(this, function() { document.execCommand('insertunorderedlist', false, null); })); elt.setAttribute('title', mxResources.get('bulletedList')); elt = menu.addItem('', Editor.indentImage, mxUtils.bind(this, function() { document.execCommand('indent', false, null); })); elt.setAttribute('title', mxResources.get('increaseIndent')); elt = menu.addItem('', Editor.outdentImage, mxUtils.bind(this, function() { document.execCommand('outdent', false, null); })); elt.setAttribute('title', mxResources.get('decreaseIndent')); })), null, Editor.alignLeftImage); alignMenu.setAttribute('data-min-width', 600); var formatMenu = this.addMenu(new Menu(mxUtils.bind(this, function(menu) { elt = menu.addItem('', Editor.subscriptImage, this.editorUi.actions.get('subscript').funct); elt.setAttribute('title', mxResources.get('subscript') + ' (' + Editor.ctrlKey + '+,)'); elt = menu.addItem('', Editor.superscriptImage, this.editorUi.actions.get('superscript').funct); elt.setAttribute('title', mxResources.get('superscript') + ' (' + Editor.ctrlKey + '+.)'); // KNOWN: IE+FF don't return keyboard focus after color dialog (calling focus doesn't help) elt = menu.addItem('', Editor.fontColorImage, this.editorUi.actions.get('fontColor').funct); elt.setAttribute('title', mxResources.get('fontColor')); elt = menu.addItem('', Editor.backgroundColorImage, this.editorUi.actions.get('backgroundColor').funct); elt.setAttribute('title', mxResources.get('backgroundColor')); elt = menu.addItem('', Editor.removeFormatImage, mxUtils.bind(this, function() { document.execCommand('removeformat', false, null); })); elt.setAttribute('title', mxResources.get('removeFormat')); })), null, Editor.textFormatImage); formatMenu.setAttribute('data-min-width', 640); this.addSeparator(null, 780); this.editorUi.addButton(Editor.codeImage, mxResources.get('html'), function() { graph.cellEditor.toggleViewMode(); if (graph.cellEditor.textarea.innerHTML.length > 0 && (graph.cellEditor.textarea.innerHTML != ' ' || !graph.cellEditor.clearOnChange)) { window.setTimeout(function() { document.execCommand('selectAll', false, null); }); } }, this.container).setAttribute('data-min-width', 780); this.addSeparator(null, 740); var insertMenu = this.addMenu(new Menu(mxUtils.bind(this, function(menu) { menu.addItem(mxResources.get('insertLink'), null, mxUtils.bind(this, function() { this.editorUi.actions.get('link').funct(); })); menu.addItem(mxResources.get('insertImage'), null, mxUtils.bind(this, function() { this.editorUi.actions.get('image').funct(); })); menu.addItem(mxResources.get('insertHorizontalRule'), null, mxUtils.bind(this, function() { document.execCommand('inserthorizontalrule', false, null); })); })), null, Editor.plusImage); insertMenu.setAttribute('data-min-width', 700); this.addSeparator(null, 700); // Table changes do no work with undo/redo var tableMenu = this.addMenu(new Menu(mxUtils.bind(this, function(menu) { var elt = graph.getSelectedElement(); var cell = graph.getParentByNames(elt, ['TD', 'TH'], graph.cellEditor.text2); var row = graph.getParentByName(elt, 'TR', graph.cellEditor.text2); if (row == null) { this.editorUi.menus.addInsertTableItem(menu); } else { var table = graph.getParentByName(row, 'TABLE', graph.cellEditor.text2); elt = menu.addItem('', Editor.addColumnLeftImage, mxUtils.bind(this, function() { try { graph.selectNode(graph.insertColumn(table, (cell != null) ? cell.cellIndex : 0)); } catch (e) { this.editorUi.handleError(e); } })); elt.setAttribute('title', mxResources.get('insertColumnBefore')); elt = menu.addItem('', Editor.addColumnRightImage, mxUtils.bind(this, function() { try { graph.selectNode(graph.insertColumn(table, (cell != null) ? cell.cellIndex + 1 : -1)); } catch (e) { this.editorUi.handleError(e); } })); elt.setAttribute('title', mxResources.get('insertColumnAfter')); elt = menu.addItem('Delete column', Editor.removeColumnImage, mxUtils.bind(this, function() { if (cell != null) { try { graph.deleteColumn(table, cell.cellIndex); } catch (e) { this.editorUi.handleError(e); } } })); elt.setAttribute('title', mxResources.get('deleteColumn')); elt = menu.addItem('', Editor.addRowAboveImage, mxUtils.bind(this, function() { try { graph.selectNode(graph.insertRow(table, row.sectionRowIndex)); } catch (e) { this.editorUi.handleError(e); } })); elt.setAttribute('title', mxResources.get('insertRowBefore')); elt = menu.addItem('', Editor.addRowBelowImage, mxUtils.bind(this, function() { try { graph.selectNode(graph.insertRow(table, row.sectionRowIndex + 1)); } catch (e) { this.editorUi.handleError(e); } })); elt.setAttribute('title', mxResources.get('insertRowAfter')); elt = menu.addItem('', Editor.removeRowImage, mxUtils.bind(this, function() { try { graph.deleteRow(table, row.sectionRowIndex); } catch (e) { this.editorUi.handleError(e); } })); elt.setAttribute('title', mxResources.get('deleteRow')); elt = menu.addItem('', Editor.strokeColorImage, mxUtils.bind(this, function() { // Converts rgb(r,g,b) values var color = table.style.borderColor.replace( /\brgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/g, function($0, $1, $2, $3) { return "#" + ("0"+Number($1).toString(16)).substr(-2) + ("0"+Number($2).toString(16)).substr(-2) + ("0"+Number($3).toString(16)).substr(-2); }); this.editorUi.pickColor(color, function(newColor) { if (newColor == null || newColor == mxConstants.NONE) { table.removeAttribute('border'); table.style.border = ''; table.style.borderCollapse = ''; } else { table.setAttribute('border', '1'); table.style.border = '1px solid ' + newColor; table.style.borderCollapse = 'collapse'; } }); })); elt.setAttribute('title', mxResources.get('borderColor')); elt = menu.addItem('', Editor.fillColorImage, mxUtils.bind(this, function() { // Converts rgb(r,g,b) values var color = table.style.backgroundColor.replace( /\brgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/g, function($0, $1, $2, $3) { return "#" + ("0"+Number($1).toString(16)).substr(-2) + ("0"+Number($2).toString(16)).substr(-2) + ("0"+Number($3).toString(16)).substr(-2); }); this.editorUi.pickColor(color, function(newColor) { if (newColor == null || newColor == mxConstants.NONE) { table.style.backgroundColor = ''; } else { table.style.backgroundColor = newColor; } }); })); elt.setAttribute('title', mxResources.get('backgroundColor')); elt = menu.addItem('', Editor.spacingImage, mxUtils.bind(this, function() { var value = table.getAttribute('cellPadding') || 0; var dlg = new FilenameDialog(this.editorUi, value, mxResources.get('apply'), mxUtils.bind(this, function(newValue) { if (newValue != null && newValue.length > 0) { table.setAttribute('cellPadding', newValue); } else { table.removeAttribute('cellPadding'); } }), mxResources.get('spacing')); this.editorUi.showDialog(dlg.container, 300, 80, true, true); dlg.init(); })); elt.setAttribute('title', mxResources.get('spacing')); elt = menu.addItem('', Editor.alignLeftImage, mxUtils.bind(this, function() { table.setAttribute('align', 'left'); })); elt.setAttribute('title', mxResources.get('left')); elt = menu.addItem('', Editor.alignCenterImage, mxUtils.bind(this, function() { table.setAttribute('align', 'center'); })); elt.setAttribute('title', mxResources.get('center')); elt = menu.addItem('', Editor.alignRightImage, mxUtils.bind(this, function() { table.setAttribute('align', 'right'); })); elt.setAttribute('title', mxResources.get('right')); } })), null, Editor.tableImage); tableMenu.setAttribute('data-min-width', 740); this.editorUi.dependsOnLanguage(mxUtils.bind(this, function() { styleElt.innerText = mxResources.get('style'); formatMenu.setAttribute('title', mxResources.get('format')); styleElt.setAttribute('title', mxResources.get('style')); fontMenu.setAttribute('title', mxResources.get('fontFamily')); sizeMenu.setAttribute('title', mxResources.get('fontSize')); insertMenu.setAttribute('title', mxResources.get('insert')); tableMenu.setAttribute('title', mxResources.get('table')); })); }; /** * Hides the current menu. */ Toolbar.prototype.hideMenu = function() { this.editorUi.hideCurrentMenu(); }; /** * Adds a label to the toolbar. */ Toolbar.prototype.setMenuText = function(menu, text) { menu.getElementsByTagName('span')[0].innerText = text }; /** * Adds a label to the toolbar. */ Toolbar.prototype.setMenuIcon = function(menu, icon) { menu.style.backgroundImage = 'url(' + icon + ')'; }; /** * Adds a label to the toolbar. */ Toolbar.prototype.addMenu = function(menu, label, icon, container) { var elt = this.editorUi.createMenuElement('', menu.funct); this.editorUi.menus.menuCreated(menu, elt, 'geButton'); if (icon != null) { elt.style.backgroundImage = 'url(' + icon + ')'; } else if (label != null) { var span = document.createElement('span'); mxUtils.write(span, label); elt.appendChild(span); } container = (container != null) ? container : this.container; container.appendChild(elt); return elt; }; /** * Adds a separator to the separator. */ Toolbar.prototype.addSeparator = function(c, minWidth) { c = (c != null) ? c : this.container; var elt = document.createElement('div'); elt.className = 'geSeparator'; c.appendChild(elt); if (minWidth != null) { elt.setAttribute('data-min-width', minWidth); } return elt; }; /** * Adds given action item */ Toolbar.prototype.addItems = function(keys, c, ignoreDisabled, icons, minWidth) { var items = []; for (var i = 0; i < keys.length; i++) { var key = keys[i]; if (key == '-') { items.push(this.addSeparator(c, minWidth)); } else { var elt = this.addItem((icons != null) ? icons[i] : null, key, c, ignoreDisabled); items.push(elt); if (minWidth != null) { elt.setAttribute('data-min-width', minWidth); } } } return items; }; /** * Adds given action item */ Toolbar.prototype.addItem = function(sprite, key, container) { var action = this.editorUi.actions.get(key); var elt = null; if (action != null) { elt = this.editorUi.addButton(sprite, '', action.funct, (container != null) ? container : this.container); this.editorUi.dependsOnLanguage(mxUtils.bind(this, function() { var tooltip = action.getTitle(); if (action.shortcut != null) { tooltip += ' (' + action.shortcut + ')'; } elt.setAttribute('title', tooltip); })); var updateEnabledState = mxUtils.bind(this, function() { if (action.enabled) { elt.removeAttribute('disabled'); } else { elt.setAttribute('disabled', 'disabled'); } }); action.addListener('stateChanged', updateEnabledState); updateEnabledState(); } return elt; }; /** * Adds a handler for showing a menu in the given element. */ Toolbar.prototype.destroy = function() { if (this.gestureHandler != null) { mxEvent.removeGestureListeners(document, this.gestureHandler); this.gestureHandler = null; } };