1: <?php
2: /**
3: * CTabView class file.
4: *
5: * @author Qiang Xue <qiang.xue@gmail.com>
6: * @link http://www.yiiframework.com/
7: * @copyright 2008-2013 Yii Software LLC
8: * @license http://www.yiiframework.com/license/
9: */
10:
11: /**
12: * CTabView displays contents in multiple tabs.
13: *
14: * At any time, only one tab is visible. Users can click on the tab header
15: * to switch to see another tab of content.
16: *
17: * JavaScript is used to control the tab switching. If JavaScript is disabled,
18: * CTabView still manages to display the content in a semantically appropriate way.
19: *
20: * To specify contents and their tab structure, configure the {@link tabs} property.
21: * The {@link tabs} property takes an array with tab ID being mapped tab definition.
22: * Each tab definition is an array of the following structure:
23: * <ul>
24: * <li>title: the tab title.</li>
25: * <li>content: the content to be displayed in the tab.</li>
26: * <li>view: the name of the view to be displayed in this tab.
27: * The view will be rendered using the current controller's
28: * {@link CController::renderPartial} method.
29: * When both 'content' and 'view' are specified, 'content' will take precedence.
30: * </li>
31: * <li>url: a URL that the user browser will be redirected to when clicking on this tab.</li>
32: * <li>data: array (name=>value), this will be passed to the view when 'view' is specified.</li>
33: * </ul>
34: *
35: * For example, the {@link tabs} property can be configured as follows,
36: * <pre>
37: * $this->widget('CTabView', array(
38: * 'tabs'=>array(
39: * 'tab1'=>array(
40: * 'title'=>'tab 1 title',
41: * 'view'=>'view1',
42: * 'data'=>array('model'=>$model),
43: * ),
44: * 'tab2'=>array(
45: * 'title'=>'tab 2 title',
46: * 'url'=>'http://www.yiiframework.com/',
47: * ),
48: * ),
49: * ));
50: * </pre>
51: *
52: * By default, the first tab will be activated. To activate a different tab
53: * when the page is initially loaded, set {@link activeTab} to be the ID of the desired tab.
54: *
55: * @author Qiang Xue <qiang.xue@gmail.com>
56: * @package system.web.widgets
57: * @since 1.0
58: */
59: class CTabView extends CWidget
60: {
61: /**
62: * Default CSS class for the tab container
63: */
64: const CSS_CLASS='yiiTab';
65:
66: /**
67: * @var mixed the CSS file used for the widget. Defaults to null, meaning
68: * using the default CSS file included together with the widget.
69: * If false, no CSS file will be used. Otherwise, the specified CSS file
70: * will be included when using this widget.
71: */
72: public $cssFile;
73: /**
74: * @var string the ID of the tab that should be activated when the page is initially loaded.
75: * If not set, the first tab will be activated.
76: */
77: public $activeTab;
78: /**
79: * @var array the data that will be passed to the partial view rendered by each tab.
80: */
81: public $viewData;
82: /**
83: * @var array additional HTML options to be rendered in the container tag.
84: */
85: public $htmlOptions;
86: /**
87: * @var array tab definitions. The array keys are the IDs,
88: * and the array values are the corresponding tab contents.
89: * Each array value must be an array with the following elements:
90: * <ul>
91: * <li>title: the tab title. You need to make sure this is HTML-encoded.</li>
92: * <li>content: the content to be displayed in the tab.</li>
93: * <li>view: the name of the view to be displayed in this tab.
94: * The view will be rendered using the current controller's
95: * {@link CController::renderPartial} method.
96: * When both 'content' and 'view' are specified, 'content' will take precedence.
97: * </li>
98: * <li>url: a URL that the user browser will be redirected to when clicking on this tab.</li>
99: * <li>data: array (name=>value), this will be passed to the view when 'view' is specified.
100: * This option is available since version 1.1.1.</li>
101: * <li>visible: whether this tab is visible. Defaults to true.
102: * this option is available since version 1.1.11.</li>
103: * </ul>
104: * <pre>
105: * array(
106: * 'tab1'=>array(
107: * 'title'=>'tab 1 title',
108: * 'view'=>'view1',
109: * ),
110: * 'tab2'=>array(
111: * 'title'=>'tab 2 title',
112: * 'url'=>'http://www.yiiframework.com/',
113: * ),
114: * )
115: * </pre>
116: */
117: public $tabs=array();
118:
119: /**
120: * Runs the widget.
121: */
122: public function run()
123: {
124: foreach($this->tabs as $id=>$tab)
125: if(isset($tab['visible']) && $tab['visible']==false)
126: unset($this->tabs[$id]);
127:
128: if(empty($this->tabs))
129: return;
130:
131: if($this->activeTab===null || !isset($this->tabs[$this->activeTab]))
132: {
133: reset($this->tabs);
134: list($this->activeTab, )=each($this->tabs);
135: }
136:
137: $htmlOptions=$this->htmlOptions;
138: if(isset($this->htmlOptions['id']))
139: $this->id=$this->htmlOptions['id'];
140: else
141: $htmlOptions['id']=$this->id;
142: if(!isset($htmlOptions['class']))
143: $htmlOptions['class']=self::CSS_CLASS;
144:
145: $this->registerClientScript();
146:
147: echo CHtml::openTag('div',$htmlOptions)."\n";
148: $this->renderHeader();
149: $this->renderBody();
150: echo CHtml::closeTag('div');
151: }
152:
153: /**
154: * Registers the needed CSS and JavaScript.
155: */
156: public function registerClientScript()
157: {
158: $cs=Yii::app()->getClientScript();
159: $cs->registerCoreScript('yiitab');
160: $id=$this->getId();
161: $cs->registerScript('Yii.CTabView#'.$id,"jQuery(\"#{$id}\").yiitab();");
162:
163: if($this->cssFile!==false)
164: self::registerCssFile($this->cssFile);
165: }
166:
167: /**
168: * Registers the needed CSS file.
169: * @param string $url the CSS URL. If null, a default CSS URL will be used.
170: */
171: public static function registerCssFile($url=null)
172: {
173: $cs=Yii::app()->getClientScript();
174: if($url===null)
175: $url=$cs->getCoreScriptUrl().'/yiitab/jquery.yiitab.css';
176: $cs->registerCssFile($url,'screen');
177: }
178:
179: /**
180: * Renders the header part.
181: */
182: protected function renderHeader()
183: {
184: echo "<ul class=\"tabs\">\n";
185: foreach($this->tabs as $id=>$tab)
186: {
187: $title=isset($tab['title'])?$tab['title']:'undefined';
188: $active=$id===$this->activeTab?' class="active"' : '';
189: $url=isset($tab['url'])?$tab['url']:"#{$id}";
190: echo "<li><a href=\"{$url}\"{$active}>{$title}</a></li>\n";
191: }
192: echo "</ul>\n";
193: }
194:
195: /**
196: * Renders the body part.
197: */
198: protected function renderBody()
199: {
200: foreach($this->tabs as $id=>$tab)
201: {
202: $inactive=$id!==$this->activeTab?' style="display:none"' : '';
203: echo "<div class=\"view\" id=\"{$id}\"{$inactive}>\n";
204: if(isset($tab['content']))
205: echo $tab['content'];
206: elseif(isset($tab['view']))
207: {
208: if(isset($tab['data']))
209: {
210: if(is_array($this->viewData))
211: $data=array_merge($this->viewData, $tab['data']);
212: else
213: $data=$tab['data'];
214: }
215: else
216: $data=$this->viewData;
217: $this->getController()->renderPartial($tab['view'], $data);
218: }
219: echo "</div><!-- {$id} -->\n";
220: }
221: }
222: }
223: