1<?php 2 3namespace dokuwiki\Ui; 4 5use dokuwiki\ChangeLog\ChangeLog; 6 7/** 8 * DokuWiki Diff Interface 9 * parent class of PageDiff and MediaDiff 10 * 11 * @package dokuwiki\Ui 12 */ 13abstract class Diff extends Ui 14{ 15 /* @var string */ 16 protected $id; // page id or media id 17 protected $item; // page or media 18 19 /* @var int|string */ 20 protected $oldRev; // timestamp of older revision, '' means current one 21 protected $newRev; // timestamp of newer revision, '' means current one 22 23 /* @var array */ 24 protected $preference = []; 25 26 /* @var ChangeLog */ 27 protected $changelog; // PageChangeLog or MediaChangeLog object 28 29 /** 30 * Diff Ui constructor 31 * 32 * @param string $id page id or media id 33 */ 34 public function __construct($id) 35 { 36 $this->id = $id; 37 $this->setChangeLog(); 38 } 39 40 /** 41 * set class property changelog 42 */ 43 abstract protected function setChangeLog(); 44 45 /** 46 * item filename resolver 47 * 48 * @param string $id page id or media id 49 * @param int|string $rev revision timestamp, or empty string for current one 50 * @return string full path 51 */ 52 abstract protected function itemFN($id, $rev = ''); 53 54 /** 55 * Set a pair of revisions to be compared 56 * 57 * @param int $oldRev 58 * @param int $newRev 59 * @return $this 60 */ 61 public function compare($oldRev, $newRev) 62 { 63 $this->oldRev = $oldRev; 64 $this->newRev = $newRev; 65 return $this; 66 } 67 68 /** 69 * Gets or Sets preference of the Ui\Diff object 70 * 71 * @param string|array $prefs a key name or key-value pair(s) 72 * @param mixed $value value used when the first args is string 73 * @return array|$this 74 */ 75 public function preference($prefs = null, $value = null) 76 { 77 // set 78 if (is_string($prefs) && isset($value)) { 79 $this->preference[$prefs] = $value; 80 return $this; 81 } elseif (is_array($prefs)) { 82 foreach ($prefs as $name => $value) { 83 $this->preference[$name] = $value; 84 } 85 return $this; 86 } 87 // get 88 return $this->preference; 89 } 90 91 /** 92 * Retrieve requested revision(s) and difftype from Ui\Revisions 93 * 94 * @return void 95 */ 96 protected function preProcess() 97 { 98 global $INPUT; 99 100 // difflink icon click, eg. ?rev=123456789&do=diff 101 if ($INPUT->has('rev')) { 102 $this->oldRev = $INPUT->int('rev'); 103 $this->newRev = ''; // current revision 104 } 105 106 // submit button with two checked boxes 107 $rev2 = $INPUT->arr('rev2', []); 108 if (count($rev2) > 1) { 109 if ($rev2[0] == 'current') { 110 [$this->oldRev, $this->newRev] = [$rev2[1], '']; 111 } elseif ($rev2[1] == 'current') { 112 [$this->oldRev, $this->newRev] = [$rev2[0], '']; 113 } elseif ($rev2[0] < $rev2[1]) { 114 [$this->oldRev, $this->newRev] = [$rev2[0], $rev2[1]]; 115 } else { 116 [$this->oldRev, $this->newRev] = [$rev2[1], $rev2[0]]; 117 } 118 } 119 120 // diff view type 121 if ($INPUT->has('difftype')) { 122 // retrieve requested $difftype 123 $this->preference['difftype'] = $INPUT->str('difftype'); 124 } else { 125 // read preference from DokuWiki cookie. PageDiff only 126 $mode = get_doku_pref('difftype', $mode = null); 127 if (isset($mode)) $this->preference['difftype'] = $mode; 128 } 129 } 130 131 /** 132 * get extended revision info 133 * 134 * @param int|string $rev revision identifier, '' means current one, null means 135 * @return array revision info structure of a page or media file 136 */ 137 protected function getExtendedRevisionInfo($rev) 138 { 139 $changelog =& $this->changelog; 140 141 if ($rev) { 142 $info = $changelog->getRevisionInfo($rev); 143 //if external deletion, rev 9999999999 was used. 144 $info = is_array($info) ? $info : ($changelog->getExternalEditRevInfo() ?: []); 145 } elseif ($rev === null) { //if do=diff at just created page 146 $info = [ 147 'none' => true 148 ]; 149 } elseif (file_exists($filename = $this->itemFN($this->id))) { 150 $rev = filemtime(fullpath($filename)); 151 $info = $changelog->getRevisionInfo($rev); 152 // if external edit, file exist but has no changelog line 153 $info = is_array($info) ? $info : ($changelog->getExternalEditRevInfo() ?: []); 154 $info = $info + [ 155 'current' => true 156 ]; 157 } else { // once exists, but now removed 158 $lastRev = $changelog->getRevisions(-1, 1); // from changelog 159 $lastRev = (int) (empty($lastRev) ? 0 : $lastRev[0]); 160 $info = $changelog->getRevisionInfo($lastRev); 161 if (!(is_array($info) && $info['type'] == DOKU_CHANGE_TYPE_DELETE)) { 162 $info = $changelog->getExternalEditRevInfo(); 163 $info = is_array($info) && $info['type'] == DOKU_CHANGE_TYPE_DELETE ? $info : []; 164 } 165 $info = $info + [ 166 'current' => true 167 ]; 168 } 169 return ['item' => $this->item] + $info; 170 } 171 172 173 174 /** 175 * Build header of diff HTML 176 * 177 * @param string $l_rev Left revisions 178 * @param string $r_rev Right revision 179 * @return string[] HTML snippets for diff header 180 * @deprecated 2020-12-31 181 */ 182 public function buildDiffHead($l_rev, $r_rev) 183 { 184 dbg_deprecated('not used see '. \dokuwiki\Ui\PageDiff::class .'::show()'); 185 } 186 187} 188