mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-19 23:32:17 +02:00
N°2847 - Tab Management - iTop Pages refactoring - introduction of UIContentBlock as base block
This commit is contained in:
@@ -2353,4 +2353,9 @@ class utils
|
||||
{
|
||||
return str_replace(' ', '', ucwords(strtr($sInput, '_-', ' ')));
|
||||
}
|
||||
|
||||
public static function FilterXSS($sHTML)
|
||||
{
|
||||
return str_ireplace('<script', '<script', $sHTML);
|
||||
}
|
||||
}
|
||||
|
||||
17
css/backoffice/components/_ajaxtab.scss
Normal file
17
css/backoffice/components/_ajaxtab.scss
Normal file
@@ -0,0 +1,17 @@
|
||||
/*!
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
@@ -25,3 +25,7 @@
|
||||
@import "popover-menu/popover-menu";
|
||||
@import "popover-menu/popover-menu-item";
|
||||
@import "newsroom-menu";
|
||||
|
||||
@import "tabcontainer";
|
||||
@import "tab";
|
||||
@import "ajaxtab";
|
||||
17
css/backoffice/components/_tab.scss
Normal file
17
css/backoffice/components/_tab.scss
Normal file
@@ -0,0 +1,17 @@
|
||||
/*!
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
17
css/backoffice/components/_tabcontainer.scss
Normal file
17
css/backoffice/components/_tabcontainer.scss
Normal file
@@ -0,0 +1,17 @@
|
||||
/*!
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', [
|
||||
'UIBlock:Error:CannotGetBlocks' => 'Could not retrieve blocks from content area "%1$s" as it does seem to exists for page content "%2$s"',
|
||||
]);
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', [
|
||||
'UIBlock:Error:AddBlockNotTabForbidden' => 'Cannot add block %1$s to %2$s (only Tab blocks are allowed)',
|
||||
]);
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', [
|
||||
'UIBlock:Error:AddBlockForbidden' => 'Cannot add block to %1$s',
|
||||
]);
|
||||
8
documentation/deprecations.md
Normal file
8
documentation/deprecations.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Deprecated in 2.8.0
|
||||
|
||||
* TabManager::GetCurrentTabLength()
|
||||
* TabManager::TruncateTab()
|
||||
* TabManager::SelectTab()
|
||||
* TabManager::RenderIntoContent()
|
||||
|
||||
* iTopWebPage::SelectTab()
|
||||
@@ -192,9 +192,15 @@ return array(
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\PageContent\\PageContent' => $baseDir . '/sources/application/UI/Layout/PageContent/PageContent.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\PageContent\\PageContentFactory' => $baseDir . '/sources/application/UI/Layout/PageContent/PageContentFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\PageContent\\PageContentWithSideContent' => $baseDir . '/sources/application/UI/Layout/PageContent/PageContentWithSideContent.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\TabContainer\\TabContainer' => $baseDir . '/sources/application/UI/Layout/TabContainer/TabContainer.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\TabContainer\\Tab\\AjaxTab' => $baseDir . '/sources/application/UI/Layout/TabContainer/Tab/AjaxTab.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\TabContainer\\Tab\\Tab' => $baseDir . '/sources/application/UI/Layout/TabContainer/Tab/Tab.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\TopBar\\TopBar' => $baseDir . '/sources/application/UI/Layout/TopBar/TopBar.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\TopBar\\TopBarFactory' => $baseDir . '/sources/application/UI/Layout/TopBar/TopBarFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\UIContentBlock' => $baseDir . '/sources/application/UI/Layout/UIContentBlock.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\iUIContentBlock' => $baseDir . '/sources/application/UI/Layout/iUIContentBlock.php',
|
||||
'Combodo\\iTop\\Application\\UI\\UIBlock' => $baseDir . '/sources/application/UI/UIBlock.php',
|
||||
'Combodo\\iTop\\Application\\UI\\UIException' => $baseDir . '/sources/application/UI/UIException.php',
|
||||
'Combodo\\iTop\\Application\\UI\\iUIBlock' => $baseDir . '/sources/application/UI/iUIBlock.php',
|
||||
'Combodo\\iTop\\Composer\\iTopComposer' => $baseDir . '/sources/Composer/iTopComposer.php',
|
||||
'Combodo\\iTop\\Controller\\AjaxRenderController' => $baseDir . '/sources/Controller/AjaxRenderController.php',
|
||||
@@ -2187,7 +2193,6 @@ return array(
|
||||
'Twig_Util_DeprecationCollector' => $vendorDir . '/twig/twig/lib/Twig/Util/DeprecationCollector.php',
|
||||
'Twig_Util_TemplateDirIterator' => $vendorDir . '/twig/twig/lib/Twig/Util/TemplateDirIterator.php',
|
||||
'TypeError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/TypeError.php',
|
||||
'UIBlockManager' => $baseDir . '/sources/application/WebPage/UIBlockManager.php',
|
||||
'UIExtKeyWidget' => $baseDir . '/application/ui.extkeywidget.class.inc.php',
|
||||
'UIHTMLEditorWidget' => $baseDir . '/application/ui.htmleditorwidget.class.inc.php',
|
||||
'UILinksWidget' => $baseDir . '/application/ui.linkswidget.class.inc.php',
|
||||
|
||||
@@ -422,9 +422,15 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\PageContent\\PageContent' => __DIR__ . '/../..' . '/sources/application/UI/Layout/PageContent/PageContent.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\PageContent\\PageContentFactory' => __DIR__ . '/../..' . '/sources/application/UI/Layout/PageContent/PageContentFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\PageContent\\PageContentWithSideContent' => __DIR__ . '/../..' . '/sources/application/UI/Layout/PageContent/PageContentWithSideContent.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\TabContainer\\TabContainer' => __DIR__ . '/../..' . '/sources/application/UI/Layout/TabContainer/TabContainer.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\TabContainer\\Tab\\AjaxTab' => __DIR__ . '/../..' . '/sources/application/UI/Layout/TabContainer/Tab/AjaxTab.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\TabContainer\\Tab\\Tab' => __DIR__ . '/../..' . '/sources/application/UI/Layout/TabContainer/Tab/Tab.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\TopBar\\TopBar' => __DIR__ . '/../..' . '/sources/application/UI/Layout/TopBar/TopBar.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\TopBar\\TopBarFactory' => __DIR__ . '/../..' . '/sources/application/UI/Layout/TopBar/TopBarFactory.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\UIContentBlock' => __DIR__ . '/../..' . '/sources/application/UI/Layout/UIContentBlock.php',
|
||||
'Combodo\\iTop\\Application\\UI\\Layout\\iUIContentBlock' => __DIR__ . '/../..' . '/sources/application/UI/Layout/iUIContentBlock.php',
|
||||
'Combodo\\iTop\\Application\\UI\\UIBlock' => __DIR__ . '/../..' . '/sources/application/UI/UIBlock.php',
|
||||
'Combodo\\iTop\\Application\\UI\\UIException' => __DIR__ . '/../..' . '/sources/application/UI/UIException.php',
|
||||
'Combodo\\iTop\\Application\\UI\\iUIBlock' => __DIR__ . '/../..' . '/sources/application/UI/iUIBlock.php',
|
||||
'Combodo\\iTop\\Composer\\iTopComposer' => __DIR__ . '/../..' . '/sources/Composer/iTopComposer.php',
|
||||
'Combodo\\iTop\\Controller\\AjaxRenderController' => __DIR__ . '/../..' . '/sources/Controller/AjaxRenderController.php',
|
||||
@@ -2417,7 +2423,6 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
|
||||
'Twig_Util_DeprecationCollector' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Util/DeprecationCollector.php',
|
||||
'Twig_Util_TemplateDirIterator' => __DIR__ . '/..' . '/twig/twig/lib/Twig/Util/TemplateDirIterator.php',
|
||||
'TypeError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/TypeError.php',
|
||||
'UIBlockManager' => __DIR__ . '/../..' . '/sources/application/WebPage/UIBlockManager.php',
|
||||
'UIExtKeyWidget' => __DIR__ . '/../..' . '/application/ui.extkeywidget.class.inc.php',
|
||||
'UIHTMLEditorWidget' => __DIR__ . '/../..' . '/application/ui.htmleditorwidget.class.inc.php',
|
||||
'UILinksWidget' => __DIR__ . '/../..' . '/application/ui.linkswidget.class.inc.php',
|
||||
|
||||
@@ -35,14 +35,13 @@ try
|
||||
|
||||
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
|
||||
|
||||
$oPage = new ajax_page("");
|
||||
$oPage = new AjaxPage("");
|
||||
$oPage->no_cache();
|
||||
|
||||
$operation = utils::ReadParam('operation', '');
|
||||
$sClass = utils::ReadParam('class', 'MissingAjaxParam', false, 'class');
|
||||
|
||||
switch($operation)
|
||||
{
|
||||
switch ($operation) {
|
||||
case 'download_document':
|
||||
LoginWebPage::DoLoginEx('backoffice', false);
|
||||
$id = utils::ReadParam('id', '');
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace Combodo\iTop\Renderer;
|
||||
|
||||
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
|
||||
use Combodo\iTop\Application\UI\iUIBlock;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
* Class BlockRenderer
|
||||
@@ -220,6 +221,8 @@ class BlockRenderer
|
||||
HTML;
|
||||
}
|
||||
|
||||
// TODO 2.8.0
|
||||
//$sOutput .= utils::FilterXSS($this->RenderHtml());
|
||||
$sOutput .= $this->RenderHtml();
|
||||
|
||||
// JS last so all markup is build and ready
|
||||
@@ -269,4 +272,4 @@ HTML;
|
||||
return array_merge(['oUIBlock' => $this->oBlock], $this->aContextParams);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
namespace Combodo\iTop\Application\UI\Component\Panel;
|
||||
|
||||
|
||||
use Combodo\iTop\Application\UI\iUIBlock;
|
||||
use Combodo\iTop\Application\UI\UIBlock;
|
||||
use Combodo\iTop\Application\UI\Layout\UIContentBlock;
|
||||
|
||||
/**
|
||||
* Class Panel
|
||||
@@ -30,7 +29,7 @@ use Combodo\iTop\Application\UI\UIBlock;
|
||||
* @package Combodo\iTop\Application\UI\Component\Panel
|
||||
* @since 2.8.0
|
||||
*/
|
||||
class Panel extends UIBlock
|
||||
class Panel extends UIContentBlock
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-panel';
|
||||
@@ -119,63 +118,6 @@ class Panel extends UIBlock
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetSubBlocks()
|
||||
{
|
||||
return $this->aSubBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all sub blocks at once, replacing all existing ones
|
||||
*
|
||||
* @param \Combodo\iTop\Application\UI\iUIBlock[] $aSubBlocks
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function SetSubBlocks(array $aSubBlocks)
|
||||
{
|
||||
foreach ($aSubBlocks as $oSubBlock)
|
||||
{
|
||||
$this->AddSubBlock($oSubBlock);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add $oSubBlock, replacing any block with the same ID
|
||||
*
|
||||
* @param \Combodo\iTop\Application\UI\iUIBlock $oSubBlock
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function AddSubBlock(iUIBlock $oSubBlock)
|
||||
{
|
||||
$this->aSubBlocks[$oSubBlock->GetId()] = $oSubBlock;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the sub block identified by $sId.
|
||||
* Note that if no sub block matches the ID, it proceeds silently.
|
||||
*
|
||||
* @param string $sId ID of the sub block to remove
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function RemoveSubBlock(string $sId)
|
||||
{
|
||||
if (array_key_exists($sId, $this->aSubBlocks))
|
||||
{
|
||||
unset($this->aSubBlocks[$sId]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
@@ -195,4 +137,4 @@ class Panel extends UIBlock
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,13 @@
|
||||
namespace Combodo\iTop\Application\UI\Layout\PageContent;
|
||||
|
||||
|
||||
use Combodo\iTop\Application\UI\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\iUIBlock;
|
||||
use Combodo\iTop\Application\UI\Layout\iUIContentBlock;
|
||||
use Combodo\iTop\Application\UI\Layout\UIContentBlock;
|
||||
use Combodo\iTop\Application\UI\UIBlock;
|
||||
use Exception;
|
||||
use Combodo\iTop\Application\UI\UIException;
|
||||
use Dict;
|
||||
|
||||
/**
|
||||
* Class PageContent
|
||||
@@ -32,7 +36,7 @@ use Exception;
|
||||
* @internal
|
||||
* @since 2.8.0
|
||||
*/
|
||||
class PageContent extends UIBlock
|
||||
class PageContent extends UIBlock implements iUIContentBlock
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-page-content';
|
||||
@@ -41,8 +45,9 @@ class PageContent extends UIBlock
|
||||
/** @var string ENUM_CONTENT_AREA_MAIN The main content area */
|
||||
public const ENUM_CONTENT_AREA_MAIN = 'main';
|
||||
|
||||
/** @var \Combodo\iTop\Application\UI\iUIBlock[][] $aContentAreasBlocks Blocks for the different content parts of the layout */
|
||||
/** @var iUIContentBlock[] $aContentAreasBlocks Blocks for the different content parts of the layout */
|
||||
protected $aContentAreasBlocks;
|
||||
|
||||
/** @var string $sExtraHtmlContent HTML content that do not come from blocks and will be output as-is by the component */
|
||||
protected $sExtraHtmlContent;
|
||||
|
||||
@@ -58,102 +63,6 @@ class PageContent extends UIBlock
|
||||
$this->SetMainBlocks([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all block for a content area at once, replacing all existing ones.
|
||||
*
|
||||
* @param string $sAreaId
|
||||
* @param \Combodo\iTop\Application\UI\iUIBlock[] $aBlocks
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function SetContentAreaBlocks(string $sAreaId, array $aBlocks)
|
||||
{
|
||||
$this->aContentAreasBlocks[$sAreaId] = $aBlocks;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all blocks from the $sAreaId content area
|
||||
*
|
||||
* @param string $sAreaId
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\iUIBlock[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function GetContentAreaBlocks(string $sAreaId)
|
||||
{
|
||||
if (!array_key_exists($sAreaId, $this->aContentAreasBlocks))
|
||||
{
|
||||
throw new Exception('Could not retrieve blocks from content area "'.$sAreaId.'" as it does seem to exists for page content "'.$this->GetId().'"');
|
||||
}
|
||||
|
||||
return $this->aContentAreasBlocks[$sAreaId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the $sAreaId content area exists
|
||||
*
|
||||
* @param string $sAreaId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function IsExistingContentArea(string $sAreaId)
|
||||
{
|
||||
return isset($this->aContentAreasBlocks[$sAreaId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add $oBlock to the $sAreaId content area.
|
||||
* Note that if the area doesn't exist yet, it is created. Also if a block with the same ID already exists, it will be replaced.
|
||||
*
|
||||
* @param string $sAreaId
|
||||
* @param \Combodo\iTop\Application\UI\iUIBlock $oBlock
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function AddBlockToContentArea(string $sAreaId, iUIBlock $oBlock)
|
||||
{
|
||||
if (!array_key_exists($sAreaId, $this->aContentAreasBlocks))
|
||||
{
|
||||
$this->aContentAreasBlocks[$sAreaId] = [];
|
||||
}
|
||||
|
||||
$this->aContentAreasBlocks[$sAreaId][$oBlock->GetId()] = $oBlock;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the $sBlockId from the $sAreaId content area.
|
||||
* Note that if the $sBlockId or the $sAreaId do not exist, it proceeds silently.
|
||||
*
|
||||
* @param string $sAreaId
|
||||
* @param string $sBlockId
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function RemoveBlockFromContentArea(string $sAreaId, string $sBlockId)
|
||||
{
|
||||
if (array_key_exists($sAreaId, $this->aContentAreasBlocks) && array_key_exists($sBlockId, $this->aContentAreasBlocks[$sAreaId]))
|
||||
{
|
||||
unset($this->aContentAreasBlocks[$sAreaId][$sBlockId]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the content areas IDs
|
||||
*
|
||||
* @see static::ENUM_CONTENT_AREA_MAIN, ...
|
||||
* @return array
|
||||
*/
|
||||
protected function EnumContentAreas()
|
||||
{
|
||||
return array_keys($this->aContentAreasBlocks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all main blocks at once.
|
||||
*
|
||||
@@ -161,7 +70,7 @@ class PageContent extends UIBlock
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function SetMainBlocks(array $aBlocks)
|
||||
public function SetMainBlocks(array $aBlocks): self
|
||||
{
|
||||
$this->SetContentAreaBlocks(static::ENUM_CONTENT_AREA_MAIN, $aBlocks);
|
||||
|
||||
@@ -208,6 +117,111 @@ class PageContent extends UIBlock
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add $oBlock to the $sAreaId content area.
|
||||
* Note that if the area doesn't exist yet, it is created. Also if a block with the same ID already exists, it will be replaced.
|
||||
*
|
||||
* @param string $sAreaId
|
||||
* @param \Combodo\iTop\Application\UI\iUIBlock $oBlock
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function AddBlockToContentArea(string $sAreaId, iUIBlock $oBlock): self
|
||||
{
|
||||
if (!array_key_exists($sAreaId, $this->aContentAreasBlocks)) {
|
||||
$this->aContentAreasBlocks[$sAreaId] = new UIContentBlock($sAreaId);
|
||||
}
|
||||
|
||||
$this->aContentAreasBlocks[$sAreaId]->AddSubBlock($oBlock);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function AddSubBlock(iUIBlock $oSubBlock): iUIContentBlock
|
||||
{
|
||||
$this->AddMainBlock($oSubBlock);
|
||||
return $this->aContentAreasBlocks[static::ENUM_CONTENT_AREA_MAIN];
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the $sBlockId from the $sAreaId content area.
|
||||
* Note that if the $sBlockId or the $sAreaId do not exist, it proceeds silently.
|
||||
*
|
||||
* @param string $sAreaId
|
||||
* @param string $sBlockId
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function RemoveBlockFromContentArea(string $sAreaId, string $sBlockId)
|
||||
{
|
||||
if (array_key_exists($sAreaId, $this->aContentAreasBlocks)) {
|
||||
$this->aContentAreasBlocks[$sAreaId]->RemoveSubBlock($sBlockId);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all block for a content area at once, replacing all existing ones.
|
||||
*
|
||||
* @param string $sAreaId
|
||||
* @param \Combodo\iTop\Application\UI\iUIBlock[] $aBlocks
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
protected function SetContentAreaBlocks(string $sAreaId, array $aBlocks): self
|
||||
{
|
||||
if (!isset($this->aContentAreasBlocks[$sAreaId])) {
|
||||
$this->aContentAreasBlocks[$sAreaId] = new UIContentBlock($sAreaId);
|
||||
}
|
||||
|
||||
$this->aContentAreasBlocks[$sAreaId]->SetSubBlocks($aBlocks);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all blocks from the $sAreaId content area
|
||||
*
|
||||
* @param string $sAreaId
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\iUIBlock[]
|
||||
* @throws \Combodo\iTop\Application\UI\UIException
|
||||
*/
|
||||
protected function GetContentAreaBlocks(string $sAreaId): array
|
||||
{
|
||||
if (!array_key_exists($sAreaId, $this->aContentAreasBlocks)) {
|
||||
throw new UIException($this, Dict::Format('UIBlock:Error:CannotGetBlocks', $sAreaId, $this->GetId()));
|
||||
}
|
||||
|
||||
return $this->aContentAreasBlocks[$sAreaId]->GetSubBlocks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the $sAreaId content area exists
|
||||
*
|
||||
* @param string $sAreaId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function IsExistingContentArea(string $sAreaId)
|
||||
{
|
||||
return isset($this->aContentAreasBlocks[$sAreaId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the content areas IDs
|
||||
*
|
||||
* @return array
|
||||
* @see static::ENUM_CONTENT_AREA_MAIN, ...
|
||||
*/
|
||||
protected function EnumContentAreas()
|
||||
{
|
||||
return array_keys($this->aContentAreasBlocks);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the extra HTML content
|
||||
*
|
||||
@@ -215,18 +229,19 @@ class PageContent extends UIBlock
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function SetExtraHtmlContent(string $sExtraHtmlContent)
|
||||
public function SetExtraHtmlContent(string $sExtraHtmlContent): self
|
||||
{
|
||||
$this->sExtraHtmlContent = $sExtraHtmlContent;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function AddExtraHtmlContent(string $sExtraHtmlContent):iUIBlock
|
||||
public function AddHtml(string $sHtml): iUIBlock
|
||||
{
|
||||
$this->sExtraHtmlContent .= $sExtraHtmlContent;
|
||||
$oBlock = new Html($sHtml);
|
||||
$this->AddMainBlock($oBlock);
|
||||
|
||||
return $this;
|
||||
return $oBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,21 +254,30 @@ class PageContent extends UIBlock
|
||||
return $this->sExtraHtmlContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function GetSubBlocks()
|
||||
public function GetSubBlocks(): array
|
||||
{
|
||||
$aSubBlocks = [];
|
||||
foreach($this->EnumContentAreas() as $sAreaId)
|
||||
{
|
||||
foreach($this->GetContentAreaBlocks($sAreaId) as $oBlock)
|
||||
{
|
||||
$aSubBlocks[$oBlock->GetId()] = $oBlock;
|
||||
}
|
||||
}
|
||||
return $this->GetMainBlocks();
|
||||
}
|
||||
|
||||
return $aSubBlocks;
|
||||
public function GetSubBlock(string $sId): ?iUIBlock
|
||||
{
|
||||
return $this->aContentAreasBlocks[static::ENUM_CONTENT_AREA_MAIN]->GetSubBlock($sId);
|
||||
}
|
||||
|
||||
public function SetSubBlocks(array $aSubBlocks): iUIContentBlock
|
||||
{
|
||||
$this->SetMainBlocks($aSubBlocks);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function RemoveSubBlock(string $sId): iUIContentBlock
|
||||
{
|
||||
$this->RemoveMainBlock($sId);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function HasSubBlock(string $sId): bool
|
||||
{
|
||||
return $this->aContentAreasBlocks[static::ENUM_CONTENT_AREA_MAIN]->HasSubBlock($sId);
|
||||
}
|
||||
}
|
||||
|
||||
118
sources/application/UI/Layout/TabContainer/Tab/AjaxTab.php
Normal file
118
sources/application/UI/Layout/TabContainer/Tab/AjaxTab.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Layout\TabContainer\Tab;
|
||||
|
||||
|
||||
use Combodo\iTop\Application\UI\iUIBlock;
|
||||
use Combodo\iTop\Application\UI\Layout\iUIContentBlock;
|
||||
use Combodo\iTop\Application\UI\UIException;
|
||||
use Dict;
|
||||
use TabManager;
|
||||
|
||||
/**
|
||||
* Class AjaxTab
|
||||
*
|
||||
* @package Combodo\iTop\Application\UI\Layout\TabContainer\Tab
|
||||
*/
|
||||
class AjaxTab extends Tab
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-ajaxtab';
|
||||
public const HTML_TEMPLATE_REL_PATH = 'layouts/tabcontainer/ajaxtab/layout';
|
||||
public const JS_TEMPLATE_REL_PATH = 'layouts/tabcontainer/ajaxtab/layout';
|
||||
|
||||
private $sURL;
|
||||
private $bCache;
|
||||
|
||||
public function GetType(): string
|
||||
{
|
||||
return TabManager::ENUM_TAB_TYPE_AJAX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sHtml
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\iUIBlock
|
||||
* @throws \Combodo\iTop\Application\UI\UIException
|
||||
*/
|
||||
public function AddHtml(string $sHtml): iUIBlock
|
||||
{
|
||||
throw new UIException($this, Dict::Format('UIBlock:Error:AddBlockForbidden', $this->GetId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Combodo\iTop\Application\UI\iUIBlock $oSubBlock
|
||||
*
|
||||
* @return iUIContentBlock
|
||||
* @throws \Combodo\iTop\Application\UI\UIException
|
||||
*/
|
||||
public function AddSubBlock(iUIBlock $oSubBlock): iUIContentBlock
|
||||
{
|
||||
throw new UIException($this, Dict::Format('UIBlock:Error:AddBlockForbidden', $this->GetId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|\Combodo\iTop\Application\UI\iUIBlock[]
|
||||
*/
|
||||
public function GetSubBlocks(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $sURL
|
||||
*
|
||||
* @return AjaxTab
|
||||
*/
|
||||
public function SetURL(string $sURL): self
|
||||
{
|
||||
$this->sURL = $sURL;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $bCache
|
||||
*
|
||||
* @return AjaxTab
|
||||
*/
|
||||
public function SetCache(string $bCache): self
|
||||
{
|
||||
$this->bCache = $bCache;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function GetURL()
|
||||
{
|
||||
return $this->sURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function GetCache()
|
||||
{
|
||||
return $this->bCache ? 'true' : 'false';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
55
sources/application/UI/Layout/TabContainer/Tab/Tab.php
Normal file
55
sources/application/UI/Layout/TabContainer/Tab/Tab.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Layout\TabContainer\Tab;
|
||||
|
||||
|
||||
use Combodo\iTop\Application\UI\Layout\UIContentBlock;
|
||||
use TabManager;
|
||||
|
||||
/**
|
||||
* Class Tab
|
||||
*
|
||||
* @package Combodo\iTop\Application\UI\Layout\TabContainer\Tab
|
||||
*/
|
||||
class Tab extends UIContentBlock
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-tab';
|
||||
public const HTML_TEMPLATE_REL_PATH = 'layouts/tabcontainer/tab/layout';
|
||||
public const JS_TEMPLATE_REL_PATH = 'layouts/tabcontainer/tab/layout';
|
||||
|
||||
protected $sTitle;
|
||||
|
||||
public function __construct(string $sTabCode, string $sTitle)
|
||||
{
|
||||
parent::__construct($sTabCode);
|
||||
$this->sTitle = $sTitle;
|
||||
}
|
||||
|
||||
public function GetType(): string
|
||||
{
|
||||
return TabManager::ENUM_TAB_TYPE_HTML;
|
||||
}
|
||||
|
||||
public function GetTitle(): string
|
||||
{
|
||||
return $this->sTitle;
|
||||
}
|
||||
}
|
||||
125
sources/application/UI/Layout/TabContainer/TabContainer.php
Normal file
125
sources/application/UI/Layout/TabContainer/TabContainer.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2020 Combodo SARL
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Layout\TabContainer;
|
||||
|
||||
|
||||
use Combodo\iTop\Application\UI\iUIBlock;
|
||||
use Combodo\iTop\Application\UI\Layout\iUIContentBlock;
|
||||
use Combodo\iTop\Application\UI\Layout\TabContainer\Tab\AjaxTab;
|
||||
use Combodo\iTop\Application\UI\Layout\TabContainer\Tab\Tab;
|
||||
use Combodo\iTop\Application\UI\Layout\UIContentBlock;
|
||||
use Combodo\iTop\Application\UI\UIException;
|
||||
use Dict;
|
||||
|
||||
/**
|
||||
* Class TabContainer
|
||||
*
|
||||
* @package Combodo\iTop\Application\UI\Layout\TabContainer
|
||||
*/
|
||||
class TabContainer extends UIContentBlock
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-tabcontainer';
|
||||
public const HTML_TEMPLATE_REL_PATH = 'layouts/tabcontainer/layout';
|
||||
public const JS_TEMPLATE_REL_PATH = 'layouts/tabcontainer/layout';
|
||||
|
||||
private $sName;
|
||||
private $sPrefix;
|
||||
|
||||
/**
|
||||
* TabContainer constructor.
|
||||
*
|
||||
* @param $sName
|
||||
* @param $sPrefix
|
||||
*/
|
||||
public function __construct($sName, $sPrefix)
|
||||
{
|
||||
parent::__construct("{$sName}".((!empty($sPrefix)) ? "-{$sPrefix}" : ""));
|
||||
|
||||
$this->sName = $sName;
|
||||
$this->sPrefix = $sPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sTabCode
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function TabExists(string $sTabCode): bool
|
||||
{
|
||||
return $this->HasSubBlock($sTabCode);
|
||||
}
|
||||
|
||||
public function GetTab($sTabCode): ?Tab
|
||||
{
|
||||
/** @var \Combodo\iTop\Application\UI\Layout\TabContainer\Tab\Tab $oTab */
|
||||
$oTab = $this->GetSubBlock($sTabCode);
|
||||
return $oTab;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sTabCode
|
||||
* @param string $sTitle
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Layout\TabContainer\Tab\Tab
|
||||
* @throws \Combodo\iTop\Application\UI\UIException
|
||||
*/
|
||||
public function AddAjaxTab(string $sTabCode, string $sTitle): Tab
|
||||
{
|
||||
$oTab = new AjaxTab($sTabCode, $sTitle);
|
||||
$this->AddSubBlock($oTab);
|
||||
return $oTab;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $sTabCode
|
||||
* @param string $sTitle
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Layout\TabContainer\Tab\Tab
|
||||
* @throws \Combodo\iTop\Application\UI\UIException
|
||||
*/
|
||||
public function AddTab(string $sTabCode, string $sTitle): Tab
|
||||
{
|
||||
$oTab = new Tab($sTabCode, $sTitle);
|
||||
$this->AddSubBlock($oTab);
|
||||
return $oTab;
|
||||
}
|
||||
|
||||
public function RemoveTab(string $sTabCode): self
|
||||
{
|
||||
$this->RemoveSubBlock($sTabCode);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Combodo\iTop\Application\UI\iUIBlock $oSubBlock
|
||||
*
|
||||
* @return iUIContentBlock
|
||||
* @throws \Combodo\iTop\Application\UI\UIException
|
||||
*/
|
||||
public function AddSubBlock(iUIBlock $oSubBlock): iUIContentBlock
|
||||
{
|
||||
if (!($oSubBlock instanceof Tab)) {
|
||||
throw new UIException($this, Dict::Format('UIBlock:Error:AddBlockNotTabForbidden', $oSubBlock->GetId(), $this->GetId()));
|
||||
}
|
||||
return parent::AddSubBlock($oSubBlock);
|
||||
}
|
||||
}
|
||||
113
sources/application/UI/Layout/UIContentBlock.php
Normal file
113
sources/application/UI/Layout/UIContentBlock.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Layout;
|
||||
|
||||
|
||||
use Combodo\iTop\Application\UI\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\iUIBlock;
|
||||
use Combodo\iTop\Application\UI\UIBlock;
|
||||
|
||||
class UIContentBlock extends UIBlock implements iUIContentBlock
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-contentblock';
|
||||
public const HTML_TEMPLATE_REL_PATH = 'layouts/contentblock/layout';
|
||||
public const JS_TEMPLATE_REL_PATH = 'layouts/contentblock/layout';
|
||||
|
||||
protected $aSubBlocks;
|
||||
|
||||
/**
|
||||
* UIContentBlock constructor.
|
||||
*
|
||||
* @param string|null $sName
|
||||
*/
|
||||
public function __construct(string $sName = null)
|
||||
{
|
||||
parent::__construct($sName);
|
||||
|
||||
$this->aSubBlocks = [];
|
||||
}
|
||||
|
||||
public function AddHtml(string $sHtml): iUIBlock
|
||||
{
|
||||
$oBlock = new Html($sHtml);
|
||||
$this->AddSubBlock($oBlock);
|
||||
|
||||
return $oBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetSubBlocks(): array
|
||||
{
|
||||
return $this->aSubBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sId
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\iUIBlock|null
|
||||
*/
|
||||
public function GetSubBlock(string $sId): ?iUIBlock
|
||||
{
|
||||
return isset($this->aSubBlocks[$sId]) ? $this->aSubBlocks[$sId] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all sub blocks at once, replacing all existing ones
|
||||
*
|
||||
* @param \Combodo\iTop\Application\UI\iUIBlock[] $aSubBlocks
|
||||
*
|
||||
* @return iUIContentBlock
|
||||
*/
|
||||
public function SetSubBlocks(array $aSubBlocks): iUIContentBlock
|
||||
{
|
||||
foreach ($aSubBlocks as $oSubBlock) {
|
||||
$this->AddSubBlock($oSubBlock);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add $oSubBlock, replacing any block with the same ID
|
||||
*
|
||||
* @param \Combodo\iTop\Application\UI\iUIBlock $oSubBlock
|
||||
*
|
||||
* @return iUIContentBlock
|
||||
*/
|
||||
public function AddSubBlock(iUIBlock $oSubBlock): iUIContentBlock
|
||||
{
|
||||
$this->aSubBlocks[$oSubBlock->GetId()] = $oSubBlock;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the sub block identified by $sId.
|
||||
* Note that if no sub block matches the ID, it proceeds silently.
|
||||
*
|
||||
* @param string $sId ID of the sub block to remove
|
||||
*
|
||||
* @return iUIContentBlock
|
||||
*/
|
||||
public function RemoveSubBlock(string $sId): iUIContentBlock
|
||||
{
|
||||
if ($this->HasSubBlock($sId)) {
|
||||
unset($this->aSubBlocks[$sId]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function HasSubBlock(string $sId): bool
|
||||
{
|
||||
return array_key_exists($sId, $this->aSubBlocks);
|
||||
}
|
||||
}
|
||||
56
sources/application/UI/Layout/iUIContentBlock.php
Normal file
56
sources/application/UI/Layout/iUIContentBlock.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Application\UI\Layout;
|
||||
|
||||
use Combodo\iTop\Application\UI\iUIBlock;
|
||||
|
||||
interface iUIContentBlock
|
||||
{
|
||||
public function AddHtml(string $sHtml): iUIBlock;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetSubBlocks(): array;
|
||||
|
||||
/**
|
||||
* @param string $sId
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\iUIBlock|null
|
||||
*/
|
||||
public function GetSubBlock(string $sId): ?iUIBlock;
|
||||
|
||||
/**
|
||||
* Set all sub blocks at once, replacing all existing ones
|
||||
*
|
||||
* @param \Combodo\iTop\Application\UI\iUIBlock[] $aSubBlocks
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function SetSubBlocks(array $aSubBlocks): iUIContentBlock;
|
||||
|
||||
/**
|
||||
* Add $oSubBlock, replacing any block with the same ID
|
||||
*
|
||||
* @param \Combodo\iTop\Application\UI\iUIBlock $oSubBlock
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function AddSubBlock(iUIBlock $oSubBlock): iUIContentBlock;
|
||||
|
||||
/**
|
||||
* Remove the sub block identified by $sId.
|
||||
* Note that if no sub block matches the ID, it proceeds silently.
|
||||
*
|
||||
* @param string $sId ID of the sub block to remove
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function RemoveSubBlock(string $sId): iUIContentBlock;
|
||||
|
||||
public function HasSubBlock(string $sId): bool;
|
||||
}
|
||||
@@ -209,8 +209,7 @@ abstract class UIBlock implements iUIBlock
|
||||
return $aFiles;
|
||||
}
|
||||
|
||||
|
||||
public function AddExtraHtmlContent(string $sHTML) :iUIBlock
|
||||
public function AddHtml(string $sHTML): iUIBlock
|
||||
{
|
||||
// By default this does nothing
|
||||
return $this;
|
||||
|
||||
20
sources/application/UI/UIException.php
Normal file
20
sources/application/UI/UIException.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
|
||||
namespace Combodo\iTop\Application\UI;
|
||||
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
class UIException extends Exception
|
||||
{
|
||||
public function __construct(iUIBlock $oBlock, string $message = "", int $code = 0, Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($oBlock->GetId().': '.$message, $code, $previous);
|
||||
}
|
||||
}
|
||||
@@ -115,5 +115,5 @@ interface iUIBlock
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function AddExtraHtmlContent(string $sHTML) :iUIBlock;
|
||||
public function AddHtml(string $sHTML): iUIBlock;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
|
||||
use Combodo\iTop\Application\UI\iUIBlock;
|
||||
use Combodo\iTop\Renderer\BlockRenderer;
|
||||
|
||||
class AjaxPage extends WebPage implements iTabbedPage
|
||||
{
|
||||
@@ -15,6 +18,7 @@ class AjaxPage extends WebPage implements iTabbedPage
|
||||
protected $m_sReadyScript;
|
||||
protected $m_oTabs;
|
||||
private $m_sMenu; // If set, then the menu will be updated
|
||||
const DEFAULT_PAGE_TEMPLATE_REL_PATH = 'pages/backoffice/ajaxpage/layout';
|
||||
|
||||
/**
|
||||
* constructor for the web page
|
||||
@@ -44,7 +48,7 @@ class AjaxPage extends WebPage implements iTabbedPage
|
||||
*/
|
||||
public function AddTabContainer($sTabContainer, $sPrefix = '')
|
||||
{
|
||||
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
|
||||
$this->AddUiBlock($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,10 +199,10 @@ EOF
|
||||
}
|
||||
|
||||
// Render the blocks
|
||||
$this->s_content = $this->oUIBlockManager->RenderIntoContent($this->s_content, $this);
|
||||
//$this->s_content = $this->oUIBlockManager->RenderIntoContent($this->s_content, $this);
|
||||
|
||||
// Render the tabs in the page (if any)
|
||||
$this->s_content = $this->m_oTabs->RenderIntoContent($this->s_content, $this);
|
||||
//$this->s_content = $this->m_oTabs->RenderIntoContent($this->s_content, $this);
|
||||
|
||||
// Additional UI widgets to be activated inside the ajax fragment
|
||||
// Important: Testing the content type is not enough because some ajax handlers have not correctly positionned the flag (e.g json response corrupted by the script)
|
||||
@@ -211,6 +215,40 @@ EOF
|
||||
}
|
||||
$this->outputCollapsibleSectionInit();
|
||||
|
||||
|
||||
$aData = [];
|
||||
$aData['oLayout'] = $this->oContentLayout;
|
||||
|
||||
$aData['aPage'] = [
|
||||
'sAbsoluteUrlAppRoot' => addslashes(utils::GetAbsoluteUrlAppRoot()),
|
||||
'sTitle' => $this->s_title,
|
||||
'aMetadata' => [
|
||||
'sCharset' => static::PAGES_CHARSET,
|
||||
'sLang' => $this->GetLanguageForMetadata(),
|
||||
],
|
||||
'aCssFiles' => $this->a_linked_stylesheets,
|
||||
'aCssInline' => $this->a_styles,
|
||||
'aJsFiles' => $this->a_linked_scripts,
|
||||
'aJsInlineLive' => $this->a_scripts,
|
||||
// TODO 2.8.0: TEMP, used while developping, remove it.
|
||||
'sSanitizedContent' => utils::FilterXSS($this->s_content),
|
||||
'sDeferredContent' => utils::FilterXSS($this->s_deferred_content),
|
||||
];
|
||||
|
||||
$oTwigEnv = TwigHelper::GetTwigEnvironment(BlockRenderer::TWIG_BASE_PATH, BlockRenderer::TWIG_ADDITIONAL_PATHS);
|
||||
// Render final TWIG into global HTML
|
||||
$oKpi = new ExecutionKPI();
|
||||
$sHtml = TwigHelper::RenderTemplate($oTwigEnv, $aData, $this->GetTemplateRelPath());
|
||||
$oKpi->ComputeAndReport('TWIG rendering');
|
||||
|
||||
// Echo global HTML
|
||||
$oKpi = new ExecutionKPI();
|
||||
echo $sHtml;
|
||||
$oKpi->ComputeAndReport('Echoing ('.round(strlen($sHtml) / 1024).' Kb)');
|
||||
|
||||
|
||||
return;
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$s_captured_output = $this->ob_get_clean_safe();
|
||||
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline')) {
|
||||
@@ -297,13 +335,14 @@ EOF
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function add($sHtml)
|
||||
public function add($sHtml): ?iUIBlock
|
||||
{
|
||||
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != '')) {
|
||||
$this->m_oTabs->AddToTab($this->m_oTabs->GetCurrentTabContainer(), $this->m_oTabs->GetCurrentTab(), $sHtml);
|
||||
} else {
|
||||
parent::add($sHtml);
|
||||
return parent::add($sHtml);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
use \Combodo\iTop\Application\UI\iUIBlock;
|
||||
|
||||
/**
|
||||
* CLI page
|
||||
@@ -48,9 +49,10 @@ class CLIPage implements Page
|
||||
}
|
||||
}
|
||||
|
||||
public function add($sText)
|
||||
public function add($sText): ?iUIBlock
|
||||
{
|
||||
echo $sText;
|
||||
return null;
|
||||
}
|
||||
|
||||
public function p($sText)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
use \Combodo\iTop\Application\UI\iUIBlock;
|
||||
|
||||
/**
|
||||
* Simple web page with no includes or fancy formatting, useful to generateXML documents
|
||||
@@ -64,9 +65,10 @@ class CSVPage extends WebPage
|
||||
{
|
||||
}
|
||||
|
||||
public function add($sText)
|
||||
public function add($sText): ?iUIBlock
|
||||
{
|
||||
$this->s_content .= $sText;
|
||||
return null;
|
||||
}
|
||||
|
||||
public function p($sText)
|
||||
|
||||
@@ -22,30 +22,29 @@
|
||||
*/
|
||||
class NiceWebPage extends WebPage
|
||||
{
|
||||
const DEFAULT_PAGE_TEMPLATE_REL_PATH = 'pages/backoffice/nicewebpage/layout';
|
||||
var $m_aReadyScripts;
|
||||
var $m_sRootUrl;
|
||||
|
||||
public function __construct($s_title, $bPrintable = false)
|
||||
{
|
||||
parent::__construct($s_title, $bPrintable);
|
||||
|
||||
public function __construct($s_title, $bPrintable = false)
|
||||
{
|
||||
parent::__construct($s_title, $bPrintable);
|
||||
$this->m_aReadyScripts = array();
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.min.js');
|
||||
if(utils::IsDevelopmentEnvironment()) // Needed since many other plugins still rely on oldies like $.browser
|
||||
if (utils::IsDevelopmentEnvironment()) // Needed since many other plugins still rely on oldies like $.browser
|
||||
{
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate.dev.js');
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-migrate.prod.min.js');
|
||||
}
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-ui.custom.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery-ui.custom.min.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/utils.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/hovertip.js');
|
||||
// table sorting
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablesorter.pager.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.tablehover.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/table-selectable-lines.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/table-selectable-lines.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/field_sorter.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/datatable.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.positionBy.js');
|
||||
@@ -249,13 +248,24 @@ EOF
|
||||
parent::output();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
* @since 2.7.0
|
||||
*/
|
||||
protected function LoadTheme()
|
||||
{
|
||||
// TODO 2.8.0: Remove light-grey when development of Full Moon is done.
|
||||
// TODO 2.8.0: Reuse theming mechanism for Full Moon
|
||||
$sCssThemeUrl = ThemeHandler::GetCurrentThemeUrl();
|
||||
$this->add_linked_stylesheet($sCssThemeUrl);
|
||||
|
||||
$sCssRelPath = utils::GetCSSFromSASS(
|
||||
'css/backoffice/main.scss',
|
||||
array(
|
||||
APPROOT.'css/backoffice/',
|
||||
)
|
||||
);
|
||||
$this->add_saas($sCssRelPath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\iUIBlock;
|
||||
|
||||
|
||||
/**
|
||||
* Generic interface common to CLI and Web pages
|
||||
@@ -24,7 +26,7 @@ interface Page
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($sText);
|
||||
public function add($sText): ?iUIBlock;
|
||||
|
||||
/**
|
||||
* Add a paragraph to the body of the page
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
* @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
|
||||
@@ -15,13 +18,16 @@ class TabManager
|
||||
|
||||
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 = array();
|
||||
$this->m_aTabs = [];
|
||||
$this->m_sCurrentTabContainer = '';
|
||||
$this->m_sCurrentTab = '';
|
||||
}
|
||||
@@ -30,13 +36,14 @@ class TabManager
|
||||
* @param string $sTabContainer
|
||||
* @param string $sPrefix
|
||||
*
|
||||
* @return string
|
||||
* @return \Combodo\iTop\Application\UI\iUIBlock
|
||||
*/
|
||||
public function AddTabContainer($sTabContainer, $sPrefix = '')
|
||||
public function AddTabContainer(string $sTabContainer, $sPrefix = ''): TabContainer
|
||||
{
|
||||
$this->m_aTabs[$sTabContainer] = array('prefix' => $sPrefix, 'tabs' => array());
|
||||
$oTabContainer = new TabContainer($sTabContainer, $sPrefix);
|
||||
$this->m_aTabs[$sTabContainer] = $oTabContainer;
|
||||
|
||||
return "\$Tabs:$sTabContainer\$";
|
||||
return $oTabContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,19 +51,18 @@ class TabManager
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function AddToCurrentTab($sHtml)
|
||||
public function AddToCurrentTab(string $sHtml): void
|
||||
{
|
||||
$this->AddToTab($this->m_sCurrentTabContainer, $this->m_sCurrentTab, $sHtml);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @deprecated 2.8.0
|
||||
*/
|
||||
public function GetCurrentTabLength()
|
||||
{
|
||||
$iLength = isset($this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html']) ? strlen($this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html']) : 0;
|
||||
|
||||
return $iLength;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,15 +73,11 @@ class TabManager
|
||||
* @param integer $iLength The length/offset at which to truncate the tab
|
||||
*
|
||||
* @return string The truncated part
|
||||
* @deprecated 2.8.0
|
||||
*/
|
||||
public function TruncateTab($sTabContainer, $sTab, $iLength)
|
||||
public function TruncateTab(string $sTabContainer, string $sTab, int $iLength)
|
||||
{
|
||||
$sResult = substr($this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html'],
|
||||
$iLength);
|
||||
$this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html'] = substr($this->m_aTabs[$this->m_sCurrentTabContainer]['tabs'][$this->m_sCurrentTab]['html'],
|
||||
0, $iLength);
|
||||
|
||||
return $sResult;
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,9 +86,9 @@ class TabManager
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function TabExists($sTabContainer, $sTab)
|
||||
public function TabExists(string $sTabContainer, string $sTab)
|
||||
{
|
||||
return isset($this->m_aTabs[$sTabContainer]['tabs'][$sTab]);
|
||||
return isset($this->m_aTabs[$sTabContainer]) ? $this->m_aTabs[$sTabContainer]->TabExists($sTab) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,6 +99,14 @@ class TabManager
|
||||
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
|
||||
@@ -106,19 +116,16 @@ class TabManager
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function AddToTab($sTabContainer, $sTabCode, $sHtml, $sTabTitle = null)
|
||||
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);
|
||||
}
|
||||
|
||||
// If target tab is not of type 'html', throw an exception
|
||||
if ($this->m_aTabs[$sTabContainer]['tabs'][$sTabCode]['type'] != static::ENUM_TAB_TYPE_HTML) {
|
||||
throw new Exception("Cannot add HTML content to the tab '$sTabCode' of type '{$this->m_aTabs[$sTabContainer]['tabs'][$sTabCode]['type']}'");
|
||||
}
|
||||
$oTab = $this->GetTab($sTabContainer, $sTabCode);
|
||||
|
||||
// Append to the content of the tab
|
||||
$this->m_aTabs[$sTabContainer]['tabs'][$sTabCode]['html'] .= $sHtml;
|
||||
$oTab->AddHtml($sHtml);
|
||||
|
||||
return ''; // Nothing to add to the page for now
|
||||
}
|
||||
@@ -139,16 +146,21 @@ class TabManager
|
||||
/**
|
||||
* @param string $sTabCode
|
||||
*
|
||||
* @param string|null $sTabTitle
|
||||
*
|
||||
* @return string
|
||||
* @throws \Combodo\iTop\Application\UI\UIException
|
||||
*/
|
||||
public function SetCurrentTab($sTabCode = '', $sTabTitle = null)
|
||||
public function SetCurrentTab(string $sTabCode = '', string $sTabTitle = null): ?string
|
||||
{
|
||||
$sPreviousTabCode = $this->m_sCurrentTab;
|
||||
$this->m_sCurrentTab = $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);
|
||||
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;
|
||||
@@ -166,16 +178,20 @@ class TabManager
|
||||
* @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($sTabCode, $sUrl, $bCache = true, $sTabTitle = null)
|
||||
public function AddAjaxTab(string $sTabCode, string $sUrl, bool $bCache = true, string $sTabTitle = null): string
|
||||
{
|
||||
// Set the content of the tab
|
||||
$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;
|
||||
/** @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
|
||||
}
|
||||
@@ -200,14 +216,14 @@ class TabManager
|
||||
* @param string $sTabCode
|
||||
* @param string|null $sTabContainer
|
||||
*/
|
||||
public function RemoveTab($sTabCode, $sTabContainer = null)
|
||||
public function RemoveTab(string $sTabCode, string $sTabContainer = null)
|
||||
{
|
||||
if ($sTabContainer == null) {
|
||||
$sTabContainer = $this->m_sCurrentTabContainer;
|
||||
}
|
||||
if (isset($this->m_aTabs[$sTabContainer]['tabs'][$sTabCode])) {
|
||||
if (isset($this->m_aTabs[$sTabContainer]) && $this->m_aTabs[$sTabContainer]->TabExists($sTabCode)) {
|
||||
// Delete the content of the tab
|
||||
unset($this->m_aTabs[$sTabContainer]['tabs'][$sTabCode]);
|
||||
$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)) {
|
||||
@@ -224,16 +240,18 @@ class TabManager
|
||||
*
|
||||
* @return mixed The actual name of the tab (as a string) or false if not found
|
||||
*/
|
||||
public function FindTab($sPattern, $sTabContainer = null)
|
||||
public function FindTab(string $sPattern, string $sTabContainer = null)
|
||||
{
|
||||
$result = false;
|
||||
if ($sTabContainer == null) {
|
||||
$sTabContainer = $this->m_sCurrentTabContainer;
|
||||
}
|
||||
foreach ($this->m_aTabs[$sTabContainer]['tabs'] as $sTabCode => $void) {
|
||||
if (preg_match($sPattern, $sTabCode)) {
|
||||
$result = $sTabCode;
|
||||
break;
|
||||
if (isset($this->m_aTabs[$sTabContainer])) {
|
||||
foreach ($this->m_aTabs[$sTabContainer]->GetSubBlocks() as $sTabCode => $void) {
|
||||
if (preg_match($sPattern, $sTabCode)) {
|
||||
$result = $sTabCode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,26 +268,11 @@ class TabManager
|
||||
* @param string $sTabCode
|
||||
*
|
||||
* @return string
|
||||
* @deprecated 2.8.0
|
||||
*/
|
||||
public function SelectTab($sTabContainer, $sTabCode)
|
||||
public function SelectTab(string $sTabContainer, string $sTabCode)
|
||||
{
|
||||
$container_index = 0;
|
||||
$tab_index = 0;
|
||||
foreach ($this->m_aTabs as $sCurrentTabContainerName => $aTabs) {
|
||||
if ($sTabContainer == $sCurrentTabContainerName) {
|
||||
foreach ($aTabs['tabs'] as $sCurrentTabLabel => $void) {
|
||||
if ($sCurrentTabLabel == $sTabCode) {
|
||||
break;
|
||||
}
|
||||
$tab_index++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$container_index++;
|
||||
}
|
||||
$sSelector = '#tabbedContent_'.$container_index.' > ul';
|
||||
|
||||
return "window.setTimeout(\"$('$sSelector').tabs('select', $tab_index);\", 100);"; // Let the time to the tabs widget to initialize
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -277,14 +280,15 @@ class TabManager
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
* @return mixed
|
||||
* @deprecated 2.8.0
|
||||
*/
|
||||
public function RenderIntoContent($sContent, WebPage $oPage)
|
||||
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'];
|
||||
$container_index = 0;
|
||||
if (count($aTabs['tabs']) > 0) {
|
||||
// Clean tabs
|
||||
foreach ($aTabs['tabs'] as $sTabCode => $aTabData) {
|
||||
@@ -384,37 +388,36 @@ EOF
|
||||
* @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($sTabContainer, $sTabCode, $sTabType = self::DEFAULT_TAB_TYPE, $sTabTitle = null)
|
||||
protected function InitTab(string $sTabContainer, string $sTabCode, string $sTabType = self::DEFAULT_TAB_TYPE, string $sTabTitle = null): Tab
|
||||
{
|
||||
$oTab = null;
|
||||
if (!$this->TabExists($sTabContainer, $sTabCode)) {
|
||||
// Container
|
||||
if (!array_key_exists($sTabContainer, $this->m_aTabs)) {
|
||||
$this->m_aTabs[$sTabContainer] = array(
|
||||
'prefix' => '',
|
||||
'tabs' => array(),
|
||||
);
|
||||
if (!isset($this->m_aTabs[$sTabContainer])) {
|
||||
$oTabContainer = $this->AddTabContainer($sTabContainer);
|
||||
} else {
|
||||
$oTabContainer = $this->m_aTabs[$sTabContainer];
|
||||
}
|
||||
|
||||
// Common properties
|
||||
$this->m_aTabs[$sTabContainer]['tabs'][$sTabCode] = array(
|
||||
'type' => $sTabType,
|
||||
'title' => ($sTabTitle !== null) ? Dict::S($sTabTitle) : Dict::S($sTabCode),
|
||||
);
|
||||
$sTitle = ($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;
|
||||
$oTab = $oTabContainer->AddAjaxTab($sTabCode, $sTitle);
|
||||
break;
|
||||
|
||||
case static::ENUM_TAB_TYPE_HTML:
|
||||
default:
|
||||
$this->m_aTabs[$sTabContainer]['tabs'][$sTabCode]['html'] = null;
|
||||
$oTab = $oTabContainer->AddTab($sTabCode, $sTitle);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$oTab = $this->GetTab($sTabContainer, $sTabCode);
|
||||
}
|
||||
|
||||
return $oTab;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\UI\iUIBlock;
|
||||
use Combodo\iTop\Renderer\BlockRenderer;
|
||||
|
||||
|
||||
class UIBlockManager
|
||||
{
|
||||
/** @var iUIBlock[] */
|
||||
private $aMainBlocks; // Top blocks to render
|
||||
/** @var iUIBlock[] */
|
||||
private $aAllBlocks; // All blocks recursively
|
||||
private $sCurrentBlockId; // Current block ('' for no current block)
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->aMainBlocks = [];
|
||||
$this->aAllBlocks = [];
|
||||
$this->sCurrentBlockId = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a block to render
|
||||
*
|
||||
* @param iUIBlock $oUIBlock
|
||||
*/
|
||||
public function AddBlock(iUIBlock $oUIBlock)
|
||||
{
|
||||
$sId = $oUIBlock->GetId();
|
||||
$this->aMainBlocks[$sId] = $oUIBlock;
|
||||
$this->aAllBlocks[$sId] = $oUIBlock;
|
||||
$this->sCurrentBlockId = $sId;
|
||||
|
||||
$aSubBlocks = $oUIBlock->GetSubBlocks();
|
||||
$this->aAllBlocks = array_merge($this->aAllBlocks, $aSubBlocks);
|
||||
}
|
||||
|
||||
public function AddHtml(string $sHTML)
|
||||
{
|
||||
if ($this->sCurrentBlockId == '') {
|
||||
return;
|
||||
}
|
||||
$this->aAllBlocks[$this->sCurrentBlockId]->AddExtraHtmlContent($sHTML);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current UIBlock to write into
|
||||
*
|
||||
* @param string $sId
|
||||
*/
|
||||
public function SetCurrentUIBlock(string $sId = '')
|
||||
{
|
||||
$this->sCurrentBlockId = $sId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if an UIBlock is the current target to write into
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function HasCurrentBlock(): bool
|
||||
{
|
||||
return isset($this->aAllBlocks[$this->sCurrentBlockId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current UIBlock
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\iUIBlock|null
|
||||
*/
|
||||
public function GetCurrentUIBlock(): ?iUIBlock
|
||||
{
|
||||
return $this->GetBlock($this->sCurrentBlockId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get UIBlock from Id
|
||||
*
|
||||
* @param string $sId
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\iUIBlock|null
|
||||
*/
|
||||
public function GetBlock(string $sId): ?iUIBlock
|
||||
{
|
||||
if (isset($this->aAllBlocks[$sId])) {
|
||||
return $this->aAllBlocks[$sId];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the blocks into the page and return the HTML to add
|
||||
*
|
||||
* @param string $sContent
|
||||
* @param \WebPage $oPage
|
||||
*
|
||||
* @return string
|
||||
* @throws \ReflectionException
|
||||
* @throws \Twig\Error\LoaderError
|
||||
* @throws \Twig\Error\RuntimeError
|
||||
* @throws \Twig\Error\SyntaxError
|
||||
*/
|
||||
public function RenderIntoContent(string &$sContent, WebPage $oPage): string
|
||||
{
|
||||
foreach ($this->aMainBlocks as $oBlock) {
|
||||
$oBlockRenderer = new BlockRenderer($oBlock);
|
||||
|
||||
// Add HTML
|
||||
$sContent .= $oBlockRenderer->RenderHtml();
|
||||
|
||||
// Add inline CSS and JS
|
||||
$oPage->add_style($oBlockRenderer->RenderCssInline());
|
||||
$oPage->add_ready_script($oBlockRenderer->RenderJsInline());
|
||||
|
||||
// Add external files
|
||||
foreach ($oBlockRenderer->GetCssFiles() as $sFile) {
|
||||
$oPage->add_linked_stylesheet($sFile);
|
||||
}
|
||||
foreach ($oBlockRenderer->GetJsFiles() as $sFile) {
|
||||
$oPage->add_linked_script($sFile);
|
||||
}
|
||||
}
|
||||
return $sContent;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
|
||||
use Combodo\iTop\Application\UI\iUIBlock;
|
||||
use Combodo\iTop\Application\UI\Layout\UIContentBlock;
|
||||
use Combodo\iTop\Renderer\BlockRenderer;
|
||||
|
||||
|
||||
@@ -42,6 +43,8 @@ class WebPage implements Page
|
||||
* @since 2.7.0 N°2529
|
||||
*/
|
||||
const PAGES_CHARSET = 'utf-8';
|
||||
const DEFAULT_PAGE_TEMPLATE_REL_PATH = 'pages/backoffice/webpage/layout';
|
||||
|
||||
protected $s_title;
|
||||
protected $s_content;
|
||||
protected $s_deferred_content;
|
||||
@@ -64,8 +67,14 @@ class WebPage implements Page
|
||||
protected $bPrintable;
|
||||
protected $bHasCollapsibleSection;
|
||||
protected $bAddJSDict;
|
||||
/** @var UIBlockManager */
|
||||
protected $oUIBlockManager;
|
||||
/** @var \Combodo\iTop\Application\UI\Layout\iUIContentBlock $oContentLayout */
|
||||
protected $oContentLayout;
|
||||
protected $sTemplateRelPath;
|
||||
|
||||
/**
|
||||
* @var bool|string|string[]
|
||||
*/
|
||||
private $s_OutputFormat;
|
||||
|
||||
/**
|
||||
* WebPage constructor.
|
||||
@@ -97,7 +106,9 @@ class WebPage implements Page
|
||||
$this->bHasCollapsibleSection = false;
|
||||
$this->bPrintable = $bPrintable;
|
||||
$this->bAddJSDict = true;
|
||||
$this->oUIBlockManager = new UIBlockManager();
|
||||
$this->oContentLayout = new UIContentBlock();
|
||||
$this->SetTemplateRelPath(static::DEFAULT_PAGE_TEMPLATE_REL_PATH);
|
||||
|
||||
ob_start(); // Start capturing the output
|
||||
}
|
||||
|
||||
@@ -128,13 +139,9 @@ class WebPage implements Page
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function add($s_html)
|
||||
public function add($s_html): ?iUIBlock
|
||||
{
|
||||
if ($this->oUIBlockManager->HasCurrentBlock()) {
|
||||
$this->oUIBlockManager->AddHtml($s_html);
|
||||
} else {
|
||||
$this->s_content .= $s_html;
|
||||
}
|
||||
return $this->oContentLayout->AddHtml($s_html);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -303,19 +310,13 @@ class WebPage implements Page
|
||||
*
|
||||
* @param \Combodo\iTop\Application\UI\iUIBlock $oBlock
|
||||
*
|
||||
* @param \WebPage $iTopWebPage
|
||||
*
|
||||
* @return void
|
||||
* @throws \ReflectionException
|
||||
* @throws \Twig\Error\LoaderError
|
||||
* @throws \Twig\Error\RuntimeError
|
||||
* @throws \Twig\Error\SyntaxError
|
||||
* @throws \Exception
|
||||
* @return \Combodo\iTop\Application\UI\iUIBlock block added
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public function AddUiBlock(iUIBlock $oBlock, WebPage $iTopWebPage)
|
||||
public function AddUiBlock(iUIBlock $oBlock): iUIBlock
|
||||
{
|
||||
$iTopWebPage->GetUIBlockManager()->AddBlock($oBlock);
|
||||
$this->oContentLayout->AddSubBlock($oBlock);
|
||||
return $oBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -695,112 +696,84 @@ class WebPage implements Page
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
foreach ($this->a_headers as $s_header)
|
||||
{
|
||||
header($s_header);
|
||||
}
|
||||
|
||||
$s_captured_output = $this->ob_get_clean_safe();
|
||||
echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
|
||||
echo "<html>\n";
|
||||
echo "<head>\n";
|
||||
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
|
||||
echo "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, shrink-to-fit=no\" />";
|
||||
echo "<title>".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</title>\n";
|
||||
echo $this->get_base_tag();
|
||||
|
||||
// Render the blocks
|
||||
$this->s_content = $this->oUIBlockManager->RenderIntoContent($this->s_content, $this);
|
||||
|
||||
// First put stylesheets so they can be loaded before browser interprets JS files, otherwise visual glitch can occur.
|
||||
foreach ($this->a_linked_stylesheets as $a_stylesheet)
|
||||
{
|
||||
if (strpos($a_stylesheet['link'], '?') === false)
|
||||
{
|
||||
$s_stylesheet = $a_stylesheet['link']."?t=".utils::GetCacheBusterTimestamp();
|
||||
}
|
||||
else
|
||||
{
|
||||
$s_stylesheet = $a_stylesheet['link']."&t=".utils::GetCacheBusterTimestamp();
|
||||
}
|
||||
if ($a_stylesheet['condition'] != "")
|
||||
{
|
||||
echo "<!--[if {$a_stylesheet['condition']}]>\n";
|
||||
}
|
||||
echo "<link rel=\"stylesheet\" type=\"text/css\" href=\"{$s_stylesheet}\" />\n";
|
||||
if ($a_stylesheet['condition'] != "")
|
||||
{
|
||||
echo "<![endif]-->\n";
|
||||
// Send headers
|
||||
if ($this->GetOutputFormat() === 'html') {
|
||||
foreach ($this->a_headers as $sHeader) {
|
||||
header($sHeader);
|
||||
}
|
||||
}
|
||||
|
||||
// Then inline styles
|
||||
if (count($this->a_styles) > 0)
|
||||
{
|
||||
echo "<style>\n";
|
||||
foreach ($this->a_styles as $s_style)
|
||||
{
|
||||
echo "$s_style\n";
|
||||
}
|
||||
echo "</style>\n";
|
||||
$this->s_content = $this->ob_get_clean_safe();
|
||||
|
||||
$aData = [];
|
||||
|
||||
$aData['oLayout'] = $this->oContentLayout;
|
||||
|
||||
// CSS files
|
||||
foreach ($this->oContentLayout->GetCssFilesUrlRecursively(true) as $sFileAbsUrl) {
|
||||
$this->add_linked_stylesheet($sFileAbsUrl);
|
||||
}
|
||||
// JS files
|
||||
foreach ($this->oContentLayout->GetJsFilesUrlRecursively(true) as $sFileAbsUrl) {
|
||||
$this->add_linked_script($sFileAbsUrl);
|
||||
}
|
||||
|
||||
// Base structure of data to pass to the TWIG template
|
||||
$aData['aPage'] = [
|
||||
'sAbsoluteUrlAppRoot' => addslashes(utils::GetAbsoluteUrlAppRoot()),
|
||||
'sTitle' => $this->s_title,
|
||||
'aMetadata' => [
|
||||
'sCharset' => static::PAGES_CHARSET,
|
||||
'sLang' => $this->GetLanguageForMetadata(),
|
||||
],
|
||||
'aCssFiles' => $this->a_linked_stylesheets,
|
||||
'aCssInline' => $this->a_styles,
|
||||
'aJsFiles' => $this->a_linked_scripts,
|
||||
'aJsInlineLive' => $this->a_scripts,
|
||||
// TODO 2.8.0: TEMP, used while developping, remove it.
|
||||
'sSanitizedContent' => utils::FilterXSS($this->s_content),
|
||||
'sDeferredContent' => utils::FilterXSS($this->s_deferred_content),
|
||||
];
|
||||
|
||||
if ($this->a_base['href'] != '') {
|
||||
$aData['aPage']['aMetadata']['sBaseUrl'] = $this->a_base['href'];
|
||||
}
|
||||
|
||||
if ($this->a_base['target'] != '') {
|
||||
$aData['aPage']['aMetadata']['sBaseTarget'] = $this->a_base['target'];
|
||||
}
|
||||
|
||||
// Favicon
|
||||
if (class_exists('MetaModel') && MetaModel::GetConfig())
|
||||
{
|
||||
echo "<link rel=\"shortcut icon\" href=\"".utils::GetAbsoluteUrlAppRoot()."images/favicon.ico?t=".utils::GetCacheBusterTimestamp()."\" />\n";
|
||||
if (class_exists('MetaModel') && MetaModel::GetConfig()) {
|
||||
$aData['aPage']['sFaviconUrl'] = $this->GetFaviconAbsoluteUrl();
|
||||
}
|
||||
|
||||
// Dict entries for JS
|
||||
if ($this->bAddJSDict)
|
||||
{
|
||||
$this->output_dict_entries();
|
||||
}
|
||||
// if ($this->bAddJSDict) {
|
||||
// $this->output_dict_entries();
|
||||
// }
|
||||
|
||||
// JS files
|
||||
foreach ($this->a_linked_scripts as $s_script)
|
||||
{
|
||||
// Make sure that the URL to the script contains the application's version number
|
||||
// so that the new script do NOT get reloaded from the cache when the application is upgraded
|
||||
if (strpos($s_script, '?') === false)
|
||||
{
|
||||
$s_script .= "?t=".utils::GetCacheBusterTimestamp();
|
||||
}
|
||||
else
|
||||
{
|
||||
$s_script .= "&t=".utils::GetCacheBusterTimestamp();
|
||||
}
|
||||
echo "<script type=\"text/javascript\" src=\"$s_script\"></script>\n";
|
||||
}
|
||||
|
||||
// JS inline scripts
|
||||
if (count($this->a_scripts) > 0)
|
||||
{
|
||||
echo "<script type=\"text/javascript\">\n";
|
||||
foreach ($this->a_scripts as $s_script)
|
||||
{
|
||||
echo "$s_script\n";
|
||||
}
|
||||
echo "</script>\n";
|
||||
}
|
||||
// if (trim($s_captured_output) != "") {
|
||||
// echo "<div class=\"raw_output\">".utils::FilterXSS($s_captured_output)."</div>\n";
|
||||
// }
|
||||
|
||||
echo "</head>\n";
|
||||
echo "<body>\n";
|
||||
echo self::FilterXSS($this->s_content);
|
||||
if (trim($s_captured_output) != "")
|
||||
{
|
||||
echo "<div class=\"raw_output\">".self::FilterXSS($s_captured_output)."</div>\n";
|
||||
}
|
||||
echo '<div id="at_the_end">'.self::FilterXSS($this->s_deferred_content).'</div>';
|
||||
echo "</body>\n";
|
||||
echo "</html>\n";
|
||||
$oTwigEnv = TwigHelper::GetTwigEnvironment(BlockRenderer::TWIG_BASE_PATH, BlockRenderer::TWIG_ADDITIONAL_PATHS);
|
||||
// Render final TWIG into global HTML
|
||||
$oKpi = new ExecutionKPI();
|
||||
$sHtml = TwigHelper::RenderTemplate($oTwigEnv, $aData, $this->GetTemplateRelPath());
|
||||
$oKpi->ComputeAndReport('TWIG rendering');
|
||||
|
||||
if (class_exists('DBSearch'))
|
||||
{
|
||||
// Echo global HTML
|
||||
$oKpi = new ExecutionKPI();
|
||||
echo $sHtml;
|
||||
$oKpi->ComputeAndReport('Echoing ('.round(strlen($sHtml) / 1024).' Kb)');
|
||||
|
||||
|
||||
if (class_exists('DBSearch')) {
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
if (class_exists('ExecutionKPI'))
|
||||
{
|
||||
if (class_exists('ExecutionKPI')) {
|
||||
ExecutionKPI::ReportStats();
|
||||
}
|
||||
}
|
||||
@@ -824,31 +797,6 @@ class WebPage implements Page
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HTML base tag
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_base_tag()
|
||||
{
|
||||
$sTag = '';
|
||||
if (($this->a_base['href'] != '') || ($this->a_base['target'] != ''))
|
||||
{
|
||||
$sTag = '<base ';
|
||||
if (($this->a_base['href'] != ''))
|
||||
{
|
||||
$sTag .= "href =\"{$this->a_base['href']}\" ";
|
||||
}
|
||||
if (($this->a_base['target'] != ''))
|
||||
{
|
||||
$sTag .= "target =\"{$this->a_base['target']}\" ";
|
||||
}
|
||||
$sTag .= " />\n";
|
||||
}
|
||||
|
||||
return $sTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an ID (for any kind of HTML tag) that is guaranteed unique in this page
|
||||
*
|
||||
@@ -907,11 +855,6 @@ class WebPage implements Page
|
||||
return $this->iTransactionId;
|
||||
}
|
||||
|
||||
public static function FilterXSS($sHTML)
|
||||
{
|
||||
return str_ireplace('<script', '<script', $sHTML);
|
||||
}
|
||||
|
||||
/**
|
||||
* What is the currently selected output format
|
||||
*
|
||||
@@ -1149,11 +1092,55 @@ EOD
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \UIBlockManager
|
||||
* Return the language for the page metadata based on the current user
|
||||
*
|
||||
* @return string
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public function GetUIBlockManager(): \UIBlockManager
|
||||
protected function GetLanguageForMetadata()
|
||||
{
|
||||
return $this->oUIBlockManager;
|
||||
$sUserLang = UserRights::GetUserLanguage();
|
||||
|
||||
return strtolower(substr($sUserLang, 0, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the absolute URL for the favicon
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
* @since 2.8.0
|
||||
*/
|
||||
protected function GetFaviconAbsoluteUrl()
|
||||
{
|
||||
// TODO 2.8.0: Make it a property so it can be changed programmatically
|
||||
// TODO 2.8.0: How to set both dark/light mode favicons
|
||||
return utils::GetAbsoluteUrlAppRoot().'images/favicon.ico';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the template path to use for the page
|
||||
*
|
||||
* @param string $sTemplateRelPath Relative path (from <ITOP>/templates/) to the template path
|
||||
*
|
||||
* @return $this
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public function SetTemplateRelPath($sTemplateRelPath)
|
||||
{
|
||||
$this->sTemplateRelPath = $sTemplateRelPath;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the relative path (from <ITOP>/templates/) to the page template
|
||||
*
|
||||
* @return string
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public function GetTemplateRelPath()
|
||||
{
|
||||
return $this->sTemplateRelPath;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
use \Combodo\iTop\Application\UI\iUIBlock;
|
||||
|
||||
/**
|
||||
* Class XMLPage
|
||||
@@ -68,7 +69,7 @@ class XMLPage extends WebPage
|
||||
}
|
||||
}
|
||||
|
||||
public function add($sText)
|
||||
public function add($sText): ?iUIBlock
|
||||
{
|
||||
if (!$this->m_bPassThrough)
|
||||
{
|
||||
@@ -95,6 +96,7 @@ class XMLPage extends WebPage
|
||||
$this->m_bHeaderSent = true;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function small_p($sText)
|
||||
|
||||
@@ -39,14 +39,12 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
/** @var string DEFAULT_BREADCRUMB_ENTRY_ICON_TYPE */
|
||||
const DEFAULT_BREADCRUMB_ENTRY_ICON_TYPE = self::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_IMAGE;
|
||||
|
||||
/** @var string DEFAULT_PAGE_TEMPLATE_REL_PATH The relative path (from <ITOP>/templates/) to the default page template */
|
||||
/** @var string DEFAULT_PAGE_TEMPLATE_REL_PATH The relative path (from <ITOP>/templates/) to the default page template */
|
||||
const DEFAULT_PAGE_TEMPLATE_REL_PATH = 'pages/backoffice/layout';
|
||||
|
||||
private $m_aMessages;
|
||||
private $m_aInitScript = array();
|
||||
protected $sTemplateRelPath;
|
||||
/** @var \Combodo\iTop\Application\UI\Layout\PageContent\PageContent $oContentLayout */
|
||||
protected $oContentLayout;
|
||||
|
||||
protected $m_oTabs;
|
||||
protected $bBreadCrumbEnabled;
|
||||
protected $sBreadCrumbEntryId;
|
||||
@@ -72,7 +70,6 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
$this->m_oTabs = new TabManager();
|
||||
$this->oCtx = new ContextTag(ContextTag::TAG_CONSOLE);
|
||||
|
||||
$this->SetTemplateRelPath(static::DEFAULT_PAGE_TEMPLATE_REL_PATH);
|
||||
// By default, content layout is empty, only manually added content will be displayed (eg. $this->add(xxx))
|
||||
$this->SetContentLayout(PageContentFactory::MakeStandardEmpty());
|
||||
|
||||
@@ -155,31 +152,6 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the template path to use for the page
|
||||
*
|
||||
* @param string $sTemplateRelPath Relative path (from <ITOP>/templates/) to the template path
|
||||
*
|
||||
* @return $this
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public function SetTemplateRelPath($sTemplateRelPath)
|
||||
{
|
||||
$this->sTemplateRelPath = $sTemplateRelPath;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the relative path (from <ITOP>/templates/) to the page template
|
||||
*
|
||||
* @return string
|
||||
* @since 2.8.0
|
||||
*/
|
||||
public function GetTemplateRelPath()
|
||||
{
|
||||
return $this->sTemplateRelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -663,25 +635,7 @@ JS
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function LoadTheme()
|
||||
{
|
||||
// TODO 2.8.0: Remove light-grey when development of Full Moon is done.
|
||||
// TODO 2.8.0: Reuse theming mechanism for Full Moon
|
||||
$sCssThemeUrl = ThemeHandler::GetCurrentThemeUrl();
|
||||
$this->add_linked_stylesheet($sCssThemeUrl);
|
||||
|
||||
$sCssRelPath = utils::GetCSSFromSASS(
|
||||
'css/backoffice/main.scss',
|
||||
array(
|
||||
APPROOT.'css/backoffice/',
|
||||
)
|
||||
);
|
||||
$this->add_saas($sCssRelPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see static::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_IMAGE, static::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES
|
||||
@@ -784,32 +738,6 @@ JS
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the language for the page metadata based on the current user
|
||||
*
|
||||
* @return string
|
||||
* @since 2.8.0
|
||||
*/
|
||||
protected function GetLanguageForMetadata()
|
||||
{
|
||||
$sUserLang = UserRights::GetUserLanguage();
|
||||
|
||||
return strtolower(substr($sUserLang, 0 ,2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the absolute URL for the favicon
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
* @since 2.8.0
|
||||
*/
|
||||
protected function GetFaviconAbsoluteUrl()
|
||||
{
|
||||
// TODO 2.8.0: Make it a property so it can be changed programmatically
|
||||
// TODO 2.8.0: How to set both dark/light mode favicons
|
||||
return utils::GetAbsoluteUrlAppRoot().'images/favicon.ico';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the navigation menu layout (id, menu groups, ...)
|
||||
@@ -855,6 +783,7 @@ JS
|
||||
public function SetContentLayout(PageContent $oLayout)
|
||||
{
|
||||
$this->oContentLayout = $oLayout;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -867,7 +796,9 @@ JS
|
||||
*/
|
||||
protected function GetContentLayout()
|
||||
{
|
||||
return $this->oContentLayout;
|
||||
/** @var PageContent $oPageContent */
|
||||
$oPageContent = $this->oContentLayout;
|
||||
return $oPageContent;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1046,14 +977,7 @@ EOF;
|
||||
// Prepare internal parts (js files, css files, js snippets, css snippets, ...)
|
||||
// - Generate necessary dict. files
|
||||
$this->output_dict_entries();
|
||||
|
||||
// TODO 2.8.0: Check if we can keep this as is
|
||||
// Render the blocks
|
||||
$this->s_content = $this->oUIBlockManager->RenderIntoContent($this->s_content, $this);
|
||||
|
||||
// Render the tabs in the page (if any)
|
||||
$this->s_content = $this->m_oTabs->RenderIntoContent($this->s_content, $this);
|
||||
$this->GetContentLayout()->SetExtraHtmlContent(self::FilterXSS($this->s_content));
|
||||
$this->GetContentLayout()->SetExtraHtmlContent(utils::FilterXSS($this->s_content));
|
||||
|
||||
// Base structure of data to pass to the TWIG template
|
||||
$aData['aPage'] = [
|
||||
@@ -1068,11 +992,14 @@ EOF;
|
||||
|
||||
// Base tag
|
||||
// Note: We might consider to put the app_root_url parameter here, but that would need a BIG rework on iTop AND the extensions to replace all the "../images|js|css/xxx.yyy"...
|
||||
if(!empty($this->a_base['href']))
|
||||
{
|
||||
if (!empty($this->a_base['href'])) {
|
||||
$aData['aPage']['aMetadata']['sBaseUrl'] = $this->a_base['href'];
|
||||
}
|
||||
|
||||
if ($this->a_base['target'] != '') {
|
||||
$aData['aPage']['aMetadata']['sBaseTarget'] = $this->a_base['target'];
|
||||
}
|
||||
|
||||
// Layouts
|
||||
$aData['aLayouts'] = [
|
||||
'sBanner' => $this->RenderBannerHtml(),
|
||||
@@ -1121,8 +1048,8 @@ EOF;
|
||||
'aJsInlineOnDomReady' => $this->m_aReadyScripts,
|
||||
'aJsInlineLive' => $this->a_scripts,
|
||||
// TODO 2.8.0: TEMP, used while developping, remove it.
|
||||
'sSanitizedContent' => self::FilterXSS($this->s_content),
|
||||
'sDeferredContent' => self::FilterXSS($this->s_deferred_content),
|
||||
'sSanitizedContent' => utils::FilterXSS($this->s_content),
|
||||
'sDeferredContent' => utils::FilterXSS($this->s_deferred_content),
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1285,28 +1212,22 @@ EOF;
|
||||
// $sOnClick = " onclick=\"if ($('#global-search-input').val() != '') { $('#global-search form').submit(); } \"";
|
||||
// $sDefaultPlaceHolder = Dict::S("UI:YourSearch");
|
||||
|
||||
if ($this->IsPrintableVersion())
|
||||
{
|
||||
if ($this->IsPrintableVersion()) {
|
||||
$sHtml .= ' <!-- Beginning of page content -->';
|
||||
$sHtml .= self::FilterXSS($this->s_content);
|
||||
$sHtml .= utils::FilterXSS($this->s_content);
|
||||
$sHtml .= ' <!-- End of page content -->';
|
||||
}
|
||||
elseif ($this->GetOutputFormat() == 'html')
|
||||
{
|
||||
} elseif ($this->GetOutputFormat() == 'html') {
|
||||
|
||||
// Add the captured output
|
||||
if (trim($s_captured_output) != "")
|
||||
{
|
||||
$sHtml .= "<div id=\"rawOutput\" title=\"Debug Output\"><div style=\"height:500px; overflow-y:auto;\">".self::FilterXSS($s_captured_output)."</div></div>\n";
|
||||
if (trim($s_captured_output) != "") {
|
||||
$sHtml .= "<div id=\"rawOutput\" title=\"Debug Output\"><div style=\"height:500px; overflow-y:auto;\">".utils::FilterXSS($s_captured_output)."</div></div>\n";
|
||||
}
|
||||
$sHtml .= "<div id=\"at_the_end\">".self::FilterXSS($this->s_deferred_content)."</div>";
|
||||
$sHtml .= "<div id=\"at_the_end\">".utils::FilterXSS($this->s_deferred_content)."</div>";
|
||||
$sHtml .= "<div style=\"display:none\" title=\"ex2\" id=\"ex2\">Please wait...</div>\n"; // jqModal Window
|
||||
$sHtml .= "<div style=\"display:none\" title=\"dialog\" id=\"ModalDlg\"></div>";
|
||||
$sHtml .= "<div style=\"display:none\" id=\"ajax_content\"></div>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= self::FilterXSS($this->s_content);
|
||||
} else {
|
||||
$sHtml .= utils::FilterXSS($this->s_content);
|
||||
}
|
||||
|
||||
if ($this->IsPrintableVersion())
|
||||
@@ -1362,7 +1283,7 @@ EOF;
|
||||
*/
|
||||
public function AddTabContainer($sTabContainer, $sPrefix = '')
|
||||
{
|
||||
$this->add($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
|
||||
$this->AddUiBlock($this->m_oTabs->AddTabContainer($sTabContainer, $sPrefix));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1432,6 +1353,8 @@ EOF;
|
||||
*
|
||||
* @param string $sTabContainer
|
||||
* @param string $sTabCode
|
||||
*
|
||||
* @deprecated 2.8.0
|
||||
*/
|
||||
public function SelectTab($sTabContainer, $sTabCode)
|
||||
{
|
||||
@@ -1442,16 +1365,14 @@ EOF;
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function add($sHtml)
|
||||
public function add($sHtml): ?iUIBlock
|
||||
{
|
||||
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != ''))
|
||||
{
|
||||
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != '')) {
|
||||
$this->m_oTabs->AddToCurrentTab($sHtml);
|
||||
} else {
|
||||
return parent::add($sHtml);
|
||||
}
|
||||
else
|
||||
{
|
||||
parent::add($sHtml);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
<div class="ibo-html">{{ oUIBlock.GetHtml()|raw }}</div>
|
||||
{% apply spaceless %}
|
||||
{{ oUIBlock.GetHtml()|raw }}
|
||||
{% endapply %}
|
||||
9
templates/layouts/contentblock/layout.html.twig
Normal file
9
templates/layouts/contentblock/layout.html.twig
Normal file
@@ -0,0 +1,9 @@
|
||||
{% apply spaceless %}
|
||||
{# <div id="{{ oUIBlock.GetId() }}" class="ibo-content-block"> #}
|
||||
{% block iboContentBlockContainer %}
|
||||
{% for oSubBlock in oUIBlock.GetSubBlocks() %}
|
||||
{{ render_block(oSubBlock, {aPage: aPage}) }}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
{# </div> #}
|
||||
{% endapply %}
|
||||
0
templates/layouts/contentblock/layout.js.twig
Normal file
0
templates/layouts/contentblock/layout.js.twig
Normal file
25
templates/layouts/tabcontainer/layout.html.twig
Normal file
25
templates/layouts/tabcontainer/layout.html.twig
Normal file
@@ -0,0 +1,25 @@
|
||||
<div id="{{ oUIBlock.GetId() }}" class="ibo-tab-container">
|
||||
{% block iboTabContainer %}
|
||||
<!-- tabs -->
|
||||
<div id="tabbedContent_{$sPrefix}{$container_index}" class="light">
|
||||
<ul>
|
||||
{% for oTab in oUIBlock.GetSubBlocks() %}
|
||||
{% if oTab.GetType() == 'ajax' %}
|
||||
<li data-cache="{{ oTab.GetCache() }}"><a href="{{ oTab.GetURL() }}" class="tab" data-tab-id="$sTabCodeForHtml"><span>{{ oTab.GetTitle() }}</span></a></li>
|
||||
{% elseif oTab.GetType() == 'html' %}
|
||||
<li><a href="#tab_{{ oTab.GetId() }}" class="tab" data-tab-id="$sTabCodeForHtml"><span>{{ oTab.GetTitle() }}</span></a></li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% for oTab in oUIBlock.GetSubBlocks() %}
|
||||
{% if oTab.GetType() == 'html' %}
|
||||
<div id="tab_{{ oTab.GetId() }}">
|
||||
{{ render_block(oTab, {aPage: aPage}) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<!-- end of tabs-->
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
42
templates/layouts/tabcontainer/layout.js.twig
Normal file
42
templates/layouts/tabcontainer/layout.js.twig
Normal file
@@ -0,0 +1,42 @@
|
||||
// The "tab widgets" to handle.
|
||||
var tabs = $('div[id^=tabbedContent]');
|
||||
|
||||
// Ugly patch for a change in the behavior of jQuery UI:
|
||||
// Before jQuery UI 1.9, tabs were always considered as "local" (opposed to Ajax)
|
||||
// when their href was beginning by #. Starting with 1.9, a <base> tag in the page
|
||||
// is taken into account and causes "local" tabs to be considered as Ajax
|
||||
// unless their URL is equal to the URL of the page...
|
||||
if ($('base').length > 0) {
|
||||
$('div[id^=tabbedContent] > ul > li > a').each(function () {
|
||||
var sHash = location.hash;
|
||||
var sCleanLocation = location.href.toString().replace(sHash, '').replace(/#$/, '');
|
||||
$(this).attr("href", sCleanLocation + $(this).attr("href"));
|
||||
});
|
||||
}
|
||||
if ($.bbq) {
|
||||
// This selector will be reused when selecting actual tab widget A elements.
|
||||
var tab_a_selector = 'ul.ui-tabs-nav a';
|
||||
|
||||
// Enable tabs on all tab widgets. The `event` property must be overridden so
|
||||
// that the tabs aren't changed on click, and any custom event name can be
|
||||
// specified. Note that if you define a callback for the 'select' event, it
|
||||
// will be executed for the selected tab whenever the hash changes.
|
||||
tabs.tabs({event: 'change'});
|
||||
|
||||
// Define our own click handler for the tabs, overriding the default.
|
||||
tabs.find(tab_a_selector).click(function () {
|
||||
var state = {};
|
||||
|
||||
// Get the id of this tab widget.
|
||||
var id = $(this).closest('div[id^=tabbedContent]').attr('id');
|
||||
|
||||
// Get the index of this tab.
|
||||
var idx = $(this).parent().prevAll().length;
|
||||
|
||||
// Set the state!
|
||||
state[id] = idx;
|
||||
$.bbq.pushState(state);
|
||||
});
|
||||
} else {
|
||||
tabs.tabs();
|
||||
}
|
||||
7
templates/layouts/tabcontainer/tab/layout.html.twig
Normal file
7
templates/layouts/tabcontainer/tab/layout.html.twig
Normal file
@@ -0,0 +1,7 @@
|
||||
<div id="{{ oUIBlock.GetId() }}" class="ibo-tab-content-block">
|
||||
{% block iboContentBlockContainer %}
|
||||
{% for oSubBlock in oUIBlock.GetSubBlocks() %}
|
||||
{{ render_block(oSubBlock, {aPage: aPage}) }}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
0
templates/layouts/tabcontainer/tab/layout.js.twig
Normal file
0
templates/layouts/tabcontainer/tab/layout.js.twig
Normal file
1
templates/pages/backoffice/ajaxpage/layout.html.twig
Normal file
1
templates/pages/backoffice/ajaxpage/layout.html.twig
Normal file
@@ -0,0 +1 @@
|
||||
{{ render_block(oLayout, {aPage: aPage}) }}
|
||||
@@ -1,38 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ aPage.aMetadata.sLang }}">
|
||||
<head>
|
||||
<meta charset="{{ aPage.aMetadata.sCharset }}">
|
||||
{# This block can be used to add your own meta tags by extending the default template #}
|
||||
{% block iboPageExtraMetas %}
|
||||
{% endblock %}
|
||||
{% if aPage.aMetadata.sBaseUrl is defined %}
|
||||
<base href="{{ aPage.aMetadata.sBaseUrl }}">
|
||||
{% endif %}
|
||||
<title>{{ aPage.sTitle }}</title>
|
||||
<link rel="shortcut icon" href="{{ aPage.sFaviconUrl|add_itop_version }}" />
|
||||
<link rel="search" type="application/opensearchdescription+xml" title="iTop" href="{{ aPage.sAbsoluteUrlAppRoot }}pages/opensearch.xml.php" />
|
||||
{% extends "pages/backoffice/nicewebpage/layout.html.twig" %}
|
||||
|
||||
{# Stylesheets MUST be loaded before any scripts otherwise we may face problems such as
|
||||
- Visual glitches
|
||||
- jQuery scripts spurious problems (like failing on a 'reload') #}
|
||||
{% block iboPageCssFiles %}
|
||||
{% for aCssFileData in aPage.aCssFiles %}
|
||||
{% if aCssFileData['condition'] != '' %}<!--[if {{ aCssFileData['condition'] }}]>{% endif %}
|
||||
<link type="text/css" href="{{ aCssFileData['link']|add_itop_version }}" rel="stylesheet" />
|
||||
{% if aCssFileData['condition'] != '' %}<![endif]-->{% endif %}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block iboPageCssInline %}
|
||||
{# We put each styles in a dedicated style tag to prevent massive failure if 1 style is broken (eg. missing semi-colon, bracket, ...) #}
|
||||
{% for sCssInline in aPage.aCssInline %}
|
||||
<style>
|
||||
{{ sCssInline|raw }}
|
||||
</style>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body data-gui-type="backoffice">
|
||||
{% block iboPageBodyHtml %}
|
||||
{{ render_block(aLayouts.oNavigationMenu, {aPage: aPage}) }}
|
||||
<div id="ibo-page-container">
|
||||
<div id="ibo-top-container">
|
||||
@@ -49,41 +17,10 @@
|
||||
<div style="display:none" title="dialog" id="ModalDlg"></div>
|
||||
<div style="display:none" id="ajax_content"></div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block iboPageJsFiles %}
|
||||
{% for sJsFile in aPage.aJsFiles %}
|
||||
<script type="text/javascript" src="{{ sJsFile|add_itop_version }}"></script>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block iboPageJsInlineScripts %}
|
||||
<script type="text/javascript">
|
||||
{# TODO: How to do this in native JS? #}
|
||||
$(document).ready(function(){
|
||||
{% block iboPageJsInlineOnInit %}
|
||||
{% for sJsInline in aPage.aJsInlineOnInit %}
|
||||
{{ sJsInline|raw }}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block iboPageJsInlineOnDomReady %}
|
||||
setTimeout(function(){
|
||||
{% for sJsInline in aPage.aJsInlineOnDomReady %}
|
||||
{{ sJsInline|raw }}
|
||||
{% endfor %}
|
||||
}, 50);
|
||||
{% endblock %}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% block iboPageJsInlineLive %}
|
||||
{% for sJsInline in aPage.aJsInlineLive %}
|
||||
{# We put each scripts in a dedicated script tag to prevent massive failure if 1 script is broken (eg. missing semi-colon or non closed multi-line comment) #}
|
||||
<script type="text/javascript">
|
||||
{{ sJsInline|raw }}
|
||||
</script>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
{% block iboPageJsInlineOnInit %}
|
||||
{% for sJsInline in aPage.aJsInlineOnInit %}
|
||||
{{ sJsInline|raw }}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
10
templates/pages/backoffice/nicewebpage/layout.html.twig
Normal file
10
templates/pages/backoffice/nicewebpage/layout.html.twig
Normal file
@@ -0,0 +1,10 @@
|
||||
{% extends "pages/backoffice/webpage/layout.html.twig" %}
|
||||
|
||||
{% block iboPageJsInlineOnDomReady %}
|
||||
setTimeout(function () {
|
||||
{% for sJsInline in aPage.aJsInlineOnDomReady %}
|
||||
{{ sJsInline|raw }}
|
||||
{% endfor %}
|
||||
}, 50);
|
||||
{% endblock %}
|
||||
|
||||
77
templates/pages/backoffice/webpage/layout.html.twig
Normal file
77
templates/pages/backoffice/webpage/layout.html.twig
Normal file
@@ -0,0 +1,77 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ aPage.aMetadata.sLang }}">
|
||||
<head>
|
||||
<meta charset="{{ aPage.aMetadata.sCharset }}">
|
||||
{# This block can be used to add your own meta tags by extending the default template #}
|
||||
{% block iboPageExtraMetas %}
|
||||
{% endblock %}
|
||||
{% if aPage.aMetadata.sBaseUrl is defined or aPage.aMetadata.sBaseTarget is defined %}
|
||||
<base {% if aPage.aMetadata.sBaseUrl is defined %}href="{{ aPage.aMetadata.sBaseUrl }}"{% endif %} {% if aPage.aMetadata.sBaseTarget is defined %}target="{{ aPage.aMetadata.sBaseTarget }}"{% endif %}>
|
||||
{% endif %}
|
||||
<title>{{ aPage.sTitle }}</title>
|
||||
{% if aPage.sFaviconUrl is defined %}
|
||||
<link rel="shortcut icon" href="{{ aPage.sFaviconUrl|add_itop_version }}"/>
|
||||
{% endif %}
|
||||
<link rel="search" type="application/opensearchdescription+xml" title="iTop" href="{{ aPage.sAbsoluteUrlAppRoot }}pages/opensearch.xml.php"/>
|
||||
|
||||
{# Stylesheets MUST be loaded before any scripts otherwise we may face problems such as
|
||||
- Visual glitches
|
||||
- jQuery scripts spurious problems (like failing on a 'reload') #}
|
||||
{% block iboPageCssFiles %}
|
||||
{% for aCssFileData in aPage.aCssFiles %}
|
||||
{% if aCssFileData['condition'] != '' %}<!--[if {{ aCssFileData['condition'] }}]>{% endif %}
|
||||
<link type="text/css" href="{{ aCssFileData['link']|add_itop_version }}" rel="stylesheet" />
|
||||
{% if aCssFileData['condition'] != '' %}<![endif]-->{% endif %}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block iboPageCssInline %}
|
||||
{# We put each styles in a dedicated style tag to prevent massive failure if 1 style is broken (eg. missing semi-colon, bracket, ...) #}
|
||||
{% for sCssInline in aPage.aCssInline %}
|
||||
<style>
|
||||
{{ sCssInline|raw }}
|
||||
</style>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body data-gui-type="backoffice">
|
||||
{% block iboPageBodyHtml %}
|
||||
<div id="ibo-page-container">
|
||||
{{ render_block(oLayout, {aPage: aPage}) }}
|
||||
|
||||
{# TODO: Remove this when modal development is done #}
|
||||
<div id="at_the_end">{{ aPage.sDeferredContent|raw }}</div>
|
||||
<div style="display:none" title="ex2" id="ex2">Please wait...</div>
|
||||
<div style="display:none" title="dialog" id="ModalDlg"></div>
|
||||
<div style="display:none" id="ajax_content"></div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block iboPageJsFiles %}
|
||||
{% for sJsFile in aPage.aJsFiles %}
|
||||
<script type="text/javascript" src="{{ sJsFile|add_itop_version }}"></script>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block iboPageJsInlineScripts %}
|
||||
<script type="text/javascript">
|
||||
{# TODO: How to do this in native JS? #}
|
||||
$(document).ready(function () {
|
||||
{% block iboPageJsInlineOnInit %}
|
||||
{% endblock %}
|
||||
|
||||
{% block iboPageJsInlineOnDomReady %}
|
||||
{% endblock %}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% block iboPageJsInlineLive %}
|
||||
{% for sJsInline in aPage.aJsInlineLive %}
|
||||
{# We put each scripts in a dedicated script tag to prevent massive failure if 1 script is broken (eg. missing semi-colon or non closed multi-line comment) #}
|
||||
<script type="text/javascript">
|
||||
{{ sJsInline|raw }}
|
||||
</script>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user