Files
iTop/sources/application/WebPage/TabManager.php

424 lines
12 KiB
PHP

<?php
/**
* @copyright Copyright (C) 2010-2020 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\UI\Layout\TabContainer\Tab\Tab;
use Combodo\iTop\Application\UI\Layout\TabContainer\TabContainer;
/**
* Helper class to implement JQueryUI tabs inside a page
*/
class TabManager
{
const ENUM_TAB_TYPE_HTML = 'html';
const ENUM_TAB_TYPE_AJAX = 'ajax';
const DEFAULT_TAB_TYPE = self::ENUM_TAB_TYPE_HTML;
/**
* @var TabContainer[]
*/
protected $m_aTabs;
protected $m_sCurrentTabContainer;
protected $m_sCurrentTab;
public function __construct()
{
$this->m_aTabs = [];
$this->m_sCurrentTabContainer = '';
$this->m_sCurrentTab = '';
}
/**
* @param string $sTabContainer
* @param string $sPrefix
*
* @return \Combodo\iTop\Application\UI\iUIBlock
*/
public function AddTabContainer(string $sTabContainer, $sPrefix = ''): TabContainer
{
$oTabContainer = new TabContainer($sTabContainer, $sPrefix);
$this->m_aTabs[$sTabContainer] = $oTabContainer;
return $oTabContainer;
}
/**
* @param string $sHtml
*
* @throws \Exception
*/
public function AddToCurrentTab(string $sHtml): void
{
$this->AddToTab($this->m_sCurrentTabContainer, $this->m_sCurrentTab, $sHtml);
}
/**
* @return int
* @deprecated 2.8.0
*/
public function GetCurrentTabLength()
{
return 0;
}
/**
* Truncates the given tab to the specifed length and returns the truncated part
*
* @param string $sTabContainer The tab container in which to truncate the tab
* @param string $sTab The name/identifier of the tab to truncate
* @param integer $iLength The length/offset at which to truncate the tab
*
* @return string The truncated part
* @deprecated 2.8.0
*/
public function TruncateTab(string $sTabContainer, string $sTab, int $iLength)
{
return '';
}
/**
* @param string $sTabContainer
* @param string $sTab
*
* @return bool
*/
public function TabExists(string $sTabContainer, string $sTab)
{
return isset($this->m_aTabs[$sTabContainer]) ? $this->m_aTabs[$sTabContainer]->TabExists($sTab) : false;
}
/**
* @return int
*/
public function TabsContainerCount()
{
return count($this->m_aTabs);
}
private function GetTab(string $sTabContainer, string $sTab): ?Tab
{
if ($this->TabExists($sTabContainer, $sTab)) {
return $this->m_aTabs[$sTabContainer]->GetTab($sTab);
}
return null;
}
/**
* @param string $sTabContainer
* @param string $sTabCode
* @param string $sHtml
* @param string|null $sTabTitle
*
* @return string
* @throws \Exception
*/
public function AddToTab(string $sTabContainer, string $sTabCode, string $sHtml, $sTabTitle = null): string
{
if (!$this->TabExists($sTabContainer, $sTabCode)) {
$this->InitTab($sTabContainer, $sTabCode, static::ENUM_TAB_TYPE_HTML, $sTabTitle);
}
$oTab = $this->GetTab($sTabContainer, $sTabCode);
// Append to the content of the tab
$oTab->AddHtml($sHtml);
return ''; // Nothing to add to the page for now
}
/**
* @param string $sTabContainer
*
* @return string
*/
public function SetCurrentTabContainer($sTabContainer = '')
{
$sPreviousTabContainer = $this->m_sCurrentTabContainer;
$this->m_sCurrentTabContainer = $sTabContainer;
return $sPreviousTabContainer;
}
/**
* @param string $sTabCode
*
* @param string|null $sTabTitle
*
* @return string
* @throws \Combodo\iTop\Application\UI\UIException
*/
public function SetCurrentTab(string $sTabCode = '', string $sTabTitle = null): ?string
{
$sPreviousTabCode = $this->m_sCurrentTab;
$this->m_sCurrentTab = $sTabCode;
if ($sTabCode != '') {
// 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;
}
/**
* 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 $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.
*
* @param string|null $sTabTitle
*
* @return string
*
* @throws \Combodo\iTop\Application\UI\UIException
* @since 2.0.3
*/
public function AddAjaxTab(string $sTabCode, string $sUrl, bool $bCache = true, string $sTabTitle = null): string
{
// Set the content of the tab
/** @var \Combodo\iTop\Application\UI\Layout\TabContainer\Tab\AjaxTab $oTab */
$oTab = $this->InitTab($this->m_sCurrentTabContainer, $sTabCode, static::ENUM_TAB_TYPE_AJAX, $sTabTitle);
$oTab->SetURL($sUrl)
->SetCache($bCache);
return ''; // Nothing to add to the page for now
}
/**
* @return string
*/
public function GetCurrentTabContainer()
{
return $this->m_sCurrentTabContainer;
}
/**
* @return string
*/
public function GetCurrentTab()
{
return $this->m_sCurrentTab;
}
/**
* @param string $sTabCode
* @param string|null $sTabContainer
*/
public function RemoveTab(string $sTabCode, string $sTabContainer = null)
{
if ($sTabContainer == null) {
$sTabContainer = $this->m_sCurrentTabContainer;
}
if (isset($this->m_aTabs[$sTabContainer]) && $this->m_aTabs[$sTabContainer]->TabExists($sTabCode)) {
// Delete the content of the tab
$this->m_aTabs[$sTabContainer]->RemoveTab($sTabCode);
// If we just removed the active tab, let's reset the active tab
if (($this->m_sCurrentTabContainer == $sTabContainer) && ($this->m_sCurrentTab == $sTabCode)) {
$this->m_sCurrentTab = '';
}
}
}
/**
* Finds the tab whose title matches a given pattern
*
* @param string $sPattern
* @param string|null $sTabContainer
*
* @return mixed The actual name of the tab (as a string) or false if not found
*/
public function FindTab(string $sPattern, string $sTabContainer = null)
{
$result = false;
if ($sTabContainer == null) {
$sTabContainer = $this->m_sCurrentTabContainer;
}
if (isset($this->m_aTabs[$sTabContainer])) {
foreach ($this->m_aTabs[$sTabContainer]->GetSubBlocks() as $sTabCode => $void) {
if (preg_match($sPattern, $sTabCode)) {
$result = $sTabCode;
break;
}
}
}
return $result;
}
/**
* Make the given tab the active one, as if it were clicked
* DOES NOT WORK: apparently in the *old* version of jquery
* that we are using this is not supported... TO DO upgrade
* the whole jquery bundle...
*
* @param string $sTabContainer
* @param string $sTabCode
*
* @return string
* @deprecated 2.8.0
*/
public function SelectTab(string $sTabContainer, string $sTabCode)
{
return '';
}
/**
* @param string $sContent
* @param \WebPage $oPage
*
* @return mixed
* @deprecated 2.8.0
*/
public function RenderIntoContent(string $sContent, WebPage $oPage)
{
// Render the tabs in the page (if any)
$container_index = 0;
foreach ($this->m_aTabs as $sTabContainerName => $aTabs) {
$sTabs = '';
$sPrefix = $aTabs['prefix'];
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 ($sTabCode === '') {
unset($aTabs['tabs'][$sTabCode]);
}
}
// Render tabs
if ($oPage->IsPrintableVersion()) {
$oPage->add_ready_script(
<<< EOF
oHiddeableChapters = {};
EOF
);
$sTabs = "<!-- tabs -->\n<div id=\"tabbedContent_{$sPrefix}{$container_index}\" class=\"light\">\n";
$i = 0;
foreach ($aTabs['tabs'] as $sTabCode => $aTabData) {
$sTabCodeForJs = addslashes($sTabCode);
$sTabTitleForHtml = utils::HtmlEntities($aTabData['title']);
$sTabId = "tab_{$sPrefix}{$container_index}$i";
switch ($aTabData['type']) {
case static::ENUM_TAB_TYPE_AJAX:
$sTabHtml = '';
$sUrl = $aTabData['url'];
$oPage->add_ready_script(
<<< EOF
$.post('$sUrl', {printable: '1'}, function(data){
$('#$sTabId > .printable-tab-content').append(data);
});
EOF
);
break;
case static::ENUM_TAB_TYPE_HTML:
default:
$sTabHtml = $aTabData['html'];
}
$sTabs .= "<div class=\"printable-tab\" id=\"$sTabId\"><h2 class=\"printable-tab-title\">$sTabTitleForHtml</h2><div class=\"printable-tab-content\">".$sTabHtml."</div></div>\n";
$oPage->add_ready_script(
<<< EOF
oHiddeableChapters['$sTabId'] = '$sTabTitleForHtml';
EOF
);
$i++;
}
$sTabs .= "</div>\n<!-- end of tabs-->\n";
} else {
$sTabs = "<!-- tabs -->\n<div id=\"tabbedContent_{$sPrefix}{$container_index}\" class=\"light\">\n";
$sTabs .= "<ul>\n";
// Display the unordered list that will be rendered as the tabs
$i = 0;
foreach ($aTabs['tabs'] as $sTabCode => $aTabData) {
$sTabCodeForHtml = utils::HtmlEntities($sTabCode);
$sTabTitleForHtml = utils::HtmlEntities($aTabData['title']);
switch ($aTabData['type']) {
case static::ENUM_TAB_TYPE_AJAX:
$sTabs .= "<li data-cache=\"".($aTabData['cache'] ? 'true' : 'false')."\"><a href=\"{$aTabData['url']}\" class=\"tab\" data-tab-id=\"$sTabCodeForHtml\"><span>$sTabTitleForHtml</span></a></li>\n";
break;
case static::ENUM_TAB_TYPE_HTML:
default:
$sTabs .= "<li><a href=\"#tab_{$sPrefix}{$container_index}$i\" class=\"tab\" data-tab-id=\"$sTabCodeForHtml\"><span>$sTabTitleForHtml</span></a></li>\n";
}
$i++;
}
$sTabs .= "</ul>\n";
// Now add the content of the tabs themselves
$i = 0;
foreach ($aTabs['tabs'] as $sTabCode => $aTabData) {
switch ($aTabData['type']) {
case static::ENUM_TAB_TYPE_AJAX:
// Nothing to add
break;
case static::ENUM_TAB_TYPE_HTML:
default:
$sTabs .= "<div id=\"tab_{$sPrefix}{$container_index}$i\">".$aTabData['html']."</div>\n";
}
$i++;
}
$sTabs .= "</div>\n<!-- end of tabs-->\n";
}
}
$sContent = str_replace("\$Tabs:$sTabContainerName\$", $sTabs, $sContent);
$container_index++;
}
return $sContent;
}
/**
* @param string $sTabContainer
* @param string $sTabCode
* @param string $sTabType
* @param string|null $sTabTitle
*
* @return \Combodo\iTop\Application\UI\Layout\TabContainer\Tab\Tab
* @throws \Combodo\iTop\Application\UI\UIException
* @since 2.7.0
*/
protected function InitTab(string $sTabContainer, string $sTabCode, string $sTabType = self::DEFAULT_TAB_TYPE, string $sTabTitle = null): Tab
{
$oTab = null;
if (!$this->TabExists($sTabContainer, $sTabCode)) {
if (!isset($this->m_aTabs[$sTabContainer])) {
$oTabContainer = $this->AddTabContainer($sTabContainer);
} else {
$oTabContainer = $this->m_aTabs[$sTabContainer];
}
$sTitle = ($sTabTitle !== null) ? Dict::S($sTabTitle) : Dict::S($sTabCode);
switch ($sTabType) {
case static::ENUM_TAB_TYPE_AJAX:
$oTab = $oTabContainer->AddAjaxTab($sTabCode, $sTitle);
break;
case static::ENUM_TAB_TYPE_HTML:
default:
$oTab = $oTabContainer->AddTab($sTabCode, $sTitle);
break;
}
} else {
$oTab = $this->GetTab($sTabContainer, $sTabCode);
}
return $oTab;
}
}