N°2847 - FieldSet and Fields

This commit is contained in:
Eric
2020-09-23 08:55:58 +02:00
parent 33f11d2a43
commit 98d2e42bad
21 changed files with 341 additions and 119 deletions

View File

@@ -17,6 +17,11 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Application\UI\Component\Field\Field;
use Combodo\iTop\Application\UI\Component\FieldSet\FieldSet;
use Combodo\iTop\Application\UI\Layout\Column\Column;
use Combodo\iTop\Application\UI\Layout\MultiColumn\MultiColumn;
define('OBJECT_PROPERTIES_TAB', 'ObjectProperties');
define('HILIGHT_CLASS_CRITICAL', 'red');
@@ -806,93 +811,43 @@ EOF
$sClass = get_class($this);
$aDetailsList = MetaModel::GetZListItems($sClass, 'details');
$aDetailsStruct = self::ProcessZlist($aDetailsList, array('UI:PropertiesTab' => array()), 'UI:PropertiesTab', 'col1', '');
// Compute the list of properties to display, first the attributes in the 'details' list, then
// all the remaining attributes that are not external fields
$sEditMode = ($bEditMode) ? 'edit' : 'view';
$aDetails = array();
$iInputId = 0;
$aFieldsMap = array();
$aFieldsComments = (isset($aExtraParams['fieldsComments'])) ? $aExtraParams['fieldsComments'] : array();
$aExtraFlags = (isset($aExtraParams['fieldsFlags'])) ? $aExtraParams['fieldsFlags'] : array();
foreach($aDetailsStruct as $sTab => $aCols)
{
$aDetails[$sTab] = array();
$aTableStyles[] = 'vertical-align:top';
$aTableClasses = array();
$aColStyles[] = 'vertical-align:top';
$aColClasses = array();
foreach ($aDetailsStruct as $sTab => $aCols) {
ksort($aCols);
$iColCount = count($aCols);
if ($iColCount > 1)
{
$aTableClasses[] = 'n-cols-details';
$aTableClasses[] = $iColCount.'-cols-details';
$aColStyles[] = 'width:'.floor(100 / $iColCount).'%';
}
else
{
$aTableClasses[] = 'one-col-details';
}
$oPage->SetCurrentTab($sTab);
$oPage->add('<table style="'.implode('; ', $aTableStyles).'" class="'.implode(' ',
$aTableClasses).'" data-mode="'.$sEditMode.'"><tr>');
foreach($aCols as $sColIndex => $aFieldsets)
{
$oPage->add('<td style="'.implode('; ', $aColStyles).'" class="'.implode(' ', $aColClasses).'">');
$sPreviousLabel = '';
$aDetails[$sTab][$sColIndex] = array();
foreach($aFieldsets as $sFieldsetName => $aFields)
{
if (!empty($sFieldsetName) && ($sFieldsetName[0] != '_'))
{
$sLabel = $sFieldsetName;
$oMultiColumn = new MultiColumn();
$oPage->AddUiBlock($oMultiColumn);
foreach ($aCols as $sColIndex => $aFieldsets) {
$oColumn = new Column();
$oMultiColumn->AddColumn($oColumn);
foreach ($aFieldsets as $sFieldsetName => $aFields) {
if ($sFieldsetName[0] != '_') {
$oFieldSet = new FieldSet(Dict::S($sFieldsetName));
$oColumn->AddSubBlock($oFieldSet);
}
else
{
$sLabel = '';
}
if ($sLabel != $sPreviousLabel)
{
if (!empty($sPreviousLabel))
{
$oPage->add('<fieldset>');
$oPage->add('<legend>'.Dict::S($sPreviousLabel).'</legend>');
}
$oPage->Details($aDetails[$sTab][$sColIndex]);
if (!empty($sPreviousLabel))
{
$oPage->add('</fieldset>');
}
$aDetails[$sTab][$sColIndex] = array();
$sPreviousLabel = $sLabel;
}
foreach($aFields as $sAttCode)
{
$aDetails = [];
foreach ($aFields as $sAttCode) {
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
$sAttDefClass = get_class($oAttDef);
$sAttLabel = MetaModel::GetLabel($sClass, $sAttCode);
if ($bEditMode)
{
if ($bEditMode) {
$sComments = isset($aFieldsComments[$sAttCode]) ? $aFieldsComments[$sAttCode] : '';
$sInfos = '';
$iFlags = $this->GetFormAttributeFlags($sAttCode);
if (array_key_exists($sAttCode, $aExtraFlags))
{
if (array_key_exists($sAttCode, $aExtraFlags)) {
// the caller may override some flags if needed
$iFlags = $iFlags | $aExtraFlags[$sAttCode];
}
if ((!$oAttDef->IsLinkSet()) && (($iFlags & OPT_ATT_HIDDEN) == 0) && !($oAttDef instanceof AttributeDashboard))
{
if ((!$oAttDef->IsLinkSet()) && (($iFlags & OPT_ATT_HIDDEN) == 0) && !($oAttDef instanceof AttributeDashboard)) {
$sInputId = $this->m_iFormId.'_'.$sAttCode;
if ($oAttDef->IsWritable())
{
if ($sStateAttCode == $sAttCode)
{
if ($oAttDef->IsWritable()) {
if ($sStateAttCode == $sAttCode) {
// State attribute is always read-only from the UI
$sHTMLValue = $this->GetStateLabel();
$val = array(
@@ -901,20 +856,15 @@ EOF
'comments' => $sComments,
'infos' => $sInfos,
);
}
else
{
if ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE))
{
} else {
if ($iFlags & (OPT_ATT_READONLY | OPT_ATT_SLAVE)) {
// Check if the attribute is not read-only because of a synchro...
if ($iFlags & OPT_ATT_SLAVE)
{
if ($iFlags & OPT_ATT_SLAVE) {
$aReasons = array();
$this->GetSynchroReplicaFlags($sAttCode, $aReasons);
$sSynchroIcon = "&nbsp;<img id=\"synchro_$sInputId\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
$sTip = '';
foreach($aReasons as $aRow)
{
foreach ($aReasons as $aRow) {
$sDescription = htmlentities($aRow['description'], ENT_QUOTES,
'UTF-8');
$sDescription = str_replace(array("\r\n", "\n"), "<br/>",
@@ -985,10 +935,8 @@ EOF
// - For simple fields, we get the raw (stored) value as well
$bExcludeRawValue = false;
foreach (static::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude)
{
if (is_a($sAttDefClass, $sAttDefClassToExclude, true))
{
foreach (static::GetAttDefClassesToExcludeFromMarkupMetadataRawValue() as $sAttDefClassToExclude) {
if (is_a($sAttDefClass, $sAttDefClassToExclude, true)) {
$bExcludeRawValue = true;
break;
}
@@ -996,24 +944,22 @@ EOF
$val['value_raw'] = ($bExcludeRawValue === false) ? $this->Get($sAttCode) : '';
// The field is visible, add it to the current column
$aDetails[$sTab][$sColIndex][] = $val;
$iInputId++;
$aDetails[] = $val;
$oField = new Field($val);
if ($sFieldsetName[0] != '_') {
$oFieldSet->AddSubBlock($oField);
} else {
$oColumn->AddSubBlock($oField);
}
}
}
// if ($sFieldsetName[0] != '_') {
// $oFieldSet->AddSubBlock(new Html($oPage->GetDetails($aDetails)));
// } else {
// $oColumn->AddSubBlock(new Html($oPage->GetDetails($aDetails)));
// }
}
if (!empty($sPreviousLabel))
{
$oPage->add('<fieldset>');
$oPage->add('<legend>'.Dict::S($sFieldsetName).'</legend>');
}
$oPage->Details($aDetails[$sTab][$sColIndex]);
if (!empty($sPreviousLabel))
{
$oPage->add('</fieldset>');
}
$oPage->add('</td>');
}
$oPage->add('</tr></table>');
}
return $aFieldsMap;

View File

@@ -18,4 +18,6 @@
@import "ajaxtab";
@import "title";
@import "form";
@import "input";
@import "input";
@import "fieldset";
@import "field";

View File

@@ -0,0 +1,34 @@
/*!
* copyright Copyright (C) 2010-2020 Combodo SARL
* license http://opensource.org/licenses/AGPL-3.0
*/
.ibo-field-large {
display: inherit;
.ibo-field-label {
display: inherit;
}
}
.ibo-field-small {
display: table;
width: 100%;
.ibo-field-label {
display: table-cell;
vertical-align: top;
}
}
.ibo-field-label {
min-width: 100px;
max-width: 145px;
width: 30%;
padding-right: 10px;
}
.ibo-field-value {
display: table;
width: 100%;
}

View File

@@ -0,0 +1,4 @@
/*!
* copyright Copyright (C) 2010-2020 Combodo SARL
* license http://opensource.org/licenses/AGPL-3.0
*/

View File

@@ -23,4 +23,6 @@
@import "activity-panel/activity-entry";
@import "activity-panel/caselog-entry";
@import "activity-panel/edits-entry";
@import "activity-panel/transition-entry";
@import "activity-panel/transition-entry";
@import "multicolumn";
@import "column";

View File

@@ -0,0 +1,7 @@
/*!
* copyright Copyright (C) 2010-2020 Combodo SARL
* license http://opensource.org/licenses/AGPL-3.0
*/
.ibo-column {
}

View File

@@ -0,0 +1,10 @@
/*!
* copyright Copyright (C) 2010-2020 Combodo SARL
* license http://opensource.org/licenses/AGPL-3.0
*/
.ibo-multi-column {
width: 100%;
display: flex;
flex-wrap: nowrap;
}

View File

@@ -40,3 +40,5 @@ if ($.bbq) {
} else {
tabs.tabs();
}
$('.ibo-tab-container-spinner').hide();
$('.ibo-tab-container').show();

View File

@@ -155,6 +155,8 @@ return array(
'Combodo\\iTop\\Application\\UI\\Component\\Breadcrumbs\\Breadcrumbs' => $baseDir . '/sources/application/UI/Component/Breadcrumbs/Breadcrumbs.php',
'Combodo\\iTop\\Application\\UI\\Component\\Button\\Button' => $baseDir . '/sources/application/UI/Component/Button/Button.php',
'Combodo\\iTop\\Application\\UI\\Component\\Button\\ButtonFactory' => $baseDir . '/sources/application/UI/Component/Button/ButtonFactory.php',
'Combodo\\iTop\\Application\\UI\\Component\\FieldSet\\FieldSet' => $baseDir . '/sources/application/UI/Component/FieldSet/FieldSet.php',
'Combodo\\iTop\\Application\\UI\\Component\\Field\\Field' => $baseDir . '/sources/application/UI/Component/Field/Field.php',
'Combodo\\iTop\\Application\\UI\\Component\\Form\\Form' => $baseDir . '/sources/application/UI/Component/Form/Form.php',
'Combodo\\iTop\\Application\\UI\\Component\\GlobalSearch\\GlobalSearch' => $baseDir . '/sources/application/UI/Component/GlobalSearch/GlobalSearch.php',
'Combodo\\iTop\\Application\\UI\\Component\\GlobalSearch\\GlobalSearchFactory' => $baseDir . '/sources/application/UI/Component/GlobalSearch/GlobalSearchFactory.php',
@@ -195,6 +197,8 @@ return array(
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityEntry\\TransitionEntry' => $baseDir . '/sources/application/UI/Layout/ActivityPanel/ActivityEntry/TransitionEntry.php',
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityPanel' => $baseDir . '/sources/application/UI/Layout/ActivityPanel/ActivityPanel.php',
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityPanelFactory' => $baseDir . '/sources/application/UI/Layout/ActivityPanel/ActivityPanelFactory.php',
'Combodo\\iTop\\Application\\UI\\Layout\\Column\\Column' => $baseDir . '/sources/application/UI/Layout/Column/Column.php',
'Combodo\\iTop\\Application\\UI\\Layout\\MultiColumn\\MultiColumn' => $baseDir . '/sources/application/UI/Layout/MultiColumn/MultiColumn.php',
'Combodo\\iTop\\Application\\UI\\Layout\\NavigationMenu\\NavigationMenu' => $baseDir . '/sources/application/UI/Layout/NavigationMenu/NavigationMenu.php',
'Combodo\\iTop\\Application\\UI\\Layout\\NavigationMenu\\NavigationMenuFactory' => $baseDir . '/sources/application/UI/Layout/NavigationMenu/NavigationMenuFactory.php',
'Combodo\\iTop\\Application\\UI\\Layout\\PageContent\\PageContent' => $baseDir . '/sources/application/UI/Layout/PageContent/PageContent.php',

View File

@@ -385,6 +385,8 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'Combodo\\iTop\\Application\\UI\\Component\\Breadcrumbs\\Breadcrumbs' => __DIR__ . '/../..' . '/sources/application/UI/Component/Breadcrumbs/Breadcrumbs.php',
'Combodo\\iTop\\Application\\UI\\Component\\Button\\Button' => __DIR__ . '/../..' . '/sources/application/UI/Component/Button/Button.php',
'Combodo\\iTop\\Application\\UI\\Component\\Button\\ButtonFactory' => __DIR__ . '/../..' . '/sources/application/UI/Component/Button/ButtonFactory.php',
'Combodo\\iTop\\Application\\UI\\Component\\FieldSet\\FieldSet' => __DIR__ . '/../..' . '/sources/application/UI/Component/FieldSet/FieldSet.php',
'Combodo\\iTop\\Application\\UI\\Component\\Field\\Field' => __DIR__ . '/../..' . '/sources/application/UI/Component/Field/Field.php',
'Combodo\\iTop\\Application\\UI\\Component\\Form\\Form' => __DIR__ . '/../..' . '/sources/application/UI/Component/Form/Form.php',
'Combodo\\iTop\\Application\\UI\\Component\\GlobalSearch\\GlobalSearch' => __DIR__ . '/../..' . '/sources/application/UI/Component/GlobalSearch/GlobalSearch.php',
'Combodo\\iTop\\Application\\UI\\Component\\GlobalSearch\\GlobalSearchFactory' => __DIR__ . '/../..' . '/sources/application/UI/Component/GlobalSearch/GlobalSearchFactory.php',
@@ -425,6 +427,8 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityEntry\\TransitionEntry' => __DIR__ . '/../..' . '/sources/application/UI/Layout/ActivityPanel/ActivityEntry/TransitionEntry.php',
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityPanel' => __DIR__ . '/../..' . '/sources/application/UI/Layout/ActivityPanel/ActivityPanel.php',
'Combodo\\iTop\\Application\\UI\\Layout\\ActivityPanel\\ActivityPanelFactory' => __DIR__ . '/../..' . '/sources/application/UI/Layout/ActivityPanel/ActivityPanelFactory.php',
'Combodo\\iTop\\Application\\UI\\Layout\\Column\\Column' => __DIR__ . '/../..' . '/sources/application/UI/Layout/Column/Column.php',
'Combodo\\iTop\\Application\\UI\\Layout\\MultiColumn\\MultiColumn' => __DIR__ . '/../..' . '/sources/application/UI/Layout/MultiColumn/MultiColumn.php',
'Combodo\\iTop\\Application\\UI\\Layout\\NavigationMenu\\NavigationMenu' => __DIR__ . '/../..' . '/sources/application/UI/Layout/NavigationMenu/NavigationMenu.php',
'Combodo\\iTop\\Application\\UI\\Layout\\NavigationMenu\\NavigationMenuFactory' => __DIR__ . '/../..' . '/sources/application/UI/Layout/NavigationMenu/NavigationMenuFactory.php',
'Combodo\\iTop\\Application\\UI\\Layout\\PageContent\\PageContent' => __DIR__ . '/../..' . '/sources/application/UI/Layout/PageContent/PageContent.php',

View File

@@ -0,0 +1,41 @@
<?php
/**
* @copyright Copyright (C) 2010-2020 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Application\UI\Component\Field;
use Combodo\iTop\Application\UI\UIBlock;
/**
* Class Field
*
* @package Combodo\iTop\Application\UI\Component\Field
*/
class Field extends UIBlock
{
// Overloaded constants
public const BLOCK_CODE = 'ibo-field';
public const HTML_TEMPLATE_REL_PATH = 'components/field/layout';
public const JS_TEMPLATE_REL_PATH = 'components/field/layout';
/** @var array */
protected $aParams;
public function __construct(array $aParams, ?string $sId = null)
{
parent::__construct($sId);
$this->aParams = $aParams;
}
/**
* @return string
*/
public function GetParams(): array
{
return $this->aParams;
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* @copyright Copyright (C) 2010-2020 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Application\UI\Component\FieldSet;
use Combodo\iTop\Application\UI\Layout\UIContentBlock;
/**
* Class FieldSet
*
* @package Combodo\iTop\Application\UI\Component\FieldSet
*/
class FieldSet extends UIContentBlock
{
// Overloaded constants
public const BLOCK_CODE = 'ibo-fieldset';
public const HTML_TEMPLATE_REL_PATH = 'components/fieldset/layout';
public const JS_TEMPLATE_REL_PATH = 'components/fieldset/layout';
/** @var string */
protected $sLegend;
/**
* FieldSet constructor.
*
* @param string $sLegend
* @param string|null $sId
*/
public function __construct(string $sLegend, ?string $sId = null)
{
parent::__construct($sId);
$this->sLegend = $sLegend;
}
/**
* @return string
*/
public function GetLegend(): string
{
return $this->sLegend;
}
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* @copyright Copyright (C) 2010-2020 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Application\UI\Layout\Column;
use Combodo\iTop\Application\UI\Layout\UIContentBlock;
/**
* Class Column
*
* @package Combodo\iTop\Application\UI\Layout\Column
*/
class Column extends UIContentBlock
{
// Overloaded constants
public const BLOCK_CODE = 'ibo-column';
public const HTML_TEMPLATE_REL_PATH = 'layouts/column/layout';
public const JS_TEMPLATE_REL_PATH = 'layouts/column/layout';
}

View File

@@ -0,0 +1,44 @@
<?php
/**
* @copyright Copyright (C) 2010-2020 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Application\UI\Layout\MultiColumn;
use Combodo\iTop\Application\UI\Layout\Column\Column;
use Combodo\iTop\Application\UI\UIBlock;
/**
* Class MultiColumn
*
* @package Combodo\iTop\Application\UI\Layout\MultiColumn
*/
class MultiColumn extends UIBlock
{
// Overloaded constants
public const BLOCK_CODE = 'ibo-multicolumn';
public const HTML_TEMPLATE_REL_PATH = 'layouts/multicolumn/layout';
public const JS_TEMPLATE_REL_PATH = 'layouts/multicolumn/layout';
/** @var array */
protected $aColumns;
public function __construct(?string $sId = null)
{
parent::__construct($sId);
$this->aColumns = [];
}
public function AddColumn(Column $oColumn): self
{
$this->aColumns[] = $oColumn;
return $this;
}
public function GetSubBlocks()
{
return $this->aColumns;
}
}

View File

@@ -4,6 +4,7 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Application\UI\iUIBlock;
use Combodo\iTop\Application\UI\Layout\TabContainer\Tab\Tab;
use Combodo\iTop\Application\UI\Layout\TabContainer\TabContainer;
@@ -56,6 +57,24 @@ class TabManager
$this->AddToTab($this->m_sCurrentTabContainer, $this->m_sCurrentTab, $sHtml);
}
public function AddUIBlockToCurrentTab(iUIBlock $oBlock): iUIBlock
{
$this->AddUIBlockToTab($this->m_sCurrentTabContainer, $this->m_sCurrentTab, $oBlock);
return $oBlock;
}
public function AddUIBlockToTab(string $sTabContainer, string $sTabCode, iUIBlock $oBlock, $sTabTitle = null): void
{
if (!$this->TabExists($sTabContainer, $sTabCode)) {
$this->InitTab($sTabContainer, $sTabCode, static::ENUM_TAB_TYPE_HTML, $sTabTitle);
}
$oTab = $this->GetTab($sTabContainer, $sTabCode);
// Append to the content of the tab
$oTab->AddSubBlock($oBlock);
}
/**
* @return int
* @deprecated 2.8.0

View File

@@ -45,6 +45,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
private $m_aMessages;
private $m_aInitScript = array();
/** @var \TabManager */
protected $m_oTabs;
protected $bBreadCrumbEnabled;
protected $sBreadCrumbEntryId;
@@ -1320,6 +1321,14 @@ EOF;
return null;
}
public function AddUiBlock(iUIBlock $oBlock): iUIBlock
{
if (($this->m_oTabs->GetCurrentTabContainer() != '') && ($this->m_oTabs->GetCurrentTab() != '')) {
return $this->m_oTabs->AddUIBlockToCurrentTab($oBlock);
}
return parent::AddUiBlock($oBlock);
}
/**
* @inheritDoc
*/

View File

@@ -0,0 +1,5 @@
{% set aParams = oUIBlock.GetParams() %}
<div class="ibo-field ibo-field-{{ aParams.layout }}">
<div class="ibo-field-label">{{ aParams.label|raw }}</div>
<div class="ibo-field-value">{{ aParams.value|raw }}</div>
</div>

View File

@@ -0,0 +1,6 @@
<fieldset class="ibo-fieldset">
<legend>{{ oUIBlock.GetLegend() }}</legend>
{% for oSubBlock in oUIBlock.GetSubBlocks() %}
{{ render_block(oSubBlock, {aPage: aPage}) }}
{% endfor %}
</fieldset>

View File

@@ -0,0 +1,7 @@
{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
<div class="ibo-column">
{% for oSubBlock in oUIBlock.GetSubBlocks() %}
{{ render_block(oSubBlock, {aPage: aPage}) }}
{% endfor %}
</div>

View File

@@ -0,0 +1,7 @@
{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
<div class="ibo-multi-column">
{% for oSubBlock in oUIBlock.GetSubBlocks() %}
{{ render_block(oSubBlock, {aPage: aPage}) }}
{% endfor %}
</div>

View File

@@ -1,27 +1,26 @@
{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
<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>
{% block iboTabContainer %}
<div class="ibo-tab-container-spinner"><i class="fas fa-spinner fa-spin fa-2x"></i></div>
<!-- tabs -->
<div id="tabbedContent_{$sPrefix}{$container_index}" class="ibo-tab-container light" style="display: none;">
<ul class="ibo-tab-container-header">
{% for oTab in oUIBlock.GetSubBlocks() %}
{% if oTab.GetType() == 'html' %}
<div id="tab_{{ oTab.GetId() }}">
{{ render_block(oTab, {aPage: aPage}) }}
</div>
{% if oTab.GetType() == 'ajax' %}
<li class="ibo-tab-header ibo-tab-header-ajax" data-cache="{{ oTab.GetCache() }}"><a href="{{ oTab.GetURL() }}" class="ibo-tab-link" data-tab-id="$sTabCodeForHtml"><span>{{ oTab.GetTitle() }}</span></a></li>
{% elseif oTab.GetType() == 'html' %}
<li class="ibo-tab-header ibo-tab-header-html"><a href="#tab_{{ oTab.GetId() }}" class="ibo-tab-link" data-tab-id="$sTabCodeForHtml"><span>{{ oTab.GetTitle() }}</span></a></li>
{% endif %}
{% endfor %}
</div>
<!-- end of tabs-->
{% endblock %}
</div>
</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 %}