JavaScript

AMD

Les développeurs doivent utiliser le standard AMD (Définition du module asynchrone) pour écrire du code JavaScript dans Elgg.

Ici, nous allons décrire la création et l’exécution des modules AMD. La documentation RequireJS pour définir des modules peut également être utile.

Exécuter un module dans la page en cours

Il est facile de dire à Elgg de charger un module existant dans la page en cours :

<?php
elgg_require_js("myplugin/say_hello");

Du côté client, cela chargera le module de manière asynchrone, chargera toutes les dépendances, et exécutera la fonction de définition du module si elle existe.

Définir le Module

Ici, nous définissons un module de base qui modifie la page, en passant une « fonction de définition » à define() :

// in views/default/myplugin/say_hello.js

define(function(require) {
    var elgg = require("elgg");
    var $ = require("jquery");

    $('body').append(elgg.echo('hello_world'));
});

Le nom du module est déterminé par le nom de vue, qui est ici monplugin/say_hello.js. Nous retirons l’extension .js, pour conserver monplugin/say_hello.

Avertissement

La fonction de définition doit avoir un argument nommé require.

Rendre les modules dépendants d’autres modules

Ci-dessous nous refactorisons un peu de sorte que le module dépende d’un nouveau module monplugin/hello pour fournir la salutation :

// in views/default/myplugin/hello.js

define(function(require) {
    var elgg = require("elgg");

    return elgg.echo('hello_world');
});
// in views/default/myplugin/say_hello.js

define(function(require) {
    var $ = require("jquery");
    var hello = require("myplugin/hello");

    $('body').append(hello);
});

Passer des paramètres aux modules

Les hooks de plugin elgg.data

Le module elgg fournit un objet elgg.data qui est peuplé à partir de deux hooks côté serveur :

  • elgg.data, site : Ceci filtre un tableau associatif de données spécifiques au site, transmises au client et mises en cache.

  • elgg.data, page : Ceci filtre un tableau associatif de données non mises en cache, et spécifiques à la page transmise au client.

Passons quelques données au module :

<?php

function myplugin_config_site($hook, $type, $value, $params) {
    // this will be cached client-side
    $value['myplugin']['api'] = elgg_get_site_url() . 'myplugin-api';
    $value['myplugin']['key'] = 'none';
    return $value;
}

function myplugin_config_page($hook, $type, $value, $params) {
    $user = elgg_get_logged_in_user_entity();
    if ($user) {
        $value['myplugin']['key'] = $user->myplugin_api_key;
        return $value;
    }
}

elgg_register_plugin_hook_handler('elgg.data', 'site', 'myplugin_config_site');
elgg_register_plugin_hook_handler('elgg.data', 'page', 'myplugin_config_page');
define(function(require) {
    var elgg = require("elgg");

    var api = elgg.data.myplugin.api;
    var key = elgg.data.myplugin.key; // "none" or a user's key

    // ...
});

Note

Dans elgg.data les données de la page remplacent les données du site. Notez également que json_encode() est utilisé pour copier les données côté client, de sorte que les données doivent être encodables en JSON.

Créer un module de configuration

Vous pouvez utiliser un module PHP pour transmettre des valeurs à partir du serveur. Pour créer le module monplugin/settings, créez le fichier de la vue views/default/monplugin/settings.js.php (notez la double extension .js.php).

<?php

// this will be cached client-side
$settings = [
    'api' => elgg_get_site_url() . 'myplugin-api',
    'key' => null,
];
?>
define(<?php echo json_encode($settings); ?>);

Vous devez également enregistrer manuellement la vue en tant que ressource externe :

<?php
// note the view name does not include ".php"
elgg_register_simplecache_view('myplugin/settings.js');

Note

La vue PHP est mise en cache, vous devez donc traiter la sortie comme statique (la même pour tous les utilisateurs) et éviter toute logique spécifique à la session.

Définir l’URL d’un module

Vous pouvez avoir un script AMD en dehors de vos vues que vous souhaitez mettre à disposition en tant que module.

La meilleure façon d’y parvenir est de configurer le chemin d’accès au fichier à l’aide du fichier views.php dans la racine de votre plugin :

<?php // views.php
return [
    'default' => [
        'underscore.js' => 'vendor/bower-asset/underscore/underscore.min.js',
    ],
];

Si vous avez copié le script directement dans votre plugin au lieu de le gérer avec Composer, vous pouvez utiliser quelque chose comme ceci à la place :

<?php // views.php
return [
    'default' => [
        'underscore.js' => __DIR__ . '/bower_components/underscore/underscore.min.js',
    ],
];

Voilà ! Elgg chargera maintenant ce fichier chaque fois que le module « underscore » est requis.

Utiliser des bibliothèques JS traditionnelles comme modules

Il est possible de prendre en charge les bibliothèques JavaScript qui ne se déclarent pas comme modules AMD (c’est-à-dire qu’elles déclarent plutôt des variables globales) si vous les intégrez via des shims en définissant exports et deps dans elgg_define_js :

// set the path, define its dependencies, and what value it returns
elgg_define_js('jquery.form', [
    'deps' => ['jquery'],
    'exports' => 'jQuery.fn.ajaxForm',
]);

Lorsque cela est demandé côté client :

  1. Le module jQuery est chargé, car il est marqué comme une dépendance.

  2. https://elgg.example.org/cache/125235034/views/default/jquery.form.js est chargé et exécuté.

  3. La valeur de window.jQuery.fn.ajaxForm est renvoyée par le module.

Avertissement

Les appels à elgg_define_js() doivent être faits dans un gestionnaire d’événement init, system.

Quelques points à noter

  1. N’utilisez plus elgg.provide() ni d’autres moyens pour attacher du code à elgg ou à d’autres objets globaux. Utilisez des modules.

  2. Renvoyez la valeur du module au lieu de l’ajouter à une variable globale.

  3. Les fichiers statiques (.js, .css,etc.) sont automatiquement minifiés et mis en cache par le système simplecache de Elgg.

  4. La configuration est également mise en cache dans le simplecache et ne doit pas s’appuyer sur des valeurs spécifiques à l’utilisateur comme get_language().

Démarrer votre plugin

Pour ajouter des fonctionnalités à chaque page ou vous assurer que vos gestionnaires de hooks sont enregistrés assez tôt, vous pouvez créer un module de démarrage pour votre plugin, avec le nom boot/<plugin_id>.

// in views/default/boot/example.js

define(function(require) {
    var elgg = require("elgg");
    var Plugin = require("elgg/Plugin");

    // plugin logic
    function my_init() { ... }

    return new Plugin({
        // executed in order of plugin priority
        init: function () {
            elgg.register_hook_handler("init", "system", my_init, 400);
        }
    });
});

Lorsque votre plugin est actif, ce module sera automatiquement chargé sur chaque page. D’autres modules peuvent dépendre de elgg/init pour s’assurer que tous les modules de démarrage sont chargés.

Chaque module de démarrage doit renvoyer une instance de elgg/Plugin. Le constructeur doit recevoir un objet avec une fonction dans la clef init. La fonction init sera appelée selon l’ordre du plugin dans la zone d’administration d’Elgg.

Note

Bien que cela ne soit pas strictement nécessaire, vous pouvez utiliser l’événement init, system pour contrôler quand votre code d’initialisation s’exécute par rapport à d’autres modules.

Avertissement

Un module de démarrage (boot) ne peut pas dépendre des modules elgg/init ou elgg/ready.

Modules fournis avec Elgg

Modules jquery et jquery-ui

Vous devez faire dépendre de ces modules pour utiliser les méthodes $ ou $.ui. À l’avenir, Elgg pourrait cesser de les charger par défaut.

Module elgg

elgg.echo()

Traduisez le texte de l’interface

elgg.echo('example:text', ['arg1']);

elgg.system_message()

Affichez un message d’état à l’utilisateur.

elgg.system_message(elgg.echo('success'));

elgg.register_error()

Affiche un message d’erreur à l’utilisateur.

elgg.register_error(elgg.echo('error'));

elgg.normalize_url()

Normalise une URL par rapport à la racine elgg :

// "http://localhost/elgg/blog"
elgg.normalize_url('/blog');

elgg.forward()

Redirige vers une nouvelle page.

elgg.forward('/blog');

Cette fonction normalise automatiquement l’URL.

elgg.parse_url()

Analyse et découpe une URL en ses composants :

// returns {
//   fragment: "fragment",
//   host: "community.elgg.org",
//   path: "/file.php",
//   query: "arg=val"
// }
elgg.parse_url('http://community.elgg.org/file.php?arg=val#fragment');

elgg.get_page_owner_guid()

Récupère le GUID du propriétaire de la page actuelle.

elgg.register_hook_handler()

Enregistrez un gestionnaire de hook avec le système d’événements. Pour de meilleurs résultats, faites-le dans un module de démarrage plugin.

// boot module: /views/default/boot/example.js
define(function (require) {
    var elgg = require('elgg');
    var Plugin = require('elgg/Plugin');

    elgg.register_hook_handler('foo', 'bar', function () { ... });

    return new Plugin();
});

elgg.trigger_hook()

Émet un hook d’événement dans le système d’événements. Pour de meilleurs résultats faites-le dépendre du module elgg/init.

// old
value = elgg.trigger_hook('my_plugin:filter', 'value', {}, value);

define(function (require) {
    require('elgg/init');
    var elgg = require('elgg');

    value = elgg.trigger_hook('my_plugin:filter', 'value', {}, value);
});

elgg.security.refreshToken()

Forcer le rafraîchissement de tous les jetons XSRF sur la page.

Par défaut, ceci est automatiquement appelé toutes les 5 minutes.

Cela nécessite un jeton de sécurité valide dans 1.8, mais pas dans 1.9.

L’utilisateur sera averti si sa session a expiré.

elgg.security.addToken()

Ajoute un jeton de sécurité à un objet, une URL ou une chaîne de requête :

// returns {
//   __elgg_token: "1468dc44c5b437f34423e2d55acfdd87",
//   __elgg_ts: 1328143779,
//   other: "data"
// }
elgg.security.addToken({'other': 'data'});

// returns: "action/add?__elgg_ts=1328144079&__elgg_token=55fd9c2d7f5075d11e722358afd5fde2"
elgg.security.addToken("action/add");

// returns "?arg=val&__elgg_ts=1328144079&__elgg_token=55fd9c2d7f5075d11e722358afd5fde2"
elgg.security.addToken("?arg=val");

elgg.get_logged_in_user_entity()

Renvoie l’utilisateur connecté sous le forme d’un objet JS ElggUser.

elgg.get_logged_in_user_guid()

Renvoie le GUID de l’utilisateur connecté.

elgg.is_logged_in()

True si l’utilisateur est connecté.

elgg.is_admin_logged_in()

True si l’utilisateur est connecté et est administrateur.

elgg.config.get_language()

Récupère la langue de la page actuelle.

Un certain nombre de valeurs de configuration sont définies dans l’objet elgg :

// The root of the website.
elgg.config.wwwroot;
// The default site language.
elgg.config.language;
// The current page's viewtype
elgg.config.viewtype;
// The Elgg version (YYYYMMDDXX).
elgg.config.version;
// The Elgg release (X.Y.Z).
elgg.config.release;

Module elgg/Ajax

Voir la page Ajax pour plus de détails.

Module elgg/init

elgg/init charge et initialise tous les modules de démarrage dans l’ordre de priorité et déclenche le hook [init, system].

Ajoutez ce module aux exigences (require) de ce module pour vous assurer que tous les plugins sont prêts.

Module elgg/Plugin

Utilisé pour créer un module de démarrage boot.

Module elgg/ready

elgg/ready charge et initialise tous les modules de démarrage des plugins dans l’ordre de priorité.

Ajoutez ce module aux exigences (require) de ce module pour vous assurer que tous les plugins sont prêts.

Module elgg/spinner

Le module elgg/spinner peut être utilisé pour créer un indicateur de chargement Ajax positionné en haut de la fenêtre.

define(function (require) {
   var spinner = require('elgg/spinner');

   elgg.action('friend/add', {
       beforeSend: spinner.start,
       complete: spinner.stop,
       success: function (json) {
           // ...
       }
   });
});

Note

Le module elgg/Ajax utilise le spinner par défaut.

Module elgg/popup

Le module elgg/popup peut être utilisé pour afficher une superposition (overlay) placée relativement à son ancre (déclencheur).

Le module elgg/popup est chargé par défaut, et lier un module popup à une ancre est aussi simple que d’ajouter l’attribut rel="popup" et de définir le module cible avec un attribut href (ou data-href). Le positionnement du module popup peut être défini avec l’attribut data-position de l’élément déclencheur.

echo elgg_format_element('div', [
   'class' => 'elgg-module-popup hidden',
   'id' => 'popup-module',
], 'Popup module content');

// Simple anchor
echo elgg_view('output/url', [
   'href' => '#popup-module',
   'text' => 'Show popup',
   'rel' => 'popup',
]);

// Button with custom positioning of the popup
echo elgg_format_element('button', [
   'rel' => 'popup',
   'class' => 'elgg-button elgg-button-submit',
   'text' => 'Show popup',
   'data-href' => '#popup-module',
   'data-position' => json_encode([
      'my' => 'center bottom',
      'at' => 'center top',
   ]),
]);

Le module elgg/popup vous permet de créer des éléments d’interface utilisateur/UX plus complexes. Vous pouvez ouvrir et fermer les modules contextuels via le code :

define(function(require) {
   var $ = require('jquery');
   $(document).on('click', '.elgg-button-popup', function(e) {

      e.preventDefault();

      var $trigger = $(this);
      var $target = $('#my-target');
              var $close = $target.find('.close');

      require(['elgg/popup'], function(popup) {
                popup.open($trigger, $target, {
                       'collision': 'fit none'
                });

        $close.on('click', popup.close);
              });
   });
});

Vous pouvez utiliser le hook plugin getOptions, ui.popup pour manipuler la position du popup avant qu’il ne soit ouvert. Vous pouvez utiliser les événements jQuery open et close pour manipuler le module popup après son ouverture ou sa fermeture.

define(function(require) {

   var elgg = require('elgg');
   var $ = require('jquery');

   $('#my-target').on('open', function() {
      var $module = $(this);
      var $trigger = $module.data('trigger');

      elgg.ajax('ajax/view/my_module', {
         beforeSend: function() {
            $trigger.hide();
            $module.html('').addClass('elgg-ajax-loader');
         },
         success: function(output) {
            $module.removeClass('elgg-ajax-loader').html(output);
         }
      });
   }).on('close', function() {
      var $trigger = $(this).data('trigger');
      $trigger.show();
   });
});

Les modules popups ouverts contiennent toujours les données suivantes auxquelles on peut accéder via $.data() :

  • trigger - élément jQuery utilisé pour déclencher l’ouverture du module popup

  • position - Objet définissant la position du module popup qui a été passé à $.position()

Par défaut, l’élément target sera ajouté à $('body'), modifiant ainsi la hiérarchie DOM. Si vous devez conserver la position DOM du module popup, vous pouvez ajouter la classe .elgg-popup-inline à votre déclencheur.

Module elgg/widgets

Plugins qui chargent une disposition widget via Ajax devraient s’initialiser via ce module :

require(['elgg/widgets'], function (widgets) {
    widgets.init();
});

Module elgg/lightbox

Elgg est distribué avec la bibliothèque jQuery Colorbox. Veuillez consulter http://www.jacklmoore.com/colorbox pour plus d’informations sur les options de cette lightbox.

Utilisez les classes suivantes pour lier vos éléments d’ancrage à des boîtes surgissantes lightbox :

  • elgg-lightbox - charge une ressource HTML

  • elgg-lightbox-photo - charge une ressource de type image (devrait être utilisé pour éviter d’afficher les octets d’image bruts au lieu de la balise img)

  • elgg-lightbox-inline - affiche un élément HTML en ligne dans une boîte surgissante lightbox

  • elgg-lightbox-iframe - charge une ressource dans une iframe

Vous pouvez appliquer des options de colorbox à un élément individuel elgg-lightbox en définissant l’attribut data-colorbox-opts avec un objet de paramètres JSON.

echo elgg_view('output/url', [
   'text' => 'Open lightbox',
   'href' => 'ajax/view/my_view',
   'class' => 'elgg-lightbox',
   'data-colorbox-opts' => json_encode([
      'width' => '300px',
   ])
]);

Utilisez le hook plugin "getOptions", "ui.lightbox" pour filtrer les options passées à $.colorbox() chaque fois qu’une lightbox est ouverte. Notez que le gestionnaire de hook doit dépendre du module AMD elgg/init.

Le module AMD elgg/lightbox devrait être utilisé pour ouvrir et fermer la lightbox de manière promgrammatique :

define(function(require) {
   var lightbox = require('elgg/lightbox');
   var spinner = require('elgg/spinner');

   lightbox.open({
      html: '<p>Hello world!</p>',
      onClosed: function() {
         lightbox.open({
            onLoad: spinner.start,
            onComplete: spinner.stop,
            photo: true,
            href: 'https://elgg.org/cache/1457904417/default/community_theme/graphics/logo.png',
         });
      }
   });
});

Pour prendre en charge des ensembles de galerie (via l’attribut rel), vous devez lier colorbox directement à un sélecteur spécifique (notez que cela ignorera data-colorbox-opts sur tous les éléments d’un ensemble) :

require(['elgg/lightbox'], function(lightbox) {
   var options = {
      photo: true,
      width: 500
   };
   lightbox.bind('a[rel="my-gallery"]', options, false); // 3rd attribute ensures binding is done without proxies
});

Vous pouvez également redimensionner la lightbox via le code si nécessaire :

define(function(require) {
   var lightbox = require('elgg/lightbox');

   lightbox.resize({
      width: '300px'
   });
});

Module elgg/ckeditor

Ce module peut être utilisé pour ajouter un éditeur WYSIWYG à un textarea (nécessite l’activation du plugin ckeditor). Notez que le WYSIWYG sera automatiquement attaché à toutes les instances de .elgg-input-longtext.

require(['elgg/ckeditor'], function (elggCKEditor) {
   elggCKEditor.bind('#my-text-area');

   // Toggle CKEditor
   elggCKEditor.toggle('#my-text-area');

   // Focus on CKEditor input
   elggCKEditor.focus('#my-text-area');
   // or
   $('#my-text-area').trigger('focus');

   // Reset CKEditor input
   elggCKEditor.reset('#my-text-area');
   // or
   $('#my-text-area').trigger('reset');

});

Composant d’onglets en ligne

Le composant d’onglets en ligne déclenche un événement open chaque fois qu’un onglet est ouvert et, en cas d’onglets ajax, une fois le chargement terminé :

// Add custom animation to tab content
    require(['jquery', 'elgg/ready'], function($) {
            $(document).on('open', '.theme-sandbox-tab-callback', function() {
                    $(this).find('a').text('Clicked!');
                    $(this).data('target').hide().show('slide', {
                            duration: 2000,
                            direction: 'right',
                            complete: function() {
                                    alert('Thank you for clicking. We hope you enjoyed the show!');
                                    $(this).css('display', ''); // .show() adds display property
                            }
                    });
            });
    });

Scripts traditionnels

Bien que nous vous recommandions fortement d’utiliser des modules AMD, vous pouvez enregistrer des scripts avec elgg_register_js :

elgg_register_js('jquery', $cdnjs_url);

Ceci remplacera toutes les URLs précédemment enregistrées sous ce nom.

Chargez une bibliothèque sur la page actuelle avec elgg_load_js :

elgg_load_js('jquery');

Cela chargera la bibliothèque dans le pied de page. Vous devez utiliser la fonction require() pour dépendre de modules comme elgg et query.

Avertissement

L’utilisation de scripts en ligne n’est PAS PRISE EN CHARGE car :
  • Ils ne sont pas vérifiables (maintenance)

  • Ils ne peuvent pas être mis en cache (performances)

  • Ils empêchent l’utilisation de la stratégie de sécurité du contenu (sécurité)

  • Ils empêchent les scripts d’être chargés avec defer ou async (performance)

Les scripts en ligne dans le noyau ou dans les plugins joints sont considérés comme des bogues hérités.

Hooks

Le moteur JS dispose d’un système de hooks similaire aux hooks de plugin du moteur PHP : des hooks sont déclenchés et des plugins peuvent enregistrer des fonctions pour réagir ou pour modifier l’information. Il n’y a pas de concept d’événement Elgg dans le moteur JS ; tout dans le moteur JS est implémenté sous forme de hook.

Enregistrer des gestionnaires de hook

Les fonctions de gestionnaire sont enregistrées à l’aide de elgg.register_hook_handler(). Plusieurs gestionnaires peuvent être enregistrés pour le même hook.

L’exemple suivant enregistre la fonction handleFoo pour le hook foo, bar.

define(function (require) {
    var elgg = require('elgg');
    var Plugin = require('elgg/Plugin');

    function handleFoo(hook, type, params, value) {
        // do something
    }

    elgg.register_hook_handler('foo', 'bar', handleFoo);

    return new Plugin();
});

La fonction de gestion

Le gestionnaire va recevoir 4 arguments :

  • hook - Le nom du hook

  • type - Le type de hook

  • params - Un objet ou un ensemble de paramètres propres au hook

  • value - La valeur actuelle

La valeur value passera par chaque hook. Selon le hook, les fonctions de rappel peuvent simplement réagir ou modifier les données.

Déclencher des hooks personnalisés

Les plugins peuvent déclencher leurs propres hooks :

define(function(require) {
    require('elgg/init');
    var elgg = require('elgg');

    elgg.trigger_hook('name', 'type', {params}, "value");
});

Note

Soyez conscient du timing. Si vous ne faites pas dépendre de elgg/init, d’autres plugins n’auront peut-être pas eu la possibilité d’enregistrer leurs gestionnaires.

Hooks disponibles

init, system

Les plugins devraient enregistrer leurs fonctions d’initialisation via ce hook. Il est déclenché après le chargement des JS de Elgg et l’initialisation de tous les modules de démarrage des plugins. Faites-le dépendre du module elgg/init pour être sûr que l’initialisation est bien terminée.

ready, system

Ce hook est déclenché lorsque le système a complètement démarré (après init). Faites-le dépendre du module elgg/ready pour être sûr que le démarrage est bien terminé.

getOptions, ui.popup

Ce hook est déclenché pour les affichages surgissants ("rel"="popup") et permet des options de placement personnalisées.

getOptions, ui.lightbox

Ce hook peut être utilisé pour filtrer les options transmises à $.colorbox()

config, ckeditor

Cela filtre l’objet de configuration CKEditor. Enregsitrez un gestionnaire pour ce hook dans un module de démarrage du plugin. Les valeurs par défaut sont visibles dans le module elgg/ckeditor/config.

prepare, ckeditor

Ce crochet peut être utilisé pour modifier globalement CKEDITOR. Vous pouvez utiliser ce hook pour enregistrer de nouveaux plugins CKEditor et ajouter des liaisons d’événements (event bindings).

ajax_request_data, *

Ceci filtre les données de requête envoyées par le module elgg/Ajax. Voir Ajax pour plus d’informations.

ajax_response_data, *

Ceci filtre les données de réponse retournées aux utilisateurs du module elgg/Ajax. Voir Ajax pour plus de détails.

insert, editor

Ce hook est déclenché par le plugin embed et peut être utilisé pour filtrer le contenu avant qu’il ne soit inséré dans le textarea. Ce hook peut également être utilisé par les éditeurs WYSIWYG pour insérer du contenu à l’aide de leur propre API (dans ce cas, le gestionnaire devrait renvoyer false). Voir le plugin ckeditor pour un exemple.

Actifs tierce-partie (assets)

Nous vous recommandons de gérer les scripts et les styles tiers avec Composer. Le noyau Elgg utilise fxp/composer-asset-plugin à cette fin. Ce plugin vous permet de récupérer les dépendances des référentiels de package Bower ou NPM, à l’aide de l’outil de ligne de commande Composer.

Par exemple, pour inclure jQuery, vous pouvez exécuter les commandes composer suivantes :

composer global require fxp/composer-asset-plugin:~1.1.4
composer require bower-asset/jquery:~2.0

Note

fxp/composer-asset-plugin doit être installé globalement ! Consultez https://github.com/francoispluchino/composer-asset-plugin pour plus d’informations.