From 907d785046834eacb492a88a0eab9f349921de8d Mon Sep 17 00:00:00 2001 From: "ctrlaltca@gmail.com" <> Date: Sun, 3 Jul 2011 15:03:58 +0000 Subject: Rewoked TAccordion (fixes #340); added AnimationDuration parameter, added example in quickstart. --- .../Javascripts/source/prado/controls/accordion.js | 275 +++++++++++---------- framework/Web/UI/WebControls/TAccordion.php | 153 +++++++----- framework/Web/UI/WebControls/assets/accordion.css | 8 +- 3 files changed, 236 insertions(+), 200 deletions(-) (limited to 'framework/Web') diff --git a/framework/Web/Javascripts/source/prado/controls/accordion.js b/framework/Web/Javascripts/source/prado/controls/accordion.js index e7d84694..f25b5e1a 100644 --- a/framework/Web/Javascripts/source/prado/controls/accordion.js +++ b/framework/Web/Javascripts/source/prado/controls/accordion.js @@ -7,143 +7,146 @@ * http://creativecommons.org/licenses/by-sa/3.0/us/ */ -if (typeof Effect == 'undefined') - throw("You must have the script.aculo.us Effect library to use this accordion"); - Prado.WebUI.TAccordion = Class.create(); Prado.WebUI.TAccordion.prototype = { - initialize : function(options) - { - this.element = $(options.ID); - this.onInit(options); - Prado.Registry.set(options.ID, this); - }, - - onInit : function(options) - { - this.accordion = $(options.ID); - this.options = options; - this.contents = this.accordion.select('div.'+this.options.contentClass); - this.isAnimating = false; - this.current = this.options.defaultExpandedCount ? this.contents[this.options.defaultExpandedCount-1] : this.contents[0]; - this.toExpand = null; - - if (options.maxHeight) - this.maxHeight = options.maxHeight; - else - { - this.maxHeight = 0; - this.checkMaxHeight(); - } - - this.initialHide(); - this.attachInitialMaxHeight(); - - var clickHandler = this.clickHandler.bindAsEventListener(this); - this.accordion.observe('click', clickHandler); - }, - - expand: function(el) { - this.toExpand = el.next('div.'+this.options.contentClass); - if(this.current != this.toExpand){ - this.toExpand.show(); - this.animate(); - } - }, - - checkMaxHeight: function() { - for(var i=0; i this.maxHeight) { - this.maxHeight = this.contents[i].getHeight(); - } - } - }, - - attachInitialMaxHeight: function() { - this.current.previous('div.'+this.options.toggleClass).addClassName(this.options.toggleActive); - if(this.current.getHeight() != this.maxHeight) this.current.setStyle({height: this.maxHeight+"px"}); - }, - - clickHandler: function(e) { - var el = e.element(); - if(el.hasClassName(this.options.toggleClass) && !this.isAnimating) { - this.expand(el); - } - }, - - initialHide: function(){ - for(var i=0; i this.maxHeight) + this.maxHeight = view.getHeight(); + } + }, + + elementClicked : function(event,viewID) + { + var i = 0; + for(var index in this.options.Views) + { + if ($(index)) + { + var header = $(index+'_0'); + if(index == viewID) + { + this.oldView = this.currentView; + this.currentView = index; + + this.hiddenField.value=i; + } + } + i++; + } + if(this.oldView != this.currentView) + { + if(this.options.Duration > 0) + { + this.animate(); + } else { + $(this.currentView).setStyle({ height: this.maxHeight+"px" }); + $(this.currentView).show(); + $(this.oldView).hide(); + + var oldHeader = $(this.oldView+'_0'); + var currentHeader = $(this.currentView+'_0'); + oldHeader.className=this.options.HeaderCssClass; + currentHeader.className=this.options.ActiveHeaderCssClass; + } + } + }, + + animate: function() { + var effects = new Array(); + var options = { + sync: true, + scaleFrom: 0, + scaleContent: false, + transition: Effect.Transitions.sinoidal, + scaleMode: { + originalHeight: this.maxHeight, + originalWidth: this.accordion.getWidth() + }, + scaleX: false, + scaleY: true + }; + + effects.push(new Effect.Scale(this.currentView, 100, options)); + + options = { + sync: true, + scaleContent: false, + transition: Effect.Transitions.sinoidal, + scaleX: false, + scaleY: true + }; + + effects.push(new Effect.Scale(this.oldView, 0, options)); + + var oldHeader = $(this.oldView+'_0'); + var currentHeader = $(this.currentView+'_0'); + + new Effect.Parallel(effects, { + duration: this.options.Duration, + fps: 35, + queue: { + position: 'end', + scope: 'accordion' + }, + beforeStart: function() { + $(this.currentView).setStyle({ height: "0px" }); + $(this.currentView).show(); + + oldHeader.className=this.options.HeaderCssClass; + currentHeader.className=this.options.ActiveHeaderCssClass; + }.bind(this), + afterFinish: function() { + $(this.oldView).hide(); + $(this.currentView).setStyle({ height: this.maxHeight+"px" }); + }.bind(this) + }); + } }; - -/* -document.observe("dom:loaded", function(){ - accordion = new Accordion("test-accordion", 2); -}) -*/ \ No newline at end of file diff --git a/framework/Web/UI/WebControls/TAccordion.php b/framework/Web/UI/WebControls/TAccordion.php index 7ab35e39..29427195 100644 --- a/framework/Web/UI/WebControls/TAccordion.php +++ b/framework/Web/UI/WebControls/TAccordion.php @@ -35,6 +35,14 @@ * - {@link setActiveHeaderCssClass ActiveHeaderCssClass} - the CSS class name for the active accordion div element (defaults to 'accordion-header-active'); * - {@link setViewCssClass ViewCssClass} - the CSS class for the div element enclosing view content (defaults to 'accordion-view'); * + * When the user clicks on a view header, the switch between the old visible view and the clicked one is animated. + * You can use the {@link setAnimationDuration AnimationDuration} property to set the animation length in seconds; + * it defaults to 1 second, and when set to 0 it will produce an immediate switch with no animation. + * + * The TAccordion auto-sizes itself to the largest of all views, so it can encompass all of them without scrolling. + * If you want to specify a fixed height (in pixels), use the {@link setViewHeight ViewHeight} property. + * When a TAccordion is nested inside another, it's adviced to manually specify a {@link setViewHeight ViewHeight} for the internal TAccordion + * * To use TAccordion, write a template like following: * * @@ -82,8 +90,8 @@ class TAccordion extends TWebControl implements IPostBackDataHandler /** * Returns the index of the active accordion view. - * Note, this property may not return the correct index. - * To ensure the correctness, call {@link getActiveView()} first. + * Note, this property may not return the correct index. + * To ensure the correctness, call {@link getActiveView()} first. * @return integer the zero-based index of the active accordion view. If -1, it means no active accordion view. Default is 0 (the first view is active). */ public function getActiveViewIndex() @@ -100,24 +108,24 @@ class TAccordion extends TWebControl implements IPostBackDataHandler $this->setViewState('ActiveViewIndex',TPropertyValue::ensureInteger($value),0); } - /** + /** * Returns the ID of the active accordion view. - * Note, this property may not return the correct ID. - * To ensure the correctness, call {@link getActiveView()} first. + * Note, this property may not return the correct ID. + * To ensure the correctness, call {@link getActiveView()} first. * @return string The ID of the active accordion view. Defaults to '', meaning not set. - */ - public function getActiveViewID() - { + */ + public function getActiveViewID() + { return $this->getViewState('ActiveViewID',''); - } + } - /** + /** * @param string The ID of the active accordion view. - */ - public function setActiveViewID($value) - { + */ + public function setActiveViewID($value) + { $this->setViewState('ActiveViewID',$value,''); - } + } /** * Returns the currently active view. @@ -173,46 +181,62 @@ class TAccordion extends TWebControl implements IPostBackDataHandler } /** - * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to ''. - */ + * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to ''. + */ public function getCssUrl() { return $this->getViewState('CssUrl','default'); } /** - * @param string URL for the CSS file including all relevant CSS class definitions. - */ + * @param string URL for the CSS file including all relevant CSS class definitions. + */ public function setCssUrl($value) { $this->setViewState('CssUrl',TPropertyValue::ensureString($value),''); } /** - * @return string CSS class for the whole accordion control div. - */ + * @return string CSS class for the whole accordion control div. + */ public function getCssClass() { $cssClass=parent::getCssClass(); - return $cssClass===''?'accordion':$cssClass; + return $cssClass===''?'accordion':$cssClass; } /** - * @return string CSS class for the currently displayed view div. Defaults to 'accordion-view'. - */ + * @return string CSS class for the currently displayed view div. Defaults to 'accordion-view'. + */ public function getViewCssClass() { return $this->getViewStyle()->getCssClass(); } /** - * @param string CSS class for the currently displayed view div. - */ + * @param string CSS class for the currently displayed view div. + */ public function setViewCssClass($value) { $this->getViewStyle()->setCssClass($value); } + /** + * @return string CSS class for the currently displayed view div. Defaults to 'accordion-view'. + */ + public function getAnimationDuration() + { + return $this->getViewState('AnimationDuration','1'); + } + + /** + * @param string CSS class for the currently displayed view div. + */ + public function setAnimationDuration($value) + { + $this->setViewState('AnimationDuration',$value); + } + /** * @return TStyle the style for all the view div */ @@ -227,21 +251,21 @@ class TAccordion extends TWebControl implements IPostBackDataHandler return $style; } - /** + /** * @return string CSS class for view headers. Defaults to 'accordion-header'. - */ + */ public function getHeaderCssClass() - { + { return $this->getHeaderStyle()->getCssClass(); - } + } - /** + /** * @param string CSS class for view headers. - */ + */ public function setHeaderCssClass($value) - { + { $this->getHeaderStyle()->setCssClass($value); - } + } /** * @return TStyle the style for all the inactive header div @@ -257,22 +281,21 @@ class TAccordion extends TWebControl implements IPostBackDataHandler return $style; } - /** + /** * @return string Extra CSS class for the active header. Defaults to 'accordion-header-active'. - */ + */ public function getActiveHeaderCssClass() - { + { return $this->getActiveHeaderStyle()->getCssClass(); - } + } - /** + /** * @param string Extra CSS class for the active header. Will be added to the normal header specified by HeaderCssClass. - */ + */ public function setActiveHeaderCssClass($value) - { + { $this->getActiveHeaderStyle()->setCssClass($value); - } - + } /** * @return TStyle the style for the active header div @@ -403,15 +426,15 @@ class TAccordion extends TWebControl implements IPostBackDataHandler protected function registerStyleSheet() { $url = $this->getCssUrl(); - + if($url === '') { return; } - + if($url === 'default') { $url = $this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'accordion.css'); } - + if($url !== '') { $this->getPage()->getClientScript()->registerStyleSheetFile($url, $url); } @@ -423,15 +446,20 @@ class TAccordion extends TWebControl implements IPostBackDataHandler protected function registerClientScript() { $id=$this->getClientID(); - $options = TJavaScript::encode($this->getClientOptions()); + $options=TJavaScript::encode($this->getClientOptions()); $className=$this->getClientClassName(); $page=$this->getPage(); $cs=$page->getClientScript(); $cs->registerPradoScript('accordion'); - $code = "new $className($options);"; + $code="new $className($options);"; $cs->registerEndScript("prado:$id", $code); - $cs->registerHiddenField($id.'_1',$this->getActiveViewIndex()); + // ensure an item is always active and visible + $index = $this->getActiveViewIndex(); + if(!$this->getViews()->itemAt($index)->Visible) + $index=0; + $cs->registerHiddenField($id.'_1', $index); $page->registerRequiresPostData($this); + $page->registerRequiresPostData($id."_1"); } /** @@ -450,21 +478,22 @@ class TAccordion extends TWebControl implements IPostBackDataHandler protected function getClientOptions() { $options['ID']=$this->getClientID(); - $options['toggleActive']=$this->getActiveHeaderCssClass(); - $options['toggleClass']=$this->getHeaderCssClass(); - $options['contentClass']=$this->getViewCssClass(); - $options['defaultExpandedCount']=$this->getActiveViewIndex()+1; + $options['ActiveHeaderCssClass']=$this->getActiveHeaderCssClass(); + $options['HeaderCssClass']=$this->getHeaderCssClass(); + $options['Duration']=$this->getAnimationDuration(); + if (($viewheight = $this->getViewHeight())>0) $options['maxHeight'] = $viewheight; - /* - $viewIDs=array(); + $views=''; foreach($this->getViews() as $view) { - if($view->getVisible()) - $viewIDs[]=$view->getClientID(); + if($views!='') + $views.=', '; + $views.= '"'.$view->getClientID().'":'.($view->getVisible() ? '1': '0' ); } - $options['Views']='[\''.implode('\',\'',$viewIDs).'\']'; - */ + + $options['Views']='{'.$views.='}'; + $viewIDs=array(); return $options; } @@ -525,6 +554,9 @@ class TAccordionView extends TWebControl */ protected function addAttributesToRender($writer) { + if(!$this->getActive() && $this->getPage()->getClientSupportsJavaScript()) + $this->getStyle()->setStyleField('display','none'); + $this->getStyle()->mergeWith($this->getParent()->getViewStyle()); parent::addAttributesToRender($writer); @@ -622,8 +654,7 @@ class TAccordionView extends TWebControl { $writer->addAttribute('id',$this->getClientID().'_0'); -// $style=$this->getActive()?$this->getParent()->getActiveHeaderStyle():$this->getParent()->getHeaderStyle(); - $style=$this->getParent()->getHeaderStyle(); + $style=$this->getActive()?$this->getParent()->getActiveHeaderStyle():$this->getParent()->getHeaderStyle(); $style->addAttributesToRender($writer); @@ -687,4 +718,4 @@ class TAccordionViewCollection extends TControlCollection } } -?> \ No newline at end of file +?> diff --git a/framework/Web/UI/WebControls/assets/accordion.css b/framework/Web/UI/WebControls/assets/accordion.css index 09ac764d..842868e7 100644 --- a/framework/Web/UI/WebControls/assets/accordion.css +++ b/framework/Web/UI/WebControls/assets/accordion.css @@ -7,16 +7,18 @@ div.accordion-header { padding: 3px; z-index: 10; position: relative; cursor: pointer; -} - -div.accordion-header { background-color: #5577aa; color: white; font-weight: bold; border: 1px solid; } div.accordion-header-active { + padding: 3px; + z-index: 10; position: relative; + cursor: pointer; background-color: #334477; + color: red; font-weight: bold; + border: 1px solid red; } div.accordion-view { -- cgit v1.2.3