1<?php 2/** 3 * DokuWiki Plugin comment (Syntax Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Your Name 7 */ 8 9if (!defined('DOKU_INC')) die(); 10 11class syntax_plugin_comment extends DokuWiki_Syntax_Plugin { 12 13 protected static $comments = array(); 14 protected static $commentCounter = 0; 15 16 public function getType() { 17 return 'formatting'; 18 } 19 20 public function getPType() { 21 return 'normal'; 22 } 23 24 public function getSort() { 25 return 195; 26 } 27 28 public function connectTo($mode) { 29 // Syntax for comment - must capture multiple pipes 30 $this->Lexer->addSpecialPattern('\{\{comment>.+?\}\}', $mode, 'plugin_comment'); 31 // Syntax for list of all comments 32 $this->Lexer->addSpecialPattern('\{\{comments-list\}\}', $mode, 'plugin_comment'); 33 } 34 35 public function handle($match, $state, $pos, Doku_Handler $handler) { 36 // Detect syntax type 37 if ($match === '{{comments-list}}') { 38 return array('type' => 'list'); 39 } 40 41 // Process comment 42 $match = substr($match, 10, -2); // Remove {{comment> and }} 43 44 // Split into parts by | 45 $parts = explode('|', $match); 46 47 $text = isset($parts[0]) ? trim($parts[0]) : ''; 48 $comment = isset($parts[1]) ? trim($parts[1]) : ''; 49 $status = 'open'; 50 51 // Check status in third part 52 if (isset($parts[2])) { 53 $statusPart = trim($parts[2]); 54 if (preg_match('/^status=(open|resolved|closed)$/i', $statusPart, $matches)) { 55 $status = strtolower($matches[1]); 56 } 57 } 58 59 return array( 60 'type' => 'comment', 61 'text' => $text, 62 'comment' => $comment, 63 'status' => $status 64 ); 65 } 66 67 public function render($mode, Doku_Renderer $renderer, $data) { 68 if ($mode !== 'xhtml') return false; 69 70 // Render comments list 71 if ($data['type'] === 'list') { 72 $this->renderCommentsList($renderer); 73 return true; 74 } 75 76 // Render individual comment 77 self::$commentCounter++; 78 $commentNum = self::$commentCounter; 79 80 // Save comment for end-of-page list 81 self::$comments[] = array( 82 'num' => $commentNum, 83 'text' => $data['text'], 84 'comment' => $data['comment'], 85 'status' => $data['status'] 86 ); 87 88 // CSS classes by status 89 $statusClass = 'comment-' . $data['status']; 90 91 // Emoji for status 92 $statusEmoji = array( 93 'open' => '', 94 'resolved' => '✅', 95 'closed' => '❌' 96 ); 97 $emoji = isset($statusEmoji[$data['status']]) ? $statusEmoji[$data['status']] : ''; 98 99 // Render highlighted text with comment number 100 $renderer->doc .= '<span class="comment-highlight ' . $statusClass . '" data-comment="' . $commentNum . '" id="comment-ref-' . $commentNum . '">'; 101 $renderer->doc .= hsc($data['text']); 102 $renderer->doc .= '<sup class="comment-number"><a href="#comment-bubble-' . $commentNum . '" class="comment-link">[' . $commentNum . ']</a></sup>'; 103 $renderer->doc .= '</span>'; 104 105 // Side bubble with comment 106 $renderer->doc .= '<span class="comment-bubble ' . $statusClass . '" data-comment-id="' . $commentNum . '" id="comment-bubble-' . $commentNum . '">'; 107 $renderer->doc .= '<span class="comment-num"><a href="#comment-ref-' . $commentNum . '" class="comment-backlink">[' . $commentNum . ']</a></span> '; 108 $renderer->doc .= '<span class="comment-status">' . $emoji . '</span><br>'; 109 $renderer->doc .= hsc($data['comment']); 110 $renderer->doc .= '</span>'; 111 112 return true; 113 } 114 115 /** 116 * Render list of all comments on the page 117 */ 118 protected function renderCommentsList($renderer) { 119 if (empty(self::$comments)) { 120 $renderer->doc .= '<div class="comments-summary"><p><em>There are no comments on this page.</em></p></div>'; 121 return; 122 } 123 124 $renderer->doc .= '<div class="comments-summary">'; 125 $renderer->doc .= '<h3>Comments on this page</h3>'; 126 127 foreach (self::$comments as $comment) { 128 $statusClass = 'comment-' . $comment['status']; 129 $renderer->doc .= '<aside><div name="Comment" class="comment-item ' . $statusClass . '">'; 130 $renderer->doc .= '<div class="comment-header">'; 131 $renderer->doc .= '<span class="comment-num">[' . $comment['num'] . ']</span> '; 132 $renderer->doc .= '<span class="comment-status-badge ' . $statusClass . '">' . hsc($comment['status']) . '</span>'; 133 $renderer->doc .= '</div>'; 134 $renderer->doc .= '<div class="comment-text-ref"><strong>Text:</strong> ' . hsc($comment['text']) . '</div>'; 135 $renderer->doc .= '<div class="comment-content"><strong>Comment:</strong> ' . hsc($comment['comment']) . '</div>'; 136 $renderer->doc .= '</div></aside> '; 137 } 138 139 $renderer->doc .= '</div>'; 140 } 141}