diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php index 1877490b4..31cfe1fe4 100644 --- a/application/cmdbabstract.class.inc.php +++ b/application/cmdbabstract.class.inc.php @@ -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(''); - foreach($aCols as $sColIndex => $aFieldsets) - { - $oPage->add(''); } - $oPage->add('
'); - $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('
'); - $oPage->add(''.Dict::S($sPreviousLabel).''); - } - $oPage->Details($aDetails[$sTab][$sColIndex]); - if (!empty($sPreviousLabel)) - { - $oPage->add('
'); - } - $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 = " "; $sTip = ''; - foreach($aReasons as $aRow) - { + foreach ($aReasons as $aRow) { $sDescription = htmlentities($aRow['description'], ENT_QUOTES, 'UTF-8'); $sDescription = str_replace(array("\r\n", "\n"), "
", @@ -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('
'); - $oPage->add(''.Dict::S($sFieldsetName).''); - } - $oPage->Details($aDetails[$sTab][$sColIndex]); - if (!empty($sPreviousLabel)) - { - $oPage->add('
'); - } - $oPage->add('
'); } return $aFieldsMap; diff --git a/css/backoffice/components/_all.scss b/css/backoffice/components/_all.scss index 0539711ae..ecaaa2edf 100644 --- a/css/backoffice/components/_all.scss +++ b/css/backoffice/components/_all.scss @@ -18,4 +18,6 @@ @import "ajaxtab"; @import "title"; @import "form"; -@import "input"; \ No newline at end of file +@import "input"; +@import "fieldset"; +@import "field"; \ No newline at end of file diff --git a/css/backoffice/components/_field.scss b/css/backoffice/components/_field.scss new file mode 100644 index 000000000..ee36d1a89 --- /dev/null +++ b/css/backoffice/components/_field.scss @@ -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%; +} \ No newline at end of file diff --git a/css/backoffice/components/_fieldset.scss b/css/backoffice/components/_fieldset.scss new file mode 100644 index 000000000..2b1c120e8 --- /dev/null +++ b/css/backoffice/components/_fieldset.scss @@ -0,0 +1,4 @@ +/*! + * copyright Copyright (C) 2010-2020 Combodo SARL + * license http://opensource.org/licenses/AGPL-3.0 + */ diff --git a/css/backoffice/layout/_all.scss b/css/backoffice/layout/_all.scss index 20ae44aaa..c866387f8 100644 --- a/css/backoffice/layout/_all.scss +++ b/css/backoffice/layout/_all.scss @@ -23,4 +23,6 @@ @import "activity-panel/activity-entry"; @import "activity-panel/caselog-entry"; @import "activity-panel/edits-entry"; -@import "activity-panel/transition-entry"; \ No newline at end of file +@import "activity-panel/transition-entry"; +@import "multicolumn"; +@import "column"; \ No newline at end of file diff --git a/css/backoffice/layout/_column.scss b/css/backoffice/layout/_column.scss new file mode 100644 index 000000000..e0ae24b08 --- /dev/null +++ b/css/backoffice/layout/_column.scss @@ -0,0 +1,7 @@ +/*! + * copyright Copyright (C) 2010-2020 Combodo SARL + * license http://opensource.org/licenses/AGPL-3.0 + */ + +.ibo-column { +} \ No newline at end of file diff --git a/css/backoffice/layout/_multicolumn.scss b/css/backoffice/layout/_multicolumn.scss new file mode 100644 index 000000000..1284ddec5 --- /dev/null +++ b/css/backoffice/layout/_multicolumn.scss @@ -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; +} \ No newline at end of file diff --git a/js/layouts/tab-container.js b/js/layouts/tab-container.js index a0527a4fc..2f62d07e5 100644 --- a/js/layouts/tab-container.js +++ b/js/layouts/tab-container.js @@ -40,3 +40,5 @@ if ($.bbq) { } else { tabs.tabs(); } +$('.ibo-tab-container-spinner').hide(); +$('.ibo-tab-container').show(); \ No newline at end of file diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php index 66a290779..e45a082d9 100644 --- a/lib/composer/autoload_classmap.php +++ b/lib/composer/autoload_classmap.php @@ -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', diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php index eb3cf7b0f..b3aa92969 100644 --- a/lib/composer/autoload_static.php +++ b/lib/composer/autoload_static.php @@ -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', diff --git a/sources/application/UI/Component/Field/Field.php b/sources/application/UI/Component/Field/Field.php new file mode 100644 index 000000000..eb8b596b2 --- /dev/null +++ b/sources/application/UI/Component/Field/Field.php @@ -0,0 +1,41 @@ +aParams = $aParams; + } + + /** + * @return string + */ + public function GetParams(): array + { + return $this->aParams; + } + +} \ No newline at end of file diff --git a/sources/application/UI/Component/FieldSet/FieldSet.php b/sources/application/UI/Component/FieldSet/FieldSet.php new file mode 100644 index 000000000..1a50ea9cd --- /dev/null +++ b/sources/application/UI/Component/FieldSet/FieldSet.php @@ -0,0 +1,47 @@ +sLegend = $sLegend; + } + + /** + * @return string + */ + public function GetLegend(): string + { + return $this->sLegend; + } + +} \ No newline at end of file diff --git a/sources/application/UI/Layout/Column/Column.php b/sources/application/UI/Layout/Column/Column.php new file mode 100644 index 000000000..36ac0c648 --- /dev/null +++ b/sources/application/UI/Layout/Column/Column.php @@ -0,0 +1,23 @@ +aColumns = []; + } + + public function AddColumn(Column $oColumn): self + { + $this->aColumns[] = $oColumn; + return $this; + } + + public function GetSubBlocks() + { + return $this->aColumns; + } +} \ No newline at end of file diff --git a/sources/application/WebPage/TabManager.php b/sources/application/WebPage/TabManager.php index d064e7858..a66cbe3aa 100644 --- a/sources/application/WebPage/TabManager.php +++ b/sources/application/WebPage/TabManager.php @@ -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 diff --git a/sources/application/WebPage/iTopWebPage.php b/sources/application/WebPage/iTopWebPage.php index ef2d13c52..369ee9f09 100644 --- a/sources/application/WebPage/iTopWebPage.php +++ b/sources/application/WebPage/iTopWebPage.php @@ -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 */ diff --git a/templates/components/field/layout.html.twig b/templates/components/field/layout.html.twig new file mode 100644 index 000000000..019b27d24 --- /dev/null +++ b/templates/components/field/layout.html.twig @@ -0,0 +1,5 @@ +{% set aParams = oUIBlock.GetParams() %} +
+
{{ aParams.label|raw }}
+
{{ aParams.value|raw }}
+
\ No newline at end of file diff --git a/templates/components/fieldset/layout.html.twig b/templates/components/fieldset/layout.html.twig new file mode 100644 index 000000000..8a48346eb --- /dev/null +++ b/templates/components/fieldset/layout.html.twig @@ -0,0 +1,6 @@ +
+ {{ oUIBlock.GetLegend() }} + {% for oSubBlock in oUIBlock.GetSubBlocks() %} + {{ render_block(oSubBlock, {aPage: aPage}) }} + {% endfor %} +
\ No newline at end of file diff --git a/templates/layouts/column/layout.html.twig b/templates/layouts/column/layout.html.twig new file mode 100644 index 000000000..716e4f3eb --- /dev/null +++ b/templates/layouts/column/layout.html.twig @@ -0,0 +1,7 @@ +{# @copyright Copyright (C) 2010-2020 Combodo SARL #} +{# @license http://opensource.org/licenses/AGPL-3.0 #} +
+ {% for oSubBlock in oUIBlock.GetSubBlocks() %} + {{ render_block(oSubBlock, {aPage: aPage}) }} + {% endfor %} +
\ No newline at end of file diff --git a/templates/layouts/multicolumn/layout.html.twig b/templates/layouts/multicolumn/layout.html.twig new file mode 100644 index 000000000..440076158 --- /dev/null +++ b/templates/layouts/multicolumn/layout.html.twig @@ -0,0 +1,7 @@ +{# @copyright Copyright (C) 2010-2020 Combodo SARL #} +{# @license http://opensource.org/licenses/AGPL-3.0 #} +
+ {% for oSubBlock in oUIBlock.GetSubBlocks() %} + {{ render_block(oSubBlock, {aPage: aPage}) }} + {% endfor %} +
\ No newline at end of file diff --git a/templates/layouts/tabcontainer/layout.html.twig b/templates/layouts/tabcontainer/layout.html.twig index b7815fdfe..17949b722 100644 --- a/templates/layouts/tabcontainer/layout.html.twig +++ b/templates/layouts/tabcontainer/layout.html.twig @@ -1,27 +1,26 @@ {# @copyright Copyright (C) 2010-2020 Combodo SARL #} {# @license http://opensource.org/licenses/AGPL-3.0 #} -
- {% block iboTabContainer %} - -
- +{% block iboTabContainer %} +
+ + - - {% endblock %} -
+ + {% for oTab in oUIBlock.GetSubBlocks() %} + {% if oTab.GetType() == 'html' %} +
+ {{ render_block(oTab, {aPage: aPage}) }} +
+ {% endif %} + {% endfor %} +
+ +{% endblock %}