Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Monday, June 21, 2010

Table Row Height Reported Wrongly

Turns out that in all current browsers there may be a 1 pixel discrepancy between the reported height of a table row and the actual height of the table row.

Not only that, but identical table rows in the same table may differ in height from each other.

Figure 1

Friday, May 15, 2009

JASH - debug safari

Need to debug javascript/css on .. safari? Sure, the thing is coming along in that respect, but its built-in tools and even firebug lite just don't cut it sometimes. Give JASH a go.

(Not sure I'd recommend JASH for ie debugging, since the script debugger / debugbar / ie developer toolbar are a little more convenient)

UPDATE: I've used JASH a little more, and found it useful a little less.

Wednesday, May 13, 2009

Disabled input fires no events

Evidently, a dom node "<input disabled="disabled"/>" will not fire any events, even if you do, say, something as direct as this: "<input disabled="disabled" onclick="alert('clicked it.');"/>"

Saturday, May 2, 2009

How to Avoid CSS Hacks

I've decided to use a very tiny bit of javascript to free me of css hacks. I already use js to add a class "jsEnabled" to the <html> element so that I can style things differently if I know that javascript is going to swoop in and alter them later (tabs, carousels, etc). Taking this a step further, I put the browser name + version number in the html element classname. Then in the css, you can write ".ie7 .my-div {float:none;}" Sure, we're not supposed to rely on javascript. But we usually do. And this is just for minor tweaks anyway. The site will still *work* with js turned off, you'd just lose that tiny css tweak you made that relies on it.

Thursday, April 16, 2009

Close on MouseOut, Except .. Related Target

For a mouseout event, the event target is the thing you're leaving - mousing out of - the event relatedTarget is the thing you're leaving to, or entering.


        jQuery('#something').mouseout(function(e){
            /*
                don't close the subnav if we've moused out -> onto an autocomplete resultset.
            */
            var targ = e.relatedTarget, i = 0;
            //we're only checking the most recent 5 parents (ancestors).
            while(targ && ++i<5){
                //don't close the subnav if we're mousing over an autocomplete list.
                if(targ.className && targ.className.indexOf('ac_results')>-1){
                    return;
                }
                targ = targ.parentNode;
            }
            /**/
           
            //ok, close me..
            $(this).hide();
        });

YUI-Like Javascript Namespaces

I really like the idea of Javascript namespaces for projects that have a lot of javascript (or even a little javascript on a lot of pages). YUI has a really good implementation, so I took a look at how they did theirs and ripped out the namespace creation part so I could use it on any project I wanted without having to include the YUI library.

The biggest benefit to using namespaces is avoidance of collisions. When using namespaces, you can be sure that no 3rd-party library or other coder is overwriting your functions or properties. Also, you can also use a javascript compresser / combiner to combine a lot of JS files into 1 JS file in order to reduce the amount of requests you make to the server. If you use namespaces, you can be sure that when you put all of the JS files together, you won't have any collisions.

To use the code, first put the following code in a globl js file:

if (typeof YourSite == "undefined") {
   var YourSite = {};
}

YourSite.namespace = function() {
    var a = arguments, o = null, i, j, d;
    for (i = 0; i < a.length; i = i + 1) {
        d = a[i].split(".");
        o = window;
        for (j = 0; j < d.length; j = j + 1) {
            o[d[j]] = o[d[j]] || {};
            o = o[d[j]];
        }
    }
    return o;
};

Then for each page or section of your site you can create a namespace:
YourSite.namespace("YourSite.Section1");
Then when creating functions or properties, you can write:

YourSite.Section1.myProperty = "blah";

YourSite.Section1.myFunction = function(){
    alert(YourSite.Section1.myProperty);
}

YourSite.Section1.myFunction();


Wednesday, March 11, 2009

JAWR = awesome, but please make it work with sitemesh

Any astute reader out there.. use JAWR on your J2EE projects. It's fabulous. It just doesn't seem to play well with sitemesh (and I put the blame on sitemesh).

JAWR allows for properties-file-driven bundling + auto-minification (via YUI-Compressor [or your favorite, maybe]) of CSS and JS. It also supports a debug mode, which you can switch on with one variable change.

Know of a great .NET, PHP, or Python equivalent of JAWR? Please comment!

Wednesday, December 24, 2008

Quick! way to get repeated characters

want 8 spaces?


(new Array(8)).join(' ')

it's quick not only as in fewer keystrokes/less code, but is also blazingly fast to execute compared to a for-loop implementation.

Tuesday, May 27, 2008

Super Simple XML-String to JSON

Yes, there are other libraries for this. Yes, they are more complete. So why this? I didn't need all the features of a complete xml->json map, I just wanted something to handle my nice, super simple use-case. And I hate wasted bandwidth. This library is 620 BYTES when YUI-compressed.

This is for a specific task. I trust the xml source. (So nobody yell "hey! - you're using eval() - you're eveel!").

Prerequisites:
  • you have a string of well-formed xml.
  • you don't have & don't care about node attributes, namespaces or CDATA (ie. your XML is 'Super Simple').

Good Ideas:
  • Don't use a library that will dirty the object prototype.
    (ie. mess up for-loops that look like this: for(var prop in obj){..})
  • Strip comments and whitespace, use safe variable-name substitution—use YUI Compressor.

Confessions:
  • It uses eval().
  • It uses regular-expressions (regexes).
  • It could probably stand to be optimized a bit.

The Code:

var xmlString = "<root><a/><b>data1</b><b>data2</b></root>";

function xmlString2json (xmlString) {
    return xmlString.replace(
            //expand empty tags
            /\<([^>]*)\/\>/g, "<$1></$1>"
        ).replace(
            //convert closing tags to closing braces
            /\<\/([^>]*)\>/g,"},"
        ).replace(
            //convert opening tags to "{NODENAME:["
            //notice that the array literal is opened, but not closed.
            /\<([^>]*)\>/g,"{'$1':[" 
        ).replace(
            //remove extraneous commas
            /,}/g,"]}"
        ).replace(
            //close array literal, begin adding needed singlequotes
            /:([^{}]*?)}/g,":'$1]'}"
        ).replace(
            //adjust singlequotes, bring inside array literal notation (left side)
            /'\[/g,"['"
        ).replace(
            //adjust singlequotes, bring inside array literal notation (right side)
            /\]'/g,"']"
        ).replace(
            //remove empty strings (which are from empty tags)
            /\[''\]/g,"[]"
        ).replace(
            //remove final, ending extraneous comma
            /},$/, '}'
    );
}

var json = xmlString2json(xmlString);
// {'root':[{'a':[]},{'b':['data1']},{'b':['data2']}]}

function cleanTree(r, p){
    if(r.length == 1 && typeof r[0] == "string"){
        //might want to trim leading and trailing whitespace from r[0] first
        // could be expressed as a series of ternary operations:
        // return r[0]=="true"?true:r[0]=="false"?false:r[0].search(/^[0-9]+$/)==0?1*r[0]:r[0]
        // expressed this way for readability:
        if(r[0] == "true"){
            return true;
        }
        if(r[0] == "false"){
            return false;
        }
        if(r[0].search(/^[0-9]+$/) == 0){
            return 1*r[0];
        }
        return r[0];
    }
    p = p || {};
    for( i in r ){
        var nn = '';
        for( name in r[i] ){
            nn = name;
        }
        var subnode = r[i][nn];
        if(p[nn]){
            if(typeof p[nn] == "object" && typeof p[nn].length == "number"){
                p[nn].push( cleanTree(subnode) );
            } else {
                p[nn] = [ p[nn], cleanTree(subnode) ];
            }
        } else {
            p[nn] = cleanTree(subnode);
        }
    }
    return p;
}

var jso = eval('('+json+')');
var cleaned = cleanTree(jso.testImages);
console.log(cleaned);


At this point, you might be wondering, "Why all those [extra] arrays?" My idea was to approximate the concept of the childNodes array. Really, you could just take the initial JSON and run with it, keeping in mind that it is structured with 'childNodes' arrays. But in case you'd rather have it 'cleaned' up .. I made the recursive cleanTree function to do just that.

"What if I have actual xml, not just a string representation thereof?" you may question.

Give this a shot:

var xmlString = (new XMLSerializer()).serializeToString( myXMLDoc );

Someone else's related post (reminder to self to see if his xml2json will work in actionscript / how readily adaptable it is): converting xml to json.

Monday, March 31, 2008

dom nodes + for-loops THAT WORK

Imagine you have a collection of DOM nodes (html element nodes, whatever you want to call them) stored in the variable ‘elements’, and that var len = elements.length. The following for-loop will not work. Every element will have an onclick event handler function that calls clicked(len) – not the respective clicked(i)



WRONG

    for( var i = 0; i < len; i++){
        
        var el = elements[i];
        el.addListener('click', function(){clicked(i);}, false);
        
    }



RIGHT

    (function loop( I ){
        if (I == len) return;
        var i = I;
        
        
        var el = elements[i];
        el.addListener('click', function(){clicked(i);}, false);
        
        
        loop(++I);
    })(0);

Note: addListener is not any browser’s implementation. It’s just my way of saying addEventListener (or, for IE, attachEvent). Also, for brevity, the function ‘clicked’ is not here defined. Yes, this is documented in a couple places around the web. But those places are not obvious or easily searchable for everyone.

Tuesday, February 26, 2008

If

Have you ever seen code like this?

if(condition){
   stuff
}

This won't work for all cases, but I often enjoy writing it like this:

if(!condition) return;
stuff

Note: if you are NOT minifying your code, the bottom method is probably leaner, but if you ARE minifying, stick with the top method.

Reduce the Verbosity of Prototypal Class Definitions

I ran across some code like this recently:


function SomeClass(args){
...
}
SomeClass.prototype.firstMethod = function(args){ ... };
SomeClass.prototype.secondMethod = function(args){ ... };
SomeClass.prototype.thirdMethod = function(args){ ... };
...
...


Maybe, like me, you cringe when you see repetitious code. Maybe not. If not, return. So I got to thinking of a way to streamline this class.


function SomeClass(args){};
SomeClass.prototype = new (function(args){
   var me = this;
   me.firstMethod = function(args){ ... };
   me.secondMethod = function(args){ ... };
   me.thirdMethod = function(args){ ... };
   ...
})();

/* to test it, we'll create an instance and check if it has it's own [copy of] firstMethod */

var myClass = new SomeClass(args);
alert(myClass.hasOwnProperty('firstMethod'));
/* false, it does not have a local copy of the method */