Merge branch 'MDL-69215-master-2' of git://github.com/andrewnicols/moodle

This commit is contained in:
Jake Dallimore 2020-07-16 10:39:52 +08:00 committed by Sara Arjona
commit 988d0d4c50
12 changed files with 492 additions and 35 deletions

View File

@ -1,2 +1,2 @@
define ("core/icon_system_fontawesome",["core/icon_system","jquery","core/ajax","core/mustache","core/localstorage","core/url"],function(a,b,c,d,e,f){var g=null,h=null,i=function(){a.apply(this,arguments)};i.prototype=Object.create(a.prototype);i.prototype.init=function(){if(g){return b.when(this)}var a=e.get("core/iconmap-fontawesome");if(a){a=JSON.parse(a)}if(a){g=a;return b.when(this)}if(null===h){h=c.call([{methodname:"core_output_load_fontawesome_icon_map",args:[]}],!0,!1,!1,0,M.cfg.themerev)[0]}return h.then(function(a){g={};b.each(a,function(a,b){g[b.component+"/"+b.pix]=b.to});e.set("core/iconmap-fontawesome",JSON.stringify(g));return this}.bind(this))};i.prototype.renderIcon=function(a,b,c,e){var h=g[b+"/"+a],i=!1;if("undefined"==typeof h){var j=f.imageUrl(a,b);i={attributes:[{name:"src",value:j},{name:"alt",value:c},{name:"title",value:c}]}}var k={key:h,title:c,alt:c,unmappedIcon:i};if("undefined"==typeof c||""===c){k["aria-hidden"]=!0}var l=d.render(e,k);return l.trim()};i.prototype.getTemplateName=function(){return"core/pix_icon_fontawesome"};return i});
define ("core/icon_system_fontawesome",["core/icon_system","jquery","core/ajax","core/mustache","core/localstorage","core/url"],function(a,b,c,d,e,f){var g=null,h=null,i=function(){a.apply(this,arguments)};i.prototype=Object.create(a.prototype);i.prototype.init=function(){if(g){return b.when(this)}var a=e.get("core/iconmap-fontawesome");if(a){a=JSON.parse(a)}if(a){g=a;return b.when(this)}if(null===h){h=c.call([{methodname:"core_output_load_fontawesome_icon_system_map",args:{themename:M.cfg.theme}}],!0,!1,!1,0,M.cfg.themerev)[0]}return h.then(function(a){g={};b.each(a,function(a,b){g[b.component+"/"+b.pix]=b.to});e.set("core/iconmap-fontawesome",JSON.stringify(g));return this}.bind(this))};i.prototype.renderIcon=function(a,b,c,e){var h=g[b+"/"+a],i=!1;if("undefined"==typeof h){var j=f.imageUrl(a,b);i={attributes:[{name:"src",value:j},{name:"alt",value:c},{name:"title",value:c}]}}var k={key:h,title:c,alt:c,unmappedIcon:i};if("undefined"==typeof c||""===c){k["aria-hidden"]=!0}var l=d.render(e,k);return l.trim()};i.prototype.getTemplateName=function(){return"core/pix_icon_fontawesome"};return i});
//# sourceMappingURL=icon_system_fontawesome.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -58,8 +58,10 @@ define(['core/icon_system', 'jquery', 'core/ajax', 'core/mustache', 'core/locals
if (fetchMap === null) {
fetchMap = Ajax.call([{
methodname: 'core_output_load_fontawesome_icon_map',
args: []
methodname: 'core_output_load_fontawesome_icon_system_map',
args: {
themename: M.cfg.theme,
},
}], true, false, false, 0, M.cfg.themerev)[0];
}

View File

@ -0,0 +1,98 @@
<?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/>.
/**
* A web service to load the mapping of moodle pix names to fontawesome icon names.
*
* @package core
* @category external
* @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\external\output\icon_system;
use external_api;
use external_function_parameters;
use external_multiple_structure;
use external_single_structure;
use external_value;
use core\output\icon_system_fontawesome;
use theme_config;
/**
* Web service to load font awesome icon maps.
*
* @package core
* @category external
* @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class load_fontawesome_map extends external_api {
/**
* Description of the parameters suitable for the `execute` function.
*
* @return external_function_parameters
*/
public static function execute_parameters() {
return new external_function_parameters([
'themename' => new external_value(PARAM_ALPHANUMEXT, 'The theme to fetch the map for'),
]);
}
/**
* Return a mapping of icon names to icons.
*
* @param string $themename The theme to fetch icons for
* @return array the mapping
*/
public static function execute(string $themename) {
[
'themename' => $themename,
] = self::validate_parameters(self::execute_parameters(), [
'themename' => $themename,
]);
$theme = theme_config::load($themename);
$instance = icon_system_fontawesome::instance($theme->get_icon_system());
$result = [];
foreach ($instance->get_icon_name_map() as $from => $to) {
[$component, $pix] = explode(':', $from);
$result[] = [
'component' => $component,
'pix' => $pix,
'to' => $to,
];
}
return $result;
}
/**
* Description of the return value for the `execute` function.
*
* @return external_description
*/
public static function execute_returns() {
return new external_multiple_structure(new external_single_structure([
'component' => new external_value(PARAM_COMPONENT, 'The component for the icon.'),
'pix' => new external_value(PARAM_RAW, 'Value to map the icon from.'),
'to' => new external_value(PARAM_RAW, 'Value to map the icon to.'),
]));
}
}

View File

@ -34,6 +34,7 @@ use core_component;
use moodle_exception;
use context_system;
use theme_config;
use core\external\output\icon_system\load_fontawesome_map;
/**
* This class contains a list of webservice functions related to output.
@ -202,24 +203,13 @@ class external extends external_api {
/**
* Return a mapping of icon names to icons.
*
* @deprecated since Moodle 3.10
* @return array the mapping
*/
public static function load_fontawesome_icon_map() {
$instance = icon_system::instance(icon_system::FONTAWESOME);
global $PAGE;
$map = $instance->get_icon_name_map();
$result = [];
foreach ($map as $from => $to) {
list($component, $pix) = explode(':', $from);
$one = [];
$one['component'] = $component;
$one['pix'] = $pix;
$one['to'] = $to;
$result[] = $one;
}
return $result;
return load_fontawesome_map::execute($PAGE->theme->name);
}
/**
@ -228,13 +218,16 @@ class external extends external_api {
* @return external_description
*/
public static function load_fontawesome_icon_map_returns() {
return new external_multiple_structure(new external_single_structure(
array(
'component' => new external_value(PARAM_COMPONENT, 'The component for the icon.'),
'pix' => new external_value(PARAM_RAW, 'Value to map the icon from.'),
'to' => new external_value(PARAM_RAW, 'Value to map the icon to.')
)
));
return load_fontawesome_map::execute_returns();
}
/**
* The `load_fontawesome_icon_map` function has been replaced with
* @see load_fontawesome_map::execute()
*
* @return bool
*/
public static function load_fontawesome_icon_map_is_deprecated() {
return true;
}
}

View File

@ -79,15 +79,24 @@ abstract class icon_system {
global $PAGE;
if (empty(self::$instance)) {
$icontype = $PAGE->theme->get_icon_system();
self::$instance = new $icontype();
$iconsystem = $PAGE->theme->get_icon_system();
self::$instance = new $iconsystem();
}
// If $type is specified we need to make sure that the theme icon system supports this type,
// if not, we will return a generic new instance of the $type.
if ($type === null || is_a(self::$instance, $type)) {
if ($type === null) {
// No type specified. Return the icon system for the current theme.
return self::$instance;
}
if (!static::is_valid_system($type)) {
throw new \coding_exception("Invalid icon system requested '{$type}'");
}
if (is_a(self::$instance, $type) && is_a($type, get_class(self::$instance), true)) {
// The requested type is an exact match for the current icon system.
return self::$instance;
} else {
// Return the requested icon system.
return new $type();
}
}
@ -99,7 +108,7 @@ abstract class icon_system {
* @return boolean
*/
public final static function is_valid_system($system) {
return class_exists($system) && is_subclass_of($system, self::class);
return class_exists($system) && is_a($system, static::class, true);
}
/**
@ -153,4 +162,3 @@ abstract class icon_system {
self::$instance = null;
}
}

View File

@ -38,7 +38,7 @@ defined('MOODLE_INTERNAL') || die();
* @copyright 2016 Damyon Wiese
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class icon_system_standard {
class icon_system_standard extends icon_system {
public function render_pix_icon(renderer_base $output, pix_icon $icon) {
$data = $icon->export_for_template($output);

View File

@ -1646,6 +1646,14 @@ $functions = array(
'loginrequired' => false,
'ajax' => true,
),
'core_output_load_fontawesome_icon_system_map' => array(
'classname' => 'core\external\output\icon_system\load_fontawesome_map',
'methodname' => 'execute',
'description' => 'Load the mapping of moodle pix names to fontawesome icon names',
'type' => 'read',
'loginrequired' => false,
'ajax' => true,
),
// Question related functions.
'core_question_update_flag' => array(
'classname' => 'core_question_external',

View File

@ -0,0 +1,98 @@
<?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/>.
/**
* External functions test for record_feedback_action.
*
* @package core
* @category test
* @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\external\output\icon_system;
use externallib_advanced_testcase;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
/**
* Class record_userfeedback_action_testcase
*
* @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass core\external\output\icon_system\load_fontawesome_map
*/
class load_fontawesome_map_testcase extends externallib_advanced_testcase {
/**
* Perform setup before these tests are run.
*/
public static function setUpBeforeClass(): void {
global $CFG;
// In normal operation the external_api classes will have been loaded by the caller.
// The load_fontawesome_map class should not need to supplement our lack of autoloading of these classes.
require_once($CFG->libdir . '/externallib.php');
}
/**
* Ensure that a valid theme which uses fontawesome returns a map.
*
* @covers ::execute_parameters
* @covers ::execute
* @covers ::execute_returns
* @dataProvider valid_fontawesome_theme_provider
* @param string $themename
*/
public function test_execute(string $themename): void {
$result = load_fontawesome_map::execute($themename);
$this->assertIsArray($result);
foreach ($result as $value) {
$this->assertArrayHasKey('component', $value);
$this->assertArrayHasKey('pix', $value);
$this->assertArrayHasKey('to', $value);
}
}
/**
* Ensure that an invalid theme cannot be loaded.
*/
public function test_execute_invalid_themename(): void {
$result = load_fontawesome_map::execute('invalidtheme');
$this->assertDebuggingCalled(
'This page should be using theme invalidtheme which cannot be initialised. Falling back to the site theme boost'
);
$this->assertIsArray($result);
}
/**
* Data provider for valid themes to use with the execute function.
*
* @return array
*/
public function valid_fontawesome_theme_provider(): array {
return [
'Boost theme' => ['boost'],
'Classic theme (extends boost)' => ['classic'],
];
}
}

View File

@ -0,0 +1,248 @@
<?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/>.
/**
* Unit tests for lib/outputcomponents.php.
*
* @package core
* @category test
* @copyright 2011 David Mudrak <david@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\output;
use advanced_testcase;
use coding_exception;
/**
* Unit tests for the `icon_system` class.
*
* @coversDefaultClass core\output\icon_system
*/
class icon_system_test extends advanced_testcase {
/**
* Check whether the supplied classes are valid icon subsystems of the supplied one.
*
* @covers ::is_valid_system
* @dataProvider is_valid_subsystem_provider
* @param string $parent The class to call ::is_valid_system() on
* @param string $system The class to request
* @param bool $expected Whether the supplied relationship is valid
*/
public function test_is_valid_subsystem(string $parent, string $system, bool $expected): void {
$this->assertEquals($expected, $parent::is_valid_system($system));
}
/**
* Ensure that the ::instance() function throws an appropriate Exception when an inappropriate relationship is
* specified.
*
* @covers ::instance
* @dataProvider invalid_instance_provider
* @param string $parent The class to call ::instance() on
* @param string $system The class to request
*/
public function test_invalid_instance(string $parent, string $system): void {
$this->expectException(coding_exception::class);
$this->expectExceptionMessage("Invalid icon system requested '{$system}'");
$parent::instance($system);
}
/**
* Ensure that the ::instance() function returns an instance of the supplied system for a valid icon system
* relationship.
*
* @covers ::instance
* @dataProvider valid_instance_provider
* @param string $parent The class to call ::instance() on
* @param string $system The class to request
*/
public function test_valid_instance(string $parent, string $system): void {
$instance = $parent::instance($system);
$this->assertInstanceOf($parent, $instance);
$this->assertInstanceOf($system, $instance);
}
/**
* Ensure that subsequent calls without arguments to ::instance() return the exact same instance.
*
* @covers ::instance
*/
public function test_instance_singleton(): void {
$singleton = icon_system::instance();
// Calling instance() again returns the same singleton.
$this->assertSame($singleton, icon_system::instance());
}
/**
* Ensure thaat subsequent calls with an argument to ::instance() return the exact same instance.
*
* @covers ::instance
*/
public function test_instance_singleton_named_default(): void {
global $PAGE;
$singleton = icon_system::instance();
$defaultsystem = $PAGE->theme->get_icon_system();
$this->assertSame($singleton, icon_system::instance($defaultsystem));
}
/**
* Ensure that ::instance() returns an instance of the correct icon system when requested on the core icon_system
* class.
*
* @covers ::instance
* @dataProvider valid_instance_provider
* @param string $parent The class to call ::instance() on
* @param string $child The class to request
*/
public function test_instance_singleton_named(string $parent, string $child): void {
$iconsystem = icon_system::instance($child);
$this->assertInstanceOf($child, $iconsystem);
}
/**
* Ensure that ::instance() returns an instance of the correct icon system when called on a named parent class.
*
* @covers ::instance
* @dataProvider valid_instance_provider
* @param string $parent The class to call ::instance() on
* @param string $child The class to request
*/
public function test_instance_singleton_named_child(string $parent, string $child): void {
$iconsystem = $parent::instance($child);
$this->assertInstanceOf($parent, $iconsystem);
$this->assertInstanceOf($child, $iconsystem);
}
/**
* Ensure that the ::reset_caches() function resets the stored instance such that ::instance() returns a new
* instance in subsequent calls.
*
* @covers ::instance
* @covers ::reset_caches
*/
public function test_instance_singleton_reset(): void {
$singleton = icon_system::instance();
// Reset the cache.
icon_system::reset_caches();
// Calling instance() again returns a new singleton.
$newsingleton = icon_system::instance();
$this->assertNotSame($singleton, $newsingleton);
// Calling it again gets the new singleton.
$this->assertSame($newsingleton, icon_system::instance());
}
/**
* Returns data for data providers containing:
* - parent icon system
* - child icon system
* - whether it is a valid child
*
* @return array
*/
public function icon_system_provider(): array {
return [
'icon_system => icon_system_standard' => [
icon_system::class,
icon_system_standard::class,
true,
],
'icon_system => icon_system_fontawesome' => [
icon_system::class,
icon_system_fontawesome::class,
true,
],
'icon_system => \theme_classic\output\icon_system_fontawesome' => [
icon_system::class,
\theme_classic\output\icon_system_fontawesome::class,
true,
],
'icon_system => notification' => [
icon_system::class,
notification::class,
false,
],
'icon_system_standard => icon_system_standard' => [
icon_system_standard::class,
icon_system_standard::class,
true,
],
'icon_system_standard => icon_system_fontawesome' => [
icon_system_standard::class,
icon_system_fontawesome::class,
false,
],
'icon_system_standard => \theme_classic\output\icon_system_fontawesome' => [
icon_system_standard::class,
\theme_classic\output\icon_system_fontawesome::class,
false,
],
'icon_system_fontawesome => icon_system_standard' => [
icon_system_fontawesome::class,
icon_system_standard::class,
false,
],
];
}
/**
* Data provider for tests of `is_valid`.
*
* @return array
*/
public function is_valid_subsystem_provider(): array {
return $this->icon_system_provider();
}
/**
* Data provider for tests of `instance` containing only invalid tests.
*
* @return array
*/
public function invalid_instance_provider(): array {
return array_filter(
$this->icon_system_provider(),
function($data) {
return !$data[2];
},
ARRAY_FILTER_USE_BOTH
);
}
/**
* Data provider for tests of `instance` containing only valid tests.
*
* @return array
*/
public function valid_instance_provider(): array {
return array_filter(
$this->icon_system_provider(),
function($data) {
return $data[2];
},
ARRAY_FILTER_USE_BOTH
);
}
}

View File

@ -29,6 +29,8 @@ information provided here is intended especially for developers.
- course_in_list (now: core_course_list_element)
- coursecat (now: core_course_category)
* The form element 'htmleditor', which was deprecated in 3.6, has been removed.
* The `core_output_load_fontawesome_icon_map` web service has been deprecated and replaced by
`core_output_load_fontawesome_icon_system_map` which takes the name of the theme to generate the icon system map for.
=== 3.9 ===
* Following function has been deprecated, please use \core\task\manager::run_from_cli().

View File

@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
$version = 2020071100.01; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2020071500.00; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
$release = '4.0dev (Build: 20200711)'; // Human-friendly version name