Minimal.js 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103
  1. /**
  2. * Installing theme.
  3. */
  4. Editor.themes.push('min');
  5. /**
  6. * Testing dockable windows.
  7. */
  8. EditorUi.windowed = urlParams['windows'] != '0';
  9. /**
  10. * Code for the minimal UI theme.
  11. */
  12. EditorUi.initMinimalTheme = function()
  13. {
  14. // Disabled in lightbox and chromeless mode
  15. if (urlParams['lightbox'] == '1' || urlParams['chrome'] == '0' || typeof window.Format === 'undefined' || typeof window.Menus === 'undefined')
  16. {
  17. window.uiTheme = null;
  18. return;
  19. }
  20. var iw = 0;
  21. try
  22. {
  23. iw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  24. }
  25. catch (e)
  26. {
  27. // ignore
  28. }
  29. Menus.prototype.autoPopup = false;
  30. function toggleFormat(ui, visible)
  31. {
  32. if (EditorUi.windowed)
  33. {
  34. var graph = ui.editor.graph;
  35. graph.popupMenuHandler.hideMenu();
  36. if (ui.formatWindow == null)
  37. {
  38. var x = Math.max(10, ui.diagramContainer.clientWidth - 248);
  39. var y = 60;
  40. var h = Math.min(566,graph.container.clientHeight - 10);
  41. ui.formatWindow = new WrapperWindow(ui, mxResources.get('format'), x, y, 240, h,
  42. function(container)
  43. {
  44. var format = ui.createFormat(container);
  45. format.init();
  46. });
  47. ui.formatWindow.window.addListener(mxEvent.SHOW, mxUtils.bind(this, function()
  48. {
  49. ui.formatWindow.window.fit();
  50. }));
  51. ui.formatWindow.window.minimumSize = new mxRectangle(0, 0, 240, 80);
  52. }
  53. else
  54. {
  55. ui.formatWindow.window.setVisible((visible != null) ?
  56. visible : !ui.formatWindow.window.isVisible());
  57. }
  58. }
  59. else
  60. {
  61. if (ui.formatElt == null)
  62. {
  63. ui.formatElt = ui.createSidebarContainer();
  64. var format = ui.createFormat(ui.formatElt);
  65. format.init();
  66. ui.formatElt.style.border = 'none';
  67. ui.formatElt.style.width = '240px';
  68. ui.formatElt.style.borderLeft = '1px solid gray';
  69. ui.formatElt.style.right = '0px';
  70. }
  71. var wrapper = ui.diagramContainer.parentNode;
  72. if (ui.formatElt.parentNode != null)
  73. {
  74. ui.formatElt.parentNode.removeChild(ui.formatElt);
  75. wrapper.style.right = '0px';
  76. }
  77. else
  78. {
  79. wrapper.parentNode.appendChild(ui.formatElt);
  80. wrapper.style.right = ui.formatElt.style.width;
  81. }
  82. }
  83. };
  84. function createSidebar(ui, container)
  85. {
  86. var css = 'position:absolute;border-width:1px;cusor:pointer;border-style:none;' +
  87. 'height:24px;bottom:0px;text-align:center;padding:8px 6px 0 6px;border-top-style:solid;' +
  88. 'width:50%;height:32px;box-sizing:border-box;font-size:11px;';
  89. var menuObj = new Menubar(ui, container);
  90. function addMenu(id, label)
  91. {
  92. var menu = ui.menus.get(id);
  93. var elt = menuObj.addMenu(label, mxUtils.bind(this, function()
  94. {
  95. // Allows extensions of menu.functid
  96. menu.funct.apply(this, arguments);
  97. }));
  98. elt.setAttribute('title', label);
  99. elt.style.cssText = css;
  100. elt.className = 'geTitle';
  101. container.appendChild(elt);
  102. return elt;
  103. };
  104. if (Editor.enableCustomLibraries && (urlParams['embed'] != '1' || urlParams['libraries'] == '1'))
  105. {
  106. // Defined in native apps together with openLibrary
  107. if (ui.actions.get('newLibrary') != null)
  108. {
  109. var div = document.createElement('div');
  110. div.style.cssText = css;
  111. div.className = 'geTitle';
  112. mxUtils.write(div, mxResources.get('newLibrary'));
  113. container.appendChild(div);
  114. mxEvent.addListener(div, 'click', this.actions.get('newLibrary').funct);
  115. var div = div.cloneNode(false);
  116. div.style.left = '50%';
  117. div.style.borderLeftStyle = 'solid';
  118. mxUtils.write(div, mxResources.get('openLibrary'));
  119. container.appendChild(div);
  120. mxEvent.addListener(div, 'click', this.actions.get('openLibrary').funct);
  121. }
  122. else
  123. {
  124. var elt = addMenu('newLibrary', mxResources.get('newLibrary'));
  125. elt.style.display = 'block';
  126. elt.style.fontSize = '11px';
  127. elt.style.left = '0';
  128. var elt = addMenu('openLibraryFrom', mxResources.get('openLibraryFrom'));
  129. elt.style.borderLeftStyle = 'solid';
  130. elt.style.display = 'block';
  131. elt.style.fontSize = '11px';
  132. elt.style.left = '50%';
  133. }
  134. }
  135. container.appendChild(ui.sidebar.container);
  136. container.style.overflow = 'hidden';
  137. };
  138. function toggleShapes(ui, visible)
  139. {
  140. if (EditorUi.windowed)
  141. {
  142. var graph = ui.editor.graph;
  143. graph.popupMenuHandler.hideMenu();
  144. if (ui.sidebarWindow == null)
  145. {
  146. var w = Math.min(graph.container.clientWidth - 10, 218);
  147. var h = Math.min(graph.container.clientHeight - 40, 650);
  148. ui.sidebarWindow = new WrapperWindow(ui, mxResources.get('shapes'),
  149. 10, 56, w - 6, h - 6, function(container)
  150. {
  151. createSidebar(ui, container);
  152. });
  153. ui.sidebarWindow.window.addListener(mxEvent.SHOW, mxUtils.bind(this, function()
  154. {
  155. ui.sidebarWindow.window.fit();
  156. }));
  157. ui.sidebarWindow.window.minimumSize = new mxRectangle(0, 0, 90, 90);
  158. ui.sidebarWindow.window.setVisible(true);
  159. if (isLocalStorage)
  160. {
  161. ui.getLocalData('sidebar', function(value)
  162. {
  163. ui.sidebar.showEntries(value, null, true);
  164. });
  165. }
  166. ui.restoreLibraries();
  167. }
  168. else
  169. {
  170. ui.sidebarWindow.window.setVisible((visible != null) ?
  171. visible : !ui.sidebarWindow.window.isVisible());
  172. }
  173. }
  174. else
  175. {
  176. if (ui.sidebarElt == null)
  177. {
  178. ui.sidebarElt = ui.createSidebarContainer();
  179. createSidebar(ui, ui.sidebarElt);
  180. ui.sidebarElt.style.border = 'none';
  181. ui.sidebarElt.style.width = '210px';
  182. ui.sidebarElt.style.borderRight = '1px solid gray';
  183. }
  184. var wrapper = ui.diagramContainer.parentNode;
  185. if (ui.sidebarElt.parentNode != null)
  186. {
  187. ui.sidebarElt.parentNode.removeChild(ui.sidebarElt);
  188. wrapper.style.left = '0px';
  189. }
  190. else
  191. {
  192. wrapper.parentNode.appendChild(ui.sidebarElt);
  193. wrapper.style.left = ui.sidebarElt.style.width;
  194. }
  195. }
  196. };
  197. // Changes colors for some UI elements
  198. var fill = '#29b6f2';
  199. Editor.checkmarkImage = Graph.createSvgImage(22, 18, '<path transform="translate(4 0)" d="M7.181,15.007a1,1,0,0,1-.793-0.391L3.222,10.5A1,1,0,1,1,4.808,9.274L7.132,12.3l6.044-8.86A1,1,0,1,1,14.83,4.569l-6.823,10a1,1,0,0,1-.8.437H7.181Z" fill="' + fill + '"/>').src;
  200. mxConstraintHandler.prototype.pointImage = Graph.createSvgImage(5, 5,
  201. '<path d="m 0 0 L 5 5 M 0 5 L 5 0" stroke-width="2" style="stroke-opacity:0.4" stroke="#ffffff"/>' +
  202. '<path d="m 0 0 L 5 5 M 0 5 L 5 0" stroke="' + fill + '"/>');
  203. mxOutline.prototype.sizerImage = null;
  204. mxConstants.VERTEX_SELECTION_COLOR = '#C0C0C0';
  205. mxConstants.EDGE_SELECTION_COLOR = '#C0C0C0';
  206. mxConstants.CONNECT_HANDLE_FILLCOLOR = '#cee7ff';
  207. mxConstants.DEFAULT_VALID_COLOR = fill;
  208. mxConstants.GUIDE_COLOR = '#C0C0C0';
  209. mxConstants.OUTLINE_COLOR = '#29b6f2';
  210. mxConstants.OUTLINE_HANDLE_FILLCOLOR = '#29b6f2';
  211. mxConstants.OUTLINE_HANDLE_STROKECOLOR = '#fff';
  212. Graph.prototype.svgShadowColor = '#3D4574';
  213. Graph.prototype.svgShadowOpacity = '0.4';
  214. Graph.prototype.svgShadowSize = '0.6';
  215. Graph.prototype.svgShadowBlur = '1.2';
  216. Format.inactiveTabBackgroundColor = '#e4e4e4';
  217. mxGraphHandler.prototype.previewColor = '#C0C0C0';
  218. mxRubberband.prototype.defaultOpacity = 50;
  219. HoverIcons.prototype.inactiveOpacity = 25;
  220. Format.prototype.showCloseButton = false;
  221. EditorUi.prototype.closableScratchpad = false;
  222. EditorUi.prototype.toolbarHeight = 46;
  223. EditorUi.prototype.footerHeight = 0;
  224. Graph.prototype.editAfterInsert = !mxClient.IS_IOS && !mxClient.IS_ANDROID;
  225. /**
  226. * Creates inline CSS element.
  227. */
  228. Editor.styleElt = document.createElement('style')
  229. Editor.styleElt.type = 'text/css';
  230. Editor.styleElt.innerHTML = Editor.createMinimalCss();
  231. document.getElementsByTagName('head')[0].appendChild(Editor.styleElt);
  232. /**
  233. * Sets the XML node for the current diagram.
  234. */
  235. Editor.prototype.isChromelessView = function()
  236. {
  237. return false;
  238. };
  239. /**
  240. * Sets the XML node for the current diagram.
  241. */
  242. Graph.prototype.isLightboxView = function()
  243. {
  244. return false;
  245. };
  246. var editorUiRefresh = EditorUi.prototype.refresh;
  247. /**
  248. * Changes refresh to only update the diagram container in sketch mode.
  249. */
  250. EditorUi.prototype.refresh = function(sizeDidChange)
  251. {
  252. editorUiRefresh.apply(this, arguments);
  253. if (this.tabContainer != null)
  254. {
  255. // Makes room for view zoom menu
  256. this.tabContainer.style.right = '62px';
  257. this.diagramContainer.style.bottom = this.tabContainerHeight + 'px';
  258. }
  259. };
  260. // Overridden to update save menu state
  261. /**
  262. * Updates action states depending on the selection.
  263. */
  264. var editorUiUpdateActionStates = EditorUi.prototype.updateActionStates;
  265. EditorUi.prototype.updateActionStates = function()
  266. {
  267. editorUiUpdateActionStates.apply(this, arguments);
  268. this.menus.get('save').setEnabled(this.getCurrentFile() != null || urlParams['embed'] == '1');
  269. };
  270. // Hides keyboard shortcuts in menus
  271. var menusAddShortcut = Menus.prototype.addShortcut;
  272. Menus.prototype.addShortcut = function(item, action)
  273. {
  274. if (action.shortcut != null && iw < 900 && !mxClient.IS_IOS)
  275. {
  276. var td = item.firstChild.nextSibling;
  277. td.setAttribute('title', action.shortcut);
  278. }
  279. else
  280. {
  281. menusAddShortcut.apply(this, arguments);
  282. }
  283. };
  284. // Overridden to toggle window instead
  285. EditorUi.prototype.toggleFormatPanel = function(visible)
  286. {
  287. if (this.formatWindow != null)
  288. {
  289. this.formatWindow.window.setVisible((visible != null) ?
  290. visible : !this.formatWindow.window.isVisible());
  291. }
  292. else
  293. {
  294. toggleFormat(this);
  295. }
  296. };
  297. EditorUi.prototype.isFormatPanelVisible = function()
  298. {
  299. return (this.formatWindow != null && this.formatWindow.window.isVisible()) ||
  300. (this.formatWindow == null && this.formatWidth > 0);
  301. };
  302. DiagramFormatPanel.prototype.isMathOptionVisible = function()
  303. {
  304. return true;
  305. };
  306. // Initializes the user interface
  307. var editorUiDestroy = EditorUi.prototype.destroy;
  308. EditorUi.prototype.destroy = function()
  309. {
  310. this.destroyWindows();
  311. editorUiDestroy.apply(this, arguments);
  312. };
  313. // Hides windows when a file is closed
  314. var editorUiSetGraphEnabled = EditorUi.prototype.setGraphEnabled;
  315. EditorUi.prototype.setGraphEnabled = function(enabled)
  316. {
  317. editorUiSetGraphEnabled.apply(this, arguments);
  318. if (!enabled)
  319. {
  320. if (this.sidebarWindow != null)
  321. {
  322. this.sidebarWindow.window.setVisible(false);
  323. }
  324. if (this.formatWindow != null)
  325. {
  326. this.formatWindow.window.setVisible(false);
  327. }
  328. }
  329. else
  330. {
  331. var iw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  332. if (iw >= 1000 && this.sidebarWindow != null)
  333. {
  334. this.sidebarWindow.window.setVisible(true);
  335. }
  336. if (this.formatWindow != null && iw >= 1000)
  337. {
  338. this.formatWindow.window.setVisible(true);
  339. }
  340. }
  341. };
  342. // Disables centering of graph after iframe resize
  343. EditorUi.prototype.chromelessWindowResize = function() {};
  344. // Adds actions and menus
  345. var menusInit = Menus.prototype.init;
  346. Menus.prototype.init = function()
  347. {
  348. menusInit.apply(this, arguments);
  349. var ui = this.editorUi;
  350. if (EditorUi.enablePlantUml && !ui.isOffline())
  351. {
  352. ui.actions.put('plantUml', new Action(mxResources.get('plantUml') + '...', function()
  353. {
  354. var dlg = new ParseDialog(ui, mxResources.get('plantUml') + '...', 'plantUml');
  355. ui.showDialog(dlg.container, 620, 420, true, false);
  356. dlg.init();
  357. }));
  358. }
  359. ui.actions.put('mermaid', new Action(mxResources.get('mermaid') + '...', function()
  360. {
  361. var dlg = new ParseDialog(ui, mxResources.get('mermaid') + '...', 'mermaid');
  362. ui.showDialog(dlg.container, 620, 420, true, false);
  363. dlg.init();
  364. }));
  365. var methods = ['horizontalFlow', 'verticalFlow', '-', 'horizontalTree', 'verticalTree',
  366. 'radialTree', '-', 'organic', 'circle'];
  367. var addInsertItem = function(menu, parent, title, method)
  368. {
  369. menu.addItem(title, null, mxUtils.bind(this, function()
  370. {
  371. var dlg = new CreateGraphDialog(ui, title, method);
  372. ui.showDialog(dlg.container, 620, 420, true, false);
  373. // Executed after dialog is added to dom
  374. dlg.init();
  375. }), parent);
  376. };
  377. this.put('insertLayout', new Menu(mxUtils.bind(this, function(menu, parent)
  378. {
  379. for (var i = 0; i < methods.length; i++)
  380. {
  381. if (methods[i] == '-')
  382. {
  383. menu.addSeparator(parent);
  384. }
  385. else
  386. {
  387. addInsertItem(menu, parent, mxResources.get(methods[i]) + '...', methods[i]);
  388. }
  389. }
  390. })));
  391. };
  392. // Installs the format toolbar
  393. EditorUi.prototype.installFormatToolbar = function(container)
  394. {
  395. var graph = this.editor.graph;
  396. var div = document.createElement('div');
  397. div.style.cssText = 'position:absolute;top:10px;z-index:1;border-radius:4px;' +
  398. 'box-shadow:0px 0px 3px 1px #d1d1d1;padding:6px;white-space:nowrap;background-color:#fff;' +
  399. 'transform:translate(-50%, 0);left:50%;';
  400. graph.getSelectionModel().addListener(mxEvent.CHANGE, mxUtils.bind(this, function(sender, evt)
  401. {
  402. if (graph.getSelectionCount() > 0)
  403. {
  404. container.appendChild(div);
  405. div.innerHTML = 'Selected: ' + graph.getSelectionCount();
  406. }
  407. else if (div.parentNode != null)
  408. {
  409. div.parentNode.removeChild(div);
  410. }
  411. }));
  412. };
  413. var formatWindowInitialized = false;
  414. EditorUi.prototype.initFormatWindow = function()
  415. {
  416. if (!formatWindowInitialized && this.formatWindow != null)
  417. {
  418. formatWindowInitialized = true;
  419. var toggleMinimized = this.formatWindow.window.toggleMinimized;
  420. var w = 240;
  421. this.formatWindow.window.toggleMinimized = function()
  422. {
  423. toggleMinimized.apply(this, arguments);
  424. if (this.minimized)
  425. {
  426. w = parseInt(this.div.style.width);
  427. this.div.style.width = '140px';
  428. this.table.style.width = '140px';
  429. this.div.style.left = (parseInt(this.div.style.left) + w - 140) + 'px';
  430. }
  431. else
  432. {
  433. this.div.style.width = w + 'px';
  434. this.table.style.width = this.div.style.width;
  435. this.div.style.left = (Math.max(0, parseInt(this.div.style.left) - w + 140)) + 'px';
  436. }
  437. this.fit();
  438. };
  439. mxEvent.addListener(this.formatWindow.window.title, 'dblclick', mxUtils.bind(this, function(evt)
  440. {
  441. if (mxEvent.getSource(evt) == this.formatWindow.window.title)
  442. {
  443. this.formatWindow.window.toggleMinimized();
  444. }
  445. }));
  446. }
  447. };
  448. // Initializes the user interface
  449. var editorUiInit = EditorUi.prototype.init;
  450. EditorUi.prototype.init = function()
  451. {
  452. editorUiInit.apply(this, arguments);
  453. var libs = Editor.enableCustomLibraries && (urlParams['embed'] != '1' ||
  454. urlParams['libraries'] == '1');
  455. var div = document.createElement('div');
  456. div.style.cssText = 'position:absolute;left:0px;right:0px;top:0px;overflow-y:auto;overflow-x:hidden;';
  457. div.style.bottom = (libs) ? '32px' : '0px';
  458. this.sidebar = this.createSidebar(div);
  459. if (iw >= 1000 || urlParams['clibs'] != null || urlParams['libs'] != null ||
  460. urlParams['search-shapes'] != null)
  461. {
  462. toggleShapes(this, true);
  463. if (this.sidebar != null && urlParams['search-shapes'] != null && this.sidebar.searchShapes != null)
  464. {
  465. this.sidebar.searchShapes(urlParams['search-shapes']);
  466. this.sidebar.showEntries('search');
  467. }
  468. }
  469. if (EditorUi.windowed && iw >= 1000)
  470. {
  471. toggleFormat(this, true);
  472. this.formatWindow.window.setVisible(true);
  473. }
  474. // Needed for creating elements in Format panel
  475. var ui = this;
  476. var graph = ui.editor.graph;
  477. ui.toolbar = this.createToolbar(ui.createDiv('geToolbar'));
  478. ui.defaultLibraryName = mxResources.get('untitledLibrary');
  479. var menubar = document.createElement('div');
  480. menubar.className = 'geMenubarContainer';
  481. var before = null;
  482. var menuObj = new Menubar(ui, menubar);
  483. function addMenu(id, small, img)
  484. {
  485. var menu = ui.menus.get(id);
  486. var elt = menuObj.addMenu(mxResources.get(id), mxUtils.bind(this, function()
  487. {
  488. // Allows extensions of menu.functid
  489. if (!elt.classList.contains('mxDisabled'))
  490. {
  491. menu.funct.apply(this, arguments);
  492. }
  493. }), before);
  494. elt.className = 'geMenuItem';
  495. elt.style.display = 'inline-block';
  496. elt.style.boxSizing = 'border-box';
  497. elt.style.top = '6px';
  498. elt.style.marginRight = '6px';
  499. elt.style.height = '30px';
  500. elt.style.paddingTop = '6px';
  501. elt.style.paddingBottom = '6px';
  502. elt.style.cursor = 'pointer';
  503. elt.setAttribute('title', mxResources.get(id));
  504. ui.menus.menuCreated(menu, elt, 'geMenuItem');
  505. if (img != null)
  506. {
  507. elt.style.backgroundImage = 'url(' + img + ')';
  508. elt.style.backgroundPosition = 'center center';
  509. elt.style.backgroundRepeat = 'no-repeat';
  510. elt.style.backgroundSize = '24px 24px';
  511. elt.style.width = '34px';
  512. elt.innerText = '';
  513. }
  514. else if (!small)
  515. {
  516. elt.style.backgroundImage = 'url(' + mxWindow.prototype.normalizeImage + ')';
  517. elt.style.backgroundPosition = 'right 6px center';
  518. elt.style.backgroundRepeat = 'no-repeat';
  519. elt.style.paddingRight = '22px';
  520. }
  521. return elt;
  522. };
  523. function addMenuItem(label, fn, small, tooltip, action, img)
  524. {
  525. var btn = document.createElement('a');
  526. btn.className = 'geMenuItem';
  527. btn.style.display = 'inline-block';
  528. btn.style.boxSizing = 'border-box';
  529. btn.style.height = '30px';
  530. btn.style.padding = '6px';
  531. btn.style.position = 'relative';
  532. btn.style.verticalAlign = 'top';
  533. btn.style.top = '0px';
  534. if (ui.statusContainer != null)
  535. {
  536. menubar.insertBefore(btn, ui.statusContainer);
  537. }
  538. else
  539. {
  540. menubar.appendChild(btn);
  541. }
  542. if (img != null)
  543. {
  544. btn.style.backgroundImage = 'url(' + img + ')';
  545. btn.style.backgroundPosition = 'center center';
  546. btn.style.backgroundRepeat = 'no-repeat';
  547. btn.style.backgroundSize = '24px 24px';
  548. btn.style.width = '34px';
  549. }
  550. else
  551. {
  552. mxUtils.write(btn, label);
  553. }
  554. // Prevents focus
  555. mxEvent.addListener(btn, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown',
  556. mxUtils.bind(this, function(evt)
  557. {
  558. evt.preventDefault();
  559. }));
  560. mxEvent.addListener(btn, 'click', function(evt)
  561. {
  562. if (btn.getAttribute('disabled') != 'disabled')
  563. {
  564. fn(evt);
  565. }
  566. mxEvent.consume(evt);
  567. });
  568. if (small == null)
  569. {
  570. btn.style.marginRight = '4px';
  571. }
  572. if (tooltip != null)
  573. {
  574. btn.setAttribute('title', tooltip);
  575. }
  576. if (action != null)
  577. {
  578. function updateState()
  579. {
  580. if (action.isEnabled())
  581. {
  582. btn.removeAttribute('disabled');
  583. btn.style.cursor = 'pointer';
  584. }
  585. else
  586. {
  587. btn.setAttribute('disabled', 'disabled');
  588. btn.style.cursor = 'default';
  589. }
  590. };
  591. action.addListener('stateChanged', updateState);
  592. graph.addListener('enabledChanged', updateState);
  593. updateState();
  594. }
  595. return btn;
  596. };
  597. function createGroup(btns, op, container)
  598. {
  599. var btnGroup = document.createElement('div');
  600. btnGroup.className = 'geMenuItem';
  601. btnGroup.style.display = 'inline-block';
  602. btnGroup.style.verticalAlign = 'top';
  603. btnGroup.style.marginRight = '6px';
  604. btnGroup.style.padding = '0 4px 0 4px';
  605. btnGroup.style.height = '30px';
  606. btnGroup.style.position = 'relative';
  607. btnGroup.style.top = '0px';
  608. for (var i = 0; i < btns.length; i++)
  609. {
  610. if (btns[i] != null)
  611. {
  612. btns[i].style.margin = '0px';
  613. btns[i].style.boxShadow = 'none';
  614. btnGroup.appendChild(btns[i]);
  615. }
  616. }
  617. if (op != null)
  618. {
  619. mxUtils.setOpacity(btnGroup, op);
  620. }
  621. if (ui.statusContainer != null)
  622. {
  623. menubar.insertBefore(btnGroup, ui.statusContainer);
  624. }
  625. else
  626. {
  627. menubar.appendChild(btnGroup);
  628. }
  629. return btnGroup;
  630. };
  631. ui.statusContainer = ui.createStatusContainer();
  632. ui.statusContainer.style.position = 'relative';
  633. ui.statusContainer.style.maxWidth = '';
  634. ui.statusContainer.style.color = 'gray';
  635. ui.statusContainer.style.cursor = 'default';
  636. function updateTitle()
  637. {
  638. var file = ui.getCurrentFile();
  639. if (file != null && file.getTitle() != null)
  640. {
  641. var mode = file.getMode();
  642. if (mode == 'google')
  643. {
  644. mode = 'googleDrive';
  645. }
  646. else if (mode == 'github')
  647. {
  648. mode = 'gitHub';
  649. }
  650. else if (mode == 'gitlab')
  651. {
  652. mode = 'gitLab';
  653. }
  654. else if (mode == 'onedrive')
  655. {
  656. mode = 'oneDrive';
  657. }
  658. mode = mxResources.get(mode);
  659. menubar.setAttribute('title', file.getTitle() + ((mode != null) ? ' (' + mode + ')' : ''));
  660. }
  661. else
  662. {
  663. menubar.removeAttribute('title');
  664. }
  665. };
  666. // Hides popup menus
  667. var uiHideCurrentMenu = ui.hideCurrentMenu;
  668. ui.hideCurrentMenu = function()
  669. {
  670. uiHideCurrentMenu.apply(this, arguments);
  671. this.editor.graph.popupMenuHandler.hideMenu();
  672. };
  673. // Connects the status bar to the editor status
  674. var uiDescriptorChanged = ui.descriptorChanged;
  675. ui.descriptorChanged = function()
  676. {
  677. uiDescriptorChanged.apply(this, arguments);
  678. updateTitle();
  679. };
  680. ui.setStatusText(ui.editor.getStatus());
  681. menubar.appendChild(ui.statusContainer);
  682. ui.buttonContainer = document.createElement('div');
  683. ui.buttonContainer.style.cssText = 'display:flex;justify-content:flex-end;padding-right:10px;gap:6px;' +
  684. 'white-space:nowrap;background-color:inherit;align-items:center;min-width:0;margin-left:auto;';
  685. menubar.appendChild(ui.buttonContainer);
  686. // Container for the user element
  687. ui.menubarContainer = ui.buttonContainer;
  688. ui.tabContainer = document.createElement('div');
  689. ui.tabContainer.className = 'geTabContainer geTabItem';
  690. ui.tabContainer.style.cssText = 'position:absolute;left:0px;right:0px;bottom:0px;height:30px;' +
  691. 'white-space:nowrap;visibility:hidden;';
  692. var previousParent = ui.diagramContainer.parentNode;
  693. var wrapper = document.createElement('div');
  694. wrapper.style.cssText = 'position:absolute;top:0px;left:0px;right:0px;bottom:0px;overflow:hidden;';
  695. ui.diagramContainer.style.top = '47px';
  696. var insertImage = Editor.addBoxImage;
  697. // Hides hover icons if freehand is active
  698. if (ui.hoverIcons != null)
  699. {
  700. var hoverIconsUpdate = ui.hoverIcons.update;
  701. ui.hoverIcons.update = function()
  702. {
  703. if (!graph.freehand.isDrawing())
  704. {
  705. hoverIconsUpdate.apply(this, arguments);
  706. }
  707. };
  708. }
  709. // Removes sketch style from freehand shapes
  710. if (graph.freehand != null)
  711. {
  712. var freehandCreateStyle = graph.freehand.createStyle;
  713. graph.freehand.createStyle = function(stencil)
  714. {
  715. return freehandCreateStyle.apply(this, arguments) + 'sketch=0;';
  716. };
  717. }
  718. // Connects the status bar to the editor status
  719. ui.editor.addListener('statusChanged', mxUtils.bind(this, function()
  720. {
  721. ui.setStatusText(ui.editor.getStatus());
  722. }));
  723. ui.setStatusText(ui.editor.getStatus());
  724. var viewZoomMenu = ui.menus.get('viewZoom');
  725. if (viewZoomMenu != null)
  726. {
  727. var fitFunction = function(evt)
  728. {
  729. if (mxEvent.isAltDown(evt))
  730. {
  731. ui.hideCurrentMenu();
  732. ui.actions.get('customZoom').funct();
  733. mxEvent.consume(evt);
  734. }
  735. // geItem is a dropdown menu, geMenuItem is a button in the toolbar
  736. else if (mxEvent.getSource(evt).className == 'geMenuItem' || mxEvent.isShiftDown(evt))
  737. {
  738. ui.hideCurrentMenu();
  739. ui.actions.get('smartFit').funct();
  740. mxEvent.consume(evt);
  741. }
  742. };
  743. var zoomInAction = ui.actions.get('zoomIn');
  744. var zoomOutAction = ui.actions.get('zoomOut');
  745. var resetViewAction = ui.actions.get('resetView');
  746. var undoAction = ui.actions.get('undo');
  747. var redoAction = ui.actions.get('redo');
  748. var undoElt = addMenuItem('', undoAction.funct, null, mxResources.get('undo') + ' (' + undoAction.shortcut + ')', undoAction, Editor.undoImage);
  749. var redoElt = addMenuItem('', redoAction.funct, null, mxResources.get('redo') + ' (' + redoAction.shortcut + ')', redoAction, Editor.redoImage);
  750. var fitElt = addMenuItem('', fitFunction, true, mxResources.get('fit') + ' (' + Editor.ctrlKey + '+H)', resetViewAction, Editor.zoomFitImage);
  751. menubar.style.cssText = 'position:absolute;left:0px;right:0px;top:0px;height:30px;padding:8px;' +
  752. 'text-align:left;white-space:nowrap;';
  753. this.tabContainer.style.right = '70px';
  754. var elt = menuObj.addMenu('100%', viewZoomMenu.funct);
  755. elt.setAttribute('title', mxResources.get('zoom') + ' (Alt+Mousewheel)');
  756. elt.className = 'geTabItem';
  757. elt.style.height = ui.tabContainerHeight + 'px';
  758. elt.style.position = 'absolute';
  759. elt.style.display = (urlParams['pages'] != '0') ? 'flex' : 'none';
  760. elt.style.alignItems = 'center';
  761. elt.style.justifyContent = 'center';
  762. elt.style.paddingRight = '11px';
  763. elt.style.whiteSpace = 'nowrap';
  764. elt.style.overflow = 'hidden';
  765. elt.style.fontSize = '11px';
  766. elt.style.width = '51px';
  767. elt.style.right = '0px';
  768. elt.style.bottom = '0px';
  769. elt.style.boxSizing = 'content-box';
  770. elt.style.backgroundImage = 'url(' + mxWindow.prototype.minimizeImage + ')';
  771. elt.style.backgroundPosition = 'right 6px top 15px';
  772. elt.style.backgroundRepeat = 'no-repeat';
  773. elt.style.backgroundSize = '10px';
  774. elt.style.zIndex = '1';
  775. wrapper.appendChild(elt);
  776. // Updates the label if the scale changes
  777. (function(elt)
  778. {
  779. // Adds shift+/alt+click on zoom label
  780. mxEvent.addListener(elt, 'click', fitFunction);
  781. var updateZoom = mxUtils.bind(this, function(sender, evt, f)
  782. {
  783. f = (f != null) ? f : 1;
  784. elt.innerText = '';
  785. mxUtils.write(elt, Math.round(ui.editor.graph.view.scale * 100 * f) + '%');
  786. });
  787. ui.editor.graph.view.addListener(mxEvent.EVENT_SCALE, updateZoom);
  788. ui.editor.addListener('resetGraphView', updateZoom);
  789. ui.editor.addListener('pageSelected', updateZoom);
  790. // Zoom Preview
  791. ui.editor.graph.addListener('zoomPreview', mxUtils.bind(this, function(sender, evt)
  792. {
  793. updateZoom(sender, evt, evt.getProperty('factor'));
  794. }));
  795. })(elt);
  796. // Augments setGraphEnabled to update visible state
  797. var uiSetGraphEnabled = ui.setGraphEnabled;
  798. ui.setGraphEnabled = function()
  799. {
  800. uiSetGraphEnabled.apply(this, arguments);
  801. if (this.tabContainer != null)
  802. {
  803. elt.style.visibility = this.tabContainer.style.visibility;
  804. this.diagramContainer.style.bottom = (urlParams['pages'] != '0' &&
  805. this.tabContainer.style.visibility != 'hidden') ?
  806. this.tabContainerHeight + 'px' : '0px';
  807. }
  808. };
  809. }
  810. wrapper.appendChild(menubar);
  811. wrapper.appendChild(ui.diagramContainer);
  812. previousParent.appendChild(wrapper);
  813. ui.updateTabContainer();
  814. if (!EditorUi.windowed && iw >= 1000)
  815. {
  816. toggleFormat(this, true);
  817. }
  818. wrapper.appendChild(ui.tabContainer);
  819. function refreshMenu()
  820. {
  821. // Removes all existing menu items
  822. var node = menubar.firstChild;
  823. while (node != null)
  824. {
  825. var temp = node.nextSibling;
  826. if (node.className == 'geMenuItem' || node.className == 'geItem')
  827. {
  828. node.parentNode.removeChild(node);
  829. }
  830. node = temp;
  831. }
  832. before = menubar.firstChild;
  833. iw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  834. var small = iw < 1000;
  835. var appElt = null;
  836. if (!small)
  837. {
  838. appElt = addMenu('diagram');
  839. }
  840. var temp = (small) ? addMenu('diagram', null, Editor.menuImage) : null;
  841. if (temp != null)
  842. {
  843. appElt = temp;
  844. }
  845. createGroup([appElt, addMenuItem(mxResources.get('shapes'), ui.actions.get('toggleShapes').funct, null,
  846. mxResources.get('shapes'), ui.actions.get('image'), (small) ? Editor.shapesImage : null),
  847. addMenuItem(mxResources.get('format'), ui.actions.get('format').funct, null,
  848. mxResources.get('format') + ' (' + ui.actions.get('format').shortcut + ')', ui.actions.get('image'),
  849. (small) ? Editor.formatImage : null)],
  850. (small) ? 60 : null);
  851. var elt = addMenu('insert', true, (small) ? insertImage : null);
  852. createGroup([elt, addMenuItem(mxResources.get('delete'), ui.actions.get('delete').funct,
  853. null, mxResources.get('delete'), ui.actions.get('delete'),
  854. (small) ? Editor.trashImage : null)], (small) ? 60 : null);
  855. if (!graph.isEnabled())
  856. {
  857. elt.classList.add('mxDisabled');
  858. }
  859. if (iw >= 411)
  860. {
  861. createGroup([undoElt, redoElt], 60);
  862. if (iw >= 520)
  863. {
  864. createGroup([fitElt,
  865. (iw >= 640) ? addMenuItem('', zoomInAction.funct, true, mxResources.get('zoomIn') + ' (' + Editor.ctrlKey + ' +)',
  866. zoomInAction, Editor.zoomInImage) : null,
  867. (iw >= 640) ? addMenuItem('', zoomOutAction.funct, true, mxResources.get('zoomOut') + ' (' + Editor.ctrlKey + ' -)',
  868. zoomOutAction, Editor.zoomOutImage) : null], 60);
  869. }
  870. }
  871. };
  872. refreshMenu();
  873. ui.addListener('lockedChanged', refreshMenu);
  874. mxEvent.addListener(window, 'resize', function()
  875. {
  876. refreshMenu();
  877. if (ui.sidebarWindow != null)
  878. {
  879. ui.sidebarWindow.window.fit();
  880. }
  881. if (ui.formatWindow != null)
  882. {
  883. ui.formatWindow.window.fit();
  884. }
  885. if (ui.actions.outlineWindow != null)
  886. {
  887. ui.actions.outlineWindow.window.fit();
  888. }
  889. if (ui.actions.layersWindow != null)
  890. {
  891. ui.actions.layersWindow.window.fit();
  892. }
  893. if (ui.menus.chatWindow != null)
  894. {
  895. ui.menus.chatWindow.window.fit();
  896. }
  897. if (ui.menus.tagsWindow != null)
  898. {
  899. ui.menus.tagsWindow.window.fit();
  900. }
  901. if (ui.menus.findWindow != null)
  902. {
  903. ui.menus.findWindow.window.fit();
  904. }
  905. if (ui.menus.findReplaceWindow != null)
  906. {
  907. ui.menus.findReplaceWindow.window.fit();
  908. }
  909. });
  910. };
  911. };
  912. (function()
  913. {
  914. var initialized = false;
  915. // ChromeApp has async local storage
  916. if (uiTheme == 'min' && !initialized && !mxClient.IS_CHROMEAPP)
  917. {
  918. EditorUi.initMinimalTheme();
  919. initialized = true;
  920. }
  921. var uiInitTheme = EditorUi.initTheme;
  922. // For async startup like chromeos
  923. EditorUi.initTheme = function()
  924. {
  925. uiInitTheme.apply(this, arguments);
  926. if (uiTheme == 'min' && !initialized)
  927. {
  928. this.initMinimalTheme();
  929. initialized = true;
  930. }
  931. };
  932. })();