[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/ChangeLog/ -> RevisionInfo.php (source)

   1  <?php
   2  
   3  namespace dokuwiki\ChangeLog;
   4  
   5  /**
   6   * Class RevisionInfo
   7   *
   8   * Provides methods to show Revision Information in DokuWiki Ui components:
   9   *  - Ui\Recent
  10   *  - Ui\PageRevisions
  11   *  - Ui\MediaRevisions
  12   *  - Ui\PageDiff
  13   *  - Ui\MediaDiff
  14   */
  15  class RevisionInfo
  16  {
  17      public const MODE_PAGE = 'page';
  18      public const MODE_MEDIA = 'media';
  19  
  20      /* @var array */
  21      protected $info;
  22  
  23      /**
  24       * Constructor
  25       *
  26       * @param array $info Revision Information structure with entries:
  27       *      - date:  unix timestamp
  28       *      - ip:    IPv4 or IPv6 address
  29       *      - type:  change type (log line type)
  30       *      - id:    page id
  31       *      - user:  user name
  32       *      - sum:   edit summary (or action reason)
  33       *      - extra: extra data (varies by line type)
  34       *      - sizechange: change of filesize
  35       *      additionally,
  36       *      - current:   (optional) whether current revision or not
  37       *      - timestamp: (optional) set only when external edits occurred
  38       *      - mode:  (internal use) ether "media" or "page"
  39       */
  40      public function __construct($info = null)
  41      {
  42          if (!is_array($info) || !isset($info['id'])) {
  43              $info = [
  44                  'mode' => self::MODE_PAGE,
  45                  'date' => false,
  46              ];
  47          }
  48          $this->info = $info;
  49      }
  50  
  51      /**
  52       * Set or return whether this revision is current page or media file
  53       *
  54       * This method does not check exactly whether the revision is current or not. Instead,
  55       * set value of associated "current" key for internal use. Some UI element like diff
  56       * link button depend on relation to current page or media file. A changelog line does
  57       * not indicate whether it corresponds to current page or media file.
  58       *
  59       * @param bool $value true if the revision is current, otherwise false
  60       * @return bool
  61       */
  62      public function isCurrent($value = null)
  63      {
  64          return (bool) $this->val('current', $value);
  65      }
  66  
  67      /**
  68       * Return or set a value of associated key of revision information
  69       * but does not allow to change values of existing keys
  70       *
  71       * @param string $key
  72       * @param mixed $value
  73       * @return string|null
  74       */
  75      public function val($key, $value = null)
  76      {
  77          if (isset($value) && !array_key_exists($key, $this->info)) {
  78              // setter, only for new keys
  79              $this->info[$key] = $value;
  80          }
  81          if (array_key_exists($key, $this->info)) {
  82              // getter
  83              return $this->info[$key];
  84          }
  85          return null;
  86      }
  87  
  88      /**
  89       * Set extra key-value to the revision information
  90       * but does not allow to change values of existing keys
  91       * @param array $info
  92       * @return void
  93       */
  94      public function append(array $info)
  95      {
  96          foreach ($info as $key => $value) {
  97              $this->val($key, $value);
  98          }
  99      }
 100  
 101  
 102      /**
 103       * file icon of the page or media file
 104       * used in [Ui\recent]
 105       *
 106       * @return string
 107       */
 108      public function showFileIcon()
 109      {
 110          $id = $this->val('id');
 111          if ($this->val('mode') == self::MODE_MEDIA) {
 112              // media file revision
 113              return media_printicon($id);
 114          } elseif ($this->val('mode') == self::MODE_PAGE) {
 115              // page revision
 116              return '<img class="icon" src="' . DOKU_BASE . 'lib/images/fileicons/file.png" alt="' . $id . '" />';
 117          }
 118      }
 119  
 120      /**
 121       * edit date and time of the page or media file
 122       * used in [Ui\recent, Ui\Revisions]
 123       *
 124       * @param bool $checkTimestamp  enable timestamp check, alter formatted string when timestamp is false
 125       * @return string
 126       */
 127      public function showEditDate($checkTimestamp = false)
 128      {
 129          $formatted = dformat($this->val('date'));
 130          if ($checkTimestamp && $this->val('timestamp') === false) {
 131              // exact date is unknown for externally deleted file
 132              // when unknown, alter formatted string "YYYY-mm-DD HH:MM" to "____-__-__ __:__"
 133              $formatted = preg_replace('/[0-9a-zA-Z]/', '_', $formatted);
 134          }
 135          return '<span class="date">' . $formatted . '</span>';
 136      }
 137  
 138      /**
 139       * edit summary
 140       * used in [Ui\recent, Ui\Revisions]
 141       *
 142       * @return string
 143       */
 144      public function showEditSummary()
 145      {
 146          return '<span class="sum">' . ' – ' . hsc($this->val('sum')) . '</span>';
 147      }
 148  
 149      /**
 150       * editor of the page or media file
 151       * used in [Ui\recent, Ui\Revisions]
 152       *
 153       * @return string
 154       */
 155      public function showEditor()
 156      {
 157          if ($this->val('user')) {
 158              $html = '<bdi>' . editorinfo($this->val('user')) . '</bdi>';
 159              if (auth_ismanager()) {
 160                  $html .= ' <bdo dir="ltr">(' . $this->val('ip') . ')</bdo>';
 161              }
 162          } else {
 163              $html = '<bdo dir="ltr">' . $this->val('ip') . '</bdo>';
 164          }
 165          return '<span class="user">' . $html . '</span>';
 166      }
 167  
 168      /**
 169       * name of the page or media file
 170       * used in [Ui\recent, Ui\Revisions]
 171       *
 172       * @return string
 173       */
 174      public function showFileName()
 175      {
 176          $id = $this->val('id');
 177          $rev = $this->isCurrent() ? '' : $this->val('date');
 178  
 179          if ($this->val('mode') == self::MODE_MEDIA) {
 180              // media file revision
 181              $params = ['tab_details' => 'view', 'ns' => getNS($id), 'image' => $id];
 182              if ($rev) $params += ['rev' => $rev];
 183              $href = media_managerURL($params, '&');
 184              $display_name = $id;
 185              $exists = file_exists(mediaFN($id, $rev));
 186          } elseif ($this->val('mode') == self::MODE_PAGE) {
 187              // page revision
 188              $params = $rev ? ['rev' => $rev] : [];
 189              $href = wl($id, $params, false, '&');
 190              $display_name = useHeading('navigation') ? hsc(p_get_first_heading($id)) : $id;
 191              if (!$display_name) $display_name = $id;
 192              $exists = page_exists($id, $rev);
 193          }
 194  
 195          if ($exists) {
 196              $class = 'wikilink1';
 197          } elseif ($this->isCurrent()) {
 198              //show only not-existing link for current page, which allows for directly create a new page/upload
 199              $class = 'wikilink2';
 200          } else {
 201              //revision is not in attic
 202              return $display_name;
 203          }
 204          if ($this->val('type') == DOKU_CHANGE_TYPE_DELETE) {
 205              $class = 'wikilink2';
 206          }
 207          return '<a href="' . $href . '" class="' . $class . '">' . $display_name . '</a>';
 208      }
 209  
 210      /**
 211       * Revision Title for PageDiff table headline
 212       *
 213       * @return string
 214       */
 215      public function showRevisionTitle()
 216      {
 217          global $lang;
 218  
 219          if (!$this->val('date')) return '&mdash;';
 220  
 221          $id = $this->val('id');
 222          $rev = $this->isCurrent() ? '' : $this->val('date');
 223          $params = ($rev) ? ['rev' => $rev] : [];
 224  
 225          // revision info may have timestamp key when external edits occurred
 226          $date = ($this->val('timestamp') === false)
 227              ? $lang['unknowndate']
 228              : dformat($this->val('date'));
 229  
 230  
 231          if ($this->val('mode') == self::MODE_MEDIA) {
 232              // media file revision
 233              $href = ml($id, $params, false, '&');
 234              $exists = file_exists(mediaFN($id, $rev));
 235          } elseif ($this->val('mode') == self::MODE_PAGE) {
 236              // page revision
 237              $href = wl($id, $params, false, '&');
 238              $exists = page_exists($id, $rev);
 239          }
 240          if ($exists) {
 241              $class = 'wikilink1';
 242          } elseif ($this->isCurrent()) {
 243              //show only not-existing link for current page, which allows for directly create a new page/upload
 244              $class = 'wikilink2';
 245          } else {
 246              //revision is not in attic
 247              return $id . ' [' . $date . ']';
 248          }
 249          if ($this->val('type') == DOKU_CHANGE_TYPE_DELETE) {
 250              $class = 'wikilink2';
 251          }
 252          return '<bdi><a class="' . $class . '" href="' . $href . '">' . $id . ' [' . $date . ']' . '</a></bdi>';
 253      }
 254  
 255      /**
 256       * diff link icon in recent changes list, to compare (this) current revision with previous one
 257       * all items in "recent changes" are current revision of the page or media
 258       *
 259       * @return string
 260       */
 261      public function showIconCompareWithPrevious()
 262      {
 263          global $lang;
 264          $id = $this->val('id');
 265  
 266          $href = '';
 267          if ($this->val('mode') == self::MODE_MEDIA) {
 268              // media file revision
 269              // unlike page, media file does not copied to media_attic when uploaded.
 270              // diff icon will not be shown when external edit occurred
 271              // because no attic file to be compared with current.
 272              $revs = (new MediaChangeLog($id))->getRevisions(0, 1);
 273              $showLink = (count($revs) && file_exists(mediaFN($id, $revs[0])) && file_exists(mediaFN($id)));
 274              if ($showLink) {
 275                  $param = ['tab_details' => 'history', 'mediado' => 'diff', 'ns' => getNS($id), 'image' => $id];
 276                  $href = media_managerURL($param, '&');
 277              }
 278          } elseif ($this->val('mode') == self::MODE_PAGE) {
 279              // page revision
 280              // when a page just created anyway, it is natural to expect no older revisions
 281              // even if it had once existed but deleted before. Simply ignore to check changelog.
 282              if ($this->val('type') !== DOKU_CHANGE_TYPE_CREATE) {
 283                  $href = wl($id, ['do' => 'diff'], false, '&');
 284              }
 285          }
 286  
 287          if ($href) {
 288              return '<a href="' . $href . '" class="diff_link">'
 289                    . '<img src="' . DOKU_BASE . 'lib/images/diff.png" width="15" height="11"'
 290                    . ' title="' . $lang['diff'] . '" alt="' . $lang['diff'] . '" />'
 291                    . '</a>';
 292          } else {
 293              return '<img src="' . DOKU_BASE . 'lib/images/blank.gif" width="15" height="11" alt="" />';
 294          }
 295      }
 296  
 297      /**
 298       * diff link icon in revisions list, compare this revision with current one
 299       * the icon does not displayed for the current revision
 300       *
 301       * @return string
 302       */
 303      public function showIconCompareWithCurrent()
 304      {
 305          global $lang;
 306          $id = $this->val('id');
 307          $rev = $this->isCurrent() ? '' : $this->val('date');
 308  
 309          $href = '';
 310          if ($this->val('mode') == self::MODE_MEDIA) {
 311              // media file revision
 312              if (!$this->isCurrent() && file_exists(mediaFN($id, $rev))) {
 313                  $param = ['mediado' => 'diff', 'image' => $id, 'rev' => $rev];
 314                  $href = media_managerURL($param, '&');
 315              }
 316          } elseif ($this->val('mode') == self::MODE_PAGE) {
 317              // page revision
 318              if (!$this->isCurrent()) {
 319                  $href = wl($id, ['rev' => $rev, 'do' => 'diff'], false, '&');
 320              }
 321          }
 322  
 323          if ($href) {
 324              return '<a href="' . $href . '" class="diff_link">'
 325                    . '<img src="' . DOKU_BASE . 'lib/images/diff.png" width="15" height="11"'
 326                    . ' title="' . $lang['diff'] . '" alt="' . $lang['diff'] . '" />'
 327                    . '</a>';
 328          } else {
 329              return '<img src="' . DOKU_BASE . 'lib/images/blank.gif" width="15" height="11" alt="" />';
 330          }
 331      }
 332  
 333      /**
 334       * icon for revision action
 335       * used in [Ui\recent]
 336       *
 337       * @return string
 338       */
 339      public function showIconRevisions()
 340      {
 341          global $lang;
 342  
 343          if (!actionOK('revisions')) {
 344              return '';
 345          }
 346  
 347          $id = $this->val('id');
 348          if ($this->val('mode') == self::MODE_MEDIA) {
 349              // media file revision
 350              $param  = ['tab_details' => 'history', 'ns' => getNS($id), 'image' => $id];
 351              $href = media_managerURL($param, '&');
 352          } elseif ($this->val('mode') == self::MODE_PAGE) {
 353              // page revision
 354              $href = wl($id, ['do' => 'revisions'], false, '&');
 355          }
 356          return '<a href="' . $href . '" class="revisions_link">'
 357                . '<img src="' . DOKU_BASE . 'lib/images/history.png" width="12" height="14"'
 358                . ' title="' . $lang['btn_revs'] . '" alt="' . $lang['btn_revs'] . '" />'
 359                . '</a>';
 360      }
 361  
 362      /**
 363       * size change
 364       * used in [Ui\recent, Ui\Revisions]
 365       *
 366       * @return string
 367       */
 368      public function showSizeChange()
 369      {
 370          $class = 'sizechange';
 371          $value = filesize_h(abs($this->val('sizechange')));
 372          if ($this->val('sizechange') > 0) {
 373              $class .= ' positive';
 374              $value = '+' . $value;
 375          } elseif ($this->val('sizechange') < 0) {
 376              $class .= ' negative';
 377              $value = '-' . $value;
 378          } else {
 379              $value = '±' . $value;
 380          }
 381          return '<span class="' . $class . '">' . $value . '</span>';
 382      }
 383  
 384      /**
 385       * current indicator, used in revision list
 386       * not used in Ui\Recent because recent files are always current one
 387       *
 388       * @return string
 389       */
 390      public function showCurrentIndicator()
 391      {
 392          global $lang;
 393          return $this->isCurrent() ? '(' . $lang['current'] . ')' : '';
 394      }
 395  }