1(function(stylesheet, stencils) 2{ 3 // Callbacks: 4 // mxClientOnLoad is called after the script is loaded with the stylesheet and the function to create a 5 // graph (wich takes the container as an argument and returns the graph instance that was created). 6 // mxClientOnCreate is called when a graph has been created with the graph. 7 mxStencilRegistry.dynamicLoading = false; 8 9 // Adds CSS for tooltips 10 try 11 { 12 var style = document.createElement('style') 13 style.type = 'text/css' 14 style.innerHTML = ['div.mxTooltip {', 15 '-webkit-box-shadow: 3px 3px 12px #C0C0C0;', 16 '-moz-box-shadow: 3px 3px 12px #C0C0C0;', 17 'box-shadow: 3px 3px 12px #C0C0C0;', 18 'background: #FFFFCC;', 19 'border-style: solid;', 20 'border-width: 1px;', 21 'border-color: black;', 22 'font-family: Arial;', 23 'font-size: 8pt;', 24 'position: absolute;', 25 'cursor: default;', 26 'padding: 4px;', 27 'color: black;}'].join('\n'); 28 document.getElementsByTagName('head')[0].appendChild(style) 29 } 30 catch (e) 31 { 32 // ignore 33 } 34 35 var originalNoFo = mxClient.NO_FO; 36 var mathJaxLoading = (typeof(MathJax) !== 'undefined' && typeof(MathJax.Hub) !== 'undefined'); 37 var mathJaxQueue = []; 38 39 function loadMathJax() 40 { 41 // Uses existing configuration if MathJax already in page 42 if (!mathJaxLoading) 43 { 44 mathJaxLoading = true; 45 46 window.MathJax = 47 { 48 skipStartupTypeset: true, 49 showMathMenu: false, 50 messageStyle: 'none', 51 AuthorInit: function () 52 { 53 MathJax.Hub.Config({ 54 jax: ['input/TeX', 'input/MathML', 'input/AsciiMath', 'output/SVG'], 55 extensions: ['tex2jax.js', 'mml2jax.js', 'asciimath2jax.js'], 56 TeX: { 57 extensions: ['AMSmath.js', 'AMSsymbols.js', 'noErrors.js', 'noUndefined.js'] 58 } 59 }); 60 61 MathJax.Hub.Register.StartupHook('Begin', function() 62 { 63 for (var i = 0; i < mathJaxQueue.length; i++) 64 { 65 MathJax.Hub.Queue(['Typeset', MathJax.Hub, mathJaxQueue[i]]); 66 } 67 }); 68 } 69 }; 70 71 var script = document.createElement('script'); 72 script.type = 'text/javascript'; 73 script.src = 'https://app.diagrams.net/math/MathJax.js'; 74 document.getElementsByTagName('head')[0].appendChild(script); 75 } 76 }; 77 78 function addMathJaxGraph(graph) 79 { 80 // Initial rendering when MathJax finished loading 81 if (typeof(MathJax) !== 'undefined' && typeof(MathJax.Hub) !== 'undefined') 82 { 83 MathJax.Hub.Queue(['Typeset', MathJax.Hub, graph.container]); 84 } 85 else 86 { 87 mathJaxQueue.push(graph.container); 88 } 89 90 // Rendering math again on repaint 91 graph.addListener(mxEvent.SIZE, function(sender, evt) 92 { 93 if (typeof(MathJax) !== 'undefined' && typeof(MathJax.Hub) !== 'undefined') 94 { 95 MathJax.Hub.Queue(['Typeset', MathJax.Hub, graph.container]); 96 } 97 }); 98 }; 99 100 // Handles relative images 101 mxGraph.prototype.getImageFromBundles = function(key) 102 { 103 if (key != null) 104 { 105 if (key.substring(0, 7) != 'http://' && key.substring(0, 8) != 'https://' && key.substring(0, 10) != 'data:image') 106 { 107 if (key.charAt(0) == '/') 108 { 109 key = key.substring(1, key.length); 110 } 111 112 key = 'https://app.diagrams.net/' + key; 113 } 114 115 return key; 116 } 117 118 return null; 119 }; 120 121 if (stencils != null) 122 { 123 for (var i = 0; i < stencils.length; i++) 124 { 125 var xmlDoc = mxUtils.parseXml(stencils[i]); 126 mxStencilRegistry.parseStencilSet(xmlDoc.documentElement); 127 } 128 } 129 130 // Panning for touch devices 131 if (mxClient.IS_TOUCH) 132 { 133 mxPanningHandler.prototype.isPanningTrigger = function(me) 134 { 135 return true; 136 }; 137 } 138 139 (function() 140 { 141 function initGraph(container) 142 { 143 try 144 { 145 var child = container.firstChild; 146 147 while (child != null && child.nodeType != mxConstants.NODETYPE_ELEMENT) 148 { 149 child = child.nextSibling; 150 } 151 152 var xml = mxUtils.trim(child.innerHTML); 153 container.innerHTML = ''; 154 155 // Instance needed for decompress helper function 156 var graph = new Graph(container); 157 158 if (xml.substring(0, 4) == '<') 159 { 160 xml = xml.replace(/</g, '<').replace(/>/g, '>'). 161 replace(/&gt;/g, '>').replace(/&lt;/g, '<'). 162 replace(/&quot;/g, '"').replace(/
/g, '\n'); 163 } 164 else if (xml.substring(0, 3) == '%3C') 165 { 166 xml = decodeURIComponent(xml); 167 } 168 else 169 { 170 xml = Graph.decompress(xml); 171 } 172 173 var xmlDocument = mxUtils.parseXml(xml); 174 var configNode = null; 175 var diagrams = null; 176 177 if (xmlDocument.documentElement != null && xmlDocument.documentElement.nodeName == 'mxfile') 178 { 179 diagrams = xmlDocument.documentElement.getElementsByTagName('diagram'); 180 configNode = xmlDocument.documentElement; 181 182 if (diagrams.length > 0) 183 { 184 xml = mxUtils.getTextContent(diagrams[0]); 185 xml = Graph.decompress(xml); 186 xmlDocument = mxUtils.parseXml(xml); 187 } 188 } 189 190 if (xmlDocument.documentElement != null && xmlDocument.documentElement.nodeName == 'mxGraphModel') 191 { 192 var decoder = new mxCodec(xmlDocument); 193 var node = xmlDocument.documentElement; 194 195 if (configNode == null) 196 { 197 configNode = node; 198 } 199 200 graph.resetViewOnRootChange = false; 201 graph.setEnabled(false); 202 203 if (diagrams != null && diagrams.length > 0) 204 { 205 /** 206 * Adds placeholder for %page% and %pagenumber% 207 */ 208 var graphGetGlobalVariable = graph.getGlobalVariable; 209 210 graph.getGlobalVariable = function(name) 211 { 212 if (name == 'page') 213 { 214 return diagrams[0].getAttribute('name') || 'Page-1'; 215 } 216 else if (name == 'pagenumber') 217 { 218 return 1; 219 } 220 else if (name == 'pagecount') 221 { 222 return diagrams.length; 223 } 224 225 return graphGetGlobalVariable.apply(this, arguments); 226 }; 227 } 228 229 graph.foldingEnabled = configNode.getAttribute('nav') == '1'; 230 graph.cellRenderer.forceControlClickHandler = graph.foldingEnabled; 231 232 var tooltips = configNode.getAttribute('tooltips'); 233 234 if (tooltips != '0') 235 { 236 graph.setTooltips(true); 237 } 238 else 239 { 240 graph.setTooltips(false); 241 } 242 243 // Loads the stylesheet 244 if (stylesheet != null) 245 { 246 var xmlDoc = mxUtils.parseXml(stylesheet); 247 var dec = new mxCodec(xmlDoc); 248 dec.decode(xmlDoc.documentElement, graph.getStylesheet()); 249 } 250 251 var math = configNode.getAttribute('math'); 252 253 if (math == '1') 254 { 255 mxClient.NO_FO = true; 256 loadMathJax(); 257 } 258 259 // Enables panning with left mouse button 260 var pan = configNode.getAttribute('pan'); 261 262 if (pan != '0') 263 { 264 graph.panningHandler.useLeftButtonForPanning = true; 265 graph.panningHandler.ignoreCell = true; 266 container.style.cursor = 'move'; 267 graph.setPanning(true); 268 } 269 else 270 { 271 container.style.cursor = 'default'; 272 } 273 274 var resize = configNode.getAttribute('resize'); 275 var border = Number(configNode.getAttribute('border') || 0); 276 graph.border = border; 277 278 var fit = configNode.getAttribute('fit'); 279 280 if ((container.style.width != '100%' && fit != '1' && resize != '0') || 281 (container.style.width == '' && container.style.height == '')) 282 { 283 graph.resizeContainer = true; 284 graph.centerZoom = false; 285 } 286 else 287 { 288 // Updates the container height for autosize width 289 if (resize != '0' && container.style.width == '100%' && container.style.height == '') 290 { 291 graph.resizeContainer = true; 292 graph.centerZoom = false; 293 294 graph.doResizeContainer = function(width, height) 295 { 296 // Fixes container size for different box models 297 if (mxClient.IS_IE) 298 { 299 if (document.documentMode >= 9) 300 { 301 width += 3; 302 height += 5; 303 } 304 else 305 { 306 width += 1; 307 height += 1; 308 } 309 } 310 else 311 { 312 height += 1; 313 } 314 315 if (this.maximumContainerSize != null) 316 { 317 width = Math.min(this.maximumContainerSize.width, width); 318 height = Math.min(this.maximumContainerSize.height, height); 319 } 320 321 this.container.style.height = Math.ceil(height + 18) + 'px'; 322 }; 323 } 324 else 325 { 326 graph.centerZoom = true; 327 } 328 } 329 330 // Adds handling for hyperlinks, tooltips 331 var links = configNode.getAttribute('links'); 332 var hl = configNode.getAttribute('highlight'); 333 334 if (links != '0' || tooltips != '0') 335 { 336 var cursor = container.style.cursor; 337 var tol = graph.getTolerance(); 338 339 graph.addMouseListener( 340 { 341 currentState: null, 342 currentLink: null, 343 highlight: (hl != null && hl != '' && hl != mxConstants.NONE) ? 344 new mxCellHighlight(graph, hl, 2) : null, 345 startX: 0, 346 startY: 0, 347 mouseDown: function(sender, me) 348 { 349 this.startX = me.getGraphX(); 350 this.startY = me.getGraphY(); 351 }, 352 mouseMove: function(sender, me) 353 { 354 if (graph.isMouseDown) 355 { 356 if (this.currentLink != null) 357 { 358 var dx = Math.abs(this.startX - me.getGraphX()); 359 var dy = Math.abs(this.startY - me.getGraphY()); 360 361 if (dx > tol || dy > tol) 362 { 363 this.clear(); 364 } 365 } 366 } 367 else 368 { 369 if (this.currentState != null && (me.getState() == this.currentState || me.getState() == null) && 370 graph.intersects(this.currentState, me.getGraphX(), me.getGraphY())) 371 { 372 return; 373 } 374 375 var tmp = graph.view.getState(me.getCell()); 376 377 if (tmp != this.currentState) 378 { 379 if (this.currentState != null) 380 { 381 this.clear(); 382 } 383 384 this.currentState = tmp; 385 386 if (this.currentState != null) 387 { 388 this.activate(this.currentState); 389 } 390 } 391 } 392 }, 393 mouseUp: function(sender, me) 394 { 395 var tmp = this.currentLink; 396 this.clear(); 397 398 if (tmp != null) 399 { 400 if (tmp.charAt(0) == '#') 401 { 402 window.location.hash = tmp; 403 } 404 else 405 { 406 window.open(tmp); 407 } 408 } 409 }, 410 activate: function(state) 411 { 412 this.currentLink = graph.getLinkForCell(state.cell); 413 414 if (this.currentLink != null) 415 { 416 container.style.cursor = 'pointer'; 417 418 if (this.highlight != null) 419 { 420 this.highlight.highlight(state); 421 } 422 } 423 }, 424 clear: function() 425 { 426 container.style.cursor = cursor; 427 this.currentState = null; 428 this.currentLink = null; 429 430 if (this.highlight != null) 431 { 432 this.highlight.hide(); 433 } 434 } 435 }); 436 } 437 438 var x0 = Number(configNode.getAttribute('x0') || 0); 439 var y0 = Number(configNode.getAttribute('y0') || 0); 440 graph.view.translate.x = -x0 + border; 441 graph.view.translate.y = -y0 + border; 442 443 function graphAdded(node) 444 { 445 var img = node.getAttribute('backgroundImage'); 446 447 if (img != null) 448 { 449 img = JSON.parse(img); 450 graph.setBackgroundImage(new mxImage(img.src, img.width, img.height)); 451 graph.view.validateBackgroundImage(); 452 } 453 454 if (fit != '0') 455 { 456 graph.fit(border); 457 } 458 459 if (math == '1') 460 { 461 addMathJaxGraph(graph); 462 } 463 464 // Keeps hashtag links on same page 465 var links = graph.container.getElementsByTagName('a'); 466 467 if (links != null) 468 { 469 for (var i = 0; i < links.length; i++) 470 { 471 var href = links[i].getAttribute('href'); 472 473 if (href != null && href.charAt(0) == '#' && 474 links[i].getAttribute('target') == '_blank') 475 { 476 links[i].removeAttribute('target'); 477 } 478 } 479 } 480 }; 481 482 // Load from URL via url attribute 483 var url = configNode.getAttribute('url'); 484 485 if (url != null) 486 { 487 try 488 { 489 // Workaround for unsupported CORS in IE9 XHR 490 var xhr = (navigator.userAgent != null && navigator.userAgent.indexOf('MSIE 9') > 0) ? 491 new XDomainRequest() : new XMLHttpRequest(); 492 xhr.open('GET', url); 493 494 xhr.onload = mxUtils.bind(this, function() 495 { 496 try 497 { 498 if (math == '1') 499 { 500 mxClient.NO_FO = mxClient.IS_SF; 501 } 502 503 var data = (xhr.getText != null) ? xhr.getText() : xhr.responseText; 504 505 if (data != null) 506 { 507 var newDocument = mxUtils.parseXml(data); 508 509 // LATER: Add support for .png (with XML) files 510 // Adds support for HTML 511 if (newDocument != null && newDocument.documentElement.nodeName == 'html') 512 { 513 var divs = newDocument.documentElement.getElementsByTagName('div'); 514 515 if (divs.length > 0 && divs[0].getAttribute('class') == 'mxgraph') 516 { 517 var divs2 = divs[0].getElementsByTagName('div'); 518 519 if (divs2.length > 0) 520 { 521 var data = mxUtils.getTextContent(divs2[0]); 522 data = Graph.decompress(data); 523 524 if (data.length > 0) 525 { 526 newDocument = mxUtils.parseXml(data); 527 } 528 } 529 } 530 } 531 532 if (newDocument != null && newDocument.documentElement.nodeName == 'svg') 533 { 534 var tmp = newDocument.documentElement.getAttribute('content'); 535 536 if (tmp != null && tmp.charAt(0) != '<' && tmp.charAt(0) != '%') 537 { 538 tmp = unescape((window.atob) ? atob(tmp) : Base64.decode(cont, tmp)); 539 } 540 541 if (tmp != null && tmp.charAt(0) == '%') 542 { 543 tmp = decodeURIComponent(tmp); 544 } 545 546 if (tmp != null && tmp.length > 0) 547 { 548 newDocument = mxUtils.parseXml(tmp); 549 } 550 } 551 552 if (newDocument.documentElement.nodeName == 'mxfile') 553 { 554 var diagrams = newDocument.documentElement.getElementsByTagName('diagram'); 555 556 if (diagrams.length > 0) 557 { 558 var text = mxUtils.trim(mxUtils.getTextContent(diagrams[0])); 559 var node = null; 560 561 if (text.length > 0) 562 { 563 var tmp = Graph.decompress(text); 564 565 if (tmp != null && tmp.length > 0) 566 { 567 newDocument = mxUtils.parseXml(tmp); 568 } 569 } 570 else 571 { 572 var temp = mxUtils.getChildNodes(diagrams[0]); 573 574 if (temp.length > 0) 575 { 576 // Creates new document for unique IDs within mxGraphModel 577 newDocument = mxUtils.createXmlDocument(); 578 newDocument.appendChild(newDocument.importNode(temp[0], true)); 579 } 580 } 581 } 582 } 583 584 decoder = new mxCodec(newDocument); 585 decoder.decode(newDocument.documentElement, graph.getModel()); 586 graphAdded(newDocument.documentElement); 587 } 588 else 589 { 590 graph.container.innerHTML = 'Cannot load ' + mxUtils.htmlEntities(url); 591 } 592 593 mxClient.NO_FO = originalNoFo; 594 } 595 catch (e) 596 { 597 graph.container.innerHTML = 'Cannot load ' + mxUtils.htmlEntities(url) + ': ' + mxUtils.htmlEntities(e.message); 598 } 599 }); 600 601 xhr.onerror = function() 602 { 603 graph.container.innerHTML = 'Cannot load ' + mxUtils.htmlEntities(url); 604 }; 605 606 xhr.send(); 607 } 608 catch (e) 609 { 610 graph.container.innerHTML = 'Cannot load ' + mxUtils.htmlEntities(url) + ': ' + mxUtils.htmlEntities(e.message); 611 } 612 } 613 else 614 { 615 decoder.decode(node, graph.getModel()); 616 graphAdded(node); 617 } 618 619 if (container.style.width != '100%' && fit != '0' && resize == '1') 620 { 621 graph.resizeContainer = true; 622 graph.centerZoom = false; 623 } 624 625 // Adds zoom, edit etc in top, left corner 626 var buttons = document.createElement('div'); 627 buttons.style.position = 'absolute'; 628 buttons.style.overflow = 'visible'; 629 buttons.style.cursor = 'pointer'; 630 631 var bs = graph.getBorderSizes(); 632 633 var left = 0; 634 var fontSize = 10; 635 var bw = 16; 636 var bh = 16; 637 638 if (mxClient.IS_TOUCH) 639 { 640 bw = 24; 641 bh = 24; 642 var fontSize = 14; 643 } 644 645 function addButton(label, funct) 646 { 647 var btn = document.createElement('div'); 648 btn.style.position = 'absolute'; 649 btn.style.border = '1px solid gray'; 650 btn.style.textAlign = 'center'; 651 btn.style.cursor = 'hand'; 652 btn.style.width = bw + 'px'; 653 btn.style.height = bh + 'px'; 654 btn.style.left = left + 'px'; 655 btn.style.top = '0px'; 656 btn.style.backgroundColor = 'white'; 657 mxUtils.setOpacity(btn, 50); 658 659 var table = document.createElement('table'); 660 table.style.borderWidth = '0px'; 661 table.style.width = '100%'; 662 table.style.height = '100%'; 663 var tbody = document.createElement('tbody'); 664 var tr = document.createElement('tr'); 665 var td = document.createElement('td'); 666 td.style.verticalAlign = 'middle'; 667 td.style.textAlign = 'center'; 668 td.style.fontSize = fontSize + 'px'; 669 td.style.padding = '0px'; 670 mxUtils.write(td, label); 671 tr.appendChild(td); 672 tbody.appendChild(tr); 673 table.appendChild(tbody); 674 btn.appendChild(table); 675 676 mxEvent.addListener(btn, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown', function(evt) 677 { 678 mxEvent.consume(evt); 679 }); 680 681 mxEvent.addListener(btn, (mxClient.IS_POINTER) ? 'pointerup' : 'mouseup', function(evt) 682 { 683 funct(); 684 mxEvent.consume(evt); 685 }); 686 687 if (!mxClient.IS_POINTER && mxClient.IS_TOUCH) 688 { 689 mxEvent.addListener(btn, 'touchstart', function(evt) 690 { 691 mxEvent.consume(evt); 692 }); 693 694 mxEvent.addListener(btn, 'touchend', function(evt) 695 { 696 funct(); 697 mxEvent.consume(evt); 698 }); 699 } 700 701 left += bw; 702 buttons.appendChild(btn); 703 704 return btn; 705 }; 706 707 var zoom = configNode.getAttribute('zoom'); 708 709 if (zoom != '0') 710 { 711 addButton('+', function() 712 { 713 graph.zoomIn(); 714 }); 715 716 addButton('-', function() 717 { 718 graph.zoomOut(); 719 }); 720 } 721 722 var edit = configNode.getAttribute('edit'); 723 724 if (edit != null) 725 { 726 var button = addButton('', function() 727 { 728 // _blank is a special value to open a new editor 729 // in client mode and send the XML as a message 730 if (edit == '_blank') 731 { 732 if (url != null) 733 { 734 window.open('https://app.diagrams.net/#U' + encodeURIComponent(url)); 735 } 736 else 737 { 738 var wnd = null; 739 740 var receive = function(evt) 741 { 742 if (evt.data == 'ready' && evt.source == wnd) 743 { 744 wnd.postMessage(xml, '*'); 745 window.removeEventListener('message', receive); 746 } 747 }; 748 749 window.addEventListener('message', receive); 750 wnd = window.open('https://app.diagrams.net/?client=1'); 751 } 752 } 753 else 754 { 755 window.open(edit); 756 } 757 }); 758 759 // Do not use HTML entity to avoid problems with XHTML 760 button.innerHTML = '...'; 761 } 762 763 function show() 764 { 765 buttons.style.top = (container.offsetTop + bs.y) + 'px'; 766 buttons.style.left = (container.offsetLeft + bs.x) + 'px'; 767 buttons.style.visibility = 'visible'; 768 }; 769 770 if (!mxClient.IS_POINTER && !mxClient.IS_TOUCH) 771 { 772 function hide() 773 { 774 buttons.style.visibility = 'hidden'; 775 }; 776 777 mxEvent.addListener(container, 'mouseover', show); 778 mxEvent.addListener(buttons, 'mouseover', show); 779 mxEvent.addListener(container, 'mouseout', hide); 780 mxEvent.addListener(buttons, 'mouseout', hide); 781 hide(); 782 } 783 else 784 { 785 show(); 786 } 787 788 if (buttons.firstChild != null) 789 { 790 if (container.nextSibling != null) 791 { 792 container.parentNode.insertBefore(buttons, container.nextSibling); 793 } 794 else 795 { 796 container.parentNode.appendChild(buttons); 797 } 798 } 799 800 if (typeof(window.mxClientOnCreate) == 'function') 801 { 802 window.mxClientOnCreate(graph); 803 } 804 } 805 } 806 catch (err) 807 { 808 if (window.console != null) 809 { 810 console.log('Error:', err); 811 } 812 } 813 814 mxClient.NO_FO = originalNoFo; 815 816 return graph; 817 }; 818 819 if (typeof(mxClientOnLoad) == 'function') 820 { 821 mxClientOnLoad(stylesheet, initGraph); 822 } 823 else if (mxClient.isBrowserSupported()) 824 { 825 var tmp = document.getElementsByTagName('*'); 826 var divs = []; 827 828 for (var i = 0; i < tmp.length; i++) 829 { 830 divs.push(tmp[i]); 831 } 832 833 for (var i = 0; i < divs.length; i++) 834 { 835 if (divs[i].className.toString().indexOf('mxgraph') >= 0) 836 { 837 initGraph(divs[i]); 838 } 839 } 840 } 841 })(); 842// Last line will be replaced by servlet for passing arguments. 843 844