[JS] Tworzymy aplikację JS z wykorzystaniem Backbone.js, część 3 – Integracja z Facebookiem
W kolejnej części serii omówię proces tworzenia aplikacji na Facebooku oraz integrację API Facebooka z aplikacją społecznościową napisaną w języku JavaScript, zbudowaną na bazie frameworka Backbone.js. Będzie to proces podobny do tego, który miał miejsce w przypadku integracji z Twitterem.
Jak dobrze wszystkim wiadomo, Facebook jest siecią społecznościową o największym zasięgu na świecie. Dlatego warto, aby strony internetowe i aplikacje internetowe posiadały integrację z jego usługami. Na nasze szczęście, Facebook udostępnia odpowiednie narzędzia. Należy jednak pamiętać o tym, by jednak posiadać wiarygodne konto w tym serwisie (tzn. nie powinno zawierać fałszywych danych i powinno się z niego korzystać) inaczej nie będzie można skorzystać z Facebook API.
Integrujemy aplikację z Facebookiem
Każdego rodzaju integracja strony WWW czy też aplikacji internetowej sprowadza się do tego, by uzyskać odpowiedni klucz aplikacji w usługach Facebooka. W tym celu należy się udać na stronę dla developerów Facebooka, zalogować się i wejść do zakładki Apps.
Na kolejnej stronie, klikamy w przycisk Create new app i powinien pojawić się popup z wstępnym informacjami do wypełnienia. Trzeba będzie podać nazwę dla aplikacji, jej przestrzeń nazw oraz kategorię.
Po wypełnieniu tych danych, nastąpi przekierowanie do strony z danymi o aplikacji korzystającej z serwisów Facebooka. Zobaczymy tam, informacje o identyfikatorze aplikacji, o sekretnym kodzie jej przyznanym, sposobie integracji aplikacji z serwisem Facebooka, itd.
Aby nasza aplikacja społecznościowa działała poprawnie, należy ją umieścić na jakimś serwerze (może być lokalnym) i podać adres WWW pod jakim będzie można znaleźć naszą aplikację w Internecie. W przypadku tworzenia aplikacji na lokalnym serwerze możemy wpisać localhost lub wpisać nazwę wirtualnej domeny (jeden z kolejnych wpisów na blogu). Ewentualnie, jeśli mamy możliwość zamieszczenia naszej aplikacji na zdalnym serwerze z podpiętą domeną, to wpisujemy nazwę rzeczywistej domeny, np. piotrnalepa.pl w polu App domains.
Na czas tworzenia aplikacji pozostawiamy tryb "piaskownicy" włączony i przechodzimy do sekcji związanej z integracją naszej aplikacji społecznościowej z serwisem Facebooka. Tam, w polu Webiste with Facebook Login wpisujemy adres strony (wraz z http://). Innych części nie musimy uzupełniać w tej chwili.
Kolejnym krokiem, aby uzyskać dostęp do usług na których nam zależy jest ustawienie uprawnień aplikacji. W tym celu, w lewym menu wybieramy pozycję Zezwolenia i edytujemy ustawienia. W naszym przypadku, potrzebujemy następujących zezwoleń:
- user_status
- Pozwala aplikacji na dostęp do statusów użytkownika i do wysyłania wiadomości na ścianę użytkownika.
- publish_actions
- Pozwala aplikacji publikować wiadomości do Facebooka za pomocą Open Grapha.
- publish_stream
- Opcjonalnie, pozwolenie aplikacji na wysyłanie wiadomości na fanpage, którym zarządza użytkownik.
- read_stream
- Opcjonalnie, pozwolenie aplikacji na dostęp do wszystkich wiadomości jakie wysłał użytkownik.
- status_update
- Zezwala aplikacji na aktualizację statusu użytkownika.
- manage_pages
- Opcjonalnie, zezwala aplikacji na zarządzanie fanpage'ami użytkownika.
Dodatkowo, ustawiamy Auth token parameter na URI Fragment. Tym samym dane do logowania aplikacji będziemy przesyłać za pomocą przygotowanego adresu URL.
To byłoby wszystko, jeśli chodzi o część związaną z przygotowaniem dostępu do usług Facebooka dla naszej aplikacji społecznościowej.
Integracja z Facebook API za pomocą Javascript
W celu wykorzystania potencjału Facebook API nie trzeba korzystać z dodatkowej biblioteki JS wspomagającej działanie aplikacji, tak jak to miało miejsce w przypadku integracji z Twitterem, gdzie przydatna się okazała biblioteka Codebird.js i to za jej pośrednictwem generowaliśmy zapytania do Twitter API w celu uzyskania danych o użytkowniku i pobrania tweetów z jego profilu.
Backbone.js – model dla pojedynczego postu
Teraz możemy przejść do części związanej z kodowaniem. Podobnie jak w przypadku integracji z Twitterem zaczniemy od zdefiniowania modelu pojedynczej wiadomości ze ściany na Facebooku. Kod wygląda następująco:
1 2 3 4 5 6 7 8 | // js/app/model/post.js (function () { 'use strict'; APP.model = APP.model || {}; APP.model.Post = Backbone.Model.extend(); })(); |
Jak widać, nie zachodzi w tym przypadku nic nadzwyczajnego. Definiujemy tylko nowy typ modelu rozszerzając standardowy model w Backbone.js.
Backbone.js – kolekcja modeli postów
Kolejnym krokiem, który wygląda praktycznie identycznie jak w przypadku kolekcji tweetów, jest utworzenie kolekcji postów. W tym celu definiujemy następujący kod:
1 2 3 4 5 6 7 8 9 10 | // js/app/collection/posts.js (function () { 'use strict'; APP.collection = APP.collection || {}; APP.collection.Posts = Backbone.Collection.extend({ model : APP.model.Post }); })(); |
Backbone.js – widok pojedynczego facebookowego postu
Po krótkich listingach kodu odpowiedzialnego za tworzenie modelu i kolekcji postów z Facebooka, przyszła pora na coś nieco bardziej złożonego. Tym razem trzeba będzie zdefiniować zachowanie się aplikacji w momencie renderowania widoku pojedynczej wiadomości na Facebooku. Kod odpowiedzialny za uzyskanie pojedynczego widoku wiadomości wygląda następująco:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | // js/app/view/post.js (function () { 'use strict'; APP.view = APP.view || {}; APP.view.Post = Backbone.View.extend({ // pojedyncza wiadomość z Facebooka będzie umieszczona w tagu article tagName : 'article', // i będzie miała klasę className : 'post', // a kod HTML widoku będzie pobierany z szablonu post.js template : 'post', // renderowanie widoku render : function () { var text; var templateVars = { text : '', userName : '', photoUrl : '', postDate : '' }; var item; var that = this; // generowanie linka HTML na podstawie adresu URL zamieszczonego w treści posta var createUrl = function urlify(text) { var urlRegex = /(https?:\/\/[^\s]+)/g; return text.replace(urlRegex, function (url) { return '<a href="https://blog.piotrnalepa.pl/2013/10/23/js-tworzymy-aplikacje-js-z-wykorzystaniem-backbone-js-czesc-3/" rel="nofollow" target="_blank">' + url + '</a>'; }); }; // jeśli wiadomość ma treść, to rozpoczynamy generowanie widoku wiadomości if (that.model.get('message')) { // przygotowanie zapytania do Facebook Graph w celu uzyskania zdjęcia użytkownika w odpowiednim formacie var userPictureQuery = '/' + that.model.get('from').id + '/picture?width=180&height=180'; var userPicture; // wysyłamy przygotowane zapytanie do Facebooka FB.api(userPictureQuery, function(response) { // w odpowiedzi dostajemy informację o adresie URL do zdjęcia userPicture = response.data.url; // na podstawie informacji pobranych z Facebooka i zamieszczonych w modelu // wypełniamy zmienne danymi text = createUrl(that.model.get('message')); templateVars = { text : text, userName : that.model.get('from').name, userDescription : '', photoUrl : userPicture, postDate : APP.parseDate(that.model.get('created_time')), followersCount : 1, friendsCount : 1, tweetsCount : 1 }; // ładujemy szablon widoku posta i wypełniamy go przygotowanymi danymi item = APP.loadTemplate(that.template, templateVars); // wstawiamy do kontenera wiadomości that.$el.append(item); }); return that; } else { return false; } } }); })(); |
W tym momencie już wykorzystujemy API Facebooka w celu pobrania odpowiedniego obrazka użytkownika z systemu. Pozostała reszta wygląda podobnie jak w przypadku Twittera. Byłbyś w stanie odpowiednio zrefaktoryzować kod, tak aby większość rzeczy się nie powtarzała? (opcjonalnie)
Backbone.js - szablon pojedynczej wiadomości
Jak można przeczytać w treści powyższego listingu, widok przekazuje dane do szablonu, którego kod wygląda następująco:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | // js/app/template/post.js <aside> <img class="post-user-image" src="{{= photoUrl }}" alt="{{= userName }}" width="75" height="75"> </aside> <section> <header> <h3>{{= userName }}</h3> <time datetime="{{= postDate }}">{{= postDate }}</time> </header> <p>{{= text }}</p> </section> <div class="user-profile"> <div class="user-info"> <img class="user-image" src="{{= photoUrl }}" alt="{{= userName }}" width="75" height="75"/> <div class="user-name"> <h3>{{= userName }}</h3> <p>{{= userDescription }}</p> </div> <div class="user-follow icon"><i class="icon-group"></i> <span>Follow user</span></div> <div class="user-send-message icon"><i class="icon-envelope-alt"></i> <span>Send private message</span></div> </div> <div class="user-social"> <div class="user-followers count"> <span>{{= followersCount }}</span> <span>Followers</span> </div> <div class="user-friends count"> <span>{{= friendsCount }}</span> <span>Friends</span> </div> <div class="user-tweets count"> <span>{{= tweetsCount }}</span> <span>Tweets</span> </div> </div> <i class="icon-remove-sign"></i> </div> |
Na pierwszy rzut oka, może się wydawać że tego kodu HTML jest tam dużo, ale tak nie jest. Końcowy efekt będzie wyglądał w następujący sposób:
Backbone.js - ściana wiadomości z Facebooka
Mając już przygotowane elementy składowe dla pojedynczego obiektu jakim jest wiadomość z Facebooka możemy połączyć to wszystko w jedną całość. Dzięki temu, uzyskamy widok ściany wiadomości z portalu społecznościowego. Kod wygląda następująco:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | // js/app/view/facebook.js (function () { 'use strict'; APP.view = APP.view || {}; APP.view.Facebook = Backbone.View.extend({ el : $('body').find('main'), container : $('<div/>').prop({ id : 'facebook' }), collection : {}, // zdarzenie kliknięcia na przycisku do zalogowania się na Facebooku events : { 'click.APP #facebook-login' : 'login' }, initialize : function () { console.info('Facebook: initializing Facebook timeline view'); var fbResponse; // pobieramy informację czy użytkownik jest zalogowany w aplikacji // za pomocą Facebooka APP.facebook.getLoginStatus(function (data) { fbResponse = data; }); // jeśli nie jest zalogowany, pokaż przycisk logowania if (fbResponse.status === 'unknown') { console.warn('Facebook: User is not logged in to Facebook'); this.showLoginButton(); } // jeśli jest zalogowany, ale nie dokonał autoryzacji dostępu aplikacji // do jego danych na Facebooku to dokonaj autoryzacji else if (fbResponse.status === 'not_authorized') { console.warn('Facebook: App is not authorized'); this.login(); } // jeśli jest zalogowany i aplikacja została autoryzowana, // to wyświetl wiadomości z profilu na Facebooku else if (fbResponse.status === 'connected') { console.info('Facebook: User is logged in to Facebook and app is authorized'); this.getPosts(); } }, //funkcja generująca widok ściany wiadomości render : function () { console.info('Facebook: rendering Facebook view'); var that = this; // wyczyść dotychczasową zawartość widoku that.$el.empty(); that.container.empty(); // dla każdego obiektu wiadomości znajdującego się w kolekcji wiadomości z Facebooka _.each(this.collection.models, function (item) { // wygeneruj widok pojedynczej wiadomości that.renderPost(item); }, this); // wygenerowany widok wszystkich wiadomości wstaw do widoku ściany wiadomości that.$el.append(that.container); }, // funkcja pobierająca wiadomości z Facebooka za pomocą API Facebooka getPosts : function () { console.info('Facebook: rendering timeline posts'); var that = this; // pobierz wiadomości ze ściany użytkownika APP.facebook.api('/me/home', function(response) { console.info('Facebook: creating collection of posts from data'); // utwórz nową kolekcję wiadomości that.collection = new APP.collection.Posts(response.data); // paginacja wiadomości, dzięki temu można doczytywać na bieżąco // starsze bądź nowsze wiadomości that.prevPage = response.paging.previous; that.nextPage = response.paging.next; that.render(); }); }, // funkcja generująca widok pojedynczej wiadomości renderPost : function (item) { console.info('Facebook: render post'); var postView = new APP.view.Post({ model : item }); this.container.append(postView.render().el); }, // funkcja wyświetlająca przycisk do logowania na Facebooku showLoginButton : function () { console.info('Facebook: showing Facebook login button'); var button = $('<a/>').prop({ id : 'facebook-login', className : 'btn btn-primary', href : '#facebook-login' }).text('Zaloguj się do Facebooka'); this.$el.empty().append(button); }, // funkcja logująca użytkownika do Facebooka login : function (event) { if (event) { event.preventDefault(); } console.info('Facebook: Logging into Facebook', event); var that = this; // logowanie użytkownika za pomocą Facebook API APP.facebook.login(function (response) { if (response.authResponse) { console.info('Facebook: User is logged in and app is authorized'); that.getPosts(); } else { console.error('Facebook: User declined to authorize app', response); that.showLoginButton(); } }, { scope : 'email,read_stream,publish_actions,publish_stream,manage_pages' }); // scope określa zakres uprawnień dostępu do danych użytkownika potrzebnych // do działania aplikacji społecznościowej // zakres uprawnień był omówiony wcześniej w tej części tutorialu } }); })(); |
Powyższy kod jest odpowiedzialny za generowanie widoku logowania do portalu społecznościowego Facebook, a następnie do wyświetlenia wiadomości użytkownika z jego profilu. Tym samym wzbogaciliśmy naszą aplikację o kolejną funkcjonalność. W następnej części będzie omówiony sposób wysyłania wiadomości do obydwu sieci społecznościowych, tj. Facebooka i Twittera, jednocześnie.
Krótkie podsumowanie
Mam nadzieję, że dzisiejsza część serii okaże się przydatna i pomoże Ci w rozwinięciu swoich umiejętności programistycznych oraz zainspiruje Ciebie do eksperymentowania z powyższym kodem tak, aby spełniał wszystkie Twoje wymagania.
Po raz kolejny jednak przypomnę, że powyższy kod nie jest końcowym produktem. W profesjonalnym webdevelopmencie wymagałby on jeszcze kilku istotnych szlifów, aby był odporny na różnego rodzaju sytuacje.
Inne części z serii
- Część 1 – Tworzymy aplikację JS z wykorzystaniem Backbone.js - Zapoznanie z frameworkiem
- Część 2 - Tworzymy aplikację JS z wykorzystaniem Backbone.js – Integracja z Twitterem
- Część 3 - Tworzymy aplikację JS z wykorzystaniem Backbone.js – Integracja z Facebookiem
- Część 4 - Tworzymy aplikację JS z wykorzystaniem Backbone.js – wysyłanie wiadomości