summaryrefslogtreecommitdiff
path: root/framework/zii/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'framework/zii/widgets')
-rw-r--r--framework/zii/widgets/CBaseListView.php284
-rw-r--r--framework/zii/widgets/CBreadcrumbs.php116
-rw-r--r--framework/zii/widgets/CDetailView.php242
-rw-r--r--framework/zii/widgets/CListView.php276
-rw-r--r--framework/zii/widgets/CMenu.php317
-rw-r--r--framework/zii/widgets/CPortlet.php126
-rw-r--r--framework/zii/widgets/assets/detailview/styles.css44
-rw-r--r--framework/zii/widgets/assets/gridview/bg.gifbin0 -> 243 bytes
-rw-r--r--framework/zii/widgets/assets/gridview/delete.pngbin0 -> 715 bytes
-rw-r--r--framework/zii/widgets/assets/gridview/down.gifbin0 -> 55 bytes
-rw-r--r--framework/zii/widgets/assets/gridview/jquery.yiigridview.js413
-rw-r--r--framework/zii/widgets/assets/gridview/loading.gifbin0 -> 1849 bytes
-rw-r--r--framework/zii/widgets/assets/gridview/styles.css120
-rw-r--r--framework/zii/widgets/assets/gridview/up.gifbin0 -> 54 bytes
-rw-r--r--framework/zii/widgets/assets/gridview/update.pngbin0 -> 713 bytes
-rw-r--r--framework/zii/widgets/assets/gridview/view.pngbin0 -> 803 bytes
-rw-r--r--framework/zii/widgets/assets/listview/down.gifbin0 -> 55 bytes
-rw-r--r--framework/zii/widgets/assets/listview/jquery.yiilistview.js114
-rw-r--r--framework/zii/widgets/assets/listview/loading.gifbin0 -> 1849 bytes
-rw-r--r--framework/zii/widgets/assets/listview/styles.css56
-rw-r--r--framework/zii/widgets/assets/listview/up.gifbin0 -> 54 bytes
-rw-r--r--framework/zii/widgets/grid/CButtonColumn.php323
-rw-r--r--framework/zii/widgets/grid/CCheckBoxColumn.php187
-rw-r--r--framework/zii/widgets/grid/CDataColumn.php144
-rw-r--r--framework/zii/widgets/grid/CGridColumn.php193
-rw-r--r--framework/zii/widgets/grid/CGridView.php550
-rw-r--r--framework/zii/widgets/grid/CLinkColumn.php96
-rw-r--r--framework/zii/widgets/jui/CJuiAccordion.php94
-rw-r--r--framework/zii/widgets/jui/CJuiAutoComplete.php100
-rw-r--r--framework/zii/widgets/jui/CJuiButton.php184
-rw-r--r--framework/zii/widgets/jui/CJuiDatePicker.php133
-rw-r--r--framework/zii/widgets/jui/CJuiDialog.php83
-rw-r--r--framework/zii/widgets/jui/CJuiDraggable.php78
-rw-r--r--framework/zii/widgets/jui/CJuiDroppable.php78
-rw-r--r--framework/zii/widgets/jui/CJuiInputWidget.php74
-rw-r--r--framework/zii/widgets/jui/CJuiProgressBar.php74
-rw-r--r--framework/zii/widgets/jui/CJuiResizable.php79
-rw-r--r--framework/zii/widgets/jui/CJuiSelectable.php84
-rw-r--r--framework/zii/widgets/jui/CJuiSlider.php76
-rw-r--r--framework/zii/widgets/jui/CJuiSliderInput.php148
-rw-r--r--framework/zii/widgets/jui/CJuiSortable.php89
-rw-r--r--framework/zii/widgets/jui/CJuiTabs.php135
-rw-r--r--framework/zii/widgets/jui/CJuiWidget.php145
43 files changed, 5255 insertions, 0 deletions
diff --git a/framework/zii/widgets/CBaseListView.php b/framework/zii/widgets/CBaseListView.php
new file mode 100644
index 0000000..8f404c3
--- /dev/null
+++ b/framework/zii/widgets/CBaseListView.php
@@ -0,0 +1,284 @@
+<?php
+/**
+ * CBaseListView class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CBaseListView is the base class for {@link CListView} and {@link CGridView}.
+ *
+ * CBaseListView implements the common features needed by a view wiget for rendering multiple models.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CBaseListView.php 3101 2011-03-22 17:35:19Z qiang.xue $
+ * @package zii.widgets
+ * @since 1.1
+ */
+abstract class CBaseListView extends CWidget
+{
+ /**
+ * @var IDataProvider the data provider for the view.
+ */
+ public $dataProvider;
+ /**
+ * @var string the tag name for the view container. Defaults to 'div'.
+ */
+ public $tagName='div';
+ /**
+ * @var array the HTML options for the view container tag.
+ */
+ public $htmlOptions=array();
+ /**
+ * @var boolean whether to enable sorting. Note that if the {@link IDataProvider::sort} property
+ * of {@link dataProvider} is false, this will be treated as false as well. When sorting is enabled,
+ * sortable columns will have their headers clickable to trigger sorting along that column.
+ * Defaults to true.
+ * @see sortableAttributes
+ */
+ public $enableSorting=true;
+ /**
+ * @var boolean whether to enable pagination. Note that if the {@link IDataProvider::pagination} property
+ * of {@link dataProvider} is false, this will be treated as false as well. When pagination is enabled,
+ * a pager will be displayed in the view so that it can trigger pagination of the data display.
+ * Defaults to true.
+ */
+ public $enablePagination=true;
+ /**
+ * @var array the configuration for the pager. Defaults to <code>array('class'=>'CLinkPager')</code>.
+ * @see enablePagination
+ */
+ public $pager=array('class'=>'CLinkPager');
+ /**
+ * @var string the template to be used to control the layout of various sections in the view.
+ * These tokens are recognized: {summary}, {items} and {pager}. They will be replaced with the
+ * summary text, the items, and the pager.
+ */
+ public $template="{summary}\n{items}\n{pager}";
+ /**
+ * @var string the summary text template for the view. These tokens are recognized and will be replaced
+ * with the corresponding values:
+ * <ul>
+ * <li>{start}: the starting row number (1-based) currently being displayed</li>
+ * <li>{end}: the ending row number (1-based) currently being displayed</li>
+ * <li>{count}: the total number of rows</li>
+ * <li>{page}: the page number (1-based) current being displayed, available since version 1.1.3</li>
+ * <li>{pages}: the total number of pages, available since version 1.1.3</li>
+ * </ul>
+ */
+ public $summaryText;
+ /**
+ * @var string the message to be displayed when {@link dataProvider} does not have any data.
+ */
+ public $emptyText;
+ /**
+ * @var string the CSS class name for the container of all data item display. Defaults to 'items'.
+ */
+ public $itemsCssClass='items';
+ /**
+ * @var string the CSS class name for the summary text container. Defaults to 'summary'.
+ */
+ public $summaryCssClass='summary';
+ /**
+ * @var string the CSS class name for the pager container. Defaults to 'pager'.
+ */
+ public $pagerCssClass='pager';
+ /**
+ * @var string the CSS class name that will be assigned to the widget container element
+ * when the widget is updating its content via AJAX. Defaults to 'loading'.
+ * @since 1.1.1
+ */
+ public $loadingCssClass='loading';
+
+ /**
+ * Initializes the view.
+ * This method will initialize required property values and instantiate {@link columns} objects.
+ */
+ public function init()
+ {
+ if($this->dataProvider===null)
+ throw new CException(Yii::t('zii','The "dataProvider" property cannot be empty.'));
+
+ $this->dataProvider->getData();
+
+ $this->htmlOptions['id']=$this->getId();
+
+ if($this->enableSorting && $this->dataProvider->getSort()===false)
+ $this->enableSorting=false;
+ if($this->enablePagination && $this->dataProvider->getPagination()===false)
+ $this->enablePagination=false;
+ }
+
+ /**
+ * Renders the view.
+ * This is the main entry of the whole view rendering.
+ * Child classes should mainly override {@link renderContent} method.
+ */
+ public function run()
+ {
+ $this->registerClientScript();
+
+ echo CHtml::openTag($this->tagName,$this->htmlOptions)."\n";
+
+ $this->renderContent();
+ $this->renderKeys();
+
+ echo CHtml::closeTag($this->tagName);
+ }
+
+ /**
+ * Renders the main content of the view.
+ * The content is divided into sections, such as summary, items, pager.
+ * Each section is rendered by a method named as "renderXyz", where "Xyz" is the section name.
+ * The rendering results will replace the corresponding placeholders in {@link template}.
+ */
+ public function renderContent()
+ {
+ ob_start();
+ echo preg_replace_callback("/{(\w+)}/",array($this,'renderSection'),$this->template);
+ ob_end_flush();
+ }
+
+ /**
+ * Renders a section.
+ * This method is invoked by {@link renderContent} for every placeholder found in {@link template}.
+ * It should return the rendering result that would replace the placeholder.
+ * @param array $matches the matches, where $matches[0] represents the whole placeholder,
+ * while $matches[1] contains the name of the matched placeholder.
+ * @return string the rendering result of the section
+ */
+ protected function renderSection($matches)
+ {
+ $method='render'.$matches[1];
+ if(method_exists($this,$method))
+ {
+ $this->$method();
+ $html=ob_get_contents();
+ ob_clean();
+ return $html;
+ }
+ else
+ return $matches[0];
+ }
+
+ /**
+ * Renders the empty message when there is no data.
+ */
+ public function renderEmptyText()
+ {
+ $emptyText=$this->emptyText===null ? Yii::t('zii','No results found.') : $this->emptyText;
+ echo CHtml::tag('span', array('class'=>'empty'), $emptyText);
+ }
+
+ /**
+ * Renders the key values of the data in a hidden tag.
+ */
+ public function renderKeys()
+ {
+ echo CHtml::openTag('div',array(
+ 'class'=>'keys',
+ 'style'=>'display:none',
+ 'title'=>Yii::app()->getRequest()->getUrl(),
+ ));
+ foreach($this->dataProvider->getKeys() as $key)
+ echo "<span>".CHtml::encode($key)."</span>";
+ echo "</div>\n";
+ }
+
+ /**
+ * Renders the summary text.
+ */
+ public function renderSummary()
+ {
+ if(($count=$this->dataProvider->getItemCount())<=0)
+ return;
+
+ echo '<div class="'.$this->summaryCssClass.'">';
+ if($this->enablePagination)
+ {
+ if(($summaryText=$this->summaryText)===null)
+ $summaryText=Yii::t('zii','Displaying {start}-{end} of {count} result(s).');
+ $pagination=$this->dataProvider->getPagination();
+ $total=$this->dataProvider->getTotalItemCount();
+ $start=$pagination->currentPage*$pagination->pageSize+1;
+ $end=$start+$count-1;
+ if($end>$total)
+ {
+ $end=$total;
+ $start=$end-$count+1;
+ }
+ echo strtr($summaryText,array(
+ '{start}'=>$start,
+ '{end}'=>$end,
+ '{count}'=>$total,
+ '{page}'=>$pagination->currentPage+1,
+ '{pages}'=>$pagination->pageCount,
+ ));
+ }
+ else
+ {
+ if(($summaryText=$this->summaryText)===null)
+ $summaryText=Yii::t('zii','Total {count} result(s).');
+ echo strtr($summaryText,array(
+ '{count}'=>$count,
+ '{start}'=>1,
+ '{end}'=>$count,
+ '{page}'=>1,
+ '{pages}'=>1,
+ ));
+ }
+ echo '</div>';
+ }
+
+ /**
+ * Renders the pager.
+ */
+ public function renderPager()
+ {
+ if(!$this->enablePagination)
+ return;
+
+ $pager=array();
+ $class='CLinkPager';
+ if(is_string($this->pager))
+ $class=$this->pager;
+ else if(is_array($this->pager))
+ {
+ $pager=$this->pager;
+ if(isset($pager['class']))
+ {
+ $class=$pager['class'];
+ unset($pager['class']);
+ }
+ }
+ $pager['pages']=$this->dataProvider->getPagination();
+
+ if($pager['pages']->getPageCount()>1)
+ {
+ echo '<div class="'.$this->pagerCssClass.'">';
+ $this->widget($class,$pager);
+ echo '</div>';
+ }
+ else
+ $this->widget($class,$pager);
+ }
+
+ /**
+ * Registers necessary client scripts.
+ * This method is invoked by {@link run}.
+ * Child classes may override this method to register customized client scripts.
+ */
+ public function registerClientScript()
+ {
+ }
+
+ /**
+ * Renders the data items for the view.
+ * Each item is corresponding to a single data model instance.
+ * Child classes should override this method to provide the actual item rendering logic.
+ */
+ abstract public function renderItems();
+}
diff --git a/framework/zii/widgets/CBreadcrumbs.php b/framework/zii/widgets/CBreadcrumbs.php
new file mode 100644
index 0000000..3d4b7be
--- /dev/null
+++ b/framework/zii/widgets/CBreadcrumbs.php
@@ -0,0 +1,116 @@
+<?php
+/**
+ * CBreadcrumbs class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CBreadcrumbs displays a list of links indicating the position of the current page in the whole website.
+ *
+ * For example, breadcrumbs like "Home > Sample Post > Edit" means the user is viewing an edit page
+ * for the "Sample Post". He can click on "Sample Post" to view that page, or he can click on "Home"
+ * to return to the homepage.
+ *
+ * To use CBreadcrumbs, one usually needs to configure its {@link links} property, which specifies
+ * the links to be displayed. For example,
+ *
+ * <pre>
+ * $this->widget('zii.widgets.CBreadcrumbs', array(
+ * 'links'=>array(
+ * 'Sample post'=>array('post/view', 'id'=>12),
+ * 'Edit',
+ * ),
+ * ));
+ * </pre>
+ *
+ * Because breadcrumbs usually appears in nearly every page of a website, the widget is better to be placed
+ * in a layout view. One can define a property "breadcrumbs" in the base controller class and assign it to the widget
+ * in the layout, like the following:
+ *
+ * <pre>
+ * $this->widget('zii.widgets.CBreadcrumbs', array(
+ * 'links'=>$this->breadcrumbs,
+ * ));
+ * </pre>
+ *
+ * Then, in each view script, one only needs to assign the "breadcrumbs" property as needed.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CBreadcrumbs.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package zii.widgets
+ * @since 1.1
+ */
+class CBreadcrumbs extends CWidget
+{
+ /**
+ * @var string the tag name for the breadcrumbs container tag. Defaults to 'div'.
+ */
+ public $tagName='div';
+ /**
+ * @var array the HTML attributes for the breadcrumbs container tag.
+ */
+ public $htmlOptions=array('class'=>'breadcrumbs');
+ /**
+ * @var boolean whether to HTML encode the link labels. Defaults to true.
+ */
+ public $encodeLabel=true;
+ /**
+ * @var string the first hyperlink in the breadcrumbs (called home link).
+ * If this property is not set, it defaults to a link pointing to {@link CWebApplication::homeUrl} with label 'Home'.
+ * If this property is false, the home link will not be rendered.
+ */
+ public $homeLink;
+ /**
+ * @var array list of hyperlinks to appear in the breadcrumbs. If this property is empty,
+ * the widget will not render anything. Each key-value pair in the array
+ * will be used to generate a hyperlink by calling CHtml::link(key, value). For this reason, the key
+ * refers to the label of the link while the value can be a string or an array (used to
+ * create a URL). For more details, please refer to {@link CHtml::link}.
+ * If an element's key is an integer, it means the element will be rendered as a label only (meaning the current page).
+ *
+ * The following example will generate breadcrumbs as "Home > Sample post > Edit", where "Home" points to the homepage,
+ * "Sample post" points to the "index.php?r=post/view&id=12" page, and "Edit" is a label. Note that the "Home" link
+ * is specified via {@link homeLink} separately.
+ *
+ * <pre>
+ * array(
+ * 'Sample post'=>array('post/view', 'id'=>12),
+ * 'Edit',
+ * )
+ * </pre>
+ */
+ public $links=array();
+ /**
+ * @var string the separator between links in the breadcrumbs. Defaults to ' &raquo; '.
+ */
+ public $separator=' &raquo; ';
+
+ /**
+ * Renders the content of the portlet.
+ */
+ public function run()
+ {
+ if(empty($this->links))
+ return;
+
+ echo CHtml::openTag($this->tagName,$this->htmlOptions)."\n";
+ $links=array();
+ if($this->homeLink===null)
+ $links[]=CHtml::link(Yii::t('zii','Home'),Yii::app()->homeUrl);
+ else if($this->homeLink!==false)
+ $links[]=$this->homeLink;
+ foreach($this->links as $label=>$url)
+ {
+ if(is_string($label) || is_array($url))
+ $links[]=CHtml::link($this->encodeLabel ? CHtml::encode($label) : $label, $url);
+ else
+ $links[]='<span>'.($this->encodeLabel ? CHtml::encode($url) : $url).'</span>';
+ }
+ echo implode($this->separator,$links);
+ echo CHtml::closeTag($this->tagName);
+ }
+} \ No newline at end of file
diff --git a/framework/zii/widgets/CDetailView.php b/framework/zii/widgets/CDetailView.php
new file mode 100644
index 0000000..5cfb74d
--- /dev/null
+++ b/framework/zii/widgets/CDetailView.php
@@ -0,0 +1,242 @@
+<?php
+/**
+ * CDetailView class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CDetailView displays the detail of a single data model.
+ *
+ * CDetailView is best used for displaying a model in a regular format (e.g. each model attribute
+ * is displayed as a row in a table.) The model can be either an instance of {@link CModel}
+ * or an associative array.
+ *
+ * CDetailView uses the {@link attributes} property to determines which model attributes
+ * should be displayed and how they should be formatted.
+ *
+ * A typical usage of CDetailView is as follows:
+ * <pre>
+ * $this->widget('zii.widgets.CDetailView', array(
+ * 'data'=>$model,
+ * 'attributes'=>array(
+ * 'title', // title attribute (in plain text)
+ * 'owner.name', // an attribute of the related object "owner"
+ * 'description:html', // description attribute in HTML
+ * array( // related city displayed as a link
+ * 'label'=>'City',
+ * 'type'=>'raw',
+ * 'value'=>CHtml::link(CHtml::encode($model->city->name),
+ * array('city/view','id'=>$model->city->id)),
+ * ),
+ * ),
+ * ));
+ * </pre>
+ *
+ * @property CFormatter $formatter The formatter instance. Defaults to the 'format' application component.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CDetailView.php 3427 2011-10-25 00:03:52Z alexander.makarow $
+ * @package zii.widgets
+ * @since 1.1
+ */
+class CDetailView extends CWidget
+{
+ private $_formatter;
+
+ /**
+ * @var mixed the data model whose details are to be displayed. This can be either a {@link CModel} instance
+ * (e.g. a {@link CActiveRecord} object or a {@link CFormModel} object) or an associative array.
+ */
+ public $data;
+ /**
+ * @var array a list of attributes to be displayed in the detail view. Each array element
+ * represents the specification for displaying one particular attribute.
+ *
+ * An attribute can be specified as a string in the format of "Name:Type:Label".
+ * Both "Type" and "Label" are optional.
+ *
+ * "Name" refers to the attribute name. It can be either a property (e.g. "title") or a sub-property (e.g. "owner.username").
+ *
+ * "Label" represents the label for the attribute display. If it is not given, "Name" will be used to generate the appropriate label.
+ *
+ * "Type" represents the type of the attribute. It determines how the attribute value should be formatted and displayed.
+ * It is defaulted to be 'text'.
+ * "Type" should be recognizable by the {@link formatter}. In particular, if "Type" is "xyz", then the "formatXyz" method
+ * of {@link formatter} will be invoked to format the attribute value for display. By default when {@link CFormatter} is used,
+ * these "Type" values are valid: raw, text, ntext, html, date, time, datetime, boolean, number, email, image, url.
+ * For more details about these types, please refer to {@link CFormatter}.
+ *
+ * An attribute can also be specified in terms of an array with the following elements:
+ * <ul>
+ * <li>label: the label associated with the attribute. If this is not specified, the following "name" element
+ * will be used to generate an appropriate label.</li>
+ * <li>name: the name of the attribute. This can be either a property or a sub-property of the model.
+ * If the below "value" element is specified, this will be ignored.</li>
+ * <li>value: the value to be displayed. If this is not specified, the above "name" element will be used
+ * to retrieve the corresponding attribute value for display. Note that this value will be formatted according
+ * to the "type" option as described below.</li>
+ * <li>type: the type of the attribute that determines how the attribute value would be formatted.
+ * Please see above for possible values.
+ * <li>cssClass: the CSS class to be used for this item. This option is available since version 1.1.3.</li>
+ * <li>template: the template used to render the attribute. If this is not specified, {@link itemTemplate}
+ * will be used instead. For more details on how to set this option, please refer to {@link itemTemplate}.
+ * This option is available since version 1.1.1.</li>
+ * <li>visible: whether the attribute is visible. If set to <code>false</code>, the table row for the attribute will not be rendered.
+ * This option is available since version 1.1.5.</li>
+ * </ul>
+ */
+ public $attributes;
+ /**
+ * @var string the text to be displayed when an attribute value is null. Defaults to "Not set".
+ */
+ public $nullDisplay;
+ /**
+ * @var string the name of the tag for rendering the detail view. Defaults to 'table'.
+ * @see itemTemplate
+ */
+ public $tagName='table';
+ /**
+ * @var string the template used to render a single attribute. Defaults to a table row.
+ * These tokens are recognized: "{class}", "{label}" and "{value}". They will be replaced
+ * with the CSS class name for the item, the label and the attribute value, respectively.
+ * @see itemCssClass
+ */
+ public $itemTemplate="<tr class=\"{class}\"><th>{label}</th><td>{value}</td></tr>\n";
+ /**
+ * @var array the CSS class names for the items displaying attribute values. If multiple CSS class names are given,
+ * they will be assigned to the items sequentially and repeatedly.
+ * Defaults to <code>array('odd', 'even')</code>.
+ */
+ public $itemCssClass=array('odd','even');
+ /**
+ * @var array the HTML options used for {@link tagName}
+ */
+ public $htmlOptions=array('class'=>'detail-view');
+ /**
+ * @var string the base script URL for all detail view resources (e.g. javascript, CSS file, images).
+ * Defaults to null, meaning using the integrated detail view resources (which are published as assets).
+ */
+ public $baseScriptUrl;
+ /**
+ * @var string the URL of the CSS file used by this detail view. Defaults to null, meaning using the integrated
+ * CSS file. If this is set false, you are responsible to explicitly include the necessary CSS file in your page.
+ */
+ public $cssFile;
+
+ /**
+ * Initializes the detail view.
+ * This method will initialize required property values.
+ */
+ public function init()
+ {
+ if($this->data===null)
+ throw new CException(Yii::t('zii','Please specify the "data" property.'));
+ if($this->attributes===null)
+ {
+ if($this->data instanceof CModel)
+ $this->attributes=$this->data->attributeNames();
+ else if(is_array($this->data))
+ $this->attributes=array_keys($this->data);
+ else
+ throw new CException(Yii::t('zii','Please specify the "attributes" property.'));
+ }
+ if($this->nullDisplay===null)
+ $this->nullDisplay='<span class="null">'.Yii::t('zii','Not set').'</span>';
+ $this->htmlOptions['id']=$this->getId();
+
+ if($this->baseScriptUrl===null)
+ $this->baseScriptUrl=Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias('zii.widgets.assets')).'/detailview';
+
+ if($this->cssFile!==false)
+ {
+ if($this->cssFile===null)
+ $this->cssFile=$this->baseScriptUrl.'/styles.css';
+ Yii::app()->getClientScript()->registerCssFile($this->cssFile);
+ }
+ }
+
+ /**
+ * Renders the detail view.
+ * This is the main entry of the whole detail view rendering.
+ */
+ public function run()
+ {
+ $formatter=$this->getFormatter();
+ echo CHtml::openTag($this->tagName,$this->htmlOptions);
+
+ $i=0;
+ $n=is_array($this->itemCssClass) ? count($this->itemCssClass) : 0;
+
+ foreach($this->attributes as $attribute)
+ {
+ if(is_string($attribute))
+ {
+ if(!preg_match('/^([\w\.]+)(:(\w*))?(:(.*))?$/',$attribute,$matches))
+ throw new CException(Yii::t('zii','The attribute must be specified in the format of "Name:Type:Label", where "Type" and "Label" are optional.'));
+ $attribute=array(
+ 'name'=>$matches[1],
+ 'type'=>isset($matches[3]) ? $matches[3] : 'text',
+ );
+ if(isset($matches[5]))
+ $attribute['label']=$matches[5];
+ }
+
+ if(isset($attribute['visible']) && !$attribute['visible'])
+ continue;
+
+ $tr=array('{label}'=>'', '{class}'=>$n ? $this->itemCssClass[$i%$n] : '');
+ if(isset($attribute['cssClass']))
+ $tr['{class}']=$attribute['cssClass'].' '.($n ? $tr['{class}'] : '');
+
+ if(isset($attribute['label']))
+ $tr['{label}']=$attribute['label'];
+ else if(isset($attribute['name']))
+ {
+ if($this->data instanceof CModel)
+ $tr['{label}']=$this->data->getAttributeLabel($attribute['name']);
+ else
+ $tr['{label}']=ucwords(trim(strtolower(str_replace(array('-','_','.'),' ',preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $attribute['name'])))));
+ }
+
+ if(!isset($attribute['type']))
+ $attribute['type']='text';
+ if(isset($attribute['value']))
+ $value=$attribute['value'];
+ else if(isset($attribute['name']))
+ $value=CHtml::value($this->data,$attribute['name']);
+ else
+ $value=null;
+
+ $tr['{value}']=$value===null ? $this->nullDisplay : $formatter->format($value,$attribute['type']);
+
+ echo strtr(isset($attribute['template']) ? $attribute['template'] : $this->itemTemplate,$tr);
+
+ $i++;
+
+ }
+
+ echo CHtml::closeTag($this->tagName);
+ }
+
+ /**
+ * @return CFormatter the formatter instance. Defaults to the 'format' application component.
+ */
+ public function getFormatter()
+ {
+ if($this->_formatter===null)
+ $this->_formatter=Yii::app()->format;
+ return $this->_formatter;
+ }
+
+ /**
+ * @param CFormatter $value the formatter instance
+ */
+ public function setFormatter($value)
+ {
+ $this->_formatter=$value;
+ }
+}
diff --git a/framework/zii/widgets/CListView.php b/framework/zii/widgets/CListView.php
new file mode 100644
index 0000000..d1acf2f
--- /dev/null
+++ b/framework/zii/widgets/CListView.php
@@ -0,0 +1,276 @@
+<?php
+/**
+ * CListView class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.CBaseListView');
+
+/**
+ * CListView displays a list of data items in terms of a list.
+ *
+ * Unlike {@link CGridView} which displays the data items in a table, CListView allows one to use
+ * a view template to render each data item. As a result, CListView could generate more flexible
+ * rendering result.
+ *
+ * CListView supports both sorting and pagination of the data items. The sorting
+ * and pagination can be done in AJAX mode or normal page request. A benefit of using CListView is that
+ * when the user browser disables JavaScript, the sorting and pagination automatically degenerate
+ * to normal page requests and are still functioning as expected.
+ *
+ * CListView should be used together with a {@link IDataProvider data provider}, preferrably a
+ * {@link CActiveDataProvider}.
+ *
+ * The minimal code needed to use CListView is as follows:
+ *
+ * <pre>
+ * $dataProvider=new CActiveDataProvider('Post');
+ *
+ * $this->widget('zii.widgets.CListView', array(
+ * 'dataProvider'=>$dataProvider,
+ * 'itemView'=>'_post', // refers to the partial view named '_post'
+ * 'sortableAttributes'=>array(
+ * 'title',
+ * 'create_time'=>'Post Time',
+ * ),
+ * ));
+ * </pre>
+ *
+ * The above code first creates a data provider for the <code>Post</code> ActiveRecord class.
+ * It then uses CListView to display every data item as returned by the data provider.
+ * The display is done via the partial view named '_post'. This partial view will be rendered
+ * once for every data item. In the view, one can access the current data item via variable <code>$data</code>.
+ * For more details, see {@link itemView}.
+ *
+ * In order to support sorting, one has to specify the {@link sortableAttributes} property.
+ * By doing so, a list of hyperlinks that can sort the data will be displayed.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CListView.php 3286 2011-06-16 17:34:34Z qiang.xue $
+ * @package zii.widgets
+ * @since 1.1
+ */
+class CListView extends CBaseListView
+{
+ /**
+ * @var string the view used for rendering each data item.
+ * This property value will be passed as the first parameter to either {@link CController::renderPartial}
+ * or {@link CWidget::render} to render each data item.
+ * In the corresponding view template, the following variables can be used in addition to those declared in {@link viewData}:
+ * <ul>
+ * <li><code>$this</code>: refers to the owner of this list view widget. For example, if the widget is in the view of a controller,
+ * then <code>$this</code> refers to the controller.</li>
+ * <li><code>$data</code>: refers to the data item currently being rendered.</li>
+ * <li><code>$index</code>: refers to the zero-based index of the data item currently being rendered.</li>
+ * <li><code>$widget</code>: refers to this list view widget instance.</li>
+ * </ul>
+ */
+ public $itemView;
+ /**
+ * @var string the HTML code to be displayed between any two consecutive items.
+ * @since 1.1.7
+ */
+ public $separator;
+ /**
+ * @var array additional data to be passed to {@link itemView} when rendering each data item.
+ * This array will be extracted into local PHP variables that can be accessed in the {@link itemView}.
+ */
+ public $viewData=array();
+ /**
+ * @var array list of sortable attribute names. In order for an attribute to be sortable, it must also
+ * appear as a sortable attribute in the {@link IDataProvider::sort} property of {@link dataProvider}.
+ * @see enableSorting
+ */
+ public $sortableAttributes;
+ /**
+ * @var string the template to be used to control the layout of various components in the list view.
+ * These tokens are recognized: {summary}, {sorter}, {items} and {pager}. They will be replaced with the
+ * summary text, the sort links, the data item list, and the pager.
+ */
+ public $template="{summary}\n{sorter}\n{items}\n{pager}";
+ /**
+ * @var string the CSS class name that will be assigned to the widget container element
+ * when the widget is updating its content via AJAX. Defaults to 'list-view-loading'.
+ * @since 1.1.1
+ */
+ public $loadingCssClass='list-view-loading';
+ /**
+ * @var string the CSS class name for the sorter container. Defaults to 'sorter'.
+ */
+ public $sorterCssClass='sorter';
+ /**
+ * @var string the text shown before sort links. Defaults to 'Sort by: '.
+ */
+ public $sorterHeader;
+ /**
+ * @var string the text shown after sort links. Defaults to empty.
+ */
+ public $sorterFooter='';
+ /**
+ * @var mixed the ID of the container whose content may be updated with an AJAX response.
+ * Defaults to null, meaning the container for this list view instance.
+ * If it is set false, it means sorting and pagination will be performed in normal page requests
+ * instead of AJAX requests. If the sorting and pagination should trigger the update of multiple
+ * containers' content in AJAX fashion, these container IDs may be listed here (separated with comma).
+ */
+ public $ajaxUpdate;
+ /**
+ * @var string the jQuery selector of the HTML elements that may trigger AJAX updates when they are clicked.
+ * If not set, the pagination links and the sorting links will trigger AJAX updates.
+ * @since 1.1.7
+ */
+ public $updateSelector;
+ /**
+ * @var string the name of the GET variable that indicates the request is an AJAX request triggered
+ * by this widget. Defaults to 'ajax'. This is effective only when {@link ajaxUpdate} is not false.
+ */
+ public $ajaxVar='ajax';
+ /**
+ * @var mixed the URL for the AJAX requests should be sent to. {@link CHtml::normalizeUrl()} will be
+ * called on this property. If not set, the current page URL will be used for AJAX requests.
+ * @since 1.1.8
+ */
+ public $ajaxUrl;
+ /**
+ * @var string a javascript function that will be invoked before an AJAX update occurs.
+ * The function signature is <code>function(id)</code> where 'id' refers to the ID of the list view.
+ */
+ public $beforeAjaxUpdate;
+ /**
+ * @var string a javascript function that will be invoked after a successful AJAX response is received.
+ * The function signature is <code>function(id, data)</code> where 'id' refers to the ID of the list view
+ * 'data' the received ajax response data.
+ */
+ public $afterAjaxUpdate;
+ /**
+ * @var string the base script URL for all list view resources (e.g. javascript, CSS file, images).
+ * Defaults to null, meaning using the integrated list view resources (which are published as assets).
+ */
+ public $baseScriptUrl;
+ /**
+ * @var string the URL of the CSS file used by this list view. Defaults to null, meaning using the integrated
+ * CSS file. If this is set false, you are responsible to explicitly include the necessary CSS file in your page.
+ */
+ public $cssFile;
+ /**
+ * @var string the HTML tag name for the container of all data item display. Defaults to 'div'.
+ * @since 1.1.4
+ */
+ public $itemsTagName='div';
+
+ /**
+ * Initializes the list view.
+ * This method will initialize required property values and instantiate {@link columns} objects.
+ */
+ public function init()
+ {
+ if($this->itemView===null)
+ throw new CException(Yii::t('zii','The property "itemView" cannot be empty.'));
+ parent::init();
+
+ if(!isset($this->htmlOptions['class']))
+ $this->htmlOptions['class']='list-view';
+
+ if($this->baseScriptUrl===null)
+ $this->baseScriptUrl=Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias('zii.widgets.assets')).'/listview';
+
+ if($this->cssFile!==false)
+ {
+ if($this->cssFile===null)
+ $this->cssFile=$this->baseScriptUrl.'/styles.css';
+ Yii::app()->getClientScript()->registerCssFile($this->cssFile);
+ }
+ }
+
+ /**
+ * Registers necessary client scripts.
+ */
+ public function registerClientScript()
+ {
+ $id=$this->getId();
+
+ if($this->ajaxUpdate===false)
+ $ajaxUpdate=array();
+ else
+ $ajaxUpdate=array_unique(preg_split('/\s*,\s*/',$this->ajaxUpdate.','.$id,-1,PREG_SPLIT_NO_EMPTY));
+ $options=array(
+ 'ajaxUpdate'=>$ajaxUpdate,
+ 'ajaxVar'=>$this->ajaxVar,
+ 'pagerClass'=>$this->pagerCssClass,
+ 'loadingClass'=>$this->loadingCssClass,
+ 'sorterClass'=>$this->sorterCssClass,
+ );
+ if($this->ajaxUrl!==null)
+ $options['url']=CHtml::normalizeUrl($this->ajaxUrl);
+ if($this->updateSelector!==null)
+ $options['updateSelector']=$this->updateSelector;
+ if($this->beforeAjaxUpdate!==null)
+ $options['beforeAjaxUpdate']=(strpos($this->beforeAjaxUpdate,'js:')!==0 ? 'js:' : '').$this->beforeAjaxUpdate;
+ if($this->afterAjaxUpdate!==null)
+ $options['afterAjaxUpdate']=(strpos($this->afterAjaxUpdate,'js:')!==0 ? 'js:' : '').$this->afterAjaxUpdate;
+
+ $options=CJavaScript::encode($options);
+ $cs=Yii::app()->getClientScript();
+ $cs->registerCoreScript('jquery');
+ $cs->registerCoreScript('bbq');
+ $cs->registerScriptFile($this->baseScriptUrl.'/jquery.yiilistview.js',CClientScript::POS_END);
+ $cs->registerScript(__CLASS__.'#'.$id,"jQuery('#$id').yiiListView($options);");
+ }
+
+ /**
+ * Renders the data item list.
+ */
+ public function renderItems()
+ {
+ echo CHtml::openTag($this->itemsTagName,array('class'=>$this->itemsCssClass))."\n";
+ $data=$this->dataProvider->getData();
+ if(($n=count($data))>0)
+ {
+ $owner=$this->getOwner();
+ $render=$owner instanceof CController ? 'renderPartial' : 'render';
+ $j=0;
+ foreach($data as $i=>$item)
+ {
+ $data=$this->viewData;
+ $data['index']=$i;
+ $data['data']=$item;
+ $data['widget']=$this;
+ $owner->$render($this->itemView,$data);
+ if($j++ < $n-1)
+ echo $this->separator;
+ }
+ }
+ else
+ $this->renderEmptyText();
+ echo CHtml::closeTag($this->itemsTagName);
+ }
+
+ /**
+ * Renders the sorter.
+ */
+ public function renderSorter()
+ {
+ if($this->dataProvider->getItemCount()<=0 || !$this->enableSorting || empty($this->sortableAttributes))
+ return;
+ echo CHtml::openTag('div',array('class'=>$this->sorterCssClass))."\n";
+ echo $this->sorterHeader===null ? Yii::t('zii','Sort by: ') : $this->sorterHeader;
+ echo "<ul>\n";
+ $sort=$this->dataProvider->getSort();
+ foreach($this->sortableAttributes as $name=>$label)
+ {
+ echo "<li>";
+ if(is_integer($name))
+ echo $sort->link($label);
+ else
+ echo $sort->link($name,$label);
+ echo "</li>\n";
+ }
+ echo "</ul>";
+ echo $this->sorterFooter;
+ echo CHtml::closeTag('div');
+ }
+}
diff --git a/framework/zii/widgets/CMenu.php b/framework/zii/widgets/CMenu.php
new file mode 100644
index 0000000..47947ad
--- /dev/null
+++ b/framework/zii/widgets/CMenu.php
@@ -0,0 +1,317 @@
+<?php
+/**
+ * CMenu class file.
+ *
+ * @author Jonah Turnquist <poppitypop@gmail.com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CMenu displays a multi-level menu using nested HTML lists.
+ *
+ * The main property of CMenu is {@link items}, which specifies the possible items in the menu.
+ * A menu item has three main properties: visible, active and items. The "visible" property
+ * specifies whether the menu item is currently visible. The "active" property specifies whether
+ * the menu item is currently selected. And the "items" property specifies the child menu items.
+ *
+ * The following example shows how to use CMenu:
+ * <pre>
+ * $this->widget('zii.widgets.CMenu', array(
+ * 'items'=>array(
+ * // Important: you need to specify url as 'controller/action',
+ * // not just as 'controller' even if default acion is used.
+ * array('label'=>'Home', 'url'=>array('site/index')),
+ * // 'Products' menu item will be selected no matter which tag parameter value is since it's not specified.
+ * array('label'=>'Products', 'url'=>array('product/index'), 'items'=>array(
+ * array('label'=>'New Arrivals', 'url'=>array('product/new', 'tag'=>'new')),
+ * array('label'=>'Most Popular', 'url'=>array('product/index', 'tag'=>'popular')),
+ * )),
+ * array('label'=>'Login', 'url'=>array('site/login'), 'visible'=>Yii::app()->user->isGuest),
+ * ),
+ * ));
+ * </pre>
+ *
+ *
+ * @author Jonah Turnquist <poppitypop@gmail.com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CMenu.php 3520 2011-12-29 09:54:22Z mdomba $
+ * @package zii.widgets
+ * @since 1.1
+ */
+class CMenu extends CWidget
+{
+ /**
+ * @var array list of menu items. Each menu item is specified as an array of name-value pairs.
+ * Possible option names include the following:
+ * <ul>
+ * <li>label: string, optional, specifies the menu item label. When {@link encodeLabel} is true, the label
+ * will be HTML-encoded. If the label is not specified, it defaults to an empty string.</li>
+ * <li>url: string or array, optional, specifies the URL of the menu item. It is passed to {@link CHtml::normalizeUrl}
+ * to generate a valid URL. If this is not set, the menu item will be rendered as a span text.</li>
+ * <li>visible: boolean, optional, whether this menu item is visible. Defaults to true.
+ * This can be used to control the visibility of menu items based on user permissions.</li>
+ * <li>items: array, optional, specifies the sub-menu items. Its format is the same as the parent items.</li>
+ * <li>active: boolean, optional, whether this menu item is in active state (currently selected).
+ * If a menu item is active and {@link activeClass} is not empty, its CSS class will be appended with {@link activeClass}.
+ * If this option is not set, the menu item will be set active automatically when the current request
+ * is triggered by {@link url}. Note that the GET parameters not specified in the 'url' option will be ignored.</li>
+ * <li>template: string, optional, the template used to render this menu item.
+ * When this option is set, it will override the global setting {@link itemTemplate}.
+ * Please see {@link itemTemplate} for more details. This option has been available since version 1.1.1.</li>
+ * <li>linkOptions: array, optional, additional HTML attributes to be rendered for the link or span tag of the menu item.</li>
+ * <li>itemOptions: array, optional, additional HTML attributes to be rendered for the container tag of the menu item.</li>
+ * <li>submenuOptions: array, optional, additional HTML attributes to be rendered for the container of the submenu if this menu item has one.
+ * When this option is set, the {@link submenuHtmlOptions} property will be ignored for this particular submenu.
+ * This option has been available since version 1.1.6.</li>
+ * </ul>
+ */
+ public $items=array();
+ /**
+ * @var string the template used to render an individual menu item. In this template,
+ * the token "{menu}" will be replaced with the corresponding menu link or text.
+ * If this property is not set, each menu will be rendered without any decoration.
+ * This property will be overridden by the 'template' option set in individual menu items via {@items}.
+ * @since 1.1.1
+ */
+ public $itemTemplate;
+ /**
+ * @var boolean whether the labels for menu items should be HTML-encoded. Defaults to true.
+ */
+ public $encodeLabel=true;
+ /**
+ * @var string the CSS class to be appended to the active menu item. Defaults to 'active'.
+ * If empty, the CSS class of menu items will not be changed.
+ */
+ public $activeCssClass='active';
+ /**
+ * @var boolean whether to automatically activate items according to whether their route setting
+ * matches the currently requested route. Defaults to true.
+ * @since 1.1.3
+ */
+ public $activateItems=true;
+ /**
+ * @var boolean whether to activate parent menu items when one of the corresponding child menu items is active.
+ * The activated parent menu items will also have its CSS classes appended with {@link activeCssClass}.
+ * Defaults to false.
+ */
+ public $activateParents=false;
+ /**
+ * @var boolean whether to hide empty menu items. An empty menu item is one whose 'url' option is not
+ * set and which doesn't contain visible child menu items. Defaults to true.
+ */
+ public $hideEmptyItems=true;
+ /**
+ * @var array HTML attributes for the menu's root container tag
+ */
+ public $htmlOptions=array();
+ /**
+ * @var array HTML attributes for the submenu's container tag.
+ */
+ public $submenuHtmlOptions=array();
+ /**
+ * @var string the HTML element name that will be used to wrap the label of all menu links.
+ * For example, if this property is set as 'span', a menu item may be rendered as
+ * &lt;li&gt;&lt;a href="url"&gt;&lt;span&gt;label&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
+ * This is useful when implementing menu items using the sliding window technique.
+ * Defaults to null, meaning no wrapper tag will be generated.
+ * @since 1.1.4
+ */
+ public $linkLabelWrapper;
+ /**
+ * @var string the CSS class that will be assigned to the first item in the main menu or each submenu.
+ * Defaults to null, meaning no such CSS class will be assigned.
+ * @since 1.1.4
+ */
+ public $firstItemCssClass;
+ /**
+ * @var string the CSS class that will be assigned to the last item in the main menu or each submenu.
+ * Defaults to null, meaning no such CSS class will be assigned.
+ * @since 1.1.4
+ */
+ public $lastItemCssClass;
+ /**
+ * @var string the CSS class that will be assigned to every item.
+ * Defaults to null, meaning no such CSS class will be assigned.
+ * @since 1.1.9
+ */
+ public $itemCssClass;
+
+ /**
+ * Initializes the menu widget.
+ * This method mainly normalizes the {@link items} property.
+ * If this method is overridden, make sure the parent implementation is invoked.
+ */
+ public function init()
+ {
+ $this->htmlOptions['id']=$this->getId();
+ $route=$this->getController()->getRoute();
+ $this->items=$this->normalizeItems($this->items,$route,$hasActiveChild);
+ }
+
+ /**
+ * Calls {@link renderMenu} to render the menu.
+ */
+ public function run()
+ {
+ $this->renderMenu($this->items);
+ }
+
+ /**
+ * Renders the menu items.
+ * @param array $items menu items. Each menu item will be an array with at least two elements: 'label' and 'active'.
+ * It may have three other optional elements: 'items', 'linkOptions' and 'itemOptions'.
+ */
+ protected function renderMenu($items)
+ {
+ if(count($items))
+ {
+ echo CHtml::openTag('ul',$this->htmlOptions)."\n";
+ $this->renderMenuRecursive($items);
+ echo CHtml::closeTag('ul');
+ }
+ }
+
+ /**
+ * Recursively renders the menu items.
+ * @param array $items the menu items to be rendered recursively
+ */
+ protected function renderMenuRecursive($items)
+ {
+ $count=0;
+ $n=count($items);
+ foreach($items as $item)
+ {
+ $count++;
+ $options=isset($item['itemOptions']) ? $item['itemOptions'] : array();
+ $class=array();
+ if($item['active'] && $this->activeCssClass!='')
+ $class[]=$this->activeCssClass;
+ if($count===1 && $this->firstItemCssClass!==null)
+ $class[]=$this->firstItemCssClass;
+ if($count===$n && $this->lastItemCssClass!==null)
+ $class[]=$this->lastItemCssClass;
+ if($this->itemCssClass!==null)
+ $class[]=$this->itemCssClass;
+ if($class!==array())
+ {
+ if(empty($options['class']))
+ $options['class']=implode(' ',$class);
+ else
+ $options['class'].=' '.implode(' ',$class);
+ }
+
+ echo CHtml::openTag('li', $options);
+
+ $menu=$this->renderMenuItem($item);
+ if(isset($this->itemTemplate) || isset($item['template']))
+ {
+ $template=isset($item['template']) ? $item['template'] : $this->itemTemplate;
+ echo strtr($template,array('{menu}'=>$menu));
+ }
+ else
+ echo $menu;
+
+ if(isset($item['items']) && count($item['items']))
+ {
+ echo "\n".CHtml::openTag('ul',isset($item['submenuOptions']) ? $item['submenuOptions'] : $this->submenuHtmlOptions)."\n";
+ $this->renderMenuRecursive($item['items']);
+ echo CHtml::closeTag('ul')."\n";
+ }
+
+ echo CHtml::closeTag('li')."\n";
+ }
+ }
+
+ /**
+ * Renders the content of a menu item.
+ * Note that the container and the sub-menus are not rendered here.
+ * @param array $item the menu item to be rendered. Please see {@link items} on what data might be in the item.
+ * @return string
+ * @since 1.1.6
+ */
+ protected function renderMenuItem($item)
+ {
+ if(isset($item['url']))
+ {
+ $label=$this->linkLabelWrapper===null ? $item['label'] : '<'.$this->linkLabelWrapper.'>'.$item['label'].'</'.$this->linkLabelWrapper.'>';
+ return CHtml::link($label,$item['url'],isset($item['linkOptions']) ? $item['linkOptions'] : array());
+ }
+ else
+ return CHtml::tag('span',isset($item['linkOptions']) ? $item['linkOptions'] : array(), $item['label']);
+ }
+
+ /**
+ * Normalizes the {@link items} property so that the 'active' state is properly identified for every menu item.
+ * @param array $items the items to be normalized.
+ * @param string $route the route of the current request.
+ * @param boolean $active whether there is an active child menu item.
+ * @return array the normalized menu items
+ */
+ protected function normalizeItems($items,$route,&$active)
+ {
+ foreach($items as $i=>$item)
+ {
+ if(isset($item['visible']) && !$item['visible'])
+ {
+ unset($items[$i]);
+ continue;
+ }
+ if(!isset($item['label']))
+ $item['label']='';
+ if($this->encodeLabel)
+ $items[$i]['label']=CHtml::encode($item['label']);
+ $hasActiveChild=false;
+ if(isset($item['items']))
+ {
+ $items[$i]['items']=$this->normalizeItems($item['items'],$route,$hasActiveChild);
+ if(empty($items[$i]['items']) && $this->hideEmptyItems)
+ {
+ unset($items[$i]['items']);
+ if(!isset($item['url']))
+ {
+ unset($items[$i]);
+ continue;
+ }
+ }
+ }
+ if(!isset($item['active']))
+ {
+ if($this->activateParents && $hasActiveChild || $this->activateItems && $this->isItemActive($item,$route))
+ $active=$items[$i]['active']=true;
+ else
+ $items[$i]['active']=false;
+ }
+ else if($item['active'])
+ $active=true;
+ }
+ return array_values($items);
+ }
+
+ /**
+ * Checks whether a menu item is active.
+ * This is done by checking if the currently requested URL is generated by the 'url' option
+ * of the menu item. Note that the GET parameters not specified in the 'url' option will be ignored.
+ * @param array $item the menu item to be checked
+ * @param string $route the route of the current request
+ * @return boolean whether the menu item is active
+ */
+ protected function isItemActive($item,$route)
+ {
+ if(isset($item['url']) && is_array($item['url']) && !strcasecmp(trim($item['url'][0],'/'),$route))
+ {
+ if(count($item['url'])>1)
+ {
+ foreach(array_splice($item['url'],1) as $name=>$value)
+ {
+ if(!isset($_GET[$name]) || $_GET[$name]!=$value)
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+} \ No newline at end of file
diff --git a/framework/zii/widgets/CPortlet.php b/framework/zii/widgets/CPortlet.php
new file mode 100644
index 0000000..173bfc9
--- /dev/null
+++ b/framework/zii/widgets/CPortlet.php
@@ -0,0 +1,126 @@
+<?php
+/**
+ * CPortlet class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CPortlet is the base class for portlet widgets.
+ *
+ * A portlet displays a fragment of content, usually in terms of a block
+ * on the side bars of a Web page.
+ *
+ * To specify the content of the portlet, override the {@link renderContent}
+ * method, or insert the content code between the {@link CController::beginWidget}
+ * and {@link CController::endWidget} calls. For example,
+ *
+ * <pre>
+ * <?php $this->beginWidget('zii.widgets.CPortlet'); ?>
+ * ...insert content here...
+ * <?php $this->endWidget(); ?>
+ * </pre>
+ *
+ * A portlet also has an optional {@link title}. One may also override {@link renderDecoration}
+ * to further customize the decorative display of a portlet (e.g. adding min/max buttons).
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CPortlet.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package zii.widgets
+ * @since 1.1
+ */
+class CPortlet extends CWidget
+{
+ /**
+ * @var string the tag name for the portlet container tag. Defaults to 'div'.
+ */
+ public $tagName='div';
+ /**
+ * @var array the HTML attributes for the portlet container tag.
+ */
+ public $htmlOptions=array('class'=>'portlet');
+ /**
+ * @var string the title of the portlet. Defaults to null.
+ * When this is not set, Decoration will not be displayed.
+ * Note that the title will not be HTML-encoded when rendering.
+ */
+ public $title;
+ /**
+ * @var string the CSS class for the decoration container tag. Defaults to 'portlet-decoration'.
+ */
+ public $decorationCssClass='portlet-decoration';
+ /**
+ * @var string the CSS class for the portlet title tag. Defaults to 'portlet-title'.
+ */
+ public $titleCssClass='portlet-title';
+ /**
+ * @var string the CSS class for the content container tag. Defaults to 'portlet-content'.
+ */
+ public $contentCssClass='portlet-content';
+ /**
+ * @var boolean whether to hide the portlet when the body content is empty. Defaults to true.
+ * @since 1.1.4
+ */
+ public $hideOnEmpty=true;
+
+ private $_openTag;
+
+ /**
+ * Initializes the widget.
+ * This renders the open tags needed by the portlet.
+ * It also renders the decoration, if any.
+ */
+ public function init()
+ {
+ ob_start();
+ ob_implicit_flush(false);
+
+ $this->htmlOptions['id']=$this->getId();
+ echo CHtml::openTag($this->tagName,$this->htmlOptions)."\n";
+ $this->renderDecoration();
+ echo "<div class=\"{$this->contentCssClass}\">\n";
+
+ $this->_openTag=ob_get_contents();
+ ob_clean();
+ }
+
+ /**
+ * Renders the content of the portlet.
+ */
+ public function run()
+ {
+ $this->renderContent();
+ $content=ob_get_clean();
+ if($this->hideOnEmpty && trim($content)==='')
+ return;
+ echo $this->_openTag;
+ echo $content;
+ echo "</div>\n";
+ echo CHtml::closeTag($this->tagName);
+ }
+
+ /**
+ * Renders the decoration for the portlet.
+ * The default implementation will render the title if it is set.
+ */
+ protected function renderDecoration()
+ {
+ if($this->title!==null)
+ {
+ echo "<div class=\"{$this->decorationCssClass}\">\n";
+ echo "<div class=\"{$this->titleCssClass}\">{$this->title}</div>\n";
+ echo "</div>\n";
+ }
+ }
+
+ /**
+ * Renders the content of the portlet.
+ * Child classes should override this method to render the actual content.
+ */
+ protected function renderContent()
+ {
+ }
+} \ No newline at end of file
diff --git a/framework/zii/widgets/assets/detailview/styles.css b/framework/zii/widgets/assets/detailview/styles.css
new file mode 100644
index 0000000..bc5f6d2
--- /dev/null
+++ b/framework/zii/widgets/assets/detailview/styles.css
@@ -0,0 +1,44 @@
+table.detail-view .null
+{
+ color: pink;
+}
+
+table.detail-view
+{
+ background: white;
+ border-collapse: collapse;
+ width: 100%;
+ margin: 0;
+}
+
+table.detail-view th, table.detail-view td
+{
+ font-size: 0.9em;
+ border: 1px white solid;
+ padding: 0.3em 0.6em;
+ vertical-align: top;
+}
+
+table.detail-view th
+{
+ text-align: right;
+ width: 160px;
+}
+
+table.detail-view tr.odd
+{
+ background:#E5F1F4;
+}
+
+table.detail-view tr.even
+{
+ background:#F8F8F8;
+}
+
+table.detail-view tr.odd th
+{
+}
+
+table.detail-view tr.even th
+{
+}
diff --git a/framework/zii/widgets/assets/gridview/bg.gif b/framework/zii/widgets/assets/gridview/bg.gif
new file mode 100644
index 0000000..4283989
--- /dev/null
+++ b/framework/zii/widgets/assets/gridview/bg.gif
Binary files differ
diff --git a/framework/zii/widgets/assets/gridview/delete.png b/framework/zii/widgets/assets/gridview/delete.png
new file mode 100644
index 0000000..dc4c12a
--- /dev/null
+++ b/framework/zii/widgets/assets/gridview/delete.png
Binary files differ
diff --git a/framework/zii/widgets/assets/gridview/down.gif b/framework/zii/widgets/assets/gridview/down.gif
new file mode 100644
index 0000000..a4933b8
--- /dev/null
+++ b/framework/zii/widgets/assets/gridview/down.gif
Binary files differ
diff --git a/framework/zii/widgets/assets/gridview/jquery.yiigridview.js b/framework/zii/widgets/assets/gridview/jquery.yiigridview.js
new file mode 100644
index 0000000..700f247
--- /dev/null
+++ b/framework/zii/widgets/assets/gridview/jquery.yiigridview.js
@@ -0,0 +1,413 @@
+/**
+ * jQuery Yii GridView plugin file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2010 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ * @version $Id: jquery.yiigridview.js 3486 2011-12-16 00:25:01Z mdomba $
+ */
+
+(function ($) {
+ var selectCheckedRows, methods,
+ gridSettings = [];
+
+ /**
+ * 1. Selects rows that have checkbox checked (only checkbox that is connected with selecting a row)
+ * 2. Check if "check all" need to be checked/unchecked
+ * @return object the jQuery object
+ */
+ selectCheckedRows = function (gridId) {
+ var settings = gridSettings[gridId],
+ table = $('#' + gridId).children('.' + settings.tableClass);
+
+ table.children('tbody').find('input.select-on-check').filter(':checked').each(function () {
+ $(this).closest('tr').addClass('selected');
+ });
+
+ table.children('thead').find('th input').filter('[type="checkbox"]').each(function () {
+ var name = this.name.substring(0, this.name.length - 4) + '[]', //.. remove '_all' and add '[]''
+ $checks = $("input[name='" + name + "']", table);
+ this.checked = $checks.length > 0 && $checks.length === $checks.filter(':checked').length;
+ });
+ return this;
+ };
+
+ methods = {
+ /**
+ * yiiGridView set function.
+ * @param options map settings for the grid view. Available options are as follows:
+ * - ajaxUpdate: array, IDs of the containers whose content may be updated by ajax response
+ * - ajaxVar: string, the name of the GET variable indicating the ID of the element triggering the AJAX request
+ * - pagerClass: string, the CSS class for the pager container
+ * - tableClass: string, the CSS class for the table
+ * - selectableRows: integer, the number of rows that can be selected
+ * - updateSelector: string, the selector for choosing which elements can trigger ajax requests
+ * - beforeAjaxUpdate: function, the function to be called before ajax request is sent
+ * - afterAjaxUpdate: function, the function to be called after ajax response is received
+ * - ajaxUpdateError: function, the function to be called if an ajax error occurs
+ * - selectionChanged: function, the function to be called after the row selection is changed
+ * @return object the jQuery object
+ */
+ init: function (options) {
+ var settings = $.extend({
+ ajaxUpdate: [],
+ ajaxVar: 'ajax',
+ pagerClass: 'pager',
+ loadingClass: 'loading',
+ filterClass: 'filters',
+ tableClass: 'items',
+ selectableRows: 1
+ // updateSelector: '#id .pager a, '#id .grid thead th a',
+ // beforeAjaxUpdate: function (id) {},
+ // afterAjaxUpdate: function (id, data) {},
+ // selectionChanged: function (id) {},
+ // url: 'ajax request URL'
+ }, options || {});
+
+ return this.each(function () {
+ var $grid = $(this),
+ id = $grid.attr('id'),
+ inputSelector = '#' + id + ' .' + settings.filterClass + ' input, ' + '#' + id + ' .' + settings.filterClass + ' select';
+
+ settings.tableClass = settings.tableClass.replace(/\s+/g, '.');
+ if (settings.updateSelector === undefined) {
+ settings.updateSelector = '#' + id + ' .' + settings.pagerClass.replace(/\s+/g, '.') + ' a, #' + id + ' .' + settings.tableClass + ' thead th a';
+ }
+
+ gridSettings[id] = settings;
+
+ if (settings.ajaxUpdate.length > 0) {
+ $(document).on('click', settings.updateSelector, function () {
+ $('#' + id).yiiGridView('update', {url: $(this).attr('href')});
+ return false;
+ });
+ }
+
+ $(document).on('change', inputSelector, function () {
+ var data = $(inputSelector).serialize();
+ if (settings.pageVar !== undefined) {
+ data += '&' + settings.pageVar + '=1';
+ }
+ $('#' + id).yiiGridView('update', {data: data});
+ });
+
+ if (settings.selectableRows > 0) {
+ selectCheckedRows(this.id);
+ $(document).on('click', '#' + id + ' .' + settings.tableClass + ' > tbody > tr', function (e) {
+ var $currentGrid, $row, isRowSelected, $checks,
+ $target = $(e.target);
+
+ if ($target.closest('td').hasClass('button-column') || (e.target.type === 'checkbox' && !$target.hasClass('select-on-check'))) {
+ return;
+ }
+
+ $row = $(this);
+ $currentGrid = $('#' + id);
+ $checks = $('input.select-on-check', $currentGrid);
+ isRowSelected = $row.toggleClass('selected').hasClass('selected');
+
+ if (settings.selectableRows === 1) {
+ $row.siblings().removeClass('selected');
+ $checks.prop('checked', false);
+ }
+ $('input.select-on-check', $row).prop('checked', isRowSelected);
+ $("input.select-on-check-all", $currentGrid).prop('checked', $checks.length === $checks.filter(':checked').length);
+
+ if (settings.selectionChanged !== undefined) {
+ settings.selectionChanged(id);
+ }
+ });
+ if (settings.selectableRows > 1) {
+ $(document).on('click', '#' + id + ' .select-on-check-all', function () {
+ var $currentGrid = $('#' + id),
+ $checks = $('input.select-on-check', $currentGrid),
+ $checksAll = $('input.select-on-check-all', $currentGrid),
+ $rows = $currentGrid.children('.' + settings.tableClass).children('tbody').children();
+ if (this.checked) {
+ $rows.addClass('selected');
+ $checks.prop('checked', true);
+ $checksAll.prop('checked', true);
+ } else {
+ $rows.removeClass('selected');
+ $checks.prop('checked', false);
+ $checksAll.prop('checked', false);
+ }
+ if (settings.selectionChanged !== undefined) {
+ settings.selectionChanged(id);
+ }
+ });
+ }
+ } else {
+ $(document).on('click', '#' + id + ' .select-on-check', false);
+ }
+ });
+ },
+
+ /**
+ * Returns the key value for the specified row
+ * @param row integer the row number (zero-based index)
+ * @return string the key value
+ */
+ getKey: function (row) {
+ return this.children('.keys').children('span').eq(row).text();
+ },
+
+ /**
+ * Returns the URL that generates the grid view content.
+ * @return string the URL that generates the grid view content.
+ */
+ getUrl: function () {
+ var sUrl = gridSettings[this.attr('id')].url;
+ return sUrl || this.children('.keys').attr('title');
+ },
+
+ /**
+ * Returns the jQuery collection of the cells in the specified row.
+ * @param row integer the row number (zero-based index)
+ * @return jQuery the jQuery collection of the cells in the specified row.
+ */
+ getRow: function (row) {
+ var sClass = gridSettings[this.attr('id')].tableClass;
+ return this.children('.' + sClass).children('tbody').children('tr').eq(row).children();
+ },
+
+ /**
+ * Returns the jQuery collection of the cells in the specified column.
+ * @param column integer the column number (zero-based index)
+ * @return jQuery the jQuery collection of the cells in the specified column.
+ */
+ getColumn: function (column) {
+ var sClass = gridSettings[this.attr('id')].tableClass;
+ return this.children('.' + sClass).children('tbody').children('tr').children('td:nth-child(' + (column + 1) + ')');
+ },
+
+ /**
+ * Performs an AJAX-based update of the grid view contents.
+ * @param options map the AJAX request options (see jQuery.ajax API manual). By default,
+ * the URL to be requested is the one that generates the current content of the grid view.
+ * @return object the jQuery object
+ */
+ update: function (options) {
+ var customError;
+ if (options && options.error !== undefined) {
+ customError = options.error;
+ delete options.error;
+ }
+
+ return this.each(function () {
+ var $form,
+ $grid = $(this),
+ id = $grid.attr('id'),
+ settings = gridSettings[id];
+ $grid.addClass(settings.loadingClass);
+
+ options = $.extend({
+ type: 'GET',
+ url: $grid.yiiGridView('getUrl'),
+ success: function (data) {
+ var $data = $('<div>' + data + '</div>');
+ $grid.removeClass(settings.loadingClass);
+ $.each(settings.ajaxUpdate, function (i, el) {
+ var updateId = '#' + el;
+ $(updateId).replaceWith($(updateId, $data));
+ });
+ if (settings.afterAjaxUpdate !== undefined) {
+ settings.afterAjaxUpdate(id, data);
+ }
+ if (settings.selectableRows > 0) {
+ selectCheckedRows(id);
+ }
+ },
+ error: function (XHR, textStatus, errorThrown) {
+ var ret, err;
+ $grid.removeClass(settings.loadingClass);
+ if (XHR.readyState === 0 || XHR.status === 0) {
+ return;
+ }
+ if (customError !== undefined) {
+ ret = customError(XHR);
+ if (ret !== undefined && !ret) {
+ return;
+ }
+ }
+ switch (textStatus) {
+ case 'timeout':
+ err = 'The request timed out!';
+ break;
+ case 'parsererror':
+ err = 'Parser error!';
+ break;
+ case 'error':
+ if (XHR.status && !/^\s*$/.test(XHR.status)) {
+ err = 'Error ' + XHR.status;
+ } else {
+ err = 'Error';
+ }
+ if (XHR.responseText && !/^\s*$/.test(XHR.responseText)) {
+ err = err + ': ' + XHR.responseText;
+ }
+ break;
+ }
+
+ if (settings.ajaxUpdateError !== undefined) {
+ settings.ajaxUpdateError(XHR, textStatus, errorThrown, err);
+ } else if (err) {
+ alert(err);
+ }
+ }
+ }, options || {});
+ if (options.data !== undefined && options.type === 'GET') {
+ options.url = $.param.querystring(options.url, options.data);
+ options.data = {};
+ }
+
+ if (settings.ajaxUpdate !== false) {
+ options.url = $.param.querystring(options.url, settings.ajaxVar + '=' + id);
+ if (settings.beforeAjaxUpdate !== undefined) {
+ settings.beforeAjaxUpdate(id, options);
+ }
+ $.ajax(options);
+ } else { // non-ajax mode
+ if (options.type === 'GET') {
+ window.location.href = options.url;
+ } else { // POST mode
+ $form = $('<form action="' + options.url + '" method="post"></form>').appendTo('body');
+ if (options.data === undefined) {
+ options.data = {};
+ }
+
+ if (options.data.returnUrl === undefined) {
+ options.data.returnUrl = window.location.href;
+ }
+
+ $.each(options.data, function (name, value) {
+ $form.append($('<input type="hidden" name="t" value="" />').attr('name', name).val(value));
+ });
+ $form.submit();
+ }
+ }
+ });
+ },
+
+ /**
+ * Returns the key values of the currently selected rows.
+ * @return array the key values of the currently selected rows.
+ */
+ getSelection: function () {
+ var settings = gridSettings[this.attr('id')],
+ keys = this.find('.keys span'),
+ selection = [];
+ this.children('.' + settings.tableClass).children('tbody').children().each(function (i) {
+ if ($(this).hasClass('selected')) {
+ selection.push(keys.eq(i).text());
+ }
+ });
+ return selection;
+ },
+
+ /**
+ * Returns the key values of the currently checked rows.
+ * @param column_id string the ID of the column
+ * @return array the key values of the currently checked rows.
+ */
+ getChecked: function (column_id) {
+ var settings = gridSettings[this.attr('id')],
+ keys = this.find('.keys span'),
+ checked = [];
+ if (column_id.substring(column_id.length - 2) !== '[]') {
+ column_id = column_id + '[]';
+ }
+ this.children('.' + settings.tableClass).children('tbody').children('tr').children('td').children('input[name="' + column_id + '"]').each(function (i) {
+ if (this.checked) {
+ checked.push(keys.eq(i).text());
+ }
+ });
+ return checked;
+ }
+ };
+
+ $.fn.yiiGridView = function (method) {
+ if (methods[method]) {
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+ } else if (typeof method === 'object' || !method) {
+ return methods.init.apply(this, arguments);
+ } else {
+ $.error('Method ' + method + ' does not exist on jQuery.yiiGridView');
+ return false;
+ }
+ };
+
+/******************************************************************************
+ *** DEPRECATED METHODS
+ *** used before Yii 1.1.9
+ ******************************************************************************/
+ $.fn.yiiGridView.settings = gridSettings;
+ /**
+ * Returns the key value for the specified row
+ * @param id string the ID of the grid view container
+ * @param row integer the row number (zero-based index)
+ * @return string the key value
+ */
+ $.fn.yiiGridView.getKey = function (id, row) {
+ return $('#' + id).yiiGridView('getKey', row);
+ };
+
+ /**
+ * Returns the URL that generates the grid view content.
+ * @param id string the ID of the grid view container
+ * @return string the URL that generates the grid view content.
+ */
+ $.fn.yiiGridView.getUrl = function (id) {
+ return $('#' + id).yiiGridView('getUrl');
+ };
+
+ /**
+ * Returns the jQuery collection of the cells in the specified row.
+ * @param id string the ID of the grid view container
+ * @param row integer the row number (zero-based index)
+ * @return jQuery the jQuery collection of the cells in the specified row.
+ */
+ $.fn.yiiGridView.getRow = function (id, row) {
+ return $('#' + id).yiiGridView('getRow', row);
+ };
+
+ /**
+ * Returns the jQuery collection of the cells in the specified column.
+ * @param id string the ID of the grid view container
+ * @param column integer the column number (zero-based index)
+ * @return jQuery the jQuery collection of the cells in the specified column.
+ */
+ $.fn.yiiGridView.getColumn = function (id, column) {
+ return $('#' + id).yiiGridView('getColumn', column);
+ };
+
+ /**
+ * Performs an AJAX-based update of the grid view contents.
+ * @param id string the ID of the grid view container
+ * @param options map the AJAX request options (see jQuery.ajax API manual). By default,
+ * the URL to be requested is the one that generates the current content of the grid view.
+ */
+ $.fn.yiiGridView.update = function (id, options) {
+ $('#' + id).yiiGridView('update', options);
+ };
+
+ /**
+ * Returns the key values of the currently selected rows.
+ * @param id string the ID of the grid view container
+ * @return array the key values of the currently selected rows.
+ */
+ $.fn.yiiGridView.getSelection = function (id) {
+ return $('#' + id).yiiGridView('getSelection');
+ };
+
+ /**
+ * Returns the key values of the currently checked rows.
+ * @param id string the ID of the grid view container
+ * @param column_id string the ID of the column
+ * @return array the key values of the currently checked rows.
+ */
+ $.fn.yiiGridView.getChecked = function (id, column_id) {
+ return $('#' + id).yiiGridView('getChecked', column_id);
+ };
+})(jQuery); \ No newline at end of file
diff --git a/framework/zii/widgets/assets/gridview/loading.gif b/framework/zii/widgets/assets/gridview/loading.gif
new file mode 100644
index 0000000..5b33f7e
--- /dev/null
+++ b/framework/zii/widgets/assets/gridview/loading.gif
Binary files differ
diff --git a/framework/zii/widgets/assets/gridview/styles.css b/framework/zii/widgets/assets/gridview/styles.css
new file mode 100644
index 0000000..d304d49
--- /dev/null
+++ b/framework/zii/widgets/assets/gridview/styles.css
@@ -0,0 +1,120 @@
+.grid-view-loading
+{
+ background:url(loading.gif) no-repeat;
+}
+
+.grid-view
+{
+ padding: 15px 0;
+}
+
+.grid-view table.items
+{
+ background: white;
+ border-collapse: collapse;
+ width: 100%;
+ border: 1px #D0E3EF solid;
+}
+
+.grid-view table.items th, .grid-view table.items td
+{
+ font-size: 0.9em;
+ border: 1px white solid;
+ padding: 0.3em;
+}
+
+.grid-view table.items th
+{
+ color: white;
+ background: url("bg.gif") repeat-x scroll left top white;
+ text-align: center;
+}
+
+.grid-view table.items th a
+{
+ color: #EEE;
+ font-weight: bold;
+ text-decoration: none;
+}
+
+.grid-view table.items th a:hover
+{
+ color: #FFF;
+}
+
+.grid-view table.items th a.asc
+{
+ background:url(up.gif) right center no-repeat;
+ padding-right: 10px;
+}
+
+.grid-view table.items th a.desc
+{
+ background:url(down.gif) right center no-repeat;
+ padding-right: 10px;
+}
+
+.grid-view table.items tr.even
+{
+ background: #F8F8F8;
+}
+
+.grid-view table.items tr.odd
+{
+ background: #E5F1F4;
+}
+
+.grid-view table.items tr.selected
+{
+ background: #BCE774;
+}
+
+.grid-view table.items tr:hover
+{
+ background: #ECFBD4;
+}
+
+.grid-view .link-column img
+{
+ border: 0;
+}
+
+.grid-view .button-column
+{
+ text-align: center;
+ width: 60px;
+}
+
+.grid-view .button-column img
+{
+ border: 0;
+}
+
+.grid-view .checkbox-column
+{
+ width: 15px;
+}
+
+.grid-view .summary
+{
+ margin: 0 0 5px 0;
+ text-align: right;
+}
+
+.grid-view .pager
+{
+ margin: 5px 0 0 0;
+ text-align: right;
+}
+
+.grid-view .empty
+{
+ font-style: italic;
+}
+
+.grid-view .filters input,
+.grid-view .filters select
+{
+ width: 100%;
+ border: 1px solid #ccc;
+} \ No newline at end of file
diff --git a/framework/zii/widgets/assets/gridview/up.gif b/framework/zii/widgets/assets/gridview/up.gif
new file mode 100644
index 0000000..890b038
--- /dev/null
+++ b/framework/zii/widgets/assets/gridview/up.gif
Binary files differ
diff --git a/framework/zii/widgets/assets/gridview/update.png b/framework/zii/widgets/assets/gridview/update.png
new file mode 100644
index 0000000..438b7c1
--- /dev/null
+++ b/framework/zii/widgets/assets/gridview/update.png
Binary files differ
diff --git a/framework/zii/widgets/assets/gridview/view.png b/framework/zii/widgets/assets/gridview/view.png
new file mode 100644
index 0000000..cadbec3
--- /dev/null
+++ b/framework/zii/widgets/assets/gridview/view.png
Binary files differ
diff --git a/framework/zii/widgets/assets/listview/down.gif b/framework/zii/widgets/assets/listview/down.gif
new file mode 100644
index 0000000..a4933b8
--- /dev/null
+++ b/framework/zii/widgets/assets/listview/down.gif
Binary files differ
diff --git a/framework/zii/widgets/assets/listview/jquery.yiilistview.js b/framework/zii/widgets/assets/listview/jquery.yiilistview.js
new file mode 100644
index 0000000..682402f
--- /dev/null
+++ b/framework/zii/widgets/assets/listview/jquery.yiilistview.js
@@ -0,0 +1,114 @@
+/**
+ * jQuery Yii ListView plugin file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2010 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ * @version $Id: jquery.yiilistview.js 3296 2011-06-22 17:15:17Z qiang.xue $
+ */
+
+;(function($) {
+ /**
+ * yiiListView set function.
+ * @param options map settings for the list view. Availablel options are as follows:
+ * - ajaxUpdate: array, IDs of the containers whose content may be updated by ajax response
+ * - ajaxVar: string, the name of the GET variable indicating the ID of the element triggering the AJAX request
+ * - pagerClass: string, the CSS class for the pager container
+ * - sorterClass: string, the CSS class for the sorter container
+ * - updateSelector: string, the selector for choosing which elements can trigger ajax requests
+ * - beforeAjaxUpdate: function, the function to be called before ajax request is sent
+ * - afterAjaxUpdate: function, the function to be called after ajax response is received
+ */
+ $.fn.yiiListView = function(options) {
+ return this.each(function(){
+ var settings = $.extend({}, $.fn.yiiListView.defaults, options || {});
+ var $this = $(this);
+ var id = $this.attr('id');
+ if(settings.updateSelector == undefined) {
+ settings.updateSelector = '#'+id+' .'+settings.pagerClass.replace(/\s+/g,'.')+' a, #'+id+' .'+settings.sorterClass.replace(/\s+/g,'.')+' a';
+ }
+ $.fn.yiiListView.settings[id] = settings;
+
+ if(settings.ajaxUpdate.length > 0) {
+ $(settings.updateSelector).die('click').live('click',function(){
+ $.fn.yiiListView.update(id, {url: $(this).attr('href')});
+ return false;
+ });
+ }
+ });
+ };
+
+ $.fn.yiiListView.defaults = {
+ ajaxUpdate: [],
+ ajaxVar: 'ajax',
+ pagerClass: 'pager',
+ loadingClass: 'loading',
+ sorterClass: 'sorter'
+ // updateSelector: '#id .pager a, '#id .sort a',
+ // beforeAjaxUpdate: function(id) {},
+ // afterAjaxUpdate: function(id, data) {},
+ // url: 'ajax request URL'
+ };
+
+ $.fn.yiiListView.settings = {};
+
+ /**
+ * Returns the key value for the specified row
+ * @param id string the ID of the list view container
+ * @param index integer the zero-based index of the data item
+ * @return string the key value
+ */
+ $.fn.yiiListView.getKey = function(id, index) {
+ return $('#'+id+' > div.keys > span:eq('+index+')').text();
+ };
+
+ /**
+ * Returns the URL that generates the list view content.
+ * @param id string the ID of the list view container
+ * @return string the URL that generates the list view content.
+ */
+ $.fn.yiiListView.getUrl = function(id) {
+ var settings = $.fn.yiiListView.settings[id];
+ return settings.url || $('#'+id+' > div.keys').attr('title');
+ };
+
+ /**
+ * Performs an AJAX-based update of the list view contents.
+ * @param id string the ID of the list view container
+ * @param options map the AJAX request options (see jQuery.ajax API manual). By default,
+ * the URL to be requested is the one that generates the current content of the list view.
+ */
+ $.fn.yiiListView.update = function(id, options) {
+ var settings = $.fn.yiiListView.settings[id];
+ $('#'+id).addClass(settings.loadingClass);
+ options = $.extend({
+ type: 'GET',
+ url: $.fn.yiiListView.getUrl(id),
+ success: function(data,status) {
+ $.each(settings.ajaxUpdate, function(i,v) {
+ var id='#'+v;
+ $(id).replaceWith($(id,'<div>'+data+'</div>'));
+ });
+ if(settings.afterAjaxUpdate != undefined)
+ settings.afterAjaxUpdate(id, data);
+ $('#'+id).removeClass(settings.loadingClass);
+ },
+ error: function(XMLHttpRequest, textStatus, errorThrown) {
+ $('#'+id).removeClass(settings.loadingClass);
+ alert(XMLHttpRequest.responseText);
+ }
+ }, options || {});
+
+ if(options.data!=undefined && options.type=='GET') {
+ options.url = $.param.querystring(options.url, options.data);
+ options.data = {};
+ }
+ options.url = $.param.querystring(options.url, settings.ajaxVar+'='+id);
+
+ if(settings.beforeAjaxUpdate != undefined)
+ settings.beforeAjaxUpdate(id);
+ $.ajax(options);
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/framework/zii/widgets/assets/listview/loading.gif b/framework/zii/widgets/assets/listview/loading.gif
new file mode 100644
index 0000000..5b33f7e
--- /dev/null
+++ b/framework/zii/widgets/assets/listview/loading.gif
Binary files differ
diff --git a/framework/zii/widgets/assets/listview/styles.css b/framework/zii/widgets/assets/listview/styles.css
new file mode 100644
index 0000000..974507c
--- /dev/null
+++ b/framework/zii/widgets/assets/listview/styles.css
@@ -0,0 +1,56 @@
+.list-view-loading
+{
+ background:url(loading.gif) no-repeat;
+}
+
+.list-view .summary
+{
+ margin: 0 0 5px 0;
+ text-align: right;
+}
+
+.list-view .sorter
+{
+ margin: 0 0 5px 0;
+ text-align: right;
+}
+
+.list-view .pager
+{
+ margin: 5px 0 0 0;
+ text-align: right;
+}
+
+.list-view .sorter
+{
+ font-size: 0.9em;
+}
+
+.list-view .sorter ul
+{
+ display: inline;
+ list-style-image:none;
+ list-style-position:outside;
+ list-style-type:none;
+ margin:0;
+ padding:0;
+}
+
+.list-view .sorter li
+{
+ display: inline;
+ margin: 0 0 0 5px;
+ padding: 0;
+}
+
+.list-view .sorter a.asc
+{
+ background:url(up.gif) right center no-repeat;
+ padding-right: 10px;
+}
+
+.list-view .sorter a.desc
+{
+ background:url(down.gif) right center no-repeat;
+ padding-right: 10px;
+}
diff --git a/framework/zii/widgets/assets/listview/up.gif b/framework/zii/widgets/assets/listview/up.gif
new file mode 100644
index 0000000..890b038
--- /dev/null
+++ b/framework/zii/widgets/assets/listview/up.gif
Binary files differ
diff --git a/framework/zii/widgets/grid/CButtonColumn.php b/framework/zii/widgets/grid/CButtonColumn.php
new file mode 100644
index 0000000..7774103
--- /dev/null
+++ b/framework/zii/widgets/grid/CButtonColumn.php
@@ -0,0 +1,323 @@
+<?php
+/**
+ * CButtonColumn class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.grid.CGridColumn');
+
+/**
+ * CButtonColumn represents a grid view column that renders one or several buttons.
+ *
+ * By default, it will display three buttons, "view", "update" and "delete", which triggers the corresponding
+ * actions on the model of the row.
+ *
+ * By configuring {@link buttons} and {@link template} properties, the column can display other buttons
+ * and customize the display order of the buttons.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CButtonColumn.php 3424 2011-10-24 20:13:19Z mdomba $
+ * @package zii.widgets.grid
+ * @since 1.1
+ */
+class CButtonColumn extends CGridColumn
+{
+ /**
+ * @var array the HTML options for the data cell tags.
+ */
+ public $htmlOptions=array('class'=>'button-column');
+ /**
+ * @var array the HTML options for the header cell tag.
+ */
+ public $headerHtmlOptions=array('class'=>'button-column');
+ /**
+ * @var array the HTML options for the footer cell tag.
+ */
+ public $footerHtmlOptions=array('class'=>'button-column');
+ /**
+ * @var string the template that is used to render the content in each data cell.
+ * These default tokens are recognized: {view}, {update} and {delete}. If the {@link buttons} property
+ * defines additional buttons, their IDs are also recognized here. For example, if a button named 'preview'
+ * is declared in {@link buttons}, we can use the token '{preview}' here to specify where to display the button.
+ */
+ public $template='{view} {update} {delete}';
+ /**
+ * @var string the label for the view button. Defaults to "View".
+ * Note that the label will not be HTML-encoded when rendering.
+ */
+ public $viewButtonLabel;
+ /**
+ * @var string the image URL for the view button. If not set, an integrated image will be used.
+ * You may set this property to be false to render a text link instead.
+ */
+ public $viewButtonImageUrl;
+ /**
+ * @var string a PHP expression that is evaluated for every view button and whose result is used
+ * as the URL for the view button. In this expression, the variable
+ * <code>$row</code> the row number (zero-based); <code>$data</code> the data model for the row;
+ * and <code>$this</code> the column object.
+ */
+ public $viewButtonUrl='Yii::app()->controller->createUrl("view",array("id"=>$data->primaryKey))';
+ /**
+ * @var array the HTML options for the view button tag.
+ */
+ public $viewButtonOptions=array('class'=>'view');
+
+ /**
+ * @var string the label for the update button. Defaults to "Update".
+ * Note that the label will not be HTML-encoded when rendering.
+ */
+ public $updateButtonLabel;
+ /**
+ * @var string the image URL for the update button. If not set, an integrated image will be used.
+ * You may set this property to be false to render a text link instead.
+ */
+ public $updateButtonImageUrl;
+ /**
+ * @var string a PHP expression that is evaluated for every update button and whose result is used
+ * as the URL for the update button. In this expression, the variable
+ * <code>$row</code> the row number (zero-based); <code>$data</code> the data model for the row;
+ * and <code>$this</code> the column object.
+ */
+ public $updateButtonUrl='Yii::app()->controller->createUrl("update",array("id"=>$data->primaryKey))';
+ /**
+ * @var array the HTML options for the update button tag.
+ */
+ public $updateButtonOptions=array('class'=>'update');
+
+ /**
+ * @var string the label for the delete button. Defaults to "Delete".
+ * Note that the label will not be HTML-encoded when rendering.
+ */
+ public $deleteButtonLabel;
+ /**
+ * @var string the image URL for the delete button. If not set, an integrated image will be used.
+ * You may set this property to be false to render a text link instead.
+ */
+ public $deleteButtonImageUrl;
+ /**
+ * @var string a PHP expression that is evaluated for every delete button and whose result is used
+ * as the URL for the delete button. In this expression, the variable
+ * <code>$row</code> the row number (zero-based); <code>$data</code> the data model for the row;
+ * and <code>$this</code> the column object.
+ */
+ public $deleteButtonUrl='Yii::app()->controller->createUrl("delete",array("id"=>$data->primaryKey))';
+ /**
+ * @var array the HTML options for the view button tag.
+ */
+ public $deleteButtonOptions=array('class'=>'delete');
+ /**
+ * @var string the confirmation message to be displayed when delete button is clicked.
+ * By setting this property to be false, no confirmation message will be displayed.
+ * This property is used only if <code>$this->buttons['delete']['click']</code> is not set.
+ */
+ public $deleteConfirmation;
+ /**
+ * @var string a javascript function that will be invoked after the delete ajax call.
+ * This property is used only if <code>$this->buttons['delete']['click']</code> is not set.
+ *
+ * The function signature is <code>function(link, success, data)</code>
+ * <ul>
+ * <li><code>link</code> references the delete link.</li>
+ * <li><code>success</code> status of the ajax call, true if the ajax call was successful, false if the ajax call failed.
+ * <li><code>data</code> the data returned by the server in case of a successful call or XHR object in case of error.
+ * </ul>
+ * Note that if success is true it does not mean that the delete was successful, it only means that the ajax call was successful.
+ *
+ * Example:
+ * <pre>
+ * array(
+ * class'=>'CButtonColumn',
+ * 'afterDelete'=>'function(link,success,data){ if(success) alert("Delete completed successfuly"); }',
+ * ),
+ * </pre>
+ */
+ public $afterDelete;
+ /**
+ * @var array the configuration for additional buttons. Each array element specifies a single button
+ * which has the following format:
+ * <pre>
+ * 'buttonID' => array(
+ * 'label'=>'...', // text label of the button
+ * 'url'=>'...', // a PHP expression for generating the URL of the button
+ * 'imageUrl'=>'...', // image URL of the button. If not set or false, a text link is used
+ * 'options'=>array(...), // HTML options for the button tag
+ * 'click'=>'...', // a JS function to be invoked when the button is clicked
+ * 'visible'=>'...', // a PHP expression for determining whether the button is visible
+ * )
+ * </pre>
+ * In the PHP expression for the 'url' option and/or 'visible' option, the variable <code>$row</code>
+ * refers to the current row number (zero-based), and <code>$data</code> refers to the data model for
+ * the row.
+ *
+ * Note that in order to display these additional buttons, the {@link template} property needs to
+ * be configured so that the corresponding button IDs appear as tokens in the template.
+ */
+ public $buttons=array();
+
+ /**
+ * Initializes the column.
+ * This method registers necessary client script for the button column.
+ */
+ public function init()
+ {
+ $this->initDefaultButtons();
+
+ foreach($this->buttons as $id=>$button)
+ {
+ if(strpos($this->template,'{'.$id.'}')===false)
+ unset($this->buttons[$id]);
+ else if(isset($button['click']))
+ {
+ if(!isset($button['options']['class']))
+ $this->buttons[$id]['options']['class']=$id;
+ if(strpos($button['click'],'js:')!==0)
+ $this->buttons[$id]['click']='js:'.$button['click'];
+ }
+ }
+
+ $this->registerClientScript();
+ }
+
+ /**
+ * Initializes the default buttons (view, update and delete).
+ */
+ protected function initDefaultButtons()
+ {
+ if($this->viewButtonLabel===null)
+ $this->viewButtonLabel=Yii::t('zii','View');
+ if($this->updateButtonLabel===null)
+ $this->updateButtonLabel=Yii::t('zii','Update');
+ if($this->deleteButtonLabel===null)
+ $this->deleteButtonLabel=Yii::t('zii','Delete');
+ if($this->viewButtonImageUrl===null)
+ $this->viewButtonImageUrl=$this->grid->baseScriptUrl.'/view.png';
+ if($this->updateButtonImageUrl===null)
+ $this->updateButtonImageUrl=$this->grid->baseScriptUrl.'/update.png';
+ if($this->deleteButtonImageUrl===null)
+ $this->deleteButtonImageUrl=$this->grid->baseScriptUrl.'/delete.png';
+ if($this->deleteConfirmation===null)
+ $this->deleteConfirmation=Yii::t('zii','Are you sure you want to delete this item?');
+
+ foreach(array('view','update','delete') as $id)
+ {
+ $button=array(
+ 'label'=>$this->{$id.'ButtonLabel'},
+ 'url'=>$this->{$id.'ButtonUrl'},
+ 'imageUrl'=>$this->{$id.'ButtonImageUrl'},
+ 'options'=>$this->{$id.'ButtonOptions'},
+ );
+ if(isset($this->buttons[$id]))
+ $this->buttons[$id]=array_merge($button,$this->buttons[$id]);
+ else
+ $this->buttons[$id]=$button;
+ }
+
+ if(!isset($this->buttons['delete']['click']))
+ {
+ if(is_string($this->deleteConfirmation))
+ $confirmation="if(!confirm(".CJavaScript::encode($this->deleteConfirmation).")) return false;";
+ else
+ $confirmation='';
+
+ if(Yii::app()->request->enableCsrfValidation)
+ {
+ $csrfTokenName = Yii::app()->request->csrfTokenName;
+ $csrfToken = Yii::app()->request->csrfToken;
+ $csrf = "\n\t\tdata:{ '$csrfTokenName':'$csrfToken' },";
+ }
+ else
+ $csrf = '';
+
+ if($this->afterDelete===null)
+ $this->afterDelete='function(){}';
+
+ $this->buttons['delete']['click']=<<<EOD
+function() {
+ $confirmation
+ var th=this;
+ var afterDelete=$this->afterDelete;
+ $.fn.yiiGridView.update('{$this->grid->id}', {
+ type:'POST',
+ url:$(this).attr('href'),$csrf
+ success:function(data) {
+ $.fn.yiiGridView.update('{$this->grid->id}');
+ afterDelete(th,true,data);
+ },
+ error:function(XHR) {
+ return afterDelete(th,false,XHR);
+ }
+ });
+ return false;
+}
+EOD;
+ }
+ }
+
+ /**
+ * Registers the client scripts for the button column.
+ */
+ protected function registerClientScript()
+ {
+ $js=array();
+ foreach($this->buttons as $id=>$button)
+ {
+ if(isset($button['click']))
+ {
+ $function=CJavaScript::encode($button['click']);
+ $class=preg_replace('/\s+/','.',$button['options']['class']);
+ $js[]="jQuery('#{$this->grid->id} a.{$class}').live('click',$function);";
+ }
+ }
+
+ if($js!==array())
+ Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$this->id, implode("\n",$js));
+ }
+
+ /**
+ * Renders the data cell content.
+ * This method renders the view, update and delete buttons in the data cell.
+ * @param integer $row the row number (zero-based)
+ * @param mixed $data the data associated with the row
+ */
+ protected function renderDataCellContent($row,$data)
+ {
+ $tr=array();
+ ob_start();
+ foreach($this->buttons as $id=>$button)
+ {
+ $this->renderButton($id,$button,$row,$data);
+ $tr['{'.$id.'}']=ob_get_contents();
+ ob_clean();
+ }
+ ob_end_clean();
+ echo strtr($this->template,$tr);
+ }
+
+ /**
+ * Renders a link button.
+ * @param string $id the ID of the button
+ * @param array $button the button configuration which may contain 'label', 'url', 'imageUrl' and 'options' elements.
+ * See {@link buttons} for more details.
+ * @param integer $row the row number (zero-based)
+ * @param mixed $data the data object associated with the row
+ */
+ protected function renderButton($id,$button,$row,$data)
+ {
+ if (isset($button['visible']) && !$this->evaluateExpression($button['visible'],array('row'=>$row,'data'=>$data)))
+ return;
+ $label=isset($button['label']) ? $button['label'] : $id;
+ $url=isset($button['url']) ? $this->evaluateExpression($button['url'],array('data'=>$data,'row'=>$row)) : '#';
+ $options=isset($button['options']) ? $button['options'] : array();
+ if(!isset($options['title']))
+ $options['title']=$label;
+ if(isset($button['imageUrl']) && is_string($button['imageUrl']))
+ echo CHtml::link(CHtml::image($button['imageUrl'],$label),$url,$options);
+ else
+ echo CHtml::link($label,$url,$options);
+ }
+}
diff --git a/framework/zii/widgets/grid/CCheckBoxColumn.php b/framework/zii/widgets/grid/CCheckBoxColumn.php
new file mode 100644
index 0000000..24356ac
--- /dev/null
+++ b/framework/zii/widgets/grid/CCheckBoxColumn.php
@@ -0,0 +1,187 @@
+<?php
+/**
+ * CCheckBoxColumn class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.grid.CGridColumn');
+
+/**
+ * CCheckBoxColumn represents a grid view column of checkboxes.
+ *
+ * CCheckBoxColumn supports no selection (read-only), single selection and multiple selection.
+ * The mode is determined according to {@link selectableRows}. When in multiple selection mode, the header cell will display
+ * an additional checkbox, clicking on which will check or uncheck all of the checkboxes in the data cells.
+ *
+ * Additionally selecting a checkbox can select a grid view row (depending on {@link CGridView::selectableRows} value) if
+ * {@link selectableRows} is null (default).
+ *
+ * By default, the checkboxes rendered in data cells will have the values that are the same as
+ * the key values of the data model. One may change this by setting either {@link name} or
+ * {@link value}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CCheckBoxColumn.php 3437 2011-11-07 15:03:58Z mdomba $
+ * @package zii.widgets.grid
+ * @since 1.1
+ */
+class CCheckBoxColumn extends CGridColumn
+{
+ /**
+ * @var string the attribute name of the data model. The corresponding attribute value will be rendered
+ * in each data cell as the checkbox value. Note that if {@link value} is specified, this property will be ignored.
+ * @see value
+ */
+ public $name;
+ /**
+ * @var string a PHP expression that will be evaluated for every data cell and whose result will be rendered
+ * in each data cell as the checkbox value. In this expression, the variable
+ * <code>$row</code> the row number (zero-based); <code>$data</code> the data model for the row;
+ * and <code>$this</code> the column object.
+ */
+ public $value;
+ /**
+ * @var string a PHP expression that will be evaluated for every data cell and whose result will
+ * determine if checkbox for each data cell is checked. In this expression, the variable
+ * <code>$row</code> the row number (zero-based); <code>$data</code> the data model for the row;
+ * and <code>$this</code> the column object.
+ * @since 1.1.4
+ */
+ public $checked;
+ /**
+ * @var array the HTML options for the data cell tags.
+ */
+ public $htmlOptions=array('class'=>'checkbox-column');
+ /**
+ * @var array the HTML options for the header cell tag.
+ */
+ public $headerHtmlOptions=array('class'=>'checkbox-column');
+ /**
+ * @var array the HTML options for the footer cell tag.
+ */
+ public $footerHtmlOptions=array('class'=>'checkbox-column');
+ /**
+ * @var array the HTML options for the checkboxes.
+ */
+ public $checkBoxHtmlOptions=array();
+ /**
+ * @var integer the number of rows that can be checked.
+ * Possible values:
+ * <ul>
+ * <li>0 - the state of the checkbox cannot be changed (read-only mode)</li>
+ * <li>1 - only one row can be checked. Checking a checkbox has nothing to do with selecting the row</li>
+ * <li>2 or more - multiple checkboxes can be checked. Checking a checkbox has nothing to do with selecting the row</li>
+ * <li>null - {@link CGridView::selectableRows} is used to control how many checkboxes can be checked.
+ * Cheking a checkbox will also select the row.</li>
+ * </ul>
+ * You may also call the JavaScript function <code>$.fn.yiiGridView.getChecked(containerID,columnID)</code>
+ * to retrieve the key values of the checked rows.
+ * @since 1.1.6
+ */
+ public $selectableRows=null;
+
+ /**
+ * Initializes the column.
+ * This method registers necessary client script for the checkbox column.
+ */
+ public function init()
+ {
+ if(isset($this->checkBoxHtmlOptions['name']))
+ $name=$this->checkBoxHtmlOptions['name'];
+ else
+ {
+ $name=$this->id;
+ if(substr($name,-2)!=='[]')
+ $name.='[]';
+ $this->checkBoxHtmlOptions['name']=$name;
+ }
+ $name=strtr($name,array('['=>"\\[",']'=>"\\]"));
+
+ if($this->selectableRows===null)
+ {
+ if(isset($this->checkBoxHtmlOptions['class']))
+ $this->checkBoxHtmlOptions['class'].=' select-on-check';
+ else
+ $this->checkBoxHtmlOptions['class']='select-on-check';
+ return;
+ }
+
+ $cball=$cbcode='';
+ if($this->selectableRows==0)
+ {
+ //.. read only
+ $cbcode="return false;";
+ }
+ elseif($this->selectableRows==1)
+ {
+ //.. only one can be checked, uncheck all other
+ $cbcode="$(\"input:not(#\"+this.id+\")[name='$name']\").prop('checked',false);";
+ }
+ else
+ {
+ //.. process check/uncheck all
+ $cball=<<<CBALL
+$('#{$this->id}_all').live('click',function() {
+ var checked=this.checked;
+ $("input[name='$name']").each(function() {this.checked=checked;});
+});
+
+CBALL;
+ $cbcode="$('#{$this->id}_all').prop('checked', $(\"input[name='$name']\").length==$(\"input[name='$name']:checked\").length);";
+ }
+
+ $js=$cball;
+ $js.=<<<EOD
+$("input[name='$name']").live('click', function() {
+ $cbcode
+});
+EOD;
+ Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$this->id,$js);
+ }
+
+ /**
+ * Renders the header cell content.
+ * This method will render a checkbox in the header when {@link selectableRows} is greater than 1
+ * or in case {@link selectableRows} is null when {@link CGridView::selectableRows} is greater than 1.
+ */
+ protected function renderHeaderCellContent()
+ {
+ if($this->selectableRows===null && $this->grid->selectableRows>1)
+ echo CHtml::checkBox($this->id.'_all',false,array('class'=>'select-on-check-all'));
+ else if($this->selectableRows>1)
+ echo CHtml::checkBox($this->id.'_all',false);
+ else
+ parent::renderHeaderCellContent();
+ }
+
+ /**
+ * Renders the data cell content.
+ * This method renders a checkbox in the data cell.
+ * @param integer $row the row number (zero-based)
+ * @param mixed $data the data associated with the row
+ */
+ protected function renderDataCellContent($row,$data)
+ {
+ if($this->value!==null)
+ $value=$this->evaluateExpression($this->value,array('data'=>$data,'row'=>$row));
+ else if($this->name!==null)
+ $value=CHtml::value($data,$this->name);
+ else
+ $value=$this->grid->dataProvider->keys[$row];
+
+ $checked = false;
+ if($this->checked!==null)
+ $checked=$this->evaluateExpression($this->checked,array('data'=>$data,'row'=>$row));
+
+ $options=$this->checkBoxHtmlOptions;
+ $name=$options['name'];
+ unset($options['name']);
+ $options['value']=$value;
+ $options['id']=$this->id.'_'.$row;
+ echo CHtml::checkBox($name,$checked,$options);
+ }
+}
diff --git a/framework/zii/widgets/grid/CDataColumn.php b/framework/zii/widgets/grid/CDataColumn.php
new file mode 100644
index 0000000..74c13fe
--- /dev/null
+++ b/framework/zii/widgets/grid/CDataColumn.php
@@ -0,0 +1,144 @@
+<?php
+/**
+ * CDataColumn class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.grid.CGridColumn');
+
+/**
+ * CDataColumn represents a grid view column that is associated with a data attribute or expression.
+ *
+ * Either {@link name} or {@link value} should be specified. The former specifies
+ * a data attribute name, while the latter a PHP expression whose value should be rendered instead.
+ *
+ * The property {@link sortable} determines whether the grid view can be sorted according to this column.
+ * Note that the {@link name} should always be set if the column needs to be sortable. The {@link name}
+ * value will be used by {@link CSort} to render a clickable link in the header cell to trigger the sorting.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CDataColumn.php 3448 2011-11-18 10:21:42Z mdomba $
+ * @package zii.widgets.grid
+ * @since 1.1
+ */
+class CDataColumn extends CGridColumn
+{
+ /**
+ * @var string the attribute name of the data model. The corresponding attribute value will be rendered
+ * in each data cell. If {@link value} is specified, this property will be ignored
+ * unless the column needs to be sortable or filtered.
+ * @see value
+ * @see sortable
+ */
+ /**
+ * @var string the attribute name of the data model. Used for column sorting, filtering and to render the corresponding
+ * attribute value in each data cell. If {@link value} is specified it will be used to rendered the data cell instead of the attribute value.
+ * @see value
+ * @see sortable
+ */
+ public $name;
+ /**
+ * @var string a PHP expression that will be evaluated for every data cell and whose result will be rendered
+ * as the content of the data cells. In this expression, the variable
+ * <code>$row</code> the row number (zero-based); <code>$data</code> the data model for the row;
+ * and <code>$this</code> the column object.
+ */
+ public $value;
+ /**
+ * @var string the type of the attribute value. This determines how the attribute value is formatted for display.
+ * Valid values include those recognizable by {@link CGridView::formatter}, such as: raw, text, ntext, html, date, time,
+ * datetime, boolean, number, email, image, url. For more details, please refer to {@link CFormatter}.
+ * Defaults to 'text' which means the attribute value will be HTML-encoded.
+ */
+ public $type='text';
+ /**
+ * @var boolean whether the column is sortable. If so, the header cell will contain a link that may trigger the sorting.
+ * Defaults to true. Note that if {@link name} is not set, or if {@link name} is not allowed by {@link CSort},
+ * this property will be treated as false.
+ * @see name
+ */
+ public $sortable=true;
+ /**
+ * @var mixed the HTML code representing a filter input (eg a text field, a dropdown list)
+ * that is used for this data column. This property is effective only when
+ * {@link CGridView::filter} is set.
+ * If this property is not set, a text field will be generated as the filter input;
+ * If this property is an array, a dropdown list will be generated that uses this property value as
+ * the list options.
+ * If you don't want a filter for this data column, set this value to false.
+ * @since 1.1.1
+ */
+ public $filter;
+
+ /**
+ * Initializes the column.
+ */
+ public function init()
+ {
+ parent::init();
+ if($this->name===null)
+ $this->sortable=false;
+ if($this->name===null && $this->value===null)
+ throw new CException(Yii::t('zii','Either "name" or "value" must be specified for CDataColumn.'));
+ }
+
+ /**
+ * Renders the filter cell content.
+ * This method will render the {@link filter} as is if it is a string.
+ * If {@link filter} is an array, it is assumed to be a list of options, and a dropdown selector will be rendered.
+ * Otherwise if {@link filter} is not false, a text field is rendered.
+ * @since 1.1.1
+ */
+ protected function renderFilterCellContent()
+ {
+ if(is_string($this->filter))
+ echo $this->filter;
+ else if($this->filter!==false && $this->grid->filter!==null && $this->name!==null && strpos($this->name,'.')===false)
+ {
+ if(is_array($this->filter))
+ echo CHtml::activeDropDownList($this->grid->filter, $this->name, $this->filter, array('id'=>false,'prompt'=>''));
+ else if($this->filter===null)
+ echo CHtml::activeTextField($this->grid->filter, $this->name, array('id'=>false));
+ }
+ else
+ parent::renderFilterCellContent();
+ }
+
+ /**
+ * Renders the header cell content.
+ * This method will render a link that can trigger the sorting if the column is sortable.
+ */
+ protected function renderHeaderCellContent()
+ {
+ if($this->grid->enableSorting && $this->sortable && $this->name!==null)
+ echo $this->grid->dataProvider->getSort()->link($this->name,$this->header);
+ else if($this->name!==null && $this->header===null)
+ {
+ if($this->grid->dataProvider instanceof CActiveDataProvider)
+ echo CHtml::encode($this->grid->dataProvider->model->getAttributeLabel($this->name));
+ else
+ echo CHtml::encode($this->name);
+ }
+ else
+ parent::renderHeaderCellContent();
+ }
+
+ /**
+ * Renders the data cell content.
+ * This method evaluates {@link value} or {@link name} and renders the result.
+ * @param integer $row the row number (zero-based)
+ * @param mixed $data the data associated with the row
+ */
+ protected function renderDataCellContent($row,$data)
+ {
+ if($this->value!==null)
+ $value=$this->evaluateExpression($this->value,array('data'=>$data,'row'=>$row));
+ else if($this->name!==null)
+ $value=CHtml::value($data,$this->name);
+ echo $value===null ? $this->grid->nullDisplay : $this->grid->getFormatter()->format($value,$this->type);
+ }
+}
diff --git a/framework/zii/widgets/grid/CGridColumn.php b/framework/zii/widgets/grid/CGridColumn.php
new file mode 100644
index 0000000..b66e51e
--- /dev/null
+++ b/framework/zii/widgets/grid/CGridColumn.php
@@ -0,0 +1,193 @@
+<?php
+/**
+ * CGridColumn class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CGridColumn is the base class for all grid view column classes.
+ *
+ * A CGridColumn object represents the specification for rendering the cells in
+ * a particular grid view column.
+ *
+ * In a column, there is one header cell, multiple data cells, and an optional footer cell.
+ * Child classes may override {@link renderHeaderCellContent}, {@link renderDataCellContent}
+ * and {@link renderFooterCellContent} to customize how these cells are rendered.
+ *
+ * @property boolean $hasFooter Whether this column has a footer cell.
+ * This is determined based on whether {@link footer} is set.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CGridColumn.php 3426 2011-10-25 00:01:09Z alexander.makarow $
+ * @package zii.widgets.grid
+ * @since 1.1
+ */
+abstract class CGridColumn extends CComponent
+{
+ /**
+ * @var string the ID of this column. This value should be unique among all grid view columns.
+ * If this is set, it will be assigned one automatically.
+ */
+ public $id;
+ /**
+ * @var CGridView the grid view object that owns this column.
+ */
+ public $grid;
+ /**
+ * @var string the header cell text. Note that it will not be HTML-encoded.
+ */
+ public $header;
+ /**
+ * @var string the footer cell text. Note that it will not be HTML-encoded.
+ */
+ public $footer;
+ /**
+ * @var boolean whether this column is visible. Defaults to true.
+ */
+ public $visible=true;
+ /**
+ * @var string a PHP expression that is evaluated for every data cell and whose result
+ * is used as the CSS class name for the data cell. In this expression, the variable
+ * <code>$row</code> the row number (zero-based); <code>$data</code> the data model for the row;
+ * and <code>$this</code> the column object.
+ */
+ public $cssClassExpression;
+ /**
+ * @var array the HTML options for the data cell tags.
+ */
+ public $htmlOptions=array();
+ /**
+ * @var array the HTML options for the header cell tag.
+ */
+ public $headerHtmlOptions=array();
+ /**
+ * @var array the HTML options for the footer cell tag.
+ */
+ public $footerHtmlOptions=array();
+
+ /**
+ * Constructor.
+ * @param CGridView $grid the grid view that owns this column.
+ */
+ public function __construct($grid)
+ {
+ $this->grid=$grid;
+ }
+
+ /**
+ * Initializes the column.
+ * This method is invoked by the grid view when it initializes itself before rendering.
+ * You may override this method to prepare the column for rendering.
+ */
+ public function init()
+ {
+ }
+
+ /**
+ * @return boolean whether this column has a footer cell.
+ * This is determined based on whether {@link footer} is set.
+ */
+ public function getHasFooter()
+ {
+ return $this->footer!==null;
+ }
+
+ /**
+ * Renders the filter cell.
+ * @since 1.1.1
+ */
+ public function renderFilterCell()
+ {
+ echo "<td>";
+ $this->renderFilterCellContent();
+ echo "</td>";
+ }
+
+ /**
+ * Renders the header cell.
+ */
+ public function renderHeaderCell()
+ {
+ $this->headerHtmlOptions['id']=$this->id;
+ echo CHtml::openTag('th',$this->headerHtmlOptions);
+ $this->renderHeaderCellContent();
+ echo "</th>";
+ }
+
+ /**
+ * Renders a data cell.
+ * @param integer $row the row number (zero-based)
+ */
+ public function renderDataCell($row)
+ {
+ $data=$this->grid->dataProvider->data[$row];
+ $options=$this->htmlOptions;
+ if($this->cssClassExpression!==null)
+ {
+ $class=$this->evaluateExpression($this->cssClassExpression,array('row'=>$row,'data'=>$data));
+ if(isset($options['class']))
+ $options['class'].=' '.$class;
+ else
+ $options['class']=$class;
+ }
+ echo CHtml::openTag('td',$options);
+ $this->renderDataCellContent($row,$data);
+ echo '</td>';
+ }
+
+ /**
+ * Renders the footer cell.
+ */
+ public function renderFooterCell()
+ {
+ echo CHtml::openTag('td',$this->footerHtmlOptions);
+ $this->renderFooterCellContent();
+ echo '</td>';
+ }
+
+ /**
+ * Renders the header cell content.
+ * The default implementation simply renders {@link header}.
+ * This method may be overridden to customize the rendering of the header cell.
+ */
+ protected function renderHeaderCellContent()
+ {
+ echo trim($this->header)!=='' ? $this->header : $this->grid->blankDisplay;
+ }
+
+ /**
+ * Renders the footer cell content.
+ * The default implementation simply renders {@link footer}.
+ * This method may be overridden to customize the rendering of the footer cell.
+ */
+ protected function renderFooterCellContent()
+ {
+ echo trim($this->footer)!=='' ? $this->footer : $this->grid->blankDisplay;
+ }
+
+ /**
+ * Renders the data cell content.
+ * This method SHOULD be overridden to customize the rendering of the data cell.
+ * @param integer $row the row number (zero-based)
+ * @param mixed $data the data associated with the row
+ */
+ protected function renderDataCellContent($row,$data)
+ {
+ echo $this->grid->blankDisplay;
+ }
+
+ /**
+ * Renders the filter cell content.
+ * The default implementation simply renders a space.
+ * This method may be overridden to customize the rendering of the filter cell (if any).
+ * @since 1.1.1
+ */
+ protected function renderFilterCellContent()
+ {
+ echo $this->grid->blankDisplay;
+ }
+}
diff --git a/framework/zii/widgets/grid/CGridView.php b/framework/zii/widgets/grid/CGridView.php
new file mode 100644
index 0000000..d334c10
--- /dev/null
+++ b/framework/zii/widgets/grid/CGridView.php
@@ -0,0 +1,550 @@
+<?php
+/**
+ * CGridView class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.CBaseListView');
+Yii::import('zii.widgets.grid.CDataColumn');
+Yii::import('zii.widgets.grid.CLinkColumn');
+Yii::import('zii.widgets.grid.CButtonColumn');
+Yii::import('zii.widgets.grid.CCheckBoxColumn');
+
+/**
+ * CGridView displays a list of data items in terms of a table.
+ *
+ * Each row of the table represents the data of a single data item, and a column usually represents
+ * an attribute of the item (some columns may correspond to complex expression of attributes or static text).
+ *
+ * CGridView supports both sorting and pagination of the data items. The sorting
+ * and pagination can be done in AJAX mode or normal page request. A benefit of using CGridView is that
+ * when the user browser disables JavaScript, the sorting and pagination automatically degenerate
+ * to normal page requests and are still functioning as expected.
+ *
+ * CGridView should be used together with a {@link IDataProvider data provider}, preferrably a
+ * {@link CActiveDataProvider}.
+ *
+ * The minimal code needed to use CGridView is as follows:
+ *
+ * <pre>
+ * $dataProvider=new CActiveDataProvider('Post');
+ *
+ * $this->widget('zii.widgets.grid.CGridView', array(
+ * 'dataProvider'=>$dataProvider,
+ * ));
+ * </pre>
+ *
+ * The above code first creates a data provider for the <code>Post</code> ActiveRecord class.
+ * It then uses CGridView to display every attribute in every <code>Post</code> instance.
+ * The displayed table is equiped with sorting and pagination functionality.
+ *
+ * In order to selectively display attributes with different formats, we may configure the
+ * {@link CGridView::columns} property. For example, we may specify only the <code>title</code>
+ * and <code>create_time</code> attributes to be displayed, and the <code>create_time</code>
+ * should be properly formatted to show as a time. We may also display the attributes of the related
+ * objects using the dot-syntax as shown below:
+ *
+ * <pre>
+ * $this->widget('zii.widgets.grid.CGridView', array(
+ * 'dataProvider'=>$dataProvider,
+ * 'columns'=>array(
+ * 'title', // display the 'title' attribute
+ * 'category.name', // display the 'name' attribute of the 'category' relation
+ * 'content:html', // display the 'content' attribute as purified HTML
+ * array( // display 'create_time' using an expression
+ * 'name'=>'create_time',
+ * 'value'=>'date("M j, Y", $data->create_time)',
+ * ),
+ * array( // display 'author.username' using an expression
+ * 'name'=>'authorName',
+ * 'value'=>'$data->author->username',
+ * ),
+ * array( // display a column with "view", "update" and "delete" buttons
+ * 'class'=>'CButtonColumn',
+ * ),
+ * ),
+ * ));
+ * </pre>
+ *
+ * Please refer to {@link columns} for more details about how to configure this property.
+ *
+ * @property boolean $hasFooter Whether the table should render a footer.
+ * This is true if any of the {@link columns} has a true {@link CGridColumn::hasFooter} value.
+ * @property CFormatter $formatter The formatter instance. Defaults to the 'format' application component.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CGridView.php 3551 2012-02-02 12:45:25Z mdomba $
+ * @package zii.widgets.grid
+ * @since 1.1
+ */
+class CGridView extends CBaseListView
+{
+ const FILTER_POS_HEADER='header';
+ const FILTER_POS_FOOTER='footer';
+ const FILTER_POS_BODY='body';
+
+ private $_formatter;
+ /**
+ * @var array grid column configuration. Each array element represents the configuration
+ * for one particular grid column which can be either a string or an array.
+ *
+ * When a column is specified as a string, it should be in the format of "name:type:header",
+ * where "type" and "header" are optional. A {@link CDataColumn} instance will be created in this case,
+ * whose {@link CDataColumn::name}, {@link CDataColumn::type} and {@link CDataColumn::header}
+ * properties will be initialized accordingly.
+ *
+ * When a column is specified as an array, it will be used to create a grid column instance, where
+ * the 'class' element specifies the column class name (defaults to {@link CDataColumn} if absent).
+ * Currently, these official column classes are provided: {@link CDataColumn},
+ * {@link CLinkColumn}, {@link CButtonColumn} and {@link CCheckBoxColumn}.
+ */
+ public $columns=array();
+ /**
+ * @var array the CSS class names for the table body rows. If multiple CSS class names are given,
+ * they will be assigned to the rows sequentially and repeatedly. This property is ignored
+ * if {@link rowCssClassExpression} is set. Defaults to <code>array('odd', 'even')</code>.
+ * @see rowCssClassExpression
+ */
+ public $rowCssClass=array('odd','even');
+ /**
+ * @var string a PHP expression that is evaluated for every table body row and whose result
+ * is used as the CSS class name for the row. In this expression, the variable <code>$row</code>
+ * stands for the row number (zero-based), <code>$data</code> is the data model associated with
+ * the row, and <code>$this</code> is the grid object.
+ * @see rowCssClass
+ */
+ public $rowCssClassExpression;
+ /**
+ * @var boolean whether to display the table even when there is no data. Defaults to true.
+ * The {@link emptyText} will be displayed to indicate there is no data.
+ */
+ public $showTableOnEmpty=true;
+ /**
+ * @var mixed the ID of the container whose content may be updated with an AJAX response.
+ * Defaults to null, meaning the container for this grid view instance.
+ * If it is set false, it means sorting and pagination will be performed in normal page requests
+ * instead of AJAX requests. If the sorting and pagination should trigger the update of multiple
+ * containers' content in AJAX fashion, these container IDs may be listed here (separated with comma).
+ */
+ public $ajaxUpdate;
+ /**
+ * @var string the jQuery selector of the HTML elements that may trigger AJAX updates when they are clicked.
+ * If not set, the pagination links and the sorting links will trigger AJAX updates.
+ * @since 1.1.7
+ */
+ public $updateSelector;
+ /**
+ * @var string a javascript function that will be invoked if an AJAX update error occurs.
+ *
+ * The function signature is <code>function(xhr, textStatus, errorThrown, errorMessage)</code>
+ * <ul>
+ * <li><code>xhr</code> is the XMLHttpRequest object.</li>
+ * <li><code>textStatus</code> is a string describing the type of error that occurred.
+ * Possible values (besides null) are "timeout", "error", "notmodified" and "parsererror"</li>
+ * <li><code>errorThrown</code> is an optional exception object, if one occurred.</li>
+ * <li><code>errorMessage</code> is the CGridView default error message derived from xhr and errorThrown.
+ * Usefull if you just want to display this error differently. CGridView by default displays this error with an javascript.alert()</li>
+ * </ul>
+ * Note: This handler is not called for JSONP requests, because they do not use an XMLHttpRequest.
+ *
+ * Example (add in a call to CGridView):
+ * <pre>
+ * ...
+ * 'ajaxUpdateError'=>'function(xhr,ts,et,err){ $("#myerrordiv").text(err); }',
+ * ...
+ * </pre>
+ */
+ public $ajaxUpdateError;
+ /**
+ * @var string the name of the GET variable that indicates the request is an AJAX request triggered
+ * by this widget. Defaults to 'ajax'. This is effective only when {@link ajaxUpdate} is not false.
+ */
+ public $ajaxVar='ajax';
+ /**
+ * @var mixed the URL for the AJAX requests should be sent to. {@link CHtml::normalizeUrl()} will be
+ * called on this property. If not set, the current page URL will be used for AJAX requests.
+ * @since 1.1.8
+ */
+ public $ajaxUrl;
+ /**
+ * @var string a javascript function that will be invoked before an AJAX update occurs.
+ * The function signature is <code>function(id,options)</code> where 'id' refers to the ID of the grid view,
+ * 'options' the AJAX request options (see jQuery.ajax api manual).
+ */
+ public $beforeAjaxUpdate;
+ /**
+ * @var string a javascript function that will be invoked after a successful AJAX response is received.
+ * The function signature is <code>function(id, data)</code> where 'id' refers to the ID of the grid view,
+ * 'data' the received ajax response data.
+ */
+ public $afterAjaxUpdate;
+ /**
+ * @var string a javascript function that will be invoked after the row selection is changed.
+ * The function signature is <code>function(id)</code> where 'id' refers to the ID of the grid view.
+ * In this function, you may use <code>$.fn.yiiGridView.getSelection(id)</code> to get the key values
+ * of the currently selected rows.
+ * @see selectableRows
+ */
+ public $selectionChanged;
+ /**
+ * @var integer the number of table body rows that can be selected. If 0, it means rows cannot be selected.
+ * If 1, only one row can be selected. If 2 or any other number, it means multiple rows can be selected.
+ * A selected row will have a CSS class named 'selected'. You may also call the JavaScript function
+ * <code>$.fn.yiiGridView.getSelection(containerID)</code> to retrieve the key values of the selected rows.
+ */
+ public $selectableRows=1;
+ /**
+ * @var string the base script URL for all grid view resources (eg javascript, CSS file, images).
+ * Defaults to null, meaning using the integrated grid view resources (which are published as assets).
+ */
+ public $baseScriptUrl;
+ /**
+ * @var string the URL of the CSS file used by this grid view. Defaults to null, meaning using the integrated
+ * CSS file. If this is set false, you are responsible to explicitly include the necessary CSS file in your page.
+ */
+ public $cssFile;
+ /**
+ * @var string the text to be displayed in a data cell when a data value is null. This property will NOT be HTML-encoded
+ * when rendering. Defaults to an HTML blank.
+ */
+ public $nullDisplay='&nbsp;';
+ /**
+ * @var string the text to be displayed in an empty grid cell. This property will NOT be HTML-encoded when rendering. Defaults to an HTML blank.
+ * This differs from {@link nullDisplay} in that {@link nullDisplay} is only used by {@link CDataColumn} to render
+ * null data values.
+ * @since 1.1.7
+ */
+ public $blankDisplay='&nbsp;';
+ /**
+ * @var string the CSS class name that will be assigned to the widget container element
+ * when the widget is updating its content via AJAX. Defaults to 'grid-view-loading'.
+ * @since 1.1.1
+ */
+ public $loadingCssClass='grid-view-loading';
+ /**
+ * @var string the CSS class name for the table row element containing all filter input fields. Defaults to 'filters'.
+ * @see filter
+ * @since 1.1.1
+ */
+ public $filterCssClass='filters';
+ /**
+ * @var string whether the filters should be displayed in the grid view. Valid values include:
+ * <ul>
+ * <li>header: the filters will be displayed on top of each column's header cell.</li>
+ * <li>body: the filters will be displayed right below each column's header cell.</li>
+ * <li>footer: the filters will be displayed below each column's footer cell.</li>
+ * </ul>
+ * @see filter
+ * @since 1.1.1
+ */
+ public $filterPosition='body';
+ /**
+ * @var CModel the model instance that keeps the user-entered filter data. When this property is set,
+ * the grid view will enable column-based filtering. Each data column by default will display a text field
+ * at the top that users can fill in to filter the data.
+ * Note that in order to show an input field for filtering, a column must have its {@link CDataColumn::name}
+ * property set or have {@link CDataColumn::filter} as the HTML code for the input field.
+ * When this property is not set (null) the filtering is disabled.
+ * @since 1.1.1
+ */
+ public $filter;
+ /**
+ * @var boolean whether to hide the header cells of the grid. When this is true, header cells
+ * will not be rendered, which means the grid cannot be sorted anymore since the sort links are located
+ * in the header. Defaults to false.
+ * @since 1.1.1
+ */
+ public $hideHeader=false;
+
+ /**
+ * Initializes the grid view.
+ * This method will initialize required property values and instantiate {@link columns} objects.
+ */
+ public function init()
+ {
+ parent::init();
+
+ if(!isset($this->htmlOptions['class']))
+ $this->htmlOptions['class']='grid-view';
+
+ if($this->baseScriptUrl===null)
+ $this->baseScriptUrl=Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias('zii.widgets.assets')).'/gridview';
+
+ if($this->cssFile!==false)
+ {
+ if($this->cssFile===null)
+ $this->cssFile=$this->baseScriptUrl.'/styles.css';
+ Yii::app()->getClientScript()->registerCssFile($this->cssFile);
+ }
+
+ $this->initColumns();
+ }
+
+ /**
+ * Creates column objects and initializes them.
+ */
+ protected function initColumns()
+ {
+ if($this->columns===array())
+ {
+ if($this->dataProvider instanceof CActiveDataProvider)
+ $this->columns=$this->dataProvider->model->attributeNames();
+ else if($this->dataProvider instanceof IDataProvider)
+ {
+ // use the keys of the first row of data as the default columns
+ $data=$this->dataProvider->getData();
+ if(isset($data[0]) && is_array($data[0]))
+ $this->columns=array_keys($data[0]);
+ }
+ }
+ $id=$this->getId();
+ foreach($this->columns as $i=>$column)
+ {
+ if(is_string($column))
+ $column=$this->createDataColumn($column);
+ else
+ {
+ if(!isset($column['class']))
+ $column['class']='CDataColumn';
+ $column=Yii::createComponent($column, $this);
+ }
+ if(!$column->visible)
+ {
+ unset($this->columns[$i]);
+ continue;
+ }
+ if($column->id===null)
+ $column->id=$id.'_c'.$i;
+ $this->columns[$i]=$column;
+ }
+
+ foreach($this->columns as $column)
+ $column->init();
+ }
+
+ /**
+ * Creates a {@link CDataColumn} based on a shortcut column specification string.
+ * @param string $text the column specification string
+ * @return CDataColumn the column instance
+ */
+ protected function createDataColumn($text)
+ {
+ if(!preg_match('/^([\w\.]+)(:(\w*))?(:(.*))?$/',$text,$matches))
+ throw new CException(Yii::t('zii','The column must be specified in the format of "Name:Type:Label", where "Type" and "Label" are optional.'));
+ $column=new CDataColumn($this);
+ $column->name=$matches[1];
+ if(isset($matches[3]) && $matches[3]!=='')
+ $column->type=$matches[3];
+ if(isset($matches[5]))
+ $column->header=$matches[5];
+ return $column;
+ }
+
+ /**
+ * Registers necessary client scripts.
+ */
+ public function registerClientScript()
+ {
+ $id=$this->getId();
+
+ if($this->ajaxUpdate===false)
+ $ajaxUpdate=false;
+ else
+ $ajaxUpdate=array_unique(preg_split('/\s*,\s*/',$this->ajaxUpdate.','.$id,-1,PREG_SPLIT_NO_EMPTY));
+ $options=array(
+ 'ajaxUpdate'=>$ajaxUpdate,
+ 'ajaxVar'=>$this->ajaxVar,
+ 'pagerClass'=>$this->pagerCssClass,
+ 'loadingClass'=>$this->loadingCssClass,
+ 'filterClass'=>$this->filterCssClass,
+ 'tableClass'=>$this->itemsCssClass,
+ 'selectableRows'=>$this->selectableRows,
+ );
+ if($this->ajaxUrl!==null)
+ $options['url']=CHtml::normalizeUrl($this->ajaxUrl);
+ if($this->updateSelector!==null)
+ $options['updateSelector']=$this->updateSelector;
+ if($this->enablePagination)
+ $options['pageVar']=$this->dataProvider->getPagination()->pageVar;
+ if($this->beforeAjaxUpdate!==null)
+ $options['beforeAjaxUpdate']=(strpos($this->beforeAjaxUpdate,'js:')!==0 ? 'js:' : '').$this->beforeAjaxUpdate;
+ if($this->afterAjaxUpdate!==null)
+ $options['afterAjaxUpdate']=(strpos($this->afterAjaxUpdate,'js:')!==0 ? 'js:' : '').$this->afterAjaxUpdate;
+ if($this->ajaxUpdateError!==null)
+ $options['ajaxUpdateError']=(strpos($this->ajaxUpdateError,'js:')!==0 ? 'js:' : '').$this->ajaxUpdateError;
+ if($this->selectionChanged!==null)
+ $options['selectionChanged']=(strpos($this->selectionChanged,'js:')!==0 ? 'js:' : '').$this->selectionChanged;
+
+ $options=CJavaScript::encode($options);
+ $cs=Yii::app()->getClientScript();
+ $cs->registerCoreScript('jquery');
+ $cs->registerCoreScript('bbq');
+ $cs->registerScriptFile($this->baseScriptUrl.'/jquery.yiigridview.js',CClientScript::POS_END);
+ $cs->registerScript(__CLASS__.'#'.$id,"jQuery('#$id').yiiGridView($options);");
+ }
+
+ /**
+ * Renders the data items for the grid view.
+ */
+ public function renderItems()
+ {
+ if($this->dataProvider->getItemCount()>0 || $this->showTableOnEmpty)
+ {
+ echo "<table class=\"{$this->itemsCssClass}\">\n";
+ $this->renderTableHeader();
+ ob_start();
+ $this->renderTableBody();
+ $body=ob_get_clean();
+ $this->renderTableFooter();
+ echo $body; // TFOOT must appear before TBODY according to the standard.
+ echo "</table>";
+ }
+ else
+ $this->renderEmptyText();
+ }
+
+ /**
+ * Renders the table header.
+ */
+ public function renderTableHeader()
+ {
+ if(!$this->hideHeader)
+ {
+ echo "<thead>\n";
+
+ if($this->filterPosition===self::FILTER_POS_HEADER)
+ $this->renderFilter();
+
+ echo "<tr>\n";
+ foreach($this->columns as $column)
+ $column->renderHeaderCell();
+ echo "</tr>\n";
+
+ if($this->filterPosition===self::FILTER_POS_BODY)
+ $this->renderFilter();
+
+ echo "</thead>\n";
+ }
+ else if($this->filter!==null && ($this->filterPosition===self::FILTER_POS_HEADER || $this->filterPosition===self::FILTER_POS_BODY))
+ {
+ echo "<thead>\n";
+ $this->renderFilter();
+ echo "</thead>\n";
+ }
+ }
+
+ /**
+ * Renders the filter.
+ * @since 1.1.1
+ */
+ public function renderFilter()
+ {
+ if($this->filter!==null)
+ {
+ echo "<tr class=\"{$this->filterCssClass}\">\n";
+ foreach($this->columns as $column)
+ $column->renderFilterCell();
+ echo "</tr>\n";
+ }
+ }
+
+ /**
+ * Renders the table footer.
+ */
+ public function renderTableFooter()
+ {
+ $hasFilter=$this->filter!==null && $this->filterPosition===self::FILTER_POS_FOOTER;
+ $hasFooter=$this->getHasFooter();
+ if($hasFilter || $hasFooter)
+ {
+ echo "<tfoot>\n";
+ if($hasFooter)
+ {
+ echo "<tr>\n";
+ foreach($this->columns as $column)
+ $column->renderFooterCell();
+ echo "</tr>\n";
+ }
+ if($hasFilter)
+ $this->renderFilter();
+ echo "</tfoot>\n";
+ }
+ }
+
+ /**
+ * Renders the table body.
+ */
+ public function renderTableBody()
+ {
+ $data=$this->dataProvider->getData();
+ $n=count($data);
+ echo "<tbody>\n";
+
+ if($n>0)
+ {
+ for($row=0;$row<$n;++$row)
+ $this->renderTableRow($row);
+ }
+ else
+ {
+ echo '<tr><td colspan="'.count($this->columns).'">';
+ $this->renderEmptyText();
+ echo "</td></tr>\n";
+ }
+ echo "</tbody>\n";
+ }
+
+ /**
+ * Renders a table body row.
+ * @param integer $row the row number (zero-based).
+ */
+ public function renderTableRow($row)
+ {
+ if($this->rowCssClassExpression!==null)
+ {
+ $data=$this->dataProvider->data[$row];
+ echo '<tr class="'.$this->evaluateExpression($this->rowCssClassExpression,array('row'=>$row,'data'=>$data)).'">';
+ }
+ else if(is_array($this->rowCssClass) && ($n=count($this->rowCssClass))>0)
+ echo '<tr class="'.$this->rowCssClass[$row%$n].'">';
+ else
+ echo '<tr>';
+ foreach($this->columns as $column)
+ $column->renderDataCell($row);
+ echo "</tr>\n";
+ }
+
+ /**
+ * @return boolean whether the table should render a footer.
+ * This is true if any of the {@link columns} has a true {@link CGridColumn::hasFooter} value.
+ */
+ public function getHasFooter()
+ {
+ foreach($this->columns as $column)
+ if($column->getHasFooter())
+ return true;
+ return false;
+ }
+
+ /**
+ * @return CFormatter the formatter instance. Defaults to the 'format' application component.
+ */
+ public function getFormatter()
+ {
+ if($this->_formatter===null)
+ $this->_formatter=Yii::app()->format;
+ return $this->_formatter;
+ }
+
+ /**
+ * @param CFormatter $value the formatter instance
+ */
+ public function setFormatter($value)
+ {
+ $this->_formatter=$value;
+ }
+}
diff --git a/framework/zii/widgets/grid/CLinkColumn.php b/framework/zii/widgets/grid/CLinkColumn.php
new file mode 100644
index 0000000..2dd6c22
--- /dev/null
+++ b/framework/zii/widgets/grid/CLinkColumn.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * CLinkColumn class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.grid.CGridColumn');
+
+/**
+ * CLinkColumn represents a grid view column that renders a hyperlink in each of its data cells.
+ *
+ * The {@link label} and {@link url} properties determine how each hyperlink will be rendered.
+ * The {@link labelExpression}, {@link urlExpression} properties may be used instead if they are available.
+ * In addition, if {@link imageUrl} is set, an image link will be rendered.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CLinkColumn.php 3424 2011-10-24 20:13:19Z mdomba $
+ * @package zii.widgets.grid
+ * @since 1.1
+ */
+class CLinkColumn extends CGridColumn
+{
+ /**
+ * @var string the label to the hyperlinks in the data cells. Note that the label will not
+ * be HTML-encoded when rendering. This property is ignored if {@link labelExpression} is set.
+ * @see labelExpression
+ */
+ public $label='Link';
+ /**
+ * @var string a PHP expression that will be evaluated for every data cell and whose result will be rendered
+ * as the label of the hyperlink of the data cells. In this expression, the variable
+ * <code>$row</code> the row number (zero-based); <code>$data</code> the data model for the row;
+ * and <code>$this</code> the column object.
+ */
+ public $labelExpression;
+ /**
+ * @var string the URL to the image. If this is set, an image link will be rendered.
+ */
+ public $imageUrl;
+ /**
+ * @var string the URL of the hyperlinks in the data cells.
+ * This property is ignored if {@link urlExpression} is set.
+ * @see urlExpression
+ */
+ public $url='javascript:void(0)';
+ /**
+ * @var string a PHP expression that will be evaluated for every data cell and whose result will be rendered
+ * as the URL of the hyperlink of the data cells. In this expression, the variable
+ * <code>$row</code> the row number (zero-based); <code>$data</code> the data model for the row;
+ * and <code>$this</code> the column object.
+ */
+ public $urlExpression;
+ /**
+ * @var array the HTML options for the data cell tags.
+ */
+ public $htmlOptions=array('class'=>'link-column');
+ /**
+ * @var array the HTML options for the header cell tag.
+ */
+ public $headerHtmlOptions=array('class'=>'link-column');
+ /**
+ * @var array the HTML options for the footer cell tag.
+ */
+ public $footerHtmlOptions=array('class'=>'link-column');
+ /**
+ * @var array the HTML options for the hyperlinks
+ */
+ public $linkHtmlOptions=array();
+
+ /**
+ * Renders the data cell content.
+ * This method renders a hyperlink in the data cell.
+ * @param integer $row the row number (zero-based)
+ * @param mixed $data the data associated with the row
+ */
+ protected function renderDataCellContent($row,$data)
+ {
+ if($this->urlExpression!==null)
+ $url=$this->evaluateExpression($this->urlExpression,array('data'=>$data,'row'=>$row));
+ else
+ $url=$this->url;
+ if($this->labelExpression!==null)
+ $label=$this->evaluateExpression($this->labelExpression,array('data'=>$data,'row'=>$row));
+ else
+ $label=$this->label;
+ $options=$this->linkHtmlOptions;
+ if(is_string($this->imageUrl))
+ echo CHtml::link(CHtml::image($this->imageUrl,$label),$url,$options);
+ else
+ echo CHtml::link($label,$url,$options);
+ }
+}
diff --git a/framework/zii/widgets/jui/CJuiAccordion.php b/framework/zii/widgets/jui/CJuiAccordion.php
new file mode 100644
index 0000000..d1bc43f
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiAccordion.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * CJuiAccordion class file.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @author Qiang XUe <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiWidget');
+
+/**
+ * CJuiAccordion displays an accordion widget.
+ *
+ * CJuiAccordion encapsulates the {@link http://jqueryui.com/demos/accordion/ JUI Accordion}
+ * plugin.
+ *
+ * To use this widget, you may insert the following code in a view:
+ * <pre>
+ * $this->widget('zii.widgets.jui.CJuiAccordion', array(
+ * 'panels'=>array(
+ * 'panel 1'=>'content for panel 1',
+ * 'panel 2'=>'content for panel 2',
+ * // panel 3 contains the content rendered by a partial view
+ * 'panel 3'=>$this->renderPartial('_partial',null,true),
+ * ),
+ * // additional javascript options for the accordion plugin
+ * 'options'=>array(
+ * 'animated'=>'bounceslide',
+ * ),
+ * ));
+ * </pre>
+ *
+ * By configuring the {@link options} property, you may specify the options
+ * that need to be passed to the JUI accordion plugin. Please refer to
+ * the {@link http://jqueryui.com/demos/accordion/ JUI Accordion} documentation
+ * for possible options (name-value pairs).
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @author Qiang XUe <qiang.xue@gmail.com>
+ * @version $Id: CJuiAccordion.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package zii.widgets.jui
+ * @since 1.1
+ */
+class CJuiAccordion extends CJuiWidget
+{
+ /**
+ * @var array list of panels (panel title=>panel content).
+ * Note that neither panel title nor panel content will be HTML-encoded.
+ */
+ public $panels=array();
+ /**
+ * @var string the name of the container element that contains all panels. Defaults to 'div'.
+ */
+ public $tagName='div';
+ /**
+ * @var string the template that is used to generated every panel header.
+ * The token "{title}" in the template will be replaced with the panel title.
+ * Note that if you make change to this template, you may also need to adjust
+ * the 'header' setting in {@link options}.
+ */
+ public $headerTemplate='<h3><a href="#">{title}</a></h3>';
+ /**
+ * @var string the template that is used to generated every panel content.
+ * The token "{content}" in the template will be replaced with the panel content.
+ */
+ public $contentTemplate='<div>{content}</div>';
+
+ /**
+ * Run this widget.
+ * This method registers necessary javascript and renders the needed HTML code.
+ */
+ public function run()
+ {
+ $id=$this->getId();
+ if (isset($this->htmlOptions['id']))
+ $id = $this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+
+ echo CHtml::openTag($this->tagName,$this->htmlOptions)."\n";
+ foreach($this->panels as $title=>$content)
+ {
+ echo strtr($this->headerTemplate,array('{title}'=>$title))."\n";
+ echo strtr($this->contentTemplate,array('{content}'=>$content))."\n";
+ }
+ echo CHtml::closeTag($this->tagName);
+
+ $options=empty($this->options) ? '' : CJavaScript::encode($this->options);
+ Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').accordion($options);");
+ }
+}
diff --git a/framework/zii/widgets/jui/CJuiAutoComplete.php b/framework/zii/widgets/jui/CJuiAutoComplete.php
new file mode 100644
index 0000000..07e3ee7
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiAutoComplete.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * CJuiAutoComplete class file.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiInputWidget');
+
+/**
+ * CJuiAutoComplete displays an autocomplete field.
+ *
+ * CJuiAutoComplete encapsulates the {@link http://jqueryui.com/demos/autocomplete/ JUI
+ * autocomplete} plugin.
+ *
+ * To use this widget, you may insert the following code in a view:
+ * <pre>
+ * $this->widget('zii.widgets.jui.CJuiAutoComplete', array(
+ * 'name'=>'city',
+ * 'source'=>array('ac1', 'ac2', 'ac3'),
+ * // additional javascript options for the autocomplete plugin
+ * 'options'=>array(
+ * 'minLength'=>'2',
+ * ),
+ * 'htmlOptions'=>array(
+ * 'style'=>'height:20px;'
+ * ),
+ * ));
+ * </pre>
+ *
+ * By configuring the {@link options} property, you may specify the options
+ * that need to be passed to the JUI autocomplete plugin. Please refer to
+ * the {@link http://jqueryui.com/demos/autocomplete/ JUI
+ * autocomplete} documentation for possible options (name-value pairs).
+ *
+ * By configuring the {@link source} property, you may specify where to search
+ * the autocomplete options for each item. If source is an array, the list is
+ * used for autocomplete. You may also configure {@link sourceUrl} to retrieve
+ * autocomplete items from an ajax response.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @version $Id: CJuiAutoComplete.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package zii.widgets.jui
+ * @since 1.1.2
+ */
+class CJuiAutoComplete extends CJuiInputWidget
+{
+ /**
+ * @var mixed the entries that the autocomplete should choose from. This can be
+ * <ul>
+ * <li>an Array with local data</li>
+ * <li>a String, specifying a URL that returns JSON data as the entries.</li>
+ * <li>a javascript callback. Please make sure you prefix the callback name with "js:" in this case.</li>
+ * </ul>
+ */
+ public $source = array();
+ /**
+ * @var mixed the URL that will return JSON data as the autocomplete items.
+ * CHtml::normalizeUrl() will be applied to this property to convert the property
+ * into a proper URL. When this property is set, the {@link source} property will be ignored.
+ */
+ public $sourceUrl;
+
+ /**
+ * Run this widget.
+ * This method registers necessary javascript and renders the needed HTML code.
+ */
+ public function run()
+ {
+ list($name,$id)=$this->resolveNameID();
+
+ if(isset($this->htmlOptions['id']))
+ $id=$this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+
+ if(isset($this->htmlOptions['name']))
+ $name=$this->htmlOptions['name'];
+
+ if($this->hasModel())
+ echo CHtml::activeTextField($this->model,$this->attribute,$this->htmlOptions);
+ else
+ echo CHtml::textField($name,$this->value,$this->htmlOptions);
+
+ if($this->sourceUrl!==null)
+ $this->options['source']=CHtml::normalizeUrl($this->sourceUrl);
+ else
+ $this->options['source']=$this->source;
+
+ $options=CJavaScript::encode($this->options);
+
+ $js = "jQuery('#{$id}').autocomplete($options);";
+
+ $cs = Yii::app()->getClientScript();
+ $cs->registerScript(__CLASS__.'#'.$id, $js);
+ }
+}
diff --git a/framework/zii/widgets/jui/CJuiButton.php b/framework/zii/widgets/jui/CJuiButton.php
new file mode 100644
index 0000000..f8859f8
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiButton.php
@@ -0,0 +1,184 @@
+<?php
+/**
+ * CJuiButton class file.
+ *
+ * @author Sebastian Thierer <sebas@artfos.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiInputWidget');
+
+/**
+ * CJuiButton displays a button widget.
+ *
+ * CJuiButton encapsulates the {@link http://jqueryui.com/demos/button/ JUI Button}
+ * plugin.
+ *
+ * To use this widget as a submit button, you may insert the following code in a view:
+ * <pre>
+ * $this->widget('zii.widgets.jui.CJuiButton', array(
+ * 'name'=>'submit',
+ * 'caption'=>'Save',
+ * 'options'=>array(
+ * 'onclick'=>'js:function(){alert("Yes");}',
+ * ),
+ * ));
+ * </pre>
+ *
+ * To use this widget as a button, you may insert the following code in a view:
+ * <pre>
+ * $this->widget('zii.widgets.jui.CJuiButton',
+ * array(
+ * 'name'=>'button',
+ * 'caption'=>'Save',
+ * 'value'=>'asd',
+ * 'onclick'=>'js:function(){alert("Save button clicked"); this.blur(); return false;}',
+ * )
+ * );
+ * </pre>
+ *
+ * By configuring the {@link options} property, you may specify the options
+ * that need to be passed to the JUI button plugin. Please refer to
+ * the {@link http://jqueryui.com/demos/button/ JUI Button} documentation
+ * for possible options (name-value pairs).
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @version $Id: CJuiButton.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package zii.widgets.jui
+ * @since 1.1.3
+ */
+class CJuiButton extends CJuiInputWidget
+{
+ /**
+ * @var string The button type (possible types: submit, button, link, radio, checkbox, buttonset).
+ * "submit" is used as default.
+ */
+ public $buttonType = 'submit';
+
+ /**
+ * @var string The default html tag for the buttonset
+ */
+ public $htmlTag = 'div';
+ /**
+ * @var string The url used when a buttonType "link" is selected.
+ */
+ public $url = null;
+
+ /**
+ * @var mixed The value of the current item. Used only for "radio" and "checkbox"
+ */
+ public $value;
+
+ /**
+ * @var string The button text
+ */
+ public $caption="";
+ /**
+ * @var string The javascript function to be raised when this item is clicked (client event).
+ */
+ public $onclick;
+
+ /**
+ * (non-PHPdoc)
+ * @see framework/zii/widgets/jui/CJuiWidget::init()
+ */
+ public function init(){
+ parent::init();
+ if ($this->buttonType=='buttonset')
+ {
+ list($name,$id)=$this->resolveNameID();
+
+ if(isset($this->htmlOptions['id']))
+ $id=$this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+ if(isset($this->htmlOptions['name']))
+ $name=$this->htmlOptions['name'];
+ else
+ $this->htmlOptions['name']=$name;
+
+ echo CHtml::openTag($this->htmlTag, $this->htmlOptions);
+ }
+ }
+
+ /**
+ * (non-PHPdoc)
+ * @see framework/CWidget::run()
+ */
+ public function run()
+ {
+ $cs = Yii::app()->getClientScript();
+ list($name,$id)=$this->resolveNameID();
+
+ if(isset($this->htmlOptions['id']))
+ $id=$this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+ if(isset($this->htmlOptions['name']))
+ $name=$this->htmlOptions['name'];
+ else
+ $this->htmlOptions['name']=$name;
+
+ if ($this->buttonType=='buttonset')
+ {
+ echo CHtml::closeTag($this->htmlTag);
+ $cs->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').buttonset();");
+ }
+ else
+ {
+ switch($this->buttonType)
+ {
+ case 'submit':
+ echo CHtml::submitButton($this->caption, $this->htmlOptions) . "\n";
+ break;
+ case 'button':
+ echo CHtml::htmlButton($this->caption, $this->htmlOptions) . "\n";
+ break;
+ case 'link':
+ echo CHtml::link($this->caption, $this->url, $this->htmlOptions) . "\n";
+ break;
+ case 'radio':
+ if ($this->hasModel())
+ {
+ echo CHtml::activeRadioButton($this->model, $this->attribute, $this->htmlOptions);
+ echo CHtml::label($this->caption, CHtml::activeId($this->model, $this->attribute)) . "\n";
+ }
+ else
+ {
+ echo CHtml::radioButton($name, $this->value, $this->htmlOptions);
+ echo CHtml::label($this->caption, $id) . "\n";
+ }
+ break;
+ case 'checkbox':
+ if ($this->hasModel())
+ {
+ echo CHtml::activeCheckbox($this->model, $this->attribute, $this->htmlOptions);
+ echo CHtml::label($this->caption, CHtml::activeId($this->model, $this->attribute)) . "\n";
+ }
+ else
+ {
+ echo CHtml::checkbox($name, $this->value, $this->htmlOptions);
+ echo CHtml::label($this->caption, $id) . "\n";
+ }
+ break;
+ default:
+ throw new CException(Yii::t('zii','The button type "{type}" is not supported.',array('{type}'=>$this->buttonType)));
+ }
+
+ $options=empty($this->options) ? '' : CJavaScript::encode($this->options);
+ if (isset($this->onclick))
+ {
+ if(strpos($this->onclick,'js:')!==0)
+ $this->onclick='js:'.$this->onclick;
+ $click = CJavaScript::encode($this->onclick);
+ $cs->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').button($options).click($click);");
+ }
+ else
+ {
+ $cs->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').button($options);");
+ }
+ }
+ }
+}
diff --git a/framework/zii/widgets/jui/CJuiDatePicker.php b/framework/zii/widgets/jui/CJuiDatePicker.php
new file mode 100644
index 0000000..25c9ec4
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiDatePicker.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * CJuiDatePicker class file.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiInputWidget');
+
+/**
+ * CJuiDatePicker displays a datepicker.
+ *
+ * CJuiDatePicker encapsulates the {@link http://jqueryui.com/demos/datepicker/ JUI
+ * datepicker} plugin.
+ *
+ * To use this widget, you may insert the following code in a view:
+ * <pre>
+ * $this->widget('zii.widgets.jui.CJuiDatePicker', array(
+ * 'name'=>'publishDate',
+ * // additional javascript options for the date picker plugin
+ * 'options'=>array(
+ * 'showAnim'=>'fold',
+ * ),
+ * 'htmlOptions'=>array(
+ * 'style'=>'height:20px;'
+ * ),
+ * ));
+ * </pre>
+ *
+ * By configuring the {@link options} property, you may specify the options
+ * that need to be passed to the JUI datepicker plugin. Please refer to
+ * the {@link http://jqueryui.com/demos/datepicker/ JUI datepicker} documentation
+ * for possible options (name-value pairs).
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @version $Id: CJuiDatePicker.php 3539 2012-01-15 18:55:01Z mdomba $
+ * @package zii.widgets.jui
+ * @since 1.1
+ */
+class CJuiDatePicker extends CJuiInputWidget
+{
+ /**
+ * @var string the locale ID (eg 'fr', 'de') for the language to be used by the date picker.
+ * If this property is not set, I18N will not be involved. That is, the date picker will show in English.
+ * You can force English language by setting the language attribute as '' (empty string)
+ */
+ public $language;
+
+ /**
+ * @var string The i18n Jquery UI script file. It uses scriptUrl property as base url.
+ */
+ public $i18nScriptFile = 'jquery-ui-i18n.min.js';
+
+ /**
+ * @var array The default options called just one time per request. This options will alter every other CJuiDatePicker instance in the page.
+ * It has to be set at the first call of CJuiDatePicker widget in the request.
+ */
+ public $defaultOptions;
+
+ /**
+ * @var boolean If true, shows the widget as an inline calendar and the input as a hidden field. Use the onSelect event to update the hidden field
+ */
+ public $flat = false;
+
+ /**
+ * Run this widget.
+ * This method registers necessary javascript and renders the needed HTML code.
+ */
+ public function run()
+ {
+
+ list($name,$id)=$this->resolveNameID();
+
+ if(isset($this->htmlOptions['id']))
+ $id=$this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+ if(isset($this->htmlOptions['name']))
+ $name=$this->htmlOptions['name'];
+
+ if ($this->flat===false)
+ {
+ if($this->hasModel())
+ echo CHtml::activeTextField($this->model,$this->attribute,$this->htmlOptions);
+ else
+ echo CHtml::textField($name,$this->value,$this->htmlOptions);
+ }
+ else
+ {
+ if($this->hasModel())
+ {
+ echo CHtml::activeHiddenField($this->model,$this->attribute,$this->htmlOptions);
+ $attribute = $this->attribute;
+ $this->options['defaultDate'] = $this->model->$attribute;
+ }
+ else
+ {
+ echo CHtml::hiddenField($name,$this->value,$this->htmlOptions);
+ $this->options['defaultDate'] = $this->value;
+ }
+
+ if (!isset($this->options['onSelect']))
+ $this->options['onSelect']="js:function( selectedDate ) { jQuery('#{$id}').val(selectedDate);}";
+
+ $id = $this->htmlOptions['id'] = $id.'_container';
+ $this->htmlOptions['name'] = $name.'_container';
+
+ echo CHtml::tag('div', $this->htmlOptions, '');
+ }
+
+ $options=CJavaScript::encode($this->options);
+ $js = "jQuery('#{$id}').datepicker($options);";
+
+ if ($this->language!='' && $this->language!='en')
+ {
+ $this->registerScriptFile($this->i18nScriptFile);
+ $js = "jQuery('#{$id}').datepicker(jQuery.extend({showMonthAfterYear:false}, jQuery.datepicker.regional['{$this->language}'], {$options}));";
+ }
+
+ $cs = Yii::app()->getClientScript();
+
+ if (isset($this->defaultOptions))
+ {
+ $this->registerScriptFile($this->i18nScriptFile);
+ $cs->registerScript(__CLASS__, $this->defaultOptions!==null?'jQuery.datepicker.setDefaults('.CJavaScript::encode($this->defaultOptions).');':'');
+ }
+ $cs->registerScript(__CLASS__.'#'.$id, $js);
+
+ }
+} \ No newline at end of file
diff --git a/framework/zii/widgets/jui/CJuiDialog.php b/framework/zii/widgets/jui/CJuiDialog.php
new file mode 100644
index 0000000..56ba007
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiDialog.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * CJuiDialog class file.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiWidget');
+
+/**
+ * CJuiDialog displays a dialog widget.
+ *
+ * CJuiDialog encapsulates the {@link http://jqueryui.com/demos/dialog/ JUI Dialog}
+ * plugin.
+ *
+ * To use this widget, you may insert the following code in a view:
+ * <pre>
+ * $this->beginWidget('zii.widgets.jui.CJuiDialog', array(
+ * 'id'=>'mydialog',
+ * // additional javascript options for the dialog plugin
+ * 'options'=>array(
+ * 'title'=>'Dialog box 1',
+ * 'autoOpen'=>false,
+ * ),
+ * ));
+ *
+ * echo 'dialog content here';
+ *
+ * $this->endWidget('zii.widgets.jui.CJuiDialog');
+ *
+ * // the link that may open the dialog
+ * echo CHtml::link('open dialog', '#', array(
+ * 'onclick'=>'$("#mydialog").dialog("open"); return false;',
+ * ));
+ * </pre>
+ *
+ * By configuring the {@link options} property, you may specify the options
+ * that need to be passed to the JUI dialog plugin. Please refer to
+ * the {@link http://jqueryui.com/demos/dialog/ JUI Dialog} documentation
+ * for possible options (name-value pairs).
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @version $Id: CJuiDialog.php 2805 2011-01-03 16:33:46Z qiang.xue $
+ * @package zii.widgets.jui
+ * @since 1.1
+ */
+class CJuiDialog extends CJuiWidget
+{
+ /**
+ * @var string the name of the container element that contains all panels. Defaults to 'div'.
+ */
+ public $tagName='div';
+
+ /**
+ * Renders the open tag of the dialog.
+ * This method also registers the necessary javascript code.
+ */
+ public function init()
+ {
+ parent::init();
+
+ $id=$this->getId();
+ if (isset($this->htmlOptions['id']))
+ $id = $this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+
+ $options=empty($this->options) ? '' : CJavaScript::encode($this->options);
+ Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').dialog($options);");
+ echo CHtml::openTag($this->tagName,$this->htmlOptions)."\n";
+ }
+
+ /**
+ * Renders the close tag of the dialog.
+ */
+ public function run()
+ {
+ echo CHtml::closeTag($this->tagName);
+ }
+}
diff --git a/framework/zii/widgets/jui/CJuiDraggable.php b/framework/zii/widgets/jui/CJuiDraggable.php
new file mode 100644
index 0000000..67947e2
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiDraggable.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * CJuiDraggable class file.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiWidget');
+
+/**
+ * CJuiDraggable displays a draggable widget.
+ *
+ * CJuiDraggable encapsulates the {@link http://jqueryui.com/demos/draggable/ JUI Draggable}
+ * plugin.
+ *
+ * To use this widget, you may insert the following code in a view:
+ * <pre>
+ * $this->beginWidget('zii.widgets.jui.CJuiDraggable', array(
+ * // additional javascript options for the draggable plugin
+ * 'options'=>array(
+ * 'scope'=>'myScope',
+ * ),
+ * ));
+ * echo 'Your draggable content here';
+ *
+ * $this->endWidget();
+ *
+ * </pre>
+ *
+ * By configuring the {@link options} property, you may specify the options
+ * that need to be passed to the JUI Draggable plugin. Please refer to
+ * the {@link http://jqueryui.com/demos/draggable/ JUI Draggable} documentation
+ * for possible options (name-value pairs).
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @version $Id: CJuiDraggable.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package zii.widgets.jui
+ * @since 1.1
+ */
+class CJuiDraggable extends CJuiWidget
+{
+ /**
+ * @var string the name of the Draggable element. Defaults to 'div'.
+ */
+ public $tagName='div';
+
+ /**
+ * Renders the open tag of the draggable element.
+ * This method also registers the necessary javascript code.
+ */
+ public function init(){
+ parent::init();
+
+ $id=$this->getId();
+ if (isset($this->htmlOptions['id']))
+ $id = $this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+
+ $options=empty($this->options) ? '' : CJavaScript::encode($this->options);
+ Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').draggable($options);");
+
+ echo CHtml::openTag($this->tagName,$this->htmlOptions)."\n";
+ }
+
+ /**
+ * Renders the close tag of the draggable element.
+ */
+ public function run(){
+ echo CHtml::closeTag($this->tagName);
+ }
+
+}
+
+
diff --git a/framework/zii/widgets/jui/CJuiDroppable.php b/framework/zii/widgets/jui/CJuiDroppable.php
new file mode 100644
index 0000000..0c5f4cd
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiDroppable.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * CJuiDroppable class file.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiWidget');
+
+/**
+ * CJuiDroppable displays a droppable widget.
+ *
+ * CJuiDroppable encapsulates the {@link http://jqueryui.com/demos/droppable/ JUI Droppable}
+ * plugin.
+ *
+ * To use this widget, you may insert the following code in a view:
+ * <pre>
+ * $this->beginWidget('zii.widgets.jui.CJuiDroppable', array(
+ * // additional javascript options for the droppable plugin
+ * 'options'=>array(
+ * 'scope'=>'myScope',
+ * ),
+ * ));
+ * echo 'Your droppable content here';
+ *
+ * $this->endWidget();
+ *
+ * </pre>
+ *
+ * By configuring the {@link options} property, you may specify the options
+ * that need to be passed to the JUI Droppable plugin. Please refer to
+ * the {@link http://jqueryui.com/demos/droppable/ JUI Droppable} documentation
+ * for possible options (name-value pairs).
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @version $Id: CJuiDroppable.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package zii.widgets.jui
+ * @since 1.1
+ */
+class CJuiDroppable extends CJuiWidget
+{
+ /**
+ * @var string the HTML tag name of the Droppable element. Defaults to 'div'.
+ */
+ public $tagName='div';
+
+ /**
+ * Renders the open tag of the droppable element.
+ * This method also registers the necessary javascript code.
+ */
+ public function init()
+ {
+ parent::init();
+ $id=$this->getId();
+ if (isset($this->htmlOptions['id']))
+ $id = $this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+
+ echo CHtml::openTag($this->tagName,$this->htmlOptions)."\n";
+
+ $options=empty($this->options) ? '' : CJavaScript::encode($this->options);
+ Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').droppable($options);");
+ }
+
+ /**
+ * Renders the close tag of the droppable element.
+ */
+ public function run(){
+ echo CHtml::closeTag($this->tagName);
+ }
+
+}
+
+
diff --git a/framework/zii/widgets/jui/CJuiInputWidget.php b/framework/zii/widgets/jui/CJuiInputWidget.php
new file mode 100644
index 0000000..971ecfa
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiInputWidget.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * CJuiInputWidget class file.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiWidget');
+
+/**
+ * CJuiInputWidget is the base class for JUI widgets that can collect user input.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @version $Id: CJuiInputWidget.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package zii.widgets.jui
+ * @since 1.1
+ */
+abstract class CJuiInputWidget extends CJuiWidget
+{
+ /**
+ * @var CModel the data model associated with this widget.
+ */
+ public $model;
+ /**
+ * @var string the attribute associated with this widget.
+ * The name can contain square brackets (e.g. 'name[1]') which is used to collect tabular data input.
+ */
+ public $attribute;
+ /**
+ * @var string the input name. This must be set if {@link model} is not set.
+ */
+ public $name;
+ /**
+ * @var string the input value
+ */
+ public $value;
+
+
+ /**
+ * @return array the name and the ID of the input.
+ */
+ protected function resolveNameID()
+ {
+ if($this->name!==null)
+ $name=$this->name;
+ else if(isset($this->htmlOptions['name']))
+ $name=$this->htmlOptions['name'];
+ else if($this->hasModel())
+ $name=CHtml::activeName($this->model,$this->attribute);
+ else
+ throw new CException(Yii::t('zii','{class} must specify "model" and "attribute" or "name" property values.',array('{class}'=>get_class($this))));
+
+ if(($id=$this->getId(false))===null)
+ {
+ if(isset($this->htmlOptions['id']))
+ $id=$this->htmlOptions['id'];
+ else
+ $id=CHtml::getIdByName($name);
+ }
+
+ return array($name,$id);
+ }
+
+ /**
+ * @return boolean whether this widget is associated with a data model.
+ */
+ protected function hasModel()
+ {
+ return $this->model instanceof CModel && $this->attribute!==null;
+ }
+}
diff --git a/framework/zii/widgets/jui/CJuiProgressBar.php b/framework/zii/widgets/jui/CJuiProgressBar.php
new file mode 100644
index 0000000..24ca6dc
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiProgressBar.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * CJuiProgressBar class file.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiWidget');
+
+/**
+ * CJuiProgressBar displays a progress bar widget.
+ *
+ * CJuiProgressBar encapsulates the {@link http://jqueryui.com/demos/progressbar/ JUI
+ * Progressbar} plugin.
+ *
+ * To use this widget, you may insert the following code in a view:
+ * <pre>
+ * $this->widget('zii.widgets.jui.CJuiProgressBar', array(
+ * 'value'=>75,
+ * // additional javascript options for the progress bar plugin
+ * 'options'=>array(
+ * 'change'=>'js:function(event, ui) {...}',
+ * ),
+ * 'htmlOptions'=>array(
+ * 'style'=>'height:20px;'
+ * ),
+ * ));
+ * </pre>
+ *
+ * By configuring the {@link options} property, you may specify the options
+ * that need to be passed to the JUI progressbar plugin. Please refer to
+ * the {@link http://jqueryui.com/demos/progressbar/ JUI Progressbar} documentation
+ * for possible options (name-value pairs).
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @version $Id: CJuiProgressBar.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package zii.widgets.jui
+ * @since 1.1
+ */
+class CJuiProgressBar extends CJuiWidget
+{
+ /**
+ * @var string the name of the container element that contains the progress bar. Defaults to 'div'.
+ */
+ public $tagName = 'div';
+ /**
+ * @var integer the percentage of the progress. This must be an integer between 0 and 100. Defaults to 0.
+ */
+ public $value = 0;
+
+ /**
+ * Run this widget.
+ * This method registers necessary javascript and renders the needed HTML code.
+ */
+ public function run()
+ {
+ $id=$this->getId();
+ if (isset($this->htmlOptions['id']))
+ $id = $this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+
+ echo CHtml::openTag($this->tagName,$this->htmlOptions);
+ echo CHtml::closeTag($this->tagName);
+
+ $this->options['value']=$this->value;
+ $options=CJavaScript::encode($this->options);
+ Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').progressbar($options);");
+ }
+
+} \ No newline at end of file
diff --git a/framework/zii/widgets/jui/CJuiResizable.php b/framework/zii/widgets/jui/CJuiResizable.php
new file mode 100644
index 0000000..fd41210
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiResizable.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * CJuiResizable class file.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiWidget');
+
+/**
+ * CJuiResizable displays a resizable widget.
+ *
+ * CJuiResizable encapsulates the {@link http://jqueryui.com/demos/resizable/ JUI Resizable}
+ * plugin.
+ *
+ * To use this widget, you may insert the following code in a view:
+ * <pre>
+ * $this->beginWidget('zii.widgets.jui.CJuiResizable', array(
+ * // additional javascript options for the resizable plugin
+ * 'options'=>array(
+ * 'minHeight'=>'150',
+ * ),
+ * ));
+ * echo 'Your Resizable content here';
+ *
+ * $this->endWidget();
+ *
+ * </pre>
+ *
+ * By configuring the {@link options} property, you may specify the options
+ * that need to be passed to the JUI Resizable plugin. Please refer to
+ * the {@link http://jqueryui.com/demos/resizable/ JUI Resizable} documentation
+ * for possible options (name-value pairs).
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @version $Id: CJuiResizable.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package zii.widgets.jui
+ * @since 1.1
+ */
+class CJuiResizable extends CJuiWidget
+{
+ /**
+ * @var string the name of the Resizable element. Defaults to 'div'.
+ */
+ public $tagName='div';
+
+ /**
+ * Renders the open tag of the resizable element.
+ * This method also registers the necessary javascript code.
+ */
+ public function init()
+ {
+ parent::init();
+ $id=$this->getId();
+ if (isset($this->htmlOptions['id']))
+ $id = $this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+
+ $options=empty($this->options) ? '' : CJavaScript::encode($this->options);
+
+ Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').resizable($options);");
+
+ echo CHtml::openTag($this->tagName,$this->htmlOptions)."\n";
+ }
+
+ /**
+ * Renders the close tag of the resizable element.
+ */
+ public function run(){
+ echo CHtml::closeTag($this->tagName);
+ }
+
+}
+
+
diff --git a/framework/zii/widgets/jui/CJuiSelectable.php b/framework/zii/widgets/jui/CJuiSelectable.php
new file mode 100644
index 0000000..426a359
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiSelectable.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * CJuiSelectable class file.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiWidget');
+
+/**
+ * CJuiSelectable displays an accordion widget.
+ *
+ * CJuiSelectable encapsulates the {@link http://jqueryui.com/demos/selectable/ JUI Selectable}
+ * plugin.
+ *
+ * To use this widget, you may insert the following code in a view:
+ * <pre>
+ * $this->widget('zii.widgets.jui.CJuiSelectable', array(
+ * 'items'=>array(
+ * 'id1'=>'Item 1',
+ * 'id2'=>'Item 2',
+ * 'id3'=>'Item 3',
+ * ),
+ * // additional javascript options for the selectable plugin
+ * 'options'=>array(
+ * 'delay'=>'300',
+ * ),
+ * ));
+ * </pre>
+ *
+ * By configuring the {@link options} property, you may specify the options
+ * that need to be passed to the JUI Selectable plugin. Please refer to
+ * the {@link http://jqueryui.com/demos/selectable/ JUI Selectable} documentation
+ * for possible options (name-value pairs).
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @version $Id: CJuiSelectable.php 3207 2011-05-12 08:05:26Z mdomba $
+ * @package zii.widgets.jui
+ * @since 1.1
+ */
+class CJuiSelectable extends CJuiWidget {
+ /**
+ * @var array list of selectable items (id=>item content).
+ * Note that the item contents will not be HTML-encoded.
+ */
+ public $items=array();
+ /**
+ * @var string the name of the container element that contains all items. Defaults to 'ol'.
+ */
+ public $tagName='ol';
+ /**
+ * @var string the template that is used to generated every selectable item.
+ * The token "{content}" in the template will be replaced with the item content,
+ * while "{id}" will be replaced with the item ID.
+ */
+ public $itemTemplate='<li id="{id}">{content}</li>';
+
+ /**
+ * Run this widget.
+ * This method registers necessary javascript and renders the needed HTML code.
+ */
+ public function run(){
+ $id=$this->getId();
+ if (isset($this->htmlOptions['id']))
+ $id = $this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+
+ $options=empty($this->options) ? '' : CJavaScript::encode($this->options);
+ Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').selectable({$options});");
+
+ echo CHtml::openTag($this->tagName,$this->htmlOptions)."\n";
+ foreach($this->items as $id=>$content)
+ {
+ echo strtr($this->itemTemplate,array('{id}'=>$id,'{content}'=>$content))."\n";
+ }
+ echo CHtml::closeTag($this->tagName);
+ }
+}
+
+
diff --git a/framework/zii/widgets/jui/CJuiSlider.php b/framework/zii/widgets/jui/CJuiSlider.php
new file mode 100644
index 0000000..240f305
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiSlider.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * CJuiSlider class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiWidget');
+
+/**
+ * CJuiSlider displays a slider.
+ *
+ * CJuiSlider encapsulates the {@link http://jqueryui.com/demos/slider/ JUI
+ * slider} plugin.
+ *
+ * To use this widget, you may insert the following code in a view:
+ * <pre>
+ * $this->widget('zii.widgets.jui.CJuiSlider', array(
+ * 'value'=>37,
+ * // additional javascript options for the slider plugin
+ * 'options'=>array(
+ * 'min'=>10,
+ * 'max'=>50,
+ * ),
+ * 'htmlOptions'=>array(
+ * 'style'=>'height:20px;'
+ * ),
+ * ));
+ * </pre>
+ *
+ * By configuring the {@link options} property, you may specify the options
+ * that need to be passed to the JUI slider plugin. Please refer to
+ * the {@link http://jqueryui.com/demos/slider/ JUI slider} documentation
+ * for possible options (name-value pairs).
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CJuiSlider.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package zii.widgets.jui
+ * @since 1.1
+ */
+class CJuiSlider extends CJuiWidget
+{
+ /**
+ * @var string the name of the container element that contains the slider. Defaults to 'div'.
+ */
+ public $tagName = 'div';
+ /**
+ * @var integer determines the value of the slider, if there's only one handle. If there is more than one handle, determines the value of the first handle.
+ */
+ public $value;
+
+ /**
+ * Run this widget.
+ * This method registers necessary javascript and renders the needed HTML code.
+ */
+ public function run()
+ {
+ $id=$this->getId();
+ if (isset($this->htmlOptions['id']))
+ $id = $this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+
+ echo CHtml::openTag($this->tagName,$this->htmlOptions);
+ echo CHtml::closeTag($this->tagName);
+
+ if($this->value!==null)
+ $this->options['value']=$this->value;
+
+ $options=empty($this->options) ? '' : CJavaScript::encode($this->options);
+ Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').slider($options);");
+ }
+} \ No newline at end of file
diff --git a/framework/zii/widgets/jui/CJuiSliderInput.php b/framework/zii/widgets/jui/CJuiSliderInput.php
new file mode 100644
index 0000000..dfd3aaf
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiSliderInput.php
@@ -0,0 +1,148 @@
+<?php
+/**
+ * CJuiSliderInput class file.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiInputWidget');
+
+/**
+ * CJuiSliderInput displays a slider. It can be used in forms and post its value.
+ *
+ * CJuiSlider encapsulates the {@link http://jqueryui.com/demos/slider/ JUI
+ * slider} plugin.
+ *
+ * To use this widget, you may insert the following code in a view:
+ * <pre>
+ * $this->widget('zii.widgets.jui.CJuiSliderInput', array(
+ * 'name'=>'rate',
+ * 'value'=>37,
+ * // additional javascript options for the slider plugin
+ * 'options'=>array(
+ * 'min'=>10,
+ * 'max'=>50,
+ * ),
+ * 'htmlOptions'=>array(
+ * 'style'=>'height:20px;'
+ * ),
+ * ));
+ * </pre>
+ *
+ * The widget can also be used in range mode which uses 2 sliders to set a range.
+ * In this mode, {@link attribute} and {@link maxAttribute} will define the attribute
+ * names for the minimum and maximum range values, respectively. For example:
+ *
+ * <pre>
+ * $this->widget('zii.widgets.jui.CJuiSliderInput', array(
+ * 'model'=>$model,
+ * 'attribute'=>'timeMin',
+ * 'maxAttribute'=>'timeMax,
+ * // additional javascript options for the slider plugin
+ * 'options'=>array(
+ * 'range'=>true,
+ * 'min'=>0,
+ * 'max'=>24,
+ * ),
+ * ));
+ *
+ * If you need to use the slider event, please change the event value for 'stop' or 'change'.
+ *
+ * By configuring the {@link options} property, you may specify the options
+ * that need to be passed to the JUI slider plugin. Please refer to
+ * the {@link http://jqueryui.com/demos/slider/ JUI slider} documentation
+ * for possible options (name-value pairs).
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @version $Id: CJuiSliderInput.php 2948 2011-02-09 13:27:05Z haertl.mike $
+ * @package zii.widgets.jui
+ * @since 1.1
+ */
+class CJuiSliderInput extends CJuiInputWidget
+{
+ /**
+ * @var string the name of the container element that contains the slider. Defaults to 'div'.
+ */
+ public $tagName = 'div';
+ /**
+ * @var integer determines the value of the slider, if there's only one handle. If there is more than one handle, determines the value of the first handle.
+ */
+ public $value;
+
+ /**
+ * @var string the name of the event where the input will be attached to the slider. It
+ * can be 'slide', 'stop' or 'change'. If you want to use 'slide' event change $event property to 'change'
+ */
+ public $event = 'slide';
+
+ /**
+ * @var string name of attribute for max value if slider is used in range mode
+ */
+ public $maxAttribute;
+
+ /**
+ * Run this widget.
+ * This method registers necessary javascript and renders the needed HTML code.
+ */
+ public function run()
+ {
+ list($name,$id)=$this->resolveNameID();
+
+ $isRange=isset($this->options['range']) && $this->options['range'];
+
+ if(isset($this->htmlOptions['id']))
+ $id=$this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+ if(isset($this->htmlOptions['name']))
+ $name=$this->htmlOptions['name'];
+
+ if($this->hasModel())
+ {
+ $attribute=$this->attribute;
+ if ($isRange)
+ {
+ $options=$this->htmlOptions;
+ echo CHtml::activeHiddenField($this->model,$this->attribute,$options);
+ $options['id']=$options['id'].'_end';
+ echo CHtml::activeHiddenField($this->model,$this->maxAttribute,$options);
+ $attrMax=$this->maxAttribute;
+ $this->options['values']=array($this->model->$attribute,$this->model->$attrMax);
+ }
+ else
+ {
+ echo CHtml::activeHiddenField($this->model,$this->attribute,$this->htmlOptions);
+ $this->options['value']=$this->model->$attribute;
+ }
+ }
+ else
+ {
+ echo CHtml::hiddenField($name,$this->value,$this->htmlOptions);
+ if($this->value!==null)
+ $this->options['value']=$this->value;
+ }
+
+
+ $idHidden = $this->htmlOptions['id'];
+ $nameHidden = $name;
+
+ $this->htmlOptions['id']=$idHidden.'_slider';
+ $this->htmlOptions['name']=$nameHidden.'_slider';
+
+ echo CHtml::openTag($this->tagName,$this->htmlOptions);
+ echo CHtml::closeTag($this->tagName);
+
+ $this->options[$this->event]= $isRange ?
+ "js:function(e,ui){ v=ui.values; jQuery('#{$idHidden}').val(v[0]); jQuery('#{$idHidden}_end').val(v[1]); }":
+ 'js:function(event, ui) { jQuery(\'#'. $idHidden .'\').val(ui.value); }';
+
+ $options=empty($this->options) ? '' : CJavaScript::encode($this->options);
+
+ $js = "jQuery('#{$id}_slider').slider($options);\n";
+ Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id, $js);
+ }
+
+}
diff --git a/framework/zii/widgets/jui/CJuiSortable.php b/framework/zii/widgets/jui/CJuiSortable.php
new file mode 100644
index 0000000..7204814
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiSortable.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * CJuiSortable class file.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiWidget');
+
+/**
+ * CJuiSortable makes selected elements sortable by dragging with the mouse.
+ *
+ * CJuiSortable encapsulates the {@link http://jqueryui.com/demos/sortable/ JUI Sortable}
+ * plugin.
+ *
+ * To use this widget, you may insert the following code in a view:
+ * <pre>
+ * $this->widget('zii.widgets.jui.CJuiSortable', array(
+ * 'items'=>array(
+ * 'id1'=>'Item 1',
+ * 'id2'=>'Item 2',
+ * 'id3'=>'Item 3',
+ * ),
+ * // additional javascript options for the accordion plugin
+ * 'options'=>array(
+ * 'delay'=>'300',
+ * ),
+ * ));
+ * </pre>
+ *
+ * By configuring the {@link options} property, you may specify the options
+ * that need to be passed to the JUI Sortable plugin. Please refer to
+ * the {@link http://jqueryui.com/demos/sortable/ JUI Sortable} documentation
+ * for possible options (name-value pairs).
+ *
+ * If you are using javascript code anywhere in the code, please add "js:" at the
+ * start of the js code definition and Yii will use this string as js code.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @version $Id: CJuiSortable.php 3217 2011-05-12 23:59:50Z alexander.makarow $
+ * @package zii.widgets.jui
+ * @since 1.1
+ */
+class CJuiSortable extends CJuiWidget
+{
+ /**
+ * @var array list of sortable items (id=>item content).
+ * Note that the item contents will not be HTML-encoded.
+ */
+ public $items=array();
+ /**
+ * @var string the name of the container element that contains all items. Defaults to 'ul'.
+ */
+ public $tagName='ul';
+ /**
+ * @var string the template that is used to generated every sortable item.
+ * The token "{content}" in the template will be replaced with the item content,
+ * while "{id}" be replaced with the item ID.
+ */
+ public $itemTemplate='<li id="{id}">{content}</li>';
+
+ /**
+ * Run this widget.
+ * This method registers necessary javascript and renders the needed HTML code.
+ */
+ public function run()
+ {
+ $id=$this->getId();
+ if (isset($this->htmlOptions['id']))
+ $id = $this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+
+ $options=empty($this->options) ? '' : CJavaScript::encode($this->options);
+ Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').sortable({$options});");
+
+ echo CHtml::openTag($this->tagName,$this->htmlOptions)."\n";
+ foreach($this->items as $id=>$content)
+ {
+ echo strtr($this->itemTemplate,array('{id}'=>$id,'{content}'=>$content))."\n";
+ }
+ echo CHtml::closeTag($this->tagName);
+ }
+}
+
+
diff --git a/framework/zii/widgets/jui/CJuiTabs.php b/framework/zii/widgets/jui/CJuiTabs.php
new file mode 100644
index 0000000..b4ea8e1
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiTabs.php
@@ -0,0 +1,135 @@
+<?php
+/**
+ * CJuiTabs class file.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+Yii::import('zii.widgets.jui.CJuiWidget');
+
+/**
+ * CJuiTabs displays a tabs widget.
+ *
+ * CJuiTabs encapsulates the {@link http://jqueryui.com/demos/tabs/ JUI tabs}
+ * plugin.
+ *
+ * To use this widget, you may insert the following code in a view:
+ * <pre>
+ * $this->widget('zii.widgets.jui.CJuiTabs', array(
+ * 'tabs'=>array(
+ * 'StaticTab 1'=>'Content for tab 1',
+ * 'StaticTab 2'=>array('content'=>'Content for tab 2', 'id'=>'tab2'),
+ * // panel 3 contains the content rendered by a partial view
+ * 'AjaxTab'=>array('ajax'=>$ajaxUrl),
+ * ),
+ * // additional javascript options for the tabs plugin
+ * 'options'=>array(
+ * 'collapsible'=>true,
+ * ),
+ * ));
+ * </pre>
+ *
+ * By configuring the {@link options} property, you may specify the options
+ * that need to be passed to the JUI tabs plugin. Please refer to
+ * the {@link http://jqueryui.com/demos/tabs/ JUI tabs} documentation
+ * for possible options (name-value pairs).
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @version $Id: CJuiTabs.php 3400 2011-09-22 00:47:39Z sebathi $
+ * @package zii.widgets.jui
+ * @since 1.1
+ */
+class CJuiTabs extends CJuiWidget
+{
+ /**
+ * @var array list of tabs (tab title=>tab content).
+ * Note that the tab title will not be HTML-encoded.
+ * The tab content can be either a string or an array. When it is an array, it can
+ * be in one of the following two formats:
+ * <pre>
+ * array('id'=>'myTabID', 'content'=>'tab content')
+ * array('id'=>'myTabID', 'ajax'=>URL)
+ * </pre>
+ * where the 'id' element is optional. The second format allows the tab content
+ * to be dynamically fetched from the specified URL via AJAX. The URL can be either
+ * a string or an array. If an array, it will be normalized into a URL using {@link CHtml::normalizeUrl}.
+ */
+ public $tabs=array();
+ /**
+ * @var string the name of the container element that contains all panels. Defaults to 'div'.
+ */
+ public $tagName='div';
+ /**
+ * @var string the template that is used to generated every panel title.
+ * The token "{title}" in the template will be replaced with the panel title and
+ * the token "{url}" will be replaced with "#TabID" or with the url of the ajax request.
+ */
+ public $headerTemplate='<li><a href="{url}" title="{id}">{title}</a></li>';
+ /**
+ * @var string the template that is used to generated every tab content.
+ * The token "{content}" in the template will be replaced with the panel content
+ * and the token "{id}" with the tab ID.
+ */
+ public $contentTemplate='<div id="{id}">{content}</div>';
+
+ /**
+ * Run this widget.
+ * This method registers necessary javascript and renders the needed HTML code.
+ */
+ public function run()
+ {
+ $id=$this->getId();
+ if (isset($this->htmlOptions['id']))
+ $id = $this->htmlOptions['id'];
+ else
+ $this->htmlOptions['id']=$id;
+
+ echo CHtml::openTag($this->tagName,$this->htmlOptions)."\n";
+
+ $tabsOut = "";
+ $contentOut = "";
+ $tabCount = 0;
+
+ foreach($this->tabs as $title=>$content)
+ {
+ $tabId = (is_array($content) && isset($content['id']))?$content['id']:$id.'_tab_'.$tabCount++;
+
+ if (!is_array($content))
+ {
+ $tabsOut .= strtr($this->headerTemplate, array('{title}'=>$title, '{url}'=>'#'.$tabId, '{id}'=>'#' . $tabId))."\n";
+ $contentOut .= strtr($this->contentTemplate, array('{content}'=>$content,'{id}'=>$tabId))."\n";
+ }
+ elseif (isset($content['ajax']))
+ {
+ $tabsOut .= strtr($this->headerTemplate, array('{title}'=>$title, '{url}'=>CHtml::normalizeUrl($content['ajax']), '{id}'=>'#' . $tabId))."\n";
+ }
+ else
+ {
+ $tabsOut .= strtr($this->headerTemplate, array('{title}'=>$title, '{url}'=>'#'.$tabId, '{id}'=>$tabId))."\n";
+ if(isset($content['content']))
+ $contentOut .= strtr($this->contentTemplate, array('{content}'=>$content['content'],'{id}'=>$tabId))."\n";
+ }
+ }
+ echo "<ul>\n" . $tabsOut . "</ul>\n";
+ echo $contentOut;
+
+ echo CHtml::closeTag($this->tagName)."\n";
+
+ $options=empty($this->options) ? '' : CJavaScript::encode($this->options);
+ Yii::app()->getClientScript()->registerScript(__CLASS__.'#'.$id,"jQuery('#{$id}').tabs($options);");
+ }
+
+ /**
+ * Registers the core script files.
+ * This method overrides the parent implementation by registering the cookie plugin when cookie option is used.
+ */
+ protected function registerCoreScripts()
+ {
+ parent::registerCoreScripts();
+ if(isset($this->options['cookie']))
+ Yii::app()->getClientScript()->registerCoreScript('cookie');
+ }
+}
diff --git a/framework/zii/widgets/jui/CJuiWidget.php b/framework/zii/widgets/jui/CJuiWidget.php
new file mode 100644
index 0000000..3649444
--- /dev/null
+++ b/framework/zii/widgets/jui/CJuiWidget.php
@@ -0,0 +1,145 @@
+<?php
+/**
+ * CJuiWidget class file.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * This is the base class for all JUI widget classes.
+ *
+ * @author Sebastian Thierer <sebathi@gmail.com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CJuiWidget.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package zii.widgets.jui
+ * @since 1.1
+ */
+abstract class CJuiWidget extends CWidget
+{
+ /**
+ * @var string the root URL that contains all JUI JavaScript files.
+ * If this property is not set (default), Yii will publish the JUI package included in the zii release and use
+ * that to infer the root script URL. You should set this property if you intend to use
+ * a JUI package whose version is different from the one included in zii.
+ * Note that under this URL, there must be a file whose name is specified by {@link scriptFile}.
+ * Do not append any slash character to the URL.
+ */
+ public $scriptUrl;
+ /**
+ * @var string the root URL that contains all JUI theme folders.
+ * If this property is not set (default), Yii will publish the JUI package included in the zii release and use
+ * that to infer the root theme URL. You should set this property if you intend to use
+ * a theme that is not found in the JUI package included in zii.
+ * Note that under this URL, there must be a directory whose name is specified by {@link theme}.
+ * Do not append any slash character to the URL.
+ */
+ public $themeUrl;
+ /**
+ * @var string the JUI theme name. Defaults to 'base'. Make sure that under {@link themeUrl} there
+ * is a directory whose name is the same as this property value (case-sensitive).
+ */
+ public $theme='base';
+ /**
+ * @var mixed the main JUI JavaScript file. Defaults to 'jquery-ui.min.js'.
+ * Note the file must exist under the URL specified by {@link scriptUrl}.
+ * If you need to include multiple script files (e.g. during development, you want to include individual
+ * plugin script files rather than the minized JUI script file), you may set this property
+ * as an array of the script file names.
+ * This property can also be set as false, which means the widget will not include any script file,
+ * and it is your responsibility to explicitly include it somewhere else.
+ */
+ public $scriptFile='jquery-ui.min.js';
+ /**
+ * @var mixed the theme CSS file name. Defaults to 'jquery-ui.css'.
+ * Note the file must exist under the URL specified by {@link themeUrl}/{@link theme}.
+ * If you need to include multiple theme CSS files (e.g. during development, you want to include individual
+ * plugin CSS files), you may set this property as an array of the CSS file names.
+ * This property can also be set as false, which means the widget will not include any theme CSS file,
+ * and it is your responsibility to explicitly include it somewhere else.
+ */
+ public $cssFile='jquery-ui.css';
+ /**
+ * @var array the initial JavaScript options that should be passed to the JUI plugin.
+ */
+ public $options=array();
+ /**
+ * @var array the HTML attributes that should be rendered in the HTML tag representing the JUI widget.
+ */
+ public $htmlOptions=array();
+
+ /**
+ * Initializes the widget.
+ * This method will publish JUI assets if necessary.
+ * It will also register jquery and JUI JavaScript files and the theme CSS file.
+ * If you override this method, make sure you call the parent implementation first.
+ */
+ public function init()
+ {
+ $this->resolvePackagePath();
+ $this->registerCoreScripts();
+ parent::init();
+ }
+
+ /**
+ * Determine the JUI package installation path.
+ * This method will identify the JavaScript root URL and theme root URL.
+ * If they are not explicitly specified, it will publish the included JUI package
+ * and use that to resolve the needed paths.
+ */
+ protected function resolvePackagePath()
+ {
+ if($this->scriptUrl===null || $this->themeUrl===null)
+ {
+ $cs=Yii::app()->getClientScript();
+ if($this->scriptUrl===null)
+ $this->scriptUrl=$cs->getCoreScriptUrl().'/jui/js';
+ if($this->themeUrl===null)
+ $this->themeUrl=$cs->getCoreScriptUrl().'/jui/css';
+ }
+ }
+
+ /**
+ * Registers the core script files.
+ * This method registers jquery and JUI JavaScript files and the theme CSS file.
+ */
+ protected function registerCoreScripts()
+ {
+ $cs=Yii::app()->getClientScript();
+ if(is_string($this->cssFile))
+ $cs->registerCssFile($this->themeUrl.'/'.$this->theme.'/'.$this->cssFile);
+ else if(is_array($this->cssFile))
+ {
+ foreach($this->cssFile as $cssFile)
+ $cs->registerCssFile($this->themeUrl.'/'.$this->theme.'/'.$cssFile);
+ }
+
+ $cs->registerCoreScript('jquery');
+ if(is_string($this->scriptFile))
+ $this->registerScriptFile($this->scriptFile);
+ else if(is_array($this->scriptFile))
+ {
+ foreach($this->scriptFile as $scriptFile)
+ $this->registerScriptFile($scriptFile);
+ }
+ }
+
+ /**
+ * Registers a JavaScript file under {@link scriptUrl}.
+ * Note that by default, the script file will be rendered at the end of a page to improve page loading speed.
+ * @param string $fileName JavaScript file name
+ * @param integer $position the position of the JavaScript file. Valid values include the following:
+ * <ul>
+ * <li>CClientScript::POS_HEAD : the script is inserted in the head section right before the title element.</li>
+ * <li>CClientScript::POS_BEGIN : the script is inserted at the beginning of the body section.</li>
+ * <li>CClientScript::POS_END : the script is inserted at the end of the body section.</li>
+ * </ul>
+ */
+ protected function registerScriptFile($fileName,$position=CClientScript::POS_END)
+ {
+ Yii::app()->getClientScript()->registerScriptFile($this->scriptUrl.'/'.$fileName,$position);
+ }
+}