CListView.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <?php
  2. /**
  3. * CListView class file.
  4. *
  5. * @author Qiang Xue <qiang.xue@gmail.com>
  6. * @link http://www.yiiframework.com/
  7. * @copyright 2008-2013 Yii Software LLC
  8. * @license http://www.yiiframework.com/license/
  9. */
  10. Yii::import('zii.widgets.CBaseListView');
  11. /**
  12. * CListView displays a list of data items in terms of a list.
  13. *
  14. * Unlike {@link CGridView} which displays the data items in a table, CListView allows one to use
  15. * a view template to render each data item. As a result, CListView could generate more flexible
  16. * rendering result.
  17. *
  18. * CListView supports both sorting and pagination of the data items. The sorting
  19. * and pagination can be done in AJAX mode or normal page request. A benefit of using CListView is that
  20. * when the user browser disables JavaScript, the sorting and pagination automatically degenerate
  21. * to normal page requests and are still functioning as expected.
  22. *
  23. * CListView should be used together with a {@link IDataProvider data provider}, preferably a
  24. * {@link CActiveDataProvider}.
  25. *
  26. * The minimal code needed to use CListView is as follows:
  27. *
  28. * <pre>
  29. * $dataProvider=new CActiveDataProvider('Post');
  30. *
  31. * $this->widget('zii.widgets.CListView', array(
  32. * 'dataProvider'=>$dataProvider,
  33. * 'itemView'=>'_post', // refers to the partial view named '_post'
  34. * 'sortableAttributes'=>array(
  35. * 'title',
  36. * 'create_time'=>'Post Time',
  37. * ),
  38. * ));
  39. * </pre>
  40. *
  41. * The above code first creates a data provider for the <code>Post</code> ActiveRecord class.
  42. * It then uses CListView to display every data item as returned by the data provider.
  43. * The display is done via the partial view named '_post'. This partial view will be rendered
  44. * once for every data item. In the view, one can access the current data item via variable <code>$data</code>.
  45. * For more details, see {@link itemView}.
  46. *
  47. * In order to support sorting, one has to specify the {@link sortableAttributes} property.
  48. * By doing so, a list of hyperlinks that can sort the data will be displayed.
  49. *
  50. * @author Qiang Xue <qiang.xue@gmail.com>
  51. * @package zii.widgets
  52. * @since 1.1
  53. */
  54. class CListView extends CBaseListView
  55. {
  56. /**
  57. * @var string the view used for rendering each data item.
  58. * This property value will be passed as the first parameter to either {@link CController::renderPartial}
  59. * or {@link CWidget::render} to render each data item.
  60. * In the corresponding view template, the following variables can be used in addition to those declared in {@link viewData}:
  61. * <ul>
  62. * <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,
  63. * then <code>$this</code> refers to the controller.</li>
  64. * <li><code>$data</code>: refers to the data item currently being rendered.</li>
  65. * <li><code>$index</code>: refers to the zero-based index of the data item currently being rendered.</li>
  66. * <li><code>$widget</code>: refers to this list view widget instance.</li>
  67. * </ul>
  68. */
  69. public $itemView;
  70. /**
  71. * @var string the HTML code to be displayed between any two consecutive items.
  72. * @since 1.1.7
  73. */
  74. public $separator;
  75. /**
  76. * @var array additional data to be passed to {@link itemView} when rendering each data item.
  77. * This array will be extracted into local PHP variables that can be accessed in the {@link itemView}.
  78. */
  79. public $viewData=array();
  80. /**
  81. * @var array list of sortable attribute names. In order for an attribute to be sortable, it must also
  82. * appear as a sortable attribute in the {@link IDataProvider::sort} property of {@link dataProvider}.
  83. * @see enableSorting
  84. */
  85. public $sortableAttributes;
  86. /**
  87. * @var string the template to be used to control the layout of various components in the list view.
  88. * These tokens are recognized: {summary}, {sorter}, {items} and {pager}. They will be replaced with the
  89. * summary text, the sort links, the data item list, and the pager.
  90. */
  91. public $template="{summary}\n{sorter}\n{items}\n{pager}";
  92. /**
  93. * @var string the CSS class name that will be assigned to the widget container element
  94. * when the widget is updating its content via AJAX. Defaults to 'list-view-loading'.
  95. * @since 1.1.1
  96. */
  97. public $loadingCssClass='list-view-loading';
  98. /**
  99. * @var string the CSS class name for the sorter container. Defaults to 'sorter'.
  100. */
  101. public $sorterCssClass='sorter';
  102. /**
  103. * @var string the text shown before sort links. Defaults to 'Sort by: '.
  104. */
  105. public $sorterHeader;
  106. /**
  107. * @var string the text shown after sort links. Defaults to empty.
  108. */
  109. public $sorterFooter='';
  110. /**
  111. * @var mixed the ID of the container whose content may be updated with an AJAX response.
  112. * Defaults to null, meaning the container for this list view instance.
  113. * If it is set false, it means sorting and pagination will be performed in normal page requests
  114. * instead of AJAX requests. If the sorting and pagination should trigger the update of multiple
  115. * containers' content in AJAX fashion, these container IDs may be listed here (separated with comma).
  116. */
  117. public $ajaxUpdate;
  118. /**
  119. * @var string the jQuery selector of the HTML elements that may trigger AJAX updates when they are clicked.
  120. * If not set, the pagination links and the sorting links will trigger AJAX updates.
  121. * @since 1.1.7
  122. */
  123. public $updateSelector;
  124. /**
  125. * @var string a javascript function that will be invoked if an AJAX update error occurs.
  126. *
  127. * The function signature is <code>function(xhr, textStatus, errorThrown, errorMessage)</code>
  128. * <ul>
  129. * <li><code>xhr</code> is the XMLHttpRequest object.</li>
  130. * <li><code>textStatus</code> is a string describing the type of error that occurred.
  131. * Possible values (besides null) are "timeout", "error", "notmodified" and "parsererror"</li>
  132. * <li><code>errorThrown</code> is an optional exception object, if one occurred.</li>
  133. * <li><code>errorMessage</code> is the CGridView default error message derived from xhr and errorThrown.
  134. * Usefull if you just want to display this error differently. CGridView by default displays this error with an javascript.alert()</li>
  135. * </ul>
  136. * Note: This handler is not called for JSONP requests, because they do not use an XMLHttpRequest.
  137. *
  138. * Example (add in a call to CGridView):
  139. * <pre>
  140. * ...
  141. * 'ajaxUpdateError'=>'function(xhr,ts,et,err,id){ $("#"+id).text(err); }',
  142. * ...
  143. * </pre>
  144. * @since 1.1.13
  145. */
  146. public $ajaxUpdateError;
  147. /**
  148. * @var string the name of the GET variable that indicates the request is an AJAX request triggered
  149. * by this widget. Defaults to 'ajax'. This is effective only when {@link ajaxUpdate} is not false.
  150. */
  151. public $ajaxVar='ajax';
  152. /**
  153. * @var mixed the URL for the AJAX requests should be sent to. {@link CHtml::normalizeUrl()} will be
  154. * called on this property. If not set, the current page URL will be used for AJAX requests.
  155. * @since 1.1.8
  156. */
  157. public $ajaxUrl;
  158. /**
  159. * @var string the type ('GET' or 'POST') of the AJAX requests. If not set, 'GET' will be used.
  160. * You can set this to 'POST' if you are filtering by many fields at once and have a problem with GET query string length.
  161. * Note that in POST mode direct links and {@link enableHistory} feature may not work correctly!
  162. * @since 1.1.14
  163. */
  164. public $ajaxType;
  165. /**
  166. * @var string a javascript function that will be invoked before an AJAX update occurs.
  167. * The function signature is <code>function(id)</code> where 'id' refers to the ID of the list view.
  168. */
  169. public $beforeAjaxUpdate;
  170. /**
  171. * @var string a javascript function that will be invoked after a successful AJAX response is received.
  172. * The function signature is <code>function(id, data)</code> where 'id' refers to the ID of the list view
  173. * 'data' the received ajax response data.
  174. */
  175. public $afterAjaxUpdate;
  176. /**
  177. * @var string the base script URL for all list view resources (e.g. javascript, CSS file, images).
  178. * Defaults to null, meaning using the integrated list view resources (which are published as assets).
  179. */
  180. public $baseScriptUrl;
  181. /**
  182. * @var string the URL of the CSS file used by this list view. Defaults to null, meaning using the integrated
  183. * CSS file. If this is set false, you are responsible to explicitly include the necessary CSS file in your page.
  184. */
  185. public $cssFile;
  186. /**
  187. * @var string the HTML tag name for the container of all data item display. Defaults to 'div'.
  188. * @since 1.1.4
  189. */
  190. public $itemsTagName='div';
  191. /**
  192. * @var boolean whether to leverage the {@link https://developer.mozilla.org/en/DOM/window.history DOM history object}. Set this property to true
  193. * to persist state of list across page revisits. Note, there are two limitations for this feature:
  194. * - this feature is only compatible with browsers that support HTML5.
  195. * - expect unexpected functionality (e.g. multiple ajax calls) if there is more than one grid/list on a single page with enableHistory turned on.
  196. * @since 1.1.11
  197. */
  198. public $enableHistory=false;
  199. /**
  200. * Initializes the list view.
  201. * This method will initialize required property values and instantiate {@link columns} objects.
  202. */
  203. public function init()
  204. {
  205. if($this->itemView===null)
  206. throw new CException(Yii::t('zii','The property "itemView" cannot be empty.'));
  207. parent::init();
  208. if(!isset($this->htmlOptions['class']))
  209. $this->htmlOptions['class']='list-view';
  210. if($this->baseScriptUrl===null)
  211. $this->baseScriptUrl=Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias('zii.widgets.assets')).'/listview';
  212. if($this->cssFile!==false)
  213. {
  214. if($this->cssFile===null)
  215. $this->cssFile=$this->baseScriptUrl.'/styles.css';
  216. Yii::app()->getClientScript()->registerCssFile($this->cssFile);
  217. }
  218. }
  219. /**
  220. * Registers necessary client scripts.
  221. */
  222. public function registerClientScript()
  223. {
  224. $id=$this->getId();
  225. if($this->ajaxUpdate===false)
  226. $ajaxUpdate=array();
  227. else
  228. $ajaxUpdate=array_unique(preg_split('/\s*,\s*/',$this->ajaxUpdate.','.$id,-1,PREG_SPLIT_NO_EMPTY));
  229. $options=array(
  230. 'ajaxUpdate'=>$ajaxUpdate,
  231. 'ajaxVar'=>$this->ajaxVar,
  232. 'pagerClass'=>$this->pagerCssClass,
  233. 'loadingClass'=>$this->loadingCssClass,
  234. 'sorterClass'=>$this->sorterCssClass,
  235. 'enableHistory'=>$this->enableHistory
  236. );
  237. if($this->ajaxUrl!==null)
  238. $options['url']=CHtml::normalizeUrl($this->ajaxUrl);
  239. if($this->ajaxType!==null)
  240. $options['ajaxType']=strtoupper($this->ajaxType);
  241. if($this->updateSelector!==null)
  242. $options['updateSelector']=$this->updateSelector;
  243. foreach(array('beforeAjaxUpdate', 'afterAjaxUpdate', 'ajaxUpdateError') as $event)
  244. {
  245. if($this->$event!==null)
  246. {
  247. if($this->$event instanceof CJavaScriptExpression)
  248. $options[$event]=$this->$event;
  249. else
  250. $options[$event]=new CJavaScriptExpression($this->$event);
  251. }
  252. }
  253. $options=CJavaScript::encode($options);
  254. $cs=Yii::app()->getClientScript();
  255. $cs->registerCoreScript('jquery');
  256. $cs->registerCoreScript('bbq');
  257. if($this->enableHistory)
  258. $cs->registerCoreScript('history');
  259. $cs->registerScriptFile($this->baseScriptUrl.'/jquery.yiilistview.js',CClientScript::POS_END);
  260. $cs->registerScript(__CLASS__.'#'.$id,"jQuery('#$id').yiiListView($options);");
  261. }
  262. /**
  263. * Renders the data item list.
  264. */
  265. public function renderItems()
  266. {
  267. echo CHtml::openTag($this->itemsTagName,array('class'=>$this->itemsCssClass))."\n";
  268. $data=$this->dataProvider->getData();
  269. if(($n=count($data))>0)
  270. {
  271. $owner=$this->getOwner();
  272. $viewFile=$owner->getViewFile($this->itemView);
  273. $j=0;
  274. foreach($data as $i=>$item)
  275. {
  276. $data=$this->viewData;
  277. $data['index']=$i;
  278. $data['data']=$item;
  279. $data['widget']=$this;
  280. $owner->renderFile($viewFile,$data);
  281. if($j++ < $n-1)
  282. echo $this->separator;
  283. }
  284. }
  285. else
  286. $this->renderEmptyText();
  287. echo CHtml::closeTag($this->itemsTagName);
  288. }
  289. /**
  290. * Renders the sorter.
  291. */
  292. public function renderSorter()
  293. {
  294. if($this->dataProvider->getItemCount()<=0 || !$this->enableSorting || empty($this->sortableAttributes))
  295. return;
  296. echo CHtml::openTag('div',array('class'=>$this->sorterCssClass))."\n";
  297. echo $this->sorterHeader===null ? Yii::t('zii','Sort by: ') : $this->sorterHeader;
  298. echo "<ul>\n";
  299. $sort=$this->dataProvider->getSort();
  300. foreach($this->sortableAttributes as $name=>$label)
  301. {
  302. echo "<li>";
  303. if(is_integer($name))
  304. echo $sort->link($label);
  305. else
  306. echo $sort->link($name,$label);
  307. echo "</li>\n";
  308. }
  309. echo "</ul>";
  310. echo $this->sorterFooter;
  311. echo CHtml::closeTag('div');
  312. }
  313. }