viernes, 30 de octubre de 2015
Aplicaciones web de gestión con Oracle JET. ¿Porqué no habías salido antes?
Me figuraba que sería otro de los "tochos" de esta empresa, con documentación críptica y montones de manuales por leerse. Nada de eso: El producto va como como la seda. Con JET se pueden empezar aplicaciones con un par de clicks, sabiendo que estás sobre un framework muy bien estructurado y que te quita la mayoría de dolores de cabeza típicos de una aplicación de gestión.
Una vez descargada la plantilla, sólo hay que hacer copia-pegar de las "recetas" que cubren una gran cantidad de supuestos de uso o "patterns" que nos encontramos en este tipo de aplicaciones. La plantilla está diseñada para que el código esté ordenado y sea fácil de mantener.
Está basado sobre código abierto (aunque JET no lo es al 100% de momento). Usa, entre otros, jquery y knockout para la sincronización.
Las plantillas vienen por defecto con mobile first, lo que nos ahorra tener que pensar también en el aspecto del renderizado en múltiples plataformas.
Para aplicaciones de gestión es especialmente interesante el apartado de Data collections, podemos asociar los UI widgets a nuestras fuentes de datos de forma bastante fácil.
Sólo necesitamos un sencillo servidor web corriendo en la raiz del proyecto para poder trabajar.
A diferencia de otros frameworks más especializados, JET decide un montón de cosas del front de tu aplicación. El aspecto, menús, interacción,... Esto puede ser bueno si lo que necesitas es concentrarte en el backend.
Lo que me gusta es que trabajas con él de la misma forma en que tú ya estás trabajando: Cuando necesitas algo, lo buscas, le haces copiar-pegar y lo adaptas a tu necesidad.
El contar con el respaldo de una empresa como Oracle también es un tanto a favor en cuanto a la estabilidad y mantenimiento del framework. Oracle quiere meterse en las tablets y los móviles y me da la impresión de que por este camino, ayudando a los desarrolladores, va a conseguirlo.
No es para nada casualidad que hace poco Oracle creaba su centro de soporte para Node y sacara los drivers oficiales (node-oracledb) para conectar este con su gestor de base de datos. La apuesta de Oracle por Javascript y el mobile va muy en serio.
jueves, 17 de septiembre de 2015
Javascript atravesar árbol JSON
El problema
Tenemos el árbol de menú de una aplicación. Cada hoja tiene unos permisos asociados. Sólo queremos mostrar los nodos de los que el usuario tenga algún permiso.
Una posible forma de hacerlo es recorrer el árbol una vez y acumular en los nodos los permisos del nivel por debajo. El recorrido sería en postorden.
Los usuarios tienen grupos de permisos (roles). En el momento de generar el menú de un usuario particular, deberemos volver a recorrer el árbol, esta vez en anchura (por niveles), tomando sólo aquellos nodos que tengan algún permiso coincidente. Si no hay ninguno, no es necesario bajar al siguiente nivel de esa rama.
Árbol de menús
var modulos = [
{permiso: [], descripcion: 'Almacenes', url: '#',
submenus: [
{permiso: ['compras.alb.ver'], descripcion: 'Artículos', url: '/app/articulos'},
{permiso: ['compras.prov.ver'], descripcion: 'Proveedores', url: '/app/proveedores'},
{permiso: ['alm.inv.ver'], descripcion: 'Inventario', url: '/app/inventario'},
{permiso: ['alm.edit'], descripcion: 'Almacenes', url: '/app/almacenes'}
]
},
{permiso: [], descripcion: 'Compras', url: '#',
submenus: [
{permiso: ['compras.pedidos.ver'], descripcion: 'Pedidos', url: '/app/compras/pedidos'},
{permiso: ['compras.albaranes.ver'], descripcion: 'Albaranes', url: '/app/compras/albaranes',
submenus: [
{permiso: ['compras.alb.edt'], descripcion: 'Editar', url: '/app/albaranes/edit'},
{permiso: ['compras.alb.lst'], descripcion: 'Listar', url: '/app/albaranes/list'},
]},
]
},
];
El nodo Almacenes debería contener los permisos de los que tiene por debajo, el nodo Albaranes debería contener [compras.alb.edt, compras.alb.lst] y el nodo Compras [compras.pedidos.ver, compras.albaranes.ver, compras.alb.edt, compras.alb.lst].
Recorrido de un árbol JSON en postorden
Observamos que tenemos tanto objects como arrays: Atravesamos los arrays con forEach y los objetos examinando sus claves con for (var key in obj) . Bajamos hasta la primera hoja de la izquierda, visitando las hermanas para subir después al nodo superior. El proceso se repite de forma recursiva hasta haber visitado todos los nodos. Mantenemos la referencia al nodo inmediatamente superior con parent para poder acumular en él los permisos.
var _und = require("underscore");
// último nodo visitado
var lastObject=null;
/**
* Atraviesa un arbol JSON en postorden
* @param x - el nodo actual
* @param level - sólo para debug, caracter para imprimir delante de los nodos
* @parent - referencia al nodo padre o null
*/
function traverse(x, level, parent) {
if (isArray(x)) {
traverseArray(x, level, parent);
} else if ((typeof x === 'object') && (x !== null)) {
traverseObject(x, level, parent);
} else {
// tipus primitiu
}
}
/**
* Determina si el tipo es array
* @param o - el objeto javascript
* @return true si es un aray
*/
function isArray(o) {
return Object.prototype.toString.call(o) === '[object Array]';
}
function traverseArray(arr, level, parent) {
arr.forEach(function(x) {
traverse(x, level + " ", parent);
});
//console.log(level + "<array>");
}
function traverseObject(obj, level, parent) {
//console.log(level + "<object>");
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
lastObj=parent
traverse(obj[key], level + " ", obj);
}
}
// Acumulamos los permisos en el padre
// usamos _und.union para evitar permisos duplicados
if (obj && obj.descripcion) {
var p=''
if (parent) {
p=parent.descripcion
parent.permiso=_und.union(parent.permiso, obj.permiso)
} else {
p='/'
}
console.log('visitant', obj.descripcion,'amb pare', p);
}
}
Ahora ya sólo queda hacer
traverse(modulos, '')
Para mostrar los menús, podemos poner una marca de visibilidad y enviar el árbol al renderizador de plantillas que sólo mostrará los que tengan visible==true.
var recurseMenus= function(permisos, m) {
_und.each(m, function(md) {
//logger.debug('mirant si menu', md.descripcion, 'te el permís', md.permiso)
// hacemos la intersección del conjunto de permisos del usuario con los del nodo actual
var interseccio=_und.intersection(md.permiso, permisos)
// si el resultado de la intersección es diferente del conjunto vacío el usuario puede ver este menú
if (_und.size(interseccio)>0) {
//logger.debug('te permis de ', md.permiso)
md.visible=true
if (md.submenus) {
recurseMenus(permisos, md.submenus)
}
} else {
//logger.debug('no te el permis')
md.visible = false;
}
})
}
Referencias
miércoles, 15 de julio de 2015
Apuntes de Javascript
Apuntes de Javascript
Traducción/resumen de Common JavaScript “Gotchas”. A mí me ha resultado útil para no terminar con una empanada monumental.
La palabra clave var
var declara una variable y siempre debería usarse puesto que en otro caso la variable se declarará goblamente.
¡Siempre usar var para declarar variables!
¿Porqué hay tantas formas de definir una función? ¿Cuáles son las diferencias?
Encontraremos tres formas comunes de definir una función:
myFunction1 = function(arg1, arg2) {}; // NEVER do this!
function myFunction2(arg1, arg2) {}; // This is OK, but...
var myFunction3 = function(arg1, arg2) {}; // This is best!
La primera define la función y la asigna a una variable globalmente. Tal vez no es lo que deseamos.
La segunda tiene el scope adecuado pero tenemos que tener en cuenta las closures.
La tercera es la mejor ya que es sintácticamente consistente con el punto anterior y no pone la función en el scope global. Incluso podemos mejorarla con
var myFunction5 = function aDifferentName(arg1, arg2) {};
console.log(myFunction5.name); // logs "aDifferentName"
En este caso, name queda definido al nombre de la función lo que puede ser útil para hacer debug y mejora la claridad del código.
La palabra clave this: Cómo se comporta?
Generalmente, no es necesario usar this ya que no se comporta como en el resto de lenguajes OOP. En este sentido, es recomendable seguir el patrón module.
La palabra clave this es un puntero al contexto de ejecución actual. Con un ejemplo se ve mejor:
var myFunction = function()
{
console.log(this);
};
var someObject = {}; // Create an empty object. Same as: new Object();
someObject.myFunction = myFunction; // Give someObject a property
someObject.myFunction(); // Logs Object
myFunction(); // Logs...Window?
La primera llamada logea el objeto someObject porque se ejecuta en el contexto de este. Sin embargo, en la segunda llamada myFunction();se ejecuta desde el contexto de la raiz del navegador y por eso logea el objeto `window’.
Lo importante es recordar que
thisapunta a lo que sea que haya “a la izquierda del punto”.
Qué demonios es una closure?
Es una característica del lenguaje que permite que una variable no se destruya si su valor podría ser requerido en el futuro. Esto es necesario en el manejo de eventos.
Supongamos este código:
// When someone clicks a button, show a message.
var setup = function()
{
var clickMessage = "Hi there!";
$('button').click
(
function()
{
window.alert(clickMessage);
}
);
};
setup();
En un leguaje sin closures, lo más probable es que la variable clickMessage ya no existiera en el momento en que el usuario pulsara el botón. Pero Javascript “sabe” que debe mantener la variable.
Pero es que aún podemos llegar un poco más lejos con algo como esto:
(function()
{
var clickMessage = "Hi there!";
$('button').click
(
function()
{
window.alert(clickMessage);
}
);
})();
En este ejemplo ni siquiera tenemos que dar nombre a la función. Como quiera que hemos terminado el código con () se ejecutará una vez y ya podemos olvidarnos de él con la certeza de que todo lo declarado dentro existirá en el momento en que el usuario haga click.
miércoles, 10 de septiembre de 2014
Javascript herencia con factoría de objetos
Javascript no tiene un soporte claro para la herencia. Tal vez sea debido a que no existe el concepto de clase. En los lenguajes tradicionales, solemos definir la clase como una plantilla de cómo debe ser el objeto y después instanciamos a partir de esa definición.
Además, en Javascript todo es un objeto dinámico. En cualquier momento podemos añadir, quitar o cambiar cualquier propiedad de un objeto sin preocuparnos de la pertenencia a una clase o la necesidad de convertir entre clases.
Si lo que deseamos es la funcionalidad que nos otorga la herencia y preferimos el estilo de construcción de factoría de objetos, es decir, un objeto Function que nos retorna otro objeto con sus propiedades es muy fácil implementar la herencia y la sobreeescritura.
Pongo un ejemplo que se explica por si mismo:
"use strict";
// el objeto base
var Familia=function(fam) {
var obj={};
obj.familia=fam;
// Function en el objeto base
obj.tienePatas=function() {
return (obj.familia==="Hominidae")? true: false;
};
// sobreescritura de Object.toString()
obj.toString=function() {
console.log("FAMILIA ============");
console.log("Familia:", obj.familia);
};
return obj;
};
// objeto que hereda
var Genero=function(fam, gen) {
// obj es una Familia
// "heredamos" en Genero sus propiedades...
var obj=Familia(fam);
// ... y añadimos una propiedad nueva
obj.genero=gen;
// sobreescribimos (otra vez) toString
obj.toString=function() {
console.log("FAMILIA Y GENERO ============");
console.log("Familia:", obj.familia, "Genero:", obj.genero);
};
return obj;
};
// creamos nuevo objeto Familia
var monos=Familia("Hominidae");
monos.toString(); // Hominidae
console.log(monos.tienePatas()); // true
// creamos nuevo objeto Genero
var hombre=Genero("Hominidae", "Homo");
hombre.toString(); // Hominidae Homo
console.log(hombre.tienePatas()); // true
Este método es muy fácil y cómodo pero si tenemos que crear grandes cantidades de objetos es preferible usar prototype ya que ahorra gran cantidad de espacio en memoria.
Written with StackEdit.
Parámetros por defecto en Javascript
Ya sabemos que las funciones en Javascript no son otra cosa que un objeto Function. El resultado de la evaluación del cuerpo de ese objeto es lo que en otros lenguajes llamamos el resultado de la ejecución de la función.
También sabemos que los “parámetros” del objeto Function son, a su vez, objetos. Esto es tan cierto que podemos pasar otra función (otro objeto Function) como parámetro.
Un pequeño inconveniente de esta falta de tipado es que si no pasamos ningún argumento la referencia al objeto pasado queda con el valor especial undefined. Para dar un valor por defecto al objeto pasado podemos hacer:
function myFunction(param) {
// comprobamos que el objeto param esté definido
if (param === undefined) {
param = 0; // le asignamos la primitiva int con valor cero
}
}
o bien, más corto:
function myFunction(param) {
param = param || 0;
}
Written with StackEdit.
martes, 9 de septiembre de 2014
Fundamentos de objetos javascript
En javascript, la tarea de crear objetos se deja al programador el cuál escogerá la mejor estrategia según sus intereses.
Javascript no es Java en el sentido de que es un leguaje basado en objetos donde estos son la entidad fundamental. Difiere de Java en que tiene su propia filosofía acerca de la creación y uso de objetos.
Estas diferencias pueden causar problemas a los programadores que vienen de otros lenguajes y se pierden al intentar aplicar la misma filosofía que Java, o C++ a Javascript. En este sentido, la filosofía de JS se parece más a SmallTalk.
Características de javascript
Javascript no tiene ni clases ni tipos. En JS todo es un objeto (con las excepciones de null y undefined).
Un objeto JS es un contenedor que puede contener una colección de otros objetos.
Primera forma de crear un objeto
El punto de partida es el objeto vacío {}. {}significa que es un objeto y puede contener otros objetos.
Dentro de un objeto se pueden definir los miembros como nombre:objeto separados por una coma. Los nombres se conocen generalmente como las propiedades del objeto.
Por ejemplo:
{
prop1: object1,
prop2: object2,
prop3: {}
};
Nótese que prop3 es el objeto vacío.
Segunda forma de crear un objeto
new Object(); tiene el mismo efecto (casi) que {}, i.e. crea un objeto vacío.
Acceso a las propiedades
Tenemos dos métodos equivalentes para el acceso a las propiedades de un objeto:
object.property;
o
object[property];
La ventaja del segundo es que la propiedad puede ser un String y por lo tanto ser determinada dinámicamente. Por otra parte, la primera versión es más rápida por que se determina en tiempo de compilación.
También podemos formar cadenas de propiedades como
object.property1.property2;
o
object[property1][property2];
Asignar el valor de una propiedad o crear una nueva propiedad
object.property1={}; // asignar
object.property3={}; // crear y asignar una nueva propiedad
Todos los objetos javascript son dinámicos y por lo tanto podemos crear nuevas propiedades en cualquier momento.
La variable de objeto global
Para poder usar las variables tenemos que tener un método para seguirles la pista una vez creadas. Pero en Javascript la idea de variable es un tanto sutil.
JavaScript proporciona un objeto estándar llamado global object
En general, este objeto global es llamado this, aunque si estamos ejecutando en un navegador es llamado window.
Atención: this se refiere al objeto global siempre que esté fuera de una función.
Podemos crear propiedades de alcance (scope) global sencillamente dando propiedades a this fuera de una función:
this.myObject={};
Diferentes formas de crear variables globales
myObject={};var myObject; myObject={};var myObject={};
Todas ellas se traducen en
this.myObject={};
En Javascript no existen las variables globales, sólo propiedades del objeto global.
Recodar que this dentro de una función tiene un significado distinto.
Hoisting
Para hacer las cosas un poco más interesantes, hay una sutil diferencia entre:
this.property=value;
y
var property=value;
La segunda versión en realidad hace que podamos usar property antes de ser declarada. La forma en que JS hace esto es muy sencilla:
- Escanea todo el código en busca de declaraciones
var. - Lleva automáticamente la declaración al principio del código con lo que todas las variables dentro del contexto quedan declaradas y por tanto podemos usarlas en cualquier punto del programa.
- Cuando la ejecución llega a la línea
var property=value;le asigna el valor.
Semántica de las referencias a objetos
var myObject1={};
var myObject2=myObject1;
Tanto myObject1 como myObject2 referencian exactamente al mismo objeto. Un cambio en uno será visible en el otro.
Objetos que vienen con el lenguaje
Hay una serie de objetos que ya vienen con Javascript, uno de ellos es el objeto String.
new String("Hola que tal");
Crea un nuevo objeto cada vez que es llamado. Por ejemplo, podríamos tener un objeto tal como:
var myAddress={
Name: new String("Pere");
Address: new String("Eivissa");
};
console.log(myAddress.Name);
console.log(myAddress['Address']);
El objeto String es tan importante que podemos abreviar su creación llamando sencillamente a
alert('hola');
en vez de
alert(new String('hola'));
Pero en realidad Javascript está usando la segunda versión en todo caso.
El objeto Number
Podemos usar tanto
var num= new Number(3);
como
var num=3;
Lo que ocurre es que la segunda versión está ligeramente optimizada (sería un tipo primitivo en otros lenguajes) pero en el mismo momento en que hacemos esto
num.toString();
Se convierte automáticamente al objeto Number.
No se pueden añadir propiedades a un objeto primitivo.
En cambio, podemos añadir nuevas propiedades al objeto Number sin mayor problema.
Number.prototype.porDos=function() {
return this*2;
};
var num=new Number(3);
console.log(num.porDos()); // 6
Expresiones e inmutabilidad
Una expresión toma datos y los combina para producir nuevos datos.
var res=2*3+4; // res=10
pero
var n1= new Number(2);
var n2= new Number(3);
n2.age=13;
var n3=n1+n2;
console.log(n3); // 5
console.log(n3.age); // undefined
Esto ocurre porque las expresiones que combinan objetos siempre devuelven un nuevo objeto del tipo original (Number).
Disclaimer
Esta entrada es resultado de apuntes tomados al vuelo leyendo la serie de artículos de javascript escrita por Ian Elliot en i-programmer. No pretende ser una traducción al español ni nada parecido, es un simple registro para mi uso personal. Debe referirse al original para su lectura.
Fuente: i-programmer.info
Written with StackEdit.
Construcción de objetos en javascript
Construcción de objetos
Podemos construir un objeto con
var myPoint{ x:0; y:0};
Pero, por supuesto, esto sólo nos daría un copia del objeto. ¿Cómo creamos más de una instancia?, pues usando un object factory:
Point=function() {
return {x:0; y:0};
};
var myPoint= Point();
Sin embargo, así como el objeto va creciendo y se va sofisticando, es complicado de mantener; Una mejor alternativa es usar:
Point=function() {
var obj={};
obj.x=x;
obj.y=y;
return obj;
};
var myPoint= Point(1,2);
Acceso a los miembros de un objeto
Recordamos cómo dar acceso público o privado a los miembros de un objeto, aunque sabemos que en javascript no existen métodos, sólo referencias a objetos (tales como el objeto Function).
Point=function(x,y) {
var obj={};
// variables públicas
obj.x=x;
obj.y=y;
// variable privada
var privada = 10;
// este "método" es privado
function resta() {
return obj.x-obj.y;
};
// este "método" es público
obj.add=function() {
return obj.x+obj.y;
};
return obj;
};
var myPoint=Point(1,2);
console.log(myPoint.add()); // 3
myPoint.x=4;
console.log(myPoint.add()); // 6
- add es público por que se devuelve con el objeto.
- obj no existe fuera de myPoint.
- obj es una variable privada para la instancia de objeto que hemos creado.
- cualquier variable local declarada dentro del factory es tratada como privada.
Métodos de construcción
Diferencias entre new y var
Los dos métodos de construcción existentes son igualmente correctos: Usando la palabra clave new o creando un object-factory, pero posteriormente haremos una precisión respecto al uso de new y this.
new
Point=function(x,y) {
this.x=x;
this.y=y;
this.add=function() {
return this.x+this.y;
};
// no es necesario devolver this.
};
var myPoint=new Point(1,2);
console.log(myPoint.add()); // 3
myPoint.x=4;
console.log(myPoint.add()); // 6
var
Point=function(x,y) {
var obj={};
obj.x=x;
obj.y=y;
obj.add=function() {
return obj.x+obj.y;
};
return obj;
};
var myPoint=Point(1,2);
console.log(myPoint.add()); // 3
¿Cuál es la diferencia entre los dos?. La diferencia fundamental es que la versión con new devuelve el objeto this automáticamente.
Atención
Cuando nos referimos a this, estamos hablando del contexto de ejecución actual (la closure actual) dentro de una función.
this fuera de una función se refiere al objeto global this.
this dentro de una función se refiere al contexto de ejecución (la closure) actual.Cuidado con las confusiones.
this como objeto global fuera de una función no es lo mismo que el contexto raiz.
x=3;
this.x=5;
console.log('x es',x,'y this.x es', this.x);
// x es 3 y this.x es 5
Es como si al principio del programa tuviéramos el objeto llamado this instanciado de la siguiente manera:
var this={};
y cada vez que creamos un objeto con new se nos añadiera dicha línea al principio del objeto de forma automática.
Mejor estilo
Según el artículo de Ian, la versión con new suena mejor al programador que viene de otros lenguajes, pero la versión con variable es más javascript.
Disclaimer
Esta entrada es resultado de apuntes tomados al vuelo leyendo la serie de artículos de javascript escrita por Ian Elliot en i-programmer. No pretende ser una traducción al español ni nada parecido, es un simple registro para mi uso personal. Debe referirse al original para su lectura.
Fuente: i-programmer.info
Written with StackEdit.
lunes, 25 de agosto de 2014
Patrón javascript para OOP
Se refiere a usar un estilo de programación orientada a objetos en javascript.
Las funciones anónimas crean una closure dentro de ellas permitiendo que todo el scope quede oculto al exterior y accesible al interior y con ello ya tendríamos solucionado el acceso “private”.
Pero ¿Cuál sería el mejor método para hacer hacer el acceso explícitamente público ?. Pues usando el siguiente patrón llamado Yahoo Module Pattern que básicamente pone dentro del return todo lo que queramos hacer “public”.
Tomando el ejemplo de Robert Nyman,
var person = function () {
// Acceso Privado
var name = "Robert";
// Acceso Público
return {
getName : function () {
return name;
},
setName : function (newName) {
name = newName;
}
};
}(); // esta sintáxis hace que la función se autoejecute
alert(person.name); // Undefined
alert(person.getName()); // "Robert"
person.setName("Robert Nyman");
alert(person.getName()); // "Robert Nyman"
Observamos cómo hacemos name privada y las funciones de getter y setter públicas.
Si no necesitamos que la función se autoejecute (como es habitual en Node), podemos usar una sintaxis alternativa (pero no tengo claro que equivalente) y que personalmente prefiero a la anterior; Se trata de usar this para referenciar los objetos que queramos hacer públicos.
function Prova() {
// parte privada
var nombre="pere";
function mayus(algo) {
return algo.toUpperCase();
}
// parte pública
this.getName=function() {
// accedemos a la funcion
// "privada" dentro
// del closure
return mayus(nombre);
}
this.setName=function(newName) {
nombre=newName;
}
} // creamos el objeto con new
var p=new Prova();
console.log(p.nombre); // undefined
console.log(p.mayus("Pere Vilas")); // Error: has no method
console.log(p.getName()); // devuelve PERE
Referencias en javascript
Un caso de referencia incorrecta, sacado de aquí:
function addLinks () {
for (var i=0, link; i<5; i++) {
link = document.createElement("a");
link.innerHTML = "Link " + i;
link.onclick = function () {
alert(i);
};
document.body.appendChild(link);
}
}
window.onload = addLinks;
Clickando en cualquiera de los links siempre se referirá a Link5 ya que el onclick no se ejecuta.
Para solucionarlo, debemos crear una closure en el onclick para que tome el valor de i en ese momento:
function addLinks () {
for (var i=0, link; i<5; i++) {
link = document.createElement("a");
link.innerHTML = "Link " + i;
link.onclick = function (num) {
return function () {
alert(num);
};
}(i);
document.body.appendChild(link);
}
}
window.onload = addLinks;
viernes, 6 de diciembre de 2013
Enviar ficheros al servidor que residen en la máquina cliente mediante http POST
También es cierto que por tema de "atomicidad" queda más bonito enviar imágenes y datos en un solo POST que sólo puede o tener éxito o fallar.
Si en concreto usamos chrome en el cliente, podemos hacer un sencillo "work arround" instalando una extensión de chrome que pida la lectura de unos ficheros en concreto y dándole permisos. Esto tiene la ventaja de que hacemos un solo POST con toda la información necesaria.
Para acceder a los ficheros en el cliente, primero creamos el manifiesto de la extensión de chrome con la lista de ficheros a los que queremos acceder, que deben estar todos en el mismo directorio. El manifiesto también lo guardamos en ese directorio.
manifest.json
{
"name": "File holder",
"manifest_version": 2,
"version": "1.0",
"web_accessible_resources": ["imagen1.jpg", "imagen2.jpg", "imagen3.jpg"]
}
Ahora, instalamos la extensión: Vamos a chrome->extensions, activamos developer mode y hacemos Load unpacked extension. A partir de este momento, podemos acceder las imágenes locales desde el navegador con
donde [app-id] es el id de aplicación que nos sale cuando instalamos la extensión. Ya podemos acceder a los ficheros locales con el protocolo chrome-extension, por ejemplo con
Podemos enviar la imagen al servidor mediante un POST, así:
$("#bt_envia").on("click", function (e) {
var x = new XMLHttpRequest();
x.onload = function() {
// Create a form
var fd = new FormData();
fd.append("upfile", x.response);
fd.append("csrfmiddlewaretoken", "{{ csrf_token }}");
// Upload to your server
var y = new XMLHttpRequest();
y.onload = function() {
alert('File uploaded!');
};
y.open('POST', '/gestion/prova/');
y.send(fd);
};
x.responseType = 'blob';
x.open('GET', 'chrome-extension://debeanplnpndkfnlbalbmkikofkghfmk/foto.jpg');
x.send();
});
Fuente: varios en stackoverflow y
http://stackoverflow.com/questions/10611796/is-there-any-way-to-load-a-local-js-file-dynamically
Django hacer POST desde javascript con contenido binario
Para desactivar este funcionamiento y hacer el envío "raw" tenemos que poner el responseType como 'blob', de esta forma:
$("#bt_envia").on("click", function (e) {
var x = new XMLHttpRequest();
x.onload = function() {
// Create a form
var fd = new FormData();
fd.append("upfile", x.response); // x.response is a Blob object
fd.append("csrfmiddlewaretoken", "{{ csrf_token }}");
// Upload to your server
var y = new XMLHttpRequest();
y.onload = function() {
alert('Fichero subido!!');
};
y.open('POST', '/gestion/prova/');
y.send(fd);
};
x.responseType = 'blob';
x.open('GET', 'http://planetary.s3.amazonaws.com/assets/images/spacecraft/2013/20131108_2013-3896_f537.jpg', true);
x.send();
En la parte del servidor, los FILES nos vendrán directamente en el formato nativo, así que sólo tenemos que tratarlos directamente, por ejemplo grabando una imagen en un fichero.
def prova(request):
#print str(request.body)
# veure https://docs.djangoproject.com/en/dev/topics/http/file-uploads/
print "Els files son ", str(request.FILES)
f = request.FILES['upfile']
with open('c:/prova.jpg', 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
return HttpResponse('Mu guay')
Fuente: varios en stackoverflow
sábado, 16 de noviembre de 2013
Uso del atributo data en html5
El único requerimiento es que el nombre del atributo de la etiqueta debe empezar por data-
Así, esto es válido en html5:
E incluso podemos pasar datos en formato json:
Realmente útil y además valida.
Hey!, muy guay! ¿Pero qué hay acerca del tratamiento de estos atributos en la hoja de estilos?. Pues también mola porque podemos tratar los data- como cualquier otro atributo.
Vamos a saludar el santo a todos clientes que se llamen Pepe con CSS:
Rodrígez Pérez, José
Y la hoja de estilo:
div[data-nombre="Pepe"] {
background-color: red;
}
div[data-nombre="Pepe"]:after {
content: attr(data-saludo);
}
Para saber más:
htmldoctor
tutsplus
jueves, 20 de junio de 2013
Sondear (refrescar) a largo plazo con javascript jquery / jquery javascript long polling
<meta http-equiv="refresh" content="5"/>
Pero si queremos refrescar sólo un div y queremos estar seguros de que el refresco se realice incluso después de que falle alguna de las peticiones, podemos hacer:
$(document).ready(function(){
function doPoll() {
$.post('/pagina/').done(function(data) {
$('#contenedor').html(data);
}).always(function() { setTimeout(doPoll, 5000); });
}
doPoll();
});Nótese el empleo de always que es una manera elegante de no tener que pelearnos con la posibilidad de que falle una de las peticiones y el div se quede sin refrescar.
lunes, 30 de enero de 2012
Obtener valor de radiobutton con JQuery
$("input[name='nombre de grupo']:checked").val(); Fuente: Blog de Victor Puertas