1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Ajax\semantic\widgets\datatable; |
4
|
|
|
|
5
|
|
|
use Ajax\common\Widget; |
6
|
|
|
use Ajax\JsUtils; |
7
|
|
|
use Ajax\semantic\html\collections\table\HtmlTable; |
8
|
|
|
use Ajax\semantic\html\elements\HtmlInput; |
9
|
|
|
use Ajax\semantic\html\collections\menus\HtmlPaginationMenu; |
10
|
|
|
use Ajax\semantic\html\modules\checkbox\HtmlCheckbox; |
11
|
|
|
use Ajax\semantic\html\elements\HtmlButton; |
12
|
|
|
use Ajax\semantic\html\base\constants\Direction; |
13
|
|
|
use Ajax\service\JArray; |
14
|
|
|
use Ajax\semantic\html\base\HtmlSemDoubleElement; |
15
|
|
|
use Ajax\semantic\widgets\base\InstanceViewer; |
16
|
|
|
use Ajax\semantic\html\collections\table\traits\TableTrait; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* DataTable widget for displaying list of objects |
20
|
|
|
* @version 1.0 |
21
|
|
|
* @author jc |
22
|
|
|
* @since 2.2 |
23
|
|
|
* |
24
|
|
|
*/ |
25
|
|
|
class DataTable extends Widget { |
26
|
|
|
use TableTrait; |
27
|
|
|
protected $_searchField; |
28
|
|
|
protected $_urls; |
29
|
|
|
protected $_pagination; |
30
|
|
|
protected $_hasCheckboxes; |
31
|
|
|
protected $_compileParts; |
32
|
|
|
|
33
|
|
|
public function run(JsUtils $js){ |
34
|
|
|
if($this->_hasCheckboxes && isset($js)){ |
35
|
|
|
$js->execOn("change", "#".$this->identifier." [name='selection[]']", " |
36
|
|
|
var \$parentCheckbox=\$('#ck-main-ck-{$this->identifier}'),\$checkbox=\$('#{$this->identifier} [name=\"selection[]\"]'),allChecked=true,allUnchecked=true; |
37
|
|
|
\$checkbox.each(function() {if($(this).prop('checked')){allUnchecked = false;}else{allChecked = false;}}); |
38
|
|
|
if(allChecked) {\$parentCheckbox.checkbox('set checked');}else if(allUnchecked){\$parentCheckbox.checkbox('set unchecked');}else{\$parentCheckbox.checkbox('set indeterminate');}"); |
39
|
|
|
} |
40
|
|
|
parent::run($js); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
View Code Duplication |
public function __construct($identifier,$model,$modelInstance=NULL) { |
|
|
|
|
44
|
|
|
parent::__construct($identifier, $model,$modelInstance); |
45
|
|
|
$this->_instanceViewer=new InstanceViewer($identifier); |
46
|
|
|
$this->content=["table"=>new HtmlTable($identifier, 0,0)]; |
47
|
|
|
$this->_toolbarPosition=PositionInTable::BEFORETABLE; |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* {@inheritDoc} |
52
|
|
|
* @see \Ajax\semantic\html\collections\table\TableTrait::getTable() |
53
|
|
|
*/ |
54
|
|
|
protected function getTable() { |
55
|
|
|
return $this->content["table"]; |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
|
59
|
|
|
public function compile(JsUtils $js=NULL,&$view=NULL){ |
60
|
|
|
$this->_instanceViewer->setInstance($this->_model); |
61
|
|
|
$captions=$this->_instanceViewer->getCaptions(); |
62
|
|
|
|
63
|
|
|
$table=$this->content["table"]; |
64
|
|
|
|
65
|
|
|
if($this->_hasCheckboxes){ |
66
|
|
|
$this->_generateMainCheckbox($captions); |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
$table->setRowCount(0, \sizeof($captions)); |
70
|
|
|
$table->setHeaderValues($captions); |
71
|
|
|
if(isset($this->_compileParts)) |
72
|
|
|
$table->setCompileParts($this->_compileParts); |
73
|
|
|
if(isset($this->_searchField) && isset($js)){ |
74
|
|
|
$this->_searchField->postOn("change", $this->_urls,"{'s':$(this).val()}","-#".$this->identifier." tbody",["preventDefault"=>false]); |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
$this->_generateContent($table); |
78
|
|
|
|
79
|
|
|
if($this->_hasCheckboxes && $table->hasPart("thead")){ |
80
|
|
|
$table->getHeader()->getCell(0, 0)->addToProperty("class","no-sort"); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
if(isset($this->_pagination) && $this->_pagination->getVisible()){ |
84
|
|
|
$this->_generatePagination($table); |
85
|
|
|
} |
86
|
|
|
if(isset($this->_toolbar)){ |
87
|
|
|
$this->_setToolbarPosition($table, $captions); |
88
|
|
|
} |
89
|
|
|
$this->content=JArray::sortAssociative($this->content, [PositionInTable::BEFORETABLE,"table",PositionInTable::AFTERTABLE]); |
90
|
|
|
return parent::compile($js,$view); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
private function _generateMainCheckbox(&$captions){ |
94
|
|
|
$ck=new HtmlCheckbox("main-ck-".$this->identifier,""); |
95
|
|
|
$ck->setOnChecked("$('#".$this->identifier." [name=%quote%selection[]%quote%]').prop('checked',true);"); |
96
|
|
|
$ck->setOnUnchecked("$('#".$this->identifier." [name=%quote%selection[]%quote%]').prop('checked',false);"); |
97
|
|
|
\array_unshift($captions, $ck); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
protected function _generateContent($table){ |
101
|
|
|
$objects=$this->_modelInstance; |
102
|
|
|
if(isset($this->_pagination)){ |
103
|
|
|
$objects=$this->_pagination->getObjects($this->_modelInstance); |
104
|
|
|
} |
105
|
|
|
InstanceViewer::setIndex(0); |
106
|
|
|
$table->fromDatabaseObjects($objects, function($instance){ |
107
|
|
|
$this->_instanceViewer->setInstance($instance); |
108
|
|
|
InstanceViewer::$index++; |
109
|
|
|
$result= $this->_instanceViewer->getValues(); |
110
|
|
|
if($this->_hasCheckboxes){ |
111
|
|
|
$ck=new HtmlCheckbox("ck-".$this->identifier,""); |
112
|
|
|
$field=$ck->getField(); |
113
|
|
|
$field->setProperty("value",$this->_instanceViewer->getIdentifier()); |
114
|
|
|
$field->setProperty("name", "selection[]"); |
115
|
|
|
\array_unshift($result, $ck); |
116
|
|
|
} |
117
|
|
|
return $result; |
118
|
|
|
}); |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
private function _generatePagination($table){ |
122
|
|
|
$footer=$table->getFooter(); |
123
|
|
|
$footer->mergeCol(); |
124
|
|
|
$menu=new HtmlPaginationMenu("pagination-".$this->identifier,$this->_pagination->getPagesNumbers()); |
125
|
|
|
$menu->floatRight(); |
126
|
|
|
$menu->setActiveItem($this->_pagination->getPage()-1); |
127
|
|
|
$footer->setValues($menu); |
128
|
|
|
$menu->postOnClick($this->_urls,"{'p':$(this).attr('data-page')}","-#".$this->identifier." tbody",["preventDefault"=>false]); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
protected function _setToolbarPosition($table,$captions=NULL){ |
132
|
|
|
switch ($this->_toolbarPosition){ |
133
|
|
|
case PositionInTable::BEFORETABLE:case PositionInTable::AFTERTABLE: |
|
|
|
|
134
|
|
|
if(isset($this->_compileParts)===false){ |
135
|
|
|
$this->content[$this->_toolbarPosition]=$this->_toolbar; |
136
|
|
|
} |
137
|
|
|
break; |
138
|
|
|
case PositionInTable::HEADER:case PositionInTable::FOOTER: case PositionInTable::BODY: |
|
|
|
|
139
|
|
|
$this->addToolbarRow($this->_toolbarPosition,$table, $captions); |
140
|
|
|
break; |
141
|
|
|
} |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
/** |
145
|
|
|
* Associates a $callback function after the compilation of the field at $index position |
146
|
|
|
* The $callback function can take the following arguments : $field=>the compiled field, $instance : the active instance of the object, $index: the field position |
147
|
|
|
* @param int $index postion of the compiled field |
148
|
|
|
* @param callable $callback function called after the field compilation |
149
|
|
|
* @return \Ajax\semantic\widgets\datatable\DataTable |
150
|
|
|
*/ |
151
|
|
|
public function afterCompile($index,$callback){ |
152
|
|
|
$this->_instanceViewer->afterCompile($index,$callback); |
153
|
|
|
return $this; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
private function addToolbarRow($part,$table,$captions){ |
157
|
|
|
$row=$table->getPart($part)->addRow(\sizeof($captions)); |
158
|
|
|
$row->mergeCol(); |
159
|
|
|
$row->setValues([$this->_toolbar]); |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
public function getHtmlComponent(){ |
163
|
|
|
return $this->content["table"]; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
public function getUrls() { |
167
|
|
|
return $this->_urls; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
public function setUrls($urls) { |
171
|
|
|
$this->_urls=$urls; |
172
|
|
|
return $this; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
public function paginate($items_per_page=10,$page=1){ |
176
|
|
|
$this->_pagination=new Pagination($items_per_page,4,$page); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
public function getHasCheckboxes() { |
180
|
|
|
return $this->_hasCheckboxes; |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
public function setHasCheckboxes($_hasCheckboxes) { |
184
|
|
|
$this->_hasCheckboxes=$_hasCheckboxes; |
185
|
|
|
return $this; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
public function refresh($compileParts=["tbody"]){ |
189
|
|
|
$this->_compileParts=$compileParts; |
190
|
|
|
return $this; |
191
|
|
|
} |
192
|
|
|
/** |
193
|
|
|
* @param string $caption |
194
|
|
|
* @param callable $callback |
195
|
|
|
* @return callable |
196
|
|
|
*/ |
197
|
|
|
private function getFieldButtonCallable($caption,$callback=null){ |
198
|
|
|
return $this->getCallable("getFieldButton",[$caption],$callback); |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* @param mixed $object |
|
|
|
|
203
|
|
|
* @param callable $callback |
204
|
|
|
* @return callable |
205
|
|
|
*/ |
206
|
|
|
private function getCallable($thisCallback,$parameters,$callback=null){ |
207
|
|
|
$result=function($instance) use($thisCallback,$parameters,$callback){ |
208
|
|
|
$object=call_user_func_array(array($this,$thisCallback), $parameters); |
209
|
|
|
if(isset($callback)){ |
210
|
|
|
if(\is_callable($callback)){ |
211
|
|
|
$callback($object,$instance); |
212
|
|
|
} |
213
|
|
|
} |
214
|
|
|
if($object instanceof HtmlSemDoubleElement){ |
215
|
|
|
$object->setProperty("data-ajax",$this->_instanceViewer->getIdentifier()); |
216
|
|
|
} |
217
|
|
|
return $object; |
218
|
|
|
}; |
219
|
|
|
return $result; |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* @param string $caption |
224
|
|
|
* @return HtmlButton |
225
|
|
|
*/ |
226
|
|
|
private function getFieldButton($caption){ |
227
|
|
|
return new HtmlButton("",$caption); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* Inserts a new Button for each row |
232
|
|
|
* @param string $caption |
233
|
|
|
* @param callable $callback |
234
|
|
|
* @return \Ajax\semantic\widgets\datatable\DataTable |
235
|
|
|
*/ |
236
|
|
|
public function addFieldButton($caption,$callback=null){ |
237
|
|
|
$this->addField($this->getCallable("getFieldButton",[$caption],$callback)); |
238
|
|
|
return $this; |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Inserts a new Button for each row at col $index |
243
|
|
|
* @param int $index |
244
|
|
|
* @param string $caption |
245
|
|
|
* @param callable $callback |
246
|
|
|
* @return \Ajax\semantic\widgets\datatable\DataTable |
247
|
|
|
*/ |
248
|
|
|
public function insertFieldButton($index,$caption,$callback=null){ |
249
|
|
|
$this->insertField($index, $this->getFieldButtonCallable($caption,$callback)); |
250
|
|
|
return $this; |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
/** |
254
|
|
|
* Inserts a new Button for each row in col at $index |
255
|
|
|
* @param int $index |
256
|
|
|
* @param string $caption |
257
|
|
|
* @param callable $callback |
258
|
|
|
* @return \Ajax\semantic\widgets\datatable\DataTable |
259
|
|
|
*/ |
260
|
|
|
public function insertInFieldButton($index,$caption,$callback=null){ |
261
|
|
|
$this->insertInField($index, $this->getFieldButtonCallable($caption,$callback)); |
262
|
|
|
return $this; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
private function addDefaultButton($icon,$class=null,$callback=null){ |
266
|
|
|
$this->addField($this->getCallable("getDefaultButton",[$icon,$class],$callback)); |
267
|
|
|
return $this; |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
private function insertDefaultButtonIn($index,$icon,$class=null,$callback=null){ |
271
|
|
|
$this->insertInField($index,$this->getCallable("getDefaultButton",[$icon,$class],$callback)); |
272
|
|
|
return $this; |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
private function getDefaultButton($icon,$class=null){ |
276
|
|
|
$bt=$this->getFieldButton(""); |
277
|
|
|
$bt->asIcon($icon); |
278
|
|
|
if(isset($class)) |
279
|
|
|
$bt->addToProperty("class", $class); |
280
|
|
|
return $bt; |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
public function addDeleteButton($callback=null){ |
284
|
|
|
return $this->addDefaultButton("remove","delete red basic",$callback); |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
public function addEditButton($callback=null){ |
288
|
|
|
return $this->addDefaultButton("edit","edit basic",$callback); |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
public function addEditDeleteButtons($callbackEdit=null,$callbackDelete=null){ |
292
|
|
|
$this->addEditButton($callbackEdit); |
293
|
|
|
$index=$this->_instanceViewer->visiblePropertiesCount()-1; |
294
|
|
|
$this->insertDeleteButtonIn($index,$callbackDelete); |
295
|
|
|
return $this; |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
public function insertDeleteButtonIn($index,$callback=null){ |
299
|
|
|
return $this->insertDefaultButtonIn($index,"remove","delete red basic",$callback); |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
public function insertEditButtonIn($index,$callback=null){ |
303
|
|
|
return $this->insertDefaultButtonIn($index,"edit","edit basic",$callback); |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
public function addSearchInToolbar($position=Direction::RIGHT){ |
307
|
|
|
return $this->addInToolbar($this->getSearchField())->setPosition($position); |
|
|
|
|
308
|
|
|
} |
309
|
|
|
|
310
|
|
|
public function getSearchField(){ |
311
|
|
|
if(isset($this->_searchField)===false){ |
312
|
|
|
$this->_searchField=new HtmlInput("search-".$this->identifier,"search","","Search..."); |
313
|
|
|
$this->_searchField->addIcon("search",Direction::RIGHT); |
314
|
|
|
} |
315
|
|
|
return $this->_searchField; |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
/** |
319
|
|
|
* The callback function called after the insertion of each row when fromDatabaseObjects is called |
320
|
|
|
* callback function takes the parameters $row : the row inserted and $object: the instance of model used |
321
|
|
|
* @param callable $callback |
322
|
|
|
* @return DataTable |
323
|
|
|
*/ |
324
|
|
|
public function onNewRow($callback) { |
325
|
|
|
$this->content["table"]->onNewRow($callback); |
326
|
|
|
return $this; |
327
|
|
|
} |
328
|
|
|
} |
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.