Difference between revisions of "AppSuite:Writing a notification area plugin (7.6.x)"

Line 1: Line 1:
How to: Write a plugin for the notification area.
+
<div class="title">Writing a plugin for the notification area</div>
  
1. Preparations
+
__TOC__
 +
 
 +
==Preparations==
  
 
To start a new plugin for the notification area you have to add a new folder at apps.plugins/notifications/ .
 
To start a new plugin for the notification area you have to add a new folder at apps.plugins/notifications/ .
Line 47: Line 49:
 
CODE
 
CODE
  
2. Registering our plugin
+
==Registering our plugin==
  
 
Now we need to register our plugin by extending the right extension point, which is io.ox/core/notifications/register.
 
Now we need to register our plugin by extending the right extension point, which is io.ox/core/notifications/register.
Line 68: Line 70:
 
io.ox/tutorial is the id the controlelr should use to refer to our plugin and NotificationsView is the view we will create now to display it.
 
io.ox/tutorial is the id the controlelr should use to refer to our plugin and NotificationsView is the view we will create now to display it.
  
3. Creating the View
+
==Creating the View==
  
 
Since we use will use backbone to create our plugin it obviously needs a view.
 
Since we use will use backbone to create our plugin it obviously needs a view.
Line 94: Line 96:
 
Note: Events and render function are empty at the moment, but we will fix this soon.
 
Note: Events and render function are empty at the moment, but we will fix this soon.
  
4. Adding the headline
+
==Adding the headline==
  
 
Now we need to draw something. We could just put it in the render method but since we have the extension point architecture we will make use of it, to keep our actual render method cleaned up.
 
Now we need to draw something. We could just put it in the render method but since we have the extension point architecture we will make use of it, to keep our actual render method cleaned up.
Line 128: Line 130:
 
Congratulations the first steps are done. Time for some testing to see if we did it right.
 
Congratulations the first steps are done. Time for some testing to see if we did it right.
  
5. First testing
+
==First testing==
 +
 
 
Now we want to see how it looks in the program.
 
Now we want to see how it looks in the program.
 
To do this add this line of code to your register method:
 
To do this add this line of code to your register method:
Line 147: Line 150:
 
Well done now we need to add some real notifications.
 
Well done now we need to add some real notifications.
  
6. Listening for events
+
==Listening for events==
  
 
Normally a notification area listens for events of the app it is related to. For exsample the mail notifications, listen for events on from the mail api.
 
Normally a notification area listens for events of the app it is related to. For exsample the mail notifications, listen for events on from the mail api.
Line 208: Line 211:
 
CODE
 
CODE
  
7. Drawing the Notifications
+
==Drawing the Notifications==
 
Now that we have proper models, we need to draw them.
 
Now that we have proper models, we need to draw them.
 
To do this we do the same as with the header, create an extension Point and invoke drawing.
 
To do this we do the same as with the header, create an extension Point and invoke drawing.
Line 249: Line 252:
 
PICTURE
 
PICTURE
  
8. Adding a Sidepopup
+
==Adding a Sidepopup==
  
 
A notification without functions is a bit boring, so lets add some action to them by opening a sidepopup and draw the description in it.
 
A notification without functions is a bit boring, so lets add some action to them by opening a sidepopup and draw the description in it.
Line 293: Line 296:
 
Time to check if it works. In the appsuite your notifications should now open a sidepopup if you click on them.
 
Time to check if it works. In the appsuite your notifications should now open a sidepopup if you click on them.
  
9. Add a remove option
+
==Add a remove option==
 
We dont want our notifications to stay there forever, so we need a way to remove them.
 
We dont want our notifications to stay there forever, so we need a way to remove them.
 
Let's add a button to do this.
 
Let's add a button to do this.

Revision as of 13:12, 11 April 2013

Writing a plugin for the notification area

Preparations

To start a new plugin for the notification area you have to add a new folder at apps.plugins/notifications/ . For this tutorial we will create plugins/notifications/tutorial/ .

Now add a new file to your folder and name it register.js . Now add the basic markup such as copyright define, use strict and so on. Our tutorial result should look similar to this.

CODE /**

* your copyright here
* @author Mister Test <mister.test@test.test>
*/

define('plugins/notifications/tutorial/register',

   ['io.ox/core/extensions'], function (ext) {
   'use strict';
   
   //just to give something back
   return true;

}); CODE

Note: We need to use extensions so require the needed resources with ...['io.ox/core/extensions'], function (ext)... as seen above.

Your file is not loaded yet. TO do this we need to create a manifest file. Create a new file in your folder with the name manifest.json with the following code in it:

CODE { namespace: "io.ox/core/notifications" } CODE

For developing add the following code to src manifests.js CODE {

   namespace: ['io.ox/core/notifications'],
   path: 'plugins/notifications/tutorial/register'

} CODE

Registering our plugin

Now we need to register our plugin by extending the right extension point, which is io.ox/core/notifications/register. Give your plugin a unique id and indexnumber and a register function. Inside this register function we register our notification plugin at the controller and also giving it an id and our view, we create later on We do so by adding:

CODE //register our notification plugin ext.point('io.ox/core/notifications/register').extend({

   id: 'tutorial',//unique id
   index: 500, //unused index
   register: function (controller) {
       //give our plugin a name and send it to the controller together with our view
       var notifications = controller.get('io.ox/tutorial', NotificationsView);
   }

}); CODE

io.ox/tutorial is the id the controlelr should use to refer to our plugin and NotificationsView is the view we will create now to display it.

Creating the View

Since we use will use backbone to create our plugin it obviously needs a view. Call the variable like the one you gave to the controller to make it work. In our exsample the code to create the view looks like this.

CODE //the view of our plugin var NotificationsView = Backbone.View.extend({

   className: 'notifications',
   id: 'io-ox-notifications-tutorial',
       
   //events from our items
   events: {
   },
   //draws the plugin
   render: function () {
       return this;
   }

}); CODE

Note: Events and render function are empty at the moment, but we will fix this soon.

Adding the headline

Now we need to draw something. We could just put it in the render method but since we have the extension point architecture we will make use of it, to keep our actual render method cleaned up.

We start by creating an extension point we will use to draw our headline and create a container for our notifications, to put in later. Add this code to your views render method to create the point and invoke the draw method of its extensions.

CODE //build baton to wrap things up var baton = ext.Baton({ view: this }); //draw header and container by creating an extension point and invoke drawing on its extensions ext.point('io.ox/core/notifications/tutorial/header').invoke('draw', this.$el.empty(), baton); CODE

Note: Here we use our special baton objects to pass the data to the extension points. By using this.$el.empty() as a dom node to draw we ensure that we clean up properly before drawing.

Now extend the point with a simple draw method for our header and container. 'this' refers to our views dom node we draw in in the rendering method.

CODE //the header and container for the notification plugin ext.point('io.ox/core/notifications/tutorial/header').extend({

   draw: function (baton) {
       this.append(
           $('<legend class="section-title">').text('Hello World'),//header

$('

')//the container for our notifications
       );
   }

}); CODE

Congratulations the first steps are done. Time for some testing to see if we did it right.

First testing

Now we want to see how it looks in the program. To do this add this line of code to your register method: CODE notifications.collection.reset(new Backbone.Model()); CODE This creates an empty notification model and adds it to our plugins collection. We get to know how this collection works later on, for now we just need something in it for the controller to think that there is a notification to display.

When finished start your appsuite and login, add &customManifests=true to the url to load your plugin and reload the page.

Note: The notification area is loaded with a delay, so you have to wait a bit.

After its loaded you should see something like this:

PICTURE

Well done now we need to add some real notifications.

Listening for events

Normally a notification area listens for events of the app it is related to. For exsample the mail notifications, listen for events on from the mail api.

For this Tutorial we will just create a small dummy to create some Notifications for us and then trigger the proper event.

Our dummy looks like this:

CODE //simple helper to trigger some events //normally this is done by mailapi, taskapi, etc. var myEventTriggerer = {

       lookForItems: function () {
           //build some items and put them in an array
           var items = [{title: 'I am a notification', description: 'Hello world!'},
                        {title: 'I am a notification too', description: 'Hooray!'}];
           //trigger the event to add them
           $(myEventTriggerer).trigger('set-tutorial-notification', [items]);
       }
   };

CODE

This dummy creates an array with two objects containing our notifications data. Then it triggers an event on itself and passes the array as an argument.

Notifications are stored as backbone models in a collection of our view. Or models have the attributes title and description. A cid is added automatically that we use to identyfy them later on. You can also give ids as normal attributes and use them if you want more control over it. This collection is available in the register method under notifications.collection. The controller looks for changes in this collection and triggers a redraw.

To do this we create a simple functions for resetting notification models in our collection. Remove our testing line (notifications.collection.reset(new Backbone.Model());)from the register method and add our new function:

CODE //fill our collection of notification models with new ones //items here is an array of Objects containing our attributes function reset(e, items) {

   var models = [];
   items = [].concat(items);//make sure we have an array
   _(items).each(function (item) {
       models.push(new Backbone.Model(item));
       });
   notifications.collection.reset(models);//fill the collection
   }

CODE

These function simply loops over the array of items they are given, creates models from them and fills the collection with it. Reset means that the old models are gone now and only the new ones are in our collection. Functions to add and remove models are done the same way but are not always needed, as in this exsample.

Note: notifications.collection.add() does not trigger the add event. You need to do this manually, this seems to be a Backbone issue.

So now we need just listen to the event to launch our reset function and call our little dummy to fill our initial collection. We do this by adding this Code to the register method. CODE //now add the event listeners $(myEventTriggerer).on('set-tutorial-notification', reset);

//just to make sure it gets filled with values on load we trigger our search method myEventTriggerer.lookForItems(); CODE

Drawing the Notifications

Now that we have proper models, we need to draw them. To do this we do the same as with the header, create an extension Point and invoke drawing. In our views render method we need to add:

CODE //loop over collection and draw this.collection.each(function (model) {

   baton = ext.Baton({ model: model, view: this });
   ext.point('io.ox/core/notifications/tutorial/item')
       .invoke('draw', this.$('.notifications'), baton);//draw the item

}, this); CODE

This time we draw in the container div we created by our header drawing method. Next we extend our extension point to draw the actual notification items.

In our exsample it looks like this: CODE //draw a single notification item ext.point('io.ox/core/notifications/tutorial/item').extend({

   draw: function (baton) {
       this.append(
$('
')
       .attr('data-cid', baton.model.cid)//needed for identification
           .append(
$('
').text(baton.model.get('title')),//some text to fill it
           )
       );
   }

}); CODE

As you can see we add div with the classes tutorial and item and give it the attribute 'data-cid' which we fill with our models cid or your custom id from the models attributes for later identification. After that we add a node ad fill it with the title text of our model.

Open up your Appsuite and check if everything works. Be sure to load the custom manifests if needed. It should look like this:

PICTURE

Adding a Sidepopup

A notification without functions is a bit boring, so lets add some action to them by opening a sidepopup and draw the description in it.

Change your views events so it looks like this.

CODE //events from our items events: {

   'click .item': 'openPopup',

}, CODE

This calls the openPopup function of our view if you click on a div with the class item, which , in this case, are our notifications. We will create the openPopup function now, add this function to your view:

CODE //the action for our sidepopup openPopup: function (e) {

   var overlay = $('#io-ox-notifications-overlay'),//the overlay we draw our sidepopup in
       cid = $(e.currentTarget).attr('data-cid'),//getting the right model
       model = this.collection.getByCid(cid);
           
   require(['io.ox/core/tk/dialogs'], function (dialogs) {//require dialogs
       //create the popup
       new dialogs.SidePopup({ arrow: false, side: 'right' })
           .setTarget(overlay)
           .show(e, function (popup) {
               //fill it with our data
popup.append($('
').text(model.get('title')),
                            $('
'),
$('
').text(model.get('description')));
           });
   });

} CODE

This first we define some variables. Overlay is the div we append our popup to, cid is the cid we added as an attribute to our notification div earlier and model is the model we get from our collection by this cid. After this we require our dialogs plugin and create a new sidepopup. The Target we draw it on is the overlay we grabbed earlier. In the show method we draw the contents of our popup. In this case its the models title variable and description variable.

Time to check if it works. In the appsuite your notifications should now open a sidepopup if you click on them.

Add a remove option

We dont want our notifications to stay there forever, so we need a way to remove them. Let's add a button to do this.

Add the button in your item draw function:

CODE ext.point('io.ox/core/notifications/tutorial/item').extend({

   draw: function (baton) {
       this.append(
$('
')
       .attr('data-cid', baton.model.cid)//needed for identification
           .append(
$('
').text(baton.model.get('title')),//some text to fill it
               $('<button class="btn" data-action="close">').text('close')//close button
           )
       );
   }

}); CODE

Now add an event to your view to be triggered on clicking it.

CODE events: {

   'click .item': 'openPopup',
   'click [data-action="close"]': 'closeNotification'

} CODE

This will call the closeNotification if the user clicks on a dom node where the attribute data-action has the value close, like our button.

Finally add the close funktion to your view:

CODE //the action for the close button closeNotification: function (e) {

   e.stopPropagation();//to prevent sidepopup from opening
           
   var cid = $(e.currentTarget).closest('.item').attr('data-cid'),//getting the right model
       model = this.collection.getByCid(cid);
           
   this.collection.remove(model);//remove it from the collection

} CODE

Again get the cid to identify the right model, then remove it from the collection. e.stopPropagation() is important here because otherwise the event would bubble up and trigger the click event for opening our sidepopup too.

Congratulations your notifications should be removed if you click the button.

You can download the exsamplecode here.