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