<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.open-xchange.com/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=D.haus</id>
	<title>Open-Xchange - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.open-xchange.com/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=D.haus"/>
	<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=Special:Contributions/D.haus"/>
	<updated>2026-06-30T22:12:16Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_portal_plugin&amp;diff=22224</id>
		<title>AppSuite:Writing a portal plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_portal_plugin&amp;diff=22224"/>
		<updated>2016-07-20T09:18:43Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Where and how to start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- !!! --&amp;gt;&lt;br /&gt;
&amp;lt;!-- PLEASE APPLY CHANGES ONLY TO THE NEW TECHNICAL DOCUMENTATION: wd/frontend/web/documentation --&amp;gt; &lt;br /&gt;
&amp;lt;!-- !!! --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Stability-stable}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a portal plugin&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This articles covers how to write a plugin that shows on the portal page. A portal plugin always gives a short overview on a piece of information (the so-called 'tile'). It can link a longer view that is opened when the tile is clicked, this we call the side pop-up. The side pop-up is optional.&lt;br /&gt;
&lt;br /&gt;
== Where and how to start ==&lt;br /&gt;
Portal plugins are collected in the folder ui/apps/plugins/portal. Start your new plugin there: Create a folder and in this folder, create two files: &amp;lt;tt&amp;gt;register.js&amp;lt;/tt&amp;gt; (where everything happens) and &amp;lt;tt&amp;gt;manifest.json&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The simplest portal plugin: An advertisement ==&lt;br /&gt;
The simplest portal plugin comes without a side pop-up and shows static content on its tile. Two uses for this would be presenting an advertisement (or your daily creed, an often used check list....) or showing a link list (for example to other parts of an company's intranet that are not integrated into the AppSuite (yet)). We will now build an advertisement, which is just a slogan.&lt;br /&gt;
&lt;br /&gt;
The beauty of this is that we do not have any dependencies (for example needing another module like the file store), so the content of our manifest.json is rather simple:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;namespace&amp;quot;: &amp;quot;portal&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nothing to see here. We say we belong in the portal namespace and that's it. We do not need to define any dependencies on other modules.&lt;br /&gt;
&lt;br /&gt;
Our register.js is only slightly longer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
define('plugins/portal/myAd/register', ['io.ox/core/extensions'], function (ext) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget').extend({&lt;br /&gt;
        id: 'myAd'&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget/myAd').extend({&lt;br /&gt;
        preview: function () {&lt;br /&gt;
            var content = $('&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;')&lt;br /&gt;
                .text('Buy stuff. It's like solid happiness.');&lt;br /&gt;
            this.append(content);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget/myAd/settings').extend({&lt;br /&gt;
        title: 'My advertisement',&lt;br /&gt;
        type: 'myAd'&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Please keep in mind, that the first parameter of define()-method refers to your app's path. According to the code above &amp;lt;tt&amp;gt;plugins/portal/myAd/&amp;lt;/tt&amp;gt; should contain the upper displayed &amp;lt;tt&amp;gt;register.js&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
So what do we have here? We have two extension points:&lt;br /&gt;
 &lt;br /&gt;
The first one is for the ad itself, ''io.ox/portal/widget/myAd''. This one contains a single method that we implement, ''preview''. ''Preview'' is responsible for the tile you see whenever you look at your portal. Technically, ''this'' contains the container to which you can attach your content. If you are brave, you can do changes on the container, too. But that is not needed for now.&lt;br /&gt;
&lt;br /&gt;
The second is less obvious: It creates an option in the settings area for the portal (the one you reach by &amp;quot;customize this page&amp;quot;). There you will have to enable your setting (yes, this is a very polite advertisement). The ''title'' is what is shown as the name of your plugin (so chose a readable one), the type references the one you used in the definition. '''Attention:''' the ''type'' attribute has to be identical to the module name in the extension point. In this case &amp;quot;io.ox/portal/widget/myAd/settings&amp;quot; has the module name ''myAd'' and the referenced ''type'' is identical: ''myAd''. Also make sure, the type doesn’t contain any &amp;quot;/&amp;quot; or &amp;quot;-&amp;quot; characters. You are save if you limit the characters used to numbers, alphabetical characters and &amp;quot;_&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== A more typical portal plugin ==&lt;br /&gt;
A typical portal plugin uses the tile to display a short summary or teaser of its contents and uses a side-popup to show the whole content.&lt;br /&gt;
&lt;br /&gt;
The manifest.json can stay the same, but the register.js needs to do a little more now:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
define(&amp;quot;plugins/portal/myAd/register&amp;quot;, ['io.ox/core/extensions'], function (ext) {&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;use strict&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget').extend({&lt;br /&gt;
        id: 'myAd'&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget/myAd').extend({&lt;br /&gt;
        title: &amp;quot;My Advertisement&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
        load: function (baton) {&lt;br /&gt;
            var def = $.Deferred();&lt;br /&gt;
            def.resolve(&amp;quot;It's like solid happiness.&amp;quot;).done(function (data) {&lt;br /&gt;
                baton.data = {&lt;br /&gt;
                    teaser: 'Buy stuff',&lt;br /&gt;
                    fullText: 'Buy stuff. It is like solid happiness.'&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
            return def;&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        preview: function (baton) {&lt;br /&gt;
            var content = $('&amp;lt;div class=&amp;quot;content pointer&amp;quot;&amp;gt;')&lt;br /&gt;
                .text(baton.data.teaser);&lt;br /&gt;
            this.append(content);&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var content = $('&amp;lt;div class=&amp;quot;myAdd&amp;quot;&amp;gt;')&lt;br /&gt;
                .text(baton.data.fullText);&lt;br /&gt;
            this.append(content);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget/myAd/settings').extend({&lt;br /&gt;
        title: 'My advertisement',&lt;br /&gt;
        type: 'myAd'&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What happened here? We have gained two new methods and all three methods seems to be passing something called ''baton'' around. The baton is actually just that - something to pass around. The baton carries data between different methods.&lt;br /&gt;
&lt;br /&gt;
=== Order of execution ===&lt;br /&gt;
How do the three functions interact? When a plugin is supposed to be rendered, the first method to be called is &amp;quot;load&amp;quot;. Load usually does some (asynchronous) loading of data, be it from the file store or some external source. Meanwhile, the empty tile (well, if you give it a title, that is already rendered, so it is not completely naked) is rendered on the portal page. &lt;br /&gt;
&lt;br /&gt;
When the loading is done, it is consensus that the loaded data is stored as baton.data. Then ''preview'' is called and usually does something with the data in the baton. It then renders its content, which is appended to the tile.&lt;br /&gt;
&lt;br /&gt;
When the tile is clicked on, a side popup is drawn (which, again, is nearly naked). Meanwhile, the function ''draw'' is called. As with ''preview'', ''draw'' usually uses the data from the baton.&lt;br /&gt;
&lt;br /&gt;
The given example is a stereotypical use case: First, ''load'' gets the data. Then ''preview'' renders a short version of the data on the tile. When clicked, ''draw'' renders a longer, more detailed view of that data on a side popup.&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
If you look closely, you will find that the class of the container on the tile has changed to &amp;quot;content pointer&amp;quot;. This is relevant, as this makes the whole tile clickable (there is a delegate for '.item .content.pointer' that does that). This is just a comfortable way to do so, you don't have to use it.  If you want to have different sections of your tile to execute different actions, you will have to implement handlers yourself.&lt;br /&gt;
&lt;br /&gt;
This covers the most common uses of portal widgets. But if you are looking for more, we got more:&lt;br /&gt;
&lt;br /&gt;
== Advanced plugins ==&lt;br /&gt;
&lt;br /&gt;
=== Initialize ===&lt;br /&gt;
Sometimes you want to do things even before loading. Maybe pre-populate the baton. For this we have the method ''initialize'':&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ext.point('io.ox/portal/widget/myAd').extend({&lt;br /&gt;
    ...&lt;br /&gt;
    initialize: function (baton) {&lt;br /&gt;
        baton.default = &amp;quot;Defaultiness&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Things that require a setup ===&lt;br /&gt;
There are some external sources that need some kind of set up before they can be used. Services that need an OAuth authorization, for example. For this, you need to implement two more functions, named ''requiresSetup'' and ''performSetup''. The former determines whether it is necessary to run a setup, the latter starts the setup process if the former returns ''true''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ext.point('io.ox/portal/widget/myAd').extend({&lt;br /&gt;
    ...&lt;br /&gt;
    requiresSetup: function () {&lt;br /&gt;
        return isMissingAnAccount();&lt;br /&gt;
    },&lt;br /&gt;
    performSetup: function () {&lt;br /&gt;
        createANewAccount();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Unique ===&lt;br /&gt;
Talking about things with OAuth... a lot of data sources are unique - people only have one twitter account. To make sure the widget can only be created once, set it to ''unique'':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ext.point('io.ox/portal/widget/myAd/settings').extend({&lt;br /&gt;
    title: 'My advertisement',&lt;br /&gt;
    type: 'myAd',&lt;br /&gt;
    unique: true&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error handling ===&lt;br /&gt;
Occasionally, it might happen that there is an error when loading an external source. Should this occur and ''load'' (which, as you know, uses a $.Deferred) call ''fail'' instead of ''done'', the function ''error'' is called. This allows you to handle this case differently. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ext.point('io.ox/portal/widget/myAd').extend({&lt;br /&gt;
    ...&lt;br /&gt;
    error: function (error) {&lt;br /&gt;
        $(this).empty().append(&lt;br /&gt;
            $('&amp;lt;div&amp;gt;').text('An error occurred.');&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is not a catch-all solution, though: If you do not use ''load'' to load that data, but do it in either ''preview'' or ''draw'', this will not work. It will also not work if the service that is called wraps the error nicely in a valid response.&lt;br /&gt;
&lt;br /&gt;
=== Configurable settings ===&lt;br /&gt;
Sometimes you want to fine-tune your widget. The place to do so is in the settings. If you mark your settings ''editable'', your settings gets a little 'edit' link and you get to define a function that is called. This function is given both the model and the view so you can build your own settings pane:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ext.point('io.ox/portal/widget/myAd/settings').extend({&lt;br /&gt;
    editable: true,&lt;br /&gt;
    edit: function (model, view) {&lt;br /&gt;
       ...&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Stuck somewhere? ==&lt;br /&gt;
You got stuck with a problem while developing? OXpedia might help you out with the article about [[AppSuite:Debugging_the_UI | debugging the UI]].&lt;br /&gt;
&lt;br /&gt;
=== Checklist: Paths, names and Types ===&lt;br /&gt;
Remember:&lt;br /&gt;
* The path of the extension point must be &amp;lt;tt&amp;gt;io.ox/portal/widget/$name&amp;lt;/tt&amp;gt;&lt;br /&gt;
* You have to have settings!&lt;br /&gt;
* The path of the settings extension point must be &amp;lt;tt&amp;gt;io.ox/portal/widget/$name/settings&amp;lt;/tt&amp;gt;&lt;br /&gt;
* The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; of the settings extension point must match the &amp;lt;tt&amp;gt;$name&amp;lt;/tt&amp;gt; of the portal plugin!&lt;br /&gt;
* go all lowercase with your widget name, versions &amp;lt;7.6 sometimes had issues with that&lt;br /&gt;
&lt;br /&gt;
=== My shiny new widget does not show up in the widget selection ===&lt;br /&gt;
Yes. That is surprising, isn't it? There is a small peculiarity about manifests: They may be in the frontend, but the backend needs to know about them. Luckily, that is done automatically on system startup. You probably did not restart your server, didn't you?&lt;br /&gt;
&lt;br /&gt;
If you cannot simply restart your server, but you want to test (good!), you can hack your widget into the list of loaded widgets. Open the &amp;lt;tt&amp;gt;io.ox/portal/widgets.js&amp;lt;/tt&amp;gt; and look for the variable DEV_PLUGINS. Add the name of your plugin in there and re-build the UI.&lt;br /&gt;
&lt;br /&gt;
== Finishing touches ==&lt;br /&gt;
Now that you have learned all there is about portal plugins, it is time to clean up. Check whether your plugin only [[AppSuite:UI manifests explained | works when a certain module is active]]. Also, maybe we can interest you in [[AppSuite:i18n |  preparing the text for readers from other countries]]? There is also an article on [[AppSuite:Configuring_portal_plugins|plugins only showing under certain circumstances]].&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_portal_plugin&amp;diff=22223</id>
		<title>AppSuite:Writing a portal plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_portal_plugin&amp;diff=22223"/>
		<updated>2016-07-20T09:18:28Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Where and how to start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- !!! --&amp;gt;&lt;br /&gt;
&amp;lt;!-- PLEASE APPLY CHANGES ONLY TO THE NEW TECHNICAL DOCUMENTATION: wd/frontend/web/documentation --&amp;gt; &lt;br /&gt;
&amp;lt;!-- !!! --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Stability-stable}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a portal plugin&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This articles covers how to write a plugin that shows on the portal page. A portal plugin always gives a short overview on a piece of information (the so-called 'tile'). It can link a longer view that is opened when the tile is clicked, this we call the side pop-up. The side pop-up is optional.&lt;br /&gt;
&lt;br /&gt;
== Where and how to start ==&lt;br /&gt;
Poral plugins are collected in the folder ui/apps/plugins/portal. Start your new plugin there: Create a folder and in this folder, create two files: &amp;lt;tt&amp;gt;register.js&amp;lt;/tt&amp;gt; (where everything happens) and &amp;lt;tt&amp;gt;manifest.json&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== The simplest portal plugin: An advertisement ==&lt;br /&gt;
The simplest portal plugin comes without a side pop-up and shows static content on its tile. Two uses for this would be presenting an advertisement (or your daily creed, an often used check list....) or showing a link list (for example to other parts of an company's intranet that are not integrated into the AppSuite (yet)). We will now build an advertisement, which is just a slogan.&lt;br /&gt;
&lt;br /&gt;
The beauty of this is that we do not have any dependencies (for example needing another module like the file store), so the content of our manifest.json is rather simple:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
{&lt;br /&gt;
	&amp;quot;namespace&amp;quot;: &amp;quot;portal&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nothing to see here. We say we belong in the portal namespace and that's it. We do not need to define any dependencies on other modules.&lt;br /&gt;
&lt;br /&gt;
Our register.js is only slightly longer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
define('plugins/portal/myAd/register', ['io.ox/core/extensions'], function (ext) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget').extend({&lt;br /&gt;
        id: 'myAd'&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget/myAd').extend({&lt;br /&gt;
        preview: function () {&lt;br /&gt;
            var content = $('&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;')&lt;br /&gt;
                .text('Buy stuff. It's like solid happiness.');&lt;br /&gt;
            this.append(content);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget/myAd/settings').extend({&lt;br /&gt;
        title: 'My advertisement',&lt;br /&gt;
        type: 'myAd'&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Please keep in mind, that the first parameter of define()-method refers to your app's path. According to the code above &amp;lt;tt&amp;gt;plugins/portal/myAd/&amp;lt;/tt&amp;gt; should contain the upper displayed &amp;lt;tt&amp;gt;register.js&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
So what do we have here? We have two extension points:&lt;br /&gt;
 &lt;br /&gt;
The first one is for the ad itself, ''io.ox/portal/widget/myAd''. This one contains a single method that we implement, ''preview''. ''Preview'' is responsible for the tile you see whenever you look at your portal. Technically, ''this'' contains the container to which you can attach your content. If you are brave, you can do changes on the container, too. But that is not needed for now.&lt;br /&gt;
&lt;br /&gt;
The second is less obvious: It creates an option in the settings area for the portal (the one you reach by &amp;quot;customize this page&amp;quot;). There you will have to enable your setting (yes, this is a very polite advertisement). The ''title'' is what is shown as the name of your plugin (so chose a readable one), the type references the one you used in the definition. '''Attention:''' the ''type'' attribute has to be identical to the module name in the extension point. In this case &amp;quot;io.ox/portal/widget/myAd/settings&amp;quot; has the module name ''myAd'' and the referenced ''type'' is identical: ''myAd''. Also make sure, the type doesn’t contain any &amp;quot;/&amp;quot; or &amp;quot;-&amp;quot; characters. You are save if you limit the characters used to numbers, alphabetical characters and &amp;quot;_&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== A more typical portal plugin ==&lt;br /&gt;
A typical portal plugin uses the tile to display a short summary or teaser of its contents and uses a side-popup to show the whole content.&lt;br /&gt;
&lt;br /&gt;
The manifest.json can stay the same, but the register.js needs to do a little more now:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
define(&amp;quot;plugins/portal/myAd/register&amp;quot;, ['io.ox/core/extensions'], function (ext) {&lt;br /&gt;
&lt;br /&gt;
    &amp;quot;use strict&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget').extend({&lt;br /&gt;
        id: 'myAd'&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget/myAd').extend({&lt;br /&gt;
        title: &amp;quot;My Advertisement&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
        load: function (baton) {&lt;br /&gt;
            var def = $.Deferred();&lt;br /&gt;
            def.resolve(&amp;quot;It's like solid happiness.&amp;quot;).done(function (data) {&lt;br /&gt;
                baton.data = {&lt;br /&gt;
                    teaser: 'Buy stuff',&lt;br /&gt;
                    fullText: 'Buy stuff. It is like solid happiness.'&lt;br /&gt;
                };&lt;br /&gt;
            });&lt;br /&gt;
            return def;&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        preview: function (baton) {&lt;br /&gt;
            var content = $('&amp;lt;div class=&amp;quot;content pointer&amp;quot;&amp;gt;')&lt;br /&gt;
                .text(baton.data.teaser);&lt;br /&gt;
            this.append(content);&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var content = $('&amp;lt;div class=&amp;quot;myAdd&amp;quot;&amp;gt;')&lt;br /&gt;
                .text(baton.data.fullText);&lt;br /&gt;
            this.append(content);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/portal/widget/myAd/settings').extend({&lt;br /&gt;
        title: 'My advertisement',&lt;br /&gt;
        type: 'myAd'&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What happened here? We have gained two new methods and all three methods seems to be passing something called ''baton'' around. The baton is actually just that - something to pass around. The baton carries data between different methods.&lt;br /&gt;
&lt;br /&gt;
=== Order of execution ===&lt;br /&gt;
How do the three functions interact? When a plugin is supposed to be rendered, the first method to be called is &amp;quot;load&amp;quot;. Load usually does some (asynchronous) loading of data, be it from the file store or some external source. Meanwhile, the empty tile (well, if you give it a title, that is already rendered, so it is not completely naked) is rendered on the portal page. &lt;br /&gt;
&lt;br /&gt;
When the loading is done, it is consensus that the loaded data is stored as baton.data. Then ''preview'' is called and usually does something with the data in the baton. It then renders its content, which is appended to the tile.&lt;br /&gt;
&lt;br /&gt;
When the tile is clicked on, a side popup is drawn (which, again, is nearly naked). Meanwhile, the function ''draw'' is called. As with ''preview'', ''draw'' usually uses the data from the baton.&lt;br /&gt;
&lt;br /&gt;
The given example is a stereotypical use case: First, ''load'' gets the data. Then ''preview'' renders a short version of the data on the tile. When clicked, ''draw'' renders a longer, more detailed view of that data on a side popup.&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
If you look closely, you will find that the class of the container on the tile has changed to &amp;quot;content pointer&amp;quot;. This is relevant, as this makes the whole tile clickable (there is a delegate for '.item .content.pointer' that does that). This is just a comfortable way to do so, you don't have to use it.  If you want to have different sections of your tile to execute different actions, you will have to implement handlers yourself.&lt;br /&gt;
&lt;br /&gt;
This covers the most common uses of portal widgets. But if you are looking for more, we got more:&lt;br /&gt;
&lt;br /&gt;
== Advanced plugins ==&lt;br /&gt;
&lt;br /&gt;
=== Initialize ===&lt;br /&gt;
Sometimes you want to do things even before loading. Maybe pre-populate the baton. For this we have the method ''initialize'':&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ext.point('io.ox/portal/widget/myAd').extend({&lt;br /&gt;
    ...&lt;br /&gt;
    initialize: function (baton) {&lt;br /&gt;
        baton.default = &amp;quot;Defaultiness&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Things that require a setup ===&lt;br /&gt;
There are some external sources that need some kind of set up before they can be used. Services that need an OAuth authorization, for example. For this, you need to implement two more functions, named ''requiresSetup'' and ''performSetup''. The former determines whether it is necessary to run a setup, the latter starts the setup process if the former returns ''true''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ext.point('io.ox/portal/widget/myAd').extend({&lt;br /&gt;
    ...&lt;br /&gt;
    requiresSetup: function () {&lt;br /&gt;
        return isMissingAnAccount();&lt;br /&gt;
    },&lt;br /&gt;
    performSetup: function () {&lt;br /&gt;
        createANewAccount();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Unique ===&lt;br /&gt;
Talking about things with OAuth... a lot of data sources are unique - people only have one twitter account. To make sure the widget can only be created once, set it to ''unique'':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ext.point('io.ox/portal/widget/myAd/settings').extend({&lt;br /&gt;
    title: 'My advertisement',&lt;br /&gt;
    type: 'myAd',&lt;br /&gt;
    unique: true&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error handling ===&lt;br /&gt;
Occasionally, it might happen that there is an error when loading an external source. Should this occur and ''load'' (which, as you know, uses a $.Deferred) call ''fail'' instead of ''done'', the function ''error'' is called. This allows you to handle this case differently. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ext.point('io.ox/portal/widget/myAd').extend({&lt;br /&gt;
    ...&lt;br /&gt;
    error: function (error) {&lt;br /&gt;
        $(this).empty().append(&lt;br /&gt;
            $('&amp;lt;div&amp;gt;').text('An error occurred.');&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is not a catch-all solution, though: If you do not use ''load'' to load that data, but do it in either ''preview'' or ''draw'', this will not work. It will also not work if the service that is called wraps the error nicely in a valid response.&lt;br /&gt;
&lt;br /&gt;
=== Configurable settings ===&lt;br /&gt;
Sometimes you want to fine-tune your widget. The place to do so is in the settings. If you mark your settings ''editable'', your settings gets a little 'edit' link and you get to define a function that is called. This function is given both the model and the view so you can build your own settings pane:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt; &lt;br /&gt;
ext.point('io.ox/portal/widget/myAd/settings').extend({&lt;br /&gt;
    editable: true,&lt;br /&gt;
    edit: function (model, view) {&lt;br /&gt;
       ...&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Stuck somewhere? ==&lt;br /&gt;
You got stuck with a problem while developing? OXpedia might help you out with the article about [[AppSuite:Debugging_the_UI | debugging the UI]].&lt;br /&gt;
&lt;br /&gt;
=== Checklist: Paths, names and Types ===&lt;br /&gt;
Remember:&lt;br /&gt;
* The path of the extension point must be &amp;lt;tt&amp;gt;io.ox/portal/widget/$name&amp;lt;/tt&amp;gt;&lt;br /&gt;
* You have to have settings!&lt;br /&gt;
* The path of the settings extension point must be &amp;lt;tt&amp;gt;io.ox/portal/widget/$name/settings&amp;lt;/tt&amp;gt;&lt;br /&gt;
* The &amp;lt;tt&amp;gt;type&amp;lt;/tt&amp;gt; of the settings extension point must match the &amp;lt;tt&amp;gt;$name&amp;lt;/tt&amp;gt; of the portal plugin!&lt;br /&gt;
* go all lowercase with your widget name, versions &amp;lt;7.6 sometimes had issues with that&lt;br /&gt;
&lt;br /&gt;
=== My shiny new widget does not show up in the widget selection ===&lt;br /&gt;
Yes. That is surprising, isn't it? There is a small peculiarity about manifests: They may be in the frontend, but the backend needs to know about them. Luckily, that is done automatically on system startup. You probably did not restart your server, didn't you?&lt;br /&gt;
&lt;br /&gt;
If you cannot simply restart your server, but you want to test (good!), you can hack your widget into the list of loaded widgets. Open the &amp;lt;tt&amp;gt;io.ox/portal/widgets.js&amp;lt;/tt&amp;gt; and look for the variable DEV_PLUGINS. Add the name of your plugin in there and re-build the UI.&lt;br /&gt;
&lt;br /&gt;
== Finishing touches ==&lt;br /&gt;
Now that you have learned all there is about portal plugins, it is time to clean up. Check whether your plugin only [[AppSuite:UI manifests explained | works when a certain module is active]]. Also, maybe we can interest you in [[AppSuite:i18n |  preparing the text for readers from other countries]]? There is also an article on [[AppSuite:Configuring_portal_plugins|plugins only showing under certain circumstances]].&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;br /&gt;
[[Category:Developer]]&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20418</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20418"/>
		<updated>2015-09-11T07:43:54Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding desktop notifications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code just adds a simple hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register'' and uses ''io.ox/core/notifications/subview'' to create the subview needed for our plugin.&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our subview and add a notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
To load our code we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications.&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. Here we have a new text attribute in our notification models that we display. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The API object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the API triggers when notifications should be added. The provided data is used by the addNotifications function.&lt;br /&gt;
**remove: A string that contains the events the API triggers when notifications should be removed. The provided data is used by the removeNotifications function.&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function.&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a matching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
This is designed to fit our core APIs like mail or calendar, but custom APIs should work as well.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usally you would have the API in a separate file but in our example we keep it with the other code for simplicity. Also note that this API just works as a dummy, normally you would use server requests etc to get your data, but depending on the design of your API this may vary.&lt;br /&gt;
&lt;br /&gt;
In our example the reset function is now handled by the API. It throws a reset event that we also added to the options of our subview, so that it listens to it properly. We also use the get function here to get additional data. If your API does not need additional data and should only use the initial data provided when the notification was created, just set the ''fullModel'' option to true.&lt;br /&gt;
Note that the API extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
==Adding Detailviews==&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the API (''fullModel'' = false), or the data from the collection is used (''fullModel'' = true). To get the right data the DOM node of the notification needs a ''data-cid'' attribute that contains the id for either API or collection.&lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a simple object with a draw function. It's important that this function returns ''one'' jquery node.&lt;br /&gt;
Also note that we added a data-cid attribute, so the API can lookup the correct item.&lt;br /&gt;
&lt;br /&gt;
In the browser it looks like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: detailview.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding desktop notifications==&lt;br /&gt;
&lt;br /&gt;
Finally you can add desktop notifications. This notifications are shown by the browser, if the appsuite is minimized or the tab is not active at the moment. The subview can show individual notifications, if there is only one new item or a more generic notification, if there are multiple new items.&lt;br /&gt;
&lt;br /&gt;
To use it you can use the following options:&lt;br /&gt;
*desktopNotificationSupport: If you want to use desktop notifications this has to be true. Default is ''true''&lt;br /&gt;
*genericDesktopNotification: This is the desktop notification shown when there are multiple new notifications or if there is no specific one. Accepts all attributes ''io.ox/core/desktopNotifications.show'' accepts. Default is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    title: gt('New notifications'),&lt;br /&gt;
    body: gt('You\'ve got new notifications'),&lt;br /&gt;
    icon: ''&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*specificDesktopNotification: Function that is called when there is only one new notification. The notifications data is provided as a model. Default is null.&lt;br /&gt;
&lt;br /&gt;
Adding a specific notification to our example would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    specificDesktopNotification: function (model) {&lt;br /&gt;
                        return {&lt;br /&gt;
                            title: 'New tutorial notification',&lt;br /&gt;
                            body: model.get('text'),&lt;br /&gt;
                            icon: ''&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
You can download the examplecode here.&lt;br /&gt;
&lt;br /&gt;
[[File: Notification780_tutorial.zip]].&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20417</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20417"/>
		<updated>2015-09-11T07:43:25Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding desktop notifications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code just adds a simple hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register'' and uses ''io.ox/core/notifications/subview'' to create the subview needed for our plugin.&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our subview and add a notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
To load our code we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications.&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. Here we have a new text attribute in our notification models that we display. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The API object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the API triggers when notifications should be added. The provided data is used by the addNotifications function.&lt;br /&gt;
**remove: A string that contains the events the API triggers when notifications should be removed. The provided data is used by the removeNotifications function.&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function.&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a matching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
This is designed to fit our core APIs like mail or calendar, but custom APIs should work as well.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usally you would have the API in a separate file but in our example we keep it with the other code for simplicity. Also note that this API just works as a dummy, normally you would use server requests etc to get your data, but depending on the design of your API this may vary.&lt;br /&gt;
&lt;br /&gt;
In our example the reset function is now handled by the API. It throws a reset event that we also added to the options of our subview, so that it listens to it properly. We also use the get function here to get additional data. If your API does not need additional data and should only use the initial data provided when the notification was created, just set the ''fullModel'' option to true.&lt;br /&gt;
Note that the API extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
==Adding Detailviews==&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the API (''fullModel'' = false), or the data from the collection is used (''fullModel'' = true). To get the right data the DOM node of the notification needs a ''data-cid'' attribute that contains the id for either API or collection.&lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a simple object with a draw function. It's important that this function returns ''one'' jquery node.&lt;br /&gt;
Also note that we added a data-cid attribute, so the API can lookup the correct item.&lt;br /&gt;
&lt;br /&gt;
In the browser it looks like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: detailview.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding desktop notifications==&lt;br /&gt;
&lt;br /&gt;
Finally you can add desktop notifications. This notifications are shown by the browser, if the appsuite is minimized or the tab is not active at the moment. The subview can show individual notifications, if there is only one new item or a more generic notification, if there are multiple new items.&lt;br /&gt;
&lt;br /&gt;
To use it you can use the following options:&lt;br /&gt;
*desktopNotificationSupport: If you want to use desktop notifications this has to be true. default is ''true''&lt;br /&gt;
*genericDesktopNotification: This is the desktop notification shown when there are multiple new notifications or if there is no specific one. Accepts all attributes ''io.ox/core/desktopNotifications.show'' accepts. Default is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    title: gt('New notifications'),&lt;br /&gt;
    body: gt('You\'ve got new notifications'),&lt;br /&gt;
    icon: ''&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*specificDesktopNotification: Function that is called when there is only one new notification. The notifications data is provided as a model. Default is null.&lt;br /&gt;
&lt;br /&gt;
Adding a specific notification to our example would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    specificDesktopNotification: function (model) {&lt;br /&gt;
                        return {&lt;br /&gt;
                            title: 'New tutorial notification',&lt;br /&gt;
                            body: model.get('text'),&lt;br /&gt;
                            icon: ''&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
You can download the examplecode here.&lt;br /&gt;
&lt;br /&gt;
[[File: Notification780_tutorial.zip]].&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20416</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20416"/>
		<updated>2015-09-11T07:42:42Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding Detailviews */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code just adds a simple hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register'' and uses ''io.ox/core/notifications/subview'' to create the subview needed for our plugin.&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our subview and add a notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
To load our code we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications.&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. Here we have a new text attribute in our notification models that we display. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The API object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the API triggers when notifications should be added. The provided data is used by the addNotifications function.&lt;br /&gt;
**remove: A string that contains the events the API triggers when notifications should be removed. The provided data is used by the removeNotifications function.&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function.&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a matching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
This is designed to fit our core APIs like mail or calendar, but custom APIs should work as well.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usally you would have the API in a separate file but in our example we keep it with the other code for simplicity. Also note that this API just works as a dummy, normally you would use server requests etc to get your data, but depending on the design of your API this may vary.&lt;br /&gt;
&lt;br /&gt;
In our example the reset function is now handled by the API. It throws a reset event that we also added to the options of our subview, so that it listens to it properly. We also use the get function here to get additional data. If your API does not need additional data and should only use the initial data provided when the notification was created, just set the ''fullModel'' option to true.&lt;br /&gt;
Note that the API extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
==Adding Detailviews==&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the API (''fullModel'' = false), or the data from the collection is used (''fullModel'' = true). To get the right data the DOM node of the notification needs a ''data-cid'' attribute that contains the id for either API or collection.&lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a simple object with a draw function. It's important that this function returns ''one'' jquery node.&lt;br /&gt;
Also note that we added a data-cid attribute, so the API can lookup the correct item.&lt;br /&gt;
&lt;br /&gt;
In the browser it looks like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: detailview.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding desktop notifications==&lt;br /&gt;
&lt;br /&gt;
Finally you can add desktop notifications. This notifications are shown by the browser, if the appsuite is minimized or the tab is not active at the moment. The subview can show individual notifications, if there is only one new item or a more generic notification, if there are more new items.&lt;br /&gt;
&lt;br /&gt;
To use it you can use the following options:&lt;br /&gt;
*desktopNotificationSupport: If you want to use desktop notifications this has to be true. default is ''true''&lt;br /&gt;
*genericDesktopNotification: This is the desktop notification shown when there are multiple new notifications or if there is no specific one. Accepts all attributes ''io.ox/core/desktopNotifications.show'' accepts. Default is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    title: gt('New notifications'),&lt;br /&gt;
    body: gt('You\'ve got new notifications'),&lt;br /&gt;
    icon: ''&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*specificDesktopNotification: Function that is called when there is only one new notification. The notifications data is provided as a model. Default is null.&lt;br /&gt;
&lt;br /&gt;
Adding a specific notification to our example would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    specificDesktopNotification: function (model) {&lt;br /&gt;
                        return {&lt;br /&gt;
                            title: 'New tutorial notification',&lt;br /&gt;
                            body: model.get('text'),&lt;br /&gt;
                            icon: ''&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
You can download the examplecode here.&lt;br /&gt;
&lt;br /&gt;
[[File: Notification780_tutorial.zip]].&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20415</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20415"/>
		<updated>2015-09-11T07:39:53Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Using APIs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code just adds a simple hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register'' and uses ''io.ox/core/notifications/subview'' to create the subview needed for our plugin.&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our subview and add a notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
To load our code we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications.&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. Here we have a new text attribute in our notification models that we display. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The API object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the API triggers when notifications should be added. The provided data is used by the addNotifications function.&lt;br /&gt;
**remove: A string that contains the events the API triggers when notifications should be removed. The provided data is used by the removeNotifications function.&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function.&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a matching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
This is designed to fit our core APIs like mail or calendar, but custom APIs should work as well.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usally you would have the API in a separate file but in our example we keep it with the other code for simplicity. Also note that this API just works as a dummy, normally you would use server requests etc to get your data, but depending on the design of your API this may vary.&lt;br /&gt;
&lt;br /&gt;
In our example the reset function is now handled by the API. It throws a reset event that we also added to the options of our subview, so that it listens to it properly. We also use the get function here to get additional data. If your API does not need additional data and should only use the initial data provided when the notification was created, just set the ''fullModel'' option to true.&lt;br /&gt;
Note that the API extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
==Adding Detailviews==&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a simple object with a draw function. It's important that this function returns one jquery node.&lt;br /&gt;
Also note that we added a data-cid attribute, so the API can lookup the correct item.&lt;br /&gt;
&lt;br /&gt;
In the browser it looks like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: detailview.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding desktop notifications==&lt;br /&gt;
&lt;br /&gt;
Finally you can add desktop notifications. This notifications are shown by the browser, if the appsuite is minimized or the tab is not active at the moment. The subview can show individual notifications, if there is only one new item or a more generic notification, if there are more new items.&lt;br /&gt;
&lt;br /&gt;
To use it you can use the following options:&lt;br /&gt;
*desktopNotificationSupport: If you want to use desktop notifications this has to be true. default is ''true''&lt;br /&gt;
*genericDesktopNotification: This is the desktop notification shown when there are multiple new notifications or if there is no specific one. Accepts all attributes ''io.ox/core/desktopNotifications.show'' accepts. Default is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    title: gt('New notifications'),&lt;br /&gt;
    body: gt('You\'ve got new notifications'),&lt;br /&gt;
    icon: ''&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*specificDesktopNotification: Function that is called when there is only one new notification. The notifications data is provided as a model. Default is null.&lt;br /&gt;
&lt;br /&gt;
Adding a specific notification to our example would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    specificDesktopNotification: function (model) {&lt;br /&gt;
                        return {&lt;br /&gt;
                            title: 'New tutorial notification',&lt;br /&gt;
                            body: model.get('text'),&lt;br /&gt;
                            icon: ''&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
You can download the examplecode here.&lt;br /&gt;
&lt;br /&gt;
[[File: Notification780_tutorial.zip]].&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20414</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20414"/>
		<updated>2015-09-11T07:31:21Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding and removing notifications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code just adds a simple hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register'' and uses ''io.ox/core/notifications/subview'' to create the subview needed for our plugin.&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our subview and add a notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
To load our code we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications.&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. Here we have a new text attribute in our notification models that we display. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
==Adding Detailviews==&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a simple object with a draw function. It's important that this function returns one jquery node.&lt;br /&gt;
Also note that we added a data-cid attribute, so the API can lookup the correct item.&lt;br /&gt;
&lt;br /&gt;
In the browser it looks like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: detailview.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding desktop notifications==&lt;br /&gt;
&lt;br /&gt;
Finally you can add desktop notifications. This notifications are shown by the browser, if the appsuite is minimized or the tab is not active at the moment. The subview can show individual notifications, if there is only one new item or a more generic notification, if there are more new items.&lt;br /&gt;
&lt;br /&gt;
To use it you can use the following options:&lt;br /&gt;
*desktopNotificationSupport: If you want to use desktop notifications this has to be true. default is ''true''&lt;br /&gt;
*genericDesktopNotification: This is the desktop notification shown when there are multiple new notifications or if there is no specific one. Accepts all attributes ''io.ox/core/desktopNotifications.show'' accepts. Default is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    title: gt('New notifications'),&lt;br /&gt;
    body: gt('You\'ve got new notifications'),&lt;br /&gt;
    icon: ''&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*specificDesktopNotification: Function that is called when there is only one new notification. The notifications data is provided as a model. Default is null.&lt;br /&gt;
&lt;br /&gt;
Adding a specific notification to our example would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    specificDesktopNotification: function (model) {&lt;br /&gt;
                        return {&lt;br /&gt;
                            title: 'New tutorial notification',&lt;br /&gt;
                            body: model.get('text'),&lt;br /&gt;
                            icon: ''&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
You can download the examplecode here.&lt;br /&gt;
&lt;br /&gt;
[[File: Notification780_tutorial.zip]].&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20413</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20413"/>
		<updated>2015-09-11T07:31:07Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding and removing notifications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code just adds a simple hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register'' and uses ''io.ox/core/notifications/subview'' to create the subview needed for our plugin.&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our subview and add a notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
To load our code we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications.&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. Here we have a new text attribute in our notification models that we display. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
==Adding Detailviews==&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a simple object with a draw function. It's important that this function returns one jquery node.&lt;br /&gt;
Also note that we added a data-cid attribute, so the API can lookup the correct item.&lt;br /&gt;
&lt;br /&gt;
In the browser it looks like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: detailview.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding desktop notifications==&lt;br /&gt;
&lt;br /&gt;
Finally you can add desktop notifications. This notifications are shown by the browser, if the appsuite is minimized or the tab is not active at the moment. The subview can show individual notifications, if there is only one new item or a more generic notification, if there are more new items.&lt;br /&gt;
&lt;br /&gt;
To use it you can use the following options:&lt;br /&gt;
*desktopNotificationSupport: If you want to use desktop notifications this has to be true. default is ''true''&lt;br /&gt;
*genericDesktopNotification: This is the desktop notification shown when there are multiple new notifications or if there is no specific one. Accepts all attributes ''io.ox/core/desktopNotifications.show'' accepts. Default is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    title: gt('New notifications'),&lt;br /&gt;
    body: gt('You\'ve got new notifications'),&lt;br /&gt;
    icon: ''&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*specificDesktopNotification: Function that is called when there is only one new notification. The notifications data is provided as a model. Default is null.&lt;br /&gt;
&lt;br /&gt;
Adding a specific notification to our example would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    specificDesktopNotification: function (model) {&lt;br /&gt;
                        return {&lt;br /&gt;
                            title: 'New tutorial notification',&lt;br /&gt;
                            body: model.get('text'),&lt;br /&gt;
                            icon: ''&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
You can download the examplecode here.&lt;br /&gt;
&lt;br /&gt;
[[File: Notification780_tutorial.zip]].&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20412</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20412"/>
		<updated>2015-09-11T07:27:43Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding and removing notifications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code just adds a simple hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register'' and uses ''io.ox/core/notifications/subview'' to create the subview needed for our plugin.&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our subview and add a notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
To load our code we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications.&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
==Adding Detailviews==&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a simple object with a draw function. It's important that this function returns one jquery node.&lt;br /&gt;
Also note that we added a data-cid attribute, so the API can lookup the correct item.&lt;br /&gt;
&lt;br /&gt;
In the browser it looks like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: detailview.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding desktop notifications==&lt;br /&gt;
&lt;br /&gt;
Finally you can add desktop notifications. This notifications are shown by the browser, if the appsuite is minimized or the tab is not active at the moment. The subview can show individual notifications, if there is only one new item or a more generic notification, if there are more new items.&lt;br /&gt;
&lt;br /&gt;
To use it you can use the following options:&lt;br /&gt;
*desktopNotificationSupport: If you want to use desktop notifications this has to be true. default is ''true''&lt;br /&gt;
*genericDesktopNotification: This is the desktop notification shown when there are multiple new notifications or if there is no specific one. Accepts all attributes ''io.ox/core/desktopNotifications.show'' accepts. Default is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    title: gt('New notifications'),&lt;br /&gt;
    body: gt('You\'ve got new notifications'),&lt;br /&gt;
    icon: ''&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*specificDesktopNotification: Function that is called when there is only one new notification. The notifications data is provided as a model. Default is null.&lt;br /&gt;
&lt;br /&gt;
Adding a specific notification to our example would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    specificDesktopNotification: function (model) {&lt;br /&gt;
                        return {&lt;br /&gt;
                            title: 'New tutorial notification',&lt;br /&gt;
                            body: model.get('text'),&lt;br /&gt;
                            icon: ''&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
You can download the examplecode here.&lt;br /&gt;
&lt;br /&gt;
[[File: Notification780_tutorial.zip]].&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20411</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20411"/>
		<updated>2015-09-11T07:19:48Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding a manifest */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code just adds a simple hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register'' and uses ''io.ox/core/notifications/subview'' to create the subview needed for our plugin.&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our subview and add a notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
To load our code we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
==Adding Detailviews==&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a simple object with a draw function. It's important that this function returns one jquery node.&lt;br /&gt;
Also note that we added a data-cid attribute, so the API can lookup the correct item.&lt;br /&gt;
&lt;br /&gt;
In the browser it looks like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: detailview.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding desktop notifications==&lt;br /&gt;
&lt;br /&gt;
Finally you can add desktop notifications. This notifications are shown by the browser, if the appsuite is minimized or the tab is not active at the moment. The subview can show individual notifications, if there is only one new item or a more generic notification, if there are more new items.&lt;br /&gt;
&lt;br /&gt;
To use it you can use the following options:&lt;br /&gt;
*desktopNotificationSupport: If you want to use desktop notifications this has to be true. default is ''true''&lt;br /&gt;
*genericDesktopNotification: This is the desktop notification shown when there are multiple new notifications or if there is no specific one. Accepts all attributes ''io.ox/core/desktopNotifications.show'' accepts. Default is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    title: gt('New notifications'),&lt;br /&gt;
    body: gt('You\'ve got new notifications'),&lt;br /&gt;
    icon: ''&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*specificDesktopNotification: Function that is called when there is only one new notification. The notifications data is provided as a model. Default is null.&lt;br /&gt;
&lt;br /&gt;
Adding a specific notification to our example would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    specificDesktopNotification: function (model) {&lt;br /&gt;
                        return {&lt;br /&gt;
                            title: 'New tutorial notification',&lt;br /&gt;
                            body: model.get('text'),&lt;br /&gt;
                            icon: ''&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
You can download the examplecode here.&lt;br /&gt;
&lt;br /&gt;
[[File: Notification780_tutorial.zip]].&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20410</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20410"/>
		<updated>2015-09-11T07:19:11Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Basic Notification */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code just adds a simple hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register'' and uses ''io.ox/core/notifications/subview'' to create the subview needed for our plugin.&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our subview and add a notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
==Adding Detailviews==&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a simple object with a draw function. It's important that this function returns one jquery node.&lt;br /&gt;
Also note that we added a data-cid attribute, so the API can lookup the correct item.&lt;br /&gt;
&lt;br /&gt;
In the browser it looks like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: detailview.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding desktop notifications==&lt;br /&gt;
&lt;br /&gt;
Finally you can add desktop notifications. This notifications are shown by the browser, if the appsuite is minimized or the tab is not active at the moment. The subview can show individual notifications, if there is only one new item or a more generic notification, if there are more new items.&lt;br /&gt;
&lt;br /&gt;
To use it you can use the following options:&lt;br /&gt;
*desktopNotificationSupport: If you want to use desktop notifications this has to be true. default is ''true''&lt;br /&gt;
*genericDesktopNotification: This is the desktop notification shown when there are multiple new notifications or if there is no specific one. Accepts all attributes ''io.ox/core/desktopNotifications.show'' accepts. Default is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    title: gt('New notifications'),&lt;br /&gt;
    body: gt('You\'ve got new notifications'),&lt;br /&gt;
    icon: ''&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*specificDesktopNotification: Function that is called when there is only one new notification. The notifications data is provided as a model. Default is null.&lt;br /&gt;
&lt;br /&gt;
Adding a specific notification to our example would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    specificDesktopNotification: function (model) {&lt;br /&gt;
                        return {&lt;br /&gt;
                            title: 'New tutorial notification',&lt;br /&gt;
                            body: model.get('text'),&lt;br /&gt;
                            icon: ''&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
You can download the examplecode here.&lt;br /&gt;
&lt;br /&gt;
[[File: Notification780_tutorial.zip]].&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20409</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20409"/>
		<updated>2015-09-11T07:18:56Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Basic Notification */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code just adds a simple hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register'' and uses ''io.ox/core/notifications/subview'' to create the subview needed for our plugin.&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our subview and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
==Adding Detailviews==&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a simple object with a draw function. It's important that this function returns one jquery node.&lt;br /&gt;
Also note that we added a data-cid attribute, so the API can lookup the correct item.&lt;br /&gt;
&lt;br /&gt;
In the browser it looks like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: detailview.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding desktop notifications==&lt;br /&gt;
&lt;br /&gt;
Finally you can add desktop notifications. This notifications are shown by the browser, if the appsuite is minimized or the tab is not active at the moment. The subview can show individual notifications, if there is only one new item or a more generic notification, if there are more new items.&lt;br /&gt;
&lt;br /&gt;
To use it you can use the following options:&lt;br /&gt;
*desktopNotificationSupport: If you want to use desktop notifications this has to be true. default is ''true''&lt;br /&gt;
*genericDesktopNotification: This is the desktop notification shown when there are multiple new notifications or if there is no specific one. Accepts all attributes ''io.ox/core/desktopNotifications.show'' accepts. Default is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    title: gt('New notifications'),&lt;br /&gt;
    body: gt('You\'ve got new notifications'),&lt;br /&gt;
    icon: ''&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*specificDesktopNotification: Function that is called when there is only one new notification. The notifications data is provided as a model. Default is null.&lt;br /&gt;
&lt;br /&gt;
Adding a specific notification to our example would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    specificDesktopNotification: function (model) {&lt;br /&gt;
                        return {&lt;br /&gt;
                            title: 'New tutorial notification',&lt;br /&gt;
                            body: model.get('text'),&lt;br /&gt;
                            icon: ''&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
You can download the examplecode here.&lt;br /&gt;
&lt;br /&gt;
[[File: Notification780_tutorial.zip]].&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20408</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20408"/>
		<updated>2015-09-11T07:18:13Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Basic Notification */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code just adds a simple hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register'' and uses ''io.ox/core/notifications/subview'' to create the subview needed for our plugin.&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
==Adding Detailviews==&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a simple object with a draw function. It's important that this function returns one jquery node.&lt;br /&gt;
Also note that we added a data-cid attribute, so the API can lookup the correct item.&lt;br /&gt;
&lt;br /&gt;
In the browser it looks like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: detailview.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding desktop notifications==&lt;br /&gt;
&lt;br /&gt;
Finally you can add desktop notifications. This notifications are shown by the browser, if the appsuite is minimized or the tab is not active at the moment. The subview can show individual notifications, if there is only one new item or a more generic notification, if there are more new items.&lt;br /&gt;
&lt;br /&gt;
To use it you can use the following options:&lt;br /&gt;
*desktopNotificationSupport: If you want to use desktop notifications this has to be true. default is ''true''&lt;br /&gt;
*genericDesktopNotification: This is the desktop notification shown when there are multiple new notifications or if there is no specific one. Accepts all attributes ''io.ox/core/desktopNotifications.show'' accepts. Default is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    title: gt('New notifications'),&lt;br /&gt;
    body: gt('You\'ve got new notifications'),&lt;br /&gt;
    icon: ''&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*specificDesktopNotification: Function that is called when there is only one new notification. The notifications data is provided as a model. Default is null.&lt;br /&gt;
&lt;br /&gt;
Adding a specific notification to our example would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    specificDesktopNotification: function (model) {&lt;br /&gt;
                        return {&lt;br /&gt;
                            title: 'New tutorial notification',&lt;br /&gt;
                            body: model.get('text'),&lt;br /&gt;
                            icon: ''&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
You can download the examplecode here.&lt;br /&gt;
&lt;br /&gt;
[[File: Notification780_tutorial.zip]].&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20407</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20407"/>
		<updated>2015-09-11T07:15:50Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Basic Notification */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code just adds a simple hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
==Adding Detailviews==&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a simple object with a draw function. It's important that this function returns one jquery node.&lt;br /&gt;
Also note that we added a data-cid attribute, so the API can lookup the correct item.&lt;br /&gt;
&lt;br /&gt;
In the browser it looks like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: detailview.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding desktop notifications==&lt;br /&gt;
&lt;br /&gt;
Finally you can add desktop notifications. This notifications are shown by the browser, if the appsuite is minimized or the tab is not active at the moment. The subview can show individual notifications, if there is only one new item or a more generic notification, if there are more new items.&lt;br /&gt;
&lt;br /&gt;
To use it you can use the following options:&lt;br /&gt;
*desktopNotificationSupport: If you want to use desktop notifications this has to be true. default is ''true''&lt;br /&gt;
*genericDesktopNotification: This is the desktop notification shown when there are multiple new notifications or if there is no specific one. Accepts all attributes ''io.ox/core/desktopNotifications.show'' accepts. Default is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    title: gt('New notifications'),&lt;br /&gt;
    body: gt('You\'ve got new notifications'),&lt;br /&gt;
    icon: ''&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*specificDesktopNotification: Function that is called when there is only one new notification. The notifications data is provided as a model. Default is null.&lt;br /&gt;
&lt;br /&gt;
Adding a specific notification to our example would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    specificDesktopNotification: function (model) {&lt;br /&gt;
                        return {&lt;br /&gt;
                            title: 'New tutorial notification',&lt;br /&gt;
                            body: model.get('text'),&lt;br /&gt;
                            icon: ''&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
You can download the examplecode here.&lt;br /&gt;
&lt;br /&gt;
[[File: Notification780_tutorial.zip]].&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=File:Notification780_tutorial.zip&amp;diff=20406</id>
		<title>File:Notification780 tutorial.zip</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=File:Notification780_tutorial.zip&amp;diff=20406"/>
		<updated>2015-09-10T15:09:06Z</updated>

		<summary type="html">&lt;p&gt;D.haus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20405</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20405"/>
		<updated>2015-09-10T15:07:36Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding Detailviews */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
==Adding Detailviews==&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a simple object with a draw function. It's important that this function returns one jquery node.&lt;br /&gt;
Also note that we added a data-cid attribute, so the API can lookup the correct item.&lt;br /&gt;
&lt;br /&gt;
In the browser it looks like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: detailview.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding desktop notifications==&lt;br /&gt;
&lt;br /&gt;
Finally you can add desktop notifications. This notifications are shown by the browser, if the appsuite is minimized or the tab is not active at the moment. The subview can show individual notifications, if there is only one new item or a more generic notification, if there are more new items.&lt;br /&gt;
&lt;br /&gt;
To use it you can use the following options:&lt;br /&gt;
*desktopNotificationSupport: If you want to use desktop notifications this has to be true. default is ''true''&lt;br /&gt;
*genericDesktopNotification: This is the desktop notification shown when there are multiple new notifications or if there is no specific one. Accepts all attributes ''io.ox/core/desktopNotifications.show'' accepts. Default is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    title: gt('New notifications'),&lt;br /&gt;
    body: gt('You\'ve got new notifications'),&lt;br /&gt;
    icon: ''&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*specificDesktopNotification: Function that is called when there is only one new notification. The notifications data is provided as a model. Default is null.&lt;br /&gt;
&lt;br /&gt;
Adding a specific notification to our example would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    },&lt;br /&gt;
                    specificDesktopNotification: function (model) {&lt;br /&gt;
                        return {&lt;br /&gt;
                            title: 'New tutorial notification',&lt;br /&gt;
                            body: model.get('text'),&lt;br /&gt;
                            icon: ''&lt;br /&gt;
                        };&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Download==&lt;br /&gt;
You can download the examplecode here.&lt;br /&gt;
&lt;br /&gt;
[[File: Notification780_tutorial.zip]].&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=File:Detailview.png&amp;diff=20404</id>
		<title>File:Detailview.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=File:Detailview.png&amp;diff=20404"/>
		<updated>2015-09-10T14:50:46Z</updated>

		<summary type="html">&lt;p&gt;D.haus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20403</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20403"/>
		<updated>2015-09-10T14:50:32Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding and removing notifications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
==Adding Detailviews==&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We use a simple object with a draw function. It's important that this function returns one jquery node.&lt;br /&gt;
Also note that we added a data-cid attribute, so the API can lookup the correct item.&lt;br /&gt;
&lt;br /&gt;
In the browser it looks like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: detailview.png]]&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20402</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20402"/>
		<updated>2015-09-10T14:47:56Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding Detailviews */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
===Adding Detailviews===&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20401</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20401"/>
		<updated>2015-09-10T14:47:47Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Using APIs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
===Adding Detailviews===&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20400</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20400"/>
		<updated>2015-09-10T14:47:31Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding and removing notifications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
===Adding Detailviews===&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20399</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20399"/>
		<updated>2015-09-10T14:47:20Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Expanding our Plugin */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
===Adding Detailviews===&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20398</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20398"/>
		<updated>2015-09-10T14:46:27Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Using APIs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Note that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly.&lt;br /&gt;
&lt;br /&gt;
===Adding Detailviews===&lt;br /&gt;
&lt;br /&gt;
Most notifications provide detailviews. Those views open when you click on a notification. For example a reminder shows the calendar appointment or task.&lt;br /&gt;
&lt;br /&gt;
You can add a detailview by adding the detailview option. This can be a string for our require module, like ''io.ox/calendar/view-detail''. Or it can be a normal object. Important is that it provides either a view constructor or a draw function. The data is provided either by the api (fullModel = false), or the data from the collection is used (fullModel = true). To get the right data the domnode of the notification needs a ''data-cid'' attribute that contains the id for either api or collection. &lt;br /&gt;
&lt;br /&gt;
In our code this would look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            var cid = _.cid(baton.model.attributes);&lt;br /&gt;
&lt;br /&gt;
            this.attr('data-cid', cid).append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    },&lt;br /&gt;
                    detailview: {&lt;br /&gt;
                        draw: function (obj) {&lt;br /&gt;
                            var node = $('&amp;lt;div&amp;gt;').append($('&amp;lt;div&amp;gt;').text('i am the tutorial detailview'),&lt;br /&gt;
                                $('&amp;lt;div&amp;gt;').text(obj.data.text));&lt;br /&gt;
                            return node;&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20396</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20396"/>
		<updated>2015-09-10T14:21:48Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Using APIs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is 'false'.&lt;br /&gt;
&lt;br /&gt;
Let's change our example to use a small api:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview',&lt;br /&gt;
    'io.ox/core/event'&lt;br /&gt;
], function (ext, Subview, Events) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    var api = {&lt;br /&gt;
        get: function (data) {&lt;br /&gt;
            var result = {&lt;br /&gt;
                id: data.id,&lt;br /&gt;
                text: 'I am ' + data.id&lt;br /&gt;
            };&lt;br /&gt;
            return $.Deferred().resolve(result);&lt;br /&gt;
        },&lt;br /&gt;
        reset: function () {&lt;br /&gt;
            counter = 0;&lt;br /&gt;
            api.trigger('reset', { id: 'myNotification' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    Events.extend(api);&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    api.reset();&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    api: api,&lt;br /&gt;
                    apiEvents: {&lt;br /&gt;
                        reset: 'reset'&lt;br /&gt;
                    }&lt;br /&gt;
                };&lt;br /&gt;
            new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            api.reset();&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reset function is now handled by the api. We also use the get function here to get additional data.&lt;br /&gt;
Not that the api extends ''io.ox/core/event''. This is needed so the event listeners function properly&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20395</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20395"/>
		<updated>2015-09-10T13:06:56Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Using APIs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*api: The api object that should be used by this subview. default is ''null'',&lt;br /&gt;
*apiEvents: An object where you can define events that the subview should listen to:&lt;br /&gt;
**add: A string that contains the events the api triggers when notifications should be added. The provided data is used by the addNotifications function;&lt;br /&gt;
**remove: A string that contains the events the api triggers when notifications should be removed. The provided data is used by the removeNotifications function;&lt;br /&gt;
**reset: A string that contains the events the api triggers when notifications should be reseted. The provided data is used by the resetNotifications function;&lt;br /&gt;
*fullModel: Some notifications have limited data and the full data must be requested from the server (our notifications usually only have id and folder). To do this the API must provide a get function that returns the full model data as the result of a deferred object. The model attributes are provided to the API.get function. If fullModel is set to true, there is no API call to get the full data as the model already has it. Default is ''false'',&lt;br /&gt;
*useListRequest: If data should be requested by the server, it can be done as a list request instead of multiple get requests. The API must have a maching list function for this. Default is false.&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20394</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20394"/>
		<updated>2015-09-10T12:50:56Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Expanding our Plugin */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin and make it autopen. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20393</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20393"/>
		<updated>2015-09-10T12:50:03Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding and removing notifications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin, make it autopen, show the ''hide all'' button. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    showHideAllButton: true,&lt;br /&gt;
                    hideAllLabel: 'Hide all tutorial notifications'&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The extension points are provided a baton which has the data of the view and the model. We use a simple counter here to create unique ids.&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;br /&gt;
&lt;br /&gt;
===Using APIs===&lt;br /&gt;
&lt;br /&gt;
Instead of manually adding or reseting notifications. The subview is also capable of handling APIs that meet certain conditions.&lt;br /&gt;
&lt;br /&gt;
To use APIs the subview provides the following options:&lt;br /&gt;
&lt;br /&gt;
*&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=File:NotificationAddRemove.png&amp;diff=20392</id>
		<title>File:NotificationAddRemove.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=File:NotificationAddRemove.png&amp;diff=20392"/>
		<updated>2015-09-10T12:44:03Z</updated>

		<summary type="html">&lt;p&gt;D.haus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20391</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20391"/>
		<updated>2015-09-10T12:43:53Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding and removing notifications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin, make it autopen, show the ''hide all'' button. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    showHideAllButton: true,&lt;br /&gt;
                    hideAllLabel: 'Hide all tutorial notifications'&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationAddRemove.png]]&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20390</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20390"/>
		<updated>2015-09-10T12:43:02Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding and removing notifications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin, make it autopen, show the ''hide all'' button. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    showHideAllButton: true,&lt;br /&gt;
                    hideAllLabel: 'Hide all tutorial notifications'&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20389</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20389"/>
		<updated>2015-09-10T12:42:08Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Adding and removing notifications */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin, make it autopen, show the ''hide all'' button. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    showHideAllButton: true,&lt;br /&gt;
                    hideAllLabel: 'Hide all tutorial notifications'&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;br /&gt;
&lt;br /&gt;
Let's expand our example by adding buttons to the footer to add notifications and reset them. Let's also add a button to remove a notification and show some data in our notifications.&lt;br /&gt;
&lt;br /&gt;
The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    var counter = 0;&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('reset notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    counter = 0;&lt;br /&gt;
                    baton.view.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('add notifications')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    baton.view.addNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
                    counter++;&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append($('&amp;lt;div&amp;gt;').text(baton.model.get('text')),&lt;br /&gt;
                $('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('remove notification').on('click', function () {&lt;br /&gt;
                    baton.view.removeNotifications(baton.model);&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    showHideAllButton: true,&lt;br /&gt;
                    hideAllLabel: 'Hide all tutorial notifications'&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification' + counter, text: 'I am notification number ' + counter });&lt;br /&gt;
            counter++;&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You should see Something like this in your browser:&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20387</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20387"/>
		<updated>2015-09-10T11:58:12Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Expanding our Plugin */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin, make it autopen, show the ''hide all'' button. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    showHideAllButton: true,&lt;br /&gt;
                    hideAllLabel: 'Hide all tutorial notifications'&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;br /&gt;
&lt;br /&gt;
==Adding and removing notifications==&lt;br /&gt;
&lt;br /&gt;
Now we need to talk about how notifications are added and removed. Our subview has a backbone collection which stores all it's notifications. The notifications need an id so the collection can avoid duplicates and handle hiding correctly. Our example notifications id was ''myNotification1''.&lt;br /&gt;
This collection can be changed by using 3 methods:&lt;br /&gt;
&lt;br /&gt;
*addNotifications: Adds notifications to the collection. Only adds notifications which have a new id. Has 2 parameters:&lt;br /&gt;
**items: Is a single object or an array of objects to be added as new notifications&lt;br /&gt;
**silent: Is a boolean that can be set to true if the new notifications should be added silently. This prevents immediate redrawing.&lt;br /&gt;
*removeNotifications: Removes notifications from the collection. Has items and silent parameter, like addNotifications.&lt;br /&gt;
*resetNotifications: Resets the collection. This throws away all notifications in the collection and fills it with the provided new ones. Can also be used to clear the collection, when an empty array is provided. Again has items and silent parameter, like addNotifications.&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=File:NotificationWithFooter.png&amp;diff=20386</id>
		<title>File:NotificationWithFooter.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=File:NotificationWithFooter.png&amp;diff=20386"/>
		<updated>2015-09-10T11:39:21Z</updated>

		<summary type="html">&lt;p&gt;D.haus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20385</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20385"/>
		<updated>2015-09-10T11:39:10Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Expanding our Plugin */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin, make it autopen, show the ''hide all'' button. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    showHideAllButton: true,&lt;br /&gt;
                    hideAllLabel: 'Hide all tutorial notifications'&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: notificationWithFooter.png]]&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20384</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20384"/>
		<updated>2015-09-10T11:38:41Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Expanding our Plugin */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;br /&gt;
&lt;br /&gt;
Let's add a footer to our plugin, make it autopen, show the ''hide all'' button. The code looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/footer').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;button class=&amp;quot;btn&amp;quot;&amp;gt;').text('click me')&lt;br /&gt;
                .on('click', function () {&lt;br /&gt;
                    alert('footer button was clicked');&lt;br /&gt;
                }));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append($('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item',&lt;br /&gt;
                        footer: 'io.ox/core/notifications/tutorial/footer'&lt;br /&gt;
                    },&lt;br /&gt;
                    autoOpen: true,&lt;br /&gt;
                    showHideAllButton: true,&lt;br /&gt;
                    hideAllLabel: 'Hide all tutorial notifications'&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And it should look like this:&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20383</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20383"/>
		<updated>2015-09-10T11:23:10Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Expanding our Plugin */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false''&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string''&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10''&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''&lt;br /&gt;
*extensionPoints: This is an object where you can define extension points used when drawing your subview. Possible points are:&lt;br /&gt;
**main: The main extension point. If you overwrite this you can draw the subview completely by hand. If you keep the default value, this extension point invokes the header, item and footer extension points for you.&lt;br /&gt;
**header: The extension point for your subview header. The default extension point uses the supplied title attribute and draws the hideall button if enabled.&lt;br /&gt;
**item: The extension point for a single notifications. This extension point has no default value and must be provided by the plugin when creating the subview. In our example this was ''io.ox/core/notifications/tutorial/item''.&lt;br /&gt;
**footer: The extension point for the footer. If your subview should have a footer you can provide an extension point for this. There is no default extension point and it's entirely optional.&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20382</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20382"/>
		<updated>2015-09-10T10:28:25Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Expanding our Plugin */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false'',&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string'',&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10'',&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is ''false''.&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20381</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20381"/>
		<updated>2015-09-10T10:27:37Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Testing our notification */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;br /&gt;
&lt;br /&gt;
==Expanding our Plugin==&lt;br /&gt;
&lt;br /&gt;
We can add more functionality to our plugin by using the options when creating the subview.&lt;br /&gt;
Here are some more:&lt;br /&gt;
&lt;br /&gt;
*showHideAllButton: Is used to show a ''hide all'' button for your subview. This button hides all current notifications of your subview. Default is ''false'',&lt;br /&gt;
*hideAllLabel: Is the aria-label for the ''hide all'' button that is used by screen readers. Default is ''empty string'',&lt;br /&gt;
*showHideSingleButton: Is used to show a ''hide'' button for your notifications. This button hides a single notification of your subview. Default is ''true''&lt;br /&gt;
*max: The maximum number of displayed notifications in this subview. The actual collection may contain more. Setting this to ''null'' will show all notifications. Default is ''10'',&lt;br /&gt;
*autoOpen: Used to open the notification area, if there is a new notification for your plugin. You may want to tie this to a user setting. Default is false.&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20380</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20380"/>
		<updated>2015-09-10T09:58:31Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Testing our notification */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
After reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20379</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20379"/>
		<updated>2015-09-10T09:57:55Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Basic Notification */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code extends two extension points: ''io.ox/core/notifications/tutorial/item'' and ''io.ox/core/notifications/register''&lt;br /&gt;
&lt;br /&gt;
We use ''io.ox/core/notifications/tutorial/item'' to draw our notification items. Here it's a simple ''hello world'' text.&lt;br /&gt;
&lt;br /&gt;
''io.ox/core/notifications/register'' is used by the notification area to load the different plugins. Those plugins are implemented as subviews of the main notification area. The index determines the order of the different subviews.&lt;br /&gt;
We define some options for our view here:&lt;br /&gt;
&lt;br /&gt;
* id: the internalId for our subview&lt;br /&gt;
* title: the text in the header of our subview&lt;br /&gt;
* extensionPoints: here we tell the subview which extensionpoints to use when drawing our notifications. For now we only use ''io.ox/core/notifications/tutorial/item'' to draw our items.&lt;br /&gt;
&lt;br /&gt;
More options will be explained later on.&lt;br /&gt;
&lt;br /&gt;
Now we create our view and add notification to it:&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Adding a manifest===&lt;br /&gt;
&lt;br /&gt;
Now we need to add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
after reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20378</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20378"/>
		<updated>2015-09-10T09:42:01Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Basic Notification */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
First let's start with showing the most basic notification plugin you can write.&lt;br /&gt;
Create a file named ''register.js'' at ''plugins/notifications/tutorial''.&lt;br /&gt;
&lt;br /&gt;
This code doesn't have api suppport or other things but adds a hello world notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we add a ''manifest.json'' file at ''plugins/notifications/tutorial'' with the following contents:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;namespace&amp;quot;: &amp;quot;io.ox/core/notifications&amp;quot;,&lt;br /&gt;
    &amp;quot;requires&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This manifest makes sure our code is loaded. You can also define capabilities like ''webmail'' here, if your notifications require specific capabilities to be enabled. They only show up if a user has these capabilities.&lt;br /&gt;
&lt;br /&gt;
===Testing our notification===&lt;br /&gt;
&lt;br /&gt;
Now it's time to test our notification. Build the UI and add ''&amp;amp;customManifests=true'' to the url, because our manifest is only present locally.&lt;br /&gt;
&lt;br /&gt;
after reloading you should see something like this:&lt;br /&gt;
&lt;br /&gt;
[[Image: basicNotification.png]]&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=File:BasicNotification.png&amp;diff=20377</id>
		<title>File:BasicNotification.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=File:BasicNotification.png&amp;diff=20377"/>
		<updated>2015-09-10T09:41:18Z</updated>

		<summary type="html">&lt;p&gt;D.haus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20376</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20376"/>
		<updated>2015-09-10T09:13:33Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Basic Notification */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
This is the most basic code for a notification plugin, it doesn't have api suppport or other things but should work:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20375</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20375"/>
		<updated>2015-09-10T09:12:17Z</updated>

		<summary type="html">&lt;p&gt;D.haus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
This is the most basic code for a notification plugin, it doesn't have api suppport or other things but should work:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 1000,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    //#. Invitations (notifications) about appointments&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20374</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20374"/>
		<updated>2015-09-10T09:04:47Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Basic Notification */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
This is the most basic code for a notification plugin, it doesn't have api suppport or other things but should work:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 100,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20373</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20373"/>
		<updated>2015-09-10T09:03:47Z</updated>

		<summary type="html">&lt;p&gt;D.haus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
This is the most basic code for a notification plugin, it doesn't have api suppport or other things but should work:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 300,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    //#. Invitations (notifications) about appointments&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    }&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({ id: 'myNotification1' });&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20372</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20372"/>
		<updated>2015-09-10T09:01:04Z</updated>

		<summary type="html">&lt;p&gt;D.haus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
This is the most basic code for a notification plugin, it doesn't have api suppport or other things but should work:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function () {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 300,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    //#. Invitations (notifications) about appointments&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({id: 'myNotification1'});&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20371</id>
		<title>AppSuite:Writing a notification area plugin</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Writing_a_notification_area_plugin&amp;diff=20371"/>
		<updated>2015-09-10T08:58:51Z</updated>

		<summary type="html">&lt;p&gt;D.haus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Writing a plugin for the notification area&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract:''' This article is a step by step tutorial to build your own notification plugin.&lt;br /&gt;
These plugins can be used for various purposes, for example reminding the user of something or showing him new invitations.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
==Basic Notification==&lt;br /&gt;
&lt;br /&gt;
This is the most basic code for a notification plugin, it doesn't have api suppport or other things but should work:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-javascript&amp;quot;&amp;gt;&lt;br /&gt;
define('plugins/notifications/tutorial/register', [&lt;br /&gt;
    'io.ox/core/extensions',&lt;br /&gt;
    'io.ox/core/notifications/subview'&lt;br /&gt;
], function (ext, Subview) {&lt;br /&gt;
&lt;br /&gt;
    'use strict';&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/tutorial/item').extend({&lt;br /&gt;
        draw: function (baton) {&lt;br /&gt;
            this.append( $('&amp;lt;span&amp;gt;').text('hello world'));&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    ext.point('io.ox/core/notifications/register').extend({&lt;br /&gt;
        id: 'tutorialplugin',&lt;br /&gt;
        index: 300,&lt;br /&gt;
        register: function () {&lt;br /&gt;
            var options = {&lt;br /&gt;
                    id: 'io.ox/tutorialplugin',&lt;br /&gt;
                    //#. Invitations (notifications) about appointments&lt;br /&gt;
                    title: 'Test Notifications',&lt;br /&gt;
                    extensionPoints: {&lt;br /&gt;
                        item: 'io.ox/core/notifications/tutorial/item'&lt;br /&gt;
                    },&lt;br /&gt;
                },&lt;br /&gt;
                subview  = new Subview(options);&lt;br /&gt;
&lt;br /&gt;
            subview.resetNotifications({id: myNotification1});&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Theming&amp;diff=17428</id>
		<title>AppSuite:Theming</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Theming&amp;diff=17428"/>
		<updated>2014-04-11T15:13:43Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Variables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-experimental}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Theming&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract.''' In this article, you can learn how to create customized themes and use them to change the look of you appsuite installation.&lt;br /&gt;
__TOC__&lt;br /&gt;
== LESS.JS ==&lt;br /&gt;
Appsuite used LESS as dynamic stylesheet language. LESS extends CSS with dynamic behavior such as variables, mixins, operations and functions.&lt;br /&gt;
&lt;br /&gt;
Please read [http://lesscss.org/#docs LESS.JS] documentation first.&lt;br /&gt;
&lt;br /&gt;
=== Using less.js ===&lt;br /&gt;
If your theme depends on less.js, you will need one more step to make it work. Why? To accelerate the login, compilation of LessCSS files was moved from the login process in the browser to the installation process on the backend. &lt;br /&gt;
&lt;br /&gt;
Backend packages for themes and any apps which ship .less files require the following changes:&lt;br /&gt;
&lt;br /&gt;
1. Add &amp;quot;skipLess=1&amp;quot; to the build command in *.spec and in debian/rules:&lt;br /&gt;
   sh /opt/open-xchange-appsuite-dev/bin/build-appsuite app skipLess=1&lt;br /&gt;
2. Add %post and %postun sections to *.spec:&lt;br /&gt;
   %post&lt;br /&gt;
   if [ &amp;quot;$1&amp;quot; = 1 ]; then&lt;br /&gt;
   UPDATE=/opt/open-xchange/appsuite/share/update-themes.sh&lt;br /&gt;
   [ -x $UPDATE ] &amp;amp;&amp;amp; $UPDATE&lt;br /&gt;
   fi&lt;br /&gt;
   %postun&lt;br /&gt;
   UPDATE=/opt/open-xchange/appsuite/share/update-themes.sh&lt;br /&gt;
   [ -x $UPDATE ] &amp;amp;&amp;amp; $UPDATE&lt;br /&gt;
&lt;br /&gt;
For multiple binary packages, the %post and %postun sections should apply only to backend packages &lt;br /&gt;
which contain .less files.&lt;br /&gt;
&lt;br /&gt;
3. Add debian/postinst and debian/postrm containing the same content:&lt;br /&gt;
   #!/bin/sh&lt;br /&gt;
   UPDATE=/opt/open-xchange/appsuite/share/update-themes.sh&lt;br /&gt;
   [ -x $UPDATE ] &amp;amp;&amp;amp; $UPDATE&lt;br /&gt;
&lt;br /&gt;
For multiple binary packages, the postinst and postrm files should apply only to backend packages which contain .less files.&lt;br /&gt;
&lt;br /&gt;
Note: Since 7.2.1, LessCSS files must have the file extension .less to be usable with the 'less' RequireJS plugin (module dependencies of the form 'less!filename.less'). Previously we were more lenient and dealt with .css, too.&lt;br /&gt;
&lt;br /&gt;
== File structure ==&lt;br /&gt;
A theme basically consists of two files located in &amp;lt;code&amp;gt;apps/themes/&amp;lt;var&amp;gt;THEME_ID&amp;lt;/var&amp;gt;/&amp;lt;/code&amp;gt;. These files are described in this and the following sections.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;var&amp;gt;THEME_ID&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt; is a unique identifier for your theme, which is not visible to users. By convention, it is best derived from a domain name you control, e.g. &amp;lt;code&amp;gt;com.example.prettytheme&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== definitions.less ===&lt;br /&gt;
This file can be used to override variables described in the &amp;quot;Variables&amp;quot; section of this article.&lt;br /&gt;
&lt;br /&gt;
=== style.less ===&lt;br /&gt;
This file can be used to define any CSS you like. Before doing this, check, if there really is no variable that can be used to achieve the same thing.&lt;br /&gt;
&lt;br /&gt;
=== Referencing paths ===&lt;br /&gt;
Since 7.2.1, all URLs are relative to the source .less file in which they are contained. This means that unless a theme changes an image it does not need to include that image anymore. &lt;br /&gt;
&lt;br /&gt;
Old themes must be updated if they change an image from the default theme: All styles from the default theme which refer to a changed image must be overwritten in the custom theme. This way the URLs resolve to the new image.&lt;br /&gt;
&lt;br /&gt;
== Variables ==&lt;br /&gt;
&lt;br /&gt;
Naming of the variables should be straight forward. Variables containing the word ''Background'' will always refer to the background color. Variables containing ''Color'' will refer to the foreground color of an element, like color of a font. ''Hover'' in most cases means &amp;quot;hovered&amp;quot; elements. ''Selected'' relates to the currently selected item. Elements that are supposed to catch the users eye can use the ''Highlight'' class and the variable contains this word.&lt;br /&gt;
&lt;br /&gt;
Variables are defined in variables.less from twitter-bootstrap and our default definitions.less. Variables that are defined in definitions.less always override variables from bootstrap's variables.less&lt;br /&gt;
&lt;br /&gt;
=== Basic ===&lt;br /&gt;
&lt;br /&gt;
==== Font ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x) || Variable (7.4.x) || Default (7.6.x)&lt;br /&gt;
|-&lt;br /&gt;
| @font-family-sans-serif || @sansFontFamily       || &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, sans-serif&lt;br /&gt;
|-&lt;br /&gt;
| @font-family-serif      || @serifFontFamily      || Georgia, &amp;quot;Times New Roman&amp;quot;, Times, serif&lt;br /&gt;
|-&lt;br /&gt;
| @font-family-monospace  || @monoFontFamily       || Monaco, Menlo, Consolas, &amp;quot;Courier New&amp;quot;, monospace&lt;br /&gt;
|-&lt;br /&gt;
| @font-size-base         || @baseFontSize         || 14px&lt;br /&gt;
|-&lt;br /&gt;
|                     || @baseFontFamily       ||&lt;br /&gt;
|-&lt;br /&gt;
| @line-height-base       || @baseLineHeight       || 1.428571429; // 20/14&lt;br /&gt;
|-&lt;br /&gt;
|                      || @altFontFamily        ||&lt;br /&gt;
|-&lt;br /&gt;
| @font-size-touch        || @touchFontSize        || 15px&lt;br /&gt;
|-&lt;br /&gt;
| @headings-font-family   || @headingsFontFamily   || inherit&lt;br /&gt;
|-&lt;br /&gt;
| @headings-font-weight   || @headingsFontWeight   || 500&lt;br /&gt;
|-&lt;br /&gt;
| @font-size-large        || @fontSizeLarge        || ceil((@font-size-base * 1.25)); // ~18px&lt;br /&gt;
|-&lt;br /&gt;
| @font-size-small        || @fontSizeSmall        || ceil((@font-size-base * 0.85)); // ~12px&lt;br /&gt;
|-&lt;br /&gt;
|                      || @fontSizeMini         ||&lt;br /&gt;
|-&lt;br /&gt;
| @vgrid-font-size        || @vgridFontSize        || 13px&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Colors ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x)   || Variable (7.4.x) || Default (7.6.x)&lt;br /&gt;
|-&lt;br /&gt;
| @background        || @bodyBackground  || #fff&lt;br /&gt;
|-&lt;br /&gt;
| @text-color        || @textColor       || @gray-dark&lt;br /&gt;
|-&lt;br /&gt;
| @link-color        || @linkColor       || @brand-primary&lt;br /&gt;
|-&lt;br /&gt;
| @link-hover-color  || @linkColorHover  || darken(@link-color, 15%)&lt;br /&gt;
|-&lt;br /&gt;
| @link-accent-color || @linkAccentColor ||  #ffad00&lt;br /&gt;
|-&lt;br /&gt;
| || @linkAccentColorHover ||&lt;br /&gt;
|-&lt;br /&gt;
| @badge-color       || @badgeColor      || @white&lt;br /&gt;
|-&lt;br /&gt;
| @badge-bg          || @badgeBackground || #aaa&lt;br /&gt;
|-&lt;br /&gt;
| @headings-color    || @headingsColor   || inherit&lt;br /&gt;
|-&lt;br /&gt;
| @black             || @black           || #000&lt;br /&gt;
|-&lt;br /&gt;
| @gray-darker       || @grayDarker      || #222&lt;br /&gt;
|-&lt;br /&gt;
| @gray-dark         || @grayDark        || #333&lt;br /&gt;
|-&lt;br /&gt;
| @gray              || @gray            || #555&lt;br /&gt;
|-&lt;br /&gt;
| @gray-light        || @grayLight       || #999&lt;br /&gt;
|-&lt;br /&gt;
| @gray-lighter      || @grayLighter     || #eee&lt;br /&gt;
|-&lt;br /&gt;
| @white             || @white           || #fff&lt;br /&gt;
|-&lt;br /&gt;
| @blue              || @blue            || darken(#049cdb, 5%)&lt;br /&gt;
|-&lt;br /&gt;
| @blue-dark         || @blueDark        || #0064cd&lt;br /&gt;
|-&lt;br /&gt;
| @blue-light        || @blueLight       || lighten(#049cdb, 25%)&lt;br /&gt;
|-&lt;br /&gt;
| @green             || @green           || #1A8D1A&lt;br /&gt;
|-&lt;br /&gt;
| @green-light       || @greenLight      || #92D050&lt;br /&gt;
|-&lt;br /&gt;
| @red               || @red             || #cc0000&lt;br /&gt;
|-&lt;br /&gt;
| @yellow            || @yellow          || #F8E400&lt;br /&gt;
|-&lt;br /&gt;
| @orange            || @orange          || #f89406&lt;br /&gt;
|-&lt;br /&gt;
| @pink              || @pink            || #E01CD9&lt;br /&gt;
|-&lt;br /&gt;
| @purple            || @purple          || #7E16CF&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Space ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x) || Variable (7.4.x) || Default (7.6.x)&lt;br /&gt;
|-&lt;br /&gt;
| || @paddingLarge ||&lt;br /&gt;
|-&lt;br /&gt;
| || @paddingSmall ||&lt;br /&gt;
|-&lt;br /&gt;
| || @paddingMini  ||&lt;br /&gt;
|-&lt;br /&gt;
| @border-radius-base  || @baseBorderRadius      || 4px&lt;br /&gt;
|-&lt;br /&gt;
| @border-radius-large || @borderRadiusLarge     || 6px&lt;br /&gt;
|-&lt;br /&gt;
| @border-radius-small || @borderRadiusSmall     || 3px&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Pagination ===&lt;br /&gt;
&lt;br /&gt;
Used where pagination is done, for example in the Calendar weekview, each week is on one &amp;quot;page&amp;quot;; one can switch the week using a pagination widget styled with these variables.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x) || Variable (7.4.x) || Default (7.6.x)&lt;br /&gt;
|-&lt;br /&gt;
| @pagination-bg        || @paginationBackground       || #fff&lt;br /&gt;
|-&lt;br /&gt;
| @pagination-border    || @paginationBorder           || #ddd&lt;br /&gt;
|-&lt;br /&gt;
| @pagination-active-bg || @paginationActiveBackground || @brand-primary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Buttons ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x)                   || Variable (7.4.x)               || Default (7.6.x)&lt;br /&gt;
|-&lt;br /&gt;
| || @btnBackground ||&lt;br /&gt;
|-&lt;br /&gt;
| || @btnBackgroundHighlight ||&lt;br /&gt;
|-&lt;br /&gt;
| || @btnBorder ||&lt;br /&gt;
|-&lt;br /&gt;
| @btn-primary-background            || @btnPrimaryBackground          || @link-color&lt;br /&gt;
|-&lt;br /&gt;
| @btn-primary-background-highlinght || @btnPrimaryBackgroundHighlight || darken(@btn-primary-background, 10%);&lt;br /&gt;
|-&lt;br /&gt;
| @btn-info-background               || @btnInfoBackground             || #5bc0de&lt;br /&gt;
|-&lt;br /&gt;
| @btn-info-background-highlight     || @btnInfoBackgroundHighlight    || #2f96b4&lt;br /&gt;
|-&lt;br /&gt;
| @btn-success-background            || @btnSuccessBackground          || #62c462&lt;br /&gt;
|-&lt;br /&gt;
| @btn-success-background-highlight  || @btnSuccessBackgroundHighlight || #51a351&lt;br /&gt;
|-&lt;br /&gt;
| @btn-warning-background            || @btnWarningBackground          || lighten(@orange, 15%)&lt;br /&gt;
|-&lt;br /&gt;
| @btn-warning-background-highlight  || @btnWarningBackgroundHighlight || @orange&lt;br /&gt;
|-&lt;br /&gt;
| @btn-danger-background             || @btnDangerBackground           || #ee5f5b&lt;br /&gt;
|-&lt;br /&gt;
| @btn-danger-background-danger-highlight || @btnDangerBackgroundHighlight || #bd362f&lt;br /&gt;
|-&lt;br /&gt;
| @btn-inverse-background            || @btnInverseBackground          || #444&lt;br /&gt;
|-&lt;br /&gt;
| @btn-inverse-background-highlight  || @btnInverseBackgroundHighlight || @gray-darker&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Dropdowns ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x)            || Variable (7.4.x)              || Default (7.6.x)&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-bg                || @dropdownBackground           || #fff&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-border            || @dropdownBorder               || rgba(0,0,0,.15)&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-divider-bg        || @dropdownDividerTop           || #e5e5e5&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-divider-bg        || @dropdownDividerBottom        || #e5e5e5&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-link-color        || @dropdownLinkColor            || @gray-dark&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-link-hover-color  || @dropdownLinkColorHover       || darken(@gray-dark, 5%)&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-link-active-color || @dropdownLinkColorActive      || @component-active-color&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-link-active-bg    || @dropdownLinkBackgroundActive || @component-active-bg&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-link-hover-bg     || @dropdownLinkBackgroundHover  || #f5f5f5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Foldertree ===&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x)            || Variable (7.4.x)              || Default (7.6.x) || Description&lt;br /&gt;
|-&lt;br /&gt;
| @foldertree-sidepane-background || @foldertreeSidepanelBackground || #f5f5f5 ||&lt;br /&gt;
|-&lt;br /&gt;
| @foldertee-section-title-color || @foldertreeSectionTitleColor || #888 || Color for sectiontitles in foldertree (like &amp;quot;Public&amp;quot; folders)&lt;br /&gt;
|-&lt;br /&gt;
| @foldertree-active-label-color || @foldertreeActiveLabelColor || #333 || ''Active'' means, user can perform an action on this item&lt;br /&gt;
|-&lt;br /&gt;
|@foldertree-passive-label-color || @foldertreePassiveLabelColor ||@hc-gray || ''Passive'' means, user can '''not''' perform any action with this item &lt;br /&gt;
|-&lt;br /&gt;
| @foldertree-hover-background || @foldertreeHoverBackground || rgba(0, 0, 0, 0.05) ||&lt;br /&gt;
|-&lt;br /&gt;
| @foldertree-selected-background || @foldertreeSelectedBackground || rgba(0, 0, 0, 0.10) ||&lt;br /&gt;
|-&lt;br /&gt;
| @foldertree-badge-background || @foldertreeBadgeBackground || @bagde-bg || see [[#Colors]] for definition of @badge-bg&lt;br /&gt;
|-&lt;br /&gt;
| @foldertree-badge-color || @foldertreeBadgeColor ||@badge-color || see [[#Colors]] for definition of @badge-color&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Calendar ===&lt;br /&gt;
==== Appointment ====&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x)            || Variable (7.4.x)              || Default (7.6.x) || Description&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-reserved || @appointmentReserved || #08c /* blue */ || Appointment status color&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-temporary || @appointmentTemporary || #ffbb00 /* yellow */ || Appointment status color&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-absent || @appointmentAbsent || #913f3f /* red */ || Appointment status color&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-free || @appointmentFree || #8eb360 /* green */ || Appointment status color&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-private || @appointmentPrivate || #555 /* gray */ || Appointment status color&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-declined-font || @appointmentDeclinedFont || #888 /* dark gray */|| Font color for declined Appointments&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-unconfirmed-alpha || @appointmentUnconfirmedAlpha || 0.4 || Transparency value for unconfirmed Appointments&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-declined-alpha || @appointmentDeclinedAlpha || 0.3 || Transparency value for declined Appointments&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-hover-pct || @appointmentHoverPct || 15% || Percentage increase of the dark pigment content on hover effect&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Week View ====&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x)            || Variable (7.4.x)              || Default (7.6.x) || Description&lt;br /&gt;
|-&lt;br /&gt;
| @weekview-appointment-lasso || @weekviewAppointmentLasso || #aeaeff || Lasso frame color&lt;br /&gt;
|-&lt;br /&gt;
| @weekview-day-in || @weekviewDayIn || #fff /* white */ || Default background color in week view&lt;br /&gt;
|-&lt;br /&gt;
| @weekview-day-out || @weekviewDayOut || #e0e0e0 /* grey */ || Background color outside of the mean working time&lt;br /&gt;
|-&lt;br /&gt;
| @weekview-timeline || @weekviewTimeline || rgba(243, 15, 170, 0.4) || Color of the Line indicating the current time&lt;br /&gt;
|-&lt;br /&gt;
| @weekview-time-width || @weekviewTimeWith || 58px || With of the time labels on the left side&lt;br /&gt;
|-&lt;br /&gt;
| @calendar-toolbar-height || @calendarToolbarHeight || 47px || Height of the control toolbar &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Month View ====&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x)            || Variable (7.4.x)              || Default (7.6.x) || Description&lt;br /&gt;
|-&lt;br /&gt;
| @monthview-appointment-out || @monthviewAppointmentOut || #aaa /* light gray */ || Color of appointments, which are not in focus&lt;br /&gt;
|-&lt;br /&gt;
| @monthview-today || @monthviewToday || #daefff /* light blue */|| Background color of the current day&lt;br /&gt;
|-&lt;br /&gt;
| || @monthview@calendarToolbarHeight || ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Area names ==&lt;br /&gt;
&lt;br /&gt;
The variables sometimes refer to common areas. To identify which area is located where, see the following annotated screenshots.&lt;br /&gt;
&lt;br /&gt;
[[File:Colors_mail.png|800px||Mail application]]&lt;br /&gt;
&lt;br /&gt;
[[File:Colors_launchpad.png|800px||Launchpad application]]&lt;br /&gt;
&lt;br /&gt;
== Replacing the logo ==&lt;br /&gt;
&lt;br /&gt;
One of the most common theme changes which requires editing &amp;lt;code&amp;gt;style.css&amp;lt;/code&amp;gt; is changing the logo in the top right corner. The logo is displayed as the background image for an element with the ID &amp;lt;code&amp;gt;io-ox-top-logo-small&amp;lt;/code&amp;gt;. A theme can therefore change the size and URL of the image:&lt;br /&gt;
 #io-ox-top-logo-small {&lt;br /&gt;
     width: 60px;&lt;br /&gt;
     height: 22px;&lt;br /&gt;
     margin: 8px 13px 0 13px;&lt;br /&gt;
     background-image: url(mylogo.png);&lt;br /&gt;
 }&lt;br /&gt;
The file &amp;lt;code&amp;gt;mylogo.png&amp;lt;/code&amp;gt; is expected to be in the same directory as &amp;lt;code&amp;gt;style.css&amp;lt;/code&amp;gt;. If you want to place the image somewhere else, then use a relative path in &amp;lt;code&amp;gt;url()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Remember that images in OX App Suite are served by the web server and not by the application server. This means that images need to be packaged separately (for dedicated web servers) and installed in &amp;lt;code&amp;gt;/var/www/appsuite/&amp;lt;/code&amp;gt; (or similar, depending on the target platform) instead of &amp;lt;code&amp;gt;/opt/open-xchange/appsuite/&amp;lt;/code&amp;gt;. Direct support for multiple packages is coming in version 7.4.1. Until then, use the build system from the &amp;lt;code&amp;gt;develop&amp;lt;/code&amp;gt; branch to [[AppSuite:UI_build_system#init-packaging|initialize the packaging]] if your theme contains images.&lt;br /&gt;
&lt;br /&gt;
== Mixins ==&lt;br /&gt;
In LESS, it is possible to include a bunch of properties from one ruleset into another ruleset. So say we have the following class:&lt;br /&gt;
&lt;br /&gt;
=== Sample ===&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-css&amp;quot;&amp;gt;&lt;br /&gt;
.border-radius(@radius: 0px) {&lt;br /&gt;
    -webkit-border-radius: @radius;&lt;br /&gt;
    -moz-border-radius: @radius;&lt;br /&gt;
    -ms-border-radius: @radius;&lt;br /&gt;
    border-radius: @radius;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#menu a {&lt;br /&gt;
  color: #111;&lt;br /&gt;
  .border-radius(5px);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read [http://www.lesscss.org/#-mixins LESS Mixins]&lt;br /&gt;
&lt;br /&gt;
=== global OX Mixins ===&lt;br /&gt;
&lt;br /&gt;
they can be found at [[#definitions.less | definitions.less]]&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Mixin || Sample || Description &lt;br /&gt;
|-&lt;br /&gt;
| .box-sizing(@boxmodel) || .box-sizing(border-box) ||&lt;br /&gt;
|-&lt;br /&gt;
| .user-select(@select) || .user-select(none) ||&lt;br /&gt;
|-&lt;br /&gt;
| .border-radius(@radius) || .border-radius(3px) ||&lt;br /&gt;
|-&lt;br /&gt;
| .box-shadow(@shadow) || .box-shadow(3px) ||&lt;br /&gt;
|-&lt;br /&gt;
| .vertical-gradient(@startColor, @endColor) || .vertical-gradient(#888, #555) ||&lt;br /&gt;
|-&lt;br /&gt;
| .radial-gradient(@color1, @color2, @color3) || .radial-gradient(#111, #222, #333) ||&lt;br /&gt;
|-&lt;br /&gt;
| .transition(@transition) || .transition(background-color 0.2s linear) ||&lt;br /&gt;
|-&lt;br /&gt;
| .animation(@animation) || .animation(slidein 300ms) ||&lt;br /&gt;
|-&lt;br /&gt;
| .animation-name(@name) || .animation-name(slideright) ||&lt;br /&gt;
|-&lt;br /&gt;
| .ellipsis || .ellipsis ||&lt;br /&gt;
|-&lt;br /&gt;
| .overflow(@type) || .overflow(hidden) ||&lt;br /&gt;
|-&lt;br /&gt;
| .overflow-x(@type) || .overflow-x(hidden) ||&lt;br /&gt;
|-&lt;br /&gt;
| .overflow-y(@type) || .overflow-y(hidden) ||&lt;br /&gt;
|-&lt;br /&gt;
| .backface-visibility(@type) || .backface-visibility(hidden) ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== How to activate a theme during development ==&lt;br /&gt;
&lt;br /&gt;
When creating a new theme, you will want to test changes quickly without building packages reinstalling them. The trick is to use [[Appsuite:Appserver|appserver]].&lt;br /&gt;
&lt;br /&gt;
# First, you need to add the theme to the list of available themes on the backend. Simply create a new file in &amp;lt;code&amp;gt;/opt/open-xchange/etc/settings/&amp;lt;/code&amp;gt; with the extension &amp;lt;code&amp;gt;.properties&amp;lt;/code&amp;gt; and add a line for your theme to it: &amp;lt;pre&amp;amp;lt;noinclude&amp;amp;gt;&amp;amp;lt;/noinclude&amp;amp;gt;&amp;gt;io.ox/core/settingOptions//themes/&amp;lt;var&amp;gt;ID&amp;lt;/var&amp;gt;=&amp;lt;var&amp;gt;Theme Name&amp;lt;/var&amp;gt;&amp;lt;/pre&amp;amp;lt;noinclude&amp;amp;gt;&amp;amp;lt;/noinclude&amp;amp;gt;&amp;gt; Replace &amp;lt;var&amp;gt;ID&amp;lt;/var&amp;gt; by the identifier (directory name) of your theme, and &amp;lt;var&amp;gt;Theme Name&amp;lt;/var&amp;gt; by the human-readable name which should appear in the UI.&lt;br /&gt;
# The server needs to be restarted to read the new settings.&lt;br /&gt;
# Now, you can use &amp;lt;code&amp;gt;appserver&amp;lt;/code&amp;gt; ([[AppSuite:appserver#Use_with_Apache|with a local web server]] if your theme includes images) to get your theme in combination with the UI which is already installed on the backend.&lt;br /&gt;
# Finally, activate your theme the list in the &amp;lt;code&amp;gt;Settings -&amp;gt; Basic&amp;lt;/code&amp;gt; view behind the option &amp;lt;code&amp;gt;Theme&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In case you also want to access the same backend without &amp;lt;code&amp;gt;appserver&amp;lt;/code&amp;gt; while your theme is selected, that theme (or at least some empty &amp;lt;code&amp;gt;.less&amp;lt;/code&amp;gt; files) should be also installed on the backend to avoid errors. To just use an empty theme, run the following as root:&lt;br /&gt;
 touch /opt/open-xchange/appsuite/apps/themes/&amp;lt;var&amp;gt;ID&amp;lt;/var&amp;gt;/definitions.less&lt;br /&gt;
 touch /opt/open-xchange/appsuite/apps/themes/&amp;lt;var&amp;gt;ID&amp;lt;/var&amp;gt;/style.less&lt;br /&gt;
 /opt/open-xchange/appsuite/share/update-themes.sh&lt;br /&gt;
The value of &amp;lt;var&amp;gt;ID&amp;lt;/var&amp;gt; here must be the same as in your &amp;lt;code&amp;gt;.properties&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
== Favicons and mobile homescreen icons ==&lt;br /&gt;
'''Note''': This chapter is not about changing AppSuite icons which are used in the application like the brand on the upper right.&lt;br /&gt;
&lt;br /&gt;
'''This documentation applies for AppSuite v.7.4.2'''&lt;br /&gt;
&lt;br /&gt;
AppSuite ships with a standard set of icons containing a&lt;br /&gt;
# favicon&lt;br /&gt;
# set of touch icons which are mainly used by mobile Safari on iOS&lt;br /&gt;
&lt;br /&gt;
These icons are used as default for all devices and browsers as long as you don't deliver your own icons with your theme. &lt;br /&gt;
&lt;br /&gt;
=== Favicon ===&lt;br /&gt;
All major browsers support the use of a favicon. The favicon is a pixel image with the size of 16x16 (32x32) and the &amp;quot;ico&amp;quot; file ending. (see [http://en.wikipedia.org/wiki/Favicon Wikipedia Favicon] for details).&lt;br /&gt;
&lt;br /&gt;
You should provide your custom favicon within your custom theme. If you do not add a custom favicon to your theme the global OX default will be used. The default icon is located under &amp;lt;tt&amp;gt;apps/themes/icons/default&amp;lt;/tt&amp;gt; on the web server.&lt;br /&gt;
&lt;br /&gt;
'''Attention:''' Safari and Internet Explorer do not support dynamic changes to the favicon for a webpage. This means, the default icon will be shown even if a custom favicon is provided within a custom theme. To enable the right favicon for a theme on Safari and IE, the overall standard &amp;lt;tt&amp;gt;favicon.ico&amp;lt;/tt&amp;gt; located under &amp;lt;tt&amp;gt;apps/themes/icons/default&amp;lt;/tt&amp;gt; on the web server must be replaced with a custom version.&lt;br /&gt;
&lt;br /&gt;
=== Apple touch icons ===&lt;br /&gt;
iOS devices (iPhone/iPad/iPod) support so called &amp;quot;Webclips&amp;quot;. Webclips are bookmarks to websites or webapps which provide a App Icon that is shown on the iOS homescreen. AppSuite offers full support for Webclips by providing all needed App icons, splashscreens and full screen support. If a user uses the &amp;quot;Add to homescreen&amp;quot; button on his iOS device, a Webclip is created, taking the right icon for his current device. Most devices need custom resolutions of the Webclip icon in the '''png''' format.&lt;br /&gt;
&lt;br /&gt;
* iPhone 3: 57 x 57 px&lt;br /&gt;
* iPhone 4 retina: 114x114 px&lt;br /&gt;
* iPhone iPhone 5 retina: 120 x 120 px&lt;br /&gt;
* iPad: 72 x 72 px&lt;br /&gt;
* iPad (iOS 7): 76 x 76px&lt;br /&gt;
* iPad retina: 144 x 144 px &lt;br /&gt;
* iPad retina (iOS 7): 152 x 152 px &lt;br /&gt;
&lt;br /&gt;
Furthermore a fullscreen Webclip App will show a splashscreen, a jpg file that is displayed on startup during app load. There are currently three different resolutions as jpg files available. '''Note''': Splashscreens must be JPG files&lt;br /&gt;
&lt;br /&gt;
* iPhone: 320 x 460 px&lt;br /&gt;
* iPhone 4: 640 x 920 px&lt;br /&gt;
* iPhone 5: 640 x 1096 px&lt;br /&gt;
&lt;br /&gt;
'''Note''': We do not provide splashscreens for iPad&lt;br /&gt;
   &lt;br /&gt;
This list may change with Apple's iOS updates. We recommend providing all of this resolutions when customizing the Webclip icons and splashscreens, even if some iOS devices use the next best resolution for an icon if a certain file is missing.&lt;br /&gt;
&lt;br /&gt;
=== Providing custom icons ===&lt;br /&gt;
To provide custom Webclip icons locate the following path in the AppSuite installation on your web server:&lt;br /&gt;
 pathToAppSuite/apps/themes/icons/default&lt;br /&gt;
&lt;br /&gt;
This folder contains all OX default icons for Webclips icons and splashscreens. Use these as samples for your own versions.&lt;br /&gt;
&lt;br /&gt;
A clean installation will have all our default icons in the &amp;quot;default&amp;quot; directory. To customize the icons we recommend using our default icons as samples and save your customized version in your theme. '''Note''': The filename has to be the same as in the default folder. Otherwise the fallback will be applied and the default icons will be used. If more advanced rewriting is needed one should edit the contents of the &amp;lt;tt&amp;gt;.htaccess&amp;lt;/tt&amp;gt; file located under &amp;lt;tt&amp;gt;apps/themes&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Theming the login page ==&lt;br /&gt;
&lt;br /&gt;
The login page is a little bit special. If you don’t use the [[Open-Xchange_servlet_for_external_login_masks|form login]] and provide your own login page, you might want to theme the login page, too. [[AppSuite:Theming the login page|Learn how to do this here]].&lt;br /&gt;
&lt;br /&gt;
=== Providing domain based login themes ===&lt;br /&gt;
&lt;br /&gt;
If you have a multibrand installation and you want to deliver not only custom themes but also custom login-themes this can be done via Apache mod_rewrite. You can do so by a domain-based rewrite rule to deliver custom themes to a user based on the URI he's using. The needed config file &amp;lt;tt&amp;gt;.htaccess&amp;lt;/tt&amp;gt; is located under &amp;lt;tt&amp;gt;apps/themes&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Sample config for domain based login theme&lt;br /&gt;
RewriteCond %{HTTP_HOST} ^www\.domain\.com$&lt;br /&gt;
RewriteCond %{REQUEST_FILENAME} -f&lt;br /&gt;
RewriteRule ^login/(.*)$ domain_com_logintheme/$1 [L]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Best practice ==&lt;br /&gt;
&lt;br /&gt;
To be really safe, it’s best to only define your own values for the variables shown above. If this really breaks anything, we consider this a bug, please report it [https://bugs.open-xchange.com/] in our bugzilla.&lt;br /&gt;
&lt;br /&gt;
Of course, using CSS in &amp;lt;code&amp;gt;style.less&amp;lt;/code&amp;gt; file to define your own styles is also possible. Make sure to test your style in such cases more carefully. It is most likely safe to change minor things using this file, but if you plan to change any positions of larger elements, this might break the complete design. So please be careful when overwriting the default CSS rules.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
[http://bradfrost.github.io/this-is-responsive/resources.html Responsive design]&lt;br /&gt;
&lt;br /&gt;
[http://lesscss.org/ LESS]&lt;br /&gt;
&lt;br /&gt;
== Caveats ==&lt;br /&gt;
&lt;br /&gt;
It is '''not''' recommended to change the size of elements or their position. If you really want to do so, please check on all devices and in all browsers and make sure you didn’t break anything. You even have to be careful when changing the font, because this might have effects on positioning, too.&lt;br /&gt;
&lt;br /&gt;
As mentioned before, changing colors should be safe.&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
	<entry>
		<id>https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Theming&amp;diff=17427</id>
		<title>AppSuite:Theming</title>
		<link rel="alternate" type="text/html" href="https://wiki.open-xchange.com/wiki/index.php?title=AppSuite:Theming&amp;diff=17427"/>
		<updated>2014-04-11T14:54:47Z</updated>

		<summary type="html">&lt;p&gt;D.haus: /* Month View */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stability-experimental}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Theming&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Abstract.''' In this article, you can learn how to create customized themes and use them to change the look of you appsuite installation.&lt;br /&gt;
__TOC__&lt;br /&gt;
== LESS.JS ==&lt;br /&gt;
Appsuite used LESS as dynamic stylesheet language. LESS extends CSS with dynamic behavior such as variables, mixins, operations and functions.&lt;br /&gt;
&lt;br /&gt;
Please read [http://lesscss.org/#docs LESS.JS] documentation first.&lt;br /&gt;
&lt;br /&gt;
=== Using less.js ===&lt;br /&gt;
If your theme depends on less.js, you will need one more step to make it work. Why? To accelerate the login, compilation of LessCSS files was moved from the login process in the browser to the installation process on the backend. &lt;br /&gt;
&lt;br /&gt;
Backend packages for themes and any apps which ship .less files require the following changes:&lt;br /&gt;
&lt;br /&gt;
1. Add &amp;quot;skipLess=1&amp;quot; to the build command in *.spec and in debian/rules:&lt;br /&gt;
   sh /opt/open-xchange-appsuite-dev/bin/build-appsuite app skipLess=1&lt;br /&gt;
2. Add %post and %postun sections to *.spec:&lt;br /&gt;
   %post&lt;br /&gt;
   if [ &amp;quot;$1&amp;quot; = 1 ]; then&lt;br /&gt;
   UPDATE=/opt/open-xchange/appsuite/share/update-themes.sh&lt;br /&gt;
   [ -x $UPDATE ] &amp;amp;&amp;amp; $UPDATE&lt;br /&gt;
   fi&lt;br /&gt;
   %postun&lt;br /&gt;
   UPDATE=/opt/open-xchange/appsuite/share/update-themes.sh&lt;br /&gt;
   [ -x $UPDATE ] &amp;amp;&amp;amp; $UPDATE&lt;br /&gt;
&lt;br /&gt;
For multiple binary packages, the %post and %postun sections should apply only to backend packages &lt;br /&gt;
which contain .less files.&lt;br /&gt;
&lt;br /&gt;
3. Add debian/postinst and debian/postrm containing the same content:&lt;br /&gt;
   #!/bin/sh&lt;br /&gt;
   UPDATE=/opt/open-xchange/appsuite/share/update-themes.sh&lt;br /&gt;
   [ -x $UPDATE ] &amp;amp;&amp;amp; $UPDATE&lt;br /&gt;
&lt;br /&gt;
For multiple binary packages, the postinst and postrm files should apply only to backend packages which contain .less files.&lt;br /&gt;
&lt;br /&gt;
Note: Since 7.2.1, LessCSS files must have the file extension .less to be usable with the 'less' RequireJS plugin (module dependencies of the form 'less!filename.less'). Previously we were more lenient and dealt with .css, too.&lt;br /&gt;
&lt;br /&gt;
== File structure ==&lt;br /&gt;
A theme basically consists of two files located in &amp;lt;code&amp;gt;apps/themes/&amp;lt;var&amp;gt;THEME_ID&amp;lt;/var&amp;gt;/&amp;lt;/code&amp;gt;. These files are described in this and the following sections.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;var&amp;gt;THEME_ID&amp;lt;/var&amp;gt;&amp;lt;/code&amp;gt; is a unique identifier for your theme, which is not visible to users. By convention, it is best derived from a domain name you control, e.g. &amp;lt;code&amp;gt;com.example.prettytheme&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== definitions.less ===&lt;br /&gt;
This file can be used to override variables described in the &amp;quot;Variables&amp;quot; section of this article.&lt;br /&gt;
&lt;br /&gt;
=== style.less ===&lt;br /&gt;
This file can be used to define any CSS you like. Before doing this, check, if there really is no variable that can be used to achieve the same thing.&lt;br /&gt;
&lt;br /&gt;
=== Referencing paths ===&lt;br /&gt;
Since 7.2.1, all URLs are relative to the source .less file in which they are contained. This means that unless a theme changes an image it does not need to include that image anymore. &lt;br /&gt;
&lt;br /&gt;
Old themes must be updated if they change an image from the default theme: All styles from the default theme which refer to a changed image must be overwritten in the custom theme. This way the URLs resolve to the new image.&lt;br /&gt;
&lt;br /&gt;
== Variables ==&lt;br /&gt;
&lt;br /&gt;
Naming of the variables should be straight forward. Variables containing the word ''Background'' will always refer to the background color. Variables containing ''Color'' will refer to the foreground color of an element, like color of a font. ''Hover'' in most cases means &amp;quot;hovered&amp;quot; elements. ''Selected'' relates to the currently selected item. Elements that are supposed to catch the users eye can use the ''Highlight'' class and the variable contains this word.&lt;br /&gt;
&lt;br /&gt;
=== Basic ===&lt;br /&gt;
&lt;br /&gt;
==== Font ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x) || Variable (7.4.x) || Default (7.6.x)&lt;br /&gt;
|-&lt;br /&gt;
| @font-family-sans-serif || @sansFontFamily       || &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, sans-serif&lt;br /&gt;
|-&lt;br /&gt;
| @font-family-serif      || @serifFontFamily      || Georgia, &amp;quot;Times New Roman&amp;quot;, Times, serif&lt;br /&gt;
|-&lt;br /&gt;
| @font-family-monospace  || @monoFontFamily       || Monaco, Menlo, Consolas, &amp;quot;Courier New&amp;quot;, monospace&lt;br /&gt;
|-&lt;br /&gt;
| @font-size-base         || @baseFontSize         || 14px&lt;br /&gt;
|-&lt;br /&gt;
|                     || @baseFontFamily       ||&lt;br /&gt;
|-&lt;br /&gt;
| @line-height-base       || @baseLineHeight       || 1.428571429; // 20/14&lt;br /&gt;
|-&lt;br /&gt;
|                      || @altFontFamily        ||&lt;br /&gt;
|-&lt;br /&gt;
| @font-size-touch        || @touchFontSize        || 15px&lt;br /&gt;
|-&lt;br /&gt;
| @headings-font-family   || @headingsFontFamily   || inherit&lt;br /&gt;
|-&lt;br /&gt;
| @headings-font-weight   || @headingsFontWeight   || 500&lt;br /&gt;
|-&lt;br /&gt;
| @font-size-large        || @fontSizeLarge        || ceil((@font-size-base * 1.25)); // ~18px&lt;br /&gt;
|-&lt;br /&gt;
| @font-size-small        || @fontSizeSmall        || ceil((@font-size-base * 0.85)); // ~12px&lt;br /&gt;
|-&lt;br /&gt;
|                      || @fontSizeMini         ||&lt;br /&gt;
|-&lt;br /&gt;
| @vgrid-font-size        || @vgridFontSize        || 13px&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Colors ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x)   || Variable (7.4.x) || Default (7.6.x)&lt;br /&gt;
|-&lt;br /&gt;
| @background        || @bodyBackground  || #fff&lt;br /&gt;
|-&lt;br /&gt;
| @text-color        || @textColor       || @gray-dark&lt;br /&gt;
|-&lt;br /&gt;
| @link-color        || @linkColor       || @brand-primary&lt;br /&gt;
|-&lt;br /&gt;
| @link-hover-color  || @linkColorHover  || darken(@link-color, 15%)&lt;br /&gt;
|-&lt;br /&gt;
| @link-accent-color || @linkAccentColor ||  #ffad00&lt;br /&gt;
|-&lt;br /&gt;
| || @linkAccentColorHover ||&lt;br /&gt;
|-&lt;br /&gt;
| @badge-color       || @badgeColor      || @white&lt;br /&gt;
|-&lt;br /&gt;
| @badge-bg          || @badgeBackground || #aaa&lt;br /&gt;
|-&lt;br /&gt;
| @headings-color    || @headingsColor   || inherit&lt;br /&gt;
|-&lt;br /&gt;
| @black             || @black           || #000&lt;br /&gt;
|-&lt;br /&gt;
| @gray-darker       || @grayDarker      || #222&lt;br /&gt;
|-&lt;br /&gt;
| @gray-dark         || @grayDark        || #333&lt;br /&gt;
|-&lt;br /&gt;
| @gray              || @gray            || #555&lt;br /&gt;
|-&lt;br /&gt;
| @gray-light        || @grayLight       || #999&lt;br /&gt;
|-&lt;br /&gt;
| @gray-lighter      || @grayLighter     || #eee&lt;br /&gt;
|-&lt;br /&gt;
| @white             || @white           || #fff&lt;br /&gt;
|-&lt;br /&gt;
| @blue              || @blue            || darken(#049cdb, 5%)&lt;br /&gt;
|-&lt;br /&gt;
| @blue-dark         || @blueDark        || #0064cd&lt;br /&gt;
|-&lt;br /&gt;
| @blue-light        || @blueLight       || lighten(#049cdb, 25%)&lt;br /&gt;
|-&lt;br /&gt;
| @green             || @green           || #1A8D1A&lt;br /&gt;
|-&lt;br /&gt;
| @green-light       || @greenLight      || #92D050&lt;br /&gt;
|-&lt;br /&gt;
| @red               || @red             || #cc0000&lt;br /&gt;
|-&lt;br /&gt;
| @yellow            || @yellow          || #F8E400&lt;br /&gt;
|-&lt;br /&gt;
| @orange            || @orange          || #f89406&lt;br /&gt;
|-&lt;br /&gt;
| @pink              || @pink            || #E01CD9&lt;br /&gt;
|-&lt;br /&gt;
| @purple            || @purple          || #7E16CF&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Space ====&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x) || Variable (7.4.x) || Default (7.6.x)&lt;br /&gt;
|-&lt;br /&gt;
| || @paddingLarge ||&lt;br /&gt;
|-&lt;br /&gt;
| || @paddingSmall ||&lt;br /&gt;
|-&lt;br /&gt;
| || @paddingMini  ||&lt;br /&gt;
|-&lt;br /&gt;
| @border-radius-base  || @baseBorderRadius      || 4px&lt;br /&gt;
|-&lt;br /&gt;
| @border-radius-large || @borderRadiusLarge     || 6px&lt;br /&gt;
|-&lt;br /&gt;
| @border-radius-small || @borderRadiusSmall     || 3px&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Pagination ===&lt;br /&gt;
&lt;br /&gt;
Used where pagination is done, for example in the Calendar weekview, each week is on one &amp;quot;page&amp;quot;; one can switch the week using a pagination widget styled with these variables.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x) || Variable (7.4.x) || Default (7.6.x)&lt;br /&gt;
|-&lt;br /&gt;
| @pagination-bg        || @paginationBackground       || #fff&lt;br /&gt;
|-&lt;br /&gt;
| @pagination-border    || @paginationBorder           || #ddd&lt;br /&gt;
|-&lt;br /&gt;
| @pagination-active-bg || @paginationActiveBackground || @brand-primary&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Buttons ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x)                   || Variable (7.4.x)               || Default (7.6.x)&lt;br /&gt;
|-&lt;br /&gt;
| || @btnBackground ||&lt;br /&gt;
|-&lt;br /&gt;
| || @btnBackgroundHighlight ||&lt;br /&gt;
|-&lt;br /&gt;
| || @btnBorder ||&lt;br /&gt;
|-&lt;br /&gt;
| @btn-primary-background            || @btnPrimaryBackground          || @link-color&lt;br /&gt;
|-&lt;br /&gt;
| @btn-primary-background-highlinght || @btnPrimaryBackgroundHighlight || darken(@btn-primary-background, 10%);&lt;br /&gt;
|-&lt;br /&gt;
| @btn-info-background               || @btnInfoBackground             || #5bc0de&lt;br /&gt;
|-&lt;br /&gt;
| @btn-info-background-highlight     || @btnInfoBackgroundHighlight    || #2f96b4&lt;br /&gt;
|-&lt;br /&gt;
| @btn-success-background            || @btnSuccessBackground          || #62c462&lt;br /&gt;
|-&lt;br /&gt;
| @btn-success-background-highlight  || @btnSuccessBackgroundHighlight || #51a351&lt;br /&gt;
|-&lt;br /&gt;
| @btn-warning-background            || @btnWarningBackground          || lighten(@orange, 15%)&lt;br /&gt;
|-&lt;br /&gt;
| @btn-warning-background-highlight  || @btnWarningBackgroundHighlight || @orange&lt;br /&gt;
|-&lt;br /&gt;
| @btn-danger-background             || @btnDangerBackground           || #ee5f5b&lt;br /&gt;
|-&lt;br /&gt;
| @btn-danger-background-danger-highlight || @btnDangerBackgroundHighlight || #bd362f&lt;br /&gt;
|-&lt;br /&gt;
| @btn-inverse-background            || @btnInverseBackground          || #444&lt;br /&gt;
|-&lt;br /&gt;
| @btn-inverse-background-highlight  || @btnInverseBackgroundHighlight || @gray-darker&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Dropdowns ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x)            || Variable (7.4.x)              || Default (7.6.x)&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-bg                || @dropdownBackground           || #fff&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-border            || @dropdownBorder               || rgba(0,0,0,.15)&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-divider-bg        || @dropdownDividerTop           || #e5e5e5&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-divider-bg        || @dropdownDividerBottom        || #e5e5e5&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-link-color        || @dropdownLinkColor            || @gray-dark&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-link-hover-color  || @dropdownLinkColorHover       || darken(@gray-dark, 5%)&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-link-active-color || @dropdownLinkColorActive      || @component-active-color&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-link-active-bg    || @dropdownLinkBackgroundActive || @component-active-bg&lt;br /&gt;
|-&lt;br /&gt;
| @dropdown-link-hover-bg     || @dropdownLinkBackgroundHover  || #f5f5f5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Foldertree ===&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x)            || Variable (7.4.x)              || Default (7.6.x) || Description&lt;br /&gt;
|-&lt;br /&gt;
| @foldertree-sidepane-background || @foldertreeSidepanelBackground || #f5f5f5 ||&lt;br /&gt;
|-&lt;br /&gt;
| @foldertee-section-title-color || @foldertreeSectionTitleColor || #888 || Color for sectiontitles in foldertree (like &amp;quot;Public&amp;quot; folders)&lt;br /&gt;
|-&lt;br /&gt;
| @foldertree-active-label-color || @foldertreeActiveLabelColor || #333 || ''Active'' means, user can perform an action on this item&lt;br /&gt;
|-&lt;br /&gt;
|@foldertree-passive-label-color || @foldertreePassiveLabelColor ||@hc-gray || ''Passive'' means, user can '''not''' perform any action with this item &lt;br /&gt;
|-&lt;br /&gt;
| @foldertree-hover-background || @foldertreeHoverBackground || rgba(0, 0, 0, 0.05) ||&lt;br /&gt;
|-&lt;br /&gt;
| @foldertree-selected-background || @foldertreeSelectedBackground || rgba(0, 0, 0, 0.10) ||&lt;br /&gt;
|-&lt;br /&gt;
| @foldertree-badge-background || @foldertreeBadgeBackground || @bagde-bg || see [[#Colors]] for definition of @badge-bg&lt;br /&gt;
|-&lt;br /&gt;
| @foldertree-badge-color || @foldertreeBadgeColor ||@badge-color || see [[#Colors]] for definition of @badge-color&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Calendar ===&lt;br /&gt;
==== Appointment ====&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x)            || Variable (7.4.x)              || Default (7.6.x) || Description&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-reserved || @appointmentReserved || #08c /* blue */ || Appointment status color&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-temporary || @appointmentTemporary || #ffbb00 /* yellow */ || Appointment status color&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-absent || @appointmentAbsent || #913f3f /* red */ || Appointment status color&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-free || @appointmentFree || #8eb360 /* green */ || Appointment status color&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-private || @appointmentPrivate || #555 /* gray */ || Appointment status color&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-declined-font || @appointmentDeclinedFont || #888 /* dark gray */|| Font color for declined Appointments&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-unconfirmed-alpha || @appointmentUnconfirmedAlpha || 0.4 || Transparency value for unconfirmed Appointments&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-declined-alpha || @appointmentDeclinedAlpha || 0.3 || Transparency value for declined Appointments&lt;br /&gt;
|-&lt;br /&gt;
| @appointment-hover-pct || @appointmentHoverPct || 15% || Percentage increase of the dark pigment content on hover effect&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Week View ====&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x)            || Variable (7.4.x)              || Default (7.6.x) || Description&lt;br /&gt;
|-&lt;br /&gt;
| @weekview-appointment-lasso || @weekviewAppointmentLasso || #aeaeff || Lasso frame color&lt;br /&gt;
|-&lt;br /&gt;
| @weekview-day-in || @weekviewDayIn || #fff /* white */ || Default background color in week view&lt;br /&gt;
|-&lt;br /&gt;
| @weekview-day-out || @weekviewDayOut || #e0e0e0 /* grey */ || Background color outside of the mean working time&lt;br /&gt;
|-&lt;br /&gt;
| @weekview-timeline || @weekviewTimeline || rgba(243, 15, 170, 0.4) || Color of the Line indicating the current time&lt;br /&gt;
|-&lt;br /&gt;
| @weekview-time-width || @weekviewTimeWith || 58px || With of the time labels on the left side&lt;br /&gt;
|-&lt;br /&gt;
| @calendar-toolbar-height || @calendarToolbarHeight || 47px || Height of the control toolbar &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Month View ====&lt;br /&gt;
{|&lt;br /&gt;
! Variable (7.6.x)            || Variable (7.4.x)              || Default (7.6.x) || Description&lt;br /&gt;
|-&lt;br /&gt;
| @monthview-appointment-out || @monthviewAppointmentOut || #aaa /* light gray */ || Color of appointments, which are not in focus&lt;br /&gt;
|-&lt;br /&gt;
| @monthview-today || @monthviewToday || #daefff /* light blue */|| Background color of the current day&lt;br /&gt;
|-&lt;br /&gt;
| || @monthview@calendarToolbarHeight || ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Area names ==&lt;br /&gt;
&lt;br /&gt;
The variables sometimes refer to common areas. To identify which area is located where, see the following annotated screenshots.&lt;br /&gt;
&lt;br /&gt;
[[File:Colors_mail.png|800px||Mail application]]&lt;br /&gt;
&lt;br /&gt;
[[File:Colors_launchpad.png|800px||Launchpad application]]&lt;br /&gt;
&lt;br /&gt;
== Replacing the logo ==&lt;br /&gt;
&lt;br /&gt;
One of the most common theme changes which requires editing &amp;lt;code&amp;gt;style.css&amp;lt;/code&amp;gt; is changing the logo in the top right corner. The logo is displayed as the background image for an element with the ID &amp;lt;code&amp;gt;io-ox-top-logo-small&amp;lt;/code&amp;gt;. A theme can therefore change the size and URL of the image:&lt;br /&gt;
 #io-ox-top-logo-small {&lt;br /&gt;
     width: 60px;&lt;br /&gt;
     height: 22px;&lt;br /&gt;
     margin: 8px 13px 0 13px;&lt;br /&gt;
     background-image: url(mylogo.png);&lt;br /&gt;
 }&lt;br /&gt;
The file &amp;lt;code&amp;gt;mylogo.png&amp;lt;/code&amp;gt; is expected to be in the same directory as &amp;lt;code&amp;gt;style.css&amp;lt;/code&amp;gt;. If you want to place the image somewhere else, then use a relative path in &amp;lt;code&amp;gt;url()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Remember that images in OX App Suite are served by the web server and not by the application server. This means that images need to be packaged separately (for dedicated web servers) and installed in &amp;lt;code&amp;gt;/var/www/appsuite/&amp;lt;/code&amp;gt; (or similar, depending on the target platform) instead of &amp;lt;code&amp;gt;/opt/open-xchange/appsuite/&amp;lt;/code&amp;gt;. Direct support for multiple packages is coming in version 7.4.1. Until then, use the build system from the &amp;lt;code&amp;gt;develop&amp;lt;/code&amp;gt; branch to [[AppSuite:UI_build_system#init-packaging|initialize the packaging]] if your theme contains images.&lt;br /&gt;
&lt;br /&gt;
== Mixins ==&lt;br /&gt;
In LESS, it is possible to include a bunch of properties from one ruleset into another ruleset. So say we have the following class:&lt;br /&gt;
&lt;br /&gt;
=== Sample ===&lt;br /&gt;
&amp;lt;pre class=&amp;quot;language-css&amp;quot;&amp;gt;&lt;br /&gt;
.border-radius(@radius: 0px) {&lt;br /&gt;
    -webkit-border-radius: @radius;&lt;br /&gt;
    -moz-border-radius: @radius;&lt;br /&gt;
    -ms-border-radius: @radius;&lt;br /&gt;
    border-radius: @radius;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#menu a {&lt;br /&gt;
  color: #111;&lt;br /&gt;
  .border-radius(5px);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read [http://www.lesscss.org/#-mixins LESS Mixins]&lt;br /&gt;
&lt;br /&gt;
=== global OX Mixins ===&lt;br /&gt;
&lt;br /&gt;
they can be found at [[#definitions.less | definitions.less]]&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
! Mixin || Sample || Description &lt;br /&gt;
|-&lt;br /&gt;
| .box-sizing(@boxmodel) || .box-sizing(border-box) ||&lt;br /&gt;
|-&lt;br /&gt;
| .user-select(@select) || .user-select(none) ||&lt;br /&gt;
|-&lt;br /&gt;
| .border-radius(@radius) || .border-radius(3px) ||&lt;br /&gt;
|-&lt;br /&gt;
| .box-shadow(@shadow) || .box-shadow(3px) ||&lt;br /&gt;
|-&lt;br /&gt;
| .vertical-gradient(@startColor, @endColor) || .vertical-gradient(#888, #555) ||&lt;br /&gt;
|-&lt;br /&gt;
| .radial-gradient(@color1, @color2, @color3) || .radial-gradient(#111, #222, #333) ||&lt;br /&gt;
|-&lt;br /&gt;
| .transition(@transition) || .transition(background-color 0.2s linear) ||&lt;br /&gt;
|-&lt;br /&gt;
| .animation(@animation) || .animation(slidein 300ms) ||&lt;br /&gt;
|-&lt;br /&gt;
| .animation-name(@name) || .animation-name(slideright) ||&lt;br /&gt;
|-&lt;br /&gt;
| .ellipsis || .ellipsis ||&lt;br /&gt;
|-&lt;br /&gt;
| .overflow(@type) || .overflow(hidden) ||&lt;br /&gt;
|-&lt;br /&gt;
| .overflow-x(@type) || .overflow-x(hidden) ||&lt;br /&gt;
|-&lt;br /&gt;
| .overflow-y(@type) || .overflow-y(hidden) ||&lt;br /&gt;
|-&lt;br /&gt;
| .backface-visibility(@type) || .backface-visibility(hidden) ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== How to activate a theme during development ==&lt;br /&gt;
&lt;br /&gt;
When creating a new theme, you will want to test changes quickly without building packages reinstalling them. The trick is to use [[Appsuite:Appserver|appserver]].&lt;br /&gt;
&lt;br /&gt;
# First, you need to add the theme to the list of available themes on the backend. Simply create a new file in &amp;lt;code&amp;gt;/opt/open-xchange/etc/settings/&amp;lt;/code&amp;gt; with the extension &amp;lt;code&amp;gt;.properties&amp;lt;/code&amp;gt; and add a line for your theme to it: &amp;lt;pre&amp;amp;lt;noinclude&amp;amp;gt;&amp;amp;lt;/noinclude&amp;amp;gt;&amp;gt;io.ox/core/settingOptions//themes/&amp;lt;var&amp;gt;ID&amp;lt;/var&amp;gt;=&amp;lt;var&amp;gt;Theme Name&amp;lt;/var&amp;gt;&amp;lt;/pre&amp;amp;lt;noinclude&amp;amp;gt;&amp;amp;lt;/noinclude&amp;amp;gt;&amp;gt; Replace &amp;lt;var&amp;gt;ID&amp;lt;/var&amp;gt; by the identifier (directory name) of your theme, and &amp;lt;var&amp;gt;Theme Name&amp;lt;/var&amp;gt; by the human-readable name which should appear in the UI.&lt;br /&gt;
# The server needs to be restarted to read the new settings.&lt;br /&gt;
# Now, you can use &amp;lt;code&amp;gt;appserver&amp;lt;/code&amp;gt; ([[AppSuite:appserver#Use_with_Apache|with a local web server]] if your theme includes images) to get your theme in combination with the UI which is already installed on the backend.&lt;br /&gt;
# Finally, activate your theme the list in the &amp;lt;code&amp;gt;Settings -&amp;gt; Basic&amp;lt;/code&amp;gt; view behind the option &amp;lt;code&amp;gt;Theme&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
In case you also want to access the same backend without &amp;lt;code&amp;gt;appserver&amp;lt;/code&amp;gt; while your theme is selected, that theme (or at least some empty &amp;lt;code&amp;gt;.less&amp;lt;/code&amp;gt; files) should be also installed on the backend to avoid errors. To just use an empty theme, run the following as root:&lt;br /&gt;
 touch /opt/open-xchange/appsuite/apps/themes/&amp;lt;var&amp;gt;ID&amp;lt;/var&amp;gt;/definitions.less&lt;br /&gt;
 touch /opt/open-xchange/appsuite/apps/themes/&amp;lt;var&amp;gt;ID&amp;lt;/var&amp;gt;/style.less&lt;br /&gt;
 /opt/open-xchange/appsuite/share/update-themes.sh&lt;br /&gt;
The value of &amp;lt;var&amp;gt;ID&amp;lt;/var&amp;gt; here must be the same as in your &amp;lt;code&amp;gt;.properties&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
== Favicons and mobile homescreen icons ==&lt;br /&gt;
'''Note''': This chapter is not about changing AppSuite icons which are used in the application like the brand on the upper right.&lt;br /&gt;
&lt;br /&gt;
'''This documentation applies for AppSuite v.7.4.2'''&lt;br /&gt;
&lt;br /&gt;
AppSuite ships with a standard set of icons containing a&lt;br /&gt;
# favicon&lt;br /&gt;
# set of touch icons which are mainly used by mobile Safari on iOS&lt;br /&gt;
&lt;br /&gt;
These icons are used as default for all devices and browsers as long as you don't deliver your own icons with your theme. &lt;br /&gt;
&lt;br /&gt;
=== Favicon ===&lt;br /&gt;
All major browsers support the use of a favicon. The favicon is a pixel image with the size of 16x16 (32x32) and the &amp;quot;ico&amp;quot; file ending. (see [http://en.wikipedia.org/wiki/Favicon Wikipedia Favicon] for details).&lt;br /&gt;
&lt;br /&gt;
You should provide your custom favicon within your custom theme. If you do not add a custom favicon to your theme the global OX default will be used. The default icon is located under &amp;lt;tt&amp;gt;apps/themes/icons/default&amp;lt;/tt&amp;gt; on the web server.&lt;br /&gt;
&lt;br /&gt;
'''Attention:''' Safari and Internet Explorer do not support dynamic changes to the favicon for a webpage. This means, the default icon will be shown even if a custom favicon is provided within a custom theme. To enable the right favicon for a theme on Safari and IE, the overall standard &amp;lt;tt&amp;gt;favicon.ico&amp;lt;/tt&amp;gt; located under &amp;lt;tt&amp;gt;apps/themes/icons/default&amp;lt;/tt&amp;gt; on the web server must be replaced with a custom version.&lt;br /&gt;
&lt;br /&gt;
=== Apple touch icons ===&lt;br /&gt;
iOS devices (iPhone/iPad/iPod) support so called &amp;quot;Webclips&amp;quot;. Webclips are bookmarks to websites or webapps which provide a App Icon that is shown on the iOS homescreen. AppSuite offers full support for Webclips by providing all needed App icons, splashscreens and full screen support. If a user uses the &amp;quot;Add to homescreen&amp;quot; button on his iOS device, a Webclip is created, taking the right icon for his current device. Most devices need custom resolutions of the Webclip icon in the '''png''' format.&lt;br /&gt;
&lt;br /&gt;
* iPhone 3: 57 x 57 px&lt;br /&gt;
* iPhone 4 retina: 114x114 px&lt;br /&gt;
* iPhone iPhone 5 retina: 120 x 120 px&lt;br /&gt;
* iPad: 72 x 72 px&lt;br /&gt;
* iPad (iOS 7): 76 x 76px&lt;br /&gt;
* iPad retina: 144 x 144 px &lt;br /&gt;
* iPad retina (iOS 7): 152 x 152 px &lt;br /&gt;
&lt;br /&gt;
Furthermore a fullscreen Webclip App will show a splashscreen, a jpg file that is displayed on startup during app load. There are currently three different resolutions as jpg files available. '''Note''': Splashscreens must be JPG files&lt;br /&gt;
&lt;br /&gt;
* iPhone: 320 x 460 px&lt;br /&gt;
* iPhone 4: 640 x 920 px&lt;br /&gt;
* iPhone 5: 640 x 1096 px&lt;br /&gt;
&lt;br /&gt;
'''Note''': We do not provide splashscreens for iPad&lt;br /&gt;
   &lt;br /&gt;
This list may change with Apple's iOS updates. We recommend providing all of this resolutions when customizing the Webclip icons and splashscreens, even if some iOS devices use the next best resolution for an icon if a certain file is missing.&lt;br /&gt;
&lt;br /&gt;
=== Providing custom icons ===&lt;br /&gt;
To provide custom Webclip icons locate the following path in the AppSuite installation on your web server:&lt;br /&gt;
 pathToAppSuite/apps/themes/icons/default&lt;br /&gt;
&lt;br /&gt;
This folder contains all OX default icons for Webclips icons and splashscreens. Use these as samples for your own versions.&lt;br /&gt;
&lt;br /&gt;
A clean installation will have all our default icons in the &amp;quot;default&amp;quot; directory. To customize the icons we recommend using our default icons as samples and save your customized version in your theme. '''Note''': The filename has to be the same as in the default folder. Otherwise the fallback will be applied and the default icons will be used. If more advanced rewriting is needed one should edit the contents of the &amp;lt;tt&amp;gt;.htaccess&amp;lt;/tt&amp;gt; file located under &amp;lt;tt&amp;gt;apps/themes&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Theming the login page ==&lt;br /&gt;
&lt;br /&gt;
The login page is a little bit special. If you don’t use the [[Open-Xchange_servlet_for_external_login_masks|form login]] and provide your own login page, you might want to theme the login page, too. [[AppSuite:Theming the login page|Learn how to do this here]].&lt;br /&gt;
&lt;br /&gt;
=== Providing domain based login themes ===&lt;br /&gt;
&lt;br /&gt;
If you have a multibrand installation and you want to deliver not only custom themes but also custom login-themes this can be done via Apache mod_rewrite. You can do so by a domain-based rewrite rule to deliver custom themes to a user based on the URI he's using. The needed config file &amp;lt;tt&amp;gt;.htaccess&amp;lt;/tt&amp;gt; is located under &amp;lt;tt&amp;gt;apps/themes&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# Sample config for domain based login theme&lt;br /&gt;
RewriteCond %{HTTP_HOST} ^www\.domain\.com$&lt;br /&gt;
RewriteCond %{REQUEST_FILENAME} -f&lt;br /&gt;
RewriteRule ^login/(.*)$ domain_com_logintheme/$1 [L]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Best practice ==&lt;br /&gt;
&lt;br /&gt;
To be really safe, it’s best to only define your own values for the variables shown above. If this really breaks anything, we consider this a bug, please report it [https://bugs.open-xchange.com/] in our bugzilla.&lt;br /&gt;
&lt;br /&gt;
Of course, using CSS in &amp;lt;code&amp;gt;style.less&amp;lt;/code&amp;gt; file to define your own styles is also possible. Make sure to test your style in such cases more carefully. It is most likely safe to change minor things using this file, but if you plan to change any positions of larger elements, this might break the complete design. So please be careful when overwriting the default CSS rules.&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
[http://bradfrost.github.io/this-is-responsive/resources.html Responsive design]&lt;br /&gt;
&lt;br /&gt;
[http://lesscss.org/ LESS]&lt;br /&gt;
&lt;br /&gt;
== Caveats ==&lt;br /&gt;
&lt;br /&gt;
It is '''not''' recommended to change the size of elements or their position. If you really want to do so, please check on all devices and in all browsers and make sure you didn’t break anything. You even have to be careful when changing the font, because this might have effects on positioning, too.&lt;br /&gt;
&lt;br /&gt;
As mentioned before, changing colors should be safe.&lt;br /&gt;
&lt;br /&gt;
[[Category:AppSuite]]&lt;br /&gt;
[[Category:UI]]&lt;/div&gt;</summary>
		<author><name>D.haus</name></author>
	</entry>
</feed>