Textpattern PHP Cross Reference Content Management Systems

Source: /textpattern/vendors/Textpattern/Admin/Theme.php - 386 lines - 9498 bytes - Summary - Text - Print

Description: Base for admin-side themes.

   1  <?php
   2  
   3  /*
   4   * Textpattern Content Management System
   5   * http://textpattern.com
   6   *
   7   * Copyright (C) 2016 The Textpattern Development Team
   8   *
   9   * This file is part of Textpattern.
  10   *
  11   * Textpattern is free software; you can redistribute it and/or
  12   * modify it under the terms of the GNU General Public License
  13   * as published by the Free Software Foundation, version 2.
  14   *
  15   * Textpattern is distributed in the hope that it will be useful,
  16   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18   * GNU General Public License for more details.
  19   *
  20   * You should have received a copy of the GNU General Public License
  21   * along with Textpattern. If not, see <http://www.gnu.org/licenses/>.
  22   */
  23  
  24  /**
  25   * Base for admin-side themes.
  26   *
  27   * @package Admin\Theme
  28   */
  29  
  30  namespace Textpattern\Admin;
  31  
  32  if (!defined('THEME')) {
  33      /**
  34       * Relative path to themes directory.
  35       */
  36  
  37      define('THEME', 'admin-themes/');
  38  }
  39  
  40  /**
  41   * Admin-side theme.
  42   *
  43   * @package Admin\Theme
  44   */
  45  
  46  abstract class Theme
  47  {
  48      /**
  49       * The theme name.
  50       *
  51       * @var string
  52       */
  53  
  54      public $name;
  55  
  56      /**
  57       * Stores a menu.
  58       *
  59       * @var array
  60       */
  61  
  62      public $menu;
  63  
  64      /**
  65       * Theme location.
  66       *
  67       * @var string
  68       */
  69  
  70      public $url;
  71  
  72      /**
  73       * Just a popup window.
  74       *
  75       * @var bool
  76       */
  77  
  78      public $is_popup;
  79  
  80      /**
  81       * Stores an activity message.
  82       *
  83       * @var bool
  84       * @see \Textpattern\Admin\Theme::announce()
  85       * @see \Textpattern\Admin\Theme::announce_async()
  86       */
  87  
  88      public $message;
  89  
  90      /**
  91       * Constructor.
  92       *
  93       * @param string $name Theme name
  94       */
  95  
  96      public function __construct($name)
  97      {
  98          $this->name = $name;
  99          $this->menu = array();
 100          $this->url = THEME.rawurlencode($name).'/';
 101          $this->is_popup = false;
 102          $this->message = '';
 103      }
 104  
 105      /**
 106       * Gets a theme's source path.
 107       *
 108       * @param  string $name Theme name
 109       * @return string Source file path for named theme
 110       */
 111  
 112      public static function path($name)
 113      {
 114          return txpath.DS.THEME.$name.DS.$name.'.php';
 115      }
 116  
 117      /**
 118       * Theme factory.
 119       *
 120       * @param  string $name Theme name
 121       * @return \Textpattern\Admin\Theme|bool An initialised theme object or FALSE on failure
 122       */
 123  
 124      public static function factory($name)
 125      {
 126          $path = Theme::path($name);
 127  
 128          if (is_readable($path)) {
 129              require_once($path);
 130          } else {
 131              return false;
 132          }
 133  
 134          $t = "{$name}_theme";
 135  
 136          if (class_exists($t)) {
 137              return new $t($name);
 138          } else {
 139              return false;
 140          }
 141      }
 142  
 143      /**
 144       * Initialise the theme singleton.
 145       *
 146       * @param  string $name Theme name
 147       * @return \Textpattern\Admin\Theme A valid theme object
 148       */
 149  
 150      public static function init($name = '')
 151      {
 152          static $instance;
 153  
 154          if ($name === '') {
 155              $name = pluggable_ui('admin_side', 'theme_name', get_pref('theme_name', 'hive'));
 156          }
 157  
 158          if ($instance && is_object($instance) && ($name == $instance->name)) {
 159              return $instance;
 160          } else {
 161              $instance = null;
 162          }
 163  
 164          $instance = Theme::factory($name);
 165  
 166          if (!$instance) {
 167              set_pref('theme_name', 'hive');
 168              die(gTxt('cannot_instantiate_theme', array('{name}' => $name, '{class}' => "{$name}_theme", '{path}' => Theme::path($name))));
 169          }
 170  
 171          return $instance;
 172      }
 173  
 174      /**
 175       * Get a list of all theme names.
 176       *
 177       * @return array Alphabetically sorted array of all available theme names
 178       */
 179  
 180      public static function names()
 181      {
 182          $dirs = glob(txpath.DS.THEME.'*');
 183  
 184          if (is_array($dirs)) {
 185              foreach ($dirs as $d) {
 186                  // Extract trailing directory name.
 187                  preg_match('#(.*)[\\/]+(.*)$#', $d, $m);
 188                  $name = $m[2];
 189  
 190                  // Accept directories containing an equally named .php file.
 191                  if (is_dir($d) && ($d != '.') && ($d != '..') && isset($name) && is_file($d.DS.$name.'.php')) {
 192                      $out[] = $name;
 193                  }
 194              }
 195  
 196              sort($out, SORT_STRING);
 197  
 198              return $out;
 199          }
 200  
 201          return array();
 202      }
 203  
 204      /**
 205       * Inherit from an ancestor theme.
 206       *
 207       * @param  string $name Name of ancestor theme
 208       * @return bool TRUE on success, FALSE on unavailable/invalid ancestor theme
 209       */
 210  
 211      public static function based_on($name)
 212      {
 213          global $production_status;
 214          $theme = Theme::factory($name);
 215  
 216          if (!$theme) {
 217              set_pref('theme_name', 'hive');
 218  
 219              if ($production_status === 'debug') {
 220                  echo gTxt('cannot_instantiate_theme', array('{name}' => $name, '{class}' => "{$name}_theme", '{path}' => Theme::path($name)));
 221              }
 222  
 223              return false;
 224          }
 225  
 226          return true;
 227      }
 228  
 229      /**
 230       * Sets Textpatterns menu structure, message contents and other application
 231       * states.
 232       *
 233       * @param  string $area Currently active top level menu
 234       * @param  string $event Currently active second level menu
 235       * @param  bool $is_popup Just a popup window for tag builder et cetera
 236       * @param  array $message The contents of the notification message pane
 237       * @return \Textpattern\Admin\Theme This theme object
 238       */
 239  
 240      public function set_state($area, $event, $is_popup, $message)
 241      {
 242          $this->is_popup = $is_popup;
 243          $this->message = $message;
 244  
 245          if ($is_popup) {
 246              return $this;
 247          }
 248  
 249          // Use legacy areas() for b/c.
 250          $areas = areas();
 251          $defaults = array(
 252              'content'      => 'article',
 253              'presentation' => 'page',
 254              'admin'        => 'admin',
 255          );
 256  
 257          if (empty($areas['start'])) {
 258              unset($areas['start']);
 259          }
 260  
 261          if (empty($areas['extensions'])) {
 262              unset($areas['extensions']);
 263          }
 264  
 265          $dflt_tab = get_pref('default_event', '');
 266  
 267          foreach ($areas as $ar => $items) {
 268              $l_ = gTxt('tab_'.$ar);
 269              $e_ = (array_key_exists($ar, $defaults)) ? $defaults[$ar] : reset($areas[$ar]);
 270              $i_ = array();
 271  
 272              if (has_privs('tab.'.$ar)) {
 273                  if (!has_privs($e_)) {
 274                      $e_ = '';
 275                  }
 276  
 277                  foreach ($items as $a => $b) {
 278                      if (has_privs($b)) {
 279                          if ($e_ === '') {
 280                              $e_ = $b;
 281                          }
 282  
 283                          if ($b == $dflt_tab) {
 284                              $this->menu[$ar]['event'] = $dflt_tab;
 285                          }
 286  
 287                          $i_[] = array('label' => $a, 'event' => $b, 'active' => ($b == $event));
 288                      }
 289                  }
 290  
 291                  if ($e_) {
 292                      $this->menu[$ar] = array(
 293                          'label'  => $l_,
 294                          'event'  => $e_,
 295                          'active' => ($ar == $area),
 296                          'items'  => $i_,
 297                      );
 298                  }
 299              }
 300          }
 301  
 302          return $this;
 303      }
 304  
 305      /**
 306       * HTML &lt;head&gt; section.
 307       *
 308       * Returned value is rendered into the head element of
 309       * all admin pages.
 310       *
 311       * @return string
 312       */
 313  
 314      abstract public function html_head();
 315  
 316      /**
 317       * Draw the theme's header.
 318       *
 319       * @return string
 320       */
 321  
 322      abstract public function header();
 323  
 324      /**
 325       * Draw the theme's footer.
 326       *
 327       * @return string
 328       */
 329  
 330      abstract public function footer();
 331  
 332      /**
 333       * Output notification message for synchronous HTML views.
 334       *
 335       * @param  array $thing Message text and status flag
 336       * @param  bool $modal If TRUE, immediate user interaction suggested
 337       * @return string HTML
 338       * @example
 339       * global $theme;
 340       * echo $theme->announce(array('my_message', E_ERROR));
 341       */
 342  
 343      public function announce($thing = array('', 0), $modal = false)
 344      {
 345          trigger_error(__FUNCTION__.' is abstract.', E_USER_ERROR);
 346      }
 347  
 348      /**
 349       * Output notification message for asynchronous JavaScript views.
 350       *
 351       * @param  array $thing Message text and status flag
 352       * @param  bool $modal If TRUE, immediate user interaction suggested
 353       * @return string JavaScript
 354       * @since 4.5.0
 355       * @example
 356       * global $theme;
 357       * echo script_js(
 358       *     $theme->announce_async(array('my_message', E_ERROR))
 359       * );
 360       */
 361  
 362      public function announce_async($thing = array('', 0), $modal = false)
 363      {
 364          trigger_error(__FUNCTION__.' is abstract.', E_USER_ERROR);
 365      }
 366  
 367      /**
 368       * Define bureaucratic details of this theme.
 369       *
 370       * All returned items are optional.
 371       *
 372       * @return array
 373       */
 374  
 375      public function manifest()
 376      {
 377          return array(
 378              'title'       => '', // Human-readable title of this theme. No HTML, keep it short.
 379              'author'      => '', // Name(s) of this theme's creator(s).
 380              'author_uri'  => '', // URI of the theme's site. Decent vanity is accepted.
 381              'version'     => '', // Version numbering. Mind version_compare().
 382              'description' => '', // Human readable short description. No HTML.
 383              'help'        => '', // URI of the theme's help and docs. Strictly optional.
 384          );
 385      }
 386  }

title

Description

title

Description

title

Description

title

title

Body