summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorctrlaltca@gmail.com <>2011-07-03 15:03:58 +0000
committerctrlaltca@gmail.com <>2011-07-03 15:03:58 +0000
commit907d785046834eacb492a88a0eab9f349921de8d (patch)
tree6dc290e97ba7a5239262c887cc6acc5ce09103a8
parent6e2d354c5a1d49fd65dc050b7d2c3d9b204112eb (diff)
Rewoked TAccordion (fixes #340); added AnimationDuration parameter, added example in quickstart.
-rw-r--r--demos/quickstart/protected/pages/Controls/Samples/TAccordion/Home.page56
-rw-r--r--demos/quickstart/protected/pages/Controls/Samples/TAccordion/Home.php10
-rw-r--r--framework/Web/Javascripts/source/prado/controls/accordion.js275
-rw-r--r--framework/Web/UI/WebControls/TAccordion.php153
-rw-r--r--framework/Web/UI/WebControls/assets/accordion.css8
5 files changed, 301 insertions, 201 deletions
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TAccordion/Home.page b/demos/quickstart/protected/pages/Controls/Samples/TAccordion/Home.page
index 2c862fb7..38ff9180 100644
--- a/demos/quickstart/protected/pages/Controls/Samples/TAccordion/Home.page
+++ b/demos/quickstart/protected/pages/Controls/Samples/TAccordion/Home.page
@@ -1,8 +1,14 @@
<com:TContent ID="body">
<h1>TAccordion Samples</h1>
+<table class="sampletable">
+
+<tr><td class="samplenote">
+A simple TAccordion populated with other controls:
+</td><td class="sampleaction">
+
<com:TAccordion>
- <com:TAccordionView ID="View1" Caption="View 1" Height="200px">
+ <com:TAccordionView ID="View1" Caption="View 1" >
<h2>View 1</h2>
</com:TAccordionView>
@@ -25,4 +31,52 @@
</com:TAccordionView>
</com:TAccordion>
+</td></tr>
+
+<tr><td class="samplenote">
+Two nested TAccordion; the external one has AnimationDuration=0, while the internal one has a fixed ViewHeight=100
+</td><td class="sampleaction">
+
+<com:TAccordion AnimationDuration="0" >
+ <com:TAccordionView Caption="View 1">
+ <p>
+ Contents for view 1: a nested TAccordion control
+ </p>
+ <com:TAccordion ViewHeight="100" >
+ <com:TAccordionView Caption="Nested View A">
+ Contents for nested view A
+ </com:TAccordionView>
+ <com:TAccordionView Caption="Nested View B">
+ Contents for nested view B
+ </com:TAccordionView>
+ <com:TAccordionView Caption="Nested View C">
+ Contents for nested view C
+ </com:TAccordionView>
+ <com:TAccordionView Caption="Nested View D">
+ Contents for nested view D
+ </com:TAccordionView>
+ </com:TAccordion>
+ <p>
+ More content for view 1
+ </p>
+ </com:TAccordionView>
+
+ <com:TAccordionView Caption="View 2">
+ <p>
+ Contents for view 2: a callback button
+ </p>
+ <com:TActiveButton ID="linkExecute" Text="Execute transaction" OnClick="executeTransaction" />
+ </com:TAccordionView>
+
+ <com:TAccordionView Caption="View 3">
+ <p>
+ Contents for view 3: a postback button
+ </p>
+ <com:TButton ID="cmd2" Text="Execute postback" OnClick="executeTransaction" />
+ </com:TAccordionView>
+
+</com:TAccordion>
+<br />
+A label to check postback/callback results: <com:TActiveLabel ID="lab1" />
+
</com:TContent>
diff --git a/demos/quickstart/protected/pages/Controls/Samples/TAccordion/Home.php b/demos/quickstart/protected/pages/Controls/Samples/TAccordion/Home.php
index badbca73..3da69927 100644
--- a/demos/quickstart/protected/pages/Controls/Samples/TAccordion/Home.php
+++ b/demos/quickstart/protected/pages/Controls/Samples/TAccordion/Home.php
@@ -2,6 +2,16 @@
class Home extends TPage
{
+ public function onLoad($param)
+ {
+ parent::onLoad($param);
+ $this->lab1->Text="";
+ }
+
+ public function executeTransaction($sender, $param)
+ {
+ $this->lab1->Text="executeTransaction ok";
+ }
}
?> \ No newline at end of file
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 {