1<?php 2 3namespace OOUI; 4 5/** 6 * IndexLayouts contain TabPanelLayout layouts as well as TabSelectWidget tabs that allow users 7 * to navigate through the tab panels and select which one to display. 8 * 9 * Default php rendering shows all the tabs 10 */ 11class IndexLayout extends MenuLayout { 12 13 /** 14 * @var StackLayout 15 */ 16 protected $stackLayout; 17 /** 18 * @var PanelLayout 19 */ 20 protected $tabPanel; 21 /** 22 * @var PanelLayout[] 23 */ 24 protected $tabPanels; 25 /** 26 * @var TabSelectWidget 27 */ 28 protected $tabSelectWidget; 29 /** 30 * @var bool 31 */ 32 protected $autoFocus; 33 /** 34 * @var bool 35 */ 36 protected $continuous; 37 /** 38 * @var string 39 */ 40 protected $currentTabPanelName; 41 42 /** 43 * @param array $config Configuration options 44 * - bool $config['continuous'] Focus on the first focusable element when a new tab panel is 45 * displayed. Disabled on mobile. (default: false) 46 * - bool $config['autoFocus'] (default: true) 47 * - bool $config['framed'] (default: true) 48 */ 49 public function __construct( array $config = [] ) { 50 $config = array_merge( 51 $config, 52 [ 'menuPosition' => 'top' ] 53 ); 54 55 parent::__construct( $config ); 56 57 $this->tabPanels = []; 58 $this->continuous = $config['continuous'] ?? false; 59 60 $this->stackLayout = $this->contentPanel ?? new StackLayout( [ 61 'continuous' => $this->continuous, 62 'expanded' => $this->expanded 63 ] ); 64 $this->setContentPanel( $this->stackLayout ); 65 $this->autoFocus = $config['autoFocus'] ?? true; 66 67 $this->tabSelectWidget = new TabSelectWidget( [ 68 'framed' => $config['framed'] ?? true 69 ] ); 70 $this->tabPanel = $this->menuPanel ?? new PanelLayout( [ 71 'expanded' => $this->expanded, 72 'preserveContent' => false 73 ] ); 74 $this->setMenuPanel( $this->tabPanel ); 75 76 $this->toggleMenu( true ); 77 78 $this->addClasses( [ 'oo-ui-indexLayout' ] ); 79 $this->stackLayout->addClasses( [ 'oo-ui-indexLayout-stackLayout' ] ); 80 $this->tabPanel 81 ->addClasses( [ 'oo-ui-indexLayout-tabPanel' ] ) 82 ->appendContent( $this->tabSelectWidget ); 83 } 84 85 public function getConfig( &$config ) { 86 $config = parent::getConfig( $config ); 87 if ( !$this->autoFocus ) { 88 $config['autoFocus'] = $this->autoFocus; 89 } 90 if ( $this->continuous ) { 91 $config['continuous'] = $this->continuous; 92 } 93 if ( count( $this->tabPanels ) ) { 94 $config['tabPanels'] = $this->tabPanels; 95 } 96 // menuPosition is not configurable 97 unset( $config['menuPosition'] ); 98 $config['tabSelectWidget'] = $this->tabSelectWidget; 99 // stackLayout and tabPanel are identical to 100 // contentPanel and menuPanel in MenuLayout 101 return $config; 102 } 103 104 /** 105 * Get the tabs widget. 106 * 107 * @return TabSelectWidget Tabs widget 108 */ 109 public function getTabs() { 110 return $this->tabSelectWidget; 111 } 112 113 /** 114 * Get a tab panel by its symbolic name. 115 * 116 * @param string $name Symbolic name of table panel 117 * @return TabPanelLayout Tab panel, if found 118 */ 119 public function getTabPanel( $name ) { 120 return $this->tabPanels[$name]; 121 } 122 123 public function getCurrentTabPanel() { 124 $name = $this->getCurrentTabPanelName(); 125 return $name ? $this->getTabPanel( $name ) : null; 126 } 127 128 public function getCurrentTabPanelName() { 129 return $this->currentTabPanelName; 130 } 131 132 /** 133 * Add tab panels to the index layout 134 * 135 * When tab panels are added with the same names as existing tab panels, the existing tab panels 136 * will be automatically removed before the new tab panels are added. 137 * 138 * @param TabPanelLayout[] $tabPanels Tab panels to add 139 */ 140 public function addTabPanels( array $tabPanels ) { 141 $tabItems = []; 142 foreach ( $tabPanels as $tabPanel ) { 143 $this->tabPanels[ $tabPanel->getName() ] = $tabPanel; 144 $tabItem = new TabOptionWidget( array_merge( [ 145 'data' => $tabPanel->getName(), 146 ], $tabPanel->getTabItemConfig() ) ); 147 $tabPanel->setTabItem( $tabItem ); 148 $tabItems[] = $tabItem; 149 } 150 $this->tabSelectWidget->addItems( $tabItems ); 151 $this->stackLayout->addItems( $tabPanels ); 152 153 // Select the first item 154 $this->getTabs()->selectItem( $tabItems[ 0 ] ); 155 } 156 157 /** 158 * Set the current tab panel by symbolic name. 159 * 160 * @param string $name Symbolic name of tab panel 161 */ 162 public function setTabPanel( $name ) { 163 if ( $name !== $this->currentTabPanelName ) { 164 $tabPanel = $this->getTabPanel( $name ); 165 $previousTabPanel = $this->getCurrentTabPanel(); 166 $selectedItem = $this->getTabs()->findSelectedItem(); 167 if ( !$selectedItem || $selectedItem->getData() !== $name ) { 168 $this->getTabs()->selectItemByData( $name ); 169 } 170 if ( $tabPanel ) { 171 if ( $previousTabPanel ) { 172 $previousTabPanel->setActive( false ); 173 } 174 $this->currentTabPanelName = $name; 175 $tabPanel->setActive( true ); 176 $this->stackLayout->setItem( $tabPanel ); 177 } 178 } 179 } 180} 181