diff --git a/application/ajaxwebpage.class.inc.php b/application/ajaxwebpage.class.inc.php index 65431480b..b893a91b9 100644 --- a/application/ajaxwebpage.class.inc.php +++ b/application/ajaxwebpage.class.inc.php @@ -1,27 +1,20 @@ - /** - * Simple web page with no includes, header or fancy formatting, useful to - * generate HTML fragments when called by an AJAX method + * Copyright (C) 2013-2020 Combodo SARL * - * @copyright Copyright (C) 2010-2017 Combodo SARL - * @license http://opensource.org/licenses/AGPL-3.0 + * This file is part of iTop. + * + * iTop is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * iTop is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License */ require_once(APPROOT."/application/webpage.class.inc.php"); @@ -62,9 +55,9 @@ class ajax_page extends WebPage implements iTabbedPage $this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix)); } - public function AddToTab($sTabContainer, $sTabLabel, $sHtml) + public function AddToTab($sTabContainer, $sTabCode, $sHtml) { - $this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabLabel, $sHtml)); + $this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabCode, $sHtml)); } public function SetCurrentTabContainer($sTabContainer = '') @@ -72,26 +65,28 @@ class ajax_page extends WebPage implements iTabbedPage return $this->m_oTabs->SetCurrentTabContainer($sTabContainer); } - public function SetCurrentTab($sTabLabel = '') + public function SetCurrentTab($sTabCode = '', $sTabTitle = null) { - return $this->m_oTabs->SetCurrentTab($sTabLabel); + return $this->m_oTabs->SetCurrentTab($sTabCode, $sTabTitle); } - + /** * Add a tab which content will be loaded asynchronously via the supplied URL - * + * * Limitations: * Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to pull content from another server. * Static content cannot be added inside such tabs. - * - * @param string $sTabLabel The (localised) label of the tab + * + * @param string $sTabCode The (localised) label of the tab * @param string $sUrl The URL to load (on the same server) * @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. flase will cause the tab to be reloaded upon each activation. + * @param string|null $sTabTitle + * * @since 2.0.3 */ - public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true) + public function AddAjaxTab($sTabCode, $sUrl, $bCache = true, $sTabTitle = null) { - $this->add($this->m_oTabs->AddAjaxTab($sTabLabel, $sUrl, $bCache)); + $this->add($this->m_oTabs->AddAjaxTab($sTabCode, $sUrl, $bCache, $sTabTitle)); } public function GetCurrentTab() @@ -99,9 +94,9 @@ class ajax_page extends WebPage implements iTabbedPage return $this->m_oTabs->GetCurrentTab(); } - public function RemoveTab($sTabLabel, $sTabContainer = null) + public function RemoveTab($sTabCode, $sTabContainer = null) { - $this->m_oTabs->RemoveTab($sTabLabel, $sTabContainer); + $this->m_oTabs->RemoveTab($sTabCode, $sTabContainer); } /** @@ -119,9 +114,9 @@ class ajax_page extends WebPage implements iTabbedPage * that we are using this is not supported... TO DO upgrade * the whole jquery bundle... */ - public function SelectTab($sTabContainer, $sTabLabel) + public function SelectTab($sTabContainer, $sTabCode) { - $this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabLabel)); + $this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabCode)); } public function AddToMenu($sHtml) diff --git a/application/itopwebpage.class.inc.php b/application/itopwebpage.class.inc.php index a26187a33..1e9030f8a 100644 --- a/application/itopwebpage.class.inc.php +++ b/application/itopwebpage.class.inc.php @@ -1,6 +1,6 @@ add($this->m_oTabs->AddToTab($sTabContainer, $sTabLabel, $sHtml)); + $this->add($this->m_oTabs->AddToTab($sTabContainer, $sTabCode, $sHtml)); } /** @@ -1502,13 +1502,14 @@ EOF; } /** - * @param string $sTabLabel + * @param string $sTabCode + * @param string|null $sTabTitle * * @return mixed|string */ - public function SetCurrentTab($sTabLabel = '') + public function SetCurrentTab($sTabCode = '', $sTabTitle = null) { - return $this->m_oTabs->SetCurrentTab($sTabLabel); + return $this->m_oTabs->SetCurrentTab($sTabCode, $sTabTitle); } /** @@ -1518,16 +1519,18 @@ EOF; * Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to pull content from * another server. Static content cannot be added inside such tabs. * - * @param string $sTabLabel The (localised) label of the tab + * @param string $sTabCode The (localised) label of the tab * @param string $sUrl The URL to load (on the same server) * @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. flase will cause the tab to be * reloaded upon each activation. + * @param string|null $sTabTitle * + * @throws \Exception * @since 2.0.3 */ - public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true) + public function AddAjaxTab($sTabCode, $sUrl, $bCache = true, $sTabTitle = null) { - $this->add($this->m_oTabs->AddAjaxTab($sTabLabel, $sUrl, $bCache)); + $this->add($this->m_oTabs->AddAjaxTab($sTabCode, $sUrl, $bCache, $sTabTitle)); } /** @@ -1539,14 +1542,14 @@ EOF; } /** - * @param string $sTabLabel + * @param string $sTabCode * @param string|null $sTabContainer * * @return mixed|void */ - public function RemoveTab($sTabLabel, $sTabContainer = null) + public function RemoveTab($sTabCode, $sTabContainer = null) { - $this->m_oTabs->RemoveTab($sTabLabel, $sTabContainer); + $this->m_oTabs->RemoveTab($sTabCode, $sTabContainer); } /** @@ -1569,11 +1572,11 @@ EOF; * the whole jquery bundle... * * @param string $sTabContainer - * @param string $sTabLabel + * @param string $sTabCode */ - public function SelectTab($sTabContainer, $sTabLabel) + public function SelectTab($sTabContainer, $sTabCode) { - $this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabLabel)); + $this->add_ready_script($this->m_oTabs->SelectTab($sTabContainer, $sTabCode)); } /** diff --git a/application/webpage.class.inc.php b/application/webpage.class.inc.php index 29620f226..da83a6006 100644 --- a/application/webpage.class.inc.php +++ b/application/webpage.class.inc.php @@ -1,6 +1,6 @@ m_aTabs[$sTabContainer]['tabs'][$sTabLabel])) + if (!$this->TabExists($sTabContainer, $sTabCode)) { - // Set the content of the tab - $this->m_aTabs[$sTabContainer]['tabs'][$sTabLabel] = array( - 'type' => 'html', - 'html' => $sHtml, - ); + $this->InitTab($sTabContainer, $sTabCode, static::ENUM_TAB_TYPE_HTML, $sTabTitle); } - else + + // If target tab is not of type 'html', throw an exception + if ($this->m_aTabs[$sTabContainer]['tabs'][$sTabCode]['type'] != static::ENUM_TAB_TYPE_HTML) { - if ($this->m_aTabs[$sTabContainer]['tabs'][$sTabLabel]['type'] != 'html') - { - throw new Exception("Cannot add HTML content to the tab '$sTabLabel' of type '{$this->m_aTabs[$sTabContainer]['tabs'][$sTabLabel]['type']}'"); - } - // Append to the content of the tab - $this->m_aTabs[$sTabContainer]['tabs'][$sTabLabel]['html'] .= $sHtml; + throw new Exception("Cannot add HTML content to the tab '$sTabCode' of type '{$this->m_aTabs[$sTabContainer]['tabs'][$sTabCode]['type']}'"); } + // Append to the content of the tab + $this->m_aTabs[$sTabContainer]['tabs'][$sTabCode]['html'] .= $sHtml; + return ''; // Nothing to add to the page for now } @@ -1304,16 +1307,22 @@ class TabManager } /** - * @param string $sTabLabel + * @param string $sTabCode * * @return string */ - public function SetCurrentTab($sTabLabel = '') + public function SetCurrentTab($sTabCode = '', $sTabTitle = null) { - $sPreviousTab = $this->m_sCurrentTab; - $this->m_sCurrentTab = $sTabLabel; + $sPreviousTabCode = $this->m_sCurrentTab; + $this->m_sCurrentTab = $sTabCode; - return $sPreviousTab; + // Init tab to HTML tab if not existing + if (!$this->TabExists($this->GetCurrentTabContainer(), $sTabCode)) + { + $this->InitTab($this->GetCurrentTabContainer(), $sTabCode, static::ENUM_TAB_TYPE_HTML, $sTabTitle); + } + + return $sPreviousTabCode; } /** @@ -1323,7 +1332,7 @@ class TabManager * Cross site scripting is not not allowed for security reasons. Use a normal tab with an IFRAME if you want to * pull content from another server. Static content cannot be added inside such tabs. * - * @param string $sTabLabel The (localised) label of the tab + * @param string $sTabCode The (localised) label of the tab * @param string $sUrl The URL to load (on the same server) * @param boolean $bCache Whether or not to cache the content of the tab once it has been loaded. false will cause * the tab to be reloaded upon each activation. @@ -1332,14 +1341,12 @@ class TabManager * * @since 2.0.3 */ - public function AddAjaxTab($sTabLabel, $sUrl, $bCache = true) + public function AddAjaxTab($sTabCode, $sUrl, $bCache = true, $sTabTitle = null) { // Set the content of the tab - $this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$sTabLabel] = array( - 'type' => 'ajax', - 'url' => $sUrl, - 'cache' => $bCache, - ); + $this->InitTab($this->m_sCurrentTabContainer, $sTabCode, static::ENUM_TAB_TYPE_AJAX, $sTabTitle); + $this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$sTabCode]['url'] = $sUrl; + $this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$sTabCode]['cache'] = $bCache; return ''; // Nothing to add to the page for now } @@ -1361,22 +1368,22 @@ class TabManager } /** - * @param string $sTabLabel + * @param string $sTabCode * @param string|null $sTabContainer */ - public function RemoveTab($sTabLabel, $sTabContainer = null) + public function RemoveTab($sTabCode, $sTabContainer = null) { if ($sTabContainer == null) { $sTabContainer = $this->m_sCurrentTabContainer; } - if (isset($this->m_aTabs[$sTabContainer]['tabs'][$sTabLabel])) + if (isset($this->m_aTabs[$sTabContainer]['tabs'][$sTabCode])) { // Delete the content of the tab - unset($this->m_aTabs[$sTabContainer]['tabs'][$sTabLabel]); + unset($this->m_aTabs[$sTabContainer]['tabs'][$sTabCode]); // If we just removed the active tab, let's reset the active tab - if (($this->m_sCurrentTabContainer == $sTabContainer) && ($this->m_sCurrentTab == $sTabLabel)) + if (($this->m_sCurrentTabContainer == $sTabContainer) && ($this->m_sCurrentTab == $sTabCode)) { $this->m_sCurrentTab = ''; } @@ -1398,11 +1405,11 @@ class TabManager { $sTabContainer = $this->m_sCurrentTabContainer; } - foreach ($this->m_aTabs[$sTabContainer]['tabs'] as $sTabLabel => $void) + foreach ($this->m_aTabs[$sTabContainer]['tabs'] as $sTabCode => $void) { - if (preg_match($sPattern, $sTabLabel)) + if (preg_match($sPattern, $sTabCode)) { - $result = $sTabLabel; + $result = $sTabCode; break; } } @@ -1417,11 +1424,11 @@ class TabManager * the whole jquery bundle... * * @param string $sTabContainer - * @param string $sTabLabel + * @param string $sTabCode * * @return string */ - public function SelectTab($sTabContainer, $sTabLabel) + public function SelectTab($sTabContainer, $sTabCode) { $container_index = 0; $tab_index = 0; @@ -1431,7 +1438,7 @@ class TabManager { foreach ($aTabs['tabs'] as $sCurrentTabLabel => $void) { - if ($sCurrentTabLabel == $sTabLabel) + if ($sCurrentTabLabel == $sTabCode) { break; } @@ -1462,6 +1469,18 @@ class TabManager $container_index = 0; if (count($aTabs['tabs']) > 0) { + // Clean tabs + foreach ($aTabs['tabs'] as $sTabCode => $aTabData) + { + // Sometimes people set an empty tab to force content NOT to be rendered in the previous one. We need to remove them. + // Note: Look for "->SetCurrentTab('');" for examples. + if (empty($sTabCode)) + { + unset($aTabs['tabs'][$sTabCode]); + } + } + + // Render tabs if ($oPage->IsPrintableVersion()) { $oPage->add_ready_script( @@ -1471,13 +1490,14 @@ EOF ); $sTabs = "\n
\n"; $i = 0; - foreach ($aTabs['tabs'] as $sTabName => $aTabData) + foreach ($aTabs['tabs'] as $sTabCode => $aTabData) { - $sTabNameEsc = addslashes($sTabName); + $sTabCodeForJs = addslashes($sTabCode); + $sTabTitleForHtml = utils::HtmlEntities($aTabData['title']); $sTabId = "tab_{$sPrefix}{$container_index}$i"; switch ($aTabData['type']) { - case 'ajax': + case static::ENUM_TAB_TYPE_AJAX: $sTabHtml = ''; $sUrl = $aTabData['url']; $oPage->add_ready_script( @@ -1489,16 +1509,14 @@ EOF ); break; - case 'html': + case static::ENUM_TAB_TYPE_HTML: default: $sTabHtml = $aTabData['html']; } - $sTabs .= "

".htmlentities($sTabName, - ENT_QUOTES, - 'UTF-8')."

".$sTabHtml."
\n"; + $sTabs .= "

$sTabTitleForHtml

".$sTabHtml."
\n"; $oPage->add_ready_script( <<< EOF -oHiddeableChapters['$sTabId'] = '$sTabNameEsc'; +oHiddeableChapters['$sTabId'] = '$sTabCodeForJs'; EOF ); $i++; @@ -1511,34 +1529,34 @@ EOF $sTabs .= "\n"; // Now add the content of the tabs themselves $i = 0; - foreach ($aTabs['tabs'] as $sTabName => $aTabData) + foreach ($aTabs['tabs'] as $sTabCode => $aTabData) { switch ($aTabData['type']) { - case 'ajax': + case static::ENUM_TAB_TYPE_AJAX: // Nothing to add break; - case 'html': + case static::ENUM_TAB_TYPE_HTML: default: $sTabs .= "
".$aTabData['html']."
\n"; } @@ -1553,4 +1571,37 @@ EOF return $sContent; } + + /** + * @param string $sTabContainer + * @param string $sTabCode + * @param string $sTabType + * @param string|null $sTabTitle + * @since 2.7.0 + */ + protected function InitTab($sTabContainer, $sTabCode, $sTabType = self::DEFAULT_TAB_TYPE, $sTabTitle = null) + { + if (!$this->TabExists($sTabContainer, $sTabCode)) + { + // Common properties + $this->m_aTabs[$sTabContainer]['tabs'][$sTabCode] = array( + 'type' => $sTabType, + 'title' => ($sTabTitle !== null) ? Dict::S($sTabTitle) : Dict::S($sTabCode), + ); + + // Specific properties + switch($sTabType) + { + case static::ENUM_TAB_TYPE_AJAX: + $this->m_aTabs[$sTabContainer]['tabs'][$sTabCode]['url'] = null; + $this->m_aTabs[$sTabContainer]['tabs'][$sTabCode]['cache'] = null; + break; + + case static::ENUM_TAB_TYPE_HTML: + default: + $this->m_aTabs[$sTabContainer]['tabs'][$sTabCode]['html'] = null; + break; + } + } + } } \ No newline at end of file diff --git a/sources/application/TwigBase/Controller/Controller.php b/sources/application/TwigBase/Controller/Controller.php index 18633782c..d2c89451c 100644 --- a/sources/application/TwigBase/Controller/Controller.php +++ b/sources/application/TwigBase/Controller/Controller.php @@ -1,7 +1,20 @@ m_oPage->AddTabContainer(''); $this->m_oPage->SetCurrentTabContainer(''); } - foreach ($this->m_aAjaxTabs as $aTab) + foreach ($this->m_aAjaxTabs as $sTabCode => $aTabData) { - $this->AddAjaxTabToPage($aTab['label'], $aTab['url'], $aTab['cache']); + $this->AddAjaxTabToPage($sTabCode, $aTabData['label'], $aTabData['url'], $aTabData['cache']); } foreach ($this->m_aLinkedScripts as $sLinkedScript) { @@ -553,9 +566,9 @@ abstract class Controller $this->m_oPage->add_linked_stylesheet($sLinkedStylesheet); } - private function AddAjaxTabToPage($sLabel, $sURL, $bCache) + private function AddAjaxTabToPage($sCode, $sTitle, $sURL, $bCache) { - $this->m_oPage->AddAjaxTab($sLabel, $sURL, $bCache); + $this->m_oPage->AddAjaxTab($sCode, $sURL, $bCache, $sTitle); } /**