mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 14:27:22 +01:00
Merge branch 'MDL-56959-master' of git://github.com/FMCorz/moodle
This commit is contained in:
commit
099a2aee68
@ -152,6 +152,9 @@ class theme_config {
|
|||||||
*/
|
*/
|
||||||
const DEFAULT_THEME = 'boost';
|
const DEFAULT_THEME = 'boost';
|
||||||
|
|
||||||
|
/** The key under which the SCSS file is stored amongst the CSS files. */
|
||||||
|
const SCSS_KEY = '__SCSS__';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array You can base your theme on other themes by linking to the other theme as
|
* @var array You can base your theme on other themes by linking to the other theme as
|
||||||
* parents. This lets you use the CSS and layouts from the other themes
|
* parents. This lets you use the CSS and layouts from the other themes
|
||||||
@ -294,7 +297,7 @@ class theme_config {
|
|||||||
* object as second parameter. A return value is not required, the tree can
|
* object as second parameter. A return value is not required, the tree can
|
||||||
* be edited in place.
|
* be edited in place.
|
||||||
*/
|
*/
|
||||||
public $csstreepostprocess = null;
|
public $csstreepostprocessor = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string Accessibility: Right arrow-like character is
|
* @var string Accessibility: Right arrow-like character is
|
||||||
@ -427,10 +430,18 @@ class theme_config {
|
|||||||
public $lessfile = false;
|
public $lessfile = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The SCSS file to compile. This takes precedence over the LESS file.
|
* The SCSS file to compile (without .scss), located in the scss/ folder of the theme.
|
||||||
* @var string
|
* Or a Closure, which receives the theme_config as argument and must
|
||||||
|
* return the SCSS content. This setting takes precedence over self::$lessfile.
|
||||||
|
* @var string|Closure
|
||||||
*/
|
*/
|
||||||
public $scssfile = false;
|
public $scss = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local cache of the SCSS property.
|
||||||
|
* @var false|array
|
||||||
|
*/
|
||||||
|
protected $scsscache = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the function to call to get the LESS code to inject.
|
* The name of the function to call to get the LESS code to inject.
|
||||||
@ -535,7 +546,7 @@ class theme_config {
|
|||||||
'rendererfactory', 'csspostprocess', 'editor_sheets', 'rarrow', 'larrow', 'uarrow', 'darrow',
|
'rendererfactory', 'csspostprocess', 'editor_sheets', 'rarrow', 'larrow', 'uarrow', 'darrow',
|
||||||
'hidefromselector', 'doctype', 'yuicssmodules', 'blockrtlmanipulations',
|
'hidefromselector', 'doctype', 'yuicssmodules', 'blockrtlmanipulations',
|
||||||
'lessfile', 'extralesscallback', 'lessvariablescallback', 'blockrendermethod',
|
'lessfile', 'extralesscallback', 'lessvariablescallback', 'blockrendermethod',
|
||||||
'scssfile', 'extrascsscallback', 'prescsscallback', 'csstreepostprocessor');
|
'scss', 'extrascsscallback', 'prescsscallback', 'csstreepostprocessor');
|
||||||
|
|
||||||
foreach ($config as $key=>$value) {
|
foreach ($config as $key=>$value) {
|
||||||
if (in_array($key, $configurable)) {
|
if (in_array($key, $configurable)) {
|
||||||
@ -815,7 +826,7 @@ class theme_config {
|
|||||||
// 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'=>'parents', 'sheet'=>$parent));
|
||||||
}
|
}
|
||||||
if (!empty($this->scssfile)) {
|
if ($this->get_scss_property()) {
|
||||||
// No need to define the type as IE here.
|
// No need to define the type as IE here.
|
||||||
$urls[] = new moodle_url($baseurl, array('theme' => $this->name, 'type' => 'scss'));
|
$urls[] = new moodle_url($baseurl, array('theme' => $this->name, 'type' => 'scss'));
|
||||||
} else if (!empty($this->lessfile)) {
|
} else if (!empty($this->lessfile)) {
|
||||||
@ -834,7 +845,7 @@ class theme_config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach ($css['theme'] as $sheet => $filename) {
|
foreach ($css['theme'] as $sheet => $filename) {
|
||||||
if ($sheet === $this->scssfile) {
|
if ($sheet === self::SCSS_KEY) {
|
||||||
// This is the theme SCSS file.
|
// This is the theme SCSS file.
|
||||||
$urls[] = new moodle_url($baseurl, array('theme' => $this->name, 'type' => 'scss'));
|
$urls[] = new moodle_url($baseurl, array('theme' => $this->name, 'type' => 'scss'));
|
||||||
} else if ($sheet === $this->lessfile) {
|
} else if ($sheet === $this->lessfile) {
|
||||||
@ -868,7 +879,7 @@ class theme_config {
|
|||||||
$csscontent .= file_get_contents($v) . "\n";
|
$csscontent .= file_get_contents($v) . "\n";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($type === 'theme' && $identifier === $this->scssfile) {
|
if ($type === 'theme' && $identifier === self::SCSS_KEY) {
|
||||||
// We need the content from SCSS because this is the SCSS file from the theme.
|
// We need the content from SCSS because this is the SCSS file from the theme.
|
||||||
$csscontent .= $this->get_css_content_from_scss(false);
|
$csscontent .= $this->get_css_content_from_scss(false);
|
||||||
} else if ($type === 'theme' && $identifier === $this->lessfile) {
|
} else if ($type === 'theme' && $identifier === $this->lessfile) {
|
||||||
@ -935,7 +946,7 @@ class theme_config {
|
|||||||
} else if ($subtype === 'theme') {
|
} else if ($subtype === 'theme') {
|
||||||
$cssfiles = $css['theme'];
|
$cssfiles = $css['theme'];
|
||||||
foreach ($cssfiles as $key => $value) {
|
foreach ($cssfiles as $key => $value) {
|
||||||
if (in_array($key, [$this->lessfile, $this->scssfile])) {
|
if (in_array($key, [$this->lessfile, self::SCSS_KEY])) {
|
||||||
// Remove the LESS/SCSS file from the theme CSS files.
|
// Remove the LESS/SCSS file from the theme CSS files.
|
||||||
// The LESS/SCSS files use the type 'less' or 'scss', not 'ie'.
|
// The LESS/SCSS files use the type 'less' or 'scss', not 'ie'.
|
||||||
unset($cssfiles[$key]);
|
unset($cssfiles[$key]);
|
||||||
@ -1075,15 +1086,13 @@ class theme_config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Current theme sheets and less file.
|
// Current theme sheets and less file.
|
||||||
// We first add the SCSS, or LESS file because we want the CSS ones to
|
// We first add the SCSS, or LESS file because we want the CSS ones to
|
||||||
// be included after the SCSS/LESS code. However, if both the SCSS/LESS file
|
// be included after the SCSS/LESS code. However, if both the LESS file
|
||||||
// and a CSS file share the same name, the CSS file is ignored.
|
// and a CSS file share the same name, the CSS file is ignored.
|
||||||
if (!empty($this->scssfile)) {
|
if ($this->get_scss_property()) {
|
||||||
$sheetfile = "{$this->dir}/scss/{$this->scssfile}.scss";
|
$cssfiles['theme'][self::SCSS_KEY] = true;
|
||||||
if (is_readable($sheetfile)) {
|
|
||||||
$cssfiles['theme'][$this->scssfile] = $sheetfile;
|
|
||||||
}
|
|
||||||
} else if (!empty($this->lessfile)) {
|
} else if (!empty($this->lessfile)) {
|
||||||
$sheetfile = "{$this->dir}/less/{$this->lessfile}.less";
|
$sheetfile = "{$this->dir}/less/{$this->lessfile}.less";
|
||||||
if (is_readable($sheetfile)) {
|
if (is_readable($sheetfile)) {
|
||||||
@ -1181,24 +1190,23 @@ class theme_config {
|
|||||||
protected function get_css_content_from_scss($themedesigner) {
|
protected function get_css_content_from_scss($themedesigner) {
|
||||||
global $CFG;
|
global $CFG;
|
||||||
|
|
||||||
$scssfile = $this->scssfile;
|
list($paths, $scss) = $this->get_scss_property();
|
||||||
if (!$scssfile || !is_readable($this->dir . '/scss/' . $scssfile . '.scss')) {
|
if (!$scss) {
|
||||||
throw new coding_exception('The theme did not define a SCSS file, or it is not readable.');
|
throw new coding_exception('The theme did not define a SCSS file, or it is not readable.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// We might need more memory to do this, so let's play safe.
|
// We might need more memory to do this, so let's play safe.
|
||||||
raise_memory_limit(MEMORY_EXTRA);
|
raise_memory_limit(MEMORY_EXTRA);
|
||||||
|
|
||||||
// Files list.
|
|
||||||
$files = $this->get_css_files($themedesigner);
|
|
||||||
|
|
||||||
// Get the SCSS file path.
|
|
||||||
$themescssfile = $files['theme'][$scssfile];
|
|
||||||
|
|
||||||
// Set-up the compiler.
|
// Set-up the compiler.
|
||||||
$compiler = new core_scss();
|
$compiler = new core_scss();
|
||||||
$compiler->prepend_raw_scss($this->get_pre_scss_code());
|
$compiler->prepend_raw_scss($this->get_pre_scss_code());
|
||||||
$compiler->set_file($themescssfile);
|
if (is_string($scss)) {
|
||||||
|
$compiler->set_file($scss);
|
||||||
|
} else {
|
||||||
|
$compiler->append_raw_scss($scss($this));
|
||||||
|
$compiler->setImportPaths($paths);
|
||||||
|
}
|
||||||
$compiler->append_raw_scss($this->get_extra_scss_code());
|
$compiler->append_raw_scss($this->get_extra_scss_code());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -1207,7 +1215,7 @@ class theme_config {
|
|||||||
|
|
||||||
} catch (\Leafo\ScssPhp\Exception $e) {
|
} catch (\Leafo\ScssPhp\Exception $e) {
|
||||||
$compiled = false;
|
$compiled = false;
|
||||||
debugging('Error while compiling SCSS ' . $scssfile . ' file: ' . $e->getMessage(), DEBUG_DEVELOPER);
|
debugging('Error while compiling SCSS: ' . $e->getMessage(), DEBUG_DEVELOPER);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to save memory.
|
// Try to save memory.
|
||||||
@ -1344,6 +1352,47 @@ class theme_config {
|
|||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the SCSS property.
|
||||||
|
*
|
||||||
|
* This resolves whether a SCSS file (or content) has to be used when generating
|
||||||
|
* the stylesheet for the theme. It will look at parents themes and check the
|
||||||
|
* SCSS properties there.
|
||||||
|
*
|
||||||
|
* @return False when SCSS is not used.
|
||||||
|
* An array with the import paths, and the path to the SCSS file or Closure as second.
|
||||||
|
*/
|
||||||
|
public function get_scss_property() {
|
||||||
|
if ($this->scsscache === null) {
|
||||||
|
$configs = [$this] + $this->parent_configs;
|
||||||
|
$scss = null;
|
||||||
|
|
||||||
|
foreach ($configs as $config) {
|
||||||
|
$path = "{$config->dir}/scss";
|
||||||
|
|
||||||
|
// We collect the SCSS property until we've found one.
|
||||||
|
if (empty($scss) && !empty($config->scss)) {
|
||||||
|
$candidate = is_string($config->scss) ? "{$path}/{$config->scss}.scss" : $config->scss;
|
||||||
|
if ($candidate instanceof Closure) {
|
||||||
|
$scss = $candidate;
|
||||||
|
} else if (is_string($candidate) && is_readable($candidate)) {
|
||||||
|
$scss = $candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We collect the import paths once we've found a SCSS property.
|
||||||
|
if ($scss && is_dir($path)) {
|
||||||
|
$paths[] = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->scsscache = $scss !== null ? [$paths, $scss] : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->scsscache;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a URL to the file that serves theme JavaScript files.
|
* Generate a URL to the file that serves theme JavaScript files.
|
||||||
*
|
*
|
||||||
@ -1521,8 +1570,8 @@ class theme_config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Post processing using an object representation of CSS.
|
// Post processing using an object representation of CSS.
|
||||||
$hastreeprocessor = !empty($this->csstreepostprocessor) && function_exists($this->csstreepostprocessor);
|
$treeprocessor = $this->get_css_tree_post_processor();
|
||||||
$needsparsing = $hastreeprocessor || !empty($this->rtlmode);
|
$needsparsing = !empty($treeprocessor) || !empty($this->rtlmode);
|
||||||
if ($needsparsing) {
|
if ($needsparsing) {
|
||||||
$parser = new core_cssparser($css);
|
$parser = new core_cssparser($css);
|
||||||
$csstree = $parser->parse();
|
$csstree = $parser->parse();
|
||||||
@ -1532,9 +1581,8 @@ class theme_config {
|
|||||||
$this->rtlize($csstree);
|
$this->rtlize($csstree);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($hastreeprocessor) {
|
if ($treeprocessor) {
|
||||||
$fn = $this->csstreepostprocessor;
|
$treeprocessor($csstree, $this);
|
||||||
$fn($csstree, $this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$css = $csstree->render();
|
$css = $csstree->render();
|
||||||
@ -2175,6 +2223,21 @@ class theme_config {
|
|||||||
// Default it to blocks.
|
// Default it to blocks.
|
||||||
return 'blocks';
|
return 'blocks';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the callable for CSS tree post processing.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function get_css_tree_post_processor() {
|
||||||
|
$configs = [$this] + $this->parent_configs;
|
||||||
|
foreach ($configs as $config) {
|
||||||
|
if ($config->csstreepostprocessor && is_callable($config->csstreepostprocessor)) {
|
||||||
|
return $config->csstreepostprocessor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,9 +27,11 @@ defined('MOODLE_INTERNAL') || die();
|
|||||||
require_once(__DIR__ . '/lib.php');
|
require_once(__DIR__ . '/lib.php');
|
||||||
|
|
||||||
$THEME->name = 'boost';
|
$THEME->name = 'boost';
|
||||||
$THEME->scssfile = 'preset';
|
|
||||||
$THEME->sheets = [];
|
$THEME->sheets = [];
|
||||||
$THEME->editor_sheets = [];
|
$THEME->editor_sheets = [];
|
||||||
|
$THEME->scss = function($theme) {
|
||||||
|
return theme_boost_get_main_scss_content($theme);
|
||||||
|
};
|
||||||
|
|
||||||
$THEME->layouts = [
|
$THEME->layouts = [
|
||||||
// Most backwards compatible layout without the blocks - this is the layout used by default.
|
// Most backwards compatible layout without the blocks - this is the layout used by default.
|
||||||
|
@ -46,38 +46,16 @@ function theme_boost_get_extra_scss($theme) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get SCSS to prepend.
|
* Returns the main SCSS content.
|
||||||
*
|
*
|
||||||
* @param theme_config $theme The theme config object.
|
* @param theme_config $theme The theme config object.
|
||||||
* @return array
|
* @return string
|
||||||
*/
|
*/
|
||||||
function theme_boost_get_pre_scss($theme) {
|
function theme_boost_get_main_scss_content($theme) {
|
||||||
global $CFG;
|
global $CFG;
|
||||||
|
|
||||||
$scss = '';
|
$scss = '';
|
||||||
$configurable = [
|
$filename = !empty($theme->settings->preset) ? $theme->settings->preset : null;
|
||||||
// Config key => [variableName, ...].
|
|
||||||
'brandcolor' => ['brand-primary'],
|
|
||||||
];
|
|
||||||
|
|
||||||
// Prepend variables first.
|
|
||||||
foreach ($configurable as $configkey => $targets) {
|
|
||||||
$value = $theme->settings->{$configkey};
|
|
||||||
if (empty($value)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
array_map(function($target) use (&$scss, $value) {
|
|
||||||
$scss .= '$' . $target . ': ' . $value . ";\n";
|
|
||||||
}, (array) $targets);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepend pre-scss.
|
|
||||||
if (!empty($theme->settings->scsspre)) {
|
|
||||||
$scss .= $theme->settings->scsspre;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now append the preset.
|
|
||||||
$filename = $theme->settings->preset;
|
|
||||||
$fs = get_file_storage();
|
$fs = get_file_storage();
|
||||||
|
|
||||||
$context = context_system::instance();
|
$context = context_system::instance();
|
||||||
@ -94,3 +72,37 @@ function theme_boost_get_pre_scss($theme) {
|
|||||||
|
|
||||||
return $scss;
|
return $scss;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get SCSS to prepend.
|
||||||
|
*
|
||||||
|
* @param theme_config $theme The theme config object.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function theme_boost_get_pre_scss($theme) {
|
||||||
|
global $CFG;
|
||||||
|
|
||||||
|
$scss = '';
|
||||||
|
$configurable = [
|
||||||
|
// Config key => [variableName, ...].
|
||||||
|
'brandcolor' => ['brand-primary'],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Prepend variables first.
|
||||||
|
foreach ($configurable as $configkey => $targets) {
|
||||||
|
$value = isset($theme->settings->{$configkey}) ? $theme->settings->{$configkey} : null;
|
||||||
|
if (empty($value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
array_map(function($target) use (&$scss, $value) {
|
||||||
|
$scss .= '$' . $target . ': ' . $value . ";\n";
|
||||||
|
}, (array) $targets);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepend pre-scss.
|
||||||
|
if (!empty($theme->settings->scsspre)) {
|
||||||
|
$scss .= $theme->settings->scsspre;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $scss;
|
||||||
|
}
|
||||||
|
@ -19,9 +19,10 @@ Removed themes:
|
|||||||
* CLI svgtool.php has moved from theme/base/cli to admin/cli and paths should be relative to the new location.
|
* CLI svgtool.php has moved from theme/base/cli to admin/cli and paths should be relative to the new location.
|
||||||
* Bootstrap 4 was added as part of a the new theme 'boost'.
|
* Bootstrap 4 was added as part of a the new theme 'boost'.
|
||||||
* Themes can now automatically compile SCSS on the fly. This works the same way as it
|
* Themes can now automatically compile SCSS on the fly. This works the same way as it
|
||||||
does compiling LESS on the fly, effecitvely adding $THEME->scssfile to your config.
|
does compiling LESS on the fly, effecitvely adding $THEME->scss to your config.
|
||||||
* Two new callbacks allow themes to inject SCSS code before and after the content provided
|
* Two new callbacks allow themes to inject SCSS code before and after the content provided
|
||||||
by the SCSS file $THEME->scssfile. See $THEME->prescsscallback and $THEME->extrascsscallback.
|
by the SCSS file $THEME->scss. See $THEME->prescsscallback and $THEME->extrascsscallback.
|
||||||
|
* $THEME->scss can also be a Closure which will return the main SCSS content.
|
||||||
* Using .dir-rtl for RTL styling is deprecated and should not be used any more. From now
|
* Using .dir-rtl for RTL styling is deprecated and should not be used any more. From now
|
||||||
the styles are automatically flipped when the language is right-to-left. However,
|
the styles are automatically flipped when the language is right-to-left. However,
|
||||||
as this is not always perfect, you can define exceptions. Please refer to the documentation
|
as this is not always perfect, you can define exceptions. Please refer to the documentation
|
||||||
|
Loading…
x
Reference in New Issue
Block a user