1<?php 2/** 3 * Discussion Plugin, threads component: displays a list of recently active discussions 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Esther Brunner <wikidesign@gmail.com> 7 */ 8 9// must be run within Dokuwiki 10if(!defined('DOKU_INC')) die(); 11 12if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 13require_once(DOKU_PLUGIN.'syntax.php'); 14 15/** 16 * All DokuWiki plugins to extend the parser/rendering mechanism 17 * need to inherit from this class 18 */ 19class syntax_plugin_discussion_threads extends DokuWiki_Syntax_Plugin { 20 21 /** 22 * return some info 23 */ 24 function getInfo(){ 25 return array( 26 'author' => 'Esther Brunner', 27 'email' => 'wikidesign@gmail.com', 28 'date' => '2006-12-02', 29 'name' => 'Discussion Plugin (threads component)', 30 'desc' => 'Displays a list of recently active discussions', 31 'url' => 'http://www.wikidesign.ch/en/plugin/discussion/start', 32 ); 33 } 34 35 function getType(){ return 'substition'; } 36 function getPType(){ return 'block'; } 37 function getSort(){ return 306; } 38 function connectTo($mode) { $this->Lexer->addSpecialPattern('\{\{threads>.+?\}\}',$mode,'plugin_discussion_threads'); } 39 40 /** 41 * Handle the match 42 */ 43 function handle($match, $state, $pos, &$handler){ 44 $match = substr($match, 10, -2); // strip {{threads> from start and }} from end 45 return cleanID($match); 46 } 47 48 /** 49 * Create output 50 */ 51 function render($mode, &$renderer, $ns) { 52 global $ID; 53 global $conf; 54 55 if ($ns == ':') $ns = ''; 56 elseif ($ns == '.') $ns = getNS($ID); 57 58 $pages = $this->_threadList($ns); 59 60 if (!count($pages)) return true; // nothing to display 61 62 if ($mode == 'xhtml'){ 63 64 // prevent caching to ensure content is always fresh 65 $renderer->info['cache'] = false; 66 67 // main table 68 $renderer->doc .= '<table class="threads">'; 69 foreach ($pages as $page){ 70 $renderer->doc .= '<tr><td class="page">'; 71 72 // page title 73 $id = $page['id']; 74 $title = $page['title']; 75 if (!$title) $title = str_replace('_', ' ', noNS($id)); 76 $renderer->doc .= $renderer->internallink(':'.$id, $title).'</td>'; 77 78 // topic starter 79 if ($this->getConf('threads_showuser')){ 80 if ($page['user']) $renderer->doc .= '<td class="user">'.$page['user'].'</td>'; 81 else $renderer->doc .= '<td class="user"> </td>'; 82 } 83 84 // number of replies 85 if ($page['num'] == 0) $repl = ''; 86 elseif ($page['num'] == 1) $repl = '1 '.$this->getLang('reply'); 87 else $repl = $page['num'].' '.$this->getLang('replies'); 88 $renderer->doc .= '<td class="num">'.$repl.'</td>'; 89 90 // last comment date 91 if ($this->getConf('threads_showdate')){ 92 $renderer->doc .= '<td class="date">'.date($conf['dformat'], $page['date']). 93 '</td>'; 94 } 95 $renderer->doc .= '</tr>'; 96 } 97 $renderer->doc .= '</table>'; 98 99 // show form to start a new discussion thread? 100 if (auth_quickaclcheck($ns.':*') >= AUTH_CREATE) 101 $renderer->doc .= $this->_newthreadForm($ns); 102 103 return true; 104 105 // for metadata renderer 106 } elseif ($mode == 'metadata'){ 107 foreach ($pages as $page){ 108 $id = $page['id']; 109 $renderer->meta['relation']['references'][$id] = true; 110 } 111 112 return true; 113 } 114 return false; 115 } 116 117 /** 118 * Returns an array of files with discussion sections, sorted by recent comments 119 */ 120 function _threadList($ns){ 121 global $conf; 122 123 require_once(DOKU_INC.'inc/search.php'); 124 125 $dir = $conf['datadir'].($ns ? '/'.str_replace(':', '/', $ns): ''); 126 127 // returns the list of pages in the given namespace and it's subspaces 128 $items = array(); 129 search($items, $dir, 'search_allpages', ''); 130 131 // add pages with comments to result 132 $result = array(); 133 foreach ($items as $item){ 134 $id = ($ns ? $ns.':' : '').$item['id']; 135 if (auth_quickaclcheck($id) < AUTH_READ) continue; // skip if no permission 136 $file = metaFN($id, '.comments'); 137 if (!@file_exists($file)) continue; // skip if no comments file 138 $data = unserialize(io_readFile($file, false)); 139 if ($data['status'] == 0) continue; // skip if comments are off 140 $date = filemtime($file); 141 $meta = p_get_metadata($id); 142 $result[$date] = array( 143 'id' => $id, 144 'title' => $meta['title'], 145 'user' => $meta['creator'], 146 'num' => $data['number'], 147 'date' => $date, 148 ); 149 } 150 151 // finally sort by time of last comment 152 krsort($result); 153 154 return $result; 155 } 156 157 /** 158 * Show the form to start a new discussion thread 159 */ 160 function _newthreadForm($ns){ 161 global $ID; 162 global $lang; 163 164 return '<div class="newthread_form">'. 165 '<form id="discussion__newthread_form" method="post" action="'.script().'" accept-charset="'.$lang['encoding'].'">'. 166 '<div class="no">'. 167 '<input type="hidden" name="id" value="'.$ID.'" />'. 168 '<input type="hidden" name="do" value="newthread" />'. 169 '<input type="hidden" name="ns" value="'.$ns.'" />'. 170 '<label class="block" for="discussion__newthread_title">'. 171 '<span>'.$this->getLang('newthread').':</span> '. 172 '<input class="edit" type="text" name="title" id="discussion__newthread_title" size="40" tabindex="1" />'. 173 '</label>'. 174 '<input class="button" type="submit" value="'.$lang['btn_create'].'" tabindex="2" />'. 175 '</div>'. 176 '</form>'. 177 '</div>'; 178 } 179 180} 181 182//Setup VIM: ex: et ts=4 enc=utf-8 : 183