1/**
2 * Copyright (c) 2006-2012, JGraph Ltd
3 */
4/**
5 * Construcs a new sidebar for the given editor.
6 */
7function Sidebar(editorUi, container)
8{
9	this.editorUi = editorUi;
10	this.container = container;
11	this.palettes = new Object();
12	this.taglist = new Object();
13	this.lastCreated = 0;
14	this.showTooltips = true;
15	this.graph = editorUi.createTemporaryGraph(this.editorUi.editor.graph.getStylesheet());
16    this.graph.cellRenderer.minSvgStrokeWidth = this.minThumbStrokeWidth;
17	this.graph.cellRenderer.antiAlias = this.thumbAntiAlias;
18	this.graph.container.style.visibility = 'hidden';
19	this.graph.foldingEnabled = false;
20
21	document.body.appendChild(this.graph.container);
22
23	this.pointerUpHandler = mxUtils.bind(this, function()
24	{
25		if (this.tooltipCloseImage == null || this.tooltipCloseImage.style.display == 'none')
26		{
27			this.showTooltips = true;
28			this.hideTooltip();
29		}
30	});
31
32	mxEvent.addListener(document, (mxClient.IS_POINTER) ? 'pointerup' : 'mouseup', this.pointerUpHandler);
33
34	this.pointerDownHandler = mxUtils.bind(this, function()
35	{
36		if (this.tooltipCloseImage == null || this.tooltipCloseImage.style.display == 'none')
37		{
38			this.showTooltips = false;
39			this.hideTooltip();
40		}
41	});
42
43	mxEvent.addListener(document, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown', this.pointerDownHandler);
44
45	this.pointerMoveHandler = mxUtils.bind(this, function(evt)
46	{
47		if (Date.now() - this.lastCreated > 300 && (this.tooltipCloseImage == null ||
48			this.tooltipCloseImage.style.display == 'none'))
49		{
50			var src = mxEvent.getSource(evt);
51
52			while (src != null)
53			{
54				if (src == this.currentElt)
55				{
56					return;
57				}
58
59				src = src.parentNode;
60			}
61
62			this.hideTooltip();
63		}
64	});
65
66	mxEvent.addListener(document, (mxClient.IS_POINTER) ? 'pointermove' : 'mousemove', this.pointerMoveHandler);
67
68	// Handles mouse leaving the window
69	this.pointerOutHandler = mxUtils.bind(this, function(evt)
70	{
71		if (evt.toElement == null && evt.relatedTarget == null)
72		{
73			this.hideTooltip();
74		}
75	});
76
77	mxEvent.addListener(document, (mxClient.IS_POINTER) ? 'pointerout' : 'mouseout', this.pointerOutHandler);
78
79	// Enables tooltips after scroll
80	mxEvent.addListener(container, 'scroll', mxUtils.bind(this, function()
81	{
82		this.showTooltips = true;
83		this.hideTooltip();
84	}));
85
86	this.init();
87};
88
89/**
90 * Adds all palettes to the sidebar.
91 */
92Sidebar.prototype.init = function()
93{
94	var dir = STENCIL_PATH;
95
96	this.addSearchPalette(true);
97	this.addGeneralPalette(true);
98	this.addMiscPalette(false);
99	this.addAdvancedPalette(false);
100	this.addBasicPalette(dir);
101
102	this.setCurrentSearchEntryLibrary('arrows');
103	this.addStencilPalette('arrows', mxResources.get('arrows'), dir + '/arrows.xml',
104		';whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#000000;strokeWidth=2');
105	this.setCurrentSearchEntryLibrary();
106
107	this.addUmlPalette(false);
108	this.addBpmnPalette(dir, false);
109
110	this.setCurrentSearchEntryLibrary('flowchart');
111	this.addStencilPalette('flowchart', 'Flowchart', dir + '/flowchart.xml',
112		';whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#000000;strokeWidth=2');
113	this.setCurrentSearchEntryLibrary();
114
115	this.setCurrentSearchEntryLibrary('clipart');
116	this.addImagePalette('clipart', mxResources.get('clipart'), dir + '/clipart/', '_128x128.png',
117		['Earth_globe', 'Empty_Folder', 'Full_Folder', 'Gear', 'Lock', 'Software', 'Virus', 'Email',
118		 'Database', 'Router_Icon', 'iPad', 'iMac', 'Laptop', 'MacBook', 'Monitor_Tower', 'Printer',
119		 'Server_Tower', 'Workstation', 'Firewall_02', 'Wireless_Router_N', 'Credit_Card',
120		 'Piggy_Bank', 'Graph', 'Safe', 'Shopping_Cart', 'Suit1', 'Suit2', 'Suit3', 'Pilot1',
121		 'Worker1', 'Soldier1', 'Doctor1', 'Tech1', 'Security1', 'Telesales1'], null,
122		 {'Wireless_Router_N': 'wireless router switch wap wifi access point wlan',
123		  'Router_Icon': 'router switch'});
124	this.setCurrentSearchEntryLibrary();
125};
126
127/**
128 * Sets the default font size.
129 */
130Sidebar.prototype.collapsedImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/collapsed.gif' : 'data:image/gif;base64,R0lGODlhDQANAIABAJmZmf///yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozNUQyRTJFNjZGNUYxMUU1QjZEOThCNDYxMDQ2MzNCQiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozNUQyRTJFNzZGNUYxMUU1QjZEOThCNDYxMDQ2MzNCQiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjFERjc3MEUxNkY1RjExRTVCNkQ5OEI0NjEwNDYzM0JCIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjFERjc3MEUyNkY1RjExRTVCNkQ5OEI0NjEwNDYzM0JCIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Af/+/fz7+vn49/b19PPy8fDv7u3s6+rp6Ofm5eTj4uHg397d3Nva2djX1tXU09LR0M/OzczLysnIx8bFxMPCwcC/vr28u7q5uLe2tbSzsrGwr66trKuqqainpqWko6KhoJ+enZybmpmYl5aVlJOSkZCPjo2Mi4qJiIeGhYSDgoGAf359fHt6eXh3dnV0c3JxcG9ubWxramloZ2ZlZGNiYWBfXl1cW1pZWFdWVVRTUlFQT05NTEtKSUhHRkVEQ0JBQD8+PTw7Ojk4NzY1NDMyMTAvLi0sKyopKCcmJSQjIiEgHx4dHBsaGRgXFhUUExIREA8ODQwLCgkIBwYFBAMCAQAAIfkEAQAAAQAsAAAAAA0ADQAAAhSMj6lrwAjcC1GyahV+dcZJgeIIFgA7';
131
132/**
133 * Sets the default font size.
134 */
135Sidebar.prototype.expandedImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/expanded.gif' : 'data:image/gif;base64,R0lGODlhDQANAIABAJmZmf///yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxREY3NzBERjZGNUYxMUU1QjZEOThCNDYxMDQ2MzNCQiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxREY3NzBFMDZGNUYxMUU1QjZEOThCNDYxMDQ2MzNCQiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjFERjc3MERENkY1RjExRTVCNkQ5OEI0NjEwNDYzM0JCIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjFERjc3MERFNkY1RjExRTVCNkQ5OEI0NjEwNDYzM0JCIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Af/+/fz7+vn49/b19PPy8fDv7u3s6+rp6Ofm5eTj4uHg397d3Nva2djX1tXU09LR0M/OzczLysnIx8bFxMPCwcC/vr28u7q5uLe2tbSzsrGwr66trKuqqainpqWko6KhoJ+enZybmpmYl5aVlJOSkZCPjo2Mi4qJiIeGhYSDgoGAf359fHt6eXh3dnV0c3JxcG9ubWxramloZ2ZlZGNiYWBfXl1cW1pZWFdWVVRTUlFQT05NTEtKSUhHRkVEQ0JBQD8+PTw7Ojk4NzY1NDMyMTAvLi0sKyopKCcmJSQjIiEgHx4dHBsaGRgXFhUUExIREA8ODQwLCgkIBwYFBAMCAQAAIfkEAQAAAQAsAAAAAA0ADQAAAhGMj6nL3QAjVHIu6azbvPtWAAA7';
136
137/**
138 *
139 */
140Sidebar.prototype.searchImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/search.png' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAEaSURBVHjabNGxS5VxFIfxz71XaWuQUJCG/gCHhgTD9VpEETg4aMOlQRp0EoezObgcd220KQiXmpretTAHQRBdojlQEJyukPdt+b1ywfvAGc7wnHP4nlZd1yKijQW8xzNc4Su+ZOYfQ3T6/f4YNvEJYzjELXp4VVXVz263+7cR2niBxAFeZ2YPi3iHR/gYERPDwhpOsd6sz8x/mfkNG3iOlWFhFj8y89J9KvzGXER0GuEaD42mgwHqUtoljbcRsTBCeINpfM/MgZLKPpaxFxGbOCqDXmILN7hoJrTKH+axhxmcYRxP0MIDnOBDZv5q1XUNIuJxifJp+UNV7t7BFM6xeic0RMQ4Bpl5W/ol7GISx/eEUUTECrbx+f8A8xhiZht9zsgAAAAASUVORK5CYII=';
141
142/**
143 * Specifies if tooltips should be visible. Default is true.
144 */
145Sidebar.prototype.enableTooltips = true;
146
147/**
148 * Specifies the delay for the tooltip. Default is 16 px.
149 */
150Sidebar.prototype.tooltipBorder = 16;
151
152/**
153 * Specifies the delay for the tooltip. Default is 300 ms.
154 */
155Sidebar.prototype.tooltipDelay = 300;
156
157/**
158 * Specifies the delay for the drop target icons. Default is 200 ms.
159 */
160Sidebar.prototype.dropTargetDelay = 200;
161
162/**
163 * Specifies the URL of the gear image.
164 */
165Sidebar.prototype.gearImage = STENCIL_PATH + '/clipart/Gear_128x128.png';
166
167/**
168 * Specifies the width of the thumbnails.
169 */
170Sidebar.prototype.thumbWidth = 42;
171
172/**
173 * Specifies the height of the thumbnails.
174 */
175Sidebar.prototype.thumbHeight = 42;
176
177/**
178 * Specifies the width of the thumbnails.
179 */
180Sidebar.prototype.minThumbStrokeWidth = 1;
181
182/**
183 * Specifies the width of the thumbnails.
184 */
185Sidebar.prototype.thumbAntiAlias = false;
186
187/**
188 * Specifies the padding for the thumbnails. Default is 3.
189 */
190Sidebar.prototype.thumbPadding = (document.documentMode >= 5) ? 2 : 3;
191
192/**
193 * Specifies the delay for the tooltip. Default is 2 px.
194 */
195Sidebar.prototype.thumbBorder = 2;
196
197/*
198 * Experimental smaller sidebar entries
199 */
200if (urlParams['sidebar-entries'] != 'large')
201{
202	Sidebar.prototype.thumbPadding = (document.documentMode >= 5) ? 0 : 1;
203	Sidebar.prototype.thumbBorder = 1;
204	Sidebar.prototype.thumbWidth = 32;
205	Sidebar.prototype.thumbHeight = 30;
206	Sidebar.prototype.minThumbStrokeWidth = 1.3;
207	Sidebar.prototype.thumbAntiAlias = true;
208}
209
210/**
211 * Specifies the size of the sidebar titles.
212 */
213Sidebar.prototype.sidebarTitleSize = 8;
214
215/**
216 * Specifies if titles in the sidebar should be enabled.
217 */
218Sidebar.prototype.sidebarTitles = false;
219
220/**
221 * Specifies if titles in the tooltips should be enabled.
222 */
223Sidebar.prototype.tooltipTitles = true;
224
225/**
226 * Specifies if titles in the tooltips should be enabled.
227 */
228Sidebar.prototype.maxTooltipWidth = 400;
229
230/**
231 * Specifies if titles in the tooltips should be enabled.
232 */
233Sidebar.prototype.maxTooltipHeight = 400;
234
235/**
236 * Specifies if stencil files should be loaded and added to the search index
237 * when stencil palettes are added. If this is false then the stencil files
238 * are lazy-loaded when the palette is shown.
239 */
240Sidebar.prototype.addStencilsToIndex = true;
241
242/**
243 * Specifies the width for clipart images. Default is 80.
244 */
245Sidebar.prototype.defaultImageWidth = 80;
246
247/**
248 * Specifies the height for clipart images. Default is 80.
249 */
250Sidebar.prototype.defaultImageHeight = 80;
251
252/**
253 * Specifies the height for clipart images. Default is 80.
254 */
255Sidebar.prototype.tooltipMouseDown = null;
256
257/**
258 * Adds all palettes to the sidebar.
259 */
260Sidebar.prototype.getTooltipOffset = function(elt, bounds)
261{
262	var b = document.body;
263	var d = document.documentElement;
264	var bottom = Math.max(b.clientHeight || 0, d.clientHeight);
265	var width = bounds.width + 2 * this.tooltipBorder + 4;
266	var height = bounds.height + 2 * this.tooltipBorder;
267
268	return new mxPoint(this.container.offsetWidth + this.editorUi.splitSize + 10 + this.editorUi.container.offsetLeft,
269		Math.min(bottom - height - 20 /*status bar*/, Math.max(0, (this.editorUi.container.offsetTop +
270			this.container.offsetTop + elt.offsetTop - this.container.scrollTop - height / 2 + 16))));
271};
272
273/**
274 * Adds all palettes to the sidebar.
275 */
276Sidebar.prototype.createTooltip = function(elt, cells, w, h, title, showLabel, off, maxSize, mouseDown, closable, applyAllStyles)
277{
278	applyAllStyles = (applyAllStyles != null) ? applyAllStyles : true;
279	this.tooltipMouseDown = mouseDown;
280
281	// Lazy creation of the DOM nodes and graph instance
282	if (this.tooltip == null)
283	{
284		this.tooltip = document.createElement('div');
285		this.tooltip.className = 'geSidebarTooltip';
286		this.tooltip.style.userSelect = 'none';
287		this.tooltip.style.zIndex = mxPopupMenu.prototype.zIndex - 1;
288		document.body.appendChild(this.tooltip);
289
290		mxEvent.addMouseWheelListener(mxUtils.bind(this, function(evt)
291		{
292			this.hideTooltip();
293		}), this.tooltip);
294
295		this.graph2 = new Graph(this.tooltip, null, null, this.editorUi.editor.graph.getStylesheet());
296		this.graph2.resetViewOnRootChange = false;
297		this.graph2.foldingEnabled = false;
298		this.graph2.gridEnabled = false;
299		this.graph2.autoScroll = false;
300		this.graph2.setTooltips(false);
301		this.graph2.setConnectable(false);
302		this.graph2.setPanning(false);
303		this.graph2.setEnabled(false);
304
305		// Blocks all links
306		this.graph2.openLink = mxUtils.bind(this, function()
307		{
308			this.hideTooltip();
309		});
310
311		mxEvent.addGestureListeners(this.tooltip, mxUtils.bind(this, function(evt)
312		{
313			if (this.tooltipMouseDown != null)
314			{
315				this.tooltipMouseDown(evt);
316			}
317
318			window.setTimeout(mxUtils.bind(this, function()
319			{
320				if (this.tooltipCloseImage == null || this.tooltipCloseImage.style.display == 'none')
321				{
322					this.hideTooltip();
323				}
324			}), 0);
325		}), null, mxUtils.bind(this, function(evt)
326		{
327			this.hideTooltip();
328		}));
329
330		if (!mxClient.IS_SVG)
331		{
332			this.graph2.view.canvas.style.position = 'relative';
333		}
334
335		var close = document.createElement('img');
336		close.setAttribute('src', Dialog.prototype.closeImage);
337		close.setAttribute('title', mxResources.get('close'));
338		close.style.position = 'absolute';
339		close.style.cursor = 'default';
340		close.style.padding = '8px';
341		close.style.right = '2px';
342		close.style.top = '2px';
343		this.tooltip.appendChild(close);
344		this.tooltipCloseImage = close;
345
346		mxEvent.addListener(close, 'click', mxUtils.bind(this, function(evt)
347		{
348			this.hideTooltip();
349			mxEvent.consume(evt);
350		}));
351	}
352
353	this.tooltipCloseImage.style.display = (closable) ? '' : 'none';
354	this.graph2.model.clear();
355	this.graph2.view.setTranslate(this.tooltipBorder, this.tooltipBorder);
356
357	if (!maxSize && (w > this.maxTooltipWidth || h > this.maxTooltipHeight))
358	{
359		this.graph2.view.scale = Math.round(Math.min(this.maxTooltipWidth / w, this.maxTooltipHeight / h) * 100) / 100;
360	}
361	else
362	{
363		this.graph2.view.scale = 1;
364	}
365
366	this.tooltip.style.display = 'block';
367	this.graph2.labelsVisible = (showLabel == null || showLabel);
368	var fo = mxClient.NO_FO;
369	mxClient.NO_FO = Editor.prototype.originalNoForeignObject;
370
371	// Applies current style for preview
372	var temp = this.graph2.cloneCells(cells);
373	this.editorUi.insertHandler(temp, null, this.graph2.model,
374		(!applyAllStyles) ? this.editorUi.editor.graph.defaultVertexStyle : null,
375		(!applyAllStyles) ? this.editorUi.editor.graph.defaultEdgeStyle : null,
376		applyAllStyles, true);
377	this.graph2.addCells(temp);
378
379	mxClient.NO_FO = fo;
380	var bounds = this.graph2.getGraphBounds();
381
382	// Maximum size applied with transform for faster repaint
383	if (maxSize && w > 0 && h > 0 && (bounds.width > w || bounds.height > h))
384	{
385		var s = Math.round(Math.min(w / bounds.width, h / bounds.height) * 100) / 100;
386
387		if (!mxClient.NO_FO)
388		{
389			this.graph2.view.getDrawPane().ownerSVGElement.style.transform = 'scale(' + s + ')';
390			this.graph2.view.getDrawPane().ownerSVGElement.style.transformOrigin = '0 0';
391			bounds.width *= s;
392			bounds.height *= s;
393		}
394		else
395		{
396			this.graph2.view.setScale(Math.round(Math.min(this.maxTooltipWidth / bounds.width, this.maxTooltipHeight / bounds.height) * 100) / 100);
397			bounds = this.graph2.getGraphBounds();
398		}
399	}
400	else if (!mxClient.NO_FO)
401	{
402		this.graph2.view.getDrawPane().ownerSVGElement.style.transform = '';
403	}
404
405	var width = bounds.width + 2 * this.tooltipBorder + 4;
406	var height = bounds.height + 2 * this.tooltipBorder;
407
408	this.tooltip.style.overflow = 'visible';
409	this.tooltip.style.width = width + 'px';
410	var w2 = width;
411
412	// Adds title for entry
413	if (this.tooltipTitles && title != null && title.length > 0)
414	{
415		if (this.tooltipTitle == null)
416		{
417			this.tooltipTitle = document.createElement('div');
418			this.tooltipTitle.style.borderTop = '1px solid gray';
419			this.tooltipTitle.style.textAlign = 'center';
420			this.tooltipTitle.style.width = '100%';
421			this.tooltipTitle.style.overflow = 'hidden';
422			this.tooltipTitle.style.position = 'absolute';
423			this.tooltipTitle.style.paddingTop = '6px';
424			this.tooltipTitle.style.bottom = '6px';
425
426			this.tooltip.appendChild(this.tooltipTitle);
427		}
428		else
429		{
430			this.tooltipTitle.innerHTML = '';
431		}
432
433		this.tooltipTitle.style.display = '';
434		mxUtils.write(this.tooltipTitle, title);
435
436		// Allows for wider labels
437		w2 = Math.min(this.maxTooltipWidth, Math.max(width, this.tooltipTitle.scrollWidth + 4));
438		var ddy = this.tooltipTitle.offsetHeight + 10;
439		height += ddy;
440
441		if (mxClient.IS_SVG)
442		{
443			this.tooltipTitle.style.marginTop = (2 - ddy) + 'px';
444		}
445		else
446		{
447			height -= 6;
448			this.tooltipTitle.style.top = (height - ddy) + 'px';
449		}
450	}
451	else if (this.tooltipTitle != null && this.tooltipTitle.parentNode != null)
452	{
453		this.tooltipTitle.style.display = 'none';
454	}
455
456	// Updates width if label is wider
457	if (w2 > width)
458	{
459		this.tooltip.style.width = w2 + 'px';
460	}
461
462	this.tooltip.style.height = height + 'px';
463	var x0 = -Math.round(bounds.x - this.tooltipBorder) +
464		((w2 > width) ? (w2 - width) / 2 : 0);
465	var y0 = -Math.round(bounds.y - this.tooltipBorder);
466	off = (off != null) ? off : this.getTooltipOffset(elt, bounds);
467	var left = off.x;
468	var top = off.y;
469
470	if (mxClient.IS_SVG)
471	{
472		if (x0 != 0 || y0 != 0)
473		{
474			this.graph2.view.canvas.setAttribute('transform', 'translate(' + x0 + ',' + y0 + ')');
475		}
476		else
477		{
478			this.graph2.view.canvas.removeAttribute('transform');
479		}
480	}
481	else
482	{
483		this.graph2.view.drawPane.style.left = x0 + 'px';
484		this.graph2.view.drawPane.style.top = y0 + 'px';
485	}
486
487	// Workaround for ignored position CSS style in IE9
488	// (changes to relative without the following line)
489	this.tooltip.style.position = 'absolute';
490	this.tooltip.style.left = left + 'px';
491	this.tooltip.style.top = top + 'px';
492
493	mxUtils.fit(this.tooltip);
494	this.lastCreated = Date.now();
495};
496
497/**
498 * Adds all palettes to the sidebar.
499 */
500Sidebar.prototype.showTooltip = function(elt, cells, w, h, title, showLabel)
501{
502	if (this.enableTooltips && this.showTooltips)
503	{
504		if (this.currentElt != elt)
505		{
506			if (this.thread != null)
507			{
508				window.clearTimeout(this.thread);
509				this.thread = null;
510			}
511
512			var show = mxUtils.bind(this, function()
513			{
514				this.createTooltip(elt, cells, w, h, title, showLabel);
515			});
516
517			if (this.tooltip != null && this.tooltip.style.display != 'none')
518			{
519				show();
520			}
521			else
522			{
523				this.thread = window.setTimeout(show, this.tooltipDelay);
524			}
525
526			this.currentElt = elt;
527		}
528	}
529};
530
531/**
532 * Hides the current tooltip.
533 */
534Sidebar.prototype.hideTooltip = function()
535{
536	if (this.thread != null)
537	{
538		window.clearTimeout(this.thread);
539		this.thread = null;
540	}
541
542	if (this.tooltip != null)
543	{
544		this.tooltip.style.display = 'none';
545		this.currentElt = null;
546	}
547
548	this.tooltipMouseDown = null;
549};
550
551/**
552 * Hides the current tooltip.
553 */
554Sidebar.prototype.addDataEntry = function(tags, width, height, title, data)
555{
556	return this.addEntry(tags, mxUtils.bind(this, function()
557	{
558	   	return this.createVertexTemplateFromData(data, width, height, title);
559	}));
560};
561
562/**
563 * Adds the give entries to the search index.
564 */
565Sidebar.prototype.addEntries = function(images)
566{
567	for (var i = 0; i < images.length; i++)
568	{
569		(mxUtils.bind(this, function(img)
570		{
571			var data = img.data;
572			var tags = (img.title != null) ? img.title : '';
573
574			if (img.tags != null)
575			{
576				tags += ' ' + img.tags;
577			}
578
579			if (data != null && tags.length > 0)
580			{
581				this.addEntry(tags, mxUtils.bind(this, function()
582				{
583					data = this.editorUi.convertDataUri(data);
584					var s = 'shape=image;verticalLabelPosition=bottom;verticalAlign=top;imageAspect=0;';
585
586					if (img.aspect == 'fixed')
587					{
588						s += 'aspect=fixed;'
589					}
590
591					return this.createVertexTemplate(s + 'image=' +
592						data, img.w, img.h, '', img.title || '', false, false, true)
593				}));
594			}
595			else if (img.xml != null && tags.length > 0)
596			{
597				this.addEntry(tags, mxUtils.bind(this, function()
598				{
599					var cells = this.editorUi.stringToCells(Graph.decompress(img.xml));
600
601					return this.createVertexTemplateFromCells(
602						cells, img.w, img.h, img.title || '', true, false, true);
603				}));
604			}
605		}))(images[i]);
606	}
607};
608
609/**
610 * Hides the current tooltip.
611 */
612Sidebar.prototype.setCurrentSearchEntryLibrary = function(id, lib)
613{
614	this.currentSearchEntryLibrary = (id != null) ? {id: id, lib: lib} : null;
615};
616
617/**
618 * Hides the current tooltip.
619 */
620Sidebar.prototype.addEntry = function(tags, fn)
621{
622	if (this.taglist != null && tags != null && tags.length > 0)
623	{
624		if (this.currentSearchEntryLibrary != null)
625		{
626			fn.parentLibraries = [this.currentSearchEntryLibrary];
627		}
628
629		// Replaces special characters
630		var tmp = tags.toLowerCase().replace(/[\/\,\(\)]/g, ' ').split(' ');
631		var tagList = [];
632		var hash = {};
633
634		// Finds unique tags
635		for (var i = 0; i < tmp.length; i++)
636		{
637			if (hash[tmp[i]] == null)
638			{
639				hash[tmp[i]] = true;
640				tagList.push(tmp[i]);
641			}
642
643			// Adds additional entry with removed trailing numbers
644			var normalized = tmp[i].replace(/\.*\d*$/, '');
645
646			if (normalized != tmp[i])
647			{
648				if (hash[normalized] == null)
649				{
650					hash[normalized] = true;
651					tagList.push(normalized);
652				}
653			}
654		}
655
656		for (var i = 0; i < tagList.length; i++)
657		{
658			this.addEntryForTag(tagList[i], fn);
659		}
660	}
661
662	return fn;
663};
664
665/**
666 * Hides the current tooltip.
667 */
668Sidebar.prototype.addEntryForTag = function(tag, fn)
669{
670	if (tag != null && tag.length > 1)
671	{
672		var entry = this.taglist[tag];
673
674		if (typeof entry !== 'object')
675		{
676			entry = {entries: []};
677			this.taglist[tag] = entry;
678		}
679
680		entry.entries.push(fn);
681	}
682};
683
684/**
685 * Adds shape search UI.
686 */
687Sidebar.prototype.searchEntries = function(searchTerms, count, page, success, error)
688{
689	if (this.taglist != null && searchTerms != null)
690	{
691		var tmp = searchTerms.toLowerCase().split(' ');
692		var dict = new mxDictionary();
693		var max = (page + 1) * count;
694		var results = [];
695		var index = 0;
696
697		for (var i = 0; i < tmp.length; i++)
698		{
699			if (tmp[i].length > 0)
700			{
701				var entry = this.taglist[tmp[i]];
702				var tmpDict = new mxDictionary();
703
704				if (entry != null)
705				{
706					var arr = entry.entries;
707					results = [];
708
709					for (var j = 0; j < arr.length; j++)
710					{
711						var entry = arr[j];
712
713						// NOTE Array does not contain duplicates
714						if ((index == 0) == (dict.get(entry) == null))
715						{
716							tmpDict.put(entry, entry);
717							results.push(entry);
718
719							if (i == tmp.length - 1 && results.length == max)
720							{
721								success(results.slice(page * count, max), max, true, tmp);
722
723								return;
724							}
725						}
726					}
727				}
728				else
729				{
730					results = [];
731				}
732
733				dict = tmpDict;
734				index++;
735			}
736		}
737
738		var len = results.length;
739		success(results.slice(page * count, (page + 1) * count), len, false, tmp);
740	}
741	else
742	{
743		success([], null, null, tmp);
744	}
745};
746
747/**
748 * Adds shape search UI.
749 */
750Sidebar.prototype.filterTags = function(tags)
751{
752	if (tags != null)
753	{
754		var arr = tags.split(' ');
755		var result = [];
756		var hash = {};
757
758		// Ignores tags with leading numbers, strips trailing numbers
759		for (var i = 0; i < arr.length; i++)
760		{
761			// Removes duplicates
762			if (hash[arr[i]] == null)
763			{
764				hash[arr[i]] = '1';
765				result.push(arr[i]);
766			}
767		}
768
769		return result.join(' ');
770	}
771
772	return null;
773};
774
775/**
776 * Adds the general palette to the sidebar.
777 */
778Sidebar.prototype.cloneCell = function(cell, value)
779{
780	var clone = cell.clone();
781
782	if (value != null)
783	{
784		clone.value = value;
785	}
786
787	return clone;
788};
789
790/**
791 * Adds shape search UI.
792 */
793Sidebar.prototype.showPopupMenuForEntry = function(elt, libs, evt)
794{
795	// Hook for subclassers
796};
797
798/**
799 * Adds shape search UI.
800 */
801Sidebar.prototype.addSearchPalette = function(expand)
802{
803	var elt = document.createElement('div');
804	elt.style.visibility = 'hidden';
805	this.container.appendChild(elt);
806
807	var div = document.createElement('div');
808	div.className = 'geSidebar';
809	div.style.boxSizing = 'border-box';
810	div.style.overflow = 'hidden';
811	div.style.width = '100%';
812	div.style.padding = '8px';
813	div.style.paddingTop = '14px';
814	div.style.paddingBottom = '0px';
815
816	if (!expand)
817	{
818		div.style.display = 'none';
819	}
820
821	var inner = document.createElement('div');
822	inner.style.whiteSpace = 'nowrap';
823	inner.style.textOverflow = 'clip';
824	inner.style.paddingBottom = '8px';
825	inner.style.cursor = 'default';
826
827	var input = document.createElement('input');
828	input.setAttribute('placeholder', mxResources.get('searchShapes'));
829	input.setAttribute('type', 'text');
830	input.style.fontSize = '12px';
831	input.style.overflow = 'hidden';
832	input.style.boxSizing = 'border-box';
833	input.style.border = 'solid 1px #d5d5d5';
834	input.style.borderRadius = '4px';
835	input.style.width = '100%';
836	input.style.outline = 'none';
837	input.style.padding = '6px';
838	input.style.paddingRight = '20px';
839	inner.appendChild(input);
840
841	var cross = document.createElement('img');
842	cross.setAttribute('src', Sidebar.prototype.searchImage);
843	cross.setAttribute('title', mxResources.get('search'));
844	cross.style.position = 'relative';
845	cross.style.left = '-18px';
846	cross.style.top = '1px';
847
848	// Needed to block event transparency in IE
849	cross.style.background = 'url(\'' + this.editorUi.editor.transparentImage + '\')';
850
851	var find;
852
853	inner.appendChild(cross);
854	div.appendChild(inner);
855
856	var center = document.createElement('center');
857	var button = mxUtils.button(mxResources.get('moreResults'), function()
858	{
859		find();
860	});
861	button.style.display = 'none';
862
863	// Workaround for inherited line-height in quirks mode
864	button.style.lineHeight = 'normal';
865	button.style.fontSize = '12px';
866	button.style.padding = '6px 12px 6px 12px';
867	button.style.marginTop = '4px';
868	button.style.marginBottom = '8px';
869	center.style.paddingTop = '4px';
870	center.style.paddingBottom = '4px';
871
872	center.appendChild(button);
873	div.appendChild(center);
874
875	var searchTerm = '';
876	var active = false;
877	var complete = false;
878	var page = 0;
879	var hash = new Object();
880
881	// Count is dynamically updated below
882	var count = 12;
883
884	var clearDiv = mxUtils.bind(this, function()
885	{
886		active = false;
887		this.currentSearch = null;
888		var child = div.firstChild;
889
890		while (child != null)
891		{
892			var next = child.nextSibling;
893
894			if (child != inner && child != center)
895			{
896				child.parentNode.removeChild(child);
897			}
898
899			child = next;
900		}
901	});
902
903	mxEvent.addListener(cross, 'click', function()
904	{
905		if (cross.getAttribute('src') == Dialog.prototype.closeImage)
906		{
907			cross.setAttribute('src', Sidebar.prototype.searchImage);
908			cross.setAttribute('title', mxResources.get('search'));
909			button.style.display = 'none';
910			input.value = '';
911			searchTerm = '';
912			clearDiv();
913		}
914
915		input.focus();
916	});
917
918	find = mxUtils.bind(this, function()
919	{
920		// Shows 4 rows (minimum 4 results)
921		count = 4 * Math.max(1, Math.floor(this.container.clientWidth / (this.thumbWidth + 10)));
922		this.hideTooltip();
923
924		if (input.value != '')
925		{
926			if (center.parentNode != null)
927			{
928				if (searchTerm != input.value)
929				{
930					clearDiv();
931					searchTerm = input.value;
932					hash = new Object();
933					complete = false;
934					page = 0;
935				}
936
937				if (!active && !complete)
938				{
939					button.setAttribute('disabled', 'true');
940					button.style.display = '';
941					button.style.cursor = 'wait';
942					button.innerHTML = mxResources.get('loading') + '...';
943					active = true;
944
945					// Ignores old results
946					var current = new Object();
947					this.currentSearch = current;
948
949					this.searchEntries(searchTerm, count, page, mxUtils.bind(this, function(results, len, more, terms)
950					{
951						if (this.currentSearch == current)
952						{
953							results = (results != null) ? results : [];
954							active = false;
955							page++;
956							this.insertSearchHint(div, searchTerm, count, page, results, len, more, terms);
957
958							// Allows to repeat the search
959							if (results.length == 0 && page == 1)
960							{
961								searchTerm = '';
962							}
963
964							if (center.parentNode != null)
965							{
966								center.parentNode.removeChild(center);
967							}
968
969							for (var i = 0; i < results.length; i++)
970							{
971								(mxUtils.bind(this, function(result)
972								{
973									try
974									{
975										var elt = result();
976
977										// Avoids duplicates in results
978										if (hash[elt.innerHTML] == null)
979										{
980											hash[elt.innerHTML] = (result.parentLibraries != null) ? result.parentLibraries.slice() : [];
981											div.appendChild(elt);
982										}
983										else if (result.parentLibraries != null)
984										{
985											hash[elt.innerHTML] = hash[elt.innerHTML].concat(result.parentLibraries);
986										}
987
988										mxEvent.addGestureListeners(elt, null, null, mxUtils.bind(this, function(evt)
989										{
990											var libs = hash[elt.innerHTML];
991
992											if (mxEvent.isPopupTrigger(evt))
993											{
994												this.showPopupMenuForEntry(elt, libs, evt);
995											}
996										}));
997
998										// Disables the built-in context menu
999										mxEvent.disableContextMenu(elt);
1000									}
1001									catch (e)
1002									{
1003										// ignore
1004									}
1005								}))(results[i]);
1006							}
1007
1008							if (more)
1009							{
1010								button.removeAttribute('disabled');
1011								button.innerHTML = mxResources.get('moreResults');
1012							}
1013							else
1014							{
1015								button.innerHTML = mxResources.get('reset');
1016								button.style.display = 'none';
1017								complete = true;
1018							}
1019
1020							button.style.cursor = '';
1021							div.appendChild(center);
1022						}
1023					}), mxUtils.bind(this, function()
1024					{
1025						// TODO: Error handling
1026						button.style.cursor = '';
1027					}));
1028				}
1029			}
1030		}
1031		else
1032		{
1033			clearDiv();
1034			input.value = '';
1035			searchTerm = '';
1036			hash = new Object();
1037			button.style.display = 'none';
1038			complete = false;
1039			input.focus();
1040		}
1041	});
1042
1043	this.searchShapes = function(value)
1044	{
1045		input.value = value;
1046		find();
1047	};
1048
1049	mxEvent.addListener(input, 'keydown', mxUtils.bind(this, function(evt)
1050	{
1051		if (evt.keyCode == 13 /* Enter */)
1052		{
1053			find();
1054			mxEvent.consume(evt);
1055		}
1056	}));
1057
1058	mxEvent.addListener(input, 'keyup', mxUtils.bind(this, function(evt)
1059	{
1060		if (input.value == '')
1061		{
1062			cross.setAttribute('src', Sidebar.prototype.searchImage);
1063			cross.setAttribute('title', mxResources.get('search'));
1064		}
1065		else
1066		{
1067			cross.setAttribute('src', Dialog.prototype.closeImage);
1068			cross.setAttribute('title', mxResources.get('reset'));
1069		}
1070
1071		if (input.value == '')
1072		{
1073			complete = true;
1074			button.style.display = 'none';
1075		}
1076		else if (input.value != searchTerm)
1077		{
1078			button.style.display = 'none';
1079			complete = false;
1080		}
1081		else if (!active)
1082		{
1083			if (complete)
1084			{
1085				button.style.display = 'none';
1086			}
1087			else
1088			{
1089				button.style.display = '';
1090			}
1091		}
1092	}));
1093
1094    // Workaround for blocked text selection in Editor
1095    mxEvent.addListener(input, 'mousedown', function(evt)
1096    {
1097    	if (evt.stopPropagation)
1098    	{
1099    		evt.stopPropagation();
1100    	}
1101
1102    	evt.cancelBubble = true;
1103    });
1104
1105    // Workaround for blocked text selection in Editor
1106    mxEvent.addListener(input, 'selectstart', function(evt)
1107    {
1108    	if (evt.stopPropagation)
1109    	{
1110    		evt.stopPropagation();
1111    	}
1112
1113    	evt.cancelBubble = true;
1114    });
1115
1116	var outer = document.createElement('div');
1117    outer.appendChild(div);
1118    this.container.appendChild(outer);
1119
1120    // Keeps references to the DOM nodes
1121	this.palettes['search'] = [elt, outer];
1122};
1123
1124/**
1125 * Adds the general palette to the sidebar.
1126 */
1127Sidebar.prototype.insertSearchHint = function(div, searchTerm, count, page, results, len, more, terms)
1128{
1129	if (results.length == 0 && page == 1)
1130	{
1131		var err = document.createElement('div');
1132		err.className = 'geTitle';
1133		err.style.cssText = 'background-color:transparent;border-color:transparent;' +
1134			'color:gray;padding:6px 0px 0px 0px !important;margin:4px 8px 4px 8px;' +
1135			'text-align:center;cursor:default !important';
1136
1137		mxUtils.write(err, mxResources.get('noResultsFor', [searchTerm]));
1138		div.appendChild(err);
1139	}
1140};
1141
1142/**
1143 * Adds the general palette to the sidebar.
1144 */
1145Sidebar.prototype.addGeneralPalette = function(expand)
1146{
1147	var lineTags = 'line lines connector connectors connection connections arrow arrows ';
1148	this.setCurrentSearchEntryLibrary('general', 'general');
1149	var sb = this;
1150
1151	var temp = parseInt(this.editorUi.editor.graph.defaultVertexStyle['fontSize']);
1152	var fontSize = !isNaN(temp) ? 'fontSize=' + Math.min(16, temp) + ';' : '';
1153
1154	// Reusable cells
1155	var field = new mxCell('List Item', new mxGeometry(0, 0, 80, 30),
1156		'text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;' +
1157		'spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];' +
1158		'portConstraint=eastwest;rotatable=0;' + fontSize);
1159	field.vertex = true;
1160
1161	var fns = [
1162	 	this.createVertexTemplateEntry('rounded=0;whiteSpace=wrap;html=1;', 120, 60, '', 'Rectangle', null, null, 'rect rectangle box'),
1163	 	this.createVertexTemplateEntry('rounded=1;whiteSpace=wrap;html=1;', 120, 60, '', 'Rounded Rectangle', null, null, 'rounded rect rectangle box'),
1164	 	// Explicit strokecolor/fillcolor=none is a workaround to maintain transparent background regardless of current style
1165	 	this.createVertexTemplateEntry('text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;',
1166 			60, 30, 'Text', 'Text', null, null, 'text textbox textarea label'),
1167	 	this.createVertexTemplateEntry('text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;', 190, 120,
1168			'<h1>Heading</h1><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>',
1169			'Textbox', null, null, 'text textbox textarea'),
1170 		this.createVertexTemplateEntry('ellipse;whiteSpace=wrap;html=1;', 120, 80, '', 'Ellipse', null, null, 'oval ellipse state'),
1171		this.createVertexTemplateEntry('whiteSpace=wrap;html=1;aspect=fixed;', 80, 80, '', 'Square', null, null, 'square'),
1172		this.createVertexTemplateEntry('ellipse;whiteSpace=wrap;html=1;aspect=fixed;', 80, 80, '', 'Circle', null, null, 'circle'),
1173	 	this.createVertexTemplateEntry('shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;', 120, 60, '', 'Process', null, null, 'process task'),
1174	 	this.createVertexTemplateEntry('rhombus;whiteSpace=wrap;html=1;', 80, 80, '', 'Diamond', null, null, 'diamond rhombus if condition decision conditional question test'),
1175	 	this.createVertexTemplateEntry('shape=parallelogram;perimeter=parallelogramPerimeter;whiteSpace=wrap;html=1;fixedSize=1;', 120, 60, '', 'Parallelogram'),
1176	 	this.createVertexTemplateEntry('shape=hexagon;perimeter=hexagonPerimeter2;whiteSpace=wrap;html=1;fixedSize=1;', 120, 80, '', 'Hexagon', null, null, 'hexagon preparation'),
1177	 	this.createVertexTemplateEntry('triangle;whiteSpace=wrap;html=1;', 60, 80, '', 'Triangle', null, null, 'triangle logic inverter buffer'),
1178	 	this.createVertexTemplateEntry('shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;', 60, 80, '', 'Cylinder', null, null, 'cylinder data database'),
1179	 	this.createVertexTemplateEntry('ellipse;shape=cloud;whiteSpace=wrap;html=1;', 120, 80, '', 'Cloud', null, null, 'cloud network'),
1180	 	this.createVertexTemplateEntry('shape=document;whiteSpace=wrap;html=1;boundedLbl=1;', 120, 80, '', 'Document'),
1181	 	this.createVertexTemplateEntry('shape=internalStorage;whiteSpace=wrap;html=1;backgroundOutline=1;', 80, 80, '', 'Internal Storage'),
1182	 	this.createVertexTemplateEntry('shape=cube;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;darkOpacity=0.05;darkOpacity2=0.1;', 120, 80, '', 'Cube'),
1183	 	this.createVertexTemplateEntry('shape=step;perimeter=stepPerimeter;whiteSpace=wrap;html=1;fixedSize=1;', 120, 80, '', 'Step'),
1184	 	this.createVertexTemplateEntry('shape=trapezoid;perimeter=trapezoidPerimeter;whiteSpace=wrap;html=1;fixedSize=1;', 120, 60, '', 'Trapezoid'),
1185	 	this.createVertexTemplateEntry('shape=tape;whiteSpace=wrap;html=1;', 120, 100, '', 'Tape'),
1186	 	this.createVertexTemplateEntry('shape=note;whiteSpace=wrap;html=1;backgroundOutline=1;darkOpacity=0.05;', 80, 100, '', 'Note'),
1187	    this.createVertexTemplateEntry('shape=card;whiteSpace=wrap;html=1;', 80, 100, '', 'Card'),
1188	    this.createVertexTemplateEntry('shape=callout;whiteSpace=wrap;html=1;perimeter=calloutPerimeter;', 120, 80, '', 'Callout', null, null, 'bubble chat thought speech message'),
1189	 	this.createVertexTemplateEntry('shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;', 30, 60, 'Actor', 'Actor', false, null, 'user person human stickman'),
1190	 	this.createVertexTemplateEntry('shape=xor;whiteSpace=wrap;html=1;', 60, 80, '', 'Or', null, null, 'logic or'),
1191	 	this.createVertexTemplateEntry('shape=or;whiteSpace=wrap;html=1;', 60, 80, '', 'And', null, null, 'logic and'),
1192	 	this.createVertexTemplateEntry('shape=dataStorage;whiteSpace=wrap;html=1;fixedSize=1;', 100, 80, '', 'Data Storage'),
1193		this.createVertexTemplateEntry('swimlane;startSize=0;', 200, 200, '', 'Container', null, null, 'container swimlane lane pool group'),
1194		this.createVertexTemplateEntry('swimlane;', 200, 200, 'Vertical Container', 'Container', null, null, 'container swimlane lane pool group'),
1195		this.createVertexTemplateEntry('swimlane;horizontal=0;', 200, 200, 'Horizontal Container', 'Horizontal Container', null, null, 'container swimlane lane pool group'),
1196		this.addEntry('list group erd table', function()
1197		{
1198			var cell = new mxCell('List', new mxGeometry(0, 0, 140, 120),
1199		    	'swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;' +
1200		    	'resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;');
1201			cell.vertex = true;
1202			cell.insert(sb.cloneCell(field, 'Item 1'));
1203			cell.insert(sb.cloneCell(field, 'Item 2'));
1204			cell.insert(sb.cloneCell(field, 'Item 3'));
1205
1206			return sb.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, 'List');
1207		}),
1208		this.addEntry('list item entry value group erd table', function()
1209		{
1210			return sb.createVertexTemplateFromCells([sb.cloneCell(field, 'List Item')], field.geometry.width, field.geometry.height, 'List Item');
1211		}),
1212		this.addEntry('curve', mxUtils.bind(this, function()
1213	 	{
1214			var cell = new mxCell('', new mxGeometry(0, 0, 50, 50), 'curved=1;endArrow=classic;html=1;');
1215			cell.geometry.setTerminalPoint(new mxPoint(0, 50), true);
1216			cell.geometry.setTerminalPoint(new mxPoint(50, 0), false);
1217			cell.geometry.points = [new mxPoint(50, 50), new mxPoint(0, 0)];
1218			cell.geometry.relative = true;
1219			cell.edge = true;
1220
1221		    return this.createEdgeTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, 'Curve');
1222	 	})),
1223	 	this.createEdgeTemplateEntry('shape=flexArrow;endArrow=classic;startArrow=classic;html=1;', 100, 100, '', 'Bidirectional Arrow', null, lineTags + 'bidirectional'),
1224	 	this.createEdgeTemplateEntry('shape=flexArrow;endArrow=classic;html=1;', 50, 50, '', 'Arrow', null, lineTags + 'directional directed'),
1225	 	this.createEdgeTemplateEntry('endArrow=none;dashed=1;html=1;', 50, 50, '', 'Dashed Line', null, lineTags + 'dashed undirected no'),
1226	 	this.createEdgeTemplateEntry('endArrow=none;dashed=1;html=1;dashPattern=1 3;strokeWidth=2;', 50, 50, '', 'Dotted Line', null, lineTags + 'dotted undirected no'),
1227	 	this.createEdgeTemplateEntry('endArrow=none;html=1;', 50, 50, '', 'Line', null, lineTags + 'simple undirected plain blank no'),
1228	 	this.createEdgeTemplateEntry('endArrow=classic;startArrow=classic;html=1;', 50, 50, '', 'Bidirectional Connector', null, lineTags + 'bidirectional'),
1229	 	this.createEdgeTemplateEntry('endArrow=classic;html=1;', 50, 50, '', 'Directional Connector', null, lineTags + 'directional directed'),
1230	 	this.createEdgeTemplateEntry('shape=link;html=1;', 100, 0, '', 'Link', null, lineTags + 'link'),
1231	 	this.addEntry(lineTags + 'edge title', mxUtils.bind(this, function()
1232		{
1233			var edge = new mxCell('', new mxGeometry(0, 0, 0, 0), 'endArrow=classic;html=1;');
1234			edge.geometry.setTerminalPoint(new mxPoint(0, 0), true);
1235			edge.geometry.setTerminalPoint(new mxPoint(100, 0), false);
1236			edge.geometry.relative = true;
1237			edge.edge = true;
1238
1239	    	var cell0 = new mxCell('Label', new mxGeometry(0, 0, 0, 0), 'edgeLabel;resizable=0;html=1;align=center;verticalAlign=middle;');
1240	    	cell0.geometry.relative = true;
1241	    	cell0.setConnectable(false);
1242	    	cell0.vertex = true;
1243	    	edge.insert(cell0);
1244
1245			return this.createEdgeTemplateFromCells([edge], 100, 0, 'Connector with Label');
1246		})),
1247		this.addEntry(lineTags + 'edge title multiplicity', mxUtils.bind(this, function()
1248		{
1249			var edge = new mxCell('', new mxGeometry(0, 0, 0, 0), 'endArrow=classic;html=1;');
1250			edge.geometry.setTerminalPoint(new mxPoint(0, 0), true);
1251			edge.geometry.setTerminalPoint(new mxPoint(160, 0), false);
1252			edge.geometry.relative = true;
1253			edge.edge = true;
1254
1255	    	var cell0 = new mxCell('Label', new mxGeometry(0, 0, 0, 0), 'edgeLabel;resizable=0;html=1;align=center;verticalAlign=middle;');
1256	    	cell0.geometry.relative = true;
1257	    	cell0.setConnectable(false);
1258	    	cell0.vertex = true;
1259	    	edge.insert(cell0);
1260
1261	    	var cell1 = new mxCell('Source', new mxGeometry(-1, 0, 0, 0), 'edgeLabel;resizable=0;html=1;align=left;verticalAlign=bottom;');
1262	    	cell1.geometry.relative = true;
1263	    	cell1.setConnectable(false);
1264	    	cell1.vertex = true;
1265	    	edge.insert(cell1);
1266
1267			return this.createEdgeTemplateFromCells([edge], 160, 0, 'Connector with 2 Labels');
1268		})),
1269		this.addEntry(lineTags + 'edge title multiplicity', mxUtils.bind(this, function()
1270		{
1271			var edge = new mxCell('', new mxGeometry(0, 0, 0, 0), 'endArrow=classic;html=1;');
1272			edge.geometry.setTerminalPoint(new mxPoint(0, 0), true);
1273			edge.geometry.setTerminalPoint(new mxPoint(160, 0), false);
1274			edge.geometry.relative = true;
1275			edge.edge = true;
1276
1277	    	var cell0 = new mxCell('Label', new mxGeometry(0, 0, 0, 0), 'edgeLabel;resizable=0;html=1;align=center;verticalAlign=middle;');
1278	    	cell0.geometry.relative = true;
1279	    	cell0.setConnectable(false);
1280	    	cell0.vertex = true;
1281	    	edge.insert(cell0);
1282
1283	    	var cell1 = new mxCell('Source', new mxGeometry(-1, 0, 0, 0), 'edgeLabel;resizable=0;html=1;align=left;verticalAlign=bottom;');
1284	    	cell1.geometry.relative = true;
1285	    	cell1.setConnectable(false);
1286	    	cell1.vertex = true;
1287	    	edge.insert(cell1);
1288
1289	    	var cell2 = new mxCell('Target', new mxGeometry(1, 0, 0, 0), 'edgeLabel;resizable=0;html=1;align=right;verticalAlign=bottom;');
1290	    	cell2.geometry.relative = true;
1291	    	cell2.setConnectable(false);
1292	    	cell2.vertex = true;
1293	    	edge.insert(cell2);
1294
1295			return this.createEdgeTemplateFromCells([edge], 160, 0, 'Connector with 3 Labels');
1296		})),
1297	 	this.addEntry(lineTags + 'edge shape symbol message mail email', mxUtils.bind(this, function()
1298		{
1299			var edge = new mxCell('', new mxGeometry(0, 0, 0, 0), 'endArrow=classic;html=1;');
1300			edge.geometry.setTerminalPoint(new mxPoint(0, 0), true);
1301			edge.geometry.setTerminalPoint(new mxPoint(100, 0), false);
1302			edge.geometry.relative = true;
1303			edge.edge = true;
1304
1305	    	var cell = new mxCell('', new mxGeometry(0, 0, 20, 14), 'shape=message;html=1;outlineConnect=0;');
1306	    	cell.geometry.relative = true;
1307	    	cell.vertex = true;
1308	    	cell.geometry.offset = new mxPoint(-10, -7);
1309	    	edge.insert(cell);
1310
1311			return this.createEdgeTemplateFromCells([edge], 100, 0, 'Connector with Symbol');
1312		}))
1313	];
1314
1315	this.addPaletteFunctions('general', mxResources.get('general'), (expand != null) ? expand : true, fns);
1316	this.setCurrentSearchEntryLibrary();
1317};
1318
1319/**
1320 * Adds the general palette to the sidebar.
1321 */
1322Sidebar.prototype.addMiscPalette = function(expand)
1323{
1324	var sb = this;
1325	var lineTags = 'line lines connector connectors connection connections arrow arrows '
1326	this.setCurrentSearchEntryLibrary('general', 'misc');
1327
1328	var fns = [
1329   	 	this.createVertexTemplateEntry('text;strokeColor=none;fillColor=none;html=1;fontSize=24;fontStyle=1;verticalAlign=middle;align=center;', 100, 40, 'Title', 'Title', null, null, 'text heading title'),
1330	 	this.createVertexTemplateEntry('text;strokeColor=none;fillColor=none;html=1;whiteSpace=wrap;verticalAlign=middle;overflow=hidden;', 100, 80,
1331 			'<ul><li>Value 1</li><li>Value 2</li><li>Value 3</li></ul>', 'Unordered List'),
1332	 	this.createVertexTemplateEntry('text;strokeColor=none;fillColor=none;html=1;whiteSpace=wrap;verticalAlign=middle;overflow=hidden;', 100, 80,
1333 			'<ol><li>Value 1</li><li>Value 2</li><li>Value 3</li></ol>', 'Ordered List'),
1334 		this.addDataEntry('table', 180, 120, 'Table 1', '7ZjBTuMwEIafJtdVnFDoXhtYLnBZeAHTTGtLjieyB9Lu0zNO3FYVVM0upMASKZU8Y49jf3+tX06SF9Xq2sla3WIJJsmvkrxwiNS1qlUBxiRZqsskv0yyLOVfkv060Cva3rSWDiz1Kci6gidpHqHLdAlPaxMTXsk6NEk+hNRMUcXLvBTcbJQmuKvlPPQ3vAnOeZKO7vSfkEo5nqMlqS24WDNHY2TtdTtZN0JpU97INT7S5jWbaBaXB45gdXCLbSru7xqwAnJrHtLoklQcMe0wpAr0Um3KIptU+i6x3NbuiHEjQnsdYN4fIC+ZtDS/YU7SLvuwfMmqdFjfS7cEiokatSVwV09Mw8fcQhtToMGA3KINLyKsY6eBxab2AYmwioGLYLaTtlAmM34YU5H+mCQT3k3BsdjF/IThjgq0nhwLHeYA6akB31vA7N8EPHsH/c6G1c/aMHqn35ulQUa5MNhwqHRZgn3lPyD6cs+Pcj8fCPtkxP4C+2of+QlUOB9VOKTC1hxOIMPF6CGDech6X6ZTWMr0O5+qiw+zlJ8j9k9gKSIdZfgMniLEaCpDm8r0hKYi/uKm/v+dK3H8ij/YQRr4hv81wX+AsXzrm/oRHQZ0Fg53nyPbvr2vlc8='),
1335 		this.addDataEntry('table', 180, 120, 'Table 2', '7ZhRb5swEMc/Da+TDSFJX0u7vrQv7bR3NzjBkvEhcynJPv3OYDeLUlS0JURTkUDyne+M+f05nXCUZOXuwYqqeIJc6ii5j5LMAmA3KneZ1DqKmcqj5C6KY0Z3FH/vmeXtLKuElQaHJMRdwpvQW9l5OkeNe+0ddSEqN0Tx6ly3BZa0zTtOw6ZQKF8qsXLzDb0E+WoUFl/UL+diZK/AoFBGWp+zAq1FVat2sS6iUDp/FHvYYnhMsFz0tjSPlF/7aAvNn6bfv7Qod70MWpcH8CChlGj3FNKoHAsfsew4sUKqTRHSPDwm6s6xec89IKWBp/ox4WQ4YdoyKqGf5QqF2QyBfQozt1D9EHYj0TsqUAalvX8jGgHaWmmdgQaniQHjHoRQ+Ukt1yH3FRChDOA9mPdFWyjpLV2EKWPf0iilt8nI5gebLhduMQNTo6Uvwa0hRY2NrHGogPHfCTg7g36zE/1+tsOY8bMKaYyLPgj5zxoBMV1raMgsVJ5L88HHwIcKkHwqwPxC/NNe/uctpP+S/+6Y/QhyzHvlSCY5QkI8nh6Lqb1crL3sj2Uao9sse8tr9oXKa3G1bnPTyz+d+I/fbTjr1WM+6XGFdsP51G8u3W+WI/YbfnoAEAps8YUKjH9+QnCxijo9IAgKLCcFrtFz+v/4byZBRmg6ZB4OQNu5o/PR3w=='),
1336 		this.addDataEntry('table title', 180, 150, 'Table with Title 1', '7VjBbqMwEP0arisMpeleQ7u9tJemP+CGCbZkbGRPQtKv37FxGnWTKJVa0q6CBJLnecbg9xg9mSQvm/W95a14NBWoJL9L8tIag/2oWZegVJKlskry2yTLUrqT7M+RWRZm05Zb0PiRgqwvWHG1hB555i8KetThRkXUCd76IYbZfOqQW5zJV4/lKQFzo5FLDZYAFmKleOtkSL8NGUKq6oFvzBK3C22j6YKqZ/FpvporWWsaz2kbfslpa6Qf3a0IcDEpvjpYhPXR7Qco7v0eTANoN5TSyQpFzLjpKUoFyFpsy4oIctcD9Vvtjk0aREIPk5vvkXuUV3pllFw9wRy5rgPFAhsVd9oJiTBr+dyndvSxHCS4sqZ95rYGjMC/pHlsIZUqjTJeJ220fxCaNk4qWGxrXwyiaWJgIzFviwZSiildRFOZ/iqSgnZTUsx2MV0+3WJptENLX4dfA7jDDhx+VMDssICbSHGU6ZSeV18g59Wwcmrts3dyflopQ8wulOkoFLKqQH+mj/KTfXQ9EO3FSPse7ev3lJ9BhetRhWMqsOx8MkxGSxnaUiZntJSbS+6qybdZyu+R9h9gKSwdZfgJnsLYaCpDmwpjZ3QVtn+qv6DGYqeP/IN10sAn/v+T+G9wlos+qp/QYUBroXD36zLMvfuz+Rc='),
1337 		this.addDataEntry('table title', 180, 150, 'Table with Title 2', '7VjBbqMwEP0arivAJdtcod1e0ktT7d0NBiwZG9nTQvbrd2xMsy1B7WoTglaVQJp5nhnwe/gdCEhWd3eaNtW9ypkIyG1AMq0U9FHdZUyIIA55HpCbII5DvIP4x8Rq5FbDhmom4TMNcd/wQsUz65FH+iRYjxrYC4+aijY2BLdKUgNUw5b/shgJEdgpCZRLphGIXC4EbQx35TeuouIi39C9eoZh0JClBe9Y/qBa47u1ajc4zPjWAodv/cvYZSp4KTHe4S7tE9NGcRvdviAwzPA7YxpYN8mOgzw1d0zVDPQeS1qeQ+UrrnsGw4rxshraEg9S0wPla++BbAw838e5JyPuJ2nHVwZOxQPbAZWlU6CCWvidthUHtm3ozpa2+C0d5T/XqnmkumTggWOkFVyITAllZZRK2geBanyDYMXQ+6QAVD2o5Yl5HepISVK8kKYs/JYECe4mwzw65HjZcg2ZkgY0fjx2BqMGWmbgswLGxwXce4q9TB/pSU4g59VIzuikekppqw96/rVU4TupFFJbCNViWvE8Z/JfDhL58CBdnYn3ZMT7TxfG4cL5H1ysr00NPpDLctN3rmYSqHsrzp8H5VyCrf4H33sv5rJ8bzWj730fyXlaPZfte6uL+d71pO8tnP95fW9CoAv43vrL987te+sZfS8KR3qSZR+8k56r9cWML4omnW/hAszrfBMKnd/5MD38wXBrb35w/AY='),
1338 		this.addDataEntry('crossfunctional cross-functional cross functional flowchart swimlane table', 400, 400, 'Cross-Functional Flowchart', '5ZjfbpswFMafhstNGJK2u1xY05tOmtYn8OAstmRsZB8C6dPvmD9NN6CNqoStTCKSz/GxcX6f+ZAJ4iSv7ywvxFeTgQri2yBOrDHYtvI6AaWCKJRZEH8JoiikXxBtJ3pZ0xsW3ILGUwZE7YA9VyW0Gbq5cx+2pU5RGs198VaZKhXcYlvs8KC6Yid44ZvIf/jUJhVSZff8YErss320saa6lxocdYS+1Kgy188zDukWD/LRT7jqShQvnGzmbkospKV1cg/fwbWFPgt1wXXWBYWRGsHe7olAP/NPo/GhWzWjmCu509ROwZdSoqMAFqGeJNmkOox3YHJAe6CSSmYo2opV2NIOBcidwD+S3LWJ3dPYozDU6LQZ1yke6PQ5RWMpxYaiVDJXXHs9hLHykf48yfiMTrOO9YYuWlkSflwHaxqXUMyOMV2+3GJitEPLZYMBuMMKHM4o1ynSROPSHHoF2hGvKcWiMyi1Gij1TXAHrymVGq0h7Z6jCz8OJyGNx5HWk0if6J0d6XoSabQgpOxqTqZXk0zjBTGNbuZkej1p0i/u0/dp0mfw5bEdfzljvhmo8/aNPj/J63/Hjj8tGOS8JszCBaOc13sZG6DszffFF9p/a75j8lzOfNnwoPmedjqbOPv9Dftlw7PgglDObMDD09qCWF7UgSk8fqZq+n77ivUL'),
1339 		this.createVertexTemplateEntry('text;html=1;strokeColor=#c0c0c0;fillColor=#ffffff;overflow=fill;rounded=0;', 280, 160,
1340 			'<table border="1" width="100%" height="100%" cellpadding="4" style="width:100%;height:100%;border-collapse:collapse;">' +
1341 			'<tr style="background-color:#A7C942;color:#ffffff;border:1px solid #98bf21;"><th align="left">Title 1</th><th align="left">Title 2</th><th align="left">Title 3</th></tr>' +
1342 			'<tr style="border:1px solid #98bf21;"><td>Value 1</td><td>Value 2</td><td>Value 3</td></tr>' +
1343 			'<tr style="background-color:#EAF2D3;border:1px solid #98bf21;"><td>Value 4</td><td>Value 5</td><td>Value 6</td></tr>' +
1344 			'<tr style="border:1px solid #98bf21;"><td>Value 7</td><td>Value 8</td><td>Value 9</td></tr>' +
1345 			'<tr style="background-color:#EAF2D3;border:1px solid #98bf21;"><td>Value 10</td><td>Value 11</td><td>Value 12</td></tr></table>', 'HTML Table 1'),
1346		this.createVertexTemplateEntry('text;html=1;strokeColor=#c0c0c0;fillColor=none;overflow=fill;', 180, 140,
1347 			'<table border="0" width="100%" height="100%" style="width:100%;height:100%;border-collapse:collapse;">' +
1348 			'<tr><td align="center">Value 1</td><td align="center">Value 2</td><td align="center">Value 3</td></tr>' +
1349 			'<tr><td align="center">Value 4</td><td align="center">Value 5</td><td align="center">Value 6</td></tr>' +
1350 			'<tr><td align="center">Value 7</td><td align="center">Value 8</td><td align="center">Value 9</td></tr></table>', 'HTML Table 2'),
1351	 	this.createVertexTemplateEntry('text;html=1;strokeColor=none;fillColor=none;overflow=fill;', 180, 140,
1352 			'<table border="1" width="100%" height="100%" style="width:100%;height:100%;border-collapse:collapse;">' +
1353 			'<tr><td align="center">Value 1</td><td align="center">Value 2</td><td align="center">Value 3</td></tr>' +
1354 			'<tr><td align="center">Value 4</td><td align="center">Value 5</td><td align="center">Value 6</td></tr>' +
1355 			'<tr><td align="center">Value 7</td><td align="center">Value 8</td><td align="center">Value 9</td></tr></table>', 'HTML Table 3'),
1356	 	this.createVertexTemplateEntry('text;html=1;strokeColor=none;fillColor=none;overflow=fill;', 160, 140,
1357 			'<table border="1" width="100%" height="100%" cellpadding="4" style="width:100%;height:100%;border-collapse:collapse;">' +
1358 			'<tr><th align="center"><b>Title</b></th></tr>' +
1359 			'<tr><td align="center">Section 1.1\nSection 1.2\nSection 1.3</td></tr>' +
1360 			'<tr><td align="center">Section 2.1\nSection 2.2\nSection 2.3</td></tr></table>', 'HTML Table 4'),
1361	 	this.addEntry('link hyperlink', mxUtils.bind(this, function()
1362	 	{
1363	 		var cell = new mxCell('Link', new mxGeometry(0, 0, 60, 40), 'text;html=1;strokeColor=none;fillColor=none;whiteSpace=wrap;align=center;verticalAlign=middle;fontColor=#0000EE;fontStyle=4;');
1364	 		cell.vertex = true;
1365	 		this.graph.setLinkForCell(cell, 'https://www.draw.io');
1366
1367	 		return this.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, 'Link');
1368	 	})),
1369	 	this.addEntry('timestamp date time text label', mxUtils.bind(this, function()
1370	 	{
1371	 		var cell = new mxCell('%date{ddd mmm dd yyyy HH:MM:ss}%', new mxGeometry(0, 0, 160, 20), 'text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;overflow=hidden;');
1372	 		cell.vertex = true;
1373	 		this.graph.setAttributeForCell(cell, 'placeholders', '1');
1374
1375	 		return this.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, 'Timestamp');
1376	 	})),
1377	 	this.addEntry('variable placeholder metadata hello world text label', mxUtils.bind(this, function()
1378	 	{
1379	 		var cell = new mxCell('%name% Text', new mxGeometry(0, 0, 80, 20), 'text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;overflow=hidden;');
1380	 		cell.vertex = true;
1381	 		this.graph.setAttributeForCell(cell, 'placeholders', '1');
1382	 		this.graph.setAttributeForCell(cell, 'name', 'Variable');
1383
1384	 		return this.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, 'Variable');
1385	 	})),
1386		this.createVertexTemplateEntry('shape=ext;double=1;rounded=0;whiteSpace=wrap;html=1;', 120, 80, '', 'Double Rectangle', null, null, 'rect rectangle box double'),
1387	 	this.createVertexTemplateEntry('shape=ext;double=1;rounded=1;whiteSpace=wrap;html=1;', 120, 80, '', 'Double Rounded Rectangle', null, null, 'rounded rect rectangle box double'),
1388 		this.createVertexTemplateEntry('ellipse;shape=doubleEllipse;whiteSpace=wrap;html=1;', 100, 60, '', 'Double Ellipse', null, null, 'oval ellipse start end state double'),
1389		this.createVertexTemplateEntry('shape=ext;double=1;whiteSpace=wrap;html=1;aspect=fixed;', 80, 80, '', 'Double Square', null, null, 'double square'),
1390		this.createVertexTemplateEntry('ellipse;shape=doubleEllipse;whiteSpace=wrap;html=1;aspect=fixed;', 80, 80, '', 'Double Circle', null, null, 'double circle'),
1391		this.createVertexTemplateEntry('rounded=1;whiteSpace=wrap;html=1;strokeWidth=2;fillWeight=4;hachureGap=8;hachureAngle=45;fillColor=#1ba1e2;sketch=1;', 120, 60, '', 'Rectangle Sketch', true, null, 'rectangle rect box text sketch comic retro'),
1392		this.createVertexTemplateEntry('ellipse;whiteSpace=wrap;html=1;strokeWidth=2;fillWeight=2;hachureGap=8;fillColor=#990000;fillStyle=dots;sketch=1;', 120, 60, '', 'Ellipse Sketch', true, null, 'ellipse oval sketch comic retro'),
1393		this.createVertexTemplateEntry('rhombus;whiteSpace=wrap;html=1;strokeWidth=2;fillWeight=-1;hachureGap=8;fillStyle=cross-hatch;fillColor=#006600;sketch=1;', 120, 60, '', 'Diamond Sketch', true, null, 'diamond sketch comic retro'),
1394	 	this.createVertexTemplateEntry('html=1;whiteSpace=wrap;shape=isoCube2;backgroundOutline=1;isoAngle=15;', 90, 100, '', 'Isometric Cube', true, null, 'cube box iso isometric'),
1395	 	this.createVertexTemplateEntry('html=1;whiteSpace=wrap;aspect=fixed;shape=isoRectangle;', 150, 90, '', 'Isometric Square', true, null, 'rectangle rect box iso isometric'),
1396	 	this.createEdgeTemplateEntry('edgeStyle=isometricEdgeStyle;endArrow=none;html=1;', 50, 100, '', 'Isometric Edge 1'),
1397	 	this.createEdgeTemplateEntry('edgeStyle=isometricEdgeStyle;endArrow=none;html=1;elbow=vertical;', 50, 100, '', 'Isometric Edge 2'),
1398	 	this.createVertexTemplateEntry('shape=curlyBracket;whiteSpace=wrap;html=1;rounded=1;', 20, 120, '', 'Left Curly Bracket'),
1399		this.createVertexTemplateEntry('shape=curlyBracket;whiteSpace=wrap;html=1;rounded=1;flipH=1;', 20, 120, '', 'Right Curly Bracket'),
1400	 	this.createVertexTemplateEntry('line;strokeWidth=2;html=1;', 160, 10, '', 'Horizontal Line'),
1401	 	this.createVertexTemplateEntry('line;strokeWidth=2;direction=south;html=1;', 10, 160, '', 'Vertical Line'),
1402	 	this.createVertexTemplateEntry('line;strokeWidth=4;html=1;perimeter=backbonePerimeter;points=[];outlineConnect=0;', 160, 10, '', 'Horizontal Backbone', false, null, 'backbone bus network'),
1403	 	this.createVertexTemplateEntry('line;strokeWidth=4;direction=south;html=1;perimeter=backbonePerimeter;points=[];outlineConnect=0;', 10, 160, '', 'Vertical Backbone', false, null, 'backbone bus network'),
1404	 	this.createVertexTemplateEntry('shape=crossbar;whiteSpace=wrap;html=1;rounded=1;', 120, 20, '', 'Horizontal Crossbar', false, null, 'crossbar distance measure dimension unit'),
1405		this.createVertexTemplateEntry('shape=crossbar;whiteSpace=wrap;html=1;rounded=1;direction=south;', 20, 120, '', 'Vertical Crossbar', false, null, 'crossbar distance measure dimension unit'),
1406	 	this.createVertexTemplateEntry('shape=image;html=1;verticalLabelPosition=bottom;verticalAlign=top;imageAspect=1;aspect=fixed;image=' + this.gearImage, 52, 61, '', 'Image (Fixed Aspect)', false, null, 'fixed image icon symbol'),
1407	 	this.createVertexTemplateEntry('shape=image;html=1;verticalLabelPosition=bottom;verticalAlign=top;imageAspect=0;image=' + this.gearImage, 50, 60, '', 'Image (Variable Aspect)', false, null, 'strechted image icon symbol'),
1408	 	this.createVertexTemplateEntry('icon;html=1;image=' + this.gearImage, 60, 60, 'Icon', 'Icon', false, null, 'icon image symbol'),
1409	 	this.createVertexTemplateEntry('label;whiteSpace=wrap;html=1;image=' + this.gearImage, 140, 60, 'Label', 'Label 1', null, null, 'label image icon symbol'),
1410	 	this.createVertexTemplateEntry('label;whiteSpace=wrap;html=1;align=center;verticalAlign=bottom;spacingLeft=0;spacingBottom=4;imageAlign=center;imageVerticalAlign=top;image=' + this.gearImage, 120, 80, 'Label', 'Label 2', null, null, 'label image icon symbol'),
1411		this.addEntry('shape group container', function()
1412		{
1413		    var cell = new mxCell('Label', new mxGeometry(0, 0, 160, 70),
1414				'html=1;whiteSpace=wrap;container=1;recursiveResize=0;collapsible=0;');
1415		    cell.vertex = true;
1416
1417			var symbol = new mxCell('', new mxGeometry(20, 20, 20, 30), 'triangle;html=1;whiteSpace=wrap;');
1418			symbol.vertex = true;
1419			cell.insert(symbol);
1420
1421    		return sb.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, 'Shape Group');
1422		}),
1423	 	this.createVertexTemplateEntry('shape=partialRectangle;whiteSpace=wrap;html=1;left=0;right=0;fillColor=none;', 120, 60, '', 'Partial Rectangle'),
1424		this.createVertexTemplateEntry('shape=partialRectangle;whiteSpace=wrap;html=1;bottom=0;top=0;fillColor=none;', 120, 60, '', 'Partial Rectangle'),
1425		this.createVertexTemplateEntry('shape=partialRectangle;whiteSpace=wrap;html=1;bottom=0;right=0;fillColor=none;', 120, 60, '', 'Partial Rectangle'),
1426		this.createVertexTemplateEntry('shape=partialRectangle;whiteSpace=wrap;html=1;bottom=1;right=1;left=1;top=0;fillColor=none;routingCenterX=-0.5;', 120, 60, '', 'Partial Rectangle'),
1427		this.createVertexTemplateEntry('shape=waypoint;sketch=0;fillStyle=solid;size=6;pointerEvents=1;points=[];fillColor=none;resizable=0;rotatable=0;perimeter=centerPerimeter;snapToPoint=1;', 40, 40, '', 'Waypoint'),
1428		this.createEdgeTemplateEntry('edgeStyle=segmentEdgeStyle;endArrow=classic;html=1;', 50, 50, '', 'Manual Line', null, lineTags + 'manual'),
1429	 	this.createEdgeTemplateEntry('shape=filledEdge;rounded=0;fixDash=1;endArrow=none;strokeWidth=10;fillColor=#ffffff;edgeStyle=orthogonalEdgeStyle;', 60, 40, '', 'Filled Edge'),
1430	 	this.createEdgeTemplateEntry('edgeStyle=elbowEdgeStyle;elbow=horizontal;endArrow=classic;html=1;', 50, 50, '', 'Horizontal Elbow', null, lineTags + 'elbow horizontal'),
1431	 	this.createEdgeTemplateEntry('edgeStyle=elbowEdgeStyle;elbow=vertical;endArrow=classic;html=1;', 50, 50, '', 'Vertical Elbow', null, lineTags + 'elbow vertical')
1432	];
1433
1434	this.addPaletteFunctions('misc', mxResources.get('misc'), (expand != null) ? expand : true, fns);
1435	this.setCurrentSearchEntryLibrary();
1436};
1437/**
1438 * Adds the container palette to the sidebar.
1439 */
1440Sidebar.prototype.addAdvancedPalette = function(expand)
1441{
1442	this.setCurrentSearchEntryLibrary('general', 'advanced');
1443	this.addPaletteFunctions('advanced', mxResources.get('advanced'), (expand != null) ? expand : false, this.createAdvancedShapes());
1444	this.setCurrentSearchEntryLibrary();
1445};
1446
1447/**
1448 * Adds the general palette to the sidebar.
1449 */
1450Sidebar.prototype.addBasicPalette = function(dir)
1451{
1452	this.setCurrentSearchEntryLibrary('basic');
1453	this.addStencilPalette('basic', mxResources.get('basic'), dir + '/basic.xml',
1454		';whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#000000;strokeWidth=2',
1455		null, null, null, null, [
1456			this.createVertexTemplateEntry('shape=partialRectangle;whiteSpace=wrap;html=1;top=0;bottom=0;fillColor=none;', 120, 60, '', 'Partial Rectangle'),
1457			this.createVertexTemplateEntry('shape=partialRectangle;whiteSpace=wrap;html=1;right=0;top=0;bottom=0;fillColor=none;routingCenterX=-0.5;', 120, 60, '', 'Partial Rectangle'),
1458			this.createVertexTemplateEntry('shape=partialRectangle;whiteSpace=wrap;html=1;bottom=0;right=0;fillColor=none;', 120, 60, '', 'Partial Rectangle'),
1459			this.createVertexTemplateEntry('shape=partialRectangle;whiteSpace=wrap;html=1;top=0;left=0;fillColor=none;', 120, 60, '', 'Partial Rectangle')
1460	]);
1461	this.setCurrentSearchEntryLibrary();
1462};
1463
1464/**
1465 * Adds the container palette to the sidebar.
1466 */
1467Sidebar.prototype.createAdvancedShapes = function()
1468{
1469	// Avoids having to bind all functions to "this"
1470	var sb = this;
1471
1472	// Reusable cells
1473	var field = new mxCell('List Item', new mxGeometry(0, 0, 60, 26), 'text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;');
1474	field.vertex = true;
1475
1476	return [
1477	 	this.createVertexTemplateEntry('shape=tapeData;whiteSpace=wrap;html=1;perimeter=ellipsePerimeter;', 80, 80, '', 'Tape Data'),
1478	 	this.createVertexTemplateEntry('shape=manualInput;whiteSpace=wrap;html=1;', 80, 80, '', 'Manual Input'),
1479	 	this.createVertexTemplateEntry('shape=loopLimit;whiteSpace=wrap;html=1;', 100, 80, '', 'Loop Limit'),
1480	 	this.createVertexTemplateEntry('shape=offPageConnector;whiteSpace=wrap;html=1;', 80, 80, '', 'Off Page Connector'),
1481	 	this.createVertexTemplateEntry('shape=delay;whiteSpace=wrap;html=1;', 80, 40, '', 'Delay'),
1482	 	this.createVertexTemplateEntry('shape=display;whiteSpace=wrap;html=1;', 80, 40, '', 'Display'),
1483	 	this.createVertexTemplateEntry('shape=singleArrow;direction=west;whiteSpace=wrap;html=1;', 100, 60, '', 'Arrow Left'),
1484	 	this.createVertexTemplateEntry('shape=singleArrow;whiteSpace=wrap;html=1;', 100, 60, '', 'Arrow Right'),
1485	 	this.createVertexTemplateEntry('shape=singleArrow;direction=north;whiteSpace=wrap;html=1;', 60, 100, '', 'Arrow Up'),
1486	 	this.createVertexTemplateEntry('shape=singleArrow;direction=south;whiteSpace=wrap;html=1;', 60, 100, '', 'Arrow Down'),
1487	 	this.createVertexTemplateEntry('shape=doubleArrow;whiteSpace=wrap;html=1;', 100, 60, '', 'Double Arrow'),
1488	 	this.createVertexTemplateEntry('shape=doubleArrow;direction=south;whiteSpace=wrap;html=1;', 60, 100, '', 'Double Arrow Vertical', null, null, 'double arrow'),
1489	 	this.createVertexTemplateEntry('shape=actor;whiteSpace=wrap;html=1;', 40, 60, '', 'User', null, null, 'user person human'),
1490	 	this.createVertexTemplateEntry('shape=cross;whiteSpace=wrap;html=1;', 80, 80, '', 'Cross'),
1491	 	this.createVertexTemplateEntry('shape=corner;whiteSpace=wrap;html=1;', 80, 80, '', 'Corner'),
1492	 	this.createVertexTemplateEntry('shape=tee;whiteSpace=wrap;html=1;', 80, 80, '', 'Tee'),
1493	 	this.createVertexTemplateEntry('shape=datastore;whiteSpace=wrap;html=1;', 60, 60, '', 'Data Store', null, null, 'data store cylinder database'),
1494	 	this.createVertexTemplateEntry('shape=orEllipse;perimeter=ellipsePerimeter;whiteSpace=wrap;html=1;backgroundOutline=1;', 80, 80, '', 'Or', null, null, 'or circle oval ellipse'),
1495	 	this.createVertexTemplateEntry('shape=sumEllipse;perimeter=ellipsePerimeter;whiteSpace=wrap;html=1;backgroundOutline=1;', 80, 80, '', 'Sum', null, null, 'sum circle oval ellipse'),
1496	 	this.createVertexTemplateEntry('shape=lineEllipse;perimeter=ellipsePerimeter;whiteSpace=wrap;html=1;backgroundOutline=1;', 80, 80, '', 'Ellipse with horizontal divider', null, null, 'circle oval ellipse'),
1497	 	this.createVertexTemplateEntry('shape=lineEllipse;line=vertical;perimeter=ellipsePerimeter;whiteSpace=wrap;html=1;backgroundOutline=1;', 80, 80, '', 'Ellipse with vertical divider', null, null, 'circle oval ellipse'),
1498	 	this.createVertexTemplateEntry('shape=sortShape;perimeter=rhombusPerimeter;whiteSpace=wrap;html=1;', 80, 80, '', 'Sort', null, null, 'sort'),
1499	 	this.createVertexTemplateEntry('shape=collate;whiteSpace=wrap;html=1;', 80, 80, '', 'Collate', null, null, 'collate'),
1500	 	this.createVertexTemplateEntry('shape=switch;whiteSpace=wrap;html=1;', 60, 60, '', 'Switch', null, null, 'switch router'),
1501		this.addEntry('process bar', function()
1502		{
1503			return sb.createVertexTemplateFromData('zZXRaoMwFIafJpcDjbNrb2233rRQ8AkyPdPQaCRJV+3T7yTG2rUVBoOtgpDzn/xJzncCIdGyateKNeVW5iBI9EqipZLS9KOqXYIQhAY8J9GKUBrgT+jbRDZ02aBhCmrzEwPtDZ9MHKBXdkpmoDWKCVN9VptO+Kw+8kqwGqMkK7nIN6yTB7uTNizbD1FSSsVPsjYMC1qFKHxwIZZSSIVxLZ1/nJNar5+oQPMT7IYCrqUta1ENzuqGaeOFTArBGs3f3Vmtoo2Se7ja1h00kSoHK4bBIKUNy3hdoPYU0mF91i9mT8EEL2ocZ3gKa00ayWujLZY4IfHKFonVDLsRGgXuQ90zBmWgneyTk3yT1iArMKrDKUeem9L3ajHrbSXwohxsQd/ggOleKM7ese048J2/fwuim1uQGmhQCW8vQMkacP3GCQgBFMftHEsr7cYYe95CnmKTPMFbYD8CQ++DGQy+/M5X4ku5wHYmdIktfvk9tecpavThqS3m/0YtnqIWPTy1cD77K2wYjo+Ay317I74A', 296, 100, 'Process Bar');
1504		}),
1505	 	this.createVertexTemplateEntry('swimlane;', 200, 200, 'Container', 'Container', null, null, 'container swimlane lane pool group'),
1506		this.addEntry('list group erd table', function()
1507		{
1508			var cell = new mxCell('List', new mxGeometry(0, 0, 140, 110),
1509		    	'swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=26;fillColor=none;horizontalStack=0;' +
1510		    	'resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;');
1511			cell.vertex = true;
1512			cell.insert(sb.cloneCell(field, 'Item 1'));
1513			cell.insert(sb.cloneCell(field, 'Item 2'));
1514			cell.insert(sb.cloneCell(field, 'Item 3'));
1515
1516			return sb.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, 'List');
1517		}),
1518		this.addEntry('list item entry value group erd table', function()
1519		{
1520			return sb.createVertexTemplateFromCells([sb.cloneCell(field, 'List Item')], field.geometry.width, field.geometry.height, 'List Item');
1521		})
1522	];
1523};
1524
1525/**
1526 * Adds the container palette to the sidebar.
1527 */
1528Sidebar.prototype.createAdvancedShapes = function()
1529{
1530	// Avoids having to bind all functions to "this"
1531	var sb = this;
1532
1533	// Reusable cells
1534	var field = new mxCell('List Item', new mxGeometry(0, 0, 60, 26), 'text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;');
1535	field.vertex = true;
1536
1537	return [
1538	 	this.createVertexTemplateEntry('shape=tapeData;whiteSpace=wrap;html=1;perimeter=ellipsePerimeter;', 80, 80, '', 'Tape Data'),
1539	 	this.createVertexTemplateEntry('shape=manualInput;whiteSpace=wrap;html=1;', 80, 80, '', 'Manual Input'),
1540	 	this.createVertexTemplateEntry('shape=loopLimit;whiteSpace=wrap;html=1;', 100, 80, '', 'Loop Limit'),
1541	 	this.createVertexTemplateEntry('shape=offPageConnector;whiteSpace=wrap;html=1;', 80, 80, '', 'Off Page Connector'),
1542	 	this.createVertexTemplateEntry('shape=delay;whiteSpace=wrap;html=1;', 80, 40, '', 'Delay'),
1543	 	this.createVertexTemplateEntry('shape=display;whiteSpace=wrap;html=1;', 80, 40, '', 'Display'),
1544	 	this.createVertexTemplateEntry('shape=singleArrow;direction=west;whiteSpace=wrap;html=1;', 100, 60, '', 'Arrow Left'),
1545	 	this.createVertexTemplateEntry('shape=singleArrow;whiteSpace=wrap;html=1;', 100, 60, '', 'Arrow Right'),
1546	 	this.createVertexTemplateEntry('shape=singleArrow;direction=north;whiteSpace=wrap;html=1;', 60, 100, '', 'Arrow Up'),
1547	 	this.createVertexTemplateEntry('shape=singleArrow;direction=south;whiteSpace=wrap;html=1;', 60, 100, '', 'Arrow Down'),
1548	 	this.createVertexTemplateEntry('shape=doubleArrow;whiteSpace=wrap;html=1;', 100, 60, '', 'Double Arrow'),
1549	 	this.createVertexTemplateEntry('shape=doubleArrow;direction=south;whiteSpace=wrap;html=1;', 60, 100, '', 'Double Arrow Vertical', null, null, 'double arrow'),
1550	 	this.createVertexTemplateEntry('shape=actor;whiteSpace=wrap;html=1;', 40, 60, '', 'User', null, null, 'user person human'),
1551	 	this.createVertexTemplateEntry('shape=cross;whiteSpace=wrap;html=1;', 80, 80, '', 'Cross'),
1552	 	this.createVertexTemplateEntry('shape=corner;whiteSpace=wrap;html=1;', 80, 80, '', 'Corner'),
1553	 	this.createVertexTemplateEntry('shape=tee;whiteSpace=wrap;html=1;', 80, 80, '', 'Tee'),
1554	 	this.createVertexTemplateEntry('shape=datastore;whiteSpace=wrap;html=1;', 60, 60, '', 'Data Store', null, null, 'data store cylinder database'),
1555	 	this.createVertexTemplateEntry('shape=orEllipse;perimeter=ellipsePerimeter;whiteSpace=wrap;html=1;backgroundOutline=1;', 80, 80, '', 'Or', null, null, 'or circle oval ellipse'),
1556	 	this.createVertexTemplateEntry('shape=sumEllipse;perimeter=ellipsePerimeter;whiteSpace=wrap;html=1;backgroundOutline=1;', 80, 80, '', 'Sum', null, null, 'sum circle oval ellipse'),
1557	 	this.createVertexTemplateEntry('shape=lineEllipse;perimeter=ellipsePerimeter;whiteSpace=wrap;html=1;backgroundOutline=1;', 80, 80, '', 'Ellipse with horizontal divider', null, null, 'circle oval ellipse'),
1558	 	this.createVertexTemplateEntry('shape=lineEllipse;line=vertical;perimeter=ellipsePerimeter;whiteSpace=wrap;html=1;backgroundOutline=1;', 80, 80, '', 'Ellipse with vertical divider', null, null, 'circle oval ellipse'),
1559	 	this.createVertexTemplateEntry('shape=sortShape;perimeter=rhombusPerimeter;whiteSpace=wrap;html=1;', 80, 80, '', 'Sort', null, null, 'sort'),
1560	 	this.createVertexTemplateEntry('shape=collate;whiteSpace=wrap;html=1;', 80, 80, '', 'Collate', null, null, 'collate'),
1561	 	this.createVertexTemplateEntry('shape=switch;whiteSpace=wrap;html=1;', 60, 60, '', 'Switch', null, null, 'switch router'),
1562		this.addEntry('process bar', function()
1563		{
1564			return sb.createVertexTemplateFromData('zZXRaoMwFIafJpcDjbNrb2233rRQ8AkyPdPQaCRJV+3T7yTG2rUVBoOtgpDzn/xJzncCIdGyateKNeVW5iBI9EqipZLS9KOqXYIQhAY8J9GKUBrgT+jbRDZ02aBhCmrzEwPtDZ9MHKBXdkpmoDWKCVN9VptO+Kw+8kqwGqMkK7nIN6yTB7uTNizbD1FSSsVPsjYMC1qFKHxwIZZSSIVxLZ1/nJNar5+oQPMT7IYCrqUta1ENzuqGaeOFTArBGs3f3Vmtoo2Se7ja1h00kSoHK4bBIKUNy3hdoPYU0mF91i9mT8EEL2ocZ3gKa00ayWujLZY4IfHKFonVDLsRGgXuQ90zBmWgneyTk3yT1iArMKrDKUeem9L3ajHrbSXwohxsQd/ggOleKM7ese048J2/fwuim1uQGmhQCW8vQMkacP3GCQgBFMftHEsr7cYYe95CnmKTPMFbYD8CQ++DGQy+/M5X4ku5wHYmdIktfvk9tecpavThqS3m/0YtnqIWPTy1cD77K2wYjo+Ay317I74A', 296, 100, 'Process Bar');
1565		}),
1566	 	this.createVertexTemplateEntry('swimlane;', 200, 200, 'Container', 'Container', null, null, 'container swimlane lane pool group'),
1567		this.addEntry('list group erd table', function()
1568		{
1569			var cell = new mxCell('List', new mxGeometry(0, 0, 140, 110),
1570		    	'swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=26;fillColor=none;horizontalStack=0;' +
1571		    	'resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;');
1572			cell.vertex = true;
1573			cell.insert(sb.cloneCell(field, 'Item 1'));
1574			cell.insert(sb.cloneCell(field, 'Item 2'));
1575			cell.insert(sb.cloneCell(field, 'Item 3'));
1576
1577			return sb.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, 'List');
1578		}),
1579		this.addEntry('list item entry value group erd table', function()
1580		{
1581			return sb.createVertexTemplateFromCells([sb.cloneCell(field, 'List Item')], field.geometry.width, field.geometry.height, 'List Item');
1582		})
1583	];
1584};
1585
1586/**
1587 * Adds the general palette to the sidebar.
1588 */
1589Sidebar.prototype.addBasicPalette = function(dir)
1590{
1591	this.setCurrentSearchEntryLibrary('basic');
1592	this.addStencilPalette('basic', mxResources.get('basic'), dir + '/basic.xml',
1593		';whiteSpace=wrap;html=1;fillColor=#ffffff;strokeColor=#000000;strokeWidth=2',
1594		null, null, null, null, [
1595			this.createVertexTemplateEntry('shape=partialRectangle;whiteSpace=wrap;html=1;top=0;bottom=0;fillColor=none;', 120, 60, '', 'Partial Rectangle'),
1596			this.createVertexTemplateEntry('shape=partialRectangle;whiteSpace=wrap;html=1;right=0;top=0;bottom=0;fillColor=none;routingCenterX=-0.5;', 120, 60, '', 'Partial Rectangle'),
1597			this.createVertexTemplateEntry('shape=partialRectangle;whiteSpace=wrap;html=1;bottom=0;right=0;fillColor=none;', 120, 60, '', 'Partial Rectangle'),
1598			this.createVertexTemplateEntry('shape=partialRectangle;whiteSpace=wrap;html=1;top=0;left=0;fillColor=none;', 120, 60, '', 'Partial Rectangle')
1599	]);
1600	this.setCurrentSearchEntryLibrary();
1601};
1602
1603/**
1604 * Adds the general palette to the sidebar.
1605 */
1606Sidebar.prototype.addUmlPalette = function(expand)
1607{
1608	// Avoids having to bind all functions to "this"
1609	var sb = this;
1610
1611	// Reusable cells
1612	var field = new mxCell('+ field: type', new mxGeometry(0, 0, 100, 26), 'text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;');
1613	field.vertex = true;
1614
1615	var divider = new mxCell('', new mxGeometry(0, 0, 40, 8), 'line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;');
1616	divider.vertex = true;
1617
1618	// Default tags
1619	var dt = 'uml static class ';
1620	this.setCurrentSearchEntryLibrary('uml');
1621
1622	var fns = [
1623   		this.createVertexTemplateEntry('html=1;', 110, 50, 'Object', 'Object', null, null, dt + 'object instance'),
1624   		this.createVertexTemplateEntry('html=1;', 110, 50, '&laquo;interface&raquo;<br><b>Name</b>', 'Interface', null, null, dt + 'interface object instance annotated annotation'),
1625	 	this.addEntry(dt + 'object instance', function()
1626		{
1627			var cell = new mxCell('Classname', new mxGeometry(0, 0, 160, 90),
1628		    	'swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;');
1629			cell.vertex = true;
1630			cell.insert(field.clone());
1631			cell.insert(divider.clone());
1632			cell.insert(sb.cloneCell(field, '+ method(type): type'));
1633
1634			return sb.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, 'Class');
1635		}),
1636		this.addEntry(dt + 'section subsection', function()
1637		{
1638			var cell = new mxCell('Classname', new mxGeometry(0, 0, 140, 110),
1639		    	'swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=26;fillColor=none;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;');
1640			cell.vertex = true;
1641			cell.insert(field.clone());
1642			cell.insert(field.clone());
1643			cell.insert(field.clone());
1644
1645			return sb.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, 'Class 2');
1646		}),
1647		this.addEntry(dt + 'item member method function variable field attribute label', function()
1648		{
1649			return sb.createVertexTemplateFromCells([sb.cloneCell(field, '+ item: attribute')], field.geometry.width, field.geometry.height, 'Item 1');
1650		}),
1651   		this.addEntry(dt + 'item member method function variable field attribute label', function()
1652		{
1653   			var cell = new mxCell('item: attribute', new mxGeometry(0, 0, 120, field.geometry.height), 'label;fontStyle=0;strokeColor=none;fillColor=none;align=left;verticalAlign=top;overflow=hidden;' +
1654   				'spacingLeft=28;spacingRight=4;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;imageWidth=16;imageHeight=16;image=' + sb.gearImage);
1655   			cell.vertex = true;
1656
1657			return sb.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, 'Item 2');
1658		}),
1659		this.addEntry(dt + 'divider hline line separator', function()
1660		{
1661			return sb.createVertexTemplateFromCells([divider.clone()], divider.geometry.width, divider.geometry.height, 'Divider');
1662		}),
1663		this.addEntry(dt + 'spacer space gap separator', function()
1664		{
1665			var cell = new mxCell('', new mxGeometry(0, 0, 20, 14), 'text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=4;spacingRight=4;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;');
1666			cell.vertex = true;
1667
1668			return sb.createVertexTemplateFromCells([cell.clone()], cell.geometry.width, cell.geometry.height, 'Spacer');
1669		}),
1670		this.createVertexTemplateEntry('text;align=center;fontStyle=1;verticalAlign=middle;spacingLeft=3;spacingRight=3;strokeColor=none;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;',
1671			80, 26, 'Title', 'Title', null, null, dt + 'title label'),
1672		this.addEntry(dt + 'component', function()
1673		{
1674		    var cell = new mxCell('&laquo;Annotation&raquo;<br/><b>Component</b>', new mxGeometry(0, 0, 180, 90), 'html=1;dropTarget=0;');
1675		    cell.vertex = true;
1676
1677			var symbol = new mxCell('', new mxGeometry(1, 0, 20, 20), 'shape=module;jettyWidth=8;jettyHeight=4;');
1678			symbol.vertex = true;
1679			symbol.geometry.relative = true;
1680			symbol.geometry.offset = new mxPoint(-27, 7);
1681			cell.insert(symbol);
1682
1683	    	return sb.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, 'Component');
1684		}),
1685		this.addEntry(dt + 'component', function()
1686		{
1687		    var cell = new mxCell('<p style="margin:0px;margin-top:6px;text-align:center;"><b>Component</b></p>' +
1688				'<hr/><p style="margin:0px;margin-left:8px;">+ Attribute1: Type<br/>+ Attribute2: Type</p>', new mxGeometry(0, 0, 180, 90),
1689				'align=left;overflow=fill;html=1;dropTarget=0;');
1690		    cell.vertex = true;
1691
1692			var symbol = new mxCell('', new mxGeometry(1, 0, 20, 20), 'shape=component;jettyWidth=8;jettyHeight=4;');
1693			symbol.vertex = true;
1694			symbol.geometry.relative = true;
1695			symbol.geometry.offset = new mxPoint(-24, 4);
1696			cell.insert(symbol);
1697
1698	    	return sb.createVertexTemplateFromCells([cell], cell.geometry.width, cell.geometry.height, 'Component with Attributes');
1699		}),
1700		this.createVertexTemplateEntry('verticalAlign=top;align=left;spacingTop=8;spacingLeft=2;spacingRight=12;shape=cube;size=10;direction=south;fontStyle=4;html=1;',
1701			180, 120, 'Block', 'Block', null, null, dt + 'block'),
1702		this.createVertexTemplateEntry('shape=module;align=left;spacingLeft=20;align=center;verticalAlign=top;', 100, 50, 'Module', 'Module', null, null, dt + 'module component'),
1703		this.createVertexTemplateEntry('shape=folder;fontStyle=1;spacingTop=10;tabWidth=40;tabHeight=14;tabPosition=left;html=1;', 70, 50,
1704		   	'package', 'Package', null, null, dt + 'package'),
1705		this.createVertexTemplateEntry('verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;',
1706			160, 90, '<p style="margin:0px;margin-top:4px;text-align:center;text-decoration:underline;"><b>Object:Type</b></p><hr/>' +
1707			'<p style="margin:0px;margin-left:8px;">field1 = value1<br/>field2 = value2<br>field3 = value3</p>', 'Object',
1708			null, null, dt + 'object instance'),
1709		this.createVertexTemplateEntry('verticalAlign=top;align=left;overflow=fill;html=1;',180, 90,
1710			'<div style="box-sizing:border-box;width:100%;background:#e4e4e4;padding:2px;">Tablename</div>' +
1711			'<table style="width:100%;font-size:1em;" cellpadding="2" cellspacing="0">' +
1712			'<tr><td>PK</td><td>uniqueId</td></tr><tr><td>FK1</td><td>' +
1713			'foreignKey</td></tr><tr><td></td><td>fieldname</td></tr></table>', 'Entity', null, null, 'er entity table'),
1714		this.addEntry(dt + 'object instance', function()
1715		{
1716		    var cell = new mxCell('<p style="margin:0px;margin-top:4px;text-align:center;">' +
1717	    			'<b>Class</b></p>' +
1718					'<hr size="1"/><div style="height:2px;"></div>', new mxGeometry(0, 0, 140, 60),
1719					'verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;');
1720		    cell.vertex = true;
1721
1722			return sb.createVertexTemplateFromCells([cell.clone()], cell.geometry.width, cell.geometry.height, 'Class 3');
1723		}),
1724		this.addEntry(dt + 'object instance', function()
1725		{
1726		    var cell = new mxCell('<p style="margin:0px;margin-top:4px;text-align:center;">' +
1727	    			'<b>Class</b></p>' +
1728					'<hr size="1"/><div style="height:2px;"></div><hr size="1"/><div style="height:2px;"></div>', new mxGeometry(0, 0, 140, 60),
1729					'verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;');
1730		    cell.vertex = true;
1731
1732			return sb.createVertexTemplateFromCells([cell.clone()], cell.geometry.width, cell.geometry.height, 'Class 4');
1733		}),
1734		this.addEntry(dt + 'object instance', function()
1735		{
1736		    var cell = new mxCell('<p style="margin:0px;margin-top:4px;text-align:center;">' +
1737	    			'<b>Class</b></p>' +
1738					'<hr size="1"/><p style="margin:0px;margin-left:4px;">+ field: Type</p><hr size="1"/>' +
1739					'<p style="margin:0px;margin-left:4px;">+ method(): Type</p>', new mxGeometry(0, 0, 160, 90),
1740					'verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;');
1741		    cell.vertex = true;
1742
1743			return sb.createVertexTemplateFromCells([cell.clone()], cell.geometry.width, cell.geometry.height, 'Class 5');
1744		}),
1745		this.addEntry(dt + 'object instance', function()
1746		{
1747		    var cell = new mxCell('<p style="margin:0px;margin-top:4px;text-align:center;">' +
1748	    			'<i>&lt;&lt;Interface&gt;&gt;</i><br/><b>Interface</b></p>' +
1749					'<hr size="1"/><p style="margin:0px;margin-left:4px;">+ field1: Type<br/>' +
1750					'+ field2: Type</p>' +
1751					'<hr size="1"/><p style="margin:0px;margin-left:4px;">' +
1752					'+ method1(Type): Type<br/>' +
1753					'+ method2(Type, Type): Type</p>', new mxGeometry(0, 0, 190, 140),
1754					'verticalAlign=top;align=left;overflow=fill;fontSize=12;fontFamily=Helvetica;html=1;');
1755		    cell.vertex = true;
1756
1757			return sb.createVertexTemplateFromCells([cell.clone()], cell.geometry.width, cell.geometry.height, 'Interface 2');
1758		}),
1759		this.createVertexTemplateEntry('shape=providedRequiredInterface;html=1;verticalLabelPosition=bottom;sketch=0;', 20, 20, '', 'Provided/Required Interface', null, null, 'uml provided required interface lollipop notation'),
1760		this.createVertexTemplateEntry('shape=requiredInterface;html=1;verticalLabelPosition=bottom;sketch=0;', 10, 20, '', 'Required Interface', null, null, 'uml required interface lollipop notation'),
1761		this.addEntry('uml lollipop notation provided required interface', function()
1762		{
1763			return sb.createVertexTemplateFromData('zVRNT8MwDP01uaLSMu6sfFxAmrQDcAytaQJZXLnu2u7XkzQZXTUmuIA4VIqf/ZzkvdQiyzf9HclaPWAJRmQ3IssJkcNq0+dgjEgTXYrsWqRp4j6R3p7Ino/ZpJYEln9CSANhK00LAQlAw4OJAGFrS/D1iciWSKywQivNPWLtwHMHvgHzsNY7z5Ato4MUb0zMgi2viLBzoUULAbnVxsSWzTtwofYBtlTACkhvgIHWtSy0rWKSJVXAJ5Lh4FBWMNMicAJ0cSzPWBW1uQN0fWlwJQRGst7OW8kmhNVn3Sd1hdp1TJMhVCzmhHipUDO54RYHm07Q6NHXfmV/65eS5jXXVJhj15yCNDz54GyxD58PwjL2v/SmMuE7POqSVdxj5vm/cK6PG4X/5deNvPjeSEfQdeOV75Rm8K/dZzo3LOaGSaMr69aF0wbIA00NhZfpVff+JSwJGr2TL2Nnr3jtbzDeabEUi2v/Tlo22kKO1gbq0Z8ZDwzE0J+cNidM2ROinF18CR6KeivQleI59pVrM8knfV04Dc1gx+FM/QA=',
1764				40, 10, 'Lollipop Notation');
1765		}),
1766		this.createVertexTemplateEntry('shape=umlBoundary;whiteSpace=wrap;html=1;', 100, 80, 'Boundary Object', 'Boundary Object', null, null, 'uml boundary object'),
1767		this.createVertexTemplateEntry('ellipse;shape=umlEntity;whiteSpace=wrap;html=1;', 80, 80, 'Entity Object', 'Entity Object', null, null, 'uml entity object'),
1768		this.createVertexTemplateEntry('ellipse;shape=umlControl;whiteSpace=wrap;html=1;', 70, 80, 'Control Object', 'Control Object', null, null, 'uml control object'),
1769		this.createVertexTemplateEntry('shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;', 30, 60, 'Actor', 'Actor', false, null, 'uml actor'),
1770		this.createVertexTemplateEntry('ellipse;whiteSpace=wrap;html=1;', 140, 70, 'Use Case', 'Use Case', null, null, 'uml use case usecase'),
1771		this.addEntry('uml activity state start', function()
1772		{
1773	    	var cell = new mxCell('', new mxGeometry(0, 0, 30, 30),
1774	    		'ellipse;html=1;shape=startState;fillColor=#000000;strokeColor=#ff0000;');
1775	    	cell.vertex = true;
1776
1777			var edge = new mxCell('', new mxGeometry(0, 0, 0, 0), 'edgeStyle=orthogonalEdgeStyle;html=1;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;');
1778			edge.geometry.setTerminalPoint(new mxPoint(15, 90), false);
1779			edge.geometry.relative = true;
1780			edge.edge = true;
1781
1782			cell.insertEdge(edge, true);
1783
1784			return sb.createVertexTemplateFromCells([cell, edge], 30, 90, 'Start');
1785		}),
1786		this.addEntry('uml activity state', function()
1787		{
1788			var cell = new mxCell('Activity', new mxGeometry(0, 0, 120, 40),
1789				'rounded=1;whiteSpace=wrap;html=1;arcSize=40;fontColor=#000000;fillColor=#ffffc0;strokeColor=#ff0000;');
1790			cell.vertex = true;
1791
1792			var edge = new mxCell('', new mxGeometry(0, 0, 0, 0), 'edgeStyle=orthogonalEdgeStyle;html=1;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;');
1793			edge.geometry.setTerminalPoint(new mxPoint(60, 100), false);
1794			edge.geometry.relative = true;
1795			edge.edge = true;
1796
1797			cell.insertEdge(edge, true);
1798
1799			return sb.createVertexTemplateFromCells([cell, edge], 120, 100, 'Activity');
1800		}),
1801		this.addEntry('uml activity composite state', function()
1802		{
1803			var cell = new mxCell('Composite State', new mxGeometry(0, 0, 160, 60),
1804					'swimlane;fontStyle=1;align=center;verticalAlign=middle;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=0;resizeLast=1;container=0;fontColor=#000000;collapsible=0;rounded=1;arcSize=30;strokeColor=#ff0000;fillColor=#ffffc0;swimlaneFillColor=#ffffc0;dropTarget=0;');
1805			cell.vertex = true;
1806
1807			var cell1 = new mxCell('Subtitle', new mxGeometry(0, 0, 200, 26), 'text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;spacingLeft=4;spacingRight=4;whiteSpace=wrap;overflow=hidden;rotatable=0;fontColor=#000000;');
1808			cell1.vertex = true;
1809			cell.insert(cell1);
1810
1811			var edge = new mxCell('', new mxGeometry(0, 0, 0, 0), 'edgeStyle=orthogonalEdgeStyle;html=1;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;');
1812			edge.geometry.setTerminalPoint(new mxPoint(80, 120), false);
1813			edge.geometry.relative = true;
1814			edge.edge = true;
1815
1816			cell.insertEdge(edge, true);
1817
1818			return sb.createVertexTemplateFromCells([cell, edge], 160, 120, 'Composite State');
1819		}),
1820		this.addEntry('uml activity condition', function()
1821		{
1822	    	var cell = new mxCell('Condition', new mxGeometry(0, 0, 80, 40), 'rhombus;whiteSpace=wrap;html=1;fillColor=#ffffc0;strokeColor=#ff0000;');
1823	    	cell.vertex = true;
1824
1825			var edge1 = new mxCell('no', new mxGeometry(0, 0, 0, 0), 'edgeStyle=orthogonalEdgeStyle;html=1;align=left;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;');
1826			edge1.geometry.setTerminalPoint(new mxPoint(180, 20), false);
1827			edge1.geometry.relative = true;
1828			edge1.geometry.x = -1;
1829			edge1.edge = true;
1830
1831			cell.insertEdge(edge1, true);
1832
1833			var edge2 = new mxCell('yes', new mxGeometry(0, 0, 0, 0), 'edgeStyle=orthogonalEdgeStyle;html=1;align=left;verticalAlign=top;endArrow=open;endSize=8;strokeColor=#ff0000;');
1834			edge2.geometry.setTerminalPoint(new mxPoint(40, 100), false);
1835			edge2.geometry.relative = true;
1836			edge2.geometry.x = -1;
1837			edge2.edge = true;
1838
1839			cell.insertEdge(edge2, true);
1840
1841			return sb.createVertexTemplateFromCells([cell, edge1, edge2], 180, 100, 'Condition');
1842		}),
1843		this.addEntry('uml activity fork join', function()
1844		{
1845	    	var cell = new mxCell('', new mxGeometry(0, 0, 200, 10), 'shape=line;html=1;strokeWidth=6;strokeColor=#ff0000;');
1846	    	cell.vertex = true;
1847
1848			var edge = new mxCell('', new mxGeometry(0, 0, 0, 0), 'edgeStyle=orthogonalEdgeStyle;html=1;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;');
1849			edge.geometry.setTerminalPoint(new mxPoint(100, 80), false);
1850			edge.geometry.relative = true;
1851			edge.edge = true;
1852
1853			cell.insertEdge(edge, true);
1854
1855			return sb.createVertexTemplateFromCells([cell, edge], 200, 80, 'Fork/Join');
1856		}),
1857		this.createVertexTemplateEntry('ellipse;html=1;shape=endState;fillColor=#000000;strokeColor=#ff0000;', 30, 30, '', 'End', null, null, 'uml activity state end'),
1858		this.createVertexTemplateEntry('shape=umlLifeline;perimeter=lifelinePerimeter;whiteSpace=wrap;html=1;container=1;collapsible=0;recursiveResize=0;outlineConnect=0;', 100, 300, ':Object', 'Lifeline', null, null, 'uml sequence participant lifeline'),
1859		this.createVertexTemplateEntry('shape=umlLifeline;participant=umlActor;perimeter=lifelinePerimeter;whiteSpace=wrap;html=1;container=1;collapsible=0;recursiveResize=0;verticalAlign=top;spacingTop=36;outlineConnect=0;',
1860				20, 300, '', 'Actor Lifeline', null, null, 'uml sequence participant lifeline actor'),
1861		this.createVertexTemplateEntry('shape=umlLifeline;participant=umlBoundary;perimeter=lifelinePerimeter;whiteSpace=wrap;html=1;container=1;collapsible=0;recursiveResize=0;verticalAlign=top;spacingTop=36;outlineConnect=0;',
1862				50, 300, '', 'Boundary Lifeline', null, null, 'uml sequence participant lifeline boundary'),
1863		this.createVertexTemplateEntry('shape=umlLifeline;participant=umlEntity;perimeter=lifelinePerimeter;whiteSpace=wrap;html=1;container=1;collapsible=0;recursiveResize=0;verticalAlign=top;spacingTop=36;outlineConnect=0;',
1864				40, 300, '', 'Entity Lifeline', null, null, 'uml sequence participant lifeline entity'),
1865		this.createVertexTemplateEntry('shape=umlLifeline;participant=umlControl;perimeter=lifelinePerimeter;whiteSpace=wrap;html=1;container=1;collapsible=0;recursiveResize=0;verticalAlign=top;spacingTop=36;outlineConnect=0;',
1866				40, 300, '', 'Control Lifeline', null, null, 'uml sequence participant lifeline control'),
1867		this.createVertexTemplateEntry('shape=umlFrame;whiteSpace=wrap;html=1;', 300, 200, 'frame', 'Frame', null, null, 'uml sequence frame'),
1868		this.createVertexTemplateEntry('shape=umlDestroy;whiteSpace=wrap;html=1;strokeWidth=3;', 30, 30, '', 'Destruction', null, null, 'uml sequence destruction destroy'),
1869		this.addEntry('uml sequence invoke invocation call activation', function()
1870		{
1871	    	var cell = new mxCell('', new mxGeometry(0, 0, 10, 80), 'html=1;points=[];perimeter=orthogonalPerimeter;');
1872	    	cell.vertex = true;
1873
1874			var edge = new mxCell('dispatch', new mxGeometry(0, 0, 0, 0), 'html=1;verticalAlign=bottom;startArrow=oval;endArrow=block;startSize=8;');
1875			edge.geometry.setTerminalPoint(new mxPoint(-60, 0), true);
1876			edge.geometry.relative = true;
1877			edge.edge = true;
1878
1879			cell.insertEdge(edge, false);
1880
1881			return sb.createVertexTemplateFromCells([cell, edge], 10, 80, 'Found Message');
1882		}),
1883		this.addEntry('uml sequence invoke call delegation synchronous invocation activation', function()
1884		{
1885	    	var cell = new mxCell('', new mxGeometry(0, 0, 10, 80), 'html=1;points=[];perimeter=orthogonalPerimeter;');
1886	    	cell.vertex = true;
1887
1888			var edge1 = new mxCell('dispatch', new mxGeometry(0, 0, 0, 0), 'html=1;verticalAlign=bottom;endArrow=block;entryX=0;entryY=0;');
1889			edge1.geometry.setTerminalPoint(new mxPoint(-70, 0), true);
1890			edge1.geometry.relative = true;
1891			edge1.edge = true;
1892
1893			cell.insertEdge(edge1, false);
1894
1895			var edge2 = new mxCell('return', new mxGeometry(0, 0, 0, 0), 'html=1;verticalAlign=bottom;endArrow=open;dashed=1;endSize=8;exitX=0;exitY=0.95;');
1896			edge2.geometry.setTerminalPoint(new mxPoint(-70, 76), false);
1897			edge2.geometry.relative = true;
1898			edge2.edge = true;
1899
1900			cell.insertEdge(edge2, true);
1901
1902			return sb.createVertexTemplateFromCells([cell, edge1, edge2], 10, 80, 'Synchronous Invocation');
1903		}),
1904		this.addEntry('uml sequence self call recursion delegation activation', function()
1905		{
1906	    	var cell = new mxCell('', new mxGeometry(-5, 20, 10, 40), 'html=1;points=[];perimeter=orthogonalPerimeter;');
1907	    	cell.vertex = true;
1908
1909			var edge = new mxCell('self call', new mxGeometry(0, 0, 0, 0), 'edgeStyle=orthogonalEdgeStyle;html=1;align=left;spacingLeft=2;endArrow=block;rounded=0;entryX=1;entryY=0;');
1910			edge.geometry.setTerminalPoint(new mxPoint(0, 0), true);
1911			edge.geometry.points = [new mxPoint(30, 0)];
1912			edge.geometry.relative = true;
1913			edge.edge = true;
1914
1915			cell.insertEdge(edge, false);
1916
1917			return sb.createVertexTemplateFromCells([cell, edge], 10, 60, 'Self Call');
1918		}),
1919		this.addEntry('uml sequence invoke call delegation callback activation', function()
1920		{
1921			// TODO: Check if more entries should be converted to compressed XML
1922			return sb.createVertexTemplateFromData('xZRNT8MwDIZ/Ta6oaymD47rBTkiTuMAxW6wmIm0q19s6fj1OE3V0Y2iCA4dK8euP2I+riGxedUuUjX52CqzIHkU2R+conKpuDtaKNDFKZAuRpgl/In264J303qSRCDVdk5CGhJ20WwhKEFo62ChoqritxURkReNMTa2X80LkC68AmgoIkEWHpF3pamlXR7WIFwASdBeb7KXY4RIc5+KBQ/ZGkY4RYY5Egyl1zLqLmmyDXQ6Zx4n5EIf+HkB2BmAjrV3LzftPIPw4hgNn1pQ1a2tH5Cp2QK1miG7vNeu4iJe4pdeY2BtvbCQDGlAljMCQxBJotJ8rWCFYSWY3LvUdmZi68rvkkLiU6QnL1m1xAzHoBOdw61WEb88II9AW67/ydQ2wq1Cy1aAGvOrFfPh6997qDA3g+dxzv3nIL6MPU/8T+kMw8+m4QPgdfrEJNo8PSQj/+s58Ag==',
1923				10, 60, 'Callback');
1924		}),
1925		this.createVertexTemplateEntry('html=1;points=[];perimeter=orthogonalPerimeter;', 10, 80, '', 'Activation', null, null, 'uml sequence activation'),
1926
1927	 	this.createEdgeTemplateEntry('html=1;verticalAlign=bottom;startArrow=oval;startFill=1;endArrow=block;startSize=8;', 60, 0, 'dispatch', 'Found Message 1', null, 'uml sequence message call invoke dispatch'),
1928	 	this.createEdgeTemplateEntry('html=1;verticalAlign=bottom;startArrow=circle;startFill=1;endArrow=open;startSize=6;endSize=8;', 80, 0, 'dispatch', 'Found Message 2', null, 'uml sequence message call invoke dispatch'),
1929	 	this.createEdgeTemplateEntry('html=1;verticalAlign=bottom;endArrow=block;', 80, 0, 'dispatch', 'Message', null, 'uml sequence message call invoke dispatch'),
1930		this.addEntry('uml sequence return message', function()
1931		{
1932			var edge = new mxCell('return', new mxGeometry(0, 0, 0, 0), 'html=1;verticalAlign=bottom;endArrow=open;dashed=1;endSize=8;');
1933			edge.geometry.setTerminalPoint(new mxPoint(80, 0), true);
1934			edge.geometry.setTerminalPoint(new mxPoint(0, 0), false);
1935			edge.geometry.relative = true;
1936			edge.edge = true;
1937
1938			return sb.createEdgeTemplateFromCells([edge], 80, 0, 'Return');
1939		}),
1940		this.addEntry('uml relation', function()
1941		{
1942			var edge = new mxCell('name', new mxGeometry(0, 0, 0, 0), 'endArrow=block;endFill=1;html=1;edgeStyle=orthogonalEdgeStyle;align=left;verticalAlign=top;');
1943			edge.geometry.setTerminalPoint(new mxPoint(0, 0), true);
1944			edge.geometry.setTerminalPoint(new mxPoint(160, 0), false);
1945			edge.geometry.relative = true;
1946			edge.geometry.x = -1;
1947			edge.edge = true;
1948
1949	    	var cell = new mxCell('1', new mxGeometry(-1, 0, 0, 0), 'edgeLabel;resizable=0;html=1;align=left;verticalAlign=bottom;');
1950	    	cell.geometry.relative = true;
1951	    	cell.setConnectable(false);
1952	    	cell.vertex = true;
1953	    	edge.insert(cell);
1954
1955			return sb.createEdgeTemplateFromCells([edge], 160, 0, 'Relation 1');
1956		}),
1957		this.addEntry('uml association', function()
1958		{
1959			var edge = new mxCell('', new mxGeometry(0, 0, 0, 0), 'endArrow=none;html=1;edgeStyle=orthogonalEdgeStyle;');
1960			edge.geometry.setTerminalPoint(new mxPoint(0, 0), true);
1961			edge.geometry.setTerminalPoint(new mxPoint(160, 0), false);
1962			edge.geometry.relative = true;
1963			edge.edge = true;
1964
1965	    	var cell1 = new mxCell('parent', new mxGeometry(-1, 0, 0, 0), 'edgeLabel;resizable=0;html=1;align=left;verticalAlign=bottom;');
1966	    	cell1.geometry.relative = true;
1967	    	cell1.setConnectable(false);
1968	    	cell1.vertex = true;
1969	    	edge.insert(cell1);
1970
1971	    	var cell2 = new mxCell('child', new mxGeometry(1, 0, 0, 0), 'edgeLabel;resizable=0;html=1;align=right;verticalAlign=bottom;');
1972	    	cell2.geometry.relative = true;
1973	    	cell2.setConnectable(false);
1974	    	cell2.vertex = true;
1975	    	edge.insert(cell2);
1976
1977			return sb.createEdgeTemplateFromCells([edge], 160, 0, 'Association 1');
1978		}),
1979		this.addEntry('uml aggregation', function()
1980		{
1981			var edge = new mxCell('1', new mxGeometry(0, 0, 0, 0), 'endArrow=open;html=1;endSize=12;startArrow=diamondThin;startSize=14;startFill=0;edgeStyle=orthogonalEdgeStyle;align=left;verticalAlign=bottom;');
1982			edge.geometry.setTerminalPoint(new mxPoint(0, 0), true);
1983			edge.geometry.setTerminalPoint(new mxPoint(160, 0), false);
1984			edge.geometry.relative = true;
1985			edge.geometry.x = -1;
1986			edge.geometry.y = 3;
1987			edge.edge = true;
1988
1989			return sb.createEdgeTemplateFromCells([edge], 160, 0, 'Aggregation 1');
1990		}),
1991		this.addEntry('uml composition', function()
1992		{
1993			var edge = new mxCell('1', new mxGeometry(0, 0, 0, 0), 'endArrow=open;html=1;endSize=12;startArrow=diamondThin;startSize=14;startFill=1;edgeStyle=orthogonalEdgeStyle;align=left;verticalAlign=bottom;');
1994			edge.geometry.setTerminalPoint(new mxPoint(0, 0), true);
1995			edge.geometry.setTerminalPoint(new mxPoint(160, 0), false);
1996			edge.geometry.relative = true;
1997			edge.geometry.x = -1;
1998			edge.geometry.y = 3;
1999			edge.edge = true;
2000
2001			return sb.createEdgeTemplateFromCells([edge], 160, 0, 'Composition 1');
2002		}),
2003		this.addEntry('uml relation', function()
2004		{
2005			var edge = new mxCell('Relation', new mxGeometry(0, 0, 0, 0), 'endArrow=open;html=1;endSize=12;startArrow=diamondThin;startSize=14;startFill=0;edgeStyle=orthogonalEdgeStyle;');
2006			edge.geometry.setTerminalPoint(new mxPoint(0, 0), true);
2007			edge.geometry.setTerminalPoint(new mxPoint(160, 0), false);
2008			edge.geometry.relative = true;
2009			edge.edge = true;
2010
2011	    	var cell1 = new mxCell('0..n', new mxGeometry(-1, 0, 0, 0), 'edgeLabel;resizable=0;html=1;align=left;verticalAlign=top;');
2012	    	cell1.geometry.relative = true;
2013	    	cell1.setConnectable(false);
2014	    	cell1.vertex = true;
2015	    	edge.insert(cell1);
2016
2017	    	var cell2 = new mxCell('1', new mxGeometry(1, 0, 0, 0), 'edgeLabel;resizable=0;html=1;align=right;verticalAlign=top;');
2018	    	cell2.geometry.relative = true;
2019	    	cell2.setConnectable(false);
2020	    	cell2.vertex = true;
2021	    	edge.insert(cell2);
2022
2023			return sb.createEdgeTemplateFromCells([edge], 160, 0, 'Relation 2');
2024		}),
2025		this.createEdgeTemplateEntry('endArrow=open;endSize=12;dashed=1;html=1;', 160, 0, 'Use', 'Dependency', null, 'uml dependency use'),
2026		this.createEdgeTemplateEntry('endArrow=block;endSize=16;endFill=0;html=1;', 160, 0, 'Extends', 'Generalization', null, 'uml generalization extend'),
2027	 	this.createEdgeTemplateEntry('endArrow=block;startArrow=block;endFill=1;startFill=1;html=1;', 160, 0, '', 'Association 2', null, 'uml association'),
2028	 	this.createEdgeTemplateEntry('endArrow=open;startArrow=circlePlus;endFill=0;startFill=0;endSize=8;html=1;', 160, 0, '', 'Inner Class', null, 'uml inner class'),
2029	 	this.createEdgeTemplateEntry('endArrow=open;startArrow=cross;endFill=0;startFill=0;endSize=8;startSize=10;html=1;', 160, 0, '', 'Terminate', null, 'uml terminate'),
2030	 	this.createEdgeTemplateEntry('endArrow=block;dashed=1;endFill=0;endSize=12;html=1;', 160, 0, '', 'Implementation', null, 'uml realization implementation'),
2031	 	this.createEdgeTemplateEntry('endArrow=diamondThin;endFill=0;endSize=24;html=1;', 160, 0, '', 'Aggregation 2', null, 'uml aggregation'),
2032	 	this.createEdgeTemplateEntry('endArrow=diamondThin;endFill=1;endSize=24;html=1;', 160, 0, '', 'Composition 2', null, 'uml composition'),
2033	 	this.createEdgeTemplateEntry('endArrow=open;endFill=1;endSize=12;html=1;', 160, 0, '', 'Association 3', null, 'uml association')
2034	];
2035
2036	this.addPaletteFunctions('uml', mxResources.get('uml'), expand || false, fns);
2037	this.setCurrentSearchEntryLibrary();
2038};
2039
2040/**
2041 * Creates and returns the given title element.
2042 */
2043Sidebar.prototype.createTitle = function(label)
2044{
2045	var elt = document.createElement('a');
2046	elt.setAttribute('title', mxResources.get('sidebarTooltip'));
2047	elt.className = 'geTitle';
2048	mxUtils.write(elt, label);
2049
2050	return elt;
2051};
2052
2053/**
2054 * Creates a thumbnail for the given cells.
2055 */
2056Sidebar.prototype.createThumb = function(cells, width, height, parent, title, showLabel, showTitle)
2057{
2058	this.graph.labelsVisible = (showLabel == null || showLabel);
2059	var fo = mxClient.NO_FO;
2060	mxClient.NO_FO = Editor.prototype.originalNoForeignObject;
2061	this.graph.view.scaleAndTranslate(1, 0, 0);
2062	this.graph.addCells(cells);
2063
2064	var bounds = this.graph.getGraphBounds();
2065	var s = Math.floor(Math.min((width - 2 * this.thumbBorder) / bounds.width,
2066		(height - 2 * this.thumbBorder) / bounds.height) * 100) / 100;
2067	this.graph.view.scaleAndTranslate(s, Math.floor((width - bounds.width * s) / 2 / s - bounds.x),
2068		Math.floor((height - bounds.height * s) / 2 / s - bounds.y));
2069	var node = null;
2070
2071	// For supporting HTML labels in IE9 standards mode the container is cloned instead
2072	if (this.graph.dialect == mxConstants.DIALECT_SVG && !mxClient.NO_FO &&
2073		this.graph.view.getCanvas().ownerSVGElement != null)
2074	{
2075		node = this.graph.view.getCanvas().ownerSVGElement.cloneNode(true);
2076	}
2077	// LATER: Check if deep clone can be used for quirks if container in DOM
2078	else
2079	{
2080		node = this.graph.container.cloneNode(false);
2081		node.innerHTML = this.graph.container.innerHTML;
2082	}
2083
2084	this.graph.getModel().clear();
2085	mxClient.NO_FO = fo;
2086
2087	node.style.position = 'relative';
2088	node.style.overflow = 'hidden';
2089	node.style.left = this.thumbBorder + 'px';
2090	node.style.top = this.thumbBorder + 'px';
2091	node.style.width = width + 'px';
2092	node.style.height = height + 'px';
2093	node.style.visibility = '';
2094	node.style.minWidth = '';
2095	node.style.minHeight = '';
2096
2097	parent.appendChild(node);
2098
2099	// Adds title for sidebar entries
2100	if (this.sidebarTitles && title != null && showTitle != false)
2101	{
2102		var border = 0;
2103		parent.style.height = (this.thumbHeight + border + this.sidebarTitleSize + 8) + 'px';
2104
2105		var div = document.createElement('div');
2106		div.style.color = Editor.isDarkMode() ? '#A0A0A0' : '#303030';
2107		div.style.fontSize = this.sidebarTitleSize + 'px';
2108		div.style.textAlign = 'center';
2109		div.style.whiteSpace = 'nowrap';
2110		div.style.overflow = 'hidden';
2111		div.style.textOverflow = 'ellipsis';
2112
2113		if (mxClient.IS_IE)
2114		{
2115			div.style.height = (this.sidebarTitleSize + 12) + 'px';
2116		}
2117
2118		div.style.paddingTop = '4px';
2119		mxUtils.write(div, title);
2120		parent.appendChild(div);
2121	}
2122
2123	return bounds;
2124};
2125
2126/**
2127 * Returns a function that creates a title.
2128 */
2129Sidebar.prototype.createSection = function(title)
2130{
2131	return mxUtils.bind(this, function()
2132	{
2133		var elt = document.createElement('div');
2134		elt.setAttribute('title', title);
2135		elt.style.textOverflow = 'ellipsis';
2136		elt.style.whiteSpace = 'nowrap';
2137		elt.style.textAlign = 'center';
2138		elt.style.overflow = 'hidden';
2139		elt.style.width = '100%';
2140		elt.style.padding = '14px 0';
2141
2142		mxUtils.write(elt, title);
2143
2144		return elt;
2145	});
2146};
2147
2148/**
2149 * Creates and returns a new palette item for the given image.
2150 */
2151Sidebar.prototype.createItem = function(cells, title, showLabel, showTitle, width, height, allowCellsInserted, showTooltip)
2152{
2153	showTooltip = (showTooltip != null) ? showTooltip : true;
2154
2155	var elt = document.createElement('a');
2156	elt.className = 'geItem';
2157	elt.style.overflow = 'hidden';
2158	var border = 2 * this.thumbBorder;
2159	elt.style.width = (this.thumbWidth + border) + 'px';
2160	elt.style.height = (this.thumbHeight + border) + 'px';
2161	elt.style.padding = this.thumbPadding + 'px';
2162
2163	// Blocks default click action
2164	mxEvent.addListener(elt, 'click', function(evt)
2165	{
2166		mxEvent.consume(evt);
2167	});
2168
2169	// Applies default styles
2170	var originalCells = cells;
2171	cells = this.graph.cloneCells(cells);
2172	this.editorUi.insertHandler(originalCells, null, this.graph.model,
2173		this.editorUi.editor.graph.defaultVertexStyle,
2174		this.editorUi.editor.graph.defaultEdgeStyle,
2175		true, true);
2176
2177	this.createThumb(originalCells, this.thumbWidth, this.thumbHeight,
2178		elt, title, showLabel, showTitle, width, height);
2179	var bounds = new mxRectangle(0, 0, width, height);
2180
2181	if (cells.length > 1 || cells[0].vertex)
2182	{
2183		var ds = this.createDragSource(elt, this.createDropHandler(cells, true, allowCellsInserted,
2184			bounds), this.createDragPreview(width, height), cells, bounds);
2185		this.addClickHandler(elt, ds, cells);
2186
2187		// Uses guides for vertices only if enabled in graph
2188		ds.isGuidesEnabled = mxUtils.bind(this, function()
2189		{
2190			return this.editorUi.editor.graph.graphHandler.guidesEnabled;
2191		});
2192	}
2193	else if (cells[0] != null && cells[0].edge)
2194	{
2195		var ds = this.createDragSource(elt, this.createDropHandler(cells, false, allowCellsInserted,
2196			bounds), this.createDragPreview(width, height), cells, bounds);
2197		this.addClickHandler(elt, ds, cells);
2198	}
2199
2200	// Shows a tooltip with the rendered cell
2201	if (!mxClient.IS_IOS && showTooltip)
2202	{
2203		mxEvent.addGestureListeners(elt, null, mxUtils.bind(this, function(evt)
2204		{
2205			if (mxEvent.isMouseEvent(evt))
2206			{
2207				this.showTooltip(elt, cells, bounds.width, bounds.height, title, showLabel);
2208			}
2209		}));
2210	}
2211
2212	return elt;
2213};
2214
2215/**
2216 * Creates a drop handler for inserting the given cells.
2217 */
2218Sidebar.prototype.updateShapes = function(source, targets)
2219{
2220	var graph = this.editorUi.editor.graph;
2221	var sourceCellStyle = graph.getCellStyle(source);
2222	var result = [];
2223
2224	graph.model.beginUpdate();
2225	try
2226	{
2227		var cellStyle = graph.getModel().getStyle(source);
2228
2229		// Lists the styles to carry over from the existing shape
2230		var styles = ['shadow', 'dashed', 'dashPattern', 'fontFamily', 'fontSize', 'fontColor', 'align', 'startFill',
2231		              'startSize', 'endFill', 'endSize', 'strokeColor', 'strokeWidth', 'fillColor', 'gradientColor',
2232		              'html', 'part', 'noEdgeStyle', 'edgeStyle', 'elbow', 'childLayout', 'recursiveResize',
2233		              'container', 'collapsible', 'connectable', 'comic', 'sketch', 'fillWeight', 'hachureGap',
2234		              'hachureAngle', 'jiggle', 'disableMultiStroke', 'disableMultiStrokeFill',
2235		              'fillStyle', 'curveFitting', 'simplification', 'sketchStyle'];
2236
2237		for (var i = 0; i < targets.length; i++)
2238		{
2239			var targetCell = targets[i];
2240
2241			if ((graph.getModel().isVertex(targetCell) == graph.getModel().isVertex(source)) ||
2242				(graph.getModel().isEdge(targetCell) == graph.getModel().isEdge(source)))
2243			{
2244				var style = graph.getCurrentCellStyle(targets[i]);
2245				graph.getModel().setStyle(targetCell, cellStyle);
2246
2247				// Removes all children of composite cells
2248				if (mxUtils.getValue(style, 'composite', '0') == '1')
2249				{
2250					var childCount = graph.model.getChildCount(targetCell);
2251
2252					for (var j = childCount; j >= 0; j--)
2253					{
2254						graph.model.remove(graph.model.getChildAt(targetCell, j));
2255					}
2256				}
2257
2258				// Replaces the participant style in the lifeline shape with the target shape
2259				if (style[mxConstants.STYLE_SHAPE] == 'umlLifeline' &&
2260					sourceCellStyle[mxConstants.STYLE_SHAPE] != 'umlLifeline')
2261				{
2262					graph.setCellStyles(mxConstants.STYLE_SHAPE, 'umlLifeline', [targetCell]);
2263					graph.setCellStyles('participant', sourceCellStyle[mxConstants.STYLE_SHAPE], [targetCell]);
2264				}
2265
2266				for (var j = 0; j < styles.length; j++)
2267				{
2268					var value = style[styles[j]];
2269
2270					if (value != null)
2271					{
2272						graph.setCellStyles(styles[j], value, [targetCell]);
2273					}
2274				}
2275
2276				result.push(targetCell);
2277			}
2278		}
2279	}
2280	finally
2281	{
2282		graph.model.endUpdate();
2283	}
2284
2285	return result;
2286};
2287
2288/**
2289 * Creates a drop handler for inserting the given cells.
2290 */
2291Sidebar.prototype.createDropHandler = function(cells, allowSplit, allowCellsInserted, bounds)
2292{
2293	allowCellsInserted = (allowCellsInserted != null) ? allowCellsInserted : true;
2294
2295	return mxUtils.bind(this, function(graph, evt, target, x, y, force)
2296	{
2297		var elt = (force) ? null : ((mxEvent.isTouchEvent(evt) || mxEvent.isPenEvent(evt)) ?
2298			document.elementFromPoint(mxEvent.getClientX(evt), mxEvent.getClientY(evt)) :
2299			mxEvent.getSource(evt));
2300
2301		while (elt != null && elt != this.container)
2302		{
2303			elt = elt.parentNode;
2304		}
2305
2306		if (elt == null && graph.isEnabled())
2307		{
2308			cells = graph.getImportableCells(cells);
2309
2310			if (cells.length > 0)
2311			{
2312				graph.stopEditing();
2313
2314				// Holding alt while mouse is released ignores drop target
2315				var validDropTarget = (target != null && !mxEvent.isAltDown(evt)) ?
2316					graph.isValidDropTarget(target, cells, evt) : false;
2317
2318				var select = null;
2319
2320				if (target != null && !validDropTarget)
2321				{
2322					target = null;
2323				}
2324
2325				if (!graph.isCellLocked(target || graph.getDefaultParent()))
2326				{
2327					graph.model.beginUpdate();
2328					try
2329					{
2330						x = Math.round(x);
2331						y = Math.round(y);
2332
2333						// Splits the target edge or inserts into target group
2334						if (allowSplit && graph.isSplitTarget(target, cells, evt))
2335						{
2336							var s = graph.view.scale;
2337							var tr = graph.view.translate;
2338							var tx = (x + tr.x) * s;
2339							var ty = (y + tr.y) * s;
2340
2341							var clones = graph.cloneCells(cells);
2342							graph.splitEdge(target, clones, null,
2343								x - bounds.width / 2, y - bounds.height / 2,
2344								tx, ty);
2345							select = clones;
2346						}
2347						else if (cells.length > 0)
2348						{
2349							select = graph.importCells(cells, x, y, target);
2350						}
2351
2352						// Executes parent layout hooks for position/order
2353						if (graph.layoutManager != null)
2354						{
2355							var layout = graph.layoutManager.getLayout(target);
2356
2357							if (layout != null)
2358							{
2359								var s = graph.view.scale;
2360								var tr = graph.view.translate;
2361								var tx = (x + tr.x) * s;
2362								var ty = (y + tr.y) * s;
2363
2364								for (var i = 0; i < select.length; i++)
2365								{
2366									layout.moveCell(select[i], tx, ty);
2367								}
2368							}
2369						}
2370
2371						if (allowCellsInserted && (evt == null || !mxEvent.isShiftDown(evt)))
2372						{
2373							graph.fireEvent(new mxEventObject('cellsInserted', 'cells', select));
2374						}
2375					}
2376					catch (e)
2377					{
2378						this.editorUi.handleError(e);
2379					}
2380					finally
2381					{
2382						graph.model.endUpdate();
2383					}
2384
2385					if (select != null && select.length > 0)
2386					{
2387						graph.scrollCellToVisible(select[0]);
2388						graph.setSelectionCells(select);
2389					}
2390
2391					if (graph.editAfterInsert && evt != null && mxEvent.isMouseEvent(evt) &&
2392						select != null && select.length == 1)
2393					{
2394						window.setTimeout(function()
2395						{
2396							graph.startEditing(select[0]);
2397						}, 0);
2398					}
2399				}
2400			}
2401
2402			mxEvent.consume(evt);
2403		}
2404	});
2405};
2406
2407/**
2408 * Creates and returns a preview element for the given width and height.
2409 */
2410Sidebar.prototype.createDragPreview = function(width, height)
2411{
2412	var elt = document.createElement('div');
2413	elt.className = 'geDragPreview';
2414	elt.style.width = width + 'px';
2415	elt.style.height = height + 'px';
2416
2417	return elt;
2418};
2419
2420/**
2421 * Creates a drag source for the given element.
2422 */
2423Sidebar.prototype.dropAndConnect = function(source, targets, direction, dropCellIndex, evt)
2424{
2425	var geo = this.getDropAndConnectGeometry(source, targets[dropCellIndex], direction, targets);
2426
2427	// Targets without the new edge for selection
2428	var tmp = [];
2429
2430	if (geo != null)
2431	{
2432		var graph = this.editorUi.editor.graph;
2433		var editingCell = null;
2434
2435		graph.model.beginUpdate();
2436		try
2437		{
2438			var sourceGeo = graph.getCellGeometry(source);
2439			var geo2 = graph.getCellGeometry(targets[dropCellIndex]);
2440
2441			// Handles special case where target should be ignored for stack layouts
2442			var targetParent = graph.model.getParent(source);
2443			var validLayout = true;
2444
2445			// Ignores parent if it has a stack layout or if it is a table or row
2446			if (graph.layoutManager != null)
2447			{
2448				var layout = graph.layoutManager.getLayout(targetParent);
2449
2450				// LATER: Use parent of parent if valid layout
2451				if (layout != null && layout.constructor == mxStackLayout)
2452				{
2453					validLayout = false;
2454				}
2455			}
2456
2457			// Checks if another container is at the drop location
2458			var tmp = (graph.model.isEdge(source)) ? null : graph.view.getState(targetParent);
2459			var dx = 0;
2460			var dy = 0;
2461
2462			// Offsets by parent position
2463			if (tmp != null)
2464			{
2465				var offset = tmp.origin;
2466				dx = offset.x;
2467				dy = offset.y;
2468
2469				var pt = geo.getTerminalPoint(false);
2470
2471				if (pt != null)
2472				{
2473					pt.x += offset.x;
2474					pt.y += offset.y;
2475				}
2476			}
2477
2478			var useParent = !graph.isTableRow(source) && !graph.isTableCell(source) &&
2479				(graph.model.isEdge(source) || (sourceGeo != null &&
2480				!sourceGeo.relative && validLayout));
2481
2482			var tempTarget = graph.getCellAt((geo.x + dx + graph.view.translate.x) * graph.view.scale,
2483				(geo.y + dy + graph.view.translate.y) * graph.view.scale, null, null, null, function(state, x, y)
2484				{
2485					return !graph.isContainer(state.cell);
2486				});
2487
2488			if (tempTarget != null && tempTarget != targetParent)
2489			{
2490				tmp = graph.view.getState(tempTarget);
2491
2492				// Offsets by new parent position
2493				if (tmp != null)
2494				{
2495					var offset = tmp.origin;
2496					targetParent = tempTarget;
2497					useParent = true;
2498
2499					if (!graph.model.isEdge(source))
2500					{
2501						geo.x -= offset.x - dx;
2502						geo.y -= offset.y - dy;
2503					}
2504				}
2505			}
2506			else if (!validLayout || graph.isTableRow(source) || graph.isTableCell(source))
2507			{
2508				geo.x += dx;
2509				geo.y += dy;
2510			}
2511
2512			dx = geo2.x;
2513			dy = geo2.y;
2514
2515			// Ignores geometry of edges
2516			if (graph.model.isEdge(targets[dropCellIndex]))
2517			{
2518				dx = 0;
2519				dy = 0;
2520			}
2521
2522			targets = graph.importCells(targets, (geo.x - (useParent ? dx : 0)),
2523				(geo.y - (useParent ? dy : 0)), (useParent) ? targetParent : null);
2524			tmp = targets;
2525
2526			if (graph.model.isEdge(source))
2527			{
2528				// Adds new terminal to edge
2529				// LATER: Push new terminal out radially from edge start point
2530				graph.model.setTerminal(source, targets[dropCellIndex],
2531					direction == mxConstants.DIRECTION_NORTH);
2532			}
2533			else if (graph.model.isEdge(targets[dropCellIndex]))
2534			{
2535				// Adds new outgoing connection to vertex and clears points
2536				graph.model.setTerminal(targets[dropCellIndex], source, true);
2537				var geo3 = graph.getCellGeometry(targets[dropCellIndex]);
2538				geo3.points = null;
2539
2540				if (geo3.getTerminalPoint(false) != null)
2541				{
2542					geo3.setTerminalPoint(geo.getTerminalPoint(false), false);
2543				}
2544				else if (useParent && graph.model.isVertex(targetParent))
2545				{
2546					// Adds parent offset to other nodes
2547					var tmpState = graph.view.getState(targetParent);
2548					var offset = (tmpState.cell != graph.view.currentRoot) ?
2549						tmpState.origin : new mxPoint(0, 0);
2550
2551					graph.cellsMoved(targets, offset.x, offset.y, null, null, true);
2552				}
2553			}
2554			else
2555			{
2556				geo2 = graph.getCellGeometry(targets[dropCellIndex]);
2557				dx = geo.x - Math.round(geo2.x);
2558				dy = geo.y - Math.round(geo2.y);
2559				geo.x = Math.round(geo2.x);
2560				geo.y = Math.round(geo2.y);
2561				graph.model.setGeometry(targets[dropCellIndex], geo);
2562				graph.cellsMoved(targets, dx, dy, null, null, true);
2563				tmp = targets.slice();
2564				editingCell = (tmp.length == 1) ? tmp[0] : null;
2565				targets.push(graph.insertEdge(null, null, '', source, targets[dropCellIndex],
2566					graph.createCurrentEdgeStyle()));
2567			}
2568
2569			if (evt == null || !mxEvent.isShiftDown(evt))
2570			{
2571				graph.fireEvent(new mxEventObject('cellsInserted', 'cells', targets));
2572			}
2573		}
2574		catch (e)
2575		{
2576			this.editorUi.handleError(e);
2577		}
2578		finally
2579		{
2580			graph.model.endUpdate();
2581		}
2582
2583		if (graph.editAfterInsert && evt != null && mxEvent.isMouseEvent(evt) &&
2584			editingCell != null)
2585		{
2586			window.setTimeout(function()
2587			{
2588				graph.startEditing(editingCell);
2589			}, 0);
2590		}
2591	}
2592
2593	return tmp;
2594};
2595
2596/**
2597 * Creates a drag source for the given element.
2598 */
2599Sidebar.prototype.getDropAndConnectGeometry = function(source, target, direction, targets)
2600{
2601	var graph = this.editorUi.editor.graph;
2602	var view = graph.view;
2603	var keepSize = targets.length > 1;
2604	var geo = graph.getCellGeometry(source);
2605	var geo2 = graph.getCellGeometry(target);
2606
2607	if (geo != null && geo2 != null)
2608	{
2609		geo2 = geo2.clone();
2610
2611		if (graph.model.isEdge(source))
2612		{
2613			var state = graph.view.getState(source);
2614			var pts = state.absolutePoints;
2615			var p0 = pts[0];
2616			var pe = pts[pts.length - 1];
2617
2618			if (direction == mxConstants.DIRECTION_NORTH)
2619			{
2620				geo2.x = p0.x / view.scale - view.translate.x - geo2.width / 2;
2621				geo2.y = p0.y / view.scale - view.translate.y - geo2.height / 2;
2622			}
2623			else
2624			{
2625				geo2.x = pe.x / view.scale - view.translate.x - geo2.width / 2;
2626				geo2.y = pe.y / view.scale - view.translate.y - geo2.height / 2;
2627			}
2628		}
2629		else
2630		{
2631			if (geo.relative)
2632			{
2633				var state = graph.view.getState(source);
2634				geo = geo.clone();
2635				geo.x = (state.x - view.translate.x) / view.scale;
2636				geo.y = (state.y - view.translate.y) / view.scale;
2637			}
2638
2639			var length = graph.defaultEdgeLength;
2640
2641			// Maintains edge length
2642			if (graph.model.isEdge(target) && geo2.getTerminalPoint(true) != null &&
2643				geo2.getTerminalPoint(false) != null)
2644			{
2645				var p0 = geo2.getTerminalPoint(true);
2646				var pe = geo2.getTerminalPoint(false);
2647				var dx = pe.x - p0.x;
2648				var dy = pe.y - p0.y;
2649
2650				length = Math.sqrt(dx * dx + dy * dy);
2651
2652				geo2.x = geo.getCenterX();
2653				geo2.y = geo.getCenterY();
2654				geo2.width = 1;
2655				geo2.height = 1;
2656
2657				if (direction == mxConstants.DIRECTION_NORTH)
2658				{
2659					geo2.height = length
2660					geo2.y = geo.y - length;
2661					geo2.setTerminalPoint(new mxPoint(geo2.x, geo2.y), false);
2662				}
2663				else if (direction == mxConstants.DIRECTION_EAST)
2664				{
2665					geo2.width = length
2666					geo2.x = geo.x + geo.width;
2667					geo2.setTerminalPoint(new mxPoint(geo2.x + geo2.width, geo2.y), false);
2668				}
2669				else if (direction == mxConstants.DIRECTION_SOUTH)
2670				{
2671					geo2.height = length
2672					geo2.y = geo.y + geo.height;
2673					geo2.setTerminalPoint(new mxPoint(geo2.x, geo2.y + geo2.height), false);
2674				}
2675				else if (direction == mxConstants.DIRECTION_WEST)
2676				{
2677					geo2.width = length
2678					geo2.x = geo.x - length;
2679					geo2.setTerminalPoint(new mxPoint(geo2.x, geo2.y), false);
2680				}
2681			}
2682			else
2683			{
2684				// Try match size or ignore if width or height < 45 which
2685				// is considered special enough to be ignored here
2686				if (!keepSize && geo2.width > 45 && geo2.height > 45 &&
2687					geo.width > 45 && geo.height > 45)
2688				{
2689					geo2.width = geo2.width * (geo.height / geo2.height);
2690					geo2.height = geo.height;
2691				}
2692
2693				geo2.x = geo.x + geo.width / 2 - geo2.width / 2;
2694				geo2.y = geo.y + geo.height / 2 - geo2.height / 2;
2695
2696				if (direction == mxConstants.DIRECTION_NORTH)
2697				{
2698					geo2.y = geo2.y - geo.height / 2 - geo2.height / 2 - length;
2699				}
2700				else if (direction == mxConstants.DIRECTION_EAST)
2701				{
2702					geo2.x = geo2.x + geo.width / 2 + geo2.width / 2 + length;
2703				}
2704				else if (direction == mxConstants.DIRECTION_SOUTH)
2705				{
2706					geo2.y = geo2.y + geo.height / 2 + geo2.height / 2 + length;
2707				}
2708				else if (direction == mxConstants.DIRECTION_WEST)
2709				{
2710					geo2.x = geo2.x - geo.width / 2 - geo2.width / 2 - length;
2711				}
2712
2713				// Adds offset to match cells without connecting edge
2714				if (graph.model.isEdge(target) && geo2.getTerminalPoint(true) != null &&
2715					target.getTerminal(false) != null)
2716				{
2717					var targetGeo = graph.getCellGeometry(target.getTerminal(false));
2718
2719					if (targetGeo != null)
2720					{
2721						if (direction == mxConstants.DIRECTION_NORTH)
2722						{
2723							geo2.x -= targetGeo.getCenterX();
2724							geo2.y -= targetGeo.getCenterY() + targetGeo.height / 2;
2725						}
2726						else if (direction == mxConstants.DIRECTION_EAST)
2727						{
2728							geo2.x -= targetGeo.getCenterX() - targetGeo.width / 2;
2729							geo2.y -= targetGeo.getCenterY();
2730						}
2731						else if (direction == mxConstants.DIRECTION_SOUTH)
2732						{
2733							geo2.x -= targetGeo.getCenterX();
2734							geo2.y -= targetGeo.getCenterY() - targetGeo.height / 2;
2735						}
2736						else if (direction == mxConstants.DIRECTION_WEST)
2737						{
2738							geo2.x -= targetGeo.getCenterX() + targetGeo.width / 2;
2739							geo2.y -= targetGeo.getCenterY();
2740						}
2741					}
2742				}
2743			}
2744		}
2745	}
2746
2747	return geo2;
2748};
2749
2750/**
2751 * Limits drop style to non-transparent source shapes.
2752 */
2753Sidebar.prototype.isDropStyleEnabled = function(cells, firstVertex)
2754{
2755	var result = true;
2756
2757	if (firstVertex != null && cells.length == 1)
2758	{
2759		var vstyle = this.graph.getCellStyle(cells[firstVertex]);
2760
2761		if (vstyle != null)
2762		{
2763			result = mxUtils.getValue(vstyle, mxConstants.STYLE_STROKECOLOR, mxConstants.NONE) != mxConstants.NONE ||
2764				mxUtils.getValue(vstyle, mxConstants.STYLE_FILLCOLOR, mxConstants.NONE) != mxConstants.NONE;
2765		}
2766	}
2767
2768	return result;
2769};
2770
2771/**
2772 * Ignores swimlanes as drop style targets.
2773 */
2774Sidebar.prototype.isDropStyleTargetIgnored = function(state)
2775{
2776	return this.graph.isSwimlane(state.cell) || this.graph.isTableCell(state.cell) ||
2777		this.graph.isTableRow(state.cell) || this.graph.isTable(state.cell);
2778};
2779
2780/**
2781 * Creates a drag source for the given element.
2782 */
2783Sidebar.prototype.createDragSource = function(elt, dropHandler, preview, cells, bounds)
2784{
2785	// Checks if the cells contain any vertices
2786	var ui = this.editorUi;
2787	var graph = ui.editor.graph;
2788	var freeSourceEdge = null;
2789	var firstVertex = null;
2790	var sidebar = this;
2791
2792	for (var i = 0; i < cells.length; i++)
2793	{
2794		if (firstVertex == null && graph.model.isVertex(cells[i]))
2795		{
2796			firstVertex = i;
2797		}
2798		else if (freeSourceEdge == null && graph.model.isEdge(cells[i]) &&
2799				graph.model.getTerminal(cells[i], true) == null)
2800		{
2801			freeSourceEdge = i;
2802		}
2803
2804		if (firstVertex != null && freeSourceEdge != null)
2805		{
2806			break;
2807		}
2808	}
2809
2810	var dropStyleEnabled = this.isDropStyleEnabled(cells, firstVertex);
2811
2812	var dragSource = mxUtils.makeDraggable(elt, graph, mxUtils.bind(this, function(graph, evt, target, x, y)
2813	{
2814		if (this.updateThread != null)
2815		{
2816			window.clearTimeout(this.updateThread);
2817		}
2818
2819		if (cells != null && currentStyleTarget != null && activeArrow == styleTarget)
2820		{
2821			var tmp = graph.isCellSelected(currentStyleTarget.cell) ? graph.getSelectionCells() : [currentStyleTarget.cell];
2822			var updatedCells = this.updateShapes((graph.model.isEdge(currentStyleTarget.cell)) ? cells[0] : cells[firstVertex], tmp);
2823			graph.setSelectionCells(updatedCells);
2824		}
2825		else if (cells != null && activeArrow != null && currentTargetState != null && activeArrow != styleTarget)
2826		{
2827			var index = (graph.model.isEdge(currentTargetState.cell) || freeSourceEdge == null) ? firstVertex : freeSourceEdge;
2828			graph.setSelectionCells(this.dropAndConnect(currentTargetState.cell, cells, direction, index, evt));
2829		}
2830		else
2831		{
2832			dropHandler.apply(this, arguments);
2833		}
2834
2835		if (this.editorUi.hoverIcons != null)
2836		{
2837			this.editorUi.hoverIcons.update(graph.view.getState(graph.getSelectionCell()));
2838		}
2839	}), preview, 0, 0, graph.autoscroll, true, true);
2840
2841	// Stops dragging if cancel is pressed
2842	graph.addListener(mxEvent.ESCAPE, function(sender, evt)
2843	{
2844		if (dragSource.isActive())
2845		{
2846			dragSource.reset();
2847		}
2848	});
2849
2850	// Overrides mouseDown to ignore popup triggers
2851	var mouseDown = dragSource.mouseDown;
2852
2853	dragSource.mouseDown = function(evt)
2854	{
2855		if (!mxEvent.isPopupTrigger(evt) && !mxEvent.isMultiTouchEvent(evt) &&
2856			!graph.isCellLocked(graph.getDefaultParent()))
2857		{
2858			graph.stopEditing();
2859			mouseDown.apply(this, arguments);
2860		}
2861	};
2862
2863	// Workaround for event redirection via image tag in quirks and IE8
2864	function createArrow(img, tooltip)
2865	{
2866		var arrow = null;
2867		arrow = mxUtils.createImage(img.src);
2868		arrow.style.width = img.width + 'px';
2869		arrow.style.height = img.height + 'px';
2870
2871		if (tooltip != null)
2872		{
2873			arrow.setAttribute('title', tooltip);
2874		}
2875
2876		mxUtils.setOpacity(arrow, (img == this.refreshTarget) ? 30 : 20);
2877		arrow.style.position = 'absolute';
2878		arrow.style.cursor = 'crosshair';
2879
2880		return arrow;
2881	};
2882
2883	var currentTargetState = null;
2884	var currentStateHandle = null;
2885	var currentStyleTarget = null;
2886	var activeTarget = false;
2887
2888	var arrowUp = createArrow(this.triangleUp, mxResources.get('connect'));
2889	var arrowRight = createArrow(this.triangleRight, mxResources.get('connect'));
2890	var arrowDown = createArrow(this.triangleDown, mxResources.get('connect'));
2891	var arrowLeft = createArrow(this.triangleLeft, mxResources.get('connect'));
2892	var styleTarget = createArrow(this.refreshTarget, mxResources.get('replace'));
2893	// Workaround for actual parentNode not being updated in old IE
2894	var styleTargetParent = null;
2895	var roundSource = createArrow(this.roundDrop);
2896	var roundTarget = createArrow(this.roundDrop);
2897	var direction = mxConstants.DIRECTION_NORTH;
2898	var activeArrow = null;
2899
2900	function checkArrow(x, y, bounds, arrow)
2901	{
2902		if (arrow.parentNode != null)
2903		{
2904			if (mxUtils.contains(bounds, x, y))
2905			{
2906				mxUtils.setOpacity(arrow, 100);
2907				activeArrow = arrow;
2908			}
2909			else
2910			{
2911				mxUtils.setOpacity(arrow, (arrow == styleTarget) ? 30 : 20);
2912			}
2913		}
2914
2915		return bounds;
2916	};
2917
2918	// Hides guides and preview if target is active
2919	var dsCreatePreviewElement = dragSource.createPreviewElement;
2920
2921	// Stores initial size of preview element
2922	dragSource.createPreviewElement = function(graph)
2923	{
2924		var elt = dsCreatePreviewElement.apply(this, arguments);
2925
2926		// Pass-through events required to tooltip on replace shape
2927		if (mxClient.IS_SVG)
2928		{
2929			elt.style.pointerEvents = 'none';
2930		}
2931
2932		this.previewElementWidth = elt.style.width;
2933		this.previewElementHeight = elt.style.height;
2934
2935		return elt;
2936	};
2937
2938	// Shows/hides hover icons
2939	var dragEnter = dragSource.dragEnter;
2940	dragSource.dragEnter = function(graph, evt)
2941	{
2942		if (ui.hoverIcons != null)
2943		{
2944			ui.hoverIcons.setDisplay('none');
2945		}
2946
2947		dragEnter.apply(this, arguments);
2948	};
2949
2950	var dragExit = dragSource.dragExit;
2951	dragSource.dragExit = function(graph, evt)
2952	{
2953		if (ui.hoverIcons != null)
2954		{
2955			ui.hoverIcons.setDisplay('');
2956		}
2957
2958		dragExit.apply(this, arguments);
2959	};
2960
2961	dragSource.dragOver = function(graph, evt)
2962	{
2963		mxDragSource.prototype.dragOver.apply(this, arguments);
2964
2965		if (this.currentGuide != null && activeArrow != null)
2966		{
2967			this.currentGuide.hide();
2968		}
2969
2970		if (this.previewElement != null)
2971		{
2972			var view = graph.view;
2973
2974			if (currentStyleTarget != null && activeArrow == styleTarget)
2975			{
2976				this.previewElement.style.display = (graph.model.isEdge(currentStyleTarget.cell)) ? 'none' : '';
2977
2978				this.previewElement.style.left = currentStyleTarget.x + 'px';
2979				this.previewElement.style.top = currentStyleTarget.y + 'px';
2980				this.previewElement.style.width = currentStyleTarget.width + 'px';
2981				this.previewElement.style.height = currentStyleTarget.height + 'px';
2982			}
2983			else if (currentTargetState != null && activeArrow != null)
2984			{
2985				if (dragSource.currentHighlight != null && dragSource.currentHighlight.state != null)
2986				{
2987					dragSource.currentHighlight.hide();
2988				}
2989
2990				var index = (graph.model.isEdge(currentTargetState.cell) || freeSourceEdge == null) ? firstVertex : freeSourceEdge;
2991				var geo = sidebar.getDropAndConnectGeometry(currentTargetState.cell, cells[index], direction, cells);
2992				var geo2 = (!graph.model.isEdge(currentTargetState.cell)) ? graph.getCellGeometry(currentTargetState.cell) : null;
2993				var geo3 = graph.getCellGeometry(cells[index]);
2994				var parent = graph.model.getParent(currentTargetState.cell);
2995				var dx = view.translate.x * view.scale;
2996				var dy = view.translate.y * view.scale;
2997
2998				if (geo2 != null && !geo2.relative && graph.model.isVertex(parent) && parent != view.currentRoot)
2999				{
3000					var pState = view.getState(parent);
3001
3002					dx = pState.x;
3003					dy = pState.y;
3004				}
3005
3006				var dx2 = geo3.x;
3007				var dy2 = geo3.y;
3008
3009				// Ignores geometry of edges
3010				if (graph.model.isEdge(cells[index]))
3011				{
3012					dx2 = 0;
3013					dy2 = 0;
3014				}
3015
3016				// Shows preview at drop location
3017				this.previewElement.style.left = ((geo.x - dx2) * view.scale + dx) + 'px';
3018				this.previewElement.style.top = ((geo.y - dy2) * view.scale + dy) + 'px';
3019
3020				if (cells.length == 1)
3021				{
3022					this.previewElement.style.width = (geo.width * view.scale) + 'px';
3023					this.previewElement.style.height = (geo.height * view.scale) + 'px';
3024				}
3025
3026				this.previewElement.style.display = '';
3027			}
3028			else if (dragSource.currentHighlight.state != null &&
3029				graph.model.isEdge(dragSource.currentHighlight.state.cell))
3030			{
3031				// Centers drop cells when splitting edges
3032				this.previewElement.style.left = Math.round(parseInt(this.previewElement.style.left) -
3033					bounds.width * view.scale / 2) + 'px';
3034				this.previewElement.style.top = Math.round(parseInt(this.previewElement.style.top) -
3035					bounds.height * view.scale / 2) + 'px';
3036			}
3037			else
3038			{
3039				this.previewElement.style.width = this.previewElementWidth;
3040				this.previewElement.style.height = this.previewElementHeight;
3041				this.previewElement.style.display = '';
3042			}
3043		}
3044	};
3045
3046	var startTime = new Date().getTime();
3047	var timeOnTarget = 0;
3048	var prev = null;
3049
3050	// Gets source cell style to compare shape below
3051	var sourceCellStyle = this.editorUi.editor.graph.getCellStyle(cells[0]);
3052
3053	// Allows drop into cell only if target is a valid root
3054	dragSource.getDropTarget = mxUtils.bind(this, function(graph, x, y, evt)
3055	{
3056		// Alt means no targets at all
3057		// LATER: Show preview where result will go
3058		var cell = (!mxEvent.isAltDown(evt) && cells != null) ?
3059			graph.getCellAt(x, y, null, null, null, function(state, x, y)
3060			{
3061				return graph.isContainer(state.cell);
3062			}) : null;
3063
3064		// Uses connectable parent vertex if one exists
3065		if (cell != null && !this.graph.isCellConnectable(cell) &&
3066			!this.graph.model.isEdge(cell))
3067		{
3068			var parent = this.graph.getModel().getParent(cell);
3069
3070			if (this.graph.getModel().isVertex(parent) &&
3071				this.graph.isCellConnectable(parent))
3072			{
3073				cell = parent;
3074			}
3075		}
3076
3077		// Ignores locked cells
3078		if (graph.isCellLocked(cell))
3079		{
3080			cell = null;
3081		}
3082
3083		var state = graph.view.getState(cell);
3084		activeArrow = null;
3085		var bbox = null;
3086
3087		// Time on target
3088		if (prev != state)
3089		{
3090			startTime = new Date().getTime();
3091			timeOnTarget = 0;
3092			prev = state;
3093
3094			if (this.updateThread != null)
3095			{
3096				window.clearTimeout(this.updateThread);
3097			}
3098
3099			if (state != null)
3100			{
3101				this.updateThread = window.setTimeout(function()
3102				{
3103					if (activeArrow == null)
3104					{
3105						prev = state;
3106						dragSource.getDropTarget(graph, x, y, evt);
3107					}
3108				}, this.dropTargetDelay + 10);
3109			}
3110		}
3111		else
3112		{
3113			timeOnTarget = new Date().getTime() - startTime;
3114		}
3115
3116		// Shift means disabled, delayed on cells with children, shows after this.dropTargetDelay, hides after 2500ms
3117		if (dropStyleEnabled && (timeOnTarget < 2500) && state != null && !mxEvent.isShiftDown(evt) &&
3118			// If shape is equal or target has no stroke, fill and gradient then use longer delay except for images
3119			(((mxUtils.getValue(state.style, mxConstants.STYLE_SHAPE) != mxUtils.getValue(sourceCellStyle, mxConstants.STYLE_SHAPE) &&
3120			(mxUtils.getValue(state.style, mxConstants.STYLE_STROKECOLOR, mxConstants.NONE) != mxConstants.NONE ||
3121			mxUtils.getValue(state.style, mxConstants.STYLE_FILLCOLOR, mxConstants.NONE) != mxConstants.NONE ||
3122			mxUtils.getValue(state.style, mxConstants.STYLE_GRADIENTCOLOR, mxConstants.NONE) != mxConstants.NONE)) ||
3123			mxUtils.getValue(sourceCellStyle, mxConstants.STYLE_SHAPE) == 'image') ||
3124			timeOnTarget > 1500 || graph.model.isEdge(state.cell)) && (timeOnTarget > this.dropTargetDelay) &&
3125			!this.isDropStyleTargetIgnored(state) && ((graph.model.isVertex(state.cell) && firstVertex != null) ||
3126			(graph.model.isEdge(state.cell) && graph.model.isEdge(cells[0]))))
3127		{
3128			if (graph.isCellEditable(state.cell))
3129			{
3130				currentStyleTarget = state;
3131				var tmp = (graph.model.isEdge(state.cell)) ? graph.view.getPoint(state) :
3132					new mxPoint(state.getCenterX(), state.getCenterY());
3133				tmp = new mxRectangle(tmp.x - this.refreshTarget.width / 2, tmp.y - this.refreshTarget.height / 2,
3134					this.refreshTarget.width, this.refreshTarget.height);
3135
3136				styleTarget.style.left = Math.floor(tmp.x) + 'px';
3137				styleTarget.style.top = Math.floor(tmp.y) + 'px';
3138
3139				if (styleTargetParent == null)
3140				{
3141					graph.container.appendChild(styleTarget);
3142					styleTargetParent = styleTarget.parentNode;
3143				}
3144
3145				checkArrow(x, y, tmp, styleTarget);
3146			}
3147		}
3148		// Does not reset on ignored edges
3149		else if (currentStyleTarget == null || !mxUtils.contains(currentStyleTarget, x, y) ||
3150			(timeOnTarget > 1500 && !mxEvent.isShiftDown(evt)))
3151		{
3152			currentStyleTarget = null;
3153
3154			if (styleTargetParent != null)
3155			{
3156				styleTarget.parentNode.removeChild(styleTarget);
3157				styleTargetParent = null;
3158			}
3159		}
3160		else if (currentStyleTarget != null && styleTargetParent != null)
3161		{
3162			// Sets active Arrow as side effect
3163			var tmp = (graph.model.isEdge(currentStyleTarget.cell)) ? graph.view.getPoint(currentStyleTarget) : new mxPoint(currentStyleTarget.getCenterX(), currentStyleTarget.getCenterY());
3164			tmp = new mxRectangle(tmp.x - this.refreshTarget.width / 2, tmp.y - this.refreshTarget.height / 2,
3165				this.refreshTarget.width, this.refreshTarget.height);
3166			checkArrow(x, y, tmp, styleTarget);
3167		}
3168
3169		// Checks if inside bounds
3170		if (activeTarget && currentTargetState != null && !mxEvent.isAltDown(evt) && activeArrow == null)
3171		{
3172			// LATER: Use hit-detection for edges
3173			bbox = mxRectangle.fromRectangle(currentTargetState);
3174
3175			if (graph.model.isEdge(currentTargetState.cell))
3176			{
3177				var pts = currentTargetState.absolutePoints;
3178
3179				if (roundSource.parentNode != null)
3180				{
3181					var p0 = pts[0];
3182					bbox.add(checkArrow(x, y, new mxRectangle(p0.x - this.roundDrop.width / 2,
3183						p0.y - this.roundDrop.height / 2, this.roundDrop.width, this.roundDrop.height), roundSource));
3184				}
3185
3186				if (roundTarget.parentNode != null)
3187				{
3188					var pe = pts[pts.length - 1];
3189					bbox.add(checkArrow(x, y, new mxRectangle(pe.x - this.roundDrop.width / 2,
3190						pe.y - this.roundDrop.height / 2,
3191						this.roundDrop.width, this.roundDrop.height), roundTarget));
3192				}
3193			}
3194			else
3195			{
3196				var bds = mxRectangle.fromRectangle(currentTargetState);
3197
3198				// Uses outer bounding box to take rotation into account
3199				if (currentTargetState.shape != null && currentTargetState.shape.boundingBox != null)
3200				{
3201					bds = mxRectangle.fromRectangle(currentTargetState.shape.boundingBox);
3202				}
3203
3204				bds.grow(this.graph.tolerance);
3205				bds.grow(HoverIcons.prototype.arrowSpacing);
3206
3207				var handler = this.graph.selectionCellsHandler.getHandler(currentTargetState.cell);
3208
3209				if (handler != null)
3210				{
3211					bds.x -= handler.horizontalOffset / 2;
3212					bds.y -= handler.verticalOffset / 2;
3213					bds.width += handler.horizontalOffset;
3214					bds.height += handler.verticalOffset;
3215
3216					// Adds bounding box of rotation handle to avoid overlap
3217					if (handler.rotationShape != null && handler.rotationShape.node != null &&
3218						handler.rotationShape.node.style.visibility != 'hidden' &&
3219						handler.rotationShape.node.style.display != 'none' &&
3220						handler.rotationShape.boundingBox != null)
3221					{
3222						bds.add(handler.rotationShape.boundingBox);
3223					}
3224				}
3225
3226				bbox.add(checkArrow(x, y, new mxRectangle(currentTargetState.getCenterX() - this.triangleUp.width / 2,
3227					bds.y - this.triangleUp.height, this.triangleUp.width, this.triangleUp.height), arrowUp));
3228				bbox.add(checkArrow(x, y, new mxRectangle(bds.x + bds.width,
3229					currentTargetState.getCenterY() - this.triangleRight.height / 2,
3230					this.triangleRight.width, this.triangleRight.height), arrowRight));
3231				bbox.add(checkArrow(x, y, new mxRectangle(currentTargetState.getCenterX() - this.triangleDown.width / 2,
3232						bds.y + bds.height, this.triangleDown.width, this.triangleDown.height), arrowDown));
3233				bbox.add(checkArrow(x, y, new mxRectangle(bds.x - this.triangleLeft.width,
3234						currentTargetState.getCenterY() - this.triangleLeft.height / 2,
3235						this.triangleLeft.width, this.triangleLeft.height), arrowLeft));
3236			}
3237
3238			// Adds tolerance
3239			if (bbox != null)
3240			{
3241				bbox.grow(10);
3242			}
3243		}
3244
3245		direction = mxConstants.DIRECTION_NORTH;
3246
3247		if (activeArrow == arrowRight)
3248		{
3249			direction = mxConstants.DIRECTION_EAST;
3250		}
3251		else if (activeArrow == arrowDown || activeArrow == roundTarget)
3252		{
3253			direction = mxConstants.DIRECTION_SOUTH;
3254		}
3255		else if (activeArrow == arrowLeft)
3256		{
3257			direction = mxConstants.DIRECTION_WEST;
3258		}
3259
3260		if (currentStyleTarget != null && activeArrow == styleTarget)
3261		{
3262			state = currentStyleTarget;
3263		}
3264
3265		var validTarget = (firstVertex == null || graph.isCellConnectable(cells[firstVertex])) &&
3266			((graph.model.isEdge(cell) && firstVertex != null) ||
3267			(graph.model.isVertex(cell) && graph.isCellConnectable(cell)));
3268
3269		// Drop arrows shown after this.dropTargetDelay, hidden after 5 secs, switches arrows after 500ms
3270		if ((currentTargetState != null && timeOnTarget >= 5000) ||
3271			(currentTargetState != state &&
3272			(bbox == null || !mxUtils.contains(bbox, x, y) ||
3273			(timeOnTarget > 500 && activeArrow == null && validTarget))))
3274		{
3275			activeTarget = false;
3276			currentTargetState = ((timeOnTarget < 5000 && timeOnTarget > this.dropTargetDelay) ||
3277				graph.model.isEdge(cell)) ? state : null;
3278
3279			if (currentTargetState != null && validTarget)
3280			{
3281				var elts = [roundSource, roundTarget, arrowUp, arrowRight, arrowDown, arrowLeft];
3282
3283				for (var i = 0; i < elts.length; i++)
3284				{
3285					if (elts[i].parentNode != null)
3286					{
3287						elts[i].parentNode.removeChild(elts[i]);
3288					}
3289				}
3290
3291				if (graph.model.isEdge(cell))
3292				{
3293					var pts = state.absolutePoints;
3294
3295					if (pts != null)
3296					{
3297						var p0 = pts[0];
3298						var pe = pts[pts.length - 1];
3299						var tol = graph.tolerance;
3300						var box = new mxRectangle(x - tol, y - tol, 2 * tol, 2 * tol);
3301
3302						roundSource.style.left = Math.floor(p0.x - this.roundDrop.width / 2) + 'px';
3303						roundSource.style.top = Math.floor(p0.y - this.roundDrop.height / 2) + 'px';
3304
3305						roundTarget.style.left = Math.floor(pe.x - this.roundDrop.width / 2) + 'px';
3306						roundTarget.style.top = Math.floor(pe.y - this.roundDrop.height / 2) + 'px';
3307
3308						if (graph.model.getTerminal(cell, true) == null)
3309						{
3310							graph.container.appendChild(roundSource);
3311						}
3312
3313						if (graph.model.getTerminal(cell, false) == null)
3314						{
3315							graph.container.appendChild(roundTarget);
3316						}
3317					}
3318				}
3319				else
3320				{
3321					var bds = mxRectangle.fromRectangle(state);
3322
3323					// Uses outer bounding box to take rotation into account
3324					if (state.shape != null && state.shape.boundingBox != null)
3325					{
3326						bds = mxRectangle.fromRectangle(state.shape.boundingBox);
3327					}
3328
3329					bds.grow(this.graph.tolerance);
3330					bds.grow(HoverIcons.prototype.arrowSpacing);
3331
3332					var handler = this.graph.selectionCellsHandler.getHandler(state.cell);
3333
3334					if (handler != null)
3335					{
3336						bds.x -= handler.horizontalOffset / 2;
3337						bds.y -= handler.verticalOffset / 2;
3338						bds.width += handler.horizontalOffset;
3339						bds.height += handler.verticalOffset;
3340
3341						// Adds bounding box of rotation handle to avoid overlap
3342						if (handler.rotationShape != null && handler.rotationShape.node != null &&
3343							handler.rotationShape.node.style.visibility != 'hidden' &&
3344							handler.rotationShape.node.style.display != 'none' &&
3345							handler.rotationShape.boundingBox != null)
3346						{
3347							bds.add(handler.rotationShape.boundingBox);
3348						}
3349					}
3350
3351					arrowUp.style.left = Math.floor(state.getCenterX() - this.triangleUp.width / 2) + 'px';
3352					arrowUp.style.top = Math.floor(bds.y - this.triangleUp.height) + 'px';
3353
3354					arrowRight.style.left = Math.floor(bds.x + bds.width) + 'px';
3355					arrowRight.style.top = Math.floor(state.getCenterY() - this.triangleRight.height / 2) + 'px';
3356
3357					arrowDown.style.left = arrowUp.style.left
3358					arrowDown.style.top = Math.floor(bds.y + bds.height) + 'px';
3359
3360					arrowLeft.style.left = Math.floor(bds.x - this.triangleLeft.width) + 'px';
3361					arrowLeft.style.top = arrowRight.style.top;
3362
3363					if (state.style['portConstraint'] != 'eastwest')
3364					{
3365						graph.container.appendChild(arrowUp);
3366						graph.container.appendChild(arrowDown);
3367					}
3368
3369					graph.container.appendChild(arrowRight);
3370					graph.container.appendChild(arrowLeft);
3371				}
3372
3373				// Hides handle for cell under mouse
3374				if (state != null)
3375				{
3376					currentStateHandle = graph.selectionCellsHandler.getHandler(state.cell);
3377
3378					if (currentStateHandle != null && currentStateHandle.setHandlesVisible != null)
3379					{
3380						currentStateHandle.setHandlesVisible(false);
3381					}
3382				}
3383
3384				activeTarget = true;
3385			}
3386			else
3387			{
3388				var elts = [roundSource, roundTarget, arrowUp, arrowRight, arrowDown, arrowLeft];
3389
3390				for (var i = 0; i < elts.length; i++)
3391				{
3392					if (elts[i].parentNode != null)
3393					{
3394						elts[i].parentNode.removeChild(elts[i]);
3395					}
3396				}
3397			}
3398		}
3399
3400		if (!activeTarget && currentStateHandle != null)
3401		{
3402			currentStateHandle.setHandlesVisible(true);
3403		}
3404
3405		// Handles drop target
3406		var target = ((!mxEvent.isAltDown(evt) || mxEvent.isShiftDown(evt)) &&
3407			!(currentStyleTarget != null && activeArrow == styleTarget)) ?
3408			mxDragSource.prototype.getDropTarget.apply(this, arguments) : null;
3409		var model = graph.getModel();
3410
3411		if (target != null)
3412		{
3413			if (activeArrow != null || !graph.isSplitTarget(target, cells, evt))
3414			{
3415				// Selects parent group as drop target
3416				while (target != null && !graph.isValidDropTarget(target, cells, evt) &&
3417					model.isVertex(model.getParent(target)))
3418				{
3419					target = model.getParent(target);
3420				}
3421
3422				if (target != null && (graph.view.currentRoot == target ||
3423					(!graph.isValidRoot(target) &&
3424					graph.getModel().getChildCount(target) == 0) ||
3425					graph.isCellLocked(target) || model.isEdge(target) ||
3426					!graph.isValidDropTarget(target, cells, evt)))
3427				{
3428					target = null;
3429				}
3430			}
3431		}
3432
3433		if (graph.isCellLocked(target))
3434		{
3435			target = null;
3436		}
3437
3438		return target;
3439	});
3440
3441	dragSource.stopDrag = function()
3442	{
3443		mxDragSource.prototype.stopDrag.apply(this, arguments);
3444
3445		var elts = [roundSource, roundTarget, styleTarget, arrowUp, arrowRight, arrowDown, arrowLeft];
3446
3447		for (var i = 0; i < elts.length; i++)
3448		{
3449			if (elts[i].parentNode != null)
3450			{
3451				elts[i].parentNode.removeChild(elts[i]);
3452			}
3453		}
3454
3455		if (currentTargetState != null && currentStateHandle != null)
3456		{
3457			currentStateHandle.reset();
3458		}
3459
3460		currentStateHandle = null;
3461		currentTargetState = null;
3462		currentStyleTarget = null;
3463		styleTargetParent = null;
3464		activeArrow = null;
3465	};
3466
3467	return dragSource;
3468};
3469
3470/**
3471 * Adds a handler for inserting the cell with a single click.
3472 */
3473Sidebar.prototype.itemClicked = function(cells, ds, evt, elt)
3474{
3475	var graph = this.editorUi.editor.graph;
3476	graph.container.focus();
3477
3478	// Alt+Click inserts and connects
3479	if (mxEvent.isAltDown(evt) && graph.getSelectionCount() == 1 &&
3480		graph.model.isVertex(graph.getSelectionCell()))
3481	{
3482		var firstVertex = null;
3483
3484		for (var i = 0; i < cells.length && firstVertex == null; i++)
3485		{
3486			if (graph.model.isVertex(cells[i]))
3487			{
3488				firstVertex = i;
3489			}
3490		}
3491
3492		if (firstVertex != null)
3493		{
3494			graph.setSelectionCells(this.dropAndConnect(graph.getSelectionCell(), cells,
3495				(mxEvent.isMetaDown(evt) || mxEvent.isControlDown(evt)) ?
3496				(mxEvent.isShiftDown(evt) ? mxConstants.DIRECTION_WEST : mxConstants.DIRECTION_NORTH) :
3497				(mxEvent.isShiftDown(evt) ? mxConstants.DIRECTION_EAST : mxConstants.DIRECTION_SOUTH),
3498				firstVertex, evt));
3499			graph.scrollCellToVisible(graph.getSelectionCell());
3500		}
3501	}
3502	// Shift+Click updates shape
3503	else if (mxEvent.isShiftDown(evt) && !graph.isSelectionEmpty())
3504	{
3505		var temp = graph.getEditableCells(graph.getSelectionCells());
3506		this.updateShapes(cells[0], temp);
3507		graph.scrollCellToVisible(temp);
3508	}
3509	else
3510	{
3511		var pt = (mxEvent.isAltDown(evt)) ? graph.getFreeInsertPoint() :
3512			graph.getCenterInsertPoint(graph.getBoundingBoxFromGeometry(cells, true));
3513		ds.drop(graph, evt, null, pt.x, pt.y, true);
3514	}
3515};
3516
3517/**
3518 * Adds a handler for inserting the cell with a single click.
3519 */
3520Sidebar.prototype.addClickHandler = function(elt, ds, cells)
3521{
3522	var graph = this.editorUi.editor.graph;
3523	var oldMouseDown = ds.mouseDown;
3524	var oldMouseMove = ds.mouseMove;
3525	var oldMouseUp = ds.mouseUp;
3526	var tol = graph.tolerance;
3527	var first = null;
3528	var sb = this;
3529
3530	ds.mouseDown =function(evt)
3531	{
3532		oldMouseDown.apply(this, arguments);
3533		first = new mxPoint(mxEvent.getClientX(evt), mxEvent.getClientY(evt));
3534
3535		if (this.dragElement != null)
3536		{
3537			this.dragElement.style.display = 'none';
3538			mxUtils.setOpacity(elt, 50);
3539		}
3540	};
3541
3542	ds.mouseMove = function(evt)
3543	{
3544		if (this.dragElement != null && this.dragElement.style.display == 'none' &&
3545			first != null && (Math.abs(first.x - mxEvent.getClientX(evt)) > tol ||
3546			Math.abs(first.y - mxEvent.getClientY(evt)) > tol))
3547		{
3548			this.dragElement.style.display = '';
3549			mxUtils.setOpacity(elt, 100);
3550		}
3551
3552		oldMouseMove.apply(this, arguments);
3553	};
3554
3555	ds.mouseUp = function(evt)
3556	{
3557		try
3558		{
3559			if (!mxEvent.isPopupTrigger(evt) && this.currentGraph == null &&
3560				this.dragElement != null && this.dragElement.style.display == 'none')
3561			{
3562				sb.itemClicked(cells, ds, evt, elt);
3563			}
3564
3565			oldMouseUp.apply(ds, arguments);
3566			mxUtils.setOpacity(elt, 100);
3567			first = null;
3568
3569			// Blocks tooltips on this element after single click
3570			sb.currentElt = elt;
3571		}
3572		catch (e)
3573		{
3574			ds.reset();
3575			sb.editorUi.handleError(e);
3576		}
3577	};
3578};
3579
3580/**
3581 * Creates a drop handler for inserting the given cells.
3582 */
3583Sidebar.prototype.createVertexTemplateEntry = function(style, width, height, value, title, showLabel, showTitle, tags)
3584{
3585	if (tags != null && title != null)
3586	{
3587		tags += ' ' + title;
3588	}
3589
3590	tags = (tags != null && tags.length > 0) ? tags : ((title != null) ? title.toLowerCase() : '');
3591
3592	return this.addEntry(tags, mxUtils.bind(this, function()
3593 	{
3594 		return this.createVertexTemplate(style, width, height, value, title, showLabel, showTitle);
3595 	}));
3596}
3597
3598/**
3599 * Creates a drop handler for inserting the given cells.
3600 */
3601Sidebar.prototype.createVertexTemplate = function(style, width, height, value, title, showLabel, showTitle, allowCellsInserted, showTooltip)
3602{
3603	var cells = [new mxCell((value != null) ? value : '', new mxGeometry(0, 0, width, height), style)];
3604	cells[0].vertex = true;
3605
3606	return this.createVertexTemplateFromCells(cells, width, height, title, showLabel, showTitle, allowCellsInserted, showTooltip);
3607};
3608
3609/**
3610 * Creates a drop handler for inserting the given cells.
3611 */
3612Sidebar.prototype.createVertexTemplateFromData = function(data, width, height, title, showLabel, showTitle, allowCellsInserted, showTooltip)
3613{
3614	var doc = mxUtils.parseXml(Graph.decompress(data));
3615	var codec = new mxCodec(doc);
3616
3617	var model = new mxGraphModel();
3618	codec.decode(doc.documentElement, model);
3619
3620	var cells = this.graph.cloneCells(model.root.getChildAt(0).children);
3621
3622	return this.createVertexTemplateFromCells(cells, width, height, title, showLabel, showTitle, allowCellsInserted, showTooltip);
3623};
3624
3625/**
3626 * Creates a drop handler for inserting the given cells.
3627 */
3628Sidebar.prototype.createVertexTemplateFromCells = function(cells, width, height, title, showLabel, showTitle, allowCellsInserted, showTooltip)
3629{
3630	// Use this line to convert calls to this function with lots of boilerplate code for creating cells
3631	//console.trace('xml', Graph.compress(mxUtils.getXml(this.graph.encodeCells(cells))), cells);
3632	return this.createItem(cells, title, showLabel, showTitle, width, height, allowCellsInserted, showTooltip);
3633};
3634
3635/**
3636 *
3637 */
3638Sidebar.prototype.createEdgeTemplateEntry = function(style, width, height, value, title, showLabel, tags, allowCellsInserted, showTooltip)
3639{
3640	tags = (tags != null && tags.length > 0) ? tags : title.toLowerCase();
3641
3642 	return this.addEntry(tags, mxUtils.bind(this, function()
3643 	{
3644 		return this.createEdgeTemplate(style, width, height, value, title, showLabel, allowCellsInserted, showTooltip);
3645 	}));
3646};
3647
3648/**
3649 * Creates a drop handler for inserting the given cells.
3650 */
3651Sidebar.prototype.createEdgeTemplate = function(style, width, height, value, title, showLabel, allowCellsInserted, showTooltip)
3652{
3653	var cell = new mxCell((value != null) ? value : '', new mxGeometry(0, 0, width, height), style);
3654	cell.geometry.setTerminalPoint(new mxPoint(0, height), true);
3655	cell.geometry.setTerminalPoint(new mxPoint(width, 0), false);
3656	cell.geometry.relative = true;
3657	cell.edge = true;
3658
3659	return this.createEdgeTemplateFromCells([cell], width, height, title, showLabel, allowCellsInserted, showTooltip);
3660};
3661
3662/**
3663 * Creates a drop handler for inserting the given cells.
3664 */
3665Sidebar.prototype.createEdgeTemplateFromCells = function(cells, width, height, title, showLabel, allowCellsInserted, showTooltip, showTitle)
3666{
3667	return this.createItem(cells, title, showLabel, (showTitle != null) ? showTitle : true, width, height, allowCellsInserted, showTooltip);
3668};
3669
3670/**
3671 * Adds the given palette.
3672 */
3673Sidebar.prototype.addPaletteFunctions = function(id, title, expanded, fns)
3674{
3675	this.addPalette(id, title, expanded, mxUtils.bind(this, function(content)
3676	{
3677		for (var i = 0; i < fns.length; i++)
3678		{
3679			content.appendChild(fns[i](content));
3680		}
3681	}));
3682};
3683
3684/**
3685 * Adds the given palette.
3686 */
3687Sidebar.prototype.addPalette = function(id, title, expanded, onInit)
3688{
3689	var elt = this.createTitle(title);
3690	this.container.appendChild(elt);
3691
3692	var div = document.createElement('div');
3693	div.className = 'geSidebar';
3694
3695	// Disables built-in pan and zoom in IE10 and later
3696	if (mxClient.IS_POINTER)
3697	{
3698		div.style.touchAction = 'none';
3699	}
3700
3701	if (expanded)
3702	{
3703		onInit(div);
3704		onInit = null;
3705	}
3706	else
3707	{
3708		div.style.display = 'none';
3709	}
3710
3711    this.addFoldingHandler(elt, div, onInit);
3712
3713	var outer = document.createElement('div');
3714    outer.appendChild(div);
3715    this.container.appendChild(outer);
3716
3717    // Keeps references to the DOM nodes
3718    if (id != null)
3719    {
3720    	this.palettes[id] = [elt, outer];
3721    }
3722
3723    return div;
3724};
3725
3726/**
3727 * Create the given title element.
3728 */
3729Sidebar.prototype.addFoldingHandler = function(title, content, funct)
3730{
3731	var initialized = false;
3732
3733	// Avoids mixed content warning in IE6-8
3734	if (!mxClient.IS_IE || document.documentMode >= 8)
3735	{
3736		title.style.backgroundImage = (content.style.display == 'none') ?
3737			'url(\'' + this.collapsedImage + '\')' : 'url(\'' + this.expandedImage + '\')';
3738	}
3739
3740	title.style.backgroundRepeat = 'no-repeat';
3741	title.style.backgroundPosition = '0% 50%';
3742
3743	mxEvent.addListener(title, 'click', mxUtils.bind(this, function(evt)
3744	{
3745		if (content.style.display == 'none')
3746		{
3747			if (!initialized)
3748			{
3749				initialized = true;
3750
3751				if (funct != null)
3752				{
3753					// Wait cursor does not show up on Mac
3754					title.style.cursor = 'wait';
3755					var prev = title.innerHTML;
3756					title.innerHTML = mxResources.get('loading') + '...';
3757
3758					window.setTimeout(function()
3759					{
3760						content.style.display = 'block';
3761						title.style.cursor = '';
3762						title.innerHTML = prev;
3763
3764						var fo = mxClient.NO_FO;
3765						mxClient.NO_FO = Editor.prototype.originalNoForeignObject;
3766						funct(content, title);
3767						mxClient.NO_FO = fo;
3768					}, (mxClient.IS_FF) ? 20 : 0);
3769				}
3770				else
3771				{
3772					content.style.display = 'block';
3773				}
3774			}
3775			else
3776			{
3777				content.style.display = 'block';
3778			}
3779
3780			title.style.backgroundImage = 'url(\'' + this.expandedImage + '\')';
3781		}
3782		else
3783		{
3784			title.style.backgroundImage = 'url(\'' + this.collapsedImage + '\')';
3785			content.style.display = 'none';
3786		}
3787
3788		mxEvent.consume(evt);
3789	}));
3790
3791	// Prevents focus
3792	mxEvent.addListener(title, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown',
3793		mxUtils.bind(this, function(evt)
3794	{
3795		evt.preventDefault();
3796	}));
3797};
3798
3799/**
3800 * Removes the palette for the given ID.
3801 */
3802Sidebar.prototype.removePalette = function(id)
3803{
3804	var elts = this.palettes[id];
3805
3806	if (elts != null)
3807	{
3808		this.palettes[id] = null;
3809
3810		for (var i = 0; i < elts.length; i++)
3811		{
3812			this.container.removeChild(elts[i]);
3813		}
3814
3815		return true;
3816	}
3817
3818	return false;
3819};
3820
3821/**
3822 * Adds the given image palette.
3823 */
3824Sidebar.prototype.addImagePalette = function(id, title, prefix, postfix, items, titles, tags)
3825{
3826	var showTitles = titles != null;
3827	var fns = [];
3828
3829	for (var i = 0; i < items.length; i++)
3830	{
3831		(mxUtils.bind(this, function(item, title, tmpTags)
3832		{
3833			if (tmpTags == null)
3834			{
3835				var slash = item.lastIndexOf('/');
3836				var dot = item.lastIndexOf('.');
3837				tmpTags = item.substring((slash >= 0) ? slash + 1 : 0, (dot >= 0) ? dot : item.length).replace(/[-_]/g, ' ');
3838			}
3839
3840			fns.push(this.createVertexTemplateEntry('image;html=1;image=' + prefix + item + postfix,
3841				this.defaultImageWidth, this.defaultImageHeight, '', title, title != null, null, this.filterTags(tmpTags)));
3842		}))(items[i], (titles != null) ? titles[i] : null, (tags != null) ? tags[items[i]] : null);
3843	}
3844
3845	this.addPaletteFunctions(id, title, false, fns);
3846};
3847
3848/**
3849 * Creates the array of tags for the given stencil. Duplicates are allowed and will be filtered out later.
3850 */
3851Sidebar.prototype.getTagsForStencil = function(packageName, stencilName, moreTags)
3852{
3853	var tags = packageName.split('.');
3854
3855	for (var i = 1; i < tags.length; i++)
3856	{
3857		tags[i] = tags[i].replace(/_/g, ' ')
3858	}
3859
3860	tags.push(stencilName.replace(/_/g, ' '));
3861
3862	if (moreTags != null)
3863	{
3864		tags.push(moreTags);
3865	}
3866
3867	return tags.slice(1, tags.length);
3868};
3869
3870/**
3871 * Adds the given stencil palette.
3872 */
3873Sidebar.prototype.addStencilPalette = function(id, title, stencilFile, style, ignore, onInit, scale, tags, customFns, groupId)
3874{
3875	scale = (scale != null) ? scale : 1;
3876
3877	if (this.addStencilsToIndex)
3878	{
3879		// LATER: Handle asynchronous loading dependency
3880		var fns = [];
3881
3882		if (customFns != null)
3883		{
3884			for (var i = 0; i < customFns.length; i++)
3885			{
3886				fns.push(customFns[i]);
3887			}
3888		}
3889
3890		mxStencilRegistry.loadStencilSet(stencilFile, mxUtils.bind(this, function(packageName, stencilName, displayName, w, h)
3891		{
3892			if (ignore == null || mxUtils.indexOf(ignore, stencilName) < 0)
3893			{
3894				var tmp = this.getTagsForStencil(packageName, stencilName);
3895				var tmpTags = (tags != null) ? tags[stencilName] : null;
3896
3897				if (tmpTags != null)
3898				{
3899					tmp.push(tmpTags);
3900				}
3901
3902				fns.push(this.createVertexTemplateEntry('shape=' + packageName + stencilName.toLowerCase() + style,
3903					Math.round(w * scale), Math.round(h * scale), '', stencilName.replace(/_/g, ' '), null, null,
3904					this.filterTags(tmp.join(' '))));
3905			}
3906		}), true, true);
3907
3908		this.addPaletteFunctions(id, title, false, fns);
3909	}
3910	else
3911	{
3912		this.addPalette(id, title, false, mxUtils.bind(this, function(content)
3913	    {
3914			if (style == null)
3915			{
3916				style = '';
3917			}
3918
3919			if (onInit != null)
3920			{
3921				onInit.call(this, content);
3922			}
3923
3924			if (customFns != null)
3925			{
3926				for (var i = 0; i < customFns.length; i++)
3927				{
3928					customFns[i](content);
3929				}
3930			}
3931
3932			mxStencilRegistry.loadStencilSet(stencilFile, mxUtils.bind(this, function(packageName, stencilName, displayName, w, h)
3933			{
3934				if (ignore == null || mxUtils.indexOf(ignore, stencilName) < 0)
3935				{
3936					content.appendChild(this.createVertexTemplate('shape=' + packageName + stencilName.toLowerCase() + style,
3937						Math.round(w * scale), Math.round(h * scale), '', stencilName.replace(/_/g, ' '), true));
3938				}
3939			}), true);
3940	    }));
3941	}
3942};
3943
3944/**
3945 * Adds the given stencil palette.
3946 */
3947Sidebar.prototype.destroy = function()
3948{
3949	if (this.graph != null)
3950	{
3951		if (this.graph.container != null && this.graph.container.parentNode != null)
3952		{
3953			this.graph.container.parentNode.removeChild(this.graph.container);
3954		}
3955
3956		this.graph.destroy();
3957		this.graph = null;
3958	}
3959
3960	if (this.pointerUpHandler != null)
3961	{
3962		mxEvent.removeListener(document, (mxClient.IS_POINTER) ? 'pointerup' : 'mouseup', this.pointerUpHandler);
3963		this.pointerUpHandler = null;
3964	}
3965
3966	if (this.pointerDownHandler != null)
3967	{
3968		mxEvent.removeListener(document, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown', this.pointerDownHandler);
3969		this.pointerDownHandler = null;
3970	}
3971
3972	if (this.pointerMoveHandler != null)
3973	{
3974		mxEvent.removeListener(document, (mxClient.IS_POINTER) ? 'pointermove' : 'mousemove', this.pointerMoveHandler);
3975		this.pointerMoveHandler = null;
3976	}
3977
3978	if (this.pointerOutHandler != null)
3979	{
3980		mxEvent.removeListener(document, (mxClient.IS_POINTER) ? 'pointerout' : 'mouseout', this.pointerOutHandler);
3981		this.pointerOutHandler = null;
3982	}
3983};
3984