Archivo de la categoría: Javascript

js-icon

Javascript: Eliminar un item de un array por su nombre

Pongan esto en su codigo:

Array.prototype.removeItem = function (a) {
    for (var i = 0; i < this.length; i++) {
      if (this[i] == a) {
        for (var i2 = i; i2 < this.length - 1; i2++) {
          this[i2] = this[i2 + 1];
        }
        this.length = this.length - 1;
        return;
      }
    }
  };

Y ya podemos eliminar elementos del array:

var frutas = ['manzana', 'banana', 'pera'];
frutas.removeItem('banana');
console.log(frutas); // Entrega ['manzana', 'pera']

Chau!

js-icon

Boilerplate (esqueleto) de plugin jQuery de la casa y en español ;)

Hola!. Me complace anunciar que pongo a disposición de todo el que quiera hacer plugins de jQuery, el boilerplate que he estado usando en los últimos años.

Es otro boilerplate como los demas, con la diferencia que al estar usandolo todo el tiempo lo fui puliendo poco a poco. Pero mucho mas importante: está en español XD

Pase pasen y vean https://github.com/capynet/jQueryPluginBoilerplate

Chau!

PHP

Detectar el navegador y toda su información desde PHP o Javascript

Hola, les hago una intro bien corta y pasamos al código.

Browscap es un proyecto que recoge la información de todos los navegadores web en una base de datos que distribuye de forma gratuita y en varios formatos.

PHP tiene soporte nativo para hacer uso de esta DB, pero debido a un par de limitaciones que PHP aun no ha solventado en su API, en GitHub un usuario creó una soluciona basada también en la DB de Browscap pero mucho mas robusta y fácil de usar.

Bien, llegados a este punto sabemos que lo que necesitamos usar es Browscap junto a la librería que se creó para explotarla.

Para mas información, toda la documentación completa de php-browscap la pueden encontrar aquí. Yo me centro en una implementación mucho mas simple porque realmente creo que de los 40 datos que entrega sobre el navegados, con apenas 7 tenemos el 99% de los casos cubiertos.

Acá tienen un ejemplo funcionando para que vean lo rápido y certero que es a la hora de conseguir la info del browser (pruébenlo con mas de uno)

Ok, pongamos algo de código que sino todo esto es muy aburrido:
Vamos a aprovechar esta librería bajo dos situaciones. en PHP y en JS

En PHP

Descarguen la librería php-browscap via Composer o a mano. Pueden saber mas sobre como descargarla aquí
Ahora que la tenemos creamos un archivo index.php para usarla.

<?php
require 'vendor/autoload.php';
use phpbrowscap\Browscap;
$bc = new Browscap('cache');
/** @var stdClass $current_browser */
$current_browser = $bc->getBrowser();
?>

Fácil, no?. Ok ya tenemos un stdClass en $current_browser con toda la información disponible del browser que llame a index.php

Aplicaciones?

Puedes por ejemplo tomar decisiones del tipo

<?php
$curr_br = $current_browser->Browser;
$CoolBrowsers = $curr_br == 'Chrome' || $curr_br == 'Firefox';
if ($CoolBrowsers) {
  add_asset('css', 'just-for-cool-browsers.css');
  $output = renderAdvancedLayout();
}
else {
  add_asset('css', 'just-for-bad-bad-browsers.css');
  $output = renderBasicLayout();
}
?>

También puedes detectar si están accediendo desde un móvil o una tablet, incluso saber si es Android, IOS, la version del SO, etc. Con toda esta información a resumidas cuentas puedes entregar un contenido muy preciso.

Beneficios

Estas entregando contenidos a medida, ergo necesitas entregar menos HTML, CSS, Js y las imágenes mas adecuadas al navegador. Esto finalmente se traduce en menos procesamiento del lado del servidor, lo que se entrega pesa menos KB y el navegador tarda menos en leer y renderizar todos los recursos (en especial JS).

En JS

Por ultimo me gustaría compartir un tip para poder aprovechar la detección de browsers en JS:
A ver, con js podemos detectar el browser usando un poco de expresiones regulares, pero llegar al detalle y la precisión a la que llega browscap es virtualmente imposible. Dicho esto, comentar que se puede entregar toda la información del browser detectado desde php simplemente haciendo esto:

<script type="application/javascript">
  var browser = <?php= json_encode($current_browser = $bc->getBrowser()); ?>;
  alert(browser.Browser);
  alert(browser.Version);
</script>

Hasta la próxima!

Node.js

Tutorial: implementar un servicio RESTful public API de modelos Mongoose en Node.js

Hola!, He terminado de hacer un ejemplo de como implementar una API pública tipo RESTful en una APP creada con express.
La idea detrás de esta app de ejemplo es la de crear automagicamente todas las URL necesarias para poder gestionar un modelo de Mongoose (aka recurso).

Su uso es realmente simple. Dentro de la carpeta “models” creas un nuevo modelo/entidad, tocas un par de detalles mas, y tienes una API publica completa de ese nuevo recurso :)

Ya no doy mas vueltas, acá la tienen:

https://github.com/capy/Simple-API-style

Chau!

Node.js

Node.js/express: Gestionar las URL de tu proyecto mas eficientemente.

Normalmente cuando haces una aplicación usando express, por comodidad tiendes a poner todas las definiciones de las url’s en la raíz del proyecto:

var express = require('express');
var app = express();
//...
//Configuraciones varias
//...
app.get("/users", function (req, res) {
    return res.render("list users");
});
app.get("/user/:uid", function (req, res) {
    return res.render("show an user");
});
app.get("/articles", function (req, res) {
    return res.render("list articles");
});
app.get("/article/:id", function (req, res) {
    return res.render("show an article");
});
app.get("/article/new", function (req, res) {
    return res.render("new article");
});
http.createServer(app).listen(app.get('port'), function () {
    console.log("http://localhost:" + app.get('port'));
});

Pero esto a la corta se vuelve algo inmanejable. La solución es adoptar un patrón que nos permita extraer las URL a archivos en los que poder juntar las url que se refieran a algo en común (en este ejemplo usuarios por un lado y articles por otro.).

Manos a la obra

crea un directorio llamado routes, crea los archivos “users.js” y “articles.js” y llévate allí las urls.
En el lugar que estaban las URL (dentro de app.js o server.js, como sea que lo hayas llamado.) pon:

var routePath = __dirname + '/routes/';
fs.readdirSync(routePath).forEach(function (file) {
    require(routePath + file)(app);
});

Este snippet se va a encargar de cargar todos los archivos que haya en la carpeta routes. Si te fijas bien vas a ver que está haciendo un require pero le pasa “(app)” al final de este. Eso es porque dentro de nuestros archivos de rutas vamos a devolver funciones que van a ejecutarse ni bien sean cargadas.

Lo ultimo que nos queda es definir la estructura que debe tener cada archivo que esté alojado en routes. Como ya no están en la raíz, vamos a encapsular estas definiciones de rutas dentro de una función, que es la que se va a encargar de hacernos llegar a app (que es la instancia de express que va a recibir nuestras rutas):

users.js:

module.exports = function (app) {
    app.get("/users", function (req, res) {
        return res.render("list users");
    });
    app.get("/user/:uid", function (req, res) {
        return res.render("show an user");
    });
};

articles.js:

module.exports = function (app) {
    app.get("/articles", function (req, res) {
        return res.render("list articles");
    });
    app.get("/article/:id", function (req, res) {
        return res.render("show an article");
    });
    app.get("/article/new", function (req, res) {
        return res.render("new article");
    });
};

Como podemos ver, en cada uno de los archivos que contienen las rutas, hemos metido las rutas dentro de module.exports = function (app){}. Esto sumado a que a cada archivo cargado se le estaba pasando la app por medio del require (require(routePath + file)(app);) todo cobra sentido.

Ya hemos acabado, ya puedes crear tantos archivos .js como tu corazón y lógica dicten, que se van a cargar sin problemas.

Chau!

1263055255_application-javascript

Generar propiedades de un objeto (JSON) dinámicamente.

El caso es el siguiente: Tenemos un objeto al que queremos crearle propiedades anidadas pero nos gustaría no tener que preocuparnos de si sus parent existen. por ejemplo, si tuviera un objeto “miObjeto” y quisiera crearle una función en miObjeto.modulos.ctools.watcher, primero tendría que crear ese path. eso o podemos usar esta función:

/**
 * Genera propiedades de un objeto (JSON) dinamicamente.
 * @returns objeto extendido.
 */
function extend(base, ns_string) {
    var parts = ns_string.split('.'),
        pl, i;
    pl = parts.length;
    for (i = 0; i < pl; i++) {
        //create a property if it doesnt exist
        if (typeof base[parts[i]] == 'undefined') {
            base[parts[i]] = {};
        }
        base = base[parts[i]];
    }
    return base;
}

Y listo, ya podemos extender nuestro objeto de forma dinámica:

var miObjeto = {};
//console.log("Esto va a dar error porque 'modulos.ctools.watcher' no existe");
//console.log(miObjeto.modulos.ctools);
extend(miObjeto, 'modulos.ctools.watcher');
extend(miObjeto, 'settings.general');
miObjeto.modulos.ctools.watcher = function () {
    console.log("Soy una función!");
};
console.log(miObjeto);

Resultado:
resultado-objeto-propiedades-dinamicas
Chau!

Node.js

Preprocesar variables de templates en express framework (nodejs)

Bien, el caso de uso es el siguiente: tenemos varios templates en los que queremos mostrar mensajes al usuario si los hubiera.
Lo normal seria hacer algo así a la hora de renderizar un template:

Para la página principal:

app.get('index', function (req, res) {
    var messages = req.flash();
    var render_options = {
        titulo: "Página principal"
    };
    if (messages.error || messages.info || messages.success) {
        if (messages.error) messages.hasError = messages.error.length > 0;
        if (messages.info) messages.hasInfo = messages.info.length > 0;
        if (messages.success) messages.hasSuccess = messages.success.length > 0;
        render_options.messages = messages;
    }
    res.render('index', render_options);
});

Para la página del usuario:

app.get('user', function (req, res) {
    var messages = req.flash();
    var render_options = {
        titulo: "Perfil de " + req.session.user.name
    };
    if (messages.error || messages.info || messages.success) {
        if (messages.error) messages.hasError = messages.error.length > 0;
        if (messages.info) messages.hasInfo = messages.info.length > 0;
        if (messages.success) messages.hasSuccess = messages.success.length > 0;
        render_options.messages = messages;
    }
    res.render('index', render_options);
});

Bien, la idea se aprecia, constantemente tenemos que trabajarnos la variable “messages” y si hay mensajes la incluimos en las opciones de renderizado del template.

¿El inconveniente? el código se repite, lo que lo hace poco mantenible y ensucia. Solo por dar un ejemplo, podés ver que estamos preparando errores del tipo “error“, “info” y “success“, y si quisieras agregar un nuevo tipo de error llamado “warning“, te las verías p… negras. Bueno se entiende el inconveniente.

Solución: Encapsular en un preprocesador

Express nos da la posibilidad de preparar variables que van a parar al template haciendo uso de app.use() y res.locals.

NOTA importante: da igual el sistema de templates que uses: Jade, Hogan.js, Mustache, Handlebars, etc. Express es agnóstico en este sentido a la hora de preparar variables. Un puntazo.

Bueno, como decía, podemos agregar un app.use() en app.configure(function () {}); (suele estar en app.js, la base de tu aplicación).
Acá está el ejemplo. Hemos quitado la lógica de tratamiento de mensajes y la hemos colocado en este middleware (si, es uno de esos famosos):

app.use(function (req, res, next) {
    var messages = req.flash();
    if (messages.error || messages.info || messages.success) {
        if (messages.error) messages.hasError = messages.error.length > 0;
        if (messages.info) messages.hasInfo = messages.info.length > 0;
        if (messages.success) messages.hasSuccess = messages.success.length > 0;
        res.locals.messages = messages;
    }
    next();
});

Lo mas notable del código anterior es que hemos asignado el resultado a res.locals.messages. res.locals, va a “mergearse” con las variables que uses en res.render() antes de llamar al template.
NOTA: next(); es necesario para que el flow de ejecución siga adelante.

Hecho lo anterior, les presento las versiones simplificadas de los ejemplos que di al principio:

app.get('index', function (req, res) {
    var render_options = {
        titulo: "Página principal"
    };
    res.render('index', render_options);
});
app.get('user', function (req, res) {
    var render_options = {
        titulo: "Perfil de " + req.session.user.name
    };
    res.render('index', render_options);
});

Mucho mejor ¿no?

Chau!