| 1: | <?php |
| 2: | |
| 3: | namespace Zippy\Html\DataList; |
| 4: | |
| 5: | use Zippy\Html\HtmlComponent; |
| 6: | use Zippy\Interfaces\Requestable; |
| 7: | use Zippy\WebApplication; |
| 8: | |
| 9: | |
| 10: | |
| 11: | |
| 12: | |
| 13: | |
| 14: | class DataTable extends AbstractList implements Requestable |
| 15: | { |
| 16: | private $columns = array(); |
| 17: | private $datalist = array(); |
| 18: | private $cellevent = null; |
| 19: | private $cellclickevent = null; |
| 20: | private $selectedrow = 0; |
| 21: | private $selectedclass = ""; |
| 22: | private $maxbuttons = 10; |
| 23: | private $firstButton = 1; |
| 24: | private $header = true; |
| 25: | private $paginator = false; |
| 26: | private $useajax = false; |
| 27: | |
| 28: | public function __construct($id, $DataSource, $header = true, $paginator = false, $useajax = false) { |
| 29: | AbstractList::__construct($id, $DataSource); |
| 30: | $this->header = $header; |
| 31: | $this->paginator = $paginator; |
| 32: | $this->useajax = $useajax; |
| 33: | } |
| 34: | |
| 35: | |
| 36: | |
| 37: | |
| 38: | final public function RenderImpl() { |
| 39: | $tag = $this->getTag(); |
| 40: | |
| 41: | $tag->appendWith($this->renderHeader()); |
| 42: | $tag->appendWith($this->renderData()); |
| 43: | $tag->appendWith($this->renderFooter()); |
| 44: | } |
| 45: | |
| 46: | |
| 47: | |
| 48: | |
| 49: | final public function AddColumn(Column $column) { |
| 50: | $this->columns[$column->fieldname] = $column; |
| 51: | } |
| 52: | |
| 53: | |
| 54: | |
| 55: | |
| 56: | public function Reload($resetpage = true) { |
| 57: | parent::Reload($resetpage); |
| 58: | |
| 59: | $this->datalist = $this->getItems(); |
| 60: | } |
| 61: | |
| 62: | |
| 63: | |
| 64: | |
| 65: | final public function RequestHandle() { |
| 66: | $p = WebApplication::$app->getRequest()->request_params[$this->id]; |
| 67: | if ($p[0] == 'sort') { |
| 68: | $this->sortf = $p[1]; |
| 69: | $this->sortd = $p[2]; |
| 70: | $this->currentpage = 1; |
| 71: | $this->Reload(); |
| 72: | } |
| 73: | if ($p[0] == 'pag') { |
| 74: | $this->currentpage = $p[1]; |
| 75: | $this->Reload(false); |
| 76: | } |
| 77: | if ($p[0] == 'cellclick' && $this->cellclickevent instanceof \Zippy\Event) { |
| 78: | $items = array(); |
| 79: | foreach($this->datalist as $it) { |
| 80: | $items[$it->getID()]=$it; |
| 81: | } |
| 82: | |
| 83: | |
| 84: | $this->cellclickevent->onEvent($this, array('dataitem' => $items[$p[2] ], 'field' => $p[1], 'rownumber' => $p[2])); |
| 85: | $this->setSelectedrow($p[2]); |
| 86: | } |
| 87: | |
| 88: | if ($this->useajax) { |
| 89: | WebApplication::$app->getResponse()->addAjaxResponse($this->AjaxAnswer()); |
| 90: | } |
| 91: | } |
| 92: | |
| 93: | |
| 94: | |
| 95: | |
| 96: | final public function setCellDrawEvent(\Zippy\Interfaces\EventReceiver $receiver, $handler) { |
| 97: | $this->cellevent = new \Zippy\Event($receiver, $handler); |
| 98: | } |
| 99: | |
| 100: | |
| 101: | |
| 102: | |
| 103: | final public function setCellClickEvent(\Zippy\Interfaces\EventReceiver $receiver, $handler) { |
| 104: | $this->cellclickevent = new \Zippy\Event($receiver, $handler); |
| 105: | } |
| 106: | |
| 107: | |
| 108: | |
| 109: | |
| 110: | private function renderHeader() { |
| 111: | if (!$this->header) { |
| 112: | return ""; |
| 113: | } |
| 114: | |
| 115: | $row = "<tr >"; |
| 116: | |
| 117: | foreach ($this->columns as $column) { |
| 118: | |
| 119: | if (!$column->visible) { |
| 120: | continue; |
| 121: | } |
| 122: | |
| 123: | $css = strlen($column->headerclass) > 0 ? "class=\"{$column->headerclass}\"" : ""; |
| 124: | |
| 125: | |
| 126: | if ($column->sortable) { |
| 127: | $sort = ""; |
| 128: | if ($column->fieldname === $this->sortf) { |
| 129: | if ($this->sortd === 'asc') { |
| 130: | $sort = '↓'; |
| 131: | } else { |
| 132: | $sort = '↑'; |
| 133: | } |
| 134: | } |
| 135: | $url = $this->getURLNode() . ':sort:' . $column->fieldname . ':' . ($this->sortd === 'asc' ? 'desc' : 'asc'); |
| 136: | $onclick = "window.location='{$url}'"; |
| 137: | if ($this->useajax) { |
| 138: | $onclick = "getUpdate('{$url}&ajax=true');event.returnValue=false; return false;"; |
| 139: | } |
| 140: | $row .= ("<th {$css} style=\"white-space: nowrap;cursor:pointer;\" onclick=\"{$onclick}\" ><span>{$column->title}</span> {$sort}</th>"); |
| 141: | } else { |
| 142: | |
| 143: | $row .= ("<th {$css} ><span>{$column->title}</span></th>"); |
| 144: | } |
| 145: | } |
| 146: | $row .= "</tr>"; |
| 147: | return $row; |
| 148: | } |
| 149: | |
| 150: | |
| 151: | |
| 152: | |
| 153: | private function renderData() { |
| 154: | |
| 155: | if (count($this->datalist) == 0) { |
| 156: | return ""; |
| 157: | } |
| 158: | |
| 159: | $rows = ""; |
| 160: | foreach ($this->datalist as $item) { |
| 161: | $rownumber = $item->getID(); |
| 162: | |
| 163: | if ($this->selectedrow == $rownumber && $this->selectedclass != "") { |
| 164: | $row = "<tr class=\"{$this->selectedclass}\" >"; |
| 165: | } else { |
| 166: | $row = "<tr >"; |
| 167: | } |
| 168: | |
| 169: | |
| 170: | foreach ($this->columns as $fieldname => $column) { |
| 171: | if (!$column->visible) { |
| 172: | continue; |
| 173: | } |
| 174: | |
| 175: | $data = strlen($item->{$fieldname}) > 0 ? $item->{$fieldname} : $column->defaultdata; |
| 176: | $css = strlen($column->rowclass) > 0 ? "class=\"{$column->rowclass}\"" : ""; |
| 177: | $onclick = ""; |
| 178: | $style = ""; |
| 179: | |
| 180: | |
| 181: | $url = $this->getURLNode() . ':cellclick:' . $fieldname . ':' . $rownumber; |
| 182: | if ($column->clickable) { |
| 183: | |
| 184: | $onclick = "window.location='{$url}'"; |
| 185: | } |
| 186: | if ($column->clickable && $this->useajax) { |
| 187: | $onclick = "getUpdate('{$url}&ajax=true');event.returnValue=false; return false;"; |
| 188: | } |
| 189: | |
| 190: | if (strlen($onclick) > 0) { |
| 191: | $onclick = " onclick=\"" . $onclick . "\" "; |
| 192: | $style = "style=\"cursor:pointer;\""; |
| 193: | } |
| 194: | |
| 195: | |
| 196: | if ($this->cellevent instanceof \Zippy\Event) { |
| 197: | $userdata = $this->cellevent->onEvent($this, array('dataitem' => $item, 'field' => $fieldname, 'rownumber' => $rownumber)); |
| 198: | if ($userdata !== null && $userdata !== false) { |
| 199: | $data = $userdata; |
| 200: | } |
| 201: | } |
| 202: | |
| 203: | $row .= ("<td {$css} {$onclick} {$style}>{$data}</td>"); |
| 204: | } |
| 205: | $row .= "</tr>"; |
| 206: | $rows .= $row; |
| 207: | } |
| 208: | return $rows; |
| 209: | } |
| 210: | |
| 211: | |
| 212: | |
| 213: | |
| 214: | private function renderFooter() { |
| 215: | if (!$this->paginator) { |
| 216: | return ""; |
| 217: | } |
| 218: | if (count($this->columns) == 0) { |
| 219: | return ""; |
| 220: | } |
| 221: | $currentpage = $this->currentpage; |
| 222: | |
| 223: | $content = '<ul class="pagination">'; |
| 224: | $pages = $this->getPageCount(); |
| 225: | if ($pages <= 1) { |
| 226: | return ''; |
| 227: | } |
| 228: | |
| 229: | if ($currentpage - $this->firstButton > $this->maxbuttons) { |
| 230: | |
| 231: | $this->firstButton = $currentpage - $this->maxbuttons; |
| 232: | } |
| 233: | if ($currentpage < $this->firstButton) { |
| 234: | $this->firstButton = $currentpage - 1; |
| 235: | } |
| 236: | |
| 237: | if ($this->firstButton > 1) { |
| 238: | $content .= "<li class=\"page-item\"><a class=\"page-link\" href='void(0);' onclick=\"" . $this->getPaginatorLink(1) . "\"><span aria-hidden=\"true\">«</span></a></li>"; |
| 239: | $content .= "<li class=\"page-item\"><a class=\"page-link\" href='void(0);' onclick=\"" . $this->getPaginatorLink($currentpage - 1) . "\"><span aria-hidden=\"true\">‹</span></a></li>"; |
| 240: | $content .= "<li class=\"page-item\"><a class=\"page-link\" href=\"javascript:void(0);\" >…</a></li>"; |
| 241: | } |
| 242: | |
| 243: | |
| 244: | for ($i = $this->firstButton; $i <= $this->firstButton + $this->maxbuttons; $i++) { |
| 245: | if ($i > $pages) { |
| 246: | break; |
| 247: | } |
| 248: | if ($currentpage == $i) { |
| 249: | $content .= "<li class=\"page-item active\"><a class=\"page-link\" href=\"javascript:void(0);\" > {$i} </a></li>"; |
| 250: | } else { |
| 251: | $content .= "<li class=\"page-item\"><a class=\"page-link\" href=\"javascript:void(0);\" onclick=\"" . $this->getPaginatorLink($i) . "\"> {$i} </a></li>"; |
| 252: | } |
| 253: | } |
| 254: | |
| 255: | if ($pages > $this->firstButton + $this->maxbuttons) { |
| 256: | $content .= "<li class=\"page-item\" ><a class=\"page-link\" href=\"javascript:void(0);\" >…</a></li>"; |
| 257: | $content .= "<li class=\"page-item\"><a class=\"page-link\" href='void(0);' onclick=\"" . $this->getPaginatorLink($currentpage + 1) . "\"aria-label=\"Next\"> <span aria-hidden=\"true\">›</span></a></li>"; |
| 258: | $content .= "<li class=\"page-item\"><a class=\"page-link\" href='void(0);' onclick=\"" . $this->getPaginatorLink($pages) . "\"aria-label=\"Next\"> <span aria-hidden=\"true\">»</span></a></li>"; |
| 259: | } |
| 260: | |
| 261: | $countall = $this->getAllRowsCount(); |
| 262: | $show = $currentpage * $this->pagesize; |
| 263: | if ($pages == $currentpage) { |
| 264: | $show = $countall; |
| 265: | } |
| 266: | if ($countall <= $this->pagesize) { |
| 267: | $show = $countall; |
| 268: | } |
| 269: | |
| 270: | $content = "<table ><tr><td valign='middle'>{$show} строк с {$countall} </td><td align='right'> {$content}</td></tr></table>"; |
| 271: | return "<tr ><td class=\"footercell\" colspan=\"" . count($this->columns) . "\" >{$content}</ul></td></tr>"; |
| 272: | } |
| 273: | |
| 274: | |
| 275: | |
| 276: | |
| 277: | private function getPaginatorLink($pageno) { |
| 278: | $url = $this->getURLNode() . ':pag:' . $pageno; |
| 279: | if ($this->useajax) { |
| 280: | $onclick = "getUpdate('{$url}&ajax=true');event.returnValue=false; return false;"; |
| 281: | } else { |
| 282: | $onclick = "window.location='{$url}';event.returnValue=false; return false;"; |
| 283: | } |
| 284: | return $onclick; |
| 285: | } |
| 286: | |
| 287: | |
| 288: | |
| 289: | |
| 290: | |
| 291: | |
| 292: | |
| 293: | |
| 294: | public function setSelectedrow($number) { |
| 295: | $this->selectedrow = $number; |
| 296: | } |
| 297: | |
| 298: | |
| 299: | |
| 300: | |
| 301: | |
| 302: | public function getSelectedRow() { |
| 303: | return $this->selectedRow; |
| 304: | } |
| 305: | |
| 306: | |
| 307: | |
| 308: | |
| 309: | |
| 310: | |
| 311: | public function setSelectedClass($selectedclass) { |
| 312: | $this->selectedclass = $selectedclass; |
| 313: | } |
| 314: | |
| 315: | |
| 316: | |
| 317: | |
| 318: | |
| 319: | public function removeAllColumns() { |
| 320: | $this->columns = array(); |
| 321: | } |
| 322: | |
| 323: | } |
| 324: | |
| 325: | |
| 326: | class Column |
| 327: | { |
| 328: | public function __construct($fieldname, $title, $sortable = false, $visible = true, $clickable = false, $headerclass = "", $rowclass = "", $defaultdata = "") { |
| 329: | $this->fieldname = $fieldname; |
| 330: | $this->visible = $visible; |
| 331: | $this->sortable = $sortable; |
| 332: | $this->clickable = $clickable; |
| 333: | $this->title = $title; |
| 334: | $this->headerclass = $headerclass; |
| 335: | $this->defaultdata = $defaultdata; |
| 336: | $this->rowclass = $rowclass; |
| 337: | } |
| 338: | |
| 339: | public $visible = true; |
| 340: | public $sortable = false; |
| 341: | public $clickable = false; |
| 342: | public $fieldname = ""; |
| 343: | public $title = ""; |
| 344: | public $headerclass = ""; |
| 345: | public $rowclass = ""; |
| 346: | public $defaultdata = " "; |
| 347: | |
| 348: | } |
| 349: | |
| 350: | |
| 351: | |
| 352: | |
| 353: | |
| 354: | |
| 355: | |
| 356: | |