213 lines
6.2 KiB
PHP
213 lines
6.2 KiB
PHP
<?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;
|
|
}
|
|
} |