chevron-left chevron-right

[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.

Integracja z Facebookiem - strona domowa usług dla programistów

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ę.

Integracja z Facebookiem - popup z formularzem

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.

Integracja z Facebookiem - karta informacji o aplikacji

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 Facebookiem - zezwolenia aplikacji

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:

Widok pojedynczej wiadomości na Facebooku/Twitterze

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

  1. Część 1 – Tworzymy aplikację JS z wykorzystaniem Backbone.js - Zapoznanie z frameworkiem
  2. Część 2 - Tworzymy aplikację JS z wykorzystaniem Backbone.js – Integracja z Twitterem
  3. Część 3 - Tworzymy aplikację JS z wykorzystaniem Backbone.js – Integracja z Facebookiem
  4. Część 4 - Tworzymy aplikację JS z wykorzystaniem Backbone.js – wysyłanie wiadomości

  • Łukasz

    Czy to jest kompletny kod? Nie mogę tego uruchomić. Wyskakuje w konsoli ‚Uncaught ReferenceError: APP is not defined’. Czy cały kod zostanie udostępniony? To by bardzo pomogło.

  • W połączeniu z kodem, który został zaprezentowany w poprzedniej części, będzie to kompletna aplikacja.
    Końcowy kod zamierzam zamieścić po ukończeniu serii, dlatego też zapraszam do śledzenia bloga 🙂

  • Łukasz

    Oczywiście śledzę, dziękuję za ciekawe tematy.

  • Łukasz

    Witam, czy seria została już ukończona? Czy będzie zamieszczony kompletny kod?

  • będę musiał w wolnej chwili usiąść i dokończyć serię. Do tej pory inne tematy skupiały moją uwagę.