[ 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 ($extension->updateAvailable()) {
 396              $html .=  '<div class="msg notify">' .
 397                  sprintf($this->getLang('update_available'), hsc($extension->getLastUpdate())) .
 398                  '</div>';
 399          }
 400          if ($extension->hasDownloadURLChanged()) {
 401              $html .= '<div class="msg notify">' .
 402                  sprintf(
 403                      $this->getLang('url_change'),
 404                      '<bdi>' . hsc($extension->getDownloadURL()) . '</bdi>',
 405                      '<bdi>' . hsc($extension->getLastDownloadURL()) . '</bdi>'
 406                  ) .
 407                  '</div>';
 408          }
 409          return $html . DOKU_LF;
 410      }
 411  
 412      /**
 413       * Create a link from the given URL
 414       *
 415       * Shortens the URL for display
 416       *
 417       * @param string $url
 418       * @return string  HTML link
 419       */
 420      public function shortlink($url)
 421      {
 422          $link = parse_url($url);
 423  
 424          $base = $link['host'];
 425          if (!empty($link['port'])) $base .= $base . ':' . $link['port'];
 426          $long = $link['path'];
 427          if (!empty($link['query'])) $long .= $link['query'];
 428  
 429          $name = shorten($base, $long, 55);
 430  
 431          $html = '<a href="' . hsc($url) . '" class="urlextern">' . hsc($name) . '</a>';
 432          return $html;
 433      }
 434  
 435      /**
 436       * Plugin/template details
 437       *
 438       * @param helper_plugin_extension_extension $extension The extension
 439       * @return string The HTML code
 440       */
 441      public function makeInfo(helper_plugin_extension_extension $extension)
 442      {
 443          $default = $this->getLang('unknown');
 444          $html = '<dl class="details">';
 445  
 446          $html .= '<dt>' . $this->getLang('status') . '</dt>';
 447          $html .= '<dd>' . $this->makeStatus($extension) . '</dd>';
 448  
 449          if ($extension->getDonationURL()) {
 450              $html .= '<dt>' . $this->getLang('donate') . '</dt>';
 451              $html .= '<dd>';
 452              $html .= '<a href="' . $extension->getDonationURL() . '" class="donate">' .
 453                  $this->getLang('donate_action') . '</a>';
 454              $html .= '</dd>';
 455          }
 456  
 457          if (!$extension->isBundled()) {
 458              $html .= '<dt>' . $this->getLang('downloadurl') . '</dt>';
 459              $html .= '<dd><bdi>';
 460              $html .= ($extension->getDownloadURL()
 461                  ? $this->shortlink($extension->getDownloadURL())
 462                  : $default);
 463              $html .= '</bdi></dd>';
 464  
 465              $html .= '<dt>' . $this->getLang('repository') . '</dt>';
 466              $html .= '<dd><bdi>';
 467              $html .= ($extension->getSourcerepoURL()
 468                  ? $this->shortlink($extension->getSourcerepoURL())
 469                  : $default);
 470              $html .= '</bdi></dd>';
 471          }
 472  
 473          if ($extension->isInstalled()) {
 474              if ($extension->getInstalledVersion()) {
 475                  $html .= '<dt>' . $this->getLang('installed_version') . '</dt>';
 476                  $html .= '<dd>';
 477                  $html .= hsc($extension->getInstalledVersion());
 478                  $html .= '</dd>';
 479              }
 480              if (!$extension->isBundled()) {
 481                  $html .= '<dt>' . $this->getLang('install_date') . '</dt>';
 482                  $html .= '<dd>';
 483                  $html .= ($extension->getUpdateDate()
 484                      ? hsc($extension->getUpdateDate())
 485                      : $this->getLang('unknown'));
 486                  $html .= '</dd>';
 487              }
 488          }
 489          if (!$extension->isInstalled() || $extension->updateAvailable()) {
 490              $html .= '<dt>' . $this->getLang('available_version') . '</dt>';
 491              $html .= '<dd>';
 492              $html .= ($extension->getLastUpdate()
 493                  ? hsc($extension->getLastUpdate())
 494                  : $this->getLang('unknown'));
 495              $html .= '</dd>';
 496          }
 497  
 498          $html .= '<dt>' . $this->getLang('provides') . '</dt>';
 499          $html .= '<dd><bdi>';
 500          $html .= ($extension->getTypes()
 501              ? hsc(implode(', ', $extension->getTypes()))
 502              : $default);
 503          $html .= '</bdi></dd>';
 504  
 505          if (!$extension->isBundled() && $extension->getCompatibleVersions()) {
 506              $html .= '<dt>' . $this->getLang('compatible') . '</dt>';
 507              $html .= '<dd>';
 508              foreach ($extension->getCompatibleVersions() as $date => $version) {
 509                  $html .= '<bdi>' . $version['label'] . ' (' . $date . ')</bdi>, ';
 510              }
 511              $html = rtrim($html, ', ');
 512              $html .= '</dd>';
 513          }
 514          if ($extension->getDependencies()) {
 515              $html .= '<dt>' . $this->getLang('depends') . '</dt>';
 516              $html .= '<dd>';
 517              $html .= $this->makeLinkList($extension->getDependencies());
 518              $html .= '</dd>';
 519          }
 520  
 521          if ($extension->getSimilarExtensions()) {
 522              $html .= '<dt>' . $this->getLang('similar') . '</dt>';
 523              $html .= '<dd>';
 524              $html .= $this->makeLinkList($extension->getSimilarExtensions());
 525              $html .= '</dd>';
 526          }
 527  
 528          if ($extension->getConflicts()) {
 529              $html .= '<dt>' . $this->getLang('conflicts') . '</dt>';
 530              $html .= '<dd>';
 531              $html .= $this->makeLinkList($extension->getConflicts());
 532              $html .= '</dd>';
 533          }
 534          $html .= '</dl>' . DOKU_LF;
 535          return $html;
 536      }
 537  
 538      /**
 539       * Generate a list of links for extensions
 540       *
 541       * @param array $ext The extensions
 542       * @return string The HTML code
 543       */
 544      public function makeLinkList($ext)
 545      {
 546          $html = '';
 547          foreach ($ext as $link) {
 548              $html .= '<bdi><a href="' .
 549                  $this->gui->tabURL('search', ['q' => 'ext:' . $link]) . '">' .
 550                  hsc($link) . '</a></bdi>, ';
 551          }
 552          return rtrim($html, ', ');
 553      }
 554  
 555      /**
 556       * Display the action buttons if they are possible
 557       *
 558       * @param helper_plugin_extension_extension $extension The extension
 559       * @return string The HTML code
 560       */
 561      public function makeActions(helper_plugin_extension_extension $extension)
 562      {
 563          global $conf;
 564          $html   = '';
 565          $errors = '';
 566  
 567          if ($extension->isInstalled()) {
 568              if (($canmod = $extension->canModify()) === true) {
 569                  if (!$extension->isProtected()) {
 570                      $html .= $this->makeAction('uninstall', $extension);
 571                  }
 572                  if ($extension->getDownloadURL()) {
 573                      if ($extension->updateAvailable()) {
 574                          $html .= $this->makeAction('update', $extension);
 575                      } else {
 576                          $html .= $this->makeAction('reinstall', $extension);
 577                      }
 578                  }
 579              } else {
 580                  $errors .= '<p class="permerror">' . $this->getLang($canmod) . '</p>';
 581              }
 582              if (!$extension->isProtected() && !$extension->isTemplate()) { // no enable/disable for templates
 583                  if ($extension->isEnabled()) {
 584                      $html .= $this->makeAction('disable', $extension);
 585                  } else {
 586                      $html .= $this->makeAction('enable', $extension);
 587                  }
 588              }
 589              if ($extension->isGitControlled()) {
 590                  $errors .= '<p class="permerror">' . $this->getLang('git') . '</p>';
 591              }
 592              if (
 593                  $extension->isEnabled() &&
 594                  in_array('Auth', $extension->getTypes()) &&
 595                  $conf['authtype'] != $extension->getID()
 596              ) {
 597                  $errors .= '<p class="permerror">' . $this->getLang('auth') . '</p>';
 598              }
 599          } elseif (($canmod = $extension->canModify()) === true) {
 600              if ($extension->getDownloadURL()) {
 601                  $html .= $this->makeAction('install', $extension);
 602              }
 603          } else {
 604              $errors .= '<div class="permerror">' . $this->getLang($canmod) . '</div>';
 605          }
 606  
 607          if (!$extension->isInstalled() && $extension->getDownloadURL()) {
 608              $html .= ' <span class="version">' . $this->getLang('available_version') . ' ';
 609              $html .= ($extension->getLastUpdate()
 610                      ? hsc($extension->getLastUpdate())
 611                      : $this->getLang('unknown')) . '</span>';
 612          }
 613  
 614          return $html . ' ' . $errors . DOKU_LF;
 615      }
 616  
 617      /**
 618       * Display an action button for an extension
 619       *
 620       * @param string                            $action    The action
 621       * @param helper_plugin_extension_extension $extension The extension
 622       * @return string The HTML code
 623       */
 624      public function makeAction($action, $extension)
 625      {
 626          $title = '';
 627  
 628          if ($action == 'install' || $action == 'reinstall') {
 629              $title = 'title="' . hsc($extension->getDownloadURL()) . '"';
 630          }
 631  
 632          $classes = 'button ' . $action;
 633          $name    = 'fn[' . $action . '][' . hsc($extension->getID()) . ']';
 634  
 635          $html = '<button class="' . $classes . '" name="' . $name . '" type="submit" ' . $title . '>' .
 636              $this->getLang('btn_' . $action) . '</button> ';
 637          return $html;
 638      }
 639  
 640      /**
 641       * Plugin/template status
 642       *
 643       * @param helper_plugin_extension_extension $extension The extension
 644       * @return string The description of all relevant statusses
 645       */
 646      public function makeStatus(helper_plugin_extension_extension $extension)
 647      {
 648          $status = [];
 649  
 650          if ($extension->isInstalled()) {
 651              $status[] = $this->getLang('status_installed');
 652              if ($extension->isProtected()) {
 653                  $status[] = $this->getLang('status_protected');
 654              } else {
 655                  $status[] = $extension->isEnabled()
 656                      ? $this->getLang('status_enabled')
 657                      : $this->getLang('status_disabled');
 658              }
 659          } else {
 660              $status[] = $this->getLang('status_not_installed');
 661          }
 662          if (!$extension->canModify()) $status[] = $this->getLang('status_unmodifiable');
 663          if ($extension->isBundled()) $status[] = $this->getLang('status_bundled');
 664          $status[] = $extension->isTemplate()
 665              ? $this->getLang('status_template')
 666              : $this->getLang('status_plugin');
 667          return implode(', ', $status);
 668      }
 669  }