Javascript - sequence of events

B

bboyle18

Hi,

I am working with a table sorting script which can be found here
http://www.workingwith.me.uk/articles/scripting/standardista_table_sorting
This script works very nicely, but when there is a large amount of data
to sort e.g > 200 then there is a slight delay in the table sort. To
cater for this I want to provide some feedback to the user to inform
them that the sort function is processing. My idea is to add a
"sorting...." message to the top right of the page, much the same as
the 'loading' message in gmail.
To do this I am dynamically creating a div element and adding it to the
document.body
I do this as part of the onclick event that triggers the table sort.

My problem is, eventhough I create and append the 'sorting...' element
at the start of the onclick event (before the sorting is done), the
element only gets added after the sorting is complete?

I cant seem to get the 'sorting..' element to be added to the page
while the sorting is in progress. Does javascript execute things in a
sequence that prevents me adding my element to the page?
Interestingly, I can execute a javascript alert and this gets displayed
before the sorting begins.....why would
document.body.appendChild(myDiv) not?

Hopefully someone has come across this before and can help. I've added
my HTML and javascript below.

Thank you,

Chris

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Table Sorter Proof of Concept</title>

<link rel="stylesheet" href="style.css" type="text/css" />

<script type='text/javascript' src='common.js'></script>
<script type='text/javascript' src='css.js'></script>
<script type='text/javascript'
src='standardista-table-sorting.js'></script>
</head>
<body>


<table class='sortable autostripe'>
<thead>
<tr>
<th>Heading</th>
<th>Heading</th>
<th>Heading</th>
<th>Heading</th>
<th>Heading</th>
<th>Heading</th>
<th>Heading</th>
<th>Heading</th>
</tr>
</thead>
<tbody>
<script>
for (var i=0; i < 500; i++) {

var number = Math.round(Math.random()*1000);

var day = (1 + Math.round(Math.random()*30));
if (day < 10) {
day = '0' + day;
}
var month = (1 + Math.round(Math.random()*11));
if (month < 10) {
month = '0' + month;
}
var year = (1990 + Math.round(Math.random()*16));

var pennies = (1 + Math.round(Math.random()*99));
if (pennies < 10) {
pennies = '0' + pennies;
}

var pounds = (1 + Math.round(Math.random()*1500));

var date = day + '/' + month + '/' + year;

document.write("<tr>");
document.write("<td>"+number+"</td>");
document.write("<td>"+date+"</td>");
document.write("<td>$"+pounds+'.'+pennies+"</td>");
document.write("<td>"+number+"</td>");
document.write("<td>"+date+"</td>");
document.write("<td>$"+pounds+'.'+pennies+"</td>");
document.write("<td>"+number+"</td>");
document.write("<td>"+date+"</td>");
document.write("</tr>");
}
</script>
</tbody>
</table>

</body>
</html>

/**
* Written by Neil Crosby.
*
http://www.workingwith.me.uk/articles/scripting/standardista_table_sorting
*
* This module is based on Stuart Langridge's "sorttable" code.
Specifically,
* the determineSortFunction, sortCaseInsensitive, sortDate,
sortNumeric, and
* sortCurrency functions are heavily based on his code. This module
would not
* have been possible without Stuart's earlier outstanding work.
*
* Use this wherever you want, but please keep this comment at the top
of this file.
*
* Copyright (c) 2006 Neil Crosby
*
* Permission is hereby granted, free of charge, to any person
obtaining a copy
* of this software and associated documentation files (the
"Software"), to deal
* in the Software without restriction, including without limitation
the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
* copies of the Software, and to permit persons to whom the Software
is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE
* SOFTWARE.
**/
var standardistaTableSorting = {

that: false,
isOdd: false,

sortColumnIndex : -1,
lastAssignedId : 0,
newRows: -1,
lastSortedTable: -1,

/**
* Initialises the Standardista Table Sorting module
**/
init : function() {
// first, check whether this web browser is capable of running this
script
if (!document.getElementsByTagName) {
return;
}

this.that = this;

this.run();

},

/**
* Runs over each table in the document, making it sortable if it has
a class
* assigned named "sortable" and an id assigned.
**/
run : function() {
var tables = document.getElementsByTagName("table");

for (var i=0; i < tables.length; i++) {
var thisTable = tables;

if (css.elementHasClass(thisTable, 'sortable')) {
this.makeSortable(thisTable);
}
}
},

/**
* Makes the given table sortable.
**/
makeSortable : function(table) {

// first, check if the table has an id. if it doesn't, give it one
if (!table.id) {
table.id = 'sortableTable'+this.lastAssignedId++;
}

// if this table does not have a thead, we don't want to know about
it
if (!table.tHead || !table.tHead.rows || 0 ==
table.tHead.rows.length) {
return;
}

// we'll assume that the last row of headings in the thead is the row
that
// wants to become clickable
var row = table.tHead.rows[table.tHead.rows.length - 1];

for (var i=0; i < row.cells.length; i++) {

// create a link with an onClick event which will
// control the sorting of the table
var linkEl = createElement('a');
linkEl.href = '#';
linkEl.onclick = this.headingClicked;
linkEl.setAttribute('columnId', i);
linkEl.title = 'Click to sort';

// move the current contents of the cell that we're
// hyperlinking into the hyperlink
var innerEls = row.cells.childNodes;
for (var j = 0; j < innerEls.length; j++) {
linkEl.appendChild(innerEls[j]);
}

// and finally add the new link back into the cell
row.cells.appendChild(linkEl);

var spanEl = createElement('span');
spanEl.className = 'tableSortArrow';
spanEl.appendChild(document.createTextNode('\u00A0\u00A0'));
row.cells.appendChild(spanEl);

}

if (css.elementHasClass(table, 'autostripe')) {
this.isOdd = false;
var rows = table.tBodies[0].rows;

// We appendChild rows that already exist to the tbody, so it moves
them rather than creating new ones
for (var i=0;i<rows.length;i++) {
this.doStripe(rows);
}
}
},

headingClicked: function(e) {

showDialog();


var that = standardistaTableSorting.that;

// linkEl is the hyperlink that was clicked on which caused
// this method to be called
var linkEl = getEventTarget(e);

// directly outside it is a td, tr, thead and table
var td = linkEl.parentNode;
var tr = td.parentNode;
var thead = tr.parentNode;
var table = thead.parentNode;

// if the table we're looking at doesn't have any rows
// (or only has one) then there's no point trying to sort it
if (!table.tBodies || table.tBodies[0].rows.length <= 1) {
return false;
}

// the column we want is indicated by td.cellIndex
var column = linkEl.getAttribute('columnId') || td.cellIndex;
//var column = td.cellIndex;

// find out what the current sort order of this column is
var arrows = css.getElementsByClass(td, 'tableSortArrow', 'span');
var previousSortOrder = '';
if (arrows.length > 0) {
previousSortOrder = arrows[0].getAttribute('sortOrder');
}

// work out how we want to sort this column using the data in the
first cell
// but just getting the first cell is no good if it contains no data
// so if the first cell just contains white space then we need to
track
// down until we find a cell which does contain some actual data
var itm = ''
var rowNum = 0;
while ('' == itm && rowNum < table.tBodies[0].rows.length) {
itm =
that.getInnerText(table.tBodies[0].rows[rowNum].cells[column]);
rowNum++;
}
var sortfn = that.determineSortFunction(itm);

// if the last column that was sorted was this one, then all we need
to
// do is reverse the sorting on this column
if (table.id == that.lastSortedTable && column ==
that.sortColumnIndex) {
newRows = that.newRows;
newRows.reverse();
// otherwise, we have to do the full sort
} else {
that.sortColumnIndex = column;
var newRows = new Array();

for (var j = 0; j < table.tBodies[0].rows.length; j++) {
newRows[j] = table.tBodies[0].rows[j];
}

newRows.sort(sortfn);
}

that.moveRows(table, newRows);
that.newRows = newRows;
that.lastSortedTable = table.id;

// now, give the user some feedback about which way the column is
sorted

// first, get rid of any arrows in any heading cells
var arrows = css.getElementsByClass(tr, 'tableSortArrow', 'span');
for (var j = 0; j < arrows.length; j++) {
var arrowParent = arrows[j].parentNode;
arrowParent.removeChild(arrows[j]);

if (arrowParent != td) {
spanEl = createElement('span');
spanEl.className = 'tableSortArrow';
spanEl.appendChild(document.createTextNode('\u00A0\u00A0'));
arrowParent.appendChild(spanEl);
}
}

// now, add back in some feedback
var spanEl = createElement('span');
spanEl.className = 'tableSortArrow';
if (null == previousSortOrder || '' == previousSortOrder || 'DESC' ==
previousSortOrder) {
spanEl.appendChild(document.createTextNode(' \u2191'));
spanEl.setAttribute('sortOrder', 'ASC');
} else {
spanEl.appendChild(document.createTextNode(' \u2193'));
spanEl.setAttribute('sortOrder', 'DESC');
}

td.appendChild(spanEl);

return false;
},

getInnerText : function(el) {

if ('string' == typeof el || 'undefined' == typeof el) {
return el;
}

if (el.innerText) {
return el.innerText; // Not needed but it is faster
}

var str = el.getAttribute('standardistaTableSortingInnerText');
if (null != str && '' != str) {
return str;
}
str = '';

var cs = el.childNodes;
var l = cs.length;
for (var i = 0; i < l; i++) {
// 'if' is considerably quicker than a 'switch' statement,
// in Internet Explorer which translates up to a good time
// reduction since this is a very often called recursive function
if (1 == cs.nodeType) { // ELEMENT NODE
str += this.getInnerText(cs);
break;
} else if (3 == cs.nodeType) { //TEXT_NODE
str += cs.nodeValue;
break;
}
}

// set the innertext for this element directly on the element
// so that it can be retrieved early next time the innertext
// is requested
el.setAttribute('standardistaTableSortingInnerText', str);

return str;
},

determineSortFunction : function(itm) {

var sortfn = this.sortCaseInsensitive;

if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) {
sortfn = this.sortDate;
}
if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) {
sortfn = this.sortDate;
}
if (itm.match(/^[£$]/)) {
sortfn = this.sortCurrency;
}
if (itm.match(/^\d?\.?\d+$/)) {
sortfn = this.sortNumeric;
}
if (itm.match(/^[+-]?\d*\.?\d+([eE]-?\d+)?$/)) {
sortfn = this.sortNumeric;
}
if
(itm.match(/^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$/))
{
sortfn = this.sortIP;
}

return sortfn;
},

sortCaseInsensitive : function(a, b) {
var that = standardistaTableSorting.that;

var aa =
that.getInnerText(a.cells[that.sortColumnIndex]).toLowerCase();
var bb =
that.getInnerText(b.cells[that.sortColumnIndex]).toLowerCase();
if (aa==bb) {
return 0;
} else if (aa<bb) {
return -1;
} else {
return 1;
}
},

sortDate : function(a,b) {
var that = standardistaTableSorting.that;

// y2k notes: two digit years less than 50 are treated as 20XX,
greater than 50 are treated as 19XX
var aa = that.getInnerText(a.cells[that.sortColumnIndex]);
var bb = that.getInnerText(b.cells[that.sortColumnIndex]);

var dt1, dt2, yr = -1;

if (aa.length == 10) {
dt1 = aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2);
} else {
yr = aa.substr(6,2);
if (parseInt(yr) < 50) {
yr = '20'+yr;
} else {
yr = '19'+yr;
}
dt1 = yr+aa.substr(3,2)+aa.substr(0,2);
}

if (bb.length == 10) {
dt2 = bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2);
} else {
yr = bb.substr(6,2);
if (parseInt(yr) < 50) {
yr = '20'+yr;
} else {
yr = '19'+yr;
}
dt2 = yr+bb.substr(3,2)+bb.substr(0,2);
}

if (dt1==dt2) {
return 0;
} else if (dt1<dt2) {
return -1;
}
return 1;
},

sortCurrency : function(a,b) {
var that = standardistaTableSorting.that;

var aa =
that.getInnerText(a.cells[that.sortColumnIndex]).replace(/[^0-9.]/g,'');
var bb =
that.getInnerText(b.cells[that.sortColumnIndex]).replace(/[^0-9.]/g,'');
return parseFloat(aa) - parseFloat(bb);
},

sortNumeric : function(a,b) {
var that = standardistaTableSorting.that;

var aa =
parseFloat(that.getInnerText(a.cells[that.sortColumnIndex]));
if (isNaN(aa)) {
aa = 0;
}
var bb =
parseFloat(that.getInnerText(b.cells[that.sortColumnIndex]));
if (isNaN(bb)) {
bb = 0;
}
return aa-bb;
},

makeStandardIPAddress : function(val) {
var vals = val.split('.');

for (x in vals) {
val = vals[x];

while (3 > val.length) {
val = '0'+val;
}
vals[x] = val;
}

val = vals.join('.');

return val;
},

sortIP : function(a,b) {
var that = standardistaTableSorting.that;

var aa =
that.makeStandardIPAddress(that.getInnerText(a.cells[that.sortColumnIndex])..toLowerCase());
var bb =
that.makeStandardIPAddress(that.getInnerText(b.cells[that.sortColumnIndex])..toLowerCase());
if (aa==bb) {
return 0;
} else if (aa<bb) {
return -1;
} else {
return 1;
}
},

moveRows : function(table, newRows) {
this.isOdd = false;

// We appendChild rows that already exist to the tbody, so it moves
them rather than creating new ones
for (var i=0;i<newRows.length;i++) {
var rowItem = newRows;

this.doStripe(rowItem);

table.tBodies[0].appendChild(rowItem);
}
},

doStripe : function(rowItem) {
if (this.isOdd) {
css.addClassToElement(rowItem, 'odd');
} else {
css.removeClassFromElement(rowItem, 'odd');
}

this.isOdd = !this.isOdd;
}

}

function standardistaTableSortingInit() {
standardistaTableSorting.init();
}

addEvent(window, 'load', standardistaTableSortingInit)

function showDialog(){

var shortcutsDiv = document.createElement('DIV');
shortcutsDiv.id = 'shortcutsDivId';
//Esc will lose focus and close it. Need an input field to focus on.
with (shortcutsDiv.style) {
display = "block";
position = "fixed";
visibility = "visible";
top = "8%";
left = "41%";
margin = "0 10% 0 10%";
width = "30%";
textAlign = "center";
MozBorderRadius = "10px";
padding = "10px";
color = "#000";
background = "#EE8800";

zIndex = 1000;
}
shortcutsDiv.innerHTML = 'sorting';
document.body.appendChild(shortcutsDiv);

}
 
R

Randy Webb

(e-mail address removed) said the following on 6/4/2006 3:13 PM:
Hi,

I am working with a table sorting script which can be found here
http://www.workingwith.me.uk/articles/scripting/standardista_table_sorting
This script works very nicely, but when there is a large amount of data
to sort e.g > 200 then there is a slight delay in the table sort. To
cater for this I want to provide some feedback to the user to inform
them that the sort function is processing. My idea is to add a
"sorting...." message to the top right of the page, much the same as
the 'loading' message in gmail.
To do this I am dynamically creating a div element and adding it to the
document.body
I do this as part of the onclick event that triggers the table sort.

My problem is, eventhough I create and append the 'sorting...' element
at the start of the onclick event (before the sorting is done), the
element only gets added after the sorting is complete?

I cant seem to get the 'sorting..' element to be added to the page
while the sorting is in progress. Does javascript execute things in a
sequence that prevents me adding my element to the page?
Interestingly, I can execute a javascript alert and this gets displayed
before the sorting begins.....why would
document.body.appendChild(myDiv) not?
Hopefully someone has come across this before and can help. I've added
my HTML and javascript below.

<FAQENTRY>
Why doesn't the display get updated when doing time intensive calculations?
</FAQENTRY>


It is a very well known about issue where the UA doesn't get updated
visibly until the function executes. The alert causes a delay so the
display gets updated.

The solution? Call a setTimeout to a second function.

function dummyFunction(){
//create the message here
window.setTimeout(realFunction,60)
}

function realFunction(){
//sort the table

//remove the message when sorting is finished.
}
 
C

Chris Moltisanti

That worked great thanks. I had to changed the JS around a bit, but the
setTimeout worked perfectly.

Thanks,

Chris
 
C

Chris Moltisanti

That worked thanks. I had to change my JS slightly but the setTimeout
worked perfectly.

Thanks,

Chris
 
D

Dr John Stockton

JRS: In article <[email protected]>
, dated Sun, 4 Jun 2006 12:13:35 remote, seen in
news:comp.lang.javascript, (e-mail address removed) posted :

One should seek and read a newsgroup FAQ, and read the group for a
while, before posting to the group.

Had you done so, you would probably have realised that posted code
should be executable as received, and therefore that you should not
permit your posting agent to line-wrap it; and, partly to help there,
you should replace tab-indenting with indenting by 2-3 spaces.


Math.round(Math.random()...) is rarely good, though it may not matter
in this case - see FAQ 4.22 - OTOH, your "pennies" range looks like
1..100.

parseInt(yr) should normally have a second parameter, though in this
case it probably does not matter; however, unary + would be better (and
maybe can be used instead of parseFloat too).

If you use a function, rather than a string of code, as the first
parameter of setTimeout, it may not always work.

Note for future reference FAQ 2.3 para 7.
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top