This post is strictly for Moodle developers. If you're not a developer you can stop reading now as this is entirely technical - sorry about that.
In Moodle 2.9 the preferred way to write JavaScript is using jQuery and a module framework called AMD. This is documented in the Javascript Modules page of the Moodle developer documentation.
So what if you're writing a new plugin now, which currently has to run in 2.8, but you'd like to update it for 2.9 later with minimal work?
I did a hack to make this work (sort of). In case anyone else is interested, here's how...
1. Wrote my JavaScript using the 'new' approach, so that it begins:
define(['jquery'], function($) {
(For the purpose of this development, I can't currently specify any dependencies other than 'jquery' here; it's hard-coded.)
2. Added a simple wrapper that simulates the AMD module framework without implementing any of it. I put this in a file called define.js. Because this is all done within my plugin, I named the global variables according to my plugin's name. Here it is:
window.format_oustudyplan_modules = {};
window.format_oustudyplan_pending = [];
window.define = function(ignored, fn) {
window.format_oustudyplan_pending.push(fn($));
};
window.format_oustudyplan_add_pending = function(module) {
var next = window.format_oustudyplan_pending.shift();
window.format_oustudyplan_modules[module] = next;
};
window.require = function(modules, fn) {
var params = [];
for (var i = 0; i < modules.length; i++) {
params.push(window.format_oustudyplan_modules[modules[i]]);
}
fn.call(this, params);
};
3. Wrote a PHP function to 'load a module':
public static function load($module) {
global $PAGE;
if (!self::$donefirst) {
$PAGE->requires->jquery();
$PAGE->requires->js(new \moodle_url('/course/format/oustudyplan/js/define.js'));
self::$donefirst = true;
}
$PAGE->requires->js_init_code('format_oustudyplan_add_pending("' . $module . '");');
$PAGE->requires->js(new \moodle_url('/course/format/oustudyplan/js/' . $module . '.js'));
}
4. Wrote another one to 'call a module function':
public static function call($module, $fn, array $params = array()) {
global $PAGE;
$jsparams = '';
foreach ($params as $param) {
if ($jsparams !== '') {
$jsparams .= ',';
}
if (is_int($param)) {
$jsparams .= $param;
} else if (is_string($params)) {
$jsparams .= '"' . addslashes_js($param) . '"';
} else {
throw new \coding_exception('Unexpected JS param');
}
}
$PAGE->requires->js_init_code(
'window.format_oustudyplan_modules.' . $module .'.' . $fn . '(' . $jsparams . ')');
}
5 To include my JavaScript, I do this (the above two functions were in a 'js' class):
js::load('sections');
js::call('sections', 'init');
These PHP functions are not the same syntax as used in the 'real' function which is a single function js_call_amd, but are similar. The intention of this approach is that I should be able to move to 2.9 syntax without having to change my JavaScript code. What I will have to do:
- Delete the PHP code above.
- Move the JavaScript into the appropriately-named directory and update it using Grunt.
- Change my loader code to use js_call_amd.
Hope this might be useful to somebody else