Una excelente recopilación de plugins, tutoriales y técnicas de jQuery:
http://www.noupe.com/jquery/all-about-jquery-plugins-tutorials-and-resources.html
Una excelente recopilación de plugins, tutoriales y técnicas de jQuery:
http://www.noupe.com/jquery/all-about-jquery-plugins-tutorials-and-resources.html
Desde ColorZilla nos traen un estupendo generador de gradientes CSS(3):
Disfrutadlo
Hola de nuevo, esta vez hemos estado más tiempo del que habríamos querido sin actualizar, pero aquí estamos de nuevo. Hoy vamos a explicar cómo hemos implementado el nuevo formulario de login (y de registro) que podéis ver si pulsais sobre el enlace que deberíais ver en la parte derecha de la cabecera y que está basado en el que podéis encontrar en este estupendo post de NETTUTS.
Bueno, para empezar crearemos la estructura HTML:
<div id="wrapper"> <div id="panel"> <div id="panel_contents"> </div> </div> <div id="show_button"><a href="#">Login</a></div> <div id="hide_button"><a href="#">Esconder</a></div> </div>
Como podéis ver, el código HTML es totalmente limpio, ni siquiera los enlaces llaman a funciones javascript (esto lo arreglamos luego gracias a las virtudes de jQuery). El contenido del panel irá, como ya habreis supuesto, en #panel_contents; en codeando.net hemos decidido incluir dos formularios, el de login y el de registro, pero cada uno puede colocar lo que desee.
El siguiente paso, será definir los estilos básicos (visibilidad, tamaño y posicionamiento):
#wrapper{ text-align: center; } #toppanel { position: absolute; top: 134px; width: 612px; z-index: 25; text-align: center; margin-left: auto; margin-right: auto; } #panel { width: 612px; position: relative; top: 1px; height: 400px; margin-left: auto; margin-right: auto; height: 0px; z-index: 10; overflow: hidden; text-align: left; } #panel_contents { height: 100%; width: 616px; position: absolute; z-index: -1; } #show_button { position: relative; top: -30px; left: 460px; } #hide_button { position: relative; font-size: 90%; font-weight: bold; z-index: 26; margin-top: -36px; }
Por supuesto, el aspecto y el posicionamiento final dependerá de vuestras necesidades de diseño; este ejemplo está basado en la implementación que hemos hecho en codeando.net.
Y por último el código javascript que hará que funcione nuestro panel desplegable:
<script type="text/javascript"><!-- $(document).ready(function() { $("div#show_button").click(function(){ $("div#show_button").toggle(); $("div#panel").animate({ height: "460px" }, "fast", "swing", function() {$("div#hide_button").toggle();}); }); $("div#hide_button").click(function(){ $("div#hide_button").toggle(); $("div#panel").animate({ height: "0px" }, "fast", "swing", function(){$("div#show_button").toggle();}); }); }); --></script>
Y con esto ya deberíamos tener nuestro panel funcionando, todo comentario será bien recibido. En otra entrega veremos cómo implementar un sistema de registro de usuarios con activación por email.
En la segunda entrega de esta serie, vamos a implementar métodos para la extracción y manipulación de datos. Comenzaremos con las funciones de acceso a datos, que serán las siguientes:
<?php public function getrow( $row = 0, $query = 'main' ) { $return = false; for ($ct=0;$ct<$this->queries[$query]['numfields'];$ct++) { $return[$ct] = $this->get($row, $ct); } return $return; } public function getassoc( $row = 0, $query = 'main' ) { $return = false; for ($ct=0;$ct<$this->queries[$query]['numfields'];$ct++) { $return[$this->queries[$query]['fields'][$ct]['name']] = $this->get($row, $ct); } return $return; } public function getarrayassoc( $start = 0, $end = 0, $query = 'main' ) { $return = false; if ($end == 0) { $end = $this->queries[$query]['numrows']; } for ($ctr=$start;$ctr<=$end;$ctr++) { $return[$ctr] = $this->getassoc($ctr, $query); } return $return; } ?>
Con estas funciones ya tenemos solucionados nuestros requerimientos de acceso a datos, ahora vamos con las funciones que nos permitirán manipularlos:
Hola de nuevo, hoy vamos a comenzar una clase de artículos en los que crearemos una librería de abstracción de bases de datos ¿que qué es eso? pues vamos a verlo.
De entrada, una capa de abstracción de bases de datos, nos permitirá cambiar el motor de la base de datos, de forma fácil y sencilla, de forma que la aplicación continúe funcionando de forma normal y sin efectuar ningún cambio en ella. Esto significa, que también podremos desarrollar aplicaciones que trabajen contra cualquier motor de bases de datos, sin cambiar nuestra sintaxis ni las funciones a utilizar.
Además, podemos implementar métodos para realizar selects, inserts, updates y deletes, entre otros, con lo que nuestro código podría quedar limpio de sentencias SQL (personalmente, es una práctica que prefiero no usar; a mí me es muy útil leer mis sentencias SQL de forma literal, pero para gustos... colores)
Bueno, pongámonos manos a la obra, lo primero que debemos hacer es crear la clase y establecer una conexión con la base de datos:
class MyDBLayer { private $db = ''; // Base de datos. private $host = 'localhost'; // Servidor. private $user = 'user'; // Usuario. private $password = 'password'; // Password. public $handler = null; // Handler de la conexión. private $engine = 'mysql'; // Motor de base de datos. private $autoconnect = false; // Indica si debemos autoconectar al crear el objeto. private $connected = false; // Indica si estamos conectados. private $queries = array(); // Contiene los queries ejecutados. public function __construct( $db, $host, $user = '', $password = '', $connect = false, $engine = 'mysql' ) { // // Inicializamos variables // $this->db = $db; $this->host = $host; if (strpos($host,'@') !== false) { $tmp = explode( '@', $host ); $this->host = $tmp[0]; $this->user = $tmp[1]; if (count($tmp) > 2) { $this->password = $tmp[2]; } if (count($tmp) > 3) { $this->autoconnect = (in_array($tmp[4],array('yes','true','1') ? true : false; } } else if (is_array($host)) { $this->host = $host[0]; $this->user = $host[1]; $this->password = $host[2]; if (count($host) > 3) { $this->autoconnect = (in_array($host[4],array('yes','true','1') ? true : false; } } else { $this->user = $user; $this->password = $password; $this->autoconnect = $connect; } if ($engine != 'mysql') $this->engine = $engine; if ($this->autoconnect) { // Si debemos conectar al inicio lo hacemos... $this->connect(); } } public function connect() { if ($this->engine == 'mysql') { $this->handler = @mysql_connect( $this->host, $this->user, $this->password ); } if ($this->handler) { if (!mysql_select_db($this->db, $this->handler)) { $this->errors[] = 'Error de selección de base de datos: ' . mysql_error(); return false; } $this->connected = true; return true; } else { $this->errors[] = 'Error de conexión con el servidor: ' . mysql_error(); return false; } }
Bien, como vereis, el constructor lo hemos montado de forma que sea capaz de recibir los parámetros de distintas formas: le podemos pasar los parámetros de forma tradicional o podemos agrupar los parámetros de conexión en el parámetro $host, ya sea como una cadena con el caracter "@" como separador (ej: host@usuario@password[@autoconectar[@motor]]) o como un array numérico, mantiendo el mismo orden de parámetros (host, usuario, password, autoconectar y motor) y una vez ha establecido las propiedades base de la clase, es capaz de realizar la conexión llamando a la función "connect", si se lo especificamos, claro.
En la función "connect", realizamos la conexión al servidor y seleccionamos la base de datos, comprobando el motor seleccionado, lo que nos da la posibilidad de extender nuestra clase para que sea capaz de trabajar sobre cualquier motor, ya sea mysql, postgre, mssql, odbc, etc...
Y para acabar con la primera entrega de esta serie, vamos a darle un poco de funcionalidad a la clase, implementando los métodos necesarios para extraer datos:
public function query( $sql, $query = 'main' ) { if (!$this->connected) { // Comprobamos si estamos conectados, si no lo hacemos. $this->connect(); } if ($this->connected) { if ($this->engine == 'mysql') { // // Realizamos el query y almacenamos el resultado en el array "queries" // $this->queries[$query]['query'] = $sql; $this->queries[$query]['result'] = mysql_query( $this->queries[$query]['query'], $this->db ) || $this->SendError(); if ($this->queries[$query]['result']) { // // Si el query ha tenido éxito, extraemos información del resultado. // $this->queries[$query]['recno'] = 0; if ((substr( strtoupper(trim($this->queries[$query]['query'])), 0, 6 ) == "SELECT") || (substr( strtoupper(trim($this->queries[$query]['query'])), 0, 7 ) == "EXPLAIN") || (substr( strtoupper(trim($this->queries[$query]['query'])), 0, 4 ) == "SHOW")) { $this->queries[$index]['numfields'] = mysql_num_fields( $this->queries[$index]['result'] ); $this->queries[$index]['numrows'] = mysql_num_rows( $this->queries[$index]['result'] ); for ($ct=0;$ct<$this->queries[$index]['numfields'];$ct++) { $this->queries[$index]['fields'][$ct]['name'] = mysql_field_name( $this->result, $ct ); $this->queries[$index]['fields'][$ct]['type'] = mysql_field_type( $this->result, $ct ); $this->queries[$index]['fields'][$ct]['size'] = mysql_field_len( $this->result, $ct ); } } } return $this->queries[$index]['result']; } } } public function get( $row, $col, $query = 'main' ) { $return = false; if ($this->engine == "mysql") { $return = mysql_result( $this->queries[$query]['result'], $row, $col ); } return $return; }
Como se puede observar, el método "query" realiza una consulta sobre la base de datos y la almacena en un array con un índice definido por nosotros, o usando uno por defecto. Además, si la consulta debe devolver resultados (es decir, no es un UPDATE ni un INSERT) extrae y almacena información sobre el resultado, como número de registros o número de campos, así como el nombre, tipo y tamaño de los mismos.
El método "get", símplemente extrae y devuelve un valor del resultado de cualquiera de las consultas realizadas o false si hay algún error.
Y aquí terminamos la entrega de hoy, en las siguientes iremos implementando nuevos métodos de acceso a datos y agregaremos nuevos motores de bases de datos a nuestra clase.
Uno de los elementos clave en una página web es el menú de navegación. Hay muchos factores que influyen en el diseño de un menú, pero ante todo:
Bien, para construir nuestro menú, primero crearemos la estructura, usando una lista desordenada (<ul>). Muchos de vosotros direis ¿porqué todo el mundo se empeña en que tengo que utilizar listas para construir un menu? La respuesta es bien sencilla: el XHTML es un lenguaje diseñado para estructurar datos, y un menú no deja de ser una lista de enlaces, por lo que lo más natural sería representarlo como lo que es, una lista.
Como ejemplo real, cogeré una web que desarrollé hace poco, www.almirantelibros.com. Lo primero, como decíamos es crear la estructura del menú:
<ul id="lmenu"> </ul>
Esto nos daría como resultado algo parecido a lo siguiente:
Ya tenemos un menú que, aunque completamente funcional, necesita que le demos forma, lo cual haremos a continuación utilizando CSS y una imagen que habremos preparado previamente. Lo primero es preparar la lista para mostrarla de forma horizontal:
ul#lmenu { padding: 0; margin: 0; } ul#lmenu li { list-style-type: none; /* Eliminamos el punto de los elementos de la lista */ float: left; /* Con esta línea ya tenemos el menú en horizontal */ height: 38px; /* Establecemos el alto, para adaptarlo a la imagen */ }
Una vez tenemos el menú en horizontal, cargaremos la imagen del menú, y digo "la imagen" porque utilizaremos una técnica llamada "CSS Sprites" que ya revisaremos a fondo, y que consiste en cargar una sola imagen como si fuera un "mapa" con todas las imágenes que vamos a utilizar, en este caso en el menú:
Y ahora vamos con el código CSS:
ul#lmenu li a, ul#lmenu li span { display: block; /* Convertimos los enlaces y el "span" en bloques */ background-image: url(/images/menu.jpg); /* Les asignamos a todos la misma imagen, así sólo la cargamos una vez */ background-repeat: no-repeat; text-indent: -24000px; /* Escondemos el texto, indentándolo fuera de la página hacia la izquierda */ } /* A continuación, con "background-position" y "width", posicionamos la imagen de fondo para cada elemento del menú */ li#lmenu1 a { background-position: left 1px; width: 72px; } li#lmenu1 a:hover { background-position: left -37px; } li#lmenu1 span { background-position: left -75px; width: 72px; } li#lmenu2 a { background-position: -100px 1px; width: 166px; } li#lmenu2 a:hover { background-position: -100px -37px } li#lmenu2 span { background-position: -100px -75px; width: 166px; } li#lmenu3 a { background-position: -292px 1px; width: 105px; } li#lmenu3 a:hover { background-position: -292px -37px } li#lmenu3 span { background-position: -292px -75px; width: 105px; } li#lmenu4 a { background-position: -423px 1px; width: 78px; } li#lmenu4 a:hover { background-position: -423px -37px } li#lmenu4 span { background-position: -423px -75px; width: 78px; } li#lmenu5 a { background-position: -528px 1px; width: 92px; } li#lmenu5 a:hover { background-position: -528px -37px } li#lmenu5 span { background-position: -528px -75px; width: 92px; } li#lmenu6 a { background-position: -645px 1px; width: 105px; } li#lmenu6 a:hover { background-position: -645px -37px } li#lmenu6 span { background-position: -645px -75px; width: 105px; }
Y con esto, ya tenemos terminado el menú, el ejemplo lo teneis en: www.almirantelibros.com
Sigamos con el ejercicio que empezamos la semana pasada, hoy vamos a retocar el ejemplo para que nuestro script no nos muestre las etiquetas ya seleccionadas. Para ello, modificaremos las opciones del plugin "autocomplete" para que envíe el contenido ya seleccionado a nuestro script PHP, quedando así nuestro código en javascript:
<script type="text/javascript"><!-- $().ready(function(){ $("#tags").autocomplete('gettags.php', { multiple: true, cacheLength: 0, autoFill: true, selectFirst: true, extraParams: { t: function() { return $("#tags").val() } }, formatItem: formatItem, formatResult: formatResult } ); }); function formatItem(row) { return row[0] + " (" + row[1] + ")"; } function formatResult(row) { return row[0]; } --></script>
Como vereis, hemos añadido un nuevo parámetro en la llamada a la función autocomplete:
extraParams: { t: function() { return $("#tags").val() } }
Con esto, hacemos que el plugin entregue el valor del campo "#tags" en el parámetro "t" en cada llamada (para que esto funcione, debemos también desactivar la caché con el parámetro: cacheLength: 0) el cual utilizaremos para crear un filtro en nuestra sentencia SQL:
<?php if ($_GET['t'] > '') { } else { $filter = ''; } $result = mysql_query( 'SELECT tag, COUNT(tag) FROM blogs_arts_tags WHERE tag LIKE "' . $_GET['q'] . '%"' . $filter . ' GROUP BY tag ORDER BY tag', $db ); } ?>
Y ya lo tenemos, podéis volver a pasar por la página de demostración para comprobar su funcionamiento, espero que lo disfrutéis ;)
Me he encontrado en Smashing Magazine con una estupenda librería de iconos sobre gráficos.
Disfrutadla.
En el primer artículo técnico de codeando.net vamos a explicar como hemos implementado en el motor de este blog un sistema de "tags" o "etiquetas", utilizando un "autocomplete" (en este caso un plugin para jQuery).
El primer paso es incluir los ficheros necesarios para la librería y el plugin:
<link rel="stylesheet" type="text/css" href="/javascript/jquery/plugins/jquery-autocomplete/jquery.autocomplete.css" /> <script type="text/javascript" src="/javascript/jquery.js"></script> <script type="text/javascript" src="/javascript/jquery/plugins/jquery-autocomplete/lib/jquery.bgiframe.min.js"></script> <script type="text/javascript" src="/javascript/jquery/plugins/jquery-autocomplete/jquery.autocomplete.pack.js"></script>
Ahora inicializaremos el plugin para el campo deseado:
$().ready(function(){ $("#tags").autocomplete('gettags.php', { multiple: true, autoFill: true, selectFirst: true, formatItem: formatItem, formatResult: formatResult } ); }); function formatItem(row) { return row[0] + " (" + row[1] + ")"; } function formatResult(row) { return row[0]; }
Pasemos ahora a explicar las opciones que definimos en el segundo parámetro que pasamos a la función autocomplete:
Con esto queda hecha la parte del cliente, ahora pasemos al lado del servidor: el fichero gettags.php. Este fichero está recibiendo los caracteres tecleados por el usuario en el parámetro GET "q", que utilizaremos para realizar una consulta a la base de datos y devolver el resultado:
$result = mysql_query( 'SELECT tag, COUNT(tag) FROM tags WHERE tag LIKE "' . $_GET['q'] . '%" GROUP BY tag ORDER BY tag', $db ); }
Y ya sólo queda mostraros el resultado final:
Hola a todos y bienvenidos a este humilde espacio donde intentaremos ir publicando artículos sobre programación para la web, la llamada Web 2.0, tecnologías de la información y otros temas que ya irán saliendo... Desde codeando.net esperamos poder ofreceros contenidos interesantes, generar discusiones y ¿porqué no? aprender también de vuestras aportaciones.
Un saludo y nos vemos en el siguiente post.