An Offline HTML Automatic Table Generator

Some of my recent posts involved the automatic production of thumbnail tables, in which specific javascript code produced the tables. I thought it might be a good idea to produce an HTML app to allow the creation of custom HTML tables. In this post I will give an example of a cross platform offline appointment calendar. I had previously posted an appointment calendar creation application, but that either has to be used online or with a virtual server.

Here is the code:

<!DOCTYPE html PUBLIC ‘-//W3C//DTD XHTML 1.0 Transitional//EN’ ‘http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd’&gt;
<html xmlns=’http://www.w3.org/1999/xhtml’&gt;
<head profile=’http://gmpg.org/xfn/11′&gt;
<title>Table Maker</title>
<style type=’text/css’>
style{display: block; position: relative; width: 100%; font :normal normal 700 15px Arial; background: black; color: white; white-space: pre-wrap}
</style>
</head>
<body><input type=”button” id=”b1″ name=”b1″ value=”Load” onclick=’makeTable();’ /><table id=”table1″ align=”center” valign=”top”></table>
<br /><br />
<input type=”radio” id=”r1″ name=”r1″ value=”” onclick=’dup(“n”);’/>Duplicate <input type=”radio” id=”r1″ name=”r1″ value=”” onclick=’dup(“y”);’ />Sequence &nbsp&nbsp&nbsp&nbsp<input type=”text” id=”lim” name=”lim” value=”total number” />
<br /><br />
<textarea id=”t1″ name=”t1″ rows=”10″ cols=”” value = “” ondblclick=’fillCell();’>text</textarea>
<br /><br />
<input type=”text” id=”t2″ name=”t2″ value=”# cells” /> <input type=”text” id=”t3″ name=”t3″ value=”cell/row” />
<br /><br />
<textarea id=”ta” name=”ta” rows=”10″ cols=” “></textarea>
<br /><br />
<style contenteditable=”true” scoped>
body {margin-left:0;margin-right:0;font:normal normal normal 12px Arial;}
a{ text-decoration: }
:link { color: rgb(0, 0, 255) }
:visited {color :rgb(100, 0,100) }
:hover { }
:active { }
#table1{position: relative; top:0; border-collapse: collapse; empty-cells: show}
td{border: 1px inset}
#r1{position: relative}
#t1{position: relative; width: 100%;}
#t2{}
#t3{}
#ta{position: relative; width: 100%;}
#b1{position: relative; top: 0}
</style>var lim = 0; var lim2 = 0; var str = ”
“; var cnt = 0; var str2 = arry = new Array(); var a = 0; var b = -1; var no = 0; var rep = “1”; var rep2 = “”; var rep3 = “”; var rep4 = “”;function dup(seq) {
var dupstr = document.getElementById(“t1”).value;
dupstr2 = new Array();
lim2 = document.getElementById(“lim”).value;
for (var i=0; i ” + document.getElementById(“t1”).value + “”;
if (cnt % document.getElementById(“t3”).value == 0) {
str += “”; } } str += ”

“;
document.getElementById(“table1”).innerHTML = str;
document.getElementById(“ta”).innerHTML = ”

\n” + str + “\n”;
}

function fillCell() {
for (var i=0; i
</body>
</html>

These inputs determine the number of cells to create and the number of cells per row.
<input type=”text” id=”t2″ name=”t2″ value=”# cells” /> <input type=”text” id=”t3″ name=”t3″ value=”cell/row” />

Clicking the Load button calls the makeTable() function and creates a string with the table code which is copied into the second textarea.

This is how that looks:

<table align=”center” valign=”top”>
<tr><td id=’td1′>text </td><td id=’td2′>text </td><td id=’td3′>text </td><td id=’td4′>text </td><td id=’td5′>text </td><td id=’td6′>text </td><td id=’td7′>text </td></tr><tr><td id=’td8′>text </td><td id=’td9′>text </td><td id=’td10′>text </td><td id=’td11′>text </td><td id=’td12′>text </td><td id=’td13′>text </td><td id=’td14′>text </td></tr><tr><td id=’td15′>text </td><td id=’td16′>text </td><td id=’td17′>text </td><td id=’td18′>text </td><td id=’td19′>text </td><td id=’td20′>text </td><td id=’td21′>text </td></tr><tr><td id=’td22′>text </td><td id=’td23′>text </td><td id=’td24′>text </td><td id=’td25′>text </td><td id=’td26′>text </td><td id=’td27′>text </td><td id=’td28′>text </td></tr><tr><td id=’td29′>text </td><td id=’td30′>text </td><td id=’td31′>text </td><td id=’td32′>text </td><td id=’td33′>text </td><td id=’td34′>text </td><td id=’td35′>text </td></tr><tr><td id=’td36′>text </td><td id=’td37′>text </td><td id=’td38′>text </td><td id=’td39′>text </td><td id=’td40′>text </td><td id=’td41′>text </td><td id=’td42′>text </td></tr><tr><td id=’td43′>text </td><td id=’td44′>text </td><td id=’td45′>text </td><td id=’td46′>text </td><td id=’td47′>text </td><td id=’td48′>text </td><td id=’td49′>text </td></tr><tr><td id=’td50′>text </td><td id=’td51′>text </td><td id=’td52′>text </td><td id=’td53′>text </td><td id=’td54′>text </td><td id=’td55′>text </td><td id=’td56′>text </td></tr><tr><td id=’td57′>text </td><td id=’td58′>text </td><td id=’td59′>text </td><td id=’td60′>text </td><td id=’td61′>text </td><td id=’td62′>text </td><td id=’td63′>text </td></tr><tr><td id=’td64′>text </td><td id=’td65′>text </td><td id=’td66′>text </td><td id=’td67′>text </td><td id=’td68′>text </td><td id=’td69′>text </td><td id=’td70′>text </td></tr><tr><td id=’td71′>text </td><td id=’td72′>text </td><td id=’td73′>text </td><td id=’td74′>text </td><td id=’td75′>text </td><td id=’td76′>text </td><td id=’td77′>text </td></tr><tr></tr>
</table>

The contents of the cells must now be created. Coding each one by hand for a large table could be tedious. Fortunately, in many cases there is a lot of repetion, such as in this case, in which the entries differ by sequential values.
In this example, the editable cells will be filled with textareas, ids being assigned sequentially
‘<textarea id=ta[” rows=”” cols=””></textarea>’~

Filling the total number box and clicking one of the radiobuttons will append n-1 copies of the original using the function dup().

function dup(seq) {
var dupstr = document.getElementById(“t1”).value;
dupstr2 = new Array();
lim2 = document.getElementById(“lim”).value;
for (var i=0; i <=lim2 -2 ; i++) {
rep2 = i + 2;
rep4 = rep2.toString();

if (seq ==”y”) {
dupstr2[i+1] = dupstr.replace(/\[/g, rep4 );
document.getElementById(“t1”).value += dupstr2[i+1];
} else {
document.getElementById(“t1″).value += dupstr;
}

}
}

Choosing Duplicate will just append the original but using Sequence will append and sequentially replace a selected character. As in previous examples, I chose ~ for a delimiter, since commas might be used in the entries. For the same reason, I chose [ as the replaceable character.

In this example I used Sequence. The first item had to be manually replaced, but all others were sequentially numbered, a great time saver.

Here is how the first textarea appears:

‘<textarea id=”ta1″ rows= cols=””></textarea>’~'<textarea id=”ta2″ rows= cols=””></textarea>’~'<textarea id=”ta3″ rows= cols=””></textarea>’~'<textarea id=”ta4″ rows= cols=””></textarea>’~'<textarea id=”ta5″ rows= cols=””></textarea>’~'<textarea id=”ta6″ rows= cols=””></textarea>’~'<textarea id=”ta7″ rows= cols=””></textarea>’~'<textarea id=”ta8″ rows= cols=””></textarea>’~'<textarea id=”ta9″ rows= cols=””></textarea>’~'<textarea id=”ta10″ rows= cols=””></textarea>’~'<textarea id=”ta11″ rows= cols=””></textarea>’~'<textarea id=”ta12″ rows= cols=””></textarea>’~'<textarea id=”ta13″ rows= cols=””></textarea>’~'<textarea id=”ta14″ rows= cols=””></textarea>’~'<textarea id=”ta15″ rows= cols=””></textarea>’~'<textarea id=”ta16″ rows= cols=””></textarea>’~'<textarea id=”ta17″ rows= cols=””></textarea>’~'<textarea id=”ta18″ rows= cols=””></textarea>’~'<textarea id=”ta19″ rows= cols=””></textarea>’~'<textarea id=”ta20″ rows= cols=””></textarea>’~'<textarea id=”ta21″ rows= cols=””></textarea>’~'<textarea id=”ta22″ rows= cols=””></textarea>’~'<textarea id=”ta23″ rows= cols=””></textarea>’~'<textarea id=”ta24″ rows= cols=””></textarea>’~'<textarea id=”ta25″ rows= cols=””></textarea>’~'<textarea id=”ta26″ rows= cols=””></textarea>’~'<textarea id=”ta27″ rows= cols=””></textarea>’~'<textarea id=”ta28″ rows= cols=””></textarea>’~'<textarea id=”ta29″ rows= cols=””></textarea>’~'<textarea id=”ta30″ rows= cols=””></textarea>’~'<textarea id=”ta31″ rows= cols=””></textarea>’~'<textarea id=”ta32″ rows= cols=””></textarea>’~'<textarea id=”ta33″ rows= cols=””></textarea>’~'<textarea id=”ta34″ rows= cols=””></textarea>’~'<textarea id=”ta35″ rows= cols=””></textarea>’~

I then needed to customize the days of the month. To do this I had to reuse the first textarea, so I cut the existing text and entered the following:

‘[‘~

Using Sequence for 31 days gave the following:
‘1’~’2’~’3’~’4’~’5’~’6’~’7’~’8’~’9’~’10’~’11’~’12’~’13’~’14’~’15’~’16’~’17’~’18’~’19’~’20’~’21’~’22’~’23’~’24’~’25’~’26’~’27’~’28’~’29’~’30’~’31’~

Since there were 35 cells and only 31 days, I had to add blank values. This is how it would look to start the month on a Tuesday, the third day of the week:

”~”~’1’~’2’~’3’~’4’~’5’~’6’~’7’~’8’~’9’~’10’~’11’~’12’~’13’~’14’~’15’~’16’~’17’~’18’~’19’~’20’~’21’~’22’~’23’~’24’~’25’~’26’~’27’~’28’~’29’~’30’~’31’~”~”~

There are two leading and two trailing blank cells.

I then pasted the cut text back and cut and pasted the day numbers in units of seven numbers into the proper location.Here is how that looks:

”~”~’1’~’2’~’3’~’4’~’5’~
‘<textarea id=”ta1″ rows=”” cols=””></textarea>’~'<textarea id=”ta2″ rows= cols=””></textarea>’~'<textarea id=”ta3″ rows= cols=””></textarea>’~'<textarea id=”ta4″ rows=”” cols=””></textarea>’~'<textarea id=”ta5″ rows= cols=””></textarea>’~'<textarea id=”ta6″ rows=”” cols=””></textarea>’~'<textarea id=”ta7″ rows= cols=””></textarea>’~’6’~’7’~’8’~’9’~’10’~’11’~’12’~'<textarea id=”ta8″ rows= cols=””></textarea>’~'<textarea id=”ta9″ rows= cols=””></textarea>’~'<textarea id=”ta10″ rows= cols=””></textarea>’~'<textarea id=”ta11″ rows= cols=””></textarea>’~'<textarea id=”ta12″ rows= cols=””></textarea>’~'<textarea id=”ta13″ rows= cols=””></textarea>’~'<textarea id=”ta14″ rows= cols=””></textarea>’~’13’~’14’~’15’~’16’~’17’~’18’~’19’~'<textarea id=”ta15″ rows= cols=””></textarea>’~'<textarea id=”ta16″ rows= cols=””></textarea>’~'<textarea id=”ta17″ rows= cols=””></textarea>’~'<textarea id=”ta18″ rows= cols=””></textarea>’~'<textarea id=”ta19″ rows= cols=””></textarea>’~'<textarea id=”ta20″ rows= cols=””></textarea>’~'<textarea id=”ta21″ rows= cols=””></textarea>’~’20’~’21’~’22’~’23’~’24’~’25’~’26’~'<textarea id=”ta22″ rows= cols=””></textarea>’~'<textarea id=”ta23″ rows= cols=””></textarea>’~'<textarea id=”ta24″ rows= cols=””></textarea>’~'<textarea id=”ta25″ rows= cols=””></textarea>’~'<textarea id=”ta26″ rows= cols=””></textarea>’~'<textarea id=”ta27″ rows= cols=””></textarea>’~'<textarea id=”ta28″ rows= cols=””></textarea>’~’27’~’28’~’29’~’30’~’31’~”~”~'<textarea id=”ta29″ rows= cols=””></textarea>’~'<textarea id=”ta30″ rows= cols=””></textarea>’~'<textarea id=”ta31″ rows= cols=””></textarea>’~'<textarea id=”ta32″ rows= cols=””></textarea>’~'<textarea id=”ta33″ rows= cols=””></textarea>’~'<textarea id=”ta34″ rows= cols=””></textarea>’~'<textarea id=”ta35″ rows= cols=””></textarea>’~

I then created a string for a day header
‘Sunday’~’Monday’~’Tuesday’~’Wednesday’~’Thursday’~’Friday’~’Saturday’~
and added it to the front of the other text.

Double clicking the first textarea creates the following code:
var arr=[
‘Sunday’,’Monday’,’Tuesday’,’Wednesday’,’Thursday’,’Friday’,’Saturday’,
”,”,’1′,’2′,’3′,’4′,’5′,
‘<textarea id=”ta1″ rows= cols=””></textarea>’,'<textarea id=”ta2″ rows= cols=””></textarea>’,'<textarea id=”ta3″ rows= cols=””></textarea>’,'<textarea id=”ta4″ rows= cols=””></textarea>’,'<textarea id=”ta5″ rows= cols=””></textarea>’,'<textarea id=”ta6″ rows= cols=””></textarea>’,'<textarea id=”ta7″ rows= cols=””></textarea>’,’6′,’7′,’8′,’9′,’10’,’11’,’12’,'<textarea id=”ta8″ rows= cols=””></textarea>’,'<textarea id=”ta9″ rows= cols=””></textarea>’,'<textarea id=”ta10″ rows= cols=””></textarea>’,'<textarea id=”ta11″ rows= cols=””></textarea>’,'<textarea id=”ta12″ rows= cols=””></textarea>’,'<textarea id=”ta13″ rows= cols=””></textarea>’,'<textarea id=”ta14″ rows= cols=””></textarea>’,’13’,’14’,’15’,’16’,’17’,’18’,’19’,'<textarea id=”ta15″ rows= cols=””></textarea>’,'<textarea id=”ta16″ rows= cols=””></textarea>’,'<textarea id=”ta17″ rows= cols=””></textarea>’,'<textarea id=”ta18″ rows= cols=””></textarea>’,'<textarea id=”ta19″ rows= cols=””></textarea>’,'<textarea id=”ta20″ rows= cols=””></textarea>’,'<textarea id=”ta21″ rows= cols=””></textarea>’,’20’,’21’,’22’,’23’,’24’,’25’,’26’,'<textarea id=”ta22″ rows= cols=””></textarea>’,'<textarea id=”ta23″ rows= cols=””></textarea>’,'<textarea id=”ta24″ rows= cols=””></textarea>’,'<textarea id=”ta25″ rows= cols=””></textarea>’,'<textarea id=”ta26″ rows= cols=””></textarea>’,'<textarea id=”ta27″ rows= cols=””></textarea>’,'<textarea id=”ta28″ rows= cols=””></textarea>’,’27’,’28’,’29’,’30’,’31’,”,”,'<textarea id=”ta29″ rows= cols=””></textarea>’,'<textarea id=”ta30″ rows= cols=””></textarea>’,'<textarea id=”ta31″ rows= cols=””></textarea>’,'<textarea id=”ta32″ rows= cols=””></textarea>’,'<textarea id=”ta33″ rows= cols=””></textarea>’,'<textarea id=”ta34″ rows= cols=””></textarea>’,'<textarea id=”ta35″ rows= cols=””></textarea>’]; var no = 0; var lim=76;
function fillCells() {
for (var i=0; i <= lim; i ++ ){
no = i + 1;
document.getElementById(“td” + no).innerHTML= arr[i];
}
}

which is appended to the second textarea.

I used the block style element that I had described in a previous post, so I could interactively edit the table style.

When finished with any style adjustments, create a blank html file, copy and paste the table style code between <style> tags, copy and paste the table code into the body and copy and paste the javascript code between tags.

Click image for larger view

raw-table

This gave an acceptable calendar, but I thought it could be a little nicer with some further style adjustments, so I added some more code to the style section.

Here is how the final calendar appears:

Click image for larger view

autotable

and here is the calendar code:

<!DOCTYPE html PUBLIC ‘-//W3C//DTD XHTML 1.0 Transitional//EN’ ‘http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd’&gt;
<html xmlns=’http://www.w3.org/1999/xhtml’&gt;
<head profile=’http://gmpg.org/xfn/11′&gt;
<title>test</title>
<style type=’text/css’>
body {margin-left:0;margin-right:0;font:normal normal normal 12px Arial;}
a{ text-decoration: }
:link { color: rgb(0, 0, 255) }
:visited {color :rgb(100, 0,100) }
:hover { }
:active { }
#table1{position: relative; top:0; border-collapse: collapse; empty-cells: show}
td{border: 1px inset}
textarea{height: 100px}
#tr1{background: #DDFFEE}
</style>
</head>
<body onload=’fillCells();’><table align=”center” valign=”top”>
<tr style=”background: #FFEEAA; font-size: 15pt”><td id=’td1′>text </td><td id=’td2′>text </td><td id=’td3′>text </td><td id=’td4′>text </td><td id=’td5′>text </td><td id=’td6′>text </td><td id=’td7′>text </td></tr><tr id=”tr1″><td id=’td8′>text </td><td id=’td9′>text </td><td id=’td10′>text </td><td id=’td11′>text </td><td id=’td12′>text </td><td id=’td13′>text </td><td id=’td14′>text </td></tr><tr><td id=’td15′>text </td><td id=’td16′>text </td><td id=’td17′>text </td><td id=’td18′>text </td><td id=’td19′>text </td><td id=’td20′>text </td><td id=’td21′>text </td></tr><tr id=”tr1″><td id=’td22′>text </td><td id=’td23′>text </td><td id=’td24′>text </td><td id=’td25′>text </td><td id=’td26′>text </td><td id=’td27′>text </td><td id=’td28′>text </td></tr><tr><td id=’td29′>text </td><td id=’td30′>text </td><td id=’td31′>text </td><td id=’td32′>text </td><td id=’td33′>text </td><td id=’td34′>text </td><td id=’td35′>text </td></tr><tr id=”tr1″><td id=’td36′>text </td><td id=’td37′>text </td><td id=’td38′>text </td><td id=’td39′>text </td><td id=’td40′>text </td><td id=’td41′>text </td><td id=’td42′>text </td></tr><tr><td id=’td43′>text </td><td id=’td44′>text </td><td id=’td45′>text </td><td id=’td46′>text </td><td id=’td47′>text </td><td id=’td48′>text </td><td id=’td49′>text </td></tr><tr id=”tr1″><td id=’td50′>text </td><td id=’td51′>text </td><td id=’td52′>text </td><td id=’td53′>text </td><td id=’td54′>text </td><td id=’td55′>text </td><td id=’td56′>text </td></tr><tr><td id=’td57′>text </td><td id=’td58′>text </td><td id=’td59′>text </td><td id=’td60′>text </td><td id=’td61′>text </td><td id=’td62′>text </td><td id=’td63′>text </td></tr><tr id=”tr1″><td id=’td64′>text </td><td id=’td65′>text </td><td id=’td66′>text </td><td id=’td67′>text </td><td id=’td68′>text </td><td id=’td69′>text </td><td id=’td70′>text </td></tr><tr><td id=’td71′>text </td><td id=’td72′>text </td><td id=’td73′>text </td><td id=’td74′>text </td><td id=’td75′>text </td><td id=’td76′>text </td><td id=’td77′>text </td></tr><tr></tr>
</table>

var arr=[
‘Sunday’,’Monday’,’Tuesday’,’Wednesday’,’Thursday’,’Friday’,’Saturday’,
”,”,’1′,’2′,’3′,’4′,’5′,
”,”,”,”,”,”,”,’6′,’7′,’8′,’9′,’10’,’11’,’12’,”,”,”,”,”,”,”,’13’,’14’,’15’,’16’,’17’,’18’,’19’,”,”,”,”,”,”,”,’20’,’21’,’22’,’23’,’24’,’25’,’26’,”,”,”,”,”,”,”,’27’,’28’,’29’,’30’,’31’,”,”,”,”,”,”,”,”,”]; var no = 0; var lim=76;
function fillCells() {
for (var i=0; i
</body>
</html>

The textareas are editable and scrollable, so nearly anything can be put in them. However, in this example they cannot be saved. However, that is not difficult. Since the textareas have an id, their values can be placed in a delimited string and saved in local storage. I have done that and it works fine, but I think that code is beyond the scope of this post. The editable calendar was not a goal in itself, but an example of how to easily create complex tables. I will leave it as an exercise to write the code to make it work.

There is also the need to change the date numbering and I have done that as well, but I will also leave that as an exercise.

An Offline HTML Database Using Local Storage

This is an HTML app to create an offline database in a csv type format, using local storage. The data can be parsed and inserted into a table, which can be copied, pasted into a Google Doc and saved as a PDF file, all done offline on a Chromebook. Of course it should be completely platform independent.

Here is the code:

<!DOCTYPE html PUBLIC ‘-//W3C//DTD XHTML 1.0 Transitional//EN’ ‘http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd’&gt;
<html xmlns=’http://www.w3.org/1999/xhtml’&gt;
<head profile=’http://gmpg.org/xfn/11′&gt;
<title>HTML DB</title>
<style type=’text/css’>
body {margin-left:0;margin-right:0;font:normal normal 800 15px Arial; white-space: pre-wrap}
a{ text-decoration: }
:link { color: rgb(0, 0, 255) }
:visited {color :rgb(100, 0,100) }
:hover { }
:active { }
#Q{}
#d1{position: absolute; top: 10px; left: 10px}
td{position: relative; border: 1px solid black; font:normal normal 800 15px Arial; background: #EEEEEE;}
#table1{position:absolute; empty-cells: hide; text-align: center; visibility:hidden; top: 10px;left: 10px}
</style>
</head>
<body>

How would you rate the Registration?
1 2 3

How would you rate the Course?
1 2 3

Comments

<table id =”table1″ align=”center”>
<tr><td id=”Q” onclick=’restore();’ >Registration</td><td id=”Q”>Course</td><td id=”Q”>Comment</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td id=”td11″></td><td id=”td12″><td id=”td13″></td><td id=”td14″></td><td id=”td15″></td><td id=”td16″></td><td id=”td17″></td><td id=”td18″></td><td id=”td19″></td><td id=”td110″></td></tr>
<tr><td id=”td21″></td><td id=”td22″><td id=”td23″></td><td id=”td24″></td><td id=”td25″></td><td id=”td26″></td><td id=”td27″></td><td id=”td28″></td><td id=”td29″></td><td id=”td210″></td></tr>
<tr><td id=”td31″></td><td id=”td32″><td id=”td33″></td><td id=”td34″></td><td id=”td35″></td><td id=”td36″></td><td id=”td37″></td><td id=”td38″></td><td id=”td39″></td><td id=”td310″></td></tr>
<tr><td id=”td41″></td><td id=”td42″><td id=”td43″></td><td id=”td44″></td><td id=”td45″></td><td id=”td46″></td><td id=”td47″></td><td id=”td48″></td><td id=”td49″></td><td id=”td410″></td></tr>
<tr><td id=”td51″></td><td id=”td52″><td id=”td53″></td><td id=”td54″></td><td id=”td55″></td><td id=”td56″></td><td id=”td57″></td><td id=”td58″></td><td id=”td59″></td><td id=”td510″></td></tr>
<tr><td id=”td61″></td><td id=”td62″><td id=”td63″></td><td id=”td64″></td><td id=”td65″></td><td id=”td66″></td><td id=”td67″></td><td id=”td68″></td><td id=”td69″></td><td id=”td610″></td></tr>
<tr><td id=”td71″></td><td id=”td72″><td id=”td73″></td><td id=”td74″></td><td id=”td75″></td><td id=”td76″></td><td id=”td77″></td><td id=”td78″></td><td id=”td79″></td><td id=”td710″></td></tr>
<tr><td id=”td81″></td><td id=”td82″><td id=”td83″></td><td id=”td84″></td><td id=”td85″></td><td id=”td86″></td><td id=”td87″></td><td id=”td88″></td><td id=”td89″></td><td id=”td810″></td></tr>
<tr><td id=”td91″></td><td id=”td92″><td id=”td93″></td><td id=”td94″></td><td id=”td95″></td><td id=”td96″></td><td id=”td97″></td><td id=”td98″></td><td id=”td99″></td><td id=”td910″></td></tr>
<tr><td id=”td101″></td><td id=”td102″><td id=”td103″></td><td id=”td104″></td><td id=”td105″></td><td id=”td106″></td><td id=”td107″></td><td id=”td108″></td><td id=”td109″></td><td id=”td1010″></td></tr>
</table>

var str = “”; var r; var a = 0; var b = 0; var lim = 3; var str2 = “”; var key;

function clearAll() {
localStorage.clear();
alert(“done”);
}

function clearKey() {
localStorage.removeItem(document.getElementById(“text1”).value);
alert(document.getElementById(“text1″).value + ” Cleared”);
}

function restore() {
document.getElementById(“d1”).style.visibility = “visible”;
document.getElementById(“table1”).style.visibility = “hidden”;
}

function fill() {
key = prompt(“database key”);
if (localStorage.getItem(key, str) != null) str2 = localStorage.getItem(key, str);
r =document.getElementsByName(“r1”);
for (var i=0; i -1) {
document.getElementById(“td” + j.toString() + i.toString()).innerHTML = str.substr(b,a-b);
if (i -1) {
document.getElementById(“td” + j.toString() + “3”).innerHTML= str.substr(b,a-b).replace(/\^/g, ‘\n’);
b = a+1;
}
}

}

</body>
</html>

 

In addition to creating the table, it has functions for removing either all local storage or selected databases.

This is the code for setting up the interface. It has 2 sets of radiobuttons, 3 buttons, a text input and a textarea.

How would you rate the Registration?
1 2 3

How would you rate the Course?
1 2 3

Comments

Here is how the interface appears:

Click image for larger view.

DB-Interface

The radiobuttons and text area provide the input.

<table id =”table1″ align=”center”>
<tr><td id=”Q” onclick=’restore();’ >Registration</td><td id=”Q”>Course</td><td id=”Q”>Comment</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td id=”td11″></td><td id=”td12″><td id=”td13″></td><td id=”td14″></td><td id=”td15″></td><td id=”td16″></td><td id=”td17″></td><td id=”td18″></td><td id=”td19″></td><td id=”td110″></td></tr>
<tr><td id=”td21″></td><td id=”td22″><td id=”td23″></td><td id=”td24″></td><td id=”td25″></td><td id=”td26″></td><td id=”td27″></td><td id=”td28″></td><td id=”td29″></td><td id=”td210″></td></tr>
<tr><td id=”td31″></td><td id=”td32″><td id=”td33″></td><td id=”td34″></td><td id=”td35″></td><td id=”td36″></td><td id=”td37″></td><td id=”td38″></td><td id=”td39″></td><td id=”td310″></td></tr>
<tr><td id=”td41″></td><td id=”td42″><td id=”td43″></td><td id=”td44″></td><td id=”td45″></td><td id=”td46″></td><td id=”td47″></td><td id=”td48″></td><td id=”td49″></td><td id=”td410″></td></tr>
<tr><td id=”td51″></td><td id=”td52″><td id=”td53″></td><td id=”td54″></td><td id=”td55″></td><td id=”td56″></td><td id=”td57″></td><td id=”td58″></td><td id=”td59″></td><td id=”td510″></td></tr>
<tr><td id=”td61″></td><td id=”td62″><td id=”td63″></td><td id=”td64″></td><td id=”td65″></td><td id=”td66″></td><td id=”td67″></td><td id=”td68″></td><td id=”td69″></td><td id=”td610″></td></tr>
<tr><td id=”td71″></td><td id=”td72″><td id=”td73″></td><td id=”td74″></td><td id=”td75″></td><td id=”td76″></td><td id=”td77″></td><td id=”td78″></td><td id=”td79″></td><td id=”td710″></td></tr>
<tr><td id=”td81″></td><td id=”td82″><td id=”td83″></td><td id=”td84″></td><td id=”td85″></td><td id=”td86″></td><td id=”td87″></td><td id=”td88″></td><td id=”td89″></td><td id=”td810″></td></tr>
<tr><td id=”td91″></td><td id=”td92″><td id=”td93″></td><td id=”td94″></td><td id=”td95″></td><td id=”td96″></td><td id=”td97″></td><td id=”td98″></td><td id=”td99″></td><td id=”td910″></td></tr>
<tr><td id=”td101″></td><td id=”td102″><td id=”td103″></td><td id=”td104″></td><td id=”td105″></td><td id=”td106″></td><td id=”td107″></td><td id=”td108″></td><td id=”td109″></td><td id=”td1010″></td></tr>
</table>

This is the output table. It is set for up to 10 items for 10 records, but of course can be enlarged as needed. Unused cells are hidden in the output.
#table1{position:absolute; empty-cells: hide; text-align: center; visibility:hidden; top: 10px;left: 10px}

The table is kept hidden until the recall button is clicked.
function fill() {
key = prompt(“database key”);
if (localStorage.getItem(key, str) != null) str2 = localStorage.getItem(key, str);
r =document.getElementsByName(“r1”);
for (var i=0; i < r.length ;i++) {
if (r[i].checked){
str2 += r[i].value + “~”;
break;
}
}
r =document.getElementsByName(“r2”);
for (var i=0; i < r.length ;i++) {
if (r[i].checked){
str2 += r[i].value + “~”;
break;
}
}
str2 += document.getElementById(“ta1”).value.replace(/\n/g, ‘^’) + “\n”;
var done = localStorage.setItem(key, str2);
alert(“Thank you for your reply”);
a = 0;
b = 0;
}

This is the storage code. The data is stored under a key name, so several databases can be created, each with a different keyname.

The inputs are parsed and added to a composite string, which is then stored.
var done = localStorage.setItem(key, str2);

This app allows a multiline message. CSV stands for Comma Separated Variable, but there are several problems using csv storage for a multiword and multiline message delimiter. Commas are often used in multiword messages and can not be distinguished from the delimiter. Spaces, which are also often used to delimit obviously can not be used for the same reason. For my csv files I use a tilde (~), very seldom used in English, although something else would be needed for Spanish input.

The same problem occurs with multiline messages as the newline character is used to delimit records. The workaround is to convert the newline character using the replace function, save as a single line string and after the new record has been retrieved, convert it back.
str2 += document.getElementById(“ta1”).value.replace(/\n/g, ‘^’) + “\n”;
document.getElementById(“td” + j.toString() + “3”).innerHTML= str.substr(b,a-b).replace(/\^/g, ‘\n’);

This is the code to retrieve the data and populate the table.

function recall() {
str = “”;
document.getElementById(“table1”).style.visibility = “visible”;
document.getElementById(“d1”).style.visibility = “hidden”;
var opnstr = prompt(“Open Key”, “”);
str = localStorage.getItem(opnstr, str);
for (var j=1; j <=4; j++) {
for (var i=1; i <=lim; i++) {
a = str.indexOf(“~”,b);

if (a > -1) {
document.getElementById(“td” + j.toString() + i.toString()).innerHTML = str.substr(b,a-b);
if (i < lim) b=a+1;
}

}
a = str.indexOf(“\n”,b);

if (a > -1) {
document.getElementById(“td” + j.toString() + “3”).innerHTML= str.substr(b,a-b).replace(/\^/g, ‘\n’);
b = a+1;
}
}

}

Here is how that looks:

Click Image for larger view

DB-Output

This function clears all local storage.

function clearAll() {
localStorage.clear();
alert(“done”);
}
function clearKey() {
localStorage.removeItem(document.getElementById(“text1”).value);
alert(document.getElementById(“text1″).value + ” Cleared”);
}

Entering a keyname and double clicking text1 clears the selected database.

As I previously mentioned the table can be copied and ultimately saved offline as a PDF. Here is how that looks:

Click image for larger view.

DB-PDF

An HTML, Javascript Image Thumbnail Creator and Viewer

I have written an app entirely in html and javascript that creates a table of image thumbnails. Clicking a thumbnail displays the image in a new window. Doubleclicking the display window returns to the original for a selection of a new image.

Here is the html file:

<!DOCTYPE html PUBLIC ‘-//W3C//DTD XHTML 1.0 Transitional//EN’ ‘http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd’&gt;
<html xmlns=’http://www.w3.org/1999/xhtml’&gt;
<head profile=’http://gmpg.org/xfn/11′&gt;
<title>Viewer</title>
<style type=’text/css’>
body {margin-left:0;margin-right:0;font:normal normal normal 12px Arial; white-space: pre-wrap}
a{ text-decoration: }
:link { color: rgb(0, 0, 255) }
:visited {color :rgb(100, 0,100) }
:hover { }
:active { }#left,#right{font:normal normal 800 18px Arial}
#arrows{position: absolute; width: 200px; height: 50px; left: 50%; top: 600px; margin-left: -100px; text-align: center}
#d1{position: absolute; text-align: center; top: 0; left: 0; width: 100%; height: 100%; visibility: hidden; background: black; padding: 20px}
td{height: 50px; text-align: center; border: 1px solid black; padding: 1px}
</style>
</head>
<body onload=’loadSelect();’>

&lt;script type=”text/javascript” src=”thumbs.js”&gt;&lt;/script&gt;

var fil; var content = “

“; var cnt = 0; var width; var height; var a = 0; var b; var fl2; var fl = “”;

function changeImage(dir) {
a = document.getElementById(“ta1”).value.indexOf(“showImage”, a + 1) + 11;
b = document.getElementById(“ta1”).value.indexOf(“‘”, a + 1);
fl = document.getElementById(“ta1”).value.substr(a, b – a);
if (a == 39) fl2 = fl;
if (fl == “d=”) {
fl = fl2;
a = 39;
}
document.getElementById(“d1”).innerHTML = ‘

‘;
if (im.clientWidth > im.clientHeight && im.clientWidth/im.clientHeight > 1.6 ) {
document.getElementById(“im”).style.width=”800px”;
} else {
document.getElementById(“im”).style.height=”500px”;
}
}

function showImage(fl) {
document.getElementById(“d1”).innerHTML = ‘

‘;
if (im.clientWidth > im.clientHeight && im.clientWidth/im.clientHeight > 1.6 ) {
document.getElementById(“im”).style.width=”800px”;
} else {
document.getElementById(“im”).style.height=”500px”;
}

document.getElementById(“d1”).style.visibility = “visible”;
document.getElementById(“t1”).style.visibility = “hidden”;
document.getElementById(“control”).style.visibility = “hidden”;
}

function restore() {
document.getElementById(“d1”).style.visibility = “hidden”;
document.getElementById(“t1”).style.visibility = “visible”;
document.getElementById(“control”).style.visibility = “visible”;
}

function test() {
if (document.getElementById(“s1”).value != “Choose Set”) {
if (document.getElementById(“s1”).value == “thumb1”) content = thumb1;
if (document.getElementById(“s1”).value == “thumb2”) content = thumb2;
if (document.getElementById(“s1”).value == “thumb3”) content = thumb3;
if (document.getElementById(“s1”).value == “thumb4”) content = thumb4;
} else {
content += “

“;
}
document.getElementById(“t1”).innerHTML = content;
content = content.replace(/”/g,’\\”‘);
document.getElementById(“ta1″).value = ‘”‘ + content + ‘”;’;
content = “”;
}

function add() {
if (cnt > 0) {
fil = document.getElementById(“file”).value;
fil = fld + fil.substr(12,fil.length);
content += “

;”;
if (cnt % 10 == 0) content += “ “;
}
cnt ++;
}

</body>
</html>

This code creates the interface:

The file input only gives the filename, so the folder has to be chosen from a list.

<select id=”s2″ onchange=’getFolder();’></select>
The options for the select are set in the javascript file in the function getFolder().

First choose the filename with the file input and then select the folder from which you chose the filename. Repeat for as many thumbnails as you want. A quirk requires that the file input be opened one time after the last image is chosen, but it can then be immediately closed. If this is not done, the last image will not be included. The files do not have to be in the same folder, so long as you associate the correct folder with each file.

This is done by the function add().

function add() {
if (cnt > 0) {
fil = document.getElementById(“file”).value;
fil = fld + fil.substr(12,fil.length);
content += “<td id=’td” + cnt.toString() + “‘ onclick=\”showImage(‘” + fil + “‘);\”><img src='” + fil + “‘ height=’50px’ alt=” /></td>;”;
if (cnt % 10 == 0) content += “</tr><tr>”;
}
cnt ++;
}

Here is how the GUI looks:

Click image for larger view

thumbs-Interface

 

After all the images have been added, click Create Thumbnails and the thumbnails will be displayed in a table that starts a new row after each 10 thumbnails. This is done by the function test().
function test() {
if (document.getElementById(“s1”).value != “Choose Thumbnail Set”) {
if (document.getElementById(“s1”).value == “thumb1”) content = thumb1;
if (document.getElementById(“s1”).value == “thumb2”) content = thumb2;
if (document.getElementById(“s1”).value == “thumb3”) content = thumb3;
if (document.getElementById(“s1”).value == “thumb4”) content = thumb4;
} else {
content += “</tr>”;
}
document.getElementById(“t1”).innerHTML = content;
content = content.replace(/”/g,’\\”‘);
document.getElementById(“ta1″).value = ‘”‘ + content + ‘”;’;
content = “”;
}

Here is how some thumnails look:

Click image for larger view

thumbnails

The textarea contains the string that created the thumbnails. This can be used to save the list of images as a playlist, so it can be reloaded.

content = content.replace(/”/g,’\\”‘);
This line is to automatically escape all repeat quotation marks corresponding the bounding quotes.

Here is the js file:

var thumb1; var thumb2; var thumb3; var thumb4; var fld;thumb1 = “<tr><td id=’td1′ onclick=\”showImage(‘file:///media/removable/TOSHIBA%20EXT/My%20Pictures/Y5.jpg’);\”><img src=’file:///media/removable/TOSHIBA%20EXT/My%20Pictures/Y5.jpg’ height=’50px’ alt=” /></td>;<td id=’td2′ onclick=\”showImage(‘file:///media/removable/TOSHIBA%20EXT/My%20Pictures/Animated GIF/condor.gif’);\”><img src=’file:///media/removable/TOSHIBA%20EXT/My%20Pictures/Animated GIF/condor.gif’ height=’50px’ alt=” /></td>;<td id=’td3′ onclick=\”showImage(‘file:///media/removable/TOSHIBA%20EXT/My%20Pictures/Animated GIF/garden.gif’);\”><img src=’file:///media/removable/TOSHIBA%20EXT/My%20Pictures/Animated GIF/garden.gif’ height=’50px’ alt=” /></td>;<td id=’td4′ onclick=\”showImage(‘file:///media/removable/TOSHIBA%20EXT/My%20Pictures/A-E/bird.png’);\”><img src=’file:///media/removable/TOSHIBA%20EXT/My%20Pictures/A-E/bird.png’ height=’50px’ alt=” /></td></tr>”;

function loadSelect() {
document.getElementById(“s1”).innerHTML='<option>Choose Set</option><option>thumb1</option><option>thumb2</option><option>thumb3</option><option>thumb4</option>’;
document.getElementById(“s2”).innerHTML='<option>Choose Folder</option><option>Downloads</option><option>MyPics</option><option>anigif</option><option>A-E</option><option>F-J</option><option>Win A-E</option><option>Win F-J</option>’;
}

function getFolder() {
if (document.getElementById(“s2”).value == “Downloads”) fld = “file:///home/chronos/u-1eb10e124afb2b2cad22d7f9b971259b7789c079/Downloads/”;
if (document.getElementById(“s2”).value == “MyPics”) fld = “file:///media/removable/TOSHIBA%20EXT/My%20Pictures/”;
if (document.getElementById(“s2”).value == “anigif”) fld = “file:///media/removable/TOSHIBA%20EXT/My%20Pictures/Animated GIF/”;
if (document.getElementById(“s2”).value == “A-E”) fld = “file:///media/removable/TOSHIBA%20EXT/My%20Pictures/A-E/”;
if (document.getElementById(“s2”).value == “F-J”) fld = “file:///media/removable/TOSHIBA%20EXT/My%20Pictures/F-J/”;
if (document.getElementById(“s2”).value == “Win A-E”) fld = “file://I:/My Pictures/A-E/”;
if (document.getElementById(“s2”).value == “Win F-J”) fld = “file://I:/My Pictures/F-J/”;
}

loadSelect(), which is called on loading the html file sets the values of the select boxes.

getFolder() set the name of the folder to be associated with the chosen image.

Playlists can be created by copying and pasting the contents of the textarea into variables named thumb1, thumb2, etc.

These playlists can then ve loaded by clicking an option in the Choose Set select box. The table of thumbnaols will then be displayed as if they had been created by the add() function.

Clicking a thumbnail dosplays the corresponding image.

Here is how that looks:

Click image for larger view

view

Doubleclicking the view window returns the thumbnail window to allow another image to be displayed.

Rather than going back and forth between the two windows it is possible to view all the images in sequence by clickinbg the Cycle button at the bottom of the view window. After the last image is shown, it will go back to the first image

HTML On-The-Fly Viewing of 2D Images in 3D

I have previously demonstrated how to convert 2d to 3d images. With the advent of css3 it is now, however, possible to display 2d images in 3d without conversion. This is with the use of rotateY and perspective.

Here is the code:

<!DOCTYPE html PUBLIC ‘-//W3C//DTD XHTML 1.0 Transitional//EN’ ‘http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd’&gt;
<html xmlns=’http://www.w3.org/1999/xhtml’&gt;
<head profile=’http://gmpg.org/xfn/11′&gt;
<title>3D</title>
<style type=’text/css’>
body{background: black}
.container{position:absolute; left: 50%; margin-left: -450px; width: 900px; top: 100px}
#fil1{position: absolute; left: 10px; top: 5%; width: 100px}
#b1{position: absolute; left: 10px; top: 10%; width: 80px}
#h1{position: absolute; left: 10px; top: 15%; background: white; font-size: 15pt }
#t1{position: absolute; left: 10px; top: 20%; }
#h2{position: absolute; left: 10px; top: 25%; background: white; font-size: 15pt }
#t2{position: absolute; left: 10px; top: 30%; }#f1_container { position: absolute; top: 0; left: 0; width: 50%;
-webkit-perspective: 1000;
-moz-perspective: 1000px; }
#f2_container { position: absolute; top: 0; left: 50%; width: 50%;
-webkit-perspective: 1000;
-moz-perspective: 1000px; }#f1card {width: 100%; height: 100%;
-webkit-transform-style: preserve-3d;
-webkit-transition: all 1.0s linear;
-moz-transform-style: preserve-3d;
-moz-transition: all 1.0s linear;
-o-transform-style: preserve-3d;
-o-transition: all 1.0s linear;
-ms-transform-style: preserve-3d;
-ms-transition: all 1.0s linear;
transform-style: preserve-3d;
transition: all 1.0s linear;
-webkit-transform: rotateY(10deg);
-moz-transform: rotateY(10deg);
-o-transform: rotateY(10deg);
-ms-transform: rotateY(10deg);
transform: rotateY(10deg);
}#f2card {width: 100%; height: 100%;
-webkit-transform-style: preserve-3d;
-webkit-transition: all 1.0s linear;
-moz-transform-style: preserve-3d;
-moz-transition: all 1.0s linear;
-o-transform-style: preserve-3d;
-o-transition: all 1.0s linear;
-ms-transform-style: preserve-3d;
-ms-transition: all 1.0s linear;
transform-style: preserve-3d;
transition: all 1.0s linear;
-webkit-transform: rotateY(-10deg);
-moz-transform: rotateY(-10deg);
-o-transform: rotateY(-10deg);
-ms-transform: rotateY(-10deg);
transform: rotateY(-10deg);
}img{ border: 1px solid #CCCCCC; border-radius:10px; width: 100%}</style>
</head>
<body>

<input type=”file” id= “fil1″ name=”fil1″ value=”” /> <input type=”button” id= “b1″ name=”b1″ value=”Load File” onclick=’getFile();’ /> <h id=”h1″>Left Rotation</h> <input type=”text” id= “t1″ name=”t1″ value=”10” ondblclick=’document.getElementById(“t1″).value=””;’/> <h id=”h2″>Right Rotation</h> <input type=”text” id= “t2″ name=”t2″ value=”-10″ ondblclick=’document.getElementById(“t2″).value=””;’/>

</div>

</div>
</div>

var v1; var v2;
function getFile() {
var rot = parseInt(document.getElementById(‘t1’).value);
var rot2 = parseInt(document.getElementById(‘t2’).value);
var fl = document.getElementById(“fil1”).value;
if (fl.indexOf(“fake”) > -1) fl = fl.substr(12, fl.length – 12);
fl = “ “;
v1 = document.getElementById(“f1card”);
v2 = document.getElementById(“f2card”);
v1.innerHTML = fl;
v2.innerHTML = fl;
v1.style.WebkitTransform= “rotateY(” + rot + “deg)”;
v1.style.MozTransform= “rotateY(” + rot + “deg)”;
v1.style.msTransform= “rotateY(” + rot + “deg)”;
v1.style.transform= “rotateY(” + rot + “deg)”;
v2.style.WebkitTransform= “rotateY(” + rot2 + “deg)”;
v2.style.MozTransform= “rotateY(” + rot2 + “deg)”;
v2.style.msTransform= “rotateY(” + rot2 + “deg)”;
v2.style.transform= “rotateY(” + rot2 + “deg)”;
}

</body></html>

Two layers are created, each of which contains the same image, only rotated to a different angle.

Here is how the interface looks:

Click image for larger view

css3Viewer css3-interface

All changes can be applied interactively by clicking the Load File button. An image can be selected with the file input box. All images to be used must be in the same folder as the html file.

var fl = document.getElementById(“fil1”).value;
if (fl.indexOf(“fake”) > -1) fl = fl.substr(12, fl.length – 12);
fl = “<Img SRC='” + fl + “‘ alt=’ ‘ /> “;

The reason for the if is my Chromebook  adds a pseudo folder the filename, so the true filename must be extracted as a substring.

The right and left images can be rotated independently in both the positive and negative directions and to any angle. Your personal preference will decide which combination of rotations works best.

var rot = parseInt(document.getElementById(‘t1’).value);
var rot2 = parseInt(document.getElementById(‘t2’).value);

v1 = document.getElementById(“f1card”);
v2 = document.getElementById(“f2card”);
v1.innerHTML = fl;
v2.innerHTML = fl;
v1.style.WebkitTransform= “rotateY(” + rot + “deg)”;
v1.style.MozTransform= “rotateY(” + rot + “deg)”;
v1.style.msTransform= “rotateY(” + rot + “deg)”;
v1.style.transform= “rotateY(” + rot + “deg)”;
v2.style.WebkitTransform= “rotateY(” + rot2 + “deg)”;
v2.style.MozTransform= “rotateY(” + rot2 + “deg)”;
v2.style.msTransform= “rotateY(” + rot2 + “deg)”;
v2.style.transform= “rotateY(” + rot2 + “deg)”;

Here are some different values for the rotations.

Click imagesfor larger view

negative left – positive right
negpos

zero left – negative right
zeroneg

positive left – negative right
posneg

more positive left – more negative right
moreposneg

The browser’s internal zoom can enlarge or shrink the image.

Not only can you view the image in 3d without conversion, but it could also be used as a converter. Just capture the image on the screen anfd save as an image file.