Blame | Last modification | View Log | Download
<?php namespace ProcessWire;/*** Class MarkupAdminDataTable** @method string render()** @property-read array $headerRow* @property-read array $footerRow* @property-read array $rows* @property-read array $rowClasses* @property-read array $rowAttrs* @property-read array $actions* @property bool $encodeEntities* @property bool $sortable* @property bool $resizable* @property string $class* @property string $caption* @property bool $responsive* @property array $settings* @property string $id**/class MarkupAdminDataTable extends ModuleJS {public static function getModuleInfo() {return array('title' => 'Admin Data Table','summary' => 'Generates markup for data tables used by ProcessWire admin','version' => 107,'permanent' => true,);}const responsiveNo = 0; // responsive offconst responsiveYes = 1; // each td becomes 1-row, each 2 columns with th + td side-by-sideconst responsiveAlt = 2; // each td becomes 1-row, with th + td stacked on top of each other/*** Number of table instances, for unique id attributes** @var int**/static protected $instanceCnt = 0;/*** Table rows** @var array**/protected $rows = array();protected $headerRow = array();protected $footerRow = array();protected $rowClasses = array();protected $rowAttrs = array();protected $actions = array();/*** Initialize module and default settings**/public function init() {// defaults for settings that are typically set globally for all tables$defaults = array('class' => 'AdminDataTable AdminDataList','addClass' => '','responsiveClass' => 'AdminDataTableResponsive','responsiveAltClass' => 'AdminDataTableResponsiveAlt','sortableClass' => 'AdminDataTableSortable','resizableClass' => 'AdminDataTableResizable','loadStyles' => true,'loadScripts' => true,);// settings set globally for all tables (when present)$settings = $this->wire('config')->MarkupAdminDataTable;if(empty($settings)) {$settings = $defaults;} else {$settings = array_merge($defaults, $settings);}if(!empty($settings['sortableClass'])) {$this->modules->get("JqueryTableSorter");}$this->loadStyles = $settings['loadStyles'];$this->loadScripts = $settings['loadScripts'];$this->set('encodeEntities', true);$this->set('sortable', true);$this->set('resizable', false);$this->set('class', ''); // extra class(es), populated by addClass() method$this->set('caption', '');$this->set('responsive', self::responsiveYes);$this->set('settings', $settings);$this->set('id', '');parent::init();}/*** Get property** @param string $key* @return mixed|null**/public function get($key) {if($key === 'rows' || $key === 'headerRow' || $key === 'footerRow') return $this->$key;if($key === 'rowClasses' || $key === 'rowAttrs' || $key === 'actions') return $this->$key;return parent::get($key);}/*** Set the header row for the table** @param array $a Array of header row labels (strings)* @return $this**/public function headerRow(array $a) {$this->headerRow = $a;return $this;}/*** Set the footer row for the table** @param array $a Array of footer row labels (strings)* @return $this**/public function footerRow(array $a) {$this->footerRow = $this->setupRow($a);return $this;}/*** Add a row to the table** @param array $a Array of columns that will each be a `<td>`, where each element may be one of the following:* - `string`: converts to `<td>string</td>`* - `array('label' => 'url')`: converts to `<td><a href='url'>label</a></td>`* - `array('label', 'class')`: converts to `<td class='class'>label</td>`* @param array $options Optionally specify any one of the following:* - separator (bool): specify true to show a stronger visual separator above the column* - class (string): specify one or more class names to apply to the `<tr>`* - attrs (array): array of attr => value for attributes to add to the `<tr>`* @return $this**/public function row(array $a, array $options = array()) {$defaults = array('separator' => false,'class' => '','attrs' => array(),);$options = array_merge($defaults, $options);$n = count($this->rows);if($options['separator']) {$options['class'] .= ($options['class'] ? ' ' : '') . 'AdminDataListSeparator';}$this->rows[$n] = $this->setupRow($a);if(!empty($options['class'])) $this->rowClasses[$n] = $options['class'];if(!empty($options['attrs'])) $this->rowAttrs[$n] = $options['attrs'];return $this;}/*** Setup/prepare a table row for rendering (internal)** @param array $a* @return array**/protected function setupRow(array $a) {$row = array();foreach($a as $k => $v) {if(is_string($k)) {// Associative arrays get converted to:// Anchor Text => URL$v = "<a href='$v'>" . $this->encode($k) . "</a>";} else if(is_array($v)) {// class name is specified in $v[1]foreach($v as $kk => $vv) {$v[$kk] = $this->encode($vv);}} else {$v = $this->encode($v);}$row[] = $v;}return $row;}/*** Add action(s) button underneath the table** @param array $action Array in format array('button-label' => 'url')* @return $this**/public function action(array $action) {foreach($action as $label => $url) {$this->actions[$label] = $url;}return $this;}/*** Render the table** @return string**/public function ___render() {$tableClass = trim($this->settings('class') . ' ' . $this->class);if($this->responsive == self::responsiveYes) {$tableClass .= ' ' . $this->settings('responsiveClass');} else if($this->responsive == self::responsiveAlt) {$tableClass .= ' ' . $this->settings('responsiveClass') . ' ' . $this->settings('responsiveAltClass');}if($this->sortable) $tableClass .= ' ' . $this->settings('sortableClass');if($this->resizable) {$tableClass .= ' ' . $this->settings('resizableClass');/** @var JqueryTableSorter $tableSorter */$tableSorter = $this->modules->get('JqueryTableSorter');$tableSorter->use('widgets');}if($this->settings('addClass')) $tableClass .= ' ' . $this->settings('addClass');$out = '';$maxCols = 0;$id = $this->id ? $this->id : "AdminDataTable" . (++self::$instanceCnt);if(count($this->rows)) {$out = "\n<table id='$id' class='$tableClass'>";if($this->caption) $out .= "\n\t<caption>{$this->caption}</caption>";if(count($this->headerRow)) {$out .= "\n\t<thead>\n\t<tr>";foreach($this->headerRow as $th) {$class = '';if(is_array($th)) list($th, $class) = $th;$th = $this->encode($th);if($class) $class = " class='" . $this->encode($class) . "'";$out .= "\n\t\t<th$class>$th</th>";$maxCols++;}$out .= "\n\t</tr>\n\t</thead>";}if(count($this->footerRow)) {$out .= "\n\t<tfoot>\n\t<tr>";foreach($this->footerRow as $td) {$out .= "\n\t\t\t<td>$td</td>";}$out .= "\n\t</tr>\n\t</tfoot>";}$out .= "\n\t<tbody>";foreach($this->rows as $n => $row) {$cols = count($row);if($cols > $maxCols) $maxCols = $cols;if($cols < $maxCols) for(; $cols < $maxCols; $cols++) $row[] = ' ';$attrs = isset($this->rowAttrs[$n]) ? $this->rowAttrs[$n] : array();if(isset($this->rowClasses[$n])) $attrs['class'] = $this->rowClasses[$n];$attrStr = '';foreach($attrs as $attrName => $attrVal) {$attrStr .= " $attrName='" . $this->wire('sanitizer')->entities($attrVal) . "'";}$out .= "\n\t\t<tr$attrStr>";foreach($row as $td) {$class = '';if(is_array($td)) list($td, $class) = $td;if(strlen($td) == 0 || $td === ' ') $class .= ($class ? ' ' : '') . 'blank';if($class) $class = " class='$class'";$out .= "\n\t\t\t<td$class>$td</td>";}$out .= "\n\t\t</tr>";}$out .= "\n\t</tbody>";$out .= "\n</table>";if($this->responsive && strpos($this->settings('responsiveClass'), 'AdminDataTableResponsive') === 0) {$out .= "\n<script>if(typeof AdminDataTable != 'undefined') AdminDataTable.initTable($('#$id'));</script>";}}if(count($this->actions)) {$out .= "\n<p>";foreach($this->actions as $label => $url) {/** @var InputfieldButton $button */$button = $this->modules->get("InputfieldButton");$button->href = $url;$button->value = $label;$out .= $button->render();}$out .= "\n</p>";}return $out;}/*** Entity encode string (when entity encoding enabled)** @param string $str* @return string**/protected function encode($str) {if(!$this->encodeEntities) return $str;return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');}/*** Set whether or not entity encoding is enabled** @param bool $encodeEntities**/public function setEncodeEntities($encodeEntities = true) {$this->encodeEntities = $encodeEntities ? true : false;}/*** Set class(es) to add to table** @param string $class**/public function setClass($class) {$this->class = $this->encode($class);}/*** Add a class to the table (without replacing existing ones)** @param string $class**/public function addClass($class) {$this->class = trim($this->class . " " . $this->encode($class));}/*** Set whether or not table is sortable** @param bool $sortable**/public function setSortable($sortable) {$this->sortable = $sortable ? true : false;}/*** Set whether or not table is resizable** @param bool $resizable**/public function setResizable($resizable) {$this->resizable = $resizable ? true : false;}/*** Set table caption** @param string $caption**/public function setCaption($caption) {$this->caption = $this->encode($caption);}/*** Set table id attribute** @param string $id**/public function setID($id) {$this->id = $id;}/*** Set the responsive mode of this table** Default behavior is responsiveYes. Specify false or 0 to disable responsive.* Or specify MarkupAdminDataTable::responsiveAlt for stacked th + td.** @param int|bool $responsive**/public function setResponsive($responsive = true) {$this->responsive = (int) $responsive;}/*** Get or set an internal setting** @pw-internal** @param string $key Setting to get or set* @param mixed $value Optional value to set* @return string|int|array|null|MarkupAdminDataTable**/public function settings($key, $value = null) {$settings = parent::get('settings');if(is_null($value)) {return isset($settings[$key]) ? $settings[$key] : null;} else {$settings[$key] = $value;parent::set('settings', $settings);return $this;}}public function isSingular() {return false;}public function isAutoload() {return false;}}