Recently, I needed a cross-browser implementation of the getElementsByClassName Javascript DOM method. I couldn’t use a JS library like jQuery because code size had to be as small as possible.
Fortunately, Robert Nyman developed back in 2008 a very good function to handle this issue.
I have refactored the function definition logic, optimized code as much as possible, fixed some bugs and added the missing querySelectorAll DOM method.
I’ve written some QUnit tests if you want to test wether it works as it should or not.
Parameters:
className One or several class names, separated by space. Multiple class names demands that each match have all of the classes specified. Mandatory.
tag Tag name of the elements to match. Optional.
elm Reference to a DOM element to look amongst its children for matches. Recommended for better performance in larger documents. Optional.
ChangeLog:
7 Dic 2011
normalize-space(@class) (space normalization) so his method wouldn’t return elements with a class attribute containing space characters other than whitespace (newlines for example). Also, namespace try/catch was removed from his version since we’re dealing with HTML documents and therefore it’s not necessary.getElementsByClassName method, so we test for this. As a fallback document will be used. See this issue for more info.Array.slice cannot be called on StaticNodeLists in IE. Instead, a regular loop is used to populate the array.So here it is my 2011 version of the getElementsByClassName function:
/*
* Refactored & improved in 2011 by Tubal Martin (http://www.margenn.com)
* Unit tests: http://www.margenn.com/tubal/javascript/getelementsbyclassname.html
* Original version developed by Robert Nyman in 2008 http://code.google.com/p/getelementsbyclassname/
*/
var getElementsByClassName = document.getElementsByClassName ?
function (className, tag, elm) {
var nodeElm = elm && elm.getElementsByClassName ? elm : document,
elements = nodeElm.getElementsByClassName(className),
nodeName = tag ? new RegExp("\\b" + tag + "\\b", "i") : null,
rElements = [],
i = 0, l = elements.length,
current;
for (; i < l; i++) {
current = elements[i];
if (!nodeName || nodeName.test(current.nodeName)) {
rElements.push(current);
}
}
return rElements;
} : document.querySelectorAll ?
function (className, tag, elm) {
var elements = (elm || document).querySelectorAll((tag || "") + "." + className.split(" ").join(".")),
rElements = [],
i = 0, l = elements.length;
for (; i < l; i++) {
rElements.push(elements[i]);
}
return rElements;
} : document.evaluate ?
function (className, tag, elm) {
var classes = className.split(" "),
classesToCheck = "",
rElements = [],
i = 0, l = classes.length,
elements, node;
for(; i < l; i++){
classesToCheck += "[contains(concat(' ', normalize-space(@class), ' '), ' " + classes[i] + " ')]";
}
elements = document.evaluate(".//" + (tag || "*") + classesToCheck, (elm || document), null, 0, null);
while (node = elements.iterateNext()) {
rElements.push(node);
}
return rElements;
} :
function (className, tag, elm) {
tag = tag || "*";
elm = elm || document;
var classes = className.split(" "),
classesToCheck = [],
elements = tag == "*" && elm.all ? elm.all : elm.getElementsByTagName(tag),
rElements = [],
i = j = 0,
il = classes.length,
jl = elements.length,
current, match, k, kl;
for (; i < il; i++) {
classesToCheck.push(new RegExp("(^|\\s)" + classes[i] + "(\\s|$)"));
}
kl = classesToCheck.length;
for (; j < jl; j++) {
current = elements[j];
match = false;
for (k = 0; k < kl; k++) {
match = classesToCheck[k].test(current.className);
if (!match) {
break;
}
}
if (match) {
rElements.push(current);
}
}
return rElements;
};

Todos los que utiliceis a diario IDEs basados en Java para programar sabreis que no son especialmente rápidos, especialmente con archivos grandes o cuando tenemos muchos archivos abiertos.
Sin embargo hay algunas recomendaciones y trucos para que nuestro IDE basado en Java funcione más rápida y agilmente.
En margenn, después de haber probado opciones como Netbeans, Eclipse PDT o Aptana, elegimos utilizar PHPStorm, de JetBrains, y la verdad es que para nosotros no hay vuelta atrás, sin duda es el mejor.
A continuación expongo mi guía de optimización de rendimiento de PHPStorm:
1. Deshabilita todos los plugins que no utilices en tu día a día
En mi caso, programo con PHP, JS, HTML y CSS por lo que todo lo demás sobra para mi. Estos son los plugins que he deshabilitado (y no son pocos):
2. Desactiva las “inspections” que no consideres necesarias
Especialmente en el caso de Javascript desactivar las inspecciones oportunas agiliza mucho el editor ya que cada vez que editas tu archivo, tiene que escanear todo de nuevo para entender cómo se relaciona el nuevo código que escribes con el existente.
Estas son las que he deshabilitado para Javascript por diferentes motivos:
Ahora cuando edito un archivo el editor no se ralentiza y la CPU no se pone al 100%.
Deshabilitadas para HTML:
Como nota adicional también he deshabilitado todas las inspecciones de PHPDoc, Probably bug y XML.
3. Desactiva las “intentions” que no consideres necesarias
Las intenciones también tienen su impacto en el rendimiento aunque en un grado menor. Desactiva todas las que no consideres útiles teniendo en cuenta tu estilo de código (formato).
Si observais, de nuevo, el lenguaje que más intentions tiene es Javascript.
4. Amplia la memoria disponible para la máquina virtual
En margenn utilizamos exclusivamente MAC OS X (Windows en virtual para testear unicamente):
En Windows y Linux la ruta y el nombre del archivo de configuración es diferente pero los parámetros son los mismos.
A continuación explico qué significa cada parámetro:
Podeis echar un vistazo a la referencia completa de las opciones de máquina virtual de Java Hotspot.
Después de seguir estos pasos, os aseguro que notareis que PHPStorm funciona más ligero y no se ralentizará apenas al editar archivos grandes.
Hasta el próximo artículo!!
A little bit about me
Me encanta Javascript! Mi compañero y socio Jano es quien mejor conoce cuánto me gusta. Ya desde mis inicios en el desarrollo web allá por 2006 cuando empezaba la revolución AJAX vi el potencial de dicho lenguaje para crear aplicaciones web altamente interactivas e incluso one-page-apps como Gmail. Además de tener potencial, el lenguaje me gustaba y era divertido jugar con él modificando una página, actualizando parte del contenido “por arte de magia” sin que la página sufriera un refresco, etc…
En dicha época (2005-2006) afortunadamente surgieron muchos proyectos cuyo objetivo era dotar a los desarrolladores de Javascript de herramientas que nos hicieran la vida más fácil a la hora de añadir interactividad y experiencia de usuario a una página o aplicación web.
Cuando por primera vez conocí jQuery, me pareció horrible…no era el javascript que yo conocía…me parecía alienígena y en un primer momento lo dejé de lado.
Un tiempo más tarde, jQuery no sólo ya no me parecía alienígena sino que lo consideraba fundamental para desarrollar un proyecto cross-browser y en una cuarta parte del tiempo.
Con el tiempo surgieron muchos frameworks, más de cien…pero eran menos de diez los favoritos y realmente buenos. De estos diez, dos llamaron mi atención: YUI y Dojo.


YUI y Dojo eran entonces y son hoy mucho más que una librería para manipular el DOM y realizar llamadas asíncronas con facilidad. Ofrecían y siguen ofreciendo un parque temático de widgets muy amplio y útil además de otras niceties como gestión de dependencias o internacionalización. Son Javascript frameworks con los que puedes construir una aplicación web de principio a fin sin utilizar librerías o plugins adicionales. No era ni es el caso de jQuery.
No quiero que se me entienda mal, me encanta jQuery pero para lo que fue concebido, ser la navaja suiza del DOM y aún sigue siendolo.
De modo que alucinado por lo que ofrecían tanto YUI como Dojo en aquel tiempo y la potencia de jQuery para manipular el DOM, tomé dos decisiones:
Así que tenía dos herramientas sobre la mesa, jQuery y YUI y vi que ambas se complementaban. jQuery lo usaría para manipulación del DOM y gestión de los eventos y YUI para todo lo demás. So far, so good.
He pasado los últimos años utilizando esta solución mixta y con muy buenos resultados y experiencias pero desde el lanzamiento de Dojo 1.5 y la firme apuesta de Dojo por mejorar la documentación me he vuelto a replantear la pregunta ¿Qué herramienta(s) debo utilizar para el front-end development? Dojo 1.5 y esa pregunta han producido que escriba esta serie de artículos.
Como jQuery está para mi en otra liga distinta a la de YUI y Dojo, la cuestión es clara, ¿cuál elijo entre YUI y Dojo? y si elijo Dojo…¿podrá sustituir también a jQuery y convertirse en mi única herramienta? Si seguis esta serie conocereis mi decisión final.
Bien…y ¿cómo voy a comparar YUI y Dojo?
De la única manera posible, utilizando ambos head to head valorando qué ofrece cada uno y cuál resulta más productivo para las mismas tareas.
Hey…y ¿qué pasa con YUI 3?
YUI 3 lamentablemente está aún hoy bastante verde (incompleto y beta en su mayoría) como para ser comparado con YUI 2.8 o Dojo 1.6.
Se que YUI 2.x puede ser utilizado con YUI 3 para cubrir las carencias de este último pero no considero este hecho relevante ya que YUI 3 no es más que un rewrite completo de YUI 2, es decir, más de lo mismo pero con arquitectura, rendimiento y flexibilidad mejorados.
El calendario
En este primer artículo de la serie voy a comparar un widget que he utilizado bastante en los proyectos, el famoso calendario.
Os pondré en contexto, el objetivo del test o demo es asociar un calendario a un campo de texto de un formulario en el que el usuario debe introducir una fecha, de tal forma que cuando el usuario vaya a introducir la fecha, se despliegue un calendario para hacerle más cómoda la selección.
Sin más preámbulos echad un ojo al código fuente de la magnífica demo que he creado :) y juguetead con ambas implementaciones del calendario antes de continuar leyendo.
Notas del desarrollo con Dojo:
<form>
<fieldset>
<legend>Dojo calendar input</legend>
<label>Select a date:</label>
<input type="text" name="dojocalendar" data-dojo-type="dijit.form.DateTextBox" data-dojo-props="name:'dojocalendar',type:'text'">
<input type="submit" value="Send">
</fieldset>
</form>
dojo.require("dijit.form.DateTextBox");

Notas del desarrollo con YUI:
<form>
<fieldset>
<legend>YUI calendar input</legend>
<label>Select a date:</label>
<div class="yuicalendar-popup-wrapper">
<input type="text" id="yuicalendarinput" autocomplete="off">
<input type="hidden" id="yuicalendarhiddeninput" name="yuicalendar">
<div id="yuiCalendarContainer"></div>
</div>
<input type="submit" value="Send">
</fieldset>
</form>
(function(y){
var initYUI = function(){
var yue = y.util.Event,
yud = y.util.Dom,
yuiCalContainer = yud.get('yuiCalendarContainer'),
yuiCalInput = yud.get('yuicalendarinput'),
yuiCalHiddenInput = yud.get('yuicalendarhiddeninput'),
setDate = function(type, args, obj) {
var date = args[0][0],
year = date[0],
month = date[1],
day = date[2],
userDate = (day < 10 ? "0" + day : day) + "/" + (month < 10 ? "0" + month : month) + "/" + year;
yuiCalInput.value = userDate;
updateInputDate(userDate);
yuiCalendar.hide();
},
getDateFields = function(userDate){
return userDate.split("/");
},
updateInputDate = function(userDate){
var dateFields = getDateFields(userDate);
yuiCalHiddenInput.value = dateFields[2] + "-" + dateFields[1] + "-" + dateFields[0];
},
updateCalendar = function(e){
var month, year, dateFields, userDate = this.value;
if (/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(userDate)) {
dateFields = getDateFields(userDate);
month = dateFields[1];
year = dateFields[2];
updateInputDate(userDate);
yuiCalendar.cfg.setProperty("selected", userDate, false);
yuiCalendar.cfg.setProperty("pagedate", month + "/" + year, false);
yuiCalendar.render();
}
},
yuiCalendar = new y.widget.Calendar("yuiCalendarContainer", {
locale_weekdays: "1char",
navigator: {
strings : {
month: "Selecciona un Mes",
year: "Introduce un Año",
submit: "Hecho",
cancel: "Cancelar",
invalidYear: "Por favor, introduce un año válido"
}
},
start_weekday: 1,
MDY_DAY_POSITION: 1,
MDY_MONTH_POSITION: 2,
MDY_YEAR_POSITION: 3,
MONTHS_LONG: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"],
WEEKDAYS_1CHAR: ["D", "L", "M", "M", "J", "V", "S"]
});
yuiCalendar.selectEvent.subscribe(setDate);
yuiCalendar.render();
yue.on("yuicalendarinput", "keyup", updateCalendar);
yue.on("yuicalendarinput", "focusin", function(e) {
this.className = "focused";
yuiCalendar.show();
});
yue.on("yuicalendarinput", "click", function(e) {
if (this.className == "focused") {
this.className = "";
return;
}
if (yuiCalContainer.style.display == "block") {
yuiCalendar.hide();
} else {
yuiCalendar.show();
}
});
yue.on(document, "click", function(e) {
var el = yue.getTarget(e);
if (el != yuiCalInput && el != yuiCalContainer && !yud.isAncestor(yuiCalContainer, el)) {
yuiCalendar.hide();
}
});
};
(new y.util.YUILoader({
require: ["calendar"],
loadOptional: false,
onSuccess: initYUI,
timeout: 10000,
combine: false
})).insert();
}(YAHOO));

Bueno, esas son mis notas de desarrollo…sin duda alguna Dojo ofrece muuuchas más ventajas sobre YUI en este escenario tan real y típico como la vida misma. Dojo cubre de forma automatizada y productiva todas las necesidades típicas en este escenario y por ello le doy un 10.
Por último he comparado las opciones que nos da cada framework en cuanto a usos del calendario más allá del típico (flexibilidad):
Tanto el Multi-Page como el Multi-Select de YUI me parecen de bastante poca utilidad la verdad. No he encontrado hasta la fecha un escenario donde haya necesitado dichas soluciones.
Conclusión
YUI 0 - 1 Dojo
Dojo ha demostrado ser mejor en todos los aspectos en esta comparación, dejando por los suelos a YUI.
¿Y vosotros qué opinais? ¿Con cuál os quedariais?
Espero que os haya gustado mi análisis y la demo, en el próximo combate entre YUI y Dojo analizaré otro widget, el autocomplete.
Stay tuned!!