diff options
Diffstat (limited to 'inc')
-rw-r--r-- | inc/Action/Diff.php | 3 | ||||
-rw-r--r-- | inc/Action/Revisions.php | 4 | ||||
-rw-r--r-- | inc/Ajax.php | 5 | ||||
-rw-r--r-- | inc/Ui/Diff.php | 546 | ||||
-rw-r--r-- | inc/Ui/MediaDiff.php | 339 | ||||
-rw-r--r-- | inc/Ui/MediaRevisions.php | 122 | ||||
-rw-r--r-- | inc/Ui/PageConflict.php | 7 | ||||
-rw-r--r-- | inc/Ui/PageDiff.php | 512 | ||||
-rw-r--r-- | inc/Ui/PageDraft.php | 8 | ||||
-rw-r--r-- | inc/Ui/PageRevisions.php | 181 | ||||
-rw-r--r-- | inc/Ui/Revisions.php | 368 | ||||
-rw-r--r-- | inc/html.php | 35 | ||||
-rw-r--r-- | inc/lang/ja/lang.php | 2 | ||||
-rw-r--r-- | inc/media.php | 252 |
14 files changed, 1421 insertions, 963 deletions
diff --git a/inc/Action/Diff.php b/inc/Action/Diff.php index 1409b246b..31024b6cd 100644 --- a/inc/Action/Diff.php +++ b/inc/Action/Diff.php @@ -34,7 +34,8 @@ class Diff extends AbstractAction /** @inheritdoc */ public function tplContent() { - (new Ui\Diff())->show(); + global $INFO; + (new Ui\PageDiff($INFO['id']))->preference('showIntro', true)->show(); } } diff --git a/inc/Action/Revisions.php b/inc/Action/Revisions.php index 27b20ec29..4b2f82275 100644 --- a/inc/Action/Revisions.php +++ b/inc/Action/Revisions.php @@ -22,7 +22,7 @@ class Revisions extends AbstractAction /** @inheritdoc */ public function tplContent() { - global $INPUT; - (new Ui\Revisions($INPUT->int('first')))->show(); + global $INFO, $INPUT; + (new Ui\PageRevisions($INFO['id']))->show($INPUT->int('first')); } } diff --git a/inc/Ajax.php b/inc/Ajax.php index f1aea7d93..a5d54a312 100644 --- a/inc/Ajax.php +++ b/inc/Ajax.php @@ -241,14 +241,11 @@ class Ajax { * @author Kate Arzamastseva <pshns@ukr.net> */ protected function callMediadiff() { - global $NS; global $INPUT; $image = ''; if($INPUT->has('image')) $image = cleanID($INPUT->str('image')); - $NS = getNS($image); - $auth = auth_quickaclcheck("$NS:*"); - media_diff($image, $NS, $auth, true); + (new Ui\MediaDiff($image))->preference('fromAjax', true)->show(); } /** diff --git a/inc/Ui/Diff.php b/inc/Ui/Diff.php index 513e0667c..eec7c58a1 100644 --- a/inc/Ui/Diff.php +++ b/inc/Ui/Diff.php @@ -2,502 +2,168 @@ namespace dokuwiki\Ui; -use dokuwiki\ChangeLog\PageChangeLog; -use dokuwiki\ChangeLog\MediaChangeLog; -use dokuwiki\Extension\Event; -use dokuwiki\Form\Form; - /** * DokuWiki Diff Interface + * parent class of PageDiff and MediaDiff * * @package dokuwiki\Ui */ -class Diff extends Ui +abstract class Diff extends Ui { - protected $text; - protected $showIntro; - protected $difftype; + /* @var string */ + protected $id; // page id or media id + protected $item; // page or media + + /* @var int|string */ + protected $oldRev; // timestamp of older revision, '' means current one + protected $newRev; // timestamp of newer revision, '' means current one + + /* @var array */ + protected $preference = []; + + /* @var ChangeLog */ + protected $changelog; // PageChangeLog or MediaChangeLog object /** * Diff Ui constructor * - * @param string $text when non-empty: compare with this text with most current version - * @param bool $showIntro display the intro text - * @param string $difftype diff view type (inline or sidebyside) + * @param string $id page id or media id */ - public function __construct($text = '', $showIntro = true, $difftype = null) + public function __construct($id) { - $this->text = $text; - $this->showIntro = $showIntro; - - // determine diff view type - if (isset($difftype)) { - $this->difftype = $difftype; - } else { - global $INPUT; - global $INFO; - $this->difftype = $INPUT->str('difftype') ?: get_doku_pref('difftype', $difftype); - if (empty($this->difftype) && $INFO['ismobile']) { - $this->difftype = 'inline'; - } - } - if ($this->difftype !== 'inline') $this->difftype = 'sidebyside'; + $this->id = $id; + $this->setChangeLog(); } /** - * Show diff - * between current page version and provided $text - * or between the revisions provided via GET or POST + * set class property changelog + */ + abstract protected function setChangeLog(); + + /** + * item filename resolver * - * @author Andreas Gohr <andi@splitbrain.org> + * @param string $id page id or media id + * @param int|string $rev revision timestamp, or empty string for current one + * @return string full path + */ + abstract protected function itemFN($id, $rev = ''); + + /** + * Set a pair of revisions to be compared * - * @return void + * @param int $oldRev + * @param int $newRev + * @return $this */ - public function show() + public function compare($oldRev, $newRev) { - global $ID; - global $REV; - global $lang; - global $INPUT; - global $INFO; - $pagelog = new PageChangeLog($ID); - - /* - * Determine requested revision(s) - */ - // we're trying to be clever here, revisions to compare can be either - // given as rev and rev2 parameters, with rev2 being optional. Or in an - // array in rev2. - $rev1 = $REV; - - $rev2 = $INPUT->ref('rev2'); - if (is_array($rev2)) { - $rev1 = (int) $rev2[0]; - $rev2 = (int) $rev2[1]; - - if (!$rev1) { - $rev1 = $rev2; - unset($rev2); - } - } else { - $rev2 = $INPUT->int('rev2'); - } - - /* - * Determine left and right revision, its texts and the header - */ - $r_minor = ''; - $l_minor = ''; - - if ($this->text) { // compare text to the most current revision - $l_rev = ''; - $l_text = rawWiki($ID, ''); - $l_head = '<a class="wikilink1" href="'. wl($ID) .'">' - . $ID .' '. dformat((int) @filemtime(wikiFN($ID))) .'</a> ' - . $lang['current']; - - $r_rev = ''; - $r_text = cleanText($this->text); - $r_head = $lang['yours']; - } else { - if ($rev1 && isset($rev2) && $rev2) { // two specific revisions wanted - // make sure order is correct (older on the left) - if ($rev1 < $rev2) { - $l_rev = $rev1; - $r_rev = $rev2; - } else { - $l_rev = $rev2; - $r_rev = $rev1; - } - } elseif ($rev1) { // single revision given, compare to current - $r_rev = ''; - $l_rev = $rev1; - } else { // no revision was given, compare previous to current - $r_rev = ''; - $revs = $pagelog->getRevisions(0, 1); - $l_rev = $revs[0]; - $REV = $l_rev; // store revision back in $REV - } - - // when both revisions are empty then the page was created just now - if (!$l_rev && !$r_rev) { - $l_text = ''; - } else { - $l_text = rawWiki($ID, $l_rev); - } - $r_text = rawWiki($ID, $r_rev); - - list($l_head, $r_head, $l_minor, $r_minor) = $this->diffHead( - $l_rev, $r_rev, null, false, ($this->difftype == 'inline') - ); - } - - /* - * Build navigation - */ - $l_nav = ''; - $r_nav = ''; - if (!$this->text) { - list($l_nav, $r_nav) = $this->diffNavigation($pagelog, $l_rev, $r_rev); - } - /* - * Create diff object and the formatter - */ - $diff = new \Diff(explode("\n", $l_text), explode("\n", $r_text)); - - if ($this->difftype == 'inline') { - $diffformatter = new \InlineDiffFormatter(); - } else { - $diffformatter = new \TableDiffFormatter(); - } - /* - * Display intro - */ - if ($this->showIntro) print p_locale_xhtml('diff'); - - /* - * Display type and exact reference - */ - if (!$this->text) { - print '<div class="diffoptions group">'; - - // create the form to select difftype - $form = new Form(['action' => wl()]); - $form->setHiddenField('id', $ID); - $form->setHiddenField('rev2[0]', $l_rev); - $form->setHiddenField('rev2[1]', $r_rev); - $form->setHiddenField('do', 'diff'); - $options = array( - 'sidebyside' => $lang['diff_side'], - 'inline' => $lang['diff_inline'] - ); - $input = $form->addDropdown('difftype', $options, $lang['diff_type']) - ->val($this->difftype)->addClass('quickselect'); - $input->useInput(false); // inhibit prefillInput() during toHTML() process - $form->addButton('do[diff]', 'Go')->attr('type','submit'); - print $form->toHTML(); - - print '<p>'; - // link to exactly this view FS#2835 - print $this->diffViewlink('difflink', $l_rev, ($r_rev ?: $INFO['currentrev'])); - print '</p>'; - - print '</div>'; // .diffoptions - } - - /* - * Display diff view table - */ - print '<div class="table">'; - print '<table class="diff diff_'. $this->difftype .'">'; - - //navigation and header - if ($this->difftype == 'inline') { - if (!$this->text) { - print '<tr>' - . '<td class="diff-lineheader">-</td>' - . '<td class="diffnav">'. $l_nav .'</td>' - . '</tr>'; - print '<tr>' - . '<th class="diff-lineheader">-</th>' - . '<th '. $l_minor .'>'. $l_head .'</th>' - .'</tr>'; - } - print '<tr>' - . '<td class="diff-lineheader">+</td>' - . '<td class="diffnav">'. $r_nav .'</td>' - .'</tr>'; - print '<tr>' - . '<th class="diff-lineheader">+</th>' - . '<th '. $r_minor .'>'. $r_head .'</th>' - . '</tr>'; - } else { - if (!$this->text) { - print '<tr>' - . '<td colspan="2" class="diffnav">'. $l_nav .'</td>' - . '<td colspan="2" class="diffnav">'. $r_nav .'</td>' - . '</tr>'; - } - print '<tr>' - . '<th colspan="2" '. $l_minor .'>'. $l_head .'</th>' - . '<th colspan="2" '. $r_minor .'>'. $r_head .'</th>' - . '</tr>'; - } - - //diff view - print $this->insertSoftbreaks($diffformatter->format($diff)); - - print '</table>'; - print '</div>'; + $this->oldRev = $oldRev; + $this->newRev = $newRev; + return $this; } - /** - * Get header of diff HTML + * Gets or Sets preference of the Ui\Diff object * - * @param string $l_rev Left revisions - * @param string $r_rev Right revision - * @param string $id Page id, if null $ID is used - * @param bool $media If it is for media files - * @param bool $inline Return the header on a single line - * @return string[] HTML snippets for diff header + * @param string|array $prefs a key name or key-value pair(s) + * @param mixed $value value used when the first args is string + * @return array|$this */ - public function diffHead($l_rev, $r_rev, $id = null, $media = false, $inline = false) + public function preference($prefs = null, $value = null) { - global $lang; - if ($id === null) { - global $ID; - $id = $ID; - } - $head_separator = $inline ? ' ' : '<br />'; - $media_or_wikiFN = $media ? 'mediaFN' : 'wikiFN'; - $ml_or_wl = $media ? 'ml' : 'wl'; - $l_minor = $r_minor = ''; - - if ($media) { - $changelog = new MediaChangeLog($id); - } else { - $changelog = new PageChangeLog($id); - } - if (!$l_rev) { - $l_head = '—'; - } else { - $l_info = $changelog->getRevisionInfo($l_rev); - if ($l_info['user']) { - $l_user = '<bdi>'.editorinfo($l_info['user']).'</bdi>'; - if (auth_ismanager()) $l_user .= ' <bdo dir="ltr">('.$l_info['ip'].')</bdo>'; - } else { - $l_user = '<bdo dir="ltr">'.$l_info['ip'].'</bdo>'; - } - $l_user = '<span class="user">'.$l_user.'</span>'; - $l_sum = ($l_info['sum']) ? '<span class="sum"><bdi>'.hsc($l_info['sum']).'</bdi></span>' : ''; - if ($l_info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) $l_minor = 'class="minor"'; - - $l_head_title = ($media) ? dformat($l_rev) : $id.' ['.dformat($l_rev).']'; - $l_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id,"rev=$l_rev").'">' - . $l_head_title.'</a></bdi>'.$head_separator.$l_user.' '.$l_sum; - } - - if ($r_rev) { - $r_info = $changelog->getRevisionInfo($r_rev); - if ($r_info['user']) { - $r_user = '<bdi>'.editorinfo($r_info['user']).'</bdi>'; - if (auth_ismanager()) $r_user .= ' <bdo dir="ltr">('.$r_info['ip'].')</bdo>'; - } else { - $r_user = '<bdo dir="ltr">'.$r_info['ip'].'</bdo>'; + // set + if (is_string($prefs) && isset($value)) { + $this->preference[$prefs] = $value; + return $this; + } elseif (is_array($prefs)) { + foreach ($prefs as $name => $value) { + $this->preference[$name] = $value; } - $r_user = '<span class="user">'.$r_user.'</span>'; - $r_sum = ($r_info['sum']) ? '<span class="sum"><bdi>'.hsc($r_info['sum']).'</bdi></span>' : ''; - if ($r_info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"'; - - $r_head_title = ($media) ? dformat($r_rev) : $id.' ['.dformat($r_rev).']'; - $r_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id,"rev=$r_rev").'">' - . $r_head_title.'</a></bdi>'.$head_separator.$r_user.' '.$r_sum; - } elseif ($_rev = @filemtime($media_or_wikiFN($id))) { - $_info = $changelog->getRevisionInfo($_rev); - if ($_info['user']) { - $_user = '<bdi>'.editorinfo($_info['user']).'</bdi>'; - if (auth_ismanager()) $_user .= ' <bdo dir="ltr">('.$_info['ip'].')</bdo>'; - } else { - $_user = '<bdo dir="ltr">'.$_info['ip'].'</bdo>'; - } - $_user = '<span class="user">'.$_user.'</span>'; - $_sum = ($_info['sum']) ? '<span class="sum"><bdi>'.hsc($_info['sum']).'</span></bdi>' : ''; - if ($_info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) $r_minor = 'class="minor"'; - - $r_head_title = ($media) ? dformat($_rev) : $id.' ['.dformat($_rev).']'; - $r_head = '<bdi><a class="wikilink1" href="'.$ml_or_wl($id).'">' - . $r_head_title.'</a></bdi> '.'('.$lang['current'].')'.$head_separator.$_user.' '.$_sum; - }else{ - $r_head = '— ('.$lang['current'].')'; + return $this; } - - return array($l_head, $r_head, $l_minor, $r_minor); + // get + return $this->preference; } /** - * Create html for revision navigation + * Retrieve requested revision(s) and difftype from Ui\Revisions * - * @param PageChangeLog $pagelog changelog object of current page - * @param int $l_rev left revision timestamp - * @param int $r_rev right revision timestamp - * @return string[] html of left and right navigation elements + * @return void */ - protected function diffNavigation($pagelog, $l_rev, $r_rev) + protected function preProcess() { - global $INFO, $ID; - - // last timestamp is not in changelog, retrieve timestamp from metadata - // note: when page is removed, the metadata timestamp is zero - if (!$r_rev) { - if (isset($INFO['meta']['last_change']['date'])) { - $r_rev = $INFO['meta']['last_change']['date']; - } else { - $r_rev = 0; - } - } - - //retrieve revisions with additional info - list($l_revs, $r_revs) = $pagelog->getRevisionsAround($l_rev, $r_rev); - $l_revisions = array(); - if (!$l_rev) { - //no left revision given, add dummy - $l_revisions[0]= array('label' => '', 'attrs' => []); - } - foreach ($l_revs as $rev) { - $info = $pagelog->getRevisionInfo($rev); - $l_revisions[$rev] = array( - 'label' => dformat($info['date']) .' '. editorinfo($info['user'], true) .' '. $info['sum'], - 'attrs' => ['title' => $rev], - ); - if ($r_rev ? $rev >= $r_rev : false) $l_revisions[$rev]['attrs']['disabled'] = 'disabled'; - } - $r_revisions = array(); - if (!$r_rev) { - //no right revision given, add dummy - $r_revisions[0] = array('label' => '', 'attrs' => []); - } - foreach ($r_revs as $rev) { - $info = $pagelog->getRevisionInfo($rev); - $r_revisions[$rev] = array( - 'label' => dformat($info['date']) .' '. editorinfo($info['user'], true) .' '. $info['sum'], - 'attrs' => ['title' => $rev], - ); - if ($rev <= $l_rev) $r_revisions[$rev]['attrs']['disabled'] = 'disabled'; - } + global $INPUT; - //determine previous/next revisions - $l_index = array_search($l_rev, $l_revs); - $l_prev = $l_index < count($l_revs) - 1 ? $l_revs[$l_index + 1] : null; - $l_next = $l_index > 1 ? $l_revs[$l_index - 1] : null; - if ($r_rev) { - $r_index = array_search($r_rev, $r_revs); - $r_prev = $r_index < count($r_revs) - 1 ? $r_revs[$r_index + 1] : null; - $r_next = $r_index > 1 ? $r_revs[$r_index - 1] : null; - } else { - //removed page - if ($l_next) { - $r_prev = $r_revs[0]; + // difflink icon click, eg. ?rev=123456789&do=diff + if ($INPUT->has('rev')) { + $this->oldRev = $INPUT->int('rev'); + $this->newRev = ''; // current revision + } + + // submit button with two checked boxes + $rev2 = $INPUT->arr('rev2', []); + if (count($rev2) > 1) { + if ($rev2[0] == 'current') { + [$this->oldRev, $this->newRev] = [$rev2[1], '']; + } elseif ($rev2[1] == 'current') { + [$this->oldRev, $this->newRev] = [$rev2[0], '']; + } elseif ($rev2[0] < $rev2[1]) { + [$this->oldRev, $this->newRev] = [$rev2[0], $rev2[1]]; } else { - $r_prev = null; + [$this->oldRev, $this->newRev] = [$rev2[1], $rev2[0]]; } - $r_next = null; - } - - /* - * Left side: - */ - $l_nav = ''; - //move back - if ($l_prev) { - $l_nav .= $this->diffViewlink('diffbothprevrev', $l_prev, $r_prev); - $l_nav .= $this->diffViewlink('diffprevrev', $l_prev, $r_rev); - } - //dropdown - $form = new Form(['action' => wl()]); - $form->setHiddenField('id', $ID); - $form->setHiddenField('difftype', $this->difftype); - $form->setHiddenField('rev2[1]', $r_rev); - $form->setHiddenField('do', 'diff'); - $input = $form->addDropdown('rev2[0]', $l_revisions)->val($l_rev)->addClass('quickselect'); - $input->useInput(false); // inhibit prefillInput() during toHTML() process - $form->addButton('do[diff]', 'Go')->attr('type','submit'); - $l_nav .= $form->toHTML(); - //move forward - if ($l_next && ($l_next < $r_rev || !$r_rev)) { - $l_nav .= $this->diffViewlink('diffnextrev', $l_next, $r_rev); } - /* - * Right side: - */ - $r_nav = ''; - //move back - if ($l_rev < $r_prev) { - $r_nav .= $this->diffViewlink('diffprevrev', $l_rev, $r_prev); - } - //dropdown - $form = new Form(['action' => wl()]); - $form->setHiddenField('id', $ID); - $form->setHiddenField('rev2[0]', $l_rev); - $form->setHiddenField('difftype', $this->difftype); - $form->setHiddenField('do', 'diff'); - $input = $form->addDropdown('rev2[1]', $r_revisions)->val($r_rev)->addClass('quickselect'); - $input->useInput(false); // inhibit prefillInput() during toHTML() process - $form->addButton('do[diff]', 'Go')->attr('type','submit'); - $r_nav .= $form->toHTML(); - //move forward - if ($r_next) { - if ($pagelog->isCurrentRevision($r_next)) { - //last revision is diff with current page - $r_nav .= $this->diffViewlink('difflastrev', $l_rev); - } else { - $r_nav .= $this->diffViewlink('diffnextrev', $l_rev, $r_next); - } + // diff view type + if ($INPUT->has('difftype')) { + // retrieve requested $difftype + $this->preference['difftype'] = $INPUT->str('difftype'); } else { - $r_nav .= $this->diffViewlink('diffbothnextrev', $l_next, $r_next); + // read preference from DokuWiki cookie. PageDiff only + $mode = get_doku_pref('difftype', $mode = null); + if (isset($mode)) $this->preference['difftype'] = $mode; } - return array($l_nav, $r_nav); } /** - * Create html link to a diff view defined by two revisions + * get extended revision info * - * @param string $linktype - * @param int $lrev oldest revision - * @param int $rrev newest revision or null for diff with current revision - * @return string html of link to a diff view + * @param int|string $rev revision identifier, '' means current one + * @return array revision info structure of a page or media file */ - protected function diffViewlink($linktype, $lrev, $rrev = null) + protected function getExtendedRevisionInfo($rev) { - global $ID, $lang; - if ($rrev === null) { - $urlparam = array( - 'do' => 'diff', - 'rev' => $lrev, - 'difftype' => $this->difftype, + $changelog =& $this->changelog; + + if ($rev) { + $info = $changelog->getRevisionInfo($rev); + } elseif (file_exists($filename = $this->itemFN($this->id))) { + $rev = filemtime(fullpath($filename)); + $info = $changelog->getRevisionInfo($rev) + array( + 'current' => true, ); - } else { - $urlparam = array( - 'do' => 'diff', - 'rev2[0]' => $lrev, - 'rev2[1]' => $rrev, - 'difftype' => $this->difftype, + } else { // once exists, but now removed + $info = array( + 'current' => true, ); } - return '<a class="'. $linktype .'" href="'. wl($ID, $urlparam) .'" title="'. $lang[$linktype] .'">' - . '<span>'. $lang[$linktype] .'</span>' - . '</a>'; + return array('item' => $this->item) + $info; } + /** - * Insert soft breaks in diff html + * Build header of diff HTML * - * @param string $diffhtml - * @return string + * @param string $l_rev Left revisions + * @param string $r_rev Right revision + * @return string[] HTML snippets for diff header + * @deprecated 2020-12-31 */ - public function insertSoftbreaks($diffhtml) + public function buildDiffHead($l_rev, $r_rev) { - // search the diff html string for both: - // - html tags, so these can be ignored - // - long strings of characters without breaking characters - return preg_replace_callback('/<[^>]*>|[^<> ]{12,}/', function ($match) { - // if match is an html tag, return it intact - if ($match[0][0] == '<') return $match[0]; - // its a long string without a breaking character, - // make certain characters into breaking characters by inserting a - // word break opportunity (<wbr> tag) in front of them. - $regex = <<< REGEX -(?(?= # start a conditional expression with a positive look ahead ... -&\#?\\w{1,6};) # ... for html entities - we don't want to split them (ok to catch some invalid combinations) -&\#?\\w{1,6}; # yes pattern - a quicker match for the html entity, since we know we have one -| -[?/,&\#;:] # no pattern - any other group of 'special' characters to insert a breaking character after -)+ # end conditional expression -REGEX; - return preg_replace('<'.$regex.'>xu', '\0<wbr>', $match[0]); - }, $diffhtml); + dbg_deprecated('not used see '. \dokuwiki\Ui\PageDiff::class .'::show()'); } } diff --git a/inc/Ui/MediaDiff.php b/inc/Ui/MediaDiff.php new file mode 100644 index 000000000..5ed46988e --- /dev/null +++ b/inc/Ui/MediaDiff.php @@ -0,0 +1,339 @@ +<?php + +namespace dokuwiki\Ui; + +use dokuwiki\ChangeLog\MediaChangeLog; +use dokuwiki\Ui\MediaRevisions; +use dokuwiki\Extension\Event; +use dokuwiki\Form\Form; +use JpegMeta; + +/** + * DokuWiki MediaDiff Interface + * + * @package dokuwiki\Ui + */ +class MediaDiff extends Diff +{ + /* @var MediaChangeLog */ + protected $changelog; + + /** + * MediaDiff Ui constructor + * + * @param string $id media id + */ + public function __construct($id) + { + if (!isset($id)) { + throw new \InvalidArgumentException('media id should not be empty!'); + } + $this->item = 'media'; + + // init preference + $this->preference['fromAjax'] = false; // see doluwiki\Ajax::callMediadiff() + $this->preference['showIntro'] = false; + $this->preference['difftype'] = 'both'; // media diff view type: both, opacity or portions + + parent::__construct($id); + } + + /** @inheritdoc */ + protected function setChangeLog() + { + $this->changelog = new MediaChangeLog($this->id); + } + + /** @inheritdoc */ + protected function itemFN($id, $rev = '') + { + return mediaFN($id, $rev); + } + + /** @inheritdoc */ + protected function preProcess() + { + parent::preProcess(); + if (!isset($this->oldRev, $this->newRev)) { + // no revision was given, compare previous to current + $revs = $this->changelog->getRevisions(0, 1); + $this->oldRev = file_exists(mediaFN($this->id, $revs[0])) ? $revs[0] : ''; + $this->newRev = ''; + } + } + + /** + * Shows difference between two revisions of media + * + * @author Kate Arzamastseva <pshns@ukr.net> + */ + public function show() + { + global $conf; + + $ns = getNS($this->id); + $auth = auth_quickaclcheck("$ns:*"); + + if ($auth < AUTH_READ || !$this->id || !$conf['mediarevisions']) return ''; + + // determine left and right revision + if (!isset($this->oldRev, $this->newRev)) $this->preProcess(); + [$oldRev, $newRev] = [$this->oldRev, $this->newRev]; + + // prepare event data + // NOTE: MEDIA_DIFF event does not found in DokuWiki Event List? + $data = array(); + $data[0] = $this->id; + $data[1] = $oldRev; + $data[2] = $newRev; + $data[3] = $ns; + $data[4] = $auth; // permission level + $data[5] = $this->preference['fromAjax']; + + // trigger event + Event::createAndTrigger('MEDIA_DIFF', $data, null, false); + + if (is_array($data) && count($data) === 6) { + $this->id = $data[0]; + $oldRev = $data[1]; + $newRev = $data[2]; + $ns = $data[3]; + $auth = $data[4]; + $this->preference['fromAjax'] = $data[5]; + } else { + return ''; + } + + $oldRevMeta = new JpegMeta(mediaFN($this->id, $oldRev)); + $newRevMeta = new JpegMeta(mediaFN($this->id, $newRev)); + + $is_img = preg_match('/\.(jpe?g|gif|png)$/', $this->id); + if ($is_img) { + // get image width and height for the mediamanager preview panel + $oldRevSize = media_image_preview_size($this->id, $oldRev, $oldRevMeta); + $newRevSize = media_image_preview_size($this->id, $newRev, $newRevMeta); + // re-check image, ensure minimum image width for showImageDiff() + $is_img = ($oldRevSize && $newRevSize && ($oldRevSize[0] >= 30 || $newRevSize[0] >= 30)); + } + + // determine requested diff view type + if (!$is_img) { + $this->preference['difftype'] = 'both'; + } + + // display intro + if ($this->preference['showIntro']) echo p_locale_xhtml('diff'); + + // print form to choose diff view type + if ($is_img && !$this->preference['fromAjax']) { + $this->showDiffViewSelector(); + echo '<div id="mediamanager__diff" >'; + } + + switch ($this->preference['difftype']) { + case 'opacity': + case 'portions': + $this->showImageDiff($oldRev, $newRev, $oldRevSize, $newRevSize); + break; + case 'both': + default: + $this->showFileDiff($oldRev, $newRev, $oldRevMeta, $newRevMeta, $auth); + break; + } + + if ($is_img && !$this->preference['fromAjax']) { + echo '</div>'; + } + } + + /** + * Print form to choose diff view type + * the dropdown is to be added through JavaScript, see lib/scripts/media.js + */ + protected function showDiffViewSelector() + { + echo '<div class="diffoptions group">'; + + $form = new Form([ + 'id' => 'mediamanager__form_diffview', + 'action' => media_managerURL([], '&'), + 'method' => 'get', + 'class' => 'diffView', + ]); + $form->addTagOpen('div')->addClass('no'); + $form->setHiddenField('sectok', null); + $form->setHiddenField('mediado', 'diff'); + $form->setHiddenField('rev2[0]', $this->oldRev ?: 'current'); + $form->setHiddenField('rev2[1]', $this->newRev ?: 'current'); + $form->addTagClose('div'); + echo $form->toHTML(); + + echo '</div>'; // .diffoptions + } + + /** + * Prints two images side by side + * and slider + * + * @author Kate Arzamastseva <pshns@ukr.net> + * + * @param string|int $oldRev revision timestamp, or empty string + * @param string|int $newRev revision timestamp, or empty string + * @param array $oldRevSize array with width and height + * @param array $newRevSize array with width and height + * @param string $type diff view type: opacity or portions + */ + protected function showImageDiff($oldRev, $newRev, $oldRevSize, $newRevSize, $type = null) + { + if (!isset($type)) { + $type = $this->preference['difftype']; + } + + // adjust image width, right side (newer) has priority + if ($oldRevSize != $newRevSize) { + if ($newRevSize[0] > $oldRevSize[0]) { + $oldRevSize = $newRevSize; + } + } + + $oldRevSrc = ml($this->id, ['rev' => $oldRev, 'h' => $oldRevSize[1], 'w' => $oldRevSize[0]]); + $newRevSrc = ml($this->id, ['rev' => $newRev, 'h' => $oldRevSize[1], 'w' => $oldRevSize[0]]); + + // slider + echo '<div class="slider" style="max-width: '.($oldRevSize[0]-20).'px;" ></div>'; + + // two images in divs + echo '<div class="imageDiff '.$type.'">'; + echo '<div class="image1" style="max-width: '.$oldRevSize[0].'px;">'; + echo '<img src="'.$oldRevSrc.'" alt="" />'; + echo '</div>'; + echo '<div class="image2" style="max-width: '.$oldRevSize[0].'px;">'; + echo '<img src="'.$newRevSrc.'" alt="" />'; + echo '</div>'; + echo '</div>'; + } + + /** + * Shows difference between two revisions of media file + * + * @author Kate Arzamastseva <pshns@ukr.net> + * + * @param string|int $oldRev revision timestamp, or empty string + * @param string|int $newRev revision timestamp, or empty string + * @param JpegMeta $oldRevMeta + * @param JpegMeta $newRevMeta + * @param int $auth permission level + */ + protected function showFileDiff($oldRev, $newRev, $oldRevMeta, $newRevMeta, $auth) + { + global $lang; + + // revison info of older file (left side) + $oldRevInfo = $this->getExtendedRevisionInfo($oldRev); + // revison info of newer file (right side) + $newRevInfo = $this->getExtendedRevisionInfo($newRev); + + // display diff view table + echo '<div class="table">'; + echo '<table>'; + echo '<tr>'; + echo '<th>'. $this->revisionTitle($oldRevInfo) .'</th>'; + echo '<th>'. $this->revisionTitle($newRevInfo) .'</th>'; + echo '</tr>'; + + echo '<tr class="image">'; + echo '<td>'; + media_preview($this->id, $auth, $oldRev, $oldRevMeta); // $auth not used in media_preview()? + echo '</td>'; + + echo '<td>'; + media_preview($this->id, $auth, $newRev, $newRevMeta); + echo '</td>'; + echo '</tr>'; + + echo '<tr class="actions">'; + echo '<td>'; + media_preview_buttons($this->id, $auth, $oldRev); // $auth used in media_preview_buttons() + echo '</td>'; + + echo '<td>'; + media_preview_buttons($this->id, $auth, $newRev); + echo '</td>'; + echo '</tr>'; + + $l_tags = media_file_tags($oldRevMeta); + $r_tags = media_file_tags($newRevMeta); + // FIXME r_tags-only stuff + foreach ($l_tags as $key => $l_tag) { + if ($l_tag['value'] != $r_tags[$key]['value']) { + $r_tags[$key]['highlighted'] = true; + $l_tags[$key]['highlighted'] = true; + } elseif (!$l_tag['value'] || !$r_tags[$key]['value']) { + unset($r_tags[$key]); + unset($l_tags[$key]); + } + } + + echo '<tr>'; + foreach (array($l_tags, $r_tags) as $tags) { + echo '<td>'; + + echo '<dl class="img_tags">'; + foreach ($tags as $tag) { + $value = cleanText($tag['value']); + if (!$value) $value = '-'; + echo '<dt>'.$lang[$tag['tag'][1]].'</dt>'; + echo '<dd>'; + if ($tag['highlighted']) echo '<strong>'; + if ($tag['tag'][2] == 'date') { + echo dformat($value); + } else { + echo hsc($value); + } + if ($tag['highlighted']) echo '</strong>'; + echo '</dd>'; + } + echo '</dl>'; + + echo '</td>'; + } + echo '</tr>'; + + echo '</table>'; + echo '</div>'; + } + + /** + * Revision Title for MediaDiff table headline + * + * @param array $info Revision info structure of a media file + * @return string + */ + protected function revisionTitle(array $info) + { + global $lang, $INFO; + + if (isset($info['date'])) { + $rev = $info['date']; + $title = '<bdi><a class="wikilink1" href="'.ml($this->id, ['rev' => $rev]).'">' + . dformat($rev).'</a></bdi>'; + } else { + $rev = false; + $title = '—'; + } + if (isset($info['current']) || ($rev && $rev == $INFO['currentrev'])) { + $title .= ' ('.$lang['current'].')'; + } + + // append separator + $title .= ($this->preference['difftype'] === 'inline') ? ' ' : '<br />'; + + // supplement + if (isset($info['date'])) { + $objRevInfo = (new MediaRevisions($this->id))->getObjRevInfo($info); + $title .= $objRevInfo->editSummary().' '.$objRevInfo->editor(); + } + return $title; + } + +} diff --git a/inc/Ui/MediaRevisions.php b/inc/Ui/MediaRevisions.php new file mode 100644 index 000000000..526aa7ae7 --- /dev/null +++ b/inc/Ui/MediaRevisions.php @@ -0,0 +1,122 @@ +<?php + +namespace dokuwiki\Ui; + +use dokuwiki\ChangeLog\MediaChangeLog; +use dokuwiki\Form\Form; + +/** + * DokuWiki MediaRevisions Interface + * + * @package dokuwiki\Ui + */ +class MediaRevisions extends Revisions +{ + /* @var MediaChangeLog */ + protected $changelog; + + /** + * MediaRevisions Ui constructor + * + * @param string $id id of media + */ + public function __construct($id) + { + if (!$id) { + throw new \InvalidArgumentException('media id should not be empty!'); + } + $this->item = 'media'; + parent::__construct($id); + } + + /** @inheritdoc */ + protected function setChangeLog() + { + $this->changelog = new MediaChangeLog($this->id); + } + + /** @inheritdoc */ + protected function itemFN($id, $rev = '') + { + return mediaFN($id, $rev); + } + + /** + * Display a list of Media Revisions in the MediaManager + * + * @author Andreas Gohr <andi@splitbrain.org> + * @author Ben Coburn <btcoburn@silicodon.net> + * @author Kate Arzamastseva <pshns@ukr.net> + * @author Satoshi Sahara <sahara.satoshi@gmail.com> + * + * @param int $first skip the first n changelog lines + * @return void + */ + public function show($first = 0) + { + global $lang; + + // get revisions, and set correct pagenation parameters (first, hasNext) + if ($first === null) $first = 0; + $hasNext = false; + $revisions = $this->getRevisions($first, $hasNext); + + // create the form + $form = new Form([ + 'id' => 'page__revisions', // must not be "media__revisions" + 'action' => media_managerURL(['image' => $this->id], '&'), + 'class' => 'changes', + ]); + $form->setHiddenField('mediado', 'diff'); // required for media revisions + $form->addTagOpen('div')->addClass('no'); + + // start listing + $form->addTagOpen('ul'); + foreach ($revisions as $info) { + $rev = $info['date']; + $class = ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? 'minor' : ''; + $form->addTagOpen('li')->addClass($class); + $form->addTagOpen('div')->addClass('li'); + + if (isset($info['current'])) { + $form->addCheckbox('rev2[]')->val('current'); + } elseif (file_exists(mediaFN($this->id, $rev))) { + $form->addCheckbox('rev2[]')->val($rev); + } else { + $form->addCheckbox('')->val($rev)->attr('disabled','disabled'); + } + $form->addHTML(' '); + + $objRevInfo = $this->getObjRevInfo($info); + $html = implode(' ', [ + $objRevInfo->editDate(), // edit date and time + $objRevInfo->difflink(), // link to diffview icon + $objRevInfo->itemName(), // name of page or media + '<div>', + $objRevInfo->editSummary(), // edit summary + $objRevInfo->editor(), // editor info + $objRevInfo->sizechange(), // size change indicator + $objRevInfo->currentIndicator(), // current indicator (only when k=1) + '</div>', + ]); + $form->addHTML($html); + + $form->addTagClose('div'); + $form->addTagClose('li'); + } + $form->addTagClose('ul'); // end of revision list + + // show button for diff view + $form->addButton('do[diff]', $lang['diff2'])->attr('type', 'submit'); + + $form->addTagClose('div'); // close div class=no + + print $form->toHTML('Revisions'); + + // provide navigation for pagenated revision list (of pages and/or media files) + print $this->navigation($first, $hasNext, function ($n) { + return media_managerURL(['first' => $n], '&', false, true); + }); + } + +} diff --git a/inc/Ui/PageConflict.php b/inc/Ui/PageConflict.php index fcab37e8f..584860100 100644 --- a/inc/Ui/PageConflict.php +++ b/inc/Ui/PageConflict.php @@ -35,7 +35,7 @@ class PageConflict extends Ui */ public function show() { - global $ID; + global $INFO; global $lang; // print intro @@ -44,7 +44,7 @@ class PageConflict extends Ui // create the form $form = new Form(['id' => 'dw__editform']); $form->addTagOpen('div')->addClass('no'); - $form->setHiddenField('id', $ID); + $form->setHiddenField('id', $INFO['id']); $form->setHiddenField('wikitext', $this->text); $form->setHiddenField('summary', $this->summary); @@ -56,7 +56,8 @@ class PageConflict extends Ui print '<br /><br /><br /><br />'; - (new Diff($this->text, false))->show(); + // print difference + (new PageDiff($INFO['id']))->compareWith($this->text)->preference('showIntro', false)->show(); } } diff --git a/inc/Ui/PageDiff.php b/inc/Ui/PageDiff.php new file mode 100644 index 000000000..34be84444 --- /dev/null +++ b/inc/Ui/PageDiff.php @@ -0,0 +1,512 @@ +<?php + +namespace dokuwiki\Ui; + +use dokuwiki\ChangeLog\PageChangeLog; +use dokuwiki\Ui\PageRevisions; +use dokuwiki\Form\Form; + +/** + * DokuWiki PageDiff Interface + * + * @author Andreas Gohr <andi@splitbrain.org> + * @author Satoshi Sahara <sahara.satoshi@gmail.com> + * @package dokuwiki\Ui + */ +class PageDiff extends Diff +{ + /* @var PageChangeLog */ + protected $changelog; + + /* @var string */ + protected $text; + + /** + * PageDiff Ui constructor + * + * @param string $id page id + */ + public function __construct($id = null) + { + global $INFO; + if (!isset($id)) $id = $INFO['id']; + $this->item = 'page'; + + // init preference + $this->preference['showIntro'] = true; + $this->preference['difftype'] = 'sidebyside'; // diff view type: inline or sidebyside + + parent::__construct($id); + } + + /** @inheritdoc */ + protected function setChangeLog() + { + $this->changelog = new PageChangeLog($this->id); + } + + /** @inheritdoc */ + protected function itemFN($id, $rev = '') + { + return wikiFN($id, $rev); + } + + /** + * Set text to be compared with most current version + * exclusively use of the compare($old, $new) method + * + * @param string $text + * @return $this + */ + public function compareWith($text = null) + { + if (isset($text)) { + $this->text = $text; + $this->oldRev = ''; + $this->newRev = null; + } + return $this; + } + + /** @inheritdoc */ + protected function preProcess() + { + parent::preProcess(); + if (!isset($this->oldRev, $this->newRev)) { + // no revision was given, compare previous to current + $this->oldRev = $this->changelog->getRevisions(0, 1)[0]; + $this->newRev = ''; + + global $INFO, $REV; + if ($this->id == $INFO['id']) + $REV = $this->oldRev; // store revision back in $REV + } + } + + /** + * Show diff + * between current page version and provided $text + * or between the revisions provided via GET or POST + * + * @author Andreas Gohr <andi@splitbrain.org> + * + * @return void + */ + public function show() + { + global $INFO, $lang; + + // determine left and right revision + if (!isset($this->oldRev)) $this->preProcess(); + + // create difference engine object + if (isset($this->text)) { // compare text to the most current revision + $oldText = rawWiki($this->id, ''); + $newText = cleanText($this->text); + } else { + // when both revisions are empty then the page was created just now + $oldText = (!$this->oldRev && !$this->newRev) ? '' : rawWiki($this->id, $this->oldRev); + $newText = rawWiki($this->id, $this->newRev); // empty when removed page + } + $Difference = new \Diff(explode("\n", $oldText), explode("\n", $newText)); + + // revison info of older page (left side) + $oldRevInfo = $this->getExtendedRevisionInfo($this->oldRev); + + // revison info of newer page (right side) + if (isset($this->text)) { + $newRevInfo = array('date' => null); + } else { + $newRevInfo = $this->getExtendedRevisionInfo($this->newRev); + } + + // determin exact revision identifiers, even for current page + $oldRev = $oldRevInfo['date']; + $newRev = $newRevInfo['date']; + + // build paired navigation + $navOlderRevisions = ''; + $navNewerRevisions = ''; + if (!isset($this->text)) { + list( + $navOlderRevisions, + $navNewerRevisions, + ) = $this->buildRevisionsNavigation($oldRev, $newRev); + } + + // display intro + if ($this->preference['showIntro']) echo p_locale_xhtml('diff'); + + // print form to choose diff view type, and exact url reference to the view + if (!isset($this->text)) { + $this->showDiffViewSelector($oldRev, $newRev); + } + + // assign minor edit checker to the variable + $classEditType = function ($info) { + return ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? ' class="minor"' : ''; + }; + + // display diff view table + echo '<div class="table">'; + echo '<table class="diff diff_'.$this->preference['difftype'] .'">'; + + //navigation and header + switch ($this->preference['difftype']) { + case 'inline': + if (!isset($this->text)) { + echo '<tr>' + .'<td class="diff-lineheader">-</td>' + .'<td class="diffnav">'. $navOlderRevisions .'</td>' + .'</tr>'; + echo '<tr>' + .'<th class="diff-lineheader">-</th>' + .'<th'.$classEditType($oldRevInfo).'>'.$this->revisionTitle($oldRevInfo).'</th>' + .'</tr>'; + } + echo '<tr>' + .'<td class="diff-lineheader">+</td>' + .'<td class="diffnav">'. $navNewerRevisions .'</td>' + .'</tr>'; + echo '<tr>' + .'<th class="diff-lineheader">+</th>' + .'<th'.$classEditType($newRevInfo).'>'.$this->revisionTitle($newRevInfo).'</th>' + .'</tr>'; + // create formatter object + $DiffFormatter = new \InlineDiffFormatter(); + break; + + case 'sidebyside': + default: + if (!isset($this->text)) { + echo '<tr>' + .'<td colspan="2" class="diffnav">'. $navOlderRevisions .'</td>' + .'<td colspan="2" class="diffnav">'. $navNewerRevisions .'</td>' + .'</tr>'; + } + echo '<tr>' + .'<th colspan="2"'.$classEditType($oldRevInfo).'>'.$this->revisionTitle($oldRevInfo).'</th>' + .'<th colspan="2"'.$classEditType($newRevInfo).'>'.$this->revisionTitle($newRevInfo).'</th>' + .'</tr>'; + // create formatter object + $DiffFormatter = new \TableDiffFormatter(); + break; + } + + // output formatted difference + echo $this->insertSoftbreaks($DiffFormatter->format($Difference)); + + echo '</table>'; + echo '</div>'; + } + + /** + * Revision Title for PageDiff table headline + * + * @param array $info Revision info structure of a page + * @return string + */ + protected function revisionTitle(array $info) + { + global $lang, $INFO; + + // use designated title when compare current page source with given text + if (array_key_exists('date', $info) && is_null($info['date'])) { + return $lang['yours']; + } + + if (isset($info['date'])) { + $rev = $info['date']; + $title = '<bdi><a class="wikilink1" href="'.wl($this->id, ['rev' => $rev]).'">' + . $this->id.' ['.dformat($rev).']'.'</a></bdi>'; + } else { + $rev = false; + $title = '—'; + } + if (isset($info['current']) || ($rev && $rev == $INFO['currentrev'])) { + $title .= ' ('.$lang['current'].')'; + } + + // append separator + $title .= ($this->preference['difftype'] === 'inline') ? ' ' : '<br />'; + + // supplement + if (isset($info['date'])) { + $objRevInfo = (new PageRevisions($this->id))->getObjRevInfo($info); + $title .= $objRevInfo->editSummary().' '.$objRevInfo->editor(); + } + return $title; + } + + /** + * Print form to choose diff view type, and exact url reference to the view + * + * @param int $oldRev timestamp of older revision, left side + * @param int $newRev timestamp of newer revision, right side + */ + protected function showDiffViewSelector($oldRev, $newRev) + { + global $lang; + + echo '<div class="diffoptions group">'; + + // create the form to select difftype + $form = new Form(['action' => wl()]); + $form->setHiddenField('id', $this->id); + $form->setHiddenField('rev2[0]', $this->oldRev ?: 'current'); + $form->setHiddenField('rev2[1]', $this->newRev ?: 'current'); + $form->setHiddenField('do', 'diff'); + $options = array( + 'sidebyside' => $lang['diff_side'], + 'inline' => $lang['diff_inline'], + ); + $input = $form->addDropdown('difftype', $options, $lang['diff_type']) + ->val($this->preference['difftype']) + ->addClass('quickselect'); + $input->useInput(false); // inhibit prefillInput() during toHTML() process + $form->addButton('do[diff]', 'Go')->attr('type','submit'); + echo $form->toHTML(); + + // show exact url reference to the view when it is meaningful + echo '<p>'; + if (!isset($this->text) && $oldRev && $newRev) { + // link to exactly this view FS#2835 + $viewUrl = $this->diffViewlink('difflink', $oldRev, $newRev); + } + echo $viewUrl ?? '<br />'; + echo '</p>'; + + echo '</div>'; // .diffoptions + } + + /** + * Create html for revision navigation + * + * The navigation consists of older and newer revisions selectors, each + * state mutually depends on the selected revision of opposite side. + * + * @param int $oldRev timestamp of older revision, older side + * @param int $newRev timestamp of newer revision, newer side + * @return string[] html of navigation for both older and newer sides + */ + protected function buildRevisionsNavigation($oldRev, $newRev) + { + global $INFO; + + $changelog =& $this->changelog; + + // determine the last revision, which is usually the timestamp of current page, + // however which might be the last revision if the page had removed. + if (!$newRev) { + if ($this->id == $INFO['id']) { + // note: when page is removed, the metadata timestamp is zero + $lastRev = $INFO['currentrev'] ?? $INFO['meta']['last_change']['date'] ?? 0; + } else { + $lastRevs = $changelog->getRevisions(-1, 1) // empty array for removed page + ?: $changelog->getRevisions(0, 1); // last entry of changelog + $lastRev = count($lastRevs) > 0 ? $lastRevs[0] : 0; + } + $newRev = $lastRev; + } + + // retrieve revisions with additional info + list($oldRevs, $newRevs) = $changelog->getRevisionsAround($oldRev, $newRev); + + // build options for dropdown selector + $olderRevisions = $this->buildRevisionOptions('older', $oldRevs, $oldRev, $newRev); + $newerRevisions = $this->buildRevisionOptions('newer', $newRevs, $oldRev, $newRev); + + //determine previous/next revisions + $index = array_search($oldRev, $oldRevs); + $oldPrevRev = $oldRevs[$index + 1]; + $oldNextRev = $oldRevs[$index - 1]; + if ($newRev) { + $index = array_search($newRev, $newRevs); + $newPrevRev = $newRevs[$index + 1]; + $newNextRev = $newRevs[$index - 1]; + } else { + //removed page + $newPrevRev = ($oldNextRev) ? $newRevs[0] : null; + $newNextRev = null; + } + + /* + * navigation UI for older revisions / Left side: + */ + $navOlderRevs = ''; + //move back + if ($oldPrevRev) { + $navOlderRevs .= $this->diffViewlink('diffbothprevrev', $oldPrevRev, $newPrevRev); + $navOlderRevs .= $this->diffViewlink('diffprevrev', $oldPrevRev, $newRev); + } + //dropdown + $navOlderRevs .= $this->buildDropdownSelector('older', $olderRevisions, $oldRev, $newRev); + //move forward + if ($oldNextRev && ($oldNextRev < $newRev || !$newRev)) { + $navOlderRevs .= $this->diffViewlink('diffnextrev', $oldNextRev, $newRev); + } + + /* + * navigation UI for newer revisions / Right side: + */ + $navNewerRevs = ''; + //move back + if ($oldRev < $newPrevRev) { + $navNewerRevs .= $this->diffViewlink('diffprevrev', $oldRev, $newPrevRev); + } + //dropdown + $navNewerRevs .= $this->buildDropdownSelector('newer', $newerRevisions, $oldRev, $newRev); + //move forward + if ($newNextRev) { + if ($changelog->isCurrentRevision($newNextRev)) { + //last revision is diff with current page + $navNewerRevs .= $this->diffViewlink('difflastrev', $oldRev); + } else { + $navNewerRevs .= $this->diffViewlink('diffnextrev', $oldRev, $newNextRev); + } + $navNewerRevs .= $this->diffViewlink('diffbothnextrev', $oldNextRev, $newNextRev); + } + return array($navOlderRevs, $navNewerRevs); + } + + /** + * prepare options for dropdwon selector + * + * @params string $side "older" or "newer" + * @params array $revs list of revsion + * @param int $oldRev timestamp of older revision, left side + * @param int $newRev timestamp of newer revision, right side + * @return array + */ + protected function buildRevisionOptions($side, $revs, $oldRev, $newRev) + { + $changelog =& $this->changelog; + $revisions = array(); + + if (($side == 'older' && !$oldRev) // NOTE: this case should not happen! + ||($side == 'newer' && (!$newRev || !page_exists($this->id))) + ) { + //no revision given, likely removed page, add dummy entry + $revisions['current'] = array( + 'label' => '—', // U+2014 — + 'attrs' => [], + ); + } + + foreach ($revs as $rev) { + $info = $changelog->getRevisionInfo($rev); + $revisions[$rev] = array( + 'label' => implode(' ', [ + dformat($info['date']), + editorinfo($info['user'], true), + $info['sum'], + ]), + 'attrs' => ['title' => $rev], + ); + if (($side == 'older' && ($newRev ? $rev >= $newRev : false)) + ||($side == 'newer' && ($rev <= $oldRev)) + ) { + $revisions[$rev]['attrs']['disabled'] = 'disabled'; + } + } + return $revisions; + } + + /** + * build Dropdown form for revisions navigation + * + * @params string $side "older" or "newer" + * @params array $options dropdown options + * @param int $oldRev timestamp of older revision, left side + * @param int $newRev timestamp of newer revision, right side + * @return sting + */ + protected function buildDropdownSelector($side, $options, $oldRev, $newRev) + { + $form = new Form(['action' => wl($this->id)]); + $form->setHiddenField('id', $this->id); + $form->setHiddenField('do', 'diff'); + $form->setHiddenField('difftype', $this->preference['difftype']); + + switch ($side) { + case 'older': // left side + $form->setHiddenField('rev2[1]', $newRev ?: 'current'); + $input = $form->addDropdown('rev2[0]', $options) + ->val($oldRev ?: 'current')->addClass('quickselect'); + $input->useInput(false); // inhibit prefillInput() during toHTML() process + break; + case 'newer': // right side + $form->setHiddenField('rev2[0]', $oldRev ?: 'current'); + $input = $form->addDropdown('rev2[1]', $options) + ->val($newRev ?: 'current')->addClass('quickselect'); + $input->useInput(false); // inhibit prefillInput() during toHTML() process + break; + } + $form->addButton('do[diff]', 'Go')->attr('type','submit'); + return $form->toHTML(); + } + + /** + * Create html link to a diff view defined by two revisions + * + * @param string $linktype + * @param int $oldRev older revision + * @param int $newRev newer revision or null for diff with current revision + * @return string html of link to a diff view + */ + protected function diffViewlink($linktype, $oldRev, $newRev = null) + { + global $lang; + if ($newRev === null) { + $urlparam = array( + 'do' => 'diff', + 'rev' => $oldRev, + 'difftype' => $this->preference['difftype'], + ); + } else { + $urlparam = array( + 'do' => 'diff', + 'rev2[0]' => $oldRev, + 'rev2[1]' => $newRev, + 'difftype' => $this->preference['difftype'], + ); + } + $attr = array( + 'class' => $linktype, + 'href' => wl($this->id, $urlparam, true, '&'), + 'title' => $lang[$linktype], + ); + return '<a '. buildAttributes($attr) .'><span>'. $lang[$linktype] .'</span></a>'; + } + + + /** + * Insert soft breaks in diff html + * + * @param string $diffhtml + * @return string + */ + public function insertSoftbreaks($diffhtml) + { + // search the diff html string for both: + // - html tags, so these can be ignored + // - long strings of characters without breaking characters + return preg_replace_callback('/<[^>]*>|[^<> ]{12,}/', function ($match) { + // if match is an html tag, return it intact + if ($match[0][0] == '<') return $match[0]; + // its a long string without a breaking character, + // make certain characters into breaking characters by inserting a + // word break opportunity (<wbr> tag) in front of them. + $regex = <<< REGEX +(?(?= # start a conditional expression with a positive look ahead ... +&\#?\\w{1,6};) # ... for html entities - we don't want to split them (ok to catch some invalid combinations) +&\#?\\w{1,6}; # yes pattern - a quicker match for the html entity, since we know we have one +| +[?/,&\#;:] # no pattern - any other group of 'special' characters to insert a breaking character after +)+ # end conditional expression +REGEX; + return preg_replace('<'.$regex.'>xu', '\0<wbr>', $match[0]); + }, $diffhtml); + } + +} diff --git a/inc/Ui/PageDraft.php b/inc/Ui/PageDraft.php index 609ee508d..ac2a63e9c 100644 --- a/inc/Ui/PageDraft.php +++ b/inc/Ui/PageDraft.php @@ -22,21 +22,21 @@ class PageDraft extends Ui public function show() { global $INFO; - global $ID; global $lang; - $draft = new \dokuwiki\Draft($ID, $INFO['client']); + $draft = new \dokuwiki\Draft($INFO['id'], $INFO['client']); $text = $draft->getDraftText(); // print intro print p_locale_xhtml('draft'); - (new Diff($text, false))->show(); + // print difference + (new PageDiff($INFO['id']))->compareWith($text)->preference('showIntro', false)->show(); // create the draft form $form = new Form(['id' => 'dw__editform']); $form->addTagOpen('div')->addClass('no'); - $form->setHiddenField('id', $ID); + $form->setHiddenField('id', $INFO['id']); $form->setHiddenField('date', $draft->getDraftDate()); $form->setHiddenField('wikitext', $text); diff --git a/inc/Ui/PageRevisions.php b/inc/Ui/PageRevisions.php new file mode 100644 index 000000000..5e633a58e --- /dev/null +++ b/inc/Ui/PageRevisions.php @@ -0,0 +1,181 @@ +<?php + +namespace dokuwiki\Ui; + +use dokuwiki\ChangeLog\PageChangeLog; +use dokuwiki\Form\Form; + +/** + * DokuWiki PageRevisions Interface + * + * @package dokuwiki\Ui + */ +class PageRevisions extends Revisions +{ + /* @var PageChangeLog */ + protected $changelog; + + /** + * PageRevisions Ui constructor + * + * @param string $id id of page + */ + public function __construct($id = null) + { + global $INFO; + if (!isset($id)) $id = $INFO['id']; + $this->item = 'page'; + parent::__construct($id); + } + + /** @inheritdoc */ + protected function setChangeLog() + { + $this->changelog = new PageChangeLog($this->id); + } + + /** @inheritdoc */ + protected function itemFN($id, $rev = '') + { + return wikiFN($id, $rev); + } + + /** + * Display list of old revisions of the page + * + * @author Andreas Gohr <andi@splitbrain.org> + * @author Ben Coburn <btcoburn@silicodon.net> + * @author Kate Arzamastseva <pshns@ukr.net> + * @author Satoshi Sahara <sahara.satoshi@gmail.com> + * + * @param int $first skip the first n changelog lines + * @return void + */ + public function show($first = 0) + { + global $lang, $REV; + + // get revisions, and set correct pagenation parameters (first, hasNext) + if ($first === null) $first = 0; + $hasNext = false; + $revisions = $this->getRevisions($first, $hasNext); + + // print intro + print p_locale_xhtml('revisions'); + + // create the form + $form = new Form([ + 'id' => 'page__revisions', + 'class' => 'changes', + ]); + $form->addTagOpen('div')->addClass('no'); + + // start listing + $form->addTagOpen('ul'); + foreach ($revisions as $info) { + $rev = $info['date']; + $class = ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? 'minor' : ''; + $form->addTagOpen('li')->addClass($class); + $form->addTagOpen('div')->addClass('li'); + + if (isset($info['current'])) { + $form->addCheckbox('rev2[]')->val('current'); + } elseif ($rev == $REV) { + $form->addCheckbox('rev2[]')->val($rev)->attr('checked','checked'); + } elseif (page_exists($this->id, $rev)) { + $form->addCheckbox('rev2[]')->val($rev); + } else { + $form->addCheckbox('')->val($rev)->attr('disabled','disabled'); + } + $form->addHTML(' '); + + $objRevInfo = $this->getObjRevInfo($info); + $html = implode(' ', [ + $objRevInfo->editDate(), // edit date and time + $objRevInfo->difflink(), // link to diffview icon + $objRevInfo->itemName(), // name of page or media + $objRevInfo->editSummary(), // edit summary + $objRevInfo->editor(), // editor info + $objRevInfo->sizechange(), // size change indicator + $objRevInfo->currentIndicator(), // current indicator (only when k=1) + ]); + $form->addHTML($html); + $form->addTagClose('div'); + $form->addTagClose('li'); + } + $form->addTagClose('ul'); // end of revision list + + // show button for diff view + $form->addButton('do[diff]', $lang['diff2'])->attr('type', 'submit'); + + $form->addTagClose('div'); // close div class=no + + print $form->toHTML('Revisions'); + + // provide navigation for pagenated revision list (of pages and/or media files) + print $this->navigation($first, $hasNext, function ($n) { + return array('do' => 'revisions', 'first' => $n); + }); + } + + /** + * Get revisions, and set correct pagenation parameters (first, hasNext) + * + * @param int $first + * @param bool $hasNext + * @return array revisions to be shown in a pagenated list + * @see also https://www.dokuwiki.org/devel:changelog + */ + protected function getRevisions(&$first, &$hasNext) + { + global $INFO, $conf; + + if ($this->id != $INFO['id']) { + return parent::getRevisions($first, $hasNext); + } + + $changelog =& $this->changelog; + + $revisions = []; + + /* we need to get one additional log entry to be able to + * decide if this is the last page or is there another one. + * see also Ui\Recent::getRecents() + */ + $revlist = $changelog->getRevisions($first, $conf['recent'] +1); + if (count($revlist) == 0 && $first != 0) { + $first = 0; + $revlist = $changelog->getRevisions($first, $conf['recent'] +1); + } + $exists = $INFO['exists']; + if ($first == 0 && $exists) { + // add current page as revision[0] + $revisions[] = array( + 'date' => $INFO['lastmod'], + 'ip' => null, + 'type' => $INFO['meta']['last_change']['type'], + 'id' => $INFO['id'], + 'user' => $INFO['editor'], + 'sum' => $INFO['sum'], + 'extra' => null, + 'sizechange' => $INFO['meta']['last_change']['sizechange'], + 'item' => $this->item, + 'current' => true, + ); + } + + // decide if this is the last page or is there another one + $hasNext = false; + if (count($revlist) > $conf['recent']) { + $hasNext = true; + array_pop($revlist); // remove one additional log entry + } + + // append each revison info array to the revisions + foreach ($revlist as $rev) { + $revisions[] = $changelog->getRevisionInfo($rev) + array('item' => $this->item); + } + return $revisions; + } + +} diff --git a/inc/Ui/Revisions.php b/inc/Ui/Revisions.php index c027244f8..ca38a213a 100644 --- a/inc/Ui/Revisions.php +++ b/inc/Ui/Revisions.php @@ -2,190 +2,45 @@ namespace dokuwiki\Ui; -use dokuwiki\ChangeLog\PageChangeLog; -use dokuwiki\ChangeLog\MediaChangeLog; -use dokuwiki\Form\Form; - /** * DokuWiki Revisions Interface + * parent class of PageRevisions and MediaRevisions * * @package dokuwiki\Ui */ -class Revisions extends Ui +abstract class Revisions extends Ui { - protected $first; - protected $media_id; + /* @var string */ + protected $id; // page id or media id + protected $item; // page or media - /** - * Revisions Ui constructor - * - * @param int $first skip the first n changelog lines - * @param bool|string $media_id id of media, or false for current page - */ - public function __construct($first = 0, $media_id = false) - { - $this->first = $first; - $this->media_id = $media_id; - } + /* @var ChangeLog */ + protected $changelog; // PageChangeLog or MediaChangeLog object /** - * Display list of old revisions - * - * @author Andreas Gohr <andi@splitbrain.org> - * @author Ben Coburn <btcoburn@silicodon.net> - * @author Kate Arzamastseva <pshns@ukr.net> - * @author Satoshi Sahara <sahara.satoshi@gmail.com> + * Revisions Ui constructor * - * @return void + * @param string $id page id or media id */ - public function show() + public function __construct($id) { - global $ID; - - if ($this->media_id) { - return $this->showMediaRevisions($this->media_id); - } else { - return $this->showPageRevisions($ID); - } + $this->id = $id; + $this->setChangeLog(); } /** - * Display a list of Media Revisions in the MediaManager - * - * @param string $id media id - * @return void + * set class property changelog */ - protected function showMediaRevisions($id) - { - global $lang; - - // get revisions, and set correct pagenation parameters (first, hasNext) - $first = $this->first; - $hasNext = false; - $revisions = $this->getRevisions($first, $hasNext); - - // create the form - $form = new Form([ - 'id' => 'page__revisions', // must not be "media__revisions" - 'action' => media_managerURL(['image' => $id], '&'), - 'class' => 'changes', - ]); - $form->setHiddenField('mediado', 'diff'); // required for media revisions - $form->addTagOpen('div')->addClass('no'); - - // start listing - $form->addTagOpen('ul'); - foreach ($revisions as $info) { - $rev = $info['date']; - $class = ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? 'minor' : ''; - $form->addTagOpen('li')->addClass($class); - $form->addTagOpen('div')->addClass('li'); - - if (isset($info['current'])) { - $form->addCheckbox('rev2[]')->val('current'); - } elseif (file_exists(mediaFN($id, $rev))) { - $form->addCheckbox('rev2[]')->val($rev); - } else { - $form->addCheckbox('')->val($rev)->attr('disabled','disabled'); - } - $form->addHTML(' '); - - $objRevInfo = $this->getObjRevInfo($info); - $html = implode(' ', [ - $objRevInfo->editDate(), // edit date and time - $objRevInfo->difflink(), // link to diffview icon - $objRevInfo->itemName(), // name of page or media - '<div>', - $objRevInfo->editSummary(), // edit summary - $objRevInfo->editor(), // editor info - html_sizechange($info['sizechange']), // size change indicator - $objRevInfo->currentIndicator(), // current indicator (only when k=1) - '</div>', - ]); - $form->addHTML($html); - - $form->addTagClose('div'); - $form->addTagClose('li'); - } - $form->addTagClose('ul'); // end of revision list - - // show button for diff view - $form->addButton('do[diff]', $lang['diff2'])->attr('type', 'submit'); - - $form->addTagClose('div'); // close div class=no - - print $form->toHTML('Revisions'); - - // provide navigation for pagenated revision list (of pages and/or media files) - print $this->htmlNavigation($id, $first, $hasNext); - } + abstract protected function setChangeLog(); /** - * Display a list of Page Revisions + * item filename resolver * - * @return void + * @param string $id page id or media id + * @param int|string $rev revision timestamp, or empty string for current one + * @return string full path */ - protected function showPageRevisions($id) - { - global $lang; - - // get revisions, and set correct pagenation parameters (first, hasNext) - $first = $this->first; - $hasNext = false; - $revisions = $this->getRevisions($first, $hasNext); - - // print intro - print p_locale_xhtml('revisions'); - - // create the form - $form = new Form([ - 'id' => 'page__revisions', - 'class' => 'changes', - ]); - $form->addTagOpen('div')->addClass('no'); - - // start listing - $form->addTagOpen('ul'); - foreach ($revisions as $info) { - $rev = $info['date']; - $class = ($info['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? 'minor' : ''; - $form->addTagOpen('li')->addClass($class); - $form->addTagOpen('div')->addClass('li'); - - if (page_exists($id, $rev)) { - $form->addCheckbox('rev2[]')->val($rev); - } else { - $form->addCheckbox('')->val($rev)->attr('disabled','disabled'); - } - $form->addHTML(' '); - - $objRevInfo = $this->getObjRevInfo($info); - $html = implode(' ', [ - $objRevInfo->editDate(), // edit date and time - $objRevInfo->difflink(), // link to diffview icon - $objRevInfo->itemName(), // name of page or media - $objRevInfo->editSummary(), // edit summary - $objRevInfo->editor(), // editor info - $objRevInfo->sizechange(), // size change indicator - $objRevInfo->currentIndicator(), // current indicator (only when k=1) - ]); - $form->addHTML($html); - $form->addTagClose('div'); - $form->addTagClose('li'); - } - $form->addTagClose('ul'); // end of revision list - - // show button for diff view - $form->addButton('do[diff]', $lang['diff2'])->attr('type', 'submit'); - - $form->addTagClose('div'); // close div class=no - - print $form->toHTML('Revisions'); - - // provide navigation for pagenated revision list (of pages and/or media files) - print $this->htmlNavigation($id, $first, $hasNext); - } - + abstract protected function itemFN($id, $rev = ''); /** * Get revisions, and set correct pagenation parameters (first, hasNext) @@ -197,15 +52,11 @@ class Revisions extends Ui */ protected function getRevisions(&$first, &$hasNext) { - global $INFO, $conf; + global $conf; - if ($this->media_id) { - $changelog = new MediaChangeLog($this->media_id); - } else { - $changelog = new PageChangeLog($INFO['id']); - } + $changelog =& $this->changelog; - $revisions = []; + $revisions = array(); /* we need to get one additional log entry to be able to * decide if this is the last page or is there another one. @@ -216,46 +67,25 @@ class Revisions extends Ui $first = 0; $revlist = $changelog->getRevisions($first, $conf['recent'] +1); } - $exists = ($this->media_id) ? file_exists(mediaFN($this->media_id)) : $INFO['exists']; - if ($first === 0 && $exists) { - // add current page or media as revision[0] - if ($this->media_id) { - $rev = filemtime(fullpath(mediaFN($this->media_id))); - $changelog->setChunkSize(1024); - $revinfo = $changelog->getRevisionInfo($rev) ?: array( - 'date' => $rev, - 'ip' => null, - 'type' => null, - 'id' => $this->media_id, - 'user' => null, - 'sum' => null, - 'extra' => null, - 'sizechange' => null, - ); - $revisions[] = $revinfo + array( - 'media' => true, - 'current' => true, - ); - } else { - if (isset($INFO['meta']['last_change'])) { - $type = $INFO['meta']['last_change']['type']; - $sizechange = $INFO['meta']['last_change']['sizechange']; - } else { - $type = $sizechange = null; - } - $revisions[] = array( - 'date' => $INFO['lastmod'], - 'ip' => null, - 'type' => $type, - 'id' => $INFO['id'], - 'user' => $INFO['editor'], - 'sum' => $INFO['sum'], - 'extra' => null, - 'sizechange' => $sizechange, - 'current' => true, - ); - } + // add current page or media as revision[0] when necessary + if ($first === 0 && file_exists($this->itemFN($this->id))) { + $rev = filemtime(fullpath($this->itemFN($this->id))); + $changelog->setChunkSize(1024); //FIXME why does chunksize change wanted? + $revinfo = $changelog->getRevisionInfo($rev) ?: array( + 'date' => $rev, + 'ip' => null, + 'type' => null, + 'id' => $this->id, + 'user' => null, + 'sum' => null, + 'extra' => null, + 'sizechange' => null, + ); + $revisions[] = $revinfo + array( + 'item' => $this->item, + 'current' => true, + ); } // decide if this is the last page or is there another one @@ -267,11 +97,7 @@ class Revisions extends Ui // append each revison info array to the revisions foreach ($revlist as $rev) { - if ($this->media_id) { - $revisions[] = $changelog->getRevisionInfo($rev) + array('media' => true); - } else { - $revisions[] = $changelog->getRevisionInfo($rev); - } + $revisions[] = $changelog->getRevisionInfo($rev) + array('item' => $this->item); } return $revisions; } @@ -279,12 +105,12 @@ class Revisions extends Ui /** * Navigation buttons for Pagenation (prev/next) * - * @param string $id page id or media id * @param int $first * @param bool $hasNext + * @param callable $callback returns array of hidden fields for the form button * @return array html */ - protected function htmlNavigation($id, $first, $hasNext) + protected function navigation($first, $hasNext, $callback) { global $conf; @@ -293,20 +119,12 @@ class Revisions extends Ui if ($first > 0) { $first = max($first - $conf['recent'], 0); $html.= '<div class="pagenav-prev">'; - if ($this->media_id) { - $html.= html_btn('newer', $id, "p", media_managerURL(['first' => $first], '&', false, true)); - } else { - $html.= html_btn('newer', $id, "p" ,['do' => 'revisions', 'first' => $first]); - } + $html.= html_btn('newer', $this->id, "p", $callback($first)); $html.= '</div>'; } if ($hasNext) { $html.= '<div class="pagenav-next">'; - if ($this->media_id) { - $html.= html_btn('older', $id, "n", media_managerURL(['first' => $last], '&', false, true)); - } else { - $html.= html_btn('older', $id, "n", ['do' => 'revisions', 'first' => $last]); - } + $html.= html_btn('older', $this->id, "n", $callback($last)); $html.= '</div>'; } $html.= '</div>'; @@ -319,7 +137,7 @@ class Revisions extends Ui * @param array $info Revision info structure of a page or media file * @return objRevInfo object (anonymous class) */ - protected function getObjRevInfo(array $info) + public function getObjRevInfo(array $info) { return new class ($info) // anonymous class (objRevInfo) { @@ -377,30 +195,30 @@ class Revisions extends Ui $id = $this->info['id']; $rev = $this->info['date']; - if (isset($this->info['media'])) { - // media file revision - if (isset($this->info['current'])) { - $href = media_managerURL(['image'=> $id, 'tab_details'=> 'view'], '&'); - $html = '<a href="'.$href.'" class="wikilink1">'.$id.'</a>'; - } elseif (file_exists(mediaFN($id, $rev))) { - $href = media_managerURL(['image'=> $id, 'tab_details'=> 'view', 'rev'=> $rev], '&'); - $html = '<a href="'.$href.'" class="wikilink1">'.$id.'</a>'; - } else { - $html = $id; - } - return $html; - } else { - // page revision - $display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id; - if (!$display_name) $display_name = $id; - if ($this->info['current'] || page_exists($id, $rev)) { - $href = wl($id, "rev=$rev", false, '&'); - $html = '<a href="'.$href.'" class="wikilink1">'.$display_name.'</a>'; - } else { - $html = $display_name; - } - return $html; + switch ($this->info['item']) { + case 'media': // media file revision + if (isset($this->info['current'])) { + $href = media_managerURL(['image'=> $id, 'tab_details'=> 'view'], '&'); + $html = '<a href="'.$href.'" class="wikilink1">'.$id.'</a>'; + } elseif (file_exists(mediaFN($id, $rev))) { + $href = media_managerURL(['image'=> $id, 'tab_details'=> 'view', 'rev'=> $rev], '&'); + $html = '<a href="'.$href.'" class="wikilink1">'.$id.'</a>'; + } else { + $html = $id; + } + return $html; + case 'page': // page revision + $display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id; + if (!$display_name) $display_name = $id; + if ($this->info['current'] || page_exists($id, $rev)) { + $href = wl($id, "rev=$rev", false, '&'); + $html = '<a href="'.$href.'" class="wikilink1">'.$display_name.'</a>'; + } else { + $html = $display_name; + } + return $html; } + return ''; } // icon difflink @@ -410,31 +228,31 @@ class Revisions extends Ui $id = $this->info['id']; $rev = $this->info['date']; - if (isset($this->info['media'])) { - // media file revision - if (isset($this->info['current']) || !file_exists(mediaFN($id, $rev))) { - $html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />'; - } else { - $href = media_managerURL(['image'=> $id, 'rev'=> $rev, 'mediado'=>'diff'], '&'); - $html = '<a href="'.$href.'" class="diff_link">' - . '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"' - . ' title="'. $lang['diff'] .'" alt="'.$lang['diff'] .'" />' - . '</a> '; - } - return $html; - } else { - // page revision - if ($this->info['current'] || !page_exists($id, $rev)) { - $html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />'; - } else { - $href = wl($id, "rev=$rev,do=diff", false, '&'); - $html = '<a href="'.$href.'" class="diff_link">' - . '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"' - . ' title="'.$lang['diff'].'" alt="'.$lang['diff'].'" />' - . '</a>'; - } - return $html; + switch ($this->info['item']) { + case 'media': // media file revision + if (isset($this->info['current']) || !file_exists(mediaFN($id, $rev))) { + $html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />'; + } else { + $href = media_managerURL(['image'=> $id, 'rev'=> $rev, 'mediado'=>'diff'], '&'); + $html = '<a href="'.$href.'" class="diff_link">' + . '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"' + . ' title="'. $lang['diff'] .'" alt="'.$lang['diff'] .'" />' + . '</a> '; + } + return $html; + case 'page': // page revision + if ($this->info['current'] || !page_exists($id, $rev)) { + $html = '<img src="'.DOKU_BASE.'lib/images/blank.gif" width="15" height="11" alt="" />'; + } else { + $href = wl($id, "rev=$rev,do=diff", false, '&'); + $html = '<a href="'.$href.'" class="diff_link">' + . '<img src="'.DOKU_BASE.'lib/images/diff.png" width="15" height="11"' + . ' title="'.$lang['diff'].'" alt="'.$lang['diff'].'" />' + . '</a>'; + } + return $html; } + return ''; } // size change diff --git a/inc/html.php b/inc/html.php index e8cfed872..a2559419b 100644 --- a/inc/html.php +++ b/inc/html.php @@ -297,12 +297,17 @@ function html_locked() { * @author Kate Arzamastseva <pshns@ukr.net> * * @param int $first skip the first n changelog lines - * @param bool|string $media_id id of media, or false for current page + * @param string $media_id id of media, or empty for current page * @deprecated 2020-07-18 */ -function html_revisions($first=0, $media_id = false) { - dbg_deprecated(\dokuwiki\Ui\Revisions::class .'::show()'); - (new dokuwiki\Ui\Revisions($first, $media_id))->show(); +function html_revisions($first = 0, $media_id = '') { + dbg_deprecated(\dokuwiki\Ui\PageRevisions::class .'::show()'); + if ($media_id) { + (new dokuwiki\Ui\MediaRevisions($media_id))->show($first); + } else { + global $INFO; + (new dokuwiki\Ui\PageRevisions($INFO['id']))->show($first); + } } /** @@ -494,7 +499,7 @@ function html_backlinks() { * @deprecated 2020-07-18 */ function html_diff_head($l_rev, $r_rev, $id = null, $media = false, $inline = false) { - dbg_deprecated('see '. \dokuwiki\Ui\Diff::class .'::diffHead()'); + dbg_deprecated('see '. \dokuwiki\Ui\PageDiff::class .'::buildDiffHead()'); } /** @@ -509,8 +514,12 @@ function html_diff_head($l_rev, $r_rev, $id = null, $media = false, $inline = fa * @deprecated 2020-07-18 */ function html_diff($text = '', $intro = true, $type = null) { - dbg_deprecated(\dokuwiki\Ui\Diff::class .'::show()'); - (new dokuwiki\Ui\Diff($text, $intro, $type))->show(); + dbg_deprecated(\dokuwiki\Ui\PageDiff::class .'::show()'); + global $INFO; + (new dokuwiki\Ui\PageDiff($INFO['id']))->compareWith($text)->preference([ + 'showIntro' => $intro, + 'difftype' => $type, + ])->show(); } /** @@ -524,7 +533,7 @@ function html_diff($text = '', $intro = true, $type = null) { * @deprecated 2020-07-18 */ function html_diff_navigation($pagelog, $type, $l_rev, $r_rev) { - dbg_deprecated('see '. \dokuwiki\Ui\Diff::class .'::diffNavigation()'); + dbg_deprecated('see '. \dokuwiki\Ui\PageDiff::class .'::buildRevisionsNavigation()'); } /** @@ -538,7 +547,7 @@ function html_diff_navigation($pagelog, $type, $l_rev, $r_rev) { * @deprecated 2020-07-18 */ function html_diff_navigationlink($difftype, $linktype, $lrev, $rrev = null) { - dbg_deprecated('see '. \dokuwiki\Ui\Diff::class .'::diffViewlink()'); + dbg_deprecated('see '. \dokuwiki\Ui\PageDiff::class .'::diffViewlink()'); } /** @@ -549,8 +558,8 @@ function html_diff_navigationlink($difftype, $linktype, $lrev, $rrev = null) { * @deprecated 2020-07-18 */ function html_insert_softbreaks($diffhtml) { - dbg_deprecated(\dokuwiki\Ui\Diff::class .'::insertSoftbreaks()'); - return (new dokuwiki\Ui\Diff())->insertSoftbreaks($diffhtml); + dbg_deprecated(\dokuwiki\Ui\PageDiff::class .'::insertSoftbreaks()'); + return (new dokuwiki\Ui\PageDiff)->insertSoftbreaks($diffhtml); } /** @@ -563,8 +572,8 @@ function html_insert_softbreaks($diffhtml) { * @deprecated 2020-07-18 */ function html_conflict($text, $summary) { - dbg_deprecated(\dokuwiki\Ui\Conflict::class .'::show()'); - (new dokuwiki\Ui\Conflict($text, $summary))->show(); + dbg_deprecated(\dokuwiki\Ui\PageConflict::class .'::show()'); + (new dokuwiki\Ui\PageConflict($text, $summary))->show(); } /** diff --git a/inc/lang/ja/lang.php b/inc/lang/ja/lang.php index 7882a8967..801543558 100644 --- a/inc/lang/ja/lang.php +++ b/inc/lang/ja/lang.php @@ -199,7 +199,7 @@ $lang['current'] = '現在'; $lang['yours'] = 'あなたのバージョン'; $lang['diff'] = '現在のリビジョンとの差分を表示'; $lang['diff2'] = '選択したリビジョン間の差分を表示'; -$lang['difflink'] = 'この比較画面にリンクする'; +$lang['difflink'] = 'この比較画面へのリンク'; $lang['diff_type'] = '差分の表示方法:'; $lang['diff_inline'] = 'インライン'; $lang['diff_side'] = '横に並べる'; diff --git a/inc/media.php b/inc/media.php index 92e685b99..e0819d6d9 100644 --- a/inc/media.php +++ b/inc/media.php @@ -997,10 +997,10 @@ function media_tab_history($image, $ns, $auth=null) { if ($auth >= AUTH_READ && $image) { if ($do == 'diff'){ - media_diff($image, $ns, $auth); + (new dokuwiki\Ui\MediaDiff($image))->show(); //media_diff($image, $ns, $auth); } else { $first = $INPUT->int('first'); - html_revisions($first, $image); + (new dokuwiki\Ui\MediaRevisions($image))->show($first); } } else { echo '<div class="nothing">'.$lang['media_perm_read'].'</div>'.NL; @@ -1017,7 +1017,7 @@ function media_tab_history($image, $ns, $auth=null) { * * @author Kate Arzamastseva <pshns@ukr.net> */ -function media_preview($image, $auth, $rev='', $meta=false) { +function media_preview($image, $auth, $rev = '', $meta = false) { $size = media_image_preview_size($image, $rev, $meta); @@ -1041,7 +1041,7 @@ function media_preview($image, $auth, $rev='', $meta=false) { echo '<img src="'.$src.'" alt="" style="max-width: '.$size[0].'px;" />'; echo '</a>'; - echo '</div>'.NL; + echo '</div>'; } } @@ -1052,12 +1052,12 @@ function media_preview($image, $auth, $rev='', $meta=false) { * * @param string $image media id * @param int $auth permission level - * @param string|int $rev revision timestamp, or empty string + * @param int|string $rev revision timestamp, or empty string */ function media_preview_buttons($image, $auth, $rev = '') { global $lang, $conf; - echo '<ul class="actions">'.DOKU_LF; + echo '<ul class="actions">'; if ($auth >= AUTH_DELETE && !$rev && file_exists(mediaFN($image))) { @@ -1071,7 +1071,7 @@ function media_preview_buttons($image, $auth, $rev = '') { $form->addTagClose('div'); echo '<li>'; echo $form->toHTML(); - echo '</li>'.DOKU_LF; + echo '</li>'; } $auth_ow = (($conf['mediarevisions']) ? AUTH_UPLOAD : AUTH_DELETE); @@ -1087,7 +1087,7 @@ function media_preview_buttons($image, $auth, $rev = '') { $form->addTagClose('div'); echo '<li>'; echo $form->toHTML(); - echo '</li>'.DOKU_LF; + echo '</li>'; } if ($auth >= AUTH_UPLOAD && $rev && $conf['mediarevisions'] && file_exists(mediaFN($image, $rev))) { @@ -1104,10 +1104,10 @@ function media_preview_buttons($image, $auth, $rev = '') { $form->addTagClose('div'); echo '<li>'; echo $form->toHTML(); - echo '</li>'.DOKU_LF; + echo '</li>'; } - echo '</ul>'.DOKU_LF; + echo '</ul>'; } /** @@ -1118,16 +1118,18 @@ function media_preview_buttons($image, $auth, $rev = '') { * @param int|string $rev * @param JpegMeta|bool $meta * @param int $size - * @return array|false + * @return array */ -function media_image_preview_size($image, $rev, $meta, $size = 500) { - if (!preg_match("/\.(jpe?g|gif|png)$/", $image) || !file_exists(mediaFN($image, $rev))) return false; +function media_image_preview_size($image, $rev, $meta = false, $size = 500) { + if (!preg_match("/\.(jpe?g|gif|png)$/", $image) + || !file_exists($filename = mediaFN($image, $rev)) + ) return array(); - $info = getimagesize(mediaFN($image, $rev)); + $info = getimagesize($filename); $w = (int) $info[0]; $h = (int) $info[1]; - if($meta && ($w > $size || $h > $size)){ + if ($meta && ($w > $size || $h > $size)) { $ratio = $meta->getResizeRatio($size, $size); $w = floor($w * $ratio); $h = floor($h * $ratio); @@ -1145,10 +1147,10 @@ function media_image_preview_size($image, $rev, $meta, $size = 500) { * @param string $alt alternative value * @return string */ -function media_getTag($tags,$meta,$alt=''){ - if($meta === false) return $alt; +function media_getTag($tags, $meta = false, $alt = '') { + if (!$meta) return $alt; $info = $meta->getField($tags); - if($info == false) return $alt; + if (!$info) return $alt; return $info; } @@ -1163,19 +1165,19 @@ function media_getTag($tags,$meta,$alt=''){ function media_file_tags($meta) { // load the field descriptions static $fields = null; - if(is_null($fields)){ + if (is_null($fields)) { $config_files = getConfigFiles('mediameta'); foreach ($config_files as $config_file) { - if(file_exists($config_file)) include($config_file); + if (file_exists($config_file)) include($config_file); } } $tags = array(); - foreach($fields as $key => $tag){ + foreach ($fields as $key => $tag) { $t = array(); if (!empty($tag[0])) $t = array($tag[0]); - if(isset($tag[3]) && is_array($tag[3])) $t = array_merge($t,$tag[3]); + if (isset($tag[3]) && is_array($tag[3])) $t = array_merge($t,$tag[3]); $value = media_getTag($t, $meta); $tags[] = array('tag' => $tag, 'value' => $value); } @@ -1234,65 +1236,10 @@ function media_details($image, $auth, $rev='', $meta=false) { * @param int $auth permission level * @param bool $fromajax * @return false|null|string + * @deprecated 2020-12-31 */ function media_diff($image, $ns, $auth, $fromajax = false) { - global $conf; - global $INPUT; - - if ($auth < AUTH_READ || !$image || !$conf['mediarevisions']) return ''; - - $rev1 = $INPUT->int('rev'); - - $rev2 = $INPUT->ref('rev2'); - if(is_array($rev2)){ - $rev1 = (int) $rev2[0]; - $rev2 = (int) $rev2[1]; - - if(!$rev1){ - $rev1 = $rev2; - unset($rev2); - } - }else{ - $rev2 = $INPUT->int('rev2'); - } - - if ($rev1 && !file_exists(mediaFN($image, $rev1))) $rev1 = false; - if ($rev2 && !file_exists(mediaFN($image, $rev2))) $rev2 = false; - - if($rev1 && $rev2){ // two specific revisions wanted - // make sure order is correct (older on the left) - if($rev1 < $rev2){ - $l_rev = $rev1; - $r_rev = $rev2; - }else{ - $l_rev = $rev2; - $r_rev = $rev1; - } - }elseif($rev1){ // single revision given, compare to current - $r_rev = ''; - $l_rev = $rev1; - }else{ // no revision was given, compare previous to current - $r_rev = ''; - $medialog = new MediaChangeLog($image); - $revs = $medialog->getRevisions(0, 1); - if (file_exists(mediaFN($image, $revs[0]))) { - $l_rev = $revs[0]; - } else { - $l_rev = ''; - } - } - - // prepare event data - $data = array(); - $data[0] = $image; - $data[1] = $l_rev; - $data[2] = $r_rev; - $data[3] = $ns; - $data[4] = $auth; - $data[5] = $fromajax; - - // trigger event - return Event::createAndTrigger('MEDIA_DIFF', $data, '_media_file_diff', true); + dbg_deprecated('see '. \dokuwiki\Ui\MediaDiff::class .'::show()'); } /** @@ -1300,13 +1247,10 @@ function media_diff($image, $ns, $auth, $fromajax = false) { * * @param array $data event data * @return false|null + * @deprecated 2020-12-31 */ function _media_file_diff($data) { - if(is_array($data) && count($data)===6) { - media_file_diff($data[0], $data[1], $data[2], $data[3], $data[4], $data[5]); - } else { - return false; - } + dbg_deprecated('see '. \dokuwiki\Ui\MediaDiff::class .'::show()'); } /** @@ -1320,120 +1264,10 @@ function _media_file_diff($data) { * @param string $ns * @param int $auth permission level * @param bool $fromajax + * @deprecated 2020-12-31 */ function media_file_diff($image, $l_rev, $r_rev, $ns, $auth, $fromajax) { - global $lang; - global $INPUT; - - $l_meta = new JpegMeta(mediaFN($image, $l_rev)); - $r_meta = new JpegMeta(mediaFN($image, $r_rev)); - - $is_img = preg_match('/\.(jpe?g|gif|png)$/', $image); - if ($is_img) { - $l_size = media_image_preview_size($image, $l_rev, $l_meta); - $r_size = media_image_preview_size($image, $r_rev, $r_meta); - $is_img = ($l_size && $r_size && ($l_size[0] >= 30 || $r_size[0] >= 30)); - - $difftype = $INPUT->str('difftype'); - - if (!$fromajax) { - $form = new Form([ - 'id' => 'mediamanager__form_diffview', - 'action' => media_managerURL([], '&'), - 'method' => 'get', - 'class' => 'diffView', - ]); - $form->addTagOpen('div')->addClass('no'); - $form->setHiddenField('sectok', null); - $form->setHiddenField('mediado', 'diff'); - $form->setHiddenField('rev2[0]', $l_rev); - $form->setHiddenField('rev2[1]', $r_rev); - echo $form->toHTML(); - - echo NL.'<div id="mediamanager__diff" >'.NL; - } - - if ($difftype == 'opacity' || $difftype == 'portions') { - media_image_diff($image, $l_rev, $r_rev, $l_size, $r_size, $difftype); - if (!$fromajax) echo '</div>'; - return; - } - } - - list($l_head, $r_head) = (new dokuwiki\Ui\Diff)->diffHead($l_rev, $r_rev, $image, true); - - ?> - <div class="table"> - <table> - <tr> - <th><?php echo $l_head; ?></th> - <th><?php echo $r_head; ?></th> - </tr> - <?php - - echo '<tr class="image">'; - echo '<td>'; - media_preview($image, $auth, $l_rev, $l_meta); - echo '</td>'; - - echo '<td>'; - media_preview($image, $auth, $r_rev, $r_meta); - echo '</td>'; - echo '</tr>'.NL; - - echo '<tr class="actions">'; - echo '<td>'; - media_preview_buttons($image, $auth, $l_rev); - echo '</td>'; - - echo '<td>'; - media_preview_buttons($image, $auth, $r_rev); - echo '</td>'; - echo '</tr>'.NL; - - $l_tags = media_file_tags($l_meta); - $r_tags = media_file_tags($r_meta); - // FIXME r_tags-only stuff - foreach ($l_tags as $key => $l_tag) { - if ($l_tag['value'] != $r_tags[$key]['value']) { - $r_tags[$key]['highlighted'] = true; - $l_tags[$key]['highlighted'] = true; - } else if (!$l_tag['value'] || !$r_tags[$key]['value']) { - unset($r_tags[$key]); - unset($l_tags[$key]); - } - } - - echo '<tr>'; - foreach(array($l_tags,$r_tags) as $tags){ - echo '<td>'.NL; - - echo '<dl class="img_tags">'; - foreach($tags as $tag){ - $value = cleanText($tag['value']); - if (!$value) $value = '-'; - echo '<dt>'.$lang[$tag['tag'][1]].'</dt>'; - echo '<dd>'; - if ($tag['highlighted']) { - echo '<strong>'; - } - if ($tag['tag'][2] == 'date') echo dformat($value); - else echo hsc($value); - if ($tag['highlighted']) { - echo '</strong>'; - } - echo '</dd>'; - } - echo '</dl>'.NL; - - echo '</td>'; - } - echo '</tr>'.NL; - - echo '</table>'.NL; - echo '</div>'.NL; - - if ($is_img && !$fromajax) echo '</div>'; + dbg_deprecated('see '. \dokuwiki\Ui\MediaDiff::class .'::showFileDiff()'); } /** @@ -1448,32 +1282,10 @@ function media_file_diff($image, $l_rev, $r_rev, $ns, $auth, $fromajax) { * @param array $l_size array with width and height * @param array $r_size array with width and height * @param string $type + * @deprecated 2020-12-31 */ function media_image_diff($image, $l_rev, $r_rev, $l_size, $r_size, $type) { - if ($l_size != $r_size) { - if ($r_size[0] > $l_size[0]) { - $l_size = $r_size; - } - } - - $l_more = array('rev' => $l_rev, 'h' => $l_size[1], 'w' => $l_size[0]); - $r_more = array('rev' => $r_rev, 'h' => $l_size[1], 'w' => $l_size[0]); - - $l_src = ml($image, $l_more); - $r_src = ml($image, $r_more); - - // slider - echo '<div class="slider" style="max-width: '.($l_size[0]-20).'px;" ></div>'.NL; - - // two images in divs - echo '<div class="imageDiff ' . $type . '">'.NL; - echo '<div class="image1" style="max-width: '.$l_size[0].'px;">'; - echo '<img src="'.$l_src.'" alt="" />'; - echo '</div>'.NL; - echo '<div class="image2" style="max-width: '.$l_size[0].'px;">'; - echo '<img src="'.$r_src.'" alt="" />'; - echo '</div>'.NL; - echo '</div>'.NL; + dbg_deprecated('see '. \dokuwiki\Ui\MediaDiff::class .'::showImageDiff()'); } /** |