mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 05:58:34 +01:00
MDL-55224 output: Support automatic flipping to RTL styles
Part of MDL-55071
This commit is contained in:
parent
fbe18cc022
commit
1d987cae5f
81
lib/classes/cssparser.php
Normal file
81
lib/classes/cssparser.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Moodle implementation of CSS parsing.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2016 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
// TODO MDL-53016 Remove this when the latter is implemented.
|
||||
require_once($CFG->libdir . '/php-css-parser/Comment/Commentable.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Renderable.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Property/AtRule.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/RuleSet/RuleSet.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/RuleSet/AtRuleSet.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Parsing/SourceException.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/CSSList/CSSList.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/CSSList/CSSBlockList.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Value/Value.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Value/ValueList.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Value/CSSFunction.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Comment/Comment.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Value/PrimitiveValue.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/CSSList/AtRuleBlockList.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/CSSList/Document.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/CSSList/KeyFrame.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/OutputFormat.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Parser.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Parsing/OutputException.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Parsing/UnexpectedTokenException.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Property/Charset.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Property/CSSNamespace.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Property/Import.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Property/Selector.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Rule/Rule.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/RuleSet/DeclarationBlock.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Settings.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Value/Color.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Value/CSSString.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Value/RuleValueList.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Value/Size.php');
|
||||
require_once($CFG->libdir . '/php-css-parser/Value/URL.php');
|
||||
|
||||
/**
|
||||
* Moodle CSS parser.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2016 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_cssparser extends \Sabberworm\CSS\Parser {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $css The CSS content.
|
||||
*/
|
||||
public function __construct($css) {
|
||||
$settings = \Sabberworm\CSS\Settings::create();
|
||||
$settings->withLenientParsing();
|
||||
parent::__construct($css, $settings);
|
||||
}
|
||||
|
||||
}
|
61
lib/classes/rtlcss.php
Normal file
61
lib/classes/rtlcss.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Moodle implementation of RTLCSS.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2016 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
// TODO MDL-53016 Remove this when the latter is implemented.
|
||||
require_once($CFG->libdir . '/rtlcss/RTLCSS.php');
|
||||
|
||||
/**
|
||||
* Moodle RTLCSS class.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2016 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class core_rtlcss extends \MoodleHQ\RTLCSS\RTLCSS {
|
||||
|
||||
/**
|
||||
* Process a block declaration.
|
||||
*
|
||||
* This is overriden in order to provide a backwards compability with the plugins
|
||||
* who already defined RTL styles the old-fashioned way. Because we do not need
|
||||
* those any more we rename them so that they do not apply.
|
||||
*
|
||||
* @todo Remove the dir-rtl flipping when dir-rtl is fully deprecated.
|
||||
* @param \Sabberworm\CSS\RuleSet\RuleSet $node The object.
|
||||
* @return void
|
||||
*/
|
||||
protected function processDeclaration($node) {
|
||||
$selectors = $node instanceof \Sabberworm\CSS\RuleSet\DeclarationBlock ? $node->getSelectors() : [];
|
||||
foreach ($selectors as $selector) {
|
||||
// The blocks containing .dir-rtl are always accepted as is.
|
||||
if (strpos($selector->getSelector(), '.dir-rtl') !== false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return parent::processDeclaration($node);
|
||||
}
|
||||
|
||||
}
|
@ -404,6 +404,12 @@ class theme_config {
|
||||
*/
|
||||
private $usesvg = null;
|
||||
|
||||
/**
|
||||
* Whether in RTL mode or not.
|
||||
* @var bool
|
||||
*/
|
||||
protected $rtlmode = false;
|
||||
|
||||
/**
|
||||
* The LESS file to compile. When set, the theme will attempt to compile the file itself.
|
||||
* @var bool
|
||||
@ -748,6 +754,7 @@ class theme_config {
|
||||
$separate = (core_useragent::is_ie() && !core_useragent::check_ie_version('10'));
|
||||
|
||||
if ($rev > -1) {
|
||||
$filename = right_to_left() ? 'all-rtl' : 'all';
|
||||
$url = new moodle_url("$CFG->httpswwwroot/theme/styles.php");
|
||||
if (!empty($CFG->slasharguments)) {
|
||||
$slashargs = '';
|
||||
@ -756,13 +763,13 @@ class theme_config {
|
||||
// The underscore is used to ensure that it isn't a valid theme name.
|
||||
$slashargs .= '/_s'.$slashargs;
|
||||
}
|
||||
$slashargs .= '/'.$this->name.'/'.$rev.'/all';
|
||||
$slashargs .= '/'.$this->name.'/'.$rev.'/'.$filename;
|
||||
if ($separate) {
|
||||
$slashargs .= '/chunk0';
|
||||
}
|
||||
$url->set_slashargument($slashargs, 'noparam', true);
|
||||
} else {
|
||||
$params = array('theme' => $this->name,'rev' => $rev, 'type' => 'all');
|
||||
$params = array('theme' => $this->name,'rev' => $rev, 'type' => $filename);
|
||||
if (!$svg) {
|
||||
// We add an SVG param so that we know not to serve SVG images.
|
||||
// We do this because all modern browsers support SVG and this param will one day be removed.
|
||||
@ -784,6 +791,9 @@ class theme_config {
|
||||
// We do this because all modern browsers support SVG and this param will one day be removed.
|
||||
$baseurl->param('svg', '0');
|
||||
}
|
||||
if (right_to_left()) {
|
||||
$baseurl->param('rtl', 1);
|
||||
}
|
||||
if ($separate) {
|
||||
// We might need to chunk long files.
|
||||
$baseurl->param('chunk', '0');
|
||||
@ -899,14 +909,14 @@ class theme_config {
|
||||
// The SCSS file of the theme is requested.
|
||||
$csscontent = $this->get_css_content_from_scss(true);
|
||||
if ($csscontent !== false) {
|
||||
return $csscontent;
|
||||
return $this->post_process($csscontent);
|
||||
}
|
||||
return '';
|
||||
} else if ($type === 'less') {
|
||||
// The LESS file of the theme is requested.
|
||||
$csscontent = $this->get_css_content_from_less(true);
|
||||
if ($csscontent !== false) {
|
||||
return $csscontent;
|
||||
return $this->post_process($csscontent);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
@ -1172,8 +1182,6 @@ class theme_config {
|
||||
// Compile the CSS.
|
||||
$compiled = $compiler->getCss();
|
||||
|
||||
// Post process the entire thing.
|
||||
$compiled = $this->post_process($compiled);
|
||||
} catch (Less_Exception_Parser $e) {
|
||||
$compiled = false;
|
||||
debugging('Error while compiling LESS ' . $lessfile . ' file: ' . $e->getMessage(), DEBUG_DEVELOPER);
|
||||
@ -1218,7 +1226,6 @@ class theme_config {
|
||||
try {
|
||||
// Compile!
|
||||
$compiled = $compiler->to_css();
|
||||
$compiled = $this->post_process($compiled);
|
||||
|
||||
} catch (\Leafo\ScssPhp\Exception $e) {
|
||||
$compiled = false;
|
||||
@ -1531,6 +1538,23 @@ class theme_config {
|
||||
}
|
||||
}
|
||||
|
||||
// Post processing using an object representation of CSS.
|
||||
$needsparsing = !empty($this->rtlmode);
|
||||
if ($needsparsing) {
|
||||
$parser = new core_cssparser($css);
|
||||
$csstree = $parser->parse();
|
||||
unset($parser);
|
||||
}
|
||||
|
||||
if ($this->rtlmode) {
|
||||
$this->rtlize($csstree);
|
||||
}
|
||||
|
||||
if ($needsparsing) {
|
||||
$css = $csstree->render();
|
||||
unset($csstree);
|
||||
}
|
||||
|
||||
// now resolve all theme settings or do any other postprocessing
|
||||
$csspostprocess = $this->csspostprocess;
|
||||
if (function_exists($csspostprocess)) {
|
||||
@ -1540,6 +1564,17 @@ class theme_config {
|
||||
return $css;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flip a stylesheet to RTL.
|
||||
*
|
||||
* @param Object $csstree The parsed CSS tree structure to flip.
|
||||
* @return void
|
||||
*/
|
||||
protected function rtlize($csstree) {
|
||||
$rtlcss = new core_rtlcss($csstree);
|
||||
$rtlcss->flip();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL for an image
|
||||
*
|
||||
@ -1869,6 +1904,17 @@ class theme_config {
|
||||
$this->usesvg = (bool)$setting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to be in RTL mode.
|
||||
*
|
||||
* This will likely be used when post processing the CSS before serving it.
|
||||
*
|
||||
* @param bool $inrtl True when in RTL mode.
|
||||
*/
|
||||
public function set_rtl_mode($inrtl = true) {
|
||||
$this->rtlmode = $inrtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if file with any image extension exists.
|
||||
*
|
||||
|
@ -66,7 +66,7 @@ if ($slashargument = min_get_slash_argument()) {
|
||||
if ($type === 'editor') {
|
||||
// The editor CSS is never chunked.
|
||||
$chunk = null;
|
||||
} else if ($type === 'all') {
|
||||
} else if ($type === 'all' || $type === 'all-rtl') {
|
||||
// We're fine.
|
||||
} else {
|
||||
css_send_css_not_found();
|
||||
@ -116,6 +116,7 @@ require("$CFG->dirroot/lib/setup.php");
|
||||
|
||||
$theme = theme_config::load($themename);
|
||||
$theme->force_svg_use($usesvg);
|
||||
$theme->set_rtl_mode($type === 'all-rtl' ? true : false);
|
||||
|
||||
$themerev = theme_get_revision();
|
||||
|
||||
@ -150,7 +151,6 @@ if ($type === 'editor') {
|
||||
} else {
|
||||
|
||||
$lock = null;
|
||||
|
||||
// Lock system to prevent concurrent requests to compile LESS/SCSS, which is really slow and CPU intensive.
|
||||
// Each client should wait for one to finish the compilation before starting a new compiling process.
|
||||
// We only do this when the file will be cached...
|
||||
@ -173,19 +173,19 @@ if ($type === 'editor') {
|
||||
$relroot = preg_replace('|^http.?://[^/]+|', '', $CFG->wwwroot);
|
||||
if (!empty($slashargument)) {
|
||||
if ($usesvg) {
|
||||
$chunkurl = "{$relroot}/theme/styles.php/{$themename}/{$rev}/all";
|
||||
$chunkurl = "{$relroot}/theme/styles.php/{$themename}/{$rev}/$type";
|
||||
} else {
|
||||
$chunkurl = "{$relroot}/theme/styles.php/_s/{$themename}/{$rev}/all";
|
||||
$chunkurl = "{$relroot}/theme/styles.php/_s/{$themename}/{$rev}/$type";
|
||||
}
|
||||
} else {
|
||||
if ($usesvg) {
|
||||
$chunkurl = "{$relroot}/theme/styles.php?theme={$themename}&rev={$rev}&type=all";
|
||||
$chunkurl = "{$relroot}/theme/styles.php?theme={$themename}&rev={$rev}&type=$type";
|
||||
} else {
|
||||
$chunkurl = "{$relroot}/theme/styles.php?theme={$themename}&rev={$rev}&type=all&svg=0";
|
||||
$chunkurl = "{$relroot}/theme/styles.php?theme={$themename}&rev={$rev}&type=$type&svg=0";
|
||||
}
|
||||
}
|
||||
|
||||
css_store_css($theme, "$candidatedir/all.css", $csscontent, true, $chunkurl);
|
||||
css_store_css($theme, "$candidatedir/$type.css", $csscontent, true, $chunkurl);
|
||||
|
||||
// Release the lock.
|
||||
if ($lock) {
|
||||
|
@ -37,6 +37,7 @@ $subtype = optional_param('subtype', '', PARAM_SAFEDIR);
|
||||
$sheet = optional_param('sheet', '', PARAM_SAFEDIR);
|
||||
$usesvg = optional_param('svg', 1, PARAM_BOOL);
|
||||
$chunk = optional_param('chunk', null, PARAM_INT);
|
||||
$rtl = optional_param('rtl', false, PARAM_BOOL);
|
||||
|
||||
if (file_exists("$CFG->dirroot/theme/$themename/config.php")) {
|
||||
// The theme exists in standard location - ok.
|
||||
@ -48,6 +49,7 @@ if (file_exists("$CFG->dirroot/theme/$themename/config.php")) {
|
||||
|
||||
$theme = theme_config::load($themename);
|
||||
$theme->force_svg_use($usesvg);
|
||||
$theme->set_rtl_mode($rtl);
|
||||
|
||||
if ($type === 'editor') {
|
||||
$csscontent = $theme->get_css_content_editor();
|
||||
@ -55,11 +57,11 @@ if ($type === 'editor') {
|
||||
}
|
||||
|
||||
$chunkurl = new moodle_url($CFG->httpswwwroot . '/theme/styles_debug.php', array('theme' => $themename,
|
||||
'type' => $type, 'subtype' => $subtype, 'sheet' => $sheet, 'usesvg' => $usesvg));
|
||||
'type' => $type, 'subtype' => $subtype, 'sheet' => $sheet, 'usesvg' => $usesvg, 'rtl' => $rtl));
|
||||
|
||||
// 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";
|
||||
$key = "$type $subtype $sheet $usesvg $rtl";
|
||||
$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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user