1<?php 2/** 3 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 4 * @author Esther Brunner <wikidesign@gmail.com> 5 */ 6 7// must be run within Dokuwiki 8if (!defined('DOKU_INC')) die(); 9 10/** 11 * Class admin_plugin_blogtng 12 */ 13class admin_plugin_blogtng extends DokuWiki_Admin_Plugin { 14 15 /** @var helper_plugin_blogtng_comments */ 16 protected $commenthelper = null; 17 /** @var helper_plugin_blogtng_entry */ 18 protected $entryhelper = null; 19 /** @var helper_plugin_blogtng_sqlite */ 20 protected $sqlitehelper = null; 21 /** @var helper_plugin_blogtng_tags */ 22 protected $taghelper = null; 23 24 /** 25 * Determine position in list in admin window 26 * Lower values are sorted up 27 * 28 * @return int 29 */ 30 public function getMenuSort() { return 200; } 31 32 /** 33 * Return true for access only by admins (config:superuser) or false if managers are allowed as well 34 * 35 * @return bool 36 */ 37 public function forAdminOnly() { return false; } 38 39 /** 40 * Constructor 41 */ 42 public function __construct() { 43 $this->commenthelper = plugin_load('helper', 'blogtng_comments'); 44 $this->entryhelper = plugin_load('helper', 'blogtng_entry'); 45 $this->sqlitehelper = plugin_load('helper', 'blogtng_sqlite'); 46 $this->taghelper = plugin_load('helper', 'blogtng_tags'); 47 } 48 49 /** 50 * Handles all actions of the admin component 51 * 52 * @author Michael Klier <chi@chimeric.de> 53 */ 54 public function handle() { 55 if(!isset($_REQUEST['btng']['admin'])) { 56 $admin = null; 57 } else { 58 $admin = (is_array($_REQUEST['btng']['admin'])) ? key($_REQUEST['btng']['admin']) : $_REQUEST['btng']['admin']; 59 } 60 //skip actions when no valid security token given 61 $noSecTokenNeeded = array('search', 'comment_edit', 'comment_preview', null); 62 if(!in_array($admin, $noSecTokenNeeded) && !checkSecurityToken()) { 63 $admin = null; 64 } 65 66 // handle actions 67 switch($admin) { 68 69 case 'comment_save': 70 // FIXME error handling? 71 $comment = $_REQUEST['btng']['comment']; 72 $this->commenthelper->save($comment); 73 msg($this->getLang('msg_comment_save'), 1); 74 break; 75 76 case 'comment_delete': 77 // FIXME error handling 78 $comment = $_REQUEST['btng']['comment']; 79 $this->commenthelper->delete($comment['cid']); 80 msg($this->getLang('msg_comment_delete'), 1); 81 break; 82 83 case 'comment_batch_edit': 84 $batch = $_REQUEST['btng']['admin']['comment_batch_edit']; 85 $cids = $_REQUEST['btng']['comments']['cids']; 86 if($cids) { 87 foreach($cids as $cid) { 88 switch($batch) { 89 // FIXME messages 90 case 'delete': 91 $this->commenthelper->delete($cid); 92 msg($this->getLang('msg_comment_delete'), 1); 93 break; 94 case 'status_hidden': 95 $this->commenthelper->moderate($cid, 'hidden'); 96 msg($this->getLang('msg_comment_status_change'), 1); 97 break; 98 case 'status_visible': 99 $this->commenthelper->moderate($cid, 'visible'); 100 msg($this->getLang('msg_comment_status_change'), 1); 101 break; 102 } 103 } 104 } 105 break; 106 107 case 'entry_set_blog': 108 // FIXME errors? 109 $pid = $_REQUEST['btng']['entry']['pid']; 110 $blog = $_REQUEST['btng']['entry']['blog']; 111 if($pid) { 112 $blogs = $this->entryhelper->get_blogs(); 113 if(in_array($blog, $blogs)) { 114 $this->entryhelper->load_by_pid($pid); 115 $this->entryhelper->entry['blog'] = $blog; 116 $this->entryhelper->save(); 117 } 118 } 119 msg($this->getLang('msg_entry_blog_change'), 1); 120 break; 121 122 case 'entry_set_commentstatus': 123 $pid = $_REQUEST['btng']['entry']['pid']; 124 $status = $_REQUEST['btng']['entry']['commentstatus']; 125 if($pid) { 126 if(in_array($status, array('disabled', 'enabled', 'closed'))) { 127 $this->entryhelper->load_by_pid($pid); 128 $this->entryhelper->entry['commentstatus'] = $status; 129 $this->entryhelper->save(); 130 } 131 } 132 msg($this->getLang('msg_comment_status_change'), 1); 133 break; 134 135 default: 136 // do nothing - show dashboard 137 break; 138 } 139 } 140 141 /** 142 * Handles the XHTML output of the admin component 143 * 144 * @author Michael Klier <chi@chimeric.de> 145 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 146 */ 147 public function html() { 148 global $ID; 149 150 ptln('<h1>'.$this->getLang('menu').'</h1>'); 151 152 $admin = (is_array($_REQUEST['btng']['admin'])) ? key($_REQUEST['btng']['admin']) : $_REQUEST['btng']['admin']; 153 154 ptln('<div id="blogtng__admin">'); 155 156 // display link back to dashboard 157 if($admin) { 158 ptln('<div class="level1">'); 159 ptln('<p><a href="' . wl($ID, array('do'=>'admin', 'page'=>'blogtng')) . '" title="' . $this->getLang('dashboard') . '">← ' . $this->getLang('dashboard') . '</a></p>'); 160 ptln('</div>'); 161 162 } 163 164 switch($admin) { 165 case 'search': 166 // display search form 167 $this->xhtml_search_form(); 168 169 ptln('<h2>' . $this->getLang('searchresults') . '</h2>'); 170 171 $query = $_REQUEST['btng']['query']; 172 $query['resultset'] = 'query'; 173 174 $this->xhtml_search_results($query); 175 break; 176 177 case 'comment_edit': 178 case 'comment_preview': 179 if($admin == 'comment_edit') { 180 $obj = $this->commenthelper->comment_by_cid($_REQUEST['btng']['comment']['cid']); 181 $comment = $obj->data; 182 if($comment) { 183 $this->xhtml_comment_edit_form($comment); 184 } 185 } 186 if($admin == 'comment_preview') { 187 $this->xhtml_comment_edit_form($_REQUEST['btng']['comment']); 188 $this->xhtml_comment_preview($_REQUEST['btng']['comment']); 189 } 190 break; 191 192 default: 193 // display search form 194 $this->xhtml_search_form(); 195 196 // print latest 'x' comments/entries 197 $query = $_REQUEST['btng']['comment']; 198 $query['resultset'] = 'comment'; 199 $this->xhtml_latest_items($query); 200 201 $query = $_REQUEST['btng']['entry']; 202 $query['resultset'] = 'entry'; 203 $this->xhtml_latest_items($query); 204 break; 205 } 206 207 ptln('</div>'); 208 } 209 210 /** 211 * Displays a list of comments or entries for a given search term 212 * 213 * @param array $query url parameters for query 214 */ 215 private function xhtml_search_results($query) { 216 if(!$this->sqlitehelper->ready()) return; 217 218 $db = $this->sqlitehelper->getDB(); 219 220 switch($query['filter']) { 221 case 'entry_title': 222 case 'entry_author': 223 $select = 'SELECT * '; 224 $from = 'FROM entries '; 225 $orderby = 'ORDER BY created DESC '; 226 $itemdisplaycallback = 'xhtml_entry_list'; 227 break; 228 case 'comment': 229 case 'comment_ip': 230 $select = 'SELECT cid, comments.pid as pid, ip, source, name, comments.mail as mail, web, avatar, comments.created as created, text, status '; 231 $from = 'FROM comments LEFT JOIN entries ON comments.pid = entries.pid '; 232 $orderby = 'ORDER BY comments.created DESC '; 233 $itemdisplaycallback = 'xhtml_comment_list'; 234 break; 235 case 'tags': 236 $select = 'SELECT DISTINCT entries.pid as pid, page, title, blog, image, created, lastmod, author, login, mail '; 237 $from = 'FROM entries LEFT JOIN tags ON entries.pid = tags.pid '; 238 $orderby = 'ORDER BY created DESC '; 239 $itemdisplaycallback = 'xhtml_entry_list'; 240 break; 241 default: 242 return; 243 } 244 $count = 'SELECT COUNT(*) as count '; 245 246 if(isset($query['blog']) && $query['blog']) { 247 $where = 'WHERE blog = ' . $db->quote_string($query['blog']) . ' '; 248 } else { 249 $where = 'WHERE blog != "" '; 250 } 251 252 if(isset($query['string']) && $query['string'] != '') { 253 switch($query['filter']) { 254 case 'entry_title': 255 $where .= 'AND ( title LIKE \'%'.$db->escape_string($query['string']).'%\' ) '; 256 break; 257 case 'entry_author': 258 $where .= 'AND ( author LIKE \'%'.$db->escape_string($query['string']).'%\' ) '; 259 break; 260 case 'comment': 261 $where .= 'AND ( comments.text LIKE \'%'.$db->escape_string($query['string']).'%\' ) '; 262 break; 263 case 'comment_ip': 264 $where .= 'AND ( comments.ip LIKE \'%'.$db->escape_string($query['string']).'%\' ) '; 265 break; 266 case 'tags': 267 $where .= 'AND ( tags.tag LIKE \'%'.$db->escape_string($query['string']).'%\' ) '; 268 break; 269 } 270 } 271 272 //comments: if pid is given limit to give page 273 if(isset($query['pid']) && $query['pid'] != '') { 274 $where .= 'AND ( comments.pid = ' . $db->quote_string($query['pid']) . ' ) '; 275 } 276 277 $sqlcount = $count . $from . $where; 278 $sqlselect = $select . $from . $where . $orderby; 279 280 281 $sqlselect .= ' LIMIT '.$this->getLimitParam($query, 20); 282 $offset = $this->getOffsetParam($query); 283 if($offset > 0) { 284 $sqlselect .= ' OFFSET '.$offset; 285 } 286 287 $res = $db->query($sqlcount); 288 $count = $db->res2single($res); 289 290 $resid = $db->query($sqlselect); 291 if($resid) { 292 $this->xhtml_show_paginated_result($resid, $query, $itemdisplaycallback, $count); 293 } 294 } 295 296 /** 297 * Display paginated results 298 * 299 * @param object $resid Database resource object 300 * @param array $query Query parameters 301 * @param string $itemdisplaycallback called for each item, to display content of item 302 * @param int $count Number of total items 303 * @param int $limit Number of results to display per page (page size) 304 * 305 * @author Michael Klier <chi@chimeric.de> 306 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 307 */ 308 private function xhtml_show_paginated_result($resid, $query, $itemdisplaycallback, $count, $limit = 20) { 309 global $lang; 310 if(!$resid) return; 311 312 $offset = $this->getOffsetParam($query); 313 $currentpage = floor($offset / $limit) + 1; 314 315 $items = $this->sqlitehelper->getDB()->res2arr($resid); 316 317 if($items) { 318 ptln('<div class="level2"><p><strong>' . $this->getLang('numhits') . ':</strong> ' . $count .'</p></div>'); 319 320 // show pagination only when enough items 321 if($count > $limit) { 322 $this->xhtml_pagination($query, $currentpage, $count, $limit); 323 } 324 325 call_user_func(array($this, $itemdisplaycallback), $items, $query); 326 327 } else { 328 ptln('<div class="level2">'); 329 ptln($lang['nothingfound']); 330 ptln('</div>'); 331 } 332 333 // show pagination only when enough items 334 if($count > $limit) { 335 $this->xhtml_pagination($query, $currentpage, $count, $limit); 336 } 337 } 338 339 /** 340 * Diplays that pagination links of a query 341 * 342 * @param array $query Query parameters 343 * @param int $currentpage number of current page 344 * @param int $maximum maximum number of items available 345 * @param int $limit number of items per page 346 * 347 * @author Michael Klier <chi@chimeric.de> 348 */ 349 private function xhtml_pagination($query, $currentpage, $maximum, $limit) { 350 $lastpage = (int) ceil($maximum / $limit); 351 352 $pages[] = 1; // first always 353 $pages[] = $lastpage; // last page always 354 $pages[] = $currentpage; // current page always 355 356 if($lastpage > 1){ // if enough pages 357 $pages[] = 2; // second and .. 358 $pages[] = $lastpage-1; // one before last 359 } 360 361 // three around current 362 if($currentpage-1 > 0) $pages[] = $currentpage-1; 363 if($currentpage-2 > 0) $pages[] = $currentpage-2; 364 if($currentpage-3 > 0) $pages[] = $currentpage-3; 365 if($currentpage+1 < $lastpage) $pages[] = $currentpage+1; 366 if($currentpage+2 < $lastpage) $pages[] = $currentpage+2; 367 if($currentpage+3 < $lastpage) $pages[] = $currentpage+3; 368 369 $pages = array_unique($pages); 370 sort($pages); 371 372 ptln('<div class="level2"><p>'); 373 374 if($currentpage > 1) { 375 $this->xhtml_paginationurl($query, ($currentpage - 2) * $limit, $limit, '«', $currentpage - 1); 376 } 377 378 $last = 0; 379 foreach($pages as $page) { 380 if($page - $last > 1) { 381 ptln('<span class="sep">...</span>'); 382 } 383 if($page == $currentpage) { 384 ptln('<span class="cur">' . $page . '</span>'); 385 } else { 386 $this->xhtml_paginationurl($query, ($page - 1) * $limit, $limit, $page, $page); 387 } 388 $last = $page; 389 } 390 391 if($currentpage < $lastpage) { 392 $this->xhtml_paginationurl($query, $currentpage * $limit, $limit, '»', $currentpage + 1); 393 } 394 395 ptln('</p></div>'); 396 } 397 398 /** 399 * Print a pagination link. 400 * 401 * @param array $query Query parameters 402 * @param int $offset number of previous items 403 * @param int $limit number of items at this page 404 * @param string $text text of url 405 * @param string $title title of url 406 * @internal param string $anchor url anchor 407 */ 408 private function xhtml_paginationurl($query, $offset, $limit, $text, $title) { 409 global $ID; 410 list($params, $anchor) = $this->buildUrlParams($query, $offset, $limit); 411 ptln("<a href='".wl($ID, $params).'#'.$anchor."' title='$title'>$text</a>"); 412 } 413 414 /** 415 * Build URL parameters. 416 * 417 * @param array $query Query parameters 418 * @param int $offset number of previous items 419 * @param int $limit number of items at this page 420 * @return array($params, $anchor) 421 */ 422 private function buildUrlParams($query, $offset, $limit) { 423 $params = array( 424 'do' => 'admin', 425 'page' => 'blogtng', 426 'btng[' . $query['resultset'] . '][limit]' => $limit , 427 'btng[' . $query['resultset'] . '][offset]' => $offset 428 ); 429 $anchor = $query['resultset'] . '_latest'; 430 431 if($query['resultset'] == 'query') { 432 $params = $params + array( 433 'btng[admin]' => 'search', 434 'btng[query][filter]' => $query['filter'], 435 'btng[query][blog]' => $query['blog'], 436 'btng[query][string]' => $query['string'], 437 'btng[query][pid]' => $query['pid'] 438 ); 439 $anchor = ''; 440 } 441 return array($params, $anchor); 442 } 443 444 /** 445 * Display the latest comments or entries 446 * 447 * @param $query Query parameters 448 * 449 * @author Michael Klier <chi@chimeric.de> 450 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 451 */ 452 private function xhtml_latest_items($query) { 453 $resultset = $query['resultset']; 454 455 printf("<h2 id='{$resultset}_latest'>".$this->getLang($resultset.'_latest').'</h2>', $this->getLimitParam($query)); 456 $this->xhtml_limit_form($query); 457 458 if(!$this->sqlitehelper->ready()) return; 459 460 $count = 'SELECT COUNT(pid) as count '; 461 $select = 'SELECT * '; 462 463 if($resultset == 'entry') { 464 $from = 'FROM entries '; 465 $where = 'WHERE blog != "" '; 466 $itemdisplaycallback = 'xhtml_entry_list'; 467 } else { 468 $from = 'FROM comments '; 469 $where = ''; 470 $itemdisplaycallback = 'xhtml_comment_list'; 471 } 472 473 $orderby = 'ORDER BY created DESC '; 474 475 $sqlcount = $count . $from . $where; 476 $sqlselect = $select . $from . $where . $orderby; 477 478 $limit = $this->getLimitParam($query); 479 $offset = $this->getOffsetParam($query); 480 $sqlselect .= 'LIMIT ' . $limit; 481 if($offset) { 482 $sqlselect .= ' OFFSET ' . $offset; 483 } 484 485 $res = $this->sqlitehelper->getDB()->query($sqlcount); 486 $count = $this->sqlitehelper->getDB()->res2single($res); 487 488 $resid = $this->sqlitehelper->getDB()->query($sqlselect); 489 if(!$resid) { 490 return; 491 } 492 $this->xhtml_show_paginated_result($resid, $query, $itemdisplaycallback, $count, $limit); 493 } 494 495 /** 496 * Displays a list of entries, as callback of xhtml_search_results() 497 * 498 * @param $entries Array of entries 499 * @param $query Query parameters 500 * 501 * @author Michael Klier <chi@chimeric.de> 502 */ 503 private function xhtml_entry_list($entries, $query) { 504 ptln('<div class="level2">'); 505 ptln('<table class="inline">'); 506 507 ptln('<th>' . $this->getLang('created') . '</th>'); 508 ptln('<th>' . $this->getLang('author') . '</th>'); 509 ptln('<th>' . $this->getLang('entry') . '</th>'); 510 ptln('<th>' . $this->getLang('blog') . '</th>'); 511 ptln('<th>' . $this->getLang('commentstatus') . '</th>'); 512 ptln('<th>' . $this->getLang('comments') . '</th>'); 513 ptln('<th>' . $this->getLang('tags') . '</th>'); 514 ptln('<th></th>'); 515 foreach($entries as $entry) { 516 $this->xhtml_entry_item($entry, $query); 517 } 518 ptln('</table>'); 519 ptln('</div>'); 520 } 521 522 /** 523 * Displays a single entry and related actions 524 * 525 * @param $entry Single entry 526 * @param $query Query parameters 527 * 528 * @author Michael Klier <chi@chimeric.de> 529 */ 530 private function xhtml_entry_item($entry, $query) { 531 global $lang; 532 global $ID; 533 534 static $class = 'odd'; 535 ptln('<tr class="' . $class . '">'); 536 $class = ($class == 'odd') ? 'even' : 'odd'; 537 538 ptln('<td class="entry_created">' . dformat($entry['created']) . '</td>'); 539 ptln('<td class="entry_author">' . hsc($entry['author']) . '</td>'); 540 ptln('<td class="entry_title">' . html_wikilink(':'.$entry['page'], $entry['title']) . '</td>'); 541 ptln('<td class="entry_set_blog">' . $this->xhtml_entry_edit_form($entry, $query, 'blog') . '</th>'); 542 ptln('<td class="entry_set_commentstatus">' . $this->xhtml_entry_edit_form($entry, $query, 'commentstatus') . '</th>'); 543 544 $this->commenthelper->setPid($entry['pid']); 545 546 // search comments of this entry link 547 ptln('<td class="entry_comments">'); 548 $count = $this->commenthelper->get_count(null, true); 549 if($count > 0) { 550 $params = array('do' => 'admin', 551 'page' => 'blogtng', 552 'btng[admin]' => 'search', 553 'btng[query][filter]' => 'comment', 554 'btng[query][pid]' => $entry['pid']); 555 ptln('<a href="' . wl($ID, $params) . '" title="' . $this->getLang('comments') . '">' . $count . '</a>'); 556 } else { 557 ptln($count); 558 } 559 ptln('</td>'); 560 561 // tags filter links 562 ptln('<td class="entry_tags">'); 563 $this->taghelper->load($entry['pid']); 564 $tags = $this->taghelper->getTags(); 565 $count = count($tags); 566 for($i = 0; $i < $count; $i++) { 567 $params = array('do' => 'admin', 568 'page' => 'blogtng', 569 'btng[admin]' => 'search', 570 'btng[query][filter]' => 'tags', 571 'btng[query][string]' => $tags[$i]); 572 $link = '<a href="' . wl($ID, $params) . '" title="' . $tags[$i] . '">' . $tags[$i] . '</a>'; 573 if($i < ($count - 1)) $link .= ', '; 574 ptln($link); 575 } 576 ptln('</td>'); 577 578 // edit links 579 ptln('<td class="entry_edit">'); 580 $params = array('id' => $entry['page'], 581 'do' => 'edit'); 582 ptln('<a href="' . wl($ID, $params) . '" class="blogtng_btn_edit" title="' . $lang['btn_secedit'] . '">' . $lang['btn_secedit'] . '</a>'); 583 ptln('</td>'); 584 585 ptln('</tr>'); 586 } 587 588 /** 589 * Displays a list of comments, as callback of xhtml_search_results() 590 * 591 * @param $comments List of comments 592 * @param $query Query parameters 593 * 594 * @author Michael Klier <chi@chimeric.de> 595 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 596 */ 597 private function xhtml_comment_list($comments, $query) { 598 global $lang; 599 600 ptln('<div class="level2">'); 601 602 ptln('<form action="' . DOKU_SCRIPT . '" method="post" id="blogtng__comment_batch_edit_form">'); 603 ptln('<input type="hidden" name="page" value="blogtng" />'); 604 ptln('<input type="hidden" name="btng[comment][limit]" value="' .$this->getLimitParam($query). '" />'); 605 ptln('<input type="hidden" name="btng[comment][offset]" value="' .$this->getLimitParam($query). '" />'); 606 ptln('<input type="hidden" name="sectok" value="' .getSecurityToken(). '" />'); 607 608 ptln('<table class="inline">'); 609 610 ptln('<th id="blogtng__admin_checkall_th"></th>'); 611 ptln('<th>' . $this->getLang('comments') . '</th>'); 612 ptln('<th></th>'); 613 614 foreach($comments as $comment) { 615 $this->xhtml_comment_item($comment); 616 } 617 618 ptln('</table>'); 619 620 ptln('<select name="btng[admin][comment_batch_edit]">'); 621 ptln('<option value="status_visible">Visible</option>'); 622 ptln('<option value="status_hidden">Hidden</option>'); 623 ptln('<option value="delete">'.$lang['btn_delete'].'</option>'); 624 ptln('</select>'); 625 ptln('<input type="submit" class="edit button" name="do[admin]" value="' . $lang['btn_update'] . '" />'); 626 ptln('</form>'); 627 628 ptln('</div>'); 629 } 630 631 /** 632 * Displays a single comment and related actions 633 * 634 * @param $comment A single comment 635 * 636 * @author Michael Klier <chi@chimeric.de> 637 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 638 */ 639 private function xhtml_comment_item($comment) { 640 global $lang; 641 global $ID; 642 643 static $class = 'odd'; 644 ptln('<tr class="' . $class . '">'); 645 $class = ($class == 'odd') ? 'even' : 'odd'; 646 647 $cmt = new blogtng_comment(); 648 $cmt->init($comment); 649 ptln('<td class="admin_checkbox">'); 650 ptln('<input type="checkbox" class="comment_cid" name="btng[comments][cids][]" value="' . $comment['cid'] . '" />'); 651 ptln('</td>'); 652 653 ptln('<td class="comment_row">'); 654 ptln('<div class="comment_text" title="'.$this->getLang('comment_text').'">' . hsc($comment['text']) . '</div>'); 655 ptln('<div class="comment_metadata">'); 656 ptln('<span class="comment_created" title="'.$this->getLang('created').'">' . dformat($comment['created']) . '</span>'); 657 ptln('<span class="comment_ip" title="'.$this->getLang('comment_ip').'">' . hsc($comment['ip']) . '</span>'); 658 659 ptln('<span class="comment_name" title="'.$this->getLang('comment_name').'">'); 660 $avatar = $cmt->tpl_avatar(16,16,true); 661 if($avatar) ptln('<img src="' . $avatar . '" alt="' . hsc($comment['name']) . '" class="avatar" /> '); 662 if($comment['mail']){ 663 ptln('<a href="mailto:' . hsc($comment['mail']) . '" class="mail" title="' . hsc($comment['mail']) . '">' . hsc($comment['name']) . '</a>'); 664 }else{ 665 ptln(hsc($comment['name'])); 666 } 667 ptln('</span>'); 668 669 $weburl = ''; 670 if($comment['web']) $weburl = '<a href="' . hsc($comment['web']) . '" title="' . hsc($comment['web']) . '">' . hsc($comment['web']) . '</a>'; 671 ptln('<span class="comment_web" title="'.$this->getLang('comment_web').'">'.$weburl.'</span>'); 672 673 ptln('<span class="comment_status" title="'.$this->getLang('comment_status').'">' . hsc($comment['status']) . '</span>'); 674 ptln('<span class="comment_source" title="'.$this->getLang('comment_source').'">' . hsc($comment['source']) . '</span>'); 675 676 $this->entryhelper->load_by_pid($comment['pid']); 677 $pagelink = html_wikilink(':'.$this->entryhelper->entry['page'], $this->entryhelper->entry['title']); 678 ptln('<span class="comment_entry" title="'.$this->getLang('comment_entry').'">' . $pagelink . '</span>'); 679 ptln('</div>'); 680 ptln('</td>'); 681 682 ptln('<td class="comment_edit">'); 683 $params = array('do'=>'admin', 684 'page'=>'blogtng', 685 'btng[comment][cid]'=>$comment['cid'], 686 'btng[admin]'=>'comment_edit'); 687 ptln('<a href="' . wl($ID, $params). '" class="blogtng_btn_edit" title="' . $lang['btn_edit'] . '">' . $lang['btn_secedit'] . '</a>'); 688 ptln('</td>'); 689 690 ptln('</tr>'); 691 } 692 693 /** 694 * Displays a preview of the comment 695 * 696 * @param array $data submitted comment properties 697 */ 698 private function xhtml_comment_preview($data) { 699 $this->entryhelper->load_by_pid($data['pid']); 700 $blogname = $this->entryhelper->get_blog(); 701 702 ptln('<div id="blogtng__comment_preview">'); 703 ptln(p_locale_xhtml('preview')); 704 ptln('<br />'); 705 $comment = new blogtng_comment(); 706 $comment->init($data); 707 $comment->output($blogname); 708 ptln('</div>'); 709 } 710 711 /** 712 * Displays the form to change the comment status of a blog entry 713 * 714 * @param $entry Blog entry 715 * @param $query Query parameters 716 * @param string $field 717 * @return Doku_Form|string 718 * 719 * @author Michael Klier <chi@chimeric.de> 720 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 721 */ 722 private function xhtml_entry_edit_form($entry, $query, $field = 'commentstatus') { 723 global $lang; 724 725 $changablefields = array('commentstatus', 'blog'); 726 if(!in_array($field, $changablefields)) return hsc($entry[$field]); 727 728 $form = new Doku_Form(array('id'=>"blogtng__entry_set_{$field}_form")); 729 $form->addHidden('do', 'admin'); 730 $form->addHidden('page', 'blogtng'); 731 $form->addHidden('btng[entry][pid]', $entry['pid']); 732 $form->addHidden('btng[entry][limit]', $this->getLimitParam($query)); 733 $form->addHidden('btng[entry][offset]', $this->getOffsetParam($query)); 734 735 if($field == 'commentstatus') { 736 $availableoptions = array('enabled', 'disabled', 'closed'); 737 } else { 738 $availableoptions = $this->entryhelper->get_blogs(); 739 } 740 $form->addElement(form_makeListBoxField("btng[entry][$field]", $availableoptions, $entry[$field], '')); 741 $form->addElement('<input type="submit" name="btng[admin][entry_set_'.$field.']" class="edit button" value="' . $lang['btn_update'] . '" />'); 742 743 ob_start(); 744 html_form("blotng__btn_entry_set_{$field}", $form); 745 $form = ob_get_clean(); 746 return $form; 747 } 748 749 /** 750 * Displays the comment edit form 751 * 752 * @param $comment 753 * 754 * @author Michael Klier <chi@chimeric.de> 755 */ 756 private function xhtml_comment_edit_form($comment) { 757 global $lang; 758 759 ptln('<div class="level1">'); 760 $form = new Doku_Form(array('id'=>'blogtng__comment_edit_form')); 761 $form->startFieldset($this->getLang('act_comment_edit')); 762 $form->addHidden('page', 'blogtng'); 763 $form->addHidden('do', 'admin'); 764 $form->addHidden('btng[comment][cid]', $comment['cid']); 765 $form->addHidden('btng[comment][pid]', $comment['pid']); 766 $form->addHidden('btng[comment][created]', $comment['created']); 767 $form->addElement(form_makeListBoxField('btng[comment][status]', array('visible', 'hidden'), $comment['status'], $this->getLang('comment_status'))); 768 $form->addElement('<br />'); 769 $form->addElement(form_makeListBoxField('btng[comment][source]', array('comment', 'trackback', 'pingback'), $comment['source'], $this->getLang('comment_source'))); 770 $form->addElement('<br />'); 771 $form->addElement(form_makeTextField('btng[comment][name]', $comment['name'], $this->getLang('comment_name'))); 772 $form->addElement('<br />'); 773 $form->addElement(form_makeTextField('btng[comment][mail]', $comment['mail'], $this->getLang('comment_mail'))); 774 $form->addElement('<br />'); 775 $form->addElement(form_makeTextField('btng[comment][web]', $comment['web'], $this->getLang('comment_web'))); 776 $form->addElement('<br />'); 777 $form->addElement(form_makeTextField('btng[comment][avatar]', $comment['avatar'], $this->getLang('comment_avatar'))); 778 $form->addElement('<br />'); 779 $form->addElement('<textarea class="edit" name="btng[comment][text]" rows="10" cols="80">' . $comment['text'] . '</textarea>'); 780 $form->addElement('<input type="submit" name="btng[admin][comment_save]" class="edit button" value="' . $lang['btn_save'] . '" />'); 781 $form->addElement('<input type="submit" name="btng[admin][comment_preview]" class="edit button" value="' . $lang['btn_preview'] . '" />'); 782 $form->addElement('<input type="submit" name="btng[admin][comment_delete]" class="edit button" value="' . $lang['btn_delete'] . '" />'); 783 $form->endFieldset(); 784 html_form('blogtng__edit_comment', $form); 785 ptln('</div>'); 786 } 787 788 /** 789 * Displays the search form 790 * 791 * @author Michael Klier <chi@chimeric.de> 792 */ 793 private function xhtml_search_form() { 794 global $lang; 795 796 ptln('<div class="level1">'); 797 798 $blogs = $this->entryhelper->get_blogs(); 799 800 $form = new Doku_Form(array('id'=>'blogtng__search_form')); 801 $form->startFieldset($lang['btn_search']); 802 $form->addHidden('page', 'blogtng'); 803 $form->addHidden('btng[admin]', 'search'); 804 805 $form->addElement(form_makeListBoxField('btng[query][blog]', $blogs, $_REQUEST['btng']['query']['blog'], $this->getLang('blog'))); 806 $form->addElement(form_makeListBoxField('btng[query][filter]', array('entry_title', 'entry_author', 'comment', 'comment_ip', 'tags'), $_REQUEST['btng']['query']['filter'], $this->getLang('filter'))); 807 $form->addElement(form_makeTextField('btng[query][string]', $_REQUEST['btng']['query']['string'],'')); 808 809 $form->addElement(form_makeButton('submit', 'admin', $lang['btn_search'])); 810 $form->endFieldset(); 811 html_form('blogtng__search_form', $form); 812 813 ptln('</div>'); 814 } 815 816 /** 817 * Displays the limit selection form 818 * 819 * @param string $query 820 * 821 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 822 */ 823 private function xhtml_limit_form($query='') { 824 global $lang; 825 826 $limit = $this->getLimitParam($query); 827 $resultset = $query['resultset']; 828 829 ptln('<div class="level1">'); 830 831 $form = new Doku_Form(array('id'=>'blogtng__'.$resultset.'_limit_form')); 832 $form->startFieldset(""); 833 $form->addHidden('page', 'blogtng'); 834 $form->addElement( 835 form_makeListBoxField("btng[{$resultset}][limit]", 836 array(5,10,15,20,25,30,40,50,100), 837 $limit, 838 $this->getLang('numhits'))); 839 $form->addHidden("btng[{$resultset}][offset]", $this->getOffsetParam($query)); 840 $form->addElement(form_makeButton('submit', 'admin', $lang['btn_update'])); 841 $form->endFieldset(); 842 html_form('blogtng__'.$resultset.'_cnt_form', $form); 843 844 ptln('</div>'); 845 } 846 847 /** 848 * Get submitted value of items per page 849 * 850 * @param array $query url parameters 851 * @param int $default value 852 * @return int number of items per page 853 * 854 * @author hArpanet <dokuwiki-blogtng@harpanet.com> 855 */ 856 private function getLimitParam($query, $default = 5) { 857 return (int) (isset($query['limit']) ? $query['limit'] : $default); 858 } 859 860 /** 861 * Get the offset of the pagination 862 * 863 * @param array $query url parameters 864 * @param int $default value 865 * @return int offset number of items 866 */ 867 public function getOffsetParam($query, $default = 0) { 868 return (int) (isset($query['offset']) ? $query['offset'] : $default); 869 } 870} 871// vim:ts=4:sw=4:et: 872