lib-navigation MDL-21113 Fixed minor javascript error when positioning sidepanel...
[moodle.git] / lib / outputlib.php
CommitLineData
571fa828 1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
f8065dd2 18/**
19 * This constant is used for html attributes which need to have an empty
20 * value and still be output by the renderers (e.g. alt="");
21 *
22 * @constant @EMPTY@
23 */
24define('HTML_ATTR_EMPTY', '@EMPTY@');
571fa828 25
d9c8f425 26require_once($CFG->libdir.'/outputcomponents.php');
27require_once($CFG->libdir.'/outputactions.php');
28require_once($CFG->libdir.'/outputfactories.php');
d9c8f425 29require_once($CFG->libdir.'/outputrenderers.php');
30
571fa828 31/**
32 * Functions for generating the HTML that Moodle should output.
33 *
34 * Please see http://docs.moodle.org/en/Developement:How_Moodle_outputs_HTML
35 * for an overview.
36 *
37 * @package moodlecore
38 * @copyright 2009 Tim Hunt
b7009474 39 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
571fa828 40 */
41
571fa828 42/**
fdeb7fa1 43 * This class represents the configuration variables of a Moodle theme.
44 *
45 * All the variables with access: public below (with a few exceptions that are marked)
46 * are the properties you can set in your theme's config.php file.
47 *
48 * There are also some methods and protected variables that are part of the inner
49 * workings of Moodle's themes system. If you are just editing a theme's config.php
fa1afe32 50 * file, you can just ignore those, and the following information for developers.
ebebf55c 51 *
52 * Normally, to create an instance of this class, you should use the
53 * {@link theme_config::load()} factory method to load a themes config.php file.
fa1afe32 54 * However, normally you don't need to bother, because moodle_page (that is, $PAGE)
fdeb7fa1 55 * will create one for you, accessible as $PAGE->theme.
571fa828 56 *
57 * @copyright 2009 Tim Hunt
58 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
59 * @since Moodle 2.0
60 */
ebebf55c 61class theme_config {
62 /**
fdeb7fa1 63 * @var string the name of this theme. Set automatically when this theme is
64 * loaded. Please do not try to set this in your theme's config.php file.
ebebf55c 65 */
fdeb7fa1 66 public $name;
571fa828 67
fdeb7fa1 68 /**
69 * @var string the folder where this themes files are stored. This is set
70 * automatically when the theme is loaded to $CFG->themedir . '/' . $this->name.
71 * Please do not try to set this in your theme's config.php file.
72 */
73 public $dir;
8954245a 74
fdeb7fa1 75 /**
76 * @var array The names of all the stylesheets from this theme that you would
77 * like included, in order. Give the names of the files without .css.
78 */
79 public $sheets = array('styles_layout', 'styles_fonts', 'styles_color');
b7009474 80
fdeb7fa1 81 /**
82 * You can base your theme on another theme by linking to the other theme as
83 * a parent. This lets you use the CSS from the other theme
d4a03c00 84 * (see {@link $parentsheets}), or layout templates (see {@link $layouts}).
fdeb7fa1 85 * That makes it easy to create a new theme that is similar to another one
86 * but with a few changes. In this theme's CSS you only need to override
87 * those rules you want to change.
88 */
89 public $parent = null;
8954245a 90
fdeb7fa1 91 /**
92 * @var boolean|array Whether and which stylesheets from the parent theme
93 * to use in this theme. (Ignored if parent is null)
94 *
fa1afe32 95 * Possible values are:
fdeb7fa1 96 * false - no parent theme CSS.
97 * true - include all the normal parent theme CSS. Currently this means
98 * array('styles_layout', 'styles_fonts', 'styles_color').
99 * array - include just the listed stylesheets. Give the files names
100 * without the .css, as in the above example.
101 */
102 public $parentsheets = false;
571fa828 103
fdeb7fa1 104 /**
105 * @var boolean|array Whether and which stylesheets from the standard theme
106 * to use in this theme.
107 *
108 * The advantages of using the standard stylesheets in your theme is that
109 * they give you a good basic layout, and when the Moodle core code is
110 * updated with new features, the standard theme CSS will be updated to match
111 * the changes in the code. Therefore, your theme is less likely to break
112 * when you upgrade Moodle.
113 *
fa1afe32 114 * Possible values are:
fdeb7fa1 115 * false - no standard theme CSS.
116 * true - include all the main standard theme CSS. Currently this means
117 * array('styles_layout', 'styles_fonts', 'styles_color').
118 * array - include just the listed stylesheets. Give the files names
119 * without the .css, as in the above example.
120 */
121 public $standardsheets = true;
571fa828 122
fdeb7fa1 123 /**
124 * @var array use the CSS fragments from these types of plugins.
125 *
126 * All the plugins of the given types will be searched for a file called
127 * styles.php and, if found, these will be included with the CSS for this theme.
128 *
129 * This allows modules to provide some basic CSS so they work out of the box.
130 * You are strongly advised to leave this enabled, otherwise you will have to
131 * provide styling in your theme for every installed block, activity, course
132 * format, ... in your Moodle site.
133 *
134 * This setting is an array of plugin types, as in the {@link get_plugin_types()}
135 * function. The default value has been chosen to be the same as Moodle 1.9.
136 * This is not necessarily the best choice.
137 *
138 * The plugin CSS is included first, before any theme CSS. To be precise,
fa1afe32 139 * if $standardsheets is true, the plugin CSS is included with the
fdeb7fa1 140 * standard theme's CSS, otherwise if $parentsheets is true, the plugin CSS
141 * will be included with the parent theme's CSS, otherwise the plugin CSS
142 * will be include with this theme's CSS.
143 */
144 public $pluginsheets = array('mod', 'block', 'format', 'gradereport');
571fa828 145
fdeb7fa1 146 /**
147 * @var boolean When this is true then Moodle will try to include a file
148 * meta.php from this theme into the <head></head> part of the page.
149 */
ebebf55c 150 public $metainclude = false;
571fa828 151
fdeb7fa1 152 /**
153 * @var boolean When this is true, and when this theme has a parent, then
154 * Moodle will try to include a file meta.php from the parent theme into the
155 * <head></head> part of the page.
156 */
ebebf55c 157 public $parentmetainclude = false;
571fa828 158
fdeb7fa1 159 /**
160 * @var boolean When this is true then Moodle will try to include the file
161 * meta.php from the standard theme into the <head></head> part of the page.
162 */
163 public $standardmetainclude = true;
571fa828 164
fdeb7fa1 165 /**
166 * If true, then this theme must have a "pix" subdirectory that contains
167 * copies of all files from the moodle/pix directory, plus a "pix/mod"
168 * directory containing all the icons for all the activity modules.
169 *
170 * @var boolean
171 */
172 public $custompix = false;
571fa828 173
fdeb7fa1 174 /**
175 * Which template to use for each general type of page.
176 *
d4a03c00 177 * This is an array of arrays. The keys of the outer array are the different
178 * types of page. Pages in Moodle are categorised into one of a short list of
179 * types like 'normal', 'home', 'popup', 'form', .... The most reliable way
180 * to get a complete list is to look at
181 * {@link http://cvs.moodle.org/moodle/theme/standard/config.php?view=markup the standard theme config.php file}.
182 * That file also has a good example of how to set this setting.
fdeb7fa1 183 *
fa1afe32 184 * If Moodle encounters a general type of page that is not listed in your theme,
d4a03c00 185 * then it will use the first layout. Therefore, should probably put 'normal'
186 * first in this array.
fdeb7fa1 187 *
d4a03c00 188 * For each page type, the value in the outer array is an array that describes
189 * how you want that type of page to look. For example
190 * <pre>
191 * $THEME->layouts = array(
192 * // Most pages. Put this first, so if we encounter an unknown page type, this is used.
193 * 'normal' => array(
194 * 'layout' => 'parent:layout.php',
195 * 'regions' => array('side-pre', 'side-post'),
196 * 'defaultregion' => 'side-post'
197 * ),
198 * // The site home page.
199 * 'home' => array(
200 * 'layout' => 'layout-home.php',
201 * 'regions' => array('side-pre', 'side-post'),
202 * 'defaultregion' => 'side-post'
203 * ),
204 * // ...
205 * );
206 * </pre>
fdeb7fa1 207 *
d4a03c00 208 * 'layout' is the layout template to use for this type of page. You can
209 * specify this in one of three ways:
fdeb7fa1 210 * <ol>
d4a03c00 211 * <li><b>filename</b> for example 'layout-home.php' as above. Use that file from this theme.</li>
212 * <li><b>parent:filename</b> for example 'parent:layout.php' as above. Use the
fdeb7fa1 213 * specified file from the parent theme. (Obviously, you can only do this
214 * if this theme has a parent!)</li>
215 * <li><b>standard:filename</b> for example 'standard:layout-popup.php'. Use
216 * the specified file from the standard theme.</li>
217 * </ol>
fa1afe32 218 * To promote consistency, you are encouraged to call your layout files
d4a03c00 219 * layout.php or layout-something.php.
fdeb7fa1 220 *
d4a03c00 221 * 'regions' This lists the regions on the page where blocks may appear. For
222 * each region you list here, your layout file must include a call to
223 * <pre>
224 * echo $OUTPUT->blocks_for_region($regionname);
225 * </pre>
226 * or equivalent so that the blocks are actually visible.
fdeb7fa1 227 *
d4a03c00 228 * 'defaultregion' If the list of regions is non-empty, then you must pick
229 * one of the one of them as 'default'. This has two meanings. First, this is
230 * where new blocks are added. Second, if there are any blocks associated with
fa1afe32 231 * the page, but in non-existent regions, they appear here. (Imaging, for example,
d4a03c00 232 * that someone added blocks using a different theme that used different region
233 * names, and then switched to this theme.)
fdeb7fa1 234 *
235 * @var array
236 */
d4a03c00 237 public $layouts = array();
571fa828 238
74623e0a 239 /*
40427883 240 * Time in seconds to cache the CSS style sheets for the chosen theme
74623e0a 241 *
40427883 242 * @var integer
243 */
244 public $csslifetime = 1800;
245
fdeb7fa1 246 /**
247 * With this you can control the colours of the big MP3 player
248 * that is used for MP3 resources.
249 *
250 * @var string
251 */
ebebf55c 252 public $resource_mp3player_colors = 'bgColour=000000&btnColour=ffffff&btnBorderColour=cccccc&iconColour=000000&iconOverColour=00cc00&trackColour=cccccc&handleColour=ffffff&loaderColour=ffffff&font=Arial&fontColour=3333FF&buffer=10&waitForPlay=no&autoPlay=yes';
571fa828 253
fdeb7fa1 254 /**
255 * With this you can control the colours of the small MP3 player
256 * that is used elsewhere
257 *.
258 * @var string
259 */
ebebf55c 260 public $filter_mediaplugin_colors = 'bgColour=000000&btnColour=ffffff&btnBorderColour=cccccc&iconColour=000000&iconOverColour=00cc00&trackColour=cccccc&handleColour=ffffff&loaderColour=ffffff&waitForPlay=yes';
261
fdeb7fa1 262 /**
263 *$THEME->rarrow = '&#x25BA;' //OR '&rarr;';
264 *$THEME->larrow = '&#x25C4;' //OR '&larr;';
265 *$CFG->block_search_button = link_arrow_right(get_string('search'), $url='', $accesshide=true);
266 *
267 * Accessibility: Right and left arrow-like characters are
268 * used in the breadcrumb trail, course navigation menu
269 * (previous/next activity), calendar, and search forum block.
270 *
271 * If the theme does not set characters, appropriate defaults
272 * are set by (lib/weblib.php:check_theme_arrows). The suggestions
273 * above are 'silent' in a screen-reader like JAWS. Please DO NOT
274 * use &lt; &gt; &raquo; - these are confusing for blind users.
275 */
ebebf55c 276
fdeb7fa1 277 /**
278 * Name of the renderer factory class to use.
279 *
280 * This is an advanced feature. Moodle output is generated by 'renderers',
281 * you can customise the HTML that is output by writing custom renderers,
282 * and then you need to specify 'renderer factory' so that Moodle can find
283 * your renderers.
284 *
285 * There are some renderer factories supplied with Moodle. Please follow these
286 * links to see what they do.
287 * <ul>
288 * <li>{@link standard_renderer_factory} - the default.</li>
289 * <li>{@link theme_overridden_renderer_factory} - use this if you want to write
290 * your own custom renderers in a renderers.php file in this theme (or the parent theme).</li>
291 * <li>{@link template_renderer_factory} - highly experimental! Do not use (yet).</li>
292 * </ul>
293 *
294 * @var string name of a class implementing the {@link renderer_factory} interface.
295 */
ebebf55c 296 public $rendererfactory = 'standard_renderer_factory';
ebebf55c 297
fdeb7fa1 298 /**
299 * Name of the icon finder class to use.
300 *
301 * This is an advanced feature. controls how Moodle converts from the icon
302 * names used in the code to URLs to embed in the HTML. You should not ever
303 * need to change this.
304 *
305 * @var string name of a class implementing the {@link icon_finder} interface.
306 */
ebebf55c 307 public $iconfinder = 'pix_icon_finder';
571fa828 308
309 /**
fdeb7fa1 310 * Function to do custom CSS processing.
311 *
312 * This is an advanced feature. If you want to do custom processing on the
313 * CSS before it is output (for example, to replace certain variable names
314 * with particular values) you can give the name of a function here.
ebebf55c 315 *
fa1afe32 316 * There are two functions available that you may wish to use (defined in lib/outputlib.php):
fdeb7fa1 317 * <ul>
318 * <li>{@link output_css_replacing_constants}</li>
319 * <li>{@link output_css_for_css_edit}</li>
320 * </ul>
321 *
322 * If you wish to write your own function, look at those two as examples,
323 * and it should be clear what you have to do.
ebebf55c 324 *
325 * @var string the name of a function.
571fa828 326 */
ebebf55c 327 public $customcssoutputfunction = null;
571fa828 328
fdeb7fa1 329 /**
330 * You can use this to control the cutoff point for strings
331 * in the navmenus (list of activities in popup menu etc)
332 * Default is 50 characters wide.
333 */
334 public $navmenuwidth = 50;
335
336 /**
337 * By setting this to true, then you will have access to a
338 * new variable in your header.html and footer.html called
339 * $navmenulist ... this contains a simple XHTML menu of
340 * all activities in the current course, mostly useful for
341 * creating popup navigation menus and so on.
342 */
343 public $makenavmenulist = false;
344
345 /**
346 * @var renderer_factory Instance of the renderer_factory implementation
347 * we are using. Implementation detail.
348 */
349 protected $rf = null;
350
351 /**
352 * @var renderer_factory Instance of the icon_finder implementation we are
353 * using. Implementation detail.
354 */
355 protected $if = null;
356
571fa828 357 /**
ebebf55c 358 * Load the config.php file for a particular theme, and return an instance
359 * of this class. (That is, this is a factory method.)
360 *
361 * @param string $themename the name of the theme.
362 * @return theme_config an instance of this class.
571fa828 363 */
ebebf55c 364 public static function load($themename) {
365 global $CFG;
571fa828 366
fa1afe32 367 // We have to use the variable name $THEME (upper case) because that
ebebf55c 368 // is what is used in theme config.php files.
369
370 // Set some other standard properties of the theme.
371 $THEME = new theme_config;
372 $THEME->name = $themename;
373 $THEME->dir = $CFG->themedir . '/' . $themename;
374
375 // Load up the theme config
376 $configfile = $THEME->dir . '/config.php';
377 if (!is_readable($configfile)) {
378 throw new coding_exception('Cannot use theme ' . $themename .
379 '. The file ' . $configfile . ' does not exist or is not readable.');
571fa828 380 }
ebebf55c 381 include($configfile);
382
383 $THEME->update_legacy_information();
384
385 return $THEME;
571fa828 386 }
387
34a2777c 388 /**
ebebf55c 389 * Get the renderer for a part of Moodle for this theme.
390 * @param string $module the name of part of moodle. E.g. 'core', 'quiz', 'qtype_multichoice'.
391 * @param moodle_page $page the page we are rendering
897b5c82 392 * @param string $subtype optional subtype such as 'news' resulting to 'mod_forum_news'
fa1afe32 393 * @return moodle_renderer_base the requested renderer.
34a2777c 394 */
897b5c82 395 public function get_renderer($module, $page, $subtype=null) {
ebebf55c 396 if (is_null($this->rf)) {
397 if (CLI_SCRIPT) {
398 $classname = 'cli_renderer_factory';
399 } else {
400 $classname = $this->rendererfactory;
401 }
402 $this->rf = new $classname($this);
403 }
404
897b5c82 405 return $this->rf->get_renderer($module, $page, $subtype);
34a2777c 406 }
407
571fa828 408 /**
ebebf55c 409 * Get the renderer for a part of Moodle for this theme.
410 * @return moodle_renderer_base the requested renderer.
571fa828 411 */
ebebf55c 412 protected function get_icon_finder() {
413 if (is_null($this->if)) {
414 $classname = $this->iconfinder;
415 $this->if = new $classname($this);
571fa828 416 }
ebebf55c 417 return $this->if;
571fa828 418 }
419
420 /**
fa1afe32 421 * Return the URL for an icon identified as in pre-Moodle 2.0 code.
ebebf55c 422 *
423 * Suppose you have old code like $url = "$CFG->pixpath/i/course.gif";
424 * then old_icon_url('i/course'); will return the equivalent URL that is correct now.
425 *
fa1afe32 426 * @param string $iconname the name of the icon.
ebebf55c 427 * @return string the URL for that icon.
571fa828 428 */
ebebf55c 429 public function old_icon_url($iconname) {
4096752d 430 return $this->get_icon_finder()->old_icon_url($iconname);
571fa828 431 }
432
433 /**
fa1afe32 434 * Return the URL for an icon identified as in pre-Moodle 2.0 code.
ebebf55c 435 *
436 * Suppose you have old code like $url = "$CFG->modpixpath/$mod/icon.gif";
437 * then mod_icon_url('icon', $mod); will return the equivalent URL that is correct now.
438 *
fa1afe32 439 * @param string $iconname the name of the icon.
440 * @param string $module the module the icon belongs to.
ebebf55c 441 * @return string the URL for that icon.
571fa828 442 */
ebebf55c 443 public function mod_icon_url($iconname, $module) {
4096752d 444 return $this->get_icon_finder()->mod_icon_url($iconname, $module);
571fa828 445 }
34a2777c 446
ebebf55c 447 /**
448 * Get the list of stylesheet URLs that need to go in the header for this theme.
449 * @return array of URLs.
450 */
451 public function get_stylesheet_urls() {
34a2777c 452 global $CFG;
453
fdeb7fa1 454 // We need to tell the CSS that is being included (for example the standard
455 // theme CSS) which theme it is being included for. Prepare the necessary param.
456 $param = '?for=' . $this->name;
34a2777c 457
ebebf55c 458 // Stylesheets, in order (standard, parent, this - some of which may be the same).
459 $stylesheets = array();
460 if ($this->name != 'standard' && $this->standardsheets) {
fdeb7fa1 461 $stylesheets[] = $CFG->httpsthemewww . '/standard/styles.php' . $param;
ebebf55c 462 }
463 if (!empty($this->parent)) {
fdeb7fa1 464 $stylesheets[] = $CFG->httpsthemewww . '/' . $this->parent . '/styles.php' . $param;
34a2777c 465 }
fdeb7fa1 466 $stylesheets[] = $CFG->httpsthemewww . '/' . $this->name . '/styles.php' . $param;
34a2777c 467
fdeb7fa1 468 // Additional styles for right-to-left languages, if applicable.
ebebf55c 469 if (right_to_left()) {
470 $stylesheets[] = $CFG->httpsthemewww . '/standard/rtl.css';
34a2777c 471
ebebf55c 472 if (!empty($this->parent) && file_exists($CFG->themedir . '/' . $this->parent . '/rtl.css')) {
473 $stylesheets[] = $CFG->httpsthemewww . '/' . $this->parent . '/rtl.css';
474 }
34a2777c 475
ebebf55c 476 if (file_exists($this->dir . '/rtl.css')) {
477 $stylesheets[] = $CFG->httpsthemewww . '/' . $this->name . '/rtl.css';
478 }
34a2777c 479 }
17a6649b 480
fdeb7fa1 481 // If the theme wants pluginsheets, get them included in the first (most
482 // general) stylesheet we are including. That is, process them with the
483 // standard CSS if we are using that, else with the parent CSS, else with
484 // our own CSS.
485 if (!empty($this->pluginsheets)) {
486 $stylesheets[0] .= '&amp;pluginsheets=1';
487 }
488
ebebf55c 489 return $stylesheets;
490 }
17a6649b 491
ebebf55c 492 /**
fdeb7fa1 493 * Get the meta tags from one theme to got in the <head> of the HTML.
fa1afe32 494 * @param string $themename the name of the theme to get meta tags from.
495 * @param string $page that page whose <head> is being output.
fdeb7fa1 496 * @return string HTML code.
497 */
498 protected function get_theme_meta_tags($themename, $page) {
499 global $CFG;
500 // At least one theme's meta.php expects to have $PAGE visible.
501 $PAGE = $page;
502 $filename = $CFG->themedir . '/' . $themename . '/meta.php';
503 if (file_exists($filename)) {
504 ob_start();
505 include_once($filename);
f77fcb5a 506 $metatags = ob_get_contents();
fdeb7fa1 507 ob_end_clean();
508 }
509 return $metatags;
510 }
511
512 /**
513 * Get all the meta tags (from this theme, standard, parent) that this theme
514 * wants in the <head> of the HTML.
515 *
fa1afe32 516 * @param string $page that page whose <head> is being output.
fdeb7fa1 517 * @return string HTML code.
518 */
519 public function get_meta_tags($page) {
520 $metatags = '';
521 if ($this->standardmetainclude) {
522 $metatags .= $this->get_theme_meta_tags('standard', $page);
523 }
524 if ($this->parent && $this->parentmetainclude) {
525 $metatags .= $this->get_theme_meta_tags($this->parent, $page);
526 }
527 if ($this->metainclude) {
528 $metatags .= $this->get_theme_meta_tags($this->name, $page);
529 }
530 return $metatags;
531 }
532
d4a03c00 533 /**
534 * Get the information from {@link $layouts} for this type of page.
535 * @param string $generaltype the general type of the page.
536 * @return array the appropriate part of {@link $layouts}.
537 */
538 protected function layout_info_for_page($generaltype) {
539 if (array_key_exists($generaltype, $this->layouts)) {
540 return $this->layouts[$generaltype];
541 } else {
542 return reset($this->layouts);
543 }
544 }
545
fdeb7fa1 546 /**
547 * Given the settings of this theme, and the page generaltype, return the
548 * full path of the page layout template to use.
549 *
550 * Used by {@link moodle_core_renderer::header()}. If an appropriate new-style
551 * template cannot be found, returns false to signal that the old-style
552 * header.html and footer.html files should be used.
553 *
d4a03c00 554 * @param string $generaltype the general type of the page.
fdeb7fa1 555 * @return string Full path to the template to use, or false if a new-style
556 * template cannot be found.
557 */
d4a03c00 558 public function template_for_page($generaltype) {
fdeb7fa1 559 global $CFG;
560
561 // Legacy fallback.
d4a03c00 562 if (empty($this->layouts)) {
fdeb7fa1 563 return false;
564 }
565
d4a03c00 566 $layoutinfo = $this->layout_info_for_page($generaltype);
567 $templatefile = $layoutinfo['layout'];
fdeb7fa1 568
569 // Parse the name that was found.
d4a03c00 570 if (strpos($templatefile, 'standard:') === 0) {
fdeb7fa1 571 $templatepath = $CFG->themedir . '/standard/' . substr($templatefile, 9);
d4a03c00 572 } else if (strpos($templatefile, 'parent:') === 0) {
fdeb7fa1 573 if (empty($this->parent)) {
574 throw new coding_exception('This theme (' . $this->name .
575 ') does not have a parent. You cannot specify a layout template like ' .
576 $templatefile);
577 }
578 $templatepath = $CFG->themedir . '/' . $this->parent . '/' . substr($templatefile, 7);
579 } else {
580 $templatepath = $this->dir . '/' . $templatefile;
581 }
582
fa1afe32 583 // Check the template exists.
fdeb7fa1 584 if (!is_readable($templatepath)) {
585 throw new coding_exception('The template ' . $templatefile . ' (' . $templatepath .
586 ') for page type ' . $generaltype . ' cannot be found in this theme (' .
587 $this->name . ')');
588 }
589
590 return $templatepath;
591 }
592
d4a03c00 593 /**
594 * Inform a block_manager about the block regions this theme wants on this
595 * type of page.
596 * @param string $generaltype the general type of the page.
597 * @param block_manager $blockmanager the block_manger to set up.
fa1afe32 598 * @return void
d4a03c00 599 */
600 public function setup_blocks($generaltype, $blockmanager) {
601 // Legacy fallback.
602 if (empty($this->layouts)) {
603 if (!in_array($generaltype, array('form', 'popup', 'maintenance'))) {
604 $blockmanager->add_regions(array(BLOCK_POS_LEFT, BLOCK_POS_RIGHT));
605 $blockmanager->set_default_region(BLOCK_POS_RIGHT);
606 }
607 return;
608 }
609
610 $layoutinfo = $this->layout_info_for_page($generaltype);
611 if (!empty($layoutinfo['regions'])) {
612 $blockmanager->add_regions($layoutinfo['regions']);
613 $blockmanager->set_default_region($layoutinfo['defaultregion']);
7d875874 614 } else {
615 $blockmanager->set_default_region('');
d4a03c00 616 }
617 }
618
1d13c75c 619 /**
620 * Get the list of all block regions known to this theme in all templates.
621 * @return array internal region name => human readable name.
622 */
623 public function get_all_block_regions() {
624 // Legacy fallback.
625 if (empty($this->layouts)) {
626 return array(
627 'side-pre' => get_string('region-side-pre', 'theme_standard'),
628 'side-post' => get_string('region-side-post', 'theme_standard'),
629 );
630 }
631
632 $regions = array();
633 foreach ($this->layouts as $layoutinfo) {
634 $ownertheme = $this->name;
635 if (strpos($layoutinfo['layout'], 'standard:') === 0) {
636 $ownertheme = 'standard';
637 } else if (strpos($layoutinfo['layout'], 'parent:') === 0) {
638 $ownertheme = $this->parent;
639 }
640
641 foreach ($layoutinfo['regions'] as $region) {
642 $regions[$region] = get_string('region-' . $region, 'theme_' . $ownertheme);
643 }
644 }
645 return $regions;
646 }
647
fdeb7fa1 648 /**
649 * Helper method used by {@link update_legacy_information()}. Update one entry
650 * in the $this->pluginsheets array, based on the legacy $property propery.
fa1afe32 651 * @param string $plugintype e.g. 'mod'.
652 * @param string $property e.g. 'modsheets'.
653 * @return void
fdeb7fa1 654 */
655 protected function update_legacy_plugin_sheets($plugintype, $property) {
d4a03c00 656 // In Moodle 1.9, modsheets etc. were ignored if standardsheets was false.
657 if (!empty($this->standardsheets) && property_exists($this, $property)) {
fdeb7fa1 658 debugging('$THEME->' . $property . ' is deprecated. Please use the new $THEME->pluginsheets instead.', DEBUG_DEVELOPER);
659 if (!empty($this->$property) && !in_array($plugintype, $this->pluginsheets)) {
660 $this->pluginsheets[] = $plugintype;
661 } else if (empty($this->$property) && in_array($plugintype, $this->pluginsheets)) {
662 unset($this->pluginsheets[array_search($plugintype, $this->pluginsheets)]);
663 }
664 }
665 }
666
667 /**
668 * This method looks a the settings that have been loaded, to see whether
ebebf55c 669 * any legacy things are being used, and outputs warning and tries to update
670 * things to use equivalent newer settings.
fa1afe32 671 * @return void
ebebf55c 672 */
673 protected function update_legacy_information() {
674 global $CFG;
fdeb7fa1 675
676 $this->update_legacy_plugin_sheets('mod', 'modsheets');
677 $this->update_legacy_plugin_sheets('block', 'blocksheets');
678 $this->update_legacy_plugin_sheets('format', 'formatsheets');
679 $this->update_legacy_plugin_sheets('gradereport', 'gradereportsheets');
680
fdeb7fa1 681 if (!empty($this->langsheets)) {
682 debugging('$THEME->langsheets is no longer supported. No languages were ' .
683 'using it for anything, and it did not seem to serve any purpose.', DEBUG_DEVELOPER);
684 }
685
ebebf55c 686 if (!empty($this->customcorners)) {
687 // $THEME->customcorners is deprecated but we provide support for it via the
688 // custom_corners_renderer_factory class in lib/deprecatedlib.php
689 debugging('$THEME->customcorners is deprecated. Please use the new $THEME->rendererfactory ' .
690 'to control HTML generation. Please use $this->rendererfactory = \'custom_corners_renderer_factory\'; ' .
691 'in your config.php file instead.', DEBUG_DEVELOPER);
692 $this->rendererfactory = 'custom_corners_renderer_factory';
34a2777c 693 }
694
ebebf55c 695 if (!empty($this->cssconstants)) {
696 debugging('$THEME->cssconstants is deprecated. Please use ' .
697 '$THEME->customcssoutputfunction = \'output_css_replacing_constants\'; ' .
698 'in your config.php file instead.', DEBUG_DEVELOPER);
699 $this->customcssoutputfunction = 'output_css_replacing_constants';
34a2777c 700 }
ebebf55c 701
702 if (!empty($this->CSSEdit)) {
703 debugging('$THEME->CSSEdit is deprecated. Please use ' .
704 '$THEME->customcssoutputfunction = \'output_css_for_css_edit\'; ' .
705 'in your config.php file instead.', DEBUG_DEVELOPER);
706 $this->customcssoutputfunction = 'output_css_for_css_edit';
34a2777c 707 }
708
ae96b517 709 if (!empty($CFG->smartpix)) {
ebebf55c 710 $this->iconfinder = 'smartpix_icon_finder';
711 } else if ($this->custompix) {
712 $this->iconfinder = 'theme_icon_finder';
713 }
34a2777c 714 }
715
ebebf55c 716 /**
717 * Set the variable $CFG->pixpath and $CFG->modpixpath to be the right
d436d197 718 * ones for this theme. These should no longer be used, but legacy code
719 * might still rely on them.
fa1afe32 720 * @return void
ebebf55c 721 */
d436d197 722 public function setup_legacy_pix_paths() {
ebebf55c 723 global $CFG;
724 if (!empty($CFG->smartpix)) {
725 if ($CFG->slasharguments) {
726 // Use this method if possible for better caching
727 $extra = '';
728 } else {
729 $extra = '?file=';
730 }
731 $CFG->pixpath = $CFG->httpswwwroot . '/pix/smartpix.php' . $extra . '/' . $this->name;
732 $CFG->modpixpath = $CFG->httpswwwroot . '/pix/smartpix.php' . $extra . '/' . $this->name . '/mod';
34a2777c 733
ebebf55c 734 } else if (empty($THEME->custompix)) {
735 $CFG->pixpath = $CFG->httpswwwroot . '/pix';
736 $CFG->modpixpath = $CFG->httpswwwroot . '/mod';
737
738 } else {
739 $CFG->pixpath = $CFG->httpsthemewww . '/' . $this->name . '/pix';
740 $CFG->modpixpath = $CFG->httpsthemewww . '/' . $this->name . '/pix/mod';
34a2777c 741 }
34a2777c 742 }
ebebf55c 743}
34a2777c 744
ebebf55c 745/**
d9c8f425 746 * This class keeps track of which HTML tags are currently open.
747 *
748 * This makes it much easier to always generate well formed XHTML output, even
749 * if execution terminates abruptly. Any time you output some opening HTML
750 * without the matching closing HTML, you should push the necessary close tags
751 * onto the stack.
ebebf55c 752 *
753 * @copyright 2009 Tim Hunt
754 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
755 * @since Moodle 2.0
756 */
d9c8f425 757class xhtml_container_stack {
758 /** @var array stores the list of open containers. */
759 protected $opencontainers = array();
fa1afe32 760 /**
d9c8f425 761 * @var array in developer debug mode, stores a stack trace of all opens and
762 * closes, so we can output helpful error messages when there is a mismatch.
fa1afe32 763 */
d9c8f425 764 protected $log = array();
fa1afe32 765 /**
d9c8f425 766 * Store whether we are developer debug mode. We need this in several places
767 * including in the destructor where we may no thave access to $CFG.
768 * @var boolean
fa1afe32 769 */
d9c8f425 770 protected $isdebugging;
34a2777c 771
d9c8f425 772 public function __construct() {
773 $this->isdebugging = debugging('', DEBUG_DEVELOPER);
ebebf55c 774 }
34a2777c 775
fa1afe32 776 /**
d9c8f425 777 * Push the close HTML for a recently opened container onto the stack.
778 * @param string $type The type of container. This is checked when {@link pop()}
779 * is called and must match, otherwise a developer debug warning is output.
780 * @param string $closehtml The HTML required to close the container.
781 * @return void
fa1afe32 782 */
d9c8f425 783 public function push($type, $closehtml) {
784 $container = new stdClass;
785 $container->type = $type;
786 $container->closehtml = $closehtml;
787 if ($this->isdebugging) {
788 $this->log('Open', $type);
3aaa27f4 789 }
d9c8f425 790 array_push($this->opencontainers, $container);
ebebf55c 791 }
34a2777c 792
fa1afe32 793 /**
d9c8f425 794 * Pop the HTML for the next closing container from the stack. The $type
795 * must match the type passed when the container was opened, otherwise a
796 * warning will be output.
797 * @param string $type The type of container.
798 * @return string the HTML required to close the container.
fa1afe32 799 */
d9c8f425 800 public function pop($type) {
801 if (empty($this->opencontainers)) {
802 debugging('<p>There are no more open containers. This suggests there is a nesting problem.</p>' .
803 $this->output_log(), DEBUG_DEVELOPER);
804 return;
3aaa27f4 805 }
ebebf55c 806
d9c8f425 807 $container = array_pop($this->opencontainers);
808 if ($container->type != $type) {
809 debugging('<p>The type of container to be closed (' . $container->type .
810 ') does not match the type of the next open container (' . $type .
811 '). This suggests there is a nesting problem.</p>' .
812 $this->output_log(), DEBUG_DEVELOPER);
ebebf55c 813 }
d9c8f425 814 if ($this->isdebugging) {
815 $this->log('Close', $type);
e8775320 816 }
d9c8f425 817 return $container->closehtml;
ebebf55c 818 }
e8775320 819
fa1afe32 820 /**
d9c8f425 821 * Close all but the last open container. This is useful in places like error
822 * handling, where you want to close all the open containers (apart from <body>)
823 * before outputting the error message.
824 * @param bool $shouldbenone assert that the stack should be empty now - causes a
825 * developer debug warning if it isn't.
826 * @return string the HTML required to close any open containers inside <body>.
fa1afe32 827 */
d9c8f425 828 public function pop_all_but_last($shouldbenone = false) {
829 if ($shouldbenone && count($this->opencontainers) != 1) {
830 debugging('<p>Some HTML tags were opened in the body of the page but not closed.</p>' .
831 $this->output_log(), DEBUG_DEVELOPER);
832 }
833 $output = '';
834 while (count($this->opencontainers) > 1) {
835 $container = array_pop($this->opencontainers);
836 $output .= $container->closehtml;
e8775320 837 }
d9c8f425 838 return $output;
e8775320 839 }
34a2777c 840
ebebf55c 841 /**
d9c8f425 842 * You can call this function if you want to throw away an instance of this
843 * class without properly emptying the stack (for example, in a unit test).
844 * Calling this method stops the destruct method from outputting a developer
845 * debug warning. After calling this method, the instance can no longer be used.
846 * @return void
ebebf55c 847 */
d9c8f425 848 public function discard() {
849 $this->opencontainers = null;
ebebf55c 850 }
d9c8f425 851
ebebf55c 852 /**
d9c8f425 853 * Emergency fallback. If we get to the end of processing and not all
854 * containers have been closed, output the rest with a developer debug warning.
855 * @return void
ebebf55c 856 */
d9c8f425 857 public function __destruct() {
858 if (empty($this->opencontainers)) {
859 return;
897b5c82 860 }
d9c8f425 861
d5a8d9aa
PS
862 // TODO: MDL-20625 this looks dangerous and problematic because we never know
863 // the order of calling of constructors ==> the transaction warning will not be included
864
d9c8f425 865 // It seems you cannot rely on $CFG, and hence the debugging function here,
866 // becuase $CFG may be destroyed before this object is.
867 if ($this->isdebugging) {
868 echo '<div class="notifytiny"><p>Some containers were left open. This suggests there is a nesting problem.</p>' .
869 $this->output_log() . '</div>';
34a2777c 870 }
d9c8f425 871 echo $this->pop_all_but_last();
872 $container = array_pop($this->opencontainers);
873 echo $container->closehtml;
34a2777c 874 }
34a2777c 875
fa1afe32 876 /**
d9c8f425 877 * Adds an entry to the log.
878 * @param string $action The name of the action
879 * @param string $type The type of action
880 * @return void
fa1afe32 881 */
d9c8f425 882 protected function log($action, $type) {
883 $this->log[] = '<li>' . $action . ' ' . $type . ' at:' .
884 format_backtrace(debug_backtrace()) . '</li>';
ebebf55c 885 }
34a2777c 886
fa1afe32 887 /**
d9c8f425 888 * Outputs the log's contents as a HTML list.
889 * @return string HTML list of the log
fa1afe32 890 */
d9c8f425 891 protected function output_log() {
892 return '<ul>' . implode("\n", $this->log) . '</ul>';
34a2777c 893 }
894}
895
7a5c78e0 896/**
897 * An icon finder is responsible for working out the correct URL for an icon.
898 *
899 * A icon finder must also have a constructor that takes a theme object.
900 * (See {@link standard_icon_finder::__construct} for an example.)
901 *
902 * Note that we are planning to change the Moodle icon naming convention before
903 * the Moodle 2.0 release. Therefore, this API will probably change.
904 *
905 * @copyright 2009 Tim Hunt
906 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
907 * @since Moodle 2.0
908 */
909interface icon_finder {
910 /**
911 * Return the URL for an icon identified as in pre-Moodle 2.0 code.
912 *
913 * Suppose you have old code like $url = "$CFG->pixpath/i/course.gif";
914 * then old_icon_url('i/course'); will return the equivalent URL that is correct now.
915 *
916 * @param string $iconname the name of the icon.
917 * @return string the URL for that icon.
918 */
919 public function old_icon_url($iconname);
920
921 /**
922 * Return the URL for an icon identified as in pre-Moodle 2.0 code.
923 *
924 * Suppose you have old code like $url = "$CFG->modpixpath/$mod/icon.gif";
925 * then mod_icon_url('icon', $mod); will return the equivalent URL that is correct now.
926 *
927 * @param string $iconname the name of the icon.
928 * @param string $module the module the icon belongs to.
929 * @return string the URL for that icon.
930 */
931 public function mod_icon_url($iconname, $module);
932}
933
934/**
935 * This icon finder implements the old scheme that was used when themes that had
936 * $THEME->custompix = false.
937 *
938 * @copyright 2009 Tim Hunt
939 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
940 * @since Moodle 2.0
941 */
942class pix_icon_finder implements icon_finder {
943 /**
944 * Constructor
945 * @param theme_config $theme the theme we are finding icons for (which is irrelevant).
946 */
947 public function __construct($theme) {
948 }
949
950 /**
951 * Implement interface method.
952 * @param string $iconname the name of the icon.
953 * @return string the URL for that icon.
954 */
955 public function old_icon_url($iconname) {
956 global $CFG;
957 if (file_exists($CFG->dirroot . '/pix/' . $iconname . '.png')) {
958 return $CFG->httpswwwroot . '/pix/' . $iconname . '.png';
959 } else {
960 return $CFG->httpswwwroot . '/pix/' . $iconname . '.gif';
961 }
962 }
963
964 /**
965 * Implement interface method.
966 * @param string $iconname the name of the icon.
967 * @param string $module the module the icon belongs to.
968 * @return string the URL for that icon.
969 */
970 public function mod_icon_url($iconname, $module) {
971 global $CFG;
972 if (file_exists($CFG->dirroot . '/mod/' . $module . '/' . $iconname . '.png')) {
973 return $CFG->httpswwwroot . '/mod/' . $module . '/' . $iconname . '.png';
974 } else {
975 return $CFG->httpswwwroot . '/mod/' . $module . '/' . $iconname . '.gif';
976 }
977 }
978}
979
980
981/**
982 * This icon finder implements the old scheme that was used for themes that had
983 * $THEME->custompix = true.
984 *
985 * @copyright 2009 Tim Hunt
986 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
987 * @since Moodle 2.0
988 */
989class theme_icon_finder implements icon_finder {
990 protected $themename;
991 /**
992 * Constructor
993 * @param theme_config $theme the theme we are finding icons for.
994 */
995 public function __construct($theme) {
996 $this->themename = $theme->name;
997 }
998
999 /**
1000 * Implement interface method.
1001 * @param string $iconname the name of the icon.
1002 * @return string the URL for that icon.
1003 */
1004 public function old_icon_url($iconname) {
1005 global $CFG;
1006 if (file_exists($CFG->themedir . '/' . $this->themename . '/pix/' . $iconname . '.png')) {
1007 return $CFG->httpsthemewww . '/' . $this->themename . '/pix/' . $iconname . '.png';
1008 } else {
1009 return $CFG->httpsthemewww . '/' . $this->themename . '/pix/' . $iconname . '.gif';
1010 }
1011 }
1012
1013 /**
1014 * Implement interface method.
1015 * @param string $iconname the name of the icon.
1016 * @param string $module the module the icon belongs to.
1017 * @return string the URL for that icon.
1018 */
1019 public function mod_icon_url($iconname, $module) {
1020 global $CFG;
1021 if (file_exists($CFG->themedir . '/' . $this->themename . '/pix/mod/' . $module . '/' . $iconname . '.png')) {
1022 return $CFG->httpsthemewww . '/' . $this->themename . '/pix/mod/' . $module . '/' . $iconname . '.png';
1023 } else {
1024 return $CFG->httpsthemewww . '/' . $this->themename . '/pix/mod/' . $module . '/' . $iconname . '.gif';
1025 }
1026 }
1027}
1028
1029
1030/**
1031 * This icon finder implements the algorithm in pix/smartpix.php.
1032 *
1033 * @copyright 2009 Tim Hunt
1034 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1035 * @since Moodle 2.0
1036 */
1037class smartpix_icon_finder extends pix_icon_finder {
1038 protected $places = array();
1039
1040 /**
1041 * Constructor
1042 * @param theme_config $theme the theme we are finding icons for.
1043 */
1044 public function __construct($theme) {
1045 global $CFG;
1046 $this->places[$CFG->themedir . '/' . $theme->name . '/pix/'] =
1047 $CFG->httpsthemewww . '/' . $theme->name . '/pix/';
1048 if (!empty($theme->parent)) {
1049 $this->places[$CFG->themedir . '/' . $theme->parent . '/pix/'] =
1050 $CFG->httpsthemewww . '/' . $theme->parent . '/pix/';
1051 }
1052 }
1053
1054 /**
1055 * Implement interface method.
1056 * @param string $iconname the name of the icon.
1057 * @return string the URL for that icon.
1058 */
1059 public function old_icon_url($iconname) {
1060 foreach ($this->places as $dirroot => $urlroot) {
1061 if (file_exists($dirroot . $iconname . '.png')) {
1062 return $dirroot . $iconname . '.png';
1063 } else if (file_exists($dirroot . $iconname . '.gif')) {
1064 return $dirroot . $iconname . '.gif';
1065 }
1066 }
1067 return parent::old_icon_url($iconname);
1068 }
1069
1070 /**
1071 * Implement interface method.
1072 * @param string $iconname the name of the icon.
1073 * @param string $module the module the icon belongs to.
1074 * @return string the URL for that icon.
1075 */
1076 public function mod_icon_url($iconname, $module) {
1077 foreach ($this->places as $dirroot => $urlroot) {
1078 if (file_exists($dirroot . 'mod/' . $iconname . '.png')) {
1079 return $dirroot . 'mod/' . $iconname . '.png';
1080 } else if (file_exists($dirroot . 'mod/' . $iconname . '.gif')) {
1081 return $dirroot . 'mod/' . $iconname . '.gif';
1082 }
1083 }
1084 return parent::old_icon_url($iconname, $module);
1085 }
1086}
1087
b7009474 1088
1089/**
1090 * Output CSS while replacing constants/variables. See MDL-6798 for details
1091 *
1092 * Information from Urs Hunkler:
1093 *
1094 * This is an adaptation of Shaun Inman's "CSS Server-side Constants" for Moodle.
1095 * http://www.shauninman.com/post/heap/2005/08/09/css_constants
1096 *
1097 * To use, specify $THEME->customcssoutputfunction = 'output_css_replacing_constants';
1098 * in your theme's config.php file.
1099 *
1100 * The constant definitions are written into a separate CSS file named like
1101 * constants.css and loaded first in config.php. You can use constants for any
1102 * CSS properties. The constant definition looks like:
1103 * <code>
1104 * \@server constants {
1105 * fontColor: #3a2830;
1106 * aLink: #116699;
1107 * aVisited: #AA2200;
1108 * aHover: #779911;
1109 * pageBackground: #FFFFFF;
1110 * backgroundColor: #EEEEEE;
1111 * backgroundSideblockHeader: #a8a4e9;
1112 * fontcolorSideblockHeader: #222222;
1113 * color1: #98818b;
1114 * color2: #bd807b;
1115 * color3: #f9d1d7;
1116 * color4: #e8d4d8;
1117 * }
1118 * </code>
1119 *
1120 * The lines in the CSS files using CSS constants look like:
1121 * <code>
1122 * body {
1123 * font-size: 100%;
1124 * background-color: pageBackground;
1125 * color: fontColor;
1126 * font-family: 'Bitstream Vera Serif', georgia, times, serif;
1127 * margin: 0;
1128 * padding: 0;
1129 * }
1130 * div#page {
1131 * margin: 0 10px;
1132 * padding-top: 5px;
1133 * border-top-width: 10px;
1134 * border-top-style: solid;
1135 * border-top-color: color3;
1136 * }
1137 * div.clearer {
1138 * clear: both;
1139 * }
1140 * a:link {
1141 * color: aLink;
fdeb7fa1 1142 * }
b7009474 1143 * </code>
1144 *
fa1afe32 1145 * @param array $files an array of the CSS fields that need to be output.
fdeb7fa1 1146 * @param array $toreplace for convenience. If you are going to output the names
1147 * of the css files, for debugging purposes, then you should output
fa1afe32 1148 * str_replace($toreplace, '', $file); because it looks prettier.
1149 * @return void
b7009474 1150 */
fdeb7fa1 1151function output_css_replacing_constants($files, $toreplace) {
b7009474 1152 // Get all the CSS.
b7009474 1153 ob_start();
1154 foreach ($files as $file) {
1155 $shortname = str_replace($toreplace, '', $file);
1156 echo '/******* ' . $shortname . " start *******/\n\n";
1157 @include_once($file);
1158 echo '/******* ' . $shortname . " end *******/\n\n";
1159 }
1160 $css = ob_get_contents();
1161 ob_end_clean();
1162
1163 if (preg_match_all("/@server\s+(?:variables|constants)\s*\{\s*([^\}]+)\s*\}\s*/i", $css, $matches)) {
1164 $variables = array();
1165 foreach ($matches[0] as $key => $server) {
1166 $css = str_replace($server, '', $css);
1167 preg_match_all("/([^:\}\s]+)\s*:\s*([^;\}]+);/", $matches[1][$key], $vars);
1168 foreach ($vars[1] as $var => $value) {
1169 $variables[$value] = $vars[2][$var];
1170 }
1171 }
1172 $css = str_replace(array_keys($variables), array_values($variables), $css);
1173 }
1174 echo $css;
1175}
1176
1177/**
1178 * This CSS output function will link to CSS files rather than including them
1179 * inline.
1180 *
1181 * The single CSS files can then be edited and saved with interactive
1182 * CSS editors like CSSEdit. Any files that have a .php extension are still included
1183 * inline.
1184 *
fa1afe32 1185 * @param array $files an array of the CSS fields that need to be output.
fdeb7fa1 1186 * @param array $toreplace for convenience. If you are going to output the names
1187 * of the css files, for debugging purposes, then you should output
fa1afe32 1188 * str_replace($toreplace, '', $file); because it looks prettier.
1189 * @return void
b7009474 1190 */
fdeb7fa1 1191function output_css_for_css_edit($files, $toreplace) {
b7009474 1192 foreach ($files as $file) {
1193 $shortname = str_replace($toreplace, '', $file);
1194 echo '/* @group ' . $shortname . " */\n\n";
1195 if (strpos($file, '.css') !== false) {
1196 echo '@import url("' . $file . '");'."\n\n";
1197 } else {
1198 @include_once($file);
1199 }
1200 echo "/* @end */\n\n";
1201 }
f77fcb5a 1202}