website_jukni/dokuwiki/lib/plugins/pagequery/syntax.php
2017-12-29 15:51:59 +01:00

354 lines
14 KiB
PHP

<?php
/**
* PageQuery Plugin: search for and list pages, sorted/grouped by name, date, creator, etc
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Symon Bent <hendrybadao@gmail.com>
*/
// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();
if (!defined('DOKU_LF')) define('DOKU_LF', "\n");
if (!defined('DOKU_TAB')) define('DOKU_TAB', "\t");
if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN . 'syntax.php');
require_once(DOKU_INC . 'inc/fulltext.php');
require_once(DOKU_PLUGIN . 'pagequery/inc/pagequery.php');
class syntax_plugin_pagequery extends DokuWiki_Syntax_Plugin {
const MAX_COLS = 12;
function getType() {
return 'substition';
}
function getPType() {
return 'block';
}
function getSort() {
return 98;
}
function connectTo($mode) {
// this regex allows multi-line syntax for easier composition/reading
$this->Lexer->addSpecialPattern('\{\{pagequery>(?m).*?(?-m)\}\}', $mode, 'plugin_pagequery');
}
/**
* Parses all the pagequery options:
* Insert the pagequery markup wherever you want your list to appear. E.g:
*
* {{pagequery>}}
*
* {{pagequery>[query];fulltext;sort=key:direction,key2:direction;group;limit=??;cols=?;spelldate;proper}}
*
* @link https://www.dokuwiki.org/plugin:pagequery See PageQuery page for full details
*/
function handle($match, $state, $pos, Doku_Handler $handler) {
$opt = array();
$match = substr($match, 12, -2); // strip markup "{{pagequery>...}}"
$params = explode(';', $match);
// remove any pre/trailing spaces due to multi-line syntax
$params = array_map('trim', $params);
$opt['query'] = $params[0];
// establish some basic option defaults
$opt['border'] = 'none'; // show borders around entire list and/or between columns
$opt['bullet'] = 'none'; // bullet style for list items
$opt['casesort'] = false; // allow case sorting
$opt['cols'] = 1; // number of displayed columns (fixed for table layout, max for column layout
$opt['dformat'] = "%d %b %Y"; // general display date format
$opt['display'] = 'name'; // how page links should be displayed
$opt['filter'] = array(); // filtering by metadata prior to sorting
$opt['fontsize'] = ''; // base fontsize of pagequery; best to use %
$opt['fullregex'] = false; // power-user regex search option--file name only
$opt['fulltext'] = false; // search full-text; including file contents
$opt['group'] = false; // group the results based on sort headings
$opt['hidejump'] = false; // hide the jump to top link
$opt['hidemsg'] = false; // hide any error messages
$opt['hidestart'] = false; // hide start pages
$opt['label'] = ''; // label to put at top of the list
$opt['layout'] = 'table'; // html layout type: table (1 col = div only) or columns (html 5 only)
$opt['limit'] = 0; // limit results to certain number
$opt['maxns'] = 0; // max number of namespaces to display (i.e. ns depth)
$opt['natsort'] = false; // allow natural case sorting
$opt['proper'] = 'none'; // display file names in Proper Case
$opt['showcount'] = false; // show the count of links found
$opt['snippet'] = array('type' => 'none', 'count' => 0, 'extent' => ''); // show content snippets/abstracts
$opt['sort'] = array(); // sort by various headings
$opt['spelldate'] = false; // spell out date headings in words where possible
$opt['underline'] = false; // faint underline below each link for clarity
$opt['nstitle'] = false; // internal use currently...
foreach ($params as $param) {
list($option, $value) = $this->_keyvalue($param, '=');
switch ($option) {
case 'casesort':
case 'fullregex':
case 'fulltext':
case 'group':
case 'hidejump':
case 'hidemsg':
case 'hidestart':
case 'natsort':
case 'showcount':
case 'spelldate':
case 'underline':
$opt[$option] = true;
break;
case 'limit':
case 'maxns':
$opt[$option] = abs($value);
break;
case 'sort':
case 'filter':
$fields = explode(',', $value);
foreach ($fields as $field) {
list($key, $expr) = $this->_keyvalue($field);
// allow for a few common naming differences
switch ($key) {
case 'pagename':
$key = 'name';
break;
case 'heading':
case 'firstheading':
$key = 'title';
break;
case 'pageid':
case 'id':
$key = 'id';
break;
case 'contrib':
$key = 'contributor';
break;
}
$opt[$option][$key] = $expr;
}
break;
case 'proper':
switch ($value) {
case 'hdr':
case 'header':
case 'group':
$opt['proper'] = 'header';
break;
case 'name':
case 'page':
$opt['proper'] = 'name';
break;
default:
$opt['proper'] = 'both';
}
break;
case 'cols':
$opt['cols'] = ($value > self::MAX_COLS) ? self::MAX_COLS : $value;
break;
case 'border':
switch ($value) {
case 'both':
case 'inside':
case 'outside':
case 'none':
$opt['border'] = $value;
break;
default:
$opt['border'] = 'both';
}
break;
case 'snippet':
$default = 'tooltip';
if (empty($value)) {
$opt['snippet']['type'] = $default;
break;
} else {
$options = explode(',', $value);
$type = ( ! empty($options[0])) ? $options[0] : $opt['snippet']['type'];
$count = ( ! empty($options[1])) ? $options[1] : $opt['snippet']['count'];
$extent = ( ! empty($options[2])) ? $options[2] : $opt['snippet']['extent'];
$valid = array('none', 'tooltip', 'inline', 'plain', 'quoted');
if ( ! in_array($type, $valid)) {
$type = $default; // empty snippet type => tooltip
}
$opt['snippet'] = array('type' => $type, 'count' => $count, 'extent' => $extent);
break;
}
case 'label':
case 'bullet':
$opt[$option] = $value;
break;
case 'display':
switch ($value) {
case 'name':
$opt['display'] = 'name';
break;
case 'title':
case 'heading':
case 'firstheading':
$opt['display'] = 'title';
$opt['nstitle'] = true;
break;
case 'pageid':
case 'id':
$opt['display'] = 'id';
break;
default:
$opt['display'] = $value;
}
if (preg_match('/\{(title|heading|firstheading)\}/', $value)) {
$opt['nstitle'] = true;
}
break;
case 'layout':
if ( ! in_array($value, array('table', 'column'))) {
$value = 'table';
}
$opt['layout'] = $value;
break;
case 'fontsize':
if ( ! empty($value)) {
$opt['fontsize'] = $value;
}
break;
}
}
return $opt;
}
function render($mode, Doku_Renderer $renderer, $opt) {
if ( ! PHP_MAJOR_VERSION >= 5 && ! PHP_MINOR_VERSION >= 3) {
$renderer->doc .= "You must have PHP 5.3 or greater to use this pagequery plugin. Please upgrade PHP or use an older version of the plugin";
return false;
}
$incl_ns = array();
$excl_ns = array();
$sort_opts = array();
$group_opts = array();
$message = '';
$lang = array(
'jump_section' => $this->getLang('jump_section'),
'link_to_top' => $this->getLang('link_to_top'),
'no_results' => $this->getLang('no_results')
);
$pq = new PageQuery($lang);
$query = $opt['query'];
if ($mode == 'xhtml') {
// first get a raw list of matching results
if ($opt['fulltext']) {
// full text searching (Dokuwiki style)
$results = $pq->page_search($query);
} else {
// page id searching (i.e. namespace and name, faster)
// fullregex option considers entire query to be a regex
// over the whole page id, incl. namespace
if ( ! $opt['fullregex']) {
list($query, $incl_ns, $excl_ns) = $pq->parse_ns_query($query);
}
// Allow for a lazy man's option!
if ($query == '*') {
$query = '.*';
}
// search by page name or path only
$results = $pq->page_lookup($query, $opt['fullregex'], $incl_ns, $excl_ns);
}
$results = $pq->validate_pages($results, $opt['hidestart'], $opt['maxns']);
$no_result = false;
if ($results === false) {
$no_result = true;
$message = $this->getLang('regex_error');
} elseif ( ! empty($results)) {
// prepare the necessary sorting arrays, as per users options
list($sort_array, $sort_opts, $group_opts) = $pq->build_sorting_array($results, $opt);
// meta data filtering of the list is next
$sort_array = $pq->filter_meta($sort_array, $opt['filter']);
if (empty($sort_array)) {
$no_result = true;
$message = $this->getLang("empty_filter");
}
} else {
$no_result = true;
}
// successful search...
if ( ! $no_result) {
// now do the sorting
$pq->msort($sort_array, $sort_opts);
// limit the result list length if required; this can only be done after sorting!
if ($opt['limit'] > 0) {
$sort_array = array_slice($sort_array, 0, $opt['limit']);
}
// do a link count BEFORE grouping (don't want to count headers...)
$count = count($sort_array);
// and finally the grouping
$keys = array('name', 'id', 'title', 'abstract', 'display');
if ( ! $opt['group']) $group_opts = array();
$sorted_results = $pq->mgroup($sort_array, $keys, $group_opts);
// and out to the page
$renderer->doc .= $pq->render_as_html($opt['layout'], $sorted_results, $opt, $count);
// no results...
} else {
if ( ! $opt['hidemsg']) {
$renderer->doc .= $pq->render_as_empty($query, $message);
}
}
return true;
} else if ($mode == 'metadata' ) {
// this is a pagequery page needing PARSER_CACHE_USE event trigger;
$renderer->meta['pagequery'] = TRUE;
unset($renderer->persistent['pagequery']);
return true;
} else {
return false;
}
}
/**
* Split a string into key => value parts.
*
* @param string $str
* @param string $delim
* @return array
*/
private function _keyvalue($str, $delim = ':') {
$parts = explode($delim, $str);
$key = isset($parts[0]) ? $parts[0] : '';
$value = isset($parts[1]) ? $parts[1] : '';
return array($key, $value);
}
}