Similar Posts
Colección de calendarios Javascript
En muchas aplicaciones web, la utilización de un campo fecha suele ser algo habitual. Es preferible que el usuario no tenga que escribir ninguna fecha, sino que esta se tenga que introducir mediante un control de tipo calendario, evitando asà que ocurran ciertos errores y facilitando la labor al usuario. Tened en cuenta que hay diversos formatos DD/MM/YYYY, MM/DD/YYYY, DD-MM-YYYY, …
Espero que esta lista de calendarios realizados mediante Javascript os pueda ser de utilidad:
- The DHTML / JavaScript Calendar: visible mediante popup o en plano, adecuado para seleccionar fecha y hora, válido para la mayorÃa de los navegadores, admite CSS, themes, navegación por teclado, muestra los dÃas de los meses adyacentes, traducido a varios idiomas, dÃas especiales resaltados de distinta manera.
- Calendar Popup: se muestra un popup mediante ventana o usando capas, implementado para que tenga el aspecto de Microsoft Outlook, fácil de usar.
- Zapatec Calendar: script comercial, muy completo, admite varios meses, válido para la mayorÃa de los navegadores, permite varios formatos de fecha y multiple selección de dÃas.
- ScriptCalendar: versión comercial, basado en objetos, fácil de usar y de modificar, válido para la mayorÃa de los navegadores.
- CalendarXP: versión comercial, muy completo que a parte del calendario pequeño, muestra un calendario grande que admite más detalles.
- Tigra Calendar: el que más me ha gustado, cada campo es seleccionable, se puede adjuntar a un campo existente, meses seleccionables mediante scrolling y muchas cosas más.
- Epoch Calendar: básico, de aspecto atractivo y válido para ser usado en aplicaciones AJAX.

Hapi.js + Vue.js modelos mejorados
En este caso voy a explicar cómo añadir una ruta en el backend para gestionar usuarios.
Antes de nada vamos a instalar tres paquetes:
- @hapi/joi para validar los datos de entrada
- @hapi/boom para mostrar errores HTTP de forma sencilla
- bcrypt para encriptar la contraseña
npm i @hapi/joi
npm i @hapi/boom
npm i bcrypt
Tendremos que añadir la ruta al manifest de glee
const manifest = {
server: {
port: Config.get( '/server/port' ),
},
register: {
plugins: [
{
plugin: './api/home',
},
{
plugin: './api/user',
},
{
plugin: './plugins/db',
options: Config.get( '/db' ),
},
],
},
};
Ahora solo falta crear el controlador para las rutas de usuarios, dos en este caso:
- GET /user/[user] para recuperar un usuario
- PUT /user para crear un nuevo usuario
Lógicamente aún no hay nada de autenticación, por lo que cualquiera puede crear un usuario realizando una llamada PUT a la URL indicando userName, email y password.
Para comprobar la validez de los datos introducidos, usaremos joi. Usando las opciones de la ruta, indicaremos las reglas que deberá cumplir cada parámetro introducido. Así, para recuperar un usuario, se comprobará que user sea string, alfanumérico y que tenga una longitud de 3 a 20 caracteres:
validate: {
params: {
user: Joi.string().alphanum().min( 3 ).max( 20 ),
},
},
Así de fácil.
En el caso de comprobar los datos de entrada de la llamada PUT, en vez de usar params, usaremos payload:
validate: {
payload: {
userName: Joi.string().alphanum().min( 3 ).max( 20 ).required(),
email: Joi.string().email().required(),
password: Joi.string().min( 8 ).required(),
},
},
Por último mostrar el código para crear un nuevo usuario. Primero se comprueba si existe un usuario con ese nickname o email. Si es así, se devuelve error usando boom, si no, se genera la contraseña encriptada (aquí no me he molestado mucho en ello, ya lo haré más adelante), y se crea el usuario usando el método create de moongose:
/**
* Route handler
*
* @param {object} request
* @param {object} h Hapi object
* @returns {object}
*/
handler: async( request, h ) => { // eslint-disable-line
try {
// TODO: Add role
const user = await User
.findOne( {
$or: [
{ userName: request.payload.username },
{ email: request.payload.email },
],
} )
.exec();
if ( user ) {
return Boom.badData( 'User exists' );
}
const password = await bcrypt.hash( request.payload.password, Config.get( '/hash/PASSWORD_HASH' ) );
const userData = Object.assign( {}, request.payload, { password } );
const newUser = await User.create( userData );
return newUser ?
{
response: true,
message: 'User created',
userId: newUser.id,
} :
Boom.boomify( {
response: false,
message: 'There was an error during user creation',
}, { statusCode: 400 } );
} catch ( error ) {
return Boom.badImplementation( 'Error', { error } );
}
},
Como último apunte, he modificado la configuración para que admita ficheros .env con los datos necesarios.
Como siempre te puedes bajar el código aquí
Añadir el sistema grid de Bootstrap al tinymce de WordPress
Uno de los problemas que hay en el editor de WordPress es que algunas veces los themes tienen diseños específicos que no se muestran en el editor. Actualmente, el uso de Bootstrap está cada vez más extendido, por lo que es buena idea añadir la opción de meter columnas en los posts de forma sencilla.
Lo primero que deberemos hacer es añadir en el functions.php el código necesario para añadir un botón al TinyMCE:
add_action( 'init', 'sw_mce_buttons' );
// Filtros para añadir los botones
function sw_mce_buttons() {
add_filter( "mce_external_plugins", "sw_mce_add_buttons" );
add_filter( 'mce_buttons', 'sw_mce_register_buttons' );
}
// Añade el script del plugin tinymce
function sw_mce_add_buttons( $plugin_array ) {
$plugin_array['iqn'] = get_template_directory_uri() . '/js/tinymce-plugin.js';
return $plugin_array;
}
// Un nuevo botón que se identifica como 'bootstrap'
function sw_mce_register_buttons( $buttons ) {
array_push( $buttons, 'bootstrap' );
return $buttons;
}
// Añadimos el css de bootstrap y uno propio para personalizar cosas
function sw_mce_css($wp) {
$wp .= ',' . get_bloginfo('stylesheet_directory') . '/bootstrap/bootstrap.min.css'.',' . get_bloginfo('stylesheet_directory') . '/css/tinymce.css';
return $wp;
}
add_filter( 'mce_css', 'sw_mce_css' );
Después tenemos que crear el javascript para el plugin de TinyMCE:
(function() {
// Creamos el plugin
tinymce.create('tinymce.plugins.iqn', {
init : function(ed, url) {
// Muestra el dialogo que permite personalizar las columnas
// Mostrará una caja de texto donde se pondra el ancho de la columna
// de 1 a 12, y cuando se indique un valor, automáticamente se añadirá otra columna
function bootstrapDialog() {
var html = '<div class="bootstrap-dialog">';
html += '<p class="howto">Añade columnas basadas en el sistema <a href="http://getbootstrap.com/css/#grid">grid de Bootstrap</a></p>';
html += '<p>Rellena el ancho (1-12) de cada celda. Nuevas celdas aparecerán automáticamente</p>';
html += '<div class="columns_container"><input type="text" class="column_width" /></div>';
html += '<p><input type="checkbox" id="new_row" name="new_row" /> <label for="new_row">Añadir nueva fila</p>';
html += '</div>';
var panel = {
type: 'container',
html: html
};
// Abre el dialogo
win = ed.windowManager.open({
title: "Columnas de Bootstrap",
spacing: 10,
padding: 10,
items: [panel], // el panel creado antes
buttons: [ // Botones
{text: "Insertar", subtype: 'primary', onclick: function() {
var content = ed.getContent();
var html = ' ';
// Si se marca la casilla, se añade una fila
if (jQuery('#new_row:checked').length == 1) html += '<div class="row">';
// Por cada columna, se crea una capa
jQuery('.column_width').each(function() {
var $this = jQuery(this);
if ($this.val()) html += '<div class="col-sm-'+$this.val()+'">Columna tamaño '+$this.val()+'</div>';
});
if (jQuery('#new_row:checked').length == 1) html += '</div>';
ed.execCommand('mceInsertContent', false, html);
win.close();
}},
{text: "Cerrar", onclick: function() {
win.close();
}}
]
});
}
ed.addButton('bootstrap', {
title : 'Columnas Bootstrap',
onclick: bootstrapDialog
});
},
createControl : function(n, cm) {
return null;
},
getInfo : function() {
return {
longname : 'Bootstrap columns',
author : 'SentidoWeb',
version : "0.1"
};
}
});
// Register plugin
tinymce.PluginManager.add( 'iqn', tinymce.plugins.iqn );
})();
jQuery(document).ready(function() {
// Se crea una casilla nueva si se actualiza el contenido de la última
jQuery('body').on('keyup', '.column_width', function() {
var $this = jQuery(this);
var $inputs = jQuery('.column_width');
if($this.val()) {
if ($inputs.index(this) == $inputs.length - 1) {
$this.after('<input type="text" class="column_width" />');
}
}
});
});
Y ya por último, crearnos el fichero tiniymce.css que se incluirá en el contenido del editor. Yo simplemente he recuadrado los elementos para que se diferencien en el editor:
.row {padding: 4px; border: 1px dashed #bbb;}
.col-sm-1,
.col-sm-2,
.col-sm-3,
.col-sm-4,
.col-sm-5,
.col-sm-6,
.col-sm-7,
.col-sm-8,
.col-sm-9,
.col-sm-10,
.col-sm-11,
.col-sm-12 {xmargin: 4px; border: 1px dotted #ccc;}
Y si modificáis el diseño del admin, podéis aprovechar ese css para añadir el css necesario para el botón.
i.mce-i-bootstrap {
font: normal 20px/1 'dashicons';
padding: 0;
vertical-align: top;
speak: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
margin-left: -2px;
padding-right: 2px;
}
i.mce-i-bootstrap:before {
content: '\f479';
}
.bootstrap-dialog p {padding: 5px 0;}
.bootstrap-dialog p a {color: #0074A2; text-decoration: underline;}
.mce-container .columns_container {border: 1px solid #F0f0f0; padding: 20px; border-radius: 4px; margin: 10px 0;}
.mce-container .columns_container input.column_width {
margin-right: 5px;
padding: 9px 3px;
text-align: center;
width: 39px;
}
QuickSearch: filtro de contenido con jQuery
QuickSearch es una librería bastante interesante que permite filtrar el contenido de elementos que contengan cierto texto. Tan solo hay que pasar una lista de elemtos y estos los filtrará para mostrar solo aquellos que cumplan cierto filtro de texto.
Se puede pasar lista de elementos (ul), párrafos, tablas, … Se le puede indicar el texto o la imagen que muestre que se está filtrando datos, indicar retraso, añadir clases css, …
QuickSearch
Vía / WebAppers
Evitar el caché en las hojas de estilo
Algo que suele ocurrir con frecuencia es que al realizar cambios en la hoja de estilos, estos no se vean reflejados en la página por el caché del navegador.
Para evitar esto, tan solo es necesario un script que cargue los estilos y que le añada un parámetro GET que sea único para que el navegador lo entienda como un fichero nuevo. En este caso el parámetro es la fecha.
function loadStyleSheets(stylelist) {
var head = $$("head")[0];
var date = new Date();
var dateString = Date.parse(date.toString());
for(var i = 0; i < stylelist.length; i++) {
var link = document.createElement("link");
link.href="style/" + styleList[i] + "?" + dateString;
link.type = "text/css";
link.rel = "stylesheet";
head.appendChild(link);
}
}
En este caso el autor hace uso de la función de Prototype $$, pero se podrÃa hacer sin el uso de este framework.
Como consejos sobre el mismo tema yo añadirÃa dos:
- si estás trabajando en local y no ves los cambios, carga en el navegador directamente el fichero .css que hayas modificado, asà los cambios aparecerán, luego los podrás ver en la página.
- si la página se crea mediante PHP le puedes añadir a la etiqueta link el parametro GET directamente:
<link rel="stylesheet" href="estilos.css?refresh=<?php echo time(); ?>" />
JS3D: librería 3D de javascript
Ya hace tiempo hablamos de una librerÃa 3D en Javascript, ahora se trata de otra librerÃa que trata elementos como puntos y trabaja sobre ellos.
Tan solo habrá que incluir la librerÃa y una capa que funciona como tapiz para que se pueda empezar a usar. Se pueden realizar rotaciones, traslaciones y escalas.
JS3D
Ejemplo
VÃa / dzone