Functional widgets in Rails
-
Upload
sebastian-sito -
Category
Technology
-
view
1.161 -
download
0
description
Transcript of Functional widgets in Rails
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 [email protected]
Twitter @sebastiandreake
Kod aplikacji live https://github.com/dreake/widget