diff --git a/application/dashboard.class.inc.php b/application/dashboard.class.inc.php index eb32d7095..462399943 100644 --- a/application/dashboard.class.inc.php +++ b/application/dashboard.class.inc.php @@ -1127,7 +1127,7 @@ EOF $sAutoApplyConfirmationMessage = addslashes(Dict::S('UI:AutoApplyConfirmationMessage')); $oPage->add_ready_script( -<<add_ready_script(""); } @@ -1352,7 +1358,7 @@ EOF $sCancelButtonLabel = Dict::S('UI:Button:Cancel'); $oPage->add_ready_script( -<<iNbCols = 1; } - + + /** + * N°2634 : we must have a unique id per dashlet ! + * To avoid collision with other dashlets with the same ID we prefix it with row/cell id + * Collisions typically happen with extensions. + * + * @param boolean $bIsCustomized + * @param string $sDashboardDivId + * @param int $iRow + * @param int $iCell + * @param string $sDashletIdOrig + * + * @return string + * + * @since 2.7.0 N°2735 + */ + public static function GetDashletUniqueId($bIsCustomized, $sDashboardDivId, $iRow, $iCell, $sDashletIdOrig) + { + if(strpos($sDashletIdOrig, 'IDrow') !== false) + { + return $sDashletIdOrig; + } + + $sDashletId = $sDashboardDivId."_IDrow$iRow-col$iCell-$sDashletIdOrig"; + if ($bIsCustomized) + { + $sDashletId = 'CUSTOM_'.$sDashletId; + } + + return $sDashletId; + } + protected function TrimCell($aDashlets) { $aKeys = array_reverse(array_keys($aDashlets)); @@ -115,7 +146,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout for($iRows = 0; $iRows < $iNbRows; $iRows++) { - $oPage->add(''); + $oPage->add(""); for($iCols = 0; $iCols < $this->iNbCols; $iCols++) { $sCellClass = ($iRows == $iNbRows-1) ? $sClass.' layout_last_used_rank' : $sClass; @@ -128,23 +159,13 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout /** @var \Dashlet $oDashlet */ foreach($aDashlets as $oDashlet) { - if ($oDashlet->IsVisible()) + if ($oDashlet::IsVisible()) { $sDashletIdOrig = $oDashlet->GetID(); - $sDashletId = $sDashletIdOrig; - if(strpos($sDashletId, 'IDrow') === false) - { - $sDashboardDivId = $aExtraParams['dashboard_div_id']; - // N°2634 : we must have a unique id per dashlet ! - // To avoid collision with other dashlets with the same ID we prefix it with row/cell id - // Collisions typically happen with extensions. - $sDashletId = $sDashboardDivId."_IDrow$iRows-col$iCols-$sDashletId"; - if (array_key_exists('bCustomized', $aExtraParams) && ((bool)$aExtraParams['bCustomized']) === true) - { - $sDashletId = 'CUSTOM_'.$sDashletId; - } - $oDashlet->SetID($sDashletId); - } + $sDashboardDivId = $aExtraParams['dashboard_div_id']; + $bIsCustomized = (array_key_exists('bCustomized', $aExtraParams) && ((bool)$aExtraParams['bCustomized']) === true); + $sDashletId = self::GetDashletUniqueId($bIsCustomized, $sDashboardDivId, $iRows, $iCols, $sDashletIdOrig); + $oDashlet->SetID($sDashletId); $this->UpdateDashletsUserPrefs($oDashlet, $sDashletIdOrig, $aExtraParams); $oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams); } @@ -167,7 +188,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout if ($bEditMode) // Add one row for extensibility { $sStyle = 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode layout_extension" data-dashboard-cell-index="'.$iCellIdx.'"'; - $oPage->add(''); + $oPage->add(""); for($iCols = 0; $iCols < $this->iNbCols; $iCols++) { $oPage->add(""); diff --git a/js/dashboard.js b/js/dashboard.js index 4a938a6aa..20eeddd51 100644 --- a/js/dashboard.js +++ b/js/dashboard.js @@ -11,6 +11,7 @@ $(function() $.widget( "itop.dashboard", { // default options + // real values must be provided when instanciating the widget : $node.dashboard(...) options: { dashboard_id: '', @@ -22,7 +23,8 @@ $(function() submit_parameters: {}, render_to: 'index.php', render_parameters: {}, - new_dashlet_parameters: {} + new_dashlet_parameters: {}, + new_dashletid_parameters: {} }, // the constructor @@ -31,10 +33,10 @@ $(function() var me = this; this.element - .addClass('itop-dashboard') - .bind('add_dashlet.itop_dashboard', function(event, oParams){ - me.add_dashlet(oParams); - }); + .addClass('itop-dashboard') + .bind('add_dashlet.itop_dashboard', function(event, oParams){ + me.add_dashlet(oParams); + }); this.ajax_div = $('
'); this.element.after(this.ajax_div); @@ -103,20 +105,6 @@ $(function() return oState; }, - _get_new_id: function() - { - var iMaxId = 0; - this.element.find(':itop-dashlet').each(function() { - var oDashlet = $(this).data('itopDashlet'); - if(oDashlet) - { - var oDashletParams = oDashlet.get_params(); - var id = parseInt(oDashletParams.dashlet_id, 10); - if (id > iMaxId) iMaxId = id; - } - }); - return 1 + iMaxId; - }, _make_draggable: function() { var me = this; @@ -154,19 +142,26 @@ $(function() }); }, add_dashlet: function(options) + { + var $container = options.container, + iNumberOfExistingDashletInCell = $container.children("div.dashlet").length, + sTempDashletId = iNumberOfExistingDashletInCell+1; + + this.get_dashletid_ajax(options, sTempDashletId); + }, + add_dashlet_prepare: function(options, sFinalDashletId) { // 1) Create empty divs for the dashlet and its properties // - var sDashletId = this._get_new_id(); - var oDashlet = $('
'); + var oDashlet = $('
'); oDashlet.appendTo(options.container); - var oDashletProperties = $('
'); + var oDashletProperties = $('
'); oDashletProperties.appendTo($('#dashlet_properties')); // 2) Ajax call to fill the divs with default values // => in return, it must call add_dashlet_finalize // - this.add_dashlet_ajax(options, sDashletId); + this.add_dashlet_ajax(options, sFinalDashletId); }, add_dashlet_finalize: function(options, sDashletId, sDashletClass) { @@ -209,6 +204,7 @@ $(function() $.widget( "itop.runtimedashboard", $.itop.dashboard, { // default options + // real values must be provided when instanciating the widget : $node.runtimedashboard(...) options: { dashboard_id: '', @@ -220,7 +216,8 @@ $(function() submit_parameters: {}, render_to: 'index.php', render_parameters: {}, - new_dashlet_parameters: {} + new_dashlet_parameters: {}, + new_dashletid_parameters: {} }, // the constructor @@ -246,6 +243,7 @@ $(function() this._superApply(arguments); }, + // _setOptions is called with a hash of all options that are changing _setOptions: function() { @@ -317,6 +315,22 @@ $(function() } }); }, + // We need a unique dashlet id, we will get it using an ajax query + get_dashletid_ajax: function(options, sTempDashletId) + { + var $container = options.container; + var oParams = this.options.new_dashletid_parameters; + oParams.dashboardid = options.dashboard_id; + oParams.iRow = $container.closest("tr").data("dashboard-row-index"); + oParams.iCell = $container.data("dashboard-cell-index"); + oParams.dashletid = sTempDashletId; + + var me = this; + $.post(this.options.render_to, oParams, function(data) { + sFinalDashletId = data; + me.add_dashlet_prepare(options, sFinalDashletId); + }); + }, add_dashlet_ajax: function(options, sDashletId) { var oParams = this.options.new_dashlet_parameters; diff --git a/pages/ajax.render.php b/pages/ajax.render.php index d85de1256..7d1424d72 100644 --- a/pages/ajax.render.php +++ b/pages/ajax.render.php @@ -1215,6 +1215,16 @@ EOF $oKPI->ComputeAndReport('Data fetch and format'); break; + case 'new_dashlet_id': + $sDashboardDivId = utils::ReadParam("dashboardid"); + $iRow = utils::ReadParam("iRow"); + $iCell = utils::ReadParam("iCell"); + $sDashletIdOrig = utils::ReadParam("dashletid"); + $sFinalDashletId = DashboardLayoutMultiCol::GetDashletUniqueId(true, $sDashboardDivId, $iRow, $iCell, $sDashletIdOrig); + $oPage = new ajax_page(''); + $oPage->add($sFinalDashletId); + break; + case 'new_dashlet': require_once(APPROOT.'application/forms.class.inc.php'); require_once(APPROOT.'application/dashlet.class.inc.php');