Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * TTabPanel class file.
4
 *
5
 * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com>
6
 * @link http://www.pradosoft.com/
7
 * @copyright Copyright &copy; 2005-2008 PradoSoft
8
 * @license http://www.pradosoft.com/license/
9
 * @version $Id: TTabPanel.php 2501 2008-08-18 23:00:14Z knut $
10
 * @package System.Web.UI.WebControls
11
 * @since 3.1.1
12
 */
13
 
14
/**
15
 * Class TTabPanel.
16
 *
17
 * TTabPanel displays a tabbed panel. Users can click on the tab bar to switching among
18
 * different tab views. Each tab view is an independent panel that can contain arbitrary content.
19
 *
20
 * A TTabPanel control consists of one or several {@link TTabView} controls representing the possible
21
 * tab views. At any time, only one tab view is visible (active), which is specified by any of
22
 * the following properties:
23
 * - {@link setActiveViewIndex ActiveViewIndex} - the zero-based integer index of the view in the view collection.
24
 * - {@link setActiveViewID ActiveViewID} - the text ID of the visible view.
25
 * - {@link setActiveView ActiveView} - the visible view instance.
26
 * If both {@link setActiveViewIndex ActiveViewIndex} and {@link setActiveViewID ActiveViewID}
27
 * are set, the latter takes precedence.
28
 *
29
 * TTabPanel uses CSS to specify the appearance of the tab bar and panel. By default,
30
 * an embedded CSS file will be published which contains the default CSS for TTabPanel.
31
 * You may also use your own CSS file by specifying the {@link setCssUrl CssUrl} property.
32
 * The following properties specify the CSS classes used for elements in a TTabPanel:
33
 * - {@link setCssClass CssClass} - the CSS class name for the outer-most div element (defaults to 'tab-panel');
34
 * - {@link setTabCssClass TabCssClass} - the CSS class name for nonactive tab div elements (defaults to 'tab-normal');
35
 * - {@link setActiveTabCssClass ActiveTabCssClass} - the CSS class name for the active tab div element (defaults to 'tab-active');
36
 * - {@link setViewCssClass ViewCssClass} - the CSS class for the div element enclosing view content (defaults to 'tab-view');
37
 *
38
 * To use TTabPanel, write a template like following:
39
 * <code>
40
 * <com:TTabPanel>
41
 *   <com:TTabView Caption="View 1">
42
 *     content for view 1
43
 *   </com:TTabView>
44
 *   <com:TTabView Caption="View 2">
45
 *     content for view 2
46
 *   </com:TTabView>
47
 *   <com:TTabView Caption="View 3">
48
 *     content for view 3
49
 *   </com:TTabView>
50
 * </com:TTabPanel>
51
 * </code>
52
 *
53
 * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com>
54
 * @version $Id: TTabPanel.php 2501 2008-08-18 23:00:14Z knut $
55
 * @since 3.1.1
56
 */
57
class TTabPanel extends TWebControl implements IPostBackDataHandler
58
{
59
	private $_dataChanged=false;
60
 
61
	/**
62
	 * @return string tag name for the control
63
	 */
64
	protected function getTagName()
65
	{
66
		return 'div';
67
	}
68
 
69
	/**
70
	 * Adds object parsed from template to the control.
71
	 * This method adds only {@link TTabView} objects into the {@link getViews Views} collection.
72
	 * All other objects are ignored.
73
	 * @param mixed object parsed from template
74
	 */
75
	public function addParsedObject($object)
76
	{
77
		if($object instanceof TTabView)
78
			$this->getControls()->add($object);
79
	}
80
 
81
	/**
82
     * Returns the index of the active tab view.
83
     * Note, this property may not return the correct index.
84
     * To ensure the correctness, call {@link getActiveView()} first.
85
	 * @return integer the zero-based index of the active tab view. If -1, it means no active tab view. Default is 0 (the first view is active).
86
	 */
87
	public function getActiveViewIndex()
88
	{
89
		return $this->getViewState('ActiveViewIndex',0);
90
	}
91
 
92
	/**
93
	 * @param integer the zero-based index of the current view in the view collection. -1 if no active view.
94
	 * @throws TInvalidDataValueException if the view index is invalid
95
	 */
96
	public function setActiveViewIndex($value)
97
	{
98
		$this->setViewState('ActiveViewIndex',TPropertyValue::ensureInteger($value),0);
99
	}
100
 
101
    /**
102
     * Returns the ID of the active tab view.
103
     * Note, this property may not return the correct ID.
104
     * To ensure the correctness, call {@link getActiveView()} first.
105
     * @return string The ID of the active tab view. Defaults to '', meaning not set.
106
     */
107
    public function getActiveViewID()
108
    {
109
		return $this->getViewState('ActiveViewID','');
110
    }
111
 
112
    /**
113
     * @param string The ID of the active tab view.
114
     */
115
    public function setActiveViewID($value)
116
    {
117
		$this->setViewState('ActiveViewID',$value,'');
118
    }
119
 
120
	/**
121
	 * Returns the currently active view.
122
	 * This method will examin the ActiveViewID, ActiveViewIndex and Views collection to
123
	 * determine which view is currently active. It will update ActiveViewID and ActiveViewIndex accordingly.
124
	 * @return TTabView the currently active view, null if no active view
125
	 * @throws TInvalidDataValueException if the active view ID or index set previously is invalid
126
	 */
127
	public function getActiveView()
128
	{
129
		$activeView=null;
130
		$views=$this->getViews();
131
		if(($id=$this->getActiveViewID())!=='')
132
		{
133
			if(($index=$views->findIndexByID($id))>=0)
134
				$activeView=$views->itemAt($index);
135
			else
136
				throw new TInvalidDataValueException('tabpanel_activeviewid_invalid',$id);
137
		}
138
		else if(($index=$this->getActiveViewIndex())>=0)
139
		{
140
			if($index<$views->getCount())
141
				$activeView=$views->itemAt($index);
142
			else
143
				throw new TInvalidDataValueException('tabpanel_activeviewindex_invalid',$index);
144
		}
145
		else
146
		{
147
			foreach($views as $index=>$view)
148
			{
149
				if($view->getActive())
150
				{
151
					$activeView=$view;
152
					break;
153
				}
154
			}
155
		}
156
		if($activeView!==null)
157
			$this->activateView($activeView);
158
		return $activeView;
159
	}
160
 
161
	/**
162
	 * @param TTabView the view to be activated
163
	 * @throws TInvalidOperationException if the view is not in the view collection
164
	 */
165
	public function setActiveView($view)
166
	{
167
		if($this->getViews()->indexOf($view)>=0)
168
			$this->activateView($view);
169
		else
170
			throw new TInvalidOperationException('tabpanel_view_inexistent');
171
	}
172
 
173
    /**
174
     * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to ''.
175
     */
176
    public function getCssUrl()
177
    {
178
        return $this->getViewState('CssUrl','default');
179
    }
180
 
181
    /**
182
     * @param string URL for the CSS file including all relevant CSS class definitions.
183
     */
184
    public function setCssUrl($value)
185
    {
186
        $this->setViewState('CssUrl',TPropertyValue::ensureString($value),'');
187
    }
188
 
189
    /**
190
     * @return string CSS class for the whole tab control div. Defaults to 'tab-panel'.
191
     */
192
    public function getCssClass()
193
    {
194
    	$cssClass=parent::getCssClass();
195
    	return $cssClass===''?'tab-panel':$cssClass;
196
    }
197
 
198
    /**
199
     * @return string CSS class for the currently displayed view div. Defaults to 'tab-view'.
200
     */
201
    public function getViewCssClass()
202
    {
203
        return $this->getViewStyle()->getCssClass();
204
    }
205
 
206
    /**
207
     * @param string CSS class for the currently displayed view div.
208
     */
209
    public function setViewCssClass($value)
210
    {
211
        $this->getViewStyle()->setCssClass($value);
212
    }
213
 
214
	/**
215
	 * @return TStyle the style for all the view div
216
	 */
217
	public function getViewStyle()
218
	{
219
		if(($style=$this->getViewState('ViewStyle',null))===null)
220
		{
221
			$style=new TStyle;
222
			$style->setCssClass('tab-view');
223
			$this->setViewState('ViewStyle',$style,null);
224
		}
225
		return $style;
226
	}
227
 
228
    /**
229
     * @return string CSS class for non-active tabs. Defaults to 'tab-normal'.
230
     */
231
    public function getTabCssClass()
232
    {
233
        return $this->getTabStyle()->getCssClass();
234
    }
235
 
236
    /**
237
     * @param string CSS class for non-active tabs.
238
     */
239
    public function setTabCssClass($value)
240
    {
241
        $this->getTabStyle()->setCssClass($value);
242
    }
243
 
244
	/**
245
	 * @return TStyle the style for all the inactive tab div
246
	 */
247
	public function getTabStyle()
248
	{
249
		if(($style=$this->getViewState('TabStyle',null))===null)
250
		{
251
			$style=new TStyle;
252
			$style->setCssClass('tab-normal');
253
			$this->setViewState('TabStyle',$style,null);
254
		}
255
		return $style;
256
	}
257
 
258
    /**
259
     * @return string CSS class for the active tab. Defaults to 'tab-active'.
260
     */
261
    public function getActiveTabCssClass()
262
    {
263
        return $this->getActiveTabStyle()->getCssClass();
264
    }
265
 
266
    /**
267
     * @param string CSS class for the active tab.
268
     */
269
    public function setActiveTabCssClass($value)
270
    {
271
        $this->getActiveTabStyle()->setCssClass($value);
272
    }
273
 
274
	/**
275
	 * @return TStyle the style for the active tab div
276
	 */
277
	public function getActiveTabStyle()
278
	{
279
		if(($style=$this->getViewState('ActiveTabStyle',null))===null)
280
		{
281
			$style=new TStyle;
282
			$style->setCssClass('tab-active');
283
			$this->setViewState('ActiveTabStyle',$style,null);
284
		}
285
		return $style;
286
	}
287
 
288
	/**
289
	 * Activates the specified view.
290
	 * If there is any other view currently active, it will be deactivated.
291
	 * @param TTabView the view to be activated. If null, all views will be deactivated.
292
	 */
293
	protected function activateView($view)
294
	{
295
		$this->setActiveViewIndex(-1);
296
		$this->setActiveViewID('');
297
		foreach($this->getViews() as $index=>$v)
298
		{
299
			if($view===$v)
300
			{
301
				$this->setActiveViewIndex($index);
302
				$this->setActiveViewID($view->getID(false));
303
				$view->setActive(true);
304
			}
305
			else
306
				$v->setActive(false);
307
		}
308
	}
309
 
310
	/**
311
	 * Loads user input data.
312
	 * This method is primarly used by framework developers.
313
	 * @param string the key that can be used to retrieve data from the input data collection
314
	 * @param array the input data collection
315
	 * @return boolean whether the data of the control has been changed
316
	 */
317
	public function loadPostData($key,$values)
318
	{
319
		if(($index=$values[$this->getClientID().'_1'])!==null)
320
		{
321
			$index=(int)$index;
322
			$currentIndex=$this->getActiveViewIndex();
323
			if($currentIndex!==$index)
324
			{
325
				$this->setActiveViewID(''); // clear up view ID
326
				$this->setActiveViewIndex($index);
327
				return $this->_dataChanged=true;
328
			}
329
		}
330
		return false;
331
	}
332
 
333
	/**
334
	 * Raises postdata changed event.
335
	 * This method is required by {@link IPostBackDataHandler} interface.
336
	 * It is invoked by the framework when {@link getActiveViewIndex ActiveViewIndex} property
337
	 * is changed on postback.
338
	 * This method is primarly used by framework developers.
339
	 */
340
	public function raisePostDataChangedEvent()
341
	{
342
		// do nothing
343
	}
344
 
345
	/**
346
	 * Returns a value indicating whether postback has caused the control data change.
347
	 * This method is required by the IPostBackDataHandler interface.
348
	 * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
349
	 */
350
	public function getDataChanged()
351
	{
352
		return $this->_dataChanged;
353
	}
354
 
355
	/**
356
	 * Adds attributes to renderer.
357
	 * @param THtmlWriter the renderer
358
	 */
359
	protected function addAttributesToRender($writer)
360
	{
361
		$writer->addAttribute('id',$this->getClientID());
362
		$this->setCssClass($this->getCssClass());
363
		parent::addAttributesToRender($writer);
364
	}
365
 
366
	/**
367
	 * Registers CSS and JS.
368
	 * This method is invoked right before the control rendering, if the control is visible.
369
	 * @param mixed event parameter
370
	 */
371
	public function onPreRender($param)
372
	{
373
		parent::onPreRender($param);
374
		$this->getActiveView();  // determine the active view
375
		$this->registerStyleSheet();
376
		$this->registerClientScript();
377
	}
378
 
379
	/**
380
	 * Registers the CSS relevant to the TTabControl.
381
	 * It will register the CSS file specified by {@link getCssUrl CssUrl}.
382
	 * If that is not set, it will use the default CSS.
383
	 */
384
	protected function registerStyleSheet()
385
	{
386
		$url = $this->getCssUrl();
387
 
388
		if($url === '') {
389
			return;
390
		}
391
 
392
		if($url === 'default') {
393
			$url = $this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'tabpanel.css');
394
		}
395
 
396
		if($url !== '') {
397
			$this->getPage()->getClientScript()->registerStyleSheetFile($url, $url);
398
		}
399
	}
400
 
401
	/**
402
	 * Registers the relevant JavaScript.
403
	 */
404
	protected function registerClientScript()
405
	{
406
		$id=$this->getClientID();
407
		$options=TJavaScript::encode($this->getClientOptions());
408
		$className=$this->getClientClassName();
409
		$page=$this->getPage();
410
		$cs=$page->getClientScript();
411
		$cs->registerPradoScript('tabpanel');
412
		$code="new $className($options);";
413
		$cs->registerEndScript("prado:$id", $code);
414
		$cs->registerHiddenField($id.'_1',$this->getActiveViewIndex());
415
		$page->registerRequiresPostData($this);
416
	}
417
 
418
	/**
419
	 * Gets the name of the javascript class responsible for performing postback for this control.
420
	 * This method overrides the parent implementation.
421
	 * @return string the javascript class name
422
	 */
423
	protected function getClientClassName()
424
	{
425
		return 'Prado.WebUI.TTabPanel';
426
	}
427
 
428
	/**
429
	 * @return array the options for JavaScript
430
	 */
431
	protected function getClientOptions()
432
	{
433
		$options['ID']=$this->getClientID();
434
		$options['ActiveCssClass']=$this->getActiveTabCssClass();
435
		$options['NormalCssClass']=$this->getTabCssClass();
436
		$viewIDs=array();
437
		foreach($this->getViews() as $view)
438
		{
439
			if($view->getVisible())
440
				$viewIDs[]=$view->getClientID();
441
		}
442
		$options['Views']='[\''.implode('\',\'',$viewIDs).'\']';
443
 
444
		return $options;
445
	}
446
 
447
	/**
448
	 * Creates a control collection object that is to be used to hold child controls
449
	 * @return TTabViewCollection control collection
450
	 */
451
	protected function createControlCollection()
452
	{
453
		return new TTabViewCollection($this);
454
	}
455
 
456
	/**
457
	 * @return TTabViewCollection list of {@link TTabView} controls
458
	 */
459
	public function getViews()
460
	{
461
		return $this->getControls();
462
	}
463
 
464
	/**
465
	 * Renders body contents of the tab control.
466
	 * @param THtmlWriter the writer used for the rendering purpose.
467
	 */
468
	public function renderContents($writer)
469
	{
470
		$views=$this->getViews();
471
		if($views->getCount()>0)
472
		{
473
			$writer->writeLine();
474
			// render tab bar
475
			foreach($views as $view)
476
			{
477
				$view->renderTab($writer);
478
				$writer->writeLine();
479
			}
480
			// render tab views
481
			foreach($views as $view)
482
			{
483
				$view->renderControl($writer);
484
				$writer->writeLine();
485
			}
486
		}
487
	}
488
}
489
 
490
/**
491
 * TTabView class.
492
 *
493
 * TTabView represents a view in a {@link TTabPanel} control.
494
 *
495
 * The content in a TTabView can be specified by the {@link setText Text} property
496
 * or its child controls. In template syntax, the latter means enclosing the content
497
 * within the TTabView component element. If both are set, {@link getText Text} takes precedence.
498
 *
499
 * Each TTabView is associated with a tab in the tab bar of the TTabPanel control.
500
 * The tab caption is specified by {@link setCaption Caption}. If {@link setNavigateUrl NavigateUrl}
501
 * is set, the tab will contain a hyperlink pointing to the specified URL. In this case,
502
 * clicking on the tab will redirect the browser to the specified URL.
503
 *
504
 * TTabView may be toggled between visible (active) and invisible (inactive) by
505
 * setting the {@link setActive Active} property.
506
 *
507
 * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com>
508
 * @version $Id: TTabPanel.php 2501 2008-08-18 23:00:14Z knut $
509
 * @since 3.1.1
510
 */
511
class TTabView extends TWebControl
512
{
513
	private $_active=false;
514
 
515
	/**
516
	 * @return the tag name for the view element
517
	 */
518
	protected function getTagName()
519
	{
520
		return 'div';
521
	}
522
 
523
	/**
524
	 * Adds attributes to renderer.
525
	 * @param THtmlWriter the renderer
526
	 */
527
	protected function addAttributesToRender($writer)
528
	{
529
		if(!$this->getActive() && $this->getPage()->getClientSupportsJavaScript())
530
			$this->getStyle()->setStyleField('display','none');
531
 
532
		$this->getStyle()->mergeWith($this->getParent()->getViewStyle());
533
 
534
		parent::addAttributesToRender($writer);
535
 
536
		$writer->addAttribute('id',$this->getClientID());
537
	}
538
 
539
	/**
540
	 * @return string the caption displayed on this tab. Defaults to ''.
541
	 */
542
	public function getCaption()
543
	{
544
		return $this->getViewState('Caption','');
545
	}
546
 
547
	/**
548
	 * @param string the caption displayed on this tab
549
	 */
550
	public function setCaption($value)
551
	{
552
		$this->setViewState('Caption',TPropertyValue::ensureString($value),'');
553
	}
554
 
555
	/**
556
	 * @return string the URL of the target page. Defaults to ''.
557
	 */
558
	public function getNavigateUrl()
559
	{
560
		return $this->getViewState('NavigateUrl','');
561
	}
562
 
563
	/**
564
	 * Sets the URL of the target page.
565
	 * If not empty, clicking on this tab will redirect the browser to the specified URL.
566
	 * @param string the URL of the target page.
567
	 */
568
	public function setNavigateUrl($value)
569
	{
570
		$this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),'');
571
	}
572
 
573
	/**
574
	 * @return string the text content displayed on this view. Defaults to ''.
575
	 */
576
	public function getText()
577
	{
578
		return $this->getViewState('Text','');
579
	}
580
 
581
	/**
582
	 * Sets the text content to be displayed on this view.
583
	 * If this is not empty, the child content of the view will be ignored.
584
	 * @param string the text content displayed on this view
585
	 */
586
	public function setText($value)
587
	{
588
		$this->setViewState('Text',TPropertyValue::ensureString($value),'');
589
	}
590
 
591
	/**
592
	 * @return boolean whether this tab view is active. Defaults to false.
593
	 */
594
	public function getActive()
595
	{
596
		return $this->_active;
597
	}
598
 
599
	/**
600
	 * @param boolean whether this tab view is active.
601
	 */
602
	public function setActive($value)
603
	{
604
		$this->_active=TPropertyValue::ensureBoolean($value);
605
	}
606
 
607
	/**
608
	 * Renders body contents of the tab view.
609
	 * @param THtmlWriter the writer used for the rendering purpose.
610
	 */
611
	public function renderContents($writer)
612
	{
613
		if(($text=$this->getText())!=='')
614
			$writer->write($text);
615
		else if($this->getHasControls())
616
			parent::renderContents($writer);
617
	}
618
 
619
	/**
620
	 * Renders the tab associated with the tab view.
621
	 * @param THtmlWriter the writer for rendering purpose.
622
	 */
623
	public function renderTab($writer)
624
	{
625
		if($this->getVisible(false) && $this->getPage()->getClientSupportsJavaScript())
626
		{
627
			$writer->addAttribute('id',$this->getClientID().'_0');
628
 
629
			$style=$this->getActive()?$this->getParent()->getActiveTabStyle():$this->getParent()->getTabStyle();
630
			$style->addAttributesToRender($writer);
631
 
632
			$writer->renderBeginTag($this->getTagName());
633
 
634
			$this->renderTabContent($writer);
635
 
636
			$writer->renderEndTag();
637
		}
638
	}
639
 
640
	/**
641
	 * Renders the content in the tab.
642
	 * By default, a hyperlink is displayed.
643
	 * @param THtmlWriter the HTML writer
644
	 */
645
	protected function renderTabContent($writer)
646
	{
647
		if(($url=$this->getNavigateUrl())==='')
648
			$url='javascript://';
649
		if(($caption=$this->getCaption())==='')
650
			$caption='&nbsp;';
651
		$writer->write("<a href=\"{$url}\">{$caption}</a>");
652
	}
653
}
654
 
655
/**
656
 * TTabViewCollection class.
657
 *
658
 * TTabViewCollection is used to maintain a list of views belong to a {@link TTabPanel}.
659
 *
660
 * @author Tomasz Wolny <tomasz.wolny@polecam.to.pl> and Qiang Xue <qiang.xue@gmail.com>
661
 * @version $Id: TTabPanel.php 2501 2008-08-18 23:00:14Z knut $
662
 * @since 3.1.1
663
 */
664
class TTabViewCollection extends TControlCollection
665
{
666
	/**
667
	 * Inserts an item at the specified position.
668
	 * This overrides the parent implementation by performing sanity check on the type of new item.
669
	 * @param integer the speicified position.
670
	 * @param mixed new item
671
	 * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TTabView} object.
672
	 */
673
	public function insertAt($index,$item)
674
	{
675
		if($item instanceof TTabView)
676
			parent::insertAt($index,$item);
677
		else
678
			throw new TInvalidDataTypeException('tabviewcollection_tabview_required');
679
	}
680
 
681
	/**
682
	 * Finds the index of the tab view whose ID is the same as the one being looked for.
683
	 * @param string the explicit ID of the tab view to be looked for
684
	 * @return integer the index of the tab view found, -1 if not found.
685
	 */
686
	public function findIndexByID($id)
687
	{
688
		foreach($this as $index=>$view)
689
		{
690
			if($view->getID(false)===$id)
691
				return $index;
692
		}
693
		return -1;
694
	}
695
}
696
 
697
?>