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: Difference between revisions

From MoodleDocs
No edit summary
 
(34 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{Moodle 2.4}}
{{Template:WillNotMigrate}}
{{Moodle Mobile 2 (Ionic 1)}}


=== Overview ===
IMPORTANT: This documentation will be obsolete in May 2018, please [https://moodle.org/mod/forum/discuss.php?d=360412 read this announcement].


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


IMPORTANT: Plugins are not automatically loaded, you must indicate the plugins to be loaded in the config.json file (plugins option)
Plugins (known as Moodle Mobile 2 addons) allow developers to extend the app functionalities.


=== Types of plugins ===
An addon is a subdirectory that implements a set of required functionalities. For those familiars with AngularJS, addones are AngularJS modules.


* General: Interactions over the global app. Like the Notifications, Upload, Help and Web
IMPORTANT: Read carefully this document ([[Moodle Mobile Customization]]) before you start developing!
* 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 ===
Please, note also that this documentation is oriented to Moodle Mobile specific APIs, before starting developing you should get familiar with AngularJS and Ionic, here you have some resources:


We are going to use this plugin: https://github.com/moodlehq/moodlemobile/tree/master/plugins/participants as an example:
'''Ionic'''
* http://ionicframework.com - Official Ionic website
* https://www.airpair.com/ionic-framework/posts/the-definitive-ionic-starter-guide - Definitive ionic starter guide
* http://mcgivery.com/100-ionic-framework-resources/ - +100 Ionic resources
* https://github.com/juarezpaf/ionic-adventures?utm_source=mobilewebweekly&utm_medium=email - More ionic resources
* http://codepen.io/ionic/public-list/ - Ionic sample code lists
* https://www.youtube.com/channel/UChYheBnVeCfhCmqZfCUdJQw - YouTube channel from Ionic
* http://www.manning.com/wilken/ - Ionic in action book


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
'''Angular'''
* https://angularjs.org - The official documentation for AngularJS
* http://manning.com/bford - AngularJS in Action book
* http://manning.com/aden - AngularJS in Depth book


A plugin must be a directory under the plugins/ dir containing:
'''Cordova'''
* http://cordova.apache.org - Official Cordova site
* http://plugins.cordova.io - Cordova official plugin registry.
* http://ngcordova.com - ngCordova AngularJS wrappers for cordova


* A main.js file, where the plugin is declared
== Moodle Mobile 2 addons ==
* Templates html files (if used)


Each addon can have services, controllers, templates and lang files. The addon needs  to specify a main.js file to initialize the addon and to register itself into one or more delegates (this determines where will the plugin be shown).


'''Defining a plugin'''
Naming conventions for addons:
* The module name for addons needs to be mm.addons.addonname and it should be defined in the addon main.js.
* All the services names inside an addon need to start with $mma, followed by the service name in camel-case. For example, $mmaForumData.
* The controllers names need to start with mma (without dollar), followed by the controller name in camel-case. The controller name needs to contain Ctrl to easily identify it as a controller. For example, mmaForumListCtrl.


<code javascript>
The app comes with a predefined set of addons: messages, forum, notifications, etc. All these addons are inside the www/addons folder.  
var templates = [
    "root/lib/text!root/plugins/participants/participants.html",
    "root/lib/text!root/plugins/participants/participant.html"
];


define(templates,function (participantsTpl, participantTpl) {
An addon can be shown in several places. The app has one delegate per each place an addon can be shown, so each addon can register itself to any set of delegates.
</code>


For loading plugins we use the RequireJS library, a plugin is a module that we must define using the lines above:
You can see the list of available delegates [https://docs.moodle.org/dev/Moodle_Mobile#Addons in this section].


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.
=== Structure of an addon ===


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
If you are not familiar with AngularJS, please, read the [https://docs.angularjs.org/guide AngularJS] guide to a complete understanding of the different terms used in this document.


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


'''Global settings of the plugin'''
controllers/
  discussion.js
  discussions.js
lang/
  en.json
services/
  forum.js   
templates/
  discussion.html
  discussions.html
main.js


<code javascript>
'''controllers and templates'''
settings: {
            name: "participants",
            type: "course",
            menuURL: "#participants/",
            lang: {
                component: "moodle"
            }
        },
</code>


The name of the plugin (must be the same that the directory name)
The controllers directory contains the module controllers, usually you are going to have there a controller per view and per template.


The type of plugin (general, course, user, settings)
In the forum example, you can see that there are two controllers and two templates:


The main link to the plugin in the App
* discussions.js|html for displaying the complete list of discussions of a forum in a course
* discussion.js|html  for displaying a single discussion.


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"
Each controller is responsible of rendering the view, for example, the discussions.js will fetch and display the list of discussions of the forum using the helper service defined in forum.js


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
The controller will also implement additional functionalities like support to "Pull down to refresh"


'''lang'''


'''Storage'''
The lang directory contain the language file with the translated strings.
<code javascript>
        storage: {
            participant: {type: "model"},
            participants: {type: "collection", model: "participant"}
        },
</code>


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


If you are not familiar with Models, you must think that participants is a table that contains the participant's records.
This directory contains the app services, usually for non-complex addons you will find a single file inside containing all the code logic used for providing the main functionality of the addon like the code for retrieving the discussions via Moodle Web Services.


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


'''Routes'''
This is a mandatory file, it:
<code javascript>
* Creates the AngularJS module
        routes: [
* Declares all the state routes the plugin is going to user. Attaching a controller and template for each different state.
            ["participants/:courseId", "participants", "showParticipants"],
* Initializes the addon and register it into one or more delegates (this determines where the plugin will be displayed in the app).
            ["participant/:courseId/:userId", "participants", "showParticipant"],
        ],
</code>


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.
== See also ==
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.


 
* [[Moodle Mobile Developing a plugin tutorial]]
'''Functions'''
* [[Moodle Mobile Developing a plugin tutorial part 2]]
<code javascript>
 
        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);
            });
        },
 
</code>
 
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.
 
* We can add an extra parameter, indicating that this function perform write actions in the server, see: https://github.com/moodlehq/moodlemobile/blob/master/plugins/addnote/main.js#L36
 
*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'''
<code javascript>
templates: {
            "participant": {
                model: "participant",
                html: participantTpl
            },
            "participants": {
                html: participantsTpl
            }
        }
</code>
 
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'''
<code javascript>
MM.registerPlugin(plugin);
</code>
 
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 by id'''
 
MM.db.get(collection, id);
 
 
'''Getting elements from storage using conditions'''
 
MM.db.where(collection, {name: value});
 
Sample code:
 
<code javascript>
var notificationsFilter = MM.db.where("notifications", {siteid: MM.config.current_site.id});
</code>
 
'''Adding a Model to a Collection (inserting an element into a table)'''
 
MM.db.insert(collection, {id: xx, name: yy, value: zz})
 
MM.db.insert(collection, {name: yy, value: zz}) (This will create a random Unique id)
 
=== Internationalization functions ===
 
'''Getting a translated string'''
 
MM.lang.s("string_id");
 
Sample code:
 
<code javascript>
MM.lang.s("therearenotnotificationsyet");
</code>
 
=== Templating functions ===
 
'''Render a template'''
 
MM.tpl.render(html, elements);
 
Sample code:
 
 
<code javascript>
var tpl = {users: users, deviceType: MM.deviceType, courseId: courseId};
var html = MM.tpl.render(MM.plugins.participants.templates.participants.html, tpl);
</code>
 
Template:
 
<code html4strict>
    <section class="users-index-list">
        <form class="search">
            <input type="search" results="5" placeholder="Search...">
        </form>
        <ul class="nav nav-v">
            <% _.each(users, function(user) { %>
            <li class="nav-item">
                <a href="#participant/<%= courseId %>/<%= user.id %>" class="media">
                    <div class="img">
                    <img width="35" src="<%= MM.fixPluginfile(user.profileimageurlsmall) %>" alt="img">
                    </div>
                    <div class="bd">
                      <h3><%= user.fullname %></h3>
                    </div>
                </a>
            </li>
            <% }); %>
        </ul>
    </section>
</code>
 
=== Message popups/dialogs===
 
MM.popMessage(text, options);
 
MM.popErrorMessage(text, options);
 
=== Device ===
 
MM.deviceType (returns phone or tablet)
 
MM.deviceConnected() (returns true or false if the device has Internet access)
 
 
 
 
[[Category: Mobile]]

Latest revision as of 07:14, 29 April 2022


Warning: This page is no longer in use. The information contained on the page should NOT be seen as relevant or reliable.



Warning: This page is no longer in use. The information contained on the page should NOT be seen as relevant or reliable.


IMPORTANT: This documentation will be obsolete in May 2018, please read this announcement.

Overview

Plugins (known as Moodle Mobile 2 addons) allow developers to extend the app functionalities.

An addon is a subdirectory that implements a set of required functionalities. For those familiars with AngularJS, addones are AngularJS modules.

IMPORTANT: Read carefully this document (Moodle Mobile Customization) before you start developing!

Please, note also that this documentation is oriented to Moodle Mobile specific APIs, before starting developing you should get familiar with AngularJS and Ionic, here you have some resources:

Ionic

Angular

Cordova

Moodle Mobile 2 addons

Each addon can have services, controllers, templates and lang files. The addon needs to specify a main.js file to initialize the addon and to register itself into one or more delegates (this determines where will the plugin be shown).

Naming conventions for addons:

  • The module name for addons needs to be mm.addons.addonname and it should be defined in the addon main.js.
  • All the services names inside an addon need to start with $mma, followed by the service name in camel-case. For example, $mmaForumData.
  • The controllers names need to start with mma (without dollar), followed by the controller name in camel-case. The controller name needs to contain Ctrl to easily identify it as a controller. For example, mmaForumListCtrl.

The app comes with a predefined set of addons: messages, forum, notifications, etc. All these addons are inside the www/addons folder.

An addon can be shown in several places. The app has one delegate per each place an addon can be shown, so each addon can register itself to any set of delegates.

You can see the list of available delegates in this section.

Structure of an addon

If you are not familiar with AngularJS, please, read the AngularJS guide to a complete understanding of the different terms used in this document.

Forum addon directory:

controllers/
 discussion.js
 discussions.js
lang/
  en.json
services/
 forum.js    
templates/
 discussion.html
 discussions.html
main.js

controllers and templates

The controllers directory contains the module controllers, usually you are going to have there a controller per view and per template.

In the forum example, you can see that there are two controllers and two templates:

  • discussions.js|html for displaying the complete list of discussions of a forum in a course
  • discussion.js|html for displaying a single discussion.

Each controller is responsible of rendering the view, for example, the discussions.js will fetch and display the list of discussions of the forum using the helper service defined in forum.js

The controller will also implement additional functionalities like support to "Pull down to refresh"

lang

The lang directory contain the language file with the translated strings.

services

This directory contains the app services, usually for non-complex addons you will find a single file inside containing all the code logic used for providing the main functionality of the addon like the code for retrieving the discussions via Moodle Web Services.

main.js

This is a mandatory file, it:

  • Creates the AngularJS module
  • Declares all the state routes the plugin is going to user. Attaching a controller and template for each different state.
  • Initializes the addon and register it into one or more delegates (this determines where the plugin will be displayed in the app).

See also