There are times in the life when you realise that the world has really changed and the things that was once so important to you doesn’t matter anymore. This is the case of my old dithered-extended quirksmode javascript library. It cost me years to enhance and extend but nothing more makes sense in a better standardized world.

A brief about the Internet history

There is a dark time in the Internet history well known among the old developers called Browser Wars. It’s the time when the Internet Explorer and the Netscape Navigator were struggling theirselves for the dominance in the web browser marketplace.

At this era, in the late 90’s, the leaders Netscape Navigator (72% of the marketshare) and Internet Explorer (18%) were often focusing in features over bug fixes, therefore this is a time of unstable browsers, shaky web standards compliance, frequent crashes, security holes and lots of user headaches.

Developers challenge at 90’s

As you can imagine, all those over-specs proprietary features poping-up in a hallucinated speed and the very loose standards compliance created an extreme-ultra-high-hostil environment for developers, specially the brand-new DHTML ones in the early and later version 4 browsers (Javascript 1.2 and 1.3 respectively). Which had to spend hours learning a “different” javascript specification for each Browser they want to support. Who of this era doesn’t remember of the evil pair document.all and document.layers ?

During that time it was common for web designers to display “best viewed in Netscape” or “best viewed in Internet Explorer” logos with 800 × 600 and link these images to a source from which the “preferred” browser could be downloaded.

Yet, although all those incompatibilities some brave guys did a really exceptional work. The first name I remember when I think about this era is our eternal HTML Guru – Jeff Rouyer who created some fantastic introduction to DHTML with his “Curious Eye” site and the “Dynamic HTML Web Magic” book. Another name I think must be cited is Dithered – Christopher who created the 1k DHTML API and many other goodies which helped developers like me in the hard time. Last but not less important is the Quirksmode – Peter-Paul Koch who wrote a lot and still writes a lot of tips for real javascript developers, specially in the quirksmode era, like use “object detection instead of browser detection”, using the defer script tag attribute when you know that the browser does not need to wait for the entire script to be parsed and evaluated and other useful things.

1k DHTML API – The base library

The 1k DHTML API is a fully-functional, cross-browser DHTML API that weighs in at about 1k. The script provides functions that set an element’s visibility, z-index, x and y coordinates, width and height, and clipping. I’ve also thrown in one that can write new HTML content into the element. The script supports NS4+, IE4+, Mozilla, Opera 4+ and any other browsers that support either W3C standards, the IE DOM, or the NS4.x DOM. – from dithered

Here’s the piece of code:

//1k DHTML API
d=document;l=d.layers;op=navigator.userAgent.indexOf('Opera')!=-1;
function gE(e,f){if(l){f=(f)?f:self;var V=f.document.layers;if(V[e])return V[e];for(var W=0;W<V.length;)t=gE(e,V[W++]);return t;}if(d.all)return d.all[e];return d.getElementById(e);}
function sE(e){l?e.visibility='show':e.style.visibility='visible';}
function hE(e){l?e.visibility='hide':e.style.visibility='hidden';}
function sZ(e,z){l?e.zIndex=z:e.style.zIndex=z;}
function sX(e,x){l?e.left=x:op?e.style.pixelLeft=x:e.style.left=x;}
function sY(e,y){l?e.top=y:op?e.style.pixelTop=y:e.style.top=y;}
function sW(e,w){l?e.clip.width=w:op?e.style.pixelWidth=w:e.style.width=w;}
function sH(e,h){l?e.clip.height=h:op?e.style.pixelHeight=h:e.style.height=h;}
function sC(e,t,r,b,x){l?(X=e.clip,X.top=t,X.right=r,X.bottom=b,X.left=x):e.style.clip='rect('+t+' '+r+' '+b+' '+x+')';}
function wH(e,h){if(l){Y=e.document;Y.open();Y.write(h);Y.close();}else if(e.innerHTML)e.innerHTML=h;}

Personal extensions

These are my own pieces of code, they follow the original code naming rules. I know that you will find some really strange things there but as I said before, they are fruit of a lot of study, experience and love XD

Core library

//Zendhi Dithered 1k DHTML Extension
function gX(e){if(l){return e.left;}else if(ie){return e.style.pixelLeft;}else{return parseInt(e.style.getPropertyValue('left'));}}
function gY(e){if(l){return e.top;}else if(ie){return e.style.pixelTop;}else{return parseInt(e.style.getPropertyValue('top'));}}
function gW(e){if(l)return e.clip.width;else return e.offsetWidth;}
function gH(e){if(l)return e.clip.height;else return e.offsetHeight;}
function gO(e){if(ie){var a=/opacity=(\d+)/gi.exec(e.style.filter);if(a==null)return 100;else return a[1];}else{if(e.style.opacity=="")return 100;else return e.style.opacity*100;}}
function sO(e,o){ie?e.style.filter="alpha(opacity="+o+")":e.style.opacity=(o/100);}
function cC(e,c){e.className=c;}
function hC(e,c){if(e.className==null){if(c==null)return true;else return false;}var namesArray=e.className.split(" ");for(var i=0;i<namesArray.length;i++)if(namesArray[i]==c)return true;return false;}
function rC(e,c){if(e.className==null)return;var newNamesArray=new Array();var namesArray=e.className.split(" ");for(var i=0;i<namesArray.length;i++)if(namesArray[i]!=c)newNamesArray.push(namesArray[i]);e.className=newNamesArray.join(" ");}
function cH(e1,e2){wH(e2,e1.innerHTML);}
function mL(e,x,y){sX(e,x);sY(e,y);}
function rL(e,w,h,m){if(ie)m=0;sW(e,w,m);sH(e,h,m);}
function bW(){if(!ie)return window.innerWidth-20;else return d.body.clientWidth;}
function bH(){if(!ie)return window.innerHeight;else return d.body.clientHeight;}
function pW(){var pw;if(d.body.scrollWidth>d.body.offsetWidth)pw=d.body.scrollWidth;else pw=d.body.offsetWidth;if(pw<bW())pw=bW();return pw;}
function pH(){var ph;if(d.body.scrollHeight>d.body.offsetHeight)ph=d.body.scrollHeight;else ph=d.body.offsetHeight;if(ph<bH())ph=bH();return ph;}
function rX(){if(!ie)return window.pageXOffset;else return d.body.scrollLeft;}
function rY(){if(!ie)return window.pageYOffset;else return d.body.scrollTop;}
function sI(id,i){e=gE(id);e.src=i;}
function dE(id,s){e=gE(id);if(typeof s=="undefined")s=(e.style.display=="none")?1:0;e.style.display=(s==1)?'':'none';}
function pI(){d.pli=new Array();var i,a=pI.arguments;for(i=0;i<a.length;i++){d.pli[i]=new Image();d.pli[i].src=a[i];}}
function wait(t){var st,now,dif;st=new Date();while(1){now = new Date();dif = now-st;if(dif>t) return;}}

XMLHttpRequest

//Zendhi Cross-Browser XMLHttpRequest
if(window.ActiveXObject&&!window.XMLHttpRequest)window.XMLHttpRequest=function(){return new ActiveXObject('Microsoft.XMLHTTP')}
function ajaxRequest(fn,url,postdata){sE(gE("mouseTrail"));if(!postdata)postdata=null;r=new XMLHttpRequest();r.onreadystatechange=function(){ajaxExecute(fn,r);};if(postdata==null){r.open("GET",url,true);}else{r.open("POST",url,true);r.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");}r.setRequestHeader("If-Modified-Since","Tue, 31 Aug 1982 00:00:00 GMT");r.send(postdata);}
function ajaxExecute(fn,obj){if(obj.readyState==4){hE(gE("mouseTrail"));if(obj.status==200)this.tmr=window.setTimeout(""+ eval(fn) +"",100);else alert(obj.status+" - "+obj.statusText);}}
function ajaxDisplay(id,obj){e=gE(id);wH(e,obj.responseText);}

Form Utilities

//Zendhi Form utilities
function isEml(field){var v=field.value, re=/^([\w\.\-])+@(([\w\-])+\.)+([\w]{2,6})+$/;return re.test(v);}
function isVal(field){var v=field.value, re=/^[-_a-z0-9!,;:@$ áàãâäéèêëíìîïóòõôöúùûü\/\+\?\.\(\)\|\n\f\r\t]+$/i;return re.test(v);}
function isNum(str,valids){if(!valids)valids="1234567890.";var f=true;var c,i;for(i=0;i<str.length;i++){c=str.charAt(i);if(f==true&&valids.indexOf(c)==-1)f=false;}return f;}
function filterNum(field){var output="";var content=field.value;var c,i;for(i=0;i<content.length;i++){c=content.charAt(i);if(c==',')c='.';if(isNum(c))output+=c;}field.value=output;}
function isSafe(chr){f=true;if((chr<'a'||chr>'z')&&(chr<'A'||chr>'Z')&&(chr<'0'||chr>'9')){switch(chr){case '\\':case '(':case ')':case '*':case '-':case '.':case '!':break;case '+':case ',':f=false;break;default:if(chr!='_')f=false;break;}}return f;}
function urlEncode(str){var output="";var ch;for(var i=0;i<str.length;i++){ch=str.charAt(i);if(ch==' '){output+='+';}else if(isSafe(ch)){output+=ch}else{output+=encodeURIComponent(ch);}}return output;}
function safeEncode(v){var output=urlEncode(v);output=output.replace(/%/gi,"@-@");return output;}
function setStatus(oElement, status){oElement.disabled=status;}
function set1stRadioChecked(buttonGroup){if(buttonGroup[0])buttonGroup[0].checked=true;else buttonGroup.checked=true;}
function getSelectedRadio(buttonGroup){if(buttonGroup[0]){for(var i=0;i<buttonGroup.length;i++){if(buttonGroup[i].checked){return i;}}}else{if(buttonGroup.checked){return 0;}}return -1;}
function getSelectedRadioValue(buttonGroup){var i=getSelectedRadio(buttonGroup);if(i==-1){return "";}else{if(buttonGroup[i]){return buttonGroup[i].value;}else{return buttonGroup.value;}}}
function getSelectedCheckbox(buttonGroup){var retArr=new Array();var lastElement=0;if(buttonGroup[0]){for(var i=0;i<buttonGroup.length;i++){if(buttonGroup[i].checked){retArr.length=lastElement;retArr[lastElement]=i;lastElement++;}}}else{if(buttonGroup.checked){retArr.length=lastElement;retArr[lastElement]=0;}}return retArr;}
function getSelectedCheckboxValue(buttonGroup){var retArr=new Array();var selectedItems=getSelectedCheckbox(buttonGroup);if(selectedItems.length!=0){retArr.length=selectedItems.length;for(var i=0;i<selectedItems.length;i++){if(buttonGroup[selectedItems[i]]){retArr[i]=buttonGroup[selectedItems[i]].value;}else{retArr[i]=buttonGroup.value;}}}return retArr;}
function getFormString(obj){var output="";for(var x=0;obj.elements[x];x++){f=obj.elements[x];if(f.type.toLowerCase()=="submit"||f.type.toLowerCase()=="reset"||f.type.toLowerCase()=="button"){}else if(f.type.toLowerCase()=="radio"){if(f.checked)output+="&"+f.name+"="+safeEncode(getSelectedRadioValue(f));}else if(f.type.toLowerCase()=="checkbox"){if(f.checked)output+="&"+f.name+"="+safeEncode(getSelectedCheckboxValue(f));}else if(f.type.toLowerCase()=="select-one"){output+="&"+f.name+"="+safeEncode(f.options[f.selectedIndex].value);}else{if(f.value.length>0)output+="&"+f.name+"="+safeEncode(f.value);}}return output.substr(1);}
function getFormHash(obj){var output="";for(var x=0;obj.elements[x];x++){f=obj.elements[x];if(f.type.toLowerCase()=="submit"||f.type.toLowerCase()=="reset"||f.type.toLowerCase()=="button"){}else if(f.type.toLowerCase()=="radio"){if(f.checked)output+="&"+f.name+"="+getSelectedRadioValue(f);}else if(f.type.toLowerCase()=="checkbox"){if(f.checked)output+="&"+f.name+"="+getSelectedCheckboxValue(f);}else if(f.type.toLowerCase()=="select-one"){output+="&"+f.name+"="+f.options[f.selectedIndex].value;}else{if(f.value.length>0)output+="&"+f.name+"="+f.value;}}return output.substr(1);}

Animation

//Zendhi Animation Framework, YES it uses Robert Penner easing equations
var tween = new Array();
var default_ease_f = "linearTween";
var default_ease_i = Math.floor(1000/60);
var default_ease_d = 60;
var blank_block   = "<table width='100%' height='100%' cellspacing='0' cellpadding='0' border='0'><tr><td align='center' valign='middle'><span></span></td></tr></table>";
var loading_block = "<table width='100%' height='100%' cellspacing='0' cellpadding='0' border='0'><tr><td align='center' valign='middle'><img src='"+imgsPath+"ico_processing.gif' alt='Loading...' /><br /></td></tr></table>";
function resetTween(){for(var item in tween){window.clearTimeout(tween[item].ct);delete tween[item];}}
function prepTween(item){var ob=tween[item];var e=gE(ob.id);if(ob.bg){e.style.background=ob.bg;wH(e,blank_block);}tweenIt(item);}
function tweenIt(item){var ob=tween[item];var e=gE(ob.id);var ease_f=(ob.f)?ob.f:default_ease_f;var ease_i=(ob.int)?ob.int:default_ease_i;var ease_d=(ob.dur)?ob.dur:default_ease_d;var mv=false;if(typeof ob.t=="undefined")ob.t=0;if(typeof ob.x=="undefined")ob.x=gX(e);if(typeof ob.y=="undefined")ob.y=gY(e);if(typeof ob.w=="undefined")ob.w=gW(e);if(typeof ob.h=="undefined")ob.h=gH(e);if(typeof ob.tx!="undefined"){sX(e,Math.floor(Math[ease_f](ob.t,ob.x,ob.tx-ob.x,ease_d)));mv=true;}if(typeof ob.ty!="undefined"){sY(e,Math.floor(Math[ease_f](ob.t,ob.y,ob.ty-ob.y,ease_d)));mv=true;}if(typeof ob.tw!="undefined"){sW(e,Math.floor(Math[ease_f](ob.t,ob.w,ob.tw-ob.w,ease_d)));mv=true;}if(typeof ob.th!="undefined"){sH(e,Math.floor(Math[ease_f](ob.t,ob.h,ob.th-ob.h,ease_d)));mv=true;}ob.t++;if(!mv)ob.t=ob.dur;if(ob.t<ease_d){ob.ct=window.setTimeout("tweenIt('"+item+"')",ease_i);}else{if(typeof ob.tx!="undefined")sX(e,ob.tx);if(typeof ob.ty!="undefined")sY(e,ob.ty);if(typeof ob.tw!="undefined")sW(e,ob.tw);if(typeof ob.th!="undefined")sH(e,ob.th);if(ob.cbf)ob.ct=window.setTimeout("tweenCallback('"+item+"')",100);}}
function tweenCallback(item){var ob=tween[item];var e=gE(ob.id);if(typeof ob.cbfi=="undefined")ob.cbfi=100;ob.ct=window.setTimeout(ob.cbf,ob.cbfi);}

Mouse Ajax Indicator

//Zendhi Mouse Indicator
var trailImg=[imgsPath +"ico_processing.gif", 16, 16];
var trailPos=[15,15];
if(d.getElementById)d.write('<div id="mouseTrail" style="position:absolute;top:0;left:0;z-index:9999;visibility:hidden;"><img src="'+trailImg[0]+'" alt="" /></div>');
function gMX(e){if(typeof e!="undefined")return e.pageX;else if(typeof window.event!="undefined")return d.body.scrollLeft+event.clientX;}
function gMY(e){if(typeof e!="undefined")return e.pageY;else if(typeof window.event!="undefined")return d.body.scrollTop+event.clientY;}
function setTrailXY(e){var x=trailPos[0]+gMX(e);var y=trailPos[1]+gMY(e);if(x+trailImg[1]>bW()+rX()-trailPos[0]-trailImg[1])x=bW()+rX()-trailPos[0]-trailImg[1]-2;if(y+trailImg[2]>bH()+rY()-trailPos[1]-trailImg[2])y=bH()+rY()-trailPos[1]-trailImg[2]-2;sX(gE("mouseTrail"),x);sY(gE("mouseTrail"),y);}
window.addEvent("mousemove", setTrailXY);

Old library in use

As an example of what i’ve accomplished with this loved library, here a pretty power site coded in the end of 2003 start of 2004. Note that XMLHttpRequest was not available yet and the page makes an interesting approach to the “ASync” loading problem.

LojComm Internet Service

Time for the new

Well, I’ve spent too much time talking about the oldies but the main reason of this entry is to archive a main decision in my development behavior. It’s not new to anyone that I’m using mootools since early 2007, I’ve even worked in some widgets and some core optimizations that year. Mootools is the javascript framework of my choice for a lot of reasons the main ones are:

  • It’s MIT License and I like the community behind it.
  • It’s very well designed, small and modular,
  • It’s almost a javascript extension, just like Sam Stephenson – Prototype but has a more friendly OO(Object Oriented) structure,
  • It’s made for developers what means it’s easy for a programmer to derive and create things over it,
  • I still can use a widget javascript framework like ExtJS over it if I had to.

That’s it. Soon I’ll be porting all my major systems to use mootools and make them even more attractive and modern, create useful widgets and work for a better world ;)