1: <?php
2: /**
3: * QTabs Base File
4: *
5: * The QTabsBase class defined here provides an interface between the generated
6: * QTabsGen class, and QCubed. This file is part of the core and will be overwritten
7: * when you update QCubed. To override, make your changes to the QTabs.class.php file instead.
8: *
9: */
10:
11: /**
12: * Implements JQuery Ui Tabs
13: *
14: * Tabs are similar to an Accordion, but tabs along the top are used to switch between panels. The top
15: * level html items in the panel will become the items that are switched.
16: *
17: * Specify the names of the tabs either in the TabHeadersArray, or assign a Name attribute to the top
18: * level child controls and those names will be used as the tab names.
19: *
20: * @property-write array $Headers Array of names for the tabs. You can also specify by assigning the Name attribute of each pane.
21: * @property-read array $SelectedId Control Id of the selected pane. Use ->Active to get the zero-based index of the selected pane.
22: *
23: * @link http://jqueryui.com/tabs/
24: * @package Controls\Base
25: */
26: class QTabsBase extends QTabsGen
27: {
28: /** @var array Names of tabs. Can also specify with Name attribute of child controls. */
29: protected $objTabHeadersArray = array();
30: /** @var bool Automatically render the children by default, since these are the tabs. */
31: protected $blnAutoRenderChildren = true;
32: /** @var string ControlId of currently selected child item. Use ->Active to get the index of the current selection. */
33: protected $strSelectedId = null;
34:
35: /**
36: * Return the javascript associated with the control.
37: * @return string
38: */
39: public function GetEndScript() {
40: $strJS = parent::GetEndScript();
41: QApplication::ExecuteJsFunction('qcubed.tabs', $this->GetJqControlId(), QJsPriority::High);
42:
43: return $strJS;
44: }
45:
46: /**
47: * Renders child controls as divs so that they become tabs.
48: * @param bool $blnDisplayOutput
49: * @return null|string
50: */
51: protected function RenderChildren($blnDisplayOutput = true) {
52: $strToReturn = $this->GetTabHeaderHtml();
53:
54: foreach ($this->GetChildControls() as $objControl) {
55: if (!$objControl->Rendered) {
56: $renderMethod = $objControl->strPreferredRenderMethod;
57: $strToReturn .= QHtml::RenderTag('div', null, $objControl->$renderMethod($blnDisplayOutput));
58: }
59: }
60:
61: if ($blnDisplayOutput) {
62: print($strToReturn);
63: return null;
64: } else
65: return $strToReturn;
66: }
67:
68: /**
69: * Returns the HTML for the tab header. This includes the names and the control logic to record what the
70: * user clicked.
71: *
72: * @return string
73: */
74: protected function GetTabHeaderHtml() {
75: $strHtml = '';
76: $childControls = $this->GetChildControls();
77: for ($i = 0, $cnt = count($childControls); $i < $cnt; ++$i) {
78: $strControlId = $childControls[$i]->ControlId;
79: if (array_key_exists($key = $strControlId, $this->objTabHeadersArray) ||
80: array_key_exists($key = $i, $this->objTabHeadersArray)) {
81: $objHeader = $this->objTabHeadersArray[$key];
82: if ($objHeader instanceof QControl) {
83: $strText = $objHeader->GetControlHtml();
84: } else {
85: $strText = (string)$objHeader;
86: }
87: }
88: elseif ($strName = $childControls[$i]->Name) {
89: $strText = $strName;
90: }
91: else {
92: $strText = 'Tab '. ($i+1);
93: }
94: $strAnchor = QHtml::RenderTag('a', ['href'=>'#' . $strControlId], $strText, false, true);
95: $strHtml .= QHtml::RenderTag ('li', null, $strAnchor);
96: }
97: return QHtml::RenderTag('ul', null, $strHtml);
98: }
99:
100: /**
101: * Set the tab header for a tab
102: *
103: * Give it a control and a name to set the header
104: *
105: * TBD: impelment ajax fetch of tab content
106: *
107: * @param integer|QControl|string $mixHeaderIndicator either the 0-based index of the header, or the section control or that control's id
108: * @param string|QControl $mixHeader string or control to render as the tab header
109: * @return void
110: */
111: public function SetHeader($mixHeaderIndicator, $mixHeader) {
112: $key = ($mixHeaderIndicator instanceof QControl) ? $mixHeaderIndicator->ControlId : $mixHeaderIndicator;
113: $this->objTabHeadersArray[$key] = $mixHeader;
114: }
115:
116: /**
117: * Generated method overrides the built-in QControl method, causing it to not redraw completely. We restore
118: * its functionality here.
119: */
120: public function Refresh() {
121: parent::Refresh();
122: QControl::Refresh();
123: }
124:
125:
126: /**
127: * Overrides default so that if a tab does not pass validation, it will be visible.
128: * @return bool
129: */
130: public function ValidateControlAndChildren() {
131: // Initially Assume Validation is True
132: $blnToReturn = true;
133:
134: // Check the Control Itself
135: if (!$this->Validate()) {
136: $blnToReturn = false;
137: }
138:
139: // Recursive call on Child Controls
140: $intControlNum = 0;
141:
142: foreach ($this->GetChildControls() as $objChildControl) {
143: // Only Enabled and Visible and Rendered controls should be validated
144: if (($objChildControl->Visible) && ($objChildControl->Enabled) && ($objChildControl->RenderMethod) && ($objChildControl->OnPage)) {
145: if (!$objChildControl->ValidateControlAndChildren()) {
146: $this->ActivateTab($intControlNum);
147: $blnToReturn = false;
148: }
149: }
150: $intControlNum++;
151: }
152:
153: return $blnToReturn;
154: }
155:
156: /**
157: * Given a tab name, index or control ID, returns its index. If invalid, returns false;
158: * @param string|integer $mixTab
159: * @return bool|int
160: */
161: protected function FindTabIndex ($mixTab) {
162: if ($mixTab === null) return false;
163:
164: if ($this->objTabHeadersArray) {
165: $count = count($this->objTabHeadersArray);
166: }
167: else {
168: $childControls = $this->GetChildControls();
169: $count = count ($childControls);
170: }
171:
172: if (is_numeric($mixTab)) {
173: if ($mixTab < $count) {
174: return $mixTab; // assume numbers less than the index are index numbers
175: }
176: }
177:
178: // If there is a headers array, check for a name in there
179: if ($this->objTabHeadersArray) {
180: for ($i = 0, $cnt = $count; $i < $cnt; ++$i) {
181: if ($this->objTabHeadersArray[$i] == $mixTab) {
182: return $i;
183: }
184: }
185: }
186:
187: for ($i = 0, $cnt = $count; $i < $cnt; ++$i) {
188: $objControl = $childControls[$i];
189: if ($mixTab == $objControl->Name) {
190: return $i;
191: }
192: elseif ($mixTab == $objControl->ControlId) {
193: return $i;
194: }
195: }
196: return false;
197: }
198:
199: /**
200: * Activate the tab with the given name, number or controlId.
201: *
202: * @param string|integer $mixTab The tab name, tab index number or control ID
203: */
204: public function ActivateTab ($mixTab) {
205: if (false !== ($i = $this->FindTabIndex($mixTab))) {
206: parent::Option2('active', $i);
207: }
208: }
209:
210: /**
211: * Enable or disable a tab, or all tabs.
212: *
213: * @param null|string|integer $mixTab If null, enables or disables all tabs. Otherwise, the name or index of a tab.
214: * @param bool $blnEnable True to enable tabs. False to disable.
215: */
216: public function EnableTab ($mixTab = null, $blnEnable = true) {
217:
218: if (is_null($mixTab)) {
219: if ($blnEnable) {
220: parent::Enable();
221: } else {
222: parent::Disable();
223: }
224: return;
225: }
226: if (false !== ($i = $this->FindTabIndex($mixTab))) {
227: if ($blnEnable) {
228: parent::Enable1($i);
229: } else {
230: parent::Disable1($i);
231: }
232:
233: }
234: }
235:
236: /**
237: * Overriding to keep info in sync.
238: * @param QControl $objControl
239: */
240: public function AddChildControl(QControl $objControl) {
241: parent::AddChildControl($objControl);
242: if (count ($this->objChildControlArray) == 1) {
243: $this->strSelectedId = $objControl->strControlId; // default to first item added being selected
244: $this->mixActive = 0;
245: }
246: }
247:
248: /**
249: * Returns the state data to restore later.
250: * @return mixed
251: */
252: protected function GetState() {
253: return ['active'=>$this->Active, 'selectedId'=>$this->strSelectedId];
254: }
255:
256: /**
257: * Restore the state of the control.
258: * @param mixed $state
259: */
260: protected function PutState($state) {
261: if (isset($state['active'])) {
262: $this->Active = $state['active'];
263: $this->strSelectedId = $state['selectedId'];
264: }
265: }
266:
267:
268: public function __get($strName) {
269: switch ($strName) {
270: case "SelectedId": return $this->strSelectedId;
271:
272: default:
273: try {
274: return parent::__get($strName);
275: } catch (QCallerException $objExc) {
276: $objExc->IncrementOffset();
277: throw $objExc;
278: }
279: }
280: }
281:
282: public function __set($strName, $mixValue) {
283: switch ($strName) {
284: case 'Headers':
285: try {
286: $this->objTabHeadersArray = QType::Cast($mixValue, QType::ArrayType);
287: $this->blnModified = true;
288: break;
289: } catch (QInvalidCastException $objExc) {
290: $objExc->IncrementOffset();
291: throw $objExc;
292: }
293:
294: case '_active': // private method to synchronize with jQuery UI
295: $this->mixActive = $mixValue[0];
296: $this->strSelectedId = $mixValue[1];
297: break;
298:
299: default:
300: try {
301: parent::__set($strName, $mixValue);
302: break;
303: } catch (QCallerException $objExc) {
304: $objExc->IncrementOffset();
305: throw $objExc;
306: }
307: }
308: }
309: }