1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8//this script may only be included - so its better to die if called directly. 9if (strpos($_SERVER["SCRIPT_NAME"], basename(__FILE__)) !== false) { 10 header("location: index.php"); 11 exit; 12} 13 14/* 15ThemeLib 16@uses TikiLib 17*/ 18 19class ThemeLib extends TikiLib 20{ 21 22 /* 23 @return array of folder names in themes directory 24 */ 25 function get_themes($theme_base_path = 'themes') 26 { 27 $themes = []; 28 $list_css = glob("{$theme_base_path}/*/css/*.css"); 29 if ($list_css == false) { 30 return []; 31 } 32 foreach ($list_css as $css) { 33 $css = dirname(dirname($css)); 34 $theme = basename($css); 35 $themes[$theme] = tr($theme); 36 } 37 unset($themes['base_files']); //make sure base_files directory is removed from the array 38 unset($themes['templates']); //make sure templates directory is removed from the array 39 return $themes; 40 } 41 42 /* replaces legacy list_styles() function 43 @return array of all themes offered by Tiki 44 */ 45 function list_themes() 46 { 47 //set special array values and get themes from the main themes directory 48 $themes = [ 49 'default' => tr('Default Bootstrap'), 50 'custom_url' => tr('Custom theme by specifying URL'), 51 ]; 52 $themes = $themes + $this->get_themes(); //this way default and custom remains on the top of the array and default keeps its description 53 54 //get multidomain themes 55 $theme_base_path = $this->get_theme_path(); // knows about $tikidomain 56 if ($theme_base_path) { 57 $themes = array_unique(array_merge($themes, $this->get_themes($theme_base_path))); 58 } 59 60 return $themes; 61 } 62 63 /* 64 @return array of all theme options 65 */ 66 function get_options() 67 { 68 $options = []; 69 foreach (glob("themes/*/options/*/css/*.css") as $css) { 70 $css = dirname(dirname($css)); 71 $option = basename($css); 72 $options[$option] = tr($option); 73 } 74 return $options; 75 } 76 77 /* replaces legacy list_style_options function 78 @param $theme - main theme (e.g. "fivealive") 79 @return array of options the theme's options directory (e.g. from "themes/fivealive/options/") 80 */ 81 function list_theme_options($theme) 82 { 83 $theme_options = []; 84 if (isset($theme) and $theme != 'custom_url') { //don't consider custom URL themes to have options 85 $option_base_path = $this->get_theme_path($theme); 86 $list_css = glob("{$option_base_path}/options/*/css/*.css"); 87 if ($list_css == false) { 88 return []; 89 } 90 foreach ($list_css as $css) { 91 $css = dirname(dirname($css)); 92 $option = basename($css); 93 $theme_options[$option] = tr($option); 94 } 95 } 96 return $theme_options; 97 } 98 99 /* the group theme setting is stored in one column, so we need an array where all themes and all options are all available 100 @return array of all themes and all options 101 */ 102 function list_themes_and_options() 103 { 104 $theme_options = []; 105 $themes = $this->list_themes(); 106 unset($themes['custom_url']); //make sure Custom URL is removed from the list as it can not have options 107 foreach ($themes as $theme) { 108 $options = $this->list_theme_options($theme); 109 foreach ($options as $option) { 110 $theme_options[$theme . '/' . $option] = $theme . '/' . $option; 111 } 112 } 113 $themes_and_options = array_merge($themes, $theme_options); //merge the two array 114 natsort($themes_and_options); //sort the values 115 return $themes_and_options; 116 } 117 118 /* if theme and option is concatenated into one string (eg: group themes, theme control), than extract theme and option info from the string 119 @return theme and option name 120 */ 121 function extract_theme_and_option($themeoption) 122 { 123 $items = explode("/", $themeoption); 124 $theme = $items[0]; //theme is always there 125 if (isset($items[1])) { //check if we have option 126 $option = $items[1]; 127 } else { 128 $option = ''; 129 } 130 return [$theme, $option]; 131 } 132 133 /* get thumbnail for theme if there is one. The thumbnail should be a png file. 134 @param $theme - theme name (e.g. fivealive) 135 @param $option - optional theme option file name 136 @return string path to thumbnail file to be used by an img element 137 */ 138 function get_thumbnail_file($theme, $option = '') 139 { 140 if (! empty($option) && $option != tr('None')) { 141 $filename = $option . '.png'; // add .png 142 } else { 143 $filename = $theme . '.png'; // add .png 144 $option = ''; 145 } 146 return $this->get_theme_path($theme, $option, $filename); 147 } 148 149 /** replaces legacy get_style_path function 150 * @param string $theme - main theme (e.g. "fivealive" - can be empty to return main themes dir) 151 * @param string $option - optional theme option file name (e.g. "akebi") 152 * @param string $filename - optional filename to look for (e.g. "purple.png") 153 * @param string $subdir - optional dir to look in, e.g. 'css' etc (will guess by file extension if this not set but filename is) 154 * @return string - path to dir or file if found or empty if not - e.g. "themes/mydomain.tld/fivealive/options/akebi/" 155 */ 156 157 function get_theme_path($theme = '', $option = '', $filename = '', $subdir = '') 158 { 159 global $tikidomain; 160 161 $path = ''; 162 $dir_base = ''; 163 if ($tikidomain && is_dir("themes/$tikidomain")) { 164 $dir_base = $tikidomain . '/'; 165 } 166 167 $theme_base = ''; 168 if (! empty($theme)) { 169 $theme_base = $theme . '/'; 170 } 171 172 if (! empty($option)) { 173 $option_base = 'options/' . $option . '/'; 174 } 175 176 if (empty($subdir) && ! empty($filename)) { 177 $extension = substr($filename, strrpos($filename, '.') + 1); 178 switch ($extension) { 179 case 'css': 180 $subdir = 'css/'; 181 break; 182 case 'php': 183 $subdir = 'icons/'; 184 break; 185 case 'png': 186 case 'gif': 187 case 'jpg': 188 case 'jpeg': 189 case 'svg': 190 $subdir = 'images/'; 191 break; 192 case 'less': 193 $subdir = 'less/'; 194 break; 195 case 'js': 196 $subdir = 'js/'; 197 break; 198 case 'tpl': 199 $subdir = 'templates/'; 200 break; 201 } 202 } 203 204 // Why does this look in 'themes/' . $dir_base . $subdir and 'themes/' . $subdir if and only if we have a $filename? Chealer 2017-01-16 205 if (empty($filename)) { 206 if (isset($option_base) && is_dir('themes/' . $dir_base . $theme_base . $option_base . $subdir)) { 207 $path = 'themes/' . $dir_base . $theme_base . $option_base . $subdir; 208 } elseif (is_dir('themes/' . $dir_base . $theme_base . $subdir)) { 209 $path = 'themes/' . $dir_base . $theme_base . $subdir; // try "parent" theme dir if no option one 210 } elseif (isset($option_base) && is_dir('themes/' . $theme_base . $option_base . $subdir)) { 211 $path = 'themes/' . $theme_base . $option_base . $subdir; // try non-tikidomain theme dirs if no domain one 212 } elseif (is_dir('themes/' . $theme_base . $subdir)) { 213 $path = 'themes/' . $theme_base . $subdir; // try root theme dir if no domain one 214 } elseif (is_dir('themes/' . $theme_base)) { 215 $path = 'themes/' . $theme_base; // fall back to "parent" theme dir with no subdir if not 216 } 217 } else { 218 if (isset($option_base) && is_file('themes/' . $dir_base . $theme_base . $option_base . $subdir . $filename)) { 219 $path = 'themes/' . $dir_base . $theme_base . $option_base . $subdir . $filename; 220 } elseif (is_file('themes/' . $dir_base . $theme_base . $subdir . $filename)) { // try "parent" themes dir if no option one 221 $path = 'themes/' . $dir_base . $theme_base . $subdir . $filename; 222 } elseif (isset($option_base) && is_file('themes/' . $theme_base . $option_base . $subdir . $filename)) { // try non-tikidomain dirs if not found 223 $path = 'themes/' . $theme_base . $option_base . $subdir . $filename; 224 } elseif (is_file('themes/' . $theme_base . $subdir . $filename)) { 225 $path = 'themes/' . $theme_base . $subdir . $filename; // fall back to "parent" themes dir if no option 226 } elseif (is_file('themes/' . $dir_base . $subdir . $filename)) { 227 $path = 'themes/' . $dir_base . $subdir . $filename; // tikidomain root themes dir? 228 } elseif (is_file('themes/' . $subdir . $filename)) { 229 $path = 'themes/' . $subdir . $filename; // root themes subdir? 230 } elseif (is_file('themes/' . $filename)) { 231 $path = 'themes/' . $filename; // root themes dir? 232 } 233 } 234 return $path; 235 } 236 237 function get_theme_css($theme = '', $option = '') 238 { 239 if ($option) { 240 return $this->get_theme_path($theme, $option, $option . '.css'); 241 } else { 242 return $this->get_theme_path($theme, $option, $theme . '.css'); 243 } 244 } 245 246 /* get list of base iconsets 247 @return $base_iconsets - an array containing all icon set names from themes/base_files/iconsets folder 248 */ 249 function list_base_iconsets() 250 { 251 $base_iconsets = []; 252 $iconsetlib = TikiLib::lib('iconset'); 253 254 if (is_dir('themes/base_files/iconsets')) { 255 foreach (scandir('themes/base_files/iconsets') as $iconset_file) { 256 if ($iconset_file[0] != '.' && $iconset_file != 'index.php') { 257 $data = $iconsetlib->loadFile('themes/base_files/iconsets/' . $iconset_file); 258 $base_iconsets[substr($iconset_file, 0, -4)] = $data['name']; 259 } 260 } 261 } 262 return $base_iconsets; 263 } 264 265 /* get list of available themes and options 266 @return array of available themes and options based on $prefs['available_themes'] setting. This function does not consider if change_theme is on or off. 267 */ 268 function get_available_themesandoptions() 269 { 270 global $prefs; 271 $available_themesandoptions = []; 272 if (count($prefs['available_themes'] != 0) and ! empty($prefs['available_themes'][0])) { //if pref['available_themes'] is set, than use it 273 $available_themesandoptions = array_combine($prefs['available_themes'], $prefs['available_themes']); // TODO: does it make any sense to combine the same pref array with itself? -- luci 274 } else { 275 $available_themesandoptions = $this->list_themes_and_options(); //else load all themes and options 276 unset($available_themesandoptions['custom_url']); //make sure Custom URL is removed from the list 277 } 278 return $available_themesandoptions; 279 } 280 /* get a list of available themes 281 @return array of available themes based on $prefs['available_themes'] setting. This function does not consider if change_theme is on or off. 282 */ 283 function get_available_themes() 284 { 285 global $prefs; 286 $available_themes = []; 287 if (! empty($prefs['available_themes']) && ! empty($prefs['available_themes'][0])) { //if pref['available_themes'] is set, than use it 288 foreach ($prefs['available_themes'] as $available_theme) { 289 $theme = $this->extract_theme_and_option($available_theme)[0]; 290 $available_themes[$theme] = $theme; 291 $available_themes['default'] = tr('Default Bootstrap'); 292 } 293 } else { 294 $available_themes = $this->list_themes(); //else load all themes and options 295 unset($available_themes['custom_url']); //make sure Custom URL is removed from the list 296 } 297 return $available_themes; 298 } 299 300 /* get a list of available options for a theme 301 @return array of available theme options based on $prefs['available_themes'] setting. This function does not consider if change_theme is on or off. 302 */ 303 function get_available_options($theme) 304 { 305 global $prefs; 306 $available_options = []; 307 if (! empty($prefs['available_themes']) && ! empty($prefs['available_themes'][0])) { 308 foreach ($prefs['available_themes'] as $available_themeandoption) { 309 $themeandoption = $this->extract_theme_and_option($available_themeandoption); 310 if ($theme === $themeandoption[0] && ! empty($themeandoption[1])) { 311 $available_options[$themeandoption[1]] = $themeandoption[1]; 312 } 313 } 314 return $available_options; 315 } else { 316 return $this->list_theme_options($theme); 317 } 318 } 319} 320