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 // last comment date 79 if ($this->getConf('threads_showdate')){ 80 $renderer->doc .= '<td class="date">'.date($conf['dformat'], $page['date']). 81 '</td>'; 82 } 83 84 // topic starter 85 if ($this->getConf('threads_showuser')){ 86 if ($page['user']) $renderer->doc .= '<td class="user">'.$page['user'].'</td>'; 87 else $renderer->doc .= '<td class="user"> </td>'; 88 } 89 90 // number of replies 91 if ($page['num'] == 0) $repl = ''; 92 elseif ($page['num'] == 1) $repl = '1 '.$this->getLang('reply'); 93 else $repl = $page['num'].' '.$this->getLang('replies'); 94 $renderer->doc .= '<td class="num">'.$repl.'</td>'; 95 96 $renderer->doc .= '</tr>'; 97 } 98 $renderer->doc .= '</table>'; 99 100 // show form to start a new discussion thread? 101 if (auth_quickaclcheck($ns.':*') >= AUTH_CREATE) 102 $renderer->doc .= $this->_newthreadForm($ns); 103 104 return true; 105 106 // for metadata renderer 107 } elseif ($mode == 'metadata'){ 108 foreach ($pages as $page){ 109 $id = $page['id']; 110 $renderer->meta['relation']['references'][$id] = true; 111 } 112 113 return true; 114 } 115 return false; 116 } 117 118 /** 119 * Returns an array of files with discussion sections, sorted by recent comments 120 */ 121 function _threadList($ns){ 122 global $conf; 123 124 require_once(DOKU_INC.'inc/search.php'); 125 126 $dir = $conf['datadir'].($ns ? '/'.str_replace(':', '/', $ns): ''); 127 128 // returns the list of pages in the given namespace and it's subspaces 129 $items = array(); 130 search($items, $dir, 'search_allpages', ''); 131 132 // add pages with comments to result 133 $result = array(); 134 foreach ($items as $item){ 135 $id = ($ns ? $ns.':' : '').$item['id']; 136 if (auth_quickaclcheck($id) < AUTH_READ) continue; // skip if no permission 137 $file = metaFN($id, '.comments'); 138 if (!@file_exists($file)) continue; // skip if no comments file 139 $data = unserialize(io_readFile($file, false)); 140 if ($data['status'] == 0) continue; // skip if comments are off 141 $date = filemtime($file); 142 $meta = p_get_metadata($id); 143 $result[$date] = array( 144 'id' => $id, 145 'title' => $meta['title'], 146 'user' => $meta['creator'], 147 'num' => $data['number'], 148 'date' => $date, 149 ); 150 } 151 152 // finally sort by time of last comment 153 krsort($result); 154 155 return $result; 156 } 157 158 /** 159 * Show the form to start a new discussion thread 160 */ 161 function _newthreadForm($ns){ 162 global $ID; 163 global $lang; 164 165 return '<div class="newthread_form">'. 166 '<form id="discussion__newthread_form" method="post" action="'.script().'" accept-charset="'.$lang['encoding'].'">'. 167 '<div class="no">'. 168 '<input type="hidden" name="id" value="'.$ID.'" />'. 169 '<input type="hidden" name="do" value="newthread" />'. 170 '<input type="hidden" name="ns" value="'.$ns.'" />'. 171 '<label class="block" for="discussion__newthread_title">'. 172 '<span>'.$this->getLang('newthread').':</span> '. 173 '<input class="edit" type="text" name="title" id="discussion__newthread_title" size="40" tabindex="1" />'. 174 '</label>'. 175 '<input class="button" type="submit" value="'.$lang['btn_create'].'" tabindex="2" />'. 176 '</div>'. 177 '</form>'. 178 '</div>'; 179 } 180 181} 182 183//Setup VIM: ex: et ts=4 enc=utf-8 : 184