Commit 258143e3 authored by Frederic Massart's avatar Frederic Massart Committed by Frédéric Massart
Browse files

MDL-56005 output: Support prepending SCSS code instead of variables only

parent d9520bc0
......@@ -35,6 +35,8 @@ class core_scss extends \Leafo\ScssPhp\Compiler {
/** @var string The path to the SCSS file. */
protected $scssfile;
/** @var array Bits of SCSS content to prepend. */
protected $scssprepend = array();
/** @var array Bits of SCSS content. */
protected $scsscontent = array();
......@@ -58,6 +60,16 @@ class core_scss extends \Leafo\ScssPhp\Compiler {
$this->scsscontent[] = $scss;
}
/**
* Prepend raw SCSS to what's to compile.
*
* @param string $scss SCSS code.
* @return void
*/
public function prepend_raw_scss($scss) {
$this->scssprepend[] = $scss;
}
/**
* Set the file to compile from.
*
......@@ -78,7 +90,7 @@ class core_scss extends \Leafo\ScssPhp\Compiler {
* @return string
*/
public function to_css() {
$content = '';
$content = implode(';', $this->scssprepend);
if (!empty($this->scssfile)) {
$content .= file_get_contents($this->scssfile);
}
......
......@@ -444,10 +444,10 @@ class theme_config {
public $lessvariablescallback = null;
/**
* The name of the function to call to get extra SCSS variables.
* The name of the function to call to get SCSS to prepend.
* @var string
*/
public $scssvariablescallback = null;
public $prescsscallback = null;
/**
* Sets the render method that should be used for rendering custom block regions by scripts such as my/index.php
......@@ -528,7 +528,7 @@ class theme_config {
'rendererfactory', 'csspostprocess', 'editor_sheets', 'rarrow', 'larrow', 'uarrow', 'darrow',
'hidefromselector', 'doctype', 'yuicssmodules', 'blockrtlmanipulations',
'lessfile', 'extralesscallback', 'lessvariablescallback', 'blockrendermethod',
'scssfile', 'extrascsscallback', 'scssvariablescallback', 'csstreepostprocessor');
'scssfile', 'extrascsscallback', 'prescsscallback', 'csstreepostprocessor');
foreach ($config as $key=>$value) {
if (in_array($key, $configurable)) {
......@@ -1190,9 +1190,9 @@ class theme_config {
// Set-up the compiler.
$compiler = new core_scss();
$compiler->prepend_raw_scss($this->get_pre_scss_code());
$compiler->set_file($themescssfile);
$compiler->append_raw_scss($this->get_extra_scss_code());
$compiler->add_variables($this->get_scss_variables());
try {
// Compile!
......@@ -1244,64 +1244,63 @@ class theme_config {
}
/**
* Return extra SCSS variables to use when compiling.
* Return extra LESS code to add when compiling.
*
* This is intended to be used by themes to inject some LESS code
* before it gets compiled. If you want to inject variables you
* should use {@link self::get_less_variables()}.
*
* @return array Where keys are the variable names, and the values are the value.
* @return string The LESS code to inject.
*/
protected function get_scss_variables() {
$variables = array();
protected function get_extra_less_code() {
$content = '';
// Getting all the candidate functions.
$candidates = array();
foreach ($this->parent_configs as $parent_config) {
if (!isset($parent_config->scssvariablescallback)) {
if (!isset($parent_config->extralesscallback)) {
continue;
}
$candidates[] = $parent_config->scssvariablescallback;
$candidates[] = $parent_config->extralesscallback;
}
$candidates[] = $this->scssvariablescallback;
$candidates[] = $this->extralesscallback;
// Calling the functions.
foreach ($candidates as $function) {
if (function_exists($function)) {
$vars = $function($this);
if (!is_array($vars)) {
debugging('Callback ' . $function . ' did not return an array() as expected', DEBUG_DEVELOPER);
continue;
}
$variables = array_merge($variables, $vars);
$content .= "\n/** Extra LESS from $function **/\n" . $function($this) . "\n";
}
}
return $variables;
return $content;
}
/**
* Return extra LESS code to add when compiling.
* Return extra SCSS code to add when compiling.
*
* This is intended to be used by themes to inject some LESS code
* This is intended to be used by themes to inject some SCSS code
* before it gets compiled. If you want to inject variables you
* should use {@link self::get_less_variables()}.
* should use {@link self::get_scss_variables()}.
*
* @return string The LESS code to inject.
* @return string The SCSS code to inject.
*/
protected function get_extra_less_code() {
protected function get_extra_scss_code() {
$content = '';
// Getting all the candidate functions.
$candidates = array();
foreach ($this->parent_configs as $parent_config) {
if (!isset($parent_config->extralesscallback)) {
if (!isset($parent_config->extrascsscallback)) {
continue;
}
$candidates[] = $parent_config->extralesscallback;
$candidates[] = $parent_config->extrascsscallback;
}
$candidates[] = $this->extralesscallback;
$candidates[] = $this->extrascsscallback;
// Calling the functions.
foreach ($candidates as $function) {
if (function_exists($function)) {
$content .= "\n/** Extra LESS from $function **/\n" . $function($this) . "\n";
$content .= "\n/** Extra SCSS from $function **/\n" . $function($this) . "\n";
}
}
......@@ -1309,31 +1308,29 @@ class theme_config {
}
/**
* Return extra SCSS code to add when compiling.
* SCSS code to prepend when compiling.
*
* This is intended to be used by themes to inject some SCSS code
* before it gets compiled. If you want to inject variables you
* should use {@link self::get_scss_variables()}.
* This is intended to be used by themes to inject SCSS code before it gets compiled.
*
* @return string The SCSS code to inject.
*/
protected function get_extra_scss_code() {
protected function get_pre_scss_code() {
$content = '';
// Getting all the candidate functions.
$candidates = array();
foreach ($this->parent_configs as $parent_config) {
if (!isset($parent_config->extrascsscallback)) {
if (!isset($parent_config->prescsscallback)) {
continue;
}
$candidates[] = $parent_config->extrascsscallback;
$candidates[] = $parent_config->prescsscallback;
}
$candidates[] = $this->extrascsscallback;
$candidates[] = $this->prescsscallback;
// Calling the functions.
foreach ($candidates as $function) {
if (function_exists($function)) {
$content .= "\n/** Extra SCSS from $function **/\n" . $function($this) . "\n";
$content .= "\n/** Pre-SCSS from $function **/\n" . $function($this) . "\n";
}
}
......
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Admin setting for SCSS variables.
*
* @package theme_boost
* @copyright 2016 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Admin setting for SCSS variables class.
*
* @package theme_boost
* @copyright 2016 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class theme_boost_admin_setting_scss_variables extends admin_setting_configtextarea {
/**
* Validate data before storage.
*
* @param string $data The data.
* @return mixed True if validated, else an error string.
*/
public function validate($data) {
if (empty($data)) {
return true;
}
try {
theme_boost_parse_scss_variables($data, false);
} catch (moodle_exception $e) {
return $e->getMessage();
}
return true;
}
}
......@@ -146,6 +146,6 @@ $THEME->parents = [];
$THEME->enable_dock = false;
$THEME->csstreepostprocessor = 'theme_boost_css_tree_post_processor';
$THEME->extrascsscallback = 'theme_boost_get_extra_scss';
$THEME->scssvariablescallback = 'theme_boost_get_scss_variables';
$THEME->prescsscallback = 'theme_boost_get_pre_scss';
$THEME->yuicssmodules = array();
$THEME->rendererfactory = 'theme_overridden_renderer_factory';
......@@ -30,7 +30,6 @@ $string['brandcolor_desc'] = 'The accent colour.';
$string['choosereadme'] = 'Boost is a modern highly customizable theme. This theme is intended to be used directly, or used as a parent theme when creating new themes utilising Boostrap 4.';
$string['currentinparentheses'] = '(current)';
$string['configtitle'] = 'Boost';
$string['errorparsingscssvariables'] = 'There was an error parsing the variable at line {$a}, please double check the syntax.';
$string['generalsettings'] = 'General settings';
$string['pluginname'] = 'Boost';
$string['preset'] = 'Theme preset';
......@@ -41,8 +40,8 @@ $string['presetpaper'] = 'Paper';
$string['presetplain'] = 'Plain';
$string['presetreadable'] = 'Readable';
$string['rawscss'] = 'Raw SCSS';
$string['rawscss_desc'] = 'Use this field to provide SCSS code which will be injected at the end of the the stylesheet.';
$string['rawscss_desc'] = 'Use this field to provide SCSS code which will be injected at the end of the stylesheet.';
$string['rawscsspre'] = 'Raw initial SCSS';
$string['rawscsspre_desc'] = 'In this field you can provide initialising SCSS code, it will be injected before everything else. Most of the time you will use this setting to define variables.';
$string['region-side-post'] = 'Right';
$string['region-side-pre'] = 'Left';
$string['scssvariables'] = 'SCSS variables';
$string['scssvariables_desc'] = 'Use this field to set your own SCSS variable values. Define one variable per line. Syntax: $my-color: red;.';
......@@ -57,73 +57,33 @@ function theme_boost_get_extra_scss($theme) {
}
/**
* Get additional SCSS variables.
* Get SCSS to prepend.
*
* @param theme_config $theme The theme config object.
* @return array
*/
function theme_boost_get_scss_variables($theme) {
$variables = [];
function theme_boost_get_pre_scss($theme) {
$scss = '';
$configurable = [
// 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 (&$variables, $value) {
$variables[$target] = $value;
array_map(function($target) use (&$scss, $value) {
$scss .= '$' . $target . ': ' . $value . ";\n";
}, (array) $targets);
}
if (!empty($theme->settings->scss_variables)) {
$variables = array_merge($variables, theme_boost_parse_scss_variables($theme->settings->scss_variables));
// Prepend pre-scss.
if (!empty($theme->settings->scsspre)) {
$scss .= $theme->settings->scsspre;
}
return $variables;
}
/**
* Parse a string into SCSS variables.
*
* - One variable definition per line,
* - The variable name is separated from the value by a colon,
* - The dollar sign is optional,
* - The trailing semi-colon is optional,
* - CSS comments (starting with //) are accepted
* - Variables names can only contain letters, numbers, hyphens and underscores.
*
* @param string $data The string to parse from.
* @param bool $lenient When non lenient, an exception will be thrown when a line cannot be parsed.
* @return array
*/
function theme_boost_parse_scss_variables($data, $lenient = true) {
$variables = [];
$lines = explode("\n", $data);
$i = 0;
foreach ($lines as $line) {
$i++;
if (preg_match('@^\s*//@', $line)) {
continue;
}
$parts = explode(':', trim($line));
$variable = ltrim($parts[0], '$ ');
$value = rtrim(ltrim(isset($parts[1]) ? $parts[1] : ''), "; ");
if (empty($variable) || !preg_match('/^[a-z0-9_-]+$/i', $variable) || (empty($value) && !is_numeric($value))) {
if ($lenient) {
continue;
}
throw new moodle_exception('errorparsingscssvariables', 'theme_boost', null, $i);
}
$variables[$variable] = $value;
}
return $variables;
return $scss;
}
......@@ -58,13 +58,13 @@ if ($ADMIN->fulltree) {
// Advanced settings.
$page = new admin_settingpage('theme_boost_advanced', get_string('advancedsettings', 'theme_boost'));
// Raw SCSS for before the content.
$setting = new theme_boost_admin_setting_scss_variables('theme_boost/scss_variables',
get_string('scssvariables', 'theme_boost'), get_string('scssvariables_desc', 'theme_boost'), '', PARAM_RAW);
// Raw SCSS to include before the content.
$setting = new admin_setting_configtextarea('theme_boost/scsspre',
get_string('rawscsspre', 'theme_boost'), get_string('rawscsspre_desc', 'theme_boost'), '', PARAM_RAW);
$setting->set_updatedcallback('theme_reset_all_caches');
$page->add($setting);
// Raw SCSS for after the content.
// Raw SCSS to include after the content.
$setting = new admin_setting_configtextarea('theme_boost/scss', get_string('rawscss', 'theme_boost'),
get_string('rawscss_desc', 'theme_boost'), '', PARAM_RAW);
$setting->set_updatedcallback('theme_reset_all_caches');
......
......@@ -17,6 +17,8 @@ Removed themes:
* 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
does compiling LESS on the fly, effecitvely adding $THEME->scssfile to your config.
* 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.
* 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,
as this is not always perfect, you can define exceptions. Please refer to the documentation
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment