SlideShare une entreprise Scribd logo
1  sur  16
ERYEM
CAMPS
Dashboard Yammer sous SharePoint
Partie 2/2
1
Présenté par :
Barbar MITRI bmitri@eryem.com
Philippe SFEIR psfeir@eryem.com
Levallois 15/01/2015
Plan
1. Présentation du sujet
1. Concept de Single Page Application
2. Architecture applicative
2. Démo et architecture projet
3. Conclusion
4. Références
2
Single Page Application
3
Une nouvelle façon d’envisager la navigation web
Serveur Web
Cloud
navigateur client
Chargement de la
page d’accueil:
charge une fois pour
toutes l’ensemble
des fichiers html, js,
css
Action utilisateur: insertion dynamique de
données dans la page, jamais de
rechargement complet de la page
4
Architecture applicative
4
Un niveau de portabilité inédit !!
1°)
2°)
3°)
6°)
Serveur
SharePoint
Poste client
1 => Connexion à l’application
SharePoint
2 => Sharepoint renvoie le contenu
Statique au client : html + CSS + JS
3=> avec l’autorisation de
Sharepoint on redirige le client
vers le serveur Proxy (NodeJS)
4=> proxy solicite le serveur de
base de données
5=> réponse de la base
6=> le proxy retourne les données
vers le client
proxy nodeJS
SQL Server
4°)
5°)
Démo
5
Démo
6
Données globales
Clic sur un login -> navigation vers la
page des données par utilisateur
Démo
7
Données par utilisateur
Démo
8
Exemple de graphe obtenu: nombre de messages postés par
utilisateur du réseau Yammer
9
Architecture du projet Durandal
dossier « app » lui-même composé d’un
dossier « services » contenant le fichier
avec les méthodes de service, d’un dossier
« viewmodels », d’un dossier « views »
dossier « css » contenant les feuilles de
style
dossier « lib » contenant les librairies js
Durandal et les plugins js
10
Index.html
<!DOCTYPE html>
<html>
<head>
<title>Durandal</title>
<!– références vers fichiers css -->
<script type="text/javascript"
src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1','packages':['c
orechart']}]}"></script>
</head>
<body>
<div id="applicationHost">
<div class="splash">
<div class="message">
Je charge le contenu statique: pages html, scripts js, fichier css, <b> UNE FOIS POUR TOUTES
!!</b>
</div>
<i class="fa fa-spinner fa-spin"></i>
</div>
</div>
<script src="lib/require/require.js" data-main="app/main"></script>
</body>
</html>
référence l’api
google utilisée pour
dessiner les
graphiques
charge require.js et
l’attribut data-main
indique le fichier js
servant de point
d’entrée, ici main.js
11
main.js requirejs.config({
paths: {
'text': '../lib/require/text',
'durandal':'../lib/durandal/js',
'plugins' : '../lib/durandal/js/plugins',
'transitions' : '../lib/durandal/js/transitions',
'knockout': '../lib/knockout/knockout-3.1.0',
'bootstrap': '../lib/bootstrap/js/bootstrap',
'jquery': '../lib/jquery/jquery-1.9.1',
'services': '../app/services',
'async': '../lib/durandal/js/plugins/async',
'propertyParser': '../lib/durandal/js/plugins/propertyParser',
'goog': '../lib/durandal/js/plugins/goog'
}
});
define('gmaps', ['async!http://maps.google.com/maps/api/js?sensor=false'],
function () {
console.log('Google maps loaded');
return window.google.maps;
});
define(['durandal/system', 'durandal/app', 'durandal/viewLocator'], function (system, app, viewLocator) {
//>>excludeStart("build", true);
system.debug(true);
//>>excludeEnd("build");
app.title = 'Durandal Starter Kit';
app.configurePlugins({
router:true,
dialog: true
});
app.start().then(function() {
viewLocator.useConvention();
app.setRoot('viewmodels/shell', 'entrance');
});
});
permet d’enregistrer un
raccourci pour chaque fichier
javascript ou dossier utilisé
permet de charger les fichiers
js référencés de manière
asynchrone et d’exécuter le
code personnalisé dans le
callback, avec un espace de
nommage isolé de l’espace de
nommage global de javascript
app.setRoot définit la page
d’accueil de l’application, ici
shell.html
12
shell.js
define(['plugins/router', 'durandal/app'], function (router, app) {
return {
router: router,
search: function() {
//It's really easy to show a message box.
//You can add custom options too. Also, it returns a promise for the user's response.
app.showMessage('Search not yet implemented...');
},
activate: function () {
router.map([
{ route: '', title:'Welcome', moduleId: 'viewmodels/welcome', nav: true },
{ route: 'flickr', moduleId: 'viewmodels/flickr', nav: true },
{ route: 'yamhisto', moduleId: 'viewmodels/yamhisto', nav: true },
{ route: 'map', moduleId: 'viewmodels/mapgoogle', nav: false },
{ route: 'chart', moduleId: 'viewmodels/chart', nav: true },
{ route: 'userStats/:UserId', moduleId: 'viewmodels/userStats', nav: false }
]).buildNavigationModel();
return router.activate();
}
};
});
shell.js est le viewmodel
javascript associé à la
page d’accueil.
La fonction activate
s’exécute à chaque fois
que la page est atteinte.
router.map permet de
définir des routes pour la
navigation côté client.
Lorsque le client requête
une route, commençant
par #, le fichier javascript
correspondant est
exécuté et la page html
chargée. Aucun appel
serveur n’est effectué,
l’ensemble des fichiers
étant déjà chargés dans
le navigateur client.
13
chart.js
var activate = function () {
jQuery.when(services.getStatMsgByUser(), services.getStatFileByUser()).then(function
(msgByUser, fileByUser) {
msgArray[0] = ['Nom', 'Nombre de messages'];
fileArray[0] = ['Nom', 'Nombre de fichiers partagés'];
jQuery.each(msgByUser[0], function (index, item) {
msgArray[index + 1] = [item.name, item.number_msg];
});
jQuery.each(fileByUser[0], function (index, item) {
fileArray[index + 1] = [item.name, item.number_file];
});
});
};
var compositionComplete = function (view, parent) {
var msgData = google.visualization.arrayToDataTable(msgArray);
var fileData = google.visualization.arrayToDataTable(fileArray);
var msgOptions = {
title: 'Nombre de messages par utilisateur'
};
var fileOptions = {
title: 'Nombre de fichiers partagés par utilisateur'
};
var msgChart = new
google.visualization.PieChart(document.getElementById('msgChart'));
msgChart.draw(msgData, msgOptions);
var fileChart = new
google.visualization.PieChart(document.getElementById('fileChart'));
fileChart.draw(fileData, fileOptions);
};
chart.js est le fichier
associé à la route #chart.
La fonction activate est
exécutée en premier
chaque fois que la page
est requêtée. Elle
construit un tableau avec
les données Yammer
récupérées par les web
services.
La fonction
compositionComplete
est exécutée après
activate, une fois que
l’ensemble des éléments
HTML du DOM a été
chargé dans le
navigateur. C’est dans
cette fonction que sont
réalisées les
manipulation sur le DOM
permettant d’afficher les
graphiques grâce aux
APIs de google.
14
Chart.html
<section>
<h2 data-bind="html: displayName"></h2>
<table>
<tr>
<td>
<div id="msgChart" style="width: 900px; height: 500px;"></div>
</td>
<td>
<div id="fileChart" style="width: 900px; height: 500px;"></div>
</td>
</tr>
</table>
</section>
Le fichier chart.html contient le squelette html de la page. Les méthodes google appelées dans le
viewmodel vont insérer les graphes dans les deux div.
Conclusion
15
Avec DurandalJS on peut construire des applications
JavaScript dynamiques et simples.
Inclus : JQuery , Knockout et RequireJS
Riche en fonctionnalités et multiplateforme
Références
16
Tutoriels et exemples javascript – jQuery:
http://www.w3schools.com/
Tutoriels et exemples knockoutJS (MVVM):
http://learn.knockoutjs.com/
Exemples DurandalJS:
http://durandaljs.com/
Proxy : http://nodejs.org/

Contenu connexe

Similaire à Tableau de bord Yammer sous SharePoint 2013

Café Numérique Arlon S03#02: Je code mon blog (EU code week Arlon)
Café Numérique Arlon S03#02: Je code mon blog (EU code week Arlon)Café Numérique Arlon S03#02: Je code mon blog (EU code week Arlon)
Café Numérique Arlon S03#02: Je code mon blog (EU code week Arlon)Café Numérique Arlon
 
XebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic Ladeu
XebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic LadeuXebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic Ladeu
XebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic LadeuPublicis Sapient Engineering
 
Partie 2: Angular
Partie 2: AngularPartie 2: Angular
Partie 2: AngularHabib Ayad
 
Flex, une techno RIA incontournable pour les futures app web ?
Flex, une techno RIA incontournable pour les futures app web ?Flex, une techno RIA incontournable pour les futures app web ?
Flex, une techno RIA incontournable pour les futures app web ?GreenIvory
 
OWF12/HTML 5 local storage , olivier thomas, cto at webtyss
OWF12/HTML 5 local storage , olivier thomas, cto at webtyssOWF12/HTML 5 local storage , olivier thomas, cto at webtyss
OWF12/HTML 5 local storage , olivier thomas, cto at webtyssParis Open Source Summit
 
Paris ember js lab #6 - Taking over server-side rendering websites
Paris ember js lab #6 - Taking over server-side rendering websitesParis ember js lab #6 - Taking over server-side rendering websites
Paris ember js lab #6 - Taking over server-side rendering websitesGuillaume Gérard
 
Play framework - Human Talks Grenoble - 12.02.2013
Play framework - Human Talks Grenoble - 12.02.2013Play framework - Human Talks Grenoble - 12.02.2013
Play framework - Human Talks Grenoble - 12.02.2013Xavier NOPRE
 
La mobilité dans Drupal
La mobilité dans DrupalLa mobilité dans Drupal
La mobilité dans DrupalAdyax
 
1-Introduction JQuery.pptx
1-Introduction JQuery.pptx1-Introduction JQuery.pptx
1-Introduction JQuery.pptxlaabid1
 
Activity
ActivityActivity
Activitydido
 
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniterAtsé François-Xavier KOBON
 
Introduction à Angularjs
Introduction à AngularjsIntroduction à Angularjs
Introduction à AngularjsRossi Oddet
 
Codedarmor 2012 - 06/03 - HTML5, CSS3 et Javascript
Codedarmor 2012 - 06/03 - HTML5, CSS3 et JavascriptCodedarmor 2012 - 06/03 - HTML5, CSS3 et Javascript
Codedarmor 2012 - 06/03 - HTML5, CSS3 et Javascriptcodedarmor
 
Nouveautés html5 et css3 dans internet explorer 10
Nouveautés html5 et css3 dans internet explorer 10Nouveautés html5 et css3 dans internet explorer 10
Nouveautés html5 et css3 dans internet explorer 10davrous
 
Introduction aux RIA (Rich Internet Applications)
Introduction aux RIA (Rich Internet Applications)Introduction aux RIA (Rich Internet Applications)
Introduction aux RIA (Rich Internet Applications)Tugdual Grall
 
Node.js, le pavé dans la mare
Node.js, le pavé dans la mareNode.js, le pavé dans la mare
Node.js, le pavé dans la mareValtech
 
Aperçu de RequireJS
Aperçu de RequireJSAperçu de RequireJS
Aperçu de RequireJSVISEO
 

Similaire à Tableau de bord Yammer sous SharePoint 2013 (20)

HTML5 en projet
HTML5 en projetHTML5 en projet
HTML5 en projet
 
Café Numérique Arlon S03#02: Je code mon blog (EU code week Arlon)
Café Numérique Arlon S03#02: Je code mon blog (EU code week Arlon)Café Numérique Arlon S03#02: Je code mon blog (EU code week Arlon)
Café Numérique Arlon S03#02: Je code mon blog (EU code week Arlon)
 
Yammer et nodejs
Yammer et nodejsYammer et nodejs
Yammer et nodejs
 
Backbonejs presentation
Backbonejs presentationBackbonejs presentation
Backbonejs presentation
 
XebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic Ladeu
XebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic LadeuXebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic Ladeu
XebiCon'17 : Entrevue avec Vue.js - Thomas Champion et Ludovic Ladeu
 
Partie 2: Angular
Partie 2: AngularPartie 2: Angular
Partie 2: Angular
 
Flex, une techno RIA incontournable pour les futures app web ?
Flex, une techno RIA incontournable pour les futures app web ?Flex, une techno RIA incontournable pour les futures app web ?
Flex, une techno RIA incontournable pour les futures app web ?
 
OWF12/HTML 5 local storage , olivier thomas, cto at webtyss
OWF12/HTML 5 local storage , olivier thomas, cto at webtyssOWF12/HTML 5 local storage , olivier thomas, cto at webtyss
OWF12/HTML 5 local storage , olivier thomas, cto at webtyss
 
Paris ember js lab #6 - Taking over server-side rendering websites
Paris ember js lab #6 - Taking over server-side rendering websitesParis ember js lab #6 - Taking over server-side rendering websites
Paris ember js lab #6 - Taking over server-side rendering websites
 
Play framework - Human Talks Grenoble - 12.02.2013
Play framework - Human Talks Grenoble - 12.02.2013Play framework - Human Talks Grenoble - 12.02.2013
Play framework - Human Talks Grenoble - 12.02.2013
 
La mobilité dans Drupal
La mobilité dans DrupalLa mobilité dans Drupal
La mobilité dans Drupal
 
1-Introduction JQuery.pptx
1-Introduction JQuery.pptx1-Introduction JQuery.pptx
1-Introduction JQuery.pptx
 
Activity
ActivityActivity
Activity
 
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
#J2Code2018 - Mettez du feu à vos applications avec CodeIgniter
 
Introduction à Angularjs
Introduction à AngularjsIntroduction à Angularjs
Introduction à Angularjs
 
Codedarmor 2012 - 06/03 - HTML5, CSS3 et Javascript
Codedarmor 2012 - 06/03 - HTML5, CSS3 et JavascriptCodedarmor 2012 - 06/03 - HTML5, CSS3 et Javascript
Codedarmor 2012 - 06/03 - HTML5, CSS3 et Javascript
 
Nouveautés html5 et css3 dans internet explorer 10
Nouveautés html5 et css3 dans internet explorer 10Nouveautés html5 et css3 dans internet explorer 10
Nouveautés html5 et css3 dans internet explorer 10
 
Introduction aux RIA (Rich Internet Applications)
Introduction aux RIA (Rich Internet Applications)Introduction aux RIA (Rich Internet Applications)
Introduction aux RIA (Rich Internet Applications)
 
Node.js, le pavé dans la mare
Node.js, le pavé dans la mareNode.js, le pavé dans la mare
Node.js, le pavé dans la mare
 
Aperçu de RequireJS
Aperçu de RequireJSAperçu de RequireJS
Aperçu de RequireJS
 

Tableau de bord Yammer sous SharePoint 2013

  • 1. ERYEM CAMPS Dashboard Yammer sous SharePoint Partie 2/2 1 Présenté par : Barbar MITRI bmitri@eryem.com Philippe SFEIR psfeir@eryem.com Levallois 15/01/2015
  • 2. Plan 1. Présentation du sujet 1. Concept de Single Page Application 2. Architecture applicative 2. Démo et architecture projet 3. Conclusion 4. Références 2
  • 3. Single Page Application 3 Une nouvelle façon d’envisager la navigation web Serveur Web Cloud navigateur client Chargement de la page d’accueil: charge une fois pour toutes l’ensemble des fichiers html, js, css Action utilisateur: insertion dynamique de données dans la page, jamais de rechargement complet de la page
  • 4. 4 Architecture applicative 4 Un niveau de portabilité inédit !! 1°) 2°) 3°) 6°) Serveur SharePoint Poste client 1 => Connexion à l’application SharePoint 2 => Sharepoint renvoie le contenu Statique au client : html + CSS + JS 3=> avec l’autorisation de Sharepoint on redirige le client vers le serveur Proxy (NodeJS) 4=> proxy solicite le serveur de base de données 5=> réponse de la base 6=> le proxy retourne les données vers le client proxy nodeJS SQL Server 4°) 5°)
  • 6. Démo 6 Données globales Clic sur un login -> navigation vers la page des données par utilisateur
  • 8. Démo 8 Exemple de graphe obtenu: nombre de messages postés par utilisateur du réseau Yammer
  • 9. 9 Architecture du projet Durandal dossier « app » lui-même composé d’un dossier « services » contenant le fichier avec les méthodes de service, d’un dossier « viewmodels », d’un dossier « views » dossier « css » contenant les feuilles de style dossier « lib » contenant les librairies js Durandal et les plugins js
  • 10. 10 Index.html <!DOCTYPE html> <html> <head> <title>Durandal</title> <!– références vers fichiers css --> <script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1','packages':['c orechart']}]}"></script> </head> <body> <div id="applicationHost"> <div class="splash"> <div class="message"> Je charge le contenu statique: pages html, scripts js, fichier css, <b> UNE FOIS POUR TOUTES !!</b> </div> <i class="fa fa-spinner fa-spin"></i> </div> </div> <script src="lib/require/require.js" data-main="app/main"></script> </body> </html> référence l’api google utilisée pour dessiner les graphiques charge require.js et l’attribut data-main indique le fichier js servant de point d’entrée, ici main.js
  • 11. 11 main.js requirejs.config({ paths: { 'text': '../lib/require/text', 'durandal':'../lib/durandal/js', 'plugins' : '../lib/durandal/js/plugins', 'transitions' : '../lib/durandal/js/transitions', 'knockout': '../lib/knockout/knockout-3.1.0', 'bootstrap': '../lib/bootstrap/js/bootstrap', 'jquery': '../lib/jquery/jquery-1.9.1', 'services': '../app/services', 'async': '../lib/durandal/js/plugins/async', 'propertyParser': '../lib/durandal/js/plugins/propertyParser', 'goog': '../lib/durandal/js/plugins/goog' } }); define('gmaps', ['async!http://maps.google.com/maps/api/js?sensor=false'], function () { console.log('Google maps loaded'); return window.google.maps; }); define(['durandal/system', 'durandal/app', 'durandal/viewLocator'], function (system, app, viewLocator) { //>>excludeStart("build", true); system.debug(true); //>>excludeEnd("build"); app.title = 'Durandal Starter Kit'; app.configurePlugins({ router:true, dialog: true }); app.start().then(function() { viewLocator.useConvention(); app.setRoot('viewmodels/shell', 'entrance'); }); }); permet d’enregistrer un raccourci pour chaque fichier javascript ou dossier utilisé permet de charger les fichiers js référencés de manière asynchrone et d’exécuter le code personnalisé dans le callback, avec un espace de nommage isolé de l’espace de nommage global de javascript app.setRoot définit la page d’accueil de l’application, ici shell.html
  • 12. 12 shell.js define(['plugins/router', 'durandal/app'], function (router, app) { return { router: router, search: function() { //It's really easy to show a message box. //You can add custom options too. Also, it returns a promise for the user's response. app.showMessage('Search not yet implemented...'); }, activate: function () { router.map([ { route: '', title:'Welcome', moduleId: 'viewmodels/welcome', nav: true }, { route: 'flickr', moduleId: 'viewmodels/flickr', nav: true }, { route: 'yamhisto', moduleId: 'viewmodels/yamhisto', nav: true }, { route: 'map', moduleId: 'viewmodels/mapgoogle', nav: false }, { route: 'chart', moduleId: 'viewmodels/chart', nav: true }, { route: 'userStats/:UserId', moduleId: 'viewmodels/userStats', nav: false } ]).buildNavigationModel(); return router.activate(); } }; }); shell.js est le viewmodel javascript associé à la page d’accueil. La fonction activate s’exécute à chaque fois que la page est atteinte. router.map permet de définir des routes pour la navigation côté client. Lorsque le client requête une route, commençant par #, le fichier javascript correspondant est exécuté et la page html chargée. Aucun appel serveur n’est effectué, l’ensemble des fichiers étant déjà chargés dans le navigateur client.
  • 13. 13 chart.js var activate = function () { jQuery.when(services.getStatMsgByUser(), services.getStatFileByUser()).then(function (msgByUser, fileByUser) { msgArray[0] = ['Nom', 'Nombre de messages']; fileArray[0] = ['Nom', 'Nombre de fichiers partagés']; jQuery.each(msgByUser[0], function (index, item) { msgArray[index + 1] = [item.name, item.number_msg]; }); jQuery.each(fileByUser[0], function (index, item) { fileArray[index + 1] = [item.name, item.number_file]; }); }); }; var compositionComplete = function (view, parent) { var msgData = google.visualization.arrayToDataTable(msgArray); var fileData = google.visualization.arrayToDataTable(fileArray); var msgOptions = { title: 'Nombre de messages par utilisateur' }; var fileOptions = { title: 'Nombre de fichiers partagés par utilisateur' }; var msgChart = new google.visualization.PieChart(document.getElementById('msgChart')); msgChart.draw(msgData, msgOptions); var fileChart = new google.visualization.PieChart(document.getElementById('fileChart')); fileChart.draw(fileData, fileOptions); }; chart.js est le fichier associé à la route #chart. La fonction activate est exécutée en premier chaque fois que la page est requêtée. Elle construit un tableau avec les données Yammer récupérées par les web services. La fonction compositionComplete est exécutée après activate, une fois que l’ensemble des éléments HTML du DOM a été chargé dans le navigateur. C’est dans cette fonction que sont réalisées les manipulation sur le DOM permettant d’afficher les graphiques grâce aux APIs de google.
  • 14. 14 Chart.html <section> <h2 data-bind="html: displayName"></h2> <table> <tr> <td> <div id="msgChart" style="width: 900px; height: 500px;"></div> </td> <td> <div id="fileChart" style="width: 900px; height: 500px;"></div> </td> </tr> </table> </section> Le fichier chart.html contient le squelette html de la page. Les méthodes google appelées dans le viewmodel vont insérer les graphes dans les deux div.
  • 15. Conclusion 15 Avec DurandalJS on peut construire des applications JavaScript dynamiques et simples. Inclus : JQuery , Knockout et RequireJS Riche en fonctionnalités et multiplateforme
  • 16. Références 16 Tutoriels et exemples javascript – jQuery: http://www.w3schools.com/ Tutoriels et exemples knockoutJS (MVVM): http://learn.knockoutjs.com/ Exemples DurandalJS: http://durandaljs.com/ Proxy : http://nodejs.org/

Notes de l'éditeur

  1. 1 => connexion à l’application Sharepoint 2 => Sharepoint renvoie le contenu Statique au client : html + CSS + JS 3=> avec l’autorisation de Sharepoint on redirige le client vers le serveur Proxy (NodeJS) 4=> proxy solicite le serveur de base de données 5=> réponse de la base 6=> le proxy retourne les données vers le client
  2. Le code suivant: <script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1','packages':['corechart']}]}"></script> référence l’api google utilisée pour dessiner les graphiques. Le code suivant: <script src="lib/require/require.js" data-main="app/main"></script> charge require.js et l’attribut data-main indique le fichier js servant de point d’entrée, ici main.js
  3. requirejs.config permet d’enregistrer un raccourci pour chaque fichier javascript ou dossier utilisé define permet de charger les fichiers js référencés de manière asynchrone et d’exécuter le code personnalisé dans le callback, avec un espace de nommage isolé de l’espace de nommage global de javascript. app.setRoot définit la page d’accueil de l’application, ici shell.html
  4. shell.js est le viewmodel javascript associé à la page d’accueil. La fonction activate s’exécute à chaque fois que la page est atteinte. router.map permet de définir des routes pour la navigation côté client. Lorsque le client requête une route, commençant par #, le fichier javascript correspondant est exécuté et la page html chargée. Aucun appel serveur n’est effectué, l’ensemble des fichiers étant déjà chargés dans le navigateur client.
  5. chart.js est le fichier associé à la route #chart. La fonction activate est exécutée en premier chaque fois que la page est requêtée. Elle construit un tableau avec les données Yammer récupérées par les web services. La fonction compositionComplete est exécutée après activate, une fois que l’ensemble des éléments HTML du DOM a été chargé dans le navigateur. C’est dans cette fonction que sont réalisées les manipulation sur le DOM permettant d’afficher les graphiques grâce aux APIs de google.