iGoogle interface updated to lastest version of jQuery

5 09 2011

Many people have asked me to update my example of an iGoogle interface to the lastest version of jQuery. I have also repaired a problem with the database connection (I had moved my webpage to a different hosting company).

Here is the new version: http://www.jsabino.com/test2/

I have used jQuery 1.6.2 and jQuery UI 1.8.16.

You can also download the full source code here: http://www.jsabino.com/iNettutsDB3.zip

Thank you very much for all your comments.

Mario





Resolución del problema de cifras del programa “Cifras y letras” con PHP

21 05 2010

Resulta que hoy al llegar a comer a casa, haciendo zapping, me he enganchado un rato al programa “Cifras y letras”, en Telemadrid. En el problema de las cifras, han salido varios muy complicados, donde los concursantes se han quedado muy lejos del exacto. Pero claro, la presentadora sí tenía el exacto, con unas operaciones que no se le habrían ocurrido ni de lejos. Por supuesto, pensé, la solución se la ha dado el ordenador.

Así que, según he terminado de comer, he dicho: vamos a hacer en PHP un programita que resuelva el problema. Es fácil, una función recursiva que examine todas las posibilidades y se quede con la mejor. En una hora aproximadamente, he obtenido esto:

$final=859;
$numbers=array(6,6,7,25,10,1);

$best=0; $solution="";

Calc($numbers,"");
echo "$best<br><br>$solution";

function Calc($numbers,$sol) {

  global $best,$final,$solution;

  if ($best==$final) return ;

  if (count($numbers)==1) {
    if (abs($numbers[0]-$final)<abs($best-$final)) {$best=$numbers[0]; $solution=$sol;}
  } else {
    foreach ($numbers as $number) {
      if (abs($number-$final)<abs($best-$final)) {$best=$number; $solution=$sol;}
      if ($best==$final) return ;
    }
    for ($i=0;$i<count($numbers)-1;$i++) {
      for ($j=$i+1;$j<count($numbers);$j++) {

        // Suma
        $new_numbers=$numbers;
        unset($new_numbers[$i]);
        unset($new_numbers[$j]);
        $new_numbers = array_values($new_numbers);
        array_push($new_numbers,$numbers[$i]+$numbers[$j]);
        Calc($new_numbers,$sol.$numbers[$i]."+".$numbers[$j]."=".($numbers[$i]+$numbers[$j])."<br>");

        // Multiplicación
        $new_numbers=$numbers;
        unset($new_numbers[$i]);
        unset($new_numbers[$j]);
        $new_numbers = array_values($new_numbers);
        array_push($new_numbers,$numbers[$i]*$numbers[$j]);
        Calc($new_numbers,$sol.$numbers[$i]."x".$numbers[$j]."=".($numbers[$i]*$numbers[$j])."<br>");

        // Resta 1
        if ($numbers[$i]-$numbers[$j]>0) {
          $new_numbers=$numbers;
          unset($new_numbers[$i]);
          unset($new_numbers[$j]);
          $new_numbers = array_values($new_numbers);
          array_push($new_numbers,$numbers[$i]-$numbers[$j]);
          Calc($new_numbers,$sol.$numbers[$i]."-".$numbers[$j]."=".($numbers[$i]-$numbers[$j])."<br>");
        }

        // Resta 2
        if ($numbers[$j]-$numbers[$i]>0) {
          $new_numbers=$numbers;
          unset($new_numbers[$i]);
          unset($new_numbers[$j]);
          $new_numbers = array_values($new_numbers);
          array_push($new_numbers,$numbers[$j]-$numbers[$i]);
          Calc($new_numbers,$sol.$numbers[$j]."-".$numbers[$i]."=".($numbers[$j]-$numbers[$i])."<br>");
        }

        // División 1
        if (($numbers[$j]!=0) && ($numbers[$i]%$numbers[$j]==0)) {
          $new_numbers=$numbers;
          unset($new_numbers[$i]);
          unset($new_numbers[$j]);
          $new_numbers = array_values($new_numbers);
          array_push($new_numbers,$numbers[$i]/$numbers[$j]);
          Calc($new_numbers,$sol.$numbers[$i]."/".$numbers[$j]."=".($numbers[$i]/$numbers[$j])."<br>");
        }

        // División 2
        if (($numbers[$i]!=0) && ($numbers[$j]%$numbers[$i]==0)) {
          $new_numbers=$numbers;
          unset($new_numbers[$i]);
          unset($new_numbers[$j]);
          $new_numbers = array_values($new_numbers);
          array_push($new_numbers,$numbers[$j]/$numbers[$i]);
          Calc($new_numbers,$sol.$numbers[$j]."/".$numbers[$i]."=".($numbers[$j]/$numbers[$i])."<br>");
        }
      }
    }
  }
}

Por supuesto, el código se puede mejorar, pero desde luego, funciona a las mil maravillas. En el array $numbers con las cifras, se introducen los números con los que jugaremos. Y la variable $final es el número buscado. Como resultado, la página muestra el número más cercano obtenido y las operaciones realizadas para encontrarlo.

Después he pensado: bueno, seguro que esto lo ha hecho antes alguien. Pues sí, he encontrado esta solución implementada en C por Pedro Reina, pero con 841 líneas de código (incluidos los comentarios). En PHP yo lo he solucionado con las míseras 83 líneas que podéis ver más arriba.

Otro día me pongo con el problema de las letras…





A complete iGoogle like interface example with jQuery

5 05 2010

After my previous post about how to mimic the iGoogle interface with database, I have been working in a new version. Now I have added all you need to build a simple page, with these features:

  • The user starts with an empty page, where he can add widgets. There is a link “Add widget at column …” that creates a new widget at the selected column.
  • Any widget can be configured in the same way that before.
  • Widget content comes from an ajax request to a page called “widgets_rpc.php”. This page receives the id of the widget and should respond with the HTML content of that widget.
  • Widget configuration is stored in the database when the user changes something and loaded at the beginning.

You can see a working example here: http://www.jsabino.com/test

And you can download the complete source code here: http://www.jsabino.com/iNettutsDB2.zip

Inside the ZIP file, you can find:

  • script.sql: the script to create the required table in the database. You must execute it.
  • iNettuts_rpc.php: the same file for saving and loading widget configuration. Change here the database connect parameters (server, database, username and password).
  • index.html: now it is a simple page with the columns layout but without any widget, because they are created dynamically by a function called “Add”. It looks for the last added widget id and creates a new one in the selected column.
function Add() {
  var i=1;
  while ($("#widget"+i).length>0) i++;
  iNettuts.addWidget("#"+$("#col").val(), {
    id:    "widget"+i,
    color: "color-blue",
    title: "widget "+i
  })
}
  • widgets_rpc.php: file that retrieves the content of each widget. It is a simple version showing only “This is the content for widget n” yet.
  • inettuts.js: the core file where the widget logic is located. It was first programmed by James Padolsey but I have changed many things. There are three new functions: initWidget (returns the default widget layout), loadWidget (gets widget content with an ajax call) and addWidget (creates a new widget). I have also modified makeSortable (now it is called several times) and sortWidgets (draws widgets in a different way).
initWidget : function (opt) {
  if (!opt.content) opt.content=iNettuts.settings.widgetDefault.content;
  return '<li class="new widget '+opt.color+'"><div class="widget-head"><h3>'+opt.title+'</h3></div><div class="widget-content">'+opt.content+'</div></li>';
},

loadWidget : function(id) {
  $.post("widgets_rpc.php", {"id":id},
    function(data){
      $("#"+id+" "+iNettuts.settings.contentSelector).html(data);
    }
  )
},

addWidget : function (where, opt) {
  $("li").removeClass("new");
  var selectorOld = iNettuts.settings.widgetSelector;
  iNettuts.settings.widgetSelector = '.new';
  $(where).append(iNettuts.initWidget(opt));
  iNettuts.addWidgetControls();
  iNettuts.settings.widgetSelector = selectorOld;
  iNettuts.makeSortable();
  iNettuts.savePreferences();
  iNettuts.loadWidget(opt.id);
},

I have tested this example both in Firefox and Internet Explorer. Some users have reported problems in the comments of my last article, but it works fine for me.





El cometa Halley

5 05 2010

Hoy se ha marchado una persona de mi equipo en la empresa. En correo de despedida que ha enviado a toda la empresa ha puesto esto:

Lo de Mario es lo más similar que he visto nunca al cometa Halley, algo que pasa por la tierra cada 75,3 años. Si tienes la suerte de coincidir con su paso… sólo puedes relajarte y disfrutar del espectáculo.

Estas cosas son las que te hacen venir con ganas a la oficina. Muchas gracias R. Te deseo lo mejor en tu nuevo trabajo.





Pixlr: editor de imágenes online

12 10 2009

PixlrMe ha sorprendido un editor de imágenes gratuito que he descubierto. La diferencia que tiene con respecto a tantos otros que ya existen es que es online: funciona directamente desde el navegador sin necesidad de instalar nada. Su nombre es Pixlr Editor.

Está implementado con Flash y tiene características muy interesantes, como:

  • Organización de los menús similar a Photoshop.
  • Múltiples herramientas de edición y filtros.
  • Capas e historial de cambios.
  • Formatos de archivo JPG, PNG, BMP y PXD (nativo de Pixlr con soporte para capas).
  • API para utilizar el editor a tu gusto en tu propia página.
  • Disponible en 23 idiomas distintos.

Esta es la URL del editor ya en español:

http://www.pixlr.com/editor/?loc=es

La misma web, dispone también de otras herramientas muy interesantes:

  • Pixlr Express: versión reducida del editor, pero con las utilidades básicas para recortar una foto, ajustar sus niveles y aplicar diversos efectos.
  • Pixlr Grabber: extensión de Firefox e instalable de Windows que permiten abir tus fotos en Pixlr Editor directamente desde el navegador o desde tu explorador de archivos.




Experimentos con HDR y el plugin Before/After de jQuery

5 10 2009

BuenosAires_HDREstoy experimentando con la fotografía HDR, utilizando fotos de mis últimos viajes. HDR significa “High Dynamic Range” (Alto Rango Dinámico) y es una técnica fotográfica consistente en mezclar una misma foto tomada con distintas exposiciones para obtener un mayor rango dinámico. Para los que no conozcan esta técnica, recomiendo la lectura de Cómo hacer fotografías en HDR.

Cuando estoy de viaje no suelo llevar trípode lo que me habría permitido hacer bracketing, así que tomé las fotos en formato RAW y luego he utilizado Photomatix para obtener el HDR a partir de 3 fotos: la original, con +1 de exposición y con -1. Photomatix me está resultando mucho más fácil de usar que otros programas, como por ejemplo Artizen HDR, que es mucho más completo, pero se tarda más en lograr buenos resultados.

Por otro lado, quería enseñar las fotos en una página web pudiendo comparar fácilmente la foto original con la tratada. Buscando un poco, encontré el plugin de jQuery “Before/After”. Este plugin permite poner una foto encima de otra y cambiar la visualización mediante un slider. Lo mejor es que compruebes el resultado tú mismo para comprender lo que se puede conseguir con este plugin:

http://www.jsabino.com/hdr

La primera foto está hecha en Buenos Aires. La segunda en El Calafate y la tercera en Ushuaia. Luego vienen tres de las cataratas de Iguazú y finalmente una realizada recientemente en la Ciudad Encantada de Cuenca.

Para hacer las fotos he utilizado mi cámara Panasonic Lumix LX-3. Esto es solo el principio: aun me queda mucho que aprender sobre HDR para que me queden bien las fotos. Al menos, el efecto que se consigue con el plugin Before/After es espectacular y permite comparar fotos en la web de una forma sencilla.





Cómo recuperar la clave WEP/WPA de mi wifi

26 09 2009

¿No habéis olvidado alguna vez la clave WEP o WPA de vuestra red inalámbrica? A mí sí me ha pasado hace tiempo. Quería conectar el portátil de un amigo que vino a casa y, aunque mi ordenador estaba conectado correctamente, no la recordaba.

Por supuesto, si tienes el usuario y contraseña de la página de configuración de tu router inalámbrico, puedes entrar y verla o, al menos, cambiarla.

Sin embargo, hay una solución más rápida. Se trata de un programa llamado WZCOOK, que te muestra las claves de todas las redes wifi a las que te has conectado con tu equipo. Además de mostrarlas, te crea un fichero en c:\wepkeys.txt para consultarlas más adelante.

Puedes descargarlo desde aquí.





How to Mimic the iGoogle Interface with Database

19 09 2009

James Padolsey wrote a great tutorial about “How to mimic the iGoogle interface” with jQuery. Thank you very much, James. I have used your code intensively.

The next step was a new article explaining how to save widgets configuration into a cookie. Very useful too. But the final part was to store that data in a database.

That’s what a have done: an example of the same code, but using a database. The changes are very easy to implement. I have just had to modify savePreferences and sortWidgets functions in inettuts.js file, and to write a new PHP file for saving and loading data.

I call jQuery post function to send the data using AJAX for savePreferences:

$.post("iNettuts_rpc.php","value="+cookieString);

As you can see, cookieString is the same variable stored into a cookie. Then iNettuts_rpc.php manages with the database. It’s a very simple PHP showing how to store the value for a user called John Doe:

header("Cache-Control: no-cache");
header("Pragma: nocache");

// User_id -&gt; Should come from a session variable
$user_id="john doe";

// DB connect parameters
$server="localhost";
$user="root";
$password="";
$database="iNettuts";

$table="iNettuts";
$field="config";

// DB connect
mysql_connect($server,$user,$password);
@mysql_select_db($database);

if (isset($_REQUEST["value"])) {
 // SET value  

 $value=$_REQUEST["value"];

 $rs=mysql_query("SELECT * FROM $table WHERE user_id='$user_id'");
 if (mysql_numrows($rs)==0)
 mysql_query("INSERT INTO $table($field,user_id) VALUES('$value','$user_id')");
 else
 mysql_query("UPDATE $table SET $field='$value' WHERE user_id='$user_id'");
 echo "OK";

} else {
 // GET value 

 $rs=mysql_query("SELECT $field FROM $table WHERE user_id='$user_id'");
 if ($row=mysql_fetch_row($rs))
 echo $row[0];
 else
 echo "";
}

mysql_close();

And finally, the most difficult part: loading data to sort widgets:

sortWidgets : function () {
 var iNettuts = this,
 $ = this.jQuery,
 settings = this.settings;

 if(!settings.saveToCookie) {
 $('body').css({background:'#000'});
 $(settings.columns).css({visibility:'visible'});
 return;
 }

 $.post("iNettuts_rpc.php", "",
 function(data){

 var cookie=data;

 if (cookie=="") {
 $('body').css({background:'#000'});
 $(settings.columns).css({visibility:'visible'});
 iNettuts.addWidgetControls();
 iNettuts.makeSortable();
 return;
 }

 /* For each column */
 $(settings.columns).each(function(i){

 var thisColumn = $(this),
 widgetData = cookie.split('|')[i].split(';');

 $(widgetData).each(function(){
 if(!this.length) {return;}
 var thisWidgetData = this.split(','),
 clonedWidget = $('#' + thisWidgetData[0]),
 colorStylePattern = /\bcolor-[\w]{1,}\b/,
 thisWidgetColorClass = $(clonedWidget).attr('class').match(colorStylePattern);

 /* Add/Replace new colour class: */
 if (thisWidgetColorClass) {
 $(clonedWidget).removeClass(thisWidgetColorClass[0]).addClass(thisWidgetData[1]);
 }

 /* Add/replace new title (Bring back reserved characters): */
 $(clonedWidget).find('h3:eq(0)').html(thisWidgetData[2].replace(/\[-PIPE-\]/g,'|').replace(/\[-COMMA-\]/g,','));

 /* Modify collapsed state if needed: */
 if(thisWidgetData[3]==='collapsed') {
 /* Set CSS styles so widget is in COLLAPSED state */
 $(clonedWidget).addClass('collapsed');
 }

 $('#' + thisWidgetData[0]).remove();
 $(thisColumn).append(clonedWidget);
 });
 });

 /* All done, remove loading gif and show columns: */
 $('body').css({background:'#000'});
 $(settings.columns).css({visibility:'visible'});

 iNettuts.addWidgetControls();
 iNettuts.makeSortable();

 });
 }

I have used the same variable names to make it easier.

You can download the full example here.





¿Qué haríamos sin Google?

6 09 2009

Continuando mi anterior entrada sobre Bing y Google, me he quedado pensando… ¿qué haríamos sin Google?

Pues muy sencillo: utilizar otros buscadores. En serio, ¿os dais cuenta de lo que Google (el buscador) ha supuesto en la historia de Internet? Quizá algún día nos lleguemos a dar cuenta.

Mientras tanto, os dejo una imagen que me ha encantado, sobre lo que podría ser Google antes de Internet:

Desde aquí, gracias a Larry Page y Sergey Brin por tan brillante idea. No sabéis la cantidad de tiempo que habré pasado simplemente haciendo búsquedas, que casi siempre han resuelto algún pequeño problema en mi vida.





Bing vs. Google

4 09 2009

Desde la reciente presentación de Bing, el nuevo buscador de Microsoft, se ha escrito mucho sobre la calidad de ambos buscadores. ¿Cuál es mejor, Bing o Google?

Pues la respuesta es: decidid vosotros mismos. Y qué mejor forma de decidir que hacer la misma búsqueda en ambos buscadores. Para eso, he descubierto ésta página:

http://www.bing-vs-google.com

Basta con introducir el texto que quieres buscar y, como resultado, te aparecen Bing y Google en sendos frames verticales, con lo que puedes comparar los resultados fácilmente:

bing.vs.google

Yo he hecho varias pruebas. Por ejemplo, he introducido “php pdf”, una búsqueda bastante poco precisa, con el objetivo de encontrar información sobre la generación de ficheros PDF desde lenguaje PHP. En Google el primer resultado ha sido una página titulada Generar PDF con PHP y MySQL, justo lo que buscaba. Sin embargo, en Bing, los primeros resultados son páginas que hablan sobre PDF y tienen extensión PHP o al contrario. Es decir, nada relevantes. El primer resultado algo útil aparece en séptimo lugar, con el enlace al manual de la librería de PDF nativa en PHP, algo que Google también enlaza en sexta posición, pero después de cinco resultados realmente interesantes, como la librería FPDF o un par de blogs como desarrolloweb y webtaller.

Esta sensación se confirma con otras búsquedas realizadas y, además, en algunos casos se nota diferencia de velocidad de carga de los frames a favor de Google. Por lo tanto, mi veredicto está claro: me sigo quedando con Google. ¿Y vosotros?