*/ // must be run within Dokuwiki if (!defined('DOKU_INC')) die(); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once(DOKU_PLUGIN.'syntax.php'); /** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_wikistats extends DokuWiki_Syntax_Plugin { /** * Get an associative array with plugin info. * *

* The returned array holds the following fields: *

*
author
Author of the plugin
*
email
Email address to contact the author
*
date
Last modified date of the plugin in * YYYY-MM-DD format
*
name
Name of the plugin
*
desc
Short description of the plugin (Text only)
*
url
Website with more information on the plugin * (eg. syntax description)
*
* @param none * @return Array Information about this plugin class. * @public * @static */ function getInfo(){ return confToHash(dirname(__FILE__).'/plugin.info.txt'); } /** * Get the type of syntax this plugin defines. * * The type of this plugin is "substition". * * @param none * @return String 'substition'. * @public * @static */ public function getType() { return 'substition'; } /** * Define how this plugin is handled regarding paragraphs. * *

* This method is important for correct XHTML nesting. It returns * one of the following values: *

*
*
normal
The plugin can be used inside paragraphs.
*
block
Open paragraphs need to be closed before * plugin output.
*
stack
Special case: Plugin wraps other paragraphs.
*
* @param none * @return String 'normal'. * @public * @static */ public function getPType() { return 'normal'; } /** * Where to sort in? * * Sort the plugin in just behind the formating tokens * Low numbers go before high numbers * * @param none * @return Integer 128. * @public * @static */ public function getSort() { return 128; } /** * Connect lookup pattern to lexer. * * @param $aMode String The desired rendermode. * @return none * @public * @see render() */ public function connectTo($mode) { $this->Lexer->addSpecialPattern('\{\{wikistats>[^}]*\}\}',$mode,'plugin_wikistats'); } /** * Handle matches of the wikistats syntax * * @param string $match The match of the syntax * @param int $state The state of the handler * @param int $pos The position in the document * @param Doku_Handler $handler The handler * @return array Data for the renderer */ public function handle($match, $state, $pos, Doku_Handler &$handler){ $match = substr($match, 12, -2); $data = array( 'ns' => array(), 'type' => array() ); $match = explode('&', $match); foreach($match as $m) { if (preg_match('/(\w+)\s*=(.+)/', $m, $temp) == 1){ $this->handleNamedParameter($temp[1], trim($temp[2]), $data); } else { $this->addNamespace($data, trim($m)); } } return $data; } /** * Handle parameters that are specified using = syntax */ function handleNamedParameter($name, $value, &$data) { static $types = array('pages', 'medias', 'stats'); switch($name) { case 'ns': foreach(preg_split('/\s*,\s*/', $value) as $value) { $this->addNamespace($data, $value); } break; case 'type': if (preg_match('/(\w+)/', $value, $match) == 1) { if (in_array($match[1], $types)) { $data[$name] = $match[1]; } } break; } } /** * Clean-up the namespace name and add it (if valid) into the $data array */ function addNamespace(&$data, $namespace) { $action = ($namespace{0} == '-') ? 'exclude' : 'include'; $namespace = cleanID(preg_replace('/^[+-]/', '', $namespace)); if (!empty($namespace)) { $data['ns'][$action][] = $namespace; } } /** * Render xhtml output or metadata * * @param string $mode Renderer mode (supported modes: xhtml) * @param Doku_Renderer $renderer The renderer * @param array $data The data from the handler() function * @return bool If rendering was successful. */ public function render($mode, Doku_Renderer &$renderer, $data) { global $conf; global $ID; global $TOC; if ($mode != 'xhtml') return false; // prevent caching to ensure the included pages are always fresh $renderer->info['cache'] = false; $list = array(); $content = ''; switch ($data['type']) { case "pages": search($list, $conf['datadir'], array($this, '_search_count'), array('type' => $data['type'], 'ns' => $data['ns']), ''); $content = $list['pages_count']; break; case "medias": search($list, $conf['mediadir'], array($this, '_search_count'), array('type' => $data['type'], 'ns' => $data['ns'])); $content = $list['medias_count']; break; case "stats": search($list, $conf['datadir'], array($this, '_search_count'), array('type' => $data['type'], 'ns' => $data['ns']), ''); search($list, $conf['mediadir'], array($this, '_search_count'), array('type' => $data['type'], 'ns' => $data['ns'])); if ($this->getConf('display_toc')) { $TOC = p_get_metadata($ID,'description tableofcontents'); } else { $TOC = NULL; } $content .= $this->displayResourceStats($list); $content .= $this->displayTagStats($list); $content .= $this->displayNamespaceStats($list['dir_label']['ns']); break; } $renderer->doc .= $content; return true; } function _search_count(&$data, $base, $file, $type, $lvl, $opts){ if ($type == 'd') { if ($data['dir_nest'] < $lvl) $data['dir_nest'] = $lvl; $data['dir_count']++; return true; } $file = str_replace("/", ":", $file); // filter included namespaces if (isset($opts['ns']['include'])) { if (!$this->isInNamespace($opts['ns']['include'], $file)) return false; } // filter excluded namespaces if (isset($opts['ns']['exclude'])) { if ($this->isInNamespace($opts['ns']['exclude'], $file)) return false; } switch ($opts['type']) { case "pages": $data['pages_count']++; break; case "medias": $data['medias_count']++; break; case "stats": $path = $file; $file = substr($file, 1); $file = substr($file, 0, strrpos($file, ':')); //if (pathinfo($path, PATHINFO_EXTENSION) != 'txt') $file = substr($file, 0, strrpos($file, ':')); switch (pathinfo($path, PATHINFO_EXTENSION)) { case 'txt': $data['pages_count']++; $data['dir_label']['ns'][$file]['pages']++; break; case 'swf': $data['flash_count']++; $data['dir_label']['ns'][$file]['medias']++; break; case 'jpg': case 'jpeg': case 'png': case 'gif': case 'svg': $data['images_count']++; $data['dir_label']['ns'][$file]['medias']++; break; case 'mov': case 'avi': case 'flv': case 'mp4': case 'webm': case 'ogv': $data['movies_count']++; $data['dir_label']['ns'][$file]['medias']++; break; case 'wav': case 'mp3': case 'ogg': $data['audio_count']++; $data['dir_label']['ns'][$file]['medias']++; break; case 'xls': case 'xlsm': case 'xlsx': case 'ods': $data['sheets_count']++; $data['dir_label']['ns'][$file]['medias']++; break; case 'doc': case 'docx': case 'odt': $data['writer_count']++; $data['dir_label']['ns'][$file]['medias']++; break; case 'ppt': case 'pptx': case 'odp': $data['presentation_count']++; $data['dir_label']['ns'][$file]['medias']++; break; case 'djvu': case 'epub': case 'mobi': case 'pdf': $data['documents_count']++; $data['dir_label']['ns'][$file]['medias']++; break; case 'tar': case 'arj': case 'zip': case 'bzip': case 'rar': case 'tgz': case 'gz': case '7z': case 'bz2': $data['archives_count']++; $data['dir_label']['ns'][$file]['medias']++; break; case 'exe': case 'com': $data['binaries_count']++; $data['dir_label']['ns'][$file]['medias']++; break; default: //var_export($file); $data['others_count']++; $data['dir_label']['ns'][$file]['medias']++; break; } break; } return false; } /** * Check if page belongs to one of namespaces in the list */ function isInNamespace($namespaces, $id) { foreach($namespaces as $ns) { if ((strpos($id, ':' . $ns . ':') === 0)) { return true; } } return false; } /** * Display pages and medias stats */ private function displayResourceStats($list) { global $TOC; $content = ''; if ($this->getConf('display_ressources_stats')) { if ($this->getConf('display_toc')) { $TOC[] = Array('hid' => 'resources', 'title' => $this->getLang('resources_title'), 'type' => 'ul', 'level' => '2'); } $class = $this->getConf('display_type'); $col = "page"; $content .= ''.DOKU_LF; $content .= '

'.$this->getLang('resources_title').'

'.DOKU_LF; $content .= '
'.DOKU_LF; $content .= ''.DOKU_LF; $content .= DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.''.DOKU_LF; if(empty($list)) { // Skip output $content .= DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.''.DOKU_LF; } else { foreach($list as $resname => $count) { if ($count <= 0) continue; // don't display resources with zero occurrences if ($resname === "dir_nest") continue; if ($resname === "dir_count") continue; if ($resname === "dir_label") continue; $content .= DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.''.DOKU_LF; } } $content .= '
'.$this->getLang('resources').'#
'.$this->getLang('empty_output').'
'.$this->getLang($resname).''.$count.'
'.DOKU_LF; $content .= '
'.DOKU_LF.DOKU_LF; } return $content; } /** * Display tags related stats */ private function displayTagStats($list) { global $TOC; $content = ''; if ($this->getConf('display_tags_stats')) { if (plugin_isdisabled('tag') || (!$tag = plugin_load('helper', 'tag'))) { msg('The Tag Plugin must be installed to display tag related stats.', -1); } else { if ($this->getConf('display_toc')) { $TOC[] = Array('hid' => 'tags', 'title' => $this->getLang('tags_title'), 'type' => 'ul', 'level' => '2'); } $occurrences = $tag->tagOccurrences(NULL, NULL, true, NULL); ksort($occurrences); $class = $this->getConf('display_type'); $col = "page"; $content .= ''.DOKU_LF; $content .= '

'.$this->getLang('tags_title').'

'.DOKU_LF; $content .= '
'.DOKU_LF; $content .= ''.DOKU_LF; $content .= DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.''.DOKU_LF; if (empty($occurrences)) { // Skip output $content .= DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.''.DOKU_LF; } else { foreach($occurrences as $tagname => $count) { if ($count <= 0) continue; // don't display tags with zero occurrences $content .= DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.''.DOKU_LF; } } $content .= '
'.$this->getLang('tags').' ('.count($occurrences).')#
'.$this->getLang('empty_output').'
'.$tagname.''.$count.'
'.DOKU_LF; $content .= '
'.DOKU_LF.DOKU_LF; } } return $content; } /** * Display namespaces related stats */ private function displayNamespaceStats($list) { global $TOC; $content = ''; if ($this->getConf('display_namespaces_stats')) { if ($this->getConf('display_toc')) { $TOC[] = Array('hid' => 'namespaces', 'title' => $this->getLang('namespaces_title'), 'type' => 'ul', 'level' => '2'); } $class = $this->getConf('display_type'); $col = "page"; $content .= ''.DOKU_LF; $content .= '

'.$this->getLang('namespaces_title').'

'.DOKU_LF; $content .= '
'.DOKU_LF; $content .= ''.DOKU_LF; $content .= DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.''.DOKU_LF; if(empty($list)) { // Skip output $content .= DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.''.DOKU_LF; } else { ksort($list); foreach($list as $namespace => $arr) { if ($namespace == '') $namespace = '[root]'; $content .= DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.DOKU_TAB.''.DOKU_LF; $content .= DOKU_TAB.''.DOKU_LF; } } $content .= '
'.$this->getLang('namespaces').' ('.count($list).')# '.$this->getLang('pages_count').'# '.$this->getLang('medias_count').'
'.$this->getLang('empty_output').'
'.$namespace.''.(isset($arr['pages']) ? $arr['pages'] : '0') .''.(isset($arr['medias']) ? $arr['medias'] : '0') .'
'.DOKU_LF; $content .= '
'.DOKU_LF.DOKU_LF; } return $content; } } // vim:ts=4:sw=4:et: