Toolbar.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935
  1. /**
  2. * Copyright (c) 2006-2012, JGraph Ltd
  3. */
  4. /**
  5. * Construcs a new toolbar for the given editor.
  6. */
  7. function Toolbar(editorUi, container)
  8. {
  9. this.editorUi = editorUi;
  10. this.container = container;
  11. this.staticElements = [];
  12. this.init();
  13. // Global handler to hide the current menu
  14. this.gestureHandler = mxUtils.bind(this, function(evt)
  15. {
  16. if (this.editorUi.currentMenu != null && mxEvent.getSource(evt) != this.editorUi.currentMenu.div)
  17. {
  18. this.hideMenu();
  19. }
  20. });
  21. mxEvent.addGestureListeners(document, this.gestureHandler);
  22. };
  23. /**
  24. * Image for the dropdown arrow.
  25. */
  26. Toolbar.prototype.dropdownImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/dropdown.gif' : 'data:image/gif;base64,R0lGODlhDQANAIABAHt7e////yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCREM1NkJFMjE0NEMxMUU1ODk1Q0M5MjQ0MTA4QjNDMSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCREM1NkJFMzE0NEMxMUU1ODk1Q0M5MjQ0MTA4QjNDMSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkQzOUMzMjZCMTQ0QjExRTU4OTVDQzkyNDQxMDhCM0MxIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkQzOUMzMjZDMTQ0QjExRTU4OTVDQzkyNDQxMDhCM0MxIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Af/+/fz7+vn49/b19PPy8fDv7u3s6+rp6Ofm5eTj4uHg397d3Nva2djX1tXU09LR0M/OzczLysnIx8bFxMPCwcC/vr28u7q5uLe2tbSzsrGwr66trKuqqainpqWko6KhoJ+enZybmpmYl5aVlJOSkZCPjo2Mi4qJiIeGhYSDgoGAf359fHt6eXh3dnV0c3JxcG9ubWxramloZ2ZlZGNiYWBfXl1cW1pZWFdWVVRTUlFQT05NTEtKSUhHRkVEQ0JBQD8+PTw7Ojk4NzY1NDMyMTAvLi0sKyopKCcmJSQjIiEgHx4dHBsaGRgXFhUUExIREA8ODQwLCgkIBwYFBAMCAQAAIfkEAQAAAQAsAAAAAA0ADQAAAhGMj6nL3QAjVHIu6azbvPtWAAA7';
  27. /**
  28. * Image element for the dropdown arrow.
  29. */
  30. Toolbar.prototype.dropdownImageHtml = '<img border="0" style="position:absolute;right:4px;top:' +
  31. ((!EditorUi.compactUi) ? 8 : 6) + 'px;" src="' + Toolbar.prototype.dropdownImage + '" valign="middle"/>';
  32. /**
  33. * Defines the background for selected buttons.
  34. */
  35. Toolbar.prototype.selectedBackground = '#d0d0d0';
  36. /**
  37. * Defines the background for selected buttons.
  38. */
  39. Toolbar.prototype.unselectedBackground = 'none';
  40. /**
  41. * Array that contains the DOM nodes that should never be removed.
  42. */
  43. Toolbar.prototype.staticElements = null;
  44. /**
  45. * Adds the toolbar elements.
  46. */
  47. Toolbar.prototype.init = function()
  48. {
  49. var sw = screen.width;
  50. // Takes into account initial compact mode
  51. sw -= (screen.height > 740) ? 56 : 0;
  52. if (sw >= 700)
  53. {
  54. var formatMenu = this.addMenu('', mxResources.get('view') + ' (' + mxResources.get('panTooltip') + ')', true, 'viewPanels', null, true);
  55. this.addDropDownArrow(formatMenu, 'geSprite-formatpanel', 38, 50, -4, -3, 36, -8);
  56. this.addSeparator();
  57. }
  58. var viewMenu = this.addMenu('', mxResources.get('zoom') + ' (Alt+Mousewheel)', true, 'viewZoom', null, true);
  59. viewMenu.showDisabled = true;
  60. viewMenu.style.whiteSpace = 'nowrap';
  61. viewMenu.style.position = 'relative';
  62. viewMenu.style.overflow = 'hidden';
  63. if (EditorUi.compactUi)
  64. {
  65. viewMenu.style.width = (mxClient.IS_QUIRKS) ? '58px' : '50px';
  66. }
  67. else
  68. {
  69. viewMenu.style.width = (mxClient.IS_QUIRKS) ? '62px' : '36px';
  70. }
  71. if (sw >= 420)
  72. {
  73. this.addSeparator();
  74. var elts = this.addItems(['zoomIn', 'zoomOut']);
  75. elts[0].setAttribute('title', mxResources.get('zoomIn') + ' (' + this.editorUi.actions.get('zoomIn').shortcut + ')');
  76. elts[1].setAttribute('title', mxResources.get('zoomOut') + ' (' + this.editorUi.actions.get('zoomOut').shortcut + ')');
  77. }
  78. // Updates the label if the scale changes
  79. this.updateZoom = mxUtils.bind(this, function()
  80. {
  81. viewMenu.innerHTML = Math.round(this.editorUi.editor.graph.view.scale * 100) + '%' +
  82. this.dropdownImageHtml;
  83. if (EditorUi.compactUi)
  84. {
  85. viewMenu.getElementsByTagName('img')[0].style.right = '1px';
  86. viewMenu.getElementsByTagName('img')[0].style.top = '5px';
  87. }
  88. });
  89. this.editorUi.editor.graph.view.addListener(mxEvent.EVENT_SCALE, this.updateZoom);
  90. this.editorUi.editor.addListener('resetGraphView', this.updateZoom);
  91. var elts = this.addItems(['-', 'undo', 'redo']);
  92. elts[1].setAttribute('title', mxResources.get('undo') + ' (' + this.editorUi.actions.get('undo').shortcut + ')');
  93. elts[2].setAttribute('title', mxResources.get('redo') + ' (' + this.editorUi.actions.get('redo').shortcut + ')');
  94. if (sw >= 470)
  95. {
  96. var elts = this.addItems(['-', 'delete']);
  97. elts[1].setAttribute('title', mxResources.get('delete') + ' (' + this.editorUi.actions.get('delete').shortcut + ')');
  98. }
  99. if (sw >= 550)
  100. {
  101. this.addItems(['-', 'toFront', 'toBack']);
  102. }
  103. if (sw >= 640)
  104. {
  105. this.addItems(['-', 'fillColor', 'strokeColor', 'shadow']);
  106. }
  107. if (sw >= 320)
  108. {
  109. this.addSeparator();
  110. this.edgeShapeMenu = this.addMenuFunction('', mxResources.get('connection'), false, mxUtils.bind(this, function(menu)
  111. {
  112. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_SHAPE, 'width'], [null, null], 'geIcon geSprite geSprite-connection', null, true).setAttribute('title', mxResources.get('line'));
  113. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_SHAPE, 'width'], ['link', null], 'geIcon geSprite geSprite-linkedge', null, true).setAttribute('title', mxResources.get('link'));
  114. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_SHAPE, 'width'], ['flexArrow', null], 'geIcon geSprite geSprite-arrow', null, true).setAttribute('title', mxResources.get('arrow'));
  115. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_SHAPE, 'width'], ['arrow', null], 'geIcon geSprite geSprite-simplearrow', null, true).setAttribute('title', mxResources.get('simpleArrow'));
  116. }));
  117. this.addDropDownArrow(this.edgeShapeMenu, 'geSprite-connection', 44, 50, 0, 0, 22, -4);
  118. this.edgeStyleMenu = this.addMenuFunction('geSprite-orthogonal', mxResources.get('waypoints'), false, mxUtils.bind(this, function(menu)
  119. {
  120. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], [null, null, null], 'geIcon geSprite geSprite-straight', null, true).setAttribute('title', mxResources.get('straight'));
  121. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['orthogonalEdgeStyle', null, null], 'geIcon geSprite geSprite-orthogonal', null, true).setAttribute('title', mxResources.get('orthogonal'));
  122. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['elbowEdgeStyle', null, null, null], 'geIcon geSprite geSprite-horizontalelbow', null, true).setAttribute('title', mxResources.get('simple'));
  123. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['elbowEdgeStyle', 'vertical', null, null], 'geIcon geSprite geSprite-verticalelbow', null, true).setAttribute('title', mxResources.get('simple'));
  124. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['isometricEdgeStyle', null, null, null], 'geIcon geSprite geSprite-horizontalisometric', null, true).setAttribute('title', mxResources.get('isometric'));
  125. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['isometricEdgeStyle', 'vertical', null, null], 'geIcon geSprite geSprite-verticalisometric', null, true).setAttribute('title', mxResources.get('isometric'));
  126. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['orthogonalEdgeStyle', '1', null], 'geIcon geSprite geSprite-curved', null, true).setAttribute('title', mxResources.get('curved'));
  127. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['entityRelationEdgeStyle', null, null], 'geIcon geSprite geSprite-entity', null, true).setAttribute('title', mxResources.get('entityRelation'));
  128. }));
  129. this.addDropDownArrow(this.edgeStyleMenu, 'geSprite-orthogonal', 44, 50, 0, 0, 22, -4);
  130. }
  131. this.addSeparator();
  132. var insertMenu = this.addMenu('', mxResources.get('insert') + ' (' + mxResources.get('doubleClickTooltip') + ')', true, 'insert', null, true);
  133. this.addDropDownArrow(insertMenu, 'geSprite-plus', 38, 48, -4, -3, 36, -8);
  134. };
  135. /**
  136. * Adds the toolbar elements.
  137. */
  138. Toolbar.prototype.addDropDownArrow = function(menu, sprite, width, atlasWidth, left, top, atlasDelta, atlasLeft)
  139. {
  140. atlasDelta = (atlasDelta != null) ? atlasDelta : 32;
  141. left = (EditorUi.compactUi) ? left : atlasLeft;
  142. menu.style.whiteSpace = 'nowrap';
  143. menu.style.overflow = 'hidden';
  144. menu.style.position = 'relative';
  145. menu.innerHTML = '<div class="geSprite ' + sprite + '" style="margin-left:' + left + 'px;margin-top:' + top + 'px;"></div>' +
  146. this.dropdownImageHtml;
  147. menu.style.width = (mxClient.IS_QUIRKS) ? atlasWidth + 'px' : (atlasWidth - atlasDelta) + 'px';
  148. if (mxClient.IS_QUIRKS)
  149. {
  150. menu.style.height = (EditorUi.compactUi) ? '24px' : '26px';
  151. }
  152. // Fix for item size in kennedy theme
  153. if (EditorUi.compactUi)
  154. {
  155. menu.getElementsByTagName('img')[0].style.left = '24px';
  156. menu.getElementsByTagName('img')[0].style.top = '5px';
  157. menu.style.width = (mxClient.IS_QUIRKS) ? width + 'px' : (width - 10) + 'px';
  158. }
  159. };
  160. /**
  161. * Sets the current font name.
  162. */
  163. Toolbar.prototype.setFontName = function(value)
  164. {
  165. if (this.fontMenu != null)
  166. {
  167. this.fontMenu.innerHTML = '<div style="width:60px;overflow:hidden;display:inline-block;">' +
  168. mxUtils.htmlEntities(value) + '</div>' + this.dropdownImageHtml;
  169. }
  170. };
  171. /**
  172. * Sets the current font name.
  173. */
  174. Toolbar.prototype.setFontSize = function(value)
  175. {
  176. if (this.sizeMenu != null)
  177. {
  178. this.sizeMenu.innerHTML = '<div style="width:24px;overflow:hidden;display:inline-block;">' +
  179. value + '</div>' + this.dropdownImageHtml;
  180. }
  181. };
  182. /**
  183. * Hides the current menu.
  184. */
  185. Toolbar.prototype.createTextToolbar = function()
  186. {
  187. var graph = this.editorUi.editor.graph;
  188. var styleElt = this.addMenu('', mxResources.get('style'), true, 'formatBlock');
  189. styleElt.style.position = 'relative';
  190. styleElt.style.whiteSpace = 'nowrap';
  191. styleElt.style.overflow = 'hidden';
  192. styleElt.innerHTML = mxResources.get('style') + this.dropdownImageHtml;
  193. if (EditorUi.compactUi)
  194. {
  195. styleElt.style.paddingRight = '18px';
  196. styleElt.getElementsByTagName('img')[0].style.right = '1px';
  197. styleElt.getElementsByTagName('img')[0].style.top = '5px';
  198. }
  199. this.addSeparator();
  200. this.fontMenu = this.addMenu('', mxResources.get('fontFamily'), true, 'fontFamily');
  201. this.fontMenu.style.position = 'relative';
  202. this.fontMenu.style.whiteSpace = 'nowrap';
  203. this.fontMenu.style.overflow = 'hidden';
  204. this.fontMenu.style.width = (mxClient.IS_QUIRKS) ? '80px' : '60px';
  205. this.setFontName(Menus.prototype.defaultFont);
  206. if (EditorUi.compactUi)
  207. {
  208. this.fontMenu.style.paddingRight = '18px';
  209. this.fontMenu.getElementsByTagName('img')[0].style.right = '1px';
  210. this.fontMenu.getElementsByTagName('img')[0].style.top = '5px';
  211. }
  212. this.addSeparator();
  213. this.sizeMenu = this.addMenu(Menus.prototype.defaultFontSize, mxResources.get('fontSize'), true, 'fontSize');
  214. this.sizeMenu.style.position = 'relative';
  215. this.sizeMenu.style.whiteSpace = 'nowrap';
  216. this.sizeMenu.style.overflow = 'hidden';
  217. this.sizeMenu.style.width = (mxClient.IS_QUIRKS) ? '44px' : '24px';
  218. this.setFontSize(Menus.prototype.defaultFontSize);
  219. if (EditorUi.compactUi)
  220. {
  221. this.sizeMenu.style.paddingRight = '18px';
  222. this.sizeMenu.getElementsByTagName('img')[0].style.right = '1px';
  223. this.sizeMenu.getElementsByTagName('img')[0].style.top = '5px';
  224. }
  225. var elts = this.addItems(['-', 'undo', 'redo','-', 'bold', 'italic', 'underline']);
  226. elts[1].setAttribute('title', mxResources.get('undo') + ' (' + this.editorUi.actions.get('undo').shortcut + ')');
  227. elts[2].setAttribute('title', mxResources.get('redo') + ' (' + this.editorUi.actions.get('redo').shortcut + ')');
  228. elts[4].setAttribute('title', mxResources.get('bold') + ' (' + this.editorUi.actions.get('bold').shortcut + ')');
  229. elts[5].setAttribute('title', mxResources.get('italic') + ' (' + this.editorUi.actions.get('italic').shortcut + ')');
  230. elts[6].setAttribute('title', mxResources.get('underline') + ' (' + this.editorUi.actions.get('underline').shortcut + ')');
  231. // KNOWN: Lost focus after click on submenu with text (not icon) in quirks and IE8. This is because the TD seems
  232. // to catch the focus on click in these browsers. NOTE: Workaround in mxPopupMenu for icon items (without text).
  233. var alignMenu = this.addMenuFunction('', mxResources.get('align'), false, mxUtils.bind(this, function(menu)
  234. {
  235. elt = menu.addItem('', null, mxUtils.bind(this, function()
  236. {
  237. document.execCommand('justifyleft', false, null);
  238. }), null, 'geIcon geSprite geSprite-left');
  239. elt.setAttribute('title', mxResources.get('left'));
  240. elt = menu.addItem('', null, mxUtils.bind(this, function()
  241. {
  242. document.execCommand('justifycenter', false, null);
  243. }), null, 'geIcon geSprite geSprite-center');
  244. elt.setAttribute('title', mxResources.get('center'));
  245. elt = menu.addItem('', null, mxUtils.bind(this, function()
  246. {
  247. document.execCommand('justifyright', false, null);
  248. }), null, 'geIcon geSprite geSprite-right');
  249. elt.setAttribute('title', mxResources.get('right'));
  250. elt = menu.addItem('', null, mxUtils.bind(this, function()
  251. {
  252. document.execCommand('justifyfull', false, null);
  253. }), null, 'geIcon geSprite geSprite-justifyfull');
  254. elt.setAttribute('title', mxResources.get('justifyfull'));
  255. elt = menu.addItem('', null, mxUtils.bind(this, function()
  256. {
  257. document.execCommand('insertorderedlist', false, null);
  258. }), null, 'geIcon geSprite geSprite-orderedlist');
  259. elt.setAttribute('title', mxResources.get('numberedList'));
  260. elt = menu.addItem('', null, mxUtils.bind(this, function()
  261. {
  262. document.execCommand('insertunorderedlist', false, null);
  263. }), null, 'geIcon geSprite geSprite-unorderedlist');
  264. elt.setAttribute('title', mxResources.get('bulletedList'));
  265. elt = menu.addItem('', null, mxUtils.bind(this, function()
  266. {
  267. document.execCommand('outdent', false, null);
  268. }), null, 'geIcon geSprite geSprite-outdent');
  269. elt.setAttribute('title', mxResources.get('decreaseIndent'));
  270. elt = menu.addItem('', null, mxUtils.bind(this, function()
  271. {
  272. document.execCommand('indent', false, null);
  273. }), null, 'geIcon geSprite geSprite-indent');
  274. elt.setAttribute('title', mxResources.get('increaseIndent'));
  275. }));
  276. alignMenu.style.position = 'relative';
  277. alignMenu.style.whiteSpace = 'nowrap';
  278. alignMenu.style.overflow = 'hidden';
  279. alignMenu.innerHTML = '<div class="geSprite geSprite-left" style="margin-left:-2px;"></div>' + this.dropdownImageHtml;
  280. alignMenu.style.width = (mxClient.IS_QUIRKS) ? '50px' : '30px';
  281. if (EditorUi.compactUi)
  282. {
  283. alignMenu.getElementsByTagName('img')[0].style.left = '22px';
  284. alignMenu.getElementsByTagName('img')[0].style.top = '5px';
  285. }
  286. var formatMenu = this.addMenuFunction('', mxResources.get('format'), false, mxUtils.bind(this, function(menu)
  287. {
  288. elt = menu.addItem('', null, this.editorUi.actions.get('subscript').funct,
  289. null, 'geIcon geSprite geSprite-subscript');
  290. elt.setAttribute('title', mxResources.get('subscript') + ' (Ctrl+,)');
  291. elt = menu.addItem('', null, this.editorUi.actions.get('superscript').funct,
  292. null, 'geIcon geSprite geSprite-superscript');
  293. elt.setAttribute('title', mxResources.get('superscript') + ' (Ctrl+.)');
  294. // KNOWN: IE+FF don't return keyboard focus after color dialog (calling focus doesn't help)
  295. elt = menu.addItem('', null, this.editorUi.actions.get('fontColor').funct,
  296. null, 'geIcon geSprite geSprite-fontcolor');
  297. elt.setAttribute('title', mxResources.get('fontColor'));
  298. elt = menu.addItem('', null, this.editorUi.actions.get('backgroundColor').funct,
  299. null, 'geIcon geSprite geSprite-fontbackground');
  300. elt.setAttribute('title', mxResources.get('backgroundColor'));
  301. elt = menu.addItem('', null, mxUtils.bind(this, function()
  302. {
  303. document.execCommand('removeformat', false, null);
  304. }), null, 'geIcon geSprite geSprite-removeformat');
  305. elt.setAttribute('title', mxResources.get('removeFormat'));
  306. }));
  307. formatMenu.style.position = 'relative';
  308. formatMenu.style.whiteSpace = 'nowrap';
  309. formatMenu.style.overflow = 'hidden';
  310. formatMenu.innerHTML = '<div class="geSprite geSprite-dots" style="margin-left:-2px;"></div>' +
  311. this.dropdownImageHtml;
  312. formatMenu.style.width = (mxClient.IS_QUIRKS) ? '50px' : '30px';
  313. if (EditorUi.compactUi)
  314. {
  315. formatMenu.getElementsByTagName('img')[0].style.left = '22px';
  316. formatMenu.getElementsByTagName('img')[0].style.top = '5px';
  317. }
  318. this.addSeparator();
  319. this.addButton('geIcon geSprite geSprite-code', mxResources.get('html'), function()
  320. {
  321. graph.cellEditor.toggleViewMode();
  322. if (graph.cellEditor.textarea.innerHTML.length > 0 && (graph.cellEditor.textarea.innerHTML != '&nbsp;' || !graph.cellEditor.clearOnChange))
  323. {
  324. window.setTimeout(function()
  325. {
  326. document.execCommand('selectAll', false, null);
  327. });
  328. }
  329. });
  330. this.addSeparator();
  331. // FIXME: Uses geButton here and geLabel in main menu
  332. var insertMenu = this.addMenuFunction('', mxResources.get('insert'), true, mxUtils.bind(this, function(menu)
  333. {
  334. menu.addItem(mxResources.get('insertLink'), null, mxUtils.bind(this, function()
  335. {
  336. this.editorUi.actions.get('link').funct();
  337. }));
  338. menu.addItem(mxResources.get('insertImage'), null, mxUtils.bind(this, function()
  339. {
  340. this.editorUi.actions.get('image').funct();
  341. }));
  342. menu.addItem(mxResources.get('insertHorizontalRule'), null, mxUtils.bind(this, function()
  343. {
  344. document.execCommand('inserthorizontalrule', false, null);
  345. }));
  346. }));
  347. insertMenu.style.whiteSpace = 'nowrap';
  348. insertMenu.style.overflow = 'hidden';
  349. insertMenu.style.position = 'relative';
  350. insertMenu.innerHTML = '<div class="geSprite geSprite-plus" style="margin-left:-4px;margin-top:-3px;"></div>' +
  351. this.dropdownImageHtml;
  352. insertMenu.style.width = (mxClient.IS_QUIRKS) ? '36px' : '16px';
  353. // Fix for item size in kennedy theme
  354. if (EditorUi.compactUi)
  355. {
  356. insertMenu.getElementsByTagName('img')[0].style.left = '24px';
  357. insertMenu.getElementsByTagName('img')[0].style.top = '5px';
  358. insertMenu.style.width = (mxClient.IS_QUIRKS) ? '50px' : '30px';
  359. }
  360. this.addSeparator();
  361. // KNOWN: All table stuff does not work with undo/redo
  362. // KNOWN: Lost focus after click on submenu with text (not icon) in quirks and IE8. This is because the TD seems
  363. // to catch the focus on click in these browsers. NOTE: Workaround in mxPopupMenu for icon items (without text).
  364. var elt = this.addMenuFunction('geIcon geSprite geSprite-table', mxResources.get('table'), false, mxUtils.bind(this, function(menu)
  365. {
  366. var elt = graph.getSelectedElement();
  367. var cell = graph.getParentByName(elt, 'TD', graph.cellEditor.text2);
  368. var row = graph.getParentByName(elt, 'TR', graph.cellEditor.text2);
  369. if (row == null)
  370. {
  371. this.editorUi.menus.addInsertTableItem(menu);
  372. }
  373. else
  374. {
  375. var table = graph.getParentByName(row, 'TABLE', graph.cellEditor.text2);
  376. elt = menu.addItem('', null, mxUtils.bind(this, function()
  377. {
  378. try
  379. {
  380. graph.selectNode(graph.insertColumn(table, (cell != null) ? cell.cellIndex : 0));
  381. }
  382. catch (e)
  383. {
  384. mxUtils.alert(mxResources.get('error') + ': ' + e.message);
  385. }
  386. }), null, 'geIcon geSprite geSprite-insertcolumnbefore');
  387. elt.setAttribute('title', mxResources.get('insertColumnBefore'));
  388. elt = menu.addItem('', null, mxUtils.bind(this, function()
  389. {
  390. try
  391. {
  392. graph.selectNode(graph.insertColumn(table, (cell != null) ? cell.cellIndex + 1 : -1));
  393. }
  394. catch (e)
  395. {
  396. mxUtils.alert(mxResources.get('error') + ': ' + e.message);
  397. }
  398. }), null, 'geIcon geSprite geSprite-insertcolumnafter');
  399. elt.setAttribute('title', mxResources.get('insertColumnAfter'));
  400. elt = menu.addItem('Delete column', null, mxUtils.bind(this, function()
  401. {
  402. if (cell != null)
  403. {
  404. try
  405. {
  406. graph.deleteColumn(table, cell.cellIndex);
  407. }
  408. catch (e)
  409. {
  410. mxUtils.alert(mxResources.get('error') + ': ' + e.message);
  411. }
  412. }
  413. }), null, 'geIcon geSprite geSprite-deletecolumn');
  414. elt.setAttribute('title', mxResources.get('deleteColumn'));
  415. elt = menu.addItem('', null, mxUtils.bind(this, function()
  416. {
  417. try
  418. {
  419. graph.selectNode(graph.insertRow(table, row.sectionRowIndex));
  420. }
  421. catch (e)
  422. {
  423. mxUtils.alert(mxResources.get('error') + ': ' + e.message);
  424. }
  425. }), null, 'geIcon geSprite geSprite-insertrowbefore');
  426. elt.setAttribute('title', mxResources.get('insertRowBefore'));
  427. elt = menu.addItem('', null, mxUtils.bind(this, function()
  428. {
  429. try
  430. {
  431. graph.selectNode(graph.insertRow(table, row.sectionRowIndex + 1));
  432. }
  433. catch (e)
  434. {
  435. mxUtils.alert(mxResources.get('error') + ': ' + e.message);
  436. }
  437. }), null, 'geIcon geSprite geSprite-insertrowafter');
  438. elt.setAttribute('title', mxResources.get('insertRowAfter'));
  439. elt = menu.addItem('', null, mxUtils.bind(this, function()
  440. {
  441. try
  442. {
  443. graph.deleteRow(table, row.sectionRowIndex);
  444. }
  445. catch (e)
  446. {
  447. mxUtils.alert(mxResources.get('error') + ': ' + e.message);
  448. }
  449. }), null, 'geIcon geSprite geSprite-deleterow');
  450. elt.setAttribute('title', mxResources.get('deleteRow'));
  451. elt = menu.addItem('', null, mxUtils.bind(this, function()
  452. {
  453. // Converts rgb(r,g,b) values
  454. var color = table.style.borderColor.replace(
  455. /\brgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/g,
  456. function($0, $1, $2, $3) {
  457. return "#" + ("0"+Number($1).toString(16)).substr(-2) + ("0"+Number($2).toString(16)).substr(-2) + ("0"+Number($3).toString(16)).substr(-2);
  458. });
  459. this.editorUi.pickColor(color, function(newColor)
  460. {
  461. if (newColor == null || newColor == mxConstants.NONE)
  462. {
  463. table.removeAttribute('border');
  464. table.style.border = '';
  465. table.style.borderCollapse = '';
  466. }
  467. else
  468. {
  469. table.setAttribute('border', '1');
  470. table.style.border = '1px solid ' + newColor;
  471. table.style.borderCollapse = 'collapse';
  472. }
  473. });
  474. }), null, 'geIcon geSprite geSprite-strokecolor');
  475. elt.setAttribute('title', mxResources.get('borderColor'));
  476. elt = menu.addItem('', null, mxUtils.bind(this, function()
  477. {
  478. // Converts rgb(r,g,b) values
  479. var color = table.style.backgroundColor.replace(
  480. /\brgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/g,
  481. function($0, $1, $2, $3) {
  482. return "#" + ("0"+Number($1).toString(16)).substr(-2) + ("0"+Number($2).toString(16)).substr(-2) + ("0"+Number($3).toString(16)).substr(-2);
  483. });
  484. this.editorUi.pickColor(color, function(newColor)
  485. {
  486. if (newColor == null || newColor == mxConstants.NONE)
  487. {
  488. table.style.backgroundColor = '';
  489. }
  490. else
  491. {
  492. table.style.backgroundColor = newColor;
  493. }
  494. });
  495. }), null, 'geIcon geSprite geSprite-fillcolor');
  496. elt.setAttribute('title', mxResources.get('backgroundColor'));
  497. elt = menu.addItem('', null, mxUtils.bind(this, function()
  498. {
  499. var value = table.getAttribute('cellPadding') || 0;
  500. var dlg = new FilenameDialog(this.editorUi, value, mxResources.get('apply'), mxUtils.bind(this, function(newValue)
  501. {
  502. if (newValue != null && newValue.length > 0)
  503. {
  504. table.setAttribute('cellPadding', newValue);
  505. }
  506. else
  507. {
  508. table.removeAttribute('cellPadding');
  509. }
  510. }), mxResources.get('spacing'));
  511. this.editorUi.showDialog(dlg.container, 300, 80, true, true);
  512. dlg.init();
  513. }), null, 'geIcon geSprite geSprite-fit');
  514. elt.setAttribute('title', mxResources.get('spacing'));
  515. elt = menu.addItem('', null, mxUtils.bind(this, function()
  516. {
  517. table.setAttribute('align', 'left');
  518. }), null, 'geIcon geSprite geSprite-left');
  519. elt.setAttribute('title', mxResources.get('left'));
  520. elt = menu.addItem('', null, mxUtils.bind(this, function()
  521. {
  522. table.setAttribute('align', 'center');
  523. }), null, 'geIcon geSprite geSprite-center');
  524. elt.setAttribute('title', mxResources.get('center'));
  525. elt = menu.addItem('', null, mxUtils.bind(this, function()
  526. {
  527. table.setAttribute('align', 'right');
  528. }), null, 'geIcon geSprite geSprite-right');
  529. elt.setAttribute('title', mxResources.get('right'));
  530. }
  531. }));
  532. elt.style.position = 'relative';
  533. elt.style.whiteSpace = 'nowrap';
  534. elt.style.overflow = 'hidden';
  535. elt.innerHTML = '<div class="geSprite geSprite-table" style="margin-left:-2px;"></div>' + this.dropdownImageHtml;
  536. elt.style.width = (mxClient.IS_QUIRKS) ? '50px' : '30px';
  537. // Fix for item size in kennedy theme
  538. if (EditorUi.compactUi)
  539. {
  540. elt.getElementsByTagName('img')[0].style.left = '22px';
  541. elt.getElementsByTagName('img')[0].style.top = '5px';
  542. }
  543. };
  544. /**
  545. * Hides the current menu.
  546. */
  547. Toolbar.prototype.hideMenu = function()
  548. {
  549. this.editorUi.hideCurrentMenu();
  550. };
  551. /**
  552. * Adds a label to the toolbar.
  553. */
  554. Toolbar.prototype.addMenu = function(label, tooltip, showLabels, name, c, showAll)
  555. {
  556. var menu = this.editorUi.menus.get(name);
  557. var elt = this.addMenuFunction(label, tooltip, showLabels, function()
  558. {
  559. menu.funct.apply(menu, arguments);
  560. }, c, showAll);
  561. menu.addListener('stateChanged', function()
  562. {
  563. elt.setEnabled(menu.enabled);
  564. });
  565. return elt;
  566. };
  567. /**
  568. * Adds a label to the toolbar.
  569. */
  570. Toolbar.prototype.addMenuFunction = function(label, tooltip, showLabels, funct, c, showAll)
  571. {
  572. return this.addMenuFunctionInContainer((c != null) ? c : this.container, label, tooltip, showLabels, funct, showAll);
  573. };
  574. /**
  575. * Adds a label to the toolbar.
  576. */
  577. Toolbar.prototype.addMenuFunctionInContainer = function(container, label, tooltip, showLabels, funct, showAll)
  578. {
  579. var elt = (showLabels) ? this.createLabel(label) : this.createButton(label);
  580. this.initElement(elt, tooltip);
  581. this.addMenuHandler(elt, showLabels, funct, showAll);
  582. container.appendChild(elt);
  583. return elt;
  584. };
  585. /**
  586. * Adds a separator to the separator.
  587. */
  588. Toolbar.prototype.addSeparator = function(c)
  589. {
  590. c = (c != null) ? c : this.container;
  591. var elt = document.createElement('div');
  592. elt.className = 'geSeparator';
  593. c.appendChild(elt);
  594. return elt;
  595. };
  596. /**
  597. * Adds given action item
  598. */
  599. Toolbar.prototype.addItems = function(keys, c, ignoreDisabled)
  600. {
  601. var items = [];
  602. for (var i = 0; i < keys.length; i++)
  603. {
  604. var key = keys[i];
  605. if (key == '-')
  606. {
  607. items.push(this.addSeparator(c));
  608. }
  609. else
  610. {
  611. items.push(this.addItem('geSprite-' + key.toLowerCase(), key, c, ignoreDisabled));
  612. }
  613. }
  614. return items;
  615. };
  616. /**
  617. * Adds given action item
  618. */
  619. Toolbar.prototype.addItem = function(sprite, key, c, ignoreDisabled)
  620. {
  621. var action = this.editorUi.actions.get(key);
  622. var elt = null;
  623. if (action != null)
  624. {
  625. var tooltip = action.label;
  626. if (action.shortcut != null)
  627. {
  628. tooltip += ' (' + action.shortcut + ')';
  629. }
  630. elt = this.addButton(sprite, tooltip, action.funct, c);
  631. if (!ignoreDisabled)
  632. {
  633. elt.setEnabled(action.enabled);
  634. action.addListener('stateChanged', function()
  635. {
  636. elt.setEnabled(action.enabled);
  637. });
  638. }
  639. }
  640. return elt;
  641. };
  642. /**
  643. * Adds a button to the toolbar.
  644. */
  645. Toolbar.prototype.addButton = function(classname, tooltip, funct, c)
  646. {
  647. var elt = this.createButton(classname);
  648. c = (c != null) ? c : this.container;
  649. this.initElement(elt, tooltip);
  650. this.addClickHandler(elt, funct);
  651. c.appendChild(elt);
  652. return elt;
  653. };
  654. /**
  655. * Initializes the given toolbar element.
  656. */
  657. Toolbar.prototype.initElement = function(elt, tooltip)
  658. {
  659. // Adds tooltip
  660. if (tooltip != null)
  661. {
  662. elt.setAttribute('title', tooltip);
  663. }
  664. this.addEnabledState(elt);
  665. };
  666. /**
  667. * Adds enabled state with setter to DOM node (avoids JS wrapper).
  668. */
  669. Toolbar.prototype.addEnabledState = function(elt)
  670. {
  671. var classname = elt.className;
  672. elt.setEnabled = function(value)
  673. {
  674. elt.enabled = value;
  675. if (value)
  676. {
  677. elt.className = classname;
  678. }
  679. else
  680. {
  681. elt.className = classname + ' mxDisabled';
  682. }
  683. };
  684. elt.setEnabled(true);
  685. };
  686. /**
  687. * Adds enabled state with setter to DOM node (avoids JS wrapper).
  688. */
  689. Toolbar.prototype.addClickHandler = function(elt, funct)
  690. {
  691. if (funct != null)
  692. {
  693. mxEvent.addListener(elt, 'click', function(evt)
  694. {
  695. if (elt.enabled)
  696. {
  697. funct(evt);
  698. }
  699. mxEvent.consume(evt);
  700. });
  701. if (document.documentMode != null && document.documentMode >= 9)
  702. {
  703. // Prevents focus
  704. mxEvent.addListener(elt, 'mousedown', function(evt)
  705. {
  706. evt.preventDefault();
  707. });
  708. }
  709. }
  710. };
  711. /**
  712. * Creates and returns a new button.
  713. */
  714. Toolbar.prototype.createButton = function(classname)
  715. {
  716. var elt = document.createElement('a');
  717. elt.setAttribute('href', 'javascript:void(0);');
  718. elt.className = 'geButton';
  719. var inner = document.createElement('div');
  720. if (classname != null)
  721. {
  722. inner.className = 'geSprite ' + classname;
  723. }
  724. elt.appendChild(inner);
  725. return elt;
  726. };
  727. /**
  728. * Creates and returns a new button.
  729. */
  730. Toolbar.prototype.createLabel = function(label, tooltip)
  731. {
  732. var elt = document.createElement('a');
  733. elt.setAttribute('href', 'javascript:void(0);');
  734. elt.className = 'geLabel';
  735. mxUtils.write(elt, label);
  736. return elt;
  737. };
  738. /**
  739. * Adds a handler for showing a menu in the given element.
  740. */
  741. Toolbar.prototype.addMenuHandler = function(elt, showLabels, funct, showAll)
  742. {
  743. if (funct != null)
  744. {
  745. var graph = this.editorUi.editor.graph;
  746. var menu = null;
  747. var show = true;
  748. mxEvent.addListener(elt, 'click', mxUtils.bind(this, function(evt)
  749. {
  750. if (show && (elt.enabled == null || elt.enabled))
  751. {
  752. graph.popupMenuHandler.hideMenu();
  753. menu = new mxPopupMenu(funct);
  754. menu.div.className += ' geToolbarMenu';
  755. menu.showDisabled = showAll;
  756. menu.labels = showLabels;
  757. menu.autoExpand = true;
  758. var offset = mxUtils.getOffset(elt);
  759. menu.popup(offset.x, offset.y + elt.offsetHeight, null, evt);
  760. this.editorUi.setCurrentMenu(menu, elt);
  761. // Workaround for scrollbar hiding menu items
  762. if (!showLabels && menu.div.scrollHeight > menu.div.clientHeight)
  763. {
  764. menu.div.style.width = '40px';
  765. }
  766. // Extends destroy to reset global state
  767. menu.addListener(mxEvent.EVENT_HIDE, mxUtils.bind(this, function()
  768. {
  769. this.currentElt = null;
  770. }));
  771. }
  772. show = true;
  773. mxEvent.consume(evt);
  774. }));
  775. // Hides menu if already showing
  776. mxEvent.addListener(elt, 'mousedown', mxUtils.bind(this, function(evt)
  777. {
  778. show = this.currentElt != elt;
  779. // Prevents focus
  780. if (document.documentMode != null && document.documentMode >= 9)
  781. {
  782. evt.preventDefault();
  783. }
  784. }));
  785. }
  786. };
  787. /**
  788. * Adds a handler for showing a menu in the given element.
  789. */
  790. Toolbar.prototype.destroy = function()
  791. {
  792. if (this.gestureHandler != null)
  793. {
  794. mxEvent.removeGestureListeners(document, this.gestureHandler);
  795. this.gestureHandler = null;
  796. }
  797. };