Textpattern | PHP Cross Reference | Content Management Systems |
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 <head> 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
Body
title
Description
Body
title
Description
Body
title
Body
title