Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

How to create a YUI 3 module

From MoodleDocs

Moodle 2.0

This document explains how to create a YUI 3 module in Moodle.

The two ways to write a YUI 3 module

There is two ways to write a YUI 3 module. The two following paragraphs are sourced from a chat with Sam Hemelryk.

The static module

The static module is the simpler of the two, in this case you simply put your code into a module.js file within your plugin. Into that file you create a namespace and define any functions or objects you want to use.

Within PHP static modules are also pretty easy to use. The first step if to create a module definition which tells moodle what your module is called, what it requires, and can optionally give it strings.

Once the module is defined you can then use any of the several JS methods for including JS in your page and pass your module definition along.

Whilst this method is simpler to write and understand especially when you are first starting out with JavaScript it isn't as easily flexible and has some quirks that you need will need to overcome, especially with more complex JavaScript.

This method of writing a module should be used if you are just starting out with JavaScript or if the JS solution you are creating is going to be relatively simple in nature. If you are writing something more complex I would strongly suggest looking at the other method as it will result in cleaner, easier to read code at the end of the day. However it will require you to learn your way around writing a Moodle module.

The YUI3 Moodle Module

This method is certainly more complex than the previous method however it is much more flexible and when you have learnt and understand what you are doing it is much quicker to write and more versatile as well. These modules can also easily include other YUI3 Moodle modules, and can choose to include module specific CSS as well.

In this method you create a yui directory within you plugin directory, and then sub directories for each module you wish to write, you name them the same as you want your module named. Into the subdirectory you create a JavaScript file with the same name that you gave the subdirectory, e.g./local/myplugin/yui/mymodule/mymodule.js The JS that you then put into this file should then be written in the same way you would write a YUI module, before you ask it certainly requires a good understanding of YUI.

I would recommend this method of writing a module providing you either have an understanding of how to write a YUI module, or you are happy to learn. It normally results in cleaner easier to read code, and if desired can easily be written in such as way as to make it VERY easy to re-use in other bits of code.... particularly helpful if you have several JavaScript objects in play at a time.

Static module quick start

1. Create a module.js file somewhere

2. The two ways Moodle can load this file are:

a- the file is in core: declare the file into /lib/outputrequirementslib.php/find_module($component)

         //example:
         case 'core_rating':
                   $module = array('name'     => 'core_rating',
                                   'fullpath' => '/rating/module.js',
                                   'requires' => array('node', 'event', 'overlay', 'io', 'json'));

b- the file is in a local plugin: the first line of your module should be

M.local_xxx = {

xxx being your plugin directory name.

3. Write the module.js

 M.local_hub={
   Y : null,
   transaction : [],
   init : function(Y){
       alert('hub module initialisation');
       this.Y = Y;
   },
 }

4. Call this module. The best place to do this is in your renderer class (since, if a theme overrides the renderer to change the HTML, they may also need to use different JavaScript.

   $this->page->requires->js_init_call('M.local_hub.init'); 

You should now have loaded and called your first YUI 3 module in Moodle. 5. If you want to load your module with some other YUI modules

   $jsmodule = array(
               'name' => 'local_hub',
               'fullpath' => '/local/hub/module.js',
               'requires' => array("overlay", "anim", "plugin")); //on this line you are loading three other YUI modules
  $this->page->requires->js_init_call('M.local_hub.init',
                null, false, $jsmodule);

6. If you want to pass parameter to the init function

PHP:

   $this->page->requires->js_init_call('M.local_hub.init',
                   array('this is the param1 value'), false, $jsmodule);

JS:

   init : function(Y, params){
       alert(params);
       ....
   }

7. Then you should be able to fill the module with your own YUI javascript from YUI examples.

YUI 3 Moodle Module quick start

1. Create the module_name.js file in /local/pluginname/yui/module_name/modulename.js or in /mod/modname/yui/modulename/modulename.js

2. The basic module_name.js structure is:

 YUI.add('moodle-local_pluginname-modulename', function(Y) {
   var ModulenameNAME = 'this_is_a_module_name';
   var MODULENAME = function() {
       MODULENAME.superclass.constructor.apply(this, arguments);
   };
   Y.extend(MODULENAME, Y.Base, {
       initializer : function(config) { // 'config' contains the parameter values
           alert('I am in initializer');
       }
   }, {
       NAME : ModulenameNAME, //module name is something mandatory. 
                               // It should be in lower case without space 
                               // as YUI use it for name space sometimes.
       ATTRS : {
                aparam : {}
       } // Attributes are the parameters sent when the $PAGE->requires->yui_module calls the module. 
         // Here you can declare default values or run functions on the parameter. 
         // The param names must be the same as the ones declared 
         // in the $PAGE->requires->yui_module call.
   });
   M.local_pluginname = M.local_pluginname || {}; // This line use existing name path if it exists, ortherwise create a new one. 
                                                // This is to avoid to overwrite previously loaded module with same name.
   M.local_pluginname.init_modulename = function(config) { // 'config' contains the parameter values
       alert('I am in the javascript module, Yeah!');
       return new MODULENAME(config); // 'config' contains the parameter values
   }
 }, '@VERSION@', {
     requires:['base','another_required_YUI_module', 'a_moodle_YUI_module']
 });

3. Call the javascript in PHP. Again, it is best to do this in a renderer class. (if you copied the previous javascript, 2 javascript alert should appear.)

 $this->page->requires->yui_module('moodle-local_pluginname-modulename', 'M.local_pluginname.init_modulename',
               array(array('aparam'=>'paramvalue')));

Full simple example

Once you understand and run the above quick start, here is simple YUI 3 example. It shows how to use another YUI 3 module in your module, and to use some events.

It includes

  • display a parameter value in two javascript alert boxes => demonstrate how to pass a param to the initialize function in two different ways
  • display an overlay when you click on an image
  • hide the overlay when you click on the body
  • some commented code to see how Moodle YUI exception works

PHP

Create a basic local plugin (in this example it is named hub) in /local/hub/ and add this code into one of the plugin pages:

  $PAGE->requires->yui_module('moodle-local_hub-comments', 'M.local_hub.init_comments',
               array(array('commentids' => '1 , 23 ,45')));

HTML

The plugin page should generate this HTML code:

<img src='http://moodle.org/theme/moodle2/pix/moodle-logo.gif' alt='the image to click on'/>
Comment
this is a comment
this is another comment

CSS

The plugin style.css should contain: /* Hide overlay markup while loading, if js is enabled */ .yui3-js-enabled .yui3-overlay-loading {

   top:-1000em;
   left:-1000em;
   position:absolute;

}

/* Overlay Look/Feel */ .yui3-overlay-content {

   padding:3px;
   border:1px solid #000;
   background-color:#aaa;

}

.yui3-overlay-content .yui3-widget-hd {

   padding:5px;
   border:2px solid #aa0000;
   background-color:#fff;

}

.yui3-overlay-content .yui3-widget-bd {

   padding:5px;
   border:2px solid #0000aa;
   background-color:#fff;

}

JS

In /local/hub/yui/comments/comments.js YUI.add('moodle-local_hub-comments', function(Y) {

   var COMMENTSNAME = 'hub_comments';
   //we declare the overlay here so it's accessible to all the extended class function'
   var overlay = new Y.Overlay({
               srcNode:"#commentoverlay", //the main div with id = commentoverlay
               width:"10em",
               height:"10em",
               xy:[ 0, 0],
               visible: false //by default it is not displayed
           });
   var COMMENTS = function() {
       COMMENTS.superclass.constructor.apply(this, arguments);
   }
   Y.extend(COMMENTS, Y.Base, {
       event:null,
       initializer : function(params) {
           //Example how to retrieve the parameter,
           //see what happens if you don't pass the parameter in the call
           alert(this.get('commentids')); // You usually use an attribute because
                                          //a attribut can have default value.
                                          //use the ATTRS default value if not passed as parameter
           alert(params.commentids); // undefined if not passed as parameter
           //render the overlay
           overlay.render();
           // position the overlay in the middle of the web browser window
           var WidgetPositionAlign = Y.WidgetPositionAlign;
           overlay.set("align", {
               node:"", //empty => viewport
               points:[WidgetPositionAlign.CC, WidgetPositionAlign.CC]
           });
           //attach a show event on the div with id = comments
           //we also change the div style to display the click zone
           Y.one('#comments').setStyle("border", "1px solid red").on('click', this.show, this);
           //uncomment the try content to see how works exception in Moodle
           //this exception has been specially created for Moodle
           try {
             //surely_not_existing_js_function();
           } catch (exception) {
               new M.core.exception(exception);
           }
       },
       show : function (e) {
           overlay.show(); //show the overlay
          
           e.halt(); // we are going to attach a new 'hide overlay' event to the body,
                     // because javascript always propagate event to parent tag,
                     // we need to tell Yahoo to stop to call the event on parent tag
                     // otherwise the hide event will be call right away.
           //we add a new event on the body in order to hide the overlay for the next click
           this.event = Y.one(document.body).on('click',this.hide,this);
       },
       hide : function () {
           overlay.hide(); //hide the overlay
           this.event.detach(); //we need to detach the hide event
                                //Note: it would work without but create js warning everytime
                                //we click on the body
       }
   }, {
       NAME : COMMENTSNAME,
       ATTRS : {
           commentids: {value : 450} //default value (has no purpose in this code except to show you
                                     // how to pass/use a param value)
       }
   });
   M.local_hub = M.local_hub || {};
   M.local_hub.init_comments = function(params) {
       return new COMMENTS(params);
   }

}, '@VERSION@', {

   requires:['base','overlay', 'moodle-enrol-notification']
   //Note: 'moodle-enrol-notification' contains Moodle YUI exception

});

Where are my methods in the IDE?

Some (all?) IDEs will fail to parse the above structure correctly and will not show you your methods in the structure/navigator pane. If this happens, use JSDoc format to mark the Y.extend() line as being a particular class:

   /**
    * @class M.local_hub.init_comments
    */
   Y.extend(COMMENTS, Y.Base, {

This depends to a certain extent on how you choose to instantiate your objects. The above init_widget() method can be replaced with a more class based method like a lot of the YUI library uses.

What else to read

Two pages are important to start with when you discover YUI 3

  • you should read the base YUI doc. It is very useful to understand the YUI 3 Moodle module.
  • you want to have a look to the YUI 3 examples. Always open the examples in a window to have a look to the complete example codes.

See Also