PhoneGap Bygg en feed Reader - Application Logic

Dette er den andre delen av serien om Audero Feed Reader. I denne artikkelen vil vi dykke inn i forretningslogikken i programmet og gi ytterligere bakgrunn på pluginene og API-en som brukes til vårt prosjekt.


1. Plugin & API Oversikt

Meldingsplugin

På flere punkter i Audero Feed Reader app vi skal bruke varsling() metode for varslingsplugin. Hvordan varselet blir vist, avhenger egentlig av hvilken plattform appen skal kjøre på. Faktisk bruker de fleste operativsystemene som støttes, en innfødt dialogboks, men andre, som Bada 2.x, bruker den klassiske nettleseren varsling() funksjon, som er mindre tilpassbar. Denne metoden aksepterer opptil fire parametere:

  1. budskap: En streng som inneholder meldingen som skal vises.
  2. alertCallback: En tilbakeringing for å påkalle når varslingsdialogen avvises.
  3. tittel: Tittel på dialogboksen (standardverdien er "varsling").
  4. button: Knappens tekst er inkludert i dialogboksen (standardverdien er "OK")

Husk at Windows Phone 7 og 8 ikke har et innebygd nettleservarsel. Så, hvis du vil bruke alert ( '-melding');, du må tildele window.alert = navigator.notification.alert.

InAppBrowser Plugin

I den første delen av denne serien nevnte jeg at et interessant poeng på kreditsiden er attributtet target = "_ blank" brukes på linkene. Denne delen vil forklare hvordan openLinksInApp () metode av applikasjon klassearbeid.

InAppBrowser er en nettleser som vises i appen din når du bruker window.open anrop. Som jeg sa i første del, fra versjon 2.3.0, har den to nye metoder: executeScript () og insertCSS (). For øyeblikket gir dette pluginet følgende fem metoder:

  • addEventListener (): Tillater brukeren å lytte etter tre hendelser (loadstart, loadstop, og exit), og å legge ved en funksjon som kjører så snart hendelsene blir sparket.
  • removeEventListener (): Brukes til å fjerne en tidligere tilknyttet lytter.
  • Lukk(): Brukes til å lukke InAppBrowser-vinduet.
  • executeScript (): Aktiverer injeksjon av JavaScript-kode i InAppBrowser vindu.
  • executeScript (): Aktiverer injeksjon av CSS kode i InAppBrowser vindu.

Hvis du ikke brukte Cordova i flere måneder, eller hvis du holder deg til versjon 2.0.0, husker du at det som standard åpnet eksterne koblinger i samme Cordova WebView som kjørte programmet. Derfor, når en ekstern side ble besøkt, ble den siste viste siden vist akkurat som før brukeren forlot den. Fra denne versjonen på er dette ikke lenger standardadferansen. Faktisk blir eksterne koblinger nå åpnet ved hjelp av Cordova WebView hvis nettadressen er i appens hvite liste. Nettadresser som ikke er på din hvite liste, åpnes ved å bruke InAppBrowser Plugin (mer om dette i dokumentasjonen). Men hva betyr dette praktisk talt? Det betyr at hvis du ikke klarer koblingene riktig, og hvis appens brukere klikker på en kobling og deretter vender tilbake til programmet, går alle jQuery Mobile eller andre slike forbedringer tapt. Dette skjer fordi alle CSS- og JavaScript-filene er lastet bare på hovedsiden, og de påfølgende nettadressene lastes inn ved hjelp av AJAX (standardsystemet vedtatt av jQuery Mobile).

Løsningen for dette problemet er implementert i openLinksInApp () metode. Faktisk er løsningen å fange klikkene på alle eksterne koblinger ved å sette inn target = "_ blank" attributt, forhindre uønsket standardadferd og åpne koblingene ved hjelp av window.open () metode. For å kunne jobbe, krever denne løsningen at du setter en hvit liste i konfigurasjonsfilen.

Google Feed API

Før du snakker om klassene av Audero Feed Reader, vi trenger å dykke inn i den magiske verdenen av Google Feed API og Google Feed JSON-grensesnittet, fordi vi vil bruke dem i kjernen i vår søknad. Som jeg påpekte i første del av denne serien, analyserer grensesnittet en RSS- eller ATOM-feed og returnerer et enhetlig og lett-å-parse JSON-objekt. Selvfølgelig kan vi gjerne administrere dette JSON-objektet ved hjelp av JavaScript.

Dette grensesnittet støtter to søketyper: Finn feed og last feed. De første søkene etter feeder basert på de oppgitte søkeordene, ble sendt som et argument, mens den andre søker etter feeds basert på en tilordnet nettadresse. I vår søknad bruker vi bare funksjonen Last inn feed.

Hver forespørsel til dette Google API må sende minst to parametere: v og q. Ja, de har veldig kryptiske navn! Den første parameteren, v, angir protokollversjonsnummeret. På tidspunktet for denne skrivingen er den eneste gyldige verdien "1.0". I den andre parameteren, q, Vi sender nettadressen til å analysere. I tillegg til disse, vil vår søknad også bruke num parameter. Dokumentasjonen angir antall innføringer som skal lastes fra strømmen som er spesifisert av q. En verdi på -1 indikerer det maksimale antall oppføringer som støttes, for øyeblikket 100. Som standard returnerer matinnmatning fire resultater. Så det er viktig å implementere vår funksjon for å laste inn 10 oppføringer som standard og deretter øke med ytterligere 10 hver gang brukeren er pålagt å vise mer.

Nå som du er klar over hvordan vi spør Google-tjenesten, er det viktig å klargjøre resultatet det kommer tilbake. Hvis nettadressen vi oppgav, var riktig, finner vi oppføringene i feedet inne i responseData.feed.entries eiendom. Hver oppføring har mye informasjon, men vi bruker bare noen få av dem. Spesielt skal vi skrive ut følgende egenskaper:

  • tittel: Oppføringstittel.
  • link: URL-adressen for HTML-versjonen av oppføringen.
  • forfatter: Forfatteren av oppføringen.
  • contentSnippet: En utdrag av mindre enn 120 tegn i innholdsattributtet. Utdraget inneholder ikke noen HTML-koder.

Opplysningene jeg har oppgitt ovenfor er nok til formål med søknaden vår, men hvis du vil lære mer, ta en titt på Google Feed-dokumentasjonen.


2. Bygg mateklassen

Dette avsnittet beskriver Mate klassen og dens metoder, alt inkludert i feed.js fil. Som jeg påpekte i den forrige delen, lagrer vi bare to felt for hver feed: tittelen og nettadressen. Så, aksepterer denne klassen disse to datapunktene som parametere. Innenfor skaper vi to private eiendommer: _db og _tableName. Husk at JavaScript ikke har egendoms- og metodesikkerhetsmodifikatorer, så vi emulerer faktisk private data.

Den første er en snarvei for lokal lagring eiendom av vindu gjenstand. Det er vant til å få tilgang til metodene som er eksponert av lagringsplugin, som vår app er basert på, og at vi vil bruke til å lagre feeds. Den andre er en streng som inneholder navnet på nøkkelen der vi skal lagre dataene. Faktisk, tilbakekalling av lagringsspesifikasjonene, lagrer dataene ved hjelp av et nøkkelverdierformat. Derfor, for å lagre vårt utvalg av feeds, må vi JSON-ify det. Det er akkurat hva vår lagre() metoden vil gjøre. På samme måte, for å hente dataene må vi analysere en JSON-streng for å gjøre det til et objekt. Denne oppgaven oppnås av laste() metode. Disse metodene er de eneste to som må være inne i klassen definisjonen fordi de bruker private eiendommer.

Den relative delen av feed.js filen er oppført nedenfor:

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

Rundt disse to enkle metodene vil vi lage en rekke andre vanlige. Spesielt bygger vi noen forekomstmetoder som Legg til(), for å legge til en ny feed, delete (), for å slette en feed, og sammenligne med(), å sammenligne en feed-forekomst med en annen feed. I tillegg til disse utvikler vi også statiske metoder som getFeeds () for å hente alle feeds fra lagring, getFeed () å hente bare ett, og sammenligne() å sammenligne to objekter.

Sammenligningsmetodene er verdt en liten diskusjon for å forstå hvordan vi vil sammenligne dem. Jeg hopper over beskrivelsen av sammenligne med() fordi det ikke gjør noe annet enn å ringe sin statiske motpart, sammenligne(), det gjør faktisk jobben. I det vil vi først teste om en av de oppgitte verdiene er nullliknende. Hvis ingen av dem er nullaktige, sammenligner vi leksikografisk navnene deres og, hvis de er lik, sammenligner nettadressen deres. Som du vil oppdage senere, vil vi imidlertid tvinge brukeren til aldri å ha to feeder med samme navn eller nettadresse.
De sammenligne() Metoden er viktig fordi den definerer måten vi sammenligner to feeder på, og dette er avgjørende for å fastslå hvordan feeds vil bli sortert i list-feeds.html side. Faktisk bruker vi innfødte sortere() array metode som aksepterer en valgfri parameter, en funksjon, som definerer sorterings rekkefølgen av arrayet basert på returverdiene.

Koden som implementerer det jeg beskrev, er følgende:

 Feed.prototype.compareTo = funksjon (andre) return Feed.compare (dette andre); ; Feed.compare = funksjon (feed, andre) if (other == null) return 1;  hvis (feed == null) return -1;  var test = feed.name.localeCompare (andre.navn); returnere (test === 0)? feed.url.localeCompare (other.url): test; ;

I tillegg til metodene som er sett så langt, oppretter vi to søkemetoder som vi skal bruke for å finne og slette en gitt feed: searchByName () og searchByUrl (). Den siste metoden jeg vil fremheve er getIndex (), og det er det som brukes til å hente indeksen til en bestemt fil.

Nå som vi har avdekket alle detaljene i denne klassen, kan jeg liste opp hele kildekoden til filen:

 funksjon Feed (navn, URL) var _db = window.localStorage; var _tableName = 'feed'; this.name = navn; this.url = url; this.save = funksjon (feeds) _db.setItem (_tableName, JSON.stringify (feeds)); ; this.load = function () return JSON.parse (_db.getItem (_tableName)); ;  Feed.prototype.add = function () var index = Feed.getIndex (dette); var feeds = Feed.getFeeds (); hvis (indeks === falsk) feeds.push (dette);  ellers feeds [index] = this;  this.save (feeds); ; Feed.prototype.delete = function () var index = Feed.getIndex (dette); var feeds = Feed.getFeeds (); hvis (index! == false) feeds.splice (indeks, 1); this.save (strømmer);  returfeeds; ; Feed.prototype.compareTo = funksjon (andre) return Feed.compare (dette andre); ; Feed.compare = funksjon (feed, andre) if (other == null) return 1;  hvis (feed == null) return -1;  var test = feed.name.localeCompare (andre.navn); returnere (test === 0)? feed.url.localeCompare (other.url): test; ; Feed.getFeeds = function () var feeds = new Feed (). Load (); returnere (feeds === null)? []: feeds; ; Feed.getFeed = funksjon (feed) var index = Feed.getIndex (feed); hvis (indeks === falsk) return null;  var feed = Feed.getFeeds () [index]; returnere ny feed (feed.name, feed.url); ; Feed.getIndex = funksjon (feed) var feeds = Feed.getFeeds (); for (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. Bygg applikasjonsklassen

Denne delen diskuterer andre og siste klasse av prosjektet, applikasjon, inneholdt i application.js fil. Målet er å initialisere layouten på sidene, legge ved hendelser til appsideelementene, og bruk Mate klasse for å lagre, laste og hente feeds.

Denne klassen er organisert for å ha inngangspunktet i initApplication () metode. Det kalles så snart Cordova har blitt initialisert og API-ene er klar til å handle. Innenfor denne metoden festes en bestemt handler til hver sideinitialisering, slik at vi kan håndtere hendelsene som utløses av sine widgets. I det vil vi også ringe Application.openLinksInApp () av grunner som er diskutert tidligere. Videre, for å forbedre brukeropplevelsen, vil vi fange hvert trykk på den fysiske tilbakeknappen (der den eksisterer) for å omdirigere brukeren til hjemmesiden til appen vår.

Kjernefunksjonen i vår søknad er initShowFeedPage () fordi den bruker Google Feed JSON-grensesnittet. Før du kjører forespørselen til tjenesten, teller vi antall innmeldinger som allerede er lastet (currentEntries variabel) og beregne hvor mange oppføringer tjenesten skal hente (entriesToShow variabel). Da kjører vi AJAX-forespørselen, ved hjelp av jQuery Ajax () metode, samtidig som vi viser siden lasting widget til brukeren. Når suksess tilbakeringingen blir utført, tester vi først om antall returnerte innstillinger er de samme som nummeret som allerede er vist, i så fall viser vi meldingen "Ingen flere oppføringer å laste". Ellers legger vi dem til listen og oppdaterer trekkspillet widgeten ($ List.collapsibleset ( 'refresh')). Sammen med hver oppføring legger vi også en håndterer til knappen som er opprettet, så hvis forbindelsen er slått av, blir en melding bedt i stedet for å få tilgang til siden.

Endelig, den updateIcons () Metoden vil bli diskutert i neste og siste del av serien.

Koden som implementerer diskutert klasse er oppført nedenfor:

 var Application = initApplication: function () $ (dokument) .on ('pageinit', '# add-feed-side', funksjon () Application.initAddFeedPage ();) .on ('pageinit' # list-feeds-page ', funksjon () Application.initListFeedPage ();) .on (' pageinit ',' # show-feed-side ', funksjon () var url = this.getAttribute (' data- url ') .on (' pageinit ',' # aurelio-page ', funksjon () Application.initAurelioPage ();) .on ('tilbakeknapp', funksjon () $ .mobile.changePage ('index.html');); Application.openLinksInApp ();, initAddFeedPage: funksjon () $ add-feed-form '). submit (funksjon (event) event.preventDefault (); var feedName = $ (' # feednavn ') .val (). trim (); var feedUrl = $ (' # feed -url ') .val (). trim (); hvis (feedName === ") navigator.notification.alert (' Navnfelt er påkrevd og kan ikke være tomt ', funksjon () ,' Feil '); return false; if (feedUrl === ") navigator.notification.alert ('URL-feltet er påkrevet og kan ikke være tomt', funksjon () , 'Feil'); returner falsk;  hvis (Feed.searchByName (feedName) === false && Feed.searchByUrl (feedUrl) === false) var feed = new Feed (feedName, feedUrl); feed.add (); navigator.notification.alert ('Feil lagret riktig', funksjon () $ .mobile.changePage ('index.html');, 'Suksess');  ellers navigator.notification.alert ('Feil ikke lagret! Enten navnet eller URL-en er allerede i bruk', funksjon () , 'Feil');  returner falsk; ); , initListFeedPage: function () var $ feedsList = $ ('# feeds-list'); var items = Feed.getFeeds (); var htmlItems = "; $ feedsList.empty (); items = items.sort (Feed.compare); for (var i = 0; i < items.length; i++)  htmlItems += '
  • '+ elementer [i] .name +'
  • '; $ feedsList.append (htmlItems) .listview ('refresh'); , initShowFeedPage: funksjon (url) var trinn = 10; var loadFeed = funksjon () var currentEntries = $ ('# feed-entries'). finn ('div [data-roll = collapsible]'). lengde; var entriesToShow = currentEntries + step; $ .ajax (url: 'https://ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=' + entriesToShow + '& q =' + encodeURI (url), dataType: 'json' , førSend: funksjon () $ .mobile.loading ('show', text: 'Vennligst vent mens du henter data ...', tekstVisible: true);, suksess: funksjon (data) var $ list = $ '# feed-entries'); if (data.responseData === null) navigator.notification.alert ('Kan ikke hente inn feedet. Ugyldig URL', funksjon () , 'Feil'); return; var items = data.responseData.feed.entries; var $ post; if (currentEntries === items.length) navigator.notification.alert ('Ingen flere oppføringer å laste', funksjon () , 'Info') ; return; for (var i = currentEntries; i < items.length; i++) $post = $('
    '); $ post .append ($ ('

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

    ') .html (' '+ items [i] .title +' ')) // Legg til tittel .append ($ ('

    ') .html (elementer [i] .contentSnippet)) // Legg til beskrivelse .append ($ ('

    ') .text (' Author: '+ items [i] .author)) .append ($ (' ') .text (' Gå til artikkelen ') .button () .click (funksjon Application.checkRequirements () === false) event.preventDefault (); navigator.notification.alert ('Tilkoblingen er slått av, slå den på', funksjon () , 'Feil'); return false; $ (dette) .removeClass ('ui-btn-active');)); $ List.append ($ post); $ list.collapsibleset ('refresh'); , feil: funksjon () navigator.notification.alert ('Unable to retrieve the Feed. Prøv senere', funksjon () , 'Feil'); , fullfør: funksjon () $ .mobile.loading ('hide'); ); ; $ ('# show-more-entries'). klikk (funksjon () loadFeed (); $ (dette) .removeClass ('ui-btn-active');); $ ('# delete-feed'). Klikk (funksjon () Feed.searchByUrl (url) .delete (); navigator.notification.alert ('Feed deleted', function () $ .mobile.changePage -feeds.html ');,' Suksess ');); hvis (Application.checkRequirements () === true) loadFeed (); ellers navigator.notification.alert ('For å bruke denne appen må du aktivere Internett-tilkoblingen din', funksjon () , 'Advarsel'); , initAurelioPage: function () $ ('a [target = _blank]'). klikk (funksjon () $ (dette) .closest ('li'). removeClass ('ui-btn-active'); ); , checkRequirements: function () if (navigator.connection.type === Connection.NONE) return false; returnere sann; , updateIcons: function () var $ buttons = $ ('en [data-ikon], knapp [data-ikon]'); var isMobileWidth = ($ (vindu). bredde () <= 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'); ); ;


    Konklusjon

    I den tredje og siste delen av denne serien ser vi hvordan du bygger og tester installatørene ved å bruke CLI og Adobe PhoneGap Build.