1/** 2 * Copyright (c) 2006-2012, JGraph Ltd 3 */ 4Format = function(editorUi, container) 5{ 6 this.editorUi = editorUi; 7 this.container = container; 8}; 9 10/** 11 * Background color for inactive tabs. 12 */ 13Format.inactiveTabBackgroundColor = '#f1f3f4'; 14 15/** 16 * Icons for markers (24x16). 17 */ 18Format.classicFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 10 2 L 5 8 L 10 14 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20); 19Format.classicThinFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 4 L 3 8 L 8 12 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20); 20Format.openFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 8 0 L 0 8 L 8 16 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 21Format.openThinFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 8 4 L 0 8 L 8 12 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 22Format.openAsyncFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 8 4 L 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 23Format.blockFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 2 L 8 14 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20); 24Format.blockThinFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 4 L 8 12 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20); 25Format.asyncFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 6 8 L 6 4 L 0 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20); 26Format.ovalFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 A 5 5 0 0 1 5 3 A 5 5 0 0 1 11 8 A 5 5 0 0 1 5 13 A 5 5 0 0 1 0 8 Z M 10 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20); 27Format.diamondFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 6 2 L 12 8 L 6 14 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20); 28Format.diamondThinFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 3 L 16 8 L 8 13 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20); 29Format.classicMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 10 2 L 5 8 L 10 14 Z M 5 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 30Format.classicThinMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 4 L 5 8 L 8 12 Z M 5 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 31Format.blockMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 2 L 8 14 Z M 8 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 32Format.blockThinMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 4 L 8 12 Z M 8 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 33Format.asyncMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 6 8 L 6 4 L 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 34Format.ovalMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 A 5 5 0 0 1 5 3 A 5 5 0 0 1 11 8 A 5 5 0 0 1 5 13 A 5 5 0 0 1 0 8 Z M 10 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 35Format.diamondMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 6 2 L 12 8 L 6 14 Z M 12 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 36Format.diamondThinMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 3 L 16 8 L 8 13 Z M 16 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 37Format.boxMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 3 L 10 3 L 10 13 L 0 13 Z M 10 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 38Format.halfCircleMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 3 A 5 5 0 0 1 5 8 A 5 5 0 0 1 0 13 M 5 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 39Format.dashMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 12 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 40Format.crossMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 12 14 M 12 2 L 0 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 41Format.circlePlusMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 A 6 6 0 0 1 6 2 A 6 6 0 0 1 12 8 A 6 6 0 0 1 6 14 A 6 6 0 0 1 0 8 Z M 6 2 L 6 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 42Format.circleMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 A 6 6 0 0 1 6 2 A 6 6 0 0 1 12 8 A 6 6 0 0 1 6 14 A 6 6 0 0 1 0 8 Z M 12 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 43Format.ERmandOneMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 6 2 L 6 14 M 9 2 L 9 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 44Format.ERmanyMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 12 8 L 0 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 45Format.ERoneToManyMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 12 8 L 0 14 M 15 2 L 15 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 46Format.ERzeroToOneMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 8 8 A 5 5 0 0 1 13 3 A 5 5 0 0 1 18 8 A 5 5 0 0 1 13 13 A 5 5 0 0 1 8 8 Z M 0 8 L 8 8 M 18 8 L 24 8 M 4 3 L 4 13" stroke="#404040" fill="transparent"/>', 32, 20); 47Format.ERzeroToManyMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 8 8 A 5 5 0 0 1 13 3 A 5 5 0 0 1 18 8 A 5 5 0 0 1 13 13 A 5 5 0 0 1 8 8 Z M 0 8 L 8 8 M 18 8 L 24 8 M 0 3 L 8 8 L 0 13" stroke="#404040" fill="transparent"/>', 32, 20); 48Format.EROneMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 5 2 L 5 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 49Format.baseDashMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 0 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 50Format.doubleBlockMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 2 L 8 14 Z M 8 8 L 16 2 L 16 14 Z M 16 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20); 51Format.doubleBlockFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 2 L 8 14 Z M 8 8 L 16 2 L 16 14 Z M 16 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20); 52 53/** 54 * Adds a style change item to the given menu. 55 */ 56Format.processMenuIcon = function(elt, transform) 57{ 58 var imgs = elt.getElementsByTagName('img'); 59 60 if (imgs.length > 0) 61 { 62 if (Editor.isDarkMode()) 63 { 64 imgs[0].style.filter = 'invert(100%)'; 65 } 66 67 imgs[0].className = 'geIcon'; 68 imgs[0].style.padding = '0px'; 69 imgs[0].style.margin = '0 0 0 2px'; 70 71 if (transform != null) 72 { 73 mxUtils.setPrefixedStyle(imgs[0].style, 'transform', transform); 74 } 75 } 76 77 return elt; 78}; 79 80/** 81 * Returns information about the current selection. 82 */ 83Format.prototype.labelIndex = 0; 84 85/** 86 * Returns information about the current selection. 87 */ 88Format.prototype.diagramIndex = 0; 89 90/** 91 * Returns information about the current selection. 92 */ 93Format.prototype.currentIndex = 0; 94 95/** 96 * Returns information about the current selection. 97 */ 98Format.prototype.showCloseButton = true; 99 100/** 101 * Background color for inactive tabs. 102 */ 103Format.prototype.roundableShapes = ['label', 'rectangle', 'internalStorage', 'corner', 104 'parallelogram', 'swimlane', 'triangle', 'trapezoid', 'ext', 'step', 'tee', 'process', 105 'link', 'rhombus', 'offPageConnector', 'loopLimit', 'hexagon', 'manualInput', 'card', 106 'curlyBracket', 'singleArrow', 'callout', 'doubleArrow', 'flexArrow', 'umlLifeline']; 107 108/** 109 * Adds the label menu items to the given menu and parent. 110 */ 111Format.prototype.init = function() 112{ 113 var ui = this.editorUi; 114 var editor = ui.editor; 115 var graph = editor.graph; 116 117 this.update = mxUtils.bind(this, function(sender, evt) 118 { 119 this.clearSelectionState(); 120 this.refresh(); 121 }); 122 123 graph.getSelectionModel().addListener(mxEvent.CHANGE, this.update); 124 graph.addListener(mxEvent.EDITING_STARTED, this.update); 125 graph.addListener(mxEvent.EDITING_STOPPED, this.update); 126 graph.getModel().addListener(mxEvent.CHANGE, this.update); 127 graph.getView().addListener('unitChanged', this.update); 128 129 graph.addListener(mxEvent.ROOT, mxUtils.bind(this, function() 130 { 131 this.refresh(); 132 })); 133 134 ui.addListener('styleChanged', mxUtils.bind(this, function(sender, evt) 135 { 136 this.refresh(); 137 })); 138 139 editor.addListener('autosaveChanged', mxUtils.bind(this, function() 140 { 141 this.refresh(); 142 })); 143 144 this.refresh(); 145}; 146 147/** 148 * Returns information about the current selection. 149 */ 150Format.prototype.clearSelectionState = function() 151{ 152 this.selectionState = null; 153}; 154 155/** 156 * Returns information about the current selection. 157 */ 158Format.prototype.getSelectionState = function() 159{ 160 if (this.selectionState == null) 161 { 162 this.selectionState = this.createSelectionState(); 163 } 164 165 return this.selectionState; 166}; 167 168/** 169 * Returns information about the current selection. 170 */ 171Format.prototype.createSelectionState = function() 172{ 173 var cells = this.editorUi.editor.graph.getSelectionCells(); 174 var result = this.initSelectionState(); 175 var initial = true; 176 177 for (var i = 0; i < cells.length; i++) 178 { 179 var style = this.editorUi.editor.graph.getCurrentCellStyle(cells[i]); 180 181 if (mxUtils.getValue(style, mxConstants.STYLE_EDITABLE, '1') != '0') 182 { 183 this.updateSelectionStateForCell(result, cells[i], cells, initial); 184 initial = false; 185 } 186 } 187 188 return result; 189}; 190 191/** 192 * Returns information about the current selection. 193 */ 194Format.prototype.initSelectionState = function() 195{ 196 return {vertices: [], edges: [], cells: [], x: null, y: null, width: null, height: null, 197 style: {}, containsImage: false, containsLabel: false, fill: true, glass: true, 198 rounded: true, autoSize: false, image: true, shadow: true, lineJumps: true, resizable: true, 199 table: false, cell: false, row: false, movable: true, rotatable: true, stroke: true}; 200}; 201 202/** 203 * Returns information about the current selection. 204 */ 205Format.prototype.updateSelectionStateForCell = function(result, cell, cells, initial) 206{ 207 var graph = this.editorUi.editor.graph; 208 result.cells.push(cell); 209 210 if (graph.getModel().isVertex(cell)) 211 { 212 result.resizable = result.resizable && graph.isCellResizable(cell); 213 result.rotatable = result.rotatable && graph.isCellRotatable(cell); 214 result.movable = result.movable && graph.isCellMovable(cell) && 215 !graph.isTableRow(cell) && !graph.isTableCell(cell); 216 result.table = result.table || graph.isTable(cell); 217 result.cell = result.cell || graph.isTableCell(cell); 218 result.row = result.row || graph.isTableRow(cell); 219 result.vertices.push(cell); 220 var geo = graph.getCellGeometry(cell); 221 222 if (geo != null) 223 { 224 if (geo.width > 0) 225 { 226 if (result.width == null) 227 { 228 result.width = geo.width; 229 } 230 else if (result.width != geo.width) 231 { 232 result.width = ''; 233 } 234 } 235 else 236 { 237 result.containsLabel = true; 238 } 239 240 if (geo.height > 0) 241 { 242 if (result.height == null) 243 { 244 result.height = geo.height; 245 } 246 else if (result.height != geo.height) 247 { 248 result.height = ''; 249 } 250 } 251 else 252 { 253 result.containsLabel = true; 254 } 255 256 if (!geo.relative || geo.offset != null) 257 { 258 var x = (geo.relative) ? geo.offset.x : geo.x; 259 var y = (geo.relative) ? geo.offset.y : geo.y; 260 261 if (result.x == null) 262 { 263 result.x = x; 264 } 265 else if (result.x != x) 266 { 267 result.x = ''; 268 } 269 270 if (result.y == null) 271 { 272 result.y = y; 273 } 274 else if (result.y != y) 275 { 276 result.y = ''; 277 } 278 } 279 } 280 } 281 else if (graph.getModel().isEdge(cell)) 282 { 283 result.edges.push(cell); 284 result.resizable = false; 285 result.rotatable = false; 286 result.movable = false; 287 } 288 289 var state = graph.view.getState(cell); 290 291 if (state != null) 292 { 293 result.autoSize = result.autoSize || this.isAutoSizeState(state); 294 result.glass = result.glass && this.isGlassState(state); 295 result.rounded = result.rounded && this.isRoundedState(state); 296 result.lineJumps = result.lineJumps && this.isLineJumpState(state); 297 result.image = result.image && this.isImageState(state); 298 result.shadow = result.shadow && this.isShadowState(state); 299 result.fill = result.fill && this.isFillState(state); 300 result.stroke = result.stroke && this.isStrokeState(state); 301 302 var shape = mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null); 303 result.containsImage = result.containsImage || shape == 'image'; 304 graph.mergeStyle(state.style, result.style, initial); 305 } 306}; 307 308/** 309 * Returns information about the current selection. 310 */ 311Format.prototype.isFillState = function(state) 312{ 313 return !this.isSpecialColor(state.style[mxConstants.STYLE_FILLCOLOR]) && 314 (state.view.graph.model.isVertex(state.cell) || 315 mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null) == 'arrow' || 316 mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null) == 'filledEdge' || 317 mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null) == 'flexArrow'); 318}; 319 320/** 321 * Returns information about the current selection. 322 */ 323Format.prototype.isStrokeState = function(state) 324{ 325 return !this.isSpecialColor(state.style[mxConstants.STYLE_STROKECOLOR]); 326}; 327 328/** 329 * Returns information about the current selection. 330 */ 331Format.prototype.isSpecialColor = function(color) 332{ 333 return mxUtils.indexOf([mxConstants.STYLE_STROKECOLOR, 334 mxConstants.STYLE_FILLCOLOR, 'inherit', 'swimlane', 335 'indicated'], color) >= 0; 336}; 337 338/** 339 * Returns information about the current selection. 340 */ 341Format.prototype.isGlassState = function(state) 342{ 343 var shape = mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null); 344 345 return (shape == 'label' || shape == 'rectangle' || shape == 'internalStorage' || 346 shape == 'ext' || shape == 'umlLifeline' || shape == 'swimlane' || 347 shape == 'process'); 348}; 349 350/** 351 * Returns information about the current selection. 352 */ 353Format.prototype.isRoundedState = function(state) 354{ 355 return (state.shape != null) ? state.shape.isRoundable() : 356 mxUtils.indexOf(this.roundableShapes, mxUtils.getValue(state.style, 357 mxConstants.STYLE_SHAPE, null)) >= 0; 358}; 359 360/** 361 * Returns information about the current selection. 362 */ 363Format.prototype.isLineJumpState = function(state) 364{ 365 var shape = mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null); 366 var curved = mxUtils.getValue(state.style, mxConstants.STYLE_CURVED, false); 367 368 return !curved && (shape == 'connector' || shape == 'filledEdge'); 369}; 370 371/** 372 * Returns information about the current selection. 373 */ 374Format.prototype.isAutoSizeState = function(state) 375{ 376 return mxUtils.getValue(state.style, mxConstants.STYLE_AUTOSIZE, null) == '1'; 377}; 378 379/** 380 * Returns information about the current selection. 381 */ 382Format.prototype.isImageState = function(state) 383{ 384 var shape = mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null); 385 386 return (shape == 'label' || shape == 'image'); 387}; 388 389/** 390 * Returns information about the current selection. 391 */ 392Format.prototype.isShadowState = function(state) 393{ 394 var shape = mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE, null); 395 396 return (shape != 'image'); 397}; 398 399/** 400 * Adds the label menu items to the given menu and parent. 401 */ 402Format.prototype.clear = function() 403{ 404 this.container.innerHTML = ''; 405 406 // Destroy existing panels 407 if (this.panels != null) 408 { 409 for (var i = 0; i < this.panels.length; i++) 410 { 411 this.panels[i].destroy(); 412 } 413 } 414 415 this.panels = []; 416}; 417 418/** 419 * Adds the label menu items to the given menu and parent. 420 */ 421Format.prototype.refresh = function() 422{ 423 if (this.pendingRefresh != null) 424 { 425 window.clearTimeout(this.pendingRefresh); 426 this.pendingRefresh = null; 427 } 428 429 this.pendingRefresh = window.setTimeout(mxUtils.bind(this, function() 430 { 431 this.immediateRefresh(); 432 })); 433}; 434 435/** 436 * Adds the label menu items to the given menu and parent. 437 */ 438Format.prototype.immediateRefresh = function() 439{ 440 // Performance tweak: No refresh needed if not visible 441 if (this.container.style.width == '0px') 442 { 443 return; 444 } 445 446 this.clear(); 447 var ui = this.editorUi; 448 var graph = ui.editor.graph; 449 450 var div = document.createElement('div'); 451 div.style.whiteSpace = 'nowrap'; 452 div.style.color = 'rgb(112, 112, 112)'; 453 div.style.textAlign = 'left'; 454 div.style.cursor = 'default'; 455 456 var label = document.createElement('div'); 457 label.className = 'geFormatSection'; 458 label.style.textAlign = 'center'; 459 label.style.fontWeight = 'bold'; 460 label.style.paddingTop = '8px'; 461 label.style.fontSize = '13px'; 462 label.style.borderWidth = '0px 0px 1px 1px'; 463 label.style.borderStyle = 'solid'; 464 label.style.display = 'inline-block'; 465 label.style.height = '25px'; 466 label.style.overflow = 'hidden'; 467 label.style.width = '100%'; 468 this.container.appendChild(div); 469 470 // Prevents text selection 471 mxEvent.addListener(label, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown', 472 mxUtils.bind(this, function(evt) 473 { 474 evt.preventDefault(); 475 })); 476 477 var ss = this.getSelectionState(); 478 var containsLabel = ss.containsLabel; 479 var currentLabel = null; 480 var currentPanel = null; 481 482 var addClickHandler = mxUtils.bind(this, function(elt, panel, index, lastEntry) 483 { 484 var clickHandler = mxUtils.bind(this, function(evt) 485 { 486 if (currentLabel != elt) 487 { 488 if (containsLabel) 489 { 490 this.labelIndex = index; 491 } 492 else if (graph.isSelectionEmpty()) 493 { 494 this.diagramIndex = index; 495 } 496 else 497 { 498 this.currentIndex = index; 499 } 500 501 if (currentLabel != null) 502 { 503 currentLabel.style.backgroundColor = Format.inactiveTabBackgroundColor; 504 currentLabel.style.borderBottomWidth = '1px'; 505 } 506 507 currentLabel = elt; 508 currentLabel.style.backgroundColor = ''; 509 currentLabel.style.borderBottomWidth = '0px'; 510 511 if (currentPanel != panel) 512 { 513 if (currentPanel != null) 514 { 515 currentPanel.style.display = 'none'; 516 } 517 518 currentPanel = panel; 519 currentPanel.style.display = ''; 520 } 521 } 522 }); 523 524 mxEvent.addListener(elt, 'click', clickHandler); 525 526 // Prevents text selection 527 mxEvent.addListener(elt, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown', 528 mxUtils.bind(this, function(evt) 529 { 530 evt.preventDefault(); 531 })); 532 533 if ((lastEntry && currentLabel == null) || 534 (index == ((containsLabel) ? this.labelIndex : ((graph.isSelectionEmpty()) ? 535 this.diagramIndex : this.currentIndex)))) 536 { 537 // Invokes handler directly as a workaround for no click on DIV in KHTML. 538 clickHandler(); 539 } 540 }); 541 542 var idx = 0; 543 544 if (graph.isSelectionEmpty()) 545 { 546 mxUtils.write(label, mxResources.get('diagram')); 547 label.style.borderLeftWidth = '0px'; 548 549 div.appendChild(label); 550 var diagramPanel = div.cloneNode(false); 551 this.panels.push(new DiagramFormatPanel(this, ui, diagramPanel)); 552 this.container.appendChild(diagramPanel); 553 554 if (Editor.styles != null) 555 { 556 diagramPanel.style.display = 'none'; 557 label.style.width = (this.showCloseButton) ? '106px' : '50%'; 558 label.style.cursor = 'pointer'; 559 label.style.backgroundColor = Format.inactiveTabBackgroundColor; 560 561 var label2 = label.cloneNode(false); 562 label2.style.borderLeftWidth = '1px'; 563 label2.style.borderRightWidth = '1px'; 564 label2.style.backgroundColor = Format.inactiveTabBackgroundColor; 565 566 addClickHandler(label, diagramPanel, idx++); 567 568 var stylePanel = div.cloneNode(false); 569 stylePanel.style.display = 'none'; 570 mxUtils.write(label2, mxResources.get('style')); 571 div.appendChild(label2); 572 this.panels.push(new DiagramStylePanel(this, ui, stylePanel)); 573 this.container.appendChild(stylePanel); 574 575 addClickHandler(label2, stylePanel, idx++); 576 } 577 578 // Adds button to hide the format panel since 579 // people don't seem to find the toolbar button 580 // and the menu item in the format menu 581 if (this.showCloseButton) 582 { 583 var label2 = label.cloneNode(false); 584 label2.style.borderLeftWidth = '1px'; 585 label2.style.borderRightWidth = '1px'; 586 label2.style.borderBottomWidth = '1px'; 587 label2.style.backgroundColor = Format.inactiveTabBackgroundColor; 588 label2.style.position = 'absolute'; 589 label2.style.right = '0px'; 590 label2.style.top = '0px'; 591 label2.style.width = '25px'; 592 593 var img = document.createElement('img'); 594 img.setAttribute('border', '0'); 595 img.setAttribute('src', Dialog.prototype.closeImage); 596 img.setAttribute('title', mxResources.get('hide')); 597 img.style.position = 'absolute'; 598 img.style.display = 'block'; 599 img.style.right = '0px'; 600 img.style.top = '8px'; 601 img.style.cursor = 'pointer'; 602 img.style.marginTop = '1px'; 603 img.style.marginRight = '6px'; 604 img.style.border = '1px solid transparent'; 605 img.style.padding = '1px'; 606 img.style.opacity = 0.5; 607 label2.appendChild(img) 608 609 mxEvent.addListener(img, 'click', function() 610 { 611 ui.actions.get('formatPanel').funct(); 612 }); 613 614 div.appendChild(label2); 615 } 616 } 617 else if (graph.isEditing()) 618 { 619 mxUtils.write(label, mxResources.get('text')); 620 div.appendChild(label); 621 this.panels.push(new TextFormatPanel(this, ui, div)); 622 } 623 else 624 { 625 label.style.backgroundColor = Format.inactiveTabBackgroundColor; 626 label.style.borderLeftWidth = '1px'; 627 label.style.cursor = 'pointer'; 628 label.style.width = (containsLabel || ss.cells.length == 0) ? '50%' : '33.3%'; 629 var label2 = label.cloneNode(false); 630 var label3 = label2.cloneNode(false); 631 632 // Workaround for ignored background in IE 633 label2.style.backgroundColor = Format.inactiveTabBackgroundColor; 634 label3.style.backgroundColor = Format.inactiveTabBackgroundColor; 635 636 // Style 637 if (containsLabel) 638 { 639 label2.style.borderLeftWidth = '0px'; 640 } 641 else 642 { 643 label.style.borderLeftWidth = '0px'; 644 mxUtils.write(label, mxResources.get('style')); 645 div.appendChild(label); 646 647 var stylePanel = div.cloneNode(false); 648 stylePanel.style.display = 'none'; 649 this.panels.push(new StyleFormatPanel(this, ui, stylePanel)); 650 this.container.appendChild(stylePanel); 651 652 addClickHandler(label, stylePanel, idx++); 653 } 654 655 // Text 656 mxUtils.write(label2, mxResources.get('text')); 657 div.appendChild(label2); 658 659 var textPanel = div.cloneNode(false); 660 textPanel.style.display = 'none'; 661 this.panels.push(new TextFormatPanel(this, ui, textPanel)); 662 this.container.appendChild(textPanel); 663 664 // Arrange 665 mxUtils.write(label3, mxResources.get('arrange')); 666 div.appendChild(label3); 667 668 var arrangePanel = div.cloneNode(false); 669 arrangePanel.style.display = 'none'; 670 this.panels.push(new ArrangePanel(this, ui, arrangePanel)); 671 this.container.appendChild(arrangePanel); 672 673 if (ss.cells.length > 0) 674 { 675 addClickHandler(label2, textPanel, idx++); 676 } 677 else 678 { 679 label2.style.display = 'none'; 680 } 681 682 addClickHandler(label3, arrangePanel, idx++, true); 683 } 684}; 685 686/** 687 * Base class for format panels. 688 */ 689BaseFormatPanel = function(format, editorUi, container) 690{ 691 this.format = format; 692 this.editorUi = editorUi; 693 this.container = container; 694 this.listeners = []; 695}; 696 697/** 698 * 699 */ 700BaseFormatPanel.prototype.buttonBackgroundColor = 'white'; 701 702/** 703 * Install input handler. 704 */ 705BaseFormatPanel.prototype.installInputHandler = function(input, key, defaultValue, min, max, unit, textEditFallback, isFloat) 706{ 707 unit = (unit != null) ? unit : ''; 708 isFloat = (isFloat != null) ? isFloat : false; 709 710 var ui = this.editorUi; 711 var graph = ui.editor.graph; 712 713 min = (min != null) ? min : 1; 714 max = (max != null) ? max : 999; 715 716 var selState = null; 717 var updating = false; 718 719 var update = mxUtils.bind(this, function(evt) 720 { 721 var value = (isFloat) ? parseFloat(input.value) : parseInt(input.value); 722 723 // Special case: angle mod 360 724 if (!isNaN(value) && key == mxConstants.STYLE_ROTATION) 725 { 726 // Workaround for decimal rounding errors in floats is to 727 // use integer and round all numbers to two decimal point 728 value = mxUtils.mod(Math.round(value * 100), 36000) / 100; 729 } 730 731 value = Math.min(max, Math.max(min, (isNaN(value)) ? defaultValue : value)); 732 733 if (graph.cellEditor.isContentEditing() && textEditFallback) 734 { 735 if (!updating) 736 { 737 updating = true; 738 739 if (selState != null) 740 { 741 graph.cellEditor.restoreSelection(selState); 742 selState = null; 743 } 744 745 textEditFallback(value); 746 input.value = value + unit; 747 748 // Restore focus and selection in input 749 updating = false; 750 } 751 } 752 else if (value != mxUtils.getValue(this.format.getSelectionState().style, key, defaultValue)) 753 { 754 if (graph.isEditing()) 755 { 756 graph.stopEditing(true); 757 } 758 759 graph.getModel().beginUpdate(); 760 try 761 { 762 var cells = this.format.getSelectionState().cells; 763 graph.setCellStyles(key, value, cells); 764 765 // Handles special case for fontSize where HTML labels are parsed and updated 766 if (key == mxConstants.STYLE_FONTSIZE) 767 { 768 graph.updateLabelElements(cells, function(elt) 769 { 770 elt.style.fontSize = value + 'px'; 771 elt.removeAttribute('size'); 772 }); 773 } 774 775 for (var i = 0; i < cells.length; i++) 776 { 777 if (graph.model.getChildCount(cells[i]) == 0) 778 { 779 graph.autoSizeCell(cells[i], false); 780 } 781 } 782 783 ui.fireEvent(new mxEventObject('styleChanged', 'keys', [key], 784 'values', [value], 'cells', cells)); 785 } 786 finally 787 { 788 graph.getModel().endUpdate(); 789 } 790 } 791 792 input.value = value + unit; 793 mxEvent.consume(evt); 794 }); 795 796 if (textEditFallback && graph.cellEditor.isContentEditing()) 797 { 798 // KNOWN: Arrow up/down clear selection text in quirks/IE 8 799 // Text size via arrow button limits to 16 in IE11. Why? 800 mxEvent.addListener(input, 'mousedown', function() 801 { 802 if (document.activeElement == graph.cellEditor.textarea) 803 { 804 selState = graph.cellEditor.saveSelection(); 805 } 806 }); 807 808 mxEvent.addListener(input, 'touchstart', function() 809 { 810 if (document.activeElement == graph.cellEditor.textarea) 811 { 812 selState = graph.cellEditor.saveSelection(); 813 } 814 }); 815 } 816 817 mxEvent.addListener(input, 'change', update); 818 mxEvent.addListener(input, 'blur', update); 819 820 return update; 821}; 822 823/** 824 * Adds the given option. 825 */ 826BaseFormatPanel.prototype.createPanel = function() 827{ 828 var div = document.createElement('div'); 829 div.className = 'geFormatSection'; 830 div.style.padding = '12px 0px 12px 14px'; 831 832 return div; 833}; 834 835/** 836 * Adds the given option. 837 */ 838BaseFormatPanel.prototype.createTitle = function(title) 839{ 840 var div = document.createElement('div'); 841 div.style.padding = '0px 0px 6px 0px'; 842 div.style.whiteSpace = 'nowrap'; 843 div.style.overflow = 'hidden'; 844 div.style.width = '200px'; 845 div.style.fontWeight = 'bold'; 846 mxUtils.write(div, title); 847 848 return div; 849}; 850 851/** 852 * 853 */ 854BaseFormatPanel.prototype.createStepper = function(input, update, step, height, disableFocus, defaultValue, isFloat) 855{ 856 step = (step != null) ? step : 1; 857 height = (height != null) ? height : 9; 858 var bigStep = 10 * step; 859 860 var stepper = document.createElement('div'); 861 mxUtils.setPrefixedStyle(stepper.style, 'borderRadius', '3px'); 862 stepper.style.border = '1px solid rgb(192, 192, 192)'; 863 stepper.style.position = 'absolute'; 864 865 var up = document.createElement('div'); 866 up.style.borderBottom = '1px solid rgb(192, 192, 192)'; 867 up.style.position = 'relative'; 868 up.style.height = height + 'px'; 869 up.style.width = '10px'; 870 up.className = 'geBtnUp'; 871 stepper.appendChild(up); 872 873 var down = up.cloneNode(false); 874 down.style.border = 'none'; 875 down.style.height = height + 'px'; 876 down.className = 'geBtnDown'; 877 stepper.appendChild(down); 878 879 mxEvent.addGestureListeners(down, function(evt) 880 { 881 // Stops text selection on shift+click 882 mxEvent.consume(evt); 883 }, null, function(evt) 884 { 885 if (input.value == '') 886 { 887 input.value = defaultValue || '2'; 888 } 889 890 var val = isFloat? parseFloat(input.value) : parseInt(input.value); 891 892 if (!isNaN(val)) 893 { 894 input.value = val - (mxEvent.isShiftDown(evt) ? bigStep : step); 895 896 if (update != null) 897 { 898 update(evt); 899 } 900 } 901 902 mxEvent.consume(evt); 903 }); 904 905 mxEvent.addGestureListeners(up, function(evt) 906 { 907 // Stops text selection on shift+click 908 mxEvent.consume(evt); 909 }, null, function(evt) 910 { 911 if (input.value == '') 912 { 913 input.value = defaultValue || '0'; 914 } 915 916 var val = isFloat? parseFloat(input.value) : parseInt(input.value); 917 918 if (!isNaN(val)) 919 { 920 input.value = val + (mxEvent.isShiftDown(evt) ? bigStep : step); 921 922 if (update != null) 923 { 924 update(evt); 925 } 926 } 927 928 mxEvent.consume(evt); 929 }); 930 931 // Disables transfer of focus to DIV but also :active CSS 932 // so it's only used for fontSize where the focus should 933 // stay on the selected text, but not for any other input. 934 if (disableFocus) 935 { 936 var currentSelection = null; 937 938 mxEvent.addGestureListeners(stepper, 939 function(evt) 940 { 941 mxEvent.consume(evt); 942 }, 943 null, 944 function(evt) 945 { 946 // Workaround for lost current selection in page because of focus in IE 947 if (currentSelection != null) 948 { 949 try 950 { 951 currentSelection.select(); 952 } 953 catch (e) 954 { 955 // ignore 956 } 957 958 currentSelection = null; 959 mxEvent.consume(evt); 960 } 961 } 962 ); 963 } 964 else 965 { 966 // Stops propagation on checkbox labels 967 mxEvent.addListener(stepper, 'click', function(evt) 968 { 969 mxEvent.consume(evt); 970 }); 971 } 972 973 return stepper; 974}; 975 976/** 977 * Adds the given option. 978 */ 979BaseFormatPanel.prototype.createOption = function(label, isCheckedFn, setCheckedFn, listener, fn) 980{ 981 var div = document.createElement('div'); 982 div.style.padding = '3px 0px 3px 0px'; 983 div.style.whiteSpace = 'nowrap'; 984 div.style.textOverflow = 'ellipsis'; 985 div.style.overflow = 'hidden'; 986 div.style.width = '200px'; 987 div.style.height = '18px'; 988 989 var cb = document.createElement('input'); 990 cb.setAttribute('type', 'checkbox'); 991 cb.style.margin = '1px 6px 0px 0px'; 992 cb.style.verticalAlign = 'top'; 993 div.appendChild(cb); 994 995 var span = document.createElement('span'); 996 span.style.verticalAlign = 'top'; 997 mxUtils.write(span, label); 998 div.appendChild(span); 999 1000 var applying = false; 1001 var value = isCheckedFn(); 1002 1003 var apply = function(newValue) 1004 { 1005 if (!applying) 1006 { 1007 applying = true; 1008 1009 if (newValue) 1010 { 1011 cb.setAttribute('checked', 'checked'); 1012 cb.defaultChecked = true; 1013 cb.checked = true; 1014 } 1015 else 1016 { 1017 cb.removeAttribute('checked'); 1018 cb.defaultChecked = false; 1019 cb.checked = false; 1020 } 1021 1022 if (value != newValue) 1023 { 1024 value = newValue; 1025 1026 // Checks if the color value needs to be updated in the model 1027 if (isCheckedFn() != value) 1028 { 1029 setCheckedFn(value); 1030 } 1031 } 1032 1033 applying = false; 1034 } 1035 }; 1036 1037 mxEvent.addListener(div, 'click', function(evt) 1038 { 1039 if (cb.getAttribute('disabled') != 'disabled') 1040 { 1041 // Toggles checkbox state for click on label 1042 var source = mxEvent.getSource(evt); 1043 1044 if (source == div || source == span) 1045 { 1046 cb.checked = !cb.checked; 1047 } 1048 1049 apply(cb.checked); 1050 } 1051 }); 1052 1053 apply(value); 1054 1055 if (listener != null) 1056 { 1057 listener.install(apply); 1058 this.listeners.push(listener); 1059 } 1060 1061 if (fn != null) 1062 { 1063 fn(div); 1064 } 1065 1066 return div; 1067}; 1068 1069/** 1070 * The string 'null' means use null in values. 1071 */ 1072BaseFormatPanel.prototype.createCellOption = function(label, key, defaultValue, enabledValue, disabledValue, fn, action, stopEditing, cells) 1073{ 1074 var ui = this.editorUi; 1075 var editor = ui.editor; 1076 var graph = editor.graph; 1077 var self = this; 1078 1079 enabledValue = (enabledValue != null) ? ((enabledValue == 'null') ? null : enabledValue) : 1; 1080 disabledValue = (disabledValue != null) ? ((disabledValue == 'null') ? null : disabledValue) : 0; 1081 1082 var style = (cells != null) ? graph.getCommonStyle(cells) : this.format.getSelectionState().style; 1083 1084 return this.createOption(label, function() 1085 { 1086 return mxUtils.getValue(style, key, defaultValue) != disabledValue; 1087 }, function(checked) 1088 { 1089 if (stopEditing) 1090 { 1091 graph.stopEditing(); 1092 } 1093 1094 if (action != null) 1095 { 1096 action.funct(); 1097 } 1098 else 1099 { 1100 graph.getModel().beginUpdate(); 1101 try 1102 { 1103 var temp = (cells != null) ? cells : self.format.getSelectionState().cells; 1104 var value = (checked) ? enabledValue : disabledValue; 1105 graph.setCellStyles(key, value, temp); 1106 1107 if (fn != null) 1108 { 1109 fn(temp, value); 1110 } 1111 1112 ui.fireEvent(new mxEventObject('styleChanged', 'keys', 1113 [key], 'values', [value], 'cells', temp)); 1114 } 1115 finally 1116 { 1117 graph.getModel().endUpdate(); 1118 } 1119 } 1120 }, 1121 { 1122 install: function(apply) 1123 { 1124 this.listener = function() 1125 { 1126 apply(mxUtils.getValue(style, key, defaultValue) != disabledValue); 1127 }; 1128 1129 graph.getModel().addListener(mxEvent.CHANGE, this.listener); 1130 }, 1131 destroy: function() 1132 { 1133 graph.getModel().removeListener(this.listener); 1134 } 1135 }); 1136}; 1137 1138/** 1139 * Adds the given color option. 1140 */ 1141BaseFormatPanel.prototype.createColorOption = function(label, getColorFn, setColorFn, 1142 defaultColor, listener, callbackFn, hideCheckbox, defaultColorValue) 1143{ 1144 var div = document.createElement('div'); 1145 div.style.padding = '3px 0px 3px 0px'; 1146 div.style.whiteSpace = 'nowrap'; 1147 div.style.overflow = 'hidden'; 1148 div.style.width = '200px'; 1149 div.style.height = '18px'; 1150 1151 var cb = document.createElement('input'); 1152 cb.setAttribute('type', 'checkbox'); 1153 cb.style.margin = '1px 6px 0px 0px'; 1154 cb.style.verticalAlign = 'top'; 1155 1156 if (!hideCheckbox) 1157 { 1158 div.appendChild(cb); 1159 } 1160 1161 var span = document.createElement('span'); 1162 span.style.verticalAlign = 'top'; 1163 mxUtils.write(span, label); 1164 div.appendChild(span); 1165 1166 var title = 'Shift+Click for Color Dropper'; 1167 var value = getColorFn(); 1168 var applying = false; 1169 var btn = null; 1170 1171 var apply = function(color, disableUpdate, forceUpdate) 1172 { 1173 if (!applying) 1174 { 1175 var defaultValue = (defaultColor == 'null') ? null : defaultColor; 1176 1177 applying = true; 1178 color = (/(^#?[a-zA-Z0-9]*$)/.test(color)) ? color : defaultValue; 1179 var tempColor = (color != null && color != mxConstants.NONE) ? color : defaultValue; 1180 1181 var div = document.createElement('div'); 1182 div.style.width = '36px'; 1183 div.style.height = '12px'; 1184 div.style.margin = '3px'; 1185 div.style.border = '1px solid black'; 1186 div.style.backgroundColor = (tempColor == 'default') ? defaultColorValue : tempColor; 1187 1188 btn.innerHTML = ''; 1189 btn.appendChild(div); 1190 1191 if (color != null && color != mxConstants.NONE && color.length > 1 && typeof color === 'string') 1192 { 1193 var clr = (color.charAt(0) == '#') ? color.substring(1).toUpperCase() : color; 1194 var name = ColorDialog.prototype.colorNames[clr]; 1195 btn.setAttribute('title', (name != null) ? name + ' (' + title + ')' : title); 1196 } 1197 1198 if (color != null && color != mxConstants.NONE) 1199 { 1200 cb.setAttribute('checked', 'checked'); 1201 cb.defaultChecked = true; 1202 cb.checked = true; 1203 } 1204 else 1205 { 1206 cb.removeAttribute('checked'); 1207 cb.defaultChecked = false; 1208 cb.checked = false; 1209 } 1210 1211 btn.style.display = (cb.checked || hideCheckbox) ? '' : 'none'; 1212 1213 if (callbackFn != null) 1214 { 1215 callbackFn(color == 'null' ? null : color); 1216 } 1217 1218 if (!disableUpdate) 1219 { 1220 value = color; 1221 1222 // Checks if the color value needs to be updated in the model 1223 if (forceUpdate || hideCheckbox || getColorFn() != value) 1224 { 1225 setColorFn(value == 'null' ? null : value, value); 1226 } 1227 } 1228 1229 applying = false; 1230 } 1231 }; 1232 1233 var clrInput = document.createElement('input'); 1234 clrInput.setAttribute('type', 'color'); 1235 clrInput.style.visibility = 'hidden'; 1236 clrInput.style.width = '0px'; 1237 clrInput.style.height = '0px'; 1238 clrInput.style.border = 'none'; 1239 div.appendChild(clrInput); 1240 1241 btn = mxUtils.button('', mxUtils.bind(this, function(evt) 1242 { 1243 var color = value; 1244 1245 if (color == 'default') 1246 { 1247 color = defaultColorValue; 1248 } 1249 1250 if (mxEvent.isShiftDown(evt) && !mxClient.IS_IE && !mxClient.IS_IE11) 1251 { 1252 clrInput.value = color; 1253 clrInput.click(); 1254 1255 mxEvent.addListener(clrInput, 'input', function() 1256 { 1257 apply(clrInput.value, null, true); 1258 }); 1259 } 1260 else 1261 { 1262 this.editorUi.pickColor(color, function(newColor) 1263 { 1264 apply(newColor, null, true); 1265 }, defaultColorValue); 1266 } 1267 1268 mxEvent.consume(evt); 1269 })); 1270 1271 btn.style.position = 'absolute'; 1272 btn.style.marginTop = '-3px'; 1273 btn.style.left = '178px'; 1274 btn.style.height = '22px'; 1275 btn.className = 'geColorBtn'; 1276 btn.style.display = (cb.checked || hideCheckbox) ? '' : 'none'; 1277 div.appendChild(btn); 1278 1279 var clr = (value != null && typeof value === 'string' && value.charAt(0) == '#') ? value.substring(1).toUpperCase() : value; 1280 var name = ColorDialog.prototype.colorNames[clr]; 1281 btn.setAttribute('title', (name != null) ? name + ' (' + title + ')' : title); 1282 1283 mxEvent.addListener(div, 'click', function(evt) 1284 { 1285 var source = mxEvent.getSource(evt); 1286 1287 if (source == cb || source.nodeName != 'INPUT') 1288 { 1289 // Toggles checkbox state for click on label 1290 if (source != cb) 1291 { 1292 cb.checked = !cb.checked; 1293 } 1294 1295 // Overrides default value with current value to make it easier 1296 // to restore previous value if the checkbox is clicked twice 1297 if (!cb.checked && value != null && value != mxConstants.NONE && 1298 defaultColor != mxConstants.NONE) 1299 { 1300 defaultColor = value; 1301 } 1302 1303 apply((cb.checked) ? defaultColor : mxConstants.NONE); 1304 } 1305 }); 1306 1307 apply(value, true); 1308 1309 if (listener != null) 1310 { 1311 listener.install(apply); 1312 this.listeners.push(listener); 1313 } 1314 1315 return div; 1316}; 1317 1318/** 1319 * 1320 */ 1321BaseFormatPanel.prototype.createCellColorOption = function(label, colorKey, defaultColor, callbackFn, setStyleFn, defaultColorValue) 1322{ 1323 var ui = this.editorUi; 1324 var editor = ui.editor; 1325 var graph = editor.graph; 1326 var self = this; 1327 1328 return this.createColorOption(label, function() 1329 { 1330 // Seems to be null sometimes, not sure why... 1331 var state = graph.view.getState(self.format.getSelectionState().cells[0]); 1332 1333 if (state != null) 1334 { 1335 return mxUtils.getValue(state.style, colorKey, null); 1336 } 1337 1338 return null; 1339 }, function(color, realValue) 1340 { 1341 graph.getModel().beginUpdate(); 1342 try 1343 { 1344 var cells = self.format.getSelectionState().cells; 1345 graph.setCellStyles(colorKey, color, cells); 1346 1347 if (setStyleFn != null) 1348 { 1349 setStyleFn(color); 1350 } 1351 1352 ui.fireEvent(new mxEventObject('styleChanged', 'keys', [colorKey], 1353 'values', [color], 'cells', cells)); 1354 } 1355 finally 1356 { 1357 graph.getModel().endUpdate(); 1358 } 1359 }, defaultColor || mxConstants.NONE, 1360 { 1361 install: function(apply) 1362 { 1363 this.listener = function() 1364 { 1365 // Seems to be null sometimes, not sure why... 1366 var state = graph.view.getState(self.format.getSelectionState().cells[0]); 1367 1368 if (state != null) 1369 { 1370 apply(mxUtils.getValue(state.style, colorKey, null), true); 1371 } 1372 }; 1373 1374 graph.getModel().addListener(mxEvent.CHANGE, this.listener); 1375 }, 1376 destroy: function() 1377 { 1378 graph.getModel().removeListener(this.listener); 1379 } 1380 }, callbackFn, null, defaultColorValue); 1381}; 1382 1383/** 1384 * 1385 */ 1386BaseFormatPanel.prototype.addArrow = function(elt, height) 1387{ 1388 height = (height != null) ? height : 10; 1389 1390 var arrow = document.createElement('div'); 1391 arrow.style.display = 'inline-block'; 1392 arrow.style.paddingRight = '4px'; 1393 arrow.style.padding = '6px'; 1394 1395 var m = (10 - height); 1396 1397 if (m == 2) 1398 { 1399 arrow.style.paddingTop = 6 + 'px'; 1400 } 1401 else if (m > 0) 1402 { 1403 arrow.style.paddingTop = (6 - m) + 'px'; 1404 } 1405 else 1406 { 1407 arrow.style.marginTop = '-2px'; 1408 } 1409 1410 arrow.style.height = height + 'px'; 1411 arrow.style.borderLeft = '1px solid #a0a0a0'; 1412 1413 var img = document.createElement('img'); 1414 img.setAttribute('border', '0'); 1415 img.setAttribute('valign', 'middle'); 1416 img.setAttribute('src', Toolbar.prototype.dropDownImage); 1417 arrow.appendChild(img); 1418 1419 var img = arrow.getElementsByTagName('img')[0]; 1420 img.style.position = 'relative'; 1421 img.style.left = '1px'; 1422 img.style.top = (mxClient.IS_FF) ? '0px' : '-4px'; 1423 mxUtils.setOpacity(arrow, 70); 1424 1425 var symbol = elt.getElementsByTagName('div')[0]; 1426 1427 if (symbol != null) 1428 { 1429 symbol.style.paddingRight = '6px'; 1430 symbol.style.marginLeft = '4px'; 1431 symbol.style.marginTop = '-1px'; 1432 symbol.style.display = 'inline-block'; 1433 mxUtils.setOpacity(symbol, 60); 1434 } 1435 1436 mxUtils.setOpacity(elt, 100); 1437 elt.style.border = '1px solid #a0a0a0'; 1438 elt.style.backgroundColor = this.buttonBackgroundColor; 1439 elt.style.backgroundImage = 'none'; 1440 elt.style.width = 'auto'; 1441 elt.className += ' geColorBtn'; 1442 mxUtils.setPrefixedStyle(elt.style, 'borderRadius', '3px'); 1443 1444 elt.appendChild(arrow); 1445 1446 return symbol; 1447}; 1448 1449/** 1450 * 1451 */ 1452BaseFormatPanel.prototype.addUnitInput = function(container, unit, right, width, update, step, marginTop, disableFocus, isFloat) 1453{ 1454 marginTop = (marginTop != null) ? marginTop : 0; 1455 1456 var input = document.createElement('input'); 1457 input.style.position = 'absolute'; 1458 input.style.textAlign = 'right'; 1459 input.style.marginTop = '-2px'; 1460 input.style.left = (228 - right - width) + 'px'; 1461 input.style.width = width + 'px'; 1462 input.style.height = '21px'; 1463 input.style.border = '1px solid rgb(160, 160, 160)'; 1464 input.style.borderRadius = '4px'; 1465 input.style.boxSizing = 'border-box'; 1466 1467 container.appendChild(input); 1468 1469 var stepper = this.createStepper(input, update, step, null, disableFocus, null, isFloat); 1470 stepper.style.marginTop = (marginTop - 2) + 'px'; 1471 stepper.style.left = (228 - right) + 'px'; 1472 container.appendChild(stepper); 1473 1474 return input; 1475}; 1476 1477/** 1478 * 1479 */ 1480BaseFormatPanel.prototype.createRelativeOption = function(label, key, width, handler, init) 1481{ 1482 width = (width != null) ? width : 52; 1483 1484 var graph = this.editorUi.editor.graph; 1485 var div = this.createPanel(); 1486 div.style.paddingTop = '10px'; 1487 div.style.paddingBottom = '10px'; 1488 mxUtils.write(div, label); 1489 div.style.fontWeight = 'bold'; 1490 1491 var update = mxUtils.bind(this, function(evt) 1492 { 1493 if (handler != null) 1494 { 1495 handler(input); 1496 } 1497 else 1498 { 1499 var value = parseInt(input.value); 1500 value = Math.min(100, Math.max(0, (isNaN(value)) ? 100 : value)); 1501 var state = graph.view.getState(this.format.getSelectionState().cells[0]); 1502 1503 if (state != null && value != mxUtils.getValue(state.style, key, 100)) 1504 { 1505 // Removes entry in style (assumes 100 is default for relative values) 1506 if (value == 100) 1507 { 1508 value = null; 1509 } 1510 1511 var cells = this.format.getSelectionState().cells; 1512 graph.setCellStyles(key, value, cells); 1513 this.editorUi.fireEvent(new mxEventObject('styleChanged', 'keys', [key], 1514 'values', [value], 'cells', cells)); 1515 } 1516 1517 input.value = ((value != null) ? value : '100') + ' %'; 1518 } 1519 1520 mxEvent.consume(evt); 1521 }); 1522 1523 var input = this.addUnitInput(div, '%', 16, width, update, 10, -15, handler != null); 1524 1525 if (key != null) 1526 { 1527 var listener = mxUtils.bind(this, function(sender, evt, force) 1528 { 1529 if (force || input != document.activeElement) 1530 { 1531 var ss = this.format.getSelectionState(); 1532 var tmp = parseInt(mxUtils.getValue(ss.style, key, 100)); 1533 input.value = (isNaN(tmp)) ? '' : tmp + ' %'; 1534 } 1535 }); 1536 1537 mxEvent.addListener(input, 'keydown', function(e) 1538 { 1539 if (e.keyCode == 13) 1540 { 1541 graph.container.focus(); 1542 mxEvent.consume(e); 1543 } 1544 else if (e.keyCode == 27) 1545 { 1546 listener(null, null, true); 1547 graph.container.focus(); 1548 mxEvent.consume(e); 1549 } 1550 }); 1551 1552 graph.getModel().addListener(mxEvent.CHANGE, listener); 1553 this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }}); 1554 listener(); 1555 } 1556 1557 mxEvent.addListener(input, 'blur', update); 1558 mxEvent.addListener(input, 'change', update); 1559 1560 if (init != null) 1561 { 1562 init(input); 1563 } 1564 1565 return div; 1566}; 1567 1568/** 1569 * 1570 */ 1571BaseFormatPanel.prototype.addLabel = function(div, title, right, width) 1572{ 1573 width = (width != null) ? width : 61; 1574 1575 var label = document.createElement('div'); 1576 mxUtils.write(label, title); 1577 label.style.position = 'absolute'; 1578 label.style.left = (240 - right - width) + 'px'; 1579 label.style.width = width + 'px'; 1580 label.style.marginTop = '6px'; 1581 label.style.textAlign = 'center'; 1582 div.appendChild(label); 1583}; 1584 1585/** 1586 * 1587 */ 1588BaseFormatPanel.prototype.addKeyHandler = function(input, listener) 1589{ 1590 mxEvent.addListener(input, 'keydown', mxUtils.bind(this, function(e) 1591 { 1592 if (e.keyCode == 13) 1593 { 1594 this.editorUi.editor.graph.container.focus(); 1595 mxEvent.consume(e); 1596 } 1597 else if (e.keyCode == 27) 1598 { 1599 if (listener != null) 1600 { 1601 listener(null, null, true); 1602 } 1603 1604 this.editorUi.editor.graph.container.focus(); 1605 mxEvent.consume(e); 1606 } 1607 })); 1608}; 1609 1610/** 1611 * 1612 */ 1613BaseFormatPanel.prototype.styleButtons = function(elts) 1614{ 1615 for (var i = 0; i < elts.length; i++) 1616 { 1617 mxUtils.setPrefixedStyle(elts[i].style, 'borderRadius', '3px'); 1618 mxUtils.setOpacity(elts[i], 100); 1619 elts[i].style.border = '1px solid #a0a0a0'; 1620 elts[i].style.padding = '4px'; 1621 elts[i].style.paddingTop = '3px'; 1622 elts[i].style.paddingRight = '1px'; 1623 elts[i].style.margin = '1px'; 1624 elts[i].style.marginRight = '2px'; 1625 elts[i].style.width = '24px'; 1626 elts[i].style.height = '20px'; 1627 elts[i].className += ' geColorBtn'; 1628 } 1629}; 1630 1631/** 1632 * Adds the label menu items to the given menu and parent. 1633 */ 1634BaseFormatPanel.prototype.destroy = function() 1635{ 1636 if (this.listeners != null) 1637 { 1638 for (var i = 0; i < this.listeners.length; i++) 1639 { 1640 this.listeners[i].destroy(); 1641 } 1642 1643 this.listeners = null; 1644 } 1645}; 1646 1647/** 1648 * Adds the label menu items to the given menu and parent. 1649 */ 1650ArrangePanel = function(format, editorUi, container) 1651{ 1652 BaseFormatPanel.call(this, format, editorUi, container); 1653 this.init(); 1654}; 1655 1656mxUtils.extend(ArrangePanel, BaseFormatPanel); 1657 1658/** 1659 * Adds the label menu items to the given menu and parent. 1660 */ 1661ArrangePanel.prototype.init = function() 1662{ 1663 var graph = this.editorUi.editor.graph; 1664 var ss = this.format.getSelectionState(); 1665 1666 if (ss.cells.length > 0) 1667 { 1668 this.container.appendChild(this.addLayerOps(this.createPanel())); 1669 // Special case that adds two panels 1670 this.addGeometry(this.container); 1671 this.addEdgeGeometry(this.container); 1672 1673 if (!ss.containsLabel || ss.edges.length == 0) 1674 { 1675 this.container.appendChild(this.addAngle(this.createPanel())); 1676 } 1677 1678 if (!ss.containsLabel && ss.edges.length == 0 && 1679 ss.style.shape != 'rectangle' && 1680 ss.style.shape != 'label') 1681 { 1682 this.container.appendChild(this.addFlip(this.createPanel())); 1683 } 1684 1685 if (ss.vertices.length > 1) 1686 { 1687 this.container.appendChild(this.addAlign(this.createPanel())); 1688 this.container.appendChild(this.addDistribute(this.createPanel())); 1689 } 1690 1691 this.container.appendChild(this.addTable(this.createPanel())); 1692 } 1693 1694 this.container.appendChild(this.addGroupOps(this.createPanel())); 1695 1696 if (ss.containsLabel) 1697 { 1698 // Adds functions from hidden style format panel 1699 var span = document.createElement('div'); 1700 span.style.width = '100%'; 1701 span.style.marginTop = '0px'; 1702 span.style.fontWeight = 'bold'; 1703 span.style.padding = '10px 0 0 14px'; 1704 mxUtils.write(span, mxResources.get('style')); 1705 this.container.appendChild(span); 1706 1707 new StyleFormatPanel(this.format, this.editorUi, this.container); 1708 } 1709}; 1710 1711/** 1712 * 1713 */ 1714ArrangePanel.prototype.addTable = function(div) 1715{ 1716 var ui = this.editorUi; 1717 var editor = ui.editor; 1718 var graph = editor.graph; 1719 var ss = this.format.getSelectionState(); 1720 div.style.paddingTop = '6px'; 1721 div.style.paddingBottom = '10px'; 1722 1723 var span = document.createElement('div'); 1724 span.style.marginTop = '2px'; 1725 span.style.marginBottom = '8px'; 1726 span.style.fontWeight = 'bold'; 1727 mxUtils.write(span, mxResources.get('table')); 1728 div.appendChild(span); 1729 1730 var panel = document.createElement('div'); 1731 panel.style.position = 'relative'; 1732 panel.style.paddingLeft = '0px'; 1733 panel.style.borderWidth = '0px'; 1734 panel.style.width = '220px'; 1735 panel.className = 'geToolbarContainer'; 1736 1737 var isTable = graph.isTable(ss.vertices[0]) || 1738 graph.isTableRow(ss.vertices[0]) || 1739 graph.isTableCell(ss.vertices[0]); 1740 var isStack = graph.isStack(ss.vertices[0]) || 1741 graph.isStackChild(ss.vertices[0]); 1742 1743 var showCols = isTable; 1744 var showRows = isTable; 1745 1746 if (isStack) 1747 { 1748 var style = (graph.isStack(ss.vertices[0])) ? ss.style : 1749 graph.getCellStyle(graph.model.getParent(ss.vertices[0])); 1750 1751 showRows = style['horizontalStack'] == '0'; 1752 showCols = !showRows; 1753 } 1754 1755 var btns = []; 1756 1757 if (showCols) 1758 { 1759 btns = btns.concat([ 1760 ui.toolbar.addButton('geSprite-insertcolumnbefore', mxResources.get('insertColumnBefore'), 1761 mxUtils.bind(this, function() 1762 { 1763 try 1764 { 1765 if (isStack) 1766 { 1767 graph.insertLane(ss.vertices[0], true); 1768 } 1769 else 1770 { 1771 graph.insertTableColumn(ss.vertices[0], true); 1772 } 1773 } 1774 catch (e) 1775 { 1776 ui.handleError(e); 1777 } 1778 }), panel), 1779 ui.toolbar.addButton('geSprite-insertcolumnafter', mxResources.get('insertColumnAfter'), 1780 mxUtils.bind(this, function() 1781 { 1782 try 1783 { 1784 if (isStack) 1785 { 1786 graph.insertLane(ss.vertices[0], false); 1787 } 1788 else 1789 { 1790 graph.insertTableColumn(ss.vertices[0], false); 1791 } 1792 } 1793 catch (e) 1794 { 1795 ui.handleError(e); 1796 } 1797 }), panel), 1798 ui.toolbar.addButton('geSprite-deletecolumn', mxResources.get('deleteColumn'), 1799 mxUtils.bind(this, function() 1800 { 1801 try 1802 { 1803 if (isStack) 1804 { 1805 graph.deleteLane(ss.vertices[0]); 1806 } 1807 else 1808 { 1809 graph.deleteTableColumn(ss.vertices[0]); 1810 } 1811 } 1812 catch (e) 1813 { 1814 ui.handleError(e); 1815 } 1816 }), panel)]); 1817 } 1818 1819 if (showRows) 1820 { 1821 btns = btns.concat([ui.toolbar.addButton('geSprite-insertrowbefore', mxResources.get('insertRowBefore'), 1822 mxUtils.bind(this, function() 1823 { 1824 try 1825 { 1826 if (isStack) 1827 { 1828 graph.insertLane(ss.vertices[0], true); 1829 } 1830 else 1831 { 1832 graph.insertTableRow(ss.vertices[0], true); 1833 } 1834 } 1835 catch (e) 1836 { 1837 ui.handleError(e); 1838 } 1839 }), panel), 1840 ui.toolbar.addButton('geSprite-insertrowafter', mxResources.get('insertRowAfter'), 1841 mxUtils.bind(this, function() 1842 { 1843 try 1844 { 1845 if (isStack) 1846 { 1847 graph.insertLane(ss.vertices[0], false); 1848 } 1849 else 1850 { 1851 graph.insertTableRow(ss.vertices[0], false); 1852 } 1853 } 1854 catch (e) 1855 { 1856 ui.handleError(e); 1857 } 1858 }), panel), 1859 ui.toolbar.addButton('geSprite-deleterow', mxResources.get('deleteRow'), 1860 mxUtils.bind(this, function() 1861 { 1862 try 1863 { 1864 if (isStack) 1865 { 1866 graph.deleteLane(ss.vertices[0]); 1867 } 1868 else 1869 { 1870 graph.deleteTableRow(ss.vertices[0]); 1871 } 1872 } 1873 catch (e) 1874 { 1875 ui.handleError(e); 1876 } 1877 }), panel)]); 1878 } 1879 1880 if (btns.length > 0) 1881 { 1882 this.styleButtons(btns); 1883 div.appendChild(panel); 1884 1885 if (btns.length > 3) 1886 { 1887 btns[2].style.marginRight = '10px'; 1888 } 1889 } 1890 1891 return div; 1892}; 1893 1894/** 1895 * 1896 */ 1897ArrangePanel.prototype.addLayerOps = function(div) 1898{ 1899 var ui = this.editorUi; 1900 var graph = ui.editor.graph; 1901 1902 var btn = mxUtils.button(mxResources.get('toFront'), function(evt) 1903 { 1904 ui.actions.get('toFront').funct(); 1905 }) 1906 1907 btn.setAttribute('title', mxResources.get('toFront') + ' (' + this.editorUi.actions.get('toFront').shortcut + ')'); 1908 btn.style.width = '104px'; 1909 btn.style.marginRight = '2px'; 1910 div.appendChild(btn); 1911 1912 var btn = mxUtils.button(mxResources.get('toBack'), function(evt) 1913 { 1914 ui.actions.get('toBack').funct(); 1915 }) 1916 1917 btn.setAttribute('title', mxResources.get('toBack') + ' (' + this.editorUi.actions.get('toBack').shortcut + ')'); 1918 btn.style.width = '104px'; 1919 div.appendChild(btn); 1920 1921 if (graph.getSelectionCount() == 1) 1922 { 1923 mxUtils.br(div); 1924 1925 var btn = mxUtils.button(mxResources.get('bringForward'), function(evt) 1926 { 1927 ui.actions.get('bringForward').funct(); 1928 }) 1929 1930 btn.setAttribute('title', mxResources.get('bringForward')); 1931 btn.style.width = '104px'; 1932 btn.style.marginRight = '2px'; 1933 btn.style.marginTop = '2px'; 1934 div.appendChild(btn); 1935 1936 var btn = mxUtils.button(mxResources.get('sendBackward'), function(evt) 1937 { 1938 ui.actions.get('sendBackward').funct(); 1939 }) 1940 1941 btn.setAttribute('title', mxResources.get('sendBackward')); 1942 btn.style.width = '104px'; 1943 btn.style.marginTop = '2px'; 1944 div.appendChild(btn); 1945 } 1946 1947 return div; 1948}; 1949 1950/** 1951 * 1952 */ 1953ArrangePanel.prototype.addGroupOps = function(div) 1954{ 1955 var ui = this.editorUi; 1956 var graph = ui.editor.graph; 1957 var ss = this.format.getSelectionState(); 1958 var cell = ss.cells[0]; 1959 var count = 0; 1960 var btn = null; 1961 1962 div.style.paddingTop = '8px'; 1963 div.style.paddingBottom = '6px'; 1964 1965 if (graph.getSelectionCount() > 1) 1966 { 1967 btn = mxUtils.button(mxResources.get('group'), function(evt) 1968 { 1969 ui.actions.get('group').funct(); 1970 }) 1971 1972 btn.setAttribute('title', mxResources.get('group') + ' (' + this.editorUi.actions.get('group').shortcut + ')'); 1973 btn.style.width = '210px'; 1974 btn.style.marginBottom = '2px'; 1975 div.appendChild(btn); 1976 count++; 1977 } 1978 else if (ss.cells.length == 1 && !graph.getModel().isEdge(cell) && !graph.isSwimlane(cell) && 1979 !graph.isTable(cell) && !ss.row && !ss.cell && graph.getModel().getChildCount(cell) > 0) 1980 { 1981 btn = mxUtils.button(mxResources.get('ungroup'), function(evt) 1982 { 1983 ui.actions.get('ungroup').funct(); 1984 }) 1985 1986 btn.setAttribute('title', mxResources.get('ungroup') + ' (' + 1987 this.editorUi.actions.get('ungroup').shortcut + ')'); 1988 btn.style.width = '210px'; 1989 btn.style.marginBottom = '2px'; 1990 div.appendChild(btn); 1991 count++; 1992 } 1993 1994 if (graph.getModel().isVertex(graph.getSelectionCell())) 1995 { 1996 if (count > 0) 1997 { 1998 mxUtils.br(div); 1999 count = 0; 2000 } 2001 2002 var btn = mxUtils.button(mxResources.get('copySize'), function(evt) 2003 { 2004 ui.actions.get('copySize').funct(evt); 2005 }); 2006 2007 btn.setAttribute('title', mxResources.get('copySize') + ' (' + 2008 this.editorUi.actions.get('copySize').shortcut + ')'); 2009 btn.style.width = '210px'; 2010 btn.style.marginBottom = '2px'; 2011 2012 div.appendChild(btn); 2013 count++; 2014 2015 if (ui.copiedSize != null && ss.vertices.length > 0) 2016 { 2017 var btn2 = mxUtils.button(mxResources.get('pasteSize'), function(evt) 2018 { 2019 ui.actions.get('pasteSize').funct(evt); 2020 }); 2021 2022 btn2.setAttribute('title', mxResources.get('pasteSize') + ' (' + 2023 this.editorUi.actions.get('pasteSize').shortcut + ')'); 2024 2025 div.appendChild(btn2); 2026 count++; 2027 2028 btn.style.width = '104px'; 2029 btn.style.marginBottom = '2px'; 2030 btn2.style.width = '104px'; 2031 btn2.style.marginBottom = '2px'; 2032 } 2033 } 2034 2035 if (graph.getSelectionCount() > 0) 2036 { 2037 if (count > 0) 2038 { 2039 mxUtils.br(div); 2040 count = 0; 2041 } 2042 2043 var btn = mxUtils.button(mxResources.get('copyData'), function(evt) 2044 { 2045 if (mxEvent.isShiftDown(evt)) 2046 { 2047 var result = graph.getDataForCells(graph.getSelectionCells()); 2048 2049 var dlg = new EmbedDialog(ui, JSON.stringify(result, null, 2), null, null, function() 2050 { 2051 console.log(result); 2052 ui.alert('Written to Console (Dev Tools)'); 2053 }, mxResources.get('copyData'), null, 'Console', 'data.json'); 2054 ui.showDialog(dlg.container, 450, 240, true, true); 2055 dlg.init(); 2056 } 2057 else 2058 { 2059 ui.actions.get('copyData').funct(evt); 2060 } 2061 }); 2062 2063 btn.setAttribute('title', mxResources.get('copyData') + ' (' + 2064 this.editorUi.actions.get('copyData').shortcut + ')' + 2065 ' Shift+Click to Extract Data'); 2066 btn.style.width = '210px'; 2067 btn.style.marginBottom = '2px'; 2068 2069 div.appendChild(btn); 2070 count++; 2071 2072 if (ui.copiedValue != null && ss.cells.length > 0) 2073 { 2074 var btn2 = mxUtils.button(mxResources.get('pasteData'), function(evt) 2075 { 2076 ui.actions.get('pasteData').funct(evt); 2077 }); 2078 2079 btn2.setAttribute('title', mxResources.get('pasteData') + ' (' + 2080 this.editorUi.actions.get('pasteData').shortcut + ')'); 2081 2082 div.appendChild(btn2); 2083 count++; 2084 2085 btn.style.width = '104px'; 2086 btn.style.marginBottom = '2px'; 2087 btn2.style.width = '104px'; 2088 btn2.style.marginBottom = '2px'; 2089 } 2090 } 2091 2092 if (ss.cells.length == 1 && graph.getModel().isVertex(cell) && !ss.row && 2093 !ss.cell && graph.getModel().isVertex(graph.getModel().getParent(cell))) 2094 { 2095 if (count > 0) 2096 { 2097 mxUtils.br(div); 2098 } 2099 2100 btn = mxUtils.button(mxResources.get('removeFromGroup'), function(evt) 2101 { 2102 ui.actions.get('removeFromGroup').funct(); 2103 }) 2104 2105 btn.setAttribute('title', mxResources.get('removeFromGroup')); 2106 btn.style.width = '210px'; 2107 btn.style.marginBottom = '2px'; 2108 div.appendChild(btn); 2109 count++; 2110 } 2111 else if (ss.cells.length > 0) 2112 { 2113 if (count > 0) 2114 { 2115 mxUtils.br(div); 2116 } 2117 2118 btn = mxUtils.button(mxResources.get('clearWaypoints'), mxUtils.bind(this, function(evt) 2119 { 2120 this.editorUi.actions.get('clearWaypoints').funct(evt); 2121 })); 2122 2123 btn.setAttribute('title', mxResources.get('clearWaypoints') + ' (' + this.editorUi.actions.get('clearWaypoints').shortcut + ')'); 2124 btn.style.width = '210px'; 2125 btn.style.marginBottom = '2px'; 2126 div.appendChild(btn); 2127 2128 count++; 2129 } 2130 2131 if (ss.cells.length == 1) 2132 { 2133 if (count > 0) 2134 { 2135 mxUtils.br(div); 2136 } 2137 2138 btn = mxUtils.button(mxResources.get('editData'), mxUtils.bind(this, function(evt) 2139 { 2140 this.editorUi.actions.get('editData').funct(); 2141 })); 2142 2143 btn.setAttribute('title', mxResources.get('editData') + ' (' + this.editorUi.actions.get('editData').shortcut + ')'); 2144 btn.style.width = '104px'; 2145 btn.style.marginBottom = '2px'; 2146 div.appendChild(btn); 2147 count++; 2148 2149 btn = mxUtils.button(mxResources.get('editLink'), mxUtils.bind(this, function(evt) 2150 { 2151 this.editorUi.actions.get('editLink').funct(); 2152 })); 2153 2154 btn.setAttribute('title', mxResources.get('editLink') + ' (' + this.editorUi.actions.get('editLink').shortcut + ')'); 2155 btn.style.width = '104px'; 2156 btn.style.marginLeft = '2px'; 2157 btn.style.marginBottom = '2px'; 2158 div.appendChild(btn); 2159 count++; 2160 } 2161 2162 if (count == 0) 2163 { 2164 div.style.display = 'none'; 2165 } 2166 2167 return div; 2168}; 2169 2170/** 2171 * 2172 */ 2173ArrangePanel.prototype.addAlign = function(div) 2174{ 2175 var graph = this.editorUi.editor.graph; 2176 div.style.paddingTop = '6px'; 2177 div.style.paddingBottom = '12px'; 2178 div.appendChild(this.createTitle(mxResources.get('align'))); 2179 2180 var stylePanel = document.createElement('div'); 2181 stylePanel.style.position = 'relative'; 2182 stylePanel.style.whiteSpace = 'nowrap'; 2183 stylePanel.style.paddingLeft = '0px'; 2184 stylePanel.style.borderWidth = '0px'; 2185 stylePanel.style.width = '220px'; 2186 stylePanel.className = 'geToolbarContainer'; 2187 2188 var left = this.editorUi.toolbar.addButton('geSprite-alignleft', mxResources.get('left'), 2189 function() { graph.alignCells(mxConstants.ALIGN_LEFT); }, stylePanel); 2190 var center = this.editorUi.toolbar.addButton('geSprite-aligncenter', mxResources.get('center'), 2191 function() { graph.alignCells(mxConstants.ALIGN_CENTER); }, stylePanel); 2192 var right = this.editorUi.toolbar.addButton('geSprite-alignright', mxResources.get('right'), 2193 function() { graph.alignCells(mxConstants.ALIGN_RIGHT); }, stylePanel); 2194 2195 var top = this.editorUi.toolbar.addButton('geSprite-aligntop', mxResources.get('top'), 2196 function() { graph.alignCells(mxConstants.ALIGN_TOP); }, stylePanel); 2197 var middle = this.editorUi.toolbar.addButton('geSprite-alignmiddle', mxResources.get('middle'), 2198 function() { graph.alignCells(mxConstants.ALIGN_MIDDLE); }, stylePanel); 2199 var bottom = this.editorUi.toolbar.addButton('geSprite-alignbottom', mxResources.get('bottom'), 2200 function() { graph.alignCells(mxConstants.ALIGN_BOTTOM); }, stylePanel); 2201 2202 this.styleButtons([left, center, right, top, middle, bottom]); 2203 right.style.marginRight = '10px'; 2204 div.appendChild(stylePanel); 2205 2206 return div; 2207}; 2208 2209/** 2210 * 2211 */ 2212ArrangePanel.prototype.addFlip = function(div) 2213{ 2214 var ui = this.editorUi; 2215 var editor = ui.editor; 2216 var graph = editor.graph; 2217 div.style.paddingTop = '6px'; 2218 div.style.paddingBottom = '10px'; 2219 2220 var span = document.createElement('div'); 2221 span.style.marginTop = '2px'; 2222 span.style.marginBottom = '8px'; 2223 span.style.fontWeight = 'bold'; 2224 mxUtils.write(span, mxResources.get('flip')); 2225 div.appendChild(span); 2226 2227 var btn = mxUtils.button(mxResources.get('horizontal'), function(evt) 2228 { 2229 graph.toggleCellStyles(mxConstants.STYLE_FLIPH, false); 2230 }) 2231 2232 btn.setAttribute('title', mxResources.get('horizontal')); 2233 btn.style.width = '104px'; 2234 btn.style.marginRight = '2px'; 2235 div.appendChild(btn); 2236 2237 var btn = mxUtils.button(mxResources.get('vertical'), function(evt) 2238 { 2239 graph.toggleCellStyles(mxConstants.STYLE_FLIPV, false); 2240 }) 2241 2242 btn.setAttribute('title', mxResources.get('vertical')); 2243 btn.style.width = '104px'; 2244 div.appendChild(btn); 2245 2246 return div; 2247}; 2248 2249/** 2250 * 2251 */ 2252ArrangePanel.prototype.addDistribute = function(div) 2253{ 2254 var ui = this.editorUi; 2255 var editor = ui.editor; 2256 var graph = editor.graph; 2257 div.style.paddingTop = '6px'; 2258 div.style.paddingBottom = '12px'; 2259 2260 div.appendChild(this.createTitle(mxResources.get('distribute'))); 2261 2262 var btn = mxUtils.button(mxResources.get('horizontal'), function(evt) 2263 { 2264 graph.distributeCells(true); 2265 }) 2266 2267 btn.setAttribute('title', mxResources.get('horizontal')); 2268 btn.style.width = '104px'; 2269 btn.style.marginRight = '2px'; 2270 div.appendChild(btn); 2271 2272 var btn = mxUtils.button(mxResources.get('vertical'), function(evt) 2273 { 2274 graph.distributeCells(false); 2275 }) 2276 2277 btn.setAttribute('title', mxResources.get('vertical')); 2278 btn.style.width = '104px'; 2279 div.appendChild(btn); 2280 2281 return div; 2282}; 2283 2284/** 2285 * 2286 */ 2287ArrangePanel.prototype.addAngle = function(div) 2288{ 2289 var ui = this.editorUi; 2290 var editor = ui.editor; 2291 var graph = editor.graph; 2292 var ss = this.format.getSelectionState(); 2293 2294 div.style.paddingBottom = '8px'; 2295 2296 var span = document.createElement('div'); 2297 span.style.position = 'absolute'; 2298 span.style.width = '70px'; 2299 span.style.marginTop = '0px'; 2300 span.style.fontWeight = 'bold'; 2301 2302 var input = null; 2303 var update = null; 2304 var btn = null; 2305 2306 if (ss.rotatable && !ss.table && !ss.row && !ss.cell) 2307 { 2308 mxUtils.write(span, mxResources.get('angle')); 2309 div.appendChild(span); 2310 2311 input = this.addUnitInput(div, '°', 16, 52, function() 2312 { 2313 update.apply(this, arguments); 2314 }); 2315 2316 mxUtils.br(div); 2317 div.style.paddingTop = '10px'; 2318 } 2319 else 2320 { 2321 div.style.paddingTop = '8px'; 2322 } 2323 2324 if (!ss.containsLabel) 2325 { 2326 var label = mxResources.get('reverse'); 2327 2328 if (ss.vertices.length > 0 && ss.edges.length > 0) 2329 { 2330 label = mxResources.get('turn') + ' / ' + label; 2331 } 2332 else if (ss.vertices.length > 0) 2333 { 2334 label = mxResources.get('turn'); 2335 } 2336 2337 btn = mxUtils.button(label, function(evt) 2338 { 2339 ui.actions.get('turn').funct(evt); 2340 }) 2341 2342 btn.setAttribute('title', label + ' (' + this.editorUi.actions.get('turn').shortcut + ')'); 2343 btn.style.width = '210px'; 2344 div.appendChild(btn); 2345 2346 if (input != null) 2347 { 2348 btn.style.marginTop = '8px'; 2349 } 2350 } 2351 2352 if (input != null) 2353 { 2354 var listener = mxUtils.bind(this, function(sender, evt, force) 2355 { 2356 if (force || document.activeElement != input) 2357 { 2358 ss = this.format.getSelectionState(); 2359 var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_ROTATION, 0)); 2360 input.value = (isNaN(tmp)) ? '' : tmp + '°'; 2361 } 2362 }); 2363 2364 update = this.installInputHandler(input, mxConstants.STYLE_ROTATION, 0, 0, 360, '°', null, true); 2365 this.addKeyHandler(input, listener); 2366 2367 graph.getModel().addListener(mxEvent.CHANGE, listener); 2368 this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }}); 2369 listener(); 2370 } 2371 2372 return div; 2373}; 2374 2375BaseFormatPanel.prototype.getUnit = function() 2376{ 2377 var unit = this.editorUi.editor.graph.view.unit; 2378 2379 switch(unit) 2380 { 2381 case mxConstants.POINTS: 2382 return 'pt'; 2383 case mxConstants.INCHES: 2384 return '"'; 2385 case mxConstants.MILLIMETERS: 2386 return 'mm'; 2387 case mxConstants.METERS: 2388 return 'm'; 2389 } 2390}; 2391 2392BaseFormatPanel.prototype.inUnit = function(pixels) 2393{ 2394 return this.editorUi.editor.graph.view.formatUnitText(pixels); 2395}; 2396 2397BaseFormatPanel.prototype.fromUnit = function(value) 2398{ 2399 var unit = this.editorUi.editor.graph.view.unit; 2400 2401 switch(unit) 2402 { 2403 case mxConstants.POINTS: 2404 return value; 2405 case mxConstants.INCHES: 2406 return value * mxConstants.PIXELS_PER_INCH; 2407 case mxConstants.MILLIMETERS: 2408 return value * mxConstants.PIXELS_PER_MM; 2409 case mxConstants.METERS: 2410 return value * mxConstants.PIXELS_PER_MM * 1000; 2411 } 2412}; 2413 2414BaseFormatPanel.prototype.isFloatUnit = function() 2415{ 2416 return this.editorUi.editor.graph.view.unit != mxConstants.POINTS; 2417}; 2418 2419BaseFormatPanel.prototype.getUnitStep = function() 2420{ 2421 var unit = this.editorUi.editor.graph.view.unit; 2422 2423 switch(unit) 2424 { 2425 case mxConstants.POINTS: 2426 return 1; 2427 case mxConstants.INCHES: 2428 return 0.1; 2429 case mxConstants.MILLIMETERS: 2430 return 0.5; 2431 case mxConstants.METERS: 2432 return 0.001; 2433 } 2434}; 2435 2436/** 2437 * 2438 */ 2439ArrangePanel.prototype.addGeometry = function(container) 2440{ 2441 var panel = this; 2442 var ui = this.editorUi; 2443 var graph = ui.editor.graph; 2444 var model = graph.getModel(); 2445 var rect = this.format.getSelectionState(); 2446 2447 var div = this.createPanel(); 2448 div.style.paddingBottom = '8px'; 2449 2450 var span = document.createElement('div'); 2451 span.style.position = 'absolute'; 2452 span.style.width = '50px'; 2453 span.style.marginTop = '0px'; 2454 span.style.fontWeight = 'bold'; 2455 mxUtils.write(span, mxResources.get('size')); 2456 div.appendChild(span); 2457 2458 var widthUpdate, heightUpdate, leftUpdate, topUpdate; 2459 var width = this.addUnitInput(div, this.getUnit(), 87, 52, function() 2460 { 2461 widthUpdate.apply(this, arguments); 2462 }, this.getUnitStep(), null, null, this.isFloatUnit()); 2463 var height = this.addUnitInput(div, this.getUnit(), 16, 52, function() 2464 { 2465 heightUpdate.apply(this, arguments); 2466 }, this.getUnitStep(), null, null, this.isFloatUnit()); 2467 2468 var autosizeBtn = document.createElement('div'); 2469 autosizeBtn.className = 'geSprite geSprite-fit'; 2470 autosizeBtn.setAttribute('title', mxResources.get('autosize') + ' (' + this.editorUi.actions.get('autosize').shortcut + ')'); 2471 autosizeBtn.style.position = 'relative'; 2472 autosizeBtn.style.cursor = 'pointer'; 2473 autosizeBtn.style.marginTop = '-3px'; 2474 autosizeBtn.style.border = '0px'; 2475 autosizeBtn.style.left = '42px'; 2476 mxUtils.setOpacity(autosizeBtn, 50); 2477 2478 mxEvent.addListener(autosizeBtn, 'mouseenter', function() 2479 { 2480 mxUtils.setOpacity(autosizeBtn, 100); 2481 }); 2482 2483 mxEvent.addListener(autosizeBtn, 'mouseleave', function() 2484 { 2485 mxUtils.setOpacity(autosizeBtn, 50); 2486 }); 2487 2488 mxEvent.addListener(autosizeBtn, 'click', function() 2489 { 2490 ui.actions.get('autosize').funct(); 2491 }); 2492 2493 div.appendChild(autosizeBtn); 2494 2495 if (rect.row) 2496 { 2497 width.style.visibility = 'hidden'; 2498 width.nextSibling.style.visibility = 'hidden'; 2499 } 2500 else 2501 { 2502 this.addLabel(div, mxResources.get('width'), 87); 2503 } 2504 2505 this.addLabel(div, mxResources.get('height'), 16); 2506 mxUtils.br(div); 2507 2508 var wrapper = document.createElement('div'); 2509 wrapper.style.paddingTop = '8px'; 2510 wrapper.style.paddingRight = '20px'; 2511 wrapper.style.whiteSpace = 'nowrap'; 2512 wrapper.style.textAlign = 'right'; 2513 var opt = this.createCellOption(mxResources.get('constrainProportions'), 2514 mxConstants.STYLE_ASPECT, null, 'fixed', 'null'); 2515 opt.style.width = '210px'; 2516 wrapper.appendChild(opt); 2517 2518 if (!rect.cell && !rect.row) 2519 { 2520 div.appendChild(wrapper); 2521 } 2522 else 2523 { 2524 autosizeBtn.style.visibility = 'hidden'; 2525 } 2526 2527 var constrainCheckbox = opt.getElementsByTagName('input')[0]; 2528 this.addKeyHandler(width, listener); 2529 this.addKeyHandler(height, listener); 2530 2531 widthUpdate = this.addGeometryHandler(width, function(geo, value, cell) 2532 { 2533 if (graph.isTableCell(cell)) 2534 { 2535 graph.setTableColumnWidth(cell, value - geo.width, true); 2536 2537 // Blocks processing in caller 2538 return true; 2539 } 2540 else if (geo.width > 0) 2541 { 2542 var value = Math.max(1, panel.fromUnit(value)); 2543 2544 if (constrainCheckbox.checked) 2545 { 2546 geo.height = Math.round((geo.height * value * 100) / geo.width) / 100; 2547 } 2548 2549 geo.width = value; 2550 } 2551 }); 2552 heightUpdate = this.addGeometryHandler(height, function(geo, value, cell) 2553 { 2554 if (graph.isTableCell(cell)) 2555 { 2556 cell = graph.model.getParent(cell); 2557 } 2558 2559 if (graph.isTableRow(cell)) 2560 { 2561 graph.setTableRowHeight(cell, value - geo.height); 2562 2563 // Blocks processing in caller 2564 return true; 2565 } 2566 else if (geo.height > 0) 2567 { 2568 var value = Math.max(1, panel.fromUnit(value)); 2569 2570 if (constrainCheckbox.checked) 2571 { 2572 geo.width = Math.round((geo.width * value * 100) / geo.height) / 100; 2573 } 2574 2575 geo.height = value; 2576 } 2577 }); 2578 2579 if (rect.resizable || rect.row || rect.cell) 2580 { 2581 container.appendChild(div); 2582 } 2583 2584 var div2 = this.createPanel(); 2585 div2.style.paddingBottom = '30px'; 2586 2587 var span = document.createElement('div'); 2588 span.style.position = 'absolute'; 2589 span.style.width = '70px'; 2590 span.style.marginTop = '0px'; 2591 span.style.fontWeight = 'bold'; 2592 mxUtils.write(span, mxResources.get('position')); 2593 div2.appendChild(span); 2594 2595 var left = this.addUnitInput(div2, this.getUnit(), 87, 52, function() 2596 { 2597 leftUpdate.apply(this, arguments); 2598 }, this.getUnitStep(), null, null, this.isFloatUnit()); 2599 var top = this.addUnitInput(div2, this.getUnit(), 16, 52, function() 2600 { 2601 topUpdate.apply(this, arguments); 2602 }, this.getUnitStep(), null, null, this.isFloatUnit()); 2603 2604 mxUtils.br(div2); 2605 2606 this.addLabel(div2, mxResources.get('left'), 87); 2607 this.addLabel(div2, mxResources.get('top'), 16); 2608 2609 var listener = mxUtils.bind(this, function(sender, evt, force) 2610 { 2611 rect = this.format.getSelectionState(); 2612 2613 if (!rect.containsLabel && rect.vertices.length == graph.getSelectionCount() && 2614 rect.width != null && rect.height != null) 2615 { 2616 div.style.display = ''; 2617 2618 if (force || document.activeElement != width) 2619 { 2620 width.value = this.inUnit(rect.width) + ((rect.width == '') ? '' : ' ' + this.getUnit()); 2621 } 2622 2623 if (force || document.activeElement != height) 2624 { 2625 height.value = this.inUnit(rect.height) + ((rect.height == '') ? '' : ' ' + this.getUnit()); 2626 } 2627 } 2628 else 2629 { 2630 div.style.display = 'none'; 2631 } 2632 2633 if (rect.vertices.length == graph.getSelectionCount() && 2634 rect.x != null && rect.y != null) 2635 { 2636 div2.style.display = ''; 2637 2638 if (force || document.activeElement != left) 2639 { 2640 left.value = this.inUnit(rect.x) + ((rect.x == '') ? '' : ' ' + this.getUnit()); 2641 } 2642 2643 if (force || document.activeElement != top) 2644 { 2645 top.value = this.inUnit(rect.y) + ((rect.y == '') ? '' : ' ' + this.getUnit()); 2646 } 2647 } 2648 else 2649 { 2650 div2.style.display = 'none'; 2651 } 2652 }); 2653 2654 this.addKeyHandler(left, listener); 2655 this.addKeyHandler(top, listener); 2656 2657 model.addListener(mxEvent.CHANGE, listener); 2658 this.listeners.push({destroy: function() { model.removeListener(listener); }}); 2659 listener(); 2660 2661 leftUpdate = this.addGeometryHandler(left, function(geo, value) 2662 { 2663 value = panel.fromUnit(value); 2664 2665 if (geo.relative) 2666 { 2667 geo.offset.x = value; 2668 } 2669 else 2670 { 2671 geo.x = value; 2672 } 2673 }); 2674 topUpdate = this.addGeometryHandler(top, function(geo, value) 2675 { 2676 value = panel.fromUnit(value); 2677 2678 if (geo.relative) 2679 { 2680 geo.offset.y = value; 2681 } 2682 else 2683 { 2684 geo.y = value; 2685 } 2686 }); 2687 2688 if (rect.movable) 2689 { 2690 if (rect.edges.length == 0 && rect.vertices.length == 1 && 2691 model.isEdge(model.getParent(rect.vertices[0]))) 2692 { 2693 var geo = graph.getCellGeometry(rect.vertices[0]); 2694 2695 if (geo != null && geo.relative) 2696 { 2697 var btn = mxUtils.button(mxResources.get('center'), mxUtils.bind(this, function(evt) 2698 { 2699 model.beginUpdate(); 2700 try 2701 { 2702 geo = geo.clone(); 2703 geo.x = 0; 2704 geo.y = 0; 2705 geo.offset = new mxPoint(); 2706 model.setGeometry(rect.vertices[0], geo); 2707 } 2708 finally 2709 { 2710 model.endUpdate(); 2711 } 2712 })); 2713 2714 btn.setAttribute('title', mxResources.get('center')); 2715 btn.style.width = '210px'; 2716 btn.style.position = 'absolute'; 2717 mxUtils.br(div2); 2718 mxUtils.br(div2); 2719 div2.appendChild(btn); 2720 } 2721 } 2722 container.appendChild(div2); 2723 } 2724}; 2725 2726/** 2727 * 2728 */ 2729ArrangePanel.prototype.addGeometryHandler = function(input, fn) 2730{ 2731 var ui = this.editorUi; 2732 var graph = ui.editor.graph; 2733 var initialValue = null; 2734 var panel = this; 2735 2736 function update(evt) 2737 { 2738 if (input.value != '') 2739 { 2740 var value = parseFloat(input.value); 2741 2742 if (isNaN(value)) 2743 { 2744 input.value = initialValue + ' ' + panel.getUnit(); 2745 } 2746 else if (value != initialValue) 2747 { 2748 graph.getModel().beginUpdate(); 2749 try 2750 { 2751 var cells = panel.format.getSelectionState().cells; 2752 2753 for (var i = 0; i < cells.length; i++) 2754 { 2755 if (graph.getModel().isVertex(cells[i])) 2756 { 2757 var geo = graph.getCellGeometry(cells[i]); 2758 2759 if (geo != null) 2760 { 2761 geo = geo.clone(); 2762 2763 if (!fn(geo, value, cells[i])) 2764 { 2765 var state = graph.view.getState(cells[i]); 2766 2767 if (state != null && graph.isRecursiveVertexResize(state)) 2768 { 2769 graph.resizeChildCells(cells[i], geo); 2770 } 2771 2772 graph.getModel().setGeometry(cells[i], geo); 2773 graph.constrainChildCells(cells[i]); 2774 } 2775 } 2776 } 2777 } 2778 } 2779 finally 2780 { 2781 graph.getModel().endUpdate(); 2782 } 2783 2784 initialValue = value; 2785 input.value = value + ' ' + panel.getUnit(); 2786 } 2787 } 2788 2789 mxEvent.consume(evt); 2790 }; 2791 2792 mxEvent.addListener(input, 'blur', update); 2793 mxEvent.addListener(input, 'change', update); 2794 mxEvent.addListener(input, 'focus', function() 2795 { 2796 initialValue = input.value; 2797 }); 2798 2799 return update; 2800}; 2801 2802ArrangePanel.prototype.addEdgeGeometryHandler = function(input, fn) 2803{ 2804 var ui = this.editorUi; 2805 var graph = ui.editor.graph; 2806 var initialValue = null; 2807 var panel = this; 2808 2809 function update(evt) 2810 { 2811 if (input.value != '') 2812 { 2813 var value = parseFloat(input.value); 2814 2815 if (isNaN(value)) 2816 { 2817 input.value = initialValue + ' pt'; 2818 } 2819 else if (value != initialValue) 2820 { 2821 graph.getModel().beginUpdate(); 2822 try 2823 { 2824 var cells = panel.format.getSelectionState().cells; 2825 2826 for (var i = 0; i < cells.length; i++) 2827 { 2828 if (graph.getModel().isEdge(cells[i])) 2829 { 2830 var geo = graph.getCellGeometry(cells[i]); 2831 2832 if (geo != null) 2833 { 2834 geo = geo.clone(); 2835 fn(geo, value); 2836 2837 graph.getModel().setGeometry(cells[i], geo); 2838 } 2839 } 2840 } 2841 } 2842 finally 2843 { 2844 graph.getModel().endUpdate(); 2845 } 2846 2847 initialValue = value; 2848 input.value = value + ' pt'; 2849 } 2850 } 2851 2852 mxEvent.consume(evt); 2853 }; 2854 2855 mxEvent.addListener(input, 'blur', update); 2856 mxEvent.addListener(input, 'change', update); 2857 mxEvent.addListener(input, 'focus', function() 2858 { 2859 initialValue = input.value; 2860 }); 2861 2862 return update; 2863}; 2864 2865/** 2866 * 2867 */ 2868ArrangePanel.prototype.addEdgeGeometry = function(container) 2869{ 2870 var ui = this.editorUi; 2871 var graph = ui.editor.graph; 2872 var rect = this.format.getSelectionState(); 2873 var div = this.createPanel(); 2874 2875 var span = document.createElement('div'); 2876 span.style.position = 'absolute'; 2877 span.style.width = '70px'; 2878 span.style.marginTop = '0px'; 2879 span.style.fontWeight = 'bold'; 2880 mxUtils.write(span, mxResources.get('width')); 2881 div.appendChild(span); 2882 2883 var widthUpdate, xtUpdate, ytUpdate, xsUpdate, ysUpdate; 2884 var width = this.addUnitInput(div, 'pt', 12, 44, function() 2885 { 2886 widthUpdate.apply(this, arguments); 2887 }); 2888 2889 mxUtils.br(div); 2890 this.addKeyHandler(width, listener); 2891 2892 var widthUpdate = mxUtils.bind(this, function(evt) 2893 { 2894 // Maximum stroke width is 999 2895 var value = parseInt(width.value); 2896 value = Math.min(999, Math.max(1, (isNaN(value)) ? 1 : value)); 2897 2898 if (value != mxUtils.getValue(rect.style, 'width', mxCellRenderer.defaultShapes['flexArrow'].prototype.defaultWidth)) 2899 { 2900 var cells = this.format.getSelectionState().cells; 2901 graph.setCellStyles('width', value, cells); 2902 ui.fireEvent(new mxEventObject('styleChanged', 'keys', ['width'], 2903 'values', [value], 'cells', cells)); 2904 } 2905 2906 width.value = value + ' pt'; 2907 mxEvent.consume(evt); 2908 }); 2909 2910 mxEvent.addListener(width, 'blur', widthUpdate); 2911 mxEvent.addListener(width, 'change', widthUpdate); 2912 2913 container.appendChild(div); 2914 2915 var divs = this.createPanel(); 2916 divs.style.paddingBottom = '30px'; 2917 2918 var span = document.createElement('div'); 2919 span.style.position = 'absolute'; 2920 span.style.width = '70px'; 2921 span.style.marginTop = '0px'; 2922 mxUtils.write(span, mxResources.get('linestart')); 2923 divs.appendChild(span); 2924 2925 var xs = this.addUnitInput(divs, 'pt', 87, 52, function() 2926 { 2927 xsUpdate.apply(this, arguments); 2928 }); 2929 var ys = this.addUnitInput(divs, 'pt', 16, 52, function() 2930 { 2931 ysUpdate.apply(this, arguments); 2932 }); 2933 2934 mxUtils.br(divs); 2935 this.addLabel(divs, mxResources.get('left'), 87); 2936 this.addLabel(divs, mxResources.get('top'), 16); 2937 container.appendChild(divs); 2938 this.addKeyHandler(xs, listener); 2939 this.addKeyHandler(ys, listener); 2940 2941 var divt = this.createPanel(); 2942 divt.style.paddingBottom = '30px'; 2943 2944 var span = document.createElement('div'); 2945 span.style.position = 'absolute'; 2946 span.style.width = '70px'; 2947 span.style.marginTop = '0px'; 2948 mxUtils.write(span, mxResources.get('lineend')); 2949 divt.appendChild(span); 2950 2951 var xt = this.addUnitInput(divt, 'pt', 87, 52, function() 2952 { 2953 xtUpdate.apply(this, arguments); 2954 }); 2955 var yt = this.addUnitInput(divt, 'pt', 16, 52, function() 2956 { 2957 ytUpdate.apply(this, arguments); 2958 }); 2959 2960 mxUtils.br(divt); 2961 this.addLabel(divt, mxResources.get('left'), 87); 2962 this.addLabel(divt, mxResources.get('top'), 16); 2963 container.appendChild(divt); 2964 this.addKeyHandler(xt, listener); 2965 this.addKeyHandler(yt, listener); 2966 2967 var listener = mxUtils.bind(this, function(sender, evt, force) 2968 { 2969 rect = this.format.getSelectionState(); 2970 var cell = rect.cells[0]; 2971 2972 if (rect.style.shape == 'link' || rect.style.shape == 'flexArrow') 2973 { 2974 div.style.display = ''; 2975 2976 if (force || document.activeElement != width) 2977 { 2978 var value = mxUtils.getValue(rect.style, 'width', 2979 mxCellRenderer.defaultShapes['flexArrow'].prototype.defaultWidth); 2980 width.value = value + ' pt'; 2981 } 2982 } 2983 else 2984 { 2985 div.style.display = 'none'; 2986 } 2987 2988 if (rect.cells.length == 1 && graph.model.isEdge(cell)) 2989 { 2990 var geo = graph.model.getGeometry(cell); 2991 2992 if (geo.sourcePoint != null && graph.model.getTerminal(cell, true) == null) 2993 { 2994 xs.value = geo.sourcePoint.x; 2995 ys.value = geo.sourcePoint.y; 2996 } 2997 else 2998 { 2999 divs.style.display = 'none'; 3000 } 3001 3002 if (geo.targetPoint != null && graph.model.getTerminal(cell, false) == null) 3003 { 3004 xt.value = geo.targetPoint.x; 3005 yt.value = geo.targetPoint.y; 3006 } 3007 else 3008 { 3009 divt.style.display = 'none'; 3010 } 3011 } 3012 else 3013 { 3014 divs.style.display = 'none'; 3015 divt.style.display = 'none'; 3016 } 3017 }); 3018 3019 xsUpdate = this.addEdgeGeometryHandler(xs, function(geo, value) 3020 { 3021 geo.sourcePoint.x = value; 3022 }); 3023 3024 ysUpdate = this.addEdgeGeometryHandler(ys, function(geo, value) 3025 { 3026 geo.sourcePoint.y = value; 3027 }); 3028 3029 xtUpdate = this.addEdgeGeometryHandler(xt, function(geo, value) 3030 { 3031 geo.targetPoint.x = value; 3032 }); 3033 3034 ytUpdate = this.addEdgeGeometryHandler(yt, function(geo, value) 3035 { 3036 geo.targetPoint.y = value; 3037 }); 3038 3039 graph.getModel().addListener(mxEvent.CHANGE, listener); 3040 this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }}); 3041 listener(); 3042}; 3043 3044/** 3045 * Adds the label menu items to the given menu and parent. 3046 */ 3047TextFormatPanel = function(format, editorUi, container) 3048{ 3049 BaseFormatPanel.call(this, format, editorUi, container); 3050 this.init(); 3051}; 3052 3053mxUtils.extend(TextFormatPanel, BaseFormatPanel); 3054 3055/** 3056 * Adds the label menu items to the given menu and parent. 3057 */ 3058TextFormatPanel.prototype.init = function() 3059{ 3060 this.container.style.borderBottom = 'none'; 3061 this.addFont(this.container); 3062}; 3063 3064/** 3065 * Adds the label menu items to the given menu and parent. 3066 */ 3067TextFormatPanel.prototype.addFont = function(container) 3068{ 3069 var ui = this.editorUi; 3070 var editor = ui.editor; 3071 var graph = editor.graph; 3072 var ss = this.format.getSelectionState(); 3073 3074 var title = this.createTitle(mxResources.get('font')); 3075 title.style.paddingLeft = '14px'; 3076 title.style.paddingTop = '10px'; 3077 title.style.paddingBottom = '6px'; 3078 container.appendChild(title); 3079 3080 var stylePanel = this.createPanel(); 3081 stylePanel.style.paddingTop = '2px'; 3082 stylePanel.style.paddingBottom = '2px'; 3083 stylePanel.style.position = 'relative'; 3084 stylePanel.style.marginLeft = '-2px'; 3085 stylePanel.style.borderWidth = '0px'; 3086 stylePanel.className = 'geToolbarContainer'; 3087 3088 if (graph.cellEditor.isContentEditing()) 3089 { 3090 var cssPanel = stylePanel.cloneNode(); 3091 3092 var cssMenu = this.editorUi.toolbar.addMenu(mxResources.get('style'), 3093 mxResources.get('style'), true, 'formatBlock', cssPanel, null, true); 3094 cssMenu.style.color = 'rgb(112, 112, 112)'; 3095 cssMenu.style.whiteSpace = 'nowrap'; 3096 cssMenu.style.overflow = 'hidden'; 3097 cssMenu.style.margin = '0px'; 3098 this.addArrow(cssMenu); 3099 cssMenu.style.width = '200px'; 3100 cssMenu.style.height = '15px'; 3101 3102 var arrow = cssMenu.getElementsByTagName('div')[0]; 3103 arrow.style.cssFloat = 'right'; 3104 container.appendChild(cssPanel); 3105 } 3106 3107 container.appendChild(stylePanel); 3108 3109 var colorPanel = this.createPanel(); 3110 colorPanel.style.marginTop = '8px'; 3111 colorPanel.style.borderTop = '1px solid #c0c0c0'; 3112 colorPanel.style.paddingTop = '6px'; 3113 colorPanel.style.paddingBottom = '6px'; 3114 3115 var fontMenu = this.editorUi.toolbar.addMenu('Helvetica', mxResources.get('fontFamily'), 3116 true, 'fontFamily', stylePanel, null, true); 3117 fontMenu.style.color = 'rgb(112, 112, 112)'; 3118 fontMenu.style.whiteSpace = 'nowrap'; 3119 fontMenu.style.overflow = 'hidden'; 3120 fontMenu.style.margin = '0px'; 3121 3122 this.addArrow(fontMenu); 3123 fontMenu.style.width = '200px'; 3124 fontMenu.style.height = '15px'; 3125 3126 var stylePanel2 = stylePanel.cloneNode(false); 3127 stylePanel2.style.marginLeft = '-3px'; 3128 var fontStyleItems = this.editorUi.toolbar.addItems(['bold', 'italic', 'underline'], stylePanel2, true); 3129 fontStyleItems[0].setAttribute('title', mxResources.get('bold') + ' (' + this.editorUi.actions.get('bold').shortcut + ')'); 3130 fontStyleItems[1].setAttribute('title', mxResources.get('italic') + ' (' + this.editorUi.actions.get('italic').shortcut + ')'); 3131 fontStyleItems[2].setAttribute('title', mxResources.get('underline') + ' (' + this.editorUi.actions.get('underline').shortcut + ')'); 3132 3133 var verticalItem = this.editorUi.toolbar.addItems(['vertical'], stylePanel2, true)[0]; 3134 3135 container.appendChild(stylePanel2); 3136 3137 this.styleButtons(fontStyleItems); 3138 this.styleButtons([verticalItem]); 3139 3140 var stylePanel3 = stylePanel.cloneNode(false); 3141 stylePanel3.style.marginLeft = '-3px'; 3142 stylePanel3.style.paddingBottom = '0px'; 3143 3144 // Helper function to return a wrapper function does not pass any arguments 3145 var callFn = function(fn) 3146 { 3147 return function() 3148 { 3149 return fn(); 3150 }; 3151 }; 3152 3153 var left = this.editorUi.toolbar.addButton('geSprite-left', mxResources.get('left'), 3154 (graph.cellEditor.isContentEditing()) ? 3155 function(evt) 3156 { 3157 graph.cellEditor.alignText(mxConstants.ALIGN_LEFT, evt); 3158 ui.fireEvent(new mxEventObject('styleChanged', 3159 'keys', [mxConstants.STYLE_ALIGN], 3160 'values', [mxConstants.ALIGN_LEFT], 3161 'cells', ss.cells)); 3162 } : callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_ALIGN], [mxConstants.ALIGN_LEFT])), stylePanel3); 3163 var center = this.editorUi.toolbar.addButton('geSprite-center', mxResources.get('center'), 3164 (graph.cellEditor.isContentEditing()) ? 3165 function(evt) 3166 { 3167 graph.cellEditor.alignText(mxConstants.ALIGN_CENTER, evt); 3168 ui.fireEvent(new mxEventObject('styleChanged', 3169 'keys', [mxConstants.STYLE_ALIGN], 3170 'values', [mxConstants.ALIGN_CENTER], 3171 'cells', ss.cells)); 3172 } : callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_ALIGN], [mxConstants.ALIGN_CENTER])), stylePanel3); 3173 var right = this.editorUi.toolbar.addButton('geSprite-right', mxResources.get('right'), 3174 (graph.cellEditor.isContentEditing()) ? 3175 function(evt) 3176 { 3177 graph.cellEditor.alignText(mxConstants.ALIGN_RIGHT, evt); 3178 ui.fireEvent(new mxEventObject('styleChanged', 3179 'keys', [mxConstants.STYLE_ALIGN], 3180 'values', [mxConstants.ALIGN_RIGHT], 3181 'cells', ss.cells)); 3182 } : callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_ALIGN], [mxConstants.ALIGN_RIGHT])), stylePanel3); 3183 3184 this.styleButtons([left, center, right]); 3185 3186 // Quick hack for strikethrough 3187 // TODO: Add translations and toggle state 3188 if (graph.cellEditor.isContentEditing()) 3189 { 3190 var strike = this.editorUi.toolbar.addButton('geSprite-removeformat', mxResources.get('strikethrough'), 3191 function() 3192 { 3193 document.execCommand('strikeThrough', false, null); 3194 }, stylePanel2); 3195 this.styleButtons([strike]); 3196 3197 strike.firstChild.style.background = 'url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PGRlZnM+PHBhdGggaWQ9ImEiIGQ9Ik0wIDBoMjR2MjRIMFYweiIvPjwvZGVmcz48Y2xpcFBhdGggaWQ9ImIiPjx1c2UgeGxpbms6aHJlZj0iI2EiIG92ZXJmbG93PSJ2aXNpYmxlIi8+PC9jbGlwUGF0aD48cGF0aCBjbGlwLXBhdGg9InVybCgjYikiIGZpbGw9IiMwMTAxMDEiIGQ9Ik03LjI0IDguNzVjLS4yNi0uNDgtLjM5LTEuMDMtLjM5LTEuNjcgMC0uNjEuMTMtMS4xNi40LTEuNjcuMjYtLjUuNjMtLjkzIDEuMTEtMS4yOS40OC0uMzUgMS4wNS0uNjMgMS43LS44My42Ni0uMTkgMS4zOS0uMjkgMi4xOC0uMjkuODEgMCAxLjU0LjExIDIuMjEuMzQuNjYuMjIgMS4yMy41NCAxLjY5Ljk0LjQ3LjQuODMuODggMS4wOCAxLjQzLjI1LjU1LjM4IDEuMTUuMzggMS44MWgtMy4wMWMwLS4zMS0uMDUtLjU5LS4xNS0uODUtLjA5LS4yNy0uMjQtLjQ5LS40NC0uNjgtLjItLjE5LS40NS0uMzMtLjc1LS40NC0uMy0uMS0uNjYtLjE2LTEuMDYtLjE2LS4zOSAwLS43NC4wNC0xLjAzLjEzLS4yOS4wOS0uNTMuMjEtLjcyLjM2LS4xOS4xNi0uMzQuMzQtLjQ0LjU1LS4xLjIxLS4xNS40My0uMTUuNjYgMCAuNDguMjUuODguNzQgMS4yMS4zOC4yNS43Ny40OCAxLjQxLjdINy4zOWMtLjA1LS4wOC0uMTEtLjE3LS4xNS0uMjV6TTIxIDEydi0ySDN2Mmg5LjYyYy4xOC4wNy40LjE0LjU1LjIuMzcuMTcuNjYuMzQuODcuNTEuMjEuMTcuMzUuMzYuNDMuNTcuMDcuMi4xMS40My4xMS42OSAwIC4yMy0uMDUuNDUtLjE0LjY2LS4wOS4yLS4yMy4zOC0uNDIuNTMtLjE5LjE1LS40Mi4yNi0uNzEuMzUtLjI5LjA4LS42My4xMy0xLjAxLjEzLS40MyAwLS44My0uMDQtMS4xOC0uMTNzLS42Ni0uMjMtLjkxLS40MmMtLjI1LS4xOS0uNDUtLjQ0LS41OS0uNzUtLjE0LS4zMS0uMjUtLjc2LS4yNS0xLjIxSDYuNGMwIC41NS4wOCAxLjEzLjI0IDEuNTguMTYuNDUuMzcuODUuNjUgMS4yMS4yOC4zNS42LjY2Ljk4LjkyLjM3LjI2Ljc4LjQ4IDEuMjIuNjUuNDQuMTcuOS4zIDEuMzguMzkuNDguMDguOTYuMTMgMS40NC4xMy44IDAgMS41My0uMDkgMi4xOC0uMjhzMS4yMS0uNDUgMS42Ny0uNzljLjQ2LS4zNC44Mi0uNzcgMS4wNy0xLjI3cy4zOC0xLjA3LjM4LTEuNzFjMC0uNi0uMS0xLjE0LS4zMS0xLjYxLS4wNS0uMTEtLjExLS4yMy0uMTctLjMzSDIxeiIvPjwvc3ZnPg==)'; 3198 strike.firstChild.style.backgroundPosition = '2px 2px'; 3199 strike.firstChild.style.backgroundSize = '18px 18px'; 3200 3201 this.styleButtons([strike]); 3202 } 3203 3204 var top = this.editorUi.toolbar.addButton('geSprite-top', mxResources.get('top'), 3205 callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_VERTICAL_ALIGN], 3206 [mxConstants.ALIGN_TOP])), stylePanel3); 3207 var middle = this.editorUi.toolbar.addButton('geSprite-middle', mxResources.get('middle'), 3208 callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_VERTICAL_ALIGN], 3209 [mxConstants.ALIGN_MIDDLE])), stylePanel3); 3210 var bottom = this.editorUi.toolbar.addButton('geSprite-bottom', mxResources.get('bottom'), 3211 callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_VERTICAL_ALIGN], 3212 [mxConstants.ALIGN_BOTTOM])), stylePanel3); 3213 3214 this.styleButtons([top, middle, bottom]); 3215 3216 container.appendChild(stylePanel3); 3217 3218 // Hack for updating UI state below based on current text selection 3219 // currentTable is the current selected DOM table updated below 3220 var sub, sup, full, tableWrapper, currentTable, tableCell, tableRow; 3221 3222 if (graph.cellEditor.isContentEditing()) 3223 { 3224 top.style.display = 'none'; 3225 middle.style.display = 'none'; 3226 bottom.style.display = 'none'; 3227 verticalItem.style.display = 'none'; 3228 3229 full = this.editorUi.toolbar.addButton('geSprite-justifyfull', mxResources.get('block'), 3230 function() 3231 { 3232 if (full.style.opacity == 1) 3233 { 3234 document.execCommand('justifyfull', false, null); 3235 } 3236 }, stylePanel3); 3237 full.style.marginRight = '9px'; 3238 full.style.opacity = 1; 3239 3240 this.styleButtons([full, 3241 sub = this.editorUi.toolbar.addButton('geSprite-subscript', 3242 mxResources.get('subscript') + ' (' + Editor.ctrlKey + '+,)', 3243 function() 3244 { 3245 document.execCommand('subscript', false, null); 3246 }, stylePanel3), sup = this.editorUi.toolbar.addButton('geSprite-superscript', 3247 mxResources.get('superscript') + ' (' + Editor.ctrlKey + '+.)', 3248 function() 3249 { 3250 document.execCommand('superscript', false, null); 3251 }, stylePanel3)]); 3252 sub.style.marginLeft = '10px'; 3253 3254 var tmp = stylePanel3.cloneNode(false); 3255 tmp.style.paddingTop = '4px'; 3256 var btns = [this.editorUi.toolbar.addButton('geSprite-orderedlist', mxResources.get('numberedList'), 3257 function() 3258 { 3259 document.execCommand('insertorderedlist', false, null); 3260 }, tmp), 3261 this.editorUi.toolbar.addButton('geSprite-unorderedlist', mxResources.get('bulletedList'), 3262 function() 3263 { 3264 document.execCommand('insertunorderedlist', false, null); 3265 }, tmp), 3266 this.editorUi.toolbar.addButton('geSprite-outdent', mxResources.get('decreaseIndent'), 3267 function() 3268 { 3269 document.execCommand('outdent', false, null); 3270 }, tmp), 3271 this.editorUi.toolbar.addButton('geSprite-indent', mxResources.get('increaseIndent'), 3272 function() 3273 { 3274 document.execCommand('indent', false, null); 3275 }, tmp), 3276 this.editorUi.toolbar.addButton('geSprite-removeformat', mxResources.get('removeFormat'), 3277 function() 3278 { 3279 document.execCommand('removeformat', false, null); 3280 }, tmp), 3281 this.editorUi.toolbar.addButton('geSprite-code', mxResources.get('html'), 3282 function() 3283 { 3284 graph.cellEditor.toggleViewMode(); 3285 }, tmp)]; 3286 this.styleButtons(btns); 3287 btns[btns.length - 2].style.marginLeft = '10px'; 3288 3289 container.appendChild(tmp); 3290 } 3291 else 3292 { 3293 fontStyleItems[2].style.marginRight = '12px'; 3294 right.style.marginRight = '12px'; 3295 } 3296 3297 // Label position 3298 var stylePanel4 = stylePanel.cloneNode(false); 3299 stylePanel4.style.marginLeft = '0px'; 3300 stylePanel4.style.paddingTop = '8px'; 3301 stylePanel4.style.paddingBottom = '4px'; 3302 stylePanel4.style.fontWeight = 'normal'; 3303 3304 mxUtils.write(stylePanel4, mxResources.get('position')); 3305 3306 // Adds label position options 3307 var positionSelect = document.createElement('select'); 3308 positionSelect.style.position = 'absolute'; 3309 positionSelect.style.left = '126px'; 3310 positionSelect.style.width = '98px'; 3311 positionSelect.style.border = '1px solid rgb(160, 160, 160)'; 3312 positionSelect.style.borderRadius = '4px'; 3313 positionSelect.style.marginTop = '-2px'; 3314 3315 var directions = ['topLeft', 'top', 'topRight', 'left', 'center', 'right', 'bottomLeft', 'bottom', 'bottomRight']; 3316 var lset = {'topLeft': [mxConstants.ALIGN_LEFT, mxConstants.ALIGN_TOP, mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_BOTTOM], 3317 'top': [mxConstants.ALIGN_CENTER, mxConstants.ALIGN_TOP, mxConstants.ALIGN_CENTER, mxConstants.ALIGN_BOTTOM], 3318 'topRight': [mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_TOP, mxConstants.ALIGN_LEFT, mxConstants.ALIGN_BOTTOM], 3319 'left': [mxConstants.ALIGN_LEFT, mxConstants.ALIGN_MIDDLE, mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_MIDDLE], 3320 'center': [mxConstants.ALIGN_CENTER, mxConstants.ALIGN_MIDDLE, mxConstants.ALIGN_CENTER, mxConstants.ALIGN_MIDDLE], 3321 'right': [mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_MIDDLE, mxConstants.ALIGN_LEFT, mxConstants.ALIGN_MIDDLE], 3322 'bottomLeft': [mxConstants.ALIGN_LEFT, mxConstants.ALIGN_BOTTOM, mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_TOP], 3323 'bottom': [mxConstants.ALIGN_CENTER, mxConstants.ALIGN_BOTTOM, mxConstants.ALIGN_CENTER, mxConstants.ALIGN_TOP], 3324 'bottomRight': [mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_BOTTOM, mxConstants.ALIGN_LEFT, mxConstants.ALIGN_TOP]}; 3325 3326 for (var i = 0; i < directions.length; i++) 3327 { 3328 var positionOption = document.createElement('option'); 3329 positionOption.setAttribute('value', directions[i]); 3330 mxUtils.write(positionOption, mxResources.get(directions[i])); 3331 positionSelect.appendChild(positionOption); 3332 } 3333 3334 stylePanel4.appendChild(positionSelect); 3335 3336 // Writing direction 3337 var stylePanel5 = stylePanel.cloneNode(false); 3338 stylePanel5.style.marginLeft = '0px'; 3339 stylePanel5.style.paddingTop = '4px'; 3340 stylePanel5.style.paddingBottom = '4px'; 3341 stylePanel5.style.fontWeight = 'normal'; 3342 3343 mxUtils.write(stylePanel5, mxResources.get('writingDirection')); 3344 3345 // Adds writing direction options 3346 // LATER: Handle reselect of same option in all selects (change event 3347 // is not fired for same option so have opened state on click) and 3348 // handle multiple different styles for current selection 3349 var dirSelect = document.createElement('select'); 3350 dirSelect.style.position = 'absolute'; 3351 dirSelect.style.border = '1px solid rgb(160, 160, 160)'; 3352 dirSelect.style.left = '126px'; 3353 dirSelect.style.width = '98px'; 3354 dirSelect.style.borderRadius = '4px'; 3355 dirSelect.style.marginTop = '-2px'; 3356 3357 // NOTE: For automatic we use the value null since automatic 3358 // requires the text to be non formatted and non-wrapped 3359 var dirs = ['automatic', 'leftToRight', 'rightToLeft']; 3360 var dirSet = {'automatic': null, 3361 'leftToRight': mxConstants.TEXT_DIRECTION_LTR, 3362 'rightToLeft': mxConstants.TEXT_DIRECTION_RTL}; 3363 3364 for (var i = 0; i < dirs.length; i++) 3365 { 3366 var dirOption = document.createElement('option'); 3367 dirOption.setAttribute('value', dirs[i]); 3368 mxUtils.write(dirOption, mxResources.get(dirs[i])); 3369 dirSelect.appendChild(dirOption); 3370 } 3371 3372 stylePanel5.appendChild(dirSelect); 3373 3374 if (!graph.isEditing()) 3375 { 3376 container.appendChild(stylePanel4); 3377 3378 mxEvent.addListener(positionSelect, 'change', function(evt) 3379 { 3380 graph.getModel().beginUpdate(); 3381 try 3382 { 3383 var vals = lset[positionSelect.value]; 3384 3385 if (vals != null) 3386 { 3387 graph.setCellStyles(mxConstants.STYLE_LABEL_POSITION, vals[0], ss.cells); 3388 graph.setCellStyles(mxConstants.STYLE_VERTICAL_LABEL_POSITION, vals[1], ss.cells); 3389 graph.setCellStyles(mxConstants.STYLE_ALIGN, vals[2], ss.cells); 3390 graph.setCellStyles(mxConstants.STYLE_VERTICAL_ALIGN, vals[3], ss.cells); 3391 } 3392 } 3393 finally 3394 { 3395 graph.getModel().endUpdate(); 3396 } 3397 3398 mxEvent.consume(evt); 3399 }); 3400 3401 // LATER: Update dir in text editor while editing and update style with label 3402 // NOTE: The tricky part is handling and passing on the auto value 3403 container.appendChild(stylePanel5); 3404 3405 mxEvent.addListener(dirSelect, 'change', function(evt) 3406 { 3407 graph.setCellStyles(mxConstants.STYLE_TEXT_DIRECTION, dirSet[dirSelect.value], ss.cells); 3408 mxEvent.consume(evt); 3409 }); 3410 } 3411 3412 // Fontsize 3413 var input = document.createElement('input'); 3414 input.style.position = 'absolute'; 3415 input.style.border = '1px solid rgb(160, 160, 160)'; 3416 input.style.textAlign = 'right'; 3417 input.style.marginTop = '4px'; 3418 input.style.left = '161px'; 3419 input.style.width = '53px'; 3420 input.style.borderRadius = '4px'; 3421 input.style.height = '23px'; 3422 input.style.boxSizing = 'border-box'; 3423 stylePanel2.appendChild(input); 3424 3425 // Workaround for font size 4 if no text is selected is update font size below 3426 // after first character was entered (as the font element is lazy created) 3427 var pendingFontSize = null; 3428 3429 var inputUpdate = this.installInputHandler(input, mxConstants.STYLE_FONTSIZE, Menus.prototype.defaultFontSize, 1, 999, ' pt', 3430 function(fontSize) 3431 { 3432 // IE does not support containsNode 3433 // KNOWN: Fixes font size issues but bypasses undo 3434 if (window.getSelection && !mxClient.IS_IE && !mxClient.IS_IE11) 3435 { 3436 var selection = window.getSelection(); 3437 var container = (selection.rangeCount > 0) ? selection.getRangeAt(0).commonAncestorContainer : 3438 graph.cellEditor.textarea; 3439 3440 function updateSize(elt, ignoreContains) 3441 { 3442 if (graph.cellEditor.textarea != null && elt != graph.cellEditor.textarea && 3443 graph.cellEditor.textarea.contains(elt) && 3444 (ignoreContains || selection.containsNode(elt, true))) 3445 { 3446 if (elt.nodeName == 'FONT') 3447 { 3448 elt.removeAttribute('size'); 3449 elt.style.fontSize = fontSize + 'px'; 3450 } 3451 else 3452 { 3453 var css = mxUtils.getCurrentStyle(elt); 3454 3455 if (css.fontSize != fontSize + 'px') 3456 { 3457 if (mxUtils.getCurrentStyle(elt.parentNode).fontSize != fontSize + 'px') 3458 { 3459 elt.style.fontSize = fontSize + 'px'; 3460 } 3461 else 3462 { 3463 elt.style.fontSize = ''; 3464 } 3465 } 3466 } 3467 } 3468 3469 ui.fireEvent(new mxEventObject('styleChanged', 3470 'keys', [mxConstants.STYLE_FONTSIZE], 3471 'values', [fontSize], 'cells', ss.cells)); 3472 }; 3473 3474 // Wraps text node or mixed selection with leading text in a font element 3475 if (container == graph.cellEditor.textarea || 3476 container.nodeType != mxConstants.NODETYPE_ELEMENT) 3477 { 3478 document.execCommand('fontSize', false, '1'); 3479 } 3480 3481 if (container != graph.cellEditor.textarea) 3482 { 3483 container = container.parentNode; 3484 } 3485 3486 if (container != null && container.nodeType == mxConstants.NODETYPE_ELEMENT) 3487 { 3488 var elts = container.getElementsByTagName('*'); 3489 updateSize(container); 3490 3491 for (var i = 0; i < elts.length; i++) 3492 { 3493 updateSize(elts[i]); 3494 } 3495 } 3496 3497 input.value = fontSize + ' pt'; 3498 } 3499 else if (window.getSelection || document.selection) 3500 { 3501 // Checks selection 3502 var par = null; 3503 3504 if (document.selection) 3505 { 3506 par = document.selection.createRange().parentElement(); 3507 } 3508 else 3509 { 3510 var selection = window.getSelection(); 3511 3512 if (selection.rangeCount > 0) 3513 { 3514 par = selection.getRangeAt(0).commonAncestorContainer; 3515 } 3516 } 3517 3518 // Node.contains does not work for text nodes in IE11 3519 function isOrContains(container, node) 3520 { 3521 while (node != null) 3522 { 3523 if (node === container) 3524 { 3525 return true; 3526 } 3527 3528 node = node.parentNode; 3529 } 3530 3531 return false; 3532 }; 3533 3534 if (par != null && isOrContains(graph.cellEditor.textarea, par)) 3535 { 3536 pendingFontSize = fontSize; 3537 3538 // Workaround for can't set font size in px is to change font size afterwards 3539 document.execCommand('fontSize', false, '4'); 3540 var elts = graph.cellEditor.textarea.getElementsByTagName('font'); 3541 3542 for (var i = 0; i < elts.length; i++) 3543 { 3544 if (elts[i].getAttribute('size') == '4') 3545 { 3546 elts[i].removeAttribute('size'); 3547 elts[i].style.fontSize = pendingFontSize + 'px'; 3548 3549 // Overrides fontSize in input with the one just assigned as a workaround 3550 // for potential fontSize values of parent elements that don't match 3551 window.setTimeout(function() 3552 { 3553 input.value = pendingFontSize + ' pt'; 3554 pendingFontSize = null; 3555 }, 0); 3556 3557 break; 3558 } 3559 } 3560 } 3561 } 3562 }, true); 3563 3564 var stepper = this.createStepper(input, inputUpdate, 1, 10, true, Menus.prototype.defaultFontSize); 3565 stepper.style.display = input.style.display; 3566 stepper.style.marginTop = '4px'; 3567 stepper.style.left = '214px'; 3568 3569 stylePanel2.appendChild(stepper); 3570 3571 var arrow = fontMenu.getElementsByTagName('div')[0]; 3572 arrow.style.cssFloat = 'right'; 3573 3574 var bgColorApply = null; 3575 var currentBgColor = '#ffffff'; 3576 3577 var fontColorApply = null; 3578 var currentFontColor = '#000000'; 3579 3580 var bgPanel = (graph.cellEditor.isContentEditing()) ? this.createColorOption(mxResources.get('backgroundColor'), function() 3581 { 3582 return currentBgColor; 3583 }, function(color) 3584 { 3585 document.execCommand('backcolor', false, (color != mxConstants.NONE) ? color : 'transparent'); 3586 ui.fireEvent(new mxEventObject('styleChanged', 3587 'keys', [mxConstants.STYLE_LABEL_BACKGROUNDCOLOR], 3588 'values', [color], 'cells', ss.cells)); 3589 }, '#ffffff', 3590 { 3591 install: function(apply) { bgColorApply = apply; }, 3592 destroy: function() { bgColorApply = null; } 3593 }, null, true) : this.createCellColorOption(mxResources.get('backgroundColor'), 3594 mxConstants.STYLE_LABEL_BACKGROUNDCOLOR, 'default', null, function(color) 3595 { 3596 graph.updateLabelElements(ss.cells, function(elt) 3597 { 3598 elt.style.backgroundColor = null; 3599 }); 3600 }, graph.shapeBackgroundColor); 3601 bgPanel.style.fontWeight = 'bold'; 3602 3603 var borderPanel = this.createCellColorOption(mxResources.get('borderColor'), 3604 mxConstants.STYLE_LABEL_BORDERCOLOR, 'default', null, null, 3605 graph.shapeForegroundColor); 3606 borderPanel.style.fontWeight = 'bold'; 3607 3608 var defs = (ss.vertices.length >= 1) ? graph.stylesheet.getDefaultVertexStyle() : graph.stylesheet.getDefaultEdgeStyle(); 3609 var panel = (graph.cellEditor.isContentEditing()) ? this.createColorOption(mxResources.get('fontColor'), function() 3610 { 3611 return currentFontColor; 3612 }, function(color) 3613 { 3614 if (mxClient.IS_FF) 3615 { 3616 // Workaround for Firefox that adds the font element around 3617 // anchor elements which ignore inherited colors is to move 3618 // the font element inside anchor elements 3619 var tmp = graph.cellEditor.textarea.getElementsByTagName('font'); 3620 var oldFonts = []; 3621 3622 for (var i = 0; i < tmp.length; i++) 3623 { 3624 oldFonts.push( 3625 { 3626 node: tmp[i], 3627 color: tmp[i].getAttribute('color') 3628 }); 3629 } 3630 3631 document.execCommand('forecolor', false, (color != mxConstants.NONE) ? 3632 color : 'transparent'); 3633 ui.fireEvent(new mxEventObject('styleChanged', 3634 'keys', [mxConstants.STYLE_FONTCOLOR], 3635 'values', [color], 'cells', ss.cells)); 3636 3637 // Finds the new or changed font element 3638 var newFonts = graph.cellEditor.textarea.getElementsByTagName('font'); 3639 3640 for (var i = 0; i < newFonts.length; i++) 3641 { 3642 if (i >= oldFonts.length || newFonts[i] != oldFonts[i].node || 3643 (newFonts[i] == oldFonts[i].node && 3644 newFonts[i].getAttribute('color') != oldFonts[i].color)) 3645 { 3646 var child = newFonts[i].firstChild; 3647 3648 // Moves the font element to inside the anchor element and adopts all children 3649 if (child != null && child.nodeName == 'A' && child.nextSibling == 3650 null && 3651 child.firstChild != null) 3652 { 3653 var parent = newFonts[i].parentNode; 3654 parent.insertBefore(child, newFonts[i]); 3655 var tmp = child.firstChild; 3656 3657 while (tmp != null) 3658 { 3659 var next = tmp.nextSibling; 3660 newFonts[i].appendChild(tmp); 3661 tmp = next; 3662 } 3663 3664 child.appendChild(newFonts[i]); 3665 } 3666 3667 break; 3668 } 3669 } 3670 } 3671 else 3672 { 3673 document.execCommand('forecolor', false, (color != mxConstants.NONE) ? 3674 color : 'transparent'); 3675 ui.fireEvent(new mxEventObject('styleChanged', 3676 'keys', [mxConstants.STYLE_FONTCOLOR], 3677 'values', [color], 'cells', ss.cells)); 3678 } 3679 }, (defs[mxConstants.STYLE_FONTCOLOR] != null) ? defs[mxConstants.STYLE_FONTCOLOR] : '#000000', 3680 { 3681 install: function(apply) { fontColorApply = apply; }, 3682 destroy: function() { fontColorApply = null; } 3683 }, null, true) : this.createCellColorOption(mxResources.get('fontColor'), 3684 mxConstants.STYLE_FONTCOLOR, 'default', function(color) 3685 { 3686 if (color == mxConstants.NONE) 3687 { 3688 bgPanel.style.display = 'none'; 3689 } 3690 else 3691 { 3692 bgPanel.style.display = ''; 3693 } 3694 3695 borderPanel.style.display = bgPanel.style.display; 3696 }, function(color) 3697 { 3698 if (color == mxConstants.NONE) 3699 { 3700 graph.setCellStyles(mxConstants.STYLE_NOLABEL, '1', ss.cells); 3701 } 3702 else 3703 { 3704 graph.setCellStyles(mxConstants.STYLE_NOLABEL, null, ss.cells); 3705 } 3706 3707 graph.setCellStyles(mxConstants.STYLE_FONTCOLOR, color, ss.cells); 3708 3709 graph.updateLabelElements(ss.cells, function(elt) 3710 { 3711 elt.removeAttribute('color'); 3712 elt.style.color = null; 3713 }); 3714 }, graph.shapeForegroundColor); 3715 panel.style.fontWeight = 'bold'; 3716 3717 colorPanel.appendChild(panel); 3718 colorPanel.appendChild(bgPanel); 3719 3720 if (!graph.cellEditor.isContentEditing()) 3721 { 3722 colorPanel.appendChild(borderPanel); 3723 } 3724 3725 container.appendChild(colorPanel); 3726 3727 var extraPanel = this.createPanel(); 3728 extraPanel.style.paddingTop = '2px'; 3729 extraPanel.style.paddingBottom = '4px'; 3730 3731 var wwCells = graph.filterSelectionCells(mxUtils.bind(this, function(cell) 3732 { 3733 var state = graph.view.getState(cell); 3734 3735 return state == null || 3736 this.format.isAutoSizeState(state) || 3737 graph.getModel().isEdge(cell) || 3738 (!graph.isTableRow(cell) && 3739 !graph.isTableCell(cell) && 3740 !graph.isCellResizable(cell)); 3741 })); 3742 3743 var wwOpt = this.createCellOption(mxResources.get('wordWrap'), mxConstants.STYLE_WHITE_SPACE, 3744 null, 'wrap', 'null', null, null, true, wwCells); 3745 wwOpt.style.fontWeight = 'bold'; 3746 3747 // Word wrap in edge labels only supported via labelWidth style 3748 if (wwCells.length > 0) 3749 { 3750 extraPanel.appendChild(wwOpt); 3751 } 3752 3753 // Delegates switch of style to formattedText action as it also convertes newlines 3754 var htmlOpt = this.createCellOption(mxResources.get('formattedText'), 'html', 0, 3755 null, null, null, ui.actions.get('formattedText')); 3756 htmlOpt.style.fontWeight = 'bold'; 3757 extraPanel.appendChild(htmlOpt); 3758 3759 var spacingPanel = this.createPanel(); 3760 spacingPanel.style.paddingTop = '10px'; 3761 spacingPanel.style.paddingBottom = '28px'; 3762 spacingPanel.style.fontWeight = 'normal'; 3763 3764 var span = document.createElement('div'); 3765 span.style.position = 'absolute'; 3766 span.style.width = '70px'; 3767 span.style.marginTop = '0px'; 3768 span.style.fontWeight = 'bold'; 3769 mxUtils.write(span, mxResources.get('spacing')); 3770 spacingPanel.appendChild(span); 3771 3772 var topUpdate, globalUpdate, leftUpdate, bottomUpdate, rightUpdate; 3773 var topSpacing = this.addUnitInput(spacingPanel, 'pt', 87, 52, function() 3774 { 3775 topUpdate.apply(this, arguments); 3776 }); 3777 var globalSpacing = this.addUnitInput(spacingPanel, 'pt', 16, 52, function() 3778 { 3779 globalUpdate.apply(this, arguments); 3780 }); 3781 3782 mxUtils.br(spacingPanel); 3783 this.addLabel(spacingPanel, mxResources.get('top'), 87); 3784 this.addLabel(spacingPanel, mxResources.get('global'), 16); 3785 mxUtils.br(spacingPanel); 3786 mxUtils.br(spacingPanel); 3787 3788 var leftSpacing = this.addUnitInput(spacingPanel, 'pt', 158, 52, function() 3789 { 3790 leftUpdate.apply(this, arguments); 3791 }); 3792 var bottomSpacing = this.addUnitInput(spacingPanel, 'pt', 87, 52, function() 3793 { 3794 bottomUpdate.apply(this, arguments); 3795 }); 3796 var rightSpacing = this.addUnitInput(spacingPanel, 'pt', 16, 52, function() 3797 { 3798 rightUpdate.apply(this, arguments); 3799 }); 3800 3801 mxUtils.br(spacingPanel); 3802 this.addLabel(spacingPanel, mxResources.get('left'), 158); 3803 this.addLabel(spacingPanel, mxResources.get('bottom'), 87); 3804 this.addLabel(spacingPanel, mxResources.get('right'), 16); 3805 3806 if (!graph.cellEditor.isContentEditing()) 3807 { 3808 container.appendChild(extraPanel); 3809 container.appendChild(this.createRelativeOption(mxResources.get('opacity'), mxConstants.STYLE_TEXT_OPACITY)); 3810 container.appendChild(spacingPanel); 3811 } 3812 else 3813 { 3814 var selState = null; 3815 var lineHeightInput = null; 3816 3817 container.appendChild(this.createRelativeOption(mxResources.get('lineheight'), null, null, function(input) 3818 { 3819 var value = (input.value == '') ? 120 : parseInt(input.value); 3820 value = Math.max(0, (isNaN(value)) ? 120 : value); 3821 3822 if (selState != null) 3823 { 3824 graph.cellEditor.restoreSelection(selState); 3825 selState = null; 3826 } 3827 3828 var selectedElement = graph.getSelectedElement(); 3829 var node = selectedElement; 3830 3831 while (node != null && node.nodeType != mxConstants.NODETYPE_ELEMENT) 3832 { 3833 node = node.parentNode; 3834 } 3835 3836 if (node != null && node == graph.cellEditor.textarea && graph.cellEditor.textarea.firstChild != null) 3837 { 3838 if (graph.cellEditor.textarea.firstChild.nodeName != 'P') 3839 { 3840 graph.cellEditor.textarea.innerHTML = '<p>' + graph.cellEditor.textarea.innerHTML + '</p>'; 3841 } 3842 3843 node = graph.cellEditor.textarea.firstChild; 3844 } 3845 3846 if (node != null && graph.cellEditor.textarea != null && node != graph.cellEditor.textarea && 3847 graph.cellEditor.textarea.contains(node)) 3848 { 3849 node.style.lineHeight = value / 100; 3850 } 3851 3852 input.value = value + ' %'; 3853 }, function(input) 3854 { 3855 // Used in CSS handler to update current value 3856 lineHeightInput = input; 3857 3858 // KNOWN: Arrow up/down clear selection text in quirks/IE 8 3859 // Text size via arrow button limits to 16 in IE11. Why? 3860 mxEvent.addListener(input, 'mousedown', function() 3861 { 3862 if (document.activeElement == graph.cellEditor.textarea) 3863 { 3864 selState = graph.cellEditor.saveSelection(); 3865 } 3866 }); 3867 3868 mxEvent.addListener(input, 'touchstart', function() 3869 { 3870 if (document.activeElement == graph.cellEditor.textarea) 3871 { 3872 selState = graph.cellEditor.saveSelection(); 3873 } 3874 }); 3875 3876 input.value = '120 %'; 3877 })); 3878 3879 var insertPanel = stylePanel.cloneNode(false); 3880 insertPanel.style.paddingLeft = '0px'; 3881 var insertBtns = this.editorUi.toolbar.addItems(['link', 'image'], insertPanel, true); 3882 3883 var btns = [ 3884 this.editorUi.toolbar.addButton('geSprite-horizontalrule', mxResources.get('insertHorizontalRule'), 3885 function() 3886 { 3887 document.execCommand('inserthorizontalrule', false); 3888 }, insertPanel), 3889 this.editorUi.toolbar.addMenuFunctionInContainer(insertPanel, 'geSprite-table', mxResources.get('table'), false, mxUtils.bind(this, function(menu) 3890 { 3891 this.editorUi.menus.addInsertTableItem(menu, null, null, false); 3892 }))]; 3893 this.styleButtons(insertBtns); 3894 this.styleButtons(btns); 3895 3896 var wrapper2 = this.createPanel(); 3897 wrapper2.style.paddingTop = '10px'; 3898 wrapper2.style.paddingBottom = '10px'; 3899 wrapper2.appendChild(this.createTitle(mxResources.get('insert'))); 3900 wrapper2.appendChild(insertPanel); 3901 container.appendChild(wrapper2); 3902 3903 var tablePanel = stylePanel.cloneNode(false); 3904 tablePanel.style.paddingLeft = '0px'; 3905 3906 var btns = [ 3907 this.editorUi.toolbar.addButton('geSprite-insertcolumnbefore', mxResources.get('insertColumnBefore'), 3908 mxUtils.bind(this, function() 3909 { 3910 try 3911 { 3912 if (currentTable != null) 3913 { 3914 graph.insertColumn(currentTable, (tableCell != null) ? tableCell.cellIndex : 0); 3915 } 3916 } 3917 catch (e) 3918 { 3919 this.editorUi.handleError(e); 3920 } 3921 }), tablePanel), 3922 this.editorUi.toolbar.addButton('geSprite-insertcolumnafter', mxResources.get('insertColumnAfter'), 3923 mxUtils.bind(this, function() 3924 { 3925 try 3926 { 3927 if (currentTable != null) 3928 { 3929 graph.insertColumn(currentTable, (tableCell != null) ? tableCell.cellIndex + 1 : -1); 3930 } 3931 } 3932 catch (e) 3933 { 3934 this.editorUi.handleError(e); 3935 } 3936 }), tablePanel), 3937 this.editorUi.toolbar.addButton('geSprite-deletecolumn', mxResources.get('deleteColumn'), 3938 mxUtils.bind(this, function() 3939 { 3940 try 3941 { 3942 if (currentTable != null && tableCell != null) 3943 { 3944 graph.deleteColumn(currentTable, tableCell.cellIndex); 3945 } 3946 } 3947 catch (e) 3948 { 3949 this.editorUi.handleError(e); 3950 } 3951 }), tablePanel), 3952 this.editorUi.toolbar.addButton('geSprite-insertrowbefore', mxResources.get('insertRowBefore'), 3953 mxUtils.bind(this, function() 3954 { 3955 try 3956 { 3957 if (currentTable != null && tableRow != null) 3958 { 3959 graph.insertRow(currentTable, tableRow.sectionRowIndex); 3960 } 3961 } 3962 catch (e) 3963 { 3964 this.editorUi.handleError(e); 3965 } 3966 }), tablePanel), 3967 this.editorUi.toolbar.addButton('geSprite-insertrowafter', mxResources.get('insertRowAfter'), 3968 mxUtils.bind(this, function() 3969 { 3970 try 3971 { 3972 if (currentTable != null && tableRow != null) 3973 { 3974 graph.insertRow(currentTable, tableRow.sectionRowIndex + 1); 3975 } 3976 } 3977 catch (e) 3978 { 3979 this.editorUi.handleError(e); 3980 } 3981 }), tablePanel), 3982 this.editorUi.toolbar.addButton('geSprite-deleterow', mxResources.get('deleteRow'), 3983 mxUtils.bind(this, function() 3984 { 3985 try 3986 { 3987 if (currentTable != null && tableRow != null) 3988 { 3989 graph.deleteRow(currentTable, tableRow.sectionRowIndex); 3990 } 3991 } 3992 catch (e) 3993 { 3994 this.editorUi.handleError(e); 3995 } 3996 }), tablePanel)]; 3997 this.styleButtons(btns); 3998 btns[2].style.marginRight = '10px'; 3999 4000 var wrapper3 = this.createPanel(); 4001 wrapper3.style.paddingTop = '10px'; 4002 wrapper3.style.paddingBottom = '10px'; 4003 wrapper3.appendChild(this.createTitle(mxResources.get('table'))); 4004 wrapper3.appendChild(tablePanel); 4005 4006 var tablePanel2 = stylePanel.cloneNode(false); 4007 tablePanel2.style.paddingLeft = '0px'; 4008 4009 var btns = [ 4010 this.editorUi.toolbar.addButton('geSprite-strokecolor', mxResources.get('borderColor'), 4011 mxUtils.bind(this, function(evt) 4012 { 4013 if (currentTable != null) 4014 { 4015 // Converts rgb(r,g,b) values 4016 var color = currentTable.style.borderColor.replace( 4017 /\brgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/g, 4018 function($0, $1, $2, $3) { 4019 return "#" + ("0"+Number($1).toString(16)).substr(-2) + ("0"+Number($2).toString(16)).substr(-2) + ("0"+Number($3).toString(16)).substr(-2); 4020 }); 4021 this.editorUi.pickColor(color, function(newColor) 4022 { 4023 var targetElt = (tableCell != null && (evt == null || !mxEvent.isShiftDown(evt))) ? tableCell : currentTable; 4024 4025 graph.processElements(targetElt, function(elt) 4026 { 4027 elt.style.border = null; 4028 }); 4029 4030 if (newColor == null || newColor == mxConstants.NONE) 4031 { 4032 targetElt.removeAttribute('border'); 4033 targetElt.style.border = ''; 4034 targetElt.style.borderCollapse = ''; 4035 } 4036 else 4037 { 4038 targetElt.setAttribute('border', '1'); 4039 targetElt.style.border = '1px solid ' + newColor; 4040 targetElt.style.borderCollapse = 'collapse'; 4041 } 4042 }); 4043 } 4044 }), tablePanel2), 4045 this.editorUi.toolbar.addButton('geSprite-fillcolor', mxResources.get('backgroundColor'), 4046 mxUtils.bind(this, function(evt) 4047 { 4048 // Converts rgb(r,g,b) values 4049 if (currentTable != null) 4050 { 4051 var color = currentTable.style.backgroundColor.replace( 4052 /\brgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/g, 4053 function($0, $1, $2, $3) { 4054 return "#" + ("0"+Number($1).toString(16)).substr(-2) + ("0"+Number($2).toString(16)).substr(-2) + ("0"+Number($3).toString(16)).substr(-2); 4055 }); 4056 this.editorUi.pickColor(color, function(newColor) 4057 { 4058 var targetElt = (tableCell != null && (evt == null || !mxEvent.isShiftDown(evt))) ? tableCell : currentTable; 4059 4060 graph.processElements(targetElt, function(elt) 4061 { 4062 elt.style.backgroundColor = null; 4063 }); 4064 4065 if (newColor == null || newColor == mxConstants.NONE) 4066 { 4067 targetElt.style.backgroundColor = ''; 4068 } 4069 else 4070 { 4071 targetElt.style.backgroundColor = newColor; 4072 } 4073 }); 4074 } 4075 }), tablePanel2), 4076 this.editorUi.toolbar.addButton('geSprite-fit', mxResources.get('spacing'), 4077 function() 4078 { 4079 if (currentTable != null) 4080 { 4081 var value = currentTable.getAttribute('cellPadding') || 0; 4082 4083 var dlg = new FilenameDialog(ui, value, mxResources.get('apply'), mxUtils.bind(this, function(newValue) 4084 { 4085 if (newValue != null && newValue.length > 0) 4086 { 4087 currentTable.setAttribute('cellPadding', newValue); 4088 } 4089 else 4090 { 4091 currentTable.removeAttribute('cellPadding'); 4092 } 4093 }), mxResources.get('spacing')); 4094 ui.showDialog(dlg.container, 300, 80, true, true); 4095 dlg.init(); 4096 } 4097 }, tablePanel2), 4098 this.editorUi.toolbar.addButton('geSprite-left', mxResources.get('left'), 4099 function() 4100 { 4101 if (currentTable != null) 4102 { 4103 currentTable.setAttribute('align', 'left'); 4104 } 4105 }, tablePanel2), 4106 this.editorUi.toolbar.addButton('geSprite-center', mxResources.get('center'), 4107 function() 4108 { 4109 if (currentTable != null) 4110 { 4111 currentTable.setAttribute('align', 'center'); 4112 } 4113 }, tablePanel2), 4114 this.editorUi.toolbar.addButton('geSprite-right', mxResources.get('right'), 4115 function() 4116 { 4117 if (currentTable != null) 4118 { 4119 currentTable.setAttribute('align', 'right'); 4120 } 4121 }, tablePanel2)]; 4122 this.styleButtons(btns); 4123 btns[2].style.marginRight = '10px'; 4124 4125 wrapper3.appendChild(tablePanel2); 4126 container.appendChild(wrapper3); 4127 4128 tableWrapper = wrapper3; 4129 } 4130 4131 function setSelected(elt, selected) 4132 { 4133 elt.style.backgroundImage = (selected) ? (Editor.isDarkMode() ? 4134 'linear-gradient(rgb(0 161 241) 0px, rgb(0, 97, 146) 100%)': 4135 'linear-gradient(#c5ecff 0px,#87d4fb 100%)') : ''; 4136 }; 4137 4138 var listener = mxUtils.bind(this, function(sender, evt, force) 4139 { 4140 ss = this.format.getSelectionState(); 4141 var fontStyle = mxUtils.getValue(ss.style, mxConstants.STYLE_FONTSTYLE, 0); 4142 setSelected(fontStyleItems[0], (fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD); 4143 setSelected(fontStyleItems[1], (fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC); 4144 setSelected(fontStyleItems[2], (fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE); 4145 fontMenu.firstChild.nodeValue = mxUtils.getValue(ss.style, mxConstants.STYLE_FONTFAMILY, Menus.prototype.defaultFont); 4146 4147 setSelected(verticalItem, mxUtils.getValue(ss.style, mxConstants.STYLE_HORIZONTAL, '1') == '0'); 4148 4149 if (force || document.activeElement != input) 4150 { 4151 var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_FONTSIZE, Menus.prototype.defaultFontSize)); 4152 input.value = (isNaN(tmp)) ? '' : tmp + ' pt'; 4153 } 4154 4155 var align = mxUtils.getValue(ss.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER); 4156 setSelected(left, align == mxConstants.ALIGN_LEFT); 4157 setSelected(center, align == mxConstants.ALIGN_CENTER); 4158 setSelected(right, align == mxConstants.ALIGN_RIGHT); 4159 4160 var valign = mxUtils.getValue(ss.style, mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE); 4161 setSelected(top, valign == mxConstants.ALIGN_TOP); 4162 setSelected(middle, valign == mxConstants.ALIGN_MIDDLE); 4163 setSelected(bottom, valign == mxConstants.ALIGN_BOTTOM); 4164 4165 var pos = mxUtils.getValue(ss.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER); 4166 var vpos = mxUtils.getValue(ss.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE); 4167 4168 if (pos == mxConstants.ALIGN_LEFT && vpos == mxConstants.ALIGN_TOP) 4169 { 4170 positionSelect.value = 'topLeft'; 4171 } 4172 else if (pos == mxConstants.ALIGN_CENTER && vpos == mxConstants.ALIGN_TOP) 4173 { 4174 positionSelect.value = 'top'; 4175 } 4176 else if (pos == mxConstants.ALIGN_RIGHT && vpos == mxConstants.ALIGN_TOP) 4177 { 4178 positionSelect.value = 'topRight'; 4179 } 4180 else if (pos == mxConstants.ALIGN_LEFT && vpos == mxConstants.ALIGN_BOTTOM) 4181 { 4182 positionSelect.value = 'bottomLeft'; 4183 } 4184 else if (pos == mxConstants.ALIGN_CENTER && vpos == mxConstants.ALIGN_BOTTOM) 4185 { 4186 positionSelect.value = 'bottom'; 4187 } 4188 else if (pos == mxConstants.ALIGN_RIGHT && vpos == mxConstants.ALIGN_BOTTOM) 4189 { 4190 positionSelect.value = 'bottomRight'; 4191 } 4192 else if (pos == mxConstants.ALIGN_LEFT) 4193 { 4194 positionSelect.value = 'left'; 4195 } 4196 else if (pos == mxConstants.ALIGN_RIGHT) 4197 { 4198 positionSelect.value = 'right'; 4199 } 4200 else 4201 { 4202 positionSelect.value = 'center'; 4203 } 4204 4205 var dir = mxUtils.getValue(ss.style, mxConstants.STYLE_TEXT_DIRECTION, mxConstants.DEFAULT_TEXT_DIRECTION); 4206 4207 if (dir == mxConstants.TEXT_DIRECTION_RTL) 4208 { 4209 dirSelect.value = 'rightToLeft'; 4210 } 4211 else if (dir == mxConstants.TEXT_DIRECTION_LTR) 4212 { 4213 dirSelect.value = 'leftToRight'; 4214 } 4215 else if (dir == mxConstants.TEXT_DIRECTION_AUTO) 4216 { 4217 dirSelect.value = 'automatic'; 4218 } 4219 4220 if (force || document.activeElement != globalSpacing) 4221 { 4222 var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING, 2)); 4223 globalSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt'; 4224 } 4225 4226 if (force || document.activeElement != topSpacing) 4227 { 4228 var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_TOP, 0)); 4229 topSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt'; 4230 } 4231 4232 if (force || document.activeElement != rightSpacing) 4233 { 4234 var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_RIGHT, 0)); 4235 rightSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt'; 4236 } 4237 4238 if (force || document.activeElement != bottomSpacing) 4239 { 4240 var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_BOTTOM, 0)); 4241 bottomSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt'; 4242 } 4243 4244 if (force || document.activeElement != leftSpacing) 4245 { 4246 var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_LEFT, 0)); 4247 leftSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt'; 4248 } 4249 }); 4250 4251 globalUpdate = this.installInputHandler(globalSpacing, mxConstants.STYLE_SPACING, 2, -999, 999, ' pt'); 4252 topUpdate = this.installInputHandler(topSpacing, mxConstants.STYLE_SPACING_TOP, 0, -999, 999, ' pt'); 4253 rightUpdate = this.installInputHandler(rightSpacing, mxConstants.STYLE_SPACING_RIGHT, 0, -999, 999, ' pt'); 4254 bottomUpdate = this.installInputHandler(bottomSpacing, mxConstants.STYLE_SPACING_BOTTOM, 0, -999, 999, ' pt'); 4255 leftUpdate = this.installInputHandler(leftSpacing, mxConstants.STYLE_SPACING_LEFT, 0, -999, 999, ' pt'); 4256 4257 this.addKeyHandler(input, listener); 4258 this.addKeyHandler(globalSpacing, listener); 4259 this.addKeyHandler(topSpacing, listener); 4260 this.addKeyHandler(rightSpacing, listener); 4261 this.addKeyHandler(bottomSpacing, listener); 4262 this.addKeyHandler(leftSpacing, listener); 4263 4264 graph.getModel().addListener(mxEvent.CHANGE, listener); 4265 this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }}); 4266 listener(); 4267 4268 if (graph.cellEditor.isContentEditing()) 4269 { 4270 var updating = false; 4271 4272 var updateCssHandler = function() 4273 { 4274 if (!updating) 4275 { 4276 updating = true; 4277 4278 window.setTimeout(function() 4279 { 4280 var node = graph.getSelectedEditingElement(); 4281 4282 if (node != null) 4283 { 4284 function getRelativeLineHeight(fontSize, css, elt) 4285 { 4286 if (elt.style != null && css != null) 4287 { 4288 var lineHeight = css.lineHeight 4289 4290 if (elt.style.lineHeight != null && elt.style.lineHeight.substring(elt.style.lineHeight.length - 1) == '%') 4291 { 4292 return parseInt(elt.style.lineHeight) / 100; 4293 } 4294 else 4295 { 4296 return (lineHeight.substring(lineHeight.length - 2) == 'px') ? 4297 parseFloat(lineHeight) / fontSize : parseInt(lineHeight); 4298 } 4299 } 4300 else 4301 { 4302 return ''; 4303 } 4304 }; 4305 4306 function getAbsoluteFontSize(css) 4307 { 4308 var fontSize = (css != null) ? css.fontSize : null; 4309 4310 if (fontSize != null && fontSize.substring(fontSize.length - 2) == 'px') 4311 { 4312 return parseFloat(fontSize); 4313 } 4314 else 4315 { 4316 return mxConstants.DEFAULT_FONTSIZE; 4317 } 4318 }; 4319 4320 var css = mxUtils.getCurrentStyle(node); 4321 var fontSize = getAbsoluteFontSize(css); 4322 var lineHeight = getRelativeLineHeight(fontSize, css, node); 4323 4324 // Finds common font size 4325 var elts = node.getElementsByTagName('*'); 4326 4327 // IE does not support containsNode 4328 if (elts.length > 0 && window.getSelection && !mxClient.IS_IE && !mxClient.IS_IE11) 4329 { 4330 var selection = window.getSelection(); 4331 4332 for (var i = 0; i < elts.length; i++) 4333 { 4334 if (selection.containsNode(elts[i], true)) 4335 { 4336 temp = mxUtils.getCurrentStyle(elts[i]); 4337 fontSize = Math.max(getAbsoluteFontSize(temp), fontSize); 4338 var lh = getRelativeLineHeight(fontSize, temp, elts[i]); 4339 4340 if (lh != lineHeight || isNaN(lh)) 4341 { 4342 lineHeight = ''; 4343 } 4344 } 4345 } 4346 } 4347 4348 function hasParentOrOnlyChild(name) 4349 { 4350 if (graph.getParentByName(node, name, graph.cellEditor.textarea) != null) 4351 { 4352 return true; 4353 } 4354 else 4355 { 4356 var child = node; 4357 4358 while (child != null && child.childNodes.length == 1) 4359 { 4360 child = child.childNodes[0]; 4361 4362 if (child.nodeName == name) 4363 { 4364 return true; 4365 } 4366 } 4367 } 4368 4369 return false; 4370 }; 4371 4372 function isEqualOrPrefixed(str, value) 4373 { 4374 if (str != null && value != null) 4375 { 4376 if (str == value) 4377 { 4378 return true; 4379 } 4380 else if (str.length > value.length + 1) 4381 { 4382 return str.substring(str.length - value.length - 1, str.length) == '-' + value; 4383 } 4384 } 4385 4386 return false; 4387 }; 4388 4389 if (css != null) 4390 { 4391 setSelected(fontStyleItems[0], css.fontWeight == 'bold' || 4392 css.fontWeight > 400 || hasParentOrOnlyChild('B') || 4393 hasParentOrOnlyChild('STRONG')); 4394 setSelected(fontStyleItems[1], css.fontStyle == 'italic' || 4395 hasParentOrOnlyChild('I') || hasParentOrOnlyChild('EM')); 4396 setSelected(fontStyleItems[2], hasParentOrOnlyChild('U')); 4397 setSelected(sup, hasParentOrOnlyChild('SUP')); 4398 setSelected(sub, hasParentOrOnlyChild('SUB')); 4399 4400 if (!graph.cellEditor.isTableSelected()) 4401 { 4402 var align = graph.cellEditor.align || mxUtils.getValue(ss.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER); 4403 4404 if (isEqualOrPrefixed(css.textAlign, 'justify')) 4405 { 4406 setSelected(full, isEqualOrPrefixed(css.textAlign, 'justify')); 4407 setSelected(left, false); 4408 setSelected(center, false); 4409 setSelected(right, false); 4410 } 4411 else 4412 { 4413 setSelected(full, false); 4414 setSelected(left, align == mxConstants.ALIGN_LEFT); 4415 setSelected(center, align == mxConstants.ALIGN_CENTER); 4416 setSelected(right, align == mxConstants.ALIGN_RIGHT); 4417 } 4418 } 4419 else 4420 { 4421 setSelected(full, isEqualOrPrefixed(css.textAlign, 'justify')); 4422 setSelected(left, isEqualOrPrefixed(css.textAlign, 'left')); 4423 setSelected(center, isEqualOrPrefixed(css.textAlign, 'center')); 4424 setSelected(right, isEqualOrPrefixed(css.textAlign, 'right')); 4425 } 4426 4427 currentTable = graph.getParentByName(node, 'TABLE', graph.cellEditor.textarea); 4428 tableRow = (currentTable == null) ? null : graph.getParentByName(node, 'TR', currentTable); 4429 tableCell = (currentTable == null) ? null : graph.getParentByNames(node, ['TD', 'TH'], currentTable); 4430 tableWrapper.style.display = (currentTable != null) ? '' : 'none'; 4431 4432 if (document.activeElement != input) 4433 { 4434 if (node.nodeName == 'FONT' && node.getAttribute('size') == '4' && 4435 pendingFontSize != null) 4436 { 4437 node.removeAttribute('size'); 4438 node.style.fontSize = pendingFontSize + ' pt'; 4439 pendingFontSize = null; 4440 } 4441 else 4442 { 4443 input.value = (isNaN(fontSize)) ? '' : fontSize + ' pt'; 4444 } 4445 4446 var lh = parseFloat(lineHeight); 4447 4448 if (!isNaN(lh)) 4449 { 4450 lineHeightInput.value = Math.round(lh * 100) + ' %'; 4451 } 4452 else 4453 { 4454 lineHeightInput.value = '100 %'; 4455 } 4456 } 4457 4458 // Converts rgb(r,g,b) values 4459 var color = css.color.replace( 4460 /\brgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d+)\s*)?\)/g, 4461 function($0, $1, $2, $3, $4) 4462 { 4463 return '#' + ('0' + Number($1).toString(16)).substr(-2) + 4464 ('0' + Number($2).toString(16)).substr(-2) + 4465 ('0' + Number($3).toString(16)).substr(-2) + (($4 != null) ? 4466 ('0' + Number($4).toString(16)).substr(-2) : ''); 4467 }); 4468 var color2 = css.backgroundColor.replace( 4469 /\brgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d+)\s*)?\)/g, 4470 function($0, $1, $2, $3, $4) 4471 { 4472 return '#' + ('0' + Number($1).toString(16)).substr(-2) + 4473 ('0' + Number($2).toString(16)).substr(-2) + 4474 ('0' + Number($3).toString(16)).substr(-2) + (($4 != null) ? 4475 ('0' + Number($4).toString(16)).substr(-2) : ''); 4476 }); 4477 4478 // Updates the color picker for the current font 4479 if (fontColorApply != null) 4480 { 4481 if (color.charAt(0) == '#') 4482 { 4483 currentFontColor = color; 4484 } 4485 else 4486 { 4487 currentFontColor = '#000000'; 4488 } 4489 4490 fontColorApply(currentFontColor, true); 4491 } 4492 4493 if (bgColorApply != null) 4494 { 4495 if (color2.charAt(0) == '#') 4496 { 4497 currentBgColor = color2; 4498 } 4499 else 4500 { 4501 currentBgColor = null; 4502 } 4503 4504 bgColorApply(currentBgColor, true); 4505 } 4506 4507 // Workaround for firstChild is null or not an object 4508 // in the log which seems to be IE8- only / 29.01.15 4509 if (fontMenu.firstChild != null) 4510 { 4511 fontMenu.firstChild.nodeValue = Graph.stripQuotes(css.fontFamily); 4512 } 4513 } 4514 } 4515 4516 updating = false; 4517 }, 0); 4518 } 4519 }; 4520 4521 if (mxClient.IS_FF || mxClient.IS_EDGE || mxClient.IS_IE || mxClient.IS_IE11) 4522 { 4523 mxEvent.addListener(graph.cellEditor.textarea, 'DOMSubtreeModified', updateCssHandler); 4524 } 4525 4526 mxEvent.addListener(graph.cellEditor.textarea, 'input', updateCssHandler); 4527 mxEvent.addListener(graph.cellEditor.textarea, 'touchend', updateCssHandler); 4528 mxEvent.addListener(graph.cellEditor.textarea, 'mouseup', updateCssHandler); 4529 mxEvent.addListener(graph.cellEditor.textarea, 'keyup', updateCssHandler); 4530 this.listeners.push({destroy: function() 4531 { 4532 // No need to remove listener since textarea is destroyed after edit 4533 }}); 4534 updateCssHandler(); 4535 } 4536 4537 return container; 4538}; 4539 4540/** 4541 * Adds the label menu items to the given menu and parent. 4542 */ 4543StyleFormatPanel = function(format, editorUi, container) 4544{ 4545 BaseFormatPanel.call(this, format, editorUi, container); 4546 this.init(); 4547}; 4548 4549mxUtils.extend(StyleFormatPanel, BaseFormatPanel); 4550 4551/** 4552 * 4553 */ 4554StyleFormatPanel.prototype.defaultStrokeColor = 'black'; 4555 4556/** 4557 * Adds the label menu items to the given menu and parent. 4558 */ 4559StyleFormatPanel.prototype.init = function() 4560{ 4561 var ui = this.editorUi; 4562 var editor = ui.editor; 4563 var graph = editor.graph; 4564 var ss = this.format.getSelectionState(); 4565 4566 if (!ss.containsLabel && ss.cells.length > 0) 4567 { 4568 if (ss.containsImage && ss.vertices.length == 1 && ss.style.shape == 'image' && 4569 ss.style.image != null && ss.style.image.substring(0, 19) == 'data:image/svg+xml;') 4570 { 4571 this.container.appendChild(this.addSvgStyles(this.createPanel())); 4572 } 4573 4574 if (!ss.containsImage || ss.style.shape == 'image') 4575 { 4576 this.container.appendChild(this.addFill(this.createPanel())); 4577 } 4578 4579 this.container.appendChild(this.addStroke(this.createPanel())); 4580 this.container.appendChild(this.addLineJumps(this.createPanel())); 4581 var opacityPanel = this.createRelativeOption(mxResources.get('opacity'), mxConstants.STYLE_OPACITY); 4582 opacityPanel.style.paddingTop = '8px'; 4583 opacityPanel.style.paddingBottom = '8px'; 4584 this.container.appendChild(opacityPanel); 4585 this.container.appendChild(this.addEffects(this.createPanel())); 4586 } 4587 4588 var opsPanel = this.addEditOps(this.createPanel()); 4589 4590 if (opsPanel.firstChild != null) 4591 { 4592 mxUtils.br(opsPanel); 4593 } 4594 4595 this.container.appendChild(this.addStyleOps(opsPanel)); 4596}; 4597 4598/** 4599 * Use browser for parsing CSS. 4600 */ 4601StyleFormatPanel.prototype.getCssRules = function(css) 4602{ 4603 var doc = document.implementation.createHTMLDocument(''); 4604 var styleElement = document.createElement('style'); 4605 4606 mxUtils.setTextContent(styleElement, css); 4607 doc.body.appendChild(styleElement); 4608 4609 return styleElement.sheet.cssRules; 4610}; 4611 4612/** 4613 * Adds the label menu items to the given menu and parent. 4614 */ 4615StyleFormatPanel.prototype.addSvgStyles = function(container) 4616{ 4617 var ui = this.editorUi; 4618 var graph = ui.editor.graph; 4619 var ss = this.format.getSelectionState(); 4620 container.style.paddingTop = '6px'; 4621 container.style.paddingBottom = '6px'; 4622 container.style.fontWeight = 'bold'; 4623 container.style.display = 'none'; 4624 4625 try 4626 { 4627 var exp = ss.style.editableCssRules; 4628 4629 if (exp != null) 4630 { 4631 var regex = new RegExp(exp); 4632 4633 var data = ss.style.image.substring(ss.style.image.indexOf(',') + 1); 4634 var xml = (window.atob) ? atob(data) : Base64.decode(data, true); 4635 var svg = mxUtils.parseXml(xml); 4636 4637 if (svg != null) 4638 { 4639 var styles = svg.getElementsByTagName('style'); 4640 4641 for (var i = 0; i < styles.length; i++) 4642 { 4643 var rules = this.getCssRules(mxUtils.getTextContent(styles[i])); 4644 4645 for (var j = 0; j < rules.length; j++) 4646 { 4647 this.addSvgRule(container, rules[j], svg, styles[i], rules, j, regex); 4648 } 4649 } 4650 } 4651 } 4652 } 4653 catch (e) 4654 { 4655 // ignore 4656 } 4657 4658 return container; 4659}; 4660 4661/** 4662 * Adds the label menu items to the given menu and parent. 4663 */ 4664StyleFormatPanel.prototype.addSvgRule = function(container, rule, svg, styleElem, rules, ruleIndex, regex) 4665{ 4666 var ui = this.editorUi; 4667 var graph = ui.editor.graph; 4668 4669 if (regex.test(rule.selectorText)) 4670 { 4671 function rgb2hex(rgb) 4672 { 4673 rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i); 4674 4675 return (rgb && rgb.length === 4) ? "#" + 4676 ("0" + parseInt(rgb[1],10).toString(16)).slice(-2) + 4677 ("0" + parseInt(rgb[2],10).toString(16)).slice(-2) + 4678 ("0" + parseInt(rgb[3],10).toString(16)).slice(-2) : ''; 4679 }; 4680 4681 var addStyleRule = mxUtils.bind(this, function(rule, key, label) 4682 { 4683 var value = mxUtils.trim(rule.style[key]); 4684 4685 if (value != '' && value.substring(0, 4) != 'url(') 4686 { 4687 var option = this.createColorOption(label + ' ' + rule.selectorText, function() 4688 { 4689 return rgb2hex(value); 4690 }, mxUtils.bind(this, function(color) 4691 { 4692 rules[ruleIndex].style[key] = color; 4693 var cssTxt = ''; 4694 4695 for (var i = 0; i < rules.length; i++) 4696 { 4697 cssTxt += rules[i].cssText + ' '; 4698 } 4699 4700 styleElem.textContent = cssTxt; 4701 var xml = mxUtils.getXml(svg.documentElement); 4702 4703 graph.setCellStyles(mxConstants.STYLE_IMAGE, 'data:image/svg+xml,' + 4704 ((window.btoa) ? btoa(xml) : Base64.encode(xml, true)), 4705 this.format.getSelectionState().cells); 4706 }), '#ffffff', 4707 { 4708 install: function(apply) 4709 { 4710 // ignore 4711 }, 4712 destroy: function() 4713 { 4714 // ignore 4715 } 4716 }); 4717 4718 container.appendChild(option); 4719 4720 // Shows container if rules are added 4721 container.style.display = ''; 4722 } 4723 }); 4724 4725 addStyleRule(rule, 'fill', mxResources.get('fill')); 4726 addStyleRule(rule, 'stroke', mxResources.get('line')); 4727 addStyleRule(rule, 'stop-color', mxResources.get('gradient')); 4728 } 4729}; 4730 4731/** 4732 * Adds the label menu items to the given menu and parent. 4733 */ 4734StyleFormatPanel.prototype.addEditOps = function(div) 4735{ 4736 var ss = this.format.getSelectionState(); 4737 var btn = null; 4738 4739 if (ss.cells.length == 1) 4740 { 4741 btn = mxUtils.button(mxResources.get('editStyle'), mxUtils.bind(this, function(evt) 4742 { 4743 this.editorUi.actions.get('editStyle').funct(); 4744 })); 4745 4746 btn.setAttribute('title', mxResources.get('editStyle') + ' (' + this.editorUi.actions.get('editStyle').shortcut + ')'); 4747 btn.style.width = '210px'; 4748 btn.style.marginBottom = '2px'; 4749 4750 div.appendChild(btn); 4751 } 4752 4753 if (ss.image && ss.cells.length > 0) 4754 { 4755 var btn2 = mxUtils.button(mxResources.get('editImage'), mxUtils.bind(this, function(evt) 4756 { 4757 this.editorUi.actions.get('image').funct(); 4758 })); 4759 4760 btn2.setAttribute('title', mxResources.get('editImage')); 4761 btn2.style.marginBottom = '2px'; 4762 4763 if (btn == null) 4764 { 4765 btn2.style.width = '210px'; 4766 } 4767 else 4768 { 4769 btn.style.width = '104px'; 4770 btn2.style.width = '104px'; 4771 btn2.style.marginLeft = '2px'; 4772 } 4773 4774 div.appendChild(btn2); 4775 } 4776 4777 return div; 4778}; 4779 4780/** 4781 * Adds the label menu items to the given menu and parent. 4782 */ 4783StyleFormatPanel.prototype.addFill = function(container) 4784{ 4785 var ui = this.editorUi; 4786 var graph = ui.editor.graph; 4787 var ss = this.format.getSelectionState(); 4788 container.style.paddingTop = '6px'; 4789 container.style.paddingBottom = '6px'; 4790 4791 // Adds gradient direction option 4792 var gradientSelect = document.createElement('select'); 4793 gradientSelect.style.position = 'absolute'; 4794 gradientSelect.style.left = '104px'; 4795 gradientSelect.style.width = '70px'; 4796 gradientSelect.style.height = '22px'; 4797 gradientSelect.style.padding = '0px'; 4798 gradientSelect.style.marginTop = '-3px'; 4799 gradientSelect.style.borderRadius = '4px'; 4800 gradientSelect.style.border = '1px solid rgb(160, 160, 160)'; 4801 gradientSelect.style.boxSizing = 'border-box'; 4802 4803 var fillStyleSelect = gradientSelect.cloneNode(false); 4804 4805 // Stops events from bubbling to color option event handler 4806 mxEvent.addListener(gradientSelect, 'click', function(evt) 4807 { 4808 mxEvent.consume(evt); 4809 }); 4810 mxEvent.addListener(fillStyleSelect, 'click', function(evt) 4811 { 4812 mxEvent.consume(evt); 4813 }); 4814 4815 var defs = (ss.vertices.length >= 1) ? graph.stylesheet.getDefaultVertexStyle() : graph.stylesheet.getDefaultEdgeStyle(); 4816 var gradientPanel = this.createCellColorOption(mxResources.get('gradient'), mxConstants.STYLE_GRADIENTCOLOR, 4817 (defs[mxConstants.STYLE_GRADIENTCOLOR] != null) ? defs[mxConstants.STYLE_GRADIENTCOLOR] : '#ffffff', function(color) 4818 { 4819 if (color == null || color == mxConstants.NONE) 4820 { 4821 gradientSelect.style.display = 'none'; 4822 } 4823 else 4824 { 4825 gradientSelect.style.display = ''; 4826 } 4827 }, function(color) 4828 { 4829 graph.updateCellStyles(mxConstants.STYLE_GRADIENTCOLOR, color, graph.getSelectionCells()); 4830 }); 4831 4832 var fillKey = (ss.style.shape == 'image') ? mxConstants.STYLE_IMAGE_BACKGROUND : mxConstants.STYLE_FILLCOLOR; 4833 var label = (ss.style.shape == 'image') ? mxResources.get('background') : mxResources.get('fill'); 4834 4835 var fillPanel = this.createCellColorOption(label, fillKey, 'default', null, mxUtils.bind(this, function(color) 4836 { 4837 graph.setCellStyles(fillKey, color, ss.cells); 4838 }), graph.shapeBackgroundColor); 4839 4840 fillPanel.style.fontWeight = 'bold'; 4841 var tmpColor = mxUtils.getValue(ss.style, fillKey, null); 4842 gradientPanel.style.display = (tmpColor != null && tmpColor != mxConstants.NONE && 4843 ss.fill && ss.style.shape != 'image') ? '' : 'none'; 4844 4845 var directions = [mxConstants.DIRECTION_NORTH, mxConstants.DIRECTION_EAST, 4846 mxConstants.DIRECTION_SOUTH, mxConstants.DIRECTION_WEST, 4847 mxConstants.DIRECTION_RADIAL]; 4848 4849 for (var i = 0; i < directions.length; i++) 4850 { 4851 var gradientOption = document.createElement('option'); 4852 gradientOption.setAttribute('value', directions[i]); 4853 mxUtils.write(gradientOption, mxResources.get(directions[i])); 4854 gradientSelect.appendChild(gradientOption); 4855 } 4856 4857 gradientPanel.appendChild(gradientSelect); 4858 4859 for (var i = 0; i < Editor.roughFillStyles.length; i++) 4860 { 4861 var fillStyleOption = document.createElement('option'); 4862 fillStyleOption.setAttribute('value', Editor.roughFillStyles[i].val); 4863 mxUtils.write(fillStyleOption, Editor.roughFillStyles[i].dispName); 4864 fillStyleSelect.appendChild(fillStyleOption); 4865 } 4866 4867 fillPanel.appendChild(fillStyleSelect); 4868 4869 var listener = mxUtils.bind(this, function() 4870 { 4871 ss = this.format.getSelectionState(); 4872 var value = mxUtils.getValue(ss.style, mxConstants.STYLE_GRADIENT_DIRECTION, mxConstants.DIRECTION_SOUTH); 4873 var fillStyle = mxUtils.getValue(ss.style, 'fillStyle', 'auto'); 4874 4875 // Handles empty string which is not allowed as a value 4876 if (value == '') 4877 { 4878 value = mxConstants.DIRECTION_SOUTH; 4879 } 4880 4881 gradientSelect.value = value; 4882 fillStyleSelect.value = fillStyle; 4883 container.style.display = (ss.fill) ? '' : 'none'; 4884 4885 var fillColor = mxUtils.getValue(ss.style, mxConstants.STYLE_FILLCOLOR, null); 4886 4887 if (!ss.fill || ss.containsImage || fillColor == null || fillColor == mxConstants.NONE || ss.style.shape == 'filledEdge') 4888 { 4889 fillStyleSelect.style.display = 'none'; 4890 gradientPanel.style.display = 'none'; 4891 } 4892 else 4893 { 4894 fillStyleSelect.style.display = (ss.style.sketch == '1') ? '' : 'none'; 4895 gradientPanel.style.display = (ss.style.sketch != '1' || fillStyle == 'solid' || fillStyle == 'auto') ? '' : 'none'; 4896 } 4897 }); 4898 4899 graph.getModel().addListener(mxEvent.CHANGE, listener); 4900 this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }}); 4901 listener(); 4902 4903 mxEvent.addListener(gradientSelect, 'change', function(evt) 4904 { 4905 graph.setCellStyles(mxConstants.STYLE_GRADIENT_DIRECTION, gradientSelect.value, ss.cells); 4906 ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_GRADIENT_DIRECTION], 4907 'values', [gradientSelect.value], 'cells', ss.cells)); 4908 mxEvent.consume(evt); 4909 }); 4910 4911 mxEvent.addListener(fillStyleSelect, 'change', function(evt) 4912 { 4913 graph.setCellStyles('fillStyle', fillStyleSelect.value, ss.cells); 4914 ui.fireEvent(new mxEventObject('styleChanged', 'keys', ['fillStyle'], 4915 'values', [fillStyleSelect.value], 'cells', ss.cells)); 4916 mxEvent.consume(evt); 4917 }); 4918 4919 container.appendChild(fillPanel); 4920 container.appendChild(gradientPanel); 4921 4922 // Adds custom colors 4923 var custom = this.getCustomColors(); 4924 4925 for (var i = 0; i < custom.length; i++) 4926 { 4927 container.appendChild(this.createCellColorOption(custom[i].title, custom[i].key, custom[i].defaultValue)); 4928 } 4929 4930 return container; 4931}; 4932 4933/** 4934 * Adds the label menu items to the given menu and parent. 4935 */ 4936StyleFormatPanel.prototype.getCustomColors = function() 4937{ 4938 var ss = this.format.getSelectionState(); 4939 var result = []; 4940 4941 if (ss.style.shape == 'swimlane' || ss.style.shape == 'table') 4942 { 4943 result.push({title: mxResources.get('laneColor'), key: 'swimlaneFillColor', defaultValue: 'default'}); 4944 } 4945 4946 return result; 4947}; 4948 4949/** 4950 * Adds the label menu items to the given menu and parent. 4951 */ 4952StyleFormatPanel.prototype.addStroke = function(container) 4953{ 4954 var ui = this.editorUi; 4955 var graph = ui.editor.graph; 4956 var ss = this.format.getSelectionState(); 4957 4958 container.style.paddingTop = '6px'; 4959 container.style.paddingBottom = '4px'; 4960 container.style.whiteSpace = 'normal'; 4961 4962 var colorPanel = document.createElement('div'); 4963 colorPanel.style.fontWeight = 'bold'; 4964 4965 if (!ss.stroke) 4966 { 4967 colorPanel.style.display = 'none'; 4968 } 4969 4970 // Adds gradient direction option 4971 var styleSelect = document.createElement('select'); 4972 styleSelect.style.position = 'absolute'; 4973 styleSelect.style.height = '22px'; 4974 styleSelect.style.padding = '0px'; 4975 styleSelect.style.marginTop = '-3px'; 4976 styleSelect.style.boxSizing = 'border-box'; 4977 styleSelect.style.left = '94px'; 4978 styleSelect.style.width = '80px'; 4979 styleSelect.style.border = '1px solid rgb(160, 160, 160)'; 4980 styleSelect.style.borderRadius = '4px'; 4981 4982 var styles = ['sharp', 'rounded', 'curved']; 4983 4984 for (var i = 0; i < styles.length; i++) 4985 { 4986 var styleOption = document.createElement('option'); 4987 styleOption.setAttribute('value', styles[i]); 4988 mxUtils.write(styleOption, mxResources.get(styles[i])); 4989 styleSelect.appendChild(styleOption); 4990 } 4991 4992 mxEvent.addListener(styleSelect, 'change', function(evt) 4993 { 4994 graph.getModel().beginUpdate(); 4995 try 4996 { 4997 var keys = [mxConstants.STYLE_ROUNDED, mxConstants.STYLE_CURVED]; 4998 // Default for rounded is 1 4999 var values = ['0', null]; 5000 5001 if (styleSelect.value == 'rounded') 5002 { 5003 values = ['1', null]; 5004 } 5005 else if (styleSelect.value == 'curved') 5006 { 5007 values = [null, '1']; 5008 } 5009 5010 for (var i = 0; i < keys.length; i++) 5011 { 5012 graph.setCellStyles(keys[i], values[i], ss.cells); 5013 } 5014 5015 ui.fireEvent(new mxEventObject('styleChanged', 'keys', keys, 5016 'values', values, 'cells', ss.cells)); 5017 } 5018 finally 5019 { 5020 graph.getModel().endUpdate(); 5021 } 5022 5023 mxEvent.consume(evt); 5024 }); 5025 5026 // Stops events from bubbling to color option event handler 5027 mxEvent.addListener(styleSelect, 'click', function(evt) 5028 { 5029 mxEvent.consume(evt); 5030 }); 5031 5032 var strokeKey = (ss.style.shape == 'image') ? mxConstants.STYLE_IMAGE_BORDER : mxConstants.STYLE_STROKECOLOR; 5033 var label = (ss.style.shape == 'image') ? mxResources.get('border') : mxResources.get('line'); 5034 5035 var lineColor = this.createCellColorOption(label, strokeKey, 'default', null, mxUtils.bind(this, function(color) 5036 { 5037 graph.setCellStyles(strokeKey, color, ss.cells); 5038 }), graph.shapeForegroundColor); 5039 5040 lineColor.appendChild(styleSelect); 5041 colorPanel.appendChild(lineColor); 5042 5043 // Used if only edges selected 5044 var stylePanel = colorPanel.cloneNode(false); 5045 stylePanel.style.fontWeight = 'normal'; 5046 stylePanel.style.whiteSpace = 'nowrap'; 5047 stylePanel.style.position = 'relative'; 5048 stylePanel.style.paddingLeft = '0px'; 5049 stylePanel.style.marginBottom = '2px'; 5050 stylePanel.style.overflow = 'hidden'; 5051 stylePanel.style.marginTop = '2px'; 5052 stylePanel.style.width = '220px'; 5053 stylePanel.className = 'geToolbarContainer'; 5054 5055 var addItem = mxUtils.bind(this, function(menu, width, cssName, keys, values) 5056 { 5057 var item = this.editorUi.menus.styleChange(menu, '', keys, values, 'geIcon', null); 5058 5059 var pat = document.createElement('div'); 5060 pat.style.width = width + 'px'; 5061 pat.style.height = '1px'; 5062 pat.style.borderBottom = '1px ' + cssName + ' ' + this.defaultStrokeColor; 5063 pat.style.paddingTop = '6px'; 5064 5065 item.firstChild.firstChild.style.padding = '0px 4px 0px 4px'; 5066 item.firstChild.firstChild.style.width = width + 'px'; 5067 item.firstChild.firstChild.appendChild(pat); 5068 5069 return item; 5070 }); 5071 5072 var pattern = this.editorUi.toolbar.addMenuFunctionInContainer(stylePanel, 'geSprite-orthogonal', mxResources.get('pattern'), false, mxUtils.bind(this, function(menu) 5073 { 5074 addItem(menu, 75, 'solid', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], [null, null]).setAttribute('title', mxResources.get('solid')); 5075 addItem(menu, 75, 'dashed', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', null]).setAttribute('title', mxResources.get('dashed')); 5076 addItem(menu, 75, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 1']).setAttribute('title', mxResources.get('dotted') + ' (1)'); 5077 addItem(menu, 75, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 2']).setAttribute('title', mxResources.get('dotted') + ' (2)'); 5078 addItem(menu, 75, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 4']).setAttribute('title', mxResources.get('dotted') + ' (3)'); 5079 })); 5080 5081 // Used for mixed selection (vertices and edges) 5082 var altStylePanel = stylePanel.cloneNode(false); 5083 5084 var edgeShape = this.editorUi.toolbar.addMenuFunctionInContainer(altStylePanel, 'geSprite-connection', mxResources.get('connection'), false, mxUtils.bind(this, function(menu) 5085 { 5086 this.editorUi.menus.styleChange(menu, '', [mxConstants.STYLE_SHAPE, mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE, 'width'], [null, null, null, null], 'geIcon geSprite geSprite-connection', null, true).setAttribute('title', mxResources.get('line')); 5087 this.editorUi.menus.styleChange(menu, '', [mxConstants.STYLE_SHAPE, mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE, 'width'], ['link', null, null, null], 'geIcon geSprite geSprite-linkedge', null, true).setAttribute('title', mxResources.get('link')); 5088 this.editorUi.menus.styleChange(menu, '', [mxConstants.STYLE_SHAPE, mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE, 'width'], ['flexArrow', null, null, null], 'geIcon geSprite geSprite-arrow', null, true).setAttribute('title', mxResources.get('arrow')); 5089 this.editorUi.menus.styleChange(menu, '', [mxConstants.STYLE_SHAPE, mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE, 'width'], ['arrow', null, null, null], 'geIcon geSprite geSprite-simplearrow', null, true).setAttribute('title', mxResources.get('simpleArrow')); 5090 })); 5091 5092 var altPattern = this.editorUi.toolbar.addMenuFunctionInContainer(altStylePanel, 'geSprite-orthogonal', mxResources.get('pattern'), false, mxUtils.bind(this, function(menu) 5093 { 5094 addItem(menu, 33, 'solid', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], [null, null]).setAttribute('title', mxResources.get('solid')); 5095 addItem(menu, 33, 'dashed', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', null]).setAttribute('title', mxResources.get('dashed')); 5096 addItem(menu, 33, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 1']).setAttribute('title', mxResources.get('dotted') + ' (1)'); 5097 addItem(menu, 33, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 2']).setAttribute('title', mxResources.get('dotted') + ' (2)'); 5098 addItem(menu, 33, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 4']).setAttribute('title', mxResources.get('dotted') + ' (3)'); 5099 })); 5100 5101 var stylePanel2 = stylePanel.cloneNode(false); 5102 5103 // Stroke width 5104 var input = document.createElement('input'); 5105 input.style.position = 'absolute'; 5106 input.style.textAlign = 'right'; 5107 input.style.marginTop = '2px'; 5108 input.style.width = '52px'; 5109 input.style.height = '21px'; 5110 input.style.left = '146px'; 5111 input.style.border = '1px solid rgb(160, 160, 160)'; 5112 input.style.borderRadius = '4px'; 5113 input.style.boxSizing = 'border-box'; 5114 input.setAttribute('title', mxResources.get('linewidth')); 5115 5116 stylePanel.appendChild(input); 5117 5118 var altInput = input.cloneNode(true); 5119 altStylePanel.appendChild(altInput); 5120 5121 function update(evt) 5122 { 5123 // Maximum stroke width is 999 5124 var value = parseFloat(input.value); 5125 value = Math.min(999, Math.max(0, (isNaN(value)) ? 1 : value)); 5126 5127 if (value != mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1)) 5128 { 5129 graph.setCellStyles(mxConstants.STYLE_STROKEWIDTH, value, ss.cells); 5130 ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_STROKEWIDTH], 5131 'values', [value], 'cells', ss.cells)); 5132 } 5133 5134 input.value = value + ' pt'; 5135 mxEvent.consume(evt); 5136 }; 5137 5138 function altUpdate(evt) 5139 { 5140 // Maximum stroke width is 999 5141 var value = parseFloat(altInput.value); 5142 value = Math.min(999, Math.max(0, (isNaN(value)) ? 1 : value)); 5143 5144 if (value != mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1)) 5145 { 5146 graph.setCellStyles(mxConstants.STYLE_STROKEWIDTH, value, ss.cells); 5147 ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_STROKEWIDTH], 5148 'values', [value], 'cells', ss.cells)); 5149 } 5150 5151 altInput.value = value + ' pt'; 5152 mxEvent.consume(evt); 5153 }; 5154 5155 var stepper = this.createStepper(input, update, 1, 9); 5156 stepper.style.display = input.style.display; 5157 stepper.style.marginTop = '2px'; 5158 stepper.style.left = '198px'; 5159 stylePanel.appendChild(stepper); 5160 5161 var altStepper = this.createStepper(altInput, altUpdate, 1, 9); 5162 altStepper.style.display = altInput.style.display; 5163 altStepper.style.marginTop = '2px'; 5164 altInput.style.position = 'absolute'; 5165 altStepper.style.left = '198px'; 5166 altStylePanel.appendChild(altStepper); 5167 5168 mxEvent.addListener(input, 'blur', update); 5169 mxEvent.addListener(input, 'change', update); 5170 5171 mxEvent.addListener(altInput, 'blur', altUpdate); 5172 mxEvent.addListener(altInput, 'change', altUpdate); 5173 5174 var edgeStyle = this.editorUi.toolbar.addMenuFunctionInContainer(stylePanel2, 'geSprite-orthogonal', mxResources.get('waypoints'), false, mxUtils.bind(this, function(menu) 5175 { 5176 if (ss.style.shape != 'arrow') 5177 { 5178 this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], [null, null, null], 'geIcon geSprite geSprite-straight', null, true).setAttribute('title', mxResources.get('straight')); 5179 this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['orthogonalEdgeStyle', null, null], 'geIcon geSprite geSprite-orthogonal', null, true).setAttribute('title', mxResources.get('orthogonal')); 5180 this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['elbowEdgeStyle', null, null, null], 'geIcon geSprite geSprite-horizontalelbow', null, true).setAttribute('title', mxResources.get('simple')); 5181 this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['elbowEdgeStyle', 'vertical', null, null], 'geIcon geSprite geSprite-verticalelbow', null, true).setAttribute('title', mxResources.get('simple')); 5182 this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['isometricEdgeStyle', null, null, null], 'geIcon geSprite geSprite-horizontalisometric', null, true).setAttribute('title', mxResources.get('isometric')); 5183 this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['isometricEdgeStyle', 'vertical', null, null], 'geIcon geSprite geSprite-verticalisometric', null, true).setAttribute('title', mxResources.get('isometric')); 5184 5185 if (ss.style.shape == 'connector') 5186 { 5187 this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['orthogonalEdgeStyle', '1', null], 'geIcon geSprite geSprite-curved', null, true).setAttribute('title', mxResources.get('curved')); 5188 } 5189 5190 this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['entityRelationEdgeStyle', null, null], 'geIcon geSprite geSprite-entity', null, true).setAttribute('title', mxResources.get('entityRelation')); 5191 } 5192 })); 5193 5194 var lineStart = this.editorUi.toolbar.addMenuFunctionInContainer(stylePanel2, 'geSprite-startclassic', mxResources.get('linestart'), false, mxUtils.bind(this, function(menu) 5195 { 5196 if (ss.style.shape == 'connector' || ss.style.shape == 'flexArrow' || ss.style.shape == 'filledEdge') 5197 { 5198 var item = this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.NONE, 0], 'geIcon', null, false); 5199 item.setAttribute('title', mxResources.get('none')); 5200 5201 var font = document.createElement('font'); 5202 font.style.fontSize = '10px'; 5203 mxUtils.write(font, mxResources.get('none')); 5204 item.firstChild.firstChild.appendChild(font); 5205 5206 if (ss.style.shape == 'connector' || ss.style.shape == 'filledEdge') 5207 { 5208 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_CLASSIC, 1], null, null, false, Format.classicFilledMarkerImage.src)); 5209 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_CLASSIC_THIN, 1], null, null, false, Format.classicThinFilledMarkerImage.src)); 5210 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_OPEN, 0], null, null, false, Format.openFilledMarkerImage.src)); 5211 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_OPEN_THIN, 0], null, null, false, Format.openThinFilledMarkerImage.src)); 5212 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['openAsync', 0], null, null, false, Format.openAsyncFilledMarkerImage.src)); 5213 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_BLOCK, 1], null, null, false, Format.blockFilledMarkerImage.src)); 5214 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_BLOCK_THIN, 1], null, null, false, Format.blockThinFilledMarkerImage.src)); 5215 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['async', 1], null, null, false, Format.asyncFilledMarkerImage.src)); 5216 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_OVAL, 1], null, null, false, Format.ovalFilledMarkerImage.src)); 5217 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_DIAMOND, 1], null, null, false, Format.diamondFilledMarkerImage.src)); 5218 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_DIAMOND_THIN, 1], null, null, false, Format.diamondThinFilledMarkerImage.src)); 5219 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_CLASSIC, 0], null, null, false, Format.classicMarkerImage.src)); 5220 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_CLASSIC_THIN, 0], null, null, false, Format.classicThinMarkerImage.src)); 5221 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_BLOCK, 0], null, null, false, Format.blockMarkerImage.src)); 5222 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_BLOCK_THIN, 0], null, null, false, Format.blockThinMarkerImage.src)); 5223 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['async', 0], null, null, false, Format.asyncMarkerImage.src)); 5224 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_OVAL, 0], null, null, false, Format.ovalMarkerImage.src)); 5225 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_DIAMOND, 0], null, null, false, Format.diamondMarkerImage.src)); 5226 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_DIAMOND_THIN, 0], null, null, false, Format.diamondThinMarkerImage.src)); 5227 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['box', 0], null, null, false, Format.boxMarkerImage.src)); 5228 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['halfCircle', 0], null, null, false, Format.halfCircleMarkerImage.src)); 5229 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['dash', 0], null, null, false, Format.dashMarkerImage.src)); 5230 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['cross', 0], null, null, false, Format.crossMarkerImage.src)); 5231 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['circlePlus', 0], null, null, false, Format.circlePlusMarkerImage.src)); 5232 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['circle', 1], null, null, false, Format.circleMarkerImage.src)); 5233 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['baseDash', 0], null, null, false, Format.baseDashMarkerImage.src)); 5234 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERone', 0], null, null, false, Format.EROneMarkerImage.src)); 5235 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERmandOne', 0], null, null, false, Format.ERmandOneMarkerImage.src)); 5236 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERmany', 0], null, null, false, Format.ERmanyMarkerImage.src)); 5237 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERoneToMany', 0], null, null, false, Format.ERoneToManyMarkerImage.src)); 5238 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERzeroToOne', 0], null, null, false, Format.ERzeroToOneMarkerImage.src)); 5239 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERzeroToMany', 0], null, null, false, Format.ERzeroToManyMarkerImage.src)); 5240 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['doubleBlock', 0], null, null, false, Format.doubleBlockMarkerImage.src)); 5241 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['doubleBlock', 1], null, null, false, Format.doubleBlockFilledMarkerImage.src)); 5242 } 5243 else 5244 { 5245 this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW], [mxConstants.ARROW_BLOCK], 'geIcon geSprite geSprite-startblocktrans', null, false).setAttribute('title', mxResources.get('block')); 5246 } 5247 5248 menu.div.style.width = '40px'; 5249 } 5250 })); 5251 5252 var lineEnd = this.editorUi.toolbar.addMenuFunctionInContainer(stylePanel2, 'geSprite-endclassic', mxResources.get('lineend'), false, mxUtils.bind(this, function(menu) 5253 { 5254 if (ss.style.shape == 'connector' || ss.style.shape == 'flexArrow' || ss.style.shape == 'filledEdge') 5255 { 5256 var item = this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.NONE, 0], 'geIcon', null, false); 5257 item.setAttribute('title', mxResources.get('none')); 5258 5259 var font = document.createElement('font'); 5260 font.style.fontSize = '10px'; 5261 mxUtils.write(font, mxResources.get('none')); 5262 item.firstChild.firstChild.appendChild(font); 5263 5264 if (ss.style.shape == 'connector' || ss.style.shape == 'filledEdge') 5265 { 5266 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_CLASSIC, 1], null, null, false, Format.classicFilledMarkerImage.src), 'scaleX(-1)'); 5267 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_CLASSIC_THIN, 1], null, null, false, Format.classicThinFilledMarkerImage.src), 'scaleX(-1)'); 5268 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_OPEN, 0], null, null, false, Format.openFilledMarkerImage.src), 'scaleX(-1)'); 5269 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_OPEN_THIN, 0], null, null, false, Format.openThinFilledMarkerImage.src), 'scaleX(-1)'); 5270 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['openAsync', 0], null, null, false, Format.openAsyncFilledMarkerImage.src), 'scaleX(-1)'); 5271 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_BLOCK, 1], null, null, false, Format.blockFilledMarkerImage.src), 'scaleX(-1)'); 5272 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_BLOCK_THIN, 1], null, null, false, Format.blockThinFilledMarkerImage.src), 'scaleX(-1)'); 5273 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['async', 1], null, null, false, Format.asyncFilledMarkerImage.src), 'scaleX(-1)'); 5274 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_OVAL, 1], null, null, false, Format.ovalFilledMarkerImage.src), 'scaleX(-1)'); 5275 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_DIAMOND, 1], null, null, false, Format.diamondFilledMarkerImage.src), 'scaleX(-1)'); 5276 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_DIAMOND_THIN, 1], null, null, false, Format.diamondThinFilledMarkerImage.src), 'scaleX(-1)'); 5277 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_CLASSIC, 0], null, null, false, Format.classicMarkerImage.src), 'scaleX(-1)'); 5278 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_CLASSIC_THIN, 0], null, null, false, Format.classicThinMarkerImage.src), 'scaleX(-1)'); 5279 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_BLOCK, 0], null, null, false, Format.blockMarkerImage.src), 'scaleX(-1)'); 5280 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_BLOCK_THIN, 0], null, null, false, Format.blockThinMarkerImage.src), 'scaleX(-1)'); 5281 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['async', 0], null, null, false, Format.asyncMarkerImage.src), 'scaleX(-1)'); 5282 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_OVAL, 0], null, null, false, Format.ovalMarkerImage.src), 'scaleX(-1)'); 5283 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_DIAMOND, 0], null, null, false, Format.diamondMarkerImage.src), 'scaleX(-1)'); 5284 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_DIAMOND_THIN, 0], null, null, false, Format.diamondThinMarkerImage.src), 'scaleX(-1)'); 5285 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['box', 0], null, null, false, Format.boxMarkerImage.src), 'scaleX(-1)'); 5286 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['halfCircle', 0], null, null, false, Format.halfCircleMarkerImage.src), 'scaleX(-1)'); 5287 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['dash', 0], null, null, false, Format.dashMarkerImage.src), 'scaleX(-1)'); 5288 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['cross', 0], null, null, false, Format.crossMarkerImage.src), 'scaleX(-1)'); 5289 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['circlePlus', 0], null, null, false, Format.circlePlusMarkerImage.src), 'scaleX(-1)'); 5290 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['circle', 0], null, null, false, Format.circleMarkerImage.src), 'scaleX(-1)'); 5291 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['baseDash', 0], null, null, false, Format.baseDashMarkerImage.src), 'scaleX(-1)'); 5292 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERone', 0], null, null, false, Format.EROneMarkerImage.src), 'scaleX(-1)'); 5293 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERmandOne', 0], null, null, false, Format.ERmandOneMarkerImage.src), 'scaleX(-1)'); 5294 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERmany', 0], null, null, false, Format.ERmanyMarkerImage.src), 'scaleX(-1)'); 5295 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERoneToMany', 0], null, null, false, Format.ERoneToManyMarkerImage.src), 'scaleX(-1)'); 5296 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERzeroToOne', 0], null, null, false, Format.ERzeroToOneMarkerImage.src), 'scaleX(-1)'); 5297 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERzeroToMany', 0], null, null, false, Format.ERzeroToManyMarkerImage.src), 'scaleX(-1)'); 5298 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['doubleBlock', 0], null, null, false, Format.doubleBlockMarkerImage.src), 'scaleX(-1)'); 5299 Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['doubleBlock', 1], null, null, false, Format.doubleBlockFilledMarkerImage.src), 'scaleX(-1)'); 5300 } 5301 else 5302 { 5303 this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW], [mxConstants.ARROW_BLOCK], 'geIcon geSprite geSprite-endblocktrans', null, false).setAttribute('title', mxResources.get('block')); 5304 } 5305 5306 menu.div.style.width = '40px'; 5307 } 5308 })); 5309 5310 var elt = this.addArrow(edgeShape, 8); 5311 elt.nextSibling.style.position = 'relative'; 5312 elt.nextSibling.style.top = '-2px'; 5313 elt = this.addArrow(edgeStyle, 10); 5314 elt.nextSibling.style.position = 'relative'; 5315 elt.nextSibling.style.top = '-3px'; 5316 edgeStyle.getElementsByTagName('img')[0].style.top = '-1px'; 5317 this.addArrow(lineStart); 5318 this.addArrow(lineEnd); 5319 5320 var symbol = this.addArrow(pattern, 9); 5321 symbol.className = 'geIcon'; 5322 symbol.style.width = 'auto'; 5323 5324 var altSymbol = this.addArrow(altPattern, 9); 5325 altSymbol.className = 'geIcon'; 5326 altSymbol.style.width = '22px'; 5327 5328 var solid = document.createElement('div'); 5329 solid.style.width = '84px'; 5330 solid.style.height = '1px'; 5331 solid.style.borderBottom = '1px solid ' + this.defaultStrokeColor; 5332 solid.style.marginBottom = '7px'; 5333 symbol.appendChild(solid); 5334 5335 var altSolid = document.createElement('div'); 5336 altSolid.style.width = '23px'; 5337 altSolid.style.height = '1px'; 5338 altSolid.style.borderBottom = '1px solid ' + this.defaultStrokeColor; 5339 altSolid.style.marginBottom = '7px'; 5340 altSymbol.appendChild(altSolid); 5341 5342 pattern.style.height = '15px'; 5343 pattern.style.marginLeft = '16px'; 5344 altPattern.style.height = '15px'; 5345 altPattern.style.marginLeft = '3px'; 5346 edgeShape.style.marginLeft = '10px'; 5347 edgeShape.style.height = '15px'; 5348 edgeStyle.style.marginLeft = '10px'; 5349 edgeStyle.style.height = '17px'; 5350 lineStart.style.marginLeft = '3px'; 5351 lineStart.style.height = '17px'; 5352 lineEnd.style.marginLeft = '3px'; 5353 lineEnd.style.height = '17px'; 5354 5355 container.appendChild(colorPanel); 5356 container.appendChild(altStylePanel); 5357 container.appendChild(stylePanel); 5358 5359 var arrowPanel = stylePanel.cloneNode(false); 5360 arrowPanel.style.padding = '5px 4px 6px 0px'; 5361 arrowPanel.style.fontWeight = 'normal'; 5362 5363 var span = document.createElement('div'); 5364 span.style.position = 'absolute'; 5365 span.style.marginLeft = '0px'; 5366 span.style.marginBottom = '12px'; 5367 span.style.marginTop = '2px'; 5368 span.style.fontWeight = 'normal'; 5369 span.style.width = '76px'; 5370 5371 mxUtils.write(span, mxResources.get('lineend')); 5372 arrowPanel.appendChild(span); 5373 5374 var endSpacingUpdate, endSizeUpdate; 5375 var endSpacing = this.addUnitInput(arrowPanel, 'pt', 98, 52, function() 5376 { 5377 endSpacingUpdate.apply(this, arguments); 5378 }); 5379 var endSize = this.addUnitInput(arrowPanel, 'pt', 30, 52, function() 5380 { 5381 endSizeUpdate.apply(this, arguments); 5382 }); 5383 5384 mxUtils.br(arrowPanel); 5385 5386 var spacer = document.createElement('div'); 5387 spacer.style.height = '8px'; 5388 arrowPanel.appendChild(spacer); 5389 5390 span = span.cloneNode(false); 5391 mxUtils.write(span, mxResources.get('linestart')); 5392 arrowPanel.appendChild(span); 5393 5394 var startSpacingUpdate, startSizeUpdate; 5395 var startSpacing = this.addUnitInput(arrowPanel, 'pt', 98, 52, function() 5396 { 5397 startSpacingUpdate.apply(this, arguments); 5398 }); 5399 var startSize = this.addUnitInput(arrowPanel, 'pt', 30, 52, function() 5400 { 5401 startSizeUpdate.apply(this, arguments); 5402 }); 5403 5404 mxUtils.br(arrowPanel); 5405 this.addLabel(arrowPanel, mxResources.get('spacing'), 98, 52); 5406 this.addLabel(arrowPanel, mxResources.get('size'), 30, 52); 5407 mxUtils.br(arrowPanel); 5408 5409 var perimeterPanel = colorPanel.cloneNode(false); 5410 perimeterPanel.style.fontWeight = 'normal'; 5411 perimeterPanel.style.position = 'relative'; 5412 perimeterPanel.style.paddingLeft = '16px' 5413 perimeterPanel.style.marginBottom = '2px'; 5414 perimeterPanel.style.marginTop = '6px'; 5415 perimeterPanel.style.borderWidth = '0px'; 5416 perimeterPanel.style.paddingBottom = '18px'; 5417 5418 var span = document.createElement('div'); 5419 span.style.position = 'absolute'; 5420 span.style.marginLeft = '3px'; 5421 span.style.marginBottom = '12px'; 5422 span.style.marginTop = '1px'; 5423 span.style.fontWeight = 'normal'; 5424 span.style.width = '120px'; 5425 mxUtils.write(span, mxResources.get('perimeter')); 5426 perimeterPanel.appendChild(span); 5427 5428 var perimeterUpdate; 5429 var perimeterSpacing = this.addUnitInput(perimeterPanel, 'pt', 30, 52, function() 5430 { 5431 perimeterUpdate.apply(this, arguments); 5432 }); 5433 5434 if (ss.edges.length == ss.cells.length) 5435 { 5436 container.appendChild(stylePanel2); 5437 container.appendChild(arrowPanel); 5438 } 5439 else if (ss.vertices.length == ss.cells.length) 5440 { 5441 container.appendChild(perimeterPanel); 5442 } 5443 5444 var listener = mxUtils.bind(this, function(sender, evt, force) 5445 { 5446 ss = this.format.getSelectionState(); 5447 var color = mxUtils.getValue(ss.style, strokeKey, null); 5448 5449 if (force || document.activeElement != input) 5450 { 5451 var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1)); 5452 input.value = (isNaN(tmp)) ? '' : tmp + ' pt'; 5453 } 5454 5455 if (force || document.activeElement != altInput) 5456 { 5457 var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1)); 5458 altInput.value = (isNaN(tmp)) ? '' : tmp + ' pt'; 5459 } 5460 5461 styleSelect.style.visibility = (ss.style.shape == 'connector' || ss.style.shape == 'filledEdge') ? '' : 'hidden'; 5462 5463 if (mxUtils.getValue(ss.style, mxConstants.STYLE_CURVED, null) == '1') 5464 { 5465 styleSelect.value = 'curved'; 5466 } 5467 else if (mxUtils.getValue(ss.style, mxConstants.STYLE_ROUNDED, null) == '1') 5468 { 5469 styleSelect.value = 'rounded'; 5470 } 5471 5472 if (mxUtils.getValue(ss.style, mxConstants.STYLE_DASHED, null) == '1') 5473 { 5474 if (mxUtils.getValue(ss.style, mxConstants.STYLE_DASH_PATTERN, null) == null) 5475 { 5476 solid.style.borderBottom = '1px dashed ' + this.defaultStrokeColor; 5477 } 5478 else 5479 { 5480 solid.style.borderBottom = '1px dotted ' + this.defaultStrokeColor; 5481 } 5482 } 5483 else 5484 { 5485 solid.style.borderBottom = '1px solid ' + this.defaultStrokeColor; 5486 } 5487 5488 altSolid.style.borderBottom = solid.style.borderBottom; 5489 5490 // Updates toolbar icon for edge style 5491 var edgeStyleDiv = edgeStyle.getElementsByTagName('div')[0]; 5492 5493 if (edgeStyleDiv != null) 5494 { 5495 var es = mxUtils.getValue(ss.style, mxConstants.STYLE_EDGE, null); 5496 5497 if (mxUtils.getValue(ss.style, mxConstants.STYLE_NOEDGESTYLE, null) == '1') 5498 { 5499 es = null; 5500 } 5501 5502 if (es == 'orthogonalEdgeStyle' && mxUtils.getValue(ss.style, mxConstants.STYLE_CURVED, null) == '1') 5503 { 5504 edgeStyleDiv.className = 'geSprite geSprite-curved'; 5505 } 5506 else if (es == 'straight' || es == 'none' || es == null) 5507 { 5508 edgeStyleDiv.className = 'geSprite geSprite-straight'; 5509 } 5510 else if (es == 'entityRelationEdgeStyle') 5511 { 5512 edgeStyleDiv.className = 'geSprite geSprite-entity'; 5513 } 5514 else if (es == 'elbowEdgeStyle') 5515 { 5516 edgeStyleDiv.className = 'geSprite ' + ((mxUtils.getValue(ss.style, 5517 mxConstants.STYLE_ELBOW, null) == 'vertical') ? 5518 'geSprite-verticalelbow' : 'geSprite-horizontalelbow'); 5519 } 5520 else if (es == 'isometricEdgeStyle') 5521 { 5522 edgeStyleDiv.className = 'geSprite ' + ((mxUtils.getValue(ss.style, 5523 mxConstants.STYLE_ELBOW, null) == 'vertical') ? 5524 'geSprite-verticalisometric' : 'geSprite-horizontalisometric'); 5525 } 5526 else 5527 { 5528 edgeStyleDiv.className = 'geSprite geSprite-orthogonal'; 5529 } 5530 } 5531 5532 // Updates icon for edge shape 5533 var edgeShapeDiv = edgeShape.getElementsByTagName('div')[0]; 5534 5535 if (edgeShapeDiv != null) 5536 { 5537 if (ss.style.shape == 'link') 5538 { 5539 edgeShapeDiv.className = 'geSprite geSprite-linkedge'; 5540 } 5541 else if (ss.style.shape == 'flexArrow') 5542 { 5543 edgeShapeDiv.className = 'geSprite geSprite-arrow'; 5544 } 5545 else if (ss.style.shape == 'arrow') 5546 { 5547 edgeShapeDiv.className = 'geSprite geSprite-simplearrow'; 5548 } 5549 else 5550 { 5551 edgeShapeDiv.className = 'geSprite geSprite-connection'; 5552 } 5553 } 5554 5555 if (ss.edges.length == ss.cells.length) 5556 { 5557 altStylePanel.style.display = ''; 5558 stylePanel.style.display = 'none'; 5559 } 5560 else 5561 { 5562 altStylePanel.style.display = 'none'; 5563 stylePanel.style.display = ''; 5564 } 5565 5566 if (Graph.lineJumpsEnabled && ss.edges.length > 0 && 5567 ss.vertices.length == 0 && ss.lineJumps) 5568 { 5569 container.style.borderBottomStyle = 'none'; 5570 } 5571 5572 function updateArrow(marker, fill, elt, prefix) 5573 { 5574 var markerDiv = elt.getElementsByTagName('div')[0]; 5575 5576 if (markerDiv != null) 5577 { 5578 markerDiv.className = ui.getCssClassForMarker(prefix, ss.style.shape, marker, fill); 5579 markerDiv.nextSibling.style.marginLeft = '1px'; 5580 markerDiv.nextSibling.style.paddingRight = '5px'; 5581 5582 if (markerDiv.className == 'geSprite geSprite-noarrow') 5583 { 5584 markerDiv.innerHTML = mxUtils.htmlEntities(mxResources.get('none')); 5585 markerDiv.style.backgroundImage = 'none'; 5586 markerDiv.style.verticalAlign = 'top'; 5587 markerDiv.style.marginTop = '4px'; 5588 markerDiv.style.fontSize = '10px'; 5589 markerDiv.style.filter = 'none'; 5590 markerDiv.style.color = this.defaultStrokeColor; 5591 markerDiv.nextSibling.style.marginTop = '0px'; 5592 } 5593 else 5594 { 5595 markerDiv.nextSibling.style.position = 'relative'; 5596 markerDiv.nextSibling.style.top = '-2px'; 5597 } 5598 } 5599 5600 return markerDiv; 5601 }; 5602 5603 var sourceDiv = updateArrow(mxUtils.getValue(ss.style, mxConstants.STYLE_STARTARROW, null), 5604 mxUtils.getValue(ss.style, 'startFill', '1'), lineStart, 'start'); 5605 var targetDiv = updateArrow(mxUtils.getValue(ss.style, mxConstants.STYLE_ENDARROW, null), 5606 mxUtils.getValue(ss.style, 'endFill', '1'), lineEnd, 'end'); 5607 5608 // Special cases for markers 5609 if (sourceDiv != null && targetDiv != null) 5610 { 5611 if (ss.style.shape == 'arrow') 5612 { 5613 sourceDiv.className = 'geSprite geSprite-noarrow'; 5614 targetDiv.className = 'geSprite geSprite-endblocktrans'; 5615 } 5616 else if (ss.style.shape == 'link') 5617 { 5618 sourceDiv.className = 'geSprite geSprite-noarrow'; 5619 targetDiv.className = 'geSprite geSprite-noarrow'; 5620 } 5621 } 5622 5623 mxUtils.setOpacity(edgeStyle, (ss.style.shape == 'arrow') ? 30 : 100); 5624 5625 if (ss.style.shape != 'connector' && ss.style.shape != 'flexArrow' && ss.style.shape != 'filledEdge') 5626 { 5627 mxUtils.setOpacity(lineStart, 30); 5628 mxUtils.setOpacity(lineEnd, 30); 5629 } 5630 else 5631 { 5632 mxUtils.setOpacity(lineStart, 100); 5633 mxUtils.setOpacity(lineEnd, 100); 5634 } 5635 5636 if (force || document.activeElement != startSize) 5637 { 5638 var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_MARKERSIZE)); 5639 startSize.value = (isNaN(tmp)) ? '' : tmp + ' pt'; 5640 } 5641 5642 if (force || document.activeElement != startSpacing) 5643 { 5644 var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_SOURCE_PERIMETER_SPACING, 0)); 5645 startSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt'; 5646 } 5647 5648 if (force || document.activeElement != endSize) 5649 { 5650 var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_ENDSIZE, mxConstants.DEFAULT_MARKERSIZE)); 5651 endSize.value = (isNaN(tmp)) ? '' : tmp + ' pt'; 5652 } 5653 5654 if (force || document.activeElement != startSpacing) 5655 { 5656 var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_TARGET_PERIMETER_SPACING, 0)); 5657 endSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt'; 5658 } 5659 5660 if (force || document.activeElement != perimeterSpacing) 5661 { 5662 var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_PERIMETER_SPACING, 0)); 5663 perimeterSpacing.value = (isNaN(tmp)) ? '' : tmp + ' pt'; 5664 } 5665 }); 5666 5667 startSizeUpdate = this.installInputHandler(startSize, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_MARKERSIZE, 0, 999, ' pt'); 5668 startSpacingUpdate = this.installInputHandler(startSpacing, mxConstants.STYLE_SOURCE_PERIMETER_SPACING, 0, -999, 999, ' pt'); 5669 endSizeUpdate = this.installInputHandler(endSize, mxConstants.STYLE_ENDSIZE, mxConstants.DEFAULT_MARKERSIZE, 0, 999, ' pt'); 5670 endSpacingUpdate = this.installInputHandler(endSpacing, mxConstants.STYLE_TARGET_PERIMETER_SPACING, 0, -999, 999, ' pt'); 5671 perimeterUpdate = this.installInputHandler(perimeterSpacing, mxConstants.STYLE_PERIMETER_SPACING, 0, 0, 999, ' pt'); 5672 5673 this.addKeyHandler(input, listener); 5674 this.addKeyHandler(startSize, listener); 5675 this.addKeyHandler(startSpacing, listener); 5676 this.addKeyHandler(endSize, listener); 5677 this.addKeyHandler(endSpacing, listener); 5678 this.addKeyHandler(perimeterSpacing, listener); 5679 5680 graph.getModel().addListener(mxEvent.CHANGE, listener); 5681 this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }}); 5682 listener(); 5683 5684 return container; 5685}; 5686 5687/** 5688 * Adds UI for configuring line jumps. 5689 */ 5690StyleFormatPanel.prototype.addLineJumps = function(container) 5691{ 5692 var ss = this.format.getSelectionState(); 5693 5694 if (Graph.lineJumpsEnabled && ss.edges.length > 0 && 5695 ss.vertices.length == 0 && ss.lineJumps) 5696 { 5697 container.style.padding = '2px 0px 24px 14px'; 5698 5699 var ui = this.editorUi; 5700 var editor = ui.editor; 5701 var graph = editor.graph; 5702 5703 var span = document.createElement('div'); 5704 span.style.position = 'absolute'; 5705 span.style.maxWidth = '82px'; 5706 span.style.overflow = 'hidden'; 5707 span.style.textOverflow = 'ellipsis'; 5708 5709 mxUtils.write(span, mxResources.get('lineJumps')); 5710 container.appendChild(span); 5711 5712 var styleSelect = document.createElement('select'); 5713 styleSelect.style.position = 'absolute'; 5714 styleSelect.style.height = '21px'; 5715 styleSelect.style.padding = '0px'; 5716 styleSelect.style.marginTop = '-2px'; 5717 styleSelect.style.boxSizing = 'border-box'; 5718 styleSelect.style.right = '76px'; 5719 styleSelect.style.width = '54px'; 5720 styleSelect.style.border = '1px solid rgb(160, 160, 160)'; 5721 styleSelect.style.borderRadius = '4px'; 5722 5723 var styles = ['none', 'arc', 'gap', 'sharp', 'line']; 5724 5725 for (var i = 0; i < styles.length; i++) 5726 { 5727 var styleOption = document.createElement('option'); 5728 styleOption.setAttribute('value', styles[i]); 5729 mxUtils.write(styleOption, mxResources.get(styles[i])); 5730 styleSelect.appendChild(styleOption); 5731 } 5732 5733 mxEvent.addListener(styleSelect, 'change', function(evt) 5734 { 5735 graph.getModel().beginUpdate(); 5736 try 5737 { 5738 graph.setCellStyles('jumpStyle', styleSelect.value, ss.cells); 5739 ui.fireEvent(new mxEventObject('styleChanged', 'keys', ['jumpStyle'], 5740 'values', [styleSelect.value], 'cells', ss.cells)); 5741 } 5742 finally 5743 { 5744 graph.getModel().endUpdate(); 5745 } 5746 5747 mxEvent.consume(evt); 5748 }); 5749 5750 // Stops events from bubbling to color option event handler 5751 mxEvent.addListener(styleSelect, 'click', function(evt) 5752 { 5753 mxEvent.consume(evt); 5754 }); 5755 5756 container.appendChild(styleSelect); 5757 5758 var jumpSizeUpdate; 5759 5760 var jumpSize = this.addUnitInput(container, 'pt', 16, 42, function() 5761 { 5762 jumpSizeUpdate.apply(this, arguments); 5763 }); 5764 5765 jumpSizeUpdate = this.installInputHandler(jumpSize, 'jumpSize', 5766 Graph.defaultJumpSize, 0, 999, ' pt'); 5767 5768 var listener = mxUtils.bind(this, function(sender, evt, force) 5769 { 5770 ss = this.format.getSelectionState(); 5771 styleSelect.value = mxUtils.getValue(ss.style, 'jumpStyle', 'none'); 5772 5773 if (force || document.activeElement != jumpSize) 5774 { 5775 var tmp = parseInt(mxUtils.getValue(ss.style, 'jumpSize', Graph.defaultJumpSize)); 5776 jumpSize.value = (isNaN(tmp)) ? '' : tmp + ' pt'; 5777 } 5778 }); 5779 5780 this.addKeyHandler(jumpSize, listener); 5781 5782 graph.getModel().addListener(mxEvent.CHANGE, listener); 5783 this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }}); 5784 listener(); 5785 } 5786 else 5787 { 5788 container.style.display = 'none'; 5789 } 5790 5791 return container; 5792}; 5793 5794/** 5795 * Adds the label menu items to the given menu and parent. 5796 */ 5797StyleFormatPanel.prototype.addEffects = function(div) 5798{ 5799 var ui = this.editorUi; 5800 var editor = ui.editor; 5801 var graph = editor.graph; 5802 var ss = this.format.getSelectionState(); 5803 5804 div.style.paddingTop = '4px'; 5805 div.style.paddingBottom = '0px'; 5806 5807 var table = document.createElement('table'); 5808 5809 table.style.width = '210px'; 5810 table.style.fontWeight = 'bold'; 5811 table.style.tableLayout = 'fixed'; 5812 var tbody = document.createElement('tbody'); 5813 var row = document.createElement('tr'); 5814 row.style.padding = '0px'; 5815 var left = document.createElement('td'); 5816 left.style.padding = '0px'; 5817 left.style.width = '50%'; 5818 left.setAttribute('valign', 'top'); 5819 5820 var right = left.cloneNode(true); 5821 right.style.paddingLeft = '8px'; 5822 row.appendChild(left); 5823 row.appendChild(right); 5824 tbody.appendChild(row); 5825 table.appendChild(tbody); 5826 div.appendChild(table); 5827 5828 var current = left; 5829 var count = 0; 5830 5831 var addOption = mxUtils.bind(this, function(label, key, defaultValue) 5832 { 5833 var opt = this.createCellOption(label, key, defaultValue); 5834 opt.style.width = '100%'; 5835 current.appendChild(opt); 5836 current = (current == left) ? right : left; 5837 count++; 5838 }); 5839 5840 var listener = mxUtils.bind(this, function(sender, evt, force) 5841 { 5842 ss = this.format.getSelectionState(); 5843 5844 left.innerHTML = ''; 5845 right.innerHTML = ''; 5846 current = left; 5847 5848 if (ss.rounded) 5849 { 5850 addOption(mxResources.get('rounded'), mxConstants.STYLE_ROUNDED, 0); 5851 } 5852 5853 if (ss.style.shape == 'swimlane') 5854 { 5855 addOption(mxResources.get('divider'), 'swimlaneLine', 1); 5856 } 5857 5858 if (!ss.containsImage) 5859 { 5860 addOption(mxResources.get('shadow'), mxConstants.STYLE_SHADOW, 0); 5861 } 5862 5863 if (ss.glass) 5864 { 5865 addOption(mxResources.get('glass'), mxConstants.STYLE_GLASS, 0); 5866 } 5867 5868 addOption(mxResources.get('sketch'), 'sketch', 0); 5869 }); 5870 5871 graph.getModel().addListener(mxEvent.CHANGE, listener); 5872 this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }}); 5873 listener(); 5874 5875 return div; 5876} 5877 5878/** 5879 * Adds the label menu items to the given menu and parent. 5880 */ 5881StyleFormatPanel.prototype.addStyleOps = function(div) 5882{ 5883 div.style.paddingTop = '10px'; 5884 div.style.paddingBottom = '10px'; 5885 5886 var btn = mxUtils.button(mxResources.get('setAsDefaultStyle'), mxUtils.bind(this, function(evt) 5887 { 5888 this.editorUi.actions.get('setAsDefaultStyle').funct(); 5889 })); 5890 5891 btn.setAttribute('title', mxResources.get('setAsDefaultStyle') + ' (' + this.editorUi.actions.get('setAsDefaultStyle').shortcut + ')'); 5892 btn.style.width = '210px'; 5893 div.appendChild(btn); 5894 5895 return div; 5896}; 5897 5898/** 5899 * Adds the label menu items to the given menu and parent. 5900 */ 5901DiagramStylePanel = function(format, editorUi, container) 5902{ 5903 BaseFormatPanel.call(this, format, editorUi, container); 5904 this.init(); 5905}; 5906 5907mxUtils.extend(DiagramStylePanel, BaseFormatPanel); 5908 5909/** 5910 * Adds the label menu items to the given menu and parent. 5911 */ 5912DiagramStylePanel.prototype.init = function() 5913{ 5914 var ui = this.editorUi; 5915 var editor = ui.editor; 5916 var graph = editor.graph; 5917 5918 this.darkModeChangedListener = mxUtils.bind(this, function() 5919 { 5920 this.format.cachedStyleEntries = []; 5921 }); 5922 5923 ui.addListener('darkModeChanged', this.darkModeChangedListener); 5924 this.container.appendChild(this.addView(this.createPanel())); 5925}; 5926 5927/** 5928 * Adds the label menu items to the given menu and parent. 5929 */ 5930DiagramStylePanel.prototype.addView = function(div) 5931{ 5932 var ui = this.editorUi; 5933 var editor = ui.editor; 5934 var graph = editor.graph; 5935 var model = graph.getModel(); 5936 5937 div.style.whiteSpace = 'normal'; 5938 5939 var sketch = graph.currentVertexStyle['sketch'] == '1' && graph.currentEdgeStyle['sketch'] == '1'; 5940 var rounded = graph.currentVertexStyle['rounded'] == '1'; 5941 var curved = graph.currentEdgeStyle['curved'] == '1'; 5942 5943 var opts = document.createElement('div'); 5944 opts.style.paddingBottom = '12px'; 5945 opts.style.marginRight = '16px'; 5946 div.style.paddingTop = '8px'; 5947 5948 var table = document.createElement('table'); 5949 5950 table.style.width = '210px'; 5951 table.style.fontWeight = 'bold'; 5952 5953 var tbody = document.createElement('tbody'); 5954 var row = document.createElement('tr'); 5955 row.style.padding = '0px'; 5956 5957 var left = document.createElement('td'); 5958 left.style.padding = '0px'; 5959 left.style.width = '50%'; 5960 left.setAttribute('valign', 'middle'); 5961 5962 var right = left.cloneNode(true); 5963 right.style.paddingLeft = '8px'; 5964 row.appendChild(left); 5965 row.appendChild(right); 5966 tbody.appendChild(row); 5967 table.appendChild(tbody); 5968 5969 // Sketch 5970 left.appendChild(this.createOption(mxResources.get('sketch'), function() 5971 { 5972 return sketch; 5973 }, function(checked) 5974 { 5975 sketch = checked; 5976 5977 if (checked) 5978 { 5979 graph.currentEdgeStyle['sketch'] = '1'; 5980 graph.currentVertexStyle['sketch'] = '1'; 5981 } 5982 else 5983 { 5984 delete graph.currentEdgeStyle['sketch']; 5985 delete graph.currentVertexStyle['sketch']; 5986 } 5987 5988 graph.updateCellStyles('sketch', (checked) ? '1' : null, graph.getVerticesAndEdges()); 5989 }, null, function(div) 5990 { 5991 div.style.width = 'auto'; 5992 })); 5993 5994 // Rounded 5995 right.appendChild(this.createOption(mxResources.get('rounded'), function() 5996 { 5997 return rounded; 5998 }, function(checked) 5999 { 6000 rounded = checked; 6001 6002 if (checked) 6003 { 6004 graph.currentEdgeStyle['rounded'] = '1'; 6005 graph.currentVertexStyle['rounded'] = '1'; 6006 } 6007 else 6008 { 6009 delete graph.currentEdgeStyle['rounded']; 6010 delete graph.currentVertexStyle['rounded']; 6011 } 6012 6013 graph.updateCellStyles('rounded', (checked) ? '1' : '0', graph.getVerticesAndEdges()); 6014 }, null, function(div) 6015 { 6016 div.style.width = 'auto'; 6017 })); 6018 6019 // Curved 6020 left = left.cloneNode(false); 6021 right = right.cloneNode(false); 6022 row = row.cloneNode(false); 6023 row.appendChild(left); 6024 row.appendChild(right); 6025 tbody.appendChild(row); 6026 6027 left.appendChild(this.createOption(mxResources.get('curved'), function() 6028 { 6029 return curved; 6030 }, function(checked) 6031 { 6032 curved = checked; 6033 6034 if (checked) 6035 { 6036 graph.currentEdgeStyle['curved'] = '1'; 6037 } 6038 else 6039 { 6040 delete graph.currentEdgeStyle['curved']; 6041 } 6042 6043 graph.updateCellStyles('curved', (checked) ? '1' : null, graph.getVerticesAndEdges(false, true)); 6044 }, null, function(div) 6045 { 6046 div.style.width = 'auto'; 6047 })); 6048 6049 opts.appendChild(table); 6050 div.appendChild(opts); 6051 6052 var defaultStyles = ['fillColor', 'strokeColor', 'fontColor', 'gradientColor']; 6053 6054 var updateCells = mxUtils.bind(this, function(styles, graphStyle) 6055 { 6056 var cells = graph.getVerticesAndEdges(); 6057 6058 model.beginUpdate(); 6059 try 6060 { 6061 for (var i = 0; i < cells.length; i++) 6062 { 6063 var style = graph.getCellStyle(cells[i]); 6064 6065 // Handles special label background color 6066 if (style['labelBackgroundColor'] != null) 6067 { 6068 graph.updateCellStyles('labelBackgroundColor', (graphStyle != null) ? 6069 graphStyle.background : null, [cells[i]]); 6070 } 6071 6072 var edge = model.isEdge(cells[i]); 6073 var newStyle = model.getStyle(cells[i]); 6074 var current = (edge) ? graph.currentEdgeStyle : graph.currentVertexStyle; 6075 6076 for (var j = 0; j < styles.length; j++) 6077 { 6078 if ((style[styles[j]] != null && style[styles[j]] != mxConstants.NONE) || 6079 (styles[j] != mxConstants.STYLE_FILLCOLOR && 6080 styles[j] != mxConstants.STYLE_STROKECOLOR)) 6081 { 6082 newStyle = mxUtils.setStyle(newStyle, styles[j], current[styles[j]]); 6083 } 6084 } 6085 6086 model.setStyle(cells[i], newStyle); 6087 } 6088 } 6089 finally 6090 { 6091 model.endUpdate(); 6092 } 6093 }); 6094 6095 var removeStyles = mxUtils.bind(this, function(style, styles, defaultStyle) 6096 { 6097 if (style != null) 6098 { 6099 for (var j = 0; j < styles.length; j++) 6100 { 6101 if (((style[styles[j]] != null && 6102 style[styles[j]] != mxConstants.NONE) || 6103 (styles[j] != mxConstants.STYLE_FILLCOLOR && 6104 styles[j] != mxConstants.STYLE_STROKECOLOR))) 6105 { 6106 style[styles[j]] = defaultStyle[styles[j]]; 6107 } 6108 } 6109 } 6110 }); 6111 6112 var applyStyle = mxUtils.bind(this, function(style, result, cell, graphStyle, theGraph) 6113 { 6114 if (style != null) 6115 { 6116 if (cell != null) 6117 { 6118 // Handles special label background color 6119 if (result['labelBackgroundColor'] != null) 6120 { 6121 var bg = (graphStyle != null) ? graphStyle.background : null; 6122 theGraph = (theGraph != null) ? theGraph : graph; 6123 6124 if (bg == null) 6125 { 6126 bg = theGraph.background; 6127 } 6128 6129 if (bg == null) 6130 { 6131 bg = theGraph.defaultPageBackgroundColor; 6132 } 6133 6134 result['labelBackgroundColor'] = bg; 6135 } 6136 } 6137 6138 for (var key in style) 6139 { 6140 if (cell == null || ((result[key] != null && 6141 result[key] != mxConstants.NONE) || 6142 (key != mxConstants.STYLE_FILLCOLOR && 6143 key != mxConstants.STYLE_STROKECOLOR))) 6144 { 6145 result[key] = style[key]; 6146 } 6147 } 6148 } 6149 }); 6150 6151 var btn = mxUtils.button(mxResources.get('reset'), mxUtils.bind(this, function(evt) 6152 { 6153 var all = graph.getVerticesAndEdges(true, true); 6154 6155 if (all.length > 0) 6156 { 6157 model.beginUpdate(); 6158 try 6159 { 6160 graph.updateCellStyles('sketch', null, all); 6161 graph.updateCellStyles('rounded', null, all); 6162 graph.updateCellStyles('curved', null, graph.getVerticesAndEdges(false, true)); 6163 } 6164 finally 6165 { 6166 model.endUpdate(); 6167 } 6168 } 6169 6170 ui.clearDefaultStyle(); 6171 })); 6172 6173 btn.setAttribute('title', mxResources.get('reset')); 6174 btn.style.textOverflow = 'ellipsis'; 6175 btn.style.maxWidth = '90px'; 6176 right.appendChild(btn); 6177 6178 var createPreview = mxUtils.bind(this, function(commonStyle, vertexStyle, edgeStyle, graphStyle, container) 6179 { 6180 // Wrapper needed to catch events 6181 var div = document.createElement('div'); 6182 div.style.position = 'absolute'; 6183 div.style.display = 'inline-block'; 6184 div.style.overflow = 'hidden'; 6185 div.style.pointerEvents = 'none'; 6186 div.style.width = '100%'; 6187 div.style.height = '100%'; 6188 container.appendChild(div); 6189 6190 var graph2 = new Graph(div, null, null, graph.getStylesheet()); 6191 6192 graph2.resetViewOnRootChange = false; 6193 graph2.foldingEnabled = false; 6194 graph2.gridEnabled = false; 6195 graph2.autoScroll = false; 6196 graph2.setTooltips(false); 6197 graph2.setConnectable(false); 6198 graph2.setPanning(false); 6199 graph2.setEnabled(false); 6200 6201 graph2.getCellStyle = function(cell) 6202 { 6203 var result = mxUtils.clone(Graph.prototype.getCellStyle.apply(this, arguments)); 6204 var defaultStyle = graph.stylesheet.getDefaultVertexStyle(); 6205 var appliedStyle = vertexStyle; 6206 6207 if (model.isEdge(cell)) 6208 { 6209 defaultStyle = graph.stylesheet.getDefaultEdgeStyle(); 6210 appliedStyle = edgeStyle; 6211 } 6212 6213 removeStyles(result, defaultStyles, defaultStyle); 6214 applyStyle(commonStyle, result, cell, graphStyle, graph2); 6215 applyStyle(appliedStyle, result, cell, graphStyle, graph2); 6216 6217 if (result != null) 6218 { 6219 result = this.postProcessCellStyle(result); 6220 } 6221 6222 return result; 6223 }; 6224 6225 // Avoid HTML labels to capture events in bubble phase 6226 graph2.model.beginUpdate(); 6227 try 6228 { 6229 var v1 = graph2.insertVertex(graph2.getDefaultParent(), null, 'Shape', 14, 8, 70, 40, 'strokeWidth=2;'); 6230 var e1 = graph2.insertEdge(graph2.getDefaultParent(), null, 'Connector', v1, v1, 6231 'edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;endSize=5;strokeWidth=2;') 6232 e1.geometry.points = [new mxPoint(32, 70)]; 6233 e1.geometry.offset = new mxPoint(0, 8); 6234 } 6235 finally 6236 { 6237 graph2.model.endUpdate(); 6238 } 6239 }); 6240 6241 // Entries 6242 var entries = document.createElement('div'); 6243 entries.style.position = 'relative'; 6244 div.appendChild(entries); 6245 6246 // Cached entries 6247 if (this.format.cachedStyleEntries == null) 6248 { 6249 this.format.cachedStyleEntries = []; 6250 } 6251 6252 var addEntry = mxUtils.bind(this, function(commonStyle, vertexStyle, edgeStyle, graphStyle, index) 6253 { 6254 var panel = this.format.cachedStyleEntries[index]; 6255 6256 if (panel == null) 6257 { 6258 panel = document.createElement('div'); 6259 panel.style.display = 'inline-block'; 6260 panel.style.position = 'relative'; 6261 panel.style.width = '96px'; 6262 panel.style.height = '90px'; 6263 panel.style.cursor = 'pointer'; 6264 panel.style.border = '1px solid gray'; 6265 panel.style.borderRadius = '8px'; 6266 panel.style.margin = '2px'; 6267 panel.style.overflow = 'hidden'; 6268 6269 if (graphStyle != null && graphStyle.background != null) 6270 { 6271 panel.style.backgroundColor = graphStyle.background; 6272 } 6273 6274 createPreview(commonStyle, vertexStyle, edgeStyle, graphStyle, panel); 6275 6276 mxEvent.addGestureListeners(panel, mxUtils.bind(this, function(evt) 6277 { 6278 panel.style.opacity = 0.5; 6279 }), null, mxUtils.bind(this, function(evt) 6280 { 6281 panel.style.opacity = 1; 6282 graph.currentVertexStyle = mxUtils.clone(graph.defaultVertexStyle); 6283 graph.currentEdgeStyle = mxUtils.clone(graph.defaultEdgeStyle); 6284 6285 applyStyle(commonStyle, graph.currentVertexStyle); 6286 applyStyle(commonStyle, graph.currentEdgeStyle); 6287 applyStyle(vertexStyle, graph.currentVertexStyle); 6288 applyStyle(edgeStyle, graph.currentEdgeStyle); 6289 6290 if (sketch) 6291 { 6292 graph.currentEdgeStyle['sketch'] = '1'; 6293 graph.currentVertexStyle['sketch'] = '1'; 6294 } 6295 else 6296 { 6297 graph.currentEdgeStyle['sketch'] = '0'; 6298 graph.currentVertexStyle['sketch'] = '0'; 6299 } 6300 6301 if (rounded) 6302 { 6303 graph.currentVertexStyle['rounded'] = '1'; 6304 graph.currentEdgeStyle['rounded'] = '1'; 6305 } 6306 else 6307 { 6308 graph.currentVertexStyle['rounded'] = '0'; 6309 graph.currentEdgeStyle['rounded'] = '1'; 6310 } 6311 6312 if (curved) 6313 { 6314 graph.currentEdgeStyle['curved'] = '1'; 6315 } 6316 else 6317 { 6318 graph.currentEdgeStyle['curved'] = '0'; 6319 } 6320 6321 model.beginUpdate(); 6322 try 6323 { 6324 updateCells(defaultStyles, graphStyle); 6325 6326 var change = new ChangePageSetup(ui, (graphStyle != null) ? graphStyle.background : null); 6327 change.ignoreImage = true; 6328 model.execute(change); 6329 6330 model.execute(new ChangeGridColor(ui, (graphStyle != null && graphStyle.gridColor != null) ? 6331 graphStyle.gridColor : graph.view.defaultGridColor)); 6332 } 6333 finally 6334 { 6335 model.endUpdate(); 6336 } 6337 })); 6338 6339 mxEvent.addListener(panel, 'mouseenter', mxUtils.bind(this, function(evt) 6340 { 6341 var prev = graph.getCellStyle; 6342 var prevBg = graph.background; 6343 var prevGrid = graph.view.gridColor; 6344 6345 graph.background = (graphStyle != null) ? graphStyle.background : null; 6346 graph.view.gridColor = (graphStyle != null && graphStyle.gridColor != null) ? 6347 graphStyle.gridColor : graph.view.defaultGridColor; 6348 6349 graph.getCellStyle = function(cell) 6350 { 6351 var result = mxUtils.clone(prev.apply(this, arguments)); 6352 6353 var defaultStyle = graph.stylesheet.getDefaultVertexStyle(); 6354 var appliedStyle = vertexStyle; 6355 6356 if (model.isEdge(cell)) 6357 { 6358 defaultStyle = graph.stylesheet.getDefaultEdgeStyle(); 6359 appliedStyle = edgeStyle; 6360 } 6361 6362 removeStyles(result, defaultStyles, defaultStyle); 6363 applyStyle(commonStyle, result, cell, graphStyle); 6364 applyStyle(appliedStyle, result, cell, graphStyle); 6365 6366 if (result != null) 6367 { 6368 result = this.postProcessCellStyle(result); 6369 } 6370 6371 return result; 6372 }; 6373 6374 graph.refresh(); 6375 graph.getCellStyle = prev; 6376 graph.background = prevBg; 6377 graph.view.gridColor = prevGrid; 6378 })); 6379 6380 mxEvent.addListener(panel, 'mouseleave', mxUtils.bind(this, function(evt) 6381 { 6382 graph.refresh(); 6383 })); 6384 6385 // Workaround for broken cache in IE11 6386 if (!mxClient.IS_IE && !mxClient.IS_IE11) 6387 { 6388 this.format.cachedStyleEntries[index] = panel; 6389 } 6390 } 6391 6392 entries.appendChild(panel); 6393 }); 6394 6395 // Maximum palettes to switch the switcher 6396 var maxEntries = 10; 6397 var pageCount = Math.ceil(Editor.styles.length / maxEntries); 6398 this.format.currentStylePage = (this.format.currentStylePage != null) ? this.format.currentStylePage : 0; 6399 var dots = []; 6400 6401 var addEntries = mxUtils.bind(this, function() 6402 { 6403 if (dots.length > 0) 6404 { 6405 dots[this.format.currentStylePage].style.background = '#84d7ff'; 6406 } 6407 6408 for (var i = this.format.currentStylePage * maxEntries; 6409 i < Math.min((this.format.currentStylePage + 1) * maxEntries, 6410 Editor.styles.length); i++) 6411 { 6412 var s = Editor.styles[i]; 6413 addEntry(s.commonStyle, s.vertexStyle, s.edgeStyle, s.graph, i); 6414 } 6415 }); 6416 6417 var selectPage = mxUtils.bind(this, function(index) 6418 { 6419 if (index >= 0 && index < pageCount) 6420 { 6421 dots[this.format.currentStylePage].style.background = 'transparent'; 6422 entries.innerHTML = ''; 6423 this.format.currentStylePage = index; 6424 addEntries(); 6425 } 6426 }); 6427 6428 if (pageCount > 1) 6429 { 6430 // Selector 6431 var switcher = document.createElement('div'); 6432 switcher.style.whiteSpace = 'nowrap'; 6433 switcher.style.position = 'relative'; 6434 switcher.style.textAlign = 'center'; 6435 switcher.style.paddingTop = '4px'; 6436 switcher.style.width = '210px'; 6437 6438 div.style.paddingBottom = '8px'; 6439 6440 for (var i = 0; i < pageCount; i++) 6441 { 6442 var dot = document.createElement('div'); 6443 dot.style.display = 'inline-block'; 6444 dot.style.width = '6px'; 6445 dot.style.height = '6px'; 6446 dot.style.marginLeft = '4px'; 6447 dot.style.marginRight = '3px'; 6448 dot.style.borderRadius = '3px'; 6449 dot.style.cursor = 'pointer'; 6450 dot.style.background = 'transparent'; 6451 dot.style.border = '1px solid #b5b6b7'; 6452 6453 (mxUtils.bind(this, function(index, elt) 6454 { 6455 mxEvent.addListener(dot, 'click', mxUtils.bind(this, function() 6456 { 6457 selectPage(index); 6458 })); 6459 }))(i, dot); 6460 6461 switcher.appendChild(dot); 6462 dots.push(dot); 6463 } 6464 6465 div.appendChild(switcher); 6466 addEntries(); 6467 6468 if (pageCount < 15) 6469 { 6470 var left = document.createElement('div'); 6471 left.style.position = 'absolute'; 6472 left.style.left = '0px'; 6473 left.style.top = '0px'; 6474 left.style.bottom = '0px'; 6475 left.style.width = '24px'; 6476 left.style.height = '24px'; 6477 left.style.margin = '0px'; 6478 left.style.cursor = 'pointer'; 6479 left.style.opacity = '0.5'; 6480 left.style.backgroundRepeat = 'no-repeat'; 6481 left.style.backgroundPosition = 'center center'; 6482 left.style.backgroundSize = '24px 24px'; 6483 left.style.backgroundImage = 'url(' + Editor.previousImage + ')'; 6484 6485 if (Editor.isDarkMode()) 6486 { 6487 left.style.filter = 'invert(100%)'; 6488 } 6489 6490 var right = left.cloneNode(false); 6491 right.style.backgroundImage = 'url(' + Editor.nextImage + ')'; 6492 right.style.left = ''; 6493 right.style.right = '2px'; 6494 6495 switcher.appendChild(left); 6496 switcher.appendChild(right); 6497 6498 mxEvent.addListener(left, 'click', mxUtils.bind(this, function() 6499 { 6500 selectPage(mxUtils.mod(this.format.currentStylePage - 1, pageCount)); 6501 })); 6502 6503 mxEvent.addListener(right, 'click', mxUtils.bind(this, function() 6504 { 6505 selectPage(mxUtils.mod(this.format.currentStylePage + 1, pageCount)); 6506 })); 6507 6508 // Hover state 6509 function addHoverState(elt) 6510 { 6511 mxEvent.addListener(elt, 'mouseenter', function() 6512 { 6513 elt.style.opacity = '1'; 6514 }); 6515 mxEvent.addListener(elt, 'mouseleave', function() 6516 { 6517 elt.style.opacity = '0.5'; 6518 }); 6519 }; 6520 6521 addHoverState(left); 6522 addHoverState(right); 6523 } 6524 } 6525 else 6526 { 6527 addEntries(); 6528 } 6529 6530 return div; 6531}; 6532 6533/** 6534 * Adds the label menu items to the given menu and parent. 6535 */ 6536 DiagramStylePanel.prototype.destroy = function() 6537 { 6538 BaseFormatPanel.prototype.destroy.apply(this, arguments); 6539 6540 if (this.darkModeChangedListener) 6541 { 6542 this.editorUi.removeListener(this.darkModeChangedListener); 6543 this.darkModeChangedListener = null; 6544 } 6545 }; 6546 6547/** 6548 * Adds the label menu items to the given menu and parent. 6549 */ 6550DiagramFormatPanel = function(format, editorUi, container) 6551{ 6552 BaseFormatPanel.call(this, format, editorUi, container); 6553 this.init(); 6554}; 6555 6556mxUtils.extend(DiagramFormatPanel, BaseFormatPanel); 6557 6558/** 6559 * Switch to disable page view. 6560 */ 6561DiagramFormatPanel.showPageView = true; 6562 6563/** 6564 * Specifies if the background image option should be shown. Default is true. 6565 */ 6566DiagramFormatPanel.prototype.showBackgroundImageOption = true; 6567 6568/** 6569 * Adds the label menu items to the given menu and parent. 6570 */ 6571DiagramFormatPanel.prototype.init = function() 6572{ 6573 var ui = this.editorUi; 6574 var editor = ui.editor; 6575 var graph = editor.graph; 6576 6577 this.container.appendChild(this.addView(this.createPanel())); 6578 6579 if (graph.isEnabled()) 6580 { 6581 this.container.appendChild(this.addOptions(this.createPanel())); 6582 this.container.appendChild(this.addPaperSize(this.createPanel())); 6583 this.container.appendChild(this.addStyleOps(this.createPanel())); 6584 } 6585}; 6586 6587/** 6588 * Adds the label menu items to the given menu and parent. 6589 */ 6590DiagramFormatPanel.prototype.addView = function(div) 6591{ 6592 var ui = this.editorUi; 6593 var editor = ui.editor; 6594 var graph = editor.graph; 6595 6596 div.appendChild(this.createTitle(mxResources.get('view'))); 6597 6598 // Grid 6599 this.addGridOption(div); 6600 6601 // Page View 6602 if (DiagramFormatPanel.showPageView) 6603 { 6604 div.appendChild(this.createOption(mxResources.get('pageView'), function() 6605 { 6606 return graph.pageVisible; 6607 }, function(checked) 6608 { 6609 ui.actions.get('pageView').funct(); 6610 }, 6611 { 6612 install: function(apply) 6613 { 6614 this.listener = function() 6615 { 6616 apply(graph.pageVisible); 6617 }; 6618 6619 ui.addListener('pageViewChanged', this.listener); 6620 }, 6621 destroy: function() 6622 { 6623 ui.removeListener(this.listener); 6624 } 6625 })); 6626 } 6627 6628 if (graph.isEnabled()) 6629 { 6630 // Background 6631 var bg = this.createColorOption(mxResources.get('background'), function() 6632 { 6633 return graph.background; 6634 }, function(color) 6635 { 6636 var change = new ChangePageSetup(ui, color); 6637 change.ignoreImage = true; 6638 6639 graph.model.execute(change); 6640 }, '#ffffff', 6641 { 6642 install: function(apply) 6643 { 6644 this.listener = function() 6645 { 6646 apply(graph.background); 6647 }; 6648 6649 ui.addListener('backgroundColorChanged', this.listener); 6650 }, 6651 destroy: function() 6652 { 6653 ui.removeListener(this.listener); 6654 } 6655 }); 6656 6657 if (this.showBackgroundImageOption) 6658 { 6659 var label = bg.getElementsByTagName('span')[0]; 6660 label.style.display = 'inline-block'; 6661 label.style.textOverflow = 'ellipsis'; 6662 label.style.overflow = 'hidden'; 6663 label.style.maxWidth = '68px'; 6664 6665 if (mxClient.IS_FF) 6666 { 6667 label.style.marginTop = '1px'; 6668 } 6669 6670 var btn = mxUtils.button(mxResources.get('change'), function(evt) 6671 { 6672 ui.showBackgroundImageDialog(null, ui.editor.graph.backgroundImage); 6673 mxEvent.consume(evt); 6674 }) 6675 6676 btn.className = 'geColorBtn'; 6677 btn.style.position = 'absolute'; 6678 btn.style.marginTop = '-3px'; 6679 btn.style.height = '22px'; 6680 btn.style.left = '118px'; 6681 btn.style.width = '56px'; 6682 6683 bg.appendChild(btn); 6684 } 6685 6686 div.appendChild(bg); 6687 } 6688 6689 return div; 6690}; 6691 6692/** 6693 * Adds the label menu items to the given menu and parent. 6694 */ 6695DiagramFormatPanel.prototype.addOptions = function(div) 6696{ 6697 var ui = this.editorUi; 6698 var editor = ui.editor; 6699 var graph = editor.graph; 6700 6701 div.appendChild(this.createTitle(mxResources.get('options'))); 6702 6703 if (graph.isEnabled()) 6704 { 6705 // Connection arrows 6706 div.appendChild(this.createOption(mxResources.get('connectionArrows'), function() 6707 { 6708 return graph.connectionArrowsEnabled; 6709 }, function(checked) 6710 { 6711 ui.actions.get('connectionArrows').funct(); 6712 }, 6713 { 6714 install: function(apply) 6715 { 6716 this.listener = function() 6717 { 6718 apply(graph.connectionArrowsEnabled); 6719 }; 6720 6721 ui.addListener('connectionArrowsChanged', this.listener); 6722 }, 6723 destroy: function() 6724 { 6725 ui.removeListener(this.listener); 6726 } 6727 })); 6728 6729 // Connection points 6730 div.appendChild(this.createOption(mxResources.get('connectionPoints'), function() 6731 { 6732 return graph.connectionHandler.isEnabled(); 6733 }, function(checked) 6734 { 6735 ui.actions.get('connectionPoints').funct(); 6736 }, 6737 { 6738 install: function(apply) 6739 { 6740 this.listener = function() 6741 { 6742 apply(graph.connectionHandler.isEnabled()); 6743 }; 6744 6745 ui.addListener('connectionPointsChanged', this.listener); 6746 }, 6747 destroy: function() 6748 { 6749 ui.removeListener(this.listener); 6750 } 6751 })); 6752 6753 // Guides 6754 div.appendChild(this.createOption(mxResources.get('guides'), function() 6755 { 6756 return graph.graphHandler.guidesEnabled; 6757 }, function(checked) 6758 { 6759 ui.actions.get('guides').funct(); 6760 }, 6761 { 6762 install: function(apply) 6763 { 6764 this.listener = function() 6765 { 6766 apply(graph.graphHandler.guidesEnabled); 6767 }; 6768 6769 ui.addListener('guidesEnabledChanged', this.listener); 6770 }, 6771 destroy: function() 6772 { 6773 ui.removeListener(this.listener); 6774 } 6775 })); 6776 } 6777 6778 return div; 6779}; 6780 6781/** 6782 * 6783 */ 6784DiagramFormatPanel.prototype.addGridOption = function(container) 6785{ 6786 var fPanel = this; 6787 var ui = this.editorUi; 6788 var graph = ui.editor.graph; 6789 6790 var input = document.createElement('input'); 6791 input.style.position = 'absolute'; 6792 input.style.textAlign = 'right'; 6793 input.style.width = '48px'; 6794 input.style.marginTop = '-2px'; 6795 input.style.height = '21px'; 6796 input.style.border = '1px solid rgb(160, 160, 160)'; 6797 input.style.borderRadius = '4px'; 6798 input.style.boxSizing = 'border-box'; 6799 input.value = this.inUnit(graph.getGridSize()) + ' ' + this.getUnit(); 6800 6801 var stepper = this.createStepper(input, update, this.getUnitStep(), null, null, null, this.isFloatUnit()); 6802 input.style.display = (graph.isGridEnabled()) ? '' : 'none'; 6803 stepper.style.display = input.style.display; 6804 6805 mxEvent.addListener(input, 'keydown', function(e) 6806 { 6807 if (e.keyCode == 13) 6808 { 6809 graph.container.focus(); 6810 mxEvent.consume(e); 6811 } 6812 else if (e.keyCode == 27) 6813 { 6814 input.value = graph.getGridSize(); 6815 graph.container.focus(); 6816 mxEvent.consume(e); 6817 } 6818 }); 6819 6820 function update(evt) 6821 { 6822 var value = fPanel.isFloatUnit()? parseFloat(input.value) : parseInt(input.value); 6823 value = fPanel.fromUnit(Math.max(fPanel.inUnit(1), (isNaN(value)) ? fPanel.inUnit(10) : value)); 6824 6825 if (value != graph.getGridSize()) 6826 { 6827 mxGraph.prototype.gridSize = value; 6828 graph.setGridSize(value) 6829 } 6830 6831 input.value = fPanel.inUnit(value) + ' ' + fPanel.getUnit(); 6832 mxEvent.consume(evt); 6833 }; 6834 6835 mxEvent.addListener(input, 'blur', update); 6836 mxEvent.addListener(input, 'change', update); 6837 6838 input.style.right = '78px'; 6839 stepper.style.marginTop = '-17px'; 6840 stepper.style.right = '66px'; 6841 6842 var panel = this.createColorOption(mxResources.get('grid'), function() 6843 { 6844 var color = graph.view.gridColor; 6845 6846 return (graph.isGridEnabled()) ? color : null; 6847 }, function(color) 6848 { 6849 var enabled = graph.isGridEnabled(); 6850 6851 if (color == mxConstants.NONE) 6852 { 6853 graph.setGridEnabled(false); 6854 } 6855 else 6856 { 6857 graph.setGridEnabled(true); 6858 ui.setGridColor(color); 6859 } 6860 6861 input.style.display = (graph.isGridEnabled()) ? '' : 'none'; 6862 stepper.style.display = input.style.display; 6863 6864 if (enabled != graph.isGridEnabled()) 6865 { 6866 graph.defaultGridEnabled = graph.isGridEnabled(); 6867 ui.fireEvent(new mxEventObject('gridEnabledChanged')); 6868 } 6869 }, Editor.isDarkMode() ? graph.view.defaultDarkGridColor : graph.view.defaultGridColor, 6870 { 6871 install: function(apply) 6872 { 6873 this.listener = function() 6874 { 6875 apply((graph.isGridEnabled()) ? graph.view.gridColor : null); 6876 }; 6877 6878 ui.addListener('gridColorChanged', this.listener); 6879 ui.addListener('gridEnabledChanged', this.listener); 6880 }, 6881 destroy: function() 6882 { 6883 ui.removeListener(this.listener); 6884 } 6885 }); 6886 6887 panel.appendChild(input); 6888 panel.appendChild(stepper); 6889 container.appendChild(panel); 6890}; 6891 6892/** 6893 * Adds the label menu items to the given menu and parent. 6894 */ 6895DiagramFormatPanel.prototype.addDocumentProperties = function(div) 6896{ 6897 // Hook for subclassers 6898 var ui = this.editorUi; 6899 var editor = ui.editor; 6900 var graph = editor.graph; 6901 6902 div.appendChild(this.createTitle(mxResources.get('options'))); 6903 6904 return div; 6905}; 6906 6907/** 6908 * Adds the label menu items to the given menu and parent. 6909 */ 6910DiagramFormatPanel.prototype.addPaperSize = function(div) 6911{ 6912 var ui = this.editorUi; 6913 var editor = ui.editor; 6914 var graph = editor.graph; 6915 6916 div.appendChild(this.createTitle(mxResources.get('paperSize'))); 6917 6918 var accessor = PageSetupDialog.addPageFormatPanel(div, 'formatpanel', graph.pageFormat, function(pageFormat) 6919 { 6920 if (graph.pageFormat == null || graph.pageFormat.width != pageFormat.width || 6921 graph.pageFormat.height != pageFormat.height) 6922 { 6923 var change = new ChangePageSetup(ui, null, null, pageFormat); 6924 change.ignoreColor = true; 6925 change.ignoreImage = true; 6926 6927 graph.model.execute(change); 6928 } 6929 }); 6930 6931 this.addKeyHandler(accessor.widthInput, function() 6932 { 6933 accessor.set(graph.pageFormat); 6934 }); 6935 this.addKeyHandler(accessor.heightInput, function() 6936 { 6937 accessor.set(graph.pageFormat); 6938 }); 6939 6940 var listener = function() 6941 { 6942 accessor.set(graph.pageFormat); 6943 }; 6944 6945 ui.addListener('pageFormatChanged', listener); 6946 this.listeners.push({destroy: function() { ui.removeListener(listener); }}); 6947 6948 graph.getModel().addListener(mxEvent.CHANGE, listener); 6949 this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }}); 6950 6951 return div; 6952}; 6953 6954/** 6955 * Adds the label menu items to the given menu and parent. 6956 */ 6957DiagramFormatPanel.prototype.addStyleOps = function(div) 6958{ 6959 var btn = mxUtils.button(mxResources.get('editData'), mxUtils.bind(this, function(evt) 6960 { 6961 this.editorUi.actions.get('editData').funct(); 6962 })); 6963 6964 btn.setAttribute('title', mxResources.get('editData') + ' (' + this.editorUi.actions.get('editData').shortcut + ')'); 6965 btn.style.width = '210px'; 6966 btn.style.marginBottom = '2px'; 6967 div.appendChild(btn); 6968 6969 mxUtils.br(div); 6970 6971 btn = mxUtils.button(mxResources.get('clearDefaultStyle'), mxUtils.bind(this, function(evt) 6972 { 6973 this.editorUi.actions.get('clearDefaultStyle').funct(); 6974 })); 6975 6976 btn.setAttribute('title', mxResources.get('clearDefaultStyle') + ' (' + this.editorUi.actions.get('clearDefaultStyle').shortcut + ')'); 6977 btn.style.width = '210px'; 6978 div.appendChild(btn); 6979 6980 return div; 6981}; 6982 6983/** 6984 * Adds the label menu items to the given menu and parent. 6985 */ 6986DiagramFormatPanel.prototype.destroy = function() 6987{ 6988 BaseFormatPanel.prototype.destroy.apply(this, arguments); 6989 6990 if (this.gridEnabledListener) 6991 { 6992 this.editorUi.removeListener(this.gridEnabledListener); 6993 this.gridEnabledListener = null; 6994 } 6995}; 6996