## Implementation

Since a lot of the implementaion follows the old version I'm going to try to concentrate on the more important parts. Espescially how the sorting is done and how this was done to maximize performance.

### Sorting

Just like in the old version the `Array` `sort` is used, but unlike the old version most of the work that was done in the compare function has been moved out of this function and is done once before the sorting starts.

#### Caching the Data

Before the sorting is started an array is made that contains JavaScript objects which contains the needed information to do the actual sorting of the table. This information consists of the value used to sort the rows as well as a reference to the actual row element so that we can reorder the rows once the sorting is done.

    SortableTable.prototype.getCache = function (sType, nColumn) {
       var rows = this.tBody.rows;
       var l = rows.length;
       var a = new Array(l);
       var r;
       for (var i = 0; i < l; i++) {
          r = rows[i];
          a[i] = {
             value:   this.getRowValue(r, sType, nColumn),
             element: r
          };
       };
       return a;
    };

One thing to note here is that the `length` is calculated once before the loop. The reason for this is that getting `rows.length` is an expensive operation in IE and we do not want to do it once for every row.

Once we have this array we do not need to interact with the DOM during the actual sorting of the array.

### The sort method

The function `getCache` prepares the data and once that is done the actual code to sort the table is more or less book keeping. The compare function to use when sorting is returned by the method `getSortFunction`. In its current state this function just returns a funtion that compares the `value` properties of the object inside the cache array. One might want to modify this for more esoteric data types where the operator `<` is not defined.

Once the cache array has been sorted the table rows are reinserted in the same order as the cache array. The property `element` of the JS object in the array is used to find the correct row element.

    SortableTable.prototype.sort = function (nColumn, bDescending, sSortType) {
       if (sSortType == null)
          sSortType = this.getSortType(nColumn);

       // exit if None
       if (sSortType == "None")
          return;

       if (bDescending == null) {
          if (this.sortColumn != nColumn)
             this.descending = true;
          else
             this.descending = !this.descending;
       }

       this.sortColumn = nColumn;

       if (typeof this.onbeforesort == "function")
          this.onbeforesort();

       var f = this.getSortFunction(sSortType, nColumn);
       var a = this.getCache(sSortType, nColumn);
       var tBody = this.tBody;

       a.sort(f);

       if (this.descending)
          a.reverse();

       if (SortableTable.removeBeforeSort) {
          // remove from doc
          var nextSibling = tBody.nextSibling;
          var p = tBody.parentNode;
          p.removeChild(tBody);
       }

       // insert in the new order
       var l = a.length;
       for (var i = 0; i < l; i++)
          tBody.appendChild(a[i].element);

       if (SortableTable.removeBeforeSort) {
          // insert into doc
          p.insertBefore(tBody, nextSibling);
       }

       this.updateHeaderArrows();

       this.destroyCache(a);

       if (typeof this.onsort == "function")
          this.onsort();
    };

In some browser (namely Mozilla) the DOM manipulations are faster when done on a disconnected DOM tree. Therefore when `SortableTable.removeBeforeSort` is true we first disconnect the tree before reorganizing the rows and once the reorganization is done we reinsert the table.

## Setting up the Header

### Sort Arrows

When the `SortableTable` is constructed images are added to the table header cells. These images then changes their background image to indicate that the column is sorted.

### Hooking up the events

Also at creation, event listeners are added to the table header cells. In this case we use `addEventListener` if available and if not we try to use `attachEvent`. These are set to call `this._headerOnclick`, which is just an encapsulation of `this.headerOnclick()`. There are 2 reasons why it is done in this way. The first is so that `this` will point to the JS object inside the function `headerOnclick` and not on the table cell element. The other reason is that we need to be able to detach the event listener when destroying the JS object. If we used an anonymous function this would not have been possible.

    function SortableTable(oTable, oSortTypes) {
       ...
       var oThis = this;
       this._headerOnclick = function (e) {
          oThis.headerOnclick(e);
       };
       ...
    }

    SortableTable.prototype.initHeader = function (oSortTypes) {
       var cells = this.tHead.rows[0].cells;
       var l = cells.length;
       var img, c;
       for (var i = 0; i < l; i++) {
          c = cells[i];
          img = this.document.createElement("IMG");
          img.src = "images/blank.png";
          c.appendChild(img);
          if (oSortTypes[i] != null) {
             c._sortType = oSortTypes[i];
          }
          if ("addEventListener" in c)
             c.addEventListener("click", this._headerOnclick, false);
          else if ("attachEvent" in c)
             c.attachEvent("onclick", this._headerOnclick);
       }
       this.updateHeaderArrows();
    };

Sortable Table
Implementation
API
Demo
Download

Author: Erik Arvidsson