Recent.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <?php
  2. namespace dokuwiki\Ui;
  3. use dokuwiki\ChangeLog\PageChangeLog;
  4. use dokuwiki\ChangeLog\MediaChangeLog;
  5. use dokuwiki\ChangeLog\RevisionInfo;
  6. use dokuwiki\Form\Form;
  7. /**
  8. * DokuWiki Recent Interface
  9. *
  10. * @package dokuwiki\Ui
  11. */
  12. class Recent extends Ui
  13. {
  14. protected $first;
  15. protected $show_changes;
  16. /**
  17. * Recent Ui constructor
  18. *
  19. * @param int $first skip the first n changelog lines
  20. * @param string $show_changes type of changes to show; 'pages', 'mediafiles', or 'both'
  21. */
  22. public function __construct($first = 0, $show_changes = 'both')
  23. {
  24. $this->first = $first;
  25. $this->show_changes = $show_changes;
  26. }
  27. /**
  28. * Display recent changes
  29. *
  30. * @author Andreas Gohr <andi@splitbrain.org>
  31. * @author Matthias Grimm <matthiasgrimm@users.sourceforge.net>
  32. * @author Ben Coburn <btcoburn@silicodon.net>
  33. * @author Kate Arzamastseva <pshns@ukr.net>
  34. * @author Satoshi Sahara <sahara.satoshi@gmail.com>
  35. *
  36. * @return void
  37. */
  38. public function show()
  39. {
  40. global $conf, $lang;
  41. global $ID;
  42. // get recent items, and set correct pagination parameters (first, hasNext)
  43. $first = $this->first;
  44. $hasNext = false;
  45. $recents = $this->getRecents($first, $hasNext);
  46. // print intro
  47. print p_locale_xhtml('recent');
  48. if (getNS($ID) != '') {
  49. print '<div class="level1"><p>'
  50. . sprintf($lang['recent_global'], getNS($ID), wl('', 'do=recent'))
  51. .'</p></div>';
  52. }
  53. // create the form
  54. $form = new Form(['id'=>'dw__recent', 'method'=>'GET', 'action'=> wl($ID), 'class'=>'changes']);
  55. $form->addTagOpen('div')->addClass('no');
  56. $form->setHiddenField('sectok', null);
  57. $form->setHiddenField('do', 'recent');
  58. $form->setHiddenField('id', $ID);
  59. // show dropdown selector, whether include not only recent pages but also recent media files?
  60. if ($conf['mediarevisions']) {
  61. $this->addRecentItemSelector($form);
  62. }
  63. // start listing of recent items
  64. $form->addTagOpen('ul');
  65. foreach ($recents as $recent) {
  66. // check possible external edition for current page or media
  67. $this->checkCurrentRevision($recent);
  68. $RevInfo = new RevisionInfo($recent);
  69. $RevInfo->isCurrent(true);
  70. $class = ($RevInfo->val('type') === DOKU_CHANGE_TYPE_MINOR_EDIT) ? 'minor': '';
  71. $form->addTagOpen('li')->addClass($class);
  72. $form->addTagOpen('div')->addClass('li');
  73. $html = implode(' ', [
  74. $RevInfo->showFileIcon(), // filetype icon
  75. $RevInfo->showEditDate(), // edit date and time
  76. $RevInfo->showIconCompareWithPrevious(), // link to diff view icon
  77. $RevInfo->showIconRevisions(), // link to revisions icon
  78. $RevInfo->showFileName(), // name of page or media
  79. $RevInfo->showEditSummary(), // edit summary
  80. $RevInfo->showEditor(), // editor info
  81. $RevInfo->showSizechange(), // size change indicator
  82. ]);
  83. $form->addHTML($html);
  84. $form->addTagClose('div');
  85. $form->addTagClose('li');
  86. }
  87. $form->addTagClose('ul');
  88. $form->addTagClose('div'); // close div class=no
  89. // provide navigation for paginated recent list (of pages and/or media files)
  90. $form->addHTML($this->htmlNavigation($first, $hasNext));
  91. print $form->toHTML('Recent');
  92. }
  93. /**
  94. * Get recent items, and set correct pagination parameters (first, hasNext)
  95. *
  96. * @param int $first
  97. * @param bool $hasNext
  98. * @return array recent items to be shown in a paginated list
  99. *
  100. * @see also dokuwiki\Changelog::getRevisionInfo()
  101. */
  102. protected function getRecents(&$first, &$hasNext)
  103. {
  104. global $ID, $conf;
  105. $flags = 0;
  106. if ($this->show_changes == 'mediafiles' && $conf['mediarevisions']) {
  107. $flags = RECENTS_MEDIA_CHANGES;
  108. } elseif ($this->show_changes == 'pages') {
  109. $flags = 0;
  110. } elseif ($conf['mediarevisions']) {
  111. $flags = RECENTS_MEDIA_PAGES_MIXED;
  112. }
  113. /* we need to get one additionally log entry to be able to
  114. * decide if this is the last page or is there another one.
  115. * This is the cheapest solution to get this information.
  116. */
  117. $recents = getRecents($first, $conf['recent'] + 1, getNS($ID), $flags);
  118. if (count($recents) == 0 && $first != 0) {
  119. $first = 0;
  120. $recents = getRecents($first, $conf['recent'] + 1, getNS($ID), $flags);
  121. }
  122. $hasNext = false;
  123. if (count($recents) > $conf['recent']) {
  124. $hasNext = true;
  125. array_pop($recents); // remove extra log entry
  126. }
  127. return $recents;
  128. }
  129. /**
  130. * Check possible external deletion for current page or media
  131. *
  132. * To keep sort order in the recent list, we ignore externally modification.
  133. * It is not possible to know when external deletion had happened,
  134. * $info['date'] is to be incremented 1 second when such deletion detected.
  135. */
  136. protected function checkCurrentRevision(array &$info)
  137. {
  138. $itemType = $info['media'] ? 'media' : 'page';
  139. if ($itemType == 'page') {
  140. $changelog = new PageChangelog($info['id']);
  141. } else {
  142. $changelog = new MediaChangelog($info['id']);
  143. }
  144. if (!$changelog->isCurrentRevision($info['date'])) {
  145. $currentRevInfo = $changelog->getCurrentRevisionInfo();
  146. if ($currentRevInfo['type'] == DOKU_CHANGE_TYPE_DELETE) {
  147. // the page or media file was externally deleted, updated info because the link is already red
  148. // externally created and edited not updated because sorting by date is not worth so much changes
  149. $info = array_merge($info, $currentRevInfo);
  150. }
  151. }
  152. unset($changelog);
  153. }
  154. /**
  155. * Navigation buttons for Pagination (prev/next)
  156. *
  157. * @param int $first
  158. * @param bool $hasNext
  159. * @return string html
  160. */
  161. protected function htmlNavigation($first, $hasNext)
  162. {
  163. global $conf, $lang;
  164. $last = $first + $conf['recent'];
  165. $html = '<div class="pagenav">';
  166. if ($first > 0) {
  167. $first = max($first - $conf['recent'], 0);
  168. $html.= '<div class="pagenav-prev">';
  169. $html.= '<button type="submit" name="first['.$first.']" accesskey="n"'
  170. . ' title="'.$lang['btn_newer'].' [N]" class="button show">'
  171. . $lang['btn_newer']
  172. . '</button>';
  173. $html.= '</div>';
  174. }
  175. if ($hasNext) {
  176. $html.= '<div class="pagenav-next">';
  177. $html.= '<button type="submit" name="first['.$last.']" accesskey="p"'
  178. . ' title="'.$lang['btn_older'].' [P]" class="button show">'
  179. . $lang['btn_older']
  180. . '</button>';
  181. $html.= '</div>';
  182. }
  183. $html.= '</div>';
  184. return $html;
  185. }
  186. /**
  187. * Add dropdown selector of item types to the form instance
  188. *
  189. * @param Form $form
  190. * @return void
  191. */
  192. protected function addRecentItemSelector(Form $form)
  193. {
  194. global $lang;
  195. $form->addTagOpen('div')->addClass('changeType');
  196. $options = array(
  197. 'pages' => $lang['pages_changes'],
  198. 'mediafiles' => $lang['media_changes'],
  199. 'both' => $lang['both_changes'],
  200. );
  201. $form->addDropdown('show_changes', $options, $lang['changes_type'])
  202. ->val($this->show_changes)->addClass('quickselect');
  203. $form->addButton('do[recent]', $lang['btn_apply'])->attr('type','submit');
  204. $form->addTagClose('div');
  205. }
  206. }