|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* TDataList class file |
|
4
|
|
|
* |
|
5
|
|
|
* @author Qiang Xue <[email protected]> |
|
6
|
|
|
* @link https://github.com/pradosoft/prado |
|
7
|
|
|
* @copyright Copyright © 2005-2016 The PRADO Group |
|
8
|
|
|
* @license https://github.com/pradosoft/prado/blob/master/LICENSE |
|
9
|
|
|
* @package Prado\Web\UI\WebControls |
|
10
|
|
|
*/ |
|
11
|
|
|
|
|
12
|
|
|
namespace Prado\Web\UI\WebControls; |
|
13
|
|
|
|
|
14
|
|
|
use Prado\Exceptions\TInvalidOperationException; |
|
15
|
|
|
use Prado\Prado; |
|
16
|
|
|
use Prado\TPropertyValue; |
|
17
|
|
|
use Prado\Exceptions\TInvalidDataValueException; |
|
18
|
|
|
use Prado\Exceptions\TInvalidDataTypeException; |
|
19
|
|
|
use Prado\Web\UI\ITemplate; |
|
20
|
|
|
|
|
21
|
|
|
/** |
|
22
|
|
|
* TDataList class |
|
23
|
|
|
* |
|
24
|
|
|
* TDataList represents a data bound and updatable list control. |
|
25
|
|
|
* |
|
26
|
|
|
* Like {@link TRepeater}, TDataList displays its content repeatedly based on |
|
27
|
|
|
* the data fetched from {@link setDataSource DataSource}. |
|
28
|
|
|
* The repeated contents in TDataList are called items, which are controls and |
|
29
|
|
|
* can be accessed through {@link getItems Items}. When {@link dataBind()} is |
|
30
|
|
|
* invoked, TDataList creates an item for each row of data and binds the data |
|
31
|
|
|
* row to the item. Optionally, a TDataList can have a header, a footer and/or |
|
32
|
|
|
* separators between items. |
|
33
|
|
|
* |
|
34
|
|
|
* TDataList differs from {@link TRepeater} in that it supports tiling the items |
|
35
|
|
|
* in different manners and it maintains status of items to handle data update. |
|
36
|
|
|
* |
|
37
|
|
|
* The layout of the repeated contents are specified by inline templates. |
|
38
|
|
|
* TDataList items, header, footer, etc. are being instantiated with the corresponding |
|
39
|
|
|
* templates when data is being bound to the repeater. |
|
40
|
|
|
* |
|
41
|
|
|
* Since v3.1.0, the layout can also be by renderers. A renderer is a control class |
|
42
|
|
|
* that can be instantiated as datalist items, header, etc. A renderer can thus be viewed |
|
43
|
|
|
* as an external template (in fact, it can also be non-templated controls). |
|
44
|
|
|
* |
|
45
|
|
|
* A renderer can be any control class. |
|
46
|
|
|
* - If the class implements {@link \Prado\IDataRenderer}, the <b>Data</b> |
|
47
|
|
|
* property will be set as the data row during databinding. Many PRADO controls |
|
48
|
|
|
* implement this interface, such as {@link TLabel}, {@link TTextBox}, etc. |
|
49
|
|
|
* - If the class implements {@link IItemDataRenderer}, the <b>ItemIndex</b> property will be set |
|
50
|
|
|
* as the zero-based index of the item in the datalist item collection, and |
|
51
|
|
|
* the <b>ItemType</b> property as the item's type (such as TListItemType::Item). |
|
52
|
|
|
* {@link TDataListItemRenderer} may be used as the convenient base class which |
|
53
|
|
|
* already implements {@link IDataItemRenderer}. |
|
54
|
|
|
* |
|
55
|
|
|
* The following properties are used to specify different types of template and renderer |
|
56
|
|
|
* for a datalist: |
|
57
|
|
|
* - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}: |
|
58
|
|
|
* for each repeated row of data |
|
59
|
|
|
* - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}: |
|
60
|
|
|
* for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer} |
|
61
|
|
|
* will be used instead. |
|
62
|
|
|
* - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}: |
|
63
|
|
|
* for the datalist header. |
|
64
|
|
|
* - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}: |
|
65
|
|
|
* for the datalist footer. |
|
66
|
|
|
* - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}: |
|
67
|
|
|
* for content to be displayed between items. |
|
68
|
|
|
* - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}: |
|
69
|
|
|
* used when data bound to the datalist is empty. |
|
70
|
|
|
* - {@link setEditItemTemplate EditItemTemplate}, {@link setEditItemRenderer EditItemRenderer}: |
|
71
|
|
|
* for the row being editted. |
|
72
|
|
|
* - {@link setSelectedItemTemplate SelectedItemTemplate}, {@link setSelectedItemRenderer SelectedItemRenderer}: |
|
73
|
|
|
* for the row being selected. |
|
74
|
|
|
* |
|
75
|
|
|
* If a content type is defined with both a template and a renderer, the latter takes precedence. |
|
76
|
|
|
* |
|
77
|
|
|
* When {@link dataBind()} is being called, TDataList undergoes the following lifecycles for each row of data: |
|
78
|
|
|
* - create item based on templates or renderers |
|
79
|
|
|
* - set the row of data to the item |
|
80
|
|
|
* - raise {@link onItemCreated OnItemCreated}: |
|
81
|
|
|
* - add the item as a child control |
|
82
|
|
|
* - call dataBind() of the item |
|
83
|
|
|
* - raise {@link onItemDataBound OnItemDataBound}: |
|
84
|
|
|
* |
|
85
|
|
|
* TDataList raises an {@link onItemCommand OnItemCommand} whenever a button control |
|
86
|
|
|
* within some datalist item raises a <b>OnCommand</b> event. Therefore, |
|
87
|
|
|
* you can handle all sorts of <b>OnCommand</b> event in a central place by |
|
88
|
|
|
* writing an event handler for {@link onItemCommand OnItemCommand}. |
|
89
|
|
|
* |
|
90
|
|
|
* An additional event is raised if the <b>OnCommand</b> event has one of the following |
|
91
|
|
|
* command names: |
|
92
|
|
|
* - edit: user wants to edit an item. <b>OnEditCommand</b> event will be raised. |
|
93
|
|
|
* - update: user wants to save the change to an item. <b>OnUpdateCommand</b> event will be raised. |
|
94
|
|
|
* - select: user selects an item. <b>OnSelectedIndexChanged</b> event will be raised. |
|
95
|
|
|
* - delete: user deletes an item. <b>OnDeleteCommand</b> event will be raised. |
|
96
|
|
|
* - cancel: user cancels previously editting action. <b>OnCancelCommand</b> event will be raised. |
|
97
|
|
|
* |
|
98
|
|
|
* TDataList provides a few properties to support tiling the items. |
|
99
|
|
|
* The number of columns used to display the data items is specified via |
|
100
|
|
|
* {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection} |
|
101
|
|
|
* governs the order of the items being rendered. |
|
102
|
|
|
* The layout of the data items in the list is specified via {@link setRepeatLayout RepeatLayout}, |
|
103
|
|
|
* which can take one of the following values: |
|
104
|
|
|
* - Table (default): items are organized using HTML table and cells. |
|
105
|
|
|
* When using this layout, one can set {@link setCellPadding CellPadding} and |
|
106
|
|
|
* {@link setCellSpacing CellSpacing} to adjust the cellpadding and cellpadding |
|
107
|
|
|
* of the table, and {@link setCaption Caption} and {@link setCaptionAlign CaptionAlign} |
|
108
|
|
|
* to add a table caption with the specified alignment. |
|
109
|
|
|
* - Flow: items are organized using HTML spans and breaks. |
|
110
|
|
|
* - Raw: TDataList does not generate any HTML tags to do the tiling. |
|
111
|
|
|
* |
|
112
|
|
|
* Items in TDataList can be in one of the three status: normal browsing, |
|
113
|
|
|
* being editted and being selected. To change the status of a particular |
|
114
|
|
|
* item, set {@link setSelectedItemIndex SelectedItemIndex} or |
|
115
|
|
|
* {@link setEditItemIndex EditItemIndex}. The former will change |
|
116
|
|
|
* the indicated item to selected mode, which will cause the item to |
|
117
|
|
|
* use {@link setSelectedItemTemplate SelectedItemTemplate} or |
|
118
|
|
|
* {@link setSelectedItemRenderer SelectedItemRenderer} for presentation. |
|
119
|
|
|
* The latter will change the indicated item to edit mode and to use corresponding |
|
120
|
|
|
* template or renderer. |
|
121
|
|
|
* Note, if an item is in edit mode, then selecting this item will have no effect. |
|
122
|
|
|
* |
|
123
|
|
|
* Different styles may be applied to items in different status. The style |
|
124
|
|
|
* application is performed in a hierarchical way: Style in higher hierarchy |
|
125
|
|
|
* will inherit from styles in lower hierarchy. |
|
126
|
|
|
* Starting from the lowest hierarchy, the item styles include |
|
127
|
|
|
* - item's own style |
|
128
|
|
|
* - {@link getItemStyle ItemStyle} |
|
129
|
|
|
* - {@link getAlternatingItemStyle AlternatingItemStyle} |
|
130
|
|
|
* - {@link getSelectedItemStyle SelectedItemStyle} |
|
131
|
|
|
* - {@link getEditItemStyle EditItemStyle}. |
|
132
|
|
|
* Therefore, if background color is set as red in {@link getItemStyle ItemStyle}, |
|
133
|
|
|
* {@link getEditItemStyle EditItemStyle} will also have red background color |
|
134
|
|
|
* unless it is set to a different value explicitly. |
|
135
|
|
|
* |
|
136
|
|
|
* When a page containing a datalist is post back, the datalist will restore automatically |
|
137
|
|
|
* all its contents, including items, header, footer and separators. |
|
138
|
|
|
* However, the data row associated with each item will not be recovered and become null. |
|
139
|
|
|
* To access the data, use one of the following ways: |
|
140
|
|
|
* - Use {@link getDataKeys DataKeys} to obtain the data key associated with |
|
141
|
|
|
* the specified datalist item and use the key to fetch the corresponding data |
|
142
|
|
|
* from some persistent storage such as DB. |
|
143
|
|
|
* - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback. |
|
144
|
|
|
* Be aware though, if the size of your dataset is big, your page size will become big. Some |
|
145
|
|
|
* complex data may also have serializing problem if saved in viewstate. |
|
146
|
|
|
* |
|
147
|
|
|
* @author Qiang Xue <[email protected]> |
|
148
|
|
|
* @package Prado\Web\UI\WebControls |
|
149
|
|
|
* @since 3.0 |
|
150
|
|
|
*/ |
|
151
|
|
|
class TDataList extends TBaseDataList implements \Prado\Web\UI\INamingContainer, IRepeatInfoUser |
|
152
|
|
|
{ |
|
153
|
|
|
/** |
|
154
|
|
|
* Command name that TDataList understands. They are case-insensitive. |
|
155
|
|
|
*/ |
|
156
|
|
|
const CMD_SELECT = 'Select'; |
|
157
|
|
|
const CMD_EDIT = 'Edit'; |
|
158
|
|
|
const CMD_UPDATE = 'Update'; |
|
159
|
|
|
const CMD_DELETE = 'Delete'; |
|
160
|
|
|
const CMD_CANCEL = 'Cancel'; |
|
161
|
|
|
|
|
162
|
|
|
/** |
|
163
|
|
|
* @var TDataListItemCollection item list |
|
164
|
|
|
*/ |
|
165
|
|
|
private $_items; |
|
166
|
|
|
/** |
|
167
|
|
|
* @var Itemplate various item templates |
|
168
|
|
|
*/ |
|
169
|
|
|
private $_itemTemplate; |
|
170
|
|
|
private $_emptyTemplate; |
|
171
|
|
|
private $_alternatingItemTemplate; |
|
172
|
|
|
private $_selectedItemTemplate; |
|
173
|
|
|
private $_editItemTemplate; |
|
174
|
|
|
private $_headerTemplate; |
|
175
|
|
|
private $_footerTemplate; |
|
176
|
|
|
private $_separatorTemplate; |
|
177
|
|
|
/** |
|
178
|
|
|
* @var TControl header item |
|
179
|
|
|
*/ |
|
180
|
|
|
private $_header; |
|
181
|
|
|
/** |
|
182
|
|
|
* @var TControl footer item |
|
183
|
|
|
*/ |
|
184
|
|
|
private $_footer; |
|
185
|
|
|
|
|
186
|
|
|
/** |
|
187
|
|
|
* @return TDataListItemCollection item list |
|
188
|
|
|
*/ |
|
189
|
|
|
public function getItems() |
|
190
|
|
|
{ |
|
191
|
|
|
if (!$this->_items) { |
|
192
|
|
|
$this->_items = new TDataListItemCollection; |
|
193
|
|
|
} |
|
194
|
|
|
return $this->_items; |
|
195
|
|
|
} |
|
196
|
|
|
|
|
197
|
|
|
/** |
|
198
|
|
|
* @return int number of items |
|
199
|
|
|
*/ |
|
200
|
|
|
public function getItemCount() |
|
201
|
|
|
{ |
|
202
|
|
|
return $this->_items ? $this->_items->getCount() : 0; |
|
203
|
|
|
} |
|
204
|
|
|
|
|
205
|
|
|
/** |
|
206
|
|
|
* @return string the class name for datalist items. Defaults to empty, meaning not set. |
|
207
|
|
|
* @since 3.1.0 |
|
208
|
|
|
*/ |
|
209
|
|
|
public function getItemRenderer() |
|
210
|
|
|
{ |
|
211
|
|
|
return $this->getViewState('ItemRenderer', ''); |
|
212
|
|
|
} |
|
213
|
|
|
|
|
214
|
|
|
/** |
|
215
|
|
|
* Sets the item renderer class. |
|
216
|
|
|
* |
|
217
|
|
|
* If not empty, the class will be used to instantiate as datalist items. |
|
218
|
|
|
* This property takes precedence over {@link getItemTemplate ItemTemplate}. |
|
219
|
|
|
* |
|
220
|
|
|
* @param string $value the renderer class name in namespace format. |
|
221
|
|
|
* @see setItemTemplate |
|
222
|
|
|
* @since 3.1.0 |
|
223
|
|
|
*/ |
|
224
|
|
|
public function setItemRenderer($value) |
|
225
|
|
|
{ |
|
226
|
|
|
$this->setViewState('ItemRenderer', $value, ''); |
|
227
|
|
|
} |
|
228
|
|
|
|
|
229
|
|
|
/** |
|
230
|
|
|
* @return string the class name for alternative datalist items. Defaults to empty, meaning not set. |
|
231
|
|
|
* @since 3.1.0 |
|
232
|
|
|
*/ |
|
233
|
|
|
public function getAlternatingItemRenderer() |
|
234
|
|
|
{ |
|
235
|
|
|
return $this->getViewState('AlternatingItemRenderer', ''); |
|
236
|
|
|
} |
|
237
|
|
|
|
|
238
|
|
|
/** |
|
239
|
|
|
* Sets the alternative item renderer class. |
|
240
|
|
|
* |
|
241
|
|
|
* If not empty, the class will be used to instantiate as alternative datalist items. |
|
242
|
|
|
* This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}. |
|
243
|
|
|
* |
|
244
|
|
|
* @param string $value the renderer class name in namespace format. |
|
245
|
|
|
* @param mixed $value |
|
246
|
|
|
* @see setAlternatingItemTemplate |
|
247
|
|
|
* @since 3.1.0 |
|
248
|
|
|
*/ |
|
249
|
|
|
public function setAlternatingItemRenderer($value) |
|
250
|
|
|
{ |
|
251
|
|
|
$this->setViewState('AlternatingItemRenderer', $value, ''); |
|
252
|
|
|
} |
|
253
|
|
|
|
|
254
|
|
|
/** |
|
255
|
|
|
* @return string the class name for the datalist item being editted. Defaults to empty, meaning not set. |
|
256
|
|
|
* @since 3.1.0 |
|
257
|
|
|
*/ |
|
258
|
|
|
public function getEditItemRenderer() |
|
259
|
|
|
{ |
|
260
|
|
|
return $this->getViewState('EditItemRenderer', ''); |
|
261
|
|
|
} |
|
262
|
|
|
|
|
263
|
|
|
/** |
|
264
|
|
|
* Sets the renderer class for the datalist item being editted. |
|
265
|
|
|
* |
|
266
|
|
|
* If not empty, the class will be used to instantiate as the datalist item. |
|
267
|
|
|
* This property takes precedence over {@link getEditItemTemplate EditItemTemplate}. |
|
268
|
|
|
* |
|
269
|
|
|
* @param string $value the renderer class name in namespace format. |
|
270
|
|
|
* @see setEditItemTemplate |
|
271
|
|
|
* @since 3.1.0 |
|
272
|
|
|
*/ |
|
273
|
|
|
public function setEditItemRenderer($value) |
|
274
|
|
|
{ |
|
275
|
|
|
$this->setViewState('EditItemRenderer', $value, ''); |
|
276
|
|
|
} |
|
277
|
|
|
|
|
278
|
|
|
/** |
|
279
|
|
|
* @return string the class name for the datalist item being selected. Defaults to empty, meaning not set. |
|
280
|
|
|
* @since 3.1.0 |
|
281
|
|
|
*/ |
|
282
|
|
|
public function getSelectedItemRenderer() |
|
283
|
|
|
{ |
|
284
|
|
|
return $this->getViewState('SelectedItemRenderer', ''); |
|
285
|
|
|
} |
|
286
|
|
|
|
|
287
|
|
|
/** |
|
288
|
|
|
* Sets the renderer class for the datalist item being selected. |
|
289
|
|
|
* |
|
290
|
|
|
* If not empty, the class will be used to instantiate as the datalist item. |
|
291
|
|
|
* This property takes precedence over {@link getSelectedItemTemplate SelectedItemTemplate}. |
|
292
|
|
|
* |
|
293
|
|
|
* @param string $value the renderer class name in namespace format. |
|
294
|
|
|
* @see setSelectedItemTemplate |
|
295
|
|
|
* @since 3.1.0 |
|
296
|
|
|
*/ |
|
297
|
|
|
public function setSelectedItemRenderer($value) |
|
298
|
|
|
{ |
|
299
|
|
|
$this->setViewState('SelectedItemRenderer', $value, ''); |
|
300
|
|
|
} |
|
301
|
|
|
|
|
302
|
|
|
/** |
|
303
|
|
|
* @return string the class name for datalist item separators. Defaults to empty, meaning not set. |
|
304
|
|
|
* @since 3.1.0 |
|
305
|
|
|
*/ |
|
306
|
|
|
public function getSeparatorRenderer() |
|
307
|
|
|
{ |
|
308
|
|
|
return $this->getViewState('SeparatorRenderer', ''); |
|
309
|
|
|
} |
|
310
|
|
|
|
|
311
|
|
|
/** |
|
312
|
|
|
* Sets the datalist item separator renderer class. |
|
313
|
|
|
* |
|
314
|
|
|
* If not empty, the class will be used to instantiate as datalist item separators. |
|
315
|
|
|
* This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}. |
|
316
|
|
|
* |
|
317
|
|
|
* @param string $value the renderer class name in namespace format. |
|
318
|
|
|
* @see setSeparatorTemplate |
|
319
|
|
|
* @since 3.1.0 |
|
320
|
|
|
*/ |
|
321
|
|
|
public function setSeparatorRenderer($value) |
|
322
|
|
|
{ |
|
323
|
|
|
$this->setViewState('SeparatorRenderer', $value, ''); |
|
324
|
|
|
} |
|
325
|
|
|
|
|
326
|
|
|
/** |
|
327
|
|
|
* @return string the class name for datalist header item. Defaults to empty, meaning not set. |
|
328
|
|
|
* @since 3.1.0 |
|
329
|
|
|
*/ |
|
330
|
|
|
public function getHeaderRenderer() |
|
331
|
|
|
{ |
|
332
|
|
|
return $this->getViewState('HeaderRenderer', ''); |
|
333
|
|
|
} |
|
334
|
|
|
|
|
335
|
|
|
/** |
|
336
|
|
|
* Sets the datalist header renderer class. |
|
337
|
|
|
* |
|
338
|
|
|
* If not empty, the class will be used to instantiate as datalist header item. |
|
339
|
|
|
* This property takes precedence over {@link getHeaderTemplate HeaderTemplate}. |
|
340
|
|
|
* |
|
341
|
|
|
* @param string $value the renderer class name in namespace format. |
|
342
|
|
|
* @see setHeaderTemplate |
|
343
|
|
|
* @since 3.1.0 |
|
344
|
|
|
*/ |
|
345
|
|
|
public function setHeaderRenderer($value) |
|
346
|
|
|
{ |
|
347
|
|
|
$this->setViewState('HeaderRenderer', $value, ''); |
|
348
|
|
|
} |
|
349
|
|
|
|
|
350
|
|
|
/** |
|
351
|
|
|
* @return string the class name for datalist footer item. Defaults to empty, meaning not set. |
|
352
|
|
|
* @since 3.1.0 |
|
353
|
|
|
*/ |
|
354
|
|
|
public function getFooterRenderer() |
|
355
|
|
|
{ |
|
356
|
|
|
return $this->getViewState('FooterRenderer', ''); |
|
357
|
|
|
} |
|
358
|
|
|
|
|
359
|
|
|
/** |
|
360
|
|
|
* Sets the datalist footer renderer class. |
|
361
|
|
|
* |
|
362
|
|
|
* If not empty, the class will be used to instantiate as datalist footer item. |
|
363
|
|
|
* This property takes precedence over {@link getFooterTemplate FooterTemplate}. |
|
364
|
|
|
* |
|
365
|
|
|
* @param string $value the renderer class name in namespace format. |
|
366
|
|
|
* @see setFooterTemplate |
|
367
|
|
|
* @since 3.1.0 |
|
368
|
|
|
*/ |
|
369
|
|
|
public function setFooterRenderer($value) |
|
370
|
|
|
{ |
|
371
|
|
|
$this->setViewState('FooterRenderer', $value, ''); |
|
372
|
|
|
} |
|
373
|
|
|
|
|
374
|
|
|
/** |
|
375
|
|
|
* @return string the class name for empty datalist item. Defaults to empty, meaning not set. |
|
376
|
|
|
* @since 3.1.0 |
|
377
|
|
|
*/ |
|
378
|
|
|
public function getEmptyRenderer() |
|
379
|
|
|
{ |
|
380
|
|
|
return $this->getViewState('EmptyRenderer', ''); |
|
381
|
|
|
} |
|
382
|
|
|
|
|
383
|
|
|
/** |
|
384
|
|
|
* Sets the datalist empty renderer class. |
|
385
|
|
|
* |
|
386
|
|
|
* The empty renderer is created as the child of the datalist |
|
387
|
|
|
* if data bound to the datalist is empty. |
|
388
|
|
|
* This property takes precedence over {@link getEmptyTemplate EmptyTemplate}. |
|
389
|
|
|
* |
|
390
|
|
|
* @param string $value the renderer class name in namespace format. |
|
391
|
|
|
* @see setEmptyTemplate |
|
392
|
|
|
* @since 3.1.0 |
|
393
|
|
|
*/ |
|
394
|
|
|
public function setEmptyRenderer($value) |
|
395
|
|
|
{ |
|
396
|
|
|
$this->setViewState('EmptyRenderer', $value, ''); |
|
397
|
|
|
} |
|
398
|
|
|
|
|
399
|
|
|
/** |
|
400
|
|
|
* @return ITemplate the template for item |
|
401
|
|
|
*/ |
|
402
|
|
|
public function getItemTemplate() |
|
403
|
|
|
{ |
|
404
|
|
|
return $this->_itemTemplate; |
|
405
|
|
|
} |
|
406
|
|
|
|
|
407
|
|
|
/** |
|
408
|
|
|
* @param ITemplate $value the template for item |
|
409
|
|
|
* @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. |
|
410
|
|
|
*/ |
|
411
|
|
View Code Duplication |
public function setItemTemplate($value) |
|
|
|
|
|
|
412
|
|
|
{ |
|
413
|
|
|
if ($value instanceof ITemplate || $value === null) { |
|
414
|
|
|
$this->_itemTemplate = $value; |
|
|
|
|
|
|
415
|
|
|
} else { |
|
416
|
|
|
throw new TInvalidDataTypeException('datalist_template_required', 'ItemTemplate'); |
|
417
|
|
|
} |
|
418
|
|
|
} |
|
419
|
|
|
|
|
420
|
|
|
/** |
|
421
|
|
|
* @return TTableItemStyle the style for item |
|
422
|
|
|
*/ |
|
423
|
|
View Code Duplication |
public function getItemStyle() |
|
|
|
|
|
|
424
|
|
|
{ |
|
425
|
|
|
if (($style = $this->getViewState('ItemStyle', null)) === null) { |
|
426
|
|
|
$style = new TTableItemStyle; |
|
427
|
|
|
$this->setViewState('ItemStyle', $style, null); |
|
428
|
|
|
} |
|
429
|
|
|
return $style; |
|
430
|
|
|
} |
|
431
|
|
|
|
|
432
|
|
|
/** |
|
433
|
|
|
* @return ITemplate the template for each alternating item |
|
434
|
|
|
*/ |
|
435
|
|
|
public function getAlternatingItemTemplate() |
|
436
|
|
|
{ |
|
437
|
|
|
return $this->_alternatingItemTemplate; |
|
438
|
|
|
} |
|
439
|
|
|
|
|
440
|
|
|
/** |
|
441
|
|
|
* @param ITemplate $value the template for each alternating item |
|
442
|
|
|
* @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. |
|
443
|
|
|
*/ |
|
444
|
|
|
public function setAlternatingItemTemplate($value) |
|
445
|
|
|
{ |
|
446
|
|
|
if ($value instanceof ITemplate || $value === null) { |
|
447
|
|
|
$this->_alternatingItemTemplate = $value; |
|
448
|
|
|
} else { |
|
449
|
|
|
throw new TInvalidDataTypeException('datalist_template_required', 'AlternatingItemType'); |
|
450
|
|
|
} |
|
451
|
|
|
} |
|
452
|
|
|
|
|
453
|
|
|
/** |
|
454
|
|
|
* @return TTableItemStyle the style for each alternating item |
|
455
|
|
|
*/ |
|
456
|
|
View Code Duplication |
public function getAlternatingItemStyle() |
|
|
|
|
|
|
457
|
|
|
{ |
|
458
|
|
|
if (($style = $this->getViewState('AlternatingItemStyle', null)) === null) { |
|
459
|
|
|
$style = new TTableItemStyle; |
|
460
|
|
|
$this->setViewState('AlternatingItemStyle', $style, null); |
|
461
|
|
|
} |
|
462
|
|
|
return $style; |
|
463
|
|
|
} |
|
464
|
|
|
|
|
465
|
|
|
/** |
|
466
|
|
|
* @return ITemplate the selected item template |
|
467
|
|
|
*/ |
|
468
|
|
|
public function getSelectedItemTemplate() |
|
469
|
|
|
{ |
|
470
|
|
|
return $this->_selectedItemTemplate; |
|
471
|
|
|
} |
|
472
|
|
|
|
|
473
|
|
|
/** |
|
474
|
|
|
* @param ITemplate $value the selected item template |
|
475
|
|
|
* @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. |
|
476
|
|
|
*/ |
|
477
|
|
|
public function setSelectedItemTemplate($value) |
|
478
|
|
|
{ |
|
479
|
|
|
if ($value instanceof ITemplate || $value === null) { |
|
480
|
|
|
$this->_selectedItemTemplate = $value; |
|
481
|
|
|
} else { |
|
482
|
|
|
throw new TInvalidDataTypeException('datalist_template_required', 'SelectedItemTemplate'); |
|
483
|
|
|
} |
|
484
|
|
|
} |
|
485
|
|
|
|
|
486
|
|
|
/** |
|
487
|
|
|
* @return TTableItemStyle the style for selected item |
|
488
|
|
|
*/ |
|
489
|
|
View Code Duplication |
public function getSelectedItemStyle() |
|
|
|
|
|
|
490
|
|
|
{ |
|
491
|
|
|
if (($style = $this->getViewState('SelectedItemStyle', null)) === null) { |
|
492
|
|
|
$style = new TTableItemStyle; |
|
493
|
|
|
$this->setViewState('SelectedItemStyle', $style, null); |
|
494
|
|
|
} |
|
495
|
|
|
return $style; |
|
496
|
|
|
} |
|
497
|
|
|
|
|
498
|
|
|
/** |
|
499
|
|
|
* @return ITemplate the edit item template |
|
500
|
|
|
*/ |
|
501
|
|
|
public function getEditItemTemplate() |
|
502
|
|
|
{ |
|
503
|
|
|
return $this->_editItemTemplate; |
|
504
|
|
|
} |
|
505
|
|
|
|
|
506
|
|
|
/** |
|
507
|
|
|
* @param ITemplate $value the edit item template |
|
508
|
|
|
* @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. |
|
509
|
|
|
*/ |
|
510
|
|
View Code Duplication |
public function setEditItemTemplate($value) |
|
|
|
|
|
|
511
|
|
|
{ |
|
512
|
|
|
if ($value instanceof ITemplate || $value === null) { |
|
513
|
|
|
$this->_editItemTemplate = $value; |
|
514
|
|
|
} else { |
|
515
|
|
|
throw new TInvalidDataTypeException('datalist_template_required', 'EditItemTemplate'); |
|
516
|
|
|
} |
|
517
|
|
|
} |
|
518
|
|
|
|
|
519
|
|
|
/** |
|
520
|
|
|
* @return TTableItemStyle the style for edit item |
|
521
|
|
|
*/ |
|
522
|
|
View Code Duplication |
public function getEditItemStyle() |
|
|
|
|
|
|
523
|
|
|
{ |
|
524
|
|
|
if (($style = $this->getViewState('EditItemStyle', null)) === null) { |
|
525
|
|
|
$style = new TTableItemStyle; |
|
526
|
|
|
$this->setViewState('EditItemStyle', $style, null); |
|
527
|
|
|
} |
|
528
|
|
|
return $style; |
|
529
|
|
|
} |
|
530
|
|
|
|
|
531
|
|
|
/** |
|
532
|
|
|
* @return ITemplate the header template |
|
533
|
|
|
*/ |
|
534
|
|
|
public function getHeaderTemplate() |
|
535
|
|
|
{ |
|
536
|
|
|
return $this->_headerTemplate; |
|
537
|
|
|
} |
|
538
|
|
|
|
|
539
|
|
|
/** |
|
540
|
|
|
* @param ITemplate $value the header template |
|
541
|
|
|
* @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. |
|
542
|
|
|
*/ |
|
543
|
|
View Code Duplication |
public function setHeaderTemplate($value) |
|
|
|
|
|
|
544
|
|
|
{ |
|
545
|
|
|
if ($value instanceof ITemplate || $value === null) { |
|
546
|
|
|
$this->_headerTemplate = $value; |
|
547
|
|
|
} else { |
|
548
|
|
|
throw new TInvalidDataTypeException('datalist_template_required', 'HeaderTemplate'); |
|
549
|
|
|
} |
|
550
|
|
|
} |
|
551
|
|
|
|
|
552
|
|
|
/** |
|
553
|
|
|
* @return TTableItemStyle the style for header |
|
554
|
|
|
*/ |
|
555
|
|
View Code Duplication |
public function getHeaderStyle() |
|
|
|
|
|
|
556
|
|
|
{ |
|
557
|
|
|
if (($style = $this->getViewState('HeaderStyle', null)) === null) { |
|
558
|
|
|
$style = new TTableItemStyle; |
|
559
|
|
|
$this->setViewState('HeaderStyle', $style, null); |
|
560
|
|
|
} |
|
561
|
|
|
return $style; |
|
562
|
|
|
} |
|
563
|
|
|
|
|
564
|
|
|
/** |
|
565
|
|
|
* @return TControl the header item |
|
566
|
|
|
*/ |
|
567
|
|
|
public function getHeader() |
|
568
|
|
|
{ |
|
569
|
|
|
return $this->_header; |
|
570
|
|
|
} |
|
571
|
|
|
|
|
572
|
|
|
/** |
|
573
|
|
|
* @return ITemplate the footer template |
|
574
|
|
|
*/ |
|
575
|
|
|
public function getFooterTemplate() |
|
576
|
|
|
{ |
|
577
|
|
|
return $this->_footerTemplate; |
|
578
|
|
|
} |
|
579
|
|
|
|
|
580
|
|
|
/** |
|
581
|
|
|
* @param ITemplate $value the footer template |
|
582
|
|
|
* @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. |
|
583
|
|
|
*/ |
|
584
|
|
View Code Duplication |
public function setFooterTemplate($value) |
|
|
|
|
|
|
585
|
|
|
{ |
|
586
|
|
|
if ($value instanceof ITemplate || $value === null) { |
|
587
|
|
|
$this->_footerTemplate = $value; |
|
588
|
|
|
} else { |
|
589
|
|
|
throw new TInvalidDataTypeException('datalist_template_required', 'FooterTemplate'); |
|
590
|
|
|
} |
|
591
|
|
|
} |
|
592
|
|
|
|
|
593
|
|
|
/** |
|
594
|
|
|
* @return TTableItemStyle the style for footer |
|
595
|
|
|
*/ |
|
596
|
|
View Code Duplication |
public function getFooterStyle() |
|
|
|
|
|
|
597
|
|
|
{ |
|
598
|
|
|
if (($style = $this->getViewState('FooterStyle', null)) === null) { |
|
599
|
|
|
$style = new TTableItemStyle; |
|
600
|
|
|
$this->setViewState('FooterStyle', $style, null); |
|
601
|
|
|
} |
|
602
|
|
|
return $style; |
|
603
|
|
|
} |
|
604
|
|
|
|
|
605
|
|
|
/** |
|
606
|
|
|
* @return TControl the footer item |
|
607
|
|
|
*/ |
|
608
|
|
|
public function getFooter() |
|
609
|
|
|
{ |
|
610
|
|
|
return $this->_footer; |
|
611
|
|
|
} |
|
612
|
|
|
|
|
613
|
|
|
/** |
|
614
|
|
|
* @return ITemplate the template applied when no data is bound to the datalist |
|
615
|
|
|
*/ |
|
616
|
|
|
public function getEmptyTemplate() |
|
617
|
|
|
{ |
|
618
|
|
|
return $this->_emptyTemplate; |
|
619
|
|
|
} |
|
620
|
|
|
|
|
621
|
|
|
/** |
|
622
|
|
|
* @param ITemplate $value the template applied when no data is bound to the datalist |
|
623
|
|
|
* @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. |
|
624
|
|
|
*/ |
|
625
|
|
View Code Duplication |
public function setEmptyTemplate($value) |
|
|
|
|
|
|
626
|
|
|
{ |
|
627
|
|
|
if ($value instanceof ITemplate || $value === null) { |
|
628
|
|
|
$this->_emptyTemplate = $value; |
|
629
|
|
|
} else { |
|
630
|
|
|
throw new TInvalidDataTypeException('datalist_template_required', 'EmptyTemplate'); |
|
631
|
|
|
} |
|
632
|
|
|
} |
|
633
|
|
|
|
|
634
|
|
|
/** |
|
635
|
|
|
* @return ITemplate the separator template |
|
636
|
|
|
*/ |
|
637
|
|
|
public function getSeparatorTemplate() |
|
638
|
|
|
{ |
|
639
|
|
|
return $this->_separatorTemplate; |
|
640
|
|
|
} |
|
641
|
|
|
|
|
642
|
|
|
/** |
|
643
|
|
|
* @param ITemplate $value the separator template |
|
644
|
|
|
* @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. |
|
645
|
|
|
*/ |
|
646
|
|
View Code Duplication |
public function setSeparatorTemplate($value) |
|
|
|
|
|
|
647
|
|
|
{ |
|
648
|
|
|
if ($value instanceof ITemplate || $value === null) { |
|
649
|
|
|
$this->_separatorTemplate = $value; |
|
650
|
|
|
} else { |
|
651
|
|
|
throw new TInvalidDataTypeException('datalist_template_required', 'SeparatorTemplate'); |
|
652
|
|
|
} |
|
653
|
|
|
} |
|
654
|
|
|
|
|
655
|
|
|
/** |
|
656
|
|
|
* @return TTableItemStyle the style for separator |
|
657
|
|
|
*/ |
|
658
|
|
View Code Duplication |
public function getSeparatorStyle() |
|
|
|
|
|
|
659
|
|
|
{ |
|
660
|
|
|
if (($style = $this->getViewState('SeparatorStyle', null)) === null) { |
|
661
|
|
|
$style = new TTableItemStyle; |
|
662
|
|
|
$this->setViewState('SeparatorStyle', $style, null); |
|
663
|
|
|
} |
|
664
|
|
|
return $style; |
|
665
|
|
|
} |
|
666
|
|
|
|
|
667
|
|
|
/** |
|
668
|
|
|
* @return int the zero-based index of the selected item in {@link getItems Items}. |
|
669
|
|
|
* A value -1 means no item selected. |
|
670
|
|
|
*/ |
|
671
|
|
|
public function getSelectedItemIndex() |
|
672
|
|
|
{ |
|
673
|
|
|
return $this->getViewState('SelectedItemIndex', -1); |
|
674
|
|
|
} |
|
675
|
|
|
|
|
676
|
|
|
/** |
|
677
|
|
|
* Selects an item by its index in {@link getItems Items}. |
|
678
|
|
|
* Previously selected item will be un-selected. |
|
679
|
|
|
* If the item to be selected is already in edit mode, it will remain in edit mode. |
|
680
|
|
|
* If the index is less than 0, any existing selection will be cleared up. |
|
681
|
|
|
* @param int $value the selected item index |
|
682
|
|
|
*/ |
|
683
|
|
|
public function setSelectedItemIndex($value) |
|
684
|
|
|
{ |
|
685
|
|
|
if (($value = TPropertyValue::ensureInteger($value)) < 0) { |
|
686
|
|
|
$value = -1; |
|
687
|
|
|
} |
|
688
|
|
|
if (($current = $this->getSelectedItemIndex()) !== $value) { |
|
689
|
|
|
$this->setViewState('SelectedItemIndex', $value, -1); |
|
690
|
|
|
$items = $this->getItems(); |
|
691
|
|
|
$itemCount = $items->getCount(); |
|
692
|
|
View Code Duplication |
if ($current >= 0 && $current < $itemCount) { |
|
|
|
|
|
|
693
|
|
|
$item = $items->itemAt($current); |
|
694
|
|
|
if (($item instanceof IItemDataRenderer) && $item->getItemType() !== TListItemType::EditItem) { |
|
695
|
|
|
$item->setItemType($current % 2 ? TListItemType::AlternatingItem : TListItemType::Item); |
|
696
|
|
|
} |
|
697
|
|
|
} |
|
698
|
|
View Code Duplication |
if ($value >= 0 && $value < $itemCount) { |
|
|
|
|
|
|
699
|
|
|
$item = $items->itemAt($value); |
|
700
|
|
|
if (($item instanceof IItemDataRenderer) && $item->getItemType() !== TListItemType::EditItem) { |
|
701
|
|
|
$item->setItemType(TListItemType::SelectedItem); |
|
702
|
|
|
} |
|
703
|
|
|
} |
|
704
|
|
|
} |
|
705
|
|
|
} |
|
706
|
|
|
|
|
707
|
|
|
/** |
|
708
|
|
|
* @return TControl the selected item, null if no item is selected. |
|
709
|
|
|
*/ |
|
710
|
|
View Code Duplication |
public function getSelectedItem() |
|
|
|
|
|
|
711
|
|
|
{ |
|
712
|
|
|
$index = $this->getSelectedItemIndex(); |
|
713
|
|
|
$items = $this->getItems(); |
|
714
|
|
|
if ($index >= 0 && $index < $items->getCount()) { |
|
715
|
|
|
return $items->itemAt($index); |
|
716
|
|
|
} else { |
|
717
|
|
|
return null; |
|
718
|
|
|
} |
|
719
|
|
|
} |
|
720
|
|
|
|
|
721
|
|
|
/** |
|
722
|
|
|
* @throws TInvalidOperationException if {@link getDataKeyField DataKeyField} is empty. |
|
723
|
|
|
* @return mixed the key value of the currently selected item |
|
724
|
|
|
*/ |
|
725
|
|
|
public function getSelectedDataKey() |
|
726
|
|
|
{ |
|
727
|
|
|
if ($this->getDataKeyField() === '') { |
|
728
|
|
|
throw new TInvalidOperationException('datalist_datakeyfield_required'); |
|
729
|
|
|
} |
|
730
|
|
|
$index = $this->getSelectedItemIndex(); |
|
731
|
|
|
$dataKeys = $this->getDataKeys(); |
|
732
|
|
|
if ($index >= 0 && $index < $dataKeys->getCount()) { |
|
733
|
|
|
return $dataKeys->itemAt($index); |
|
734
|
|
|
} else { |
|
735
|
|
|
return null; |
|
736
|
|
|
} |
|
737
|
|
|
} |
|
738
|
|
|
|
|
739
|
|
|
/** |
|
740
|
|
|
* @return int the zero-based index of the edit item in {@link getItems Items}. |
|
741
|
|
|
* A value -1 means no item is in edit mode. |
|
742
|
|
|
*/ |
|
743
|
|
|
public function getEditItemIndex() |
|
744
|
|
|
{ |
|
745
|
|
|
return $this->getViewState('EditItemIndex', -1); |
|
746
|
|
|
} |
|
747
|
|
|
|
|
748
|
|
|
/** |
|
749
|
|
|
* Edits an item by its index in {@link getItems Items}. |
|
750
|
|
|
* Previously editting item will change to normal item state. |
|
751
|
|
|
* If the index is less than 0, any existing edit item will be cleared up. |
|
752
|
|
|
* @param int $value the edit item index |
|
753
|
|
|
*/ |
|
754
|
|
View Code Duplication |
public function setEditItemIndex($value) |
|
|
|
|
|
|
755
|
|
|
{ |
|
756
|
|
|
if (($value = TPropertyValue::ensureInteger($value)) < 0) { |
|
757
|
|
|
$value = -1; |
|
758
|
|
|
} |
|
759
|
|
|
if (($current = $this->getEditItemIndex()) !== $value) { |
|
760
|
|
|
$this->setViewState('EditItemIndex', $value, -1); |
|
761
|
|
|
$items = $this->getItems(); |
|
762
|
|
|
$itemCount = $items->getCount(); |
|
763
|
|
|
if ($current >= 0 && $current < $itemCount) { |
|
764
|
|
|
$items->itemAt($current)->setItemType($current % 2 ? TListItemType::AlternatingItem : TListItemType::Item); |
|
765
|
|
|
} |
|
766
|
|
|
if ($value >= 0 && $value < $itemCount) { |
|
767
|
|
|
$items->itemAt($value)->setItemType(TListItemType::EditItem); |
|
768
|
|
|
} |
|
769
|
|
|
} |
|
770
|
|
|
} |
|
771
|
|
|
|
|
772
|
|
|
/** |
|
773
|
|
|
* @return TControl the edit item |
|
774
|
|
|
*/ |
|
775
|
|
View Code Duplication |
public function getEditItem() |
|
|
|
|
|
|
776
|
|
|
{ |
|
777
|
|
|
$index = $this->getEditItemIndex(); |
|
778
|
|
|
$items = $this->getItems(); |
|
779
|
|
|
if ($index >= 0 && $index < $items->getCount()) { |
|
780
|
|
|
return $items->itemAt($index); |
|
781
|
|
|
} else { |
|
782
|
|
|
return null; |
|
783
|
|
|
} |
|
784
|
|
|
} |
|
785
|
|
|
|
|
786
|
|
|
/** |
|
787
|
|
|
* @return bool whether the header should be shown. Defaults to true. |
|
788
|
|
|
*/ |
|
789
|
|
|
public function getShowHeader() |
|
790
|
|
|
{ |
|
791
|
|
|
return $this->getViewState('ShowHeader', true); |
|
792
|
|
|
} |
|
793
|
|
|
|
|
794
|
|
|
/** |
|
795
|
|
|
* @param bool $value whether to show header |
|
796
|
|
|
*/ |
|
797
|
|
|
public function setShowHeader($value) |
|
798
|
|
|
{ |
|
799
|
|
|
$this->setViewState('ShowHeader', TPropertyValue::ensureBoolean($value), true); |
|
800
|
|
|
} |
|
801
|
|
|
|
|
802
|
|
|
/** |
|
803
|
|
|
* @return bool whether the footer should be shown. Defaults to true. |
|
804
|
|
|
*/ |
|
805
|
|
|
public function getShowFooter() |
|
806
|
|
|
{ |
|
807
|
|
|
return $this->getViewState('ShowFooter', true); |
|
808
|
|
|
} |
|
809
|
|
|
|
|
810
|
|
|
/** |
|
811
|
|
|
* @param bool $value whether to show footer |
|
812
|
|
|
*/ |
|
813
|
|
|
public function setShowFooter($value) |
|
814
|
|
|
{ |
|
815
|
|
|
$this->setViewState('ShowFooter', TPropertyValue::ensureBoolean($value), true); |
|
816
|
|
|
} |
|
817
|
|
|
|
|
818
|
|
|
/** |
|
819
|
|
|
* @return TRepeatInfo repeat information (primarily used by control developers) |
|
820
|
|
|
*/ |
|
821
|
|
View Code Duplication |
protected function getRepeatInfo() |
|
|
|
|
|
|
822
|
|
|
{ |
|
823
|
|
|
if (($repeatInfo = $this->getViewState('RepeatInfo', null)) === null) { |
|
824
|
|
|
$repeatInfo = new TRepeatInfo; |
|
825
|
|
|
$this->setViewState('RepeatInfo', $repeatInfo, null); |
|
826
|
|
|
} |
|
827
|
|
|
return $repeatInfo; |
|
828
|
|
|
} |
|
829
|
|
|
|
|
830
|
|
|
/** |
|
831
|
|
|
* @return string caption of the table layout |
|
832
|
|
|
*/ |
|
833
|
|
|
public function getCaption() |
|
834
|
|
|
{ |
|
835
|
|
|
return $this->getRepeatInfo()->getCaption(); |
|
836
|
|
|
} |
|
837
|
|
|
|
|
838
|
|
|
/** |
|
839
|
|
|
* @param string $value caption of the table layout |
|
840
|
|
|
*/ |
|
841
|
|
|
public function setCaption($value) |
|
842
|
|
|
{ |
|
843
|
|
|
$this->getRepeatInfo()->setCaption($value); |
|
844
|
|
|
} |
|
845
|
|
|
|
|
846
|
|
|
/** |
|
847
|
|
|
* @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet. |
|
848
|
|
|
*/ |
|
849
|
|
|
public function getCaptionAlign() |
|
850
|
|
|
{ |
|
851
|
|
|
return $this->getRepeatInfo()->getCaptionAlign(); |
|
852
|
|
|
} |
|
853
|
|
|
|
|
854
|
|
|
/** |
|
855
|
|
|
* @param mixed $value |
|
856
|
|
|
* @return TTableCaptionAlign alignment of the caption of the table layout. |
|
857
|
|
|
*/ |
|
858
|
|
|
public function setCaptionAlign($value) |
|
859
|
|
|
{ |
|
860
|
|
|
$this->getRepeatInfo()->setCaptionAlign($value); |
|
861
|
|
|
} |
|
862
|
|
|
|
|
863
|
|
|
/** |
|
864
|
|
|
* @return int the number of columns that the list should be displayed with. Defaults to 0 meaning not set. |
|
865
|
|
|
*/ |
|
866
|
|
|
public function getRepeatColumns() |
|
867
|
|
|
{ |
|
868
|
|
|
return $this->getRepeatInfo()->getRepeatColumns(); |
|
869
|
|
|
} |
|
870
|
|
|
|
|
871
|
|
|
/** |
|
872
|
|
|
* @param int $value the number of columns that the list should be displayed with. |
|
873
|
|
|
*/ |
|
874
|
|
|
public function setRepeatColumns($value) |
|
875
|
|
|
{ |
|
876
|
|
|
$this->getRepeatInfo()->setRepeatColumns($value); |
|
877
|
|
|
} |
|
878
|
|
|
|
|
879
|
|
|
/** |
|
880
|
|
|
* @return TRepeatDirection the direction of traversing the list, defaults to TRepeatDirection::Vertical |
|
881
|
|
|
*/ |
|
882
|
|
|
public function getRepeatDirection() |
|
883
|
|
|
{ |
|
884
|
|
|
return $this->getRepeatInfo()->getRepeatDirection(); |
|
885
|
|
|
} |
|
886
|
|
|
|
|
887
|
|
|
/** |
|
888
|
|
|
* @param TRepeatDirection $value the direction of traversing the list |
|
889
|
|
|
*/ |
|
890
|
|
|
public function setRepeatDirection($value) |
|
891
|
|
|
{ |
|
892
|
|
|
$this->getRepeatInfo()->setRepeatDirection($value); |
|
893
|
|
|
} |
|
894
|
|
|
|
|
895
|
|
|
/** |
|
896
|
|
|
* @return TRepeatLayout how the list should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table. |
|
897
|
|
|
*/ |
|
898
|
|
|
public function getRepeatLayout() |
|
899
|
|
|
{ |
|
900
|
|
|
return $this->getRepeatInfo()->getRepeatLayout(); |
|
901
|
|
|
} |
|
902
|
|
|
|
|
903
|
|
|
/** |
|
904
|
|
|
* @param TRepeatLayout $value how the list should be displayed, using table or using line breaks |
|
905
|
|
|
*/ |
|
906
|
|
|
public function setRepeatLayout($value) |
|
907
|
|
|
{ |
|
908
|
|
|
$this->getRepeatInfo()->setRepeatLayout($value); |
|
909
|
|
|
} |
|
910
|
|
|
|
|
911
|
|
|
/** |
|
912
|
|
|
* This method overrides parent's implementation to handle |
|
913
|
|
|
* {@link onItemCommand OnItemCommand} event which is bubbled from |
|
914
|
|
|
* datalist items and their child controls. |
|
915
|
|
|
* If the event parameter is {@link TDataListCommandEventParameter} and |
|
916
|
|
|
* the command name is a recognized one, which includes 'select', 'edit', |
|
917
|
|
|
* 'delete', 'update', and 'cancel' (case-insensitive), then a |
|
918
|
|
|
* corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}). |
|
919
|
|
|
* This method should only be used by control developers. |
|
920
|
|
|
* @param TControl $sender the sender of the event |
|
921
|
|
|
* @param TEventParameter $param event parameter |
|
922
|
|
|
* @return bool whether the event bubbling should stop here. |
|
923
|
|
|
*/ |
|
924
|
|
|
public function bubbleEvent($sender, $param) |
|
925
|
|
|
{ |
|
926
|
|
|
if ($param instanceof TDataListCommandEventParameter) { |
|
927
|
|
|
$this->onItemCommand($param); |
|
928
|
|
|
$command = $param->getCommandName(); |
|
929
|
|
|
if (strcasecmp($command, self::CMD_SELECT) === 0) { |
|
930
|
|
|
if (($item = $param->getItem()) instanceof IItemDataRenderer) { |
|
931
|
|
|
$this->setSelectedItemIndex($item->getItemIndex()); |
|
932
|
|
|
} |
|
933
|
|
|
$this->onSelectedIndexChanged($param); |
|
934
|
|
|
return true; |
|
935
|
|
|
} elseif (strcasecmp($command, self::CMD_EDIT) === 0) { |
|
936
|
|
|
$this->onEditCommand($param); |
|
937
|
|
|
return true; |
|
938
|
|
|
} elseif (strcasecmp($command, self::CMD_DELETE) === 0) { |
|
939
|
|
|
$this->onDeleteCommand($param); |
|
940
|
|
|
return true; |
|
941
|
|
|
} elseif (strcasecmp($command, self::CMD_UPDATE) === 0) { |
|
942
|
|
|
$this->onUpdateCommand($param); |
|
943
|
|
|
return true; |
|
944
|
|
|
} elseif (strcasecmp($command, self::CMD_CANCEL) === 0) { |
|
945
|
|
|
$this->onCancelCommand($param); |
|
946
|
|
|
return true; |
|
947
|
|
|
} |
|
948
|
|
|
} |
|
949
|
|
|
return false; |
|
950
|
|
|
} |
|
951
|
|
|
|
|
952
|
|
|
|
|
953
|
|
|
/** |
|
954
|
|
|
* Raises <b>OnItemCreated</b> event. |
|
955
|
|
|
* This method is invoked after a data list item is created and instantiated with |
|
956
|
|
|
* template, but before added to the page hierarchy. |
|
957
|
|
|
* The datalist item control responsible for the event |
|
958
|
|
|
* can be determined from the event parameter. |
|
959
|
|
|
* If you override this method, be sure to call parent's implementation |
|
960
|
|
|
* so that event handlers have chance to respond to the event. |
|
961
|
|
|
* @param TDataListItemEventParameter $param event parameter |
|
962
|
|
|
*/ |
|
963
|
|
|
public function onItemCreated($param) |
|
964
|
|
|
{ |
|
965
|
|
|
$this->raiseEvent('OnItemCreated', $this, $param); |
|
966
|
|
|
} |
|
967
|
|
|
|
|
968
|
|
|
/** |
|
969
|
|
|
* Raises <b>OnItemDataBound</b> event. |
|
970
|
|
|
* This method is invoked right after an item is data bound. |
|
971
|
|
|
* The datalist item control responsible for the event |
|
972
|
|
|
* can be determined from the event parameter. |
|
973
|
|
|
* If you override this method, be sure to call parent's implementation |
|
974
|
|
|
* so that event handlers have chance to respond to the event. |
|
975
|
|
|
* @param TDataListItemEventParameter $param event parameter |
|
976
|
|
|
*/ |
|
977
|
|
|
public function onItemDataBound($param) |
|
978
|
|
|
{ |
|
979
|
|
|
$this->raiseEvent('OnItemDataBound', $this, $param); |
|
980
|
|
|
} |
|
981
|
|
|
|
|
982
|
|
|
/** |
|
983
|
|
|
* Raises <b>OnItemCommand</b> event. |
|
984
|
|
|
* This method is invoked when a child control of the data list |
|
985
|
|
|
* raises an <b>OnCommand</b> event. |
|
986
|
|
|
* @param TDataListCommandEventParameter $param event parameter |
|
987
|
|
|
*/ |
|
988
|
|
|
public function onItemCommand($param) |
|
989
|
|
|
{ |
|
990
|
|
|
$this->raiseEvent('OnItemCommand', $this, $param); |
|
991
|
|
|
} |
|
992
|
|
|
|
|
993
|
|
|
/** |
|
994
|
|
|
* Raises <b>OnEditCommand</b> event. |
|
995
|
|
|
* This method is invoked when a child control of the data list |
|
996
|
|
|
* raises an <b>OnCommand</b> event and the command name is 'edit' (case-insensitive). |
|
997
|
|
|
* @param TDataListCommandEventParameter $param event parameter |
|
998
|
|
|
*/ |
|
999
|
|
|
public function onEditCommand($param) |
|
1000
|
|
|
{ |
|
1001
|
|
|
$this->raiseEvent('OnEditCommand', $this, $param); |
|
1002
|
|
|
} |
|
1003
|
|
|
|
|
1004
|
|
|
/** |
|
1005
|
|
|
* Raises <b>OnDeleteCommand</b> event. |
|
1006
|
|
|
* This method is invoked when a child control of the data list |
|
1007
|
|
|
* raises an <b>OnCommand</b> event and the command name is 'delete' (case-insensitive). |
|
1008
|
|
|
* @param TDataListCommandEventParameter $param event parameter |
|
1009
|
|
|
*/ |
|
1010
|
|
|
public function onDeleteCommand($param) |
|
1011
|
|
|
{ |
|
1012
|
|
|
$this->raiseEvent('OnDeleteCommand', $this, $param); |
|
1013
|
|
|
} |
|
1014
|
|
|
|
|
1015
|
|
|
/** |
|
1016
|
|
|
* Raises <b>OnUpdateCommand</b> event. |
|
1017
|
|
|
* This method is invoked when a child control of the data list |
|
1018
|
|
|
* raises an <b>OnCommand</b> event and the command name is 'update' (case-insensitive). |
|
1019
|
|
|
* @param TDataListCommandEventParameter $param event parameter |
|
1020
|
|
|
*/ |
|
1021
|
|
|
public function onUpdateCommand($param) |
|
1022
|
|
|
{ |
|
1023
|
|
|
$this->raiseEvent('OnUpdateCommand', $this, $param); |
|
1024
|
|
|
} |
|
1025
|
|
|
|
|
1026
|
|
|
/** |
|
1027
|
|
|
* Raises <b>OnCancelCommand</b> event. |
|
1028
|
|
|
* This method is invoked when a child control of the data list |
|
1029
|
|
|
* raises an <b>OnCommand</b> event and the command name is 'cancel' (case-insensitive). |
|
1030
|
|
|
* @param TDataListCommandEventParameter $param event parameter |
|
1031
|
|
|
*/ |
|
1032
|
|
|
public function onCancelCommand($param) |
|
1033
|
|
|
{ |
|
1034
|
|
|
$this->raiseEvent('OnCancelCommand', $this, $param); |
|
1035
|
|
|
} |
|
1036
|
|
|
|
|
1037
|
|
|
/** |
|
1038
|
|
|
* Returns a value indicating whether this control contains header item. |
|
1039
|
|
|
* This method is required by {@link IRepeatInfoUser} interface. |
|
1040
|
|
|
* @return bool whether the datalist has header |
|
1041
|
|
|
*/ |
|
1042
|
|
|
public function getHasHeader() |
|
1043
|
|
|
{ |
|
1044
|
|
|
return ($this->getShowHeader() && ($this->_headerTemplate !== null || $this->getHeaderRenderer() !== '')); |
|
1045
|
|
|
} |
|
1046
|
|
|
|
|
1047
|
|
|
/** |
|
1048
|
|
|
* Returns a value indicating whether this control contains footer item. |
|
1049
|
|
|
* This method is required by {@link IRepeatInfoUser} interface. |
|
1050
|
|
|
* @return bool whether the datalist has footer |
|
1051
|
|
|
*/ |
|
1052
|
|
|
public function getHasFooter() |
|
1053
|
|
|
{ |
|
1054
|
|
|
return ($this->getShowFooter() && ($this->_footerTemplate !== null || $this->getFooterRenderer() !== '')); |
|
1055
|
|
|
} |
|
1056
|
|
|
|
|
1057
|
|
|
/** |
|
1058
|
|
|
* Returns a value indicating whether this control contains separator items. |
|
1059
|
|
|
* This method is required by {@link IRepeatInfoUser} interface. |
|
1060
|
|
|
* @return bool always false. |
|
1061
|
|
|
*/ |
|
1062
|
|
|
public function getHasSeparators() |
|
1063
|
|
|
{ |
|
1064
|
|
|
return $this->_separatorTemplate !== null || $this->getSeparatorRenderer() !== ''; |
|
1065
|
|
|
} |
|
1066
|
|
|
|
|
1067
|
|
|
/** |
|
1068
|
|
|
* Returns a style used for rendering items. |
|
1069
|
|
|
* This method is required by {@link IRepeatInfoUser} interface. |
|
1070
|
|
|
* @param string $itemType item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager) |
|
1071
|
|
|
* @param int $index index of the item being rendered |
|
1072
|
|
|
* @return TStyle item style |
|
1073
|
|
|
*/ |
|
1074
|
|
|
public function generateItemStyle($itemType, $index) |
|
1075
|
|
|
{ |
|
1076
|
|
|
if (($item = $this->getItem($itemType, $index)) !== null && ($item instanceof IStyleable) && $item->getHasStyle()) { |
|
1077
|
|
|
$style = $item->getStyle(); |
|
1078
|
|
|
$item->clearStyle(); |
|
1079
|
|
|
return $style; |
|
1080
|
|
|
} else { |
|
1081
|
|
|
return null; |
|
1082
|
|
|
} |
|
1083
|
|
|
} |
|
1084
|
|
|
|
|
1085
|
|
|
/** |
|
1086
|
|
|
* Renders an item in the list. |
|
1087
|
|
|
* This method is required by {@link IRepeatInfoUser} interface. |
|
1088
|
|
|
* @param THtmlWriter $writer writer for rendering purpose |
|
1089
|
|
|
* @param TRepeatInfo $repeatInfo repeat information |
|
1090
|
|
|
* @param string $itemType item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager) |
|
1091
|
|
|
* @param int $index zero-based index of the item in the item list |
|
1092
|
|
|
*/ |
|
1093
|
|
|
public function renderItem($writer, $repeatInfo, $itemType, $index) |
|
1094
|
|
|
{ |
|
1095
|
|
|
$item = $this->getItem($itemType, $index); |
|
1096
|
|
|
if ($repeatInfo->getRepeatLayout() === TRepeatLayout::Raw && get_class($item) === 'TDataListItem') { |
|
1097
|
|
|
$item->setTagName('div'); |
|
1098
|
|
|
} |
|
1099
|
|
|
$item->renderControl($writer); |
|
1100
|
|
|
} |
|
1101
|
|
|
|
|
1102
|
|
|
/** |
|
1103
|
|
|
* @param TListItemType $itemType item type |
|
1104
|
|
|
* @param int $index item index |
|
1105
|
|
|
* @return TControl data list item with the specified item type and index |
|
1106
|
|
|
*/ |
|
1107
|
|
|
private function getItem($itemType, $index) |
|
1108
|
|
|
{ |
|
1109
|
|
|
switch ($itemType) { |
|
1110
|
|
|
case TListItemType::Item: |
|
1111
|
|
|
case TListItemType::AlternatingItem: |
|
1112
|
|
|
case TListItemType::SelectedItem: |
|
1113
|
|
|
case TListItemType::EditItem: |
|
1114
|
|
|
return $this->getItems()->itemAt($index); |
|
1115
|
|
|
case TListItemType::Header: |
|
1116
|
|
|
return $this->getControls()->itemAt(0); |
|
1117
|
|
|
case TListItemType::Footer: |
|
1118
|
|
|
return $this->getControls()->itemAt($this->getControls()->getCount() - 1); |
|
1119
|
|
|
case TListItemType::Separator: |
|
1120
|
|
|
$i = $index + $index + 1; |
|
1121
|
|
|
if ($this->_headerTemplate !== null || $this->getHeaderRenderer() !== '') { |
|
1122
|
|
|
$i++; |
|
1123
|
|
|
} |
|
1124
|
|
|
return $this->getControls()->itemAt($i); |
|
1125
|
|
|
} |
|
1126
|
|
|
return null; |
|
1127
|
|
|
} |
|
1128
|
|
|
|
|
1129
|
|
|
/** |
|
1130
|
|
|
* Creates a datalist item. |
|
1131
|
|
|
* This method invokes {@link createItem} to create a new datalist item. |
|
1132
|
|
|
* @param int $itemIndex zero-based item index. |
|
1133
|
|
|
* @param TListItemType $itemType item type |
|
1134
|
|
|
* @return TControl the created item, null if item is not created |
|
1135
|
|
|
*/ |
|
1136
|
|
View Code Duplication |
private function createItemInternal($itemIndex, $itemType) |
|
|
|
|
|
|
1137
|
|
|
{ |
|
1138
|
|
|
if (($item = $this->createItem($itemIndex, $itemType)) !== null) { |
|
1139
|
|
|
$param = new TDataListItemEventParameter($item); |
|
|
|
|
|
|
1140
|
|
|
$this->onItemCreated($param); |
|
1141
|
|
|
$this->getControls()->add($item); |
|
1142
|
|
|
return $item; |
|
1143
|
|
|
} else { |
|
1144
|
|
|
return null; |
|
1145
|
|
|
} |
|
1146
|
|
|
} |
|
1147
|
|
|
|
|
1148
|
|
|
/** |
|
1149
|
|
|
* Creates a datalist item and performs databinding. |
|
1150
|
|
|
* This method invokes {@link createItem} to create a new datalist item. |
|
1151
|
|
|
* @param int $itemIndex zero-based item index. |
|
1152
|
|
|
* @param TListItemType $itemType item type |
|
1153
|
|
|
* @param mixed $dataItem data to be associated with the item |
|
1154
|
|
|
* @return TControl the created item, null if item is not created |
|
1155
|
|
|
*/ |
|
1156
|
|
View Code Duplication |
private function createItemWithDataInternal($itemIndex, $itemType, $dataItem) |
|
|
|
|
|
|
1157
|
|
|
{ |
|
1158
|
|
|
if (($item = $this->createItem($itemIndex, $itemType)) !== null) { |
|
1159
|
|
|
$param = new TDataListItemEventParameter($item); |
|
|
|
|
|
|
1160
|
|
|
if ($item instanceof \Prado\IDataRenderer) { |
|
1161
|
|
|
$item->setData($dataItem); |
|
1162
|
|
|
} |
|
1163
|
|
|
$this->onItemCreated($param); |
|
1164
|
|
|
$this->getControls()->add($item); |
|
1165
|
|
|
$item->dataBind(); |
|
1166
|
|
|
$this->onItemDataBound($param); |
|
1167
|
|
|
return $item; |
|
1168
|
|
|
} else { |
|
1169
|
|
|
return null; |
|
1170
|
|
|
} |
|
1171
|
|
|
} |
|
1172
|
|
|
|
|
1173
|
|
|
private function getAlternatingItemDisplay() |
|
1174
|
|
|
{ |
|
1175
|
|
|
if (($classPath = $this->getAlternatingItemRenderer()) === '' && $this->_alternatingItemTemplate === null) { |
|
1176
|
|
|
return [$this->getItemRenderer(), $this->_itemTemplate]; |
|
1177
|
|
|
} else { |
|
1178
|
|
|
return [$classPath, $this->_alternatingItemTemplate]; |
|
1179
|
|
|
} |
|
1180
|
|
|
} |
|
1181
|
|
|
|
|
1182
|
|
|
private function getSelectedItemDisplay($itemIndex) |
|
1183
|
|
|
{ |
|
1184
|
|
|
if (($classPath = $this->getSelectedItemRenderer()) === '' && $this->_selectedItemTemplate === null) { |
|
1185
|
|
|
if ($itemIndex % 2 === 0) { |
|
1186
|
|
|
return [$this->getItemRenderer(), $this->_itemTemplate]; |
|
1187
|
|
|
} else { |
|
1188
|
|
|
return $this->getAlternatingItemDisplay(); |
|
1189
|
|
|
} |
|
1190
|
|
|
} else { |
|
1191
|
|
|
return [$classPath, $this->_selectedItemTemplate]; |
|
1192
|
|
|
} |
|
1193
|
|
|
} |
|
1194
|
|
|
|
|
1195
|
|
|
private function getEditItemDisplay($itemIndex) |
|
1196
|
|
|
{ |
|
1197
|
|
|
if (($classPath = $this->getEditItemRenderer()) === '' && $this->_editItemTemplate === null) { |
|
1198
|
|
|
return $this->getSelectedItemDisplay($itemIndex); |
|
1199
|
|
|
} else { |
|
1200
|
|
|
return [$classPath, $this->_editItemTemplate]; |
|
1201
|
|
|
} |
|
1202
|
|
|
} |
|
1203
|
|
|
|
|
1204
|
|
|
/** |
|
1205
|
|
|
* Creates a datalist item instance based on the item type and index. |
|
1206
|
|
|
* @param int $itemIndex zero-based item index |
|
1207
|
|
|
* @param TListItemType $itemType item type |
|
1208
|
|
|
* @return TControl created datalist item |
|
1209
|
|
|
*/ |
|
1210
|
|
|
protected function createItem($itemIndex, $itemType) |
|
1211
|
|
|
{ |
|
1212
|
|
|
$template = null; |
|
1213
|
|
|
$classPath = null; |
|
1214
|
|
|
switch ($itemType) { |
|
1215
|
|
|
case TListItemType::Item: |
|
1216
|
|
|
$classPath = $this->getItemRenderer(); |
|
1217
|
|
|
$template = $this->_itemTemplate; |
|
1218
|
|
|
break; |
|
1219
|
|
|
case TListItemType::AlternatingItem: |
|
1220
|
|
|
list($classPath, $template) = $this->getAlternatingItemDisplay(); |
|
1221
|
|
|
break; |
|
1222
|
|
|
case TListItemType::SelectedItem: |
|
1223
|
|
|
list($classPath, $template) = $this->getSelectedItemDisplay($itemIndex); |
|
1224
|
|
|
break; |
|
1225
|
|
|
case TListItemType::EditItem: |
|
1226
|
|
|
list($classPath, $template) = $this->getEditItemDisplay($itemIndex); |
|
1227
|
|
|
break; |
|
1228
|
|
|
case TListItemType::Header: |
|
1229
|
|
|
$classPath = $this->getHeaderRenderer(); |
|
1230
|
|
|
$template = $this->_headerTemplate; |
|
1231
|
|
|
break; |
|
1232
|
|
|
case TListItemType::Footer: |
|
1233
|
|
|
$classPath = $this->getFooterRenderer(); |
|
1234
|
|
|
$template = $this->_footerTemplate; |
|
1235
|
|
|
break; |
|
1236
|
|
|
case TListItemType::Separator: |
|
1237
|
|
|
$classPath = $this->getSeparatorRenderer(); |
|
1238
|
|
|
$template = $this->_separatorTemplate; |
|
1239
|
|
|
break; |
|
1240
|
|
|
default: |
|
1241
|
|
|
throw new TInvalidDataValueException('datalist_itemtype_unknown', $itemType); |
|
1242
|
|
|
} |
|
1243
|
|
View Code Duplication |
if ($classPath !== '') { |
|
|
|
|
|
|
1244
|
|
|
$item = Prado::createComponent($classPath); |
|
1245
|
|
|
if ($item instanceof IItemDataRenderer) { |
|
1246
|
|
|
$item->setItemIndex($itemIndex); |
|
1247
|
|
|
$item->setItemType($itemType); |
|
1248
|
|
|
} |
|
1249
|
|
|
} elseif ($template !== null) { |
|
1250
|
|
|
$item = new TDataListItem; |
|
1251
|
|
|
$item->setItemIndex($itemIndex); |
|
1252
|
|
|
$item->setItemType($itemType); |
|
1253
|
|
|
$template->instantiateIn($item); |
|
1254
|
|
|
} else { |
|
1255
|
|
|
$item = null; |
|
1256
|
|
|
} |
|
1257
|
|
|
|
|
1258
|
|
|
return $item; |
|
1259
|
|
|
} |
|
1260
|
|
|
|
|
1261
|
|
|
/** |
|
1262
|
|
|
* Creates empty datalist content. |
|
1263
|
|
|
*/ |
|
1264
|
|
View Code Duplication |
protected function createEmptyContent() |
|
|
|
|
|
|
1265
|
|
|
{ |
|
1266
|
|
|
if (($classPath = $this->getEmptyRenderer()) !== '') { |
|
1267
|
|
|
$this->getControls()->add(Prado::createComponent($classPath)); |
|
1268
|
|
|
} elseif ($this->_emptyTemplate !== null) { |
|
1269
|
|
|
$this->_emptyTemplate->instantiateIn($this); |
|
1270
|
|
|
} |
|
1271
|
|
|
} |
|
1272
|
|
|
|
|
1273
|
|
|
/** |
|
1274
|
|
|
* Applies styles to items, header, footer and separators. |
|
1275
|
|
|
* Item styles are applied in a hierarchical way. Style in higher hierarchy |
|
1276
|
|
|
* will inherit from styles in lower hierarchy. |
|
1277
|
|
|
* Starting from the lowest hierarchy, the item styles include |
|
1278
|
|
|
* item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle}, |
|
1279
|
|
|
* {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}. |
|
1280
|
|
|
* Therefore, if background color is set as red in {@link getItemStyle ItemStyle}, |
|
1281
|
|
|
* {@link getEditItemStyle EditItemStyle} will also have red background color |
|
1282
|
|
|
* unless it is set to a different value explicitly. |
|
1283
|
|
|
*/ |
|
1284
|
|
|
protected function applyItemStyles() |
|
1285
|
|
|
{ |
|
1286
|
|
|
$itemStyle = $this->getViewState('ItemStyle', null); |
|
1287
|
|
|
|
|
1288
|
|
|
$alternatingItemStyle = $this->getViewState('AlternatingItemStyle', null); |
|
1289
|
|
View Code Duplication |
if ($itemStyle !== null) { |
|
|
|
|
|
|
1290
|
|
|
if ($alternatingItemStyle === null) { |
|
1291
|
|
|
$alternatingItemStyle = $itemStyle; |
|
1292
|
|
|
} else { |
|
1293
|
|
|
$alternatingItemStyle->mergeWith($itemStyle); |
|
1294
|
|
|
} |
|
1295
|
|
|
} |
|
1296
|
|
|
|
|
1297
|
|
|
$selectedItemStyle = $this->getViewState('SelectedItemStyle', null); |
|
1298
|
|
|
|
|
1299
|
|
|
$editItemStyle = $this->getViewState('EditItemStyle', null); |
|
1300
|
|
View Code Duplication |
if ($selectedItemStyle !== null) { |
|
|
|
|
|
|
1301
|
|
|
if ($editItemStyle === null) { |
|
1302
|
|
|
$editItemStyle = $selectedItemStyle; |
|
1303
|
|
|
} else { |
|
1304
|
|
|
$editItemStyle->mergeWith($selectedItemStyle); |
|
1305
|
|
|
} |
|
1306
|
|
|
} |
|
1307
|
|
|
|
|
1308
|
|
|
// apply header style if any |
|
1309
|
|
View Code Duplication |
if ($this->_header !== null && $this->_header instanceof IStyleable) { |
|
|
|
|
|
|
1310
|
|
|
if ($headerStyle = $this->getViewState('HeaderStyle', null)) { |
|
1311
|
|
|
$this->_header->getStyle()->mergeWith($headerStyle); |
|
1312
|
|
|
} |
|
1313
|
|
|
} |
|
1314
|
|
|
|
|
1315
|
|
|
// apply footer style if any |
|
1316
|
|
View Code Duplication |
if ($this->_footer !== null && $this->_footer instanceof IStyleable) { |
|
|
|
|
|
|
1317
|
|
|
if ($footerStyle = $this->getViewState('FooterStyle', null)) { |
|
1318
|
|
|
$this->_footer->getStyle()->mergeWith($footerStyle); |
|
1319
|
|
|
} |
|
1320
|
|
|
} |
|
1321
|
|
|
|
|
1322
|
|
|
$selectedIndex = $this->getSelectedItemIndex(); |
|
1323
|
|
|
$editIndex = $this->getEditItemIndex(); |
|
1324
|
|
|
|
|
1325
|
|
|
// apply item styles if any |
|
1326
|
|
|
foreach ($this->getItems() as $index => $item) { |
|
1327
|
|
|
if ($index === $editIndex) { |
|
1328
|
|
|
$style = $editItemStyle; |
|
1329
|
|
|
} elseif ($index === $selectedIndex) { |
|
1330
|
|
|
$style = $selectedItemStyle; |
|
1331
|
|
|
} elseif ($index % 2 === 0) { |
|
1332
|
|
|
$style = $itemStyle; |
|
1333
|
|
|
} else { |
|
1334
|
|
|
$style = $alternatingItemStyle; |
|
1335
|
|
|
} |
|
1336
|
|
|
if ($style && $item instanceof IStyleable) { |
|
1337
|
|
|
$item->getStyle()->mergeWith($style); |
|
1338
|
|
|
} |
|
1339
|
|
|
} |
|
1340
|
|
|
|
|
1341
|
|
|
// apply separator style if any |
|
1342
|
|
|
if (($separatorStyle = $this->getViewState('SeparatorStyle', null)) !== null && $this->getHasSeparators()) { |
|
1343
|
|
|
$controls = $this->getControls(); |
|
1344
|
|
|
$count = $controls->getCount(); |
|
1345
|
|
|
for ($i = $this->_header ? 2 : 1;$i < $count;$i += 2) { |
|
1346
|
|
|
if (($separator = $controls->itemAt($i)) instanceof IStyleable) { |
|
1347
|
|
|
$separator->getStyle()->mergeWith($separatorStyle); |
|
1348
|
|
|
} |
|
1349
|
|
|
} |
|
1350
|
|
|
} |
|
1351
|
|
|
} |
|
1352
|
|
|
|
|
1353
|
|
|
/** |
|
1354
|
|
|
* Saves item count in viewstate. |
|
1355
|
|
|
* This method is invoked right before control state is to be saved. |
|
1356
|
|
|
*/ |
|
1357
|
|
View Code Duplication |
public function saveState() |
|
|
|
|
|
|
1358
|
|
|
{ |
|
1359
|
|
|
parent::saveState(); |
|
1360
|
|
|
if ($this->_items) { |
|
1361
|
|
|
$this->setViewState('ItemCount', $this->_items->getCount(), 0); |
|
1362
|
|
|
} else { |
|
1363
|
|
|
$this->clearViewState('ItemCount'); |
|
1364
|
|
|
} |
|
1365
|
|
|
} |
|
1366
|
|
|
|
|
1367
|
|
|
/** |
|
1368
|
|
|
* Loads item count information from viewstate. |
|
1369
|
|
|
* This method is invoked right after control state is loaded. |
|
1370
|
|
|
*/ |
|
1371
|
|
|
public function loadState() |
|
1372
|
|
|
{ |
|
1373
|
|
|
parent::loadState(); |
|
1374
|
|
|
if (!$this->getIsDataBound()) { |
|
1375
|
|
|
$this->restoreItemsFromViewState(); |
|
1376
|
|
|
} |
|
1377
|
|
|
$this->clearViewState('ItemCount'); |
|
1378
|
|
|
} |
|
1379
|
|
|
|
|
1380
|
|
|
/** |
|
1381
|
|
|
* Clears up all items in the data list. |
|
1382
|
|
|
*/ |
|
1383
|
|
View Code Duplication |
public function reset() |
|
|
|
|
|
|
1384
|
|
|
{ |
|
1385
|
|
|
$this->getControls()->clear(); |
|
1386
|
|
|
$this->getItems()->clear(); |
|
1387
|
|
|
$this->_header = null; |
|
1388
|
|
|
$this->_footer = null; |
|
1389
|
|
|
} |
|
1390
|
|
|
|
|
1391
|
|
|
/** |
|
1392
|
|
|
* Creates data list items based on viewstate information. |
|
1393
|
|
|
*/ |
|
1394
|
|
|
protected function restoreItemsFromViewState() |
|
1395
|
|
|
{ |
|
1396
|
|
|
$this->reset(); |
|
1397
|
|
|
if (($itemCount = $this->getViewState('ItemCount', 0)) > 0) { |
|
1398
|
|
|
$items = $this->getItems(); |
|
1399
|
|
|
$selectedIndex = $this->getSelectedItemIndex(); |
|
1400
|
|
|
$editIndex = $this->getEditItemIndex(); |
|
1401
|
|
|
$hasSeparator = $this->_separatorTemplate !== null || $this->getSeparatorRenderer() !== ''; |
|
1402
|
|
|
$this->_header = $this->createItemInternal(-1, TListItemType::Header); |
|
|
|
|
|
|
1403
|
|
|
for ($i = 0;$i < $itemCount;++$i) { |
|
1404
|
|
|
if ($hasSeparator && $i > 0) { |
|
1405
|
|
|
$this->createItemInternal($i - 1, TListItemType::Separator); |
|
1406
|
|
|
} |
|
1407
|
|
View Code Duplication |
if ($i === $editIndex) { |
|
|
|
|
|
|
1408
|
|
|
$itemType = TListItemType::EditItem; |
|
1409
|
|
|
} elseif ($i === $selectedIndex) { |
|
1410
|
|
|
$itemType = TListItemType::SelectedItem; |
|
1411
|
|
|
} else { |
|
1412
|
|
|
$itemType = $i % 2 ? TListItemType::AlternatingItem : TListItemType::Item; |
|
1413
|
|
|
} |
|
1414
|
|
|
$items->add($this->createItemInternal($i, $itemType)); |
|
1415
|
|
|
} |
|
1416
|
|
|
$this->_footer = $this->createItemInternal(-1, TListItemType::Footer); |
|
|
|
|
|
|
1417
|
|
|
} else { |
|
1418
|
|
|
$this->createEmptyContent(); |
|
1419
|
|
|
} |
|
1420
|
|
|
$this->clearChildState(); |
|
1421
|
|
|
} |
|
1422
|
|
|
|
|
1423
|
|
|
/** |
|
1424
|
|
|
* Performs databinding to populate data list items from data source. |
|
1425
|
|
|
* This method is invoked by dataBind(). |
|
1426
|
|
|
* You may override this function to provide your own way of data population. |
|
1427
|
|
|
* @param Traversable $data the data |
|
1428
|
|
|
*/ |
|
1429
|
|
|
protected function performDataBinding($data) |
|
1430
|
|
|
{ |
|
1431
|
|
|
$this->reset(); |
|
1432
|
|
|
$keys = $this->getDataKeys(); |
|
1433
|
|
|
$keys->clear(); |
|
1434
|
|
|
$keyField = $this->getDataKeyField(); |
|
1435
|
|
|
$itemIndex = 0; |
|
1436
|
|
|
$items = $this->getItems(); |
|
1437
|
|
|
$hasSeparator = $this->_separatorTemplate !== null || $this->getSeparatorRenderer() !== ''; |
|
1438
|
|
|
$selectedIndex = $this->getSelectedItemIndex(); |
|
1439
|
|
|
$editIndex = $this->getEditItemIndex(); |
|
1440
|
|
|
foreach ($data as $key => $dataItem) { |
|
1441
|
|
|
if ($keyField !== '') { |
|
1442
|
|
|
$keys->add($this->getDataFieldValue($dataItem, $keyField)); |
|
1443
|
|
|
} else { |
|
1444
|
|
|
$keys->add($key); |
|
1445
|
|
|
} |
|
1446
|
|
|
if ($itemIndex === 0) { |
|
1447
|
|
|
$this->_header = $this->createItemWithDataInternal(-1, TListItemType::Header, null); |
|
|
|
|
|
|
1448
|
|
|
} |
|
1449
|
|
|
if ($hasSeparator && $itemIndex > 0) { |
|
1450
|
|
|
$this->createItemWithDataInternal($itemIndex - 1, TListItemType::Separator, null); |
|
1451
|
|
|
} |
|
1452
|
|
View Code Duplication |
if ($itemIndex === $editIndex) { |
|
|
|
|
|
|
1453
|
|
|
$itemType = TListItemType::EditItem; |
|
1454
|
|
|
} elseif ($itemIndex === $selectedIndex) { |
|
1455
|
|
|
$itemType = TListItemType::SelectedItem; |
|
1456
|
|
|
} else { |
|
1457
|
|
|
$itemType = $itemIndex % 2 ? TListItemType::AlternatingItem : TListItemType::Item; |
|
1458
|
|
|
} |
|
1459
|
|
|
$items->add($this->createItemWithDataInternal($itemIndex, $itemType, $dataItem)); |
|
1460
|
|
|
$itemIndex++; |
|
1461
|
|
|
} |
|
1462
|
|
View Code Duplication |
if ($itemIndex > 0) { |
|
|
|
|
|
|
1463
|
|
|
$this->_footer = $this->createItemWithDataInternal(-1, TListItemType::Footer, null); |
|
|
|
|
|
|
1464
|
|
|
} else { |
|
1465
|
|
|
$this->createEmptyContent(); |
|
1466
|
|
|
$this->dataBindChildren(); |
|
1467
|
|
|
} |
|
1468
|
|
|
$this->setViewState('ItemCount', $itemIndex, 0); |
|
1469
|
|
|
} |
|
1470
|
|
|
|
|
1471
|
|
|
/** |
|
1472
|
|
|
* Renders the data list control. |
|
1473
|
|
|
* This method overrides the parent implementation. |
|
1474
|
|
|
* @param THtmlWriter $writer writer for rendering purpose. |
|
1475
|
|
|
*/ |
|
1476
|
|
|
public function render($writer) |
|
1477
|
|
|
{ |
|
1478
|
|
|
if ($this->getHasControls()) { |
|
1479
|
|
|
if ($this->getItemCount() > 0) { |
|
1480
|
|
|
$this->applyItemStyles(); |
|
1481
|
|
|
$repeatInfo = $this->getRepeatInfo(); |
|
1482
|
|
|
$repeatInfo->renderRepeater($writer, $this); |
|
1483
|
|
|
} elseif ($this->_emptyTemplate !== null || $this->getEmptyRenderer() !== '') { |
|
1484
|
|
|
parent::render($writer); |
|
1485
|
|
|
} |
|
1486
|
|
|
} |
|
1487
|
|
|
} |
|
1488
|
|
|
} |
|
1489
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.