mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
MDL-52715 lib: Addition of new requirements class.
This adds a fragment requirements class to allow plugins to register JavaScript to be used in an mform.
This commit is contained in:
parent
c9d91bb734
commit
cc73ea075e
1
lib/amd/build/fragment.min.js
vendored
Normal file
1
lib/amd/build/fragment.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
define(["jquery","core/ajax"],function(a,b){var c=function(c,d,e){var f=[];for(var g in e)f.push({name:g,value:e[g]});var h=a.Deferred(),i=b.call([{methodname:"core_get_fragment",args:{component:c,callback:d,args:f}}],!1);return i[0].done(function(a){h.resolve(a)}).fail(function(a){h.reject(a)}),h.promise()};return{fragment_load:function(a,b,d){return c(a,b,d)},fragment_append:function(b,d,e,f,g){a("#fragment-html").empty(),Y.on("#fragment-html").detach(),a("#fragment-html").remove(),a("#ajax-import-scripts").empty(),Y.on("#ajax-import-scripts").detach(),a("#ajax-import-scripts").remove(),a.when(c("mod_assign","fragment",e)).then(function(b){a(f).append('<div id="fragment-html">'),a(f).append("</div>"),a("#fragment-html").append(b.html),a(g).append('<div id="ajax-import-scripts">'),a(g).append("</div>"),a("#ajax-import-scripts").append(b.javascript)})}}});
|
116
lib/amd/src/fragment.js
Normal file
116
lib/amd/src/fragment.js
Normal file
@ -0,0 +1,116 @@
|
||||
// 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 way to call HTML fragments to be inserted as required via JavaScript.
|
||||
*
|
||||
* @module core/fragment
|
||||
* @class fragment
|
||||
* @package core
|
||||
* @copyright 2016 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since 3.1
|
||||
*/
|
||||
define(['jquery', 'core/ajax'], function($, ajax) {
|
||||
|
||||
/**
|
||||
* Loads an HTML fragment through a callback.
|
||||
*
|
||||
* @method load_fragment
|
||||
* @param {string} component Component where callback is located.
|
||||
* @param {string} callback Callback function name.
|
||||
* @param {object} params Parameters for the callback.
|
||||
* @return {Promise} JQuery promise object resolved when the fragment has been loaded.
|
||||
*/
|
||||
var load_fragment = function(component, callback, params) {
|
||||
// Change params into required webservice format.
|
||||
var formattedparams = [];
|
||||
for (var index in params) {
|
||||
formattedparams.push({name: index, value: params[index]});
|
||||
}
|
||||
|
||||
// Ajax stuff.
|
||||
var deferred = $.Deferred();
|
||||
|
||||
var promises = ajax.call([{
|
||||
methodname: 'core_get_fragment',
|
||||
args:{
|
||||
component: component,
|
||||
callback: callback,
|
||||
args: formattedparams
|
||||
}
|
||||
}], false);
|
||||
|
||||
// Worth noting somewhere that the assign module seems to require userid, rownum etc. to be passed via POST / GET.
|
||||
|
||||
promises[0].done(function(data) {
|
||||
deferred.resolve(data);
|
||||
}).fail(function(ex) {
|
||||
deferred.reject(ex);
|
||||
});
|
||||
return deferred.promise();
|
||||
};
|
||||
|
||||
return /** @alias module:core/fragment */{
|
||||
|
||||
/**
|
||||
* Loads an HTML fragment through a callback.
|
||||
*
|
||||
* @method fragment_load
|
||||
* @param {string} component Component where callback is located.
|
||||
* @param {string} callback Callback function name.
|
||||
* @param {object} params Parameters for the callback.
|
||||
* @return {Promise} JQuery promise object resolved when the fragment has been loaded.
|
||||
*/
|
||||
fragment_load: function(component, callback, params) {
|
||||
|
||||
return load_fragment(component, callback, params);
|
||||
},
|
||||
|
||||
/**
|
||||
* Appends HTML and JavaScript fragments to specified nodes.
|
||||
*
|
||||
* @method fragment_append
|
||||
* @param {string} component Component where callback is located.
|
||||
* @param {string} callback Callback function name.
|
||||
* @param {object} params Parameters for the callback.
|
||||
* @param {string} htmlnodeidentifier The 'class' or 'id' to attach the HTML.
|
||||
* @param {string} javascriptnodeidentifier The 'class' or 'id' to attach the JavaScript.
|
||||
* @return {void}
|
||||
*/
|
||||
fragment_append: function(component, callback, params, htmlnodeidentifier, javascriptnodeidentifier) {
|
||||
// Clean up previous code if found first.
|
||||
$('#fragment-html').empty();
|
||||
Y.on('#fragment-html').detach();
|
||||
$('#fragment-html').remove();
|
||||
$('#ajax-import-scripts').empty();
|
||||
Y.on('#ajax-import-scripts').detach();
|
||||
$('#ajax-import-scripts').remove();
|
||||
// $(".moodle-dialogue-base").empty();
|
||||
// $(".moodle-dialogue-base").remove();
|
||||
|
||||
$.when(load_fragment('mod_assign', "fragment", params)).then(function(data) {
|
||||
// Attach new HTML and JavaScript.
|
||||
$(htmlnodeidentifier).append("<div id=\"fragment-html\">");
|
||||
$(htmlnodeidentifier).append("</div>");
|
||||
$('#fragment-html').append(data.html);
|
||||
|
||||
$(javascriptnodeidentifier).append("<div id=\"ajax-import-scripts\">");
|
||||
$(javascriptnodeidentifier).append("</div>");
|
||||
$('#ajax-import-scripts').append(data.javascript);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
@ -1051,6 +1051,16 @@ $functions = array(
|
||||
'ajax' => true,
|
||||
),
|
||||
|
||||
'core_get_fragment' => array(
|
||||
'classname' => 'core_external',
|
||||
'methodname' => 'get_fragment',
|
||||
'classpath' => 'lib/external/externallib.php',
|
||||
'description' => 'Return a fragment for inclusion, such as a JavaScript page.',
|
||||
'type' => 'read',
|
||||
'loginrequired' => false,
|
||||
'ajax' => true,
|
||||
),
|
||||
|
||||
|
||||
// === Calendar related functions ===
|
||||
|
||||
|
75
lib/external/externallib.php
vendored
75
lib/external/externallib.php
vendored
@ -260,4 +260,79 @@ class core_external extends external_api {
|
||||
'string' => new external_value(PARAM_RAW, 'translated string'))
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of get_fragment parameters
|
||||
*
|
||||
* @return external_function_parameters
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
public static function get_fragment_parameters() {
|
||||
return new external_function_parameters(
|
||||
array(
|
||||
'component' => new external_value(PARAM_RAW, 'Component for the callback e.g. mod_asign'),
|
||||
'callback' => new external_value(PARAM_RAW, 'Name of the callback to execute'),
|
||||
'args' => new external_multiple_structure(
|
||||
new external_single_structure(
|
||||
array(
|
||||
'name' => new external_value(PARAM_ALPHANUMEXT, 'param name'),
|
||||
'value' => new external_value(PARAM_TEXT, 'param value')
|
||||
)
|
||||
), 'args for the callback are optional', VALUE_OPTIONAL
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a HTML fragment for inserting into something. Initial use is for inserting mforms into
|
||||
* a page using AJAX.
|
||||
*
|
||||
* @param string $component Name of the component.
|
||||
* @param string $callback Function callback name.
|
||||
* @param array $args optional arguments for the callback.
|
||||
* @return array HTML and JavaScript fragments for insertion into stuff.
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
public static function get_fragment($component, $callback, $args = null) {
|
||||
global $PAGE;
|
||||
|
||||
$params = self::validate_parameters(self::get_fragment_parameters(),
|
||||
array(
|
||||
'component' => $component,
|
||||
'callback' => $callback,
|
||||
'args' => $args
|
||||
)
|
||||
);
|
||||
|
||||
// Reformat arguments into something less unwieldy.
|
||||
$arguments = array();
|
||||
foreach ($params['args'] as $paramargument) {
|
||||
$arguments[$paramargument['name']] = $paramargument['value'];
|
||||
}
|
||||
|
||||
// Remove warning about context not being set.
|
||||
$PAGE->set_context(context_system::instance());
|
||||
|
||||
$PAGE->set_requirements_for_fragments();
|
||||
$data = component_callback($params['component'], $params['callback'], $arguments);
|
||||
$jsfooter = $PAGE->requires->get_end_code();
|
||||
$output = array('html' => $data, 'javascript' => $jsfooter);
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of get_fragment() result value
|
||||
*
|
||||
* @return array
|
||||
* @since Moodle 3.1
|
||||
*/
|
||||
public static function get_fragment_returns() {
|
||||
return new external_single_structure(
|
||||
array(
|
||||
'html' => new external_value(PARAM_RAW, 'HTML fragment.'),
|
||||
'javascript' => new external_value(PARAM_RAW, 'JavaScript fragment')
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
191
lib/outputfragmentrequirementslib.php
Normal file
191
lib/outputfragmentrequirementslib.php
Normal file
@ -0,0 +1,191 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Library functions to facilitate the use of JavaScript in Moodle.
|
||||
*
|
||||
* Note: you can find history of this file in lib/ajax/ajaxlib.php
|
||||
*
|
||||
* @copyright 2016 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @package core
|
||||
* @category output
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* This class tracks all the things that are needed by the current page.
|
||||
*
|
||||
* Normally, the only instance of this class you will need to work with is the
|
||||
* one accessible via $PAGE->requires.
|
||||
*
|
||||
* Typical usage would be
|
||||
* <pre>
|
||||
* $PAGE->requires->js_call_amd('mod_forum/view', 'init');
|
||||
* </pre>
|
||||
*
|
||||
* It also supports obsoleted coding style with/without YUI3 modules.
|
||||
* <pre>
|
||||
* $PAGE->requires->js_init_call('M.mod_forum.init_view');
|
||||
* $PAGE->requires->css('/mod/mymod/userstyles.php?id='.$id); // not overridable via themes!
|
||||
* $PAGE->requires->js('/mod/mymod/script.js');
|
||||
* $PAGE->requires->js('/mod/mymod/small_but_urgent.js', true);
|
||||
* $PAGE->requires->js_function_call('init_mymod', array($data), true);
|
||||
* </pre>
|
||||
*
|
||||
* There are some natural restrictions on some methods. For example, {@link css()}
|
||||
* can only be called before the <head> tag is output. See the comments on the
|
||||
* individual methods for details.
|
||||
*
|
||||
* @copyright 2016 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 3.1
|
||||
* @package core
|
||||
* @category output
|
||||
*/
|
||||
class fragment_requirements_manager extends page_requirements_manager {
|
||||
|
||||
/**
|
||||
* Append YUI3 module to default YUI3 JS loader.
|
||||
* The structure of module array is described at {@link http://developer.yahoo.com/yui/3/yui/}
|
||||
*
|
||||
* @param string|array $module name of module (details are autodetected), or full module specification as array
|
||||
* @return void
|
||||
*/
|
||||
public function js_module($module) {
|
||||
global $CFG;
|
||||
|
||||
if (empty($module)) {
|
||||
throw new coding_exception('Missing YUI3 module name or full description.');
|
||||
}
|
||||
|
||||
if (is_string($module)) {
|
||||
$module = $this->find_module($module);
|
||||
}
|
||||
|
||||
if (empty($module) or empty($module['name']) or empty($module['fullpath'])) {
|
||||
throw new coding_exception('Missing YUI3 module details.');
|
||||
}
|
||||
|
||||
$module['fullpath'] = $this->js_fix_url($module['fullpath'])->out(false);
|
||||
// Add all needed strings.
|
||||
if (!empty($module['strings'])) {
|
||||
foreach ($module['strings'] as $string) {
|
||||
$identifier = $string[0];
|
||||
$component = isset($string[1]) ? $string[1] : 'moodle';
|
||||
$a = isset($string[2]) ? $string[2] : null;
|
||||
$this->string_for_js($identifier, $component, $a);
|
||||
}
|
||||
}
|
||||
unset($module['strings']);
|
||||
|
||||
// Process module requirements and attempt to load each. This allows
|
||||
// moodle modules to require each other.
|
||||
if (!empty($module['requires'])) {
|
||||
foreach ($module['requires'] as $requirement) {
|
||||
$rmodule = $this->find_module($requirement);
|
||||
if (is_array($rmodule)) {
|
||||
$this->js_module($rmodule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->extramodules[$module['name']] = $module;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns js code to load amd module loader, then insert inline script tags
|
||||
* that contain require() calls using RequireJS.
|
||||
* @return string
|
||||
*/
|
||||
protected function get_amd_footercode() {
|
||||
global $CFG;
|
||||
$output = '';
|
||||
|
||||
// First include must be to a module with no dependencies, this prevents multiple requests.
|
||||
$prefix = "require(['core/first'], function() {\n";
|
||||
$suffix = "\n});";
|
||||
$output .= html_writer::script($prefix . implode(";\n", $this->amdjscode) . $suffix);
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate any HTML that needs to go at the end of the page.
|
||||
*
|
||||
* Normally, this method is called automatically by the code that prints the
|
||||
* page footer. You should not normally need to call it in your own code.
|
||||
*
|
||||
* @return string the HTML code to to at the end of the page.
|
||||
*/
|
||||
public function get_end_code() {
|
||||
global $CFG;
|
||||
|
||||
$output = '';
|
||||
|
||||
// Call amd init functions.
|
||||
$output .= $this->get_amd_footercode();
|
||||
|
||||
// Add other requested modules.
|
||||
$output .= $this->get_extra_modules_code();
|
||||
|
||||
$this->js_init_code('M.util.js_complete("init");', true);
|
||||
|
||||
// All the other linked scripts - there should be as few as possible.
|
||||
if ($this->jsincludes['footer']) {
|
||||
foreach ($this->jsincludes['footer'] as $url) {
|
||||
$output .= html_writer::script('', $url);
|
||||
}
|
||||
}
|
||||
|
||||
// Add all needed strings.
|
||||
$strings = array();
|
||||
foreach ($this->stringsforjs as $component => $v) {
|
||||
foreach ($v as $indentifier => $langstring) {
|
||||
$strings[$component][$indentifier] = $langstring->out();
|
||||
}
|
||||
}
|
||||
// Append don't overwrite.
|
||||
$output .= html_writer::script(js_writer::set_variable('M.str', $strings));
|
||||
|
||||
// Add variables.
|
||||
if ($this->jsinitvariables['footer']) {
|
||||
$js = '';
|
||||
foreach ($this->jsinitvariables['footer'] as $data) {
|
||||
list($var, $value) = $data;
|
||||
$js .= js_writer::set_variable($var, $value, true);
|
||||
}
|
||||
$output .= html_writer::script($js);
|
||||
}
|
||||
|
||||
$inyuijs = $this->get_javascript_code(false);
|
||||
$ondomreadyjs = $this->get_javascript_code(true);
|
||||
// See if this is still needed when we get to the ajax page.
|
||||
$jsinit = $this->get_javascript_init_code();
|
||||
$handlersjs = $this->get_event_handler_code();
|
||||
|
||||
// There is a global Y, make sure it is available in your scope.
|
||||
$js = "(function() {{$inyuijs}{$ondomreadyjs}{$jsinit}{$handlersjs}})();";
|
||||
|
||||
$output .= html_writer::script($js);
|
||||
|
||||
// return 'bottom stuff';
|
||||
return $output;
|
||||
|
||||
}
|
||||
}
|
@ -33,6 +33,7 @@ require_once($CFG->libdir.'/outputactions.php');
|
||||
require_once($CFG->libdir.'/outputfactories.php');
|
||||
require_once($CFG->libdir.'/outputrenderers.php');
|
||||
require_once($CFG->libdir.'/outputrequirementslib.php');
|
||||
require_once($CFG->libdir.'/outputfragmentrequirementslib.php');
|
||||
|
||||
/**
|
||||
* Invalidate all server and client side caches.
|
||||
|
@ -824,6 +824,13 @@ class moodle_page {
|
||||
return $this->_navbar->has_items();
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the requirements manager over to receive fragments.
|
||||
*/
|
||||
public function set_requirements_for_fragments() {
|
||||
$this->_requires = new fragment_requirements_manager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the current user see this page in editing mode.
|
||||
* That is, are they allowed to edit this page, and are they currently in
|
||||
|
Loading…
x
Reference in New Issue
Block a user