Best javascript questions in May 2012

Is there a setting on Google Analytics to suppress use of cookies for users who have not yet given consent

65 votes

According to EU Article 5(3) of the E-Privacy Directive (a.k.a 'The Cookie Laws'), web sites that target EU users have to gain opt-in consent from users before they set a cookie.

See ICO Guidance

I am trying to square this with Google Analytics on my web site.

I would imagine that Google Analytics (GA) can do a certain level of analytic data gathering without requiring the use of cookies.

However, I cannot find any info on this (on the Google sites/settings panels) about how to relay information about the 'state of consent' back to Google during a page request. So, my only option seems to be that I should not embed Google tag code at all if the user has not explicitly given consent. Which seems a bit drastic.

Letting my serverside script set a 'hasConsentedToCookies=FALSE' flag in the JavaScript tags would allow me to instruct Google's services to run in a gracefully degraded fashion.

Is there a setting on Google Analytics to suppress use of cookies for users that have not yet given consent?

If so, where can I find info on this?

Google Analytics has a new set of APIs to assist with compliance with a cookie opt-out. Here's the documentation, and here's their help docs.

(There has been some ambiguity as to whether the EU Cookie Regulations (as implemented in member countries) require that passive web analytics tracking requires opt-in mechanisms for compliance. If you're concerned one way or another, consult an attorney. Google is empowering you to make the decision as to how you want to proceed)

Basically, they'll leave implementation details to you, but, the idea is, once you've determined whether or not to track the user in Google Analytics, if the answer is to not track, you'd set the following property to true before Google Analytics runs:

window['ga-disable-UA-XXXXXX-Y'] = true;

Where UA-XXXXXX-Y is your account ID in Google Analytics

As the other posters have noted, Google Analytics relies on cookies. So, you're not able to do any kind of tracking without cookies. If you've determined that someone is not to be cookied for tracking, you'll need to implement something like this:

if(doNotCookie()){
   window['ga-disable-UA-XXXXXX-Y'] = true;
}

Opt In

This does require a little bit of jujitsu for when you first load Google Analytics, since this property will need to be set before Google Analytics runs to prevent tracking from ever happening, which means, for an "opt in to tracking" approach, you'd probably need to implement a mechanism where, on first visit, Google Analytics is automatically disabled in the absence of an opt-in cookie (cookies that determine cookie preferences are explicitly allowed), and then, if an opt-in happens, re-runs Google Analytics. On subsequent pageviews, all would run smoothly.

Could look something like (pseudo-code):

if( hasOptedOut() || hasNotExpressedCookiePreferenceYet() ){ //functions you've defined elsewhere
     window['ga-disable-UA-XXXXXX-Y'] = true;
}
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-XXXXXXX-Y']);
  _gaq.push(['_trackPageview']);


  function onOptIn(){ //have this run when/if they opt-in.
      window['ga-disable-UA-XXXXXX-Y'] = false;
      //...snip...
      //set a cookie to express that the user has opted-in to tracking, for future pageviews
      _gaq.push(['_trackPageview']); // now run the pageview that you 'missed'
   }

Opt Out

With this approach, you'd allow the user to opt-out of tracking, which would mean you'd use a cookie to set the ga-disable-UA-XXXXXX-Y' property and a cookie to manage it in the future:

if( hasOptedOut() ){ // function you've defined elsewhere 
     window['ga-disable-UA-XXXXXX-Y'] = true;
}

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-XXXXXX-Y']);
  _gaq.push(['_trackPageview']);

Why "$().ready(handler)" is not recommended?

57 votes

From the jQuery API docs site for ready

All three of the following syntaxes are equivalent:

  • $(document).ready(handler)
  • $().ready(handler) (this is not recommended)
  • $(handler)

After doing homework - reading and playing with the source code, I have no idea why

$().ready(handler) 

is not recommended. The first and third ways, are exactly the same, the third option calls the ready function on a cached jQuery object with document:

rootjQuery = jQuery(document);
...
...

// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
    return rootjQuery.ready( selector );
}

But the ready function has no interaction with the selector of the selected node elements, The ready source code:

ready: function( fn ) {
    // Attach the listeners
    jQuery.bindReady();
        // Add the callback
    readyList.add( fn );
        return this;
},

As you can see, it justs add the callback to an internal queue( readyList) and doesn't change or use the elements in the set. This lets you call the ready function on every jQuery object.

Like:

  • regular selector: $('a').ready(handler) DEMO
  • Nonsense selector: $('fdhjhjkdafdsjkjriohfjdnfj').ready(handler) DEMO
  • Undefined selector:$().ready(handler) DEMO

Finally... to my question: Why $().ready(handler) is not recommended?

I got an official answer from one of the jQuery developers:

$().ready(fn) only works because $() used to be a shortcut to $(document) (jQuery <1.4)
So $().ready(fn) was a readable code.

But people used to do things like $().mouseover() and all sorts of other madness.
and people had to do $([]) to get an empty jQuery object

So in 1.4 we changed it so $() gives an empty jQuery and we just made $().ready(fn) work so as not to break a lot of code

$().ready(fn) is literally now just patched in core to make it work properly for the legacy case.

The best place for the ready function is $.ready(fn), but it's a really old design decision and that is what we have now.


I asked him:

Do you $(fn) is more readable than $().ready(fn) ?!

His answer was:

I always do $(document).ready(fn) in actual apps and typically there's only one doc ready block in the app it's not exactly like a maintenance thing.

I think $(fn) is pretty unreadable too, it's just A Thing That You Have To Know Works™...

What is the cost of '$(this)'?

35 votes

People here often suggest to cache the jQuery object created from a DOM element, like with this code:

$('#container input').each(function() {
    $(this).addClass('fooClass');
    $(this).attr('data-bar', "bar");
    $(this).css('background-color', 'red');
});
  • Does caching the jQuery object really improve the performance of our code?
  • What happens "behind the scenes" when you pass a DOM element to the jQuery constructor?

Inspired by this question on meta, I'll answer my question.

In the jQuery tag info this warning appears:

The jQuery function $() is expensive. Calling it repeatedly is extremely inefficient.

Well... that is true only for strings selectors, which get parsed with regex to find out what are they:

quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/

Then if the string is a selector(other than id) jQuery traverse the DOM to find a match with it's expensive find function:

} else if ( !context || context.jquery ) {
    return ( context || rootjQuery ).find( selector );
}

So yes it's expensive, but that is only true for selectors!
If we pass a DOMElement the only action jQuery does is saving the DOMElement parameter as the context of the new just created jQuery object and setting the length of the context to 1:

// Handle $(DOMElement)
if ( selector.nodeType ) {
    this.context = this[0] = selector; // Selector here is a DOMElement
    this.length = 1;
    return this;
}

I did some tests with jsPerf, and I found that indeed caching the jQuery object has only a little effect:

enter image description here

In Chrome it's only 7% slower. (In IE it's a little bit more significant- 12%)

32 votes

Possible Duplicate:
What does tilde (~) preceding jQuery object do?

I found a strange !!~ in the code when reading: https://github.com/LearnBoost/mongoose/blob/master/lib/document.js#L678

Document.prototype.isModified = function (path) {
  return !!~this.modifiedPaths.indexOf(path);
};

I have read that What is the !! (not not) operator in JavaScript? and How to: The ~ operator?; why did the author use !!~ here?

I tried:

!!~1  // -> true
!!~0  // -> true
!!~-1 // -> false
!!~-2 // -> true

It seems that it only be false when the number is -1. Is it right? Why not just check the number is not -1 or >=0?

The !!~expr returns false when expr is -1; it returns true otherwise. It works like this:

   -1 = 1111 1111 1111 1111 1111 1111 1111 1111b
  ~-1 = 0000 0000 0000 0000 0000 0000 0000 0000b // ~ = bitwise not = invert all bits
   !0 = true
!true = false

A value other than -1 will have at least one bit set to zero; inverting it will create a truthy value; applying ! operator twice to a truthy value yields boolean true.

The above-mentioned function returns true if the string/array modifiedPaths contains the string/value path:

!!~"abc".indexOf("d") // indexOf() returns -1, the expression evaluates to false
!!~"abc".indexOf("a") // indexOf() returns  0, the expression evaluates to true
!!~"abc".indexOf("b") // indexOf() returns +1, the expression evaluates to true

I personally think this is poor coding considering how much time you spent deciphering this one line of code. It could easily have been written as follows:

return this.modifiedPaths.indexOf(path) >= 0;

Does this code need to be in a document.ready?

28 votes

The document.ready is used to execute code after the DOM is fully loaded. This can be used to attach event handlers to elements on the page e.g

$(function(){ 
    $('#somediv').click(function(){ 

    }); 
}) 

<div id="somediv"> </div> 

Internally jQuery hooks up to DOMContentLoaded in browsers such as Firefox/Opera. In IE's case some extra logic is implemented to check when the DOM is ready1.

I have a few questions, my first one being, when binding event handlers to the document itself, is it necessary to put that code in a document.ready ? I have always been writing the code below without wrapping it in a document.ready

$(document).keydown(function(e){
    if (e.which == 39) { 
       alert( "right arrow pressed" );
       return false;
    }
});

And as you can see, it works. My understanding is, since this code doesn't hook up to any elements within the document, but the document itself, there's no need to wrap it in a document.ready handler. Another reason i don't wrap it is because i used to do the same in vanilla javascript the equivalent would be the code below, which also works.

document.onkeydown= function(){
var keyCode = event.keyCode || event.which;   
    if (keyCode == 39) { 
       alert( "right arrow pressed" );
       return false;
    }
}

I've seen numerous posts where people wrap it in a document.ready, is there any downside of not wrapping this code in document.ready ?

Also i think this question stems from my lack of clarity of what happens during this time when the DOM is being constructed, so if someone can explain what happens during the period right before the DOM is ready. To me the document is ready when the html has been parsed and converted into a DOM tree, or is there more to it ?

In summary, here are my questions

  1. When binding event handlers to the document itself, is it necessary to put that code in a document.ready.
  2. Are there any downsides to not wrapping the code in the document.ready ?
  3. What sequence of events take place when the document is being constructed, right before the document.ready is fired ?

If you are binding to the document itself, you don't need to wait until it is ready. There shouldn't be any downsides to not wrapping it in document.ready in this case.

document.ready gets fired when the DOMReady event is triggered by the browser, or when a specific test is successful for versions of browsers that don't support the DOMReady event.

Additional information. (5/22)

Most modern browsers implement the DOMContentLoaded event which fires when all elements defined on the document are ready to be manipulated by javascript. Other browsers either rely on a setTimeout loop that continuously checks the readystate of the document or binds directly to the onreadystatechanged method of the document (taken from jquery core). The document itself is ready to be manipulated before javascript is ever executed, therefore you never need to wait when binding directly to the document.

The only gotcha here is that if the code interacts with elements other than the document, there is a chance that the event could be triggered on the document before those elements exist. It is very unlikely for that to happen, but it can happen. If that is something that can happen with your code, then it makes sense to place it inside of $(document).ready() to prevent that scenario. Your sample doesn't warrant being placed inside of $(document).ready().

jqGrid does not render correctly in Chrome/Chrome Frame

18 votes

Currently using Chrome v19.0.1084.46 (Official Build 135956) beta-m jqGrid 4.3.2 (latest release)

The problem is that no matter the size of my grid, columns, or containing div, a small fraction of my last column gets pushed beyond the edge of the grid, causing horizontal scroll bars to appear, which should not happen. See below:

grid

I've been fiddling with the following attributes on jqGrid to try and fix this:

  • width
  • autowidth
  • height
  • shrinkToFit
  • scrollOffset - Had the best luck with this one, but nothing repeatable.

I've also stripped down to the basic grid css only, thinking it might have been a rule I put in place...with no luck.

Has anyone else experienced this and/or found a solution to this? Help is much appreciated.

I updated today my Chrome to version 19, have reproduced the problem and made the corresponding quick&dirty fix:

I suggest to change the line of jqGrid code

isSafari = $.browser.webkit || $.browser.safari ? true : false;

to the following

isSafari = ($.browser.webkit || $.browser.safari) &&
    parseFloat($.browser.version)<536.5 ? true : false; // Chrome < version 19

The demo use the fix. The fixed version of jquery.jqGrid.src.js which I used in the demo you can get here.

I tested it in IE9 (v9.0.8112.16421), IE8 (8.0.6001.18702CO), Chrome 18.0.125.168, Chrome 19.0.1084.46, Safari 5.1.7 (7534.57.2), Firefox 12, Opera 11.62. In all the web browsers the demo has no horizontal scrollbars and it looks as following:

enter image description here

In the future it would be better to change the calculation of width of the grid more deep to have no direct dependency from any version number or web browser. I hope it will be possible if one would use more jQuery methods $.width and $.outerWidth in some places of jqGrid. In any way I hope that the above described fix would be already helpful for many jqGrid users.

UPDATED: I posted my suggestion to trirand as the bug report.

UPDATED 2: To be exactly there are three places in the code where are used the same $.browser.webkit || $.browser.safari construct as described above: inside setGridWidth, inside of getOffset, inside of calculation of the width of multiselect column, inside showHideCol and inside setGridWidth. The first three places uses isSafari variable. The last two places uses $.browser.webkit || $.browser.safari directly. One should replace in all the places the code

$.browser.webkit||$.browser.safari

to

($.browser.webkit || $.browser.safari) && parseFloat($.browser.version)<536.5

So one should do this in three places:

  1. at the definition of the isSafari (see me original post)
  2. inside of showHideCol
  3. inside of setGridWidth

You can download the fixed version of the jquery.jqGrid.src with all the fixes here. You can make the same changes in the code of jquery.jqGrid.src yourself if you have to use old version of jqGrid. To created minimized version for the production you can use any minimizer which you good know. I use for example Microsoft Ajax Minifier 4.0. Just install it and execute

AjaxMin.exe jquery.jqGrid.src-fixed3.js -o jquery.jqGrid.min-fixed3.js

As the result you will get jquery.jqGrid.min-fixed3.js which will be even smaller as original jquery.jqGrid.min.js. Even if you add the comment header to the file (see modified file) the file will be still smaller as original version of jquery.jqGrid.min.js.

After some iterations of my bug report and the improvements there are one more version of the fix where the method cellWidth was introduced:

cellWidth : function () {
    var $testDiv = $("<div class='ui-jqgrid' style='left:10000px'><table class='ui-jqgrid-btable' style='width:5px;'><tr class='jqgrow'><td style='width:5px;'></td></tr></table></div>"),
        testCell = $testDiv.appendTo("body")
            .find("td")
            .width();
        $testDiv.remove();
        return testCell !== 5;
}

See here. If you prefer to follow the way you can do this also. In the case in all places where isSafari or $.browser.webkit || $.browser.safari (in showHideCol and setGridWidth) are used you can use $.jgrid.cellWidth() instead.

UPDATED 3: Today was published jqGrid 4.3.3 which contains the fix which I described above (the cellWidth method). So I recommend all to use the new version.

How to pause JavaScript execution in Internet Explorer?

18 votes

I have the following scenario:

  • Main page
  • Nested page
  • Common JS file (which is included in both pages)

The nested page is subsequently loaded into an iframe of the main page. Both pages invoke a function from the common JS file on page load.

Live demo:
http://www.ecmazing.com/misc/pause-execution/mainpage.html
http://www.ecmazing.com/misc/pause-execution/nestedpage.html
http://www.ecmazing.com/misc/pause-execution/common.js

The common JS file contains one global function which paints the H1 element red. I would like to pause execution at the beginning of that function, so that the execution is paused while the H1 element is still black.

How to do it on the main page:

This is trivial. Simply load the page, open the dev tools of the browser, select the common.js file, and set a break-point at the first line of the function. Now, reload the page. The break-point will persist the reload, and execution will be paused.

How to do it on the nested page:

Now, in Chrome and Firefox (Firebug), the break-point that was set above (for the main page), will also work for the nested page. Both pages use the same JS file, and setting a break point in that file will apply for both pages automatically. Unfortunately, this rule does not apply to IE.

And even worse, even if I set the break point subsequently, and then reload the iframe only, the break-point will not persist.

So, I don't know how to pause execution for the nested page in IE. Can it be done? (I'm dealing with this by manually setting a debugger; at the beginning of the function, but I would love to be able to set the break-point via the dev tools in IE, if that's possible.)

The closest I can come to a solution is to set a breakpoint within the loadIFrame() function on the main page and then 'step in' until the nested page's Common.js file is loaded. In a more complicated example you would then be able to set your breakpoints within the new Common.js file and they would work correctly until the next time the iframe is loaded, when they would all be lost again.

Find out if HTML height is set by style or by content

17 votes

I have 2 divs:

<div id="div1"></div>
<div id="div2">div2</div>​

in my css:

#div1{ height:20px}​

Both divs have 20px height, check demo
How can I find out if the div have it's height due to content or have been set in css or inline style?
This helps me find out the dimensions have been set by the developer or just calculated by the browser.

I found a way to achieve it :)

function getRealHeight(element){
    var height=0;
    if (element.children().length>0){
        var temp = $('<div></div>');
        temp.append(element.children());
        height = element.height();
        element.append(temp.children());
    } else {
        var html=element.html();
        element.html('');
        height = element.height();
        element.html(html);
    }
    return height;
}

DEMO

What JavaScript should be included in the <head> and what included in the <body>?

17 votes

I am confused about which JavaScript should be included where?

For instance:

  • Where should one include the jQuery libraries? In the <head> or before the closing </body> element?

  • If the JavaScript is defined at the bottom in the <body>, can it be used inline in the body?

  • If it blocks parallel downloads, then why is it never said to include your CSS at the bottom?

The Place of the <script> Element

The script elements block progressive page downloads.
Browsers download several components at a time, but when they encounter an external script, they stop further downloads until the script file is downloaded, parsed, and executed.
This hurts the overall page time, especially if it happens several times during a page load.
To minimize the blocking effect, you can place the script element toward the end of the page, right before the closing tag.
This way there will be no other resources for the script to block. The rest of the page components will be downloaded and already engaging the user.
The worst antipattern is to use separate files in the head of the document:

<!doctype html>
<html>
<head>
    <title>My App</title>
    <!-- ANTIPATTERN -->
    <script src="jquery.js"></script>
    <script src="jquery.quickselect.js"></script>
    <script src="jquery.lightbox.js"></script>
    <script src="myapp.js"></script>
</head>
<body>
...
</body>
</html>

A better option is to combine all the files:

<!doctype html>
<html>
<head>
    <title>My App</title>
    <script src="all_20100426.js"></script>
</head>
<body>
    ...
</body>
</html>

And the best option is to put the combined script at the very end of the page:

<!doctype html>
<html>
<head>
    <title>My App</title>
</head>
<body>
    ...
    <script src="all_20100426.js"></script>
</body>

“JavaScript Patterns, by Stoyan Stefanov (O’Reilly). Copyright 2010 Yahoo!, Inc., 9780596806750.”

jquery $('<div>') vs $('<div />')

15 votes

Possible Duplicate:
$('<element>') vs $('<element />') in jQuery

Which one of these two are the correct way to do it:

$('<div>') 

or

$('<div />')

They both seem to work. Is one way more right than the other, or do they both always work?

They produce identical results in jQuery.

Animating a changing ranking table

14 votes

I have a ranking table which changes every second. I want to animate the table rows smoothly (not necessarily every second; maybe every 5 seconds).

A quick search revealed this jQuery plugin, based on this animated table sort. For my purposes, it looks a bit too much like a sports ranking, and the code is outdated and unmaintained.

Are there alternative plugins/libraries to animate changing ranking tables?

There is an interesting post on stackoverflow on your same subject: Using jquery, how to I animate adding a new list item to a list?

Of course it should be changed a little bit, because maybe you want to add more than one item to the list.

But what you can do is to refresh it every X seconds, and for each of the list item add the item in an animated way.

How does inline Javascript (in HTML) work?

13 votes

I know this is bad practice. Don't write code like this if at all possible.

Of course, we'll always find ourselves in situations where a clever snippet of inline Javascript can address an issue quickly.

I am pursuing this query in the interest of fully understanding what happens (and the potential pitfalls) when something like this is written:

<a href="#" onclick="alert('Hi')">Click Me</a>

As far as I can tell this is functionally the same as

<script type="text/javascript">
   $(function(){ // I use jQuery in this example
       document.getElementById('click_me').onclick = 
           function () { alert('Hi'); };
   });
</script>
<a href="#" id="click_me">Click Me</a>

Extrapolating from this it seems that the string assigned to attribute onclick is inserted within an anonymous function which is assigned to the element's click handler. Is this actually the case?

Because I'm starting to do things like this:

<a href="#" onclick="$(this).next().fadeIn(); return false;">Display my next sibling</a> <!-- Return false in handler so as not to scroll to top of page! --> 

Which works. But I don't know how much of a hack this is. It looks suspicious because there is no apparent function that is being returned from!

You might ask, why are you doing this, Steve? Inline JS is bad practice!

Well to be quite honest I'm tired of editing three different sections of code just to modify one section of a page, especially when I'm just prototyping something to see if it will work at all. It is so much easier and sometimes even makes sense for the code specifically related to this HTML element to be defined right within the element: When I decide 2 minutes later that this was a terrible, terrible idea I can nuke the entire div (or whatever) and I don't have a bunch of mysterious JS and CSS cruft hanging around in the rest of the page, slowing down rendering ever so slightly. This is similar to the concept of locality of reference but instead of cache misses we're looking at bugs and code bloat.

You've got it nearly correct, but you haven't accounted for context:

<a href="#" onclick="alert(this)">Click Me</a>

is actually closer to:

<script type="text/javascript">
document.getElementById('click_me').addEventListener("click", function(event) {
    (function(event) {
        alert(this);
    }).call(document.getElementById('click_me'), event);
});
</script>
<a href="#" id="click_me">Click Me</a>

Inline event handlers set this equal to the target of the event.

Finding closest anchor href via scrollOffset

13 votes

I have a UIWebView with an HTML page completely loaded. The UIWebView has a frame of 320 x 480 and scrolls horizontally. I can get the current offset a user is currently at. I would like to find the closest anchor using the XY offset so I can "jump to" that anchors position. Is this at all possible? Can someone point me to a resource in Javascript for doing this?

<a id="p-1">Text Text Text Text Text Text Text Text Text<a id="p-2">Text Text Text Text Text Text Text Text Text ... 

Update

My super sad JS code:

function posForElement(e)
{
    var totalOffsetY = 0;

    do
    {
        totalOffsetY += e.offsetTop;
    } while(e = e.offsetParent)

    return totalOffsetY;
}

function getClosestAnchor(locationX, locationY)
{
    var a = document.getElementsByTagName('a');

    var currentAnchor;
    for (var idx = 0; idx < a.length; ++idx)
    {
        if(a[idx].getAttribute('id') && a[idx+1])
        {
            if(posForElement(a[idx]) <= locationX && locationX <= posForElement(a[idx+1])) 
            {
                currentAnchor = a[idx];
                break;
            }
            else
            {
                currentAnchor = a[0];
            }
        }
    }

    return currentAnchor.getAttribute('id');
}

Objective-C

float pageOffset = 320.0f;

NSString *path = [[NSBundle mainBundle] pathForResource:@"GetAnchorPos" ofType:@"js"];
NSString *jsCode = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[webView stringByEvaluatingJavaScriptFromString:jsCode];

NSString *execute = [NSString stringWithFormat:@"getClosestAnchor('%f', '0')", pageOffset];
NSString *anchorID = [webView stringByEvaluatingJavaScriptFromString:execute];

[UPDATE] I rewrote the code to match all the anchors that have an id, and simplified the comparison of the norm of the vectors in my sortByDistance function.

Check my attempt on jsFiddle (the previous one was here ).

The javascript part :

// findPos : courtesy of @ppk - see http://www.quirksmode.org/js/findpos.html
var findPos = function(obj) {
    var curleft = 0,
        curtop = 0;
    if (obj.offsetParent) {
        curleft = obj.offsetLeft;
        curtop = obj.offsetTop;
        while ((obj = obj.offsetParent)) {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        }
    }
    return [curleft, curtop];
};

var anchors = document.body.querySelectorAll('a[id]');

var findClosestAnchor = function( anchors ) {

    var sortByDistance = function(element1, element2) {

        var pos1 = findPos( element1 ),
            pos2 = findPos( element2 );

        // vect1 & vect2 represent 2d vectors going from the top left extremity of each element to the point positionned at the scrolled offset of the window
        var vect1 = [
                window.scrollX - pos1[0],
                window.scrollY - pos1[1]
            ],
            vect2 = [
                window.scrollX - pos2[0],
                window.scrollY - pos2[1]
            ];

        // we compare the length of the vectors using only the sum of their components squared
        // no need to find the magnitude of each (this was inspired by Mageek’s answer)
        var sqDist1 = vect1[0] * vect1[0] + vect1[1] * vect1[1],
            sqDist2 = vect2[0] * vect2[0] + vect2[1] * vect2[1];

        if ( sqDist1 <  sqDist2 ) return -1;
        else if ( sqDist1 >  sqDist2 ) return 1;
        else return 0;
    };

    // Convert the nodelist to an array, then returns the first item of the elements sorted by distance
    return Array.prototype.slice.call( anchors ).sort( sortByDistance )[0];
};

I’ve not tested it on a smartphone yet but I don’t see any reasons why it wouldn’t work. Here is why I used the var foo = function() {}; form (more javascript patterns).

The return Array.prototype.slice.call( anchors ).sort( sortByDistance )[0]; line is actually a bit tricky.

document.body.querySelectorAll('a['id']') returns me a NodeList with all the anchors that have the attribute "id" in the body of the current page. Sadly, a NodeList object does not have a "sort" method, and it is not possible to use the sort method of the Array prototype, as it is with some other methods, such as filter or map (NodeList.prototype.sort = Array.prototype.sort would have been really nice).

This article explains better that I could why I used Array.prototype.slice.call to turn my NodeList into an array.

And finally, I used the Array.prototype.sort method (along with a custom sortByDistance function) to compare each element of the NodeList with each other, and I only return the first item, which is the closest one.

To find the position of the elements that use fixed positionning, it is possible to use this updated version of findPos : http://www.greywyvern.com/?post=331.

My answer may not be the more efficient (drdigit’s must be more than mine) but I preferred simplicity over efficiency, and I think it’s the easiest one to maintain.

[YET ANOTHER UPDATE]

Here is a heavily modified version of findPos that works with webkit css columns :

// Also adapted from PPK - this guy is everywhere ! - check http://www.quirksmode.org/dom/getstyles.html
var getStyle = function(el,styleProp)
{
    if (el.currentStyle)
        var y = el.currentStyle[styleProp];
    else if (window.getComputedStyle)
        var y = document.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp);
    return y;
}

// findPos : original by @ppk - see http://www.quirksmode.org/js/findpos.html
// made recursive and transformed to returns the corect position when css columns are used

var findPos = function( obj, childCoords ) {
   if ( typeof childCoords == 'undefined'  ) {
       childCoords = [0, 0];
   }

   var parentColumnWidth,
       parentHeight;

   var curleft, curtop;

   if( obj.offsetParent && ( parentColumnWidth = parseInt( getStyle( obj.offsetParent, '-webkit-column-width' ) ) ) ) {
       parentHeight = parseInt( getStyle( obj.offsetParent, 'height' ) );
       curtop = obj.offsetTop;
       column = Math.ceil( curtop / parentHeight );
       curleft = ( ( column - 1 ) * parentColumnWidth ) + ( obj.offsetLeft % parentColumnWidth );
       curtop %= parentHeight;
   }
   else {
       curleft = obj.offsetLeft;
       curtop = obj.offsetTop;
   }

   curleft += childCoords[0];
   curtop += childCoords[1];

   if( obj.offsetParent ) {
       var coords = findPos( obj.offsetParent, [curleft, curtop] );
       curleft = coords[0];
       curtop = coords[1];
   }
   return [curleft, curtop];
}

! operator in JavaScript

13 votes

I am now confused about ! operator in JavaScript. My understanding was ! operator operates only on boolean. But a comment to one of my answers says it can operate on anything and returns a boolean, which happened to be true after I did some tests.

alert(!undefined); //true
alert(!function(){}); //false
alert(!{}); //false
alert(!null); //true
alert(!()); //crash
alert(!"false"); //false
alert(!false)​;​​​​​​​​​​​​ //true​​​​​​​​​​​​​​​​​​

Can somebody help me generalize the behavior of ! operator.

EDIT

Even more confusing stuff:

​alert( new String() == ""); //true
alert(!""); //true
alert(! new String()); //false

How? ​

! does what you think: turns true to false and vice-versa. The weird behavior has to do with how Javascript can convert literally anything to true or false.

http://11heavens.com/falsy-and-truthy-in-javascript

Like in C (only worse) all values can be promoted to true or false. The googlable terms you want are "truthy" and "falsy," or "truthiness" and "falsiness." Truthy means something converts to true, falsy means something converts to false. All values are truthy except null, undefined, 0, "", NaN, and... false

This link has more fun examples:

http://www.sitepoint.com/javascript-truthy-falsy/

And this site really likes doing pathological things with the funny behavior here:

http://wtfjs.com

Also note that == really tries hard to make things comparable whereas === just returns false if the things aren't comparable. Javascript has lots of "gotchas" like this that make me try to avoid writing more than a few dozen lines of it at a time.

Is IE The Only Browser (or version) That Does Not Allow Flash Object Manipulation?

12 votes

I've tried multiple ways to edit Flash Objects / Embeds via Javascript and it seems to work in everything but IE, so I'm thinking about just throwing IE out the window for this application unless there are older + used version of other browsers that also do not allow you to edit objects. An example of this would be:

document.getElementById(divID).innerHTML = '<object ...><embed ...><\/embed><\/object>';

or in jquery

var params = '<param name="allowFullScreen" value="true" />' +
             '<param name="allowScriptAccess" value="always" />' +
             '<param name="allowNetworking" value="all" />' +
             '<param name="movie" value="player.swf" />' +
$("#objectPlayer").html(params);

If all the rest of the modern browsers and the most used versions of them do support this kind of editing then I'll just scrap IE. And before I get floods of the SWFObject JS Framework, I'm not going to include a huge framework for a browser that I do not believe is going to contain my demographic.

JSFiddle

Here's a link to a JSFiddle I created. It works in all browsers but IE8

I believe the <param>part of your code is for <object>.

You have to pass the name/value pairs for embed too.

$("#objectPlayer embed").attr({
    "src": "fileName.swf",
    "name": "fileName",
    "allowFullScreen": "true",
    "width": 200,
    "height": 100,
    "type": "application/x-shockwave-flash"

    //and so on...
    });

But I would use SWFObject anyway, it is the industry standard, it's quite robust and it is the best way of embedding flash on the website.

Implementing smooth sketching and drawing on the <canvas> element

12 votes

I am trying to create a drawing area with canvas. I am having trouble with making the lines look smooth when drawing curves and I also have changing line thickness in my algorithm which looks bad as well because the size jumps to much as well and you can see where the size changed. I did find this link on stackoverflow but this was for a native iPhone app and I can't figure it out.

Here is my current JS code. and Here is it running on jsFiddle

var xStart,
xEnd,
yStart,
yEnd,
paint,
ctx;
$(document).ready(function (){

   ctx = $('canvas')[0].getContext("2d");
   ctx.strokeStyle = '#000';
   ctx.lineJoin="round";
   ctx.lineCap="round";
   ctx.lineWidth = 1;


   $('canvas').bind('mousedown mousemove mouseup mouseleave touchstart touchmove touchend', function(e){
        var orig = e.originalEvent;

        if(e.type == 'mousedown'){
            e.preventDefault(); e.stopPropagation();

            xStart = e.clientX - $(this).offset().left;
            yStart = e.clientY - $(this).offset().top;
            xEnd = xStart;
            yEnd = yStart;

            paint = true;
            draw(e.type);

        }else if(e.type == 'mousemove'){
            if(paint==true){
                xEnd = e.clientX - $(this).offset().left;
                yEnd = e.clientY - $(this).offset().top;


               lineThickness = 1 + Math.sqrt((xStart - xEnd) *(xStart-xEnd) + (yStart - yEnd) * (yStart-yEnd))/5;

               if(lineThickness > 10){
                    lineThickness = 10;   
               }

                ctx.lineWidth = lineThickness;
                draw(e.type);
            }
        }else if(e.type == 'mouseup'){
            paint = false;
        }else if(e.type == 'mouseleave'){
            paint = false;
        }else if(e.type == 'touchstart'){
            if(orig.touches.length == 1){
                e.preventDefault(); e.stopPropagation();

                xStart = orig.changedTouches[0].pageX - $(this).offset().left;
                yStart = orig.changedTouches[0].pageY - $(this).offset().top;
                xEnd = xStart;
                yEnd = yStart; 

                paint = true;
                draw(e.type);
            }
        }else if(e.type == 'touchmove'){
            if(orig.touches.length == 1){
                if(paint==true){
                    xEnd = orig.changedTouches[0].pageX - $(this).offset().left;
                    yEnd = orig.changedTouches[0].pageY - $(this).offset().top;


                            lineThickness = 1 + Math.sqrt((xStart - xEnd) *(xStart-xEnd) + (yStart - yEnd) * (yStart-yEnd))/6;
                       if(lineThickness > 10){
                          lineThickness = 10;   
                       }


                      ctx.lineWidth = lineThickness;


                    draw(e.type);
                }
            }
        }else if(e.type == 'touchend'){
            paint = false;
        }

      });
    });


    function draw(event){

    if(event == 'mousedown'){
        ctx.beginPath();
        ctx.moveTo(xStart, yStart);
        ctx.lineTo(xEnd, yEnd);
        ctx.stroke();
    }else if(event == 'mousemove'){
        ctx.beginPath();
        ctx.moveTo(xStart, yStart);
        ctx.lineTo(xEnd, yEnd);
        ctx.stroke();
    }else if(event == 'touchstart'){
        ctx.beginPath();
        ctx.moveTo(xStart, yStart);
        ctx.lineTo(xEnd, yEnd);
        ctx.stroke();
    }else if(event == 'touchmove'){
        ctx.beginPath();
        ctx.moveTo(xStart, yStart);
        ctx.lineTo(xEnd, yEnd);
        ctx.stroke();
    }
    xStart = xEnd;
    yStart = yEnd;                  
}

Thank you all in advance.

This is what it looks like right now if you draw. current (jagged) implementation

... and this is what I would love to achieve:

smooth brushstrokes

I made something like this a while ago and turned it into a jquery plugin. have a look over here, if it's what you're after I'll post a more detailed answer and dig out the simplified jquery version from my archives:

http://jsfiddle.net/95tft/

EDIT

OK, sorry I couldn't do this yesterday:

Originally the code above was forked from Mr Doob's 'harmony' sketcher over here: http://mrdoob.com/projects/harmony/#ribbon

(which I think is the best solution). But I kinda broke it down and remade it for my own purposes on another project. I've hacked my own plugin a bit to make it a bit easier still over here:

http://jsfiddle.net/dh3bj/

The only thing you might want to change is to change it to work on mousedown/mouseup which should be easy also have a look at the settings at the bottom of the plugin, you should be able to get the effect you want by playing with the brush size, colour, alpha (rgba) etc.

Hope that helps

Efficiency of creating an event handler in a nested loop: am I creating 1440 functions here?

12 votes

I just developed a little code to create a 24x60 table. I want to print the id of each <td> on mouseover:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<style type="text/css">
table {
    background-color:blue;
}
td {
    width: 2px;
    height: 2px;
    background-color:red;
}
</style>
</head>
<body>
<table id="time-table"></table>
<script type="text/javascript">
var table = document.getElementById( "time-table" );
for ( var r = 0; r < 24; r++ ) {
    var row = document.createElement( "tr" );
    for ( var c = 0; c < 60; c++ ) {
        var td = document.createElement( "td" );
        td.id = "td-" + r + "-" + c;
        td.onmouseover = function ( e ) {
            console.log( this.id );
        }
        row.appendChild( td );
    }
    table.appendChild( row );
}
</script>
</body>
</html>

The code works, but now I'm concerned if it is optimized? Am I creating 1440 event handling functions in the nested loops? Or is the JavaScript interpreter smart enough to only create one function and assign it to 1440 <td> elements?

No, JavaScript won't to any optimizations (well, maybe some implementations do, but you should not rely on that). You are really creating that many functions.

Better define the function once and reuse it:

var handler = function() {
    console.log(this.id);
}

for ( var r = 0; r < 24; r++ ) {
    var row = document.createElement( "tr" );
    for ( var c = 0; c < 60; c++ ) {
        var td = document.createElement( "td" );
        td.id = "td-" + r + "-" + c;
        td.onmouseover = handler;
        row.appendChild( td );
    }
    table.appendChild( row );
}

Or consider to use event delegation, that is, binding the handler to an ancestor of the cells:

table.onmouseover = function(event) {
    event = event || window.event;
    var target = event.target || event.srcElement;

    if(target.nodeName === 'TD') {
        console.log(target.id);
    }
};

This works, since events bubble up the DOM tree and might even better performance-wise in some browsers.

A good resource to learn about event handling are the articles at quirksmode.org.

How is $('h1') logging to the web console as an array in jQuery?

12 votes

If you do console.log($('some selector')) in the browser, it returns what looks like an array (first line):

picture from latest version of chrome web console on Github project page

But notice that it's not an instanceof Array, but it's actually the jQuery object.

When you do console.dir($('h1')), it shows it's actually the jQuery object.

The question is, how are they making it look like it's an array in the web console? I noticed in the jQuery source here they add reference to a few Array and Object methods, and here they add toArray (and slice and others) to the jQuery object. Is the web console somehow checking for these methods and if it finds one (toArray, indexOf, slice, etc.), it prints it as an Array? I would like to get this behavior out of any custom object, such as the Ember.ArrayProxy. Currently when you log the Ember.ArrayProxy it shows > Object or whatever, but it would be nice to show it as an array.

Any ideas?

You make your object inherit Array using the prototype, like so:

function SomeType() {
    this.push(16);
}

SomeType.prototype = [];
SomeType.prototype.constructor = SomeType; // Make sure there are no unexpected results

console.log(new SomeType()); // Displays in console as [16]

And, of course, all jQuery objects are instances of the jQuery function/constructor, so that's how jQuery does it. As a bonus, because of the inheritance, you get all the methods from Array, and the indexing that comes with it too!

Layout with fixed header and footer, fixed width sidebar and flexible content

9 votes

I'm trying set up a layout that will look like this: enter image description here

I want to use twitter bootstrap for the project, but I understand it may not be the best way to go for the basic layout that looks like this. I know how to setup the header and footer to be fixed at the top and bottom, but I have a hard time having my sidebar constant width and independently scrollable.

My current implementation is here: http://jsfiddle.net/Mwkrw/3/.

I tried setting up the fixed sidebar using Fixed sidebar naviagion in fluid twitter bootstrap 2.0 and a couple of other similar answers on stack overflow, but they all break when the sidebar is longer than the content and as far as I know there is no way to give it an independent scroll.

I would ideally like to do this with pure css - no javascript. I'm sure it's possible and it's my lack of skill and knowledge that prevents me form doing it properly, so there may be no point in unnecessarily adding javascript code. (I'm still adding a javascript tag in case it's not possible)

Thanks for all the help!

EDIT: So my header clearly did not need to be position fixed. Here is the new and improved version: http://jsfiddle.net/Mwkrw/4/ I'm still struggling with the two scrollable divs though.

The magic is in box-sizing:border-box;. For compatibility with Firefox, chrome<10, and safari<5.1, add the -webkit- and -moz- prefixes. IE supports it as of 8.0.

<!doctype html>
<html lang='en'>
    <head>
        <meta charset='utf-8'>
        <title>very structured layout</title>
        <style type='text/css'>
            *      {margin:0; padding:0;}
            body   {background:#fff; position:absolute; width:100%; height:100%;}
            #main  {background:#888; height:100%; padding:60px 0 40px; box-sizing:border-box;}
            #head  {background:#f8f; position:absolute; width:100%; height:60px;}
            #left  {background:#ff8; float:left; width:250px; height:100%; overflow:scroll;}
            #right {background:#8f8; height:100%; overflow:scroll;}
            #foot  {background:#f88; position:absolute; bottom:0; width:100%; height:40px;}​
        </style>
    </head>
    <body>
        <div id='head'>header: width = 100%, height = 40px</div>
        <div id='main'>
            <div id='left'>left: width = 250px, height = 100%</div>
            <div id='right'>right: width = 100% - 250px, height = 100%</div>
        </div>
        <div id='foot'>foot: width = 100%, height = 60px</div>​
    </body>
</html>

fiddle

edit: after Andres' solution made me realize I could achieve greater compatibility, I messed around a bit and came up with an alternate solution, which I think is more intuitive as well. It doesn't work in IE7, but it does work in IE8.

The page is the same as the above, with the only change being that the CSS is replaced with this:

*      {margin:0; padding:0;}
body   {background:#fff;}
#main  {background:#888; position:absolute; top:40px; bottom:60px; width:100%;}
#head  {background:#f8f; position:absolute; width:100%; height:40px;}
#left  {background:#ff8; position:absolute; width:250px; height:100%; overflow:scroll;}
#right {background:#8f8; margin-left:250px; height:100%; overflow:scroll;}
#foot  {background:#f88; position:absolute; bottom:0; width:100%; height:60px;}

fiddle

Note that, for both versions, #head and #foot need to have an overflow property other than visible if their content would otherwise extend off the page.

jquery .val() += idiom

9 votes

What's the clearest commonly used idiom for this jQuery snippet?

$('#someTextarea').val( $('#someTextarea').val() + someString );

It feels clunky to wrap the original code in a one-line function

EDIT: So I can pass a function, which is cool... but my real intentions are for jsfiddles, where I currently do stuff like this:

function lazylog (str) { 
    $('#ta').val( $('#ta').val() + str + '\n' );
}
// or
function lazylogPlain (str) {
    document.getElementById('ta').value += str + '\n';
}

// view results of little experiments
lazylog( test1() );
lazylog( test2() );
lazylog( test3() );
// etc...

Don't know if that context would produce different answers or just make me seem really lazy for wanting to type even less than that. console.log doesn't count, I want the textarea.

Just don't use jQuery.

document.getElementById('someTextarea').value += someString;

will be clearer, faster, and works as well as the jQuery snippet. If you really want to use the $ selector, with only one element you can also

$('#someTextarea')[0].value += someString; // least to type

Other possibilities are the .val() method with a function

$('#someTextarea').val(function(index, oldValue) { return oldValue + someString; })

or a variant with .each() (which is [nearly] equivalent to what val() does internally for text inputs):

$('#someTextarea').each(function(){ this.value += someString; })

These both need a one-line function expression you didn't like, but they have the advantage of working for more than one selected elements and they also return the jQuery object to preserve the chainability feature.