Skip to content

Commit

Permalink
MDL-52715 lib: Clean up of comments and variable names.
Browse files Browse the repository at this point in the history
  • Loading branch information
abgreeve committed Feb 3, 2016
1 parent d23bf21 commit a2161d5
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 134 deletions.
2 changes: 1 addition & 1 deletion lib/amd/build/fragment.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 27 additions & 34 deletions lib/amd/src/fragment.js
Expand Up @@ -23,18 +23,19 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since 3.1
*/
define(['jquery', 'core/ajax'], function($, ajax) {
define(['jquery', 'core/ajax', 'core/notification'], function($, ajax, notification) {

/**
* Loads an HTML fragment through a callback.
*
* @method load_fragment
* @method loadFragment
* @param {string} component Component where callback is located.
* @param {string} callback Callback function name.
* @param {integer} contextid Context ID of the fragment.
* @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) {
var loadFragment = function(component, callback, contextid, params) {
// Change params into required webservice format.
var formattedparams = [];
for (var index in params) {
Expand All @@ -49,12 +50,11 @@ define(['jquery', 'core/ajax'], function($, ajax) {
args:{
component: component,
callback: callback,
contextid: contextid,
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) {
Expand All @@ -63,6 +63,14 @@ define(['jquery', 'core/ajax'], function($, ajax) {
return deferred.promise();
};

/**
* Removes and cleans children of a node. This includes event handlers and listeners that may be
* attached to the nodes for both jquery and yui.
*
* @method recursiveCleanup
* @param {object} DOM node to be cleaned.
* @return {void}
*/
var recursiveCleanup = function(node) {
node.children().each(function(index, el) {
var child = $(el);
Expand All @@ -75,50 +83,35 @@ define(['jquery', 'core/ajax'], function($, ajax) {
if (yuinode.get('childNodes')) {
yuinode.empty();
}
yuinode.remove();
yuinode.remove(true);
};

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.
* Callbacks called by this AMD module are responsible for doing the appropriate security checks
* to access the information that is returned. This only does minimal validation on the context.
*
* @method fragment_append
* @method fragmentAppend
* @param {string} component Component where callback is located.
* @param {string} callback Callback function name.
* @param {integer} contextid Context ID of the fragment.
* @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.
recursiveCleanup($('#fragment-html'));
recursiveCleanup($('#ajax-import-scripts'));

$.when(load_fragment('mod_assign', "fragment", params)).then(function(data) {
fragmentAppend: function(component, callback, contextid, params, htmlnodeidentifier, javascriptnodeidentifier) {
$.when(loadFragment(component, callback, contextid, params)).then(function(data) {
// Clean up previous code if found first.
recursiveCleanup($('#fragment-html'));
recursiveCleanup($('#fragment-scripts'));
// Attach new HTML and JavaScript.
$(htmlnodeidentifier).append("<div id=\"fragment-html\">");
$(htmlnodeidentifier).append("</div>");
$('#fragment-html').append(data.html);
$(htmlnodeidentifier).append('<div id="fragment-html">' + data.html + '</div>');
$(javascriptnodeidentifier).append('<div id="fragment-scripts">' + data.javascript + '</div>');

$(javascriptnodeidentifier).append("<div id=\"ajax-import-scripts\">");
$(javascriptnodeidentifier).append("</div>");
$('#ajax-import-scripts').append(data.javascript);
}).fail(function(ex) {
notification.exception(ex);
});
}
};
Expand Down
1 change: 0 additions & 1 deletion lib/db/services.php
Expand Up @@ -1057,7 +1057,6 @@
'classpath' => 'lib/external/externallib.php',
'description' => 'Return a fragment for inclusion, such as a JavaScript page.',
'type' => 'read',
'loginrequired' => false,
'ajax' => true,
),

Expand Down
22 changes: 14 additions & 8 deletions lib/external/externallib.php
Expand Up @@ -270,13 +270,14 @@ public static function get_component_strings_returns() {
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'),
'component' => new external_value(PARAM_COMPONENT, 'Component for the callback e.g. mod_assign'),
'callback' => new external_value(PARAM_ALPHANUMEXT, 'Name of the callback to execute'),
'contextid' => new external_value(PARAM_INT, 'Context ID that the fragment is from'),
'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')
'value' => new external_value(PARAM_RAW, 'param value')
)
), 'args for the callback are optional', VALUE_OPTIONAL
)
Expand All @@ -287,20 +288,25 @@ public static function get_fragment_parameters() {
/**
* Get a HTML fragment for inserting into something. Initial use is for inserting mforms into
* a page using AJAX.
* This web service is designed to be called only via AJAX and not directly.
* Callbacks that are called by this web service are responsible for doing the appropriate security checks
* to access the information returned. This only does minimal validation on the context.
*
* @param string $component Name of the component.
* @param string $callback Function callback name.
* @param int $contextid Context ID this fragment is in.
* @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) {
public static function get_fragment($component, $callback, $contextid, $args = null) {
global $OUTPUT, $PAGE;

$params = self::validate_parameters(self::get_fragment_parameters(),
array(
'component' => $component,
'callback' => $callback,
'contextid' => $contextid,
'args' => $args
)
);
Expand All @@ -311,16 +317,16 @@ public static function get_fragment($component, $callback, $args = null) {
$arguments[$paramargument['name']] = $paramargument['value'];
}

// Remove warning about context not being set.
$PAGE->set_context(context_system::instance());
$context = context::instance_by_id($contextid);
self::validate_context($context);

// Hack alert: Forcing bootstrap_renderer to initiate moodle page.
$OUTPUT->header();

// Overwriting page_requirements_manager with the fragment one so only JS included from
// this point is returned to the user.
$PAGE->set_requirements_for_fragments();
$data = component_callback($params['component'], $params['callback'], $arguments);
$PAGE->start_collecting_javascript_requirements();
$data = component_callback($params['component'], 'output_fragment_' . $params['callback'], $arguments);
$jsfooter = $PAGE->requires->get_end_code();
$output = array('html' => $data, 'javascript' => $jsfooter);
return $output;
Expand Down
104 changes: 19 additions & 85 deletions lib/outputfragmentrequirementslib.php
Expand Up @@ -17,8 +17,6 @@
/**
* 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
Expand All @@ -28,28 +26,8 @@
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.
* This requirements manager captures the appropriate html for creating a fragment to
* be inserted elsewhere.
*
* @copyright 2016 Adrian Greeve <adrian@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
Expand All @@ -60,57 +38,18 @@
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
* Page fragment constructor.
*/
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;
public function __construct() {
parent::__construct();
// As this is a fragment the header should already be done.
$this->headdone = true;
}


/**
* 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() {
Expand All @@ -128,9 +67,6 @@ protected function get_amd_footercode() {
/**
* 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() {
Expand All @@ -144,26 +80,26 @@ public function get_end_code() {
// 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();
if (!empty($this->stringsforjs)) {
// 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('require(["jquery"], function($) {
M.str = $.extend(true, M.str, ' . json_encode($strings) . ');
});');
}
// Append don't overwrite.
$output .= html_writer::script('require(["jquery"], function($) {
M.str = $.extend(true, M.str, ' . json_encode($strings) . ');
});');

// Add variables.
if ($this->jsinitvariables['footer']) {
Expand All @@ -186,8 +122,6 @@ public function get_end_code() {

$output .= html_writer::script($js);

// return 'bottom stuff';
return $output;

}
}
1 change: 0 additions & 1 deletion lib/outputlib.php
Expand Up @@ -33,7 +33,6 @@
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.
Expand Down
22 changes: 19 additions & 3 deletions lib/pagelib.php
Expand Up @@ -825,10 +825,26 @@ public function has_navbar() {
}

/**
* Changes the requirements manager over to receive fragments.
* Switches from the regular requirements manager to the fragment requirements manager to
* capture all necessary JavaScript to display a chunk of HTML such as an mform. This is for use
* by the get_fragment() web service and not for use elsewhere.
*/
public function set_requirements_for_fragments() {
$this->_requires = new fragment_requirements_manager();
public function start_collecting_javascript_requirements() {
global $CFG;
require_once($CFG->libdir.'/outputfragmentrequirementslib.php');

// Check that the requirements manager has not already been switched.
if (get_class($this->_requires) == 'fragment_requirements_manager') {
throw new coding_exception('JavaScript collection has already been started.');
}
// The header needs to have been called to flush out the generic JavaScript for the page. This allows only
// JavaScript for the fragment to be collected. _wherethemewasinitialised is set when header() is called.
if (!empty($this->_wherethemewasinitialised)) {
// Change the current requirements manager over to the fragment manager to capture JS.
$this->_requires = new fragment_requirements_manager();
} else {
throw new coding_exception('$OUTPUT->header() needs to be called before collecting JavaScript requirements.');
}
}

/**
Expand Down

0 comments on commit a2161d5

Please sign in to comment.