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) == '&lt;')
159				{
160					xml = xml.replace(/&lt;/g, '<').replace(/&gt;/g, '>').
161						replace(/&amp;gt;/g, '&gt;').replace(/&amp;lt;/g, '&lt;').
162						replace(/&amp;quot;/g, '&quot;').replace(/&#xa;/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