A la hora de darle una funcionalidad más enfocada a aplicaciones de escritorio (por ejemplo con un editor WYSIWYG), suele ser necesario usar combinaciones de teclas CONTROL+tecla para ejecutar ciertas acciones.
Capturar la combinacion CTRL+tecla en javascript es muy sencillo:
var isCtrl = false;
document.onkeyup=function(e){
if(e.which == 17) isCtrl=false;
}
document.onkeydown=function(e){
if(e.which == 17) isCtrl=true;
if(e.which == 83 && isCtrl == true) {
// acción para CTRL+S y evitar que ejecute la acción propia del navegador
return false;
}
}/
La explicación es sencilla, cuando se pulsa CTRL+tecla se producen dos eventos de teclado, por lo que no es posible saber si se ha ejecutado en una sola llamada. Por ello primero comprobamos si se pulsa la tecla CTRL y se pone un flag a verdadero y luego dependiendo de la tecla que queramos, si se detecta que se pulsa y está el flag activo, se realiza la acción. Hay que devolver false para que el navegador no ejecute la acción que tiene por defecto. Cuando se deja de pulsar la tecla CTRL se pone el flag a false.
Interesante script que usa canvas para detectar rostros en las fotografías. Se basa en openCV y en el post de John Resig para evitar un captcha.
Permite la opción de reconocer una cara o varias caras, este último lo he probado con una foto y no me ha funcionado, pero como bien dice el autor, aún tiene que mejorar más el script.
Interesante opción para servicios como Facebook o Flickr para sus opciones de asociar elementos (usuarios, comentarios, …) a las fotografías. También es útil para avisar de que no se ha subido una cara cuando alguien cambia de avatar. Face detection in javascript + canvas
Vía / @rafabayona
Aunque el HTML5 no está disponible en todos los navegadores, no es mala idea ir incluyendo en nuestras webs aplicaciones que hagan uso de HTML5, e ir dándole un poco de vidilla al asunto y no estar pendientes de Internet Explorer. Por ello, este script nos puede venir muy bien:
function detectBrowserCapabilities(){
var res = new Array();
res["userAgent"] = navigator.userAgent;
var hasWebWorkers = !!window.Worker;
res["workersFlag"] = "" + hasWebWorkers;
var hasGeolocation = !!navigator.geolocation;
res["geoFlag"] = "" + hasGeolocation;
if (hasGeolocation) {
document.styleSheets[0].cssRules[1].style.display = "block";
navigator.geolocation.getCurrentPosition(function(location) {
res["geoLat"] = location.coords.latitude;
res["geoLong"] = location.coords.longitude;
});
}
var hasDb = !!window.openDatabase;
res["dbFlag"] = "" + hasDb;
var videoElement = document.createElement("video");
var hasVideo = !!videoElement["canPlayType"];
var ogg = false;
var h264 = false;
if (hasVideo) {
ogg = videoElement.canPlayType('video/ogg; codecs="theora, vorbis"') || "no";
h264 = videoElement.canPlayType('video/mp4;
codecs="avc1.42E01E, mp4a.40.2"') || "no";
}
res["videoFlag"] = "" + hasVideo;
if (hasVideo){
var vStyle = document.styleSheets[0].cssRules[0].style;
vStyle.display = "block";
}
res["h264Flag"] = "" + h264;
res["oggFlag"] = "" + ogg;
return res;
}
Nunca se para de aprender, y de John Resig menos. DocumentFragments son contenedores ligeros que pueden almacenar objetos DOM de Javascript. Yo ni había oído hablar de ellos y la verdad es que su uso es sencillo y mucho más potente que trabajar con el DOM normalmente (de 2 a 3 veces más rápido).
El ejemplo que muestra John lo dice todo y muy fácil. Primero creamos unos elementos para luego insertarlos (de forma normal y con DocumentFragments):
var div = document.getElementsByTagName("div");
for ( var i = 0; i < div.length; i++ ) {
for ( var e = 0; e < elems.length; e++ ) {
div[i].appendChild( elems[e].cloneNode(true) );
}
}
Y por último el nuevo método:
var div = document.getElementsByTagName("div");
var fragment = document.createDocumentFragment();
for ( var e = 0; e < elems.length; e++ ) {
fragment.appendChild( elems[e] );
}
for ( var i = 0; i < div.length; i++ ) {
div[i].appendChild( fragment.cloneNode(true) );
}
Resumiendo, mucho más eficiente y sencillo de usar. Seguro que para la próxima versión de jQuery nos ofrece esta implementación.
Lo bueno de los SVG es que puedes modificarlos mediante CSS directamente en el HTML, el único problema es que el SVG debe estar incrustado en el HTML, no mediante una imagen <img>, ni mediante la propiedad content de CSS.
Encontré un script muy bueno que te modifica una etiqueta img que contiene un SVG por su contenido SVG real. El problema viene cuando yo añado el SVG como una propiedad content:
.class {
content: url('imagen.svg');
}
Para ello he modificado el script anterior para que coja la propiedad content de los selectores CSS que se indiquen y añada el SVG directamente al elemento:
jQuery(document).ready(function() {
var replaceWithSVG = function(selector, url) {
jQuery('').appendTo('head');
jQuery.get(url, function(data) {
// Replace image with new SVG
jQuery(selector).prepend(data.replace(/<\?xml[^>]+>/, ''));
}, 'text');
}
var selectors = ['.site-title a', '.btn-video']
for(var i in selectors) {
var selector = selectors[i];
var url = window.getComputedStyle(
document.querySelector(selectors[i]), ':before'
).getPropertyValue('content');
url = url.replace(/url\(["']?([^'"\)]+)["']?\)/, '$1');
replaceWithSVG(selectors[i], url);
}
});
Como ya dije, esta aplicación estará basada en Mongodb, y usaremos mongoose como ODM.
El primer paso es instalar mongoose:
npm i mongoose
Una vez instalado crearemos un controlador que nos permita usar la BD en toda la aplicación Hapi.js. Para ello haremos uso de los decorate del servidor. Los decorations permite extender objectos ofrecidos por Hapi.js, en nuestro caso server y request. Usando un plugin nos conectaremos a mongodb usando mongoose y añadiremos ese objecto con los decorate.
Creamos el fichero /plugins/db.js con el siguiente código:
/**
* DB controller
*
* It uses Mongoose and "stores" it in the server and the request using `decorate`
*/const mongoose = require( 'mongoose' );
exports.plugin = {
name: 'db',
register: asyncfunction( server, options ) {
mongoose.connect( options.url, { useNewUrlParser: true } );
const db = mongoose.connection;
// eslint-disable-next-line
db.on( 'error', console.error.bind( console, 'connection error:' ) );
db.once( 'open', function() {
server.decorate( 'server', 'db', mongoose );
server.decorate( 'request', 'db', mongoose );
// eslint-disable-next-lineconsole.log( 'DB connected' );
} );
},
};
Para configurar la conectividad a mongodb tendremos que añadir los datos a la /config/index.js
Ya tenemos casi todo configurado, ahora vamos a empezar con un ejemplo creando un esquema de moongose que nos permite acceder a colecciones de mongodb.
Lo más común es tener una colección de usuarios, que tendrá los siguientes campos:
userName: de tipo String,
firstName: de tipo String,
lastName: de tipo String,
email: de tipo String,
role: que referencia a otro elemento de otra colección,
isEnabled: de tipo Boolean,
password: de tipo String,
resetPassword: un objeto representado por:
hash: de tipo String,
active: de tipo Boolean,
También crearemos un método estático que devuelva todos los elementos de la colección users para realizar pruebas:
/**
* User model based on Mongoose
*/const mongoose = require( 'mongoose' );
const Schema = mongoose.Schema;
// Mongoose schemaconst userSchema = new mongoose.Schema( {
userName: String,
firstName: String,
lastName: String,
email: String,
role: Schema.Types.ObjectId,
isEnabled: Boolean,
password: String,
resetPassword: {
hash: String,
active: Boolean,
},
} );
/**
* User static model findAll
*
* @returns {array}
*/
userSchema.static( 'findAll', asyncfunction() {
const result = awaitnewPromise( ( resolve, reject ) => {
this.model( 'User' ).find( {} ).exec( ( error, data ) => {
if ( error ) {
reject( error );
}
resolve( data );
} );
} );
return result;
} );
const User = mongoose.model( 'User', userSchema );
module.exports = User;
Ya está todo, ahora solo modificamos el handler de la ruta home.js para mostrar los valores de findAll:
¿Sabías que en javascript una función puede contener a otras? Pues ahora ya lo sabes. Fíjate en el siguiente código:
function barrioSesamo() {
function epi() {
alert(‘hola Blas’);
}
function blas() {
alert(‘hola Epi’);
}
epi();
blas();
}
barrioSesamo();
// el navegador nos presentará un par
// de alertas, a saber, “hola Blas” y
// “hola Epi”
Nada impresionante, por el momento. Lo interesante del asunto es que, al definir la función `epi` dentro de la función `barrioSesamo`, el ámbito de la misma (scope) queda limitado, de manera que solo podemos llamar a `epi` desde su propio barrio.
Vale, sigo sin impresionarte.