1<?php 2 3namespace dokuwiki\Ui; 4 5/** 6 * DokuWiki Revisions Interface 7 * parent class of PageRevisions and MediaRevisions 8 * 9 * @package dokuwiki\Ui 10 */ 11abstract class Revisions extends Ui 12{ 13 /* @var string */ 14 protected $id; // page id or media id 15 protected $item; // page or media 16 17 /* @var ChangeLog */ 18 protected $changelog; // PageChangeLog or MediaChangeLog object 19 20 /** 21 * Revisions Ui constructor 22 * 23 * @param string $id page id or media id 24 */ 25 public function __construct($id) 26 { 27 $this->id = $id; 28 $this->setChangeLog(); 29 } 30 31 /** 32 * set class property changelog 33 */ 34 abstract protected function setChangeLog(); 35 36 /** 37 * item source file resolver 38 * 39 * @param string $id page id or media id 40 * @return string full path 41 */ 42 protected function itemFN($id) // FIXME declare as abstract method 43 { 44 switch ($this->item) { 45 case 'page': return wikiFN($id); 46 case 'media': return mediaFN($id); 47 } 48 } 49 50 /** 51 * Get revisions, and set correct pagenation parameters (first, hasNext) 52 * 53 * @param int $first 54 * @param bool $hasNext 55 * @return array revisions to be shown in a pagenated list 56 * @see also https://www.dokuwiki.org/devel:changelog 57 */ 58 protected function getRevisions(&$first, &$hasNext) 59 { 60 global $conf; 61 62 $changelog =& $this->changelog; 63 64 $revisions = array(); 65 66 /* we need to get one additional log entry to be able to 67 * decide if this is the last page or is there another one. 68 * see also Ui\Recent::getRecents() 69 */ 70 $revlist = $changelog->getRevisions($first, $conf['recent'] +1); 71 if (count($revlist) == 0 && $first != 0) { 72 $first = 0; 73 $revlist = $changelog->getRevisions($first, $conf['recent'] +1); 74 } 75 76 // add current page or media as revision[0] when necessary 77 if ($first === 0 && file_exists($this->itemFN($this->id))) { 78 $rev = filemtime(fullpath($this->itemFN($this->id))); 79 $changelog->setChunkSize(1024); //FIXME why does chunksize change wanted? 80 $revinfo = $changelog->getRevisionInfo($rev) ?: array( 81 'date' => $rev, 82 'ip' => null, 83 'type' => null, 84 'id' => $this->id, 85 'user' => null, 86 'sum' => null, 87 'extra' => null, 88 'sizechange' => null, 89 ); 90 $revisions[] = $revinfo + array( 91 'item' => $this->item, 92 'current' => true, 93 ); 94 } 95 96 // decide if this is the last page or is there another one 97 $hasNext = false; 98 if (count($revlist) > $conf['recent']) { 99 $hasNext = true; 100 array_pop($revlist); // remove one additional log entry 101 } 102 103 // append each revison info array to the revisions 104 foreach ($revlist as $rev) { 105 $revisions[] = $changelog->getRevisionInfo($rev) + array('item' => $this->item); 106 } 107 return $revisions; 108 } 109 110 /** 111 * Navigation buttons for Pagenation (prev/next) 112 * 113 * @param int $first 114 * @param bool $hasNext 115 * @param callable $callback returns array of hidden fields for the form button 116 * @return array html 117 */ 118 protected function navigation($first, $hasNext, $callback) 119 { 120 global $conf; 121 122 $html = '<div class="pagenav">'; 123 $last = $first + $conf['recent']; 124 if ($first > 0) { 125 $first = max($first - $conf['recent'], 0); 126 $html.= '<div class="pagenav-prev">'; 127 $html.= html_btn('newer', $this->id, "p", $callback($first)); 128 $html.= '</div>'; 129 } 130 if ($hasNext) { 131 $html.= '<div class="pagenav-next">'; 132 $html.= html_btn('older', $this->id, "n", $callback($last)); 133 $html.= '</div>'; 134 } 135 $html.= '</div>'; 136 return $html; 137 } 138 139 /** 140 * Returns instance of objRevInfo 141 * 142 * @param array $info Revision info structure of a page or media file 143 * @return objRevInfo object (anonymous class) 144 */ 145 public function getObjRevInfo(array $info) 146 { 147 return new class ($info) // anonymous class (objRevInfo) 148 { 149 protected $info; 150 151 public function __construct(array $info) 152 { 153 $this->info = $info; 154 } 155 156 // current indicator 157 public function currentIndicator() 158 { 159 global $lang; 160 return ($this->info['current']) ? '('.$lang['current'].')' : ''; 161 } 162 163 // edit date and time of the page or media file 164 public function editDate() 165 { 166 return '<span class="date">'. dformat($this->info['date']) .'</span>'; 167 } 168 169 // edit summary 170 public function editSummary() 171 { 172 return '<span class="sum">'.' – '. hsc($this->info['sum']).'</span>'; 173 } 174 175 // editor of the page or media file 176 public function editor() 177 { 178 // slightly different with display of Ui\Recent, i.e. external edit 179 global $lang; 180 $html = '<span class="user">'; 181 if (!$this->info['user'] && !$this->info['ip']) { 182 $html.= '('.$lang['external_edit'].')'; 183 } elseif ($this->info['user']) { 184 $html.= '<bdi>'. editorinfo($this->info['user']) .'</bdi>'; 185 if (auth_ismanager()) $html.= ' <bdo dir="ltr">('. $this->info['ip'] .')</bdo>'; 186 } else { 187 $html.= '<bdo dir="ltr">'. $this->info['ip'] .'</bdo>'; 188 } 189 $html.= '</span>'; 190 return $html; 191 } 192 193 // name of the page or media file 194 public function itemName() 195 { 196 // slightly different with display of Ui\Recent, i.e. revison may not exists 197 $id = $this->info['id']; 198 $rev = $this->info['date']; 199 200 switch ($this->info['item']) { 201 case 'media': // media file revision 202 if (isset($this->info['current'])) { 203 $href = media_managerURL(['image'=> $id, 'tab_details'=> 'view'], '&'); 204 $html = '<a href="'.$href.'" class="wikilink1">'.$id.'</a>'; 205 } elseif (file_exists(mediaFN($id, $rev))) { 206 $href = media_managerURL(['image'=> $id, 'tab_details'=> 'view', 'rev'=> $rev], '&'); 207 $html = '<a href="'.$href.'" class="wikilink1">'.$id.'</a>'; 208 } else { 209 $html = $id; 210 } 211 return $html; 212 case 'page': // page revision 213 $display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id; 214 if (!$display_name) $display_name = $id; 215 if ($this->info['current'] || page_exists($id, $rev)) { 216 $href = wl($id, "rev=$rev", false, '&'); 217 $html = '<a href="'.$href.'" class="wikilink1">'.$display_name.'</a>'; 218 } else { 219 $html = $display_name; 220 } 221 return $html; 222 } 223 return ''; 224 } 225 226 // icon difflink 227 public function difflink() 228 { 229 global $lang; 230 $id = $this->info['id']; 231 $rev = $this->info['date']; 232 233 switch ($this->info['item']) { 234 case 'media': // media file revision 235 if (isset($this->info['current']) || !file_exists(mediaFN($id, $rev))) { 236 $html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />'; 237 } else { 238 $href = media_managerURL(['image'=> $id, 'rev'=> $rev, 'mediado'=>'diff'], '&'); 239 $html = '<a href="'.$href.'" class="diff_link">' 240 . '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"' 241 . ' title="'. $lang['diff'] .'" alt="'.$lang['diff'] .'" />' 242 . '</a> '; 243 } 244 return $html; 245 case 'page': // page revision 246 if ($this->info['current'] || !page_exists($id, $rev)) { 247 $html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />'; 248 } else { 249 $href = wl($id, "rev=$rev,do=diff", false, '&'); 250 $html = '<a href="'.$href.'" class="diff_link">' 251 . '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"' 252 . ' title="'.$lang['diff'].'" alt="'.$lang['diff'].'" />' 253 . '</a>'; 254 } 255 return $html; 256 } 257 return ''; 258 } 259 260 // size change 261 public function sizeChange() 262 { 263 $class = 'sizechange'; 264 $value = filesize_h(abs($this->info['sizechange'])); 265 if ($this->info['sizechange'] > 0) { 266 $class .= ' positive'; 267 $value = '+' . $value; 268 } elseif ($this->info['sizechange'] < 0) { 269 $class .= ' negative'; 270 $value = '-' . $value; 271 } else { 272 $value = '±' . $value; 273 } 274 return '<span class="'.$class.'">'.$value.'</span>'; 275 } 276 }; // end of anonymous class (objRevInfo) 277 } 278 279} 280