[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/lib/plugins/extension/helper/ -> list.php (source)

   1  <?php
   2  
   3  use dokuwiki\Extension\Plugin;
   4  
   5  /**
   6   * DokuWiki Plugin extension (Helper Component)
   7   *
   8   * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
   9   * @author  Michael Hamann <michael@content-space.de>
  10   */
  11  /**
  12   * Class helper_plugin_extension_list takes care of creating a HTML list of extensions
  13   */
  14  class helper_plugin_extension_list extends Plugin
  15  {
  16      protected $form = '';
  17      /** @var  helper_plugin_extension_gui */
  18      protected $gui;
  19  
  20      /**
  21       * Constructor
  22       *
  23       * loads additional helpers
  24       */
  25      public function __construct()
  26      {
  27          $this->gui = plugin_load('helper', 'extension_gui');
  28      }
  29  
  30      /**
  31       * Initialize the extension table form
  32       */
  33      public function startForm()
  34      {
  35          $this->form .= '<ul class="extensionList">';
  36      }
  37  
  38      /**
  39       * Build single row of extension table
  40       *
  41       * @param helper_plugin_extension_extension  $extension The extension that shall be added
  42       * @param bool                               $showinfo  Show the info area
  43       */
  44      public function addRow(helper_plugin_extension_extension $extension, $showinfo = false)
  45      {
  46          $this->startRow($extension);
  47          $this->populateColumn('legend', $this->makeLegend($extension, $showinfo));
  48          $this->populateColumn('actions', $this->makeActions($extension));
  49          $this->endRow();
  50      }
  51  
  52      /**
  53       * Adds a header to the form
  54       *
  55       * @param string $id     The id of the header
  56       * @param string $header The content of the header
  57       * @param int    $level  The level of the header
  58       */
  59      public function addHeader($id, $header, $level = 2)
  60      {
  61          $this->form .= '<h' . $level . ' id="' . $id . '">' . hsc($header) . '</h' . $level . '>' . DOKU_LF;
  62      }
  63  
  64      /**
  65       * Adds a paragraph to the form
  66       *
  67       * @param string $data The content
  68       */
  69      public function addParagraph($data)
  70      {
  71          $this->form .= '<p>' . hsc($data) . '</p>' . DOKU_LF;
  72      }
  73  
  74      /**
  75       * Add hidden fields to the form with the given data
  76       *
  77       * @param array $data key-value list of fields and their values to add
  78       */
  79      public function addHidden(array $data)
  80      {
  81          $this->form .= '<div class="no">';
  82          foreach ($data as $key => $value) {
  83              $this->form .= '<input type="hidden" name="' . hsc($key) . '" value="' . hsc($value) . '" />';
  84          }
  85          $this->form .= '</div>' . DOKU_LF;
  86      }
  87  
  88      /**
  89       * Add closing tags
  90       */
  91      public function endForm()
  92      {
  93          $this->form .= '</ul>';
  94      }
  95  
  96      /**
  97       * Show message when no results are found
  98       */
  99      public function nothingFound()
 100      {
 101          global $lang;
 102          $this->form .= '<li class="notfound">' . $lang['nothingfound'] . '</li>';
 103      }
 104  
 105      /**
 106       * Print the form
 107       *
 108       * @param bool $returnonly whether to return html or print
 109       */
 110      public function render($returnonly = false)
 111      {
 112          if ($returnonly) return $this->form;
 113          echo $this->form;
 114      }
 115  
 116      /**
 117       * Start the HTML for the row for the extension
 118       *
 119       * @param helper_plugin_extension_extension $extension The extension
 120       */
 121      private function startRow(helper_plugin_extension_extension $extension)
 122      {
 123          $this->form .= '<li id="extensionplugin__' . hsc($extension->getID()) .
 124              '" class="' . $this->makeClass($extension) . '">';
 125      }
 126  
 127      /**
 128       * Add a column with the given class and content
 129       * @param string $class The class name
 130       * @param string $html  The content
 131       */
 132      private function populateColumn($class, $html)
 133      {
 134          $this->form .= '<div class="' . $class . ' col">' . $html . '</div>' . DOKU_LF;
 135      }
 136  
 137      /**
 138       * End the row
 139       */
 140      private function endRow()
 141      {
 142          $this->form .= '</li>' . DOKU_LF;
 143      }
 144  
 145      /**
 146       * Generate the link to the plugin homepage
 147       *
 148       * @param helper_plugin_extension_extension $extension The extension
 149       * @return string The HTML code
 150       */
 151      public function makeHomepageLink(helper_plugin_extension_extension $extension)
 152      {
 153          global $conf;
 154          $url = $extension->getURL();
 155          if (strtolower(parse_url($url, PHP_URL_HOST)) == 'www.dokuwiki.org') {
 156              $linktype = 'interwiki';
 157          } else {
 158              $linktype = 'extern';
 159          }
 160          $param = [
 161              'href'   => $url,
 162              'title'  => $url,
 163              'class'  => ($linktype == 'extern') ? 'urlextern' : 'interwiki iw_doku',
 164              'target' => $conf['target'][$linktype],
 165              'rel'    => ($linktype == 'extern') ? 'noopener' : ''
 166          ];
 167          if ($linktype == 'extern' && $conf['relnofollow']) {
 168              $param['rel'] = implode(' ', [$param['rel'], 'ugc nofollow']);
 169          }
 170          $html = ' <a ' . buildAttributes($param, true) . '>' .
 171              $this->getLang('homepage_link') . '</a>';
 172          return $html;
 173      }
 174  
 175      /**
 176       * Generate the class name for the row of the extension
 177       *
 178       * @param helper_plugin_extension_extension $extension The extension object
 179       * @return string The class name
 180       */
 181      public function makeClass(helper_plugin_extension_extension $extension)
 182      {
 183          $class = ($extension->isTemplate()) ? 'template' : 'plugin';
 184          if ($extension->isInstalled()) {
 185              $class .= ' installed';
 186              $class .= ($extension->isEnabled()) ? ' enabled' : ' disabled';
 187              if ($extension->updateAvailable()) $class .= ' updatable';
 188          }
 189          if (!$extension->canModify()) $class .= ' notselect';
 190          if ($extension->isProtected()) $class .=  ' protected';
 191          //if($this->showinfo) $class.= ' showinfo';
 192          return $class;
 193      }
 194  
 195      /**
 196       * Generate a link to the author of the extension
 197       *
 198       * @param helper_plugin_extension_extension $extension The extension object
 199       * @return string The HTML code of the link
 200       */
 201      public function makeAuthor(helper_plugin_extension_extension $extension)
 202      {
 203          if ($extension->getAuthor()) {
 204              $mailid = $extension->getEmailID();
 205              if ($mailid) {
 206                  $url = $this->gui->tabURL('search', ['q' => 'authorid:' . $mailid]);
 207                  $html = '<a href="' . $url . '" class="author" title="' . $this->getLang('author_hint') . '" >' .
 208                      '<img src="//www.gravatar.com/avatar/' . $mailid .
 209                      '?s=20&amp;d=mm" width="20" height="20" alt="" /> ' .
 210                      hsc($extension->getAuthor()) . '</a>';
 211              } else {
 212                  $html = '<span class="author">' . hsc($extension->getAuthor()) . '</span>';
 213              }
 214              $html = '<bdi>' . $html . '</bdi>';
 215          } else {
 216              $html = '<em class="author">' . $this->getLang('unknown_author') . '</em>' . DOKU_LF;
 217          }
 218          return $html;
 219      }
 220  
 221      /**
 222       * Get the link and image tag for the screenshot/thumbnail
 223       *
 224       * @param helper_plugin_extension_extension $extension The extension object
 225       * @return string The HTML code
 226       */
 227      public function makeScreenshot(helper_plugin_extension_extension $extension)
 228      {
 229          $screen = $extension->getScreenshotURL();
 230          $thumb = $extension->getThumbnailURL();
 231  
 232          if ($screen) {
 233              // use protocol independent URLs for images coming from us #595
 234              $screen = str_replace('http://www.dokuwiki.org', '//www.dokuwiki.org', $screen);
 235              $thumb = str_replace('http://www.dokuwiki.org', '//www.dokuwiki.org', $thumb);
 236  
 237              $title = sprintf($this->getLang('screenshot'), hsc($extension->getDisplayName()));
 238              $img = '<a href="' . hsc($screen) . '" target="_blank" class="extension_screenshot">' .
 239                  '<img alt="' . $title . '" width="120" height="70" src="' . hsc($thumb) . '" />' .
 240                  '</a>';
 241          } elseif ($extension->isTemplate()) {
 242              $img = '<img alt="" width="120" height="70" src="' . DOKU_BASE .
 243                  'lib/plugins/extension/images/template.png" />';
 244          } else {
 245              $img = '<img alt="" width="120" height="70" src="' . DOKU_BASE .
 246                  'lib/plugins/extension/images/plugin.png" />';
 247          }
 248          $html = '<div class="screenshot" >' . $img . '<span></span></div>' . DOKU_LF;
 249          return $html;
 250      }
 251  
 252      /**
 253       * Extension main description
 254       *
 255       * @param helper_plugin_extension_extension $extension The extension object
 256       * @param bool                              $showinfo  Show the info section
 257       * @return string The HTML code
 258       */
 259      public function makeLegend(helper_plugin_extension_extension $extension, $showinfo = false)
 260      {
 261          $html  = '<div>';
 262          $html .= '<h2>';
 263          $html .= sprintf(
 264              $this->getLang('extensionby'),
 265              '<bdi>' . hsc($extension->getDisplayName()) . '</bdi>',
 266              $this->makeAuthor($extension)
 267          );
 268          $html .= '</h2>' . DOKU_LF;
 269  
 270          $html .= $this->makeScreenshot($extension);
 271  
 272          $popularity = $extension->getPopularity();
 273          if ($popularity !== false && !$extension->isBundled()) {
 274              $popularityText = sprintf($this->getLang('popularity'), round($popularity * 100, 2));
 275              $html .= '<div class="popularity" title="' . $popularityText . '">' .
 276                  '<div style="width: ' . ($popularity * 100) . '%;">' .
 277                  '<span class="a11y">' . $popularityText . '</span>' .
 278                  '</div></div>' . DOKU_LF;
 279          }
 280  
 281          if ($extension->getDescription()) {
 282              $html .= '<p><bdi>';
 283              $html .=  hsc($extension->getDescription()) . ' ';
 284              $html .= '</bdi></p>' . DOKU_LF;
 285          }
 286  
 287          $html .= $this->makeLinkbar($extension);
 288  
 289          if ($showinfo) {
 290              $url = $this->gui->tabURL('');
 291              $class = 'close';
 292          } else {
 293              $url = $this->gui->tabURL('', ['info' => $extension->getID()]);
 294              $class = '';
 295          }
 296          $html .= ' <a href="' . $url . '#extensionplugin__' . $extension->getID() .
 297              '" class="info ' . $class . '" title="' . $this->getLang('btn_info') .
 298              '" data-extid="' . $extension->getID() . '">' . $this->getLang('btn_info') . '</a>';
 299  
 300          if ($showinfo) {
 301              $html .= $this->makeInfo($extension);
 302          }
 303          $html .= $this->makeNoticeArea($extension);
 304          $html .= '</div>' . DOKU_LF;
 305          return $html;
 306      }
 307  
 308      /**
 309       * Generate the link bar HTML code
 310       *
 311       * @param helper_plugin_extension_extension $extension The extension instance
 312       * @return string The HTML code
 313       */
 314      public function makeLinkbar(helper_plugin_extension_extension $extension)
 315      {
 316          global $conf;
 317          $html  = '<div class="linkbar">';
 318          $html .= $this->makeHomepageLink($extension);
 319  
 320          $bugtrackerURL = $extension->getBugtrackerURL();
 321          if ($bugtrackerURL) {
 322              if (strtolower(parse_url($bugtrackerURL, PHP_URL_HOST)) == 'www.dokuwiki.org') {
 323                  $linktype = 'interwiki';
 324              } else {
 325                  $linktype = 'extern';
 326              }
 327              $param = [
 328                  'href'   => $bugtrackerURL,
 329                  'title'  => $bugtrackerURL,
 330                  'class'  => 'bugs',
 331                  'target' => $conf['target'][$linktype],
 332                  'rel'    => ($linktype == 'extern') ? 'noopener' : ''
 333              ];
 334              if ($conf['relnofollow']) {
 335                  $param['rel'] = implode(' ', [$param['rel'], 'ugc nofollow']);
 336              }
 337              $html .= ' <a ' . buildAttributes($param, true) . '>' .
 338                    $this->getLang('bugs_features') . '</a>';
 339          }
 340          if ($extension->getTags()) {
 341              $first = true;
 342              $html .= ' <span class="tags">' . $this->getLang('tags') . ' ';
 343              foreach ($extension->getTags() as $tag) {
 344                  if (!$first) {
 345                      $html .= ', ';
 346                  } else {
 347                      $first = false;
 348                  }
 349                  $url = $this->gui->tabURL('search', ['q' => 'tag:' . $tag]);
 350                  $html .= '<bdi><a href="' . $url . '">' . hsc($tag) . '</a></bdi>';
 351              }
 352              $html .= '</span>';
 353          }
 354          $html .= '</div>' . DOKU_LF;
 355          return $html;
 356      }
 357  
 358      /**
 359       * Notice area
 360       *
 361       * @param helper_plugin_extension_extension $extension The extension
 362       * @return string The HTML code
 363       */
 364      public function makeNoticeArea(helper_plugin_extension_extension $extension)
 365      {
 366          $html = '';
 367          $missing_dependencies = $extension->getMissingDependencies();
 368          if (!empty($missing_dependencies)) {
 369              $html .= '<div class="msg error">' .
 370                  sprintf(
 371                      $this->getLang('missing_dependency'),
 372                      '<bdi>' . implode(', ', $missing_dependencies) . '</bdi>'
 373                  ) .
 374                  '</div>';
 375          }
 376          if ($extension->isInWrongFolder()) {
 377              $html .= '<div class="msg error">' .
 378                  sprintf(
 379                      $this->getLang('wrong_folder'),
 380                      '<bdi>' . hsc($extension->getInstallName()) . '</bdi>',
 381                      '<bdi>' . hsc($extension->getBase()) . '</bdi>'
 382                  ) .
 383                  '</div>';
 384          }
 385          if (($securityissue = $extension->getSecurityIssue()) !== false) {
 386              $html .= '<div class="msg error">' .
 387                  sprintf($this->getLang('security_issue'), '<bdi>' . hsc($securityissue) . '</bdi>') .
 388                  '</div>';
 389          }
 390          if (($securitywarning = $extension->getSecurityWarning()) !== false) {
 391              $html .= '<div class="msg notify">' .
 392                  sprintf($this->getLang('security_warning'), '<bdi>' . hsc($securitywarning) . '</bdi>') .
 393                  '</div>';
 394          }
 395          if (($updateMessage = $extension->getUpdateMessage()) !== false) {
 396              $html .=  '<div class="msg notify">' .
 397                  sprintf($this->getLang('update_message'), '<bdi>' . hsc($updateMessage) . '</bdi>') .
 398                  '</div>';
 399          }
 400          if ($extension->updateAvailable()) {
 401              $html .=  '<div class="msg notify">' .
 402                  sprintf($this->getLang('update_available'), hsc($extension->getLastUpdate())) .
 403                  '</div>';
 404          }
 405          if ($extension->hasDownloadURLChanged()) {
 406              $html .= '<div class="msg notify">' .
 407                  sprintf(
 408                      $this->getLang('url_change'),
 409                      '<bdi>' . hsc($extension->getDownloadURL()) . '</bdi>',
 410                      '<bdi>' . hsc($extension->getLastDownloadURL()) . '</bdi>'
 411                  ) .
 412                  '</div>';
 413          }
 414          return $html . DOKU_LF;
 415      }
 416  
 417      /**
 418       * Create a link from the given URL
 419       *
 420       * Shortens the URL for display
 421       *
 422       * @param string $url
 423       * @return string  HTML link
 424       */
 425      public function shortlink($url)
 426      {
 427          $link = parse_url($url);
 428  
 429          $base = $link['host'];
 430          if (!empty($link['port'])) $base .= $base . ':' . $link['port'];
 431          $long = $link['path'];
 432          if (!empty($link['query'])) $long .= $link['query'];
 433  
 434          $name = shorten($base, $long, 55);
 435  
 436          $html = '<a href="' . hsc($url) . '" class="urlextern">' . hsc($name) . '</a>';
 437          return $html;
 438      }
 439  
 440      /**
 441       * Plugin/template details
 442       *
 443       * @param helper_plugin_extension_extension $extension The extension
 444       * @return string The HTML code
 445       */
 446      public function makeInfo(helper_plugin_extension_extension $extension)
 447      {
 448          $default = $this->getLang('unknown');
 449          $html = '<dl class="details">';
 450  
 451          $html .= '<dt>' . $this->getLang('status') . '</dt>';
 452          $html .= '<dd>' . $this->makeStatus($extension) . '</dd>';
 453  
 454          if ($extension->getDonationURL()) {
 455              $html .= '<dt>' . $this->getLang('donate') . '</dt>';
 456              $html .= '<dd>';
 457              $html .= '<a href="' . $extension->getDonationURL() . '" class="donate">' .
 458                  $this->getLang('donate_action') . '</a>';
 459              $html .= '</dd>';
 460          }
 461  
 462          if (!$extension->isBundled()) {
 463              $html .= '<dt>' . $this->getLang('downloadurl') . '</dt>';
 464              $html .= '<dd><bdi>';
 465              $html .= ($extension->getDownloadURL()
 466                  ? $this->shortlink($extension->getDownloadURL())
 467                  : $default);
 468              $html .= '</bdi></dd>';
 469  
 470              $html .= '<dt>' . $this->getLang('repository') . '</dt>';
 471              $html .= '<dd><bdi>';
 472              $html .= ($extension->getSourcerepoURL()
 473                  ? $this->shortlink($extension->getSourcerepoURL())
 474                  : $default);
 475              $html .= '</bdi></dd>';
 476          }
 477  
 478          if ($extension->isInstalled()) {
 479              if ($extension->getInstalledVersion()) {
 480                  $html .= '<dt>' . $this->getLang('installed_version') . '</dt>';
 481                  $html .= '<dd>';
 482                  $html .= hsc($extension->getInstalledVersion());
 483                  $html .= '</dd>';
 484              }
 485              if (!$extension->isBundled()) {
 486                  $html .= '<dt>' . $this->getLang('install_date') . '</dt>';
 487                  $html .= '<dd>';
 488                  $html .= ($extension->getUpdateDate()
 489                      ? hsc($extension->getUpdateDate())
 490                      : $this->getLang('unknown'));
 491                  $html .= '</dd>';
 492              }
 493          }
 494          if (!$extension->isInstalled() || $extension->updateAvailable()) {
 495              $html .= '<dt>' . $this->getLang('available_version') . '</dt>';
 496              $html .= '<dd>';
 497              $html .= ($extension->getLastUpdate()
 498                  ? hsc($extension->getLastUpdate())
 499                  : $this->getLang('unknown'));
 500              $html .= '</dd>';
 501          }
 502  
 503          $html .= '<dt>' . $this->getLang('provides') . '</dt>';
 504          $html .= '<dd><bdi>';
 505          $html .= ($extension->getTypes()
 506              ? hsc(implode(', ', $extension->getTypes()))
 507              : $default);
 508          $html .= '</bdi></dd>';
 509  
 510          if (!$extension->isBundled() && $extension->getCompatibleVersions()) {
 511              $html .= '<dt>' . $this->getLang('compatible') . '</dt>';
 512              $html .= '<dd>';
 513              foreach ($extension->getCompatibleVersions() as $date => $version) {
 514                  $html .= '<bdi>' . $version['label'] . ' (' . $date . ')</bdi>, ';
 515              }
 516              $html = rtrim($html, ', ');
 517              $html .= '</dd>';
 518          }
 519          if ($extension->getDependencies()) {
 520              $html .= '<dt>' . $this->getLang('depends') . '</dt>';
 521              $html .= '<dd>';
 522              $html .= $this->makeLinkList($extension->getDependencies());
 523              $html .= '</dd>';
 524          }
 525  
 526          if ($extension->getSimilarExtensions()) {
 527              $html .= '<dt>' . $this->getLang('similar') . '</dt>';
 528              $html .= '<dd>';
 529              $html .= $this->makeLinkList($extension->getSimilarExtensions());
 530              $html .= '</dd>';
 531          }
 532  
 533          if ($extension->getConflicts()) {
 534              $html .= '<dt>' . $this->getLang('conflicts') . '</dt>';
 535              $html .= '<dd>';
 536              $html .= $this->makeLinkList($extension->getConflicts());
 537              $html .= '</dd>';
 538          }
 539          $html .= '</dl>' . DOKU_LF;
 540          return $html;
 541      }
 542  
 543      /**
 544       * Generate a list of links for extensions
 545       *
 546       * @param array $ext The extensions
 547       * @return string The HTML code
 548       */
 549      public function makeLinkList($ext)
 550      {
 551          $html = '';
 552          foreach ($ext as $link) {
 553              $html .= '<bdi><a href="' .
 554                  $this->gui->tabURL('search', ['q' => 'ext:' . $link]) . '">' .
 555                  hsc($link) . '</a></bdi>, ';
 556          }
 557          return rtrim($html, ', ');
 558      }
 559  
 560      /**
 561       * Display the action buttons if they are possible
 562       *
 563       * @param helper_plugin_extension_extension $extension The extension
 564       * @return string The HTML code
 565       */
 566      public function makeActions(helper_plugin_extension_extension $extension)
 567      {
 568          global $conf;
 569          $html   = '';
 570          $errors = '';
 571  
 572          if ($extension->isInstalled()) {
 573              if (($canmod = $extension->canModify()) === true) {
 574                  if (!$extension->isProtected()) {
 575                      $html .= $this->makeAction('uninstall', $extension);
 576                  }
 577                  if ($extension->getDownloadURL()) {
 578                      if ($extension->updateAvailable()) {
 579                          $html .= $this->makeAction('update', $extension);
 580                      } else {
 581                          $html .= $this->makeAction('reinstall', $extension);
 582                      }
 583                  }
 584              } else {
 585                  $errors .= '<p class="permerror">' . $this->getLang($canmod) . '</p>';
 586              }
 587              if (!$extension->isProtected() && !$extension->isTemplate()) { // no enable/disable for templates
 588                  if ($extension->isEnabled()) {
 589                      $html .= $this->makeAction('disable', $extension);
 590                  } else {
 591                      $html .= $this->makeAction('enable', $extension);
 592                  }
 593              }
 594              if ($extension->isGitControlled()) {
 595                  $errors .= '<p class="permerror">' . $this->getLang('git') . '</p>';
 596              }
 597              if (
 598                  $extension->isEnabled() &&
 599                  in_array('Auth', $extension->getTypes()) &&
 600                  $conf['authtype'] != $extension->getID()
 601              ) {
 602                  $errors .= '<p class="permerror">' . $this->getLang('auth') . '</p>';
 603              }
 604          } elseif (($canmod = $extension->canModify()) === true) {
 605              if ($extension->getDownloadURL()) {
 606                  $html .= $this->makeAction('install', $extension);
 607              }
 608          } else {
 609              $errors .= '<div class="permerror">' . $this->getLang($canmod) . '</div>';
 610          }
 611  
 612          if (!$extension->isInstalled() && $extension->getDownloadURL()) {
 613              $html .= ' <span class="version">' . $this->getLang('available_version') . ' ';
 614              $html .= ($extension->getLastUpdate()
 615                      ? hsc($extension->getLastUpdate())
 616                      : $this->getLang('unknown')) . '</span>';
 617          }
 618  
 619          return $html . ' ' . $errors . DOKU_LF;
 620      }
 621  
 622      /**
 623       * Display an action button for an extension
 624       *
 625       * @param string                            $action    The action
 626       * @param helper_plugin_extension_extension $extension The extension
 627       * @return string The HTML code
 628       */
 629      public function makeAction($action, $extension)
 630      {
 631          $title = '';
 632  
 633          if ($action == 'install' || $action == 'reinstall') {
 634              $title = 'title="' . hsc($extension->getDownloadURL()) . '"';
 635          }
 636  
 637          $classes = 'button ' . $action;
 638          $name    = 'fn[' . $action . '][' . hsc($extension->getID()) . ']';
 639  
 640          $html = '<button class="' . $classes . '" name="' . $name . '" type="submit" ' . $title . '>' .
 641              $this->getLang('btn_' . $action) . '</button> ';
 642          return $html;
 643      }
 644  
 645      /**
 646       * Plugin/template status
 647       *
 648       * @param helper_plugin_extension_extension $extension The extension
 649       * @return string The description of all relevant statusses
 650       */
 651      public function makeStatus(helper_plugin_extension_extension $extension)
 652      {
 653          $status = [];
 654  
 655          if ($extension->isInstalled()) {
 656              $status[] = $this->getLang('status_installed');
 657              if ($extension->isProtected()) {
 658                  $status[] = $this->getLang('status_protected');
 659              } else {
 660                  $status[] = $extension->isEnabled()
 661                      ? $this->getLang('status_enabled')
 662                      : $this->getLang('status_disabled');
 663              }
 664          } else {
 665              $status[] = $this->getLang('status_not_installed');
 666          }
 667          if (!$extension->canModify()) $status[] = $this->getLang('status_unmodifiable');
 668          if ($extension->isBundled()) $status[] = $this->getLang('status_bundled');
 669          $status[] = $extension->isTemplate()
 670              ? $this->getLang('status_template')
 671              : $this->getLang('status_plugin');
 672          return implode(', ', $status);
 673      }
 674  }