diff options
Diffstat (limited to 'lib/querypath/Extension/QPList.php')
-rw-r--r-- | lib/querypath/Extension/QPList.php | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/lib/querypath/Extension/QPList.php b/lib/querypath/Extension/QPList.php new file mode 100644 index 0000000..87fb860 --- /dev/null +++ b/lib/querypath/Extension/QPList.php @@ -0,0 +1,213 @@ +<?php +/** @file + * This extension provides support for common HTML list operations. + */ + +/** + * Provide list operations for QueryPath. + * + * The QPList class is an extension to QueryPath. It provides HTML list generators + * that take lists and convert them into bulleted lists inside of QueryPath. + * + * @deprecated This will be removed from a subsequent version of QueryPath. It will + * be released as a stand-alone extension. + * @ingroup querypath_extensions + */ +class QPList implements QueryPathExtension { + const UL = 'ul'; + const OL = 'ol'; + const DL = 'dl'; + + protected $qp = NULL; + public function __construct(QueryPath $qp) { + $this->qp = $qp; + } + + public function appendTable($items, $options = array()) { + $opts = $options + array( + 'table class' => 'qptable', + ); + $base = '<?xml version="1.0"?> + <table> + <tbody> + <tr></tr> + </tbody> + </table>'; + + $qp = qp($base, 'table')->addClass($opts['table class'])->find('tr'); + if ($items instanceof TableAble) { + $headers = $items->getHeaders(); + $rows = $items->getRows(); + } + elseif ($items instanceof Traversable) { + $headers = array(); + $rows = $items; + } + else { + $headers = $items['headers']; + $rows = $items['rows']; + } + + // Add Headers: + foreach ($headers as $header) { + $qp->append('<th>' . $header . '</th>'); + } + $qp->top()->find('tr:last'); + + // Add rows and cells. + foreach ($rows as $row) { + $qp->after('<tr/>')->next(); + foreach($row as $cell) $qp->append('<td>' . $cell . '</td>'); + } + + $this->qp->append($qp->top()); + + return $this->qp; + } + + /** + * Append a list of items into an HTML DOM using one of the HTML list structures. + * This takes a one-dimensional array and converts it into an HTML UL or OL list, + * <b>or</b> it can take an associative array and convert that into a DL list. + * + * In addition to arrays, this works with any Traversable or Iterator object. + * + * OL/UL arrays can be nested. + * + * @param mixed $items + * An indexed array for UL and OL, or an associative array for DL. Iterator and + * Traversable objects can also be used. + * @param string $type + * One of ul, ol, or dl. Predefined constants are available for use. + * @param array $options + * An associative array of configuration options. The supported options are: + * - 'list class': The class that will be assigned to a list. + */ + public function appendList($items, $type = self::UL, $options = array()) { + $opts = $options + array( + 'list class' => 'qplist', + ); + if ($type == self::DL) { + $q = qp('<?xml version="1.0"?><dl></dl>', 'dl')->addClass($opts['list class']); + foreach ($items as $dt => $dd) { + $q->append('<dt>' . $dt . '</dt><dd>' . $dd . '</dd>'); + } + $q->appendTo($this->qp); + } + else { + $q = $this->listImpl($items, $type, $opts); + $this->qp->append($q->find(':root')); + } + + return $this->qp; + } + + /** + * Internal recursive list generator for appendList. + */ + protected function listImpl($items, $type, $opts, $q = NULL) { + $ele = '<' . $type . '/>'; + if (!isset($q)) + $q = qp()->append($ele)->addClass($opts['list class']); + + foreach ($items as $li) { + if ($li instanceof QueryPath) { + $q = $this->listImpl($li->get(), $type, $opts, $q); + } + elseif (is_array($li) || $li instanceof Traversable) { + $q->append('<li><ul/></li>')->find('li:last > ul'); + $q = $this->listImpl($li, $type, $opts, $q); + $q->parent(); + } + else { + $q->append('<li>' . $li . '</li>'); + } + } + return $q; + } + + /** + * Unused. + */ + protected function isAssoc($array) { + // A clever method from comment on is_array() doc page: + return count(array_diff_key($array, range(0, count($array) - 1))) != 0; + } +} +QueryPathExtensionRegistry::extend('QPList'); + +/** + * A TableAble object represents tabular data and can be converted to a table. + * + * The {@link QPList} extension to {@link QueryPath} provides a method for + * appending a table to a DOM ({@link QPList::appendTable()}). + * + * Implementing classes should provide methods for getting headers, rows + * of data, and the number of rows in the table ({@link TableAble::size()}). + * Implementors may also choose to make classes Iterable or Traversable over + * the rows of the table. + * + * Two very basic implementations of TableAble are provided in this package: + * - {@link QPTableData} provides a generic implementation. + * - {@link QPTableTextData} provides a generic implementation that also escapes + * all data. + */ +interface TableAble { + public function getHeaders(); + public function getRows(); + public function size(); +} + +/** + * Format data to be inserted into a simple HTML table. + * + * Data in the headers or rows may contain markup. If you want to + * disallow markup, use a {@see QPTableTextData} object instead. + */ +class QPTableData implements TableAble, IteratorAggregate { + + protected $headers; + protected $rows; + protected $caption; + protected $p = -1; + + public function setHeaders($array) {$this->headers = $array; return $this;} + public function getHeaders() {return $this->headers; } + public function setRows($array) {$this->rows = $array; return $this;} + public function getRows() {return $this->rows;} + public function size() {return count($this->rows);} + public function getIterator() { + return new ArrayIterator($rows); + } +} + +/** + * Provides a table where all of the headers and data are treated as text data. + * + * This provents marked-up data from being inserted into the DOM as elements. + * Instead, the text is escaped using {@see htmlentities()}. + * + * @see QPTableData + */ +class QPTableTextData extends QPTableData { + public function setHeaders($array) { + $headers = array(); + foreach ($array as $header) { + $headers[] = htmlentities($header); + } + parent::setHeaders($headers); + return $this; + } + public function setRows($array) { + $count = count($array); + for ($i = 0; $i < $count; ++$i) { + $cols = array(); + foreach ($data[$i] as $datum) { + $cols[] = htmlentities($datum); + } + $data[$i] = $cols; + } + parent::setRows($array); + return $this; + } +}
\ No newline at end of file |