run another function after sorttable

D

David Mark

Question said:
I am using the sorttable js from http://www.kryogenix.org/code/browser/sorttable/
and now need to execute another function after each time the table is
sorted but can't figure out where I need to call my function from
within the sorttable js. Can anyone guide me on this?

Well, what do we have here?

/*
SortTable
version 2
7th April 2007
Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/

Instructions:
Download this file
Add <script src="sorttable.js"></script> to your HTML


Right there you should have realized this is a throwaway effort.


Add class="sortable" to any table you'd like to make sortable


Lame design.


Click on the headers to sort


You don't "click on" anything. You "click" things.


Thanks to many, many people for contributions and suggestions.
Licenced as X11: http://www.kryogenix.org/code/browser/licence.html
This basically means: do what you want with it.
*/


var stIsIE = /*@cc_on!@*/false;


Bad omen.


sorttable = {
init: function() {
// quit if this function has already been called
if (arguments.callee.done) return;
// flag this function so we don't do the same thing twice
arguments.callee.done = true;


Why not use a variable in a closure?


// kill the timer
if (_timer) clearInterval(_timer);

if (!document.createElement || !document.getElementsByTagName) return;


That makes absolutely no sense. Should have checked for those before
_creating_ the function. If the calling code doesn't know _in advance_
what can and cannot be used, the API is virtually worthless for
cross-browser scripting.


sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;


Don't like the look of that.


forEach(document.getElementsByTagName('table'), function(table) {
if (table.className.search(/\bsortable\b/) != -1) {
sorttable.makeSortable(table);
}
});


A forEach function that takes live DOM collections? And an each
function that modifies the DOM? There's a combustible combination.


},

makeSortable: function(table) {
if (table.getElementsByTagName('thead').length == 0) {
// table doesn't have a tHead. Since it should have, create one and
// put the first table row in it.
the = document.createElement('thead');
the.appendChild(table.rows[0]);
table.insertBefore(the,table.firstChild);
}
// Safari doesn't support table.tHead, sigh
if (table.tHead == null) table.tHead =
table.getElementsByTagName('thead')[0];

if (table.tHead.rows.length != 1) return; // can't cope with two
header rows

// Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
// "total" rows, for example). This is B&R, since what you're supposed
// to do is put them in a tfoot. So, if there are sortbottom rows,
// for backwards compatibility, move them to tfoot (creating it if
needed).
sortbottomrows = [];
for (var i=0; i<table.rows.length; i++) {
if (table.rows.className.search(/\bsortbottom\b/) != -1) {
sortbottomrows[sortbottomrows.length] = table.rows;
}
}
if (sortbottomrows) {
if (table.tFoot == null) {
// table doesn't have a tfoot. Create one.
tfo = document.createElement('tfoot');
table.appendChild(tfo);
}
for (var i=0; i<sortbottomrows.length; i++) {
tfo.appendChild(sortbottomrows);
}
delete sortbottomrows;


Oh brother.


}


[...]


getInnerText: function(node) {
// gets the text we want to use for sorting for a cell.
// strips leading and trailing whitespace.
// this is *not* a generic getInnerText function; it's special to
sorttable.
// for example, you can override the cell text with a customkey
attribute.
// it also gets .value for <input> fields.


Tangled design.


hasInputs = (typeof node.getElementsByTagName == 'function') &&
node.getElementsByTagName('input').length;


Bad host object detection. Nothing says typeof must return "function"
for host object methods. In fact, it often doesn't (e.g. IE).



if (node.getAttribute("sorttable_customkey") != null) {
return node.getAttribute("sorttable_customkey");


Relies on invalid markup _and_ getAttribute. As is often the case, this
script was doomed from the start due to a thoughtless design.


}
else if (typeof node.textContent != 'undefined' && !hasInputs) {
return node.textContent.replace(/^\s+|\s+$/g, '');


Primitive.


}
else if (typeof node.innerText != 'undefined' && !hasInputs) {
return node.innerText.replace(/^\s+|\s+$/g, '');


Repetitive.


}
else if (typeof node.text != 'undefined' && !hasInputs) {
return node.text.replace(/^\s+|\s+$/g, '');


Again. And what sort of table-related node will have a "text" property?


}
else {
switch (node.nodeType) {
case 3:
if (node.nodeName.toLowerCase() == 'input') {
return node.value.replace(/^\s+|\s+$/g, '');
}
case 4:
return node.nodeValue.replace(/^\s+|\s+$/g, '');
break;


LOL. Can snip that case for sure.


case 1:
case 11:


Getting more ridiculous with every line.


var innerText = '';
for (var i = 0; i < node.childNodes.length; i++) {
innerText += sorttable.getInnerText(node.childNodes);
}
return innerText.replace(/^\s+|\s+$/g, '');
break;
default:
return '';
}
}
},

[...]

/* ******************************************************************
Supporting functions: bundled here to avoid depending on a library
****************************************************************** */

What does that mean?


// Dean Edwards/Matthias Miller/John Resig


No, no, no. :)


/* for Mozilla/Opera9 */


You know you are in trouble with comments like these. What do Mozilla
and Opera 9 exclusively have in common? Nothing, except perhaps to the
casual observer. From the looks of it, they were exclusively peering at
IE, FF (3?) and Opera 9 at the time they cobbled this together. That
indicates they had no clue what they were doing. Such a "pragmatic"
approach is to be expected from Resig and Edwards (two of the worst in
the industry). I actually don't know the other guy, but he's keeping
very bad company.


if (document.addEventListener) {


Really bad host object detection.

http://www.cinsoft.net/host.html


document.addEventListener("DOMContentLoaded", sorttable.init, false);
}

/* for Internet Explorer */
/*@cc_on @*/
/*@if (@_win32)
document.write("<script id=__ie_onload defer
src=javascript:void(0)><\/script>");
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function() {
if (this.readyState == "complete") {
sorttable.init(); // call the onload handler
}
};
/*@end @*/


LOL. This has Dean Edwards written all over it. This is the hack that
causes Dojo apps to throw "Operation Aborted" at random intervals. It's
funny because I told them to take that out to stop the sporadic
explosions. They responded by asking if I had a better way. I
explained that they could simply put a snippet of script at the bottom
of the page, call their initialization on a timeout, etc. They decided
that their users were too stupid to realize that an extra SCRIPT block
is an excellent trade for endless misery (e.g. aborted page loads). And
one guy said that putting scripts in the body would upset the
"progressive enhancement" people. With a straight face no less. The
final conclusion was that I "just didn't understand" what JS developers
want in a library (aborted page loads apparently). I should have known
better than to try to teach them anything. About the same time, they
also un-declared all of their globals because some contributor called
"bill" said it would make Dojo run faster in IE. Couldn't talk them out
of that one either, despite the fact that the test data posted clearly
did not support the ridiculous conclusions that followed. Have I
mentioned that you should not use Dojo?


/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
var _timer = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
sorttable.init(); // call the onload handler
}
}, 10);
}


That looks like Resig's contribution. But even he has moved on from UA
sniffing (but only after years of scathing code reviews). He's at the
object inference stage now.

http://www.jibbering.com/faq/faq_notes/not_browser_detect.html

http://groups.google.com/group/comp.lang.javascript/msg/8ee3b684baaa0baa


/* for other browsers */
window.onload = sorttable.init;


But that's not even close to the same behavior. I guess they don't
really "care" about "other browsers". :)


// written by Dean Edwards, 2005


Oops.


// with input from Tino Zijdel, Matthias Miller, Diego Perini

// http://dean.edwards.name/weblog/2005/10/add-event/

function dean_addEvent(element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else {
// assign each event handler a unique ID
if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++;
// create a hash table of event types for the element
if (!element.events) element.events = {};
// create a hash table of event handlers for each element/event pair
var handlers = element.events[type];
if (!handlers) {
handlers = element.events[type] = {};
// store the existing event handler (if there is one)
if (element["on" + type]) {
handlers[0] = element["on" + type];
}
}
// store the event handler in the hash table
handlers[handler.$$guid] = handler;
// assign a global event handler to do all the work
element["on" + type] = handleEvent;
}
};


Rotting garbage.


// a counter used to create unique IDs
dean_addEvent.guid = 1;

function removeEvent(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else {
// delete the event handler from the hash table
if (element.events && element.events[type]) {
delete element.events[type][handler.$$guid];
}
}
};

function handleEvent(event) {
var returnValue = true;
// grab the event object (IE uses a global event object)
event = event || fixEvent(((this.ownerDocument || this.document ||
this).parentWindow || window).event);

Depending on the context, fixEvent may get anything (e.g. a window, a
document, an element) and it may well be the wrong anything (e.g. a
window object that is unrelated to the element with the attached listener).


// get a reference to the hash table of event handlers
var handlers = this.events[event.type];
// execute each event handler
for (var i in handlers) {
this.$$handleEvent = handlers;


Any time you encounter lots of dollar signs in JS, it signifies money
being flushed down the toilet. Woe is anyone who has relied on this (or
similar) scripts over the years. But I suppose they help to perpetuate
the myth that cross-browser scripting is impossible, which keeps the bad
books selling and the incompetents who treat them as bibles employed.
Of course it is impossible for a neophyte to tackle GP event handling
(as clearly evidenced here). Just don't rely on such impossible
scripts. How hard is that? ;)


if (this.$$handleEvent(event) === false) {
returnValue = false;
}
}
return returnValue;
};

function fixEvent(event) {
// add W3C standard event methods
event.preventDefault = fixEvent.preventDefault;
event.stopPropagation = fixEvent.stopPropagation;
return event;


Leaks massive amounts of memory in some versions of FF. Rule of thumb,
don't augment host objects (especially event objects).


};
fixEvent.preventDefault = function() {
this.returnValue = false;
};
fixEvent.stopPropagation = function() {
this.cancelBubble = true;
}

// Dean's forEach: http://dean.edwards.name/base/forEach.js
/*
forEach, version 1.0
Copyright 2006, Dean Edwards
License: http://www.opensource.org/licenses/mit-license.php
*/

// array-like enumeration
if (!Array.forEach) { // mozilla already supports this


There's that multi-browser mentality peeking out from the comments again.


Array.forEach = function(array, block, context) {
for (var i = 0; i < array.length; i++) {
block.call(context, array, i, array);
}
};

Not even close (and I sure as hell wouldn't pass this a live DOM
collection).

}

// generic enumeration
Function.prototype.forEach = function(object, block, context) {
for (var key in object) {
if (typeof this.prototype[key] == "undefined") {
block.call(context, object[key], key, object);
}
}
};

// character enumeration
String.forEach = function(string, block, context) {
Array.forEach(string.split(""), function(chr, index) {
block.call(context, chr, index, string);
});
};

// globally resolve forEach enumeration
var forEach = function(object, block, context) {
if (object) {


Just document that the first argument must be "truthy". This function
returns undefined in any event, so the short-circuit is obviously
counter-productive (i.e. an exception would be _much_ preferable for the
caller).


var resolve = Object; // default
if (object instanceof Function) {


Don't use instanceof under any circumstances (sure as hell not like
this). Again, it is reminiscent of Dojo.


// functions have a "length" property
resolve = Function;
} else if (object.forEach instanceof Function) {
// the object implements a custom forEach method so use that

It just gets worse and worse. This is not how to detect a callable
object (use typeof). I'm sure the author was confused by the fact that
DOM collection objects (and others) are callable in some browsers.
That's when they should have taken a step back and re-thought this
ludicrous design. But that never seems to happen (see jQuery, Dojo,
etc.) Why are these guys so intent on creating the most inappropriate
and error-prone designs possible? It's like they aim straight for the
barriers on purpose. I guess that's what they call "pragmatism". :)


object.forEach(block, context);
return;
} else if (typeof object == "string") {
// the object is a string

There you go!

resolve = String;
} else if (typeof object.length == "number") {
// the object is array-like

Is it?

window.alert(typeof (new String('test').length)); // "number"


resolve = Array;
}
resolve.forEach(object, block, context);
}
};

Isn't that last function the ultimate in futility? Why would anyone
seek to write such a thing unless they were completely in the dark about
JS, as well as browser scripting. It's positively Dojo-esque.

So anyway, and I hope it goes without saying, do not use this script
under any circumstances.

I'm sure there will be some serious hissing on IRC tonight. Glad I
won't be there to hear it. And they say Usenet is an old-fashioned
sewer. IRC must be a subterranean system running underneath. Come on
out and get some sun boys. You must be half-blind albinos by now. :)

And I'm predicting a petulant "not helpful" response from the OP, but
we'll see. Sure as hell, this is the best help they could hope for, but
that is usually the sort of help that is arbitrarily discarded as "noise".
 
Q

Question Boy

Question said:
I am using the sorttable js fromhttp://www.kryogenix.org/code/browser/sorttable/
and now need to execute another function after each time the table is
sorted but can't figure out where I need to call my function from
within the sorttable js.  Can anyone guide me on this?

Well, what do we have here?
/*
  SortTable
  version 2
  7th April 2007
  Stuart Langridge,http://www.kryogenix.org/code/browser/sorttable/

  Instructions:
  Download this file
  Add <script src="sorttable.js"></script> to your HTML

Right there you should have realized this is a throwaway effort.

  Add class="sortable" to any table you'd like to make sortable

Lame design.

  Click on the headers to sort

You don't "click on" anything.  You "click" things.

  Thanks to many, many people for contributions and suggestions.
  Licenced as X11:http://www.kryogenix.org/code/browser/licence.html
  This basically means: do what you want with it.
*/

var stIsIE = /*@cc_on!@*/false;

Bad omen.

sorttable = {
  init: function() {
    // quit if this function has already been called
    if (arguments.callee.done) return;
    // flag this function so we don't do the same thing twice
    arguments.callee.done = true;

Why not use a variable in a closure?

    // kill the timer
    if (_timer) clearInterval(_timer);

    if (!document.createElement || !document.getElementsByTagName) return;

That makes absolutely no sense.  Should have checked for those before
_creating_ the function.  If the calling code doesn't know _in advance_
what can and cannot be used, the API is virtually worthless for
cross-browser scripting.

    sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;

Don't like the look of that.

    forEach(document.getElementsByTagName('table'), function(table) {
      if (table.className.search(/\bsortable\b/) != -1) {
        sorttable.makeSortable(table);
      }
    });

A forEach function that takes live DOM collections?  And an each
function that modifies the DOM?  There's a combustible combination.

  },

  makeSortable: function(table) {
    if (table.getElementsByTagName('thead').length == 0) {
      // table doesn't have a tHead. Since it should have, create one and
      // put the first table row in it.
      the = document.createElement('thead');
      the.appendChild(table.rows[0]);
      table.insertBefore(the,table.firstChild);
    }
    // Safari doesn't support table.tHead, sigh
    if (table.tHead == null) table.tHead =
table.getElementsByTagName('thead')[0];

    if (table.tHead.rows.length != 1) return; // can't cope with two
header rows

    // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
    // "total" rows, for example). This is B&R, since what you're supposed
    // to do is put them in a tfoot. So, if there are sortbottom rows,
    // for backwards compatibility, move them to tfoot (creating it if
needed).
    sortbottomrows = [];
    for (var i=0; i<table.rows.length; i++) {
      if (table.rows.className.search(/\bsortbottom\b/) != -1){
        sortbottomrows[sortbottomrows.length] = table.rows;
      }
    }
    if (sortbottomrows) {
      if (table.tFoot == null) {
        // table doesn't have a tfoot. Create one.
        tfo = document.createElement('tfoot');
        table.appendChild(tfo);
      }
      for (var i=0; i<sortbottomrows.length; i++) {
        tfo.appendChild(sortbottomrows);
      }
      delete sortbottomrows;

Oh brother.

    }

[...]

  getInnerText: function(node) {
    // gets the text we want to use for sorting for a cell.
    // strips leading and trailing whitespace.
    // this is *not* a generic getInnerText function; it's special to
sorttable.
    // for example, you can override the cell text with a customkey
attribute.
    // it also gets .value for <input> fields.

Tangled design.

    hasInputs = (typeof node.getElementsByTagName == 'function') &&
                 node.getElementsByTagName('input').length;

Bad host object detection.  Nothing says typeof must return "function"
for host object methods.  In fact, it often doesn't (e.g. IE).

    if (node.getAttribute("sorttable_customkey") != null) {
      return node.getAttribute("sorttable_customkey");

Relies on invalid markup _and_ getAttribute.  As is often the case, this
script was doomed from the start due to a thoughtless design.

    }
    else if (typeof node.textContent != 'undefined' && !hasInputs) {
      return node.textContent.replace(/^\s+|\s+$/g, '');

Primitive.

    }
    else if (typeof node.innerText != 'undefined' && !hasInputs) {
      return node.innerText.replace(/^\s+|\s+$/g, '');

Repetitive.

    }
    else if (typeof node.text != 'undefined' && !hasInputs) {
      return node.text.replace(/^\s+|\s+$/g, '');

Again.  And what sort of table-related node will have a "text" property?

    }
    else {
      switch (node.nodeType) {
        case 3:
          if (node.nodeName.toLowerCase() == 'input') {
            return node.value.replace(/^\s+|\s+$/g, '');
          }
        case 4:
          return node.nodeValue.replace(/^\s+|\s+$/g, '');
          break;

LOL.  Can snip that case for sure.

        case 1:
        case 11:

Getting more ridiculous with every line.

          var innerText = '';
          for (var i = 0; i < node.childNodes.length; i++) {
            innerText += sorttable.getInnerText(node.childNodes);
          }
          return innerText.replace(/^\s+|\s+$/g, '');
          break;
        default:
          return '';
      }
    }
  },

[...]

/* ******************************************************************
   Supporting functions: bundled here to avoid depending on a library
   *******************************************************************/

What does that mean?

// Dean Edwards/Matthias Miller/John Resig

No, no, no.  :)

/* for Mozilla/Opera9 */

You know you are in trouble with comments like these.  What do Mozilla
and Opera 9 exclusively have in common?  Nothing, except perhaps to the
casual observer.  From the looks of it, they were exclusively peering at
IE, FF (3?) and Opera 9 at the time they cobbled this together.  That
indicates they had no clue what they were doing.  Such a "pragmatic"
approach is to be expected from Resig and Edwards (two of the worst in
the industry).  I actually don't know the other guy, but he's keeping
very bad company.

if (document.addEventListener) {

Really bad host object detection.

http://www.cinsoft.net/host.html

    document.addEventListener("DOMContentLoaded", sorttable.init, false);

}

/* for Internet Explorer */
/*@cc_on @*/
/*@if (@_win32)
    document.write("<script id=__ie_onload defer
src=javascript:void(0)><\/script>");
    var script = document.getElementById("__ie_onload");
    script.onreadystatechange = function() {
        if (this.readyState == "complete") {
            sorttable.init(); // call the onload handler
        }
    };
/*@end @*/

LOL.  This has Dean Edwards written all over it.  This is the hack that
causes Dojo apps to throw "Operation Aborted" at random intervals.  It's
funny because I told them to take that out to stop the sporadic
explosions.  They responded by asking if I had a better way.  I
explained that they could simply put a snippet of script at the bottom
of the page, call their initialization on a timeout, etc.  They decided
that their users were too stupid to realize that an extra SCRIPT block
is an excellent trade for endless misery (e.g. aborted page loads).  And
one guy said that putting scripts in the body would upset the
"progressive enhancement" people.  With a straight face no less.  The
final conclusion was that I "just didn't understand" what JS developers
want in a library (aborted page loads apparently).  I should have known
better than to try to teach them anything.  About the same time, they
also un-declared all of their globals because some contributor called
"bill" said it would make Dojo run faster in IE.  Couldn't talk them out
of that one either, despite the fact that the test data posted clearly
did not support the ridiculous conclusions that followed.  Have I
mentioned that you should not use Dojo?

/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
    var _timer = setInterval(function() {
        if (/loaded|complete/.test(document.readyState)) {
            sorttable.init(); // call the onload handler
        }
    }, 10);

}

That looks like Resig's contribution.  But even he has moved on from UA
sniffing (but only after years of scathing code reviews).  He's at the
object inference stage now.

http://www.jibbering.com/faq/faq_notes/not_browser_detect.html

http://groups.google.com/group/comp.lang.javascript/msg/8ee3b684baaa0baa

/* for other browsers */
window.onload = sorttable.init;

But that's not even close to the same behavior.  I guess they don't
really "care" about "other browsers".  :)

// written by Dean Edwards, 2005

Oops.

// with input from Tino Zijdel, Matthias Miller, Diego Perini

//http://dean.edwards.name/weblog/2005/10/add-event/

function dean_addEvent(element, type, handler) {
        if (element.addEventListener) {
                element.addEventListener(type, handler, false);
        } else {
                // assign each event handler a unique ID
                if (!handler.$$guid) handler.$$guid = dean_addEvent.guid++;
                // create a hash table of event types forthe element
                if (!element.events) element.events = {};
                // create a hash table of event handlers for each element/event pair
                var handlers = element.events[type];
                if (!handlers) {
                        handlers = element.events[type] = {};
                        // store the existing event handler (if there is one)
                        if (element["on" + type]){
                                handlers[0] = element["on" + type];
                        }
                }
                // store the event handler in the hash table
                handlers[handler.$$guid] = handler;
                // assign a global event handler to do all the work
                element["on" + type] = handleEvent;
        }

};

Rotting garbage.

// a counter used to create unique IDs
dean_addEvent.guid = 1;

function removeEvent(element, type, handler) {
        if (element.removeEventListener) {
                element.removeEventListener(type, handler, false);
        } else {
                // delete the event handler from the hashtable
                if (element.events && element.events[type]) {
                        delete element.events[type][handler.$$guid];
                }
        }

};

function handleEvent(event) {
        var returnValue = true;
        // grab the event object (IE uses a global event object)
        event = event || fixEvent(((this.ownerDocument || this.document ||
this).parentWindow || window).event);

Depending on the context, fixEvent may get anything (e.g. a window, a
document, an element) and it may well be the wrong anything (e.g. a
window object that is unrelated to the element with the attached listener).

        // get a reference to the hash table of event handlers
        var handlers = this.events[event.type];
        // execute each event handler
        for (var i in handlers) {
                this.$$handleEvent = handlers;

Any time you encounter lots of dollar signs in JS, it signifies money
being flushed down the toilet.  Woe is anyone who has relied on this (or
similar) scripts over the years.  But I suppose they help to perpetuate
the myth that cross-browser scripting is impossible, which keeps the bad
books selling and the incompetents who treat them as bibles employed.
Of course it is impossible for a neophyte to tackle GP event handling
(as clearly evidenced here).  Just don't rely on such impossible
scripts.  How hard is that?  ;)

                if (this.$$handleEvent(event) === false) {
                        returnValue = false;
                }
        }
        return returnValue;

};

function fixEvent(event) {
        // add W3C standard event methods
        event.preventDefault = fixEvent.preventDefault;
        event.stopPropagation = fixEvent.stopPropagation;
        return event;

Leaks massive amounts of memory in some versions of FF.  Rule of thumb,
don't augment host objects (especially event objects).

};

fixEvent.preventDefault = function() {
        this.returnValue = false;};

fixEvent.stopPropagation = function() {
  this.cancelBubble = true;

}

// Dean's forEach:http://dean.edwards.name/base/forEach.js
/*
        forEach, version 1.0
        Copyright 2006, Dean Edwards
        License:http://www.opensource.org/licenses/mit-license.php
*/

// array-like enumeration
if (!Array.forEach) { // mozilla already supports this

There's that multi-browser mentality peeking out from the comments again.

        Array.forEach = function(array, block, context) {
                for (var i = 0; i < array.length; i++) {
                        block.call(context, array, i, array);
                }
        };

Not even close (and I sure as hell wouldn't pass this a live DOM
collection).

}

// generic enumeration
Function.prototype.forEach = function(object, block, context) {
        for (var key in object) {
                if (typeof this.prototype[key] == "undefined") {
                        block.call(context, object[key], key, object);
                }
        }

};

// character enumeration
String.forEach = function(string, block, context) {
        Array.forEach(string.split(""), function(chr, index) {
                block.call(context, chr, index, string);
        });

};

// globally resolve forEach enumeration
var forEach = function(object, block, context) {
        if (object) {

Just document that the first argument must be "truthy".  This function
returns undefined in any event, so the short-circuit is obviously
counter-productive (i.e. an exception would be _much_ preferable for the
caller).

                var resolve = Object; // default
                if (object instanceof Function) {

Don't use instanceof under any circumstances (sure as hell not like
this).  Again, it is reminiscent of Dojo.

                        // functions have a "length" property
                        resolve = Function;
                } else if (object.forEach instanceof Function) {
                        // the object implements a custom forEach method so use that

It just gets worse and worse.  This is not how to detect a callable
object (use typeof).  I'm sure the author was confused by the fact that
DOM collection objects (and others) are callable in some browsers.
That's when they should have taken a step back and re-thought this
ludicrous design.  But that never seems to happen (see jQuery, Dojo,
etc.)  Why are these guys so intent on creating the most inappropriate
and error-prone designs possible?  It's like they aim straight for the
barriers on purpose.  I guess that's what they call "pragmatism".  :)

                        object.forEach(block, context);
                        return;
                } else if (typeof object == "string"){
                        // the object is a string

There you go!

                        resolve = String;
                } else if (typeof object.length == "number") {
                        // the object is array-like

Is it?

window.alert(typeof (new String('test').length)); // "number"

                        resolve = Array;
                }
                resolve.forEach(object, block, context);
        }

};

Isn't that last function the ultimate in futility?  Why would anyone
seek to write such a thing unless they were completely in the dark about
JS, as well as browser scripting.  It's positively Dojo-esque.

So anyway, and I hope it goes without saying, do not use this script
under any circumstances.

I'm sure there will be some serious hissing on IRC tonight.  Glad I
won't be there to hear it.  And they say Usenet is an old-fashioned
sewer.  IRC must be a subterranean system running underneath.  Come on
out and get some sun boys.  You must be half-blind albinos by now.  :)

And I'm predicting a petulant "not helpful" response from the OP, but
we'll see.  Sure as hell, this is the best help they could hope for, but
that is usually the sort of help that is arbitrarily discarded as "noise"..





I get you don't like the js, do you have any alternatives to recommend?
 
D

David Mark

Question Boy wrote:

[...]
I get you don't like the js, do you have any alternatives to recommend?

Not bad, but a little off. It's not that I don't like the JS. It's
that the JS is so monstrously inept that nobody in their right mind
should want to use it. Of course, that describes 99.9% of the JS on the
Web. If you don't believe that, turn on error reporting in IE (or
Opera) and browse around for a bit.

Using Opera 10.5 (which is likely younger than most of the scripts it
encounters), it becomes quite evident that even "major" sites rely on
scripts that were written by observing the browsers that were out at the
time (a strategy that is the kiss of death in cross-browser scripting).

Google Groups (on discarding a reply):-

Uncaught exception: TypeError: Cannot convert 'this.Ua' to object
Error thrown at line 262, column 832 in <anonymous function: lc>() in
http://groups.google.com/groups/static/g2_email_autocomplete.js:
for(var a=0;this.Ua[a];++a)
called from line 110, column 103 in <anonymous function: handleEvent>(a)
in http://groups.google.com/groups/static/g2_email_autocomplete.js:
return this.listener[EAC_Q](this.handler||this.src,a);
called via Function.prototype.call() from line 126, column 612 in
<anonymous function: EAC_.events.fireListener>(a, b) in
http://groups.google.com/groups/static/g2_email_autocomplete.js:
b=a[EAC_2a](b);
called from line 130, column 368 in <anonymous function:
EAC_.events.lb>(a, b) in
http://groups.google.com/groups/static/g2_email_autocomplete.js:
e=EAC_.events.fireListener(a,f)
called from line 111, column 176 in <anonymous function>(n) in
http://groups.google.com/groups/static/g2_email_autocomplete.js:
return g[EAC_Q](l.src,l.key,n)

The first line indicates that the script is a lost cause. It's trying
to sniff the browser (and failing miserably). Had it "succeeded", it
would still have lost as the UA string is not an indicator of browser
features. If all they had to observe at the time was Opera 9...

MSDN:-

Opera has modified the JavaScript on msdn.microsoft.com (MSDN menus are
invisible, should appear). See browser.js for details

That's an interesting warning. Apparently Opera is getting proactive
about the incompetent developer problem. There's only so much they can
do though. The incompetence out there is overwhelming (even a behemoth
like MS can't find good help).

GMail:-

Opera has modified the JavaScript on mail.google.com (GMail deletes
messages on End key presses). See browser.js for details

Deletes messages on End key presses? *Shudder*

And the Dojo people regularly cite Gmail as being on the vanguard of
"major" web apps. How much worse can you get when the browser
developers are forced to keep a database of lousy scripts?

CNN:-

Uncaught exception: TypeError: 'exitChecker.close' is not a function
Error thrown at line 1, column 21029 in <anonymous function:
InsightExpress.PopUpInvite.prototype.Show>(second) in
http://core.insightexpressai.com/ad...com&placementID=223658296&creativeID=36384403:
exitChecker.close();
called from line 1, column 42807 in <anonymous function:
InsightExpress.onload>() in
http://core.insightexpressai.com/ad...com&placementID=223658296&creativeID=36384403:
invite.Show();
called from line 1, column 2452 in <anonymous function:
InsightExpress.OnLoad>() in
http://core.insightexpressai.com/ad...com&placementID=223658296&creativeID=36384403:
InsightExpress.onload();
called from line 1, column 3266 in <anonymous function:
InsightExpress.ready>() in
http://core.insightexpressai.com/ad...com&placementID=223658296&creativeID=36384403:
InsightExpress.OnLoad();
called from line 1, column 4137 in <anonymous function>() in
http://core.insightexpressai.com/ad...com&placementID=223658296&creativeID=36384403:
InsightExpress.ready();

Cleanup in aisle #21029. :) Pop-up blocked too. Idiots.

Yahoo:-

Opera has modified the JavaScript on www.yahoo.com (Yahoo ISP portal
blocks Opera users). See browser.js for details
JavaScript
User Javascript thread
Opera has modified the JavaScript on www.yahoo.com (Yahoo!). See
browser.js for details
JavaScript
User Javascript thread
Opera has modified the JavaScript on www.yahoo.com (Yahoo!). See
browser.js for details
JavaScript
User Javascript thread
Opera has modified the JavaScript on www.yahoo.com (Yahoo ISP portal
blocks Opera users). See browser.js for details
JavaScript
User Javascript thread
Opera has modified the JavaScript on www.yahoo.com (Yahoo!). See
browser.js for details

They are keeping an eye on the majors it seems. Won't help everyone
else though. Of course, it isn't really helping the affected sites
either as now when they fix the problems, they may break Opera's
improvised workarounds. It's really getting ridiculous, isn't it? This
is the future of application development? It's clearly already sunk
under its own weight.

NBC:-

Inline script compilation
Syntax error at line 2 while loading:
sc'+'ript language='JavaScript1.1' src="
--------------------^
expected ')', got 'JavaScript1'

Mind-boggling. These aren't obscure miscues deep in some huge
experimental Web app. These are simple documents with simple (yet often
huge) scripts that somehow managed to make it into production with very
obvious errors that show themselves immediately on load. How do you
miss those? My theory is that they don't miss them, but dismiss them as
"just one of those things". Cross-browser scripting is impossible after
all, even when the focus is narrowed to three or four browsers. :)

Of course, they don't all throw exceptions. Some simply fail to
function (e.g. Dojo's jQuery-powered forums, which makes the stop/reload
button flash like a strobe light). And speaking of Dojo, I recently
tried out some of their demos, which presumably represent them putting
their best foot forward, and effortlessly triggered exceptions all over
the place. Twitter comes to mind as well. I often see "undefined" show
up on the page in odd places and have to confirm deleted Tweets twice
(after which it usually informs that "something went wrong" and I should
try again, despite the fact that they removed the entry from the DOM).

And some minors, starting with the Dojo "foundation", which is surely
the archetypal bad "Web 2.0" site. The content is unreadable if your
screen resolution is less than whatever the QA testers used (assuming
anyone tested it at all).

http://dojofoundation.org

Uncaught exception: [object DOMException]
Error thrown at line 20, column 7387 in <anonymous function:
dojo.loaded>() in http://o.aolcdn.com/dojo/1.1.1/dojo/dojo.xd.js:
throw e;
called from line 1, column 0 in program code:
dojo.loaded();

My host's Webmail (a YUI abomination called "Zimbra"):-

JavaScript -
https://mail6d.brinkster.com/zimbra/yui/2.5.1/button/button-beta-min.js

Linked script not loaded

Not an exception of course, but illustrates how sloppy the developers
were/are (this same stupid message has been popping up forever). Wonder
if they needed that button for something? When I browse the Web, I
don't want a scary adventure. I'd turn scripting off completely if only
developers were competent enough to let me do that without penalty.

Every single exception indicates a script that has gone off the path
into weeds never envisioned by the developers. Software like that is
worse than useless (i.e. the sites would have been better off without it).

As for freely available sortable table alternatives. I don't know.
Somebody else might be able to suggest one though. Stay tuned.
 
G

Gregor Kofler

Am 2010-05-05 01:41, Question Boy meinte:
I am using the sorttable js from http://www.kryogenix.org/code/browser/sorttable/
and now need to execute another function after each time the table is
sorted but can't figure out where I need to call my function from
within the sorttable js. Can anyone guide me on this?

Ask the author?

I've written my own "sorTable-Widget" [1]. The code of the widget itself
is pretty short and easy to understand. It uses my core.js to level some
cross-browser DOM issues and event handling. Custom events are used to
allow triggering functions before or after sorting.

core.js has been scrutinized here and while I've worked on some issues,
some (still) remain. Use at your own risk.

Gregor

[1] http://vxjs.gregorkofler.com/index.php?page=sortable
 
D

David Mark

Gregor said:
Am 2010-05-05 01:41, Question Boy meinte:
I am using the sorttable js from
http://www.kryogenix.org/code/browser/sorttable/
and now need to execute another function after each time the table is
sorted but can't figure out where I need to call my function from
within the sorttable js. Can anyone guide me on this?

Ask the author?

I've written my own "sorTable-Widget" [1]. The code of the widget itself
is pretty short and easy to understand. It uses my core.js to level some
cross-browser DOM issues and event handling. Custom events are used to
allow triggering functions before or after sorting.

Looks nice. One problem on the demo page, per Opera, the "bbedit"
script appears to be missing.
core.js has been scrutinized here and while I've worked on some issues,
some (still) remain. Use at your own risk.

Nothing could be riskier than that other thing. :)
 
G

Gregor Kofler

Am 2010-05-05 12:02, David Mark meinte:
Gregor said:
Am 2010-05-05 01:41, Question Boy meinte:
I am using the sorttable js from
http://www.kryogenix.org/code/browser/sorttable/
and now need to execute another function after each time the table is
sorted but can't figure out where I need to call my function from
within the sorttable js. Can anyone guide me on this?

Ask the author?

I've written my own "sorTable-Widget" [1]. The code of the widget itself
is pretty short and easy to understand. It uses my core.js to level some
cross-browser DOM issues and event handling. Custom events are used to
allow triggering functions before or after sorting.

Looks nice. One problem on the demo page, per Opera, the "bbedit"
script appears to be missing.

Ah yes, Thanks for pointing out - fixed (i.e. removed this reference to
a no longer existing script).
Nothing could be riskier than that other thing. :)

"Question Boy's Perilous Journey to the Keep of the JavaScript Ninja".

Gregor
 
G

Gregor Kofler

Am 2010-05-05 17:53, Garrett Smith meinte:
Gregor said:
Am 2010-05-05 01:41, Question Boy meinte:
I am using the sorttable js from
[...]

[1] http://vxjs.gregorkofler.com/index.php?page=sortable
Line 1:

if(!vxJS) { throw Error("widget.sorTable: vxJS core missing."); }

If `vxJS` is not defined, a ReferenceError will result. The throw
statement with your Error won't be reached.

Correct. Well, I wonder whether I should keep these "checks" at all...

Gregor
 
G

Garrett Smith

Gregor said:
Am 2010-05-05 17:53, Garrett Smith meinte:
Gregor said:
Am 2010-05-05 01:41, Question Boy meinte:
[...]
if(!vxJS) { throw Error("widget.sorTable: vxJS core missing."); }

If `vxJS` is not defined, a ReferenceError will result. The throw
statement with your Error won't be reached.

Correct. Well, I wonder whether I should keep these "checks" at all...
The benefit is that it makes the code self-documenting.

An alternative is to use global object:

if(!this.vxJS) {
throw Error("The vxJS library was not included");
}

Another alternative is to remove the check.

If the check is removed, the user will see the ReferenceError. That is
going to work for those who understand how to fix the error but will not
help the client of vxJS does not understand what would cause that error.

Another potential problem to consider regarding dependencies is doubly
including something; when the script is included twice for a page.
 
D

David Mark

Gregor said:
Am 2010-05-05 17:53, Garrett Smith meinte:
Gregor said:
Am 2010-05-05 01:41, Question Boy meinte:
I am using the sorttable js from
[...]

[1] http://vxjs.gregorkofler.com/index.php?page=sortable
Line 1:

if(!vxJS) { throw Error("widget.sorTable: vxJS core missing."); }

If `vxJS` is not defined, a ReferenceError will result. The throw
statement with your Error won't be reached.

Correct. Well, I wonder whether I should keep these "checks" at all...

No. It's over-engineering.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,431
Messages
2,571,677
Members
48,796
Latest member
Greg L.

Latest Threads

Top