1<?php 2 3namespace dokuwiki\Ui; 4 5use dokuwiki\ChangeLog\PageChangeLog; 6use dokuwiki\ChangeLog\MediaChangeLog; 7 8/** 9 * DokuWiki Diff Interface 10 * parent class of PageDiff and MediaDiff 11 * 12 * @package dokuwiki\Ui 13 */ 14abstract class Diff extends Ui 15{ 16 /* @var string */ 17 protected $id; // page id or media id 18 19 /* @var int */ 20 protected $old_rev; // older revision, timestamp of left side 21 protected $new_rev; // newer revision, timestamp of right side 22 protected $last_rev; // current revision, or last revision when it had removed 23 24 /* @var array */ 25 protected $preference = []; 26 27 /* @var ChangeLog */ 28 protected $changelog; // PageChangeLog or MediaChangeLog object 29 30 /** 31 * Diff Ui constructor 32 * 33 * @param string $id page id or media id 34 */ 35 public function __construct($id) 36 { 37 $this->id = $id; 38 $this->setChangeLog(); 39 } 40 41 /** 42 * set class property changelog 43 */ 44 abstract protected function setChangeLog(); 45 46 /** 47 * Set a pair of revisions to be compared 48 * 49 * @param int $old_rev 50 * @param int $new_rev 51 * @return $this 52 */ 53 public function compare($old_rev, $new_rev) 54 { 55 $this->old_rev = $old_rev; 56 $this->new_rev = $new_rev; 57 return $this; 58 } 59 60 /** 61 * Gets or Sets preference of the Ui\Diff object 62 * 63 * @param string|array $prefs a key name or key-value pair(s) 64 * @param mixed $value value used when the first args is string 65 * @return array|$this 66 */ 67 public function preference($prefs = null, $value = null) 68 { 69 // set 70 if (is_string($prefs) && isset($value)) { 71 $this->preference[$prefs] = $value; 72 return $this; 73 } elseif (is_array($prefs)) { 74 foreach ($prefs as $name => $value) { 75 $this->preference[$name] = $value; 76 } 77 return $this; 78 } 79 // get 80 return $this->preference; 81 } 82 83 /** 84 * Retrieve requested revision(s) and difftype from Ui\Revisions 85 * 86 * @return void 87 */ 88 protected function preProcess() 89 { 90 global $INPUT; 91 92 // difflink icon click, eg. ?rev=123456789&do=diff 93 if ($INPUT->has('rev')) { 94 $this->old_rev = $INPUT->int('rev'); 95 $this->new_rev = ''; // current revision 96 } 97 98 // submit button with two checked boxes 99 $rev2 = $INPUT->arr('rev2', []); 100 if (count($rev2) > 1) { 101 if ($rev2[0] == 'current') { 102 [$this->old_rev, $this->new_rev] = [$rev2[1], '']; 103 } elseif ($rev2[1] == 'current') { 104 [$this->old_rev, $this->new_rev] = [$rev2[0], '']; 105 } elseif ($rev2[0] < $rev2[1]) { 106 [$this->old_rev, $this->new_rev] = [$rev2[0], $rev2[1]]; 107 } else { 108 [$this->old_rev, $this->new_rev] = [$rev2[1], $rev2[0]]; 109 } 110 } 111 112 // diff view type 113 if ($INPUT->has('difftype')) { 114 // retrieve requested $difftype 115 $this->preference['difftype'] = $INPUT->str('difftype'); 116 } else { 117 // read preference from DokuWiki cookie. PageDiff only 118 get_doku_pref('difftype', $mode); 119 if (isset($mode)) $this->preference['difftype'] = $mode; 120 } 121 } 122 123 124 125 /** 126 * Build header of diff HTML 127 * 128 * @param string $l_rev Left revisions 129 * @param string $r_rev Right revision 130 * @return string[] HTML snippets for diff header 131 */ 132 public function buildDiffHead($l_rev, $r_rev) 133 { 134 global $lang; 135 136 // detect PageDiff or MediaDiff 137 switch (get_class($this->changelog)) { 138 case PageChangeLog::class : 139 $isMedia = false; 140 $ui = new PageRevisions($this->id); 141 break; 142 case MediaChangeLog::class : 143 $isMedia = true; 144 $ui = new MediaRevisions($this->id); 145 break; 146 } 147 148 $head_separator = ($this->preference['difftype'] === 'inline') ? ' ' : '<br />'; 149 150 // assign minor edit checker to the variable 151 $minor = function ($info) { 152 return ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? 'class="minor"' : ''; 153 }; 154 155 // assign link builder to the variable 156 $idToUrl = function ($id, $rev = '') use ($isMedia) { 157 return ($isMedia) ? ml($id, $rev) : wl($id, $rev); 158 }; 159 160 // assign title builder to the variable 161 $idToTitle = function ($id, $rev = '') use ($isMedia) { 162 return ($isMedia) ? dformat($rev) : $id.' ['.dformat($rev).']'; 163 }; 164 165 // left side 166 if (!$l_rev) { 167 $l_minor = ''; 168 $l_head = '—'; 169 } else { 170 $info = $this->changelog->getRevisionInfo($l_rev); 171 $objRevInfo = $ui->getObjRevInfo($info); 172 $l_minor = $minor($info); 173 $l_head = '<bdi><a class="wikilink1" href="'.$idToUrl($this->id, "rev=$l_rev").'">' 174 .$idToTitle($this->id, $l_rev).'</a></bdi>'.$head_separator 175 .$objRevInfo->editor().' '.$objRevInfo->editSummary(); 176 177 } 178 179 // right side 180 if ($r_rev) { 181 $info = $this->changelog->getRevisionInfo($r_rev); 182 $objRevInfo = $ui->getObjRevInfo($info); 183 $r_minor = $minor($info); 184 $r_head = '<bdi><a class="wikilink1" href="'.$idToUrl($this->id, "rev=$r_rev").'">' 185 .$idToTitle($this->id, $r_rev).'</a></bdi>'.$head_separator 186 .$objRevInfo->editor().' '.$objRevInfo->editSummary(); 187 } elseif ($this->last_rev) { 188 $_rev = $this->last_rev; 189 $info = $this->changelog->getRevisionInfo($_rev); 190 $objRevInfo = $ui->getObjRevInfo($info); 191 $r_minor = $minor($info); 192 $r_head = '<bdi><a class="wikilink1" href="'.$idToUrl($this->id).'">' 193 .$idToTitle($this->id, $_rev).'</a></bdi> '.'('.$lang['current'].')'.$head_separator 194 .$objRevInfo->editor().' '.$objRevInfo->editSummary(); 195 } else { 196 $r_minor = ''; 197 $r_head = '— ('.$lang['current'].')'; 198 } 199 200 return array($l_head, $r_head, $l_minor, $r_minor); 201 } 202 203} 204