Publica en Twitter desde el safari del iPhone

Hola,

Hoy ando de inventos…  😉

Resulta que me he instalado la aplicación de Twitter para iPhone porque hace mucho tengo una cuenta en esta red social, pero también hace mucho que la tenía abandonada.

Mirando la aplicación echaba mucho en falta el poder publicar URL directamente desde el navegador del iPhone, pero buscando y buscando me encontré que en los settings de la aplicación para Twitter había una forma de hacer lo que quería.

Las instrucciones a seguir están en esta página:

Era crear un simple bookmark y luego editarlo para dejar solo el javascript. Esto estaba genial pero… las URL las publicaba a tamaño completo y esto para una red que solo permite 140 caracteres por post, es realmente un problema.

Mirando la forma en que lo hacían me di cuenta que lo que hacen es usar javascript para llamar a la aplicación de Twitter y le pasan el URL actual, o sea, el window.location.

La pregunta del millón era: ¿Qué pasa si antes de llamar a tweetie tomo la URL, la convierto  a un formato pequeño (por ejemplo: tinyUrl) y luego se la paso a la aplicación de Twitter? ¿Cómo podría hacer algo así?

Pues bien… me froté las manos y empecé:

Me creo una página HTML sin más, incluyo una referencia a Jquery desde el CDN de Microsoft, y con jQuery en mano, todo es fácil :)))))

Mi página debe:

1- Tomar un parámetro que le pasarían, el cual sería el URL en el que se encuentra navegando el usuario
2-
De alguna forma usar el servicio de TinyURL para convertir la URL a un formato pequeño
3-
y finalmente pasar el resultado a Twitter.

¿Parece simple no? Aquí está el código:

<html>
<head>
    <script type=”text/javascript” src=”http://ajax.microsoft.com/ajax/jQuery/jquery-1.5.1.min.js”></script>
    <script type=”text/javascript”>
        function makeTinyUrl(url)
        {
            $.getJSON(‘http://json-tinyurl.appspot.com/?url=’ + url + ‘&callback=?’,
            function (data)
            {
                window.location = ‘tweetie:’ + data.tinyurl;
            });
        }

        var urlParams = {};
        var e, 
        a = /+/g,  // Regex for replacing addition symbol with a space
        r = /([^&=]+)=?([^&]*)/g,
        d = function (s) { return decodeURIComponent(s.replace(a, ” “)); },
        q = window.location.search.substring(1);

        while (e = r.exec(q)) urlParams[d(e[1])] = d(e[2]);

        makeTinyUrl(urlParams[‘tw’]);

    </script>

</head>
<body/>
</html>

Después de publicar mi página HTML en un servidor,  el resto era fácil: Seguir los mismos pasos que dan en Atebits y probar… :)

Me cree un bookmark en el safari del iPhone con la siguiente URL:

y WALAAAA!!! Funciona!! :)))))

Quiero aclarar que esta URL solo la dejaré publica por un tiempo para que puedan probar, pero de ninguna forma es parte o se trata de un servicio público. 

Salu2

 

Llamada ajax en MVC usando el $.post de jquery

Hace poco pasé por la necesidad de enviar un formulario al servidor usando ajax en una aplicación MVC. El problema principal que tenía era que el formulario incluía un número “grande” de campos (o no tan grande pero resulta que soy un vago), por lo que no quería pasar el trabajo de tener que convertir todo eso a JSON como parámetros individuales. Tampoco deseaba, evidentemente, tener un método en el controlador al cual le llegaran 5 o más parámetros.

Pues bien… la vista en mi caso estaba diseñada para trabajar con un modelo definido por mí:

public class CustomerModel
{
  
public string UserName { get; set; }
  
public string FirstName { get; set; }
  
public string LastName { get; set; }
  
public string Language { get; set; }

   [DataType(DataType.Password)]
   public string Password { get; set; }
   [DataType(DataType.Password)]
  
public string ConfirmPassword { get; set; }
}

La vista:

<%@ Page Title=”” Language=”C#” MasterPageFile=”~/Views/Shared/Site.Master” Inherits=”System.Web.Mvc.ViewPage<CustomerModel>” %>

Mi formulario:

<% using (Html.BeginForm()) { %>
<
div>
  
<fieldset>
     
<legend>Customer Information</legend>
      <div class=”editor-label”>
        
<%: Html.LabelFor(m => m.FirstName) %>
     
</div>
     
<div class=”editor-field”>
        
<%: Html.TextBoxFor(m => m.FirstName) %>
     
</div>
     
<div class=”editor-label”>
       
<%: Html.LabelFor(m => m.LastName) %>
     
</div>
     
<div class=”editor-field”>
       
<%: Html.TextBoxFor(m => m.LastName) %>
     
</div>
     
<div class=”editor-label”>
       
<%: Html.LabelFor(m => m.UserName) %>
     
</div>
     
<div class=”editor-field”>
       
<%: Html.TextBoxFor(m => m.UserName) %>
     
</div>
     
<div class=”editor-label”>
        
<%: Html.LabelFor(m => m.Password) %>
     
</div>
     
<div class=”editor-field”>
       
<%: Html.PasswordFor(m => m.Password) %>
     
</div>
     
<div class=”editor-label”>
       
<%: Html.LabelFor(m => m.ConfirmPassword) %>
     
</div>
     
<div class=”editor-field”>
       
<%: Html.PasswordFor(m => m.ConfirmPassword) %>
     
</div>
     
<p>
       
<input type=”button” onclick=”uploadCustomerForm()” value=”Register” />

     
</p>
   
</fieldset>
 
</div>
 
<% } %>

La solución ideal para mí era poder pasar un objeto en javascript desde el cliente y que el controlador lo recibiera como el modelo asociado a la vista. Yo quería que el método en mi controlador se viera así:

[AcceptVerbs(HttpVerbs.Post)]
public
ActionResult SaveCustomer(CustomerModel model)
{
  
return Content(string.Format(“This is my content: {0}, {1}”,

             
model.LastName, model.FirstName));
}

Después de mucho andar por los rincones oscuros del mundo Google, hallé una solución limpia, elegante y simple.

Mi script:

<script src=”/Scripts/jquery-1.4.1.min.js” type=”text/javascript”></script>
<
script type=”text/javascript”>
 
function uploadCustomerForm()
 
{
   
var data = $(‘form’).serialize();
   
//Enviar por post
   
$.post(<% =Url.Action(“SaveCustomer”) %>, data, insertCallback);
 
}

  function insertCallback(data)
 
{
   
alert(data);
 
}

</script>

Pues sí, así de simple resultó pasar el formulario al controlador y que este recibiera como parámetro el modelo asociado a la vista. Esta instrucción resume todo lo que necesitamos:

var data = $(‘form’).serialize();

Pero, ¿dónde está el truco?

Cada elemento input de mi formulario se crea usando el helper Html.TextBoxFor el cual es asociado a una propiedad del modelo. Esto, si miramos el HTML generado, crea un input cuyo ID Name corresponde con el nombre de la propiedad que, al ser serializado, crea un JSON que hace corresponder ID=valor una representación en el formato clásico de URL (param=valor&m2=valor2&…).

Formulario serializado:

FirstName=aa&LastName=bb&UserName=aa.bb&Password=123&ConfirmPassword=123

Una curiosidad a tener en cuenta es: si miran el formulario podrán ver que he dejado fuera del formulario la propiedad Language de mi modelo, esto lo he hecho con toda intensión para que veamos que no es necesario que nuestro formulario se corresponda 100% con el modelo que tenemos asociado a la vista, pero, sí es necesario que cada ID Name de los elementos del formulario se corresponda con una propiedad llamada exactamente igual a la existente en el modelo.

Con esto… ya tenemos un post por ajax al controlador que recibe como parámetro el modelo asociado a la vista. Esto es posible también hacerlo usando ASP.NET, pero eso lo dejo para un próximo artículo.

😉

JSONP

Este ejemplo me decidí a escribirlo después de leer la serie de artículos publicados en el blog de José Alarcón sobre JSONP.

1- Llamadas AJAX a servidores remotos.
2- Soporte desde ASP.NET AJAX 4.0
3- Cuestiones de seguridad y ASP.NET rompiendo la compatibilidad en 3.5

Requisitos: Crear un input tipo text con auto completamiento de las ciudades de España. Para esto usaré geonames.org, que es un servicio gratuito que nos permite obtener geo-localizaciones a partir de determinados parámetros y cuya documentación la encontramos en su sitio:

http://www.geonames.org/export/geonames-search.html

Como JQuery está de moda… y este soporta JSONP, voy a usar el pluging que existe para el auto-completamiento y que lo pueden encontrar en http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/.

Con esto creo que completo todo lo que necesito así que vamos con el código. Empezamos con lo de siempre, indicando cual es el control al cual le vamos a aplicar el “autocomplete” y cuál será la fuente de datos.

$(“#txt_city”).autocomplete(“http://ws.geonames.org/searchJSON”,

Vamos a realizar un pequeño truco, porque al final el objetivo de este artículo es justificar el uso de JSONP, así empezamos indicando los parámetros del “autocomplete” esperando como respuesta un JSON.

dataType: ‘json’,

Seguimos especificando una función que realizará un Parse de los datos que me retorna geonames, para poder entregárselos al autocomplete de la manera que él lo entiende.

parse: function(data)
{
      var rows = new Array();
      data = data.geonames;

      for(var i=0; i<data.length; i++)
      {
         rows[i] = 
         {
           
data:data[i],
            value:data[i].name,
            result:data[i].name
         };
      }               

      return rows;
},

Nada importante hasta aquí.. una función que convierte el resultado en un arreglo que contiene el dato, el valor de cada elemento y el resultado. Seguimos con la función que se llamará a la hora de mostrar el autocomplete e indicamos que solo mostraremos el nombre de la ciudad.

formatItem: function(row, i, n)
{
      return row.name;
},

Continuamos incluyendo los parámetros necesarios para realizar la búsqueda (País, indicar que no deseo lugares geográficos, etc.) Todos estos parámetros están bien documentados en el sitio de geoname.

extraParams:
{
      q: ,
      limit: ,
      country: ‘ES’,
      featureClass: ‘P’,
      maxRows: 50,
      name_startsWith: function ()
      {
        return $(“#txt_city”).val()
      }
},

Luego decimos que nuestro autocomplete espera un máximo de 50 elementos y listo.

max: 50

Con definir nuestro html con un input cuyo ID=”txt_city”, tendremos nuestro autocomplete, así que ejecutamos….

OPS!!! Acceso denegado… Este error proviene precisamente por la imposibilidad de hacer un pedido a un dominio que no es el nuestro, estamos intentando hacer un Cross Site Scripting.

¿Cómo lo resolvemos? Un buen comienzo es estudiando la serie de artículos propuestos al inicio de este post, pero para nuestro ejemplo, JQuery lo hace tan simple como ya nos tiene acostumbrado. Cambiamos el tipo de dato que espera el autocomplete a jsonp:

dataType: ‘jsonp’,

y….

We are happy :-)

Aquí les dejo un enlace al ejemplo completo, que no es más que una simple página html ya que no usamos ASP.NET para nada, es código html duro y puro.

Ejemplo