1defc7576SSatoshi Sahara<?php 2defc7576SSatoshi Sahara 3defc7576SSatoshi Saharanamespace dokuwiki\Ui; 4defc7576SSatoshi Sahara 5defc7576SSatoshi Saharause dokuwiki\ChangeLog\PageChangeLog; 6defc7576SSatoshi Saharause dokuwiki\Form\Form; 7defc7576SSatoshi Sahara 8defc7576SSatoshi Sahara/** 9defc7576SSatoshi Sahara * DokuWiki PageDiff Interface 10defc7576SSatoshi Sahara * 11*179b4660SSatoshi Sahara * @author Andreas Gohr <andi@splitbrain.org> 12*179b4660SSatoshi Sahara * @author Satoshi Sahara <sahara.satoshi@gmail.com> 13defc7576SSatoshi Sahara * @package dokuwiki\Ui 14defc7576SSatoshi Sahara */ 1563ab9afeSSatoshi Saharaclass PageDiff extends Diff 16defc7576SSatoshi Sahara{ 17edb50e6aSSatoshi Sahara /* @var string */ 18*179b4660SSatoshi Sahara protected $text; 19defc7576SSatoshi Sahara 20defc7576SSatoshi Sahara /** 21defc7576SSatoshi Sahara * PageDiff Ui constructor 22defc7576SSatoshi Sahara * 23edb50e6aSSatoshi Sahara * @param string $id page id 24defc7576SSatoshi Sahara */ 25e4c881bdSSatoshi Sahara public function __construct($id = null) 26defc7576SSatoshi Sahara { 27defc7576SSatoshi Sahara global $INFO; 28edb50e6aSSatoshi Sahara $this->id = isset($id) ? $id : $INFO['id']; 29e71e09a6SSatoshi Sahara $this->item = 'page'; 30edb50e6aSSatoshi Sahara 31295564cdSSatoshi Sahara // init preference 32edb50e6aSSatoshi Sahara $this->preference['showIntro'] = true; 3391e70b5fSSatoshi Sahara $this->preference['difftype'] = 'sidebyside'; // diff view type: inline or sidebyside 348068440fSSatoshi Sahara 358068440fSSatoshi Sahara $this->setChangeLog(); 368068440fSSatoshi Sahara } 378068440fSSatoshi Sahara 388068440fSSatoshi Sahara /** @inheritdoc */ 398068440fSSatoshi Sahara protected function setChangeLog() 408068440fSSatoshi Sahara { 418068440fSSatoshi Sahara $this->changelog = new PageChangeLog($this->id); 42defc7576SSatoshi Sahara } 43defc7576SSatoshi Sahara 44e4c881bdSSatoshi Sahara /** 45e4c881bdSSatoshi Sahara * Set text to be compared with most current version 46e4c881bdSSatoshi Sahara * exclusively use of the compare($old, $new) method 47e4c881bdSSatoshi Sahara * 48e4c881bdSSatoshi Sahara * @param string $text 49e4c881bdSSatoshi Sahara * @return $this 50e4c881bdSSatoshi Sahara */ 51e4c881bdSSatoshi Sahara public function compareWith($text = null) 52e4c881bdSSatoshi Sahara { 53e4c881bdSSatoshi Sahara if (isset($text)) { 54e4c881bdSSatoshi Sahara $this->text = $text; 55e4c881bdSSatoshi Sahara $this->old_rev = ''; 56*179b4660SSatoshi Sahara $this->new_rev = null; 57e4c881bdSSatoshi Sahara } 58e4c881bdSSatoshi Sahara return $this; 59e4c881bdSSatoshi Sahara } 60e4c881bdSSatoshi Sahara 61b4b4c5c6SSatoshi Sahara /** @inheritdoc */ 62b4b4c5c6SSatoshi Sahara protected function preProcess() 63b4b4c5c6SSatoshi Sahara { 64b4b4c5c6SSatoshi Sahara parent::preProcess(); 65b4b4c5c6SSatoshi Sahara if (!isset($this->old_rev, $this->new_rev)) { 66b4b4c5c6SSatoshi Sahara // no revision was given, compare previous to current 6748d75c00SSatoshi Sahara $this->old_rev = $this->changelog->getRevisions(0, 1)[0]; 68b4b4c5c6SSatoshi Sahara $this->new_rev = ''; 69b4b4c5c6SSatoshi Sahara 7048d75c00SSatoshi Sahara global $INFO, $REV; 7148d75c00SSatoshi Sahara if ($this->id == $INFO['id']) 72b4b4c5c6SSatoshi Sahara $REV = $this->old_rev; // store revision back in $REV 73b4b4c5c6SSatoshi Sahara } 74b4b4c5c6SSatoshi Sahara } 75b4b4c5c6SSatoshi Sahara 76defc7576SSatoshi Sahara /** 77edb50e6aSSatoshi Sahara * Show diff 78edb50e6aSSatoshi Sahara * between current page version and provided $text 79edb50e6aSSatoshi Sahara * or between the revisions provided via GET or POST 80edb50e6aSSatoshi Sahara * 81edb50e6aSSatoshi Sahara * @author Andreas Gohr <andi@splitbrain.org> 82edb50e6aSSatoshi Sahara * 83edb50e6aSSatoshi Sahara * @return void 84defc7576SSatoshi Sahara */ 85309aaee5SSatoshi Sahara public function show() 86edb50e6aSSatoshi Sahara { 87*179b4660SSatoshi Sahara global $INFO, $lang; 8848d75c00SSatoshi Sahara 89675f74fbSSatoshi Sahara // determine left and right revision 90*179b4660SSatoshi Sahara if (!isset($this->old_rev)) $this->preProcess(); 91b4b4c5c6SSatoshi Sahara [$l_rev, $r_rev] = [$this->old_rev, $this->new_rev]; 92edb50e6aSSatoshi Sahara 9348d75c00SSatoshi Sahara // determine the last revision, which is usually the timestamp of current page, 9448d75c00SSatoshi Sahara // however which might be the last revision if the page had removed. 9548d75c00SSatoshi Sahara if ($this->id == $INFO['id']) { 9648d75c00SSatoshi Sahara $this->last_rev = $INFO['currentrev'] ?? $INFO['meta']['last_change']['date'] ?? 0; 9748d75c00SSatoshi Sahara } else { 98*179b4660SSatoshi Sahara $changelog =& $this->changelog; 99*179b4660SSatoshi Sahara $last_revs = $changelog->getRevisions(-1, 1) // empty array for removed page 100*179b4660SSatoshi Sahara ?: $changelog->getRevisions(0, 1); 101*179b4660SSatoshi Sahara $this->last_rev = count($last_revs) > 0 ? $last_revs[0] : 0; 10248d75c00SSatoshi Sahara } 10348d75c00SSatoshi Sahara 104309aaee5SSatoshi Sahara // create difference engine object 105*179b4660SSatoshi Sahara if (isset($this->text)) { // compare text to the most current revision 106*179b4660SSatoshi Sahara $oldText = rawWiki($this->id, ''); 107*179b4660SSatoshi Sahara $newText = cleanText($this->text); 108*179b4660SSatoshi Sahara } else { 109*179b4660SSatoshi Sahara // when both revisions are empty then the page was created just now 110*179b4660SSatoshi Sahara $oldText = (!$l_rev && !$r_rev) ? '' : rawWiki($this->id, $l_rev); 111*179b4660SSatoshi Sahara $newText = rawWiki($this->id, $r_rev); // empty when removed page 112*179b4660SSatoshi Sahara } 113*179b4660SSatoshi Sahara $Difference = new \Diff(explode("\n", $oldText), explode("\n", $newText)); 114*179b4660SSatoshi Sahara 115*179b4660SSatoshi Sahara // revison info of older page (left side) 116*179b4660SSatoshi Sahara $oldRevInfo = $this->getExtendedRevisionInfo($l_rev); 117*179b4660SSatoshi Sahara 118*179b4660SSatoshi Sahara // revison info of newer page (right side) 119*179b4660SSatoshi Sahara if (isset($this->text)) { 120*179b4660SSatoshi Sahara $newRevInfo = array('date' => null); 121*179b4660SSatoshi Sahara } else { 122*179b4660SSatoshi Sahara $newRevInfo = $this->getExtendedRevisionInfo($r_rev); 123*179b4660SSatoshi Sahara } 124*179b4660SSatoshi Sahara 125*179b4660SSatoshi Sahara // determin exact revision identifiers, even for current page 126*179b4660SSatoshi Sahara $oldRev = $oldRevInfo['date']; 127*179b4660SSatoshi Sahara $newRev = $newRevInfo['date']; 128*179b4660SSatoshi Sahara 129*179b4660SSatoshi Sahara // build paired navigation 130*179b4660SSatoshi Sahara $navOlderRevisions = ''; 131*179b4660SSatoshi Sahara $navNewerRevisions = ''; 132*179b4660SSatoshi Sahara if (!isset($this->text)) { 133*179b4660SSatoshi Sahara list( 134*179b4660SSatoshi Sahara $navOlderRevisions, 135*179b4660SSatoshi Sahara $navNewerRevisions, 136*179b4660SSatoshi Sahara ) = $this->buildRevisionsNavigation($oldRev, $newRev); 137*179b4660SSatoshi Sahara } 138defc7576SSatoshi Sahara 139675f74fbSSatoshi Sahara // display intro 140675f74fbSSatoshi Sahara if ($this->preference['showIntro']) echo p_locale_xhtml('diff'); 141defc7576SSatoshi Sahara 142675f74fbSSatoshi Sahara // print form to choose diff view type, and exact url reference to the view 143*179b4660SSatoshi Sahara if (!isset($this->text)) { 144*179b4660SSatoshi Sahara $this->showDiffViewSelector($oldRev, $newRev); 145defc7576SSatoshi Sahara } 146defc7576SSatoshi Sahara 147*179b4660SSatoshi Sahara // assign minor edit checker to the variable 148*179b4660SSatoshi Sahara $classEditType = function ($info) { 149*179b4660SSatoshi Sahara return ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? ' class="minor"' : ''; 150*179b4660SSatoshi Sahara }; 151*179b4660SSatoshi Sahara 152309aaee5SSatoshi Sahara // display diff view table 153295564cdSSatoshi Sahara echo '<div class="table">'; 154295564cdSSatoshi Sahara echo '<table class="diff diff_'.$this->preference['difftype'] .'">'; 155defc7576SSatoshi Sahara 156defc7576SSatoshi Sahara //navigation and header 157309aaee5SSatoshi Sahara switch ($this->preference['difftype']) { 158309aaee5SSatoshi Sahara case 'inline': 159*179b4660SSatoshi Sahara if (!isset($this->text)) { 160295564cdSSatoshi Sahara echo '<tr>' 161defc7576SSatoshi Sahara .'<td class="diff-lineheader">-</td>' 162*179b4660SSatoshi Sahara .'<td class="diffnav">'. $navOlderRevisions .'</td>' 163defc7576SSatoshi Sahara .'</tr>'; 164295564cdSSatoshi Sahara echo '<tr>' 165defc7576SSatoshi Sahara .'<th class="diff-lineheader">-</th>' 166*179b4660SSatoshi Sahara .'<th'.$classEditType($oldRevInfo).'>'.$this->revisionTitle($oldRevInfo).'</th>' 167defc7576SSatoshi Sahara .'</tr>'; 168defc7576SSatoshi Sahara } 169295564cdSSatoshi Sahara echo '<tr>' 170defc7576SSatoshi Sahara .'<td class="diff-lineheader">+</td>' 171*179b4660SSatoshi Sahara .'<td class="diffnav">'. $navNewerRevisions .'</td>' 172defc7576SSatoshi Sahara .'</tr>'; 173295564cdSSatoshi Sahara echo '<tr>' 174defc7576SSatoshi Sahara .'<th class="diff-lineheader">+</th>' 175*179b4660SSatoshi Sahara .'<th'.$classEditType($newRevInfo).'>'.$this->revisionTitle($newRevInfo).'</th>' 176defc7576SSatoshi Sahara .'</tr>'; 177309aaee5SSatoshi Sahara // create formatter object 178309aaee5SSatoshi Sahara $DiffFormatter = new \InlineDiffFormatter(); 179309aaee5SSatoshi Sahara break; 180309aaee5SSatoshi Sahara 181309aaee5SSatoshi Sahara case 'sidebyside': 182309aaee5SSatoshi Sahara default: 183*179b4660SSatoshi Sahara if (!isset($this->text)) { 184295564cdSSatoshi Sahara echo '<tr>' 185*179b4660SSatoshi Sahara .'<td colspan="2" class="diffnav">'. $navOlderRevisions .'</td>' 186*179b4660SSatoshi Sahara .'<td colspan="2" class="diffnav">'. $navNewerRevisions .'</td>' 187defc7576SSatoshi Sahara .'</tr>'; 188defc7576SSatoshi Sahara } 189295564cdSSatoshi Sahara echo '<tr>' 190*179b4660SSatoshi Sahara .'<th colspan="2"'.$classEditType($oldRevInfo).'>'.$this->revisionTitle($oldRevInfo).'</th>' 191*179b4660SSatoshi Sahara .'<th colspan="2"'.$classEditType($newRevInfo).'>'.$this->revisionTitle($newRevInfo).'</th>' 192defc7576SSatoshi Sahara .'</tr>'; 193309aaee5SSatoshi Sahara // create formatter object 194675f74fbSSatoshi Sahara $DiffFormatter = new \TableDiffFormatter(); 195309aaee5SSatoshi Sahara break; 196675f74fbSSatoshi Sahara } 197675f74fbSSatoshi Sahara 198309aaee5SSatoshi Sahara // output formatted difference 199295564cdSSatoshi Sahara echo $this->insertSoftbreaks($DiffFormatter->format($Difference)); 200defc7576SSatoshi Sahara 201295564cdSSatoshi Sahara echo '</table>'; 202295564cdSSatoshi Sahara echo '</div>'; 203defc7576SSatoshi Sahara } 204defc7576SSatoshi Sahara 205675f74fbSSatoshi Sahara /** 206*179b4660SSatoshi Sahara * Revision Title for PageDiff table headline 207*179b4660SSatoshi Sahara * 208*179b4660SSatoshi Sahara * @param array $info Revision info structure of a page 209*179b4660SSatoshi Sahara * @return string 21091e70b5fSSatoshi Sahara */ 211*179b4660SSatoshi Sahara protected function revisionTitle(array $info) 21291e70b5fSSatoshi Sahara { 213*179b4660SSatoshi Sahara global $lang, $INFO; 214*179b4660SSatoshi Sahara 215*179b4660SSatoshi Sahara // use designated title when compare current page source with given text 216*179b4660SSatoshi Sahara if (array_key_exists('date', $info) && is_null($info['date'])) { 217*179b4660SSatoshi Sahara return $lang['yours']; 218*179b4660SSatoshi Sahara } 219*179b4660SSatoshi Sahara 220*179b4660SSatoshi Sahara if (isset($info['date'])) { 221*179b4660SSatoshi Sahara $rev = $info['date']; 222*179b4660SSatoshi Sahara $title = '<bdi><a class="wikilink1" href="'.wl($this->id, ['rev' => $rev]).'">' 223*179b4660SSatoshi Sahara . $this->id.' ['.dformat($rev).']'.'</a></bdi>'; 224*179b4660SSatoshi Sahara } else { 225*179b4660SSatoshi Sahara $title = '—'; 226*179b4660SSatoshi Sahara } 227*179b4660SSatoshi Sahara if (isset($info['current']) || ($rev && $rev == $INFO['currentrev'])) { 228*179b4660SSatoshi Sahara $title .= ' ('.$lang['current'].')'; 229*179b4660SSatoshi Sahara } 230*179b4660SSatoshi Sahara 231*179b4660SSatoshi Sahara // append separator 232*179b4660SSatoshi Sahara $title .= ($this->preference['difftype'] === 'inline') ? ' ' : '<br />'; 233*179b4660SSatoshi Sahara 234*179b4660SSatoshi Sahara // supplement 235*179b4660SSatoshi Sahara if (isset($info['date'])) { 236*179b4660SSatoshi Sahara $objRevInfo = (new PageRevisions($this->id))->getObjRevInfo($info); 237*179b4660SSatoshi Sahara $title .= $objRevInfo->editSummary().' '.$objRevInfo->editor(); 238*179b4660SSatoshi Sahara } 239*179b4660SSatoshi Sahara return $title; 240*179b4660SSatoshi Sahara } 241*179b4660SSatoshi Sahara 242*179b4660SSatoshi Sahara /** 243*179b4660SSatoshi Sahara * Print form to choose diff view type, and exact url reference to the view 244*179b4660SSatoshi Sahara * 245*179b4660SSatoshi Sahara * @param int $oldRev timestamp of older revision, left side 246*179b4660SSatoshi Sahara * @param int $newRev timestamp of newer revision, right side 247*179b4660SSatoshi Sahara */ 248*179b4660SSatoshi Sahara protected function showDiffViewSelector($oldRev, $newRev) 249*179b4660SSatoshi Sahara { 250*179b4660SSatoshi Sahara global $lang; 25191e70b5fSSatoshi Sahara 25291e70b5fSSatoshi Sahara echo '<div class="diffoptions group">'; 25391e70b5fSSatoshi Sahara 25491e70b5fSSatoshi Sahara // create the form to select difftype 25591e70b5fSSatoshi Sahara $form = new Form(['action' => wl()]); 25691e70b5fSSatoshi Sahara $form->setHiddenField('id', $this->id); 25791e70b5fSSatoshi Sahara $form->setHiddenField('rev2[0]', $this->old_rev ?: 'current'); 25891e70b5fSSatoshi Sahara $form->setHiddenField('rev2[1]', $this->new_rev ?: 'current'); 25991e70b5fSSatoshi Sahara $form->setHiddenField('do', 'diff'); 26091e70b5fSSatoshi Sahara $options = array( 26191e70b5fSSatoshi Sahara 'sidebyside' => $lang['diff_side'], 262*179b4660SSatoshi Sahara 'inline' => $lang['diff_inline'], 26391e70b5fSSatoshi Sahara ); 26491e70b5fSSatoshi Sahara $input = $form->addDropdown('difftype', $options, $lang['diff_type']) 26591e70b5fSSatoshi Sahara ->val($this->preference['difftype']) 26691e70b5fSSatoshi Sahara ->addClass('quickselect'); 26791e70b5fSSatoshi Sahara $input->useInput(false); // inhibit prefillInput() during toHTML() process 26891e70b5fSSatoshi Sahara $form->addButton('do[diff]', 'Go')->attr('type','submit'); 26991e70b5fSSatoshi Sahara echo $form->toHTML(); 27091e70b5fSSatoshi Sahara 271*179b4660SSatoshi Sahara // show exact url reference to the view when it is meaningful 27291e70b5fSSatoshi Sahara echo '<p>'; 273*179b4660SSatoshi Sahara if (!isset($this->text) && $oldRev && $newRev) { 27491e70b5fSSatoshi Sahara // link to exactly this view FS#2835 275*179b4660SSatoshi Sahara $viewUrl = $this->diffViewlink('difflink', $oldRev, $newRev); 27648d75c00SSatoshi Sahara } 277*179b4660SSatoshi Sahara echo $viewUrl ?? '<br />'; 278*179b4660SSatoshi Sahara echo '</p>'; 27991e70b5fSSatoshi Sahara 28091e70b5fSSatoshi Sahara echo '</div>'; // .diffoptions 28191e70b5fSSatoshi Sahara } 28291e70b5fSSatoshi Sahara 28391e70b5fSSatoshi Sahara /** 284defc7576SSatoshi Sahara * Create html for revision navigation 285defc7576SSatoshi Sahara * 286*179b4660SSatoshi Sahara * @param int $oldRev timestamp of older revision, left side 287*179b4660SSatoshi Sahara * @param int $newRev timestamp of newer revision, right side 288defc7576SSatoshi Sahara * @return string[] html of left and right navigation elements 289defc7576SSatoshi Sahara */ 290*179b4660SSatoshi Sahara protected function buildRevisionsNavigation($oldRev, $newRev) 291defc7576SSatoshi Sahara { 292edb50e6aSSatoshi Sahara global $INFO; 293defc7576SSatoshi Sahara 294*179b4660SSatoshi Sahara $changelog =& $this->changelog; 295*179b4660SSatoshi Sahara 296*179b4660SSatoshi Sahara if (!$newRev) { 297*179b4660SSatoshi Sahara if ($this->id == $INFO['id']) { 298defc7576SSatoshi Sahara // note: when page is removed, the metadata timestamp is zero 299*179b4660SSatoshi Sahara $last_rev = $INFO['currentrev'] ?? $INFO['meta']['last_change']['date'] ?? 0; 300*179b4660SSatoshi Sahara } else { 301*179b4660SSatoshi Sahara $last_revs = $changelog->getRevisions(-1, 1) // empty array for removed page 302*179b4660SSatoshi Sahara ?: $changelog->getRevisions(0, 1); // last entry of changelog 303*179b4660SSatoshi Sahara $last_rev = count($last_revs) > 0 ? $last_revs[0] : 0; 304*179b4660SSatoshi Sahara } 305*179b4660SSatoshi Sahara $newRev = $last_rev; 306defc7576SSatoshi Sahara } 307defc7576SSatoshi Sahara 308defc7576SSatoshi Sahara // retrieve revisions with additional info 309*179b4660SSatoshi Sahara list($oldRevs, $newRevs) = $changelog->getRevisionsAround($oldRev, $newRev); 310295564cdSSatoshi Sahara 311*179b4660SSatoshi Sahara // build options for dropdown selector 312*179b4660SSatoshi Sahara $olderRevisions = $this->buildRevsionOptions('older', $oldRevs, $oldRev, $newRev); 313*179b4660SSatoshi Sahara $newerRevisions = $this->buildRevsionOptions('newer', $newRevs, $oldRev, $newRev); 314defc7576SSatoshi Sahara 315defc7576SSatoshi Sahara //determine previous/next revisions 316*179b4660SSatoshi Sahara $index = array_search($oldRev, $oldRevs); 317*179b4660SSatoshi Sahara $oldPrevRev = $oldRevs[$index + 1]; 318*179b4660SSatoshi Sahara $oldNextRev = $oldRevs[$index - 1]; 319*179b4660SSatoshi Sahara if ($newRev) { 320*179b4660SSatoshi Sahara $index = array_search($newRev, $newRevs); 321*179b4660SSatoshi Sahara $newPrevRev = $newRevs[$index + 1]; 322*179b4660SSatoshi Sahara $newNextRev = $newRevs[$index - 1]; 323defc7576SSatoshi Sahara } else { 324defc7576SSatoshi Sahara //removed page 325*179b4660SSatoshi Sahara $newPrevRev = ($oldNextRev) ? $newRevs[0] : null; 326*179b4660SSatoshi Sahara $newNextRev = null; 327defc7576SSatoshi Sahara } 328defc7576SSatoshi Sahara 329defc7576SSatoshi Sahara /* 330*179b4660SSatoshi Sahara * navigation UI for older revisions / Left side: 331defc7576SSatoshi Sahara */ 332*179b4660SSatoshi Sahara $navOlderRevs = ''; 333defc7576SSatoshi Sahara //move back 334*179b4660SSatoshi Sahara if ($oldPrevRev) { 335*179b4660SSatoshi Sahara $navOlderRevs .= $this->diffViewlink('diffbothprevrev', $oldPrevRev, $newPrevRev); 336*179b4660SSatoshi Sahara $navOlderRevs .= $this->diffViewlink('diffprevrev', $oldPrevRev, $newRev); 337defc7576SSatoshi Sahara } 338defc7576SSatoshi Sahara //dropdown 339*179b4660SSatoshi Sahara $navOlderRevs .= $this->buildDropdwonSelector('older', $olderRevisions, $oldRev, $newRev); 340defc7576SSatoshi Sahara //move forward 341*179b4660SSatoshi Sahara if ($oldNextRev && ($oldNextRev < $newRev || !$newRev)) { 342*179b4660SSatoshi Sahara $navOlderRevs .= $this->diffViewlink('diffnextrev', $oldNextRev, $newRev); 343defc7576SSatoshi Sahara } 344defc7576SSatoshi Sahara 345defc7576SSatoshi Sahara /* 346*179b4660SSatoshi Sahara * navigation UI for newer revisions / Right side: 347defc7576SSatoshi Sahara */ 348*179b4660SSatoshi Sahara $navNewerRevs = ''; 349defc7576SSatoshi Sahara //move back 350*179b4660SSatoshi Sahara if ($oldRev < $newPrevRev) { 351*179b4660SSatoshi Sahara $navNewerRevs .= $this->diffViewlink('diffprevrev', $oldRev, $newPrevRev); 352defc7576SSatoshi Sahara } 353defc7576SSatoshi Sahara //dropdown 354*179b4660SSatoshi Sahara $navNewerRevs .= $this->buildDropdwonSelector('newer', $newerRevisions, $oldRev, $newRev); 355defc7576SSatoshi Sahara //move forward 356*179b4660SSatoshi Sahara if ($newNextRev) { 357*179b4660SSatoshi Sahara if ($changelog->isCurrentRevision($newNextRev)) { 358defc7576SSatoshi Sahara //last revision is diff with current page 359*179b4660SSatoshi Sahara $navNewerRevs .= $this->diffViewlink('difflastrev', $oldRev); 360defc7576SSatoshi Sahara } else { 361*179b4660SSatoshi Sahara $navNewerRevs .= $this->diffViewlink('diffnextrev', $oldRev, $newNextRev); 362defc7576SSatoshi Sahara } 363*179b4660SSatoshi Sahara $navNewerRevs .= $this->diffViewlink('diffbothnextrev', $oldNextRev, $newNextRev); 364defc7576SSatoshi Sahara } 365*179b4660SSatoshi Sahara return array($navOlderRevs, $navNewerRevs); 366*179b4660SSatoshi Sahara } 367*179b4660SSatoshi Sahara 368*179b4660SSatoshi Sahara /** 369*179b4660SSatoshi Sahara * prepare options for dropdwon selector 370*179b4660SSatoshi Sahara * 371*179b4660SSatoshi Sahara * @params string $side "older" or "newer" 372*179b4660SSatoshi Sahara * @params array $revs list of revsion 373*179b4660SSatoshi Sahara * @param int $oldRev timestamp of older revision, left side 374*179b4660SSatoshi Sahara * @param int $newRev timestamp of newer revision, right side 375*179b4660SSatoshi Sahara * @return array 376*179b4660SSatoshi Sahara */ 377*179b4660SSatoshi Sahara protected function buildRevsionOptions($side, $revs, $oldRev, $newRev) 378*179b4660SSatoshi Sahara { 379*179b4660SSatoshi Sahara $changelog =& $this->changelog; 380*179b4660SSatoshi Sahara $revisions = array(); 381*179b4660SSatoshi Sahara 382*179b4660SSatoshi Sahara if (($side == 'older' && !$oldRev) // NOTE: this case should not happen! 383*179b4660SSatoshi Sahara ||($side == 'newer' && (!$newRev || page_exists($this->id) == false)) 384*179b4660SSatoshi Sahara ) { 385*179b4660SSatoshi Sahara //no revision given, likely removed page, add dummy entry 386*179b4660SSatoshi Sahara $revisions['current'] = array( 387*179b4660SSatoshi Sahara 'label' => '—', // U+2014 — 388*179b4660SSatoshi Sahara 'attrs' => [], 389*179b4660SSatoshi Sahara ); 390*179b4660SSatoshi Sahara } 391*179b4660SSatoshi Sahara 392*179b4660SSatoshi Sahara foreach ($revs as $rev) { 393*179b4660SSatoshi Sahara $info = $changelog->getRevisionInfo($rev); 394*179b4660SSatoshi Sahara $revisions[$rev] = array( 395*179b4660SSatoshi Sahara 'label' => implode(' ', [ 396*179b4660SSatoshi Sahara dformat($info['date']), 397*179b4660SSatoshi Sahara editorinfo($info['user'], true), 398*179b4660SSatoshi Sahara $info['sum'], 399*179b4660SSatoshi Sahara ]), 400*179b4660SSatoshi Sahara 'attrs' => ['title' => $rev], 401*179b4660SSatoshi Sahara ); 402*179b4660SSatoshi Sahara if (($side == 'older' && ($newRev ? $rev >= $newRev : false)) 403*179b4660SSatoshi Sahara ||($side == 'newer' && ($rev <= $oldRev)) 404*179b4660SSatoshi Sahara ) { 405*179b4660SSatoshi Sahara $revisions[$rev]['attrs']['disabled'] = 'disabled'; 406*179b4660SSatoshi Sahara } 407*179b4660SSatoshi Sahara } 408*179b4660SSatoshi Sahara return $revisions; 409*179b4660SSatoshi Sahara } 410*179b4660SSatoshi Sahara 411*179b4660SSatoshi Sahara /** 412*179b4660SSatoshi Sahara * build Dropdown form for revisions navigation 413*179b4660SSatoshi Sahara * 414*179b4660SSatoshi Sahara * @params string $side "older" or "newer" 415*179b4660SSatoshi Sahara * @params array $options dropdown options 416*179b4660SSatoshi Sahara * @param int $oldRev timestamp of older revision, left side 417*179b4660SSatoshi Sahara * @param int $newRev timestamp of newer revision, right side 418*179b4660SSatoshi Sahara * @return sting 419*179b4660SSatoshi Sahara */ 420*179b4660SSatoshi Sahara protected function buildDropdwonSelector($side, $options, $oldRev, $newRev) 421*179b4660SSatoshi Sahara { 422*179b4660SSatoshi Sahara $form = new Form(['action' => wl($this->id)]); 423*179b4660SSatoshi Sahara $form->setHiddenField('id', $this->id); 424*179b4660SSatoshi Sahara $form->setHiddenField('do', 'diff'); 425*179b4660SSatoshi Sahara $form->setHiddenField('difftype', $this->preference['difftype']); 426*179b4660SSatoshi Sahara 427*179b4660SSatoshi Sahara switch ($side) { 428*179b4660SSatoshi Sahara case 'older': // left side 429*179b4660SSatoshi Sahara $form->setHiddenField('rev2[1]', $newRev ?: 'current'); 430*179b4660SSatoshi Sahara $input = $form->addDropdown('rev2[0]', $options) 431*179b4660SSatoshi Sahara ->val($oldRev ?: 'current')->addClass('quickselect'); 432*179b4660SSatoshi Sahara $input->useInput(false); // inhibit prefillInput() during toHTML() process 433*179b4660SSatoshi Sahara break; 434*179b4660SSatoshi Sahara case 'newer': // right side 435*179b4660SSatoshi Sahara $form->setHiddenField('rev2[0]', $oldRev ?: 'current'); 436*179b4660SSatoshi Sahara $input = $form->addDropdown('rev2[1]', $options) 437*179b4660SSatoshi Sahara ->val($newRev ?: 'current')->addClass('quickselect'); 438*179b4660SSatoshi Sahara $input->useInput(false); // inhibit prefillInput() during toHTML() process 439*179b4660SSatoshi Sahara break; 440*179b4660SSatoshi Sahara } 441*179b4660SSatoshi Sahara $form->addButton('do[diff]', 'Go')->attr('type','submit'); 442*179b4660SSatoshi Sahara return $form->toHTML(); 443defc7576SSatoshi Sahara } 444defc7576SSatoshi Sahara 445defc7576SSatoshi Sahara /** 446defc7576SSatoshi Sahara * Create html link to a diff view defined by two revisions 447defc7576SSatoshi Sahara * 448defc7576SSatoshi Sahara * @param string $linktype 449*179b4660SSatoshi Sahara * @param int $oldRev older revision 450*179b4660SSatoshi Sahara * @param int $newRev newer revision or null for diff with current revision 451defc7576SSatoshi Sahara * @return string html of link to a diff view 452defc7576SSatoshi Sahara */ 453*179b4660SSatoshi Sahara protected function diffViewlink($linktype, $oldRev, $newRev = null) 454defc7576SSatoshi Sahara { 455edb50e6aSSatoshi Sahara global $lang; 456*179b4660SSatoshi Sahara if ($newRev === null) { 457defc7576SSatoshi Sahara $urlparam = array( 458defc7576SSatoshi Sahara 'do' => 'diff', 459*179b4660SSatoshi Sahara 'rev' => $oldRev, 460edb50e6aSSatoshi Sahara 'difftype' => $this->preference['difftype'], 461defc7576SSatoshi Sahara ); 462defc7576SSatoshi Sahara } else { 463defc7576SSatoshi Sahara $urlparam = array( 464defc7576SSatoshi Sahara 'do' => 'diff', 465*179b4660SSatoshi Sahara 'rev2[0]' => $oldRev, 466*179b4660SSatoshi Sahara 'rev2[1]' => $newRev, 467edb50e6aSSatoshi Sahara 'difftype' => $this->preference['difftype'], 468defc7576SSatoshi Sahara ); 469defc7576SSatoshi Sahara } 470295564cdSSatoshi Sahara $attr = array( 471295564cdSSatoshi Sahara 'class' => $linktype, 47248d75c00SSatoshi Sahara 'href' => wl($this->id, $urlparam, true, '&'), 473295564cdSSatoshi Sahara 'title' => $lang[$linktype], 474295564cdSSatoshi Sahara ); 475295564cdSSatoshi Sahara return '<a '. buildAttributes($attr) .'><span>'. $lang[$linktype] .'</span></a>'; 476defc7576SSatoshi Sahara } 477defc7576SSatoshi Sahara 478defc7576SSatoshi Sahara 479defc7576SSatoshi Sahara /** 480defc7576SSatoshi Sahara * Insert soft breaks in diff html 481defc7576SSatoshi Sahara * 482defc7576SSatoshi Sahara * @param string $diffhtml 483defc7576SSatoshi Sahara * @return string 484defc7576SSatoshi Sahara */ 485defc7576SSatoshi Sahara public function insertSoftbreaks($diffhtml) 486defc7576SSatoshi Sahara { 487defc7576SSatoshi Sahara // search the diff html string for both: 488defc7576SSatoshi Sahara // - html tags, so these can be ignored 489defc7576SSatoshi Sahara // - long strings of characters without breaking characters 490defc7576SSatoshi Sahara return preg_replace_callback('/<[^>]*>|[^<> ]{12,}/', function ($match) { 491defc7576SSatoshi Sahara // if match is an html tag, return it intact 492defc7576SSatoshi Sahara if ($match[0][0] == '<') return $match[0]; 493defc7576SSatoshi Sahara // its a long string without a breaking character, 494defc7576SSatoshi Sahara // make certain characters into breaking characters by inserting a 495defc7576SSatoshi Sahara // word break opportunity (<wbr> tag) in front of them. 496defc7576SSatoshi Sahara $regex = <<< REGEX 497defc7576SSatoshi Sahara(?(?= # start a conditional expression with a positive look ahead ... 498defc7576SSatoshi Sahara&\#?\\w{1,6};) # ... for html entities - we don't want to split them (ok to catch some invalid combinations) 499defc7576SSatoshi Sahara&\#?\\w{1,6}; # yes pattern - a quicker match for the html entity, since we know we have one 500defc7576SSatoshi Sahara| 501defc7576SSatoshi Sahara[?/,&\#;:] # no pattern - any other group of 'special' characters to insert a breaking character after 502defc7576SSatoshi Sahara)+ # end conditional expression 503defc7576SSatoshi SaharaREGEX; 504defc7576SSatoshi Sahara return preg_replace('<'.$regex.'>xu', '\0<wbr>', $match[0]); 505defc7576SSatoshi Sahara }, $diffhtml); 506defc7576SSatoshi Sahara } 507defc7576SSatoshi Sahara 508defc7576SSatoshi Sahara} 509