Note:

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

Moodle Mobile 2 (Ionic 1) Plugins Development

From MoodleDocs

Moodle 2.4


Overview

Plugins allow developers to extend the app functionalities. A plugin it’s a subdirectory that implements a set of required functionalities.

Types of plugins

  • General: Interactions over the global app. Like the Notifications, Upload, Help and Web
  • Course: Interactions over a course. Like course contents or participants
  • User: Interactions over an user. Like send a message, add as a contact, write a private note
  • Settings: Additional settings for the app

Structure of a plugin

We are going to use this plugin: https://github.com/moodlehq/moodlemobile/tree/master/plugins/participants as an example:

Plugins have always the same structure (no matter the type of plugin), the app uses a Register App where you declare a Plugin and then register it to the App

A plugin must be a directory under the plugins/ dir containing:

  • A main.js file, where the plugin is declared
  • Templates html files (if used)


Defining a plugin

var templates = [

   "root/lib/text!root/plugins/participants/participants.html",
   "root/lib/text!root/plugins/participants/participant.html"

];

define(templates,function (participantsTpl, participantTpl) {

For loading plugins we use the RequireJS library, a plugin is a module that we must define using the lines above:

We define a new module that depends on the html files (templates) listed above, once loaded, the contents of the HTML files will be available in the participantsTpl and participantTpl variables.

Notice that the app doesn't automatically load the plugins, you need to edit the config.json file for indicating the plugins to be loaded

"plugins" : ["notifications", "upload", "contents", "participants", "addcontact", "addnote", "sendmessage", "yourpluginname"],

Global settings of the plugin

settings: {
           name: "participants",
           type: "course",
           menuURL: "#participants/",
           lang: {
               component: "moodle"
           }
       },

The name of the plugin (must be the same that the directory name)

The type of plugin (general, course, user, settings)

The main link to the plugin in the App

The language file to use, here we are using moodle because we are using the main language file, for plugins, you should use the Moodle franken-style plugin name where the lang file is located in your Moodle installation i.e: "local_mycustomplugin"

This means that you need to put your language files in a local plugin (called mycustomplugin) in your Moodle installation, this local plugin should be the same where you are going to add your custom WebServices


Storage

       storage: {
           participant: {type: "model"},
           participants: {type: "collection", model: "participant"}
       },

Here we declare the "tables" and their "structure"

If you are not familiar with Models, you must think that participants is a table that contains the participant's records.

Notice that we are not indicating the "fields" of the "tables" this is not necessary.

Routes

       routes: [
           ["participants/:courseId", "participants", "showParticipants"],
           ["participant/:courseId/:userId", "participants", "showParticipant"],
       ],

For avoid binding DOM elements to functions, we use a Route navigation model, any time an user clicks on a button or link, the hash part of the URL is changed and the function linked to the hash part is triggered. So, if you want to trigger the function ShowParticipant, you must create a button or link that points to "#participant/courseid/userid", when the user click on the link the function showParticipant(courseid, userid) is triggered One of the advantages of using roues, is that we preserve the browser history so the "back" button on an Android device will work as expected without any extra code.


Functions

       showParticipants: function(courseId) {
           MM.panels.showLoading('center');
           
           if (MM.deviceType == "tablet") {
               MM.panels.showLoading('right');
           }
   
           var data = {
               "courseid" : courseId
           };
           
           MM.moodleWSCall('moodle_user_get_users_by_courseid', data, function(users) {
               var tpl = {users: users, deviceType: MM.deviceType, courseId: courseId};
               var html = MM.tpl.render(MM.plugins.participants.templates.participants.html, tpl);
               MM.panels.show('center', html);
               // Load the first user
               if (MM.deviceType == "tablet" && users.length > 0) {
                   MM.plugins.participants.showParticipant(courseId, users.shift().id);
               }
           });
       },
       showParticipant: function(courseId, userId) {
           var data = {
               "userlist[0][userid]": userId,
               "userlist[0][courseid]": courseId
           }
           MM.moodleWSCall('moodle_user_get_course_participants_by_id', data, function(users) {
               // Load the active user plugins.
               
               var userPlugins = [];
               for (var el in MM.plugins) {
                   var plugin = MM.plugins[el];
                   if (plugin.settings.type == "user") {
                       userPlugins.push(plugin.settings);
                   }
               }
               
               var tpl = {"user": users.shift(), "plugins": userPlugins, "courseid": courseId};
               var html = MM.tpl.render(MM.plugins.participants.templates.participant.html, tpl);
               MM.panels.show('right', html);
           });
       },

Here are the main plugin functions, as you can see we create a function for any single route defined.

As you can see, you don't need much code:

The showParticipants function does:

  • Show a loading icon in the center panel
  • If we are using a tablet, an additional loading icon is displayed in the right panel
  • Then we call a Moodle Webservice, using the MM.moodleWSCall function, indicating the name of the WS, the parameters, an a callback function.
  • When the Webservice returns info, the next step is to render a Template using the app template function and then display the template in the center panel.

Notice that for referencing the template, we use the MM global object: MM.plugins.participants.templates.participants.html (MM . registered plugins . name of the plugin . property . template name . contents of the template

  • If we are using a tablet, we load in the right panel the first participant calling the showParticipant function

Notice that for referencing the function, we use the MM global object: M.plugins.participants.showParticipant


Templates templates: {

           "participant": {
               model: "participant",
               html: participantTpl
           },
           "participants": {
               html: participantsTpl
           }
       }

Here we declare the templates we are going to use for further references.

Notice that the attribute html cointains the HTML template files contents (as mentioned above).


Register the plugin

MM.registerPlugin(plugin);

With this single line we register the plugin in the global Namespace MM (the main library of the app)


Moodle Mobile (MM) API

Most of the MM APIs are wrappers for other libraries like Backbone.

DB/Storage functions

Getting an element from storage

MM.db.get(id);

Internationalization functions

Getting a translated string

MM.lang.s("string_id");

Templating functions

Render a template

MM.tpl.render(html, elements);

Sample code:


var tpl = {users: users, deviceType: MM.deviceType, courseId: courseId}; var html = MM.tpl.render(MM.plugins.participants.templates.participants.html, tpl);

Template:

   <section class="users-index-list">
       <form class="search">
           <input type="search" results="5" placeholder="Search...">
       </form>
   </section>