functional widgets in rails

Post on 18-Dec-2014

1.161 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

 

TRANSCRIPT

Functional widgets in Rails

Sebastian Sito

Co to jest widget?

mała aplikacja wbudowana w stronę WWWmoże być funkcjonalna lub statyczna

Przykład?

AlleWidgetGoogle GadgetsFacebook like buttons

Na początek statyczny content

<script type="text/javascript" src="http://hostapp.com/api/widget/main"></script>

Uwaga na Operę!

<script type="text/javascript" src="http://hostapp.com/api/widget/main.js"></script>

Po stronie aplikacji

app/controllers/widget_controller.rb

class Api::WidgetController < ApplicationController layout :nil def main respond_to do |format| format.js end endend

Po stronie aplikacji

app/views/api/widget/main.js.erb

document.write('<div id="widget">');<%= @title %>document.write('</div>');

Personalizacja widgetu

app/controllers/widget_controller.rb

class Api::WidgetController < ApplicationController layout :nil before_filter :validate_api_key def main respond_to do |format| format.js end endend

Personalizacja widgetu

config/routes.rbnamespace :api do match '/widget/:action/:api_key', :controller => 'widget', :api_key => /.*/end

app/controllers/api/widget_controller.rbdef validate_api_key render :text => 'Invalid API key' unless params[:api_key] and return render :text => 'Wrong API credentials' if not User.find_by_key(params[:api_key]) and returnend

Personalizacja widgetu

<script type="text/javascript"> var __apiKey = "qcg35cgwhojpm839v5";</script><script type="text/javascript" src="http://hostapp.com/api/widget/main"></script>

Widget funkcjonalny

Mamy problem: aplikacja i widget to dwie różne domeny!

JSONP z pomocą

Często używany, żeby obejść problemy związane z komunikacją między domenami.

JSONvar xhr = new XMLHttpRequest();

xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { // success };};

xhr.open("GET", "http://somewhere", true);xhr.send();

JSONP z pomocą

JSONPvar tag = document.createElement("script");tag.src = 'http://somewhere?callback=foo';

document.getElementsByTagName("head")[0].appendChild(tag);

Jaka jest różnica?

Różnica w zapytaniu JSONP polega na tym, że odpowiedź jest przekazywana jako argument wywołania funkcji - stąd parametr callback.

WAŻNE!W odróżnieniu od zwykłego zapytania XHR w zapytaniu JSONP nie można wyłapać błędów - dostajemy poprostu ParseError

Jaka jest różnica?

Różnica w zapytaniu JSONP polega na tym, że odpowiedź jest przekazywana jako argument wywołania funkcji - stąd parametr callback.

WAŻNE!W odróżnieniu od zwykłego zapytania XHR w zapytaniu JSONP nie można wyłapać błędów - dostajemy poprostu ParseError

Na szczęście jQuery robi to za nas!

JSONP i Rails 3

Musimy obsłużyć:

http://hostapp.com/api/widget/action?callback=foo

JSONP i Rails 3

Musimy obsłużyć:

http://hostapp.com/api/widget/action?callback=foo

Odpowiedź można sformułować tak:

render :json => @items.to_json, :callback => params[:callback]

JSONP i Rails 3

Musimy obsłużyć:

http://hostapp.com/api/widget/action?callback=foo

Odpowiedź można sformułować tak:

render :json => @items.to_json, :callback => params[:callback]

Otrzymujemy błędy z powodu innej domeny z którą chcemy się połączyć?

SameOriginPolicy

class Api::WidgetController < ApplicationController after_filter :set_access_control_headersend

SameOriginPolicy

class Api::WidgetController < ApplicationController after_filter :set_access_control_headersend

def set_access_control_headers headers['Access-Control-Allow-Origin'] = '*' headers['Access-Control-Request-Method'] = '*'end

Wszystko razem

Jeśli widget ma wiele funkcji, trzeba jakoś sprytnie ustalić sposób komunikacji.

Wszystko razem

Jeśli widget ma wiele funkcji, trzeba jakoś sprytnie ustalić sposób komunikacji.

Ładowanie widgetu

Pomysł polega na umieszczeniu całej logiki komunikacji i widoku w samym widgecie, dzięki czemu zaoszczędzimy na requestach (będziemy wysyłać i odbierać tylko dane)

<script type="text/javascript" src="http://hostapp.com/api/widget/main"></script>

app/views/api/widget/main.js.erb

if(window.Widget == undefined) { window.Widget = { // logic here }}

Logika widgetu

if(window.Widget == undefined) { window.Widget = { Settings: {}, API: {}, Handlers: {}, GUI: {} }}

$(document).ready(function() {Widget.API.call('init', {});});

Ustawienia

Settings: { api: { url: "http://hostapp.com/api/widget" }}

API

API: { call: function(action, data) { var url = Widget.Settings.api.url + '/' + action; data['api_key'] = __apiKey; $.ajax({url: url,data: data,crossDomain: true, dataType: "jsonp", success: Widget.API.responseHandler });}

Rails response

def widget_response(action, data) response_hash = {:action => action, :data => data} render :json => response_hash.to_json, :callback => params[:callback]end

API

API: { responseHandler: function() { Widget.Handlers[action](response.data) }}

Handlers

Handlers: { init: function(data) { // populate widget with data // and draw some GUI Widget.GUI.render(data); }}

Jeszcze ciekawiej: IFRAME w widgecie

Co jeśli w swoim widgecie uruchomimy jeszcze inną stronę w IFRAME i będziemy chcieli mieć możliwość odpowiedzieć z niego na pewne zdarzenie w IFRAME?

Jeszcze ciekawiej: IFRAME w widgecie

Co jeśli w swoim widgecie uruchomimy jeszcze inną stronę w IFRAME i będziemy chcieli mieć możliwość odpowiedzieć z niego na pewne zdarzenie w IFRAME?

Hash pooling

Jeszcze ciekawiej: IFRAME w widgecie

Co jeśli w swoim widgecie uruchomimy jeszcze inną stronę w IFRAME i będziemy chcieli mieć możliwość odpowiedzieć z niego na pewne zdarzenie w IFRAME?

Hash pooling

Widget.interval = setInterval(handleWindowHash, 1000)

teraz z wewnątrz IFRAME zmieniamy hash okna nadrzędnego

window.location.hash = "trigger_sth"

Przykład

Host Apphttp://rails-widget-example.heroku.com

Widget<!doctype html><html><head><title>Widget Client</title> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript"> var __userSecret = '8102260836164404'; </script> <script type="text/javascript" src="http:// rails-widget-example.heroku.com/api/widget/main.js"> </script></head> <body><div><h1>Widget example</h1></div><div id="widget_placeholder"></div> </body></html>

Dzięki :)

E-mail sebastian@emaire.com

Twitter @sebastiandreake

Kod aplikacji live https://github.com/dreake/widget

top related