1/** 2 * Copyright (c) 2006-2012, JGraph Ltd 3 */ 4/** 5 * Constructs a new open dialog. 6 */ 7var OpenDialog = function() 8{ 9 var iframe = document.createElement('iframe'); 10 iframe.style.backgroundColor = 'transparent'; 11 iframe.allowTransparency = 'true'; 12 iframe.style.borderStyle = 'none'; 13 iframe.style.borderWidth = '0px'; 14 iframe.style.overflow = 'hidden'; 15 iframe.frameBorder = '0'; 16 17 var dx = 0; 18 iframe.setAttribute('width', (((Editor.useLocalStorage) ? 640 : 320) + dx) + 'px'); 19 iframe.setAttribute('height', (((Editor.useLocalStorage) ? 480 : 220) + dx) + 'px'); 20 iframe.setAttribute('src', OPEN_FORM); 21 22 this.container = iframe; 23}; 24 25/** 26 * Constructs a new color dialog. 27 */ 28var ColorDialog = function(editorUi, color, apply, cancelFn) 29{ 30 this.editorUi = editorUi; 31 32 var input = document.createElement('input'); 33 input.style.marginBottom = '10px'; 34 35 // Required for picker to render in IE 36 if (mxClient.IS_IE) 37 { 38 input.style.marginTop = '10px'; 39 document.body.appendChild(input); 40 } 41 42 var applyFunction = (apply != null) ? apply : this.createApplyFunction(); 43 44 function doApply() 45 { 46 var color = input.value; 47 48 // Blocks any non-alphabetic chars in colors 49 if (/(^#?[a-zA-Z0-9]*$)/.test(color)) 50 { 51 if (color != 'none' && color.charAt(0) != '#') 52 { 53 color = '#' + color; 54 } 55 56 ColorDialog.addRecentColor((color != 'none') ? color.substring(1) : color, 12); 57 applyFunction(color); 58 editorUi.hideDialog(); 59 } 60 else 61 { 62 editorUi.handleError({message: mxResources.get('invalidInput')}); 63 } 64 }; 65 66 this.init = function() 67 { 68 if (!mxClient.IS_TOUCH) 69 { 70 input.focus(); 71 } 72 }; 73 74 var picker = new mxJSColor.color(input); 75 picker.pickerOnfocus = false; 76 picker.showPicker(); 77 78 var div = document.createElement('div'); 79 mxJSColor.picker.box.style.position = 'relative'; 80 mxJSColor.picker.box.style.width = '230px'; 81 mxJSColor.picker.box.style.height = '100px'; 82 mxJSColor.picker.box.style.paddingBottom = '10px'; 83 div.appendChild(mxJSColor.picker.box); 84 85 var center = document.createElement('center'); 86 87 function createRecentColorTable() 88 { 89 var table = addPresets((ColorDialog.recentColors.length == 0) ? ['FFFFFF'] : 90 ColorDialog.recentColors, 11, 'FFFFFF', true); 91 table.style.marginBottom = '8px'; 92 93 return table; 94 }; 95 96 var addPresets = mxUtils.bind(this, function(presets, rowLength, defaultColor, addResetOption) 97 { 98 rowLength = (rowLength != null) ? rowLength : 12; 99 var table = document.createElement('table'); 100 table.style.borderCollapse = 'collapse'; 101 table.setAttribute('cellspacing', '0'); 102 table.style.marginBottom = '20px'; 103 table.style.cellSpacing = '0px'; 104 var tbody = document.createElement('tbody'); 105 table.appendChild(tbody); 106 107 var rows = presets.length / rowLength; 108 109 for (var row = 0; row < rows; row++) 110 { 111 var tr = document.createElement('tr'); 112 113 for (var i = 0; i < rowLength; i++) 114 { 115 (mxUtils.bind(this, function(clr) 116 { 117 var td = document.createElement('td'); 118 td.style.border = '1px solid black'; 119 td.style.padding = '0px'; 120 td.style.width = '16px'; 121 td.style.height = '16px'; 122 123 if (clr == null) 124 { 125 clr = defaultColor; 126 } 127 128 if (clr == 'none') 129 { 130 td.style.background = 'url(\'' + Dialog.prototype.noColorImage + '\')'; 131 } 132 else if (clr != null) 133 { 134 td.style.backgroundColor = '#' + clr; 135 var name = this.colorNames[clr.toUpperCase()]; 136 137 if (name != null) 138 { 139 td.setAttribute('title', name); 140 } 141 } 142 143 tr.appendChild(td); 144 145 if (clr != null) 146 { 147 td.style.cursor = 'pointer'; 148 149 mxEvent.addListener(td, 'click', function() 150 { 151 if (clr == 'none') 152 { 153 picker.fromString('ffffff'); 154 input.value = 'none'; 155 } 156 else 157 { 158 picker.fromString(clr); 159 } 160 }); 161 162 mxEvent.addListener(td, 'dblclick', doApply); 163 } 164 }))(presets[row * rowLength + i]); 165 } 166 167 tbody.appendChild(tr); 168 } 169 170 if (addResetOption) 171 { 172 var td = document.createElement('td'); 173 td.setAttribute('title', mxResources.get('reset')); 174 td.style.border = '1px solid black'; 175 td.style.padding = '0px'; 176 td.style.width = '16px'; 177 td.style.height = '16px'; 178 td.style.backgroundImage = 'url(\'' + Dialog.prototype.closeImage + '\')'; 179 td.style.backgroundPosition = 'center center'; 180 td.style.backgroundRepeat = 'no-repeat'; 181 td.style.cursor = 'pointer'; 182 183 tr.appendChild(td); 184 185 mxEvent.addListener(td, 'click', function() 186 { 187 ColorDialog.resetRecentColors(); 188 table.parentNode.replaceChild(createRecentColorTable(), table); 189 }); 190 } 191 192 center.appendChild(table); 193 194 return table; 195 }); 196 197 div.appendChild(input); 198 199 if (!mxClient.IS_IE && !mxClient.IS_IE11) 200 { 201 input.style.width = '182px'; 202 203 var clrInput = document.createElement('input'); 204 clrInput.setAttribute('type', 'color'); 205 clrInput.style.visibility = 'hidden'; 206 clrInput.style.width = '0px'; 207 clrInput.style.height = '0px'; 208 clrInput.style.border = 'none'; 209 clrInput.style.marginLeft = '2px'; 210 div.style.whiteSpace = 'nowrap'; 211 div.appendChild(clrInput); 212 213 div.appendChild(mxUtils.button('...', function() 214 { 215 // LATER: Check if clrInput is expanded 216 if (document.activeElement == clrInput) 217 { 218 input.focus(); 219 } 220 else 221 { 222 clrInput.value = '#' + input.value; 223 clrInput.click(); 224 } 225 })); 226 227 mxEvent.addListener(clrInput, 'input', function() 228 { 229 picker.fromString(clrInput.value.substring(1)); 230 }); 231 } 232 else 233 { 234 input.style.width = '216px'; 235 } 236 237 mxUtils.br(div); 238 239 // Adds recent colors 240 createRecentColorTable(); 241 242 // Adds presets 243 var table = addPresets(this.presetColors); 244 table.style.marginBottom = '8px'; 245 table = addPresets(this.defaultColors); 246 table.style.marginBottom = '16px'; 247 248 div.appendChild(center); 249 250 var buttons = document.createElement('div'); 251 buttons.style.textAlign = 'right'; 252 buttons.style.whiteSpace = 'nowrap'; 253 254 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 255 { 256 editorUi.hideDialog(); 257 258 if (cancelFn != null) 259 { 260 cancelFn(); 261 } 262 }); 263 cancelBtn.className = 'geBtn'; 264 265 if (editorUi.editor.cancelFirst) 266 { 267 buttons.appendChild(cancelBtn); 268 } 269 270 var applyBtn = mxUtils.button(mxResources.get('apply'), doApply); 271 applyBtn.className = 'geBtn gePrimaryBtn'; 272 buttons.appendChild(applyBtn); 273 274 if (!editorUi.editor.cancelFirst) 275 { 276 buttons.appendChild(cancelBtn); 277 } 278 279 if (color != null) 280 { 281 if (color == 'none') 282 { 283 picker.fromString('ffffff'); 284 input.value = 'none'; 285 } 286 else 287 { 288 picker.fromString(color); 289 } 290 } 291 292 div.appendChild(buttons); 293 this.picker = picker; 294 this.colorInput = input; 295 296 // LATER: Only fires if input if focused, should always 297 // fire if this dialog is showing. 298 mxEvent.addListener(div, 'keydown', function(e) 299 { 300 if (e.keyCode == 27) 301 { 302 editorUi.hideDialog(); 303 304 if (cancelFn != null) 305 { 306 cancelFn(); 307 } 308 309 mxEvent.consume(e); 310 } 311 }); 312 313 this.container = div; 314}; 315 316/** 317 * Creates function to apply value 318 */ 319ColorDialog.prototype.presetColors = ['E6D0DE', 'CDA2BE', 'B5739D', 'E1D5E7', 'C3ABD0', 'A680B8', 'D4E1F5', 'A9C4EB', '7EA6E0', 'D5E8D4', '9AC7BF', '67AB9F', 'D5E8D4', 'B9E0A5', '97D077', 'FFF2CC', 'FFE599', 'FFD966', 'FFF4C3', 'FFCE9F', 'FFB570', 'F8CECC', 'F19C99', 'EA6B66']; 320 321/** 322 * Creates function to apply value 323 */ 324 ColorDialog.prototype.colorNames = {}; 325 326/** 327 * Creates function to apply value 328 */ 329ColorDialog.prototype.defaultColors = ['none', 'FFFFFF', 'E6E6E6', 'CCCCCC', 'B3B3B3', '999999', '808080', '666666', '4D4D4D', '333333', '1A1A1A', '000000', 'FFCCCC', 'FFE6CC', 'FFFFCC', 'E6FFCC', 'CCFFCC', 'CCFFE6', 'CCFFFF', 'CCE5FF', 'CCCCFF', 'E5CCFF', 'FFCCFF', 'FFCCE6', 330 'FF9999', 'FFCC99', 'FFFF99', 'CCFF99', '99FF99', '99FFCC', '99FFFF', '99CCFF', '9999FF', 'CC99FF', 'FF99FF', 'FF99CC', 'FF6666', 'FFB366', 'FFFF66', 'B3FF66', '66FF66', '66FFB3', '66FFFF', '66B2FF', '6666FF', 'B266FF', 'FF66FF', 'FF66B3', 'FF3333', 'FF9933', 'FFFF33', 331 '99FF33', '33FF33', '33FF99', '33FFFF', '3399FF', '3333FF', '9933FF', 'FF33FF', 'FF3399', 'FF0000', 'FF8000', 'FFFF00', '80FF00', '00FF00', '00FF80', '00FFFF', '007FFF', '0000FF', '7F00FF', 'FF00FF', 'FF0080', 'CC0000', 'CC6600', 'CCCC00', '66CC00', '00CC00', '00CC66', 332 '00CCCC', '0066CC', '0000CC', '6600CC', 'CC00CC', 'CC0066', '990000', '994C00', '999900', '4D9900', '009900', '00994D', '009999', '004C99', '000099', '4C0099', '990099', '99004D', '660000', '663300', '666600', '336600', '006600', '006633', '006666', '003366', '000066', 333 '330066', '660066', '660033', '330000', '331A00', '333300', '1A3300', '003300', '00331A', '003333', '001933', '000033', '190033', '330033', '33001A']; 334 335/** 336 * Creates function to apply value 337 */ 338ColorDialog.prototype.createApplyFunction = function() 339{ 340 return mxUtils.bind(this, function(color) 341 { 342 var graph = this.editorUi.editor.graph; 343 344 graph.getModel().beginUpdate(); 345 try 346 { 347 graph.setCellStyles(this.currentColorKey, color); 348 this.editorUi.fireEvent(new mxEventObject('styleChanged', 'keys', [this.currentColorKey], 349 'values', [color], 'cells', graph.getSelectionCells())); 350 } 351 finally 352 { 353 graph.getModel().endUpdate(); 354 } 355 }); 356}; 357 358/** 359 * 360 */ 361ColorDialog.recentColors = []; 362 363/** 364 * Adds recent color for later use. 365 */ 366ColorDialog.addRecentColor = function(color, max) 367{ 368 if (color != null) 369 { 370 mxUtils.remove(color, ColorDialog.recentColors); 371 ColorDialog.recentColors.splice(0, 0, color); 372 373 if (ColorDialog.recentColors.length >= max) 374 { 375 ColorDialog.recentColors.pop(); 376 } 377 } 378}; 379 380/** 381 * Adds recent color for later use. 382 */ 383ColorDialog.resetRecentColors = function() 384{ 385 ColorDialog.recentColors = []; 386}; 387 388/** 389 * Constructs a new about dialog. 390 */ 391var AboutDialog = function(editorUi) 392{ 393 var div = document.createElement('div'); 394 div.setAttribute('align', 'center'); 395 var h3 = document.createElement('h3'); 396 mxUtils.write(h3, mxResources.get('about') + ' GraphEditor'); 397 div.appendChild(h3); 398 var img = document.createElement('img'); 399 img.style.border = '0px'; 400 img.setAttribute('width', '176'); 401 img.setAttribute('width', '151'); 402 img.setAttribute('src', IMAGE_PATH + '/logo.png'); 403 div.appendChild(img); 404 mxUtils.br(div); 405 mxUtils.write(div, 'Powered by mxGraph ' + mxClient.VERSION); 406 mxUtils.br(div); 407 var link = document.createElement('a'); 408 link.setAttribute('href', 'http://www.jgraph.com/'); 409 link.setAttribute('target', '_blank'); 410 mxUtils.write(link, 'www.jgraph.com'); 411 div.appendChild(link); 412 mxUtils.br(div); 413 mxUtils.br(div); 414 var closeBtn = mxUtils.button(mxResources.get('close'), function() 415 { 416 editorUi.hideDialog(); 417 }); 418 closeBtn.className = 'geBtn gePrimaryBtn'; 419 div.appendChild(closeBtn); 420 421 this.container = div; 422}; 423 424/** 425 * Constructs a new textarea dialog. 426 */ 427var TextareaDialog = function(editorUi, title, url, fn, cancelFn, cancelTitle, w, h, 428 addButtons, noHide, noWrap, applyTitle, helpLink, customButtons) 429{ 430 w = (w != null) ? w : 300; 431 h = (h != null) ? h : 120; 432 noHide = (noHide != null) ? noHide : false; 433 var row, td; 434 435 var table = document.createElement('table'); 436 var tbody = document.createElement('tbody'); 437 438 row = document.createElement('tr'); 439 440 td = document.createElement('td'); 441 td.style.fontSize = '10pt'; 442 td.style.width = '100px'; 443 mxUtils.write(td, title); 444 445 row.appendChild(td); 446 tbody.appendChild(row); 447 448 row = document.createElement('tr'); 449 td = document.createElement('td'); 450 451 var nameInput = document.createElement('textarea'); 452 453 if (noWrap) 454 { 455 nameInput.setAttribute('wrap', 'off'); 456 } 457 458 nameInput.setAttribute('spellcheck', 'false'); 459 nameInput.setAttribute('autocorrect', 'off'); 460 nameInput.setAttribute('autocomplete', 'off'); 461 nameInput.setAttribute('autocapitalize', 'off'); 462 463 mxUtils.write(nameInput, url || ''); 464 nameInput.style.resize = 'none'; 465 nameInput.style.width = w + 'px'; 466 nameInput.style.height = h + 'px'; 467 468 this.textarea = nameInput; 469 470 this.init = function() 471 { 472 nameInput.focus(); 473 nameInput.scrollTop = 0; 474 }; 475 476 td.appendChild(nameInput); 477 row.appendChild(td); 478 479 tbody.appendChild(row); 480 481 row = document.createElement('tr'); 482 td = document.createElement('td'); 483 td.style.paddingTop = '14px'; 484 td.style.whiteSpace = 'nowrap'; 485 td.setAttribute('align', 'right'); 486 487 if (helpLink != null) 488 { 489 var helpBtn = mxUtils.button(mxResources.get('help'), function() 490 { 491 editorUi.editor.graph.openLink(helpLink); 492 }); 493 helpBtn.className = 'geBtn'; 494 495 td.appendChild(helpBtn); 496 } 497 498 if (customButtons != null) 499 { 500 for (var i = 0; i < customButtons.length; i++) 501 { 502 (function(label, fn) 503 { 504 var customBtn = mxUtils.button(label, function(e) 505 { 506 fn(e, nameInput); 507 }); 508 customBtn.className = 'geBtn'; 509 510 td.appendChild(customBtn); 511 })(customButtons[i][0], customButtons[i][1]); 512 } 513 } 514 515 var cancelBtn = mxUtils.button(cancelTitle || mxResources.get('cancel'), function() 516 { 517 editorUi.hideDialog(); 518 519 if (cancelFn != null) 520 { 521 cancelFn(); 522 } 523 }); 524 cancelBtn.className = 'geBtn'; 525 526 if (editorUi.editor.cancelFirst) 527 { 528 td.appendChild(cancelBtn); 529 } 530 531 if (addButtons != null) 532 { 533 addButtons(td, nameInput); 534 } 535 536 if (fn != null) 537 { 538 var genericBtn = mxUtils.button(applyTitle || mxResources.get('apply'), function() 539 { 540 if (!noHide) 541 { 542 editorUi.hideDialog(); 543 } 544 545 fn(nameInput.value); 546 }); 547 548 genericBtn.className = 'geBtn gePrimaryBtn'; 549 td.appendChild(genericBtn); 550 } 551 552 if (!editorUi.editor.cancelFirst) 553 { 554 td.appendChild(cancelBtn); 555 } 556 557 row.appendChild(td); 558 tbody.appendChild(row); 559 table.appendChild(tbody); 560 this.container = table; 561}; 562 563/** 564 * Constructs a new edit file dialog. 565 */ 566var EditDiagramDialog = function(editorUi) 567{ 568 var div = document.createElement('div'); 569 div.style.textAlign = 'right'; 570 var textarea = document.createElement('textarea'); 571 textarea.setAttribute('wrap', 'off'); 572 textarea.setAttribute('spellcheck', 'false'); 573 textarea.setAttribute('autocorrect', 'off'); 574 textarea.setAttribute('autocomplete', 'off'); 575 textarea.setAttribute('autocapitalize', 'off'); 576 textarea.style.overflow = 'auto'; 577 textarea.style.resize = 'none'; 578 textarea.style.width = '600px'; 579 textarea.style.height = '360px'; 580 textarea.style.marginBottom = '16px'; 581 582 textarea.value = mxUtils.getPrettyXml(editorUi.editor.getGraphXml()); 583 div.appendChild(textarea); 584 585 this.init = function() 586 { 587 textarea.focus(); 588 }; 589 590 // Enables dropping files 591 if (Graph.fileSupport) 592 { 593 function handleDrop(evt) 594 { 595 evt.stopPropagation(); 596 evt.preventDefault(); 597 598 if (evt.dataTransfer.files.length > 0) 599 { 600 var file = evt.dataTransfer.files[0]; 601 var reader = new FileReader(); 602 603 reader.onload = function(e) 604 { 605 textarea.value = e.target.result; 606 }; 607 608 reader.readAsText(file); 609 } 610 else 611 { 612 textarea.value = editorUi.extractGraphModelFromEvent(evt); 613 } 614 }; 615 616 function handleDragOver(evt) 617 { 618 evt.stopPropagation(); 619 evt.preventDefault(); 620 }; 621 622 // Setup the dnd listeners. 623 textarea.addEventListener('dragover', handleDragOver, false); 624 textarea.addEventListener('drop', handleDrop, false); 625 } 626 627 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 628 { 629 editorUi.hideDialog(); 630 }); 631 cancelBtn.className = 'geBtn'; 632 633 if (editorUi.editor.cancelFirst) 634 { 635 div.appendChild(cancelBtn); 636 } 637 638 var select = document.createElement('select'); 639 select.style.width = '180px'; 640 select.className = 'geBtn'; 641 642 if (editorUi.editor.graph.isEnabled()) 643 { 644 var replaceOption = document.createElement('option'); 645 replaceOption.setAttribute('value', 'replace'); 646 mxUtils.write(replaceOption, mxResources.get('replaceExistingDrawing')); 647 select.appendChild(replaceOption); 648 } 649 650 var newOption = document.createElement('option'); 651 newOption.setAttribute('value', 'new'); 652 mxUtils.write(newOption, mxResources.get('openInNewWindow')); 653 654 if (EditDiagramDialog.showNewWindowOption) 655 { 656 select.appendChild(newOption); 657 } 658 659 if (editorUi.editor.graph.isEnabled()) 660 { 661 var importOption = document.createElement('option'); 662 importOption.setAttribute('value', 'import'); 663 mxUtils.write(importOption, mxResources.get('addToExistingDrawing')); 664 select.appendChild(importOption); 665 } 666 667 div.appendChild(select); 668 669 var okBtn = mxUtils.button(mxResources.get('ok'), function() 670 { 671 // Removes all illegal control characters before parsing 672 var data = Graph.zapGremlins(mxUtils.trim(textarea.value)); 673 var error = null; 674 675 if (select.value == 'new') 676 { 677 editorUi.hideDialog(); 678 editorUi.editor.editAsNew(data); 679 } 680 else if (select.value == 'replace') 681 { 682 editorUi.editor.graph.model.beginUpdate(); 683 try 684 { 685 editorUi.editor.setGraphXml(mxUtils.parseXml(data).documentElement); 686 // LATER: Why is hideDialog between begin-/endUpdate faster? 687 editorUi.hideDialog(); 688 } 689 catch (e) 690 { 691 error = e; 692 } 693 finally 694 { 695 editorUi.editor.graph.model.endUpdate(); 696 } 697 } 698 else if (select.value == 'import') 699 { 700 editorUi.editor.graph.model.beginUpdate(); 701 try 702 { 703 var doc = mxUtils.parseXml(data); 704 var model = new mxGraphModel(); 705 var codec = new mxCodec(doc); 706 codec.decode(doc.documentElement, model); 707 708 var children = model.getChildren(model.getChildAt(model.getRoot(), 0)); 709 editorUi.editor.graph.setSelectionCells(editorUi.editor.graph.importCells(children)); 710 711 // LATER: Why is hideDialog between begin-/endUpdate faster? 712 editorUi.hideDialog(); 713 } 714 catch (e) 715 { 716 error = e; 717 } 718 finally 719 { 720 editorUi.editor.graph.model.endUpdate(); 721 } 722 } 723 724 if (error != null) 725 { 726 mxUtils.alert(error.message); 727 } 728 }); 729 okBtn.className = 'geBtn gePrimaryBtn'; 730 div.appendChild(okBtn); 731 732 if (!editorUi.editor.cancelFirst) 733 { 734 div.appendChild(cancelBtn); 735 } 736 737 this.container = div; 738}; 739 740/** 741 * 742 */ 743EditDiagramDialog.showNewWindowOption = true; 744 745/** 746 * Constructs a new export dialog. 747 */ 748var ExportDialog = function(editorUi) 749{ 750 var graph = editorUi.editor.graph; 751 var bounds = graph.getGraphBounds(); 752 var scale = graph.view.scale; 753 754 var width = Math.ceil(bounds.width / scale); 755 var height = Math.ceil(bounds.height / scale); 756 757 var row, td; 758 759 var table = document.createElement('table'); 760 var tbody = document.createElement('tbody'); 761 table.setAttribute('cellpadding', (mxClient.IS_SF) ? '0' : '2'); 762 763 row = document.createElement('tr'); 764 765 td = document.createElement('td'); 766 td.style.fontSize = '10pt'; 767 td.style.width = '100px'; 768 mxUtils.write(td, mxResources.get('filename') + ':'); 769 770 row.appendChild(td); 771 772 var nameInput = document.createElement('input'); 773 nameInput.setAttribute('value', editorUi.editor.getOrCreateFilename()); 774 nameInput.style.width = '180px'; 775 776 td = document.createElement('td'); 777 td.appendChild(nameInput); 778 row.appendChild(td); 779 780 tbody.appendChild(row); 781 782 row = document.createElement('tr'); 783 784 td = document.createElement('td'); 785 td.style.fontSize = '10pt'; 786 mxUtils.write(td, mxResources.get('format') + ':'); 787 788 row.appendChild(td); 789 790 var imageFormatSelect = document.createElement('select'); 791 imageFormatSelect.style.width = '180px'; 792 793 var pngOption = document.createElement('option'); 794 pngOption.setAttribute('value', 'png'); 795 mxUtils.write(pngOption, mxResources.get('formatPng')); 796 imageFormatSelect.appendChild(pngOption); 797 798 var gifOption = document.createElement('option'); 799 800 if (ExportDialog.showGifOption) 801 { 802 gifOption.setAttribute('value', 'gif'); 803 mxUtils.write(gifOption, mxResources.get('formatGif')); 804 imageFormatSelect.appendChild(gifOption); 805 } 806 807 var jpgOption = document.createElement('option'); 808 jpgOption.setAttribute('value', 'jpg'); 809 mxUtils.write(jpgOption, mxResources.get('formatJpg')); 810 imageFormatSelect.appendChild(jpgOption); 811 812 var pdfOption = document.createElement('option'); 813 pdfOption.setAttribute('value', 'pdf'); 814 mxUtils.write(pdfOption, mxResources.get('formatPdf')); 815 imageFormatSelect.appendChild(pdfOption); 816 817 var svgOption = document.createElement('option'); 818 svgOption.setAttribute('value', 'svg'); 819 mxUtils.write(svgOption, mxResources.get('formatSvg')); 820 imageFormatSelect.appendChild(svgOption); 821 822 if (ExportDialog.showXmlOption) 823 { 824 var xmlOption = document.createElement('option'); 825 xmlOption.setAttribute('value', 'xml'); 826 mxUtils.write(xmlOption, mxResources.get('formatXml')); 827 imageFormatSelect.appendChild(xmlOption); 828 } 829 830 td = document.createElement('td'); 831 td.appendChild(imageFormatSelect); 832 row.appendChild(td); 833 834 tbody.appendChild(row); 835 836 row = document.createElement('tr'); 837 838 td = document.createElement('td'); 839 td.style.fontSize = '10pt'; 840 mxUtils.write(td, mxResources.get('zoom') + ' (%):'); 841 842 row.appendChild(td); 843 844 var zoomInput = document.createElement('input'); 845 zoomInput.setAttribute('type', 'number'); 846 zoomInput.setAttribute('value', '100'); 847 zoomInput.style.width = '180px'; 848 849 td = document.createElement('td'); 850 td.appendChild(zoomInput); 851 row.appendChild(td); 852 853 tbody.appendChild(row); 854 855 row = document.createElement('tr'); 856 857 td = document.createElement('td'); 858 td.style.fontSize = '10pt'; 859 mxUtils.write(td, mxResources.get('width') + ':'); 860 861 row.appendChild(td); 862 863 var widthInput = document.createElement('input'); 864 widthInput.setAttribute('value', width); 865 widthInput.style.width = '180px'; 866 867 td = document.createElement('td'); 868 td.appendChild(widthInput); 869 row.appendChild(td); 870 871 tbody.appendChild(row); 872 873 row = document.createElement('tr'); 874 875 td = document.createElement('td'); 876 td.style.fontSize = '10pt'; 877 mxUtils.write(td, mxResources.get('height') + ':'); 878 879 row.appendChild(td); 880 881 var heightInput = document.createElement('input'); 882 heightInput.setAttribute('value', height); 883 heightInput.style.width = '180px'; 884 885 td = document.createElement('td'); 886 td.appendChild(heightInput); 887 row.appendChild(td); 888 889 tbody.appendChild(row); 890 891 row = document.createElement('tr'); 892 893 td = document.createElement('td'); 894 td.style.fontSize = '10pt'; 895 mxUtils.write(td, mxResources.get('dpi') + ':'); 896 897 row.appendChild(td); 898 899 var dpiSelect = document.createElement('select'); 900 dpiSelect.style.width = '180px'; 901 902 var dpi100Option = document.createElement('option'); 903 dpi100Option.setAttribute('value', '100'); 904 mxUtils.write(dpi100Option, '100dpi'); 905 dpiSelect.appendChild(dpi100Option); 906 907 var dpi200Option = document.createElement('option'); 908 dpi200Option.setAttribute('value', '200'); 909 mxUtils.write(dpi200Option, '200dpi'); 910 dpiSelect.appendChild(dpi200Option); 911 912 var dpi300Option = document.createElement('option'); 913 dpi300Option.setAttribute('value', '300'); 914 mxUtils.write(dpi300Option, '300dpi'); 915 dpiSelect.appendChild(dpi300Option); 916 917 var dpi400Option = document.createElement('option'); 918 dpi400Option.setAttribute('value', '400'); 919 mxUtils.write(dpi400Option, '400dpi'); 920 dpiSelect.appendChild(dpi400Option); 921 922 var dpiCustOption = document.createElement('option'); 923 dpiCustOption.setAttribute('value', 'custom'); 924 mxUtils.write(dpiCustOption, mxResources.get('custom')); 925 dpiSelect.appendChild(dpiCustOption); 926 927 var customDpi = document.createElement('input'); 928 customDpi.style.width = '180px'; 929 customDpi.style.display = 'none'; 930 customDpi.setAttribute('value', '100'); 931 customDpi.setAttribute('type', 'number'); 932 customDpi.setAttribute('min', '50'); 933 customDpi.setAttribute('step', '50'); 934 935 var zoomUserChanged = false; 936 937 mxEvent.addListener(dpiSelect, 'change', function() 938 { 939 if (this.value == 'custom') 940 { 941 this.style.display = 'none'; 942 customDpi.style.display = ''; 943 customDpi.focus(); 944 } 945 else 946 { 947 customDpi.value = this.value; 948 949 if (!zoomUserChanged) 950 { 951 zoomInput.value = this.value; 952 } 953 } 954 }); 955 956 mxEvent.addListener(customDpi, 'change', function() 957 { 958 var dpi = parseInt(customDpi.value); 959 960 if (isNaN(dpi) || dpi <= 0) 961 { 962 customDpi.style.backgroundColor = 'red'; 963 } 964 else 965 { 966 customDpi.style.backgroundColor = ''; 967 968 if (!zoomUserChanged) 969 { 970 zoomInput.value = dpi; 971 } 972 } 973 }); 974 975 td = document.createElement('td'); 976 td.appendChild(dpiSelect); 977 td.appendChild(customDpi); 978 row.appendChild(td); 979 980 tbody.appendChild(row); 981 982 row = document.createElement('tr'); 983 984 td = document.createElement('td'); 985 td.style.fontSize = '10pt'; 986 mxUtils.write(td, mxResources.get('background') + ':'); 987 988 row.appendChild(td); 989 990 var transparentCheckbox = document.createElement('input'); 991 transparentCheckbox.setAttribute('type', 'checkbox'); 992 transparentCheckbox.checked = graph.background == null || graph.background == mxConstants.NONE; 993 994 td = document.createElement('td'); 995 td.appendChild(transparentCheckbox); 996 mxUtils.write(td, mxResources.get('transparent')); 997 998 row.appendChild(td); 999 1000 tbody.appendChild(row); 1001 1002 row = document.createElement('tr'); 1003 1004 td = document.createElement('td'); 1005 td.style.fontSize = '10pt'; 1006 mxUtils.write(td, mxResources.get('grid') + ':'); 1007 1008 row.appendChild(td); 1009 1010 var gridCheckbox = document.createElement('input'); 1011 gridCheckbox.setAttribute('type', 'checkbox'); 1012 gridCheckbox.checked = false; 1013 1014 td = document.createElement('td'); 1015 td.appendChild(gridCheckbox); 1016 1017 row.appendChild(td); 1018 1019 tbody.appendChild(row); 1020 1021 row = document.createElement('tr'); 1022 1023 td = document.createElement('td'); 1024 td.style.fontSize = '10pt'; 1025 mxUtils.write(td, mxResources.get('borderWidth') + ':'); 1026 1027 row.appendChild(td); 1028 1029 var borderInput = document.createElement('input'); 1030 borderInput.setAttribute('type', 'number'); 1031 borderInput.setAttribute('value', ExportDialog.lastBorderValue); 1032 borderInput.style.width = '180px'; 1033 1034 td = document.createElement('td'); 1035 td.appendChild(borderInput); 1036 row.appendChild(td); 1037 1038 tbody.appendChild(row); 1039 table.appendChild(tbody); 1040 1041 // Handles changes in the export format 1042 function formatChanged() 1043 { 1044 var name = nameInput.value; 1045 var dot = name.lastIndexOf('.'); 1046 1047 if (dot > 0) 1048 { 1049 nameInput.value = name.substring(0, dot + 1) + imageFormatSelect.value; 1050 } 1051 else 1052 { 1053 nameInput.value = name + '.' + imageFormatSelect.value; 1054 } 1055 1056 if (imageFormatSelect.value === 'xml') 1057 { 1058 zoomInput.setAttribute('disabled', 'true'); 1059 widthInput.setAttribute('disabled', 'true'); 1060 heightInput.setAttribute('disabled', 'true'); 1061 borderInput.setAttribute('disabled', 'true'); 1062 } 1063 else 1064 { 1065 zoomInput.removeAttribute('disabled'); 1066 widthInput.removeAttribute('disabled'); 1067 heightInput.removeAttribute('disabled'); 1068 borderInput.removeAttribute('disabled'); 1069 } 1070 1071 if (imageFormatSelect.value === 'png' || imageFormatSelect.value === 'svg' || imageFormatSelect.value === 'pdf') 1072 { 1073 transparentCheckbox.removeAttribute('disabled'); 1074 } 1075 else 1076 { 1077 transparentCheckbox.setAttribute('disabled', 'disabled'); 1078 } 1079 1080 if (imageFormatSelect.value === 'png' || imageFormatSelect.value === 'jpg' || imageFormatSelect.value === 'pdf') 1081 { 1082 gridCheckbox.removeAttribute('disabled'); 1083 } 1084 else 1085 { 1086 gridCheckbox.setAttribute('disabled', 'disabled'); 1087 } 1088 1089 if (imageFormatSelect.value === 'png') 1090 { 1091 dpiSelect.removeAttribute('disabled'); 1092 customDpi.removeAttribute('disabled'); 1093 } 1094 else 1095 { 1096 dpiSelect.setAttribute('disabled', 'disabled'); 1097 customDpi.setAttribute('disabled', 'disabled'); 1098 } 1099 }; 1100 1101 mxEvent.addListener(imageFormatSelect, 'change', formatChanged); 1102 formatChanged(); 1103 1104 function checkValues() 1105 { 1106 if (widthInput.value * heightInput.value > MAX_AREA || widthInput.value <= 0) 1107 { 1108 widthInput.style.backgroundColor = 'red'; 1109 } 1110 else 1111 { 1112 widthInput.style.backgroundColor = ''; 1113 } 1114 1115 if (widthInput.value * heightInput.value > MAX_AREA || heightInput.value <= 0) 1116 { 1117 heightInput.style.backgroundColor = 'red'; 1118 } 1119 else 1120 { 1121 heightInput.style.backgroundColor = ''; 1122 } 1123 }; 1124 1125 mxEvent.addListener(zoomInput, 'change', function() 1126 { 1127 zoomUserChanged = true; 1128 var s = Math.max(0, parseFloat(zoomInput.value) || 100) / 100; 1129 zoomInput.value = parseFloat((s * 100).toFixed(2)); 1130 1131 if (width > 0) 1132 { 1133 widthInput.value = Math.floor(width * s); 1134 heightInput.value = Math.floor(height * s); 1135 } 1136 else 1137 { 1138 zoomInput.value = '100'; 1139 widthInput.value = width; 1140 heightInput.value = height; 1141 } 1142 1143 checkValues(); 1144 }); 1145 1146 mxEvent.addListener(widthInput, 'change', function() 1147 { 1148 var s = parseInt(widthInput.value) / width; 1149 1150 if (s > 0) 1151 { 1152 zoomInput.value = parseFloat((s * 100).toFixed(2)); 1153 heightInput.value = Math.floor(height * s); 1154 } 1155 else 1156 { 1157 zoomInput.value = '100'; 1158 widthInput.value = width; 1159 heightInput.value = height; 1160 } 1161 1162 checkValues(); 1163 }); 1164 1165 mxEvent.addListener(heightInput, 'change', function() 1166 { 1167 var s = parseInt(heightInput.value) / height; 1168 1169 if (s > 0) 1170 { 1171 zoomInput.value = parseFloat((s * 100).toFixed(2)); 1172 widthInput.value = Math.floor(width * s); 1173 } 1174 else 1175 { 1176 zoomInput.value = '100'; 1177 widthInput.value = width; 1178 heightInput.value = height; 1179 } 1180 1181 checkValues(); 1182 }); 1183 1184 row = document.createElement('tr'); 1185 td = document.createElement('td'); 1186 td.setAttribute('align', 'right'); 1187 td.style.paddingTop = '22px'; 1188 td.colSpan = 2; 1189 1190 var saveBtn = mxUtils.button(mxResources.get('export'), mxUtils.bind(this, function() 1191 { 1192 if (parseInt(zoomInput.value) <= 0) 1193 { 1194 mxUtils.alert(mxResources.get('drawingEmpty')); 1195 } 1196 else 1197 { 1198 var name = nameInput.value; 1199 var format = imageFormatSelect.value; 1200 var s = Math.max(0, parseFloat(zoomInput.value) || 100) / 100; 1201 var b = Math.max(0, parseInt(borderInput.value)); 1202 var bg = graph.background; 1203 var dpi = Math.max(1, parseInt(customDpi.value)); 1204 1205 if ((format == 'svg' || format == 'png' || format == 'pdf') && transparentCheckbox.checked) 1206 { 1207 bg = null; 1208 } 1209 else if (bg == null || bg == mxConstants.NONE) 1210 { 1211 bg = '#ffffff'; 1212 } 1213 1214 ExportDialog.lastBorderValue = b; 1215 ExportDialog.exportFile(editorUi, name, format, bg, s, b, dpi, gridCheckbox.checked); 1216 } 1217 })); 1218 saveBtn.className = 'geBtn gePrimaryBtn'; 1219 1220 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 1221 { 1222 editorUi.hideDialog(); 1223 }); 1224 cancelBtn.className = 'geBtn'; 1225 1226 if (editorUi.editor.cancelFirst) 1227 { 1228 td.appendChild(cancelBtn); 1229 td.appendChild(saveBtn); 1230 } 1231 else 1232 { 1233 td.appendChild(saveBtn); 1234 td.appendChild(cancelBtn); 1235 } 1236 1237 row.appendChild(td); 1238 tbody.appendChild(row); 1239 table.appendChild(tbody); 1240 this.container = table; 1241}; 1242 1243/** 1244 * Remembers last value for border. 1245 */ 1246ExportDialog.lastBorderValue = 0; 1247 1248/** 1249 * Global switches for the export dialog. 1250 */ 1251ExportDialog.showGifOption = true; 1252 1253/** 1254 * Global switches for the export dialog. 1255 */ 1256ExportDialog.showXmlOption = true; 1257 1258/** 1259 * Hook for getting the export format. Returns null for the default 1260 * intermediate XML export format or a function that returns the 1261 * parameter and value to be used in the request in the form 1262 * key=value, where value should be URL encoded. 1263 */ 1264ExportDialog.exportFile = function(editorUi, name, format, bg, s, b, dpi, grid) 1265{ 1266 var graph = editorUi.editor.graph; 1267 1268 if (format == 'xml') 1269 { 1270 ExportDialog.saveLocalFile(editorUi, mxUtils.getXml(editorUi.editor.getGraphXml()), name, format); 1271 } 1272 else if (format == 'svg') 1273 { 1274 ExportDialog.saveLocalFile(editorUi, mxUtils.getXml(graph.getSvg(bg, s, b)), name, format); 1275 } 1276 else 1277 { 1278 var bounds = graph.getGraphBounds(); 1279 1280 // New image export 1281 var xmlDoc = mxUtils.createXmlDocument(); 1282 var root = xmlDoc.createElement('output'); 1283 xmlDoc.appendChild(root); 1284 1285 // Renders graph. Offset will be multiplied with state's scale when painting state. 1286 var xmlCanvas = new mxXmlCanvas2D(root); 1287 xmlCanvas.translate(Math.floor((b / s - bounds.x) / graph.view.scale), 1288 Math.floor((b / s - bounds.y) / graph.view.scale)); 1289 xmlCanvas.scale(s / graph.view.scale); 1290 1291 var imgExport = new mxImageExport() 1292 imgExport.drawState(graph.getView().getState(graph.model.root), xmlCanvas); 1293 1294 // Puts request data together 1295 var param = 'xml=' + encodeURIComponent(mxUtils.getXml(root)); 1296 var w = Math.ceil(bounds.width * s / graph.view.scale + 2 * b); 1297 var h = Math.ceil(bounds.height * s / graph.view.scale + 2 * b); 1298 1299 // Requests image if request is valid 1300 if (param.length <= MAX_REQUEST_SIZE && w * h < MAX_AREA) 1301 { 1302 editorUi.hideDialog(); 1303 var req = new mxXmlRequest(EXPORT_URL, 'format=' + format + 1304 '&filename=' + encodeURIComponent(name) + 1305 '&bg=' + ((bg != null) ? bg : 'none') + 1306 '&w=' + w + '&h=' + h + '&' + param + 1307 '&dpi=' + dpi); 1308 req.simulate(document, '_blank'); 1309 } 1310 else 1311 { 1312 mxUtils.alert(mxResources.get('drawingTooLarge')); 1313 } 1314 } 1315}; 1316 1317/** 1318 * Hook for getting the export format. Returns null for the default 1319 * intermediate XML export format or a function that returns the 1320 * parameter and value to be used in the request in the form 1321 * key=value, where value should be URL encoded. 1322 */ 1323ExportDialog.saveLocalFile = function(editorUi, data, filename, format) 1324{ 1325 if (data.length < MAX_REQUEST_SIZE) 1326 { 1327 editorUi.hideDialog(); 1328 var req = new mxXmlRequest(SAVE_URL, 'xml=' + encodeURIComponent(data) + '&filename=' + 1329 encodeURIComponent(filename) + '&format=' + format); 1330 req.simulate(document, '_blank'); 1331 } 1332 else 1333 { 1334 mxUtils.alert(mxResources.get('drawingTooLarge')); 1335 mxUtils.popup(xml); 1336 } 1337}; 1338 1339/** 1340 * Constructs a new metadata dialog. 1341 */ 1342var EditDataDialog = function(ui, cell) 1343{ 1344 var div = document.createElement('div'); 1345 var graph = ui.editor.graph; 1346 1347 var value = graph.getModel().getValue(cell); 1348 1349 // Converts the value to an XML node 1350 if (!mxUtils.isNode(value)) 1351 { 1352 var doc = mxUtils.createXmlDocument(); 1353 var obj = doc.createElement('object'); 1354 obj.setAttribute('label', value || ''); 1355 value = obj; 1356 } 1357 1358 var meta = {}; 1359 1360 try 1361 { 1362 var temp = mxUtils.getValue(ui.editor.graph.getCurrentCellStyle(cell), 'metaData', null); 1363 1364 if (temp != null) 1365 { 1366 meta = JSON.parse(temp); 1367 } 1368 } 1369 catch (e) 1370 { 1371 // ignore 1372 } 1373 1374 // Creates the dialog contents 1375 var form = new mxForm('properties'); 1376 form.table.style.width = '100%'; 1377 1378 var attrs = value.attributes; 1379 var names = []; 1380 var texts = []; 1381 var count = 0; 1382 1383 var id = (EditDataDialog.getDisplayIdForCell != null) ? 1384 EditDataDialog.getDisplayIdForCell(ui, cell) : null; 1385 1386 var addRemoveButton = function(text, name) 1387 { 1388 var wrapper = document.createElement('div'); 1389 wrapper.style.position = 'relative'; 1390 wrapper.style.paddingRight = '20px'; 1391 wrapper.style.boxSizing = 'border-box'; 1392 wrapper.style.width = '100%'; 1393 1394 var removeAttr = document.createElement('a'); 1395 var img = mxUtils.createImage(Dialog.prototype.closeImage); 1396 img.style.height = '9px'; 1397 img.style.fontSize = '9px'; 1398 img.style.marginBottom = (mxClient.IS_IE11) ? '-1px' : '5px'; 1399 1400 removeAttr.className = 'geButton'; 1401 removeAttr.setAttribute('title', mxResources.get('delete')); 1402 removeAttr.style.position = 'absolute'; 1403 removeAttr.style.top = '4px'; 1404 removeAttr.style.right = '0px'; 1405 removeAttr.style.margin = '0px'; 1406 removeAttr.style.width = '9px'; 1407 removeAttr.style.height = '9px'; 1408 removeAttr.style.cursor = 'pointer'; 1409 removeAttr.appendChild(img); 1410 1411 var removeAttrFn = (function(name) 1412 { 1413 return function() 1414 { 1415 var count = 0; 1416 1417 for (var j = 0; j < names.length; j++) 1418 { 1419 if (names[j] == name) 1420 { 1421 texts[j] = null; 1422 form.table.deleteRow(count + ((id != null) ? 1 : 0)); 1423 1424 break; 1425 } 1426 1427 if (texts[j] != null) 1428 { 1429 count++; 1430 } 1431 } 1432 }; 1433 })(name); 1434 1435 mxEvent.addListener(removeAttr, 'click', removeAttrFn); 1436 1437 var parent = text.parentNode; 1438 wrapper.appendChild(text); 1439 wrapper.appendChild(removeAttr); 1440 parent.appendChild(wrapper); 1441 }; 1442 1443 var addTextArea = function(index, name, value) 1444 { 1445 names[index] = name; 1446 texts[index] = form.addTextarea(names[count] + ':', value, 2); 1447 texts[index].style.width = '100%'; 1448 1449 if (value.indexOf('\n') > 0) 1450 { 1451 texts[index].setAttribute('rows', '2'); 1452 } 1453 1454 addRemoveButton(texts[index], name); 1455 1456 if (meta[name] != null && meta[name].editable == false) 1457 { 1458 texts[index].setAttribute('disabled', 'disabled'); 1459 } 1460 }; 1461 1462 var temp = []; 1463 var isLayer = graph.getModel().getParent(cell) == graph.getModel().getRoot(); 1464 1465 for (var i = 0; i < attrs.length; i++) 1466 { 1467 if ((isLayer || attrs[i].nodeName != 'label') && attrs[i].nodeName != 'placeholders') 1468 { 1469 temp.push({name: attrs[i].nodeName, value: attrs[i].nodeValue}); 1470 } 1471 } 1472 1473 // Sorts by name 1474 temp.sort(function(a, b) 1475 { 1476 if (a.name < b.name) 1477 { 1478 return -1; 1479 } 1480 else if (a.name > b.name) 1481 { 1482 return 1; 1483 } 1484 else 1485 { 1486 return 0; 1487 } 1488 }); 1489 1490 if (id != null) 1491 { 1492 var text = document.createElement('div'); 1493 text.style.width = '100%'; 1494 text.style.fontSize = '11px'; 1495 text.style.textAlign = 'center'; 1496 mxUtils.write(text, id); 1497 1498 var idInput = form.addField(mxResources.get('id') + ':', text); 1499 1500 mxEvent.addListener(text, 'dblclick', function(evt) 1501 { 1502 if (mxEvent.isShiftDown(evt)) 1503 { 1504 var dlg = new FilenameDialog(ui, id, mxResources.get('apply'), mxUtils.bind(this, function(value) 1505 { 1506 if (value != null && value.length > 0 && value != id) 1507 { 1508 if (graph.getModel().getCell(value) == null) 1509 { 1510 graph.getModel().cellRemoved(cell); 1511 cell.setId(value); 1512 id = value; 1513 idInput.innerHTML = mxUtils.htmlEntities(value); 1514 graph.getModel().cellAdded(cell); 1515 } 1516 else 1517 { 1518 ui.handleError({message: mxResources.get('alreadyExst', [value])}); 1519 } 1520 } 1521 }), mxResources.get('id')); 1522 ui.showDialog(dlg.container, 300, 80, true, true); 1523 dlg.init(); 1524 } 1525 }); 1526 1527 text.setAttribute('title', 'Shift+Double Click to Edit ID'); 1528 } 1529 1530 for (var i = 0; i < temp.length; i++) 1531 { 1532 addTextArea(count, temp[i].name, temp[i].value); 1533 count++; 1534 } 1535 1536 var top = document.createElement('div'); 1537 top.style.position = 'absolute'; 1538 top.style.top = '30px'; 1539 top.style.left = '30px'; 1540 top.style.right = '30px'; 1541 top.style.bottom = '80px'; 1542 top.style.overflowY = 'auto'; 1543 1544 top.appendChild(form.table); 1545 1546 var newProp = document.createElement('div'); 1547 newProp.style.boxSizing = 'border-box'; 1548 newProp.style.paddingRight = '160px'; 1549 newProp.style.whiteSpace = 'nowrap'; 1550 newProp.style.marginTop = '6px'; 1551 newProp.style.width = '100%'; 1552 1553 var nameInput = document.createElement('input'); 1554 nameInput.setAttribute('placeholder', mxResources.get('enterPropertyName')); 1555 nameInput.setAttribute('type', 'text'); 1556 nameInput.setAttribute('size', (mxClient.IS_IE || mxClient.IS_IE11) ? '36' : '40'); 1557 nameInput.style.boxSizing = 'border-box'; 1558 nameInput.style.marginLeft = '2px'; 1559 nameInput.style.width = '100%'; 1560 1561 newProp.appendChild(nameInput); 1562 top.appendChild(newProp); 1563 div.appendChild(top); 1564 1565 var addBtn = mxUtils.button(mxResources.get('addProperty'), function() 1566 { 1567 var name = nameInput.value; 1568 1569 // Avoid ':' in attribute names which seems to be valid in Chrome 1570 if (name.length > 0 && name != 'label' && name != 'placeholders' && name.indexOf(':') < 0) 1571 { 1572 try 1573 { 1574 var idx = mxUtils.indexOf(names, name); 1575 1576 if (idx >= 0 && texts[idx] != null) 1577 { 1578 texts[idx].focus(); 1579 } 1580 else 1581 { 1582 // Checks if the name is valid 1583 var clone = value.cloneNode(false); 1584 clone.setAttribute(name, ''); 1585 1586 if (idx >= 0) 1587 { 1588 names.splice(idx, 1); 1589 texts.splice(idx, 1); 1590 } 1591 1592 names.push(name); 1593 var text = form.addTextarea(name + ':', '', 2); 1594 text.style.width = '100%'; 1595 texts.push(text); 1596 addRemoveButton(text, name); 1597 1598 text.focus(); 1599 } 1600 1601 addBtn.setAttribute('disabled', 'disabled'); 1602 nameInput.value = ''; 1603 } 1604 catch (e) 1605 { 1606 mxUtils.alert(e); 1607 } 1608 } 1609 else 1610 { 1611 mxUtils.alert(mxResources.get('invalidName')); 1612 } 1613 }); 1614 1615 this.init = function() 1616 { 1617 if (texts.length > 0) 1618 { 1619 texts[0].focus(); 1620 } 1621 else 1622 { 1623 nameInput.focus(); 1624 } 1625 }; 1626 1627 addBtn.setAttribute('title', mxResources.get('addProperty')); 1628 addBtn.setAttribute('disabled', 'disabled'); 1629 addBtn.style.textOverflow = 'ellipsis'; 1630 addBtn.style.position = 'absolute'; 1631 addBtn.style.overflow = 'hidden'; 1632 addBtn.style.width = '144px'; 1633 addBtn.style.right = '0px'; 1634 addBtn.className = 'geBtn'; 1635 newProp.appendChild(addBtn); 1636 1637 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 1638 { 1639 ui.hideDialog.apply(ui, arguments); 1640 }); 1641 1642 cancelBtn.className = 'geBtn'; 1643 1644 var applyBtn = mxUtils.button(mxResources.get('apply'), function() 1645 { 1646 try 1647 { 1648 ui.hideDialog.apply(ui, arguments); 1649 1650 // Clones and updates the value 1651 value = value.cloneNode(true); 1652 var removeLabel = false; 1653 1654 for (var i = 0; i < names.length; i++) 1655 { 1656 if (texts[i] == null) 1657 { 1658 value.removeAttribute(names[i]); 1659 } 1660 else 1661 { 1662 value.setAttribute(names[i], texts[i].value); 1663 removeLabel = removeLabel || (names[i] == 'placeholder' && 1664 value.getAttribute('placeholders') == '1'); 1665 } 1666 } 1667 1668 // Removes label if placeholder is assigned 1669 if (removeLabel) 1670 { 1671 value.removeAttribute('label'); 1672 } 1673 1674 // Updates the value of the cell (undoable) 1675 graph.getModel().setValue(cell, value); 1676 } 1677 catch (e) 1678 { 1679 mxUtils.alert(e); 1680 } 1681 }); 1682 applyBtn.className = 'geBtn gePrimaryBtn'; 1683 1684 function updateAddBtn() 1685 { 1686 if (nameInput.value.length > 0) 1687 { 1688 addBtn.removeAttribute('disabled'); 1689 } 1690 else 1691 { 1692 addBtn.setAttribute('disabled', 'disabled'); 1693 } 1694 }; 1695 1696 mxEvent.addListener(nameInput, 'keyup', updateAddBtn); 1697 1698 // Catches all changes that don't fire a keyup (such as paste via mouse) 1699 mxEvent.addListener(nameInput, 'change', updateAddBtn); 1700 1701 var buttons = document.createElement('div'); 1702 buttons.style.cssText = 'position:absolute;left:30px;right:30px;text-align:right;bottom:30px;height:40px;' 1703 1704 if (ui.editor.graph.getModel().isVertex(cell) || ui.editor.graph.getModel().isEdge(cell)) 1705 { 1706 var replace = document.createElement('span'); 1707 replace.style.marginRight = '10px'; 1708 var input = document.createElement('input'); 1709 input.setAttribute('type', 'checkbox'); 1710 input.style.marginRight = '6px'; 1711 1712 if (value.getAttribute('placeholders') == '1') 1713 { 1714 input.setAttribute('checked', 'checked'); 1715 input.defaultChecked = true; 1716 } 1717 1718 mxEvent.addListener(input, 'click', function() 1719 { 1720 if (value.getAttribute('placeholders') == '1') 1721 { 1722 value.removeAttribute('placeholders'); 1723 } 1724 else 1725 { 1726 value.setAttribute('placeholders', '1'); 1727 } 1728 }); 1729 1730 replace.appendChild(input); 1731 mxUtils.write(replace, mxResources.get('placeholders')); 1732 1733 if (EditDataDialog.placeholderHelpLink != null) 1734 { 1735 var link = document.createElement('a'); 1736 link.setAttribute('href', EditDataDialog.placeholderHelpLink); 1737 link.setAttribute('title', mxResources.get('help')); 1738 link.setAttribute('target', '_blank'); 1739 link.style.marginLeft = '8px'; 1740 link.style.cursor = 'help'; 1741 1742 var icon = document.createElement('img'); 1743 mxUtils.setOpacity(icon, 50); 1744 icon.style.height = '16px'; 1745 icon.style.width = '16px'; 1746 icon.setAttribute('border', '0'); 1747 icon.setAttribute('valign', 'middle'); 1748 icon.style.marginTop = (mxClient.IS_IE11) ? '0px' : '-4px'; 1749 icon.setAttribute('src', Editor.helpImage); 1750 link.appendChild(icon); 1751 1752 replace.appendChild(link); 1753 } 1754 1755 buttons.appendChild(replace); 1756 } 1757 1758 if (ui.editor.cancelFirst) 1759 { 1760 buttons.appendChild(cancelBtn); 1761 buttons.appendChild(applyBtn); 1762 } 1763 else 1764 { 1765 buttons.appendChild(applyBtn); 1766 buttons.appendChild(cancelBtn); 1767 } 1768 1769 div.appendChild(buttons); 1770 this.container = div; 1771}; 1772 1773/** 1774 * Optional help link. 1775 */ 1776EditDataDialog.getDisplayIdForCell = function(ui, cell) 1777{ 1778 var id = null; 1779 1780 if (ui.editor.graph.getModel().getParent(cell) != null) 1781 { 1782 id = cell.getId(); 1783 } 1784 1785 return id; 1786}; 1787 1788/** 1789 * Optional help link. 1790 */ 1791EditDataDialog.placeholderHelpLink = null; 1792 1793/** 1794 * Constructs a new link dialog. 1795 */ 1796var LinkDialog = function(editorUi, initialValue, btnLabel, fn) 1797{ 1798 var div = document.createElement('div'); 1799 mxUtils.write(div, mxResources.get('editLink') + ':'); 1800 1801 var inner = document.createElement('div'); 1802 inner.className = 'geTitle'; 1803 inner.style.backgroundColor = 'transparent'; 1804 inner.style.borderColor = 'transparent'; 1805 inner.style.whiteSpace = 'nowrap'; 1806 inner.style.textOverflow = 'clip'; 1807 inner.style.cursor = 'default'; 1808 inner.style.paddingRight = '20px'; 1809 1810 var linkInput = document.createElement('input'); 1811 linkInput.setAttribute('value', initialValue); 1812 linkInput.setAttribute('placeholder', 'http://www.example.com/'); 1813 linkInput.setAttribute('type', 'text'); 1814 linkInput.style.marginTop = '6px'; 1815 linkInput.style.width = '400px'; 1816 linkInput.style.backgroundImage = 'url(\'' + Dialog.prototype.clearImage + '\')'; 1817 linkInput.style.backgroundRepeat = 'no-repeat'; 1818 linkInput.style.backgroundPosition = '100% 50%'; 1819 linkInput.style.paddingRight = '14px'; 1820 1821 var cross = document.createElement('div'); 1822 cross.setAttribute('title', mxResources.get('reset')); 1823 cross.style.position = 'relative'; 1824 cross.style.left = '-16px'; 1825 cross.style.width = '12px'; 1826 cross.style.height = '14px'; 1827 cross.style.cursor = 'pointer'; 1828 1829 // Workaround for inline-block not supported in IE 1830 cross.style.display = 'inline-block'; 1831 cross.style.top = '3px'; 1832 1833 // Needed to block event transparency in IE 1834 cross.style.background = 'url(' + IMAGE_PATH + '/transparent.gif)'; 1835 1836 mxEvent.addListener(cross, 'click', function() 1837 { 1838 linkInput.value = ''; 1839 linkInput.focus(); 1840 }); 1841 1842 inner.appendChild(linkInput); 1843 inner.appendChild(cross); 1844 div.appendChild(inner); 1845 1846 this.init = function() 1847 { 1848 linkInput.focus(); 1849 1850 if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5) 1851 { 1852 linkInput.select(); 1853 } 1854 else 1855 { 1856 document.execCommand('selectAll', false, null); 1857 } 1858 }; 1859 1860 var btns = document.createElement('div'); 1861 btns.style.marginTop = '18px'; 1862 btns.style.textAlign = 'right'; 1863 1864 mxEvent.addListener(linkInput, 'keypress', function(e) 1865 { 1866 if (e.keyCode == 13) 1867 { 1868 editorUi.hideDialog(); 1869 fn(linkInput.value); 1870 } 1871 }); 1872 1873 var cancelBtn = mxUtils.button(mxResources.get('cancel'), function() 1874 { 1875 editorUi.hideDialog(); 1876 }); 1877 cancelBtn.className = 'geBtn'; 1878 1879 if (editorUi.editor.cancelFirst) 1880 { 1881 btns.appendChild(cancelBtn); 1882 } 1883 1884 var mainBtn = mxUtils.button(btnLabel, function() 1885 { 1886 editorUi.hideDialog(); 1887 fn(linkInput.value); 1888 }); 1889 mainBtn.className = 'geBtn gePrimaryBtn'; 1890 btns.appendChild(mainBtn); 1891 1892 if (!editorUi.editor.cancelFirst) 1893 { 1894 btns.appendChild(cancelBtn); 1895 } 1896 1897 div.appendChild(btns); 1898 1899 this.container = div; 1900}; 1901 1902/** 1903 * 1904 */ 1905var OutlineWindow = function(editorUi, x, y, w, h) 1906{ 1907 var graph = editorUi.editor.graph; 1908 1909 var div = document.createElement('div'); 1910 div.style.position = 'absolute'; 1911 div.style.width = '100%'; 1912 div.style.height = '100%'; 1913 div.style.overflow = 'hidden'; 1914 1915 this.window = new mxWindow(mxResources.get('outline'), div, x, y, w, h, true, true); 1916 this.window.minimumSize = new mxRectangle(0, 0, 80, 80); 1917 this.window.destroyOnClose = false; 1918 this.window.setMaximizable(false); 1919 this.window.setResizable(true); 1920 this.window.setClosable(true); 1921 this.window.setVisible(true); 1922 1923 this.window.setLocation = function(x, y) 1924 { 1925 var iw = window.innerWidth || document.body.clientWidth || document.documentElement.clientWidth; 1926 var ih = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight; 1927 1928 x = Math.max(0, Math.min(x, iw - this.table.clientWidth)); 1929 y = Math.max(0, Math.min(y, ih - this.table.clientHeight - ((urlParams['sketch'] == '1') ? 3 : 48))); 1930 1931 if (this.getX() != x || this.getY() != y) 1932 { 1933 mxWindow.prototype.setLocation.apply(this, arguments); 1934 } 1935 }; 1936 1937 var resizeListener = mxUtils.bind(this, function() 1938 { 1939 var x = this.window.getX(); 1940 var y = this.window.getY(); 1941 1942 this.window.setLocation(x, y); 1943 }); 1944 1945 mxEvent.addListener(window, 'resize', resizeListener); 1946 1947 var outline = editorUi.createOutline(this.window); 1948 1949 this.destroy = function() 1950 { 1951 mxEvent.removeListener(window, 'resize', resizeListener); 1952 this.window.destroy(); 1953 outline.destroy(); 1954 } 1955 1956 this.window.addListener(mxEvent.SHOW, mxUtils.bind(this, function() 1957 { 1958 this.window.fit(); 1959 outline.setSuspended(false); 1960 })); 1961 1962 this.window.addListener(mxEvent.HIDE, mxUtils.bind(this, function() 1963 { 1964 outline.setSuspended(true); 1965 })); 1966 1967 this.window.addListener(mxEvent.NORMALIZE, mxUtils.bind(this, function() 1968 { 1969 outline.setSuspended(false); 1970 })); 1971 1972 this.window.addListener(mxEvent.MINIMIZE, mxUtils.bind(this, function() 1973 { 1974 outline.setSuspended(true); 1975 })); 1976 1977 outline.init(div); 1978 1979 var zoomInAction = editorUi.actions.get('zoomIn'); 1980 var zoomOutAction = editorUi.actions.get('zoomOut'); 1981 mxEvent.addMouseWheelListener(function(evt, up) 1982 { 1983 var outlineWheel = false; 1984 var source = mxEvent.getSource(evt); 1985 1986 while (source != null) 1987 { 1988 if (source == outline.svg) 1989 { 1990 outlineWheel = true; 1991 break; 1992 } 1993 1994 source = source.parentNode; 1995 } 1996 1997 if (outlineWheel) 1998 { 1999 if (up) 2000 { 2001 zoomInAction.funct(); 2002 } 2003 else 2004 { 2005 zoomOutAction.funct(); 2006 } 2007 } 2008 }); 2009}; 2010 2011/** 2012 * 2013 */ 2014var LayersWindow = function(editorUi, x, y, w, h) 2015{ 2016 var graph = editorUi.editor.graph; 2017 2018 var div = document.createElement('div'); 2019 div.style.userSelect = 'none'; 2020 div.style.background = (!Editor.isDarkMode()) ? '#fff' : Dialog.backdropColor; 2021 div.style.border = '1px solid whiteSmoke'; 2022 div.style.height = '100%'; 2023 div.style.marginBottom = '10px'; 2024 div.style.overflow = 'auto'; 2025 2026 var tbarHeight = (!EditorUi.compactUi) ? '30px' : '26px'; 2027 2028 var listDiv = document.createElement('div') 2029 listDiv.style.backgroundColor = (!Editor.isDarkMode()) ? '#fff' : Dialog.backdropColor; 2030 listDiv.style.position = 'absolute'; 2031 listDiv.style.overflow = 'auto'; 2032 listDiv.style.left = '0px'; 2033 listDiv.style.right = '0px'; 2034 listDiv.style.top = '0px'; 2035 listDiv.style.bottom = (parseInt(tbarHeight) + 7) + 'px'; 2036 div.appendChild(listDiv); 2037 2038 var dragSource = null; 2039 var dropIndex = null; 2040 2041 mxEvent.addListener(div, 'dragover', function(evt) 2042 { 2043 evt.dataTransfer.dropEffect = 'move'; 2044 dropIndex = 0; 2045 evt.stopPropagation(); 2046 evt.preventDefault(); 2047 }); 2048 2049 // Workaround for "no element found" error in FF 2050 mxEvent.addListener(div, 'drop', function(evt) 2051 { 2052 evt.stopPropagation(); 2053 evt.preventDefault(); 2054 }); 2055 2056 var layerCount = null; 2057 var selectionLayer = null; 2058 var ldiv = document.createElement('div'); 2059 2060 ldiv.className = 'geToolbarContainer'; 2061 ldiv.style.position = 'absolute'; 2062 ldiv.style.bottom = '0px'; 2063 ldiv.style.left = '0px'; 2064 ldiv.style.right = '0px'; 2065 ldiv.style.height = tbarHeight; 2066 ldiv.style.overflow = 'hidden'; 2067 ldiv.style.padding = (!EditorUi.compactUi) ? '1px' : '4px 0px 3px 0px'; 2068 ldiv.style.backgroundColor = (!Editor.isDarkMode()) ? 'whiteSmoke' : Dialog.backdropColor; 2069 ldiv.style.borderWidth = '1px 0px 0px 0px'; 2070 ldiv.style.borderColor = '#c3c3c3'; 2071 ldiv.style.borderStyle = 'solid'; 2072 ldiv.style.display = 'block'; 2073 ldiv.style.whiteSpace = 'nowrap'; 2074 2075 var link = document.createElement('a'); 2076 link.className = 'geButton'; 2077 2078 var removeLink = link.cloneNode(false); 2079 var img = document.createElement('img'); 2080 img.setAttribute('border', '0'); 2081 img.setAttribute('width', '22'); 2082 img.setAttribute('src', Editor.trashImage); 2083 img.style.opacity = '0.9'; 2084 2085 if (Editor.isDarkMode()) 2086 { 2087 img.style.filter = 'invert(100%)'; 2088 } 2089 2090 removeLink.appendChild(img); 2091 2092 mxEvent.addListener(removeLink, 'click', function(evt) 2093 { 2094 if (graph.isEnabled()) 2095 { 2096 graph.model.beginUpdate(); 2097 try 2098 { 2099 var index = graph.model.root.getIndex(selectionLayer); 2100 graph.removeCells([selectionLayer], false); 2101 2102 // Creates default layer if no layer exists 2103 if (graph.model.getChildCount(graph.model.root) == 0) 2104 { 2105 graph.model.add(graph.model.root, new mxCell()); 2106 graph.setDefaultParent(null); 2107 } 2108 else if (index > 0 && index <= graph.model.getChildCount(graph.model.root)) 2109 { 2110 graph.setDefaultParent(graph.model.getChildAt(graph.model.root, index - 1)); 2111 } 2112 else 2113 { 2114 graph.setDefaultParent(null); 2115 } 2116 } 2117 finally 2118 { 2119 graph.model.endUpdate(); 2120 } 2121 } 2122 2123 mxEvent.consume(evt); 2124 }); 2125 2126 if (!graph.isEnabled()) 2127 { 2128 removeLink.className = 'geButton mxDisabled'; 2129 } 2130 2131 ldiv.appendChild(removeLink); 2132 2133 var insertLink = link.cloneNode(); 2134 insertLink.setAttribute('title', mxUtils.trim(mxResources.get('moveSelectionTo', ['...']))); 2135 2136 img = img.cloneNode(false); 2137 img.setAttribute('src', Editor.verticalDotsImage); 2138 insertLink.appendChild(img); 2139 2140 mxEvent.addListener(insertLink, 'click', function(evt) 2141 { 2142 if (graph.isEnabled() && !graph.isSelectionEmpty()) 2143 { 2144 var offset = mxUtils.getOffset(insertLink); 2145 2146 editorUi.showPopupMenu(mxUtils.bind(this, function(menu, parent) 2147 { 2148 for (var i = layerCount - 1; i >= 0; i--) 2149 { 2150 (mxUtils.bind(this, function(child) 2151 { 2152 var item = menu.addItem(graph.convertValueToString(child) || 2153 mxResources.get('background'), null, mxUtils.bind(this, function() 2154 { 2155 graph.moveCells(graph.getSelectionCells(), 0, 0, false, child); 2156 }), parent); 2157 2158 if (graph.getSelectionCount() == 1 && graph.model.isAncestor(child, graph.getSelectionCell())) 2159 { 2160 menu.addCheckmark(item, Editor.checkmarkImage); 2161 } 2162 2163 }))(graph.model.getChildAt(graph.model.root, i)); 2164 } 2165 }), offset.x, offset.y + insertLink.offsetHeight, evt); 2166 } 2167 }); 2168 2169 ldiv.appendChild(insertLink); 2170 2171 var dataLink = link.cloneNode(false); 2172 dataLink.setAttribute('title', mxResources.get('editData')); 2173 2174 img = img.cloneNode(false); 2175 img.setAttribute('src', Editor.editImage); 2176 dataLink.appendChild(img); 2177 2178 mxEvent.addListener(dataLink, 'click', function(evt) 2179 { 2180 if (graph.isEnabled()) 2181 { 2182 editorUi.showDataDialog(selectionLayer); 2183 } 2184 2185 mxEvent.consume(evt); 2186 }); 2187 2188 if (!graph.isEnabled()) 2189 { 2190 dataLink.className = 'geButton mxDisabled'; 2191 } 2192 2193 ldiv.appendChild(dataLink); 2194 2195 function renameLayer(layer) 2196 { 2197 if (graph.isEnabled() && layer != null) 2198 { 2199 var label = graph.convertValueToString(layer); 2200 var dlg = new FilenameDialog(editorUi, label || mxResources.get('background'), mxResources.get('rename'), mxUtils.bind(this, function(newValue) 2201 { 2202 if (newValue != null) 2203 { 2204 graph.cellLabelChanged(layer, newValue); 2205 } 2206 }), mxResources.get('enterName')); 2207 editorUi.showDialog(dlg.container, 300, 100, true, true); 2208 dlg.init(); 2209 } 2210 }; 2211 2212 var duplicateLink = link.cloneNode(false); 2213 duplicateLink.setAttribute('title', mxResources.get('duplicate')); 2214 2215 img = img.cloneNode(false); 2216 img.setAttribute('src', Editor.duplicateImage); 2217 duplicateLink.appendChild(img); 2218 2219 mxEvent.addListener(duplicateLink, 'click', function(evt) 2220 { 2221 if (graph.isEnabled()) 2222 { 2223 var newCell = null; 2224 graph.model.beginUpdate(); 2225 try 2226 { 2227 newCell = graph.cloneCell(selectionLayer); 2228 graph.cellLabelChanged(newCell, mxResources.get('untitledLayer')); 2229 newCell.setVisible(true); 2230 newCell = graph.addCell(newCell, graph.model.root); 2231 graph.setDefaultParent(newCell); 2232 } 2233 finally 2234 { 2235 graph.model.endUpdate(); 2236 } 2237 2238 if (newCell != null && !graph.isCellLocked(newCell)) 2239 { 2240 graph.selectAll(newCell); 2241 } 2242 } 2243 }); 2244 2245 if (!graph.isEnabled()) 2246 { 2247 duplicateLink.className = 'geButton mxDisabled'; 2248 } 2249 2250 ldiv.appendChild(duplicateLink); 2251 2252 var addLink = link.cloneNode(false); 2253 addLink.setAttribute('title', mxResources.get('addLayer')); 2254 2255 img = img.cloneNode(false); 2256 img.setAttribute('src', Editor.addImage); 2257 addLink.appendChild(img); 2258 2259 mxEvent.addListener(addLink, 'click', function(evt) 2260 { 2261 if (graph.isEnabled()) 2262 { 2263 graph.model.beginUpdate(); 2264 2265 try 2266 { 2267 var cell = graph.addCell(new mxCell(mxResources.get('untitledLayer')), graph.model.root); 2268 graph.setDefaultParent(cell); 2269 } 2270 finally 2271 { 2272 graph.model.endUpdate(); 2273 } 2274 } 2275 2276 mxEvent.consume(evt); 2277 }); 2278 2279 if (!graph.isEnabled()) 2280 { 2281 addLink.className = 'geButton mxDisabled'; 2282 } 2283 2284 ldiv.appendChild(addLink); 2285 div.appendChild(ldiv); 2286 2287 var layerDivs = new mxDictionary(); 2288 2289 var dot = document.createElement('span'); 2290 dot.setAttribute('title', mxResources.get('selectionOnly')); 2291 dot.innerHTML = '•'; 2292 dot.style.position = 'absolute'; 2293 dot.style.fontWeight = 'bold'; 2294 dot.style.fontSize = '16pt'; 2295 dot.style.right = '2px'; 2296 dot.style.top = '2px'; 2297 2298 function updateLayerDot() 2299 { 2300 var div = layerDivs.get(graph.getLayerForCells(graph.getSelectionCells())); 2301 2302 if (div != null) 2303 { 2304 div.appendChild(dot); 2305 } 2306 else if (dot.parentNode != null) 2307 { 2308 dot.parentNode.removeChild(dot); 2309 } 2310 }; 2311 2312 function refresh() 2313 { 2314 layerCount = graph.model.getChildCount(graph.model.root) 2315 listDiv.innerHTML = ''; 2316 layerDivs.clear(); 2317 2318 function addLayer(index, label, child, defaultParent) 2319 { 2320 var ldiv = document.createElement('div'); 2321 ldiv.className = 'geToolbarContainer'; 2322 layerDivs.put(child, ldiv); 2323 2324 ldiv.style.overflow = 'hidden'; 2325 ldiv.style.position = 'relative'; 2326 ldiv.style.padding = '4px'; 2327 ldiv.style.height = '22px'; 2328 ldiv.style.display = 'block'; 2329 ldiv.style.backgroundColor = (!Editor.isDarkMode()) ? 'whiteSmoke' : Dialog.backdropColor; 2330 ldiv.style.borderWidth = '0px 0px 1px 0px'; 2331 ldiv.style.borderColor = '#c3c3c3'; 2332 ldiv.style.borderStyle = 'solid'; 2333 ldiv.style.whiteSpace = 'nowrap'; 2334 ldiv.setAttribute('title', label); 2335 2336 var left = document.createElement('div'); 2337 left.style.display = 'inline-block'; 2338 left.style.width = '100%'; 2339 left.style.textOverflow = 'ellipsis'; 2340 left.style.overflow = 'hidden'; 2341 2342 mxEvent.addListener(ldiv, 'dragover', function(evt) 2343 { 2344 evt.dataTransfer.dropEffect = 'move'; 2345 dropIndex = index; 2346 evt.stopPropagation(); 2347 evt.preventDefault(); 2348 }); 2349 2350 mxEvent.addListener(ldiv, 'dragstart', function(evt) 2351 { 2352 dragSource = ldiv; 2353 2354 // Workaround for no DnD on DIV in FF 2355 if (mxClient.IS_FF) 2356 { 2357 // LATER: Check what triggers a parse as XML on this in FF after drop 2358 evt.dataTransfer.setData('Text', '<layer/>'); 2359 } 2360 }); 2361 2362 mxEvent.addListener(ldiv, 'dragend', function(evt) 2363 { 2364 if (dragSource != null && dropIndex != null) 2365 { 2366 graph.addCell(child, graph.model.root, dropIndex); 2367 } 2368 2369 dragSource = null; 2370 dropIndex = null; 2371 evt.stopPropagation(); 2372 evt.preventDefault(); 2373 }); 2374 2375 var inp = document.createElement('img'); 2376 inp.setAttribute('draggable', 'false'); 2377 inp.setAttribute('align', 'top'); 2378 inp.setAttribute('border', '0'); 2379 inp.style.width = '16px'; 2380 inp.style.padding = '0px 6px 0 4px'; 2381 inp.style.marginTop = '2px'; 2382 inp.style.cursor = 'pointer'; 2383 inp.setAttribute('title', mxResources.get( 2384 graph.model.isVisible(child) ? 2385 'hide' : 'show')); 2386 2387 if (graph.model.isVisible(child)) 2388 { 2389 inp.setAttribute('src', Editor.visibleImage); 2390 mxUtils.setOpacity(ldiv, 75); 2391 } 2392 else 2393 { 2394 inp.setAttribute('src', Editor.hiddenImage); 2395 mxUtils.setOpacity(ldiv, 25); 2396 } 2397 2398 if (Editor.isDarkMode()) 2399 { 2400 inp.style.filter = 'invert(100%)'; 2401 } 2402 2403 left.appendChild(inp); 2404 2405 mxEvent.addListener(inp, 'click', function(evt) 2406 { 2407 graph.model.setVisible(child, !graph.model.isVisible(child)); 2408 mxEvent.consume(evt); 2409 }); 2410 2411 var btn = document.createElement('img'); 2412 btn.setAttribute('draggable', 'false'); 2413 btn.setAttribute('align', 'top'); 2414 btn.setAttribute('border', '0'); 2415 btn.style.width = '16px'; 2416 btn.style.padding = '0px 6px 0 0'; 2417 btn.style.marginTop = '2px'; 2418 btn.setAttribute('title', mxResources.get('lockUnlock')); 2419 2420 var style = graph.getCurrentCellStyle(child); 2421 2422 if (mxUtils.getValue(style, 'locked', '0') == '1') 2423 { 2424 btn.setAttribute('src', Editor.lockedImage); 2425 mxUtils.setOpacity(btn, 75); 2426 } 2427 else 2428 { 2429 btn.setAttribute('src', Editor.unlockedImage); 2430 mxUtils.setOpacity(btn, 25); 2431 } 2432 2433 if (Editor.isDarkMode()) 2434 { 2435 btn.style.filter = 'invert(100%)'; 2436 } 2437 2438 if (graph.isEnabled()) 2439 { 2440 btn.style.cursor = 'pointer'; 2441 } 2442 2443 mxEvent.addListener(btn, 'click', function(evt) 2444 { 2445 if (graph.isEnabled()) 2446 { 2447 var value = null; 2448 2449 graph.getModel().beginUpdate(); 2450 try 2451 { 2452 value = (mxUtils.getValue(style, 'locked', '0') == '1') ? null : '1'; 2453 graph.setCellStyles('locked', value, [child]); 2454 } 2455 finally 2456 { 2457 graph.getModel().endUpdate(); 2458 } 2459 2460 if (value == '1') 2461 { 2462 graph.removeSelectionCells(graph.getModel().getDescendants(child)); 2463 } 2464 2465 mxEvent.consume(evt); 2466 } 2467 }); 2468 2469 left.appendChild(btn); 2470 2471 var span = document.createElement('span'); 2472 mxUtils.write(span, label); 2473 span.style.display = 'block'; 2474 span.style.whiteSpace = 'nowrap'; 2475 span.style.overflow = 'hidden'; 2476 span.style.textOverflow = 'ellipsis'; 2477 span.style.position = 'absolute'; 2478 span.style.left = '52px'; 2479 span.style.right = '8px'; 2480 span.style.top = '8px'; 2481 2482 left.appendChild(span); 2483 ldiv.appendChild(left); 2484 2485 if (graph.isEnabled()) 2486 { 2487 // Fallback if no drag and drop is available 2488 if (mxClient.IS_TOUCH || mxClient.IS_POINTER || 2489 (mxClient.IS_IE && document.documentMode < 10)) 2490 { 2491 var right = document.createElement('div'); 2492 right.style.display = 'block'; 2493 right.style.textAlign = 'right'; 2494 right.style.whiteSpace = 'nowrap'; 2495 right.style.position = 'absolute'; 2496 right.style.right = '16px'; 2497 right.style.top = '6px'; 2498 2499 // Poor man's change layer order 2500 if (index > 0) 2501 { 2502 var img2 = document.createElement('a'); 2503 2504 img2.setAttribute('title', mxResources.get('toBack')); 2505 2506 img2.className = 'geButton'; 2507 img2.style.cssFloat = 'none'; 2508 img2.innerHTML = '▼'; 2509 img2.style.width = '14px'; 2510 img2.style.height = '14px'; 2511 img2.style.fontSize = '14px'; 2512 img2.style.margin = '0px'; 2513 img2.style.marginTop = '-1px'; 2514 right.appendChild(img2); 2515 2516 mxEvent.addListener(img2, 'click', function(evt) 2517 { 2518 if (graph.isEnabled()) 2519 { 2520 graph.addCell(child, graph.model.root, index - 1); 2521 } 2522 2523 mxEvent.consume(evt); 2524 }); 2525 } 2526 2527 if (index >= 0 && index < layerCount - 1) 2528 { 2529 var img1 = document.createElement('a'); 2530 2531 img1.setAttribute('title', mxResources.get('toFront')); 2532 2533 img1.className = 'geButton'; 2534 img1.style.cssFloat = 'none'; 2535 img1.innerHTML = '▲'; 2536 img1.style.width = '14px'; 2537 img1.style.height = '14px'; 2538 img1.style.fontSize = '14px'; 2539 img1.style.margin = '0px'; 2540 img1.style.marginTop = '-1px'; 2541 right.appendChild(img1); 2542 2543 mxEvent.addListener(img1, 'click', function(evt) 2544 { 2545 if (graph.isEnabled()) 2546 { 2547 graph.addCell(child, graph.model.root, index + 1); 2548 } 2549 2550 mxEvent.consume(evt); 2551 }); 2552 } 2553 2554 ldiv.appendChild(right); 2555 } 2556 2557 if (mxClient.IS_SVG && (!mxClient.IS_IE || document.documentMode >= 10)) 2558 { 2559 ldiv.setAttribute('draggable', 'true'); 2560 ldiv.style.cursor = 'move'; 2561 } 2562 } 2563 2564 mxEvent.addListener(ldiv, 'dblclick', function(evt) 2565 { 2566 var nodeName = mxEvent.getSource(evt).nodeName; 2567 2568 if (nodeName != 'INPUT' && nodeName != 'IMG') 2569 { 2570 renameLayer(child); 2571 mxEvent.consume(evt); 2572 } 2573 }); 2574 2575 if (graph.getDefaultParent() == child) 2576 { 2577 ldiv.style.background = (!Editor.isDarkMode()) ? '#e6eff8' : '#505759'; 2578 ldiv.style.fontWeight = (graph.isEnabled()) ? 'bold' : ''; 2579 selectionLayer = child; 2580 } 2581 2582 mxEvent.addListener(ldiv, 'click', function(evt) 2583 { 2584 if (graph.isEnabled()) 2585 { 2586 graph.setDefaultParent(defaultParent); 2587 graph.view.setCurrentRoot(null); 2588 2589 if (mxEvent.isShiftDown(evt)) 2590 { 2591 graph.setSelectionCells(child.children); 2592 } 2593 2594 mxEvent.consume(evt); 2595 } 2596 }); 2597 2598 listDiv.appendChild(ldiv); 2599 }; 2600 2601 // Cannot be moved or deleted 2602 for (var i = layerCount - 1; i >= 0; i--) 2603 { 2604 (mxUtils.bind(this, function(child) 2605 { 2606 addLayer(i, graph.convertValueToString(child) || 2607 mxResources.get('background'), child, child); 2608 }))(graph.model.getChildAt(graph.model.root, i)); 2609 } 2610 2611 var label = graph.convertValueToString(selectionLayer) || mxResources.get('background'); 2612 removeLink.setAttribute('title', mxResources.get('removeIt', [label])); 2613 duplicateLink.setAttribute('title', mxResources.get('duplicateIt', [label])); 2614 2615 if (graph.isSelectionEmpty()) 2616 { 2617 insertLink.className = 'geButton mxDisabled'; 2618 } 2619 2620 updateLayerDot(); 2621 }; 2622 2623 refresh(); 2624 graph.model.addListener(mxEvent.CHANGE, refresh); 2625 graph.addListener('defaultParentChanged', refresh); 2626 2627 graph.selectionModel.addListener(mxEvent.CHANGE, function() 2628 { 2629 if (graph.isSelectionEmpty()) 2630 { 2631 insertLink.className = 'geButton mxDisabled'; 2632 } 2633 else 2634 { 2635 insertLink.className = 'geButton'; 2636 } 2637 2638 updateLayerDot(); 2639 }); 2640 2641 this.window = new mxWindow(mxResources.get('layers'), div, x, y, w, h, true, true); 2642 this.window.minimumSize = new mxRectangle(0, 0, 150, 120); 2643 this.window.destroyOnClose = false; 2644 this.window.setMaximizable(false); 2645 this.window.setResizable(true); 2646 this.window.setClosable(true); 2647 this.window.setVisible(true); 2648 2649 this.init = function() 2650 { 2651 listDiv.scrollTop = listDiv.scrollHeight - listDiv.clientHeight; 2652 }; 2653 2654 this.window.addListener(mxEvent.SHOW, mxUtils.bind(this, function() 2655 { 2656 this.window.fit(); 2657 })); 2658 2659 // Make refresh available via instance 2660 this.refreshLayers = refresh; 2661 2662 this.window.setLocation = function(x, y) 2663 { 2664 var iw = window.innerWidth || document.body.clientWidth || document.documentElement.clientWidth; 2665 var ih = window.innerHeight || document.body.clientHeight || document.documentElement.clientHeight; 2666 2667 x = Math.max(0, Math.min(x, iw - this.table.clientWidth)); 2668 y = Math.max(0, Math.min(y, ih - this.table.clientHeight - ((urlParams['sketch'] == '1') ? 3 : 48))); 2669 2670 if (this.getX() != x || this.getY() != y) 2671 { 2672 mxWindow.prototype.setLocation.apply(this, arguments); 2673 } 2674 }; 2675 2676 var resizeListener = mxUtils.bind(this, function() 2677 { 2678 var x = this.window.getX(); 2679 var y = this.window.getY(); 2680 2681 this.window.setLocation(x, y); 2682 }); 2683 2684 mxEvent.addListener(window, 'resize', resizeListener); 2685 2686 this.destroy = function() 2687 { 2688 mxEvent.removeListener(window, 'resize', resizeListener); 2689 this.window.destroy(); 2690 } 2691}; 2692