Los fuentes de este ejemplo se encuentran en la rama original
del repositorio
sinatra-streaming-example-chat.
La rama simple
en
https://github.com/crguezl/sinatra-streaming-example-chat/tree/simple
contiene una versión equivalente pero con los templates separados.
[~/srcSTW/streaming/chat_with_streaming(master)]$ cat -n chat.rb 1 # coding: utf-8 2 require 'sinatra' 3 set server: 'thin', connections: [] 4 5 get '/' do 6 halt erb(:login) unless params[:user] 7 erb :chat, locals: { user: params[:user].gsub(/\W/, '') } 8 endCuando se visita la raíz la primera vez
params[:user]
es nil
y se muestra el formulario definido en login.erb
que obtiene un alias
para el usuario:
[~/sinatra/sinatra-streaming/chat_with_streaming(simple)]$ cat views/login.erb <form action='/' method='GET'> <label for='user'>User Name:</label> <input name='user' value='' autofocus/> <input type='submit' value="GO!" /> </form>El atributo
for='user'
de label
indica que esta etiqueta está asociada
con el campo input
cuyo atributo name
es user
.
Una vez que el <input name='user'>
es rellenado el formulario es procesado por la misma
ruta /
que ahora muestra el resultado de la plantilla chat
.
10 get '/stream', provides: 'text/event-stream' do 11 stream :keep_open do |out| 12 settings.connections << out 13 out.callback { settings.connections.delete(out) } 14 end 15 endRoutes may include a variety of matching conditions, such as the user
agent:
,
:host_name
and :provides
:
get '/', :provides => ['rss', 'atom', 'xml'] do builder :feed endSending an event stream from the source is a matter of constructing a plaintext response, served with a
text/event-stream
Content-Type,
that follows the Server Sent Event (SSE) format.
Sigamos:
16 17 post '/' do 18 settings.connections.each { |out| out << "data: #{params[:msg]}\n\n" } 19 204 # response without entity body 20 end
204 No Content
The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation.
If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent's active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent's active view.
The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields.
21 22 __END__ 23 24 @@ layout 25 <html> 26 <head> 27 <title>Super Simple Chat with Sinatra</title> 28 <meta charset="utf-8" /> 29 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> 30 </head> 31 <body><%= yield %></body> 32 </html>
The <script>
tag is used to define a client-side script, such as a JavaScript.
The <script>
element either contains scripting statements, or it points to an external script file through the src
attribute.
Common uses for JavaScript are image manipulation, form validation, and dynamic changes of content.
The Google Hosted Libraries
is a content distribution network for
the most popular, open-source JavaScript libraries. To add a library
to your site, simply use <script>
tags to include the library.
See https://developers.google.com/speed/libraries/devguide:
jQuery snippet: <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> site: http://jquery.com/ versions: 1.8.3, 1.8.2, 1.8.1, 1.8.0, ... note: 1.2.5 and 1.2.4 are not hosted due to their short and unstable lives in the wild.
jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development.
jquery.min.js
is a minified version of the JQuery JavaScript library,
which provides a number of basic functions for websites.
34 @@ login 35 <form action='/'> 36 <label for='user'>User Name:</label> 37 <input name='user' value='' /> 38 <input type='submit' value="GO!" /> 39 </form> 40 41 @@ chat 42 <pre id='chat'></pre> 43 44 <script> 45 // reading 46 var es = new EventSource('/stream'); 47 es.onmessage = function(e) { $('#chat').append(e.data + "\n") }; 48 49 // writing 50 $("form").live("submit", function(e) { 51 $.post('/', {msg: "<%= user %>: " + $('#msg').val()}); 52 $('#msg').val(''); $('#msg').focus(); 53 e.preventDefault(); 54 }); 55 </script> 56 57 <form> 58 <input id='msg' placeholder='type message here...' /> 59 </form>
EventSource
object, specifying the URI of a
script that generates the events:
var es = new EventSource('/stream')
When updates are pushed from the server, the onmessage
handler fires
and new data is available in its e.data
property:
47 es.onmessage = function(e) { $('#chat').append(e.data + "\n") };
~3
seconds. Your server
implementation can even have control over this reconnection timeout.
addEventListener()
to listen for events just like any
other event source:
source.addEventListener('message', function(e) { console.log(e.data); }, false); source.addEventListener('open', function(e) { // Connection was opened. }, false); source.addEventListener('error', function(e) { if (e.readyState == EventSource.CLOSED) { // Connection was closed. } }, false);
<html> <head> <title>Super Simple Chat with Sinatra</title> <meta charset="utf-8" /> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> </head> <body><pre id='chat'></pre> <script> // reading var es = new EventSource('/stream'); es.onmessage = function(e) { $('#chat').append(e.data + "\n") }; // writing $("form").live("submit", function(e) { $.post('/', {msg: "casiano: " + $('#msg').val()}); $('#msg').val(''); $('#msg').focus(); e.preventDefault(); }); </script> <form> <input id='msg' placeholder='type message here...' /> </form></body> </html>
$("form")
to specify a selector.
The dollar sign ( $
) is simply shorthand for jQuery.
With $("form")
we select all the elements with tag name form
.append( content [, content] )
content
: DOM
element, HTML string, or jQuery object to insert
at the end of each element in the set of matched elements.
content
: One or more additional DOM elements, arrays of
elements, HTML strings, or jQuery objects to insert at the end of
each element in the set of matched elements.
.live( events, handler(eventObject) ) Returns: jQueryDescription: Attach an event handler for all elements which match the current selector, now and in the future.
events
: A string containing a JavaScript event type, such as click
or keydown.
As of jQuery 1.4 the string can contain multiple, space-separated event types or custom event names.
handler(eventObject)
: A function to execute at the time the event is triggered.
.live()
method is deprecated.
Use .on()
to attach event handlers.
These are equivalent templates:
$( selector ).live( events, data, handler ); // jQuery 1.3+ $( document ).on( events, selector, data, handler ); // jQuery 1.7+The
events
argument can either be a space-separated list of event
type names and optional namespaces, or an object of event name
strings and handlers. The data
argument is optional and can be
omitted.
jQuery.post( url [, data] [, success(data, textStatus, jqXHR)] [, dataType] )
url
: A string containing the URL to which the request is sent.
data
: A map or string that is sent to the server with the request.
success(data, textStatus, jqXHR)
: A callback function that is executed if the request succeeds.
dataType
: The type of data expected from the server. Default: Intelligent Guess (xml, json, script, text, html).
This is an easy way to send a simple POST
request to a server.
It allows a single callback function to be specified that will be executed when the
request is complete (and only if the response has a successful
response code).
$.post()
returns the XMLHttpRequest
that it creates. In most cases
you won't need that object to manipulate directly, but it is available
if you need to abort the request manually.
.val
Get the input value of the first matched element.
A value is returned for all input elements, including selects and textareas. For multiple selects an array of values is returned.
For example:
$('select.foo option:selected').val(); // get the value from a dropdown select $('select.foo').val(); // get the value from a dropdown select even easier $('input:checkbox:checked').val(); // get the value from a checked checkbox $('input:radio[name=bar]:checked').val(); // get the value from a set of radio buttons
.focus( handler(eventObject) ) .focus( [eventData], handler(eventObject) ) .focus()
handler(eventObject)
: A function to execute each time the event is triggered.
eventData
: A map of data that will be passed to the event handler.
This method is a shortcut for .trigger('focus')
.
The focus event is sent to an element when it gains focus.
This event is implicitly applicable to a limited set of elements, such as form elements
(<input>
, <select>
, etc.) and links (<a href>
). In recent browser
versions, the event can be extended to include all element types
by explicitly setting the element's tabindex property. An element
can gain focus via keyboard commands, such as the Tab key, or by
mouse clicks on the element.
Elements with focus are usually highlighted in some way by the
browser, for example with a dotted line surrounding the element.
The focus is used to determine which element is the first to receive
keyboard-related events.
event.preventDefault() Returns: undefinedDescription: If this method is called, the default action of the event will not be triggered.
For example, clicked anchors will not take the browser to a new
URL. We can use event.isDefaultPrevented()
to determine if this
method has been called by an event handler that was triggered by
this event.
Casiano Rodriguez León 2015-01-07