JavaScript

AMD

Les développeurs doivent utiliser le standard AMD (« Asynchronous Module Definition » ou Définition du module asynchrone) pour écrire du code JavaScript dans Elgg.

Ici, nous allons décrire la création et l’exécution de 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 aisé d’indiquer à 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, s’il en dispose d’une.

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(['jquery', 'elgg'], function($, elgg) {
    $('body').append(elgg.echo('hello_world'));
});

Le nom du module est déterminé par le nom de vue, qui est ici myplugin/say_hello.js. Nous retirons l’extension .js, pour conserver myplugin/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 factorisons 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(['elgg'], function(elgg) {
    return elgg.echo('hello_world');
});
// in views/default/myplugin/say_hello.js

define(['jquery', 'myplugin/hello'], function($, 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(\Elgg\Hook $hook) {
    $value = $hook->getValue();

    // 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(\Elgg\Hook $hook) {
    $user = elgg_get_logged_in_user_entity();
    if (!$user) {
            return;
    }

    $value = $hook->getValue();

    $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(['elgg'], function(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 myplugin/settings, créez le fichier de la vue views/default/myplugin/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 de la section views du fichier elgg-plugin.php dans la racine de votre plugin :

<?php // elgg-plugin.php
return [
    'views' => [
            'default' => [
                'underscore.js' => 'vendor/npm-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 // elgg-plugin.php
return [
    'views' => [
            'default' => [
                'underscore.js' => __DIR__ . '/node_modules/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. Renvoie 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_current_language().

Modules fournis avec Elgg

Module elgg

elgg.echo()

Traduisez le texte de l’interface

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

elgg.system_message()

Affiche 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 de 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()

Enregistre un gestionnaire de hook avec le système d’événements.

elgg.trigger_hook()

Émet un hook d’événement dans le système d’événements.

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

elgg.security.refreshToken()

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

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

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 la forme d’un objet JS ElggUser.

elgg.get_logged_in_user_guid()

Renvoie le GUID de l’utilisateur connecté.

elgg.is_logged_in()

Vrai si l’utilisateur est connecté.

elgg.is_admin_logged_in()

Vrai 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/spinner

Le module elgg/spinner peut être utilisé pour créer un indicateur de chargement fixé en haut de la fenêtre. Cela peut être utilisé pour indiquer aux utilisateurs que le système exécute une tâche plus longue. L’utilisation des fonctionnalités ajax de elgg/Ajax le fait par défaut. Vous pouvez également l’utiliser dans votre propre code.

define(['elgg/spinner'], function (spinner) {
    spinner.start();
    // your code
    spinner.stop();
});

Module elgg/popup

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

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(['jquery', 'elgg/popup'], function($, popup) {
   $(document).on('click', '.elgg-button-popup', function(e) {

      e.preventDefault();

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

      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 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(['jquery', 'elgg/Ajax'], function($, Ajax) {

   $('#my-target').on('open', function() {
      var $module = $(this);
      var $trigger = $module.data('trigger');
      var ajax = new 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 il est possible d’accéder via $.data() :

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

  • position - Un 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

Des plugins qui chargent une mise en page 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 https://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.

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

define(['elgg/lightbox', 'elgg/spinner'], function(lightbox, 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(['elgg/lightbox'], function(lightbox) {
   lightbox.resize({
      width: '300px'
   });
});

Si vous souhaitez que votre contenu soit chargé par le module AMD elgg/Ajax, qui charge automatiquement les dépendances JS, vous pouvez passer l’option ajaxLoadWithDependencies

define(['elgg/lightbox'], function(lightbox) {
   lightbox.open({
      href: 'some/view/with/js/dependencies',
      ajaxLoadWithDependencies: true
   });
});

Module elgg/ckeditor

Ce module peut être utilisé pour ajouter un éditeur WYSIWYG à un textarea (nécessite que le plugin ckeditor soit activé). 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'], 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 recommandions fortement d’utiliser des modules AMD et qu’il n’existe pas d’API Elgg pour le chargement des scripts, vous pouvez enregistrer des scripts dans un gestionnaire de hook pour ajouter des éléments aux liens de l’entête ;

elgg_register_plugin_hook_handler('head', 'page', $callback);

Hooks

Le moteur JS dispose d’un système de hooks similaire aux hooks 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 gestionnaires sont enregistrées à l’aide de elgg.register_hook_handler(). Plusieurs gestionnaires peuvent être enregistrés pour le même hook.

La fonction gestionnaire - handler

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(['elgg'], function(elgg) {
    elgg.trigger_hook('name', 'type', {params}, "value");
});

Hooks disponibles

init, system

Les plugins devraient enregistrer leurs fonctions d’initialisation via ce hook. Il est déclenché après que les JS de Elgg sont chargés, et une fois que tous les modules de démarrage - boot - des plugins sont initialisés.

getOptions, ui.popup

Ce hook est déclenché pour les affichages surgissants - popups ("rel"="popup") et permet des options de positionnement 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. Enregistrez un gestionnaire pour ce hook dans le module de démarrage du plugin. Les valeurs par défaut sont visibles dans le module elgg/ckeditor/config.

prepare, ckeditor

Ce hook 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 demandes de données envoyées par le module elgg/Ajax. Voir Ajax pour plus de détails. Le hook doit vérifier si les données sont un objet simple ou une instance de FormData pour récupérer les valeurs à l’aide de la bonne API.

ajax_response_data, *

Ceci filtre les données de réponse retournées aux utilisateurs par le 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 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 des scripts et des styles tiers avec Composer. Le composer.json de Elgg est configuré pour installer des dépendances à partir des référentiels de packages NPM ou Yarn à l’aide de l’outil de ligne de commande Composer. La configuration de base installe les actifs à partir de Asset Packagist (un référentiel géré par la communauté Yii).

Alternativement, vous pouvez installer fxp/composer-asset-plugin globalement pour obtenir les mêmes résultats, mais l’installation et la mise à jour prennent beaucoup plus de temps.

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

composer require npm-asset/jquery:~2.0

Si vous utilisez un projet de démarrage - starter-project - ou que vous utilisez Elgg sous forme de dépendance d’un projet composer personnalisé, mettez à jour votre composer.json avec la configuration suivante :

{
    "repositories": [
        {
            "type": "composer",
            "url": "https://asset-packagist.org"
        }
    ],
        "config": {
        "fxp-asset": {
            "enabled": false
        }
    },
}

Vous pouvez trouver des informations supplémentaires sur le site de Asset Packagist.