Sunday, 25 August 2013

Using regex patterns for verifying input

We have recently been using HTML 5 and JavaScript to do form verification, as Fahad blogged about here

I have just added pattern matching to this for email and telephone number verification. Thanks to +Exson Qu  for the regex ju-ju. 

HTML5 allows form elements of type "tel" and "email". We want to add in a regular expression to each of these types to verify the element as it is typed. The regular expressions we have used are "[0-9 +s()]*" for the telephone numbers, and "^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$" for email addresses. Neither of these are 100% as it is not possible to deal with every method in the world of writing telephone numbers, and every method of constructing emails addresses, however these will do a good job on most.

It is feasible to add html in the form:

<input type="tel" name="Telephone" pattern="[0-9 +s()]*" value="" />

However this would need to be done wherever there is a telephone or fax number to be entered into KwaMoja. Then if we decide to improve the regex we would need to go through all these entries again. This can get messy.

It would be better to do this via JavaScript. We have a function called initial() that gets called when the page has been loaded. This function iterates through all the form elements in the page that has just been loaded and appends the regex pattern any with a type "tel" or a type "email". Here is the function:

function initial() {
    var n = document.getElementsByTagName("input");
    for (i = 0; i < n.length; i++) {
        if (n[i].type == "tel") n[i].pattern = "[0-9 +s()]*";
        if (n[i].type == "email") n[i].pattern = "^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$";
    }
}


We also use this function to assign other properties to form elements.

Saturday, 17 August 2013

Warehouse management - Part 1

I have been giving a lot of thought recently to how we should implement warehouse management. Just using row/bay/bin is too restrictive. 

If we have a warehouse structured like this :


it will not fit well to a rigid system of warehouse management.
 

What I propose a system where we have just one table for areas that can contain stock items. The best name would be "Locations" but that has already been taken, so I will for the moment call them "Containers". All containers can have parent containers. The above warehouse now looks like this:

As you can see the warehouse now can be modeled as a tree diagram. Each container can be set as to whether it can contain items, or just act as a container for child containers.







Each container has details of its physical position in the warehouse, and it's size. Also properties as to what it can contain (refrigeration unit for instance). Whether the contents are liquid etc.


Starting to implement this is easy, as each warehouse can be defined as a container. We just need a new table to hold the container information.

Monday, 5 August 2013

How to sort HTML tables in JavaScript

A short while ago I blogged that KwaMoja now has the facility to sort HTML tables in JavaScript. I have had numerous requests to explain more about how this is done, so here is a brief tutorial on achieving this.

The table has to be constructed in a specific way. The area of the table to be sorted has to contain one row of <th> cells followed by any number of <td> rows.

So the following HTML would be suitable:

<tr>
        <th>Header1</th>
        <th>Header2</th>
</tr>
<tr>
        <td>Data11</td>
        <td>Data12</td>
</tr>
<tr>
        <td>Data21</td>
        <td>Data22</td>
</tr>

which will look like this:


Header1 Header2
Data11 Data12
Data21 Data22

This area to be sorted must be completely contained within a pair of tags, for instance between a <table> and a </table>. If you require other things in the table, then I generally use a <tbody> and a </tbody> to surround the area to be sorted.

The JavaScript function starts with the following:



1 function SortSelect(selElem) {
2    table=selElem.parentNode.parentNode;
3    headerRow = table.rows[0];


The function is called by clicking on the <th></th> element of the column that we wish to sort by. Thus the parameter "selElem" will be that cell. The parent of that cell will be the row (<tr>) containing the header, and the parent of the row will be the element that contains the whole of the sortable table.

Thus line 2 will give us the entire table that we wish to sort. Line 3 assigns the first row of that table to the variable "headerRow"

4    columnText=selElem.innerHTML;
5    for (var j = 0, col; col = headerRow.cells[j]; j++) {
6        if (
headerRow.cells[j].innerHTML==columnText) {
7            columnNumber=j;

8    }

This section finds the column number that is to be sorted on. Line 4 finds the column header, and then lines 5 to 8 loop through the columns until the correct one is found.

09    var tmpArray = new Array();
10    for (var i = 1, row; row = table.rows[i]; i++) {
11        var rowArray = new Array();
12        for (var j = 0, col; col = row.cells[j]; j++) {
13            if (row.cells[j].tagName == 'TD' ) {
14                rowArray[j]=row.cells[j].innerHTML;
15            }
16        }
17        tmpArray[i]=rowArray;
18    }

 
This section gets the information from each cell, and feeds it into a JavaScript array object before sorting it. Line 9 creates the array object then we cycle through each row (starting at the second line, as the first contains the headings), creating an array object for each row, and finally line 17 adds that row array to the main array.

19    tmpArray.sort(
20        function(a,b) {
21                if (columnClass=="number") {
22                    return parseFloat(a[columnNumber])-parseFloat(b[columnNumber]);
23                } else if (columnClass=="date") {
24                    da=new Date(a[columnNumber]);
25                    db=new Date(b[columnNumber]);
26                    return da>db;
27                } else {
28                    return a[columnNumber].localeCompare(b[columnNumber])

29                }
30        }
31    );
 

This section performs a standard JavaScript 3d array sorting routine. It will sort by number, alphabetic, and date. Other sorting routines can be included as needed.

Finally we need to feed the sorted array back into the html table as here

32    for (var i = 0, row; row = table.rows[i+1]; i++) {
33        var rowArray = new Array();
34        rowArray=tmpArray[i];
35        for (var j = 0, col; col = row.cells[j]; j++) {
36            if (row.cells[j].tagName == 'TD' ) {
37                row.cells[j].innerHTML=rowArray[j];
38            }
39        }
40    }
 

and we have fully sorted the HTML table in 40 lines of JavaScript. I have added in some nice formatting, and cursors in, and get the following full function:

function SortSelect(selElem) {
    var tmpArray = new Array();
    th=document.getElementById("Theme").value;
    columnText=selElem.innerHTML;
    table=selElem.parentNode.parentNode;
    row = table.rows[0];
    for (var j = 0, col; col = row.cells[j]; j++) {
        if (row.cells[j].innerHTML==columnText) {
            columnNumber=j;
            s=getComputedStyle(row.cells[j], null);
            if (s.cursor=="s-resize") {
                row.cells[j].style.cursor="n-resize";
                row.cells[j].style.backgroundImage="url('css/"+th+"/images/descending.png')";
                row.cells[j].style.backgroundPosition="right center";
                row.cells[j].style.backgroundRepeat="no-repeat";
                row.cells[j].style.backgroundSize="12px";
                direction="a";
            } else {
                row.cells[j].style.cursor="s-resize";
                row.cells[j].style.backgroundImage="url('css/"+th+"/images/ascending.png')";
                row.cells[j].style.backgroundPosition="right center";
                row.cells[j].style.backgroundRepeat="no-repeat";
                row.cells[j].style.backgroundSize="12px";
                direction="d";
            }
        }
    }
    for (var i = 1, row; row = table.rows[i]; i++) {
        var rowArray = new Array();
        for (var j = 0, col; col = row.cells[j]; j++) {
            if (row.cells[j].tagName == 'TD' ) {
                rowArray[j]=row.cells[j].innerHTML;
                columnClass=row.cells[columnNumber].className;
            }
        }
        tmpArray[i]=rowArray;
    }
    tmpArray.sort(
        function(a,b) {
            if (direction=="a") {
                if (columnClass=="number") {
                    return parseFloat(a[columnNumber])-parseFloat(b[columnNumber]);
                } else if (columnClass=="date") {
                    da=new Date(a[columnNumber]);
                    db=new Date(b[columnNumber]);
                    return da>db;
                } else {
                    return a[columnNumber].localeCompare(b[columnNumber])
                }
            } else {
                if (columnClass=="number") {
                    return parseFloat(b[columnNumber])-parseFloat(a[columnNumber]);
                } else if (columnClass=="date") {
                    da=new Date(a[columnNumber]);
                    db=new Date(b[columnNumber]);
                    return da<=db;
                } else {
                    return b[columnNumber].localeCompare(a[columnNumber])
                }
            }
        }
    );
    for (var i = 0, row; row = table.rows[i+1]; i++) {
        var rowArray = new Array();
        rowArray=tmpArray[i];
        for (var j = 0, col; col = row.cells[j]; j++) {
            if (row.cells[j].tagName == 'TD' ) {
                row.cells[j].innerHTML=rowArray[j];
            }
        }
    }
    return;
}


This is called by including this inline onclick handler

 onclick="SortSelect(this)"

I hope this explanation is useful to some people.