// jQuery UI style "widget" for displaying a graph //////////////////////////////////////////////////////////////////////////////// // // graph // $(function() { // the widget definition, where "itop" is the namespace, // "dashboard" the widget name $.widget( "itop.simple_graph", { // default options options: { align: 'center', 'vertical-align': 'middle', source_url: null, sources: {}, excluded: {}, export_as_pdf: null, page_format: { label: 'Page Format:', values: { A3: 'A3', A4: 'A4', Letter: 'Letter' }, 'default': 'A4'}, page_orientation: { label: 'Page Orientation:', values: { P: 'Portait', L: 'Landscape' }, 'default': 'L' }, labels: { export_pdf_title: 'PDF Export Options', cancel: 'Cancel', 'export': 'Export', title: 'Document Title', include_list: 'Include the list of objects', comments: 'Comments', grouping_threshold: 'Grouping Threshold', additional_context_info: 'Additional Context Info', refresh: 'Refresh', check_all: 'Check All', uncheck_all: 'Uncheck All', none_selected: 'None', nb_selected: '# selected', zoom: 'Zoom', loading: 'Loading...' }, export_as_document: null, drill_down: null, grouping_threshold: 10, excluded_classes: [], attachment_obj_class: null, attachment_obj_key: null, additional_contexts: [], context_key: '' }, // the constructor _create: function() { var me = this; this.aNodes = []; this.aEdges = []; this.fZoom = 1.0; this.xOffset = 0; this.yOffset = 0; this.xPan = 0; this.yPan = 0; this.iTextHeight = 12; this.fSliderZoom = 1.0; this.bInUpdateSliderZoom = false; this.bRedrawNeeded = false; this.oPaper = Raphael(this.element.get(0), 16*this.element.width(), 16*this.element.height()); this.element .addClass('panel-resized') .addClass('itop-simple-graph') .addClass('graph'); this._create_toolkit_menu(); this._build_context_menus(); this.sTabId = null; var jTabPanel = this.element.closest('.ui-tabs-panel'); if (jTabPanel.length > 0) { // We are inside a tab, find out which one and hook its activation this.sTabId = jTabPanel.attr('id'); var jTabs = this.element.closest('.ui-tabs'); jTabs.on( "tabsactivate", function( event, ui ) { me._on_tabs_activate(ui); }); } $(window).bind('resized', function() { var that = me; window.setTimeout(function() { that._on_resize(); }, 50); } ); this.element.bind('mousewheel', function(event, delta, deltaX, deltaY) { return me._on_mousewheel(event, delta, deltaX, deltaY); }); if (this.options.source_url != null) { this.load_from_url(this.options.source_url); } }, // called when created, and later when changing options _refresh: function() { this.draw(); }, // events bound via _bind are removed automatically // revert other modifications here _destroy: function() { var sId = this.element.attr('id'); this.element .removeClass('itop-simple-graph') .removeClass('graph'); $('#tk_graph'+sId).remove(); $('#graph_'+sId+'_export_as_pdf').remove(); }, // _setOptions is called with a hash of all options that are changing _setOptions: function() { this._superApply(arguments); }, // _setOption is called for each individual option that is changing _setOption: function( key, value ) { this._superApply(arguments); }, draw: function() { this._updateBBox(); this.auto_scale(); this.oPaper.clear(); this._reset this.oPaper.setViewBox(this.xPan, this.yPan, this.element.width(), this.element.height(), false); for(var k in this.aNodes) { this.aNodes[k].aElements = []; this._draw_node(this.aNodes[k]); } for(var k in this.aEdges) { this.aEdges[k].aElements = []; this._draw_edge(this.aEdges[k]); } var me = this; this.oBackground = this.oPaper .rect(-10000, -10000, 20000, 20000) .attr({fill: '#fff', opacity: 0, cursor: 'move'}) .toBack() .drag(function(dx, dy, x, y, event) { me._on_background_move(dx, dy, x, y, event); }, function(x, y, event) { me._on_background_drag_start(x, y, event); }, function (event) { me._on_background_drag_end(event); }); this._make_tooltips(); }, _draw_node: function(oNode) { var iWidth = oNode.width; var iHeight = 32; var iFontSize = 10; var fTotalZoom = this.fZoom * this.fSliderZoom; var xPos = Math.round(oNode.x * fTotalZoom + this.xOffset); var yPos = Math.round(oNode.y * fTotalZoom + this.yOffset); oNode.tx = 0; oNode.ty = 0; switch(oNode.shape) { case 'disc': oNode.aElements.push(this.oPaper.circle(xPos, yPos, iWidth*fTotalZoom / 2).attr(oNode.disc_attr)); var oText = this.oPaper.text(xPos, yPos, oNode.label); oNode.text_attr['font-size'] = iFontSize * fTotalZoom; oText.attr(oNode.text_attr); //oText.transform('s'+this.fZoom); oNode.aElements.push(oText); break; case 'group': oNode.aElements.push(this.oPaper.circle(xPos, yPos, iWidth*fTotalZoom / 2).attr({fill: '#fff', 'stroke-width':0})); oNode.aElements.push(this.oPaper.circle(xPos, yPos, iWidth*fTotalZoom / 2).attr(oNode.disc_attr)); var xIcon = xPos - 18 * fTotalZoom; var yIcon = yPos - 18 * fTotalZoom; oNode.aElements.push(this.oPaper.image(oNode.icon_url, xIcon, yIcon, 16*fTotalZoom, 16*fTotalZoom).attr(oNode.icon_attr)); oNode.aElements.push(this.oPaper.image(oNode.icon_url, xIcon + 18*fTotalZoom, yIcon, 16*fTotalZoom, 16*fTotalZoom).attr(oNode.icon_attr)); oNode.aElements.push(this.oPaper.image(oNode.icon_url, xIcon + 9*fTotalZoom, yIcon + 18*fTotalZoom, 16*fTotalZoom, 16*fTotalZoom).attr(oNode.icon_attr)); var oText = this.oPaper.text(xPos, yPos +2, oNode.label); oNode.text_attr['font-size'] = iFontSize * fTotalZoom; oText.attr(oNode.text_attr); //oText.transform('s'+this.fZoom); var oBB = oText.getBBox(); var dy = iHeight/2*fTotalZoom + oBB.height/2; oText.remove(); oText = this.oPaper.text(xPos, yPos +dy +2, oNode.label); oText.attr(oNode.text_attr); //oText.transform('s'+this.fZoom); oNode.aElements.push(oText); oNode.aElements.push(this.oPaper.rect( xPos - oBB.width/2 -2, yPos - oBB.height/2 + dy, oBB.width +4, oBB.height).attr({fill: '#fff', stroke: '#fff', opacity: 0.9})); oText.toFront(); break; case 'icon': if(Raphael.svg) { // the colorShift plugin works only in SVG oNode.aElements.push(this.oPaper.image(oNode.icon_url, xPos - iWidth * fTotalZoom/2, yPos - iHeight * fTotalZoom/2, iWidth*fTotalZoom, iHeight*fTotalZoom).colorShift('#fff', 1)); } oNode.aElements.push(this.oPaper.image(oNode.icon_url, xPos - iWidth * fTotalZoom/2, yPos - iHeight * fTotalZoom/2, iWidth*fTotalZoom, iHeight*fTotalZoom).attr(oNode.icon_attr)); var idx = 0; for(var i in oNode.context_icons) { var sgn = 2*(idx % 2) -1; // Suite: -1, 1, -1, 1, -1, 1, -1, etc. var coef = Math.floor((1+idx)/2) * sgn; // Suite: 0, 1, -1, 2, -2, 3, -3, etc. var alpha = coef*Math.PI/4 - Math.PI/2; var x = xPos + Math.cos(alpha) * 1.25*iWidth * fTotalZoom / 2; var y = yPos + Math.sin(alpha) * 1.25*iWidth * fTotalZoom / 2; var l = iWidth/3 * fTotalZoom; oNode.aElements.push(this.oPaper.image(oNode.context_icons[i], x - l/2, y - l/2, l , l).attr(oNode.icon_attr)); idx++; } var oText = this.oPaper.text( xPos, yPos, oNode.label); oNode.text_attr['font-size'] = iFontSize * fTotalZoom; oText.attr(oNode.text_attr); //oText.transform('S'+fTotalZoom); var oBB = oText.getBBox(); var dy = iHeight/2*fTotalZoom + oBB.height/2; oText.remove(); oText = this.oPaper.text( xPos, yPos + dy, oNode.label); oText.attr(oNode.text_attr); //oText.transform('S'+fTotalZoom); oNode.aElements.push(oText); oNode.aElements.push(this.oPaper.rect( xPos - oBB.width/2 -2, yPos - oBB.height/2 + dy, oBB.width +4, oBB.height).attr({fill: '#fff', stroke: '#fff', opacity: 0.9}).toBack()); break; } if (oNode.source) { oNode.aElements.push(this.oPaper.circle(xPos, yPos, 1.25*iWidth*fTotalZoom / 2).attr({stroke: '#c33', 'stroke-width': 3*fTotalZoom }).toBack()); } if (oNode.sink) { oNode.aElements.push(this.oPaper.circle(xPos, yPos, 1.25*iWidth*fTotalZoom / 2).attr({stroke: '#33c', 'stroke-width': 3*fTotalZoom }).toBack()); } var me = this; for(k in oNode.aElements) { var sNodeId = oNode.id; $(oNode.aElements[k].node).attr({'data-type': oNode.shape, 'data-id': oNode.id} ).attr('class', 'popupMenuTarget'); oNode.aElements[k].drag( function(dx, dy, x, y, event) { clearTimeout($(this.node).data('openTimeoutId')); me._move(sNodeId, dx, dy, x, y, event); }, function(x, y, event) { me._drag_start(sNodeId, x, y, event); }, function (event) { me._drag_end(sNodeId, event); } ); } }, _move: function(sNodeId, dx, dy, x, y, event) { var fTotalZoom = this.fZoom * this.fSliderZoom; var origDx = dx / fTotalZoom; var origDy = dy / fTotalZoom; var oNode = this._find_node(sNodeId); oNode.x = oNode.xOrig + origDx; oNode.y = oNode.yOrig + origDy; for(k in oNode.aElements) { oNode.aElements[k].transform('t'+(oNode.tx + dx)+', '+(oNode.ty + dy)); for(j in this.aEdges) { var oEdge = this.aEdges[j]; if ((oEdge.source_node_id == sNodeId) || (oEdge.sink_node_id == sNodeId)) { var sPath = this._get_edge_path(oEdge); oEdge.aElements[0].attr({path: sPath}); } } } }, _drag_start: function(sNodeId, x, y, event) { var oNode = this._find_node(sNodeId); oNode.xOrig = oNode.x; oNode.yOrig = oNode.y; }, _drag_end: function(sNodeId, event) { var fTotalZoom = this.fZoom * this.fSliderZoom; var oNode = this._find_node(sNodeId); oNode.tx += (oNode.x - oNode.xOrig) * fTotalZoom; oNode.ty += (oNode.y - oNode.yOrig) * fTotalZoom; oNode.xOrig = oNode.x; oNode.yOrig = oNode.y; this._updateBBox(); }, _updateBBox: function() { this.options.xmin = 9999; this.options.xmax = -9999; this.options.ymin = 9999; this.options.ymax = -9999; for(var k in this.aNodes) { this.options.xmin = Math.min(this.aNodes[k].x + this.aNodes[k].tx - this.aNodes[k].width/2, this.options.xmin); this.options.xmax = Math.max(this.aNodes[k].x + this.aNodes[k].tx + this.aNodes[k].width/2, this.options.xmax); this.options.ymin = Math.min(this.aNodes[k].y + this.aNodes[k].ty - this.aNodes[k].width/2, this.options.ymin); this.options.ymax = Math.max(this.aNodes[k].y + this.aNodes[k].ty + this.aNodes[k].width/2, this.options.ymax); } }, _get_edge_path: function(oEdge) { var fTotalZoom = this.fZoom * this.fSliderZoom; var oStart = this._find_node(oEdge.source_node_id); var oEnd = this._find_node(oEdge.sink_node_id); var iArrowSize = 5; if ((oStart == null) || (oEnd == null)) return ''; var xStart = Math.round(oStart.x * fTotalZoom + this.xOffset); var yStart = Math.round(oStart.y * fTotalZoom + this.yOffset); var xEnd = Math.round(oEnd.x * fTotalZoom + this.xOffset); var yEnd = Math.round(oEnd.y * fTotalZoom + this.yOffset); var sPath = Raphael.format('M{0},{1}L{2},{3}', xStart, yStart, xEnd, yEnd); var vx = (xEnd - xStart); var vy = (yEnd - yStart); var l = Math.sqrt(vx*vx+vy*vy); vx = vx / l; vy = vy / l; var ux = -vy; var uy = vx; var lPos = Math.max(l/2, l - 40*fTotalZoom); var xArrow = xStart + vx * lPos; var yArrow = yStart + vy * lPos; sPath += Raphael.format('M{0},{1}l{2},{3}M{4},{5}l{6},{7}', xArrow, yArrow, fTotalZoom * iArrowSize *(-vx + ux), fTotalZoom * iArrowSize *(-vy + uy), xArrow, yArrow, fTotalZoom * iArrowSize *(-vx - ux), fTotalZoom * iArrowSize *(-vy - uy)); return sPath; }, _draw_edge: function(oEdge) { var fTotalZoom = this.fZoom * this.fSliderZoom; var fStrokeSize = Math.max(1, 2 * fTotalZoom); var sPath = this._get_edge_path(oEdge); var oAttr = $.extend(oEdge.attr); oAttr['stroke-linecap'] = 'round'; oAttr['stroke-width'] = fStrokeSize; oEdge.aElements.push(this.oPaper.path(sPath).attr(oAttr).toBack()); }, _find_node: function(sId) { for(var k in this.aNodes) { if (this.aNodes[k].id == sId) return this.aNodes[k]; } return null; }, adjust_height: function() { var maxHeight = this.element.parent().height(); // Compute the available height var element = this.element; this.element.parent().children().each(function() { if($(this).is(':visible') && !$(this).hasClass('graph') && ($(this).attr('id') != element.attr('id'))) { maxHeight = maxHeight - $(this).height(); } }); this.element.height(maxHeight - 20); this.oPaper.setSize(this.element.width(), this.element.height()); }, auto_scale: function() { var fMaxZoom = 1.5; this.adjust_height(); iMargin = 10; xmin = this.options.xmin - iMargin; xmax = this.options.xmax + iMargin; ymin = this.options.ymin - iMargin; ymax = this.options.ymax + iMargin; var xScale = this.element.width() / (xmax - xmin); var yScale = this.element.height() / (ymax - ymin + this.iTextHeight); this.fZoom = Math.min(xScale, yScale, fMaxZoom); switch(this.options.align) { case 'left': this.xOffset = -xmin * this.fZoom; break; case 'right': this.xOffset = (this.element.width() - (xmax - xmin) * this.fZoom); break; case 'center': this.xOffset = -xmin * this.fZoom + (this.element.width() - (xmax - xmin) * this.fZoom) / 2; break; } switch(this.options['vertical-align']) { case 'top': this.yOffset = -ymin * this.fZoom; break; case 'bottom': this.yOffset = this.element.height() - (ymax + this.iTextHeight) * this.fZoom; break; case 'middle': this.yOffset = -ymin * this.fZoom + (this.element.height() - (ymax - ymin + this.iTextHeight) * this.fZoom) / 2; break; } }, add_node: function(oNode) { oNode.aElements = []; oNode.tx = 0; oNode.ty = 0; this.aNodes.push(oNode); }, add_edge: function(oEdge) { oEdge.aElements = []; this.aEdges.push(oEdge); }, show_group: function(sGroupId) { this._close_all_tooltips(); // Activate the 3rd tab this.element.closest('.ui-tabs').tabs("option", "active", 2); // Scroll into view the group if ($('#'+sGroupId).length > 0) { $('#'+sGroupId)[0].scrollIntoView(); } }, _create_toolkit_menu: function() { var sPopupMenuId = 'tk_graph'+this.element.attr('id'); var sHtml = '
'; var sId = this.element.attr('id'); sHtml += this.options.labels.grouping_threshold+' '; if (this.options.additional_contexts.length > 0) { sHtml += ' '+this.options.labels.additional_context_info+' ' } sHtml += ' '; sHtml += '
'; sHtml += ''+this.options.labels.zoom+''; sHtml += '
'; sHtml += '
'; sHtml += '
'; sHtml += '
'; sHtml += '
'; this.element.before(sHtml); $('#'+sPopupMenuId+'>ul').popupmenu(); var me = this; $('#'+sPopupMenuId+'_pdf').click(function() { me.export_as_pdf(); }); $('#'+sPopupMenuId+'_attachment').click(function() { me.export_as_attachment(); }); $('#'+sId+'_grouping_threshold').spinner({ min: 2}); $('#'+sId+'_zoom').slider({ min: 0, max: 5, value: 1, step: 0.25, change: function() { me._on_zoom_change( $(this).slider('value')); } }); $('#'+sId+'_zoom_plus').click(function() { $('#'+sId+'_zoom').slider('value', 0.25 + $('#'+sId+'_zoom').slider('value')); return false; }); $('#'+sId+'_zoom_minus').click(function() { $('#'+sId+'_zoom').slider('value', $('#'+sId+'_zoom').slider('value') - 0.25); return false; }); $('#'+sId+'_contexts').multiselect({header: true, checkAllText: this.options.labels.check_all, uncheckAllText: this.options.labels.uncheck_all, noneSelectedText: this.options.labels.none_selected, selectedText: this.options.labels.nb_selected, selectedList: 1}); $('#'+sId+'_refresh_btn').button().click(function() { me.reload(); }); }, _build_context_menus: function() { var sId = this.element.attr('id'); var me = this; $.contextMenu({ selector: '#'+sId+' .popupMenuTarget', build: function(trigger, e) { // this callback is executed every time the menu is to be shown // its results are destroyed every time the menu is hidden // e is the original contextmenu event, containing e.pageX and e.pageY (amongst other data) var sType = trigger.attr('data-type'); var sNodeId = trigger.attr('data-id'); var oNode = me._find_node(sNodeId); clearTimeout(trigger.data('openTimeoutId')); /* var sObjName = trigger.attr('data-class'); var sIndex = trigger.attr('data-index'); var originalEvent = e; var bHasItems = false; */ var oResult = {callback: null, items: {}}; switch(sType) { case 'group': var sGroupIndex = oNode.group_index; if( $('#relation_group_'+sGroupIndex).length > 0) { oResult = { callback: function(key, options) { var me = $('.itop-simple-graph').data('itopSimple_graph'); // need a live value me.show_group('relation_group_'+sGroupIndex); }, items: { 'show': {name: me.options.drill_down.label } } }; } break; case 'icon': var sObjClass = oNode.obj_class; var sObjKey = oNode.obj_key; oResult = { callback: function(key, options) { var me = $('.itop-simple-graph').data('itopSimple_graph'); // need a live value var sURL = me.options.drill_down.url.replace('%1$s', sObjClass).replace('%2$s', sObjKey); window.location.href = sURL; }, items: { 'details': {name: me.options.drill_down.label } } }; break; default: oResult = false; // No context menu } return oResult; } }); }, export_as_pdf: function() { this._export_dlg(this.options.labels.export_pdf_title, this.options.export_as_pdf.url, 'download_pdf'); }, _export_dlg: function(sTitle, sSubmitUrl, sOperation) { var sId = this.element.attr('id'); var me = this; var oPositions = {}; for(k in this.aNodes) { oPositions[this.aNodes[k].id] = {x: this.aNodes[k].x, y: this.aNodes[k].y }; } var sHtmlForm = '
'; sHtmlForm += ''; sHtmlForm += ''; $('#'+sId+'_contexts').multiselect('getChecked').each(function() { sHtmlForm += ''; }); sHtmlForm += ''; for(k in this.options.excluded_classes) { sHtmlForm += ''; } for(var k1 in this.options.sources) { for(var k2 in this.options.sources[k1]) { sHtmlForm += ''; } } for(var k1 in this.options.excluded) { for(var k2 in this.options.excluded[k1]) { sHtmlForm += ''; } } if (sOperation == 'attachment') { sHtmlForm += ''; sHtmlForm += ''; } sHtmlForm += ''; sHtmlForm += ''; sHtmlForm += ''; sHtmlForm += ''; sHtmlForm += ''; sHtmlForm += ''; sHtmlForm += '
'+this.options.page_format.label+'
'+this.options.page_orientation.label+'
'+this.options.labels.title+'
'+this.options.labels.comments+'
'; sHtmlForm += ''; $('body').append(sHtmlForm); $('#graph_'+this.element.attr('id')+'_export_dlg input[name="positions"]').val(JSON.stringify(oPositions)); var me = this; if (sOperation == 'attachment') { $('#GraphExportDlg'+this.element.attr('id')+' form').submit(function() { return me._on_export_as_attachment(); }); } $('#GraphExportDlg'+this.element.attr('id')).dialog({ width: 'auto', modal: true, title: sTitle, close: function() { $(this).remove(); }, buttons: [ {text: this.options.labels['cancel'], click: function() { $(this).dialog('close');} }, {text: this.options.labels['export'], click: function() { $('#graph_'+me.element.attr('id')+'_export_dlg').submit(); $(this).dialog('close');} }, ] }); }, _on_zoom_change: function(sliderValue) { if(!this.bInUpdateSliderZoom) { var Z0 = this.fSliderZoom; var X = this.xOffset - this.element.width()/2; var Y = this.yOffset - this.element.height()/2; this.fSliderZoom = Math.pow(2 , (sliderValue - 1)); var Z1 = this.fSliderZoom = Math.pow(2 , (sliderValue - 1)); var dx = X * (1 - Z1/Z0); var dy = Y * (1 - Z1/Z0); this.xPan += dx; this.yPan += dy; this._close_all_tooltips(); this.oPaper.setViewBox(this.xPan, this.yPan, this.element.width(), this.element.height(), false); this.draw(); } }, _on_mousewheel: function(event, delta, deltaX, deltaY) { var fStep = 0.25*delta; var sId = this.element.attr('id'); $('#'+sId+'_zoom').slider('value', fStep + $('#'+sId+'_zoom').slider('value')); }, _on_resize: function() { this.element.closest('.ui-tabs').tabs({ heightStyle: "fill" }); this.auto_scale(); this._close_all_tooltips(); this.draw(); }, _on_tabs_activate: function(ui) { if (ui.newPanel.selector == ('#'+this.sTabId)) { if (this.bRedrawNeeded) { this._updateBBox(); this.auto_scale(); this.oPaper.setSize(this.element.width(), this.element.height()); this._reset_pan_and_zoom(); this.draw(); bRedrawNeeded = false; } } }, load: function(oData) { var me = this; var sId = this.element.attr('id'); this.aNodes = []; this.aEdges = []; for(k in oData.nodes) { this.add_node(oData.nodes[k]); } for(k in oData.edges) { this.add_edge(oData.edges[k]); } if (oData.groups) { this.refresh_groups(oData.groups); } if (this.element.is(':visible')) { this._updateBBox(); this.auto_scale(); this._reset_pan_and_zoom(); this.draw(); } else { this.bRedrawNeeded = true; } }, refresh_groups: function(aGroups) { if ($('#impacted_groups').length > 0) { // The "Groups" tab is present, refresh it if (aGroups.length == 0) { this.element.closest('.ui-tabs').tabs("disable", 2); $('#impacted_groups').html(''); } else { this.element.closest('.ui-tabs').tabs("enable", 2); $('#impacted_groups').html(''); var sUrl = GetAbsoluteUrlAppRoot()+'pages/ajax.render.php'; $.post(sUrl, { operation: 'relation_groups', groups: aGroups }, function(data) { $('#impacted_groups').html(data); }); } } }, _reset_pan_and_zoom: function() { this.xPan = 0; this.yPan = 0; var sId = this.element.attr('id'); this.bInUpdateSliderZoom = true; $('#'+sId+'_zoom').slider('value', 1); this.fSliderZoom = 1.0; this.bInUpdateSliderZoom = false; this.oPaper.setViewBox(this.xPan, this.yPan, this.element.width(), this.element.height(), false); }, load_from_url: function(sUrl) { this.options.load_from_url = sUrl; var me = this; var sId = this.element.attr('id'); this.options.grouping_threshold = $('#'+sId+'_grouping_threshold').val(); if (this.options.grouping_threshold < 2) { this.options.grouping_threshold = 2; $('#'+sId+'_grouping_threshold').val(this.options.grouping_threshold); } var aContexts = []; $('#'+sId+'_contexts').multiselect('getChecked').each(function() { aContexts[$(this).val()] = me.options.additional_contexts[$(this).val()].oql; }); this.element.closest('.ui-tabs').tabs({ heightStyle: "fill" }); this.adjust_height(); this._close_all_tooltips(); this.oPaper.rect(this.xPan, this.yPan, this.element.width(), this.element.height()).attr({fill: '#000', opacity: 0.4, 'stroke-width': 0}); this.oPaper.rect(this.xPan + this.element.width()/2 - 100, this.yPan + this.element.height()/2 - 10, 200, 20) .attr({fill: 'url(../setup/orange-progress.gif)', stroke: '#000', 'stroke-width': 1}); this.oPaper.text(this.xPan + this.element.width()/2, this.yPan + this.element.height()/2 - 20, this.options.labels.loading); $('#'+sId+'_refresh_btn').button('disable'); $.post(sUrl, {excluded_classes: this.options.excluded_classes, g: this.options.grouping_threshold, sources: this.options.sources, excluded: this.options.excluded, contexts: aContexts, context_key: this.options.context_key }, function(data) { me.load(data); $('#'+sId+'_refresh_btn').button('enable'); }, 'json'); }, export_as_attachment: function() { this._export_dlg(this.options.labels.export_as_attachment_title, this.options.export_as_attachment.url, 'attachment'); }, _on_export_as_attachment: function() { var oParams = {}; var oPositions = {}; var jForm = $('#GraphExportDlg'+this.element.attr('id')+' form'); for(k in this.aNodes) { oPositions[this.aNodes[k].id] = {x: this.aNodes[k].x, y: this.aNodes[k].y }; } oParams.positions = JSON.stringify(oPositions); oParams.sources = this.options.sources; oParams.excluded_classes = this.options.excluded_classes; oParams.title = jForm.find(':input[name="title"]').val(); oParams.comments = jForm.find(':input[name="comments"]').val(); oParams.include_list = jForm.find(':input[name="include_list"]:checked').length; oParams.o = jForm.find(':input[name="o"]').val(); oParams.p = jForm.find(':input[name="p"]').val(); oParams.obj_class = this.options.export_as_attachment.obj_class; oParams.obj_key = this.options.export_as_attachment.obj_key; oParams.contexts = []; var me = this; $('#'+this.element.attr('id')+'_contexts').multiselect('getChecked').each(function() { oParams.contexts[$(this).val()] = me.options.additional_contexts[$(this).val()].oql; }); oParams.context_key = this.options.context_key; var sUrl = jForm.attr('action'); var sTitle = oParams.title; var jPanel = $('#attachments').closest('.ui-tabs-panel'); var jTab = null; var sTabText = null; if (jPanel.length > 0) { var sTabId = jPanel.attr('id'); jTab = $('li[aria-controls='+sTabId+']'); sTabText = jTab.find('span').html(); jTab.find('span').html(sTabText+' '); } $.post(sUrl, oParams, function(data) { var sDownloadLink = GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?operation=download_document&class=Attachment&id='+data.att_id+'&field=contents'; var sIcon = GetAbsoluteUrlModulesRoot()+'itop-attachments/icons/pdf.png'; if (jTab != null) { var re = /^([^(]+)\(([0-9]+)\)(.*)$/; var aParts = re.exec(sTabText); if (aParts == null) { // First attachment $('#attachments').html(''); jTab.find('span').html(sTabText +' (1)'); } else { $('#attachments').append(''); var iPrevCount = parseInt(aParts[2], 10); jTab.find('span').html(aParts[1]+'('+(1 + iPrevCount)+')'+aParts[3]); } } }, 'json'); return false; }, reload: function() { this.load_from_url(this.options.load_from_url); }, _make_tooltips: function() { var me = this; $( ".popupMenuTarget" ).tooltip({ content: function() { var sDataId = $(this).attr('data-id'); var sTooltipContent = '
×
'; sTooltipContent += me._get_tooltip_content(sDataId); return sTooltipContent; }, items: '.popupMenuTarget', tooltipClass: 'tooltip-simple-graph', position: { my: "center bottom-10", at: "center top", using: function( position, feedback ) { $(this).css( position ); $( "
" ) .addClass( "arrow" ) .addClass( feedback.vertical ) .appendTo( this ); } } }) .off( "mouseover mouseout" ) .on( "mouseover", function(event){ event.stopImmediatePropagation(); var jMe = $(this); jMe.data('openTimeoutId', setTimeout(function() { var sDataId = jMe.attr('data-id'); if ($('.tooltip-close-button[data-id="'+sDataId+'"]').length == 0) { jMe.data('openTimeoutId', 0); jMe.tooltip('open'); } }, 1000)); }) .on( "mouseout", function(event){ event.stopImmediatePropagation(); clearTimeout($(this).data('openTimeoutId')); }); /* Happens at every on_drag_end !!! .on( "click", function(){ var sDataId = $(this).attr('data-id'); if ($('.tooltip-close-button[data-id="'+sDataId+'"]').length == 0) { $(this).tooltip( 'open' ); } else { $(this).tooltip( 'close' ); } $( this ).unbind( "mouseleave" ); return false; }); */ $('body').on('click', '.tooltip-close-button', function() { var sDataId = $(this).attr('data-id'); $('.popupMenuTarget[data-id="'+sDataId+'"]').tooltip('close'); }); this.element.on("click", ":not(.tooltip-simple-graph *,.tooltip-simple-graph)", function(){ $('.popupMenuTarget').each(function (i) { clearTimeout($(this).data('openTimeoutId')); $(this).data('openTimeoutId', 0); $(this).tooltip("close"); }); }); }, _get_tooltip_content: function(sNodeId) { var oNode = this._find_node(sNodeId); if (oNode !== null) { return oNode.tooltip; } return '

Node Id:'+sNodeId+'

'; }, _close_all_tooltips: function() { this.element.find('.popupMenuTarget').each(function() { clearTimeout($(this).data('openTimeoutId')); $(this).data('openTimeoutId', 0); $(this).tooltip('close'); }); }, _on_background_drag_start: function(x, y, event) { this.bDragging = true; this.xDrag = 0; this.yDrag = 0; //this._close_all_tooltips(); }, _on_background_move: function(dx, dy, x, y, event) { if (this.bDragging) { this.xDrag = dx; this.yDrag = dy; this.oPaper.setViewBox(this.xPan - this.xDrag, this.yPan - this.yDrag, this.element.width(), this.element.height(), false); } }, _on_background_drag_end: function(event) { if (this.bDragging) { this.xPan -= this.xDrag; this.yPan -= this.yDrag; this.xDrag = 0; this.yDrag = 0; this.bDragging = false; } }, }); });