PhoneGap Construire un lecteur de flux - Logique d'application

Ceci est la deuxième partie de la série sur Lecteur de flux Audero. Dans cet article, nous allons approfondir la logique métier de notre application et fournir des informations supplémentaires sur les plugins et l'API utilisés pour notre projet..


1. Présentation du plugin et de l'API

Le plugin de notification

A plusieurs endroits dans le Lecteur de flux Audero application, nous allons utiliser le alerte() méthode du Notification Plugin. Le mode d'affichage de l'alerte dépend de la plate-forme sur laquelle l'application sera exécutée. En fait, la plupart des systèmes d’exploitation pris en charge utilisent une boîte de dialogue native, mais d’autres, comme Bada 2.x, utilisent le navigateur classique. alerte() fonction, qui est moins personnalisable. Cette méthode accepte jusqu'à quatre paramètres:

  1. message: Une chaîne contenant le message à afficher.
  2. alertCallback: Un rappel à invoquer lorsque la boîte de dialogue d'alerte est fermée.
  3. Titre: Le titre du dialogue (la valeur par défaut est "alert").
  4. buttonName: Le texte du bouton inclus dans la boîte de dialogue (la valeur par défaut est "OK")

N'oubliez pas que Windows Phone 7 et 8 ne disposent pas d'une alerte de navigateur intégrée. Donc, si vous voulez utiliser alerte ('message');, vous devez assigner window.alert = navigator.notification.alert.

Le plugin InAppBrowser

Dans la première partie de cette série, j'ai mentionné qu'un point intéressant de la page des crédits est l'attribut target = "_ blank" appliqué aux liens. Cette section expliquera comment le openLinksInApp () méthode du Application travaux de classe.

InAppBrowser est un navigateur Web qui apparaît dans votre application lorsque vous utilisez le window.open appel. Comme je l'ai dit dans la première partie, à partir de la version 2.3.0, deux nouvelles méthodes sont disponibles: executeScript () et insertCSS (). Actuellement, ce plugin fournit au total les cinq méthodes suivantes:

  • addEventListener (): Permet à l'utilisateur d'écouter trois événements (loadstart, arrêt de chargement, et sortie), et pour attacher une fonction qui s'exécute dès que ces événements sont déclenchés.
  • removeEventListener (): Utilisé pour supprimer un auditeur précédemment attaché.
  • Fermer(): Utilisé pour fermer la fenêtre InAppBrowser.
  • executeScript (): Permet l’injection de code JavaScript dans le InAppBrowser la fenêtre.
  • executeScript (): Permet l’injection de code CSS dans le InAppBrowser la fenêtre.

Si vous n'avez pas utilisé Cordova pendant plusieurs mois ou si vous vous en tenez à la version 2.0.0, vous vous souviendrez que, par défaut, il ouvrait des liens externes dans le même Cordova WebView qui exécutait l'application. Par conséquent, une fois qu'une page externe a été visitée, la dernière page affichée était affichée telle qu'elle était avant que l'utilisateur ne la quitte. A partir de cette version, ce n'est plus le comportement standard. En fait, les liens externes sont désormais ouverts à l'aide de Cordova WebView si l'URL est dans la liste blanche de votre application. Les URL qui ne figurent pas sur votre liste blanche sont ouvertes à l'aide du plug-in InAppBrowser (pour plus d'informations à ce sujet dans la documentation). Mais qu'est-ce que cela signifie concrètement? Cela signifie que si vous ne gérez pas les liens correctement et que les utilisateurs de votre application cliquent sur un lien, puis reviennent à l'application, tous les outils jQuery Mobile ou autres améliorations de ce type sont perdus. Cela se produit car tous les fichiers CSS et JavaScript sont chargés uniquement dans la page principale et les URL suivantes sont chargées à l'aide d'AJAX (le système par défaut adopté par jQuery Mobile)..

Le correctif de ce problème est implémenté dans le openLinksInApp () méthode. En fait, la solution est d’attraper les clics sur tous les liens externes en définissant la target = "_ blank" attribut, empêchant le comportement par défaut non désiré et ouvrant les liens en utilisant le window.open () méthode. Pour que cette solution fonctionne, vous devrez définir une liste blanche dans le fichier de configuration..

L'API Google Feed

Avant de parler des classes du Lecteur de flux Audero, nous devons explorer le monde magique de l'API Google Feed et de l'interface JSON de Google Feed, car nous les utiliserons dans la fonctionnalité principale de notre application. Comme je l'ai indiqué dans la première partie de cette série, l'interface analyse un flux RSS ou ATOM et renvoie un objet JSON unifié et facile à analyser. Bien sûr, nous pouvons gérer cet objet JSON à l'aide de JavaScript..

Cette interface prend en charge deux types de requête: Rechercher un flux et Charger un flux. Le premier recherche les flux en fonction des mots-clés donnés passés en tant qu'argument, tandis que le second recherche les flux en fonction de l'URL d'un flux fourni. Dans notre application, nous n'utiliserons que la fonctionnalité Load Feed.

Chaque demande adressée à cette API Google doit envoyer au moins deux paramètres: v et q. Oui, ils ont des noms très cryptiques! Le premier paramètre, v, spécifie le numéro de version du protocole. Au moment d'écrire ces lignes, la seule valeur valide est "1.0". Dans le second paramètre, q, nous passons l'URL à analyser. En plus de ceux-ci, notre application utilisera également le num paramètre. La documentation spécifie le nombre d'entrées à charger à partir du flux spécifié par q. La valeur -1 indique le nombre maximal d'entrées prises en charge, actuellement 100. Par défaut, le fil de chargement renvoie quatre résultats.. Il est donc essentiel de mettre en œuvre notre fonctionnalité de chargement de 10 entrées par défaut, puis d’augmenter de 10 à chaque fois que l’utilisateur doit en montrer plus..

Maintenant que vous savez comment interroger le service Google, il est important de clarifier le résultat. Si l'URL que nous avons fournie était correcte, nous trouverons les entrées du flux à l'intérieur du fichier. responseData.feed.entries propriété. Chaque entrée contient de nombreuses informations, mais nous n'en utiliserons que quelques-unes. En particulier, nous allons imprimer les propriétés suivantes:

  • Titre: Le titre de l'entrée.
  • lien: L'URL de la version HTML de l'entrée.
  • auteur: L'auteur de l'entrée.
  • contentSnippet: Extrait de moins de 120 caractères de l'attribut content. L'extrait de code ne contient aucune balise HTML..

Les informations que j'ai fournies ci-dessus suffisent pour notre application, mais si vous souhaitez en savoir plus, consultez la documentation de Google Feed..


2. Construire la classe d'alimentation

Cette section décrira les Alimentation classe et ses méthodes, tous inclus dans la feed.js fichier. Comme je l'ai indiqué dans la partie précédente, nous n'enregistrerons que deux champs pour chaque flux: le titre et l'URL. Donc, cette classe accepte ces deux points de données en tant que paramètres. À l'intérieur, nous créons deux propriétés privées: _db et _nom de la table. N'oubliez pas que JavaScript ne comporte pas de modificateurs de visibilité des propriétés et des méthodes, nous émulons donc des données privées..

Le premier est un raccourci pour le stockage local propriété du la fenêtre objet. Il est utilisé pour accéder aux méthodes exposées par le plug-in de stockage, sur lequel notre application est basée, et que nous utiliserons pour stocker les flux. La seconde est une chaîne contenant le nom de la clé où nous allons sauvegarder les données. En fait, rappelant les spécifications de stockage, il stocke les données en utilisant un format clé-valeur. Par conséquent, pour stocker notre tableau de flux, nous devons le JSON-ify. C'est exactement ce que notre enregistrer() méthode va faire. De la même manière, pour récupérer les données, nous devons analyser une chaîne JSON afin de la transformer en objet. Cette tâche est accomplie par le charge() méthode. Ces méthodes sont les deux seules qui doivent figurer dans la définition de la classe car elles utilisent des propriétés privées..

La section relative de la feed.js le fichier est listé ci-dessous:

 fonction Feed (nom, URL) var _db = window.localStorage; var _tableName = 'feed'; this.name = name; this.url = url; this.save = function (flux) _db.setItem (_tableName, JSON.stringify (flux)); ; this.load = function () return JSON.parse (_db.getItem (_tableName)); ; 

Autour de ces deux méthodes simples, nous allons créer d’autres méthodes courantes. Plus précisément, nous allons construire des méthodes d'instance telles que ajouter(), ajouter un nouveau flux, effacer(), supprimer un flux, et comparer aux(), comparer une instance de flux avec un autre flux. En plus de cela, nous allons aussi développer des méthodes statiques telles que getFeeds () pour récupérer tous les flux de stockage, getFeed () pour n'en récupérer qu'un, et comparer() comparer deux objets.

Les méthodes de comparaison valent un peu de discussion pour comprendre Comment nous les comparerons. Je vais sauter la description de comparer aux() car il ne fait rien mais appelle sa contrepartie statique, comparer(), cela fait le travail. Dans celui-ci, nous allons d’abord tester si l’une des valeurs données est de type null. Au cas où aucun d'entre eux ne ressemble à null, nous comparerons leur nom lexicographiquement et, s'ils sont égaux, nous comparerons leur URL. Cependant, comme vous le découvrirez plus tard, nous obligerons l'utilisateur à ne jamais avoir deux flux avec le même nom ou la même URL..
le comparer() La méthode est importante car elle définit la manière dont nous comparons deux flux, ce qui est essentiel pour déterminer le mode de tri des flux dans le list-feeds.html page. En fait, nous utiliserons le natif Trier() méthode array qui accepte un paramètre facultatif, une fonction, qui définit l'ordre de tri du tableau en fonction de ses valeurs de retour.

Le code qui implémente ce que j'ai décrit est le suivant:

 Feed.prototype.compareTo = fonction (autre) return Feed.compare (this, autre); ; Feed.compare = function (feed, other) if (other == null) return 1;  if (feed == null) return -1;  var test = feed.name.localeCompare (other.name); retourner (test === 0)? feed.url.localeCompare (other.url): test; ;

En plus des méthodes vues jusqu'à présent, nous allons créer deux méthodes de recherche que nous utiliserons pour trouver et supprimer un flux donné: searchByName () et searchByUrl (). La dernière méthode que je veux mettre en évidence est getIndex (), et c'est celui utilisé pour récupérer l'index d'un certain fichier.

Maintenant que nous avons découvert tous les détails de cette classe, je peux lister tout le code source du fichier:

 fonction Feed (nom, URL) var _db = window.localStorage; var _tableName = 'feed'; this.name = name; this.url = url; this.save = function (flux) _db.setItem (_tableName, JSON.stringify (flux)); ; this.load = function () return JSON.parse (_db.getItem (_tableName)); ;  Feed.prototype.add = function () var index = Feed.getIndex (this); var feeds = Feed.getFeeds (); if (index === false) feeds.push (this);  else feeds [index] = this;  this.save (flux); ; Feed.prototype.delete = function () var index = Feed.getIndex (this); var feeds = Feed.getFeeds (); if (index! == false) feeds.splice (index, 1); this.save (nourrit);  renvoyer les flux; ; Feed.prototype.compareTo = fonction (autre) return Feed.compare (this, autre); ; Feed.compare = function (feed, other) if (other == null) return 1;  if (feed == null) return -1;  var test = feed.name.localeCompare (other.name); retourner (test === 0)? feed.url.localeCompare (other.url): test; ; Feed.getFeeds = function () var feeds = new Feed (). Load (); return (feeds === null)? []: se nourrit; ; Feed.getFeed = fonction (alimentation) var index = Feed.getIndex (alimentation); if (index === false) retourne null;  var feed = Feed.getFeeds () [index]; renvoyer le nouveau flux (feed.name, feed.url); ; Feed.getIndex = fonction (feed) var feeds = Feed.getFeeds (); pour (var i = 0; i < feeds.length; i++)  if (feed.compareTo(feeds[i]) === 0)  return i;   return false; ; Feed.deleteFeeds = function ()  new Feed().save([]); ; Feed.searchByName = function (name)  var feeds = Feed.getFeeds(); for (var i = 0; i < feeds.length; i++)  if (feeds[i].name === name)  return new Feed(feeds[i].name, feeds[i].url);   return false; ; Feed.searchByUrl = function (url)  var feeds = Feed.getFeeds(); for (var i = 0; i < feeds.length; i++)  if (feeds[i].url === url)  return new Feed(feeds[i].name, feeds[i].url);   return false; ;

3. Construire la classe d'application

Cette section aborde la deuxième et dernière classe du projet., Application, contenu à l'intérieur du application.js fichier. Son but est d’initialiser la mise en page des pages, d’attacher des événements aux éléments de la page de l’application et Alimentation classe pour sauvegarder, charger et récupérer les flux.

Cette classe est organisée pour avoir le point d’entrée dans le initApplication () méthode. Elle est appelée dès que Cordova a été initialisée et que ses API sont prêtes à fonctionner. Dans cette méthode, nous attachons un gestionnaire spécifique à chaque initialisation de page afin de pouvoir gérer les événements déclenchés par leurs widgets. Dans ce document, nous appellerons également Application.openLinksInApp () pour des raisons discutées précédemment. De plus, pour améliorer l'expérience utilisateur, nous allons saisir chaque pression du bouton de retour physique (s'il existe) pour rediriger l'utilisateur vers la page d'accueil de notre application..

La fonction principale de notre application est initShowFeedPage () car il utilise l'interface JSON de Google Feed. Avant d'exécuter la demande auprès du service, nous comptons le nombre d'entrées déjà chargées (currentEntries variable) et calcule le nombre d'entrées que le service doit extraire (entréesToShow variable). Ensuite, nous allons lancer la requête AJAX, en utilisant jQuery ajax () En même temps, nous montrons le widget de chargement de page à l'utilisateur. Lorsque le rappel de succès est exécuté, nous testons d'abord si le nombre d'entrées renvoyées est identique au nombre déjà affiché. Dans ce cas, nous affichons le message "Aucune autre entrée à charger". Sinon, nous les ajoutons à la liste et actualisons le widget accordéon ($ list.collapsibleset ('refresh')). Avec chaque entrée, nous attachons également un gestionnaire au bouton créé. Ainsi, si la connexion est désactivée, un message s'affiche au lieu d'accéder à la page..

Finalement, le updateIcons () la méthode sera discutée dans la prochaine et dernière partie de la série.

Le code qui implémente la classe discutée est répertorié ci-dessous:

 var Application = initApplication: function () $ (document) .on ('pageinit', '# add-feed-page', function () Application.initAddFeedPage ();) .on ('pageinit', ' # list-feeds-page ', function () Application.initListFeedPage ();) .on (' pageinit ',' # show-feed-page ', function () var url = this.getAttribute (' data- url '). remplacer (/(.*?) url = / g, "); Application.initShowFeedPage (url);) .on (' pageinit ',' # aurelio-page ', function () Application.initAurelioPage ();) .on ('backbutton', function () $ .mobile.changePage ('index.html');); Application.openLinksInApp ();, initAddFeedPage: function () $ ('# add-feed-form '). submit (function (event) event.preventDefault (); var feedName = $ (' # feed-name '). val (). trim (); var feedUrl = $ (' # feed -url '). val (). trim (); if (feedName === ") navigator.notification.alert (' Le champ Nom est obligatoire et ne peut pas être vide ', function () ,' Erreur '); return false; if (feedUrl === ") navigator.notification.alert ('Le champ URL est obligatoire et ne peut pas être vide', function ()  , 'Erreur'); retourne faux;  if (Feed.searchByName (feedName) === false && Feed.searchByUrl (feedUrl) === false) var feed = new Feed (feedName (feedName, feedUrl)); feed.add (); navigator.notification.alert ('Flux enregistré correctement', function () $ .mobile.changePage ('index.html');, 'Success');  else navigator.notification.alert ('Flux non enregistré! Le nom ou l'URL spécifiée est déjà utilisé', function () , 'Erreur');  return false; ); , initListFeedPage: function () var $ feedsList = $ ('# feeds-list'); var items = Feed.getFeeds (); var htmlItems = "; $ feedsList.empty (); items = items.sort (Feed.compare); pour (var i = 0; i < items.length; i++)  htmlItems += '
  • '+ items [i] .name +'
  • '; $ feedsList.append (htmlItems) .listview ('refresh'); , initShowFeedPage: function (url) var step = 10; var loadFeed = function () var currentEntries = $ ('# entrées-de-flux'). find ('div [data-role = collapsible]'). length; var entriesToShow = currentEntries + step; $ .ajax (url: 'https://ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=' + entryToShow + '& q =' + encodeURI (url), dataType: 'json' , beforeSend: function () $ .mobile.loading ('show', text: 'Veuillez patienter pendant la récupération des données…', textVisible: true);, success: function (data) var $ list = $ ( '# flux-entrées'); if (data.responseData === null) navigator.notification.alert ('Impossible d'extraire le flux. URL non valide', function () , 'Erreur'); return; var items = data.responseData.feed.entries; var $ post; if (currentEntries === items.length) navigator.notification.alert ('Plus d'entrées à charger', function () , 'Info') ; return; pour (var i = currentEntries; i < items.length; i++) $post = $('
    '); $ post .append ($ ('

    ') .text (items [i] .title)) .append ($ ('

    ') .html (' '+ items [i] .title +' ')) // Ajouter un titre .append ($ ('

    ') .html (items [i] .contentSnippet)) // Ajouter une description .append ($ ('

    ') .text (' Author: '+ items [i] .author)) .append ($ (' ')) .text (' Allez à l'article ') .button () .click (function (event) if ( Application.checkRequirements () === false) event.preventDefault (); navigator.notification.alert ('La connexion est désactivée, veuillez l'activer)', function () , 'Error'); renvoyer false; $ (this) .removeClass ('ui-btn-active');)); $ list.append ($ post); $ list.collapsibleset ('refresh'); , error: function () navigator.notification.alert ('Impossible de récupérer le flux. Essayer plus tard', function () , 'Erreur'); , complete: function () $ .mobile.loading ('masquer'); ); ; $ ('# show-more-entry'). click (function () loadFeed (); $ (this) .removeClass ('ui-btn-active');); $ ('# delete-feed'). click (function () Feed.searchByUrl (url) .delete (); navigator.notification.alert ('Flux supprimé', function () $ .mobile.changePage ('list -feeds.html ');,' Success ');); if (Application.checkRequirements () === true) loadFeed (); else navigator.notification.alert ('Pour utiliser cette application, vous devez activer votre connexion Internet', function () , 'Avertissement'); , initAurelioPage: function () $ ('a [cible = _blank]'). cliquez sur (function () $ (this) .closest ('li'). removeClass ('ui-btn-active'); ); , checkRequirements: function () if (navigator.connection.type === Connection.NONE) return false; return true; , updateIcons: function () var $ buttons = $ ('a [icône de données], bouton [icône de données]'); var isMobileWidth = ($ (fenêtre) .width () <= 480); isMobileWidth ? $buttons.attr('data-iconpos', 'notext') : $buttons.removeAttr('data-iconpos'); , openLinksInApp: function () $(document).on('click', 'a[target=_blank]', function (event) event.preventDefault(); window.open($(this).attr('href'), '_blank'); ); ;


    Conclusion

    Dans le troisième et dernier volet de cette série, nous verrons comment construire et tester les programmes d'installation à l'aide de la CLI et d'Adobe PhoneGap Build..