1/** 2 * Code for the minimal UI theme. 3 */ 4EditorUi.initMinimalTheme = function() 5{ 6 // Disabled in lightbox and chromeless mode 7 if (urlParams['lightbox'] == '1' || urlParams['chrome'] == '0' || typeof window.Format === 'undefined' || typeof window.Menus === 'undefined') 8 { 9 window.uiTheme = null; 10 11 return; 12 } 13 14 var iw = 0; 15 16 try 17 { 18 iw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 19 } 20 catch (e) 21 { 22 // ignore 23 } 24 25 /** 26 * 27 */ 28 var WrapperWindow = function(editorUi, title, x, y, w, h, fn) 29 { 30 var graph = editorUi.editor.graph; 31 32 var div = document.createElement('div'); 33 div.className = 'geSidebarContainer'; 34 div.style.position = 'absolute'; 35 div.style.width = '100%'; 36 div.style.height = '100%'; 37 div.style.border = '1px solid whiteSmoke'; 38 div.style.overflowX = 'hidden'; 39 div.style.overflowY = 'auto'; 40 41 fn(div); 42 43 this.window = new mxWindow(title, div, x, y, w, h, true, true); 44 this.window.destroyOnClose = false; 45 this.window.setMaximizable(false); 46 this.window.setResizable(true); 47 this.window.setClosable(true); 48 this.window.setVisible(true); 49 50 this.window.setLocation = function(x, y) 51 { 52 var iiw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 53 var ih = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; 54 55 x = Math.max(0, Math.min(x, iiw - this.table.clientWidth)); 56 y = Math.max(0, Math.min(y, ih - this.table.clientHeight - 57 ((urlParams['sketch'] == '1') ? 3 : 48))); 58 59 if (this.getX() != x || this.getY() != y) 60 { 61 mxWindow.prototype.setLocation.apply(this, arguments); 62 } 63 }; 64 65 // Workaround for text selection starting in Safari 66 // when dragging shapes outside of window 67 if (mxClient.IS_SF) 68 { 69 this.window.div.onselectstart = mxUtils.bind(this, function(evt) 70 { 71 if (evt == null) 72 { 73 evt = window.event; 74 } 75 76 return (evt != null && editorUi.isSelectionAllowed(evt)); 77 }); 78 } 79 }; 80 81 function toggleFormat(ui, visible) 82 { 83 var graph = ui.editor.graph; 84 graph.popupMenuHandler.hideMenu(); 85 86 if (ui.formatWindow == null) 87 { 88 ui.formatWindow = new WrapperWindow(ui, mxResources.get('format'), 89 (urlParams['sketch'] == '1') ? Math.max(10, ui.diagramContainer.clientWidth - 241) : 90 Math.max(10, ui.diagramContainer.clientWidth - 248), 60, 91 240, Math.min(566, graph.container.clientHeight - 10), function(container) 92 { 93 var format = ui.createFormat(container); 94 format.init(); 95 96 ui.addListener('darkModeChanged', mxUtils.bind(this, function() 97 { 98 format.refresh(); 99 })); 100 101 return format; 102 }); 103 104 ui.formatWindow.window.minimumSize = new mxRectangle(0, 0, 240, 80); 105 ui.formatWindow.window.setVisible(true); 106 } 107 else 108 { 109 ui.formatWindow.window.setVisible((visible != null) ? 110 visible : !ui.formatWindow.window.isVisible()); 111 } 112 113 if (ui.formatWindow.window.isVisible() && urlParams['sketch'] != '1') 114 { 115 ui.formatWindow.window.fit(); 116 } 117 }; 118 119 function toggleShapes(ui, visible) 120 { 121 var graph = ui.editor.graph; 122 graph.popupMenuHandler.hideMenu(); 123 var rect = new mxRectangle(); 124 125 if (ui.sidebarWindow == null) 126 { 127 var w = Math.min(graph.container.clientWidth - 10, 218); 128 129 ui.sidebarWindow = new WrapperWindow(ui, mxResources.get('shapes'), 10, 130 (urlParams['sketch'] == '1' && urlParams['embedInline'] != '1') ? 15 : 56, 131 w - 6, Math.min(650, graph.container.clientHeight - 30), 132 function(container) 133 { 134 var div = document.createElement('div'); 135 div.style.cssText = 'position:absolute;left:0;right:0;border-top:1px solid lightgray;' + 136 'height:24px;bottom:31px;text-align:center;cursor:pointer;padding:6px 0 0 0;'; 137 div.className = 'geTitle'; 138 div.innerHTML = '<span style="font-size:18px;margin-right:5px;">+</span>'; 139 mxUtils.write(div, mxResources.get('moreShapes')); 140 container.appendChild(div); 141 142 mxEvent.addListener(div, 'click', function() 143 { 144 ui.actions.get('shapes').funct(); 145 }); 146 147 var menuObj = new Menubar(ui, container); 148 149 function addMenu(id, label) 150 { 151 var menu = ui.menus.get(id); 152 153 var elt = menuObj.addMenu(label, mxUtils.bind(this, function() 154 { 155 // Allows extensions of menu.functid 156 menu.funct.apply(this, arguments); 157 })); 158 159 elt.style.cssText = 'position:absolute;border-top:1px solid lightgray;width:50%;' + 160 'height:24px;bottom:0px;text-align:center;cursor:pointer;padding:6px 0 0 0;cusor:pointer;'; 161 elt.className = 'geTitle'; 162 container.appendChild(elt); 163 164 return elt; 165 } 166 167 if (Editor.enableCustomLibraries && (urlParams['embed'] != '1' || urlParams['libraries'] == '1')) 168 { 169 // Defined in native apps together with openLibrary 170 if (ui.actions.get('newLibrary') != null) 171 { 172 var div = document.createElement('div'); 173 div.style.cssText = 'position:absolute;left:0px;width:50%;border-top:1px solid lightgray;' + 174 'height:30px;bottom:0px;text-align:center;cursor:pointer;padding:0px;'; 175 div.className = 'geTitle'; 176 var span = document.createElement('span'); 177 span.style.cssText = 'position:relative;top:6px;'; 178 mxUtils.write(span, mxResources.get('newLibrary')); 179 div.appendChild(span); 180 container.appendChild(div); 181 182 mxEvent.addListener(div, 'click', ui.actions.get('newLibrary').funct); 183 184 var div = document.createElement('div'); 185 div.style.cssText = 'position:absolute;left:50%;width:50%;border-top:1px solid lightgray;' + 186 'height:30px;bottom:0px;text-align:center;cursor:pointer;padding:0px;border-left: 1px solid lightgray;'; 187 div.className = 'geTitle'; 188 var span = document.createElement('span'); 189 span.style.cssText = 'position:relative;top:6px;'; 190 mxUtils.write(span, mxResources.get('openLibrary')); 191 div.appendChild(span); 192 container.appendChild(div); 193 194 mxEvent.addListener(div, 'click', ui.actions.get('openLibrary').funct); 195 } 196 else 197 { 198 var elt = addMenu('newLibrary', mxResources.get('newLibrary')); 199 elt.style.boxSizing = 'border-box'; 200 elt.style.paddingRight = '6px'; 201 elt.style.paddingLeft = '6px'; 202 elt.style.height = '32px'; 203 elt.style.left = '0'; 204 205 var elt = addMenu('openLibraryFrom', mxResources.get('openLibraryFrom')); 206 elt.style.borderLeft = '1px solid lightgray'; 207 elt.style.boxSizing = 'border-box'; 208 elt.style.paddingRight = '6px'; 209 elt.style.paddingLeft = '6px'; 210 elt.style.height = '32px'; 211 elt.style.left = '50%'; 212 } 213 } 214 else 215 { 216 div.style.bottom = '0'; 217 } 218 219 container.appendChild(ui.sidebar.container); 220 container.style.overflow = 'hidden'; 221 222 return container; 223 }); 224 225 ui.sidebarWindow.window.minimumSize = new mxRectangle(0, 0, 90, 90); 226 ui.sidebarWindow.window.setVisible(true); 227 228 ui.getLocalData('sidebar', function(value) 229 { 230 ui.sidebar.showEntries(value, null, true); 231 }); 232 233 ui.restoreLibraries(); 234 } 235 else 236 { 237 ui.sidebarWindow.window.setVisible((visible != null) ? 238 visible : !ui.sidebarWindow.window.isVisible()); 239 } 240 241 if (ui.sidebarWindow.window.isVisible()) 242 { 243 ui.sidebarWindow.window.fit(); 244 } 245 }; 246 247 // Changes colors for some UI elements 248 var fill = '#29b6f2'; 249 var stroke = '#ffffff'; 250 251 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; 252 mxWindow.prototype.closeImage = Graph.createSvgImage(18, 10, '<path d="M 5 1 L 13 9 M 13 1 L 5 9" stroke="#C0C0C0" stroke-width="2"/>').src; 253 mxWindow.prototype.minimizeImage = Graph.createSvgImage(14, 10, '<path d="M 3 7 L 7 3 L 11 7" stroke="#C0C0C0" stroke-width="2" fill="none"/>').src; 254 mxWindow.prototype.normalizeImage = Graph.createSvgImage(14, 10, '<path d="M 3 3 L 7 7 L 11 3" stroke="#C0C0C0" stroke-width="2" fill="none"/>').src; 255 mxConstraintHandler.prototype.pointImage = Graph.createSvgImage(5, 5, 256 '<path d="m 0 0 L 5 5 M 0 5 L 5 0" stroke-width="2" style="stroke-opacity:0.4" stroke="#ffffff"/>' + 257 '<path d="m 0 0 L 5 5 M 0 5 L 5 0" stroke="' + fill + '"/>'); 258 mxOutline.prototype.sizerImage = null; 259 260 mxConstants.VERTEX_SELECTION_COLOR = '#C0C0C0'; 261 mxConstants.EDGE_SELECTION_COLOR = '#C0C0C0'; 262 mxConstants.CONNECT_HANDLE_FILLCOLOR = '#cee7ff'; 263 264 mxConstants.DEFAULT_VALID_COLOR = fill; 265 mxConstants.GUIDE_COLOR = '#C0C0C0'; 266 267 mxConstants.HIGHLIGHT_STROKEWIDTH = 5; 268 mxConstants.HIGHLIGHT_OPACITY = 35; 269 mxConstants.OUTLINE_COLOR = '#29b6f2'; 270 mxConstants.OUTLINE_HANDLE_FILLCOLOR = '#29b6f2'; 271 mxConstants.OUTLINE_HANDLE_STROKECOLOR = '#fff'; 272 273 Graph.prototype.svgShadowColor = '#3D4574'; 274 Graph.prototype.svgShadowOpacity = '0.4'; 275 Graph.prototype.svgShadowSize = '0.6'; 276 Graph.prototype.svgShadowBlur = '1.2'; 277 278 Format.inactiveTabBackgroundColor = '#f0f0f0'; 279 mxGraphHandler.prototype.previewColor = '#C0C0C0'; 280 mxRubberband.prototype.defaultOpacity = 50; 281 HoverIcons.prototype.inactiveOpacity = 25; 282 Format.prototype.showCloseButton = false; 283 EditorUi.prototype.closableScratchpad = false; 284 EditorUi.prototype.toolbarHeight = (urlParams['sketch'] == '1') ? 1 : 46; 285 EditorUi.prototype.footerHeight = 0; 286 Graph.prototype.editAfterInsert = urlParams['sketch'] != '1' && 287 !mxClient.IS_IOS && !mxClient.IS_ANDROID; 288 289 /** 290 * Dynamic change of dark mode. 291 */ 292 EditorUi.prototype.setDarkMode = function(value) 293 { 294 if (this.spinner.spin(document.body, mxResources.get('working') + '...')) 295 { 296 window.setTimeout(mxUtils.bind(this, function() 297 { 298 this.spinner.stop(); 299 this.doSetDarkMode(value); 300 301 // Persist setting 302 if (urlParams['dark'] == null) 303 { 304 mxSettings.settings.darkMode = value; 305 mxSettings.save(); 306 } 307 308 this.fireEvent(new mxEventObject('darkModeChanged')); 309 }), 0); 310 } 311 }; 312 313 /** 314 * Links to dark.css 315 */ 316 var darkStyle = document.createElement('link'); 317 darkStyle.setAttribute('rel', 'stylesheet'); 318 darkStyle.setAttribute('href', STYLE_PATH + '/dark.css'); 319 darkStyle.setAttribute('charset', 'UTF-8'); 320 darkStyle.setAttribute('type', 'text/css'); 321 322 /** 323 * Dynamic change of dark mode. 324 */ 325 EditorUi.prototype.doSetDarkMode = function(value) 326 { 327 if (Editor.darkMode != value) 328 { 329 var graph = this.editor.graph; 330 Editor.darkMode = value; 331 332 // Sets instance vars and graph stylesheet 333 this.spinner.opts.color = Editor.isDarkMode() ? '#c0c0c0' : '#000'; 334 this.setGridColor(Editor.isDarkMode() ? graph.view.defaultDarkGridColor : graph.view.defaultGridColor); 335 graph.defaultPageBackgroundColor = (urlParams['embedInline'] == '1') ? 'transparent' : 336 Editor.isDarkMode() ? Editor.darkColor : '#ffffff'; 337 graph.defaultPageBorderColor = Editor.isDarkMode() ? '#505759' : '#ffffff'; 338 graph.shapeBackgroundColor = Editor.isDarkMode() ? Editor.darkColor : '#ffffff'; 339 graph.shapeForegroundColor = Editor.isDarkMode() ? Editor.lightColor : '#000000'; 340 graph.defaultThemeName = Editor.isDarkMode() ? 'darkTheme' : 'default-style2'; 341 graph.graphHandler.previewColor = Editor.isDarkMode() ? '#cccccc' : 'black'; 342 document.body.style.backgroundColor = (urlParams['embedInline'] == '1') ? 'transparent' : 343 (Editor.isDarkMode() ? Editor.darkColor : '#ffffff'); 344 graph.loadStylesheet(); 345 346 // Destroys windows with code for dark mode 347 if (this.actions.layersWindow != null) 348 { 349 var wasVisible = this.actions.layersWindow.window.isVisible(); 350 351 this.actions.layersWindow.window.setVisible(false); 352 this.actions.layersWindow.destroy(); 353 this.actions.layersWindow = null; 354 355 if (wasVisible) 356 { 357 window.setTimeout(this.actions.get('layers').funct, 0); 358 } 359 } 360 361 if (this.menus.commentsWindow != null) 362 { 363 this.menus.commentsWindow.window.setVisible(false); 364 this.menus.commentsWindow.destroy(); 365 this.menus.commentsWindow = null; 366 } 367 368 if (this.ruler != null) 369 { 370 this.ruler.updateStyle(); 371 } 372 373 // Sets global vars 374 Graph.prototype.defaultPageBackgroundColor = graph.defaultPageBackgroundColor; 375 Graph.prototype.defaultPageBorderColor = graph.defaultPageBorderColor; 376 Graph.prototype.shapeBackgroundColor = graph.shapeBackgroundColor; 377 Graph.prototype.shapeForegroundColor = graph.shapeForegroundColor; 378 Graph.prototype.defaultThemeName = graph.defaultThemeName; 379 StyleFormatPanel.prototype.defaultStrokeColor = Editor.isDarkMode() ? '#cccccc' : 'black'; 380 BaseFormatPanel.prototype.buttonBackgroundColor = Editor.isDarkMode() ? Editor.darkColor : 'white'; 381 Format.inactiveTabBackgroundColor = Editor.isDarkMode() ? 'black' : '#f0f0f0'; 382 Dialog.backdropColor = Editor.isDarkMode() ? Editor.darkColor : 'white'; 383 mxConstants.DROP_TARGET_COLOR = Editor.isDarkMode() ? '#00ff00' : '#0000FF'; 384 Editor.helpImage = (Editor.isDarkMode() && mxClient.IS_SVG) ? 385 Editor.darkHelpImage : Editor.lightHelpImage; 386 Editor.checkmarkImage = (Editor.isDarkMode() && mxClient.IS_SVG) ? 387 Editor.darkCheckmarkImage : Editor.lightCheckmarkImage; 388 389 // Updates CSS 390 styleElt.innerHTML = Editor.createMinimalCss(); 391 392 // Adds or removes link to CSS 393 if (Editor.darkMode) 394 { 395 if (darkStyle.parentNode == null) 396 { 397 var head = document.getElementsByTagName('head')[0]; 398 head.appendChild(darkStyle); 399 } 400 } 401 else if (darkStyle.parentNode != null) 402 { 403 darkStyle.parentNode.removeChild(darkStyle); 404 } 405 } 406 }; 407 408 /** 409 * Dynamic change of dark mode. 410 */ 411 Editor.createMinimalCss = function() 412 { 413 return '* { -webkit-font-smoothing: antialiased; }' + 414 'html body td.mxWindowTitle > div > img { padding: 8px 4px; }' + 415 // Dark mode styles 416 (Editor.isDarkMode() ? 417 'html body td.mxWindowTitle > div > img { margin: -4px; }' + 418 'html body .geToolbarContainer .geMenuItem, html body .geToolbarContainer .geToolbarButton, ' + 419 'html body .geMenubarContainer .geMenuItem .geMenuItem, html body .geMenubarContainer a.geMenuItem,' + 420 'html body .geMenubarContainer .geToolbarButton { filter: invert(1); }' + 421 'html body div.geToolbarContainer a.geInverted { filter: none; }' + 422 'html body .geMenubarContainer .geMenuItem .geMenuItem, html body .geMenubarContainer a.geMenuItem { color: #353535; }' + 423 'html > body > div > .geToolbarContainer { border: 1px solid #c0c0c0 !important; box-shadow: none !important; }' + 424 'html > body.geEditor > div > a.geItem { background-color: #2a2a2a; color: #cccccc; border-color: #505759; }' + 425 'html body .geTabContainer, html body .geTabContainer div, html body .geMenubarContainer { border-color: #505759 !important; }' + 426 'html body .mxCellEditor { color: #f0f0f0; }' 427 : 428 // Non-dark mode styles 429 'html body div.geToolbarContainer a.geInverted { filter: invert(1); }' + 430 'html body.geEditor .geTabContainer div { border-color: #e5e5e5 !important; }' 431 ) + 432 // End of custom styles 433 'html > body > div > a.geItem { background-color: #ffffff; color: #707070; border-top: 1px solid lightgray; border-left: 1px solid lightgray; }' + 434 'html body .geMenubarContainer { border-bottom:1px solid lightgray;background-color:#ffffff; }' + 435 'html body .mxWindow button.geBtn { font-size:12px !important; margin-left: 0; }' + 436 'html body table.mxWindow td.mxWindowPane div.mxWindowPane *:not(svg *) { font-size:9pt; }' + 437 'table.mxWindow * :not(svg *) { font-size:13px; }' + 438 'html body .mxWindow { z-index: 3; }' + 439 'html body div.diagramContainer button, html body button.geBtn { font-size:14px; font-weight:700; border-radius: 5px; }' + 440 'html body button.geBtn:active { opacity: 0.6; }' + 441 'html body a.geMenuItem { opacity: 0.75; cursor: pointer; user-select: none; }' + 442 'html body a.geMenuItem[disabled] { opacity: 0.2; }' + 443 'html body a.geMenuItem[disabled]:active { opacity: 0.2; }' + 444 'html body div.geActivePage { opacity: 0.7; }' + 445 'html body a.geMenuItem:active { opacity: 0.2; }' + 446 'html body .geToolbarButton { opacity: 0.3; }' + 447 'html body .geToolbarButton:active { opacity: 0.15; }' + 448 'html body .geStatus:active { opacity: 0.5; }' + 449 'html body .geStatus { padding-top:3px !important; }' + 450 'html body .geMenubarContainer .geStatus { margin-top: 0px !important; }' + 451 'html table.mxPopupMenu tr.mxPopupMenuItemHover:active { opacity: 0.7; }' + 452 'html body .geDialog input, html body .geToolbarContainer input, html body .mxWindow input {padding: 2px; display: inline-block; }' + 453 'html body .mxWindow input[type="checkbox"] {padding: 0px; }' + 454 'div.geDialog { border-radius: 5px; }' + 455 'html body div.geDialog button.geBigButton { color: ' + (Editor.isDarkMode() ? Editor.darkColor : '#fff') + ' !important; border: none !important; }' + 456 '.mxWindow button, .geDialog select, .mxWindow select { display:inline-block; }' + 457 'html body .mxWindow .geColorBtn, html body .geDialog .geColorBtn { background: none; }' + 458 'html body div.diagramContainer button, html body .mxWindow button, html body .geDialog button { min-width: 0px; border-radius: 5px; color: ' + (Editor.isDarkMode() ? '#cccccc' : '#353535') + ' !important; border-style: solid; border-width: 1px; border-color: rgb(216, 216, 216); }' + 459 'html body div.diagramContainer button:hover, html body .mxWindow button:hover, html body .geDialog button:hover { border-color: rgb(177, 177, 177); }' + 460 'html body div.diagramContainer button:active, html body .mxWindow button:active, html body .geDialog button:active { opacity: 0.6; }' + 461 'div.diagramContainer button.geBtn, .mxWindow button.geBtn, .geDialog button.geBtn { min-width:72px; font-weight: 600; background: none; }' + 462 'div.diagramContainer button.gePrimaryBtn, .mxWindow button.gePrimaryBtn, .geDialog button.gePrimaryBtn, html body .gePrimaryBtn { background: #29b6f2; color: #fff !important; border: none; box-shadow: none; }' + 463 'html body .gePrimaryBtn:hover { background: #29b6f2; border: none; box-shadow: inherit; }' + 464 'html body button.gePrimaryBtn:hover { background: #29b6f2; border: none; }' + 465 '.geBtn button { min-width:72px !important; }' + 466 'div.geToolbarContainer a.geButton { margin:0px; padding: 0 2px 4px 2px; } ' + 467 'html body div.geToolbarContainer a.geColorBtn { margin: 2px; } ' + 468 'html body .mxWindow td.mxWindowPane input, html body .mxWindow td.mxWindowPane select, html body .mxWindow td.mxWindowPane textarea, html body .mxWindow td.mxWindowPane radio { padding: 0px; box-sizing: border-box; }' + 469 '.geDialog, .mxWindow td.mxWindowPane *, div.geSprite, td.mxWindowTitle, .geDiagramContainer { box-sizing:content-box; }' + 470 '.mxWindow div button.geStyleButton { box-sizing: border-box; }' + 471 'table.mxWindow td.mxWindowPane button.geColorBtn { padding:0px; box-sizing: border-box; }' + 472 'td.mxWindowPane .geSidebarContainer button { padding:2px; box-sizing: border-box; }' + 473 'html body .geMenuItem { font-size:14px; text-decoration: none; font-weight: normal; padding: 6px 10px 6px 10px; border: none; border-radius: 5px; color: #353535; box-shadow: inset 0 0 0 1px rgba(0,0,0,.11), inset 0 -1px 0 0 rgba(0,0,0,.08), 0 1px 2px 0 rgba(0,0,0,.04); }' + 474 // Styling for Minimal 475 '.geTabContainer { border-bottom:1px solid lightgray; border-top:1px solid lightgray; background: ' + (Editor.isDarkMode() ? Editor.darkColor : '#fff') + ' !important; }' + 476 '.geToolbarContainer { background: ' + (Editor.isDarkMode() ? Editor.darkColor : '#fff') + '; }' + 477 'div.geSidebarContainer { background-color: ' + (Editor.isDarkMode() ? Editor.darkColor : '#fff') + '; }' + 478 'div.geSidebarContainer .geTitle { background-color: ' + (Editor.isDarkMode() ? Editor.darkColor : '#fdfdfd') + '; }' + 479 'div.mxWindow td.mxWindowPane button { background-image: none; float: none; }' + 480 'td.mxWindowTitle { height: 22px !important; background: none !important; font-size: 13px !important; text-align:center !important; border-bottom:1px solid lightgray; }' + 481 'div.mxWindow, div.mxWindowTitle { background-image: none !important; background-color:' + (Editor.isDarkMode() ? Editor.darkColor : '#fff') + ' !important; }' + 482 'div.mxWindow { border-radius:5px; box-shadow: 0px 0px 2px #C0C0C0 !important;}' + 483 'div.mxWindow *:not(svg *) { font-family: inherit !important; }' + 484 // Minimal Style UI 485 'html div.geVerticalHandle { position:absolute;bottom:0px;left:50%;cursor:row-resize;width:11px;height:11px;background:white;margin-bottom:-6px; margin-left:-6px; border: none; border-radius: 6px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.11), inset 0 -1px 0 0 rgba(0,0,0,.08), 0 1px 2px 0 rgba(0,0,0,.04); }' + 486 'html div.geInactivePage { background: ' + (Editor.isDarkMode() ? Editor.darkColor : 'rgb(249, 249, 249)') + ' !important; color: #A0A0A0 !important; } ' + 487 'html div.geActivePage { background: ' + (Editor.isDarkMode() ? Editor.darkColor : '#fff') + ' !important; ' + (Editor.isDarkMode() ? '' : 'color: #353535 !important; } ') + 488 'html div.mxRubberband { border:1px solid; border-color: #29b6f2 !important; background:rgba(41,182,242,0.4) !important; } ' + 489 'html body div.mxPopupMenu { border-radius:5px; border:1px solid #c0c0c0; padding:5px 0 5px 0; box-shadow: 0px 4px 17px -4px rgba(96,96,96,1); } ' + 490 'html table.mxPopupMenu td.mxPopupMenuItem { color: ' + (Editor.isDarkMode() ? '#cccccc' : '#353535') + '; font-size: 14px; padding-top: 4px; padding-bottom: 4px; }' + 491 'html table.mxPopupMenu tr.mxPopupMenuItemHover { background-color: ' + (Editor.isDarkMode() ? '#000000' : '#29b6f2') + '; }' + 492 'html tr.mxPopupMenuItemHover td.mxPopupMenuItem, html tr.mxPopupMenuItemHover td.mxPopupMenuItem span { color: ' + (Editor.isDarkMode() ? '#cccccc' : '#ffffff') + ' !important; }' + 493 'html tr.mxPopupMenuItem, html td.mxPopupMenuItem { transition-property: none !important; }' + 494 'html table.mxPopupMenu hr { height: 2px; background-color: rgba(0,0,0,.07); margin: 5px 0; }' + 495 'html body td.mxWindowTitle { padding-right: 14px; }' + 496 'html td.mxWindowTitle div { top: 0px !important; }' + 497 // Fixes checkbox and radio size on iOS 498 ((mxClient.IS_IOS) ? 'html input[type=checkbox], html input[type=radio] { height:12px; }' : '') + 499 ((urlParams['sketch'] == '1') ? 'a.geStatus > div { overflow: hidden; text-overflow: ellipsis; max-width: 100%; }' : ''); 500 }; 501 502 var styleElt = document.createElement('style') 503 styleElt.type = 'text/css'; 504 styleElt.innerHTML = Editor.createMinimalCss(); 505 document.getElementsByTagName('head')[0].appendChild(styleElt); 506 507 /** 508 * Sets the XML node for the current diagram. 509 */ 510 Editor.prototype.isChromelessView = function() 511 { 512 return false; 513 }; 514 515 /** 516 * Sets the XML node for the current diagram. 517 */ 518 Graph.prototype.isLightboxView = function() 519 { 520 return false; 521 }; 522 523 // Overridden to ignore tabContainer height for diagramContainer 524 var editorUiUpdateTabContainer = EditorUi.prototype.updateTabContainer; 525 526 EditorUi.prototype.updateTabContainer = function() 527 { 528 if (this.tabContainer != null) 529 { 530 // Makes room for view zoom menu 531 this.tabContainer.style.right = '70px'; 532 this.diagramContainer.style.bottom = (urlParams['sketch'] == '1') ? 533 '0px' : this.tabContainerHeight + 'px'; 534 } 535 536 editorUiUpdateTabContainer.apply(this, arguments); 537 }; 538 539 // Overridden to update save menu state 540 /** 541 * Updates action states depending on the selection. 542 */ 543 var editorUiUpdateActionStates = EditorUi.prototype.updateActionStates; 544 545 EditorUi.prototype.updateActionStates = function() 546 { 547 editorUiUpdateActionStates.apply(this, arguments); 548 549 this.menus.get('save').setEnabled(this.getCurrentFile() != null || urlParams['embed'] == '1'); 550 }; 551 552 // Hides keyboard shortcuts in menus 553 var menusAddShortcut = Menus.prototype.addShortcut; 554 555 Menus.prototype.addShortcut = function(item, action) 556 { 557 if (action.shortcut != null && iw < 900 && !mxClient.IS_IOS) 558 { 559 var td = item.firstChild.nextSibling; 560 td.setAttribute('title', action.shortcut); 561 } 562 else 563 { 564 menusAddShortcut.apply(this, arguments); 565 } 566 }; 567 568 var appUpdateUserElement = App.prototype.updateUserElement; 569 570 App.prototype.updateUserElement = function() 571 { 572 appUpdateUserElement.apply(this, arguments); 573 574 if (this.userElement != null) 575 { 576 var elt = this.userElement; 577 elt.style.cssText = 'position:relative;margin-right:4px;cursor:pointer;display:' + elt.style.display; 578 elt.className = 'geToolbarButton'; 579 elt.innerHTML = ''; 580 elt.style.backgroundImage = 'url(' + Editor.userImage + ')'; 581 elt.style.backgroundPosition = 'center center'; 582 elt.style.backgroundRepeat = 'no-repeat'; 583 elt.style.backgroundSize = '24px 24px'; 584 elt.style.height = '24px'; 585 elt.style.width = '24px'; 586 elt.style.cssFloat = 'right'; 587 elt.setAttribute('title', mxResources.get('changeUser')); 588 589 if (elt.style.display != 'none') 590 { 591 elt.style.display = 'inline-block'; 592 } 593 } 594 }; 595 596 var appUpdateButtonContainer = App.prototype.updateButtonContainer; 597 598 App.prototype.updateButtonContainer = function() 599 { 600 appUpdateButtonContainer.apply(this, arguments); 601 602 if (this.shareButton != null) 603 { 604 var elt = this.shareButton; 605 elt.style.cssText = 'display:inline-block;position:relative;box-sizing:border-box;margin-right:4px;cursor:pointer;'; 606 elt.className = 'geToolbarButton'; 607 elt.innerHTML = ''; 608 elt.style.backgroundImage = 'url(' + Editor.shareImage + ')'; 609 elt.style.backgroundPosition = 'center center'; 610 elt.style.backgroundRepeat = 'no-repeat'; 611 elt.style.backgroundSize = '24px 24px'; 612 elt.style.height = '24px'; 613 elt.style.width = '24px'; 614 615 // Share button hidden via CSS to enable notifications button 616 if (urlParams['sketch'] == '1') 617 { 618 this.shareButton.style.display = 'none'; 619 } 620 } 621 622 if (this.buttonContainer != null) 623 { 624 this.buttonContainer.style.marginTop = '-2px'; 625 this.buttonContainer.style.paddingTop = '4px'; 626 } 627 }; 628 629 EditorUi.prototype.addEmbedButtons = function() 630 { 631 if (this.buttonContainer != null && urlParams['embedInline'] != '1') 632 { 633 var div = document.createElement('div'); 634 div.style.display = 'inline-block'; 635 div.style.position = 'relative'; 636 div.style.marginTop = '6px'; 637 div.style.marginRight = '4px'; 638 639 var button = document.createElement('a'); 640 button.className = 'geMenuItem gePrimaryBtn'; 641 button.style.marginLeft = '8px'; 642 button.style.padding = '6px'; 643 644 if (urlParams['noSaveBtn'] == '1') 645 { 646 if (urlParams['saveAndExit'] != '0') 647 { 648 var saveAndExitTitle = urlParams['publishClose'] == '1' ? mxResources.get('publish') : mxResources.get('saveAndExit'); 649 mxUtils.write(button, saveAndExitTitle); 650 button.setAttribute('title', saveAndExitTitle); 651 652 mxEvent.addListener(button, 'click', mxUtils.bind(this, function() 653 { 654 this.actions.get('saveAndExit').funct(); 655 })); 656 657 div.appendChild(button); 658 } 659 } 660 else 661 { 662 mxUtils.write(button, mxResources.get('save')); 663 button.setAttribute('title', mxResources.get('save') + ' (' + Editor.ctrlKey + '+S)'); 664 665 mxEvent.addListener(button, 'click', mxUtils.bind(this, function() 666 { 667 this.actions.get('save').funct(); 668 })); 669 670 div.appendChild(button); 671 672 if (urlParams['saveAndExit'] == '1') 673 { 674 button = document.createElement('a'); 675 mxUtils.write(button, mxResources.get('saveAndExit')); 676 button.setAttribute('title', mxResources.get('saveAndExit')); 677 button.className = 'geMenuItem'; 678 button.style.marginLeft = '6px'; 679 button.style.padding = '6px'; 680 681 mxEvent.addListener(button, 'click', mxUtils.bind(this, function() 682 { 683 this.actions.get('saveAndExit').funct(); 684 })); 685 686 div.appendChild(button); 687 } 688 } 689 690 if (urlParams['noExitBtn'] != '1') 691 { 692 button = document.createElement('a'); 693 var exitTitle = urlParams['publishClose'] == '1' ? mxResources.get('close') : mxResources.get('exit'); 694 mxUtils.write(button, exitTitle); 695 button.setAttribute('title', exitTitle); 696 button.className = 'geMenuItem'; 697 button.style.marginLeft = '6px'; 698 button.style.padding = '6px'; 699 700 mxEvent.addListener(button, 'click', mxUtils.bind(this, function() 701 { 702 this.actions.get('exit').funct(); 703 })); 704 705 div.appendChild(button); 706 } 707 708 this.buttonContainer.appendChild(div); 709 this.buttonContainer.style.top = '6px'; 710 711 this.editor.fireEvent(new mxEventObject('statusChanged')); 712 } 713 }; 714 715 // Fixes sidebar tooltips (previews) 716 var sidebarGetTooltipOffset = Sidebar.prototype.getTooltipOffset; 717 718 Sidebar.prototype.getTooltipOffset = function(elt, bounds) 719 { 720 if (this.editorUi.sidebarWindow == null || 721 mxUtils.isAncestorNode(this.editorUi.picker, elt)) 722 { 723 var off = mxUtils.getOffset(this.editorUi.picker); 724 725 off.x += this.editorUi.picker.offsetWidth + 4; 726 off.y += elt.offsetTop - bounds.height / 2 + 16; 727 728 return off; 729 } 730 else 731 { 732 var result = sidebarGetTooltipOffset.apply(this, arguments); 733 var off = mxUtils.getOffset(this.editorUi.sidebarWindow.window.div); 734 735 result.x += off.x - 16; 736 result.y += off.y; 737 738 return result; 739 } 740 }; 741 742 // Adds context menu items 743 var menuCreatePopupMenu = Menus.prototype.createPopupMenu; 744 745 Menus.prototype.createPopupMenu = function(menu, cell, evt) 746 { 747 var graph = this.editorUi.editor.graph; 748 menu.smartSeparators = true; 749 menuCreatePopupMenu.apply(this, arguments); 750 751 if (urlParams['sketch'] == '1') 752 { 753 if (graph.isEnabled()) 754 { 755 menu.addSeparator(); 756 757 if (graph.getSelectionCount() == 1) 758 { 759 this.addMenuItems(menu, ['-', 'lockUnlock'], null, evt); 760 } 761 } 762 } 763 else 764 { 765 if (graph.getSelectionCount() == 1) 766 { 767 if (graph.isCellFoldable(graph.getSelectionCell())) 768 { 769 this.addMenuItems(menu, (graph.isCellCollapsed(cell)) ? ['expand'] : ['collapse'], null, evt); 770 } 771 772 this.addMenuItems(menu, ['collapsible', '-', 'lockUnlock', 'enterGroup'], null, evt); 773 menu.addSeparator(); 774 this.addSubmenu('layout', menu); 775 } 776 else if (graph.isSelectionEmpty() && graph.isEnabled()) 777 { 778 menu.addSeparator(); 779 this.addMenuItems(menu, ['editData'], null, evt); 780 menu.addSeparator(); 781 this.addSubmenu('layout', menu); 782 this.addSubmenu('insert', menu); 783 this.addMenuItems(menu, ['-', 'exitGroup'], null, evt); 784 } 785 else if (graph.isEnabled()) 786 { 787 this.addMenuItems(menu, ['-', 'lockUnlock'], null, evt); 788 } 789 } 790 791 if (graph.isEnabled() && graph.isSelectionEmpty()) 792 { 793 this.addMenuItems(menu, ['-', 'fullscreen']); 794 795 if (urlParams['embedInline'] != '1' && (Editor.isDarkMode() || 796 (!mxClient.IS_IE && !mxClient.IS_IE11))) 797 { 798 this.addMenuItems(menu, ['toggleDarkMode']); 799 } 800 } 801 }; 802 803 // Adds copy as image after paste for empty selection 804 var menuAddPopupMenuEditItems = Menus.prototype.addPopupMenuEditItems; 805 806 /** 807 * Creates the keyboard event handler for the current graph and history. 808 */ 809 Menus.prototype.addPopupMenuEditItems = function(menu, cell, evt) 810 { 811 menuAddPopupMenuEditItems.apply(this, arguments); 812 813 if (this.editorUi.editor.graph.isSelectionEmpty()) 814 { 815 this.addMenuItems(menu, ['copyAsImage'], null, evt); 816 } 817 }; 818 819 820 // Overridden to toggle window instead 821 EditorUi.prototype.toggleFormatPanel = function(visible) 822 { 823 if (this.formatWindow != null) 824 { 825 this.formatWindow.window.setVisible((visible != null) ? 826 visible : !this.formatWindow.window.isVisible()); 827 } 828 else 829 { 830 toggleFormat(this); 831 } 832 }; 833 834 DiagramFormatPanel.prototype.isMathOptionVisible = function() 835 { 836 return true; 837 }; 838 839 // Initializes the user interface 840 var editorUiDestroy = EditorUi.prototype.destroy; 841 EditorUi.prototype.destroy = function() 842 { 843 if (this.sidebarWindow != null) 844 { 845 this.sidebarWindow.window.setVisible(false); 846 this.sidebarWindow.window.destroy(); 847 this.sidebarWindow = null; 848 } 849 850 if (this.formatWindow != null) 851 { 852 this.formatWindow.window.setVisible(false); 853 this.formatWindow.window.destroy(); 854 this.formatWindow = null; 855 } 856 857 if (this.actions.outlineWindow != null) 858 { 859 this.actions.outlineWindow.window.setVisible(false); 860 this.actions.outlineWindow.window.destroy(); 861 this.actions.outlineWindow = null; 862 } 863 864 if (this.actions.layersWindow != null) 865 { 866 this.actions.layersWindow.window.setVisible(false); 867 this.actions.layersWindow.destroy(); 868 this.actions.layersWindow = null; 869 } 870 871 if (this.menus.tagsWindow != null) 872 { 873 this.menus.tagsWindow.window.setVisible(false); 874 this.menus.tagsWindow.window.destroy(); 875 this.menus.tagsWindow = null; 876 } 877 878 if (this.menus.findWindow != null) 879 { 880 this.menus.findWindow.window.setVisible(false); 881 this.menus.findWindow.window.destroy(); 882 this.menus.findWindow = null; 883 } 884 885 if (this.menus.findReplaceWindow != null) 886 { 887 this.menus.findReplaceWindow.window.setVisible(false); 888 this.menus.findReplaceWindow.window.destroy(); 889 this.menus.findReplaceWindow = null; 890 } 891 892 editorUiDestroy.apply(this, arguments); 893 }; 894 895 // Hides windows when a file is closed 896 var editorUiSetGraphEnabled = EditorUi.prototype.setGraphEnabled; 897 898 EditorUi.prototype.setGraphEnabled = function(enabled) 899 { 900 editorUiSetGraphEnabled.apply(this, arguments); 901 902 if (!enabled) 903 { 904 if (this.sidebarWindow != null) 905 { 906 this.sidebarWindow.window.setVisible(false); 907 } 908 909 if (this.formatWindow != null) 910 { 911 this.formatWindow.window.setVisible(false); 912 } 913 } 914 else 915 { 916 var iw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 917 918 if (iw >= 1000 && this.sidebarWindow != null && urlParams['sketch'] != '1') 919 { 920 this.sidebarWindow.window.setVisible(true); 921 } 922 923 if (this.formatWindow != null && (iw >= 1000 || urlParams['sketch'] == '1')) 924 { 925 this.formatWindow.window.setVisible(true); 926 } 927 } 928 }; 929 930 // Disables centering of graph after iframe resize 931 EditorUi.prototype.chromelessWindowResize = function() {}; 932 933 // Adds actions and menus 934 var menusInit = Menus.prototype.init; 935 Menus.prototype.init = function() 936 { 937 menusInit.apply(this, arguments); 938 939 var ui = this.editorUi; 940 var graph = ui.editor.graph; 941 942 ui.actions.get('editDiagram').label = mxResources.get('formatXml') + '...'; 943 ui.actions.get('createShape').label = mxResources.get('shape') + '...'; 944 ui.actions.get('outline').label = mxResources.get('outline') + '...'; 945 ui.actions.get('layers').label = mxResources.get('layers') + '...'; 946 ui.actions.get('tags').label = mxResources.get('tags') + '...'; 947 ui.actions.get('forkme').visible = urlParams['sketch'] != '1'; 948 ui.actions.get('downloadDesktop').visible = urlParams['sketch'] != '1'; 949 950 var toggleDarkModeAction = ui.actions.put('toggleDarkMode', new Action(mxResources.get('dark'), function(e) 951 { 952 ui.setDarkMode(!Editor.darkMode); 953 })); 954 955 toggleDarkModeAction.setToggleAction(true); 956 toggleDarkModeAction.setSelectedCallback(function() { return Editor.isDarkMode(); }); 957 958 var toggleSketchModeAction = ui.actions.put('toggleSketchMode', new Action(mxResources.get('sketch'), function(e) 959 { 960 ui.setSketchMode(!Editor.sketchMode); 961 })); 962 963 toggleSketchModeAction.setToggleAction(true); 964 toggleSketchModeAction.setSelectedCallback(function() { return Editor.sketchMode; }); 965 966 var togglePagesAction = ui.actions.put('togglePagesVisible', new Action(mxResources.get('pages'), function(e) 967 { 968 ui.setPagesVisible(!Editor.pagesVisible); 969 })); 970 971 togglePagesAction.setToggleAction(true); 972 togglePagesAction.setSelectedCallback(function() { return Editor.pagesVisible; }); 973 974 ui.actions.put('importCsv', new Action(mxResources.get('csv') + '...', function() 975 { 976 graph.popupMenuHandler.hideMenu(); 977 ui.showImportCsvDialog(); 978 })); 979 ui.actions.put('importText', new Action(mxResources.get('text') + '...', function() 980 { 981 var dlg = new ParseDialog(ui, 'Insert from Text'); 982 ui.showDialog(dlg.container, 620, 420, true, false); 983 dlg.init(); 984 })); 985 ui.actions.put('formatSql', new Action(mxResources.get('formatSql') + '...', function() 986 { 987 var dlg = new ParseDialog(ui, 'Insert from Text', 'formatSql'); 988 ui.showDialog(dlg.container, 620, 420, true, false); 989 dlg.init(); 990 })); 991 992 ui.actions.put('toggleShapes', new Action(mxResources.get((urlParams['sketch'] == '1') ? 993 'moreShapes' : 'shapes') + '...', function() 994 { 995 toggleShapes(ui); 996 }, null, null, Editor.ctrlKey + '+Shift+K')); 997 998 var action = ui.actions.put('toggleFormat', new Action(mxResources.get('format') + '...', function() 999 { 1000 toggleFormat(ui); 1001 })); 1002 action.shortcut = ui.actions.get('formatPanel').shortcut; 1003 1004 if (EditorUi.enablePlantUml && !ui.isOffline()) 1005 { 1006 ui.actions.put('plantUml', new Action(mxResources.get('plantUml') + '...', function() 1007 { 1008 var dlg = new ParseDialog(ui, mxResources.get('plantUml') + '...', 'plantUml'); 1009 ui.showDialog(dlg.container, 620, 420, true, false); 1010 dlg.init(); 1011 })); 1012 } 1013 1014 ui.actions.put('mermaid', new Action(mxResources.get('mermaid') + '...', function() 1015 { 1016 var dlg = new ParseDialog(ui, mxResources.get('mermaid') + '...', 'mermaid'); 1017 ui.showDialog(dlg.container, 620, 420, true, false); 1018 dlg.init(); 1019 })); 1020 1021 // Adds submenu for edit items 1022 var addPopupMenuCellEditItems = this.addPopupMenuCellEditItems; 1023 1024 this.put('editCell', new Menu(mxUtils.bind(this, function(menu, parent) 1025 { 1026 var graph = this.editorUi.editor.graph; 1027 var cell = graph.getSelectionCell(); 1028 addPopupMenuCellEditItems.call(this, menu, cell, null, parent); 1029 1030 this.addMenuItems(menu, ['editTooltip'], parent); 1031 1032 if (graph.model.isVertex(cell)) 1033 { 1034 this.addMenuItems(menu, ['editGeometry'], parent); 1035 } 1036 1037 this.addMenuItems(menu, ['-', 'edit'], parent); 1038 }))); 1039 1040 this.addPopupMenuCellEditItems = function(menu, cell, evt, parent) 1041 { 1042 // LATER: Pass-through for evt from context menu to submenu item 1043 menu.addSeparator(); 1044 this.addSubmenu('editCell', menu, parent, mxResources.get('edit')); 1045 }; 1046 1047 this.put('diagram', new Menu(mxUtils.bind(this, function(menu, parent) 1048 { 1049 var file = ui.getCurrentFile(); 1050 ui.menus.addSubmenu('extras', menu, parent, mxResources.get('preferences')); 1051 menu.addSeparator(parent); 1052 1053 if (mxClient.IS_CHROMEAPP || EditorUi.isElectronApp) 1054 { 1055 ui.menus.addMenuItems(menu, ['new', 'open', '-', 'synchronize', 1056 '-', 'save', 'saveAs', '-'], parent); 1057 } 1058 else if (urlParams['embed'] == '1') 1059 { 1060 if (urlParams['noSaveBtn'] != '1' && 1061 urlParams['embedInline'] != '1') 1062 { 1063 ui.menus.addMenuItems(menu, ['-', 'save'], parent); 1064 } 1065 1066 if (urlParams['saveAndExit'] == '1' || 1067 (urlParams['noSaveBtn'] == '1' && 1068 urlParams['saveAndExit'] != '0')) 1069 { 1070 ui.menus.addMenuItems(menu, ['saveAndExit'], parent); 1071 } 1072 1073 menu.addSeparator(parent); 1074 } 1075 else if (ui.mode == App.MODE_ATLAS) 1076 { 1077 ui.menus.addMenuItems(menu, ['save', 'synchronize', '-'], parent); 1078 } 1079 else if (urlParams['noFileMenu'] != '1') 1080 { 1081 ui.menus.addMenuItems(menu, ['new'], parent); 1082 ui.menus.addSubmenu('openFrom', menu, parent); 1083 1084 if (isLocalStorage) 1085 { 1086 this.addSubmenu('openRecent', menu, parent); 1087 } 1088 1089 if (urlParams['sketch'] != '1') 1090 { 1091 menu.addSeparator(parent); 1092 1093 if (file != null && file.constructor == DriveFile) 1094 { 1095 ui.menus.addMenuItems(menu, ['share'], parent); 1096 } 1097 1098 if (!mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp && 1099 file != null && file.constructor != LocalFile) 1100 { 1101 ui.menus.addMenuItems(menu, ['synchronize'], parent); 1102 } 1103 } 1104 1105 menu.addSeparator(parent); 1106 ui.menus.addSubmenu('save', menu, parent); 1107 } 1108 1109 ui.menus.addSubmenu('exportAs', menu, parent); 1110 1111 if (mxClient.IS_CHROMEAPP || EditorUi.isElectronApp) 1112 { 1113 ui.menus.addMenuItems(menu, ['import'], parent); 1114 } 1115 else if (urlParams['noFileMenu'] != '1') 1116 { 1117 ui.menus.addSubmenu('importFrom', menu, parent); 1118 } 1119 1120 if (urlParams['sketch'] != '1') 1121 { 1122 ui.menus.addMenuItems(menu, ['-', 'outline'], parent); 1123 1124 if (ui.commentsSupported()) 1125 { 1126 ui.menus.addMenuItems(menu, ['comments'], parent); 1127 } 1128 } 1129 1130 ui.menus.addMenuItems(menu, ['-', 'findReplace', 'layers', 'tags'], parent); 1131 1132 ui.menus.addMenuItems(menu, ['-', 'pageSetup', 'pageScale'], parent); 1133 1134 // Cannot use print in standalone mode on iOS as we cannot open new windows 1135 if (urlParams['noFileMenu'] != '1' && (!mxClient.IS_IOS || !navigator.standalone)) 1136 { 1137 ui.menus.addMenuItems(menu, ['print'], parent); 1138 } 1139 1140 if (file != null && ui.fileNode != null && urlParams['embedInline'] != '1') 1141 { 1142 var filename = (file.getTitle() != null) ? 1143 file.getTitle() : ui.defaultFilename; 1144 1145 if (!/(\.html)$/i.test(filename) && 1146 !/(\.svg)$/i.test(filename)) 1147 { 1148 this.addMenuItems(menu, ['-', 'properties']); 1149 } 1150 } 1151 1152 menu.addSeparator(parent); 1153 ui.menus.addSubmenu('help', menu, parent); 1154 1155 if (urlParams['embed'] == '1') 1156 { 1157 if (urlParams['noExitBtn'] != '1') 1158 { 1159 ui.menus.addMenuItems(menu, ['-', 'exit'], parent); 1160 } 1161 } 1162 else if (urlParams['noFileMenu'] != '1') 1163 { 1164 ui.menus.addMenuItems(menu, ['-', 'close']); 1165 } 1166 }))); 1167 1168 this.put('save', new Menu(mxUtils.bind(this, function(menu, parent) 1169 { 1170 var file = ui.getCurrentFile(); 1171 1172 if (file != null && file.constructor == DriveFile) 1173 { 1174 ui.menus.addMenuItems(menu, ['save', 'makeCopy', '-', 'rename', 'moveToFolder'], parent); 1175 } 1176 else 1177 { 1178 ui.menus.addMenuItems(menu, ['save', 'saveAs', '-', 'rename'], parent); 1179 1180 if (ui.isOfflineApp()) 1181 { 1182 if (navigator.onLine && urlParams['stealth'] != '1' && urlParams['lockdown'] != '1') 1183 { 1184 this.addMenuItems(menu, ['upload'], parent); 1185 } 1186 } 1187 else 1188 { 1189 ui.menus.addMenuItems(menu, ['makeCopy'], parent); 1190 } 1191 } 1192 1193 if (urlParams['sketch'] == '1' && !mxClient.IS_CHROMEAPP && 1194 !EditorUi.isElectronApp && file != null && 1195 file.constructor != LocalFile) 1196 { 1197 ui.menus.addMenuItems(menu, ['-', 'synchronize'], parent); 1198 } 1199 1200 ui.menus.addMenuItems(menu, ['-', 'autosave'], parent); 1201 1202 if (file != null && file.isRevisionHistorySupported()) 1203 { 1204 ui.menus.addMenuItems(menu, ['-', 'revisionHistory'], parent); 1205 } 1206 }))); 1207 1208 // Augments the existing export menu 1209 var exportAsMenu = this.get('exportAs'); 1210 1211 this.put('exportAs', new Menu(mxUtils.bind(this, function(menu, parent) 1212 { 1213 exportAsMenu.funct(menu, parent); 1214 1215 if (!mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp) 1216 { 1217 // Publish menu contains only one element by default... 1218 //ui.menus.addSubmenu('publish', menu, parent); 1219 ui.menus.addMenuItems(menu, ['publishLink'], parent); 1220 } 1221 1222 if (ui.mode != App.MODE_ATLAS && urlParams['extAuth'] != '1') 1223 { 1224 menu.addSeparator(parent); 1225 ui.menus.addSubmenu('embed', menu, parent); 1226 } 1227 }))); 1228 1229 var langMenu = this.get('language'); 1230 1231 this.put('table', new Menu(mxUtils.bind(this, function(menu, parent) 1232 { 1233 ui.menus.addInsertTableCellItem(menu, parent); 1234 }))); 1235 1236 // Adds XML option to import menu 1237 var importMenu = this.get('importFrom'); 1238 1239 this.put('importFrom', new Menu(mxUtils.bind(this, function(menu, parent) 1240 { 1241 importMenu.funct(menu, parent); 1242 1243 this.addMenuItems(menu, ['editDiagram'], parent); 1244 1245 if (urlParams['sketch'] == '1') 1246 { 1247 menu.addSeparator(parent); 1248 1249 menu.addItem(mxResources.get('csv') + '...', null, function() 1250 { 1251 ui.showImportCsvDialog(); 1252 }, parent, null, mxUtils.bind(graph, graph.isEnabled)); 1253 1254 ui.addInsertMenuItems(menu, parent, ['formatSql', '-', 1255 'fromText', 'plantUml', 'mermaid']); 1256 } 1257 }))); 1258 1259 // Extras menu is labelled preferences but keeps ID for extensions 1260 this.put('extras', new Menu(mxUtils.bind(this, function(menu, parent) 1261 { 1262 if (urlParams['embed'] != '1' && urlParams['extAuth'] != '1') 1263 { 1264 ui.menus.addSubmenu('theme', menu, parent); 1265 } 1266 1267 if (langMenu != null) 1268 { 1269 ui.menus.addSubmenu('language', menu, parent); 1270 } 1271 1272 ui.menus.addSubmenu('units', menu, parent); 1273 menu.addSeparator(parent); 1274 ui.menus.addMenuItems(menu, ['scrollbars', 'tooltips', 'ruler', '-', 'copyConnect', 'collapseExpand', '-'], parent); 1275 1276 if (urlParams['sketch'] == '1') 1277 { 1278 this.addMenuItems(menu, ['toggleSketchMode'], parent); 1279 } 1280 1281 if (urlParams['embedInline'] != '1') 1282 { 1283 if (Editor.isDarkMode() || (!mxClient.IS_IE && !mxClient.IS_IE11)) 1284 { 1285 this.addMenuItems(menu, ['toggleDarkMode'], parent); 1286 } 1287 1288 if (urlParams['embed'] != '1' && (isLocalStorage || mxClient.IS_CHROMEAPP)) 1289 { 1290 ui.menus.addMenuItems(menu, ['-', 'showStartScreen', 'search', 'scratchpad'], parent); 1291 } 1292 1293 if (urlParams['sketch'] == '1' && urlParams['pages'] == null) 1294 { 1295 this.addMenuItems(menu, ['togglePagesVisible'], parent); 1296 } 1297 } 1298 1299 menu.addSeparator(parent); 1300 ui.menus.addMenuItem(menu, 'configuration', parent); 1301 1302 if (!ui.isOfflineApp() && isLocalStorage) 1303 { 1304 ui.menus.addMenuItem(menu, 'plugins', parent); 1305 } 1306 1307 this.addMenuItems(menu, ['-', 'fullscreen'], parent); 1308 1309 // Adds trailing separator in case new plugin entries are added 1310 menu.addSeparator(parent); 1311 }))); 1312 1313 this.put('insertAdvanced', new Menu(mxUtils.bind(this, function(menu, parent) 1314 { 1315 ui.menus.addMenuItems(menu, ['importText', 'plantUml', 'mermaid', '-', 'formatSql', 'importCsv', '-', 'createShape', 'editDiagram'], parent); 1316 }))); 1317 1318 (mxUtils.bind(this, function() 1319 { 1320 var insertMenu = this.get('insert'); 1321 var insertMenuFunct = insertMenu.funct; 1322 1323 insertMenu.funct = function(menu, parent) 1324 { 1325 if (urlParams['sketch'] == '1') 1326 { 1327 ui.menus.addMenuItems(menu, ['insertFreehand'], parent); 1328 1329 if (ui.insertTemplateEnabled && !ui.isOffline()) 1330 { 1331 ui.menus.addMenuItems(menu, ['insertTemplate'], parent); 1332 } 1333 } 1334 else 1335 { 1336 insertMenuFunct.apply(this, arguments); 1337 ui.menus.addSubmenu('table', menu, parent); 1338 menu.addSeparator(parent); 1339 } 1340 1341 ui.menus.addMenuItems(menu, ['-', 'toggleShapes'], parent); 1342 }; 1343 }))(); 1344 1345 var methods = ['horizontalFlow', 'verticalFlow', '-', 'horizontalTree', 'verticalTree', 1346 'radialTree', '-', 'organic', 'circle']; 1347 1348 var addInsertItem = function(menu, parent, title, method) 1349 { 1350 menu.addItem(title, null, mxUtils.bind(this, function() 1351 { 1352 var dlg = new CreateGraphDialog(ui, title, method); 1353 ui.showDialog(dlg.container, 620, 420, true, false); 1354 // Executed after dialog is added to dom 1355 dlg.init(); 1356 }), parent); 1357 }; 1358 1359 this.put('insertLayout', new Menu(mxUtils.bind(this, function(menu, parent) 1360 { 1361 for (var i = 0; i < methods.length; i++) 1362 { 1363 if (methods[i] == '-') 1364 { 1365 menu.addSeparator(parent); 1366 } 1367 else 1368 { 1369 addInsertItem(menu, parent, mxResources.get(methods[i]) + '...', methods[i]); 1370 } 1371 } 1372 }))); 1373 }; 1374 1375 // Installs the format toolbar 1376 EditorUi.prototype.installFormatToolbar = function(container) 1377 { 1378 var graph = this.editor.graph; 1379 var div = document.createElement('div'); 1380 1381 div.style.cssText = 'position:absolute;top:10px;z-index:1;border-radius:4px;' + 1382 'box-shadow:0px 0px 3px 1px #d1d1d1;padding:6px;white-space:nowrap;background-color:#fff;' + 1383 'transform:translate(-50%, 0);left:50%;'; 1384 1385 graph.getSelectionModel().addListener(mxEvent.CHANGE, mxUtils.bind(this, function(sender, evt) 1386 { 1387 if (graph.getSelectionCount() > 0) 1388 { 1389 container.appendChild(div); 1390 div.innerHTML = 'Selected: ' + graph.getSelectionCount(); 1391 } 1392 else if (div.parentNode != null) 1393 { 1394 div.parentNode.removeChild(div); 1395 } 1396 })); 1397 }; 1398 1399 var formatWindowInitialized = false; 1400 1401 EditorUi.prototype.initFormatWindow = function() 1402 { 1403 if (!formatWindowInitialized) 1404 { 1405 formatWindowInitialized = true; 1406 this.formatWindow.window.setClosable(false); 1407 1408 var toggleMinimized = this.formatWindow.window.toggleMinimized; 1409 1410 this.formatWindow.window.toggleMinimized = function() 1411 { 1412 toggleMinimized.apply(this, arguments); 1413 1414 if (this.minimized) 1415 { 1416 this.div.style.width = '90px'; 1417 this.table.style.width = '90px'; 1418 this.div.style.left = parseInt(this.div.style.left) + 150 + 'px'; 1419 } 1420 else 1421 { 1422 1423 this.div.style.width = '240px'; 1424 this.table.style.width = '240px'; 1425 this.div.style.left = Math.max(0, parseInt(this.div.style.left) - 150) + 'px'; 1426 } 1427 1428 this.fit(); 1429 }; 1430 1431 mxEvent.addListener(this.formatWindow.window.title, 'dblclick', mxUtils.bind(this, function(evt) 1432 { 1433 if (mxEvent.getSource(evt) == this.formatWindow.window.title) 1434 { 1435 this.formatWindow.window.toggleMinimized(); 1436 } 1437 })); 1438 } 1439 }; 1440 1441 // Initializes the user interface 1442 var editorUiInit = EditorUi.prototype.init; 1443 1444 EditorUi.prototype.init = function() 1445 { 1446 editorUiInit.apply(this, arguments); 1447 1448 if (urlParams['embedInline'] != '1') 1449 { 1450 this.doSetDarkMode((urlParams['dark'] != null) ? 1451 urlParams['dark'] == 1 && !mxClient.IS_IE && 1452 !mxClient.IS_IE11 : ((mxSettings.settings.darkMode != null) ? 1453 mxSettings.settings.darkMode : (window.matchMedia && 1454 window.matchMedia('(prefers-color-scheme: dark)').matches))); 1455 } 1456 1457 var div = document.createElement('div'); 1458 div.style.cssText = 'position:absolute;left:0px;right:0px;top:0px;overflow-y:auto;overflow-x:hidden;'; 1459 div.style.bottom = (urlParams['embed'] != '1' || urlParams['libraries'] == '1') ? '63px' : '32px'; 1460 this.sidebar = this.createSidebar(div); 1461 1462 if (urlParams['sketch'] == '1') 1463 { 1464 this.toggleScratchpad(); 1465 } 1466 1467 if ((urlParams['sketch'] != '1' && iw >= 1000) || urlParams['clibs'] != null || 1468 urlParams['libs'] != null || urlParams['search-shapes'] != null) 1469 { 1470 toggleShapes(this, true); 1471 1472 if (this.sidebar != null && urlParams['search-shapes'] != null && this.sidebar.searchShapes != null) 1473 { 1474 this.sidebar.searchShapes(urlParams['search-shapes']); 1475 this.sidebar.showEntries('search'); 1476 } 1477 } 1478 1479 // Overrides mxWindow.fit to allow for embedViewport 1480 var ui = this; 1481 1482 mxWindow.prototype.fit = function() 1483 { 1484 if (!Editor.inlineFullscreen && ui.embedViewport != null) 1485 { 1486 var left = parseInt(this.div.offsetLeft); 1487 var width = parseInt(this.div.offsetWidth); 1488 var right = ui.embedViewport.x + ui.embedViewport.width; 1489 this.div.style.left = Math.max(ui.embedViewport.x, Math.min(left, right - width)) + 'px'; 1490 1491 var top = parseInt(this.div.offsetTop); 1492 var height = parseInt(this.div.offsetHeight); 1493 var bottom = ui.embedViewport.y + ui.embedViewport.height; 1494 1495 this.div.style.top = Math.max(ui.embedViewport.y, Math.min(top, bottom - height)) + 'px'; 1496 } 1497 else 1498 { 1499 mxUtils.fit(this.div); 1500 } 1501 }; 1502 1503 // Overrides insert ellipse shortcut 1504 this.keyHandler.bindAction(75, true, 'toggleShapes', true); // Ctrl+Shift+K 1505 1506 if (urlParams['sketch'] == '1' || iw >= 1000) 1507 { 1508 if (urlParams['embedInline'] != '1') 1509 { 1510 toggleFormat(this, true); 1511 1512 if (urlParams['sketch'] == '1') 1513 { 1514 this.initFormatWindow(); 1515 this.formatWindow.window.toggleMinimized(); 1516 } 1517 } 1518 } 1519 1520 // Needed for creating elements in Format panel 1521 var ui = this; 1522 var graph = ui.editor.graph; 1523 ui.toolbar = this.createToolbar(ui.createDiv('geToolbar')); 1524 ui.defaultLibraryName = mxResources.get('untitledLibrary'); 1525 1526 var menubar = document.createElement('div'); 1527 menubar.className = 'geMenubarContainer'; 1528 var before = null; 1529 var menuObj = new Menubar(ui, menubar); 1530 1531 function addMenu(id, small, img) 1532 { 1533 var menu = ui.menus.get(id); 1534 1535 var elt = menuObj.addMenu(mxResources.get(id), mxUtils.bind(this, function() 1536 { 1537 // Allows extensions of menu.functid 1538 menu.funct.apply(this, arguments); 1539 }), before); 1540 1541 elt.className = (urlParams['sketch'] == '1') ? 'geToolbarButton' : 'geMenuItem'; 1542 elt.style.display = 'inline-block'; 1543 elt.style.boxSizing = 'border-box'; 1544 elt.style.top = '6px'; 1545 elt.style.marginRight = '6px'; 1546 elt.style.height = '30px'; 1547 elt.style.paddingTop = '6px'; 1548 elt.style.paddingBottom = '6px'; 1549 elt.style.cursor = 'pointer'; 1550 elt.setAttribute('title', mxResources.get(id)); 1551 ui.menus.menuCreated(menu, elt, 'geMenuItem'); 1552 1553 if (img != null) 1554 { 1555 elt.style.backgroundImage = 'url(' + img + ')'; 1556 elt.style.backgroundPosition = 'center center'; 1557 elt.style.backgroundRepeat = 'no-repeat'; 1558 elt.style.backgroundSize = '24px 24px'; 1559 elt.style.width = '34px'; 1560 elt.innerHTML = ''; 1561 } 1562 else if (!small) 1563 { 1564 elt.style.backgroundImage = 'url(' + mxWindow.prototype.normalizeImage + ')'; 1565 elt.style.backgroundPosition = 'right 6px center'; 1566 elt.style.backgroundRepeat = 'no-repeat'; 1567 elt.style.paddingRight = '22px'; 1568 } 1569 1570 return elt; 1571 }; 1572 1573 function addMenuItem(label, fn, small, tooltip, action, img) 1574 { 1575 var btn = document.createElement('a'); 1576 btn.className = (urlParams['sketch'] == '1') ? 'geToolbarButton' : 'geMenuItem'; 1577 btn.style.display = 'inline-block'; 1578 btn.style.boxSizing = 'border-box'; 1579 btn.style.height = '30px'; 1580 btn.style.padding = '6px'; 1581 btn.style.position = 'relative'; 1582 btn.style.verticalAlign = 'top'; 1583 btn.style.top = '0px'; 1584 1585 if (urlParams['sketch'] == '1') 1586 { 1587 btn.style.borderStyle = 'none'; 1588 btn.style.boxShadow = 'none'; 1589 btn.style.padding = '6px'; 1590 btn.style.margin = '0px'; 1591 } 1592 1593 if (ui.statusContainer != null) 1594 { 1595 menubar.insertBefore(btn, ui.statusContainer); 1596 } 1597 else 1598 { 1599 menubar.appendChild(btn); 1600 } 1601 1602 if (img != null) 1603 { 1604 btn.style.backgroundImage = 'url(' + img + ')'; 1605 btn.style.backgroundPosition = 'center center'; 1606 btn.style.backgroundRepeat = 'no-repeat'; 1607 btn.style.backgroundSize = '24px 24px'; 1608 btn.style.width = '34px'; 1609 } 1610 else 1611 { 1612 mxUtils.write(btn, label); 1613 } 1614 1615 // Prevents focus 1616 mxEvent.addListener(btn, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown', 1617 mxUtils.bind(this, function(evt) 1618 { 1619 evt.preventDefault(); 1620 })); 1621 1622 mxEvent.addListener(btn, 'click', function(evt) 1623 { 1624 if (btn.getAttribute('disabled') != 'disabled') 1625 { 1626 fn(evt); 1627 } 1628 1629 mxEvent.consume(evt); 1630 }); 1631 1632 if (small == null) 1633 { 1634 btn.style.marginRight = '4px'; 1635 } 1636 1637 if (tooltip != null) 1638 { 1639 btn.setAttribute('title', tooltip); 1640 } 1641 1642 if (action != null) 1643 { 1644 function updateState() 1645 { 1646 if (action.isEnabled()) 1647 { 1648 btn.removeAttribute('disabled'); 1649 btn.style.cursor = 'pointer'; 1650 } 1651 else 1652 { 1653 btn.setAttribute('disabled', 'disabled'); 1654 btn.style.cursor = 'default'; 1655 } 1656 }; 1657 1658 action.addListener('stateChanged', updateState); 1659 graph.addListener('enabledChanged', updateState); 1660 updateState(); 1661 } 1662 1663 return btn; 1664 }; 1665 1666 function createGroup(btns, op, container) 1667 { 1668 var btnGroup = document.createElement('div'); 1669 btnGroup.className = 'geMenuItem'; 1670 btnGroup.style.display = 'inline-block'; 1671 btnGroup.style.verticalAlign = 'top'; 1672 btnGroup.style.marginRight = '6px'; 1673 btnGroup.style.padding = '0 4px 0 4px'; 1674 btnGroup.style.height = '30px'; 1675 btnGroup.style.position = 'relative'; 1676 btnGroup.style.top = '0px'; 1677 1678 if (urlParams['sketch'] == '1') 1679 { 1680 btnGroup.style.boxShadow = 'none'; 1681 } 1682 1683 for (var i = 0; i < btns.length; i++) 1684 { 1685 if (btns[i] != null) 1686 { 1687 if (urlParams['sketch'] == '1') 1688 { 1689 btns[i].style.padding = '10px 8px'; 1690 btns[i].style.width = '30px'; 1691 } 1692 1693 btns[i].style.margin = '0px'; 1694 btns[i].style.boxShadow = 'none'; 1695 btnGroup.appendChild(btns[i]); 1696 } 1697 } 1698 1699 if (op != null) 1700 { 1701 mxUtils.setOpacity(btnGroup, op); 1702 } 1703 1704 if (ui.statusContainer != null && urlParams['sketch'] != '1') 1705 { 1706 menubar.insertBefore(btnGroup, ui.statusContainer); 1707 } 1708 else 1709 { 1710 menubar.appendChild(btnGroup); 1711 } 1712 1713 return btnGroup; 1714 }; 1715 1716 ui.statusContainer = ui.createStatusContainer(); 1717 ui.statusContainer.style.position = 'relative'; 1718 ui.statusContainer.style.maxWidth = ''; 1719 ui.statusContainer.style.marginTop = '7px'; 1720 ui.statusContainer.style.marginLeft = '6px'; 1721 ui.statusContainer.style.color = 'gray'; 1722 ui.statusContainer.style.cursor = 'default'; 1723 1724 function updateTitle() 1725 { 1726 var file = ui.getCurrentFile(); 1727 1728 if (file != null && file.getTitle() != null) 1729 { 1730 var mode = file.getMode(); 1731 1732 if (mode == 'google') 1733 { 1734 mode = 'googleDrive'; 1735 } 1736 else if (mode == 'github') 1737 { 1738 mode = 'gitHub'; 1739 } 1740 else if (mode == 'gitlab') 1741 { 1742 mode = 'gitLab'; 1743 } 1744 else if (mode == 'onedrive') 1745 { 1746 mode = 'oneDrive'; 1747 } 1748 1749 mode = mxResources.get(mode); 1750 menubar.setAttribute('title', file.getTitle() + ((mode != null) ? ' (' + mode + ')' : '')); 1751 } 1752 else 1753 { 1754 menubar.removeAttribute('title'); 1755 } 1756 }; 1757 1758 // Hides popup menus 1759 var uiHideCurrentMenu = ui.hideCurrentMenu; 1760 1761 ui.hideCurrentMenu = function() 1762 { 1763 uiHideCurrentMenu.apply(this, arguments); 1764 this.editor.graph.popupMenuHandler.hideMenu(); 1765 }; 1766 1767 // Connects the status bar to the editor status 1768 var uiDescriptorChanged = ui.descriptorChanged; 1769 1770 ui.descriptorChanged = function() 1771 { 1772 uiDescriptorChanged.apply(this, arguments); 1773 updateTitle(); 1774 }; 1775 1776 ui.setStatusText(ui.editor.getStatus()); 1777 menubar.appendChild(ui.statusContainer); 1778 1779 ui.buttonContainer = document.createElement('div'); 1780 ui.buttonContainer.style.cssText = 'position:absolute;right:0px;padding-right:34px;top:10px;' + 1781 'white-space:nowrap;padding-top:2px;background-color:inherit;'; 1782 menubar.appendChild(ui.buttonContainer); 1783 1784 // Container for the user element 1785 ui.menubarContainer = ui.buttonContainer; 1786 1787 ui.tabContainer = document.createElement('div'); 1788 ui.tabContainer.className = 'geTabContainer'; 1789 ui.tabContainer.style.cssText = 'position:absolute;left:0px;right:0px;bottom:0px;height:30px;white-space:nowrap;' + 1790 'margin-bottom:-2px;visibility:hidden;'; 1791 1792 var previousParent = ui.diagramContainer.parentNode; 1793 1794 var wrapper = document.createElement('div'); 1795 wrapper.style.cssText = 'position:absolute;top:0px;left:0px;right:0px;bottom:0px;overflow:hidden;'; 1796 ui.diagramContainer.style.top = (urlParams['sketch'] == '1') ? '0px' : '47px'; 1797 1798 var viewZoomMenu = ui.menus.get('viewZoom'); 1799 var insertImage = (urlParams['sketch'] != '1') ? Editor.plusImage : Editor.shapesImage; 1800 var footer = (urlParams['sketch'] == '1') ? document.createElement('div') : null; 1801 var picker = (urlParams['sketch'] == '1') ? document.createElement('div') : null; 1802 var toolbar = (urlParams['sketch'] == '1') ? document.createElement('div') : null; 1803 1804 var refreshSidebar = mxUtils.bind(this, function() 1805 { 1806 if (this.sidebar != null) 1807 { 1808 this.sidebar.graph.stylesheet.styles = 1809 mxUtils.clone(graph.stylesheet.styles); 1810 this.sidebar.container.innerHTML = ''; 1811 this.sidebar.palettes = new Object(); 1812 this.sidebar.init(); 1813 1814 if (urlParams['sketch'] == '1') 1815 { 1816 this.scratchpad = null; 1817 this.toggleScratchpad(); 1818 } 1819 } 1820 1821 graph.refresh(); 1822 graph.view.validateBackground(); 1823 }); 1824 1825 ui.addListener('darkModeChanged', refreshSidebar); 1826 ui.addListener('sketchModeChanged', refreshSidebar); 1827 1828 var inlineSizeChanged = mxUtils.bind(this, function() 1829 { 1830 if (Editor.inlineFullscreen) 1831 { 1832 toolbar.style.left = '10px'; 1833 toolbar.style.top = '10px'; 1834 1835 picker.style.left = '10px'; 1836 picker.style.top = '60px'; 1837 1838 footer.style.top = '10px'; 1839 footer.style.right = '12px'; 1840 footer.style.left = ''; 1841 1842 ui.diagramContainer.setAttribute('data-bounds', ui.diagramContainer.style.top + ' ' + 1843 ui.diagramContainer.style.left + ' ' + ui.diagramContainer.style.width + ' ' + 1844 ui.diagramContainer.style.height); 1845 1846 ui.diagramContainer.style.top = '0px'; 1847 ui.diagramContainer.style.left = '0px'; 1848 ui.diagramContainer.style.bottom = '0px'; 1849 ui.diagramContainer.style.right = '0px'; 1850 ui.diagramContainer.style.width = ''; 1851 ui.diagramContainer.style.height = ''; 1852 } 1853 else 1854 { 1855 var bounds = ui.diagramContainer.getAttribute('data-bounds'); 1856 1857 if (bounds != null) 1858 { 1859 ui.diagramContainer.style.background = 'transparent'; 1860 ui.diagramContainer.removeAttribute('data-bounds'); 1861 var gb = graph.getGraphBounds(); 1862 var tokens = bounds.split(' '); 1863 1864 ui.diagramContainer.style.top = tokens[0]; 1865 ui.diagramContainer.style.left = tokens[1]; 1866 ui.diagramContainer.style.width = (gb.width + 50) + 'px'; 1867 ui.diagramContainer.style.height = (gb.height + 46) + 'px'; 1868 ui.diagramContainer.style.bottom = ''; 1869 ui.diagramContainer.style.right = ''; 1870 1871 var parent = window.opener || window.parent; 1872 parent.postMessage(JSON.stringify({ 1873 event: 'resize', 1874 rect: ui.diagramContainer.getBoundingClientRect() 1875 }), '*'); 1876 ui.refresh(); 1877 } 1878 1879 toolbar.style.left = ui.diagramContainer.offsetLeft + 'px'; 1880 toolbar.style.top = (ui.diagramContainer.offsetTop - 1881 toolbar.offsetHeight - 4) + 'px'; 1882 1883 picker.style.display = ''; 1884 picker.style.left = (ui.diagramContainer.offsetLeft - 1885 picker.offsetWidth - 4) + 'px'; 1886 picker.style.top = ui.diagramContainer.offsetTop + 'px'; 1887 1888 footer.style.left = (ui.diagramContainer.offsetLeft + 1889 ui.diagramContainer.offsetWidth - 1890 footer.offsetWidth) + 'px'; 1891 footer.style.top = toolbar.style.top; 1892 footer.style.right = ''; 1893 1894 ui.bottomResizer.style.left = (ui.diagramContainer.offsetLeft + 1895 (ui.diagramContainer.offsetWidth - 1896 ui.bottomResizer.offsetWidth) / 2) + 'px'; 1897 ui.bottomResizer.style.top = (ui.diagramContainer.offsetTop + 1898 ui.diagramContainer.offsetHeight - 1899 ui.bottomResizer.offsetHeight / 2 - 1) + 'px'; 1900 1901 ui.rightResizer.style.left = (ui.diagramContainer.offsetLeft + 1902 ui.diagramContainer.offsetWidth - 1903 ui.rightResizer.offsetWidth / 2 - 1) + 'px'; 1904 ui.rightResizer.style.top = (ui.diagramContainer.offsetTop + 1905 (ui.diagramContainer.offsetHeight - 1906 ui.bottomResizer.offsetHeight) / 2) + 'px'; 1907 } 1908 1909 ui.bottomResizer.style.visibility = (Editor.inlineFullscreen) ? 'hidden' : ''; 1910 ui.rightResizer.style.visibility = ui.bottomResizer.style.visibility; 1911 menubar.style.display = 'none'; 1912 toolbar.style.visibility = ''; 1913 footer.style.visibility = ''; 1914 }); 1915 1916 var inlineFullscreenChanged = mxUtils.bind(this, function() 1917 { 1918 fullscreenElt.style.backgroundImage = 'url(' + ((!Editor.inlineFullscreen) ? 1919 Editor.fullscreenImage : Editor.fullscreenExitImage) + ')'; 1920 this.diagramContainer.style.background = (Editor.inlineFullscreen) ? 1921 (Editor.isDarkMode() ? Editor.darkColor : '#ffffff') : 'transparent'; 1922 inlineSizeChanged(); 1923 }); 1924 1925 var editInlineStart = mxUtils.bind(this, function() 1926 { 1927 inlineFullscreenChanged(); 1928 toggleFormat(ui, true); 1929 ui.initFormatWindow(); 1930 var r = this.diagramContainer.getBoundingClientRect(); 1931 this.formatWindow.window.setLocation(r.x + r.width + 4, r.y); 1932 }); 1933 1934 ui.addListener('inlineFullscreenChanged', inlineFullscreenChanged); 1935 ui.addListener('editInlineStart', editInlineStart); 1936 1937 if (urlParams['embedInline'] == '1') 1938 { 1939 ui.addListener('darkModeChanged', editInlineStart); 1940 } 1941 1942 ui.addListener('editInlineStop', mxUtils.bind(this, function(evt) 1943 { 1944 ui.diagramContainer.style.width = '10px'; 1945 ui.diagramContainer.style.height = '10px'; 1946 ui.diagramContainer.style.border = ''; 1947 ui.bottomResizer.style.visibility = 'hidden'; 1948 ui.rightResizer.style.visibility = 'hidden'; 1949 toolbar.style.visibility = 'hidden'; 1950 footer.style.visibility = 'hidden'; 1951 picker.style.display = 'none'; 1952 })); 1953 1954 // Stops panning while freehand is active 1955 if (Graph.touchStyle) 1956 { 1957 graph.panningHandler.isPanningTrigger = function(me) 1958 { 1959 var evt = me.getEvent(); 1960 1961 return (me.getState() == null && (!mxEvent.isMouseEvent(evt) && 1962 !graph.freehand.isDrawing())) || 1963 (mxEvent.isPopupTrigger(evt) && (me.getState() == null || 1964 mxEvent.isControlDown(evt) || mxEvent.isShiftDown(evt))); 1965 }; 1966 } 1967 1968 // Hides hover icons if freehand is active 1969 if (ui.hoverIcons != null) 1970 { 1971 var hoverIconsUpdate = ui.hoverIcons.update; 1972 1973 ui.hoverIcons.update = function() 1974 { 1975 if (!graph.freehand.isDrawing()) 1976 { 1977 hoverIconsUpdate.apply(this, arguments); 1978 } 1979 }; 1980 } 1981 1982 // Removes sketch style from freehand shapes 1983 if (graph.freehand != null) 1984 { 1985 var freehandCreateStyle = graph.freehand.createStyle; 1986 1987 graph.freehand.createStyle = function(stencil) 1988 { 1989 return freehandCreateStyle.apply(this, arguments) + 'sketch=0;'; 1990 }; 1991 } 1992 1993 if (urlParams['sketch'] == '1') 1994 { 1995 picker.className = 'geToolbarContainer'; 1996 footer.className = 'geToolbarContainer'; 1997 toolbar.className = 'geToolbarContainer'; 1998 menubar.className = 'geToolbarContainer'; 1999 2000 ui.picker = picker; 2001 var statusVisible = false; 2002 2003 mxEvent.addListener(menubar, 'mouseenter', function() 2004 { 2005 ui.statusContainer.style.display = 'inline-block'; 2006 }); 2007 2008 mxEvent.addListener(menubar, 'mouseleave', function() 2009 { 2010 if (!statusVisible) 2011 { 2012 ui.statusContainer.style.display = 'none'; 2013 } 2014 }); 2015 2016 var setNotificationTitle = mxUtils.bind(this, function(title) 2017 { 2018 if (ui.notificationBtn != null) 2019 { 2020 if (title != null) 2021 { 2022 ui.notificationBtn.setAttribute('title', title); 2023 } 2024 else 2025 { 2026 ui.notificationBtn.removeAttribute('title'); 2027 } 2028 } 2029 }); 2030 2031 // Connects the status bar to the editor status and 2032 // moves status to bell icon tooltip for trivial messages 2033 if (urlParams['embed'] != '1') 2034 { 2035 menubar.style.visibility = (menubar.clientWidth < 14) ? 'hidden' : ''; 2036 2037 ui.editor.addListener('statusChanged', mxUtils.bind(this, function() 2038 { 2039 ui.setStatusText(ui.editor.getStatus()); 2040 2041 if (ui.statusContainer.children.length == 0 || 2042 (ui.statusContainer.children.length == 1 && 2043 typeof ui.statusContainer.firstChild.getAttribute === 'function' && 2044 ui.statusContainer.firstChild.getAttribute('class') == null)) 2045 { 2046 var title = (ui.statusContainer.firstChild != null && 2047 typeof ui.statusContainer.firstChild.getAttribute === 'function') ? 2048 ui.statusContainer.firstChild.getAttribute('title') : 2049 ui.editor.getStatus(); 2050 setNotificationTitle(title); 2051 var file = ui.getCurrentFile(); 2052 var key = (file != null) ? file.savingStatusKey : DrawioFile.prototype.savingStatusKey; 2053 2054 if (title == mxResources.get(key) + '...') 2055 { 2056 ui.statusContainer.innerHTML = '<img title="' + mxUtils.htmlEntities( 2057 mxResources.get(key)) + '...' + '"src="' + Editor.tailSpin + '">'; 2058 ui.statusContainer.style.display = 'inline-block'; 2059 statusVisible = true; 2060 } 2061 else if (ui.buttonContainer.clientWidth > 6) 2062 { 2063 ui.statusContainer.style.display = 'none'; 2064 statusVisible = false; 2065 } 2066 } 2067 else 2068 { 2069 ui.statusContainer.style.display = 'inline-block'; 2070 setNotificationTitle(null); 2071 2072 statusVisible = true; 2073 } 2074 2075 menubar.style.visibility = (menubar.clientWidth > 12) ? '' : 'hidden'; 2076 })); 2077 } 2078 else 2079 { 2080 ui.editor.addListener('statusChanged', mxUtils.bind(this, function() 2081 { 2082 menubar.style.visibility = (menubar.clientWidth > 16) ? '' : 'hidden'; 2083 })); 2084 } 2085 2086 elt = addMenu('diagram', null, Editor.menuImage); 2087 elt.style.boxShadow = 'none'; 2088 elt.style.padding = '6px'; 2089 elt.style.margin = '0px'; 2090 toolbar.appendChild(elt); 2091 2092 mxEvent.disableContextMenu(elt); 2093 2094 mxEvent.addGestureListeners(elt, mxUtils.bind(this, function(evt) 2095 { 2096 if (mxEvent.isShiftDown(evt) || mxEvent.isAltDown(evt) || 2097 mxEvent.isMetaDown(evt) || mxEvent.isControlDown(evt) || 2098 mxEvent.isPopupTrigger(evt)) 2099 { 2100 this.appIconClicked(evt); 2101 } 2102 }), null, null); 2103 2104 ui.statusContainer.style.position = ''; 2105 ui.statusContainer.style.display = 'none'; 2106 ui.statusContainer.style.margin = '0px'; 2107 ui.statusContainer.style.padding = '6px 0px'; 2108 ui.statusContainer.style.maxWidth = Math.min(iw - 240, 280) + 'px'; 2109 ui.statusContainer.style.display = 'inline-block'; 2110 ui.statusContainer.style.textOverflow = 'ellipsis'; 2111 2112 ui.buttonContainer.style.position = ''; 2113 ui.buttonContainer.style.paddingRight = '0px'; 2114 ui.buttonContainer.style.display = 'inline-block'; 2115 2116 var foldImg = document.createElement('a'); 2117 foldImg.style.padding = '0px'; 2118 foldImg.style.boxShadow = 'none'; 2119 foldImg.className = 'geMenuItem'; 2120 foldImg.style.display = 'inline-block'; 2121 foldImg.style.width = '40px'; 2122 foldImg.style.height = '12px'; 2123 foldImg.style.marginBottom = '-2px'; 2124 foldImg.style.backgroundImage = 'url(' + mxWindow.prototype.normalizeImage + ')'; 2125 foldImg.style.backgroundPosition = 'top center'; 2126 foldImg.style.backgroundRepeat = 'no-repeat'; 2127 foldImg.setAttribute('title', 'Minimize'/*TODO:mxResources.get('minimize')*/); 2128 2129 var collapsed = false; 2130 2131 var initPicker = mxUtils.bind(this, function() 2132 { 2133 picker.innerHTML = ''; 2134 2135 if (!collapsed) 2136 { 2137 function addElt(elt, title, cursor) 2138 { 2139 if (title != null) 2140 { 2141 elt.setAttribute('title', title); 2142 } 2143 2144 elt.style.cursor = (cursor != null) ? cursor : 'default'; 2145 elt.style.margin = '2px 0px'; 2146 picker.appendChild(elt); 2147 mxUtils.br(picker); 2148 2149 return elt; 2150 }; 2151 2152 // Append sidebar elements 2153 addElt(ui.sidebar.createVertexTemplate('text;strokeColor=none;fillColor=none;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;', 2154 60, 30, 'Text', mxResources.get('text'), true, false, null, true, true), mxResources.get('text') + 2155 ' (' + Editor.ctrlKey + '+Shift+X' + ')'); 2156 addElt(ui.sidebar.createVertexTemplate('shape=note;whiteSpace=wrap;html=1;backgroundOutline=1;' + 2157 'fontColor=#000000;darkOpacity=0.05;fillColor=#FFF9B2;strokeColor=none;fillStyle=solid;' + 2158 'direction=west;gradientDirection=north;gradientColor=#FFF2A1;shadow=1;size=20;pointerEvents=1;', 2159 140, 160, '', mxResources.get('note'), true, false, null, true), mxResources.get('note')); 2160 addElt(ui.sidebar.createVertexTemplate('rounded=0;whiteSpace=wrap;html=1;', 160, 80, 2161 '', mxResources.get('rectangle'), true, false, null, true), mxResources.get('rectangle') + 2162 ' (' + Editor.ctrlKey + '+K' + ')'); 2163 addElt(ui.sidebar.createVertexTemplate('ellipse;whiteSpace=wrap;html=1;', 160, 100, 2164 '', mxResources.get('ellipse'), true, false, null, true), mxResources.get('ellipse')); 2165 2166 (function() 2167 { 2168 var edgeStyle = 'edgeStyle=none;orthogonalLoop=1;jettySize=auto;html=1;'; 2169 var cell = new mxCell('', new mxGeometry(0, 0, graph.defaultEdgeLength, 0), edgeStyle); 2170 cell.geometry.setTerminalPoint(new mxPoint(0, 0), true); 2171 cell.geometry.setTerminalPoint(new mxPoint(cell.geometry.width, 0), false); 2172 cell.geometry.points = []; 2173 cell.geometry.relative = true; 2174 cell.edge = true; 2175 2176 addElt(ui.sidebar.createEdgeTemplateFromCells([cell], 2177 cell.geometry.width, cell.geometry.height, 2178 mxResources.get('line'), true, null, true, false), 2179 mxResources.get('line')); 2180 2181 cell = cell.clone(); 2182 cell.style = edgeStyle + 'shape=flexArrow;rounded=1;startSize=8;endSize=8;'; 2183 cell.geometry.width = graph.defaultEdgeLength + 20; 2184 cell.geometry.setTerminalPoint(new mxPoint(0, 20), true); 2185 cell.geometry.setTerminalPoint(new mxPoint(cell.geometry.width, 20), false); 2186 2187 var elt = addElt(ui.sidebar.createEdgeTemplateFromCells([cell], 2188 cell.geometry.width, 40, mxResources.get('arrow'), 2189 true, null, true, false), mxResources.get('arrow')); 2190 elt.style.borderBottom = '1px solid ' + (Editor.isDarkMode() ? '#505050' : 'lightgray'); 2191 elt.style.paddingBottom = '14px'; 2192 elt.style.marginBottom = '14px'; 2193 })(); 2194 2195 function addAction(action, label, image) 2196 { 2197 var elt = addMenuItem('', action.funct, null, label, action, image); 2198 elt.style.width = '40px'; 2199 elt.style.opacity = '0.7'; 2200 2201 return addElt(elt, null, 'pointer'); 2202 }; 2203 2204 addAction(ui.actions.get('insertFreehand'), mxResources.get('freehand'), Editor.freehandImage); 2205 var toggleShapesAction = ui.actions.get('toggleShapes'); 2206 addAction(toggleShapesAction, mxResources.get('shapes') + ' (' + toggleShapesAction.shortcut + ')', insertImage); 2207 2208 elt = addMenu('table', null, Editor.tableImage); 2209 elt.style.boxShadow = 'none'; 2210 elt.style.opacity = '0.7'; 2211 elt.style.padding = '6px'; 2212 elt.style.margin = '0px'; 2213 elt.style.width = '37px'; 2214 addElt(elt, null, 'pointer'); 2215 2216 addAction(ui.actions.get('insertTemplate'), mxResources.get('template'), Editor.templateImage); 2217 } 2218 2219 if (urlParams['embedInline'] != '1') 2220 { 2221 picker.appendChild(foldImg); 2222 } 2223 }); 2224 2225 mxEvent.addListener(foldImg, 'click', mxUtils.bind(this, function() 2226 { 2227 if (collapsed) 2228 { 2229 mxUtils.setPrefixedStyle(picker.style, 'transform', 'translate(0, -50%)'); 2230 picker.style.padding = '8px 6px 4px'; 2231 picker.style.top = '50%'; 2232 picker.style.bottom = ''; 2233 picker.style.height = ''; 2234 foldImg.style.backgroundImage = 'url(' + mxWindow.prototype.normalizeImage + ')'; 2235 foldImg.style.width = '40px'; 2236 foldImg.style.height = '12px'; 2237 foldImg.setAttribute('title', 'Minimize'/*TODO:mxResources.get('minimize')*/); 2238 collapsed = false; 2239 initPicker(); 2240 } 2241 else 2242 { 2243 picker.innerHTML = ''; 2244 picker.appendChild(foldImg); 2245 mxUtils.setPrefixedStyle(picker.style, 'transform', 'translate(0, 0)'); 2246 picker.style.top = ''; 2247 picker.style.bottom = '12px'; 2248 picker.style.padding = '0px'; 2249 picker.style.height = '24px'; 2250 foldImg.style.height = '24px'; 2251 foldImg.style.backgroundImage = 'url(' + Editor.plusImage + ')'; 2252 foldImg.setAttribute('title', mxResources.get('insert')); 2253 foldImg.style.width = '24px'; 2254 collapsed = true; 2255 } 2256 })); 2257 2258 initPicker(); 2259 2260 ui.addListener('darkModeChanged', initPicker); 2261 ui.addListener('sketchModeChanged', initPicker); 2262 } 2263 else 2264 { 2265 // Connects the status bar to the editor status 2266 ui.editor.addListener('statusChanged', mxUtils.bind(this, function() 2267 { 2268 ui.setStatusText(ui.editor.getStatus()); 2269 })); 2270 } 2271 2272 if (viewZoomMenu != null) 2273 { 2274 var fitFunction = function(evt) 2275 { 2276 graph.popupMenuHandler.hideMenu(); 2277 2278 if (mxEvent.isAltDown(evt)) 2279 { 2280 ui.actions.get('customZoom').funct(); 2281 } 2282 else 2283 { 2284 ui.actions.get('smartFit').funct(); 2285 } 2286 }; 2287 2288 var zoomInAction = ui.actions.get('zoomIn'); 2289 var zoomOutAction = ui.actions.get('zoomOut'); 2290 var resetViewAction = ui.actions.get('resetView'); 2291 var fullscreenAction = ui.actions.get('fullscreen'); 2292 var toggleDarkAction = ui.actions.get('toggleDarkMode'); 2293 var undoAction = ui.actions.get('undo'); 2294 var redoAction = ui.actions.get('redo'); 2295 var undoElt = addMenuItem('', undoAction.funct, null, mxResources.get('undo') + ' (' + undoAction.shortcut + ')', undoAction, Editor.undoImage); 2296 var redoElt = addMenuItem('', redoAction.funct, null, mxResources.get('redo') + ' (' + redoAction.shortcut + ')', redoAction, Editor.redoImage); 2297 var fullscreenElt = addMenuItem('', fullscreenAction.funct, null, mxResources.get('fullscreen'), fullscreenAction, Editor.fullscreenImage); 2298 2299 if (footer != null) 2300 { 2301 fullscreenElt.parentNode.removeChild(fullscreenElt); 2302 var deleteAction = ui.actions.get('delete'); 2303 var deleteElt = addMenuItem('', deleteAction.funct, null, mxResources.get('delete'), deleteAction, Editor.trashImage); 2304 deleteElt.style.opacity = '0.1'; 2305 toolbar.appendChild(deleteElt); 2306 2307 deleteAction.addListener('stateChanged', function() 2308 { 2309 deleteElt.style.opacity = (deleteAction.enabled) ? '' : '0.1'; 2310 }); 2311 2312 var undoListener = function() 2313 { 2314 undoElt.style.display = (ui.editor.undoManager.history.length > 0 || 2315 graph.isEditing()) ? 'inline-block' : 'none'; 2316 redoElt.style.display = undoElt.style.display; 2317 2318 undoElt.style.opacity = (undoAction.enabled) ? '' : '0.1'; 2319 redoElt.style.opacity = (redoAction.enabled) ? '' : '0.1'; 2320 }; 2321 2322 toolbar.appendChild(undoElt); 2323 toolbar.appendChild(redoElt); 2324 2325 undoAction.addListener('stateChanged', undoListener); 2326 redoAction.addListener('stateChanged', undoListener); 2327 undoListener(); 2328 2329 if (urlParams['layers'] != null) 2330 { 2331 var layersAction = ui.actions.get('layers'); 2332 var layersElt = addMenuItem('', layersAction.funct, null, mxResources.get('layers'), layersAction, Editor.layersImage); 2333 layersElt.style.opacity = '0.4'; 2334 footer.appendChild(layersElt); 2335 } 2336 2337 if (urlParams['tags'] != null) 2338 { 2339 var tagsAction = ui.actions.get('tags'); 2340 var tagsElt = addMenuItem('', tagsAction.funct, null, mxResources.get('tags'), tagsAction, Editor.tagsImage); 2341 tagsElt.style.opacity = '0.4'; 2342 footer.appendChild(tagsElt); 2343 } 2344 2345 var outlineAction = ui.actions.get('outline'); 2346 var outlineElt = addMenuItem('', outlineAction.funct, null, mxResources.get('outline'), outlineAction, Editor.outlineImage); 2347 footer.appendChild(outlineElt); 2348 2349 var zoomOutElt = addMenuItem('', zoomOutAction.funct, true, mxResources.get('zoomOut') + 2350 ' (' + Editor.ctrlKey + ' -/Alt+Mousewheel)', zoomOutAction, Editor.zoomOutImage); 2351 footer.appendChild(zoomOutElt); 2352 2353 var elt = document.createElement('div'); 2354 elt.innerHTML = '100%'; 2355 elt.setAttribute('title', mxResources.get('fitWindow') + '/' + mxResources.get('resetView') + ' (Enter)'); 2356 elt.style.display = 'inline-block'; 2357 elt.style.cursor = 'pointer'; 2358 elt.style.textAlign = 'center'; 2359 elt.style.whiteSpace = 'nowrap'; 2360 elt.style.paddingRight = '10px'; 2361 elt.style.textDecoration = 'none'; 2362 elt.style.verticalAlign = 'top'; 2363 elt.style.padding = '6px 0'; 2364 elt.style.fontSize = '14px'; 2365 elt.style.width = '40px'; 2366 elt.style.opacity = '0.4'; 2367 footer.appendChild(elt); 2368 2369 mxEvent.addListener(elt, 'click', fitFunction); 2370 2371 var zoomInElt = addMenuItem('', zoomInAction.funct, true, mxResources.get('zoomIn') + 2372 ' (' + Editor.ctrlKey + ' +/Alt+Mousewheel)', zoomInAction, Editor.zoomInImage); 2373 footer.appendChild(zoomInElt); 2374 2375 if (urlParams['embedInline'] == '1') 2376 { 2377 footer.appendChild(fullscreenElt); 2378 var exitAction = ui.actions.get('exit'); 2379 footer.appendChild(addMenuItem('', exitAction.funct, null, mxResources.get('exit'), exitAction, Editor.closeImage)); 2380 } 2381 2382 var pageMenu = this.createPageMenuTab(false); 2383 pageMenu.style.display = 'none'; 2384 pageMenu.style.position = ''; 2385 pageMenu.style.marginLeft = ''; 2386 pageMenu.style.top = ''; 2387 pageMenu.style.left = ''; 2388 pageMenu.style.height = '100%'; 2389 pageMenu.style.lineHeight = ''; 2390 pageMenu.style.borderStyle = 'none'; 2391 pageMenu.style.padding = '3px 0'; 2392 pageMenu.style.margin = '0px'; 2393 pageMenu.style.background = ''; 2394 pageMenu.style.border = ''; 2395 pageMenu.style.boxShadow = 'none'; 2396 pageMenu.style.verticalAlign = 'top'; 2397 pageMenu.firstChild.style.height = '100%'; 2398 pageMenu.firstChild.style.opacity = '0.6'; 2399 pageMenu.firstChild.style.margin = '0px'; 2400 footer.appendChild(pageMenu); 2401 2402 function pagesVisibleChanged() 2403 { 2404 pageMenu.style.display = ui.pages != null && 2405 (urlParams['pages'] == '1' || ui.pages.length > 1 || 2406 Editor.pagesVisible) ? 'inline-block' : 'none'; 2407 }; 2408 2409 // Page menu only visible for multiple pages 2410 ui.addListener('fileDescriptorChanged', pagesVisibleChanged); 2411 ui.addListener('pagesVisibleChanged', pagesVisibleChanged); 2412 pagesVisibleChanged(); 2413 2414 ui.tabContainer.style.visibility = 'hidden'; 2415 menubar.style.cssText = 'position:absolute;right:12px;top:10px;height:30px;z-index:1;border-radius:4px;' + 2416 'box-shadow:0px 0px 3px 1px #d1d1d1;padding:6px 0px 6px 6px;border-bottom:1px solid lightgray;' + 2417 'text-align:right;white-space:nowrap;overflow:hidden;user-select:none;'; 2418 toolbar.style.cssText = 'position:absolute;left:10px;top:10px;height:30px;z-index:1;border-radius:4px;' + 2419 'box-shadow:0px 0px 3px 1px #d1d1d1;padding:6px;border-bottom:1px solid lightgray;' + 2420 'text-align:right;white-space:nowrap;overflow:hidden;user-select:none;'; 2421 footer.style.cssText = 'position:absolute;right:12px;bottom:12px;height:28px;z-index:1;border-radius:4px;' + 2422 'box-shadow:0px 0px 3px 1px #d1d1d1;padding:8px;white-space:nowrap;user-select:none;'; 2423 wrapper.appendChild(toolbar); 2424 wrapper.appendChild(footer); 2425 2426 picker.style.cssText = 'position:absolute;left:10px;z-index:1;border-radius:4px;' + 2427 'box-shadow:0px 0px 3px 1px #d1d1d1;padding:8px 6px 4px 6px;white-space:nowrap;' + 2428 'transform:translate(0, -50%);top:50%;user-select:none;'; 2429 wrapper.appendChild(picker); 2430 2431 window.setTimeout(function() 2432 { 2433 mxUtils.setPrefixedStyle(picker.style, 'transition', 'transform .3s ease-out'); 2434 }, 0); 2435 2436 if (urlParams['format-toolbar'] == '1') 2437 { 2438 this.installFormatToolbar(wrapper); 2439 } 2440 } 2441 else 2442 { 2443 var fitElt = addMenuItem('', fitFunction, true, mxResources.get('fit') + ' (' + Editor.ctrlKey + '+H)', resetViewAction, Editor.zoomFitImage); 2444 2445 menubar.style.cssText = 'position:absolute;left:0px;right:0px;top:0px;height:30px;padding:8px;' + 2446 'text-align:left;white-space:nowrap;'; 2447 this.tabContainer.style.right = '70px'; 2448 var elt = menuObj.addMenu('100%', viewZoomMenu.funct); 2449 elt.setAttribute('title', mxResources.get('zoom') + ' (Alt+Mousewheel)'); 2450 elt.style.whiteSpace = 'nowrap'; 2451 elt.style.paddingRight = '10px'; 2452 elt.style.textDecoration = 'none'; 2453 elt.style.textDecoration = 'none'; 2454 elt.style.overflow = 'hidden'; 2455 elt.style.visibility = 'hidden'; 2456 elt.style.textAlign = 'center'; 2457 elt.style.cursor = 'pointer'; 2458 elt.style.height = (parseInt(ui.tabContainerHeight) - 1) + 'px'; 2459 elt.style.lineHeight = (parseInt(ui.tabContainerHeight) + 1) + 'px'; 2460 elt.style.position = 'absolute'; 2461 elt.style.display = 'block'; 2462 elt.style.fontSize = '12px'; 2463 elt.style.width = '59px'; 2464 elt.style.right = '0px'; 2465 elt.style.bottom = '0px'; 2466 elt.style.backgroundImage = 'url(' + mxWindow.prototype.minimizeImage + ')'; 2467 elt.style.backgroundPosition = 'right 6px center'; 2468 elt.style.backgroundRepeat = 'no-repeat'; 2469 wrapper.appendChild(elt); 2470 } 2471 2472 // Updates the label if the scale changes 2473 (function(elt) 2474 { 2475 var updateZoom = mxUtils.bind(this, function() 2476 { 2477 elt.innerHTML = Math.round(ui.editor.graph.view.scale * 100) + '%'; 2478 }); 2479 2480 ui.editor.graph.view.addListener(mxEvent.EVENT_SCALE, updateZoom); 2481 ui.editor.addListener('resetGraphView', updateZoom); 2482 ui.editor.addListener('pageSelected', updateZoom); 2483 })(elt); 2484 2485 // Augments setGraphEnabled to update visible state 2486 var uiSetGraphEnabled = ui.setGraphEnabled; 2487 2488 ui.setGraphEnabled = function() 2489 { 2490 uiSetGraphEnabled.apply(this, arguments); 2491 2492 if (this.tabContainer != null) 2493 { 2494 elt.style.visibility = this.tabContainer.style.visibility; 2495 this.diagramContainer.style.bottom = (this.tabContainer.style.visibility != 'hidden' && 2496 footer == null) ? this.tabContainerHeight + 'px' : '0px'; 2497 } 2498 }; 2499 } 2500 2501 wrapper.appendChild(menubar); 2502 wrapper.appendChild(ui.diagramContainer); 2503 previousParent.appendChild(wrapper); 2504 ui.updateTabContainer(); 2505 2506 if (footer == null) 2507 { 2508 wrapper.appendChild(ui.tabContainer); 2509 } 2510 2511 var langMenuElt = null; 2512 2513 function refreshMenu() 2514 { 2515 if (urlParams['sketch'] == '1') 2516 { 2517 if (urlParams['embedInline'] != '1') 2518 { 2519 toolbar.style.left = (picker.offsetTop - picker.offsetHeight / 2 < 58) ? '70px' : '10px'; 2520 } 2521 } 2522 else 2523 { 2524 // Removes all existing menu items 2525 var node = menubar.firstChild; 2526 2527 while (node != null) 2528 { 2529 var temp = node.nextSibling; 2530 2531 if (node.className == 'geMenuItem' || node.className == 'geItem') 2532 { 2533 node.parentNode.removeChild(node); 2534 } 2535 2536 node = temp; 2537 } 2538 2539 before = menubar.firstChild; 2540 iw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; 2541 var small = iw < 1000 || urlParams['sketch'] == '1'; 2542 var appElt = null; 2543 2544 if (!small) 2545 { 2546 appElt = addMenu('diagram'); 2547 } 2548 2549 var temp = (small) ? addMenu('diagram', null, Editor.drawLogoImage) : null; 2550 2551 if (temp != null) 2552 { 2553 appElt = temp; 2554 } 2555 2556 createGroup([appElt, addMenuItem(mxResources.get('shapes'), ui.actions.get('toggleShapes').funct, null, 2557 mxResources.get('shapes'), ui.actions.get('image'), (small) ? Editor.shapesImage : null), 2558 addMenuItem(mxResources.get('format'), ui.actions.get('toggleFormat').funct, null, 2559 mxResources.get('format') + ' (' + ui.actions.get('formatPanel').shortcut + ')', ui.actions.get('image'), 2560 (small) ? Editor.formatImage : null)], 2561 (small) ? 60 : null); 2562 2563 var elt = addMenu('insert', true, (small) ? insertImage : null); 2564 createGroup([elt, addMenuItem(mxResources.get('delete'), ui.actions.get('delete').funct, 2565 null, mxResources.get('delete'), ui.actions.get('delete'), 2566 (small) ? Editor.trashImage : null)], (small) ? 60 : null); 2567 2568 if (iw >= 411) 2569 { 2570 createGroup([undoElt, redoElt], 60); 2571 2572 if (iw >= 520) 2573 { 2574 createGroup([fitElt, 2575 (iw >= 640) ? addMenuItem('', zoomInAction.funct, true, mxResources.get('zoomIn') + ' (' + Editor.ctrlKey + ' +)', 2576 zoomInAction, Editor.zoomInImage) : null, 2577 (iw >= 640) ? addMenuItem('', zoomOutAction.funct, true, mxResources.get('zoomOut') + ' (' + Editor.ctrlKey + ' -)', 2578 zoomOutAction, Editor.zoomOutImage) : null], 60); 2579 } 2580 } 2581 } 2582 2583 if (appElt != null) 2584 { 2585 mxEvent.disableContextMenu(appElt); 2586 2587 mxEvent.addGestureListeners(appElt, mxUtils.bind(this, function(evt) 2588 { 2589 if (mxEvent.isShiftDown(evt) || mxEvent.isAltDown(evt) || 2590 mxEvent.isMetaDown(evt) || mxEvent.isControlDown(evt) || 2591 mxEvent.isPopupTrigger(evt)) 2592 { 2593 ui.appIconClicked(evt); 2594 } 2595 }), null, null); 2596 } 2597 2598 var langMenu = ui.menus.get('language'); 2599 2600 if (langMenu != null && !mxClient.IS_CHROMEAPP && 2601 !EditorUi.isElectronApp && iw >= 600 && 2602 urlParams['sketch'] != '1') 2603 { 2604 if (langMenuElt == null) 2605 { 2606 var elt = menuObj.addMenu('', langMenu.funct); 2607 elt.setAttribute('title', mxResources.get('language')); 2608 elt.className = 'geToolbarButton'; 2609 elt.style.backgroundImage = 'url(' + Editor.globeImage + ')'; 2610 elt.style.backgroundPosition = 'center center'; 2611 elt.style.backgroundRepeat = 'no-repeat'; 2612 elt.style.backgroundSize = '24px 24px'; 2613 elt.style.position = 'absolute'; 2614 elt.style.height = '24px'; 2615 elt.style.width = '24px'; 2616 elt.style.zIndex = '1'; 2617 elt.style.right = '8px'; 2618 elt.style.cursor = 'pointer'; 2619 elt.style.top = (urlParams['embed'] == '1') ? '12px' : '11px'; 2620 menubar.appendChild(elt); 2621 langMenuElt = elt; 2622 } 2623 2624 ui.buttonContainer.style.paddingRight = '34px'; 2625 } 2626 else 2627 { 2628 ui.buttonContainer.style.paddingRight = '4px'; 2629 2630 if (langMenuElt != null) 2631 { 2632 langMenuElt.parentNode.removeChild(langMenuElt); 2633 langMenuElt = null; 2634 } 2635 } 2636 }; 2637 2638 refreshMenu(); 2639 2640 mxEvent.addListener(window, 'resize', function() 2641 { 2642 refreshMenu(); 2643 2644 if (ui.sidebarWindow != null) 2645 { 2646 ui.sidebarWindow.window.fit(); 2647 } 2648 2649 if (ui.formatWindow != null) 2650 { 2651 ui.formatWindow.window.fit(); 2652 } 2653 2654 if (ui.actions.outlineWindow != null) 2655 { 2656 ui.actions.outlineWindow.window.fit(); 2657 } 2658 2659 if (ui.actions.layersWindow != null) 2660 { 2661 ui.actions.layersWindow.window.fit(); 2662 } 2663 2664 if (ui.menus.tagsWindow != null) 2665 { 2666 ui.menus.tagsWindow.window.fit(); 2667 } 2668 2669 if (ui.menus.findWindow != null) 2670 { 2671 ui.menus.findWindow.window.fit(); 2672 } 2673 2674 if (ui.menus.findReplaceWindow != null) 2675 { 2676 ui.menus.findReplaceWindow.window.fit(); 2677 } 2678 }); 2679 2680 if (urlParams['embedInline'] == '1') 2681 { 2682 document.body.style.cursor = 'text'; 2683 picker.style.transform = ''; 2684 2685 mxEvent.addGestureListeners(ui.diagramContainer.parentNode, function(evt) 2686 { 2687 if (mxEvent.getSource(evt) == 2688 ui.diagramContainer.parentNode) 2689 { 2690 ui.embedExitPoint = new mxPoint(mxEvent.getClientX(evt), mxEvent.getClientY(evt)); 2691 ui.sendEmbeddedSvgExport(); 2692 } 2693 }); 2694 2695 var div = document.createElement('div'); 2696 div.style.position = 'absolute'; 2697 div.style.width = '10px'; 2698 div.style.height = '10px'; 2699 div.style.borderRadius = '5px'; 2700 div.style.border = '1px solid gray'; 2701 div.style.background = '#ffffff'; 2702 div.style.cursor = 'row-resize'; 2703 ui.diagramContainer.parentNode.appendChild(div); 2704 ui.bottomResizer = div; 2705 2706 var x0 = null; 2707 var y0 = null; 2708 var w0 = null; 2709 var h0 = null; 2710 2711 mxEvent.addGestureListeners(div, function(evt) 2712 { 2713 h0 = parseInt(ui.diagramContainer.style.height); 2714 y0 = mxEvent.getClientY(evt); 2715 graph.popupMenuHandler.hideMenu(); 2716 mxEvent.consume(evt); 2717 }); 2718 2719 div = div.cloneNode(false); 2720 div.style.cursor = 'col-resize'; 2721 ui.diagramContainer.parentNode.appendChild(div); 2722 ui.rightResizer = div; 2723 2724 mxEvent.addGestureListeners(div, function(evt) 2725 { 2726 w0 = parseInt(ui.diagramContainer.style.width); 2727 x0 = mxEvent.getClientX(evt); 2728 graph.popupMenuHandler.hideMenu(); 2729 mxEvent.consume(evt); 2730 }); 2731 2732 mxEvent.addGestureListeners(document.body, null, function(evt) 2733 { 2734 var changed = false; 2735 2736 if (x0 != null) 2737 { 2738 ui.diagramContainer.style.width = Math.max(20, 2739 w0 + mxEvent.getClientX(evt) - x0) + 'px'; 2740 changed = true; 2741 } 2742 2743 if (y0 != null) 2744 { 2745 ui.diagramContainer.style.height = Math.max(20, 2746 h0 + mxEvent.getClientY(evt) - y0) + 'px'; 2747 changed = true; 2748 } 2749 2750 if (changed) 2751 { 2752 var parent = window.opener || window.parent; 2753 parent.postMessage(JSON.stringify({ 2754 event: 'resize', 2755 fullscreen: Editor.inlineFullscreen, 2756 rect: ui.diagramContainer.getBoundingClientRect() 2757 }), '*'); 2758 inlineSizeChanged(); 2759 ui.refresh(); 2760 } 2761 }, function(evt) 2762 { 2763 if (x0 != null || y0 != null) 2764 { 2765 mxEvent.consume(evt); 2766 } 2767 2768 x0 = null; 2769 y0 = null; 2770 }); 2771 2772 this.diagramContainer.style.borderRadius = '4px'; 2773 document.body.style.backgroundColor = 'transparent'; 2774 ui.bottomResizer.style.visibility = 'hidden'; 2775 ui.rightResizer.style.visibility = 'hidden'; 2776 toolbar.style.visibility = 'hidden'; 2777 footer.style.visibility = 'hidden'; 2778 picker.style.display = 'none'; 2779 } 2780 2781 if (urlParams['prefetchFonts'] == '1') 2782 { 2783 ui.editor.loadFonts(); 2784 } 2785 }; 2786}; 2787 2788(function() 2789{ 2790 var initialized = false; 2791 2792 // ChromeApp has async local storage 2793 if (uiTheme == 'min' && !initialized && !mxClient.IS_CHROMEAPP) 2794 { 2795 EditorUi.initMinimalTheme(); 2796 initialized = true; 2797 } 2798 2799 var uiInitTheme = EditorUi.initTheme; 2800 2801 // For async startup like chromeos 2802 EditorUi.initTheme = function() 2803 { 2804 uiInitTheme.apply(this, arguments); 2805 2806 if (uiTheme == 'min' && !initialized) 2807 { 2808 this.initMinimalTheme(); 2809 initialized = true; 2810 } 2811 }; 2812})(); 2813