4 * Construcs a new sidebar for the given editor.
6 function Sidebar(editorUi, container) {
7 this.editorUi = editorUi;
8 this.container = container;
9 this.palettes = new Object();
10 this.showTooltips = true;
11 this.graph = new Graph(document.createElement('div'), null, null, this.editorUi
12 .editor.graph.getStylesheet());
13 this.graph.resetViewOnRootChange = false;
14 this.graph.foldingEnabled = false;
15 this.graph.setConnectable(false);
16 this.graph.autoScroll = false;
17 this.graph.setTooltips(false);
18 this.graph.setEnabled(false);
20 // Container must be in the DOM for correct HTML rendering
21 this.graph.container.style.visibility = 'hidden';
22 this.graph.container.style.position = 'absolute';
23 document.body.appendChild(this.graph.container);
25 if (!mxClient.IS_TOUCH) {
26 mxEvent.addListener(document, 'mouseup', mxUtils.bind(this, function() {
27 this.showTooltips = true;
30 // Enables tooltips after scroll
31 mxEvent.addListener(container, 'scroll', mxUtils.bind(this, function() {
32 this.showTooltips = true;
35 mxEvent.addListener(document, 'mousedown', mxUtils.bind(this, function() {
36 this.showTooltips = false;
40 mxEvent.addListener(document, 'mousemove', mxUtils.bind(this, function(evt) {
41 var src = mxEvent.getSource(evt);
44 if (src == this.currentElt) {
54 // Handles mouse leaving the window
55 mxEvent.addListener(document, 'mouseout', mxUtils.bind(this, function(evt) {
56 if (evt.toElement == null && evt.relatedTarget == null) {
64 // Pre-fetches tooltip image
65 new Image().src = IMAGE_PATH + '/tooltip.png';
69 * Adds all palettes to the sidebar.
71 Sidebar.prototype.init = function() {
72 var dir = STENCIL_PATH;
75 this.addImagePalette('entry', mxResources.get('entry'), dir + '/entry/',
76 '_128x128.png', ['start', 'finally', 'end'], [mxResources.get('start'),
77 mxResources.get('finally'), mxResources.get('end')
79 this.addImagePalette('call_management', mxResources.get('call_management'),
80 dir + '/call_management/', '_128x128.png', ['answer', 'hangup', 'dial',
81 'ext_dial', 'queue', 'voicemail'
83 ], [mxResources.get('answer'), mxResources.get('hangup'), mxResources.get(
84 'dial'), mxResources.get('ext_dial'), mxResources.get('queue'),
85 mxResources.get('voicemail')
86 // , mxResources.get('callback')
88 this.addImagePalette('variable', mxResources.get('variable'), dir +
89 '/variable/', '_128x128.png', ['set', 'math'], [mxResources.get('set'),
90 mxResources.get('math')
92 this.addImagePalette('playback', mxResources.get('playback'), dir +
93 '/playback/', '_128x128.png', ['playback', 'menu',
94 'saydigits', 'saynumber', 'sayphonetic', 'tts', 'ispeechtts', 'getdigits'
95 ], [mxResources.get('playback'), mxResources
96 .get('menu'), mxResources.get('saydigits'), mxResources.get('saynumber'),
97 mxResources.get('sayphonetic'), mxResources.get('tts'), mxResources.get('ispeechtts'), mxResources.get('getdigits')
99 this.addImagePalette('recording', mxResources.get('recording'), dir +
100 '/recording/', '_128x128.png', ['record'], [mxResources.get('record')]);
101 this.addImagePalette('integrationServer', mxResources.get('integrationServer'),
102 dir + '/integration_server/', '_128x128.png', ['database', 'ispeechasr'], [
103 mxResources.get('database'), mxResources.get('ispeechasr')
105 this.addImagePalette('callflow', mxResources.get('callflow'), dir +
106 '/callflow/', '_128x128.png', ['gotoc', 'gotoif', 'gotoiftime', 'vswitch'], [
107 mxResources.get('gotoc'), mxResources.get('gotoif'), mxResources.get(
108 'gotoiftime'), mxResources.get('vswitch')
110 this.addImagePalette('stats', mxResources.get('stats'), dir + '/stats/',
112 // 'queuelog', 'goal'
114 // mxResources.get('queuelog'),
115 // mxResources.get('goal')
117 this.addImagePalette('general', mxResources.get('general'), dir + '/general/',
118 '_128x128.png', ['noop', 'system', 'agi', 'subproject','custom_app'], [mxResources.get(
119 'noop'), mxResources.get('system'), mxResources.get('agi'), mxResources.get(
120 'subproject'),mxResources.get(
126 * Specifies if tooltips should be visible. Default is true.
128 Sidebar.prototype.enableTooltips = !mxClient.IS_TOUCH;
131 * Specifies the delay for the tooltip. Default is 16 px.
133 Sidebar.prototype.tooltipBorder = 16;
136 * Specifies the delay for the tooltip. Default is 3 px.
138 Sidebar.prototype.thumbBorder = 3;
141 * Specifies the delay for the tooltip. Default is 300 ms.
143 Sidebar.prototype.tooltipDelay = 300;
146 * Specifies if edges should be used as templates if clicked. Default is true.
148 Sidebar.prototype.installEdges = true;
151 * Specifies the URL of the gear image.
153 Sidebar.prototype.gearImage = STENCIL_PATH + '/clipart/Gear_128x128.png';
156 * Specifies the width of the thumbnails.
158 Sidebar.prototype.thumbWidth = 34;
161 * Specifies the height of the thumbnails.
163 Sidebar.prototype.thumbHeight = 34;
166 * Specifies the padding for the thumbnails. Default is 3.
168 Sidebar.prototype.thumbPadding = 2;
171 * Specifies the size of the sidebar titles.
173 Sidebar.prototype.sidebarTitleSize = 9;
176 * Specifies if titles in the sidebar should be enabled.
178 Sidebar.prototype.sidebarTitles = false;
181 * Specifies if titles in the tooltips should be enabled.
183 Sidebar.prototype.tooltipTitles = false;
186 * Adds all palettes to the sidebar.
188 Sidebar.prototype.showTooltip = function(elt, cells, title, showLabel) {
189 if (this.enableTooltips && this.showTooltips) {
190 if (this.currentElt != elt) {
191 if (this.thread != null) {
192 window.clearTimeout(this.thread);
196 var show = mxUtils.bind(this, function() {
197 // Lazy creation of the DOM nodes and graph instance
198 if (this.tooltip == null) {
199 this.tooltip = document.createElement('div');
200 this.tooltip.className = 'geSidebarTooltip';
201 document.body.appendChild(this.tooltip);
203 this.graph2 = new Graph(this.tooltip, null, null, this.editorUi.editor.graph
205 this.graph2.view.setTranslate(this.tooltipBorder, this.tooltipBorder);
206 this.graph2.resetViewOnRootChange = false;
207 this.graph2.foldingEnabled = false;
208 this.graph2.autoScroll = false;
209 this.graph2.setTooltips(false);
210 this.graph2.setConnectable(false);
211 this.graph2.setEnabled(false);
213 if (!mxClient.IS_SVG) {
214 this.graph2.view.canvas.style.position = 'relative';
217 this.tooltipImage = mxUtils.createImage(IMAGE_PATH + '/tooltip.png');
218 this.tooltipImage.style.position = 'absolute';
219 this.tooltipImage.style.width = '14px';
220 this.tooltipImage.style.height = '27px';
222 document.body.appendChild(this.tooltipImage);
225 this.tooltip.style.display = 'block';
226 this.graph2.labelsVisible = (showLabel == null || showLabel);
227 this.graph2.model.clear();
228 this.graph2.addCells(cells);
230 var bounds = this.graph2.getGraphBounds();
231 var width = bounds.width + 2 * this.tooltipBorder;
232 var height = bounds.height + 2 * this.tooltipBorder;
234 if (mxClient.IS_QUIRKS) {
237 this.tooltip.style.overflow = 'hidden';
239 this.tooltip.style.overflow = 'visible';
242 this.tooltipImage.style.visibility = 'visible';
243 this.tooltip.style.width = width + 'px';
245 // Adds title for entry
246 if (this.tooltipTitles && title != null && title.length > 0) {
247 if (this.tooltipTitle == null) {
248 this.tooltipTitle = document.createElement('div');
249 this.tooltipTitle.style.borderTop = '1px solid gray';
250 this.tooltipTitle.style.textAlign = 'center';
251 this.tooltipTitle.style.width = '100%';
253 // Oversize titles are cut-off currently. Should make tooltip wider later.
254 this.tooltipTitle.style.overflow = 'hidden';
256 if (mxClient.IS_SVG) {
257 this.tooltipTitle.style.paddingTop = '2px';
259 this.tooltipTitle.style.position = 'absolute';
260 this.tooltipTitle.style.paddingTop = '6px';
263 this.tooltip.appendChild(this.tooltipTitle);
265 this.tooltipTitle.innerHTML = '';
268 this.tooltipTitle.style.display = '';
269 mxUtils.write(this.tooltipTitle, title);
271 var dy = this.tooltipTitle.offsetHeight + 10;
274 if (mxClient.IS_SVG) {
275 this.tooltipTitle.style.marginTop = (-dy) + 'px';
278 this.tooltipTitle.style.top = (height - dy) + 'px';
280 } else if (this.tooltipTitle != null && this.tooltipTitle.parentNode !=
282 this.tooltipTitle.style.display = 'none';
285 this.tooltip.style.height = height + 'px';
286 var x0 = -Math.min(0, bounds.x - this.tooltipBorder);
287 var y0 = -Math.min(0, bounds.y - this.tooltipBorder);
289 var left = this.container.clientWidth + this.editorUi.splitSize + 3;
290 var top = Math.max(0, (this.container.offsetTop + elt.offsetTop - this.container
291 .scrollTop - height / 2 + 16));
293 if (mxClient.IS_SVG) {
294 this.graph2.view.canvas.setAttribute('transform', 'translate(' + x0 +
297 this.graph2.view.drawPane.style.left = x0 + 'px';
298 this.graph2.view.drawPane.style.top = y0 + 'px';
301 // Workaround for ignored position CSS style in IE9
302 // (changes to relative without the following line)
303 // Added width of the page-sidebar
304 left += document.getElementById('page-sidebar').offsetWidth;
305 // Added static height of the page-navbar
308 this.tooltip.style.position = 'absolute';
309 this.tooltip.style.left = left + 'px';
310 this.tooltip.style.top = top + 'px';
311 this.tooltipImage.style.left = (left - 13) + 'px';
312 this.tooltipImage.style.top = (top + height / 2 - 13) + 'px';
315 if (this.tooltip != null && this.tooltip.style.display != 'none') {
318 this.thread = window.setTimeout(show, this.tooltipDelay);
321 this.currentElt = elt;
327 * Hides the current tooltip.
329 Sidebar.prototype.hideTooltip = function() {
330 if (this.thread != null) {
331 window.clearTimeout(this.thread);
335 if (this.tooltip != null) {
336 this.tooltip.style.display = 'none';
337 this.tooltipImage.style.visibility = 'hidden';
338 this.currentElt = null;
343 * Creates and returns the given title element.
345 Sidebar.prototype.createTitle = function(label) {
346 var elt = document.createElement('a');
347 elt.setAttribute('href', 'javascript:void(0);');
348 elt.className = 'geTitle';
349 mxUtils.write(elt, label);
355 * Creates a thumbnail for the given cells.
357 Sidebar.prototype.createThumb = function(cells, width, height, parent, title,
359 this.graph.labelsVisible = (showLabel == null || showLabel);
360 this.graph.view.scaleAndTranslate(1, 0, 0);
361 this.graph.addCells(cells);
362 var bounds = this.graph.getGraphBounds();
363 var corr = this.thumbBorder;
364 var s = Math.min((width - 2) / (bounds.width - bounds.x + corr), (height - 2) /
365 (bounds.height - bounds.y + corr));
366 var x0 = -Math.min(bounds.x, 0);
367 var y0 = -Math.min(bounds.y, 0);
368 this.graph.view.scaleAndTranslate(s, x0, y0);
370 bounds = this.graph.getGraphBounds();
371 var dx = Math.max(0, Math.floor((width - bounds.width - bounds.x) / 2));
372 var dy = Math.max(0, Math.floor((height - bounds.height - bounds.y) / 2));
376 // For supporting HTML labels in IE9 standards mode the container is cloned instead
377 if (this.graph.dialect == mxConstants.DIALECT_SVG && !mxClient.NO_FO) {
378 node = this.graph.view.getCanvas().ownerSVGElement.cloneNode(true);
380 // LATER: Check if deep clone can be used for quirks if container in DOM
382 node = this.graph.container.cloneNode(false);
383 node.innerHTML = this.graph.container.innerHTML;
386 this.graph.getModel().clear();
388 // Catch-all event handling
389 if (mxClient.IS_IE6) {
390 parent.style.backgroundImage = 'url(' + this.editorUi.editor.transparentImage +
395 node.style.position = 'relative';
396 node.style.overflow = 'hidden';
397 node.style.cursor = 'pointer';
398 node.style.left = (dx + dd) + 'px';
399 node.style.top = (dy + dd) + 'px';
400 node.style.width = width + 'px';
401 node.style.height = height + 'px';
402 node.style.visibility = '';
403 node.style.minWidth = '';
404 node.style.minHeight = '';
406 parent.appendChild(node);
408 // Adds title for sidebar entries
409 if (this.sidebarTitles && title != null) {
410 var border = (mxClient.IS_QUIRKS) ? 2 * this.thumbPadding + 2 : 0;
411 parent.style.height = (this.thumbHeight + border + this.sidebarTitleSize + 8) +
414 var div = document.createElement('div');
415 div.style.fontSize = this.sidebarTitleSize + 'px';
416 div.style.textAlign = 'center';
417 div.style.whiteSpace = 'nowrap';
419 if (mxClient.IS_IE) {
420 div.style.height = (this.sidebarTitleSize + 12) + 'px';
423 div.style.paddingTop = '4px';
424 mxUtils.write(div, title);
425 parent.appendChild(div);
430 * Creates and returns a new palette item for the given image.
432 Sidebar.prototype.createItem = function(cells, title, showLabel) {
433 var elt = document.createElement('a');
434 elt.setAttribute('href', 'javascript:void(0);');
435 elt.className = 'geItem';
436 elt.style.overflow = 'hidden';
437 var border = (mxClient.IS_QUIRKS) ? 8 + 2 * this.thumbPadding : 6;
438 elt.style.width = (this.thumbWidth + border) + 'px';
439 elt.style.height = (this.thumbHeight + border) + 'px';
440 elt.style.padding = this.thumbPadding + 'px';
442 // Blocks default click action
443 mxEvent.addListener(elt, 'click', function(evt) {
444 mxEvent.consume(evt);
447 this.createThumb(cells, this.thumbWidth, this.thumbHeight, elt, title,
454 * Creates a drop handler for inserting the given cells.
456 Sidebar.prototype.createDropHandler = function(cells, allowSplit) {
457 return function(graph, evt, target, x, y) {
458 if (graph.isEnabled()) {
459 cells = graph.getImportableCells(cells);
461 if (cells.length > 0) {
462 var validDropTarget = (target != null) ?
463 graph.isValidDropTarget(target, cells, evt) : false;
466 if (target != null && !validDropTarget) {
470 // Splits the target edge or inserts into target group
471 if (allowSplit && graph.isSplitEnabled() && graph.isSplitTarget(target,
473 graph.splitEdge(target, cells, null, x, y);
475 } else if (cells.length > 0) {
476 select = graph.importCells(cells, x, y, target);
479 if (select != null && select.length > 0) {
480 graph.scrollCellToVisible(select[0]);
481 graph.setSelectionCells(select);
489 * Creates and returns a preview element for the given width and height.
491 Sidebar.prototype.createDragPreview = function(width, height) {
492 var elt = document.createElement('div');
493 elt.style.border = '1px dashed black';
494 elt.style.width = width + 'px';
495 elt.style.height = height + 'px';
501 * Creates a drag source for the given element.
503 Sidebar.prototype.createDragSource = function(elt, dropHandler, preview) {
504 var dragSource = mxUtils.makeDraggable(elt, this.editorUi.editor.graph,
506 preview, 0, 0, this.editorUi.editor.graph.autoscroll, true, true);
508 // Allows drop into cell only if target is a valid root
509 dragSource.getDropTarget = function(graph, x, y) {
510 var target = mxDragSource.prototype.getDropTarget.apply(this, arguments);
512 if (!graph.isValidRoot(target)) {
523 * Adds a handler for inserting the cell with a single click.
525 Sidebar.prototype.addClickHandler = function(elt, ds) {
526 var graph = this.editorUi.editor.graph;
529 mxEvent.addGestureListeners(elt, function(evt) {
530 first = new mxPoint(mxEvent.getClientX(evt), mxEvent.getClientY(evt));
533 var oldMouseUp = ds.mouseUp;
534 ds.mouseUp = function(evt) {
535 if (!mxEvent.isPopupTrigger(evt) && this.currentGraph == null && first !=
537 var tol = graph.tolerance;
539 if (Math.abs(first.x - mxEvent.getClientX(evt)) <= tol &&
540 Math.abs(first.y - mxEvent.getClientY(evt)) <= tol) {
541 var gs = graph.getGridSize();
542 ds.drop(graph, evt, null, gs, gs);
546 oldMouseUp.apply(this, arguments);
553 * Create xml document vertex
555 Sidebar.prototype.createXmlDocument = function(element, label, variables,
557 var doc = mxUtils.createXmlDocument();
558 var node = doc.createElement(element)
559 node.setAttribute('label', label);
561 variables.forEach(function(variable, index) {
562 node.setAttribute(variable, values[index] ? values[index] : '');
570 * Creates a drop handler for inserting the given cells.
572 Sidebar.prototype.createVertexTemplate = function(style, width, height, value,
581 variables = ['key', 'model', 'ispeech_asr_language'];
582 values = ['', 0, 'it-IT'];
585 variables = ['file_id', 'opts'];
589 variables = ['file_id', 'response', 'digit'];
590 values = ['0', '5', '1'];
593 variables = ['file_id', 'response', 'digit', 'retry', 'variable_id'];
594 values = ['0', '5', '1', '1', '0'];
597 variables = ['file_id', 'response', 'mindigit', 'maxdigit', 'retry', 'variable_id'];
598 values = ['0', '5', '1', '10', '1', '0'];
601 variables = ['application', 'options'];
605 variables = ['variable_id', 'variable_value'];
609 variables = ['odbc_id', 'query', 'variable_id'];
610 values = ['0', '', '0'];
613 variables = ['output'];
617 variables = ['context', 'extension'];
621 variables = ['variable_id', 'command'];
625 variables = ['args', 'command'];
629 variables = ['condition'];
633 variables = ['interval_id'];
636 case 'gotoifmultitime':
637 variables = ['interval_id'];
641 variables = ['variable_id'];
645 variables = ['digits', 'escape_digits'];
649 variables = ['number', 'escape_digits'];
653 variables = ['text', 'escape_digits'];
657 variables = ['file', 'timeout', 'escape_digits'];
658 values = ['', '-1', '#'];
661 variables = ['sip_id', 'timeout', 'custom_app', 'url'];
662 values = ['0', '60'];
665 variables = ['phone', 'trunk_id', 'timeout', 'opts', 'url'];
666 values = ['', '0', '60'];
669 variables = ['text', 'google_tts_language'];
673 variables = ['text', 'key', 'ispeech_tts_language'];
674 values = ['', '', 'euritalianfemale'];
677 variables = ['queue_id', 'opts', 'url', 'file_id', 'timeout', 'agi',
678 'macro', 'gosub', 'position'
680 values = ['0', '', '', '0', '300'];
683 variables = ['boxnumber', 'context', 'opts'];
684 values = ['', 'from-voicemail'];
687 variables = ['project_id'];
691 variables = ['operation', 'variable_id'];
695 variables = ['queuename', 'agent', 'queue_event', 'data1', 'data2', 'data3',
701 variables = ['goalname'];
705 variables = ['list_id'];
706 values = ['0', '{CALLERID(num)}'];
714 var node = this.createXmlDocument(value, title, variables, values);
716 //var cells = [new mxCell((value != null) ? value : '', new mxGeometry(0, 0, width, height), style)];
717 var cells = [new mxCell(node, new mxGeometry(0, 0, width, height), style)];
718 cells[0].vertex = true;
720 return this.createVertexTemplateFromCells(cells, width, height, title,
725 * Creates a drop handler for inserting the given cells.
727 Sidebar.prototype.createVertexTemplateFromCells = function(cells, width, height,
729 var elt = this.createItem(cells, title, showLabel);
730 var ds = this.createDragSource(elt, this.createDropHandler(cells, true), this
731 .createDragPreview(width, height));
732 this.addClickHandler(elt, ds);
734 // Uses guides for vertices only if enabled in graph
735 ds.isGuidesEnabled = mxUtils.bind(this, function() {
736 return this.editorUi.editor.graph.graphHandler.guidesEnabled;
739 // Shows a tooltip with the rendered cell
741 mxEvent.addListener(elt, 'mousemove', mxUtils.bind(this, function(evt) {
742 this.showTooltip(elt, cells, title, showLabel);
750 * Creates a drop handler for inserting the given cells.
752 Sidebar.prototype.createEdgeTemplate = function(style, width, height, value,
754 var cells = [new mxCell((value != null) ? value : '', new mxGeometry(0, 0,
755 width, height), style)];
756 cells[0].geometry.setTerminalPoint(new mxPoint(0, height), true);
757 cells[0].geometry.setTerminalPoint(new mxPoint(width, 0), false);
758 cells[0].geometry.relative = true;
759 cells[0].edge = true;
761 return this.createEdgeTemplateFromCells(cells, width, height, title,
766 * Creates a drop handler for inserting the given cells.
768 Sidebar.prototype.createEdgeTemplateFromCells = function(cells, width, height,
770 var elt = this.createItem(cells, title, showLabel);
771 this.createDragSource(elt, this.createDropHandler(cells, false), this.createDragPreview(
774 // Installs the default edge
775 var graph = this.editorUi.editor.graph;
776 mxEvent.addListener(elt, 'click', mxUtils.bind(this, function(evt) {
777 if (this.installEdges) {
778 graph.setDefaultEdge(cells[0]);
781 // Highlights the entry for 200ms
782 elt.style.backgroundColor = '#ffffff';
784 window.setTimeout(function() {
785 elt.style.backgroundColor = '';
788 mxEvent.consume(evt);
791 // Shows a tooltip with the rendered cell
793 mxEvent.addListener(elt, 'mousemove', mxUtils.bind(this, function(evt) {
794 this.showTooltip(elt, cells, title, showLabel);
802 * Adds the given palette.
804 Sidebar.prototype.addPalette = function(id, title, expanded, onInit) {
805 var elt = this.createTitle(title);
806 this.container.appendChild(elt);
808 var div = document.createElement('div');
809 div.className = 'geSidebar';
815 div.style.display = 'none';
818 this.addFoldingHandler(elt, div, onInit);
820 var outer = document.createElement('div');
821 outer.appendChild(div);
822 this.container.appendChild(outer);
824 // Keeps references to the DOM nodes
826 this.palettes[id] = [elt, outer];
831 * Create the given title element.
833 Sidebar.prototype.addFoldingHandler = function(title, content, funct) {
834 var initialized = false;
836 title.style.backgroundImage = (content.style.display == 'none') ?
837 'url(' + IMAGE_PATH + '/collapsed.gif)' : 'url(' + IMAGE_PATH +
839 title.style.backgroundRepeat = 'no-repeat';
840 title.style.backgroundPosition = '100% 50%';
842 mxEvent.addListener(title, 'click', function(evt) {
843 if (content.style.display == 'none') {
848 title.style.cursor = 'wait';
849 window.setTimeout(function() {
851 title.style.cursor = '';
856 title.style.backgroundImage = 'url(' + IMAGE_PATH + '/expanded.gif)';
857 content.style.display = 'block';
859 title.style.backgroundImage = 'url(' + IMAGE_PATH + '/collapsed.gif)';
860 content.style.display = 'none';
863 mxEvent.consume(evt);
868 * Removes the palette for the given ID.
870 Sidebar.prototype.removePalette = function(id) {
871 var elts = this.palettes[id];
874 this.palettes[id] = null;
876 for (var i = 0; i < elts.length; i++) {
877 this.container.removeChild(elts[i]);
887 * Adds the given image palette.
889 Sidebar.prototype.addImagePalette = function(id, title, prefix, postfix, items,
892 // Expanded Sidebar only entry
893 this.addPalette(id, title, (id === 'entry'), mxUtils.bind(this, function(
895 var showTitles = titles != null;
897 for (var i = 0; i < items.length; i++) {
898 var icon = prefix + items[i] + postfix;
899 content.appendChild(this.createVertexTemplate('image;image=' + icon, 80,
900 80, items[i], (showTitles) ? titles[i] : null, showTitles));