Merge branch 'w10_MDL-44358_m27_stylesrefact' of https://github.com/skodak/moodle

This commit is contained in:
Dan Poltawski 2014-03-04 07:38:56 +08:00
commit d129de3761
5 changed files with 282 additions and 283 deletions

View File

@ -15,10 +15,12 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains CSS related class, and function for the CSS optimiser
* This file contains CSS related class, and function for the CSS optimiser.
*
* Please see the {@link css_optimiser} class for greater detail.
*
* NOTE: these functions are not expected to be used from any addons.
*
* @package core
* @subpackage cssoptimiser
* @copyright 2012 Sam Hemelryk
@ -27,6 +29,12 @@
defined('MOODLE_INTERNAL') || die();
if (!defined('THEME_DESIGNER_CACHE_LIFETIME')) {
// This can be also set in config.php file,
// it needs to be higher than the time it takes to generate all CSS content.
define('THEME_DESIGNER_CACHE_LIFETIME', 10);
}
/**
* Stores CSS in a file at the given path.
*
@ -34,50 +42,15 @@ defined('MOODLE_INTERNAL') || die();
*
* @param theme_config $theme The theme that the CSS belongs to.
* @param string $csspath The path to store the CSS at.
* @param array $cssfiles The CSS files to store.
* @param string $csscontent the complete CSS in one string
* @param bool $chunk If set to true these files will be chunked to ensure
* that no one file contains more than 4095 selectors.
* @param string $chunkurl If the CSS is be chunked then we need to know the URL
* to use for the chunked files.
*/
function css_store_css(theme_config $theme, $csspath, array $cssfiles, $chunk = false, $chunkurl = null) {
function css_store_css(theme_config $theme, $csspath, $csscontent, $chunk = false, $chunkurl = null) {
global $CFG;
$css = '';
foreach ($cssfiles as $file) {
$css .= file_get_contents($file)."\n";
}
// Check if both the CSS optimiser is enabled and the theme supports it.
if (!empty($CFG->enablecssoptimiser) && $theme->supportscssoptimisation) {
// This is an experimental feature introduced in Moodle 2.3
// The CSS optimiser organises the CSS in order to reduce the overall number
// of rules and styles being sent to the client. It does this by collating
// the CSS before it is cached removing excess styles and rules and stripping
// out any extraneous content such as comments and empty rules.
$optimiser = new css_optimiser;
$css = $theme->post_process($css);
$css = $optimiser->process($css);
// If cssoptimisestats is set then stats from the optimisation are collected
// and output at the beginning of the CSS.
if (!empty($CFG->cssoptimiserstats)) {
$css = $optimiser->output_stats_css().$css;
}
} else {
// This is the default behaviour.
// The cssoptimise setting was introduced in Moodle 2.3 and will hopefully
// in the future be changed from an experimental setting to the default.
// The css_minify_css will method will use the Minify library remove
// comments, additional whitespace and other minor measures to reduce the
// the overall CSS being sent.
// However it has the distinct disadvantage of having to minify the CSS
// before running the post process functions. Potentially things may break
// here if theme designers try to push things with CSS post processing.
$css = $theme->post_process($css);
$css = core_minify::css($css);
}
clearstatcache();
if (!file_exists(dirname($csspath))) {
@mkdir(dirname($csspath), $CFG->directorypermissions, true);
@ -88,11 +61,11 @@ function css_store_css(theme_config $theme, $csspath, array $cssfiles, $chunk =
ignore_user_abort(true);
// First up write out the single file for all those using decent browsers.
css_write_file($csspath, $css);
css_write_file($csspath, $csscontent);
if ($chunk) {
// If we need to chunk the CSS for browsers that are sub-par.
$css = css_chunk_by_selector_count($css, $chunkurl);
$css = css_chunk_by_selector_count($csscontent, $chunkurl);
$files = count($css);
$count = 1;
foreach ($css as $content) {
@ -240,6 +213,32 @@ function css_send_cached_css($csspath, $etag) {
die;
}
/**
* Sends a cached CSS content
*
* @param string $csscontent The actual CSS markup.
* @param string $etag The revision to make sure we utilise any caches.
*/
function css_send_cached_css_content($csscontent, $etag) {
// 60 days only - the revision may get incremented quite often.
$lifetime = 60*60*24*60;
header('Etag: "'.$etag.'"');
header('Content-Disposition: inline; filename="styles.php"');
header('Last-Modified: '. gmdate('D, d M Y H:i:s', time()) .' GMT');
header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
header('Pragma: ');
header('Cache-Control: public, max-age='.$lifetime);
header('Accept-Ranges: none');
header('Content-Type: text/css; charset=utf-8');
if (!min_enable_zlib_compression()) {
header('Content-Length: '.strlen($csscontent));
}
echo($csscontent);
die;
}
/**
* Sends CSS directly without caching it.
*

View File

@ -55,6 +55,11 @@ function theme_reset_all_caches() {
set_config('themerev', $next); // time is unique even when you reset/switch database
if (!empty($CFG->themedesignermode)) {
$cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'core', 'themedesigner');
$cache->purge();
}
if ($PAGE) {
$PAGE->reload_theme();
}
@ -66,8 +71,9 @@ function theme_reset_all_caches() {
* @param bool $state
*/
function theme_set_designer_mod($state) {
theme_reset_all_caches();
set_config('themedesignermode', (int)!empty($state));
// Reset caches after switching mode so that any designer mode caches get purged too.
theme_reset_all_caches();
}
/**
@ -594,14 +600,12 @@ class theme_config {
/**
* Returns the content of the CSS to be used in editor content
*
* @return string
* @return array
*/
public function editor_css_files() {
global $CFG;
$files = array();
// first editor plugins
// First editor plugins.
$plugins = core_component::get_plugin_list('editor');
foreach ($plugins as $plugin=>$fulldir) {
$sheetfile = "$fulldir/editor_styles.css";
@ -609,8 +613,8 @@ class theme_config {
$files['plugin_'.$plugin] = $sheetfile;
}
}
// then parent themes
foreach (array_reverse($this->parent_configs) as $parent_config) { // base first, the immediate parent last
// Then parent themes - base first, the immediate parent last.
foreach (array_reverse($this->parent_configs) as $parent_config) {
if (empty($parent_config->editor_sheets)) {
continue;
}
@ -621,7 +625,7 @@ class theme_config {
}
}
}
// finally this theme
// Finally this theme.
if (!empty($this->editor_sheets)) {
foreach ($this->editor_sheets as $sheet) {
$sheetfile = "$this->dir/style/$sheet.css";
@ -635,10 +639,10 @@ class theme_config {
}
/**
* Get the stylesheet URL of this theme
* Get the stylesheet URL of this theme.
*
* @param moodle_page $page Not used... deprecated?
* @return array of moodle_url
* @return moodle_url[]
*/
public function css_urls(moodle_page $page) {
global $CFG;
@ -679,50 +683,7 @@ class theme_config {
$urls[] = $url;
} else {
// find out the current CSS and cache it now for 5 seconds
// the point is to construct the CSS only once and pass it through the
// dataroot to the script that actually serves the sheets
if (!defined('THEME_DESIGNER_CACHE_LIFETIME')) {
define('THEME_DESIGNER_CACHE_LIFETIME', 4); // this can be also set in config.php
}
$candidatedir = "$CFG->cachedir/theme/$this->name";
if ($svg) {
$candidatesheet = "$candidatedir/designer.ser";
} else {
$candidatesheet = "$candidatedir/designer_nosvg.ser";
}
$rebuild = true;
if (file_exists($candidatesheet) and filemtime($candidatesheet) > time() - THEME_DESIGNER_CACHE_LIFETIME) {
if ($css = file_get_contents($candidatesheet)) {
$css = unserialize($css);
if (is_array($css)) {
$rebuild = false;
}
}
}
if ($rebuild) {
// Prepare the CSS optimiser if it is to be used,
// please note that it may be very slow and is therefore strongly discouraged in theme designer mode.
$optimiser = null;
if (!empty($CFG->enablecssoptimiser) && $this->supportscssoptimisation) {
require_once($CFG->dirroot.'/lib/csslib.php');
$optimiser = new css_optimiser;
}
$css = $this->css_content($optimiser);
// We do not want any errors here because this may fail easily because of the concurrent access.
$prevabort = ignore_user_abort(true);
check_dir_exists($candidatedir);
$tempfile = tempnam($candidatedir, 'tmpdesigner');
file_put_contents($tempfile, serialize($css));
$reporting = error_reporting(0);
chmod($tempfile, $CFG->filepermissions);
unlink($candidatesheet); // Do not rely on rename() deleting original, they may decide to change it at any time as usually.
rename($tempfile, $candidatesheet);
error_reporting($reporting);
ignore_user_abort($prevabort);
}
$css = $this->get_css_files(true);
$baseurl = new moodle_url($CFG->httpswwwroot.'/theme/styles_debug.php');
if (!$svg) {
// We add an SVG param so that we know not to serve SVG images.
@ -730,10 +691,10 @@ class theme_config {
$baseurl->param('svg', '0');
}
if (core_useragent::is_ie()) {
// lalala, IE does not allow more than 31 linked CSS files from main document
// Lalala, IE does not allow more than 31 linked CSS files from main document.
$urls[] = new moodle_url($baseurl, array('theme'=>$this->name, 'type'=>'ie', 'subtype'=>'plugins'));
foreach ($css['parents'] as $parent=>$sheets) {
// We need to serve parents individually otherwise we may easily exceed the style limit IE imposes (4096)
// We need to serve parents individually otherwise we may easily exceed the style limit IE imposes (4096).
$urls[] = new moodle_url($baseurl, array('theme'=>$this->name,'type'=>'ie', 'subtype'=>'parents', 'sheet'=>$parent));
}
$urls[] = new moodle_url($baseurl, array('theme'=>$this->name, 'type'=>'ie', 'subtype'=>'theme'));
@ -748,7 +709,8 @@ class theme_config {
}
}
foreach ($css['theme'] as $sheet=>$unused) {
$urls[] = new moodle_url($baseurl, array('sheet'=>$sheet, 'theme'=>$this->name, 'type'=>'theme')); // sheet first in order to make long urls easier to read
// Sheet first in order to make long urls easier to read.
$urls[] = new moodle_url($baseurl, array('sheet'=>$sheet, 'theme'=>$this->name, 'type'=>'theme'));
}
}
}
@ -757,14 +719,169 @@ class theme_config {
}
/**
* Returns an array of organised CSS files required for this output
* Get the whole css stylesheet for production mode.
*
* @return array
* NOTE: this method is not expected to be used from any addons.
*
* @return string CSS markup, already optimised and compressed
*/
public function css_files() {
public function get_css_content() {
global $CFG;
require_once($CFG->dirroot.'/lib/csslib.php');
$csscontent = '';
foreach ($this->get_css_files(false) as $value) {
foreach ($value as $val) {
if (is_array($val)) {
foreach ($val as $v) {
$csscontent .= file_get_contents($v) . "\n";
}
} else {
$csscontent .= file_get_contents($val) . "\n";
}
}
}
$csscontent = $this->post_process($csscontent);
if (!empty($CFG->enablecssoptimiser) && $this->supportscssoptimisation) {
// This is an experimental feature introduced in Moodle 2.3
// The CSS optimiser organises the CSS in order to reduce the overall number
// of rules and styles being sent to the client. It does this by collating
// the CSS before it is cached removing excess styles and rules and stripping
// out any extraneous content such as comments and empty rules.
$optimiser = new css_optimiser();
$csscontent = $optimiser->process($csscontent);
} else {
$csscontent = core_minify::css($csscontent);
}
return $csscontent;
}
/**
* Get the theme designer css markup,
* the parameters are coming from css_urls().
*
* NOTE: this method is not expected to be used from any addons.
*
* @param string $type
* @param string $subtype
* @param string $sheet
* @return string CSS markup
*/
public function get_css_content_debug($type, $subtype, $sheet) {
global $CFG;
require_once($CFG->dirroot.'/lib/csslib.php');
$optimiser = null;
if (!empty($CFG->enablecssoptimiser) && $this->supportscssoptimisation) {
// This is an experimental feature introduced in Moodle 2.3
// The CSS optimiser organises the CSS in order to reduce the overall number
// of rules and styles being sent to the client. It does this by collating
// the CSS before it is cached removing excess styles and rules and stripping
// out any extraneous content such as comments and empty rules.
$optimiser = new css_optimiser();
}
$cssfiles = array();
$css = $this->get_css_files(true);
if ($type === 'ie') {
// IE is a sloppy browser with weird limits, sorry.
if ($subtype === 'plugins') {
$cssfiles = $css['plugins'];
} else if ($subtype === 'parents') {
if (empty($sheet)) {
// Do not bother with the empty parent here.
} else {
// Build up the CSS for that parent so we can serve it as one file.
foreach ($css[$subtype][$sheet] as $parent => $css) {
$cssfiles[] = $css;
}
}
} else if ($subtype === 'theme') {
$cssfiles = $css['theme'];
}
} else if ($type === 'plugin') {
if (isset($css['plugins'][$subtype])) {
$cssfiles[] = $css['plugins'][$subtype];
}
} else if ($type === 'parent') {
if (isset($css['parents'][$subtype][$sheet])) {
$cssfiles[] = $css['parents'][$subtype][$sheet];
}
} else if ($type === 'theme') {
if (isset($css['theme'][$sheet])) {
$cssfiles[] = $css['theme'][$sheet];
}
}
$csscontent = '';
foreach ($cssfiles as $file) {
$contents = file_get_contents($file);
$contents = $this->post_process($contents);
$comment = "/** Path: $type $subtype $sheet.' **/\n";
$stats = '';
if ($optimiser) {
$contents = $optimiser->process($contents);
if (!empty($CFG->cssoptimiserstats)) {
$stats = $optimiser->output_stats_css();
}
}
$csscontent .= $comment.$stats.$contents."\n\n";
}
return $csscontent;
}
/**
* Get the whole css stylesheet for editor iframe.
*
* NOTE: this method is not expected to be used from any addons.
*
* @return string CSS markup
*/
public function get_css_content_editor() {
// Do not bother to optimise anything here, just very basic stuff.
$cssfiles = $this->editor_css_files();
$css = '';
foreach ($cssfiles as $file) {
$css .= file_get_contents($file)."\n";
}
return $this->post_process($css);
}
/**
* Returns an array of organised CSS files required for this output.
*
* @param bool $themedesigner
* @return array nested array of file paths
*/
protected function get_css_files($themedesigner) {
global $CFG;
$cache = null;
if ($themedesigner) {
require_once($CFG->dirroot.'/lib/csslib.php');
// We need some kind of caching here because otherwise the page navigation becomes
// way too slow in theme designer mode. Feel free to create full cache definition later...
$cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'core', 'themedesigner', array('theme' => $this->name));
if ($files = $cache->get('cssfiles')) {
if ($files['created'] > time() - THEME_DESIGNER_CACHE_LIFETIME) {
unset($files['created']);
return $files;
}
}
}
$cssfiles = array('plugins'=>array(), 'parents'=>array(), 'theme'=>array());
// get all plugin sheets
// Get all plugin sheets.
$excludes = $this->resolve_excludes('plugins_exclude_sheets');
if ($excludes !== true) {
foreach (core_component::get_plugin_types() as $type=>$unused) {
@ -802,10 +919,10 @@ class theme_config {
}
}
// find out wanted parent sheets
// Find out wanted parent sheets.
$excludes = $this->resolve_excludes('parents_exclude_sheets');
if ($excludes !== true) {
foreach (array_reverse($this->parent_configs) as $parent_config) { // base first, the immediate parent last
foreach (array_reverse($this->parent_configs) as $parent_config) { // Base first, the immediate parent last.
$parent = $parent_config->name;
if (empty($parent_config->sheets) || (!empty($excludes[$parent]) and $excludes[$parent] === true)) {
continue;
@ -823,7 +940,7 @@ class theme_config {
}
}
// current theme sheets
// Current theme sheets.
if (is_array($this->sheets)) {
foreach ($this->sheets as $sheet) {
$sheetfile = "$this->dir/style/$sheet.css";
@ -833,57 +950,15 @@ class theme_config {
}
}
if ($cache) {
$files = $cssfiles;
$files['created'] = time();
$cache->set('cssfiles', $files);
}
return $cssfiles;
}
/**
* Returns the content of the one huge CSS merged from all style sheets.
*
* @param css_optimiser|null $optimiser A CSS optimiser to use during on the content. Null = don't optimise
* @return string
*/
public function css_content(css_optimiser $optimiser = null) {
$files = array_merge($this->css_files(), array('editor'=>$this->editor_css_files()));
$css = $this->css_files_get_contents($files, array(), $optimiser);
return $css;
}
/**
* Given an array of file paths or a single file path loads the contents of
* the CSS file, processes it then returns it in the same structure it was given.
*
* Can be used recursively on the results of {@link css_files}
*
* @param array|string $file An array of file paths or a single file path
* @param array $keys An array of previous array keys [recursive addition]
* @param css_optimiser|null $optimiser A CSS optimiser to use during on the content. Null = don't optimise
* @return The converted array or the contents of the single file ($file type)
*/
protected function css_files_get_contents($file, array $keys, css_optimiser $optimiser = null) {
global $CFG;
if (is_array($file)) {
// We use a separate array to keep everything in the exact same order.
$return = array();
foreach ($file as $key=>$f) {
$return[clean_param($key, PARAM_SAFEDIR)] = $this->css_files_get_contents($f, array_merge($keys, array($key)), $optimiser);
}
return $return;
} else {
$contents = file_get_contents($file);
$contents = $this->post_process($contents);
$comment = '/** Path: '.implode(' ', $keys).' **/'."\n";
$stats = '';
if (!is_null($optimiser)) {
$contents = $optimiser->process($contents);
if (!empty($CFG->cssoptimiserstats)) {
$stats = $optimiser->output_stats_css();
}
}
return $comment.$stats.$contents;
}
}
/**
* Generate a URL to the file that serves theme JavaScript files.
*
@ -1359,7 +1434,6 @@ class theme_config {
/**
* Return true if we should look for SVG images as well.
*
* @staticvar bool $svg
* @return bool
*/
public function use_svg_icons() {

View File

@ -22,20 +22,14 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// disable moodle specific debug messages and any errors in output,
// Disable moodle specific debug messages and any errors in output,
// comment out when debugging or better look into error log!
define('NO_DEBUG_DISPLAY', true);
// we need just the values from config.php and minlib.php
define('ABORT_AFTER_CONFIG', true);
require('../config.php'); // this stops immediately at the beginning of lib/setup.php
require('../config.php');
require_once($CFG->dirroot.'/lib/csslib.php');
if (!defined('THEME_DESIGNER_CACHE_LIFETIME')) {
define('THEME_DESIGNER_CACHE_LIFETIME', 4); // this can be also set in config.php
}
if ($slashargument = min_get_slash_argument()) {
$slashargument = ltrim($slashargument, '/');
if (substr_count($slashargument, '/') < 2) {
@ -43,7 +37,7 @@ if ($slashargument = min_get_slash_argument()) {
}
if (strpos($slashargument, '_s/') === 0) {
// Can't use SVG
// Can't use SVG.
$slashargument = substr($slashargument, 3);
$usesvg = false;
} else {
@ -79,9 +73,9 @@ if ($type === 'editor') {
}
if (file_exists("$CFG->dirroot/theme/$themename/config.php")) {
// exists
// The theme exists in standard location - ok.
} else if (!empty($CFG->themedir) and file_exists("$CFG->themedir/$themename/config.php")) {
// exists
// Alternative theme location contains this theme - ok.
} else {
header('HTTP/1.0 404 not found');
die('Theme was not found, sorry.');
@ -105,19 +99,18 @@ $etag = sha1($etag);
if (file_exists($candidatesheet)) {
if (!empty($_SERVER['HTTP_IF_NONE_MATCH']) || !empty($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
// we do not actually need to verify the etag value because our files
// never change in cache because we increment the rev parameter
// We do not actually need to verify the etag value because our files
// never change in cache because we increment the rev counter.
css_send_unmodified(filemtime($candidatesheet), $etag);
}
css_send_cached_css($candidatesheet, $etag);
}
//=================================================================================
// ok, now we need to start normal moodle script, we need to load all libs and $DB
// Ok, now we need to start normal moodle script, we need to load all libs and $DB.
define('ABORT_AFTER_CONFIG_CANCEL', true);
define('NO_MOODLE_COOKIES', true); // Session not used here
define('NO_UPGRADE_CHECK', true); // Ignore upgrade check
define('NO_MOODLE_COOKIES', true); // Session not used here.
define('NO_UPGRADE_CHECK', true); // Ignore upgrade check.
require("$CFG->dirroot/lib/setup.php");
@ -131,7 +124,7 @@ if ($themerev <= 0 or $themerev != $rev) {
$rev = $themerev;
$cache = false;
$candidatedir = "$CFG->cachedir/theme/$rev/$themename/css";
$candidatedir = "$CFG->localcachedir/theme/$rev/$themename/css";
$etag = "$rev/$themename/$type";
$candidatename = $type;
if (!$usesvg) {
@ -151,12 +144,13 @@ if ($themerev <= 0 or $themerev != $rev) {
make_localcache_directory('theme', false);
if ($type === 'editor') {
$cssfiles = $theme->editor_css_files();
css_store_css($theme, "$candidatedir/editor.css", $cssfiles, false);
$csscontent = $theme->get_css_content_editor();
css_store_css($theme, "$candidatedir/editor.css", $csscontent, false);
} else {
// Older IEs require smaller chunks.
$css = $theme->css_files();
$csscontent = $theme->get_css_content();
$relroot = preg_replace('|^http.?://[^/]+|', '', $CFG->wwwroot);
if (!empty($slashargument)) {
if ($usesvg) {
@ -171,36 +165,19 @@ if ($type === 'editor') {
$chunkurl = "{$relroot}/theme/styles.php?theme={$themename}&rev={$rev}&type=all&svg=0";
}
}
$cssfiles = array();
foreach ($css as $key => $value) {
foreach ($value as $val) {
if (is_array($val)) {
foreach ($val as $k=>$v) {
$cssfiles[] = $v;
}
} else {
$cssfiles[] = $val;
}
}
}
css_store_css($theme, "$candidatedir/all.css", $cssfiles, true, $chunkurl);
css_store_css($theme, "$candidatedir/all.css", $csscontent, true, $chunkurl);
}
// verify nothing failed in cache file creation
clearstatcache();
if (!file_exists($candidatesheet)) {
// We need to send at least something, IE does not get it chunked properly but who cares.
$css = '';
foreach ($cssfiles as $file) {
$css .= file_get_contents($file)."\n";
}
css_send_uncached_css($css, false);
if (!$cache) {
// Do not pollute browser caches if invalid revision requested,
// let's ignore legacy IE breakage here too.
css_send_uncached_css($csscontent);
} else if (!$cache) {
// Do not pollute browser caches if invalid revision requested.
css_send_uncached_css(file_get_contents($candidatesheet), false);
} else if ($chunk and file_exists($candidatesheet)) {
// Greetings stupid legacy IEs!
css_send_cached_css($candidatesheet, $etag);
} else {
// This is the expected result!
css_send_cached_css($candidatesheet, $etag);
// Real browsers - this is the expected result!
css_send_cached_css_content($csscontent, $etag);
}

View File

@ -25,100 +25,47 @@
// Disable moodle specific debug messages and any errors in output,
// comment out when debugging or better look into error log!
define('NO_DEBUG_DISPLAY', true);
define('NO_UPGRADE_CHECK', true);
define('NO_MOODLE_COOKIES', true);
define('ABORT_AFTER_CONFIG', true);
require('../config.php'); // this stops immediately at the beginning of lib/setup.php
require('../config.php');
require_once($CFG->dirroot.'/lib/csslib.php');
$themename = min_optional_param('theme', 'standard', 'SAFEDIR');
$type = min_optional_param('type', '', 'SAFEDIR');
$subtype = min_optional_param('subtype', '', 'SAFEDIR');
$sheet = min_optional_param('sheet', '', 'SAFEDIR');
$usesvg = (bool)min_optional_param('svg', '1', 'INT');
if (!defined('THEME_DESIGNER_CACHE_LIFETIME')) {
define('THEME_DESIGNER_CACHE_LIFETIME', 4); // this can be also set in config.php
}
$themename = optional_param('theme', 'standard', PARAM_SAFEDIR);
$type = optional_param('type', '', PARAM_SAFEDIR);
$subtype = optional_param('subtype', '', PARAM_SAFEDIR);
$sheet = optional_param('sheet', '', PARAM_SAFEDIR);
$usesvg = optional_param('svg', 1, PARAM_BOOL);
if (file_exists("$CFG->dirroot/theme/$themename/config.php")) {
// exists
// The theme exists in standard location - ok.
} else if (!empty($CFG->themedir) and file_exists("$CFG->themedir/$themename/config.php")) {
// exists
// Alternative theme location contains this theme - ok.
} else {
css_send_css_not_found();
}
// no gzip compression when debugging
if ($usesvg) {
$candidatesheet = "$CFG->cachedir/theme/$themename/designer.ser";
} else {
// Add to the sheet name, one day we'll be able to just drop this.
$candidatesheet = "$CFG->cachedir/theme/$themename/designer_nosvg.ser";
}
$css = false;
if (is_readable($candidatesheet) and filemtime($candidatesheet) > time() - THEME_DESIGNER_CACHE_LIFETIME) {
$css = @unserialize(file_get_contents($candidatesheet));
}
if (!is_array($css)) {
// Ok, we need to start normal moodle script, we need to load all libs and $DB.
define('ABORT_AFTER_CONFIG_CANCEL', true);
define('NO_MOODLE_COOKIES', true); // Session not used here.
define('NO_UPGRADE_CHECK', true); // Ignore upgrade check.
require("$CFG->dirroot/lib/setup.php");
$theme = theme_config::load($themename);
$css = $theme->css_content();
}
$theme = theme_config::load($themename);
$theme->force_svg_use($usesvg);
if ($type === 'editor') {
if (isset($css['editor'])) {
css_send_uncached_css($css['editor']);
}
} else if ($type === 'ie') {
// IE is a sloppy browser with weird limits, sorry
if ($subtype === 'plugins') {
css_send_uncached_css($css['plugins']);
$csscontent = $theme->get_css_content_editor();
css_send_uncached_css($csscontent);
}
} else if ($subtype === 'parents') {
$sendcss = array();
if (empty($sheet)) {
// If not specific parent has been specified as $sheet then build a
// collection of @import statements into this one sheet.
// We shouldn't ever actually get here, but none the less we'll deal
// with it incase we ever do.
// @import statements arn't processed until after concurrent CSS requests
// making them slightly evil.
foreach (array_keys($css['parents']) as $sheet) {
$sendcss[] = "@import url(styles_debug.php?theme=$themename&type=$type&subtype=$subtype&sheet=$sheet);";
}
} else {
// Build up the CSS for that parent so we can serve it as one file.
foreach ($css[$subtype][$sheet] as $parent=>$css) {
$sendcss[] = $css;
}
}
css_send_uncached_css($sendcss);
} else if ($subtype === 'theme') {
css_send_uncached_css($css['theme']);
}
} else if ($type === 'plugin') {
if (isset($css['plugins'][$subtype])) {
css_send_uncached_css($css['plugins'][$subtype]);
}
} else if ($type === 'parent') {
if (isset($css['parents'][$subtype][$sheet])) {
css_send_uncached_css($css['parents'][$subtype][$sheet]);
}
} else if ($type === 'theme') {
if (isset($css['theme'][$sheet])) {
css_send_uncached_css($css['theme'][$sheet]);
// We need some kind of caching here because otherwise the page navigation becomes
// way too slow in theme designer mode. Feel free to create full cache definition later...
$key = "$type $subtype $sheet $usesvg";
$cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'core', 'themedesigner', array('theme' => $themename));
if ($content = $cache->get($key)) {
if ($content['created'] > time() - THEME_DESIGNER_CACHE_LIFETIME) {
$csscontent = $content['data'];
css_send_uncached_css($csscontent);
}
}
css_send_css_not_found();
$csscontent = $theme->get_css_content_debug($type, $subtype, $sheet);
$cache->set($key, array('data' => $csscontent, 'created' => time()));
css_send_uncached_css($csscontent);

View File

@ -3,6 +3,8 @@ information provided here is intended especially for theme designer.
=== 2.7 ===
* CSS related functions in theme class and csslib.php were refactored, addons that are
using this private API need to be updated
* Please update your css to use 'tr:nth-of-type(odd/even)' instead of '.ro/.r1' to apply tr specific css for various tables.
These classes are deprecated now and will be removed in Moodle 2.9. This has done to better support styling tables that will be altered by JavaScript.
Here is an example to update your css: