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