En janvier de cette année, jQuery a annoncé une nouvelle Registre des plugins , maintenant semblait être un bon moment pour écrire un tutoriel combinant la construction d'un plugin jQuery avec ma passion - les technologies Web en temps réel.

Grâce aux technologies Web en temps réel, il est très facile d’ajouter du contenu en direct à des pages Web précédemment statiques. Le contenu en direct peut donner vie à une page, retenir les utilisateurs et leur éviter de devoir régulièrement actualiser la page. Les mises à jour en temps réel sont généralement obtenues en vous connectant à une source de données, en vous abonnant aux données que vous souhaitez ajouter à la page, puis en mettant à jour la page à mesure que les données arrivent. Mais pourquoi ne peut-on pas y parvenir en marquant simplement une page pour identifier quelles données doivent être affichées et où? Eh bien, peut-être que c'est possible!

Le slogan de jQuery est moins écrit, faites plus . Le slogan du plugin jQuery Realtime que nous allons construire dans ce tutoriel sera moins écrit, en temps réel.

Dans ce tutoriel, nous allons créer un plug-in jQuery qui permet d'ajouter facilement du contenu en temps réel à une page en ajoutant simplement un balisage. Tout d'abord, nous couvrirons comment utiliser un service appelé Pousseur s'abonner à des données en temps réel. Nous définirons ensuite un moyen de baliser un document HTML5 avec les attributs 'data- *', de manière à ce que notre plugin jQuery temps réel puisse le consulter et le convertir en abonnements de données en temps réel. Enfin, nous allons créer le plugin jQuery qui utilisera les attributs pour s’abonner aux données et afficher instantanément les mises à jour de la page.

Si vous voulez juste plonger directement, vous pouvez voir une démo en action ou vous pouvez télécharger le code et commencez à pirater.

Les bases du pousseur

Pusher est un service hébergé qui facilite l'ajout de contenu en temps réel et d'expériences interactives aux applications Web et mobiles. Nous allons simplement vous connecter, vous abonner à certaines données et mettre à jour une page lorsque les données entrent.

Pour illustrer cela, créez un fichier appelé "example.html" et incluez la bibliothèque JavaScript Pusher du CDN Pusher. Nous savons que nous allons utiliser jQuery 2.0.0, nous devrions donc l'inclure maintenant:

Creating a realtime jQuery plugin | Webdesigner Depot

Relier

Une fois la bibliothèque JavaScript Pusher incluse, nous pouvons nous connecter à Pusher en créant une nouvelle instance «Pusher» et en transmettant une clé d'application. Créez un autre '

Note: For the tutorial we’ll use an application key that I’ve provided but for your own applications you’ll need to sign up to Pusher to get your own.

You can check that you’re connected in three different ways. You can do it manually by checking the Pusher Debug Console, if you load the page with the Pusher Debug Console open you’ll see the connection logged. The Pusher JavaScript library provides a log property that you can assign a function to and then you can manually check to make sure a connection has been established by inspecting the browser’s JavaScript console. Or you can check the connection programmatically by monitoring the connection state of the Pusher instance.

pusher_001

The Pusher Debug console

Whatever you choose to do, you’ll now be connected.

Subscribe

Pusher uses the Publish & Subscribe pattern, so to receive data from Pusher you first need to subscribe to it. Pusher uses the term channels when it comes to subscriptions, so let’s subscribe to a channel called ‘test-channel’.

As with connection state, you can check the status of a subscription in a few ways; using the Pusher Debug Console, by checking the output from ‘Pusher.log’ or by binding to the ‘pusher:subscription_succeeded’ event.

pusher_002

Using Pusher.log to log pusher-js library information

Bind to events

Those of you who use jQuery will probably be familiar with the idea of binding to events. jQuery does provide shortcuts for some events (e.g. ‘.onclick( )’) but you can also bind to events using ‘.bind(, )’. Pusher follows this convention and you can bind to events to be informed when something updates; when the connection state changes, when a subscription succeeds or when new application data is received. For this example, and with the realtime plugin, we’re interested primarily in the latter.

Let’s bind to a ‘test-event’ on the channel:

When binding to an event you simply identify the event by name and pass in a reference to a function that will be called when that event occurs (is triggered) on the channel.

If you have a Pusher account you can test that the ‘handleEvent’ function is called by using the Pusher Event Creator; enter ‘test-channel’ as the channel name, ‘test-event’ as the event name and some data (‘{ “some” : “data” }’) into the event data text area and click the submit button. You’ll then see the debug information, along with the data you entered, logged to the JavaScript console.

pusher_003 

Triggering an event from the Pusher Event Creator and logging it in the JavaScript console

Since the realtime jQuery plugin that we’re building doesn’t publish (trigger) data (it just consumes it) we won’t cover that here. But if you’re interested in finding out more checkout the Pusher server docs.

Displaying realtime updates

The next thing to consider is displaying the realtime data updates to the user.

For this we’ll need an idea for a simple application; having worked in finance for a few years I’m generally keen to avoid any type of financial example, but Bitcoin has made it interesting and relevant. So, let’s create a very simple display for showing Bitcoin prices.

Note: We’re going to use some fake data. Let’s make sure this doesn’t result in more Bitcoin panic selling!

First, let’s create some HTML where we’ll display the realtime prices. We can pre-populate the display with prices known at the time the page was loaded:

Bitcoin Fake Prices

LastLowHighVolume
BTC/USD61.157 USD51 USD95.713 USD66271 BTC / 4734629 USD

Let’s update the JavaScript to subscribe to a more appropriately named channel called ‘btc-usd’ and bind to a ‘new-price’ event:

The ‘data’ sent to the ‘handleEvent’ function should also be in a more appropriate format – here’s the JSON:

{"last": "last value","low": "low value","high": "high value","volume": "volume value"}

Now that we know this we can change the ‘handleEvent’ function to update the appropriate cell in the table:

function handleEvent( data ) {var cells = $( '#bitcoin_prices tbody tr td' );cells.eq( 1 ).text( data.last );cells.eq( 2 ).text( data.low );cells.eq( 3 ).text( data.high );cells.eq( 4 ).text( data.volume );}

If you now trigger a ‘new-price’ event on the ‘btc-usd’ channel, using the JSON we defined, the page will update to show the new values.

There are ways of both making this code nicer and, as the page grows to show more data, optimise things. But, we’re going to make it so that realtime data will be added to the page simply by applying markup.

Before we progress, let’s first add a bit of styling to the example. In the ‘’ add the following CSS:

As you can undoubtedly tell, I’m no designer. So please feel free to improve on this.

pusher_004

The “styled” Bitcoin Fake Prices application

Finally, restructure things so we’re set up for building the plugin.

  1. Create an ‘examples’ directory and within it a ‘bitcoin’ directory.
  2. Move the ‘example.html’ file to ‘examples/bitcoin’, rename it ‘index.html’.
  3. Create a ‘src’ directory at the top-level of the project.

The directory structure should now look as follows:

/
examples/
bitcoin/
index.html
src/

We’re now ready to define our realtime markup and build the realtime jQuery plugin.

Realtime markup

The first thing to highlight is that this isn’t a new idea — I worked for a company called Caplin Systems and in 2001 they had a technology known as RTML that let you markup a page so that realtime updates could be applied. The purpose here is to use jQuery to parse the page and then interpret the markup, resulting in subscriptions, event binding and ultimately live content being added to the page.

For our plugin we’ll use HTML5’s data-* attributes. These attributes don’t directly affect the layout or presentation of the page so they’re a great choice for our realtime markup.

The questions we now need to answer about the markup are:

  • Where do we put the Pusher application key?
  • How do we identify what channels should be subscribed to?
  • How do we identify the events that should be bound to on a channel?
  • How do we know what data to display in the page, and where?

The first one is relatively easy. Since we need to include our plugin JavaScript file we can add a ‘data-rt-key’ attribute to the ‘

So, from the script tag you can see we’re going to connect to Pusher using the key identified by ‘data-rt-key’. We’re going to subscribe to the ‘btc-usd’ channel and bind to the ‘new-price’ event. When an event is received we’re going to update the appropriate table cell based on the value indicated by ‘data-rt-value’; if the value of the attribute is ‘last’ then the value of the ‘last’ property is taken from the received ‘data’ object and displayed in the cell.

Hopefully what we are trying to achieve is now pretty clear. Let’s start looking at how to create a jQuery plugin.

jQuery plugin basics

The jQuery plugin creation docs are pretty good so I won’t go into the details here. We’ll simply concentrate on building the functionality that we need in our plugin.

Before we write any code we should consider how we want to use the plugin. The normal way a plugin functions is that you use jQuery to query the page, and then you execute the plugin functionality against the matched elements.

$( 'a' ).toggle();

The above code would find all ‘’ elements and then execute the ‘toggle()’ functionality on them — probably hiding all anchors, so not the most useful example you’ll ever see.

So, let’s say we would want to use the plugin as follows:

Regardons la création de la fonctionnalité attendue.

Un plugin en temps réel

Tout d'abord, créez un fichier 'realtime.jquery.js' dans le répertoire 'src'. Ce fichier contiendra la fonctionnalité du plugin. Ajoutez ensuite ce qui suit au fichier comme point de départ de notre plugin:

( function( $) {$.fn.realtime = function() {console.log( 'realtime!' );console.log( $( this ).html() );}  ;} (jQuery)); 

Nous pouvons même tester cela maintenant. Dans 'examples / bitcoin / index.html', supprimez le plugin exemple '

Si vous actualisez la page, vous verrez "realtime!" connecté à la console JavaScript avec le code HTML de la

'élément C'est génial car cela signifie que le plugin fonctionne; nous exécutons avec succès notre fonctionnalité de plug-in sur la table identifiée par le sélecteur que nous avons transmis à jQuery.

pusher_005

plugins jQuery et librairies tierces

Notre plugin temps réel s'appuie sur une bibliothèque tierce - la bibliothèque JavaScript Pusher. Pour le moment, nous l'avons inclus statiquement dans notre HTML, mais nous ne voulons pas en faire une exigence pour utiliser le plugin. Donc, chargez-le dynamiquement. jQuery permet de le faire facilement sous la forme de '.getScript ()' fonction.

Chargez donc la version 2.0 de la bibliothèque JavaScript Pusher. Nous chargerons la version hébergée HTTPS pour que les navigateurs soient satisfaits si notre plug-in est utilisé sur une page servie via HTTPS (Chrome bloque déjà les tentatives de chargement de scripts hébergés HTTP dans les pages HTTPS et Firefox le fera dans Firefox 23 ). Je vais envelopper le chargement de la bibliothèque dans une fonction comme suit:

var libraryLoaded = false;function loadPusher() {$.getScript( "https://d3dy5gmtp8yhk7.cloudfront.net/2.0/pusher.min.js" ).done( pusherLoaded ).fail( function( jqxhr, settings, exception ) {console.log( 'oh oh! ' + exception );}  );} fonction pusherLoaded (script, textStatus) {libraryLoaded = true; console.log ('pusher.min.js chargé:' + textStatus);} loadPusher (); 

Si vous rechargez la page, le message "pusher.min.js loaded: success" sera enregistré sur la console.

Comme nous développons, il est toujours bon d'avoir un moyen de journaliser les informations afin de créer à ce stade une simple fonction "log" que nous pouvons utiliser et qui se connecte simplement à la console. Nous l'utilisons maintenant et l'utilisons également pour la journalisation des événements Pusher. La source complète du plugin est maintenant:

( function( $ ) {function log( msg ) {console.log( msg );}var libraryLoaded = false;function loadPusher() {$.getScript( "https://d3dy5gmtp8yhk7.cloudfront.net/2.0/pusher.min.js" ).done( pusherLoaded ).fail( function( jqxhr, settings, exception ) {log( 'oh oh! ' + exception );}  );} fonction pusherLoaded (script, textStatus) {libraryLoaded = true; Pusher.log = log; log ('pusher.min.js chargé:' + textStatus);} $. fn.realtime = function () {log (' realtime! '); log ($ (this) .html ());}; loadPusher ();} (jQuery)); 

Vous remarquerez également que nous avons assigné la fonction 'log' à la propriété 'Pusher.log'. Cela signifie que nous pouvons voir la journalisation de la bibliothèque Pusher interne ainsi que la nôtre.

Quand devrions-nous nous connecter?

En raison de la nature asynchrone du chargement de la bibliothèque, nous ne pouvons pas garantir qu’elle aura été chargée lors de l’application de notre plug-in. Malheureusement, cela rend les choses un peu plus complexes qu'idéales, mais nous essaierons de les résoudre aussi simplement que possible.

Nous devons vérifier si la bibliothèque a été chargée - par conséquent, l'indicateur 'libraryLoaded' - et agir de manière appropriée. Si la bibliothèque a été chargée, nous pouvons nous connecter. Si ce n'est pas le cas, nous devons mettre en attente l'exécution jusqu'à ce qu'elle le fasse. De ce fait, il est plus logique de créer uniquement l'instance Pusher lorsque nous en avons vraiment besoin, c'est-à-dire lorsque nous voulons réellement nous abonner à des données.

Voyons comment nous pouvons faire cela:

var pending = [];function pusherLoaded( script, textStatus ) {libraryLoaded = true;while( pending.length !== 0 ) {var els = pending.shift();subscribe( els );}}function subscribe( els ) {}$.fn.realtime = function() {var els = this;if( libraryLoaded ) {subscribe( els );}else {pending.push( els );}};

Lorsque le plug-in est appelé, nous vérifions le drapeau 'libraryLoaded' pour voir si la bibliothèque JavaScript Pusher a été chargée. Si c'est le cas, nous sommes prêts à partir et nous pouvons nous abonner. S'il est toujours en attente, nous devons mettre en file d'attente les abonnements. Nous faisons cela en poussant la collection jQuery ('els') sur un tableau 'en attente'.

Maintenant, connectez-vous

Maintenant que nous savons que la bibliothèque JavaScript de Pusher a été chargée et que la page souhaite s'abonner aux données, nous pouvons créer notre instance "Pusher". Parce que nous voulons seulement une instance de 'Pusher' par page, nous allons suivre la Motif singleton et avoir un 'getPusher ()':

var pusher;function getPusher() {if( pusher === undefined ) {var pluginScriptTag = $("script[src$='jquery.realtime.js']");var appKey = pluginScriptTag.attr("data-rt-key");pusher = new Pusher( appKey );}return pusher;}

Cette fonction récupère la balise de script du plug-in en recherchant une balise avec un attribut 'src' qui se termine par 'jquery.realtime.js', puis obtient la valeur de l'attribut 'data-rt-key'. Il crée ensuite une nouvelle instance "Pusher", en passant la clé. Comme nous l'avons vu plus haut, la création d'une nouvelle instance 'Pusher' se traduit par une connexion à la source de nos données en cours d'établissement.

Souscrire

Nous pouvons maintenant utiliser la fonction 'getPusher ()' quand nous voulons accéder à l'instance 'Pusher'. Dans notre cas, nous voulons l'utiliser lorsque nous analysons les éléments pour déterminer les abonnements.

Mettez à jour la fonction d’espace réservé «subscribe» et ajoutez les fonctions supplémentaires indiquées ci-dessous:

function subscribe( els ) {var channelEls = els.find( "*[data-rt-channel]" );log( 'found ' + channelEls.size() + ' channels' );channelEls.each( subscribeChannel );}function subscribeChannel( index, el ) {el = $( el );var pusher = getPusher();var channelName = el.attr( 'data-rt-channel' );var channel = pusher.subscribe( channelName );}function find( els, selector ) {var topLevelEls = els.filter( selector );var childEls = els.find( selector );return topLevelEls.add( childEls );}

La fonction 'find' est une fonction utilitaire permettant d’obtenir tous les éléments d’une collection existante correspondant à un sélecteur donné en utilisant '.filtre()', avec tous les descendants des éléments en utilisant '.trouver()'. Nous utilisons cette fonction pour trouver les éléments marqués pour représenter les abonnements aux canaux (attribut 'data-rt-channel') et pour chacun, nous appelons 'subscribeChannel'. Cette fonction extrait le nom du canal auquel vous voulez vous abonner et utilise la valeur en appelant «pusher.subscribe (channelName)» pour vous abonner au canal.

Lier

Nous devons ensuite trouver tous les éléments marqués pour représenter des événements (attribut 'data-rt-event') pour être liés à:

function subscribeChannel( index, el ) {el = $( el );var pusher = getPusher();var channelName = el.attr( 'data-rt-channel' );var channel = pusher.subscribe( channelName );var eventEls = find( el, '*[data-rt-event]' );log( 'found ' + eventEls.size() + ' events' );eventEls.each( function( i, el) {bind( el, channel );} );}function bind( el, channel ) {el = $( el );var eventName = el.attr( 'data-rt-event' );channel.bind( eventName, function( data ) {displayUpdate( el, data );} );}function displayUpdate( el, data ) {}

Pour chaque élément d'événement, nous appelons notre propre fonction 'bind' qui se lie à l'événement sur le canal en utilisant 'channel.bind (eventName, eventHandler)'. La fonction de gestionnaire d'événement est une petite fermeture qui nous permet de transmettre la mise à jour des données, lorsqu'elle est reçue, et l'élément événement à une fonction 'displayUpdate'.

Si nous lançons ceci maintenant, nous pouvons voir à partir de la journalisation qu'une connexion est établie, nous trouvons un canal et nous y abonnons, et trouvons un événement auquel nous devons nous connecter.

pusher_006

jQuery temps réel marquant la recherche d'abonnement au canal et la liaison d'événement

Afficher la mise à jour

Lorsque le gestionnaire d'événement est appelé, nous devons trouver le nom de chaque propriété sur l'objet "data" (par exemple, last, low, high et volume) envoyé avec la mise à jour et rechercher tous les éléments marqués de ce nom.

function bind( el, channel ) {el = $( el );var eventName = el.attr( 'data-rt-event' );channel.bind( eventName, function( data ) {displayUpdate( el, data );} );}function displayUpdate( el, data ) {for( var propName in data ) {var value = data[ propName ];var updateEls = find( el, '*[data-rt-value="' + propName + '"]' );log( 'found ' + updateEls.size() + ' "' + propName + '" elements to update' );updateEls.text( value );}}

Nous bouclons l'objet 'data' et obtenons le nom de chaque propriété. Une fois que nous connaissons le nom de la propriété ('propName'), nous pouvons trouver les éléments associés et mettre à jour leur valeur de texte avec la nouvelle valeur de données. Pour l'instant, nous n'allons pas supporter les objets avec n'importe quel type de hiérarchie - nous voulons juste un niveau de paires de clés et de valeurs.

Si vous actualisez maintenant la page et déclenchez un événement à partir de Pusher Event Creator, les nouvelles données seront instantanément affichées dans la page.

Avez-vous travaillé avec un service de données en direct? Quelles leçons avez-vous apprises? Faites le nous savoir dans les commentaires.

Image / vignette en vedette, image de données en direct via Shutterstock.