diff options
author | ctrlaltca@gmail.com <> | 2011-07-03 15:03:58 +0000 |
---|---|---|
committer | ctrlaltca@gmail.com <> | 2011-07-03 15:03:58 +0000 |
commit | 907d785046834eacb492a88a0eab9f349921de8d (patch) | |
tree | 6dc290e97ba7a5239262c887cc6acc5ce09103a8 /framework/Web | |
parent | 6e2d354c5a1d49fd65dc050b7d2c3d9b204112eb (diff) |
Rewoked TAccordion (fixes #340); added AnimationDuration parameter, added example in quickstart.
Diffstat (limited to 'framework/Web')
-rw-r--r-- | framework/Web/Javascripts/source/prado/controls/accordion.js | 275 | ||||
-rw-r--r-- | framework/Web/UI/WebControls/TAccordion.php | 153 | ||||
-rw-r--r-- | framework/Web/UI/WebControls/assets/accordion.css | 8 |
3 files changed, 236 insertions, 200 deletions
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.contents.length; i++) { - if(this.contents[i].getHeight() > 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.contents.length; i++){ - if(this.contents[i] != this.current) { - this.contents[i].hide(); - this.contents[i].setStyle({height: 0}); - } - } - }, - - - enableOverflows: function(enable) { - if (enable) val = ''; else val = 'hidden'; - this.current.style.overflow = val; - this.toExpand.style.overflow = val; - }, - - 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.toExpand, 100, options)); - - options = { - sync: true, - scaleContent: false, - transition: Effect.Transitions.sinoidal, - scaleX: false, - scaleY: true - }; - - effects.push(new Effect.Scale(this.current, 0, options)); - - var myDuration = 0.75; - - new Effect.Parallel(effects, { - duration: myDuration, - fps: 35, - queue: { - position: 'end', - scope: 'accordion' - }, - beforeStart: function() { - this.isAnimating = true; - this.enableOverflows(false); - this.current.previous('div.'+this.options.toggleClass).removeClassName(this.options.toggleActive); - this.toExpand.previous('div.'+this.options.toggleClass).addClassName(this.options.toggleActive); - }.bind(this), - afterFinish: function() { - this.current.hide(); - this.toExpand.setStyle({ height: this.maxHeight+"px" }); - this.current = this.toExpand; - this.isAnimating = false; - this.enableOverflows(true); - }.bind(this) - }); - } - + 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.hiddenField = $(options.ID+'_1'); + + if (this.options.maxHeight) + { + this.maxHeight = this.options.maxHeight; + } else { + this.maxHeight = 0; + this.checkMaxHeight(); + } + + this.currentView = null; + this.oldView = null; + + var i = 0; + for(var view in this.options.Views) + { + var header = $(view+'_0'); + if(header) + { + Event.stopObserving(header, "click"); + Event.observe(header, "click", this.elementClicked.bindEvent(this,view)); + if(this.hiddenField.value == i) + { + this.currentView = view; + if($(this.currentView).getHeight() != this.maxHeight) + $(this.currentView).setStyle({height: this.maxHeight+"px"}); + } + } + i++; + } + }, + + checkMaxHeight: function() + { + for(var viewID in this.options.Views) + { + var view = $(viewID); + if(view.getHeight() > 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:
* <code>
* <com:TAccordion>
@@ -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,47 +181,63 @@ 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
*/
public function getViewStyle()
@@ -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 {
|