O al menos en Firefox. Se trata de que si quiero obtener el timestamp de una fecha usando el método Date.UTC me devuelve datos incorrectos.
Por ejemplo, en esta llamada Date.UTC(2008, 3, 2, 18, 33, 32) (el mes es abril porque empieza desde 0), se verá que da un el timestamp 1207161212000, mientras que si creamos un objeto Date y obtenemos su timestamp (new Date(2008, 3, 2, 18, 33, 32)).getTime() obtenemos el timestamp 1207154012000, habiendo 2 horas de diferencia.
Habrá que tener cuidado
PHP.JS es un script que quiere mover las funciones PHP a Javascript, para que el desarrollador use la misma nomenclatura, ya que hay funciones muy similares y que para desarrolladores poco experimentados puede resultarles confuso.
Yo recomiendo que la gente aprenda ambos lenguajes y que los sepa diferenciar, pero ante la confusión de lenguajes puedes echar mano a este script, aunque de rendimiento puede ir peor.
Entre las funciones nos encontramos las que tratan los arrays, strings, UTF-8, entre otras. PHP.JS
Vía / dzone
Estoy empezando a curiosear Mootools, y aunque me está gustando bastante, si que echo en falta una documentación más detallada, no solo explicar como va el API, ya que a veces son necesarios ejemplos más básicos para no tener que estar buscando en el API.
window.addEventListener('load', function() {
_lista();
}
, false);
function _lista() {
if ($('lista_categorias')) {
...
}
Habrá tres operaciones distintas: crear efecto drag, añadir evento drop a las categorÃas y añadir evento drop a las subcategorÃas. Digo crear efecto drag porque realmente lo que se hace es que cuando se ejecuta el evento mousedown, se crea una copia del elemento, y es este el que se mueve por la pantalla, guardando una referencia al elemento original. Hay distinción entre el evento drop de las categorÃas y las subcategorÃas porque si se trata de una categorÃa se añade sin más, y si es una subcategorÃa se añade en la categorÃa. A parte, si se intenta mover una categorÃa que contiene subcategorÃas, solo se añadirán las subcategorÃas, no la categorÃa.
// Drag & Drop de listado
function _lista() {
if ($('lista_categorias')) {
// Drag de cada categoria/subcategoria
// Para cada elemento li añado el evento mousedown, para que cuando se ejecute se cree una copia de ese elemento, se le de estilo semi transparente y se permita hacer drag
$$('#lista_categorias li').each(function(elemento){
elemento.addEvent('mousedown', function(e) {
e = new Event(e).stop();
window.item = elemento;
window.categoria_clone = this.clone()
.setStyles(this.getCoordinates())
.setStyles({'opacity': 0.7, 'position': 'absolute'})
.addEvent('drop', function() {console.log('DROP')})
.addEvent('emptydrop', function() {
this.remove();
}).inject(document.body);
categoria_clone.makeDraggable({
droppables: $$('#lista_categorias li')
}).start(e);
});
});
// Drop en las categorias
// Para cada categoria, le añadimos el evento drop, que permite recibir elementos "drag". Si el elemento que se recibe tiene subcategorias, entonces se cogen estas y se añaden al elemento ul que contiene, si no lo contiene, lo creamos. Si no contiene subcategorÃas, se añade sin más.
$$('#lista_categorias li.categoria').each(function(drop){
drop.addEvents({
'drop': function() {
window.categoria_clone.remove();
var ul = window.item.getElement('ul');
if (!drop.getElement('ul')) {
(new Element('ul')).inject(drop);
}
dropul = drop.getElement('ul');
if (ul) {
ul.getElements('li').each(function(li) {
li.inject(dropul);
});
ul.remove();
} else {
window.item.inject(dropul);
}
drop.setStyle('background', '#FFFFFF');
//dropFx.start('7389AE').chain(dropFx.start.pass('ffffff', dropFx));
},
'over': function() {
drop.setStyle('background', '#DDDDFF');
//dropFx.start('98B5C1');
},
'leave': function() {
drop.setStyle('background', '#FFFFFF');
// window.categoria_clone.remove();
//dropFx.start('ffffff');
}
})
});
// Si cae el drop en una subcategoria lo inserto en el padre
$$('#lista_categorias li.subcategoria').each(function(drop){
drop.addEvents({
'drop': function() {
window.categoria_clone.remove();
var ul = window.item.getElement('ul');
dropul = drop.parentNode;
if (ul) {
ul.getElements('li').each(function(li) {
li.inject(dropul);
});
ul.remove();
} else {
window.item.inject(dropul);
}
}
})
});
}
}
Buen script que nos permite mover nuestras capas mediante drag&drop y cambiarlas de tamaño.
Funciona con posicionamiento relativo y absoluto de los elementos en la página. Además permite personalizar los estilos mediante CSS. No es obtrusivo. Es posible indicar tamaños máximos y mínimos para las cajas y es compatible con la mayoría de los navegadores. DragResize
Vía / Ajaxline
Facebook pone a disposición de sus usuarios unos sliders para poder controlar el valor de ciertos elementos. Para aquellos que estén interesados en usarlos, podrán echar mano de este ejemplo realizado con Mootools, cuyo uso es muy sencillo.
Hay que tener en cuenta que no es un script accesible, porque no existe una alternativa estándar al control, ya que el slider es una capa y si no hay javascript o entorno gráfico, el valor no se podría cambiar. El script es bueno y añadirle la parte de accesibilidad no implica mucha complicación. Facebook Sliders With Mootools and CSS
Vía / CSS Globe
Uno de los problemas que se pueden tener a la hora de desarrollar un plugin es que el cliente sepa editar los widgets añadiendo o modificando el HTML. Es por ello que he creado la posibilidad de añadir un pequeño plugin jQuery de edición WYSIWYG a los widgets Texto que vienen en WordPress por defecto, pero lo mismo se puede hacer para cualquier otro widget, incluído los que crees personalmente.
Lo primero será bajarnos el plugin nicEdit, el cual permite de forma muy sencilla añadir un editor WYSIWYG a cualquier elemento. He elegido este plugin y no otro porque en el poco espacio que ofrece el textarea, poner otro plugin más completo, dificultaría su uso, de todas formas, si se quiere usar otro plugin, pues sin problema.
Yo me he creado un directorio /js donde he metido los dos ficheros de nicedit: nicEdit.js y nicEditorIcons.gif.
El siguiente paso es editar nuestro functions.php para añadir el siguiente código:
// El action in_widget_form es el encargado de llamar al método
// form del widget, el que dibuja el formulario
// Comprobaremos si es un WP_Widget_Text y si es así
// añadiremos un checkbox para permitir que el textarea
// sea WYSIWYG
add_action('in_widget_form', 'set_nicedit_form_widget', 10, 3);
function set_nicedit_form_widget($obj, $return, $instance) {
if (is_a($obj, 'WP_Widget_Text')) { ?>
<p><input class="nicedit" id="<?php echo $obj->get_field_id('nicedit'); ?>" name="<?php echo $obj->get_field_name('nicedit'); ?>" type="checkbox" <?php checked(isset($instance['nicedit']) ? $instance['nicedit'] : 0); ?> /> <label for="<?php echo $obj->get_field_id('nicedit'); ?>"><?php _e('Utilizar editor HTML'); ?></label></p>
<?php
if (isset($instance['nicedit']) && !empty($_POST)) {
// Si se ha marcado la opción nicedit en el form y se ha dado GUARDAR
// llamamos la funcion init (explicada más adelante) que se encarga de
// añadir el WYSIWYG al textarea
?>
<script type="text/javascript">
init();
</script>
<?php
}
}
}
// El WP_Widget_Text no tiene el checkbox nicedit en su código
// por lo que al hacer un update lo ignoraría
add_filter('widget_update_callback', 'set_nicedit_update_widget', 10, 4);
function set_nicedit_update_widget($instance, $new_instance, $old_instance, $obj) {
if (is_a($obj, 'WP_Widget_Text')) {
$instance["nicedit"] = isset($new_instance["nicedit"]) && $new_instance["nicedit"] == 'on';
}
return $instance;
}
// Añadimos los scripts y styles necesarios si estamos en la pantalla de widgets
add_action( 'admin_enqueue_scripts', 'add_admin_widget_scripts' );
function add_admin_widget_scripts() {
global $current_screen;
if ($current_screen->base == 'widgets') {
wp_enqueue_script( 'nicedit', get_bloginfo('template_directory') . '/js/nicEdit.js' );
wp_enqueue_script( 'admin', get_bloginfo('template_directory') . '/js/admin.js' );
wp_localize_script( 'admin', 'admin', array('path'=>get_bloginfo('template_directory')) );
wp_enqueue_style( 'admin', get_bloginfo('template_directory') . '/css/admin.css' );
}
}
Ahora deberemos añadir la funcionalidad javascript al código que hemos metido en el widget (admin.js):
// Esta función es la encargada de añadir el WYSIWYG al textarea
function init() {
// Busca todos los checkbox nicedit (le metimos un class)
// que estén seleccionados
jQuery('input:checkbox.nicedit:checked').each(function() {
var $this = jQuery(this);
// Si ya tiene un nicedit nos lo cepillamos
var niceditor = $this.data('nicedit');
var $textearea = $this.parents('form:first').find('textarea');
if (niceditor) niceditor.removeInstance($textearea.attr('id'));
// Añadimos el nicedit al textarea, puedes meterle más botones, mira la doc de nicedit para ello
var area = new nicEditor({buttonList : ['bold','italic', 'link', 'unlink', 'xhtml'], iconsPath: admin.path+ '/js/nicEditorIcons.gif'}).panelInstance($textearea.attr('id'));
$this.data('nicedit', area);
});
}
jQuery(document).ready(function() {
// Si pulsamos el checkbox, añadimos o quitamos el nicedit
// Almacenaremos el objeto nicedit para poder utilizarlo despues
jQuery('.widget-liquid-right').on('click', 'input:checkbox.nicedit', function() {
var $this = jQuery(this);
var $textearea = $this.parents('form:first').find('textarea');
var niceditor = $this.data('nicedit');
if (niceditor) {
niceditor.removeInstance($textearea.attr('id'));
$this.data('nicedit', false);
} else {
var area = new nicEditor({buttonList : ['bold','italic', 'link', 'unlink', 'xhtml'], iconsPath: admin.path+ '/js/nicEditorIcons.gif'}).panelInstance($textearea.attr('id'));
$this.data('nicedit', area);
}
});
// nicEdit controla los submits para actualizar los valores,
// pero en los widgets no funciona, por lo que antes del submit
// forzamos la actualización del valor
jQuery('#widgets-right').on('click', ':submit', function() {
// Quizás se pueda utilizar el objeto nicedit almacenado anteriormente
// pero esto lo hice así en una versión inicial menos genérica y no lo he tocado
for(var i=0; i<nicEditors.editors.length; i++) for(var j=0; j<nicEditors.editors[i].nicInstances.length; j++) nicEditors.editors[i].nicInstances[j].saveContent();
});
// Apaño el orden de los widgets para meter nicedit a los nuevos widgets
// Es necesario si se pusieran los nicedit seleccionados por defecto,
// que en este ejemplo no es el caso, pero si lo añadierais a un widget propio
// no os funcioanría si no hicierais esto.
// Lo que hago es meter un pequeño hack a la función saveOrder
wpWidgets._saveOrder = wpWidgets.saveOrder
wpWidgets.saveOrder = function() {
init();
wpWidgets._saveOrder();
}
// Activo los nicedit en los textareas marcados
// como tal cuando se carga la página al principio
init();
});
Y por último solo nos falta meterle el css necesario, en este caso, el nicedit tiene un pequeño bug y si el textarea tiene un width = 100% no calcula el tamaño real, por eso se lo metemos por css (admin.css).
textarea.widefat {
width: 400px;
height: 100px;
}
Y listo, ya solo falta que el cliente no os dé mucho la lata.
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:
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: