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-10-05', 29 'name' => 'Discussion Plugin (threads component)', 30 'desc' => 'Displays a list of recently active discussions', 31 'url' => 'http://wiki.splitbrain.org/plugin:discussion', 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, acl checked 128 $items = array(); 129 search($items, $dir, 'search_list', ''); 130 131 // add pages with comments to result 132 $result = array(); 133 foreach ($items as $item){ 134 $id = ($ns ? $ns.':' : '').$item['id']; 135 $file = metaFN($id, '.comments'); 136 if (!@file_exists($file)) continue; // skip if no comments file 137 $data = unserialize(io_readFile($file, false)); 138 if ($data['status'] == 0) continue; // skip if comments are off 139 $date = filemtime($file); 140 $meta = p_get_metadata($id); 141 $result[$date] = array( 142 'id' => $id, 143 'title' => $meta['title'], 144 'user' => $meta['creator'], 145 'num' => $data['number'], 146 'date' => $date, 147 ); 148 } 149 150 // finally sort by time of last comment 151 krsort($result); 152 153 return $result; 154 } 155 156 /** 157 * Show the form to start a new discussion thread 158 */ 159 function _newthreadForm($ns){ 160 global $ID; 161 global $lang; 162 163 return '<div class="newthread_form">'. 164 '<form id="discussion__newthread_form" method="post" action="'.script().'" accept-charset="'.$lang['encoding'].'">'. 165 '<div class="no">'. 166 '<input type="hidden" name="id" value="'.$ID.'" />'. 167 '<input type="hidden" name="do" value="newthread" />'. 168 '<input type="hidden" name="ns" value="'.$ns.'" />'. 169 '<label class="block" for="discussion__newthread_title">'. 170 '<span>'.$this->getLang('newthread').':</span> '. 171 '<input class="edit" type="text" name="title" id="discussion__newthread_title" size="40" tabindex="1" />'. 172 '</label>'. 173 '<input class="button" type="submit" value="'.$lang['btn_create'].'" tabindex="2" />'. 174 '</div>'. 175 '</form>'. 176 '</div>'; 177 } 178 179} 180 181//Setup VIM: ex: et ts=4 enc=utf-8 : 182