mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-19 15:22:17 +02:00
N°2847 - Rework of TabContainer / Tab
- Add JS widget to handle front-end logic and for better encapsulation - Move SCSS files to match convention - Update SCSS files - Remove unused SCSS file - Move HTML templates to match convention - Remove unused HTML template - Renamed codes and folders to match convention - Update PHPDoc - Reformat code - Remove usage of return type hinting when using "self"
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
/*!
|
||||
* copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
@@ -13,9 +13,8 @@
|
||||
@import "popover-menu/popover-menu-item";
|
||||
@import "newsroom-menu";
|
||||
|
||||
@import "tabcontainer";
|
||||
@import "tab";
|
||||
@import "ajaxtab";
|
||||
@import "tab-container/tab-container";
|
||||
@import "tab-container/tab";
|
||||
@import "title";
|
||||
@import "form";
|
||||
@import "input";
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
/*!
|
||||
* copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
@@ -1,37 +0,0 @@
|
||||
/*!
|
||||
* copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
.ibo-tab-container {
|
||||
|
||||
}
|
||||
|
||||
.ibo-tab-container-header {
|
||||
background: $ibo-color-grey-100;
|
||||
}
|
||||
|
||||
.ibo-tab-header {
|
||||
a {
|
||||
@extend %ibo-font-ral-med-200;
|
||||
color: $ibo-color-grey-700;
|
||||
|
||||
:hover {
|
||||
color: $ibo-color-grey-900;
|
||||
}
|
||||
}
|
||||
|
||||
&.ui-state-active a {
|
||||
color: $ibo-color-blue-800;
|
||||
@extend %ibo-font-ral-bol-200;
|
||||
|
||||
:hover {
|
||||
color: $ibo-color-blue-800;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-tab-content {
|
||||
background: $ibo-color-white-100;
|
||||
}
|
||||
|
||||
55
css/backoffice/components/tab-container/_tab-container.scss
Normal file
55
css/backoffice/components/tab-container/_tab-container.scss
Normal file
@@ -0,0 +1,55 @@
|
||||
/*!
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/* SCSS variables */
|
||||
$ibo-tab-container--tabs-list--height: 36px !default;
|
||||
$ibo-tab-container--tabs-list--padding-x: 24px !default;
|
||||
$ibo-tab-container--tabs-list--background-color: $ibo-color-grey-100 !default;
|
||||
|
||||
$ibo-tab-container--tab-header--max-width: 110px !default;
|
||||
$ibo-tab-container--tab-header--text-color: $ibo-color-grey-700 !default;
|
||||
$ibo-tab-container--tab-header--text-color--is-active: $ibo-color-blue-800 !default;
|
||||
$ibo-tab-container--tab-header--text-color--on-hover: $ibo-color-blue-800 !default;
|
||||
$ibo-tab-container--tab-header--background-color--on-hover: $ibo-color-grey-200 !default;
|
||||
|
||||
$ibo-tab-container--tab-toggler--padding-x: 24px !default;
|
||||
|
||||
/* Rules */
|
||||
.ibo-tab-container--tabs-list {
|
||||
@extend %ibo-full-height-content;
|
||||
justify-content: center;
|
||||
height: $ibo-tab-container--tabs-list--height;
|
||||
|
||||
background-color: $ibo-tab-container--tabs-list--background-color;
|
||||
@extend %ibo-font-ral-nor-150;
|
||||
}
|
||||
.ibo-tab-container--tab-header{
|
||||
@extend %ibo-full-height-content;
|
||||
|
||||
color: $ibo-tab-container--tab-header--text-color;
|
||||
|
||||
&:hover{
|
||||
color: $ibo-tab-container--tab-header--text-color--on-hover;
|
||||
background-color: $ibo-tab-container--tab-header--background-color--on-hover;
|
||||
}
|
||||
&.ui-tabs-active{
|
||||
@extend %ibo-font-ral-bol-150;
|
||||
color: $ibo-tab-container--tab-header--text-color--is-active;
|
||||
}
|
||||
}
|
||||
.ibo-tab-container--tab-toggler{
|
||||
@extend %ibo-fully-centered-content;
|
||||
padding-left: $ibo-tab-container--tab-toggler--padding-x;
|
||||
padding-right: $ibo-tab-container--tab-toggler--padding-x;
|
||||
|
||||
@extend %ibo-text-truncated-with-ellipsis;
|
||||
color: inherit; /* To get color from parent */
|
||||
|
||||
&:hover,
|
||||
&:active{
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
28
css/backoffice/components/tab-container/_tab.scss
Normal file
28
css/backoffice/components/tab-container/_tab.scss
Normal file
@@ -0,0 +1,28 @@
|
||||
/*!
|
||||
* @copyright Copyright (C) 2010-2020 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
.ibo-tab--header {
|
||||
a {
|
||||
@extend %ibo-font-ral-med-200;
|
||||
color: $ibo-color-grey-700;
|
||||
|
||||
:hover {
|
||||
color: $ibo-color-grey-900;
|
||||
}
|
||||
}
|
||||
|
||||
&.ui-state-active a {
|
||||
color: $ibo-color-blue-800;
|
||||
@extend %ibo-font-ral-bol-200;
|
||||
|
||||
:hover {
|
||||
color: $ibo-color-blue-800;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-tab--content {
|
||||
background: $ibo-color-white-100;
|
||||
}
|
||||
@@ -929,52 +929,52 @@ button.ui-button {
|
||||
.ui-spinner-down {
|
||||
bottom: 0;
|
||||
}
|
||||
.ui-tabs {
|
||||
position: relative;
|
||||
padding: .2em;
|
||||
.ui-tabs-nav {
|
||||
margin: 0;
|
||||
padding: .2em .2em 0;
|
||||
li {
|
||||
list-style: none;
|
||||
float: left;
|
||||
position: relative;
|
||||
top: 0;
|
||||
margin: 1px .2em 0 0;
|
||||
border-bottom-width: 0;
|
||||
padding: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.ui-tabs-anchor {
|
||||
float: left;
|
||||
padding: .5em 1em;
|
||||
text-decoration: none;
|
||||
}
|
||||
li.ui-tabs-active {
|
||||
margin-bottom: -1px;
|
||||
padding-bottom: 1px;
|
||||
.ui-tabs-anchor {
|
||||
cursor: text;
|
||||
}
|
||||
}
|
||||
li.ui-state-disabled {
|
||||
.ui-tabs-anchor {
|
||||
cursor: text;
|
||||
}
|
||||
}
|
||||
li.ui-tabs-loading {
|
||||
.ui-tabs-anchor {
|
||||
cursor: text;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ui-tabs-panel {
|
||||
display: block;
|
||||
border-width: 0;
|
||||
padding: 1em 1.4em;
|
||||
// background: none;
|
||||
}
|
||||
}
|
||||
//.ui-tabs {
|
||||
// position: relative;
|
||||
// padding: .2em;
|
||||
// .ui-tabs-nav {
|
||||
// margin: 0;
|
||||
// padding: .2em .2em 0;
|
||||
// li {
|
||||
// list-style: none;
|
||||
// float: left;
|
||||
// position: relative;
|
||||
// top: 0;
|
||||
// margin: 1px .2em 0 0;
|
||||
// border-bottom-width: 0;
|
||||
// padding: 0;
|
||||
// white-space: nowrap;
|
||||
// }
|
||||
// .ui-tabs-anchor {
|
||||
// float: left;
|
||||
// padding: .5em 1em;
|
||||
// text-decoration: none;
|
||||
// }
|
||||
// li.ui-tabs-active {
|
||||
// margin-bottom: -1px;
|
||||
// padding-bottom: 1px;
|
||||
// .ui-tabs-anchor {
|
||||
// cursor: text;
|
||||
// }
|
||||
// }
|
||||
// li.ui-state-disabled {
|
||||
// .ui-tabs-anchor {
|
||||
// cursor: text;
|
||||
// }
|
||||
// }
|
||||
// li.ui-tabs-loading {
|
||||
// .ui-tabs-anchor {
|
||||
// cursor: text;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .ui-tabs-panel {
|
||||
// display: block;
|
||||
// border-width: 0;
|
||||
// padding: 1em 1.4em;
|
||||
// // background: none;
|
||||
// }
|
||||
//}
|
||||
.ui-tabs-collapsible {
|
||||
.ui-tabs-nav {
|
||||
li.ui-tabs-active {
|
||||
|
||||
@@ -1,44 +1,140 @@
|
||||
// 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';
|
||||
$(function()
|
||||
{
|
||||
$.widget( 'itop.tab_container',
|
||||
{
|
||||
// default options
|
||||
options:
|
||||
{
|
||||
},
|
||||
css_classes:
|
||||
{
|
||||
},
|
||||
js_selectors:
|
||||
{
|
||||
tabs_list: '[data-role="ibo-tab-container--tabs-list"]',
|
||||
tab_header: '[data-role="ibo-tab-container--tab-header"]',
|
||||
tab_toggler: '[data-role="ibo-tab-container--tab-toggler"]',
|
||||
},
|
||||
|
||||
// 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'});
|
||||
// the constructor
|
||||
_create: function()
|
||||
{
|
||||
this.element.addClass('ibo-tab-container');
|
||||
|
||||
// Define our own click handler for the tabs, overriding the default.
|
||||
tabs.find(tab_a_selector).click(function () {
|
||||
var state = {};
|
||||
// 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) {
|
||||
this.element.find(this.js_selectors.tab_toggler).each(function () {
|
||||
const sHash = location.hash;
|
||||
const sCleanLocation = location.href.toString().replace(sHash, '').replace(/#$/, '');
|
||||
$(this).attr('href', sCleanLocation + $(this).attr('href'));
|
||||
});
|
||||
}
|
||||
|
||||
// Get the id of this tab widget.
|
||||
var id = $(this).closest('div[id^=tabbedContent]').attr('id');
|
||||
if ($.bbq) {
|
||||
// This selector will be reused when selecting actual tab widget A elements.
|
||||
const sTabAnchorSelector = 'ul.ui-tabs-nav a';
|
||||
|
||||
// Get the index of this tab.
|
||||
var idx = $(this).parent().prevAll().length;
|
||||
// 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.
|
||||
this.element.tabs({event: 'change'});
|
||||
} else {
|
||||
this.element.tabs();
|
||||
}
|
||||
|
||||
// Set the state!
|
||||
state[id] = idx;
|
||||
$.bbq.pushState(state);
|
||||
});
|
||||
} else {
|
||||
tabs.tabs();
|
||||
}
|
||||
$('.ibo-tab-container-spinner').hide();
|
||||
$('.ibo-tab-container').show();
|
||||
this._bindEvents();
|
||||
},
|
||||
// events bound via _bind are removed automatically
|
||||
// revert other modifications here
|
||||
_destroy: function()
|
||||
{
|
||||
this.element.removeClass('ibo-tab-container');
|
||||
},
|
||||
_bindEvents: function()
|
||||
{
|
||||
const me = this;
|
||||
|
||||
// Bind an event on tab activation
|
||||
this.element.on('tabsactivate', function(oEvent, oUI){
|
||||
me._onTabActivated(oUI);
|
||||
});
|
||||
// Bind an event to window.onhashchange that, when the history state changes,
|
||||
// iterates over all tab widgets, changing the current tab as necessary.
|
||||
$(window).on('hashchange', function(){
|
||||
me._onHashChange();
|
||||
});
|
||||
// Define our own click handler for the tabs, overriding the default.
|
||||
this.element.find(this.js_selectors.tab_toggler).on('click', function(){
|
||||
me._onTogglerClick($(this));
|
||||
});
|
||||
},
|
||||
|
||||
// Events callbacks
|
||||
// - Update URL hash when tab is activated
|
||||
_onTabActivated: function(oUI)
|
||||
{
|
||||
let oState = {};
|
||||
|
||||
// Get the id of this tab widget.
|
||||
const sId = this.element.attr( 'id' );
|
||||
|
||||
// Get the index of this tab.
|
||||
const iIdx = $(oUI.newTab).prevAll().length;
|
||||
|
||||
// Set the state!
|
||||
oState[ sId ] = iIdx;
|
||||
$.bbq.pushState( oState );
|
||||
},
|
||||
// - Change current tab as necessary when URL hash changes
|
||||
_onHashChange: function()
|
||||
{
|
||||
// Get the index for this tab widget from the hash, based on the
|
||||
// appropriate id property. In jQuery 1.4, you should use e.getState()
|
||||
// instead of $.bbq.getState(). The second, 'true' argument coerces the
|
||||
// string value to a number.
|
||||
const iIdx = $.bbq.getState( this.element.attr('id'), true ) || 0;
|
||||
|
||||
// Select the appropriate tab for this tab widget by triggering the custom
|
||||
// event specified in the .tabs() init above (you could keep track of what
|
||||
// tab each widget is on using .data, and only select a tab if it has
|
||||
// changed).
|
||||
this.element.find(this.js_selectors.tab_toggler).eq(iIdx).triggerHandler('change');
|
||||
|
||||
// Iterate over all truncated lists to find whether they are expanded or not
|
||||
$('a.truncated').each(function()
|
||||
{
|
||||
const sState = $.bbq.getState( this.id, true ) || 'close';
|
||||
if (sState === 'open')
|
||||
{
|
||||
$(this).trigger('open');
|
||||
}
|
||||
else
|
||||
{
|
||||
$(this).trigger('close');
|
||||
}
|
||||
});
|
||||
},
|
||||
_onTogglerClick: function(oTabHeaderElem)
|
||||
{
|
||||
if ($.bbq) {
|
||||
let oState = {};
|
||||
|
||||
// Get the id of this tab widget.
|
||||
const sId = this.element.attr('id');
|
||||
|
||||
// Get the index of this tab.
|
||||
const iIdx = oTabHeaderElem.parent().prevAll().length;
|
||||
|
||||
// Set the state!
|
||||
oState[sId] = iIdx;
|
||||
$.bbq.pushState(oState);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,7 +21,6 @@ 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;
|
||||
@@ -30,95 +29,99 @@ use TabManager;
|
||||
* Class AjaxTab
|
||||
*
|
||||
* @package Combodo\iTop\Application\UI\Layout\TabContainer\Tab
|
||||
* @internal
|
||||
* @since 2.8.0
|
||||
*/
|
||||
class AjaxTab extends Tab
|
||||
{
|
||||
class AjaxTab extends Tab {
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-ajaxtab';
|
||||
public const HTML_TEMPLATE_REL_PATH = 'layouts/tabcontainer/tab/ajaxtab';
|
||||
public const BLOCK_CODE = 'ibo-ajax-tab';
|
||||
public const TAB_TYPE = TabManager::ENUM_TAB_TYPE_AJAX;
|
||||
|
||||
protected const TAB_TYPE = TabManager::ENUM_TAB_TYPE_AJAX;
|
||||
|
||||
/** @var string */
|
||||
private $sURL;
|
||||
/** @var bool */
|
||||
/** @var string The target URL to be loaded asynchronously */
|
||||
private $sUrl;
|
||||
/** @var bool Whether the tab should should be cached by the browser or always refreshed */
|
||||
private $bCache;
|
||||
|
||||
/**
|
||||
* @param string $sHtml
|
||||
* @param string $sUrl
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\iUIBlock
|
||||
* @throws \Combodo\iTop\Application\UI\UIException
|
||||
* @return $this
|
||||
*/
|
||||
public function AddHtml(string $sHtml): iUIBlock
|
||||
{
|
||||
throw new UIException($this, Dict::Format('UIBlock:Error:AddBlockForbidden', $this->GetId()));
|
||||
}
|
||||
public function SetUrl(string $sUrl) {
|
||||
$this->sUrl = $sUrl;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetUrl(): string {
|
||||
return $this->sUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the tab should should be cached by the browser or always refreshed
|
||||
*
|
||||
* @param bool $bCache
|
||||
*
|
||||
* @return AjaxTab
|
||||
* @return $this
|
||||
*/
|
||||
public function SetCache(bool $bCache): self
|
||||
{
|
||||
public function SetCache(bool $bCache) {
|
||||
$this->bCache = $bCache;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the tab should should be cached by the browser or always refreshed
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetURL(): string
|
||||
{
|
||||
return $this->sURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetCache(): string
|
||||
{
|
||||
public function GetCache(): string {
|
||||
return $this->bCache ? 'true' : 'false';
|
||||
}
|
||||
|
||||
public function GetParameters(): array
|
||||
{
|
||||
//-------------------------------
|
||||
// iUIBlock implementation
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetParameters(): array {
|
||||
$aParams = parent::GetParameters();
|
||||
|
||||
$aParams['sURL'] = $this->GetURL();
|
||||
$aParams['sURL'] = $this->GetUrl();
|
||||
$aParams['sCache'] = $this->GetCache() ? 'true' : 'false';
|
||||
|
||||
return $aParams;
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// iUIContentBlock implementation
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Combodo\iTop\Application\UI\UIException
|
||||
*/
|
||||
public function AddHtml(string $sHtml) {
|
||||
throw new UIException($this, Dict::Format('UIBlock:Error:AddBlockForbidden', $this->GetId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Combodo\iTop\Application\UI\UIException
|
||||
*/
|
||||
public function AddSubBlock(iUIBlock $oSubBlock) {
|
||||
throw new UIException($this, Dict::Format('UIBlock:Error:AddBlockForbidden', $this->GetId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetSubBlocks(): array {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,33 +27,56 @@ use TabManager;
|
||||
* Class Tab
|
||||
*
|
||||
* @package Combodo\iTop\Application\UI\Layout\TabContainer\Tab
|
||||
* @internal
|
||||
* @since 2.8.0
|
||||
*/
|
||||
class Tab extends UIContentBlock
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-tab';
|
||||
public const HTML_TEMPLATE_REL_PATH = 'layouts/tabcontainer/tab/tab';
|
||||
public const HTML_TEMPLATE_REL_PATH = 'layouts/tab-container/tab/layout';
|
||||
|
||||
protected const TAB_TYPE = TabManager::ENUM_TAB_TYPE_HTML;
|
||||
/** @var string */
|
||||
public const TAB_TYPE = TabManager::ENUM_TAB_TYPE_HTML;
|
||||
|
||||
/** @var string */
|
||||
protected $sTitle;
|
||||
|
||||
/**
|
||||
* Tab constructor.
|
||||
*
|
||||
* @param string $sTabCode
|
||||
* @param string $sTitle
|
||||
*/
|
||||
public function __construct(string $sTabCode, string $sTitle)
|
||||
{
|
||||
parent::__construct($sTabCode);
|
||||
$this->sTitle = $sTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetType(): string
|
||||
{
|
||||
return static::TAB_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetTitle(): string
|
||||
{
|
||||
return $this->sTitle;
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
// iUIBlock implementation
|
||||
//-------------------------------
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetParameters(): array
|
||||
{
|
||||
return [
|
||||
|
||||
@@ -36,8 +36,9 @@ use Dict;
|
||||
class TabContainer extends UIContentBlock
|
||||
{
|
||||
// Overloaded constants
|
||||
public const BLOCK_CODE = 'ibo-tabcontainer';
|
||||
public const HTML_TEMPLATE_REL_PATH = 'layouts/tabcontainer/layout';
|
||||
public const BLOCK_CODE = 'ibo-tab-container';
|
||||
public const HTML_TEMPLATE_REL_PATH = 'layouts/tab-container/layout';
|
||||
public const JS_TEMPLATE_REL_PATH = 'layouts/tab-container/layout';
|
||||
public const JS_FILES_REL_PATH = [
|
||||
'js/layouts/tab-container.js'
|
||||
];
|
||||
|
||||
@@ -209,7 +209,7 @@ class TabManager
|
||||
// Set the content of the tab
|
||||
/** @var \Combodo\iTop\Application\UI\Layout\TabContainer\Tab\AjaxTab $oTab */
|
||||
$oTab = $this->InitTab($this->m_sCurrentTabContainer, $sTabCode, static::ENUM_TAB_TYPE_AJAX, $sTabTitle);
|
||||
$oTab->SetURL($sUrl)
|
||||
$oTab->SetUrl($sUrl)
|
||||
->SetCache($bCache);
|
||||
|
||||
return ''; // Nothing to add to the page for now
|
||||
|
||||
@@ -366,57 +366,6 @@ JS
|
||||
SetUserPreference(parent_id+'_'+this.id+'_height', $(this).height(), true); // true => persistent
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
// refresh the hash when the tab is changed (from a JS script)
|
||||
$('body').on( 'tabsactivate', '.ui-tabs', function(event, ui) {
|
||||
var state = {};
|
||||
|
||||
// Get the id of this tab widget.
|
||||
var id = $(ui.newTab).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
|
||||
|
||||
// Get the index of this tab.
|
||||
var idx = $(ui.newTab).prevAll().length;
|
||||
|
||||
// Set the state!
|
||||
state[ id ] = idx;
|
||||
$.bbq.pushState( state );
|
||||
});
|
||||
|
||||
// Bind an event to window.onhashchange that, when the history state changes,
|
||||
// iterates over all tab widgets, changing the current tab as necessary.
|
||||
$(window).bind( 'hashchange', function(e)
|
||||
{
|
||||
// Iterate over all tab widgets.
|
||||
tabs.each(function()
|
||||
{
|
||||
// Get the index for this tab widget from the hash, based on the
|
||||
// appropriate id property. In jQuery 1.4, you should use e.getState()
|
||||
// instead of $.bbq.getState(). The second, 'true' argument coerces the
|
||||
// string value to a number.
|
||||
var idx = $.bbq.getState( this.id, true ) || 0;
|
||||
|
||||
// Select the appropriate tab for this tab widget by triggering the custom
|
||||
// event specified in the .tabs() init above (you could keep track of what
|
||||
// tab each widget is on using .data, and only select a tab if it has
|
||||
// changed).
|
||||
$(this).find( tab_a_selector ).eq( idx ).triggerHandler( 'change' );
|
||||
});
|
||||
|
||||
// Iterate over all truncated lists to find whether they are expanded or not
|
||||
$('a.truncated').each(function()
|
||||
{
|
||||
var state = $.bbq.getState( this.id, true ) || 'close';
|
||||
if (state == 'open')
|
||||
{
|
||||
$(this).trigger('open');
|
||||
}
|
||||
else
|
||||
{
|
||||
$(this).trigger('close');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Shortcut menu actions
|
||||
$('.actions_button a').click( function() {
|
||||
|
||||
31
templates/layouts/tab-container/layout.html.twig
Normal file
31
templates/layouts/tab-container/layout.html.twig
Normal file
@@ -0,0 +1,31 @@
|
||||
{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
<div id="{{ oUIBlock.GetId() }}" class="ibo-tab-container" data-role="ibo-tab-container">
|
||||
{% block iboTabContainer %}
|
||||
<ul class="ibo-tab-container--tabs-list" data-role="ibo-tab-container--tabs-list">
|
||||
{% block iboTabContainerTabsList %}
|
||||
{% for oTab in oUIBlock.GetSubBlocks() %}
|
||||
{% if oTab.GetType() == constant('TabManager::ENUM_TAB_TYPE_AJAX') %}
|
||||
<li class="ibo-tab-container--tab-header" data-role="ibo-tab-container--tab-header" data-tab-id="tab_{{ loop.index }}" data-tab-type="{{ oTab.GetType() }}" data-cache="{{ oTab.GetCache() }}">
|
||||
<a href="{{ oTab.GetUrl() }}" class="ibo-tab-container--tab-toggler" data-role="ibo-tab-container--tab-toggler"><span>{{ oTab.GetTitle() }}</span></a>
|
||||
</li>
|
||||
{% elseif oTab.GetType() == constant('TabManager::ENUM_TAB_TYPE_HTML') %}
|
||||
<li class="ibo-tab-container--tab-header" data-role="ibo-tab-container--tab-header" data-tab-id="tab_{{ loop.index }}" data-tab-type="{{ oTab.GetType() }}">
|
||||
<a href="#tab_{{ loop.index }}" class="ibo-tab-container--tab-toggler" data-role="ibo-tab-container--tab-toggler"><span>{{ oTab.GetTitle() }}</span></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
</ul>
|
||||
{% block iboTabContainerTabsContainers %}
|
||||
{% for oTab in oUIBlock.GetSubBlocks() %}
|
||||
{% if oTab.GetType() == 'html' %}
|
||||
<div id="tab_{{ loop.index }}" class="ibo-tab-container--tab-container">
|
||||
{{ render_block(oTab, {aPage: aPage}) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
1
templates/layouts/tab-container/layout.js.twig
Normal file
1
templates/layouts/tab-container/layout.js.twig
Normal file
@@ -0,0 +1 @@
|
||||
$('#{{ oUIBlock.GetId() }}').tab_container();
|
||||
9
templates/layouts/tab-container/tab/layout.html.twig
Normal file
9
templates/layouts/tab-container/tab/layout.html.twig
Normal file
@@ -0,0 +1,9 @@
|
||||
{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
<div id="{{ oUIBlock.GetId() }}" class="ibo-tab">
|
||||
{% block iboContentBlockContainer %}
|
||||
{% for oSubBlock in oUIBlock.GetSubBlocks() %}
|
||||
{{ render_block(oSubBlock, {aPage: aPage}) }}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
@@ -1,26 +0,0 @@
|
||||
{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
{% 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" style="display: none;">
|
||||
<ul class="ibo-tab-container-header">
|
||||
{% for oTab in oUIBlock.GetSubBlocks() %}
|
||||
{% 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 %}
|
||||
</ul>
|
||||
{% for oTab in oUIBlock.GetSubBlocks() %}
|
||||
{% if oTab.GetType() == 'html' %}
|
||||
<div id="tab_{{ oTab.GetId() }}" class="ibo-tab-content">
|
||||
{{ render_block(oTab, {aPage: aPage}) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<!-- end of tabs-->
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
@@ -1,2 +0,0 @@
|
||||
{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
@@ -1,9 +0,0 @@
|
||||
{# @copyright Copyright (C) 2010-2020 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
<div id="{{ oUIBlock.GetId() }}" class="ibo-tab-content-block">
|
||||
{% block iboContentBlockContainer %}
|
||||
{% for oSubBlock in oUIBlock.GetSubBlocks() %}
|
||||
{{ render_block(oSubBlock, {aPage: aPage}) }}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
Reference in New Issue
Block a user