[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/view/control/ -> AphrontTableView.php (source)

   1  <?php
   2  
   3  final class AphrontTableView extends AphrontView {
   4  
   5    protected $data;
   6    protected $headers;
   7    protected $shortHeaders;
   8    protected $rowClasses = array();
   9    protected $columnClasses = array();
  10    protected $cellClasses = array();
  11    protected $zebraStripes = true;
  12    protected $noDataString;
  13    protected $className;
  14    protected $columnVisibility = array();
  15    private $deviceVisibility = array();
  16  
  17    protected $sortURI;
  18    protected $sortParam;
  19    protected $sortSelected;
  20    protected $sortReverse;
  21    protected $sortValues;
  22    private $deviceReadyTable;
  23  
  24    public function __construct(array $data) {
  25      $this->data = $data;
  26    }
  27  
  28    public function setHeaders(array $headers) {
  29      $this->headers = $headers;
  30      return $this;
  31    }
  32  
  33    public function setColumnClasses(array $column_classes) {
  34      $this->columnClasses = $column_classes;
  35      return $this;
  36    }
  37  
  38    public function setRowClasses(array $row_classes) {
  39      $this->rowClasses = $row_classes;
  40      return $this;
  41    }
  42  
  43    public function setCellClasses(array $cell_classes) {
  44      $this->cellClasses = $cell_classes;
  45      return $this;
  46    }
  47  
  48    public function setNoDataString($no_data_string) {
  49      $this->noDataString = $no_data_string;
  50      return $this;
  51    }
  52  
  53    public function setClassName($class_name) {
  54      $this->className = $class_name;
  55      return $this;
  56    }
  57  
  58    public function setZebraStripes($zebra_stripes) {
  59      $this->zebraStripes = $zebra_stripes;
  60      return $this;
  61    }
  62  
  63    public function setColumnVisibility(array $visibility) {
  64      $this->columnVisibility = $visibility;
  65      return $this;
  66    }
  67  
  68    public function setDeviceVisibility(array $device_visibility) {
  69      $this->deviceVisibility = $device_visibility;
  70      return $this;
  71    }
  72  
  73    public function setDeviceReadyTable($ready) {
  74      $this->deviceReadyTable = $ready;
  75      return $this;
  76    }
  77  
  78    public function setShortHeaders(array $short_headers) {
  79      $this->shortHeaders = $short_headers;
  80      return $this;
  81    }
  82  
  83    /**
  84     * Parse a sorting parameter:
  85     *
  86     *   list($sort, $reverse) = AphrontTableView::parseSortParam($sort_param);
  87     *
  88     * @param string  Sort request parameter.
  89     * @return pair   Sort value, sort direction.
  90     */
  91    public static function parseSort($sort) {
  92      return array(ltrim($sort, '-'), preg_match('/^-/', $sort));
  93    }
  94  
  95    public function makeSortable(
  96      PhutilURI $base_uri,
  97      $param,
  98      $selected,
  99      $reverse,
 100      array $sort_values) {
 101  
 102      $this->sortURI        = $base_uri;
 103      $this->sortParam      = $param;
 104      $this->sortSelected   = $selected;
 105      $this->sortReverse    = $reverse;
 106      $this->sortValues     = array_values($sort_values);
 107  
 108      return $this;
 109    }
 110  
 111    public function render() {
 112      require_celerity_resource('aphront-table-view-css');
 113  
 114      $table = array();
 115  
 116      $col_classes = array();
 117      foreach ($this->columnClasses as $key => $class) {
 118        if (strlen($class)) {
 119          $col_classes[] = $class;
 120        } else {
 121          $col_classes[] = null;
 122        }
 123      }
 124  
 125      $visibility = array_values($this->columnVisibility);
 126      $device_visibility = array_values($this->deviceVisibility);
 127      $headers = $this->headers;
 128      $short_headers = $this->shortHeaders;
 129      $sort_values = $this->sortValues;
 130      if ($headers) {
 131        while (count($headers) > count($visibility)) {
 132          $visibility[] = true;
 133        }
 134        while (count($headers) > count($device_visibility)) {
 135          $device_visibility[] = true;
 136        }
 137        while (count($headers) > count($short_headers)) {
 138          $short_headers[] = null;
 139        }
 140        while (count($headers) > count($sort_values)) {
 141          $sort_values[] = null;
 142        }
 143  
 144        $tr = array();
 145        foreach ($headers as $col_num => $header) {
 146          if (!$visibility[$col_num]) {
 147            continue;
 148          }
 149  
 150          $classes = array();
 151  
 152          if (!empty($col_classes[$col_num])) {
 153            $classes[] = $col_classes[$col_num];
 154          }
 155  
 156          if (empty($device_visibility[$col_num])) {
 157            $classes[] = 'aphront-table-view-nodevice';
 158          }
 159  
 160          if ($sort_values[$col_num] !== null) {
 161            $classes[] = 'aphront-table-view-sortable';
 162  
 163            $sort_value = $sort_values[$col_num];
 164            $sort_glyph_class = 'aphront-table-down-sort';
 165            if ($sort_value == $this->sortSelected) {
 166              if ($this->sortReverse) {
 167                $sort_glyph_class = 'aphront-table-up-sort';
 168              } else if (!$this->sortReverse) {
 169                $sort_value = '-'.$sort_value;
 170              }
 171              $classes[] = 'aphront-table-view-sortable-selected';
 172            }
 173  
 174            $sort_glyph = phutil_tag(
 175              'span',
 176              array(
 177                'class' => $sort_glyph_class,
 178              ),
 179              '');
 180  
 181            $header = phutil_tag(
 182              'a',
 183              array(
 184                'href'  => $this->sortURI->alter($this->sortParam, $sort_value),
 185                'class' => 'aphront-table-view-sort-link',
 186              ),
 187              array(
 188                $header,
 189                ' ',
 190                $sort_glyph,
 191              ));
 192          }
 193  
 194          if ($classes) {
 195            $class = implode(' ', $classes);
 196          } else {
 197            $class = null;
 198          }
 199  
 200          if ($short_headers[$col_num] !== null) {
 201            $header_nodevice = phutil_tag(
 202              'span',
 203              array(
 204                'class' => 'aphront-table-view-nodevice',
 205              ),
 206              $header);
 207            $header_device = phutil_tag(
 208              'span',
 209              array(
 210                'class' => 'aphront-table-view-device',
 211              ),
 212              $short_headers[$col_num]);
 213  
 214            $header = hsprintf('%s %s', $header_nodevice, $header_device);
 215          }
 216  
 217          $tr[] = phutil_tag('th', array('class' => $class), $header);
 218        }
 219        $table[] = phutil_tag('tr', array(), $tr);
 220      }
 221  
 222      foreach ($col_classes as $key => $value) {
 223  
 224        if (($sort_values[$key] !== null) &&
 225            ($sort_values[$key] == $this->sortSelected)) {
 226          $value = trim($value.' sorted-column');
 227        }
 228  
 229        if ($value !== null) {
 230          $col_classes[$key] = $value;
 231        }
 232      }
 233  
 234      $data = $this->data;
 235      if ($data) {
 236        $row_num = 0;
 237        foreach ($data as $row) {
 238          while (count($row) > count($col_classes)) {
 239            $col_classes[] = null;
 240          }
 241          while (count($row) > count($visibility)) {
 242            $visibility[] = true;
 243          }
 244          $tr = array();
 245          // NOTE: Use of a separate column counter is to allow this to work
 246          // correctly if the row data has string or non-sequential keys.
 247          $col_num = 0;
 248          foreach ($row as $value) {
 249            if (!$visibility[$col_num]) {
 250              ++$col_num;
 251              continue;
 252            }
 253            $class = $col_classes[$col_num];
 254            if (empty($device_visibility[$col_num])) {
 255              $class = trim($class.' aphront-table-view-nodevice');
 256            }
 257            if (!empty($this->cellClasses[$row_num][$col_num])) {
 258              $class = trim($class.' '.$this->cellClasses[$row_num][$col_num]);
 259            }
 260            $tr[] = phutil_tag('td', array('class' => $class), $value);
 261            ++$col_num;
 262          }
 263  
 264          $class = idx($this->rowClasses, $row_num);
 265          if ($this->zebraStripes && ($row_num % 2)) {
 266            if ($class !== null) {
 267              $class = 'alt alt-'.$class;
 268            } else {
 269              $class = 'alt';
 270            }
 271          }
 272  
 273          $table[] = phutil_tag('tr', array('class' => $class), $tr);
 274          ++$row_num;
 275        }
 276      } else {
 277        $colspan = max(count(array_filter($visibility)), 1);
 278        $table[] = phutil_tag(
 279          'tr',
 280          array('class' => 'no-data'),
 281          phutil_tag(
 282            'td',
 283            array('colspan' => $colspan),
 284            coalesce($this->noDataString, pht('No data available.'))));
 285      }
 286  
 287      $table_class = 'aphront-table-view';
 288      if ($this->className !== null) {
 289        $table_class .= ' '.$this->className;
 290      }
 291      if ($this->deviceReadyTable) {
 292        $table_class .= ' aphront-table-view-device-ready';
 293      }
 294  
 295      $html = phutil_tag('table', array('class' => $table_class), $table);
 296      return phutil_tag_div('aphront-table-wrap', $html);
 297    }
 298  
 299    public static function renderSingleDisplayLine($line) {
 300  
 301      // TODO: Is there a cleaner way to do this? We use a relative div with
 302      // overflow hidden to provide the bounds, and an absolute span with
 303      // white-space: pre to prevent wrapping. We need to append a character
 304      // (&nbsp; -- nonbreaking space) afterward to give the bounds div height
 305      // (alternatively, we could hard-code the line height). This is gross but
 306      // it's not clear that there's a better appraoch.
 307  
 308      return phutil_tag(
 309        'div',
 310        array(
 311          'class' => 'single-display-line-bounds',
 312        ),
 313        array(
 314          phutil_tag(
 315            'span',
 316            array(
 317              'class' => 'single-display-line-content',
 318            ),
 319            $line),
 320          "\xC2\xA0",
 321        ));
 322    }
 323  
 324  
 325  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1