1 <?php
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
19 Yii::import('bootstrap.helpers.TbHtml');
20 Yii::import('bootstrap.widgets.TbGridView');
21
22 class WhGridView extends TbGridView
23 {
24 25 26
27 public = false;
28
29 30 31 32 33
34 public = 0;
35
36 37 38 39 40
41 public $template = "{summary}\n{items}\n{pager}\n{extendedSummary}";
42
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
72 public $extendedSummary = array();
73
74 75 76
77 public $extendedSummaryCssClass = 'extended-summary';
78
79 80 81
82 public $extendedSummaryOptions = array();
83
84 85 86 87 88
89 public $componentsAfterAjaxUpdate = array();
90
91 92 93 94 95
96 public $componentsReadyScripts = array();
97
98 99 100
101 public $chartOptions = array();
102
103 104 105
106 public $responsiveTable = false;
107
108 109 110 111
112 protected $displayExtendedSummary;
113
114 115 116
117 protected $extendedSummaryTypes = array();
118
119 120 121
122 protected $extendedSummaryOperations = array(
123 'yiiwheels.widgets.grid.operations.WhSumOperation',
124 'yiiwheels.widgets.grid.operations.WhCountOfTypeOperation',
125 'yiiwheels.widgets.grid.operations.WhPercentOfTypeOperation',
126 'yiiwheels.widgets.grid.operations.WhPercentOfTypeEasyPieOperation',
127 'yiiwheels.widgets.grid.operations.WhPercentOfTypeGooglePieOperation'
128 );
129
130 131 132
133 public function init()
134 {
135 if (preg_match(
136 '/extendedsummary/i',
137 $this->template
138 ) && !empty($this->extendedSummary) && isset($this->extendedSummary['columns'])
139 ) {
140 $this->template .= "\n{extendedSummaryContent}";
141 $this->displayExtendedSummary = true;
142 }
143
144 $this->attachBehavior('ywplugin', array('class' => 'yiiwheels.behaviors.WhPlugin'));
145 $this->attachBehavior('ywchart', array('class' => 'yiiwheels.widgets.grid.behaviors.WhChart'));
146
147 parent::init();
148 }
149
150 151 152
153 public function renderContent()
154 {
155 parent::renderContent();
156 $this->registerCustomClientScript();
157 }
158
159 160 161 162 163 164
165 protected function getAttribute($data, $attribute)
166 {
167 if ($this->dataProvider instanceof CActiveDataProvider && $data->hasAttribute($attribute)) {
168 return $data->{$attribute};
169 }
170
171 if ($this->dataProvider instanceof CArrayDataProvider || $this->dataProvider instanceof CSqlDataProvider) {
172 if (is_object($data) && isset($data->{$attribute})) {
173 return $data->{$attribute};
174 }
175 if (isset($data[$attribute])) {
176 return $data[$attribute];
177 }
178 }
179 return null;
180 }
181
182 183 184 185 186 187
188 protected function getPrimaryKey($data)
189 {
190 if ($this->dataProvider instanceof CActiveDataProvider) {
191 $key = $this->dataProvider->keyAttribute === null ? $data->getPrimaryKey() : $data->{$this->dataProvider->keyAttribute};
192 return is_array($key) ? implode(',', $key) : $key;
193 }
194 if ($this->dataProvider instanceof CArrayDataProvider || $this->dataProvider instanceof CSqlDataProvider) {
195 return is_object($data) ? $data->{$this->dataProvider->keyField}
196 : $data[$this->dataProvider->keyField];
197 }
198
199 return null;
200 }
201
202 203 204
205 public function ()
206 {
207 $this->renderChart();
208 parent::renderTableHeader();
209 }
210
211 212 213
214 public function ()
215 {
216 $hasFilter = $this->filter !== null && $this->filterPosition === self::FILTER_POS_FOOTER;
217 $hasFooter = $this->getHasFooter();
218 if ($hasFilter || $hasFooter) {
219 echo "<tfoot>\n";
220 if ($hasFooter) {
221 echo "<tr>\n";
222
223 foreach ($this->columns as $column) {
224 $column->renderFooterCell();
225 }
226 echo "</tr>\n";
227 }
228 if ($hasFilter) {
229 $this->renderFilter();
230 }
231 echo "</tfoot>\n";
232 }
233 }
234
235 236 237 238
239 public function renderTableRow($row)
240 {
241 $htmlOptions = array();
242 if ($this->rowHtmlOptionsExpression !== null) {
243 $data = $this->dataProvider->data[$row];
244 $options = $this->evaluateExpression(
245 $this->rowHtmlOptionsExpression,
246 array('row' => $row, 'data' => $data)
247 );
248 if (is_array($options)) {
249 $htmlOptions = $options;
250 }
251 }
252
253 if ($this->rowCssClassExpression !== null) {
254 $data = $this->dataProvider->data[$row];
255 $class = $this->evaluateExpression($this->rowCssClassExpression, array('row' => $row, 'data' => $data));
256 } elseif (is_array($this->rowCssClass) && ($n = count($this->rowCssClass)) > 0) {
257 $class = $this->rowCssClass[$row % $n];
258 }
259
260 if (!empty($class)) {
261 if (isset($htmlOptions['class'])) {
262 $htmlOptions['class'] .= ' ' . $class;
263 } else {
264 $htmlOptions['class'] = $class;
265 }
266 }
267
268 echo TbHtml::openTag('tr', $htmlOptions);
269 foreach ($this->columns as $column) {
270 echo $this->displayExtendedSummary && !empty($this->extendedSummary['columns']) ? $this->parseColumnValue(
271 $column,
272 $row
273 ) : $column->renderDataCell($row);
274 }
275 echo TbHtml::closeTag('tr');
276 }
277
278 279 280
281 public function renderExtendedSummary()
282 {
283 if (!isset($this->extendedSummaryOptions['class'])) {
284 $this->extendedSummaryOptions['class'] = $this->extendedSummaryCssClass;
285 } else {
286 $this->extendedSummaryOptions['class'] .= ' ' . $this->extendedSummaryCssClass;
287 }
288 echo '<div ' . TbHtml::renderAttributes($this->extendedSummaryOptions) . '></div>';
289 }
290
291 292 293
294 public function renderExtendedSummaryContent()
295 {
296 if (($count = $this->dataProvider->getItemCount()) <= 0) {
297 return;
298 }
299
300 if (!empty($this->extendedSummaryTypes)) {
301 echo '<div id="' . $this->id . '-extended-summary" style="display:none">';
302 if (isset($this->extendedSummary['title'])) {
303 echo '<h3>' . $this->extendedSummary['title'] . '</h3>';
304 }
305 foreach ($this->extendedSummaryTypes as $summaryType) {
306
307 $summaryType->run();
308 echo '<br/>';
309 }
310 echo '</div>';
311 }
312 }
313
314 315 316 317 318
319 public function registerCustomClientScript()
320 {
321
322 $path = __DIR__ . DIRECTORY_SEPARATOR . 'assets';
323 $assetsUrl = $this->getAssetsUrl($path);
324
325
326 $cs = Yii::app()->getClientScript();
327
328 $fixedHeaderJs = '';
329 if ($this->fixedHeader) {
330 $cs->registerScriptFile(
331 $assetsUrl . '/js/jquery.stickytableheaders' . (!YII_DEBUG ? '.min' : '') . '.js',
332 CClientScript::POS_END);
333 $fixedHeaderJs = "$('#{$this->id} table.items').stickyTableHeaders({fixedOffset:{$this->headerOffset}});";
334 $this->componentsAfterAjaxUpdate[] = $fixedHeaderJs;
335 }
336
337 $cs->registerScript(__CLASS__ . '#Wh' . $this->id,
338 '$grid = $("#' . $this->id . '");' .
339 $fixedHeaderJs . '
340 if ($(".' . $this->extendedSummaryCssClass . '", $grid).length)
341 {
342 $(".' . $this->extendedSummaryCssClass . '", $grid).html($("#' . $this->id . '-extended-summary", $grid).html());
343 }
344 ' . (count($this->componentsReadyScripts) ? implode("\n", $this->componentsReadyScripts) : '') . '
345 $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
346 var qs = $.deparam.querystring(options.url);
347 if (qs.hasOwnProperty("ajax") && qs.ajax == "' . $this->id . '")
348 {
349 options.realsuccess = options.success;
350 options.success = function(data)
351 {
352 if (options.realsuccess) {
353 options.realsuccess(data);
354 var $data = $("<div>" + data + "</div>");
355 // we need to get the grid again... as it has been updated
356 if ($(".' . $this->extendedSummaryCssClass . '", $("#' . $this->id . '")))
357 {
358 $(".' .
359 $this->extendedSummaryCssClass .
360 '", $("#' . $this->id .
361 '")).html($("#' . $this->id .
362 '-extended-summary", $data).html());
363 }
364 ' .
365 (count($this->componentsAfterAjaxUpdate)
366 ? implode("\n", $this->componentsAfterAjaxUpdate)
367 : '') .
368 '
369 }
370 }
371 }
372 });'
373 );
374 }
375
376 377 378 379 380
381 public function getColumnByName($name)
382 {
383 foreach ($this->columns as $column) {
384 if (strcmp($column->name, $name) === 0) {
385 return $column;
386 }
387 }
388 return null;
389 }
390
391 392 393
394 protected function initColumns()
395 {
396 parent::initColumns();
397 if($this->responsiveTable) {
398 $this->attachBehavior('ywresponsive', array('class' => 'yiiwheels.widgets.grid.behaviors.WhResponsive'));
399 $this->writeResponsiveCss($this->columns, $this->id);
400 }
401 }
402
403 404 405 406 407 408
409 protected function parseColumnValue($column, $row)
410 {
411 ob_start();
412 $column->renderDataCell($row);
413 $value = ob_get_clean();
414
415 if ($column instanceof CDataColumn && array_key_exists($column->name, $this->extendedSummary['columns'])) {
416
417 $config = $this->extendedSummary['columns'][$column->name];
418
419 $config['column'] = $column;
420
421 $op = $this->getSummaryOperationInstance($column->name, $config);
422
423 $op->processValue($value);
424 }
425 return $value;
426 }
427
428 429 430 431 432 433 434
435 protected function getSummaryOperationInstance($name, $config)
436 {
437 if (!isset($config['class'])) {
438 throw new CException(Yii::t(
439 'zii',
440 'Column summary configuration must be an array containing a "type" element.'
441 ));
442 }
443
444 if (!in_array($config['class'], $this->extendedSummaryOperations)) {
445 throw new CException(Yii::t(
446 'zii',
447 '"{operation}" is an unsupported class operation.',
448 array('{operation}' => $config['class'])
449 ));
450 }
451
452
453 if (!isset($this->extendedSummaryTypes[$name])) {
454 $this->extendedSummaryTypes[$name] = Yii::createComponent($config);
455 $this->extendedSummaryTypes[$name]->init();
456 }
457 return $this->extendedSummaryTypes[$name];
458 }
459
460 }
461