วันจันทร์ที่ 26 มีนาคม พ.ศ. 2555

การเปิดหน้าเวปใหม่ภายใน frame

โค้ดตามนี้เลย

<form name="jumpy">
<select name="example" size="1" onChange="gone()">
<!-- CHANGE THE BELOW URLS TO YOUR OWN-->
<option value="http://www.yahoo.com" selected>Yahoo.com</option>
<option value="http://www.google.com">Google</option>
<option value="http://www.lycos.com">Lycos</option>
<option value="http://www.AltaVista.com">AltaVista</option>
</select>

<input type="button" name="test" value="Go!" onClick="gone()">
</form>

<script language="javascript">
<!--

//Drop-down Document Viewer- © Dynamic Drive (www.dynamicdrive.com)
//For full source code, 100's more DHTML scripts, and TOS,
//visit http://www.dynamicdrive.com

//Specify display mode (0 or 1)
//0 causes document to be displayed in an inline frame, while 1 in a new browser window
var displaymode=1
//if displaymode=0, configure inline frame attributes (ie: dimensions, intial document shown
var iframecode='<iframe id="external" style="width:95%;height:400px" src="http://www.yahoo.com"></iframe>'

/////NO NEED TO EDIT BELOW HERE////////////

if (displaymode==0)
document.write(iframecode)

function gone(){
var selectedurl=document.jumpy.example.options[document.jumpy.example.selectedIndex].value
if (document.getElementById&&displaymode==0)
document.getElementById("external").src=selectedurl
else if (document.all&&displaymode==0)
document.all.external.src=selectedurl
else{
if (!window.win2||win2.closed)
win2=window.open(selectedurl)
//else if win2 already exists
else{
win2.location=selectedurl
win2.focus()
}
}
}
//-->
</script>

การแสดงคำอธิบายในฟอร์ม


Username: [?]
Password:   [?]

จากตัวอย่างด้านบนหากเราเอาเมาส์ไปชี้ที่เครื่องหมาย ? ก็จะมีคำอธิบายขึ้นมา
โค้ด
เอาไปวางในส่วนของ head
<style type="text/css">

#hintbox{ /*CSS for pop up hint box */
position:absolute;
top: 0;
background-color: lightyellow;
width: 150px; /*Default width of hint.*/ 
padding: 3px;
border:1px solid black;
font:normal 11px Verdana;
line-height:18px;
z-index:100;
border-right: 3px solid black;
border-bottom: 3px solid black;
visibility: hidden;
}

.hintanchor{ /*CSS for link that shows hint onmouseover*/
font-weight: bold;
color: navy;
margin: 3px 8px;
}

</style>

<script type="text/javascript">

/***********************************************
* Show Hint script- © Dynamic Drive (www.dynamicdrive.com)
* This notice MUST stay intact for legal use
* Visit http://www.dynamicdrive.com/ for this script and 100s more.
***********************************************/
var horizontal_offset="9px" //horizontal offset of hint box from anchor link

/////No further editting needed

var vertical_offset="0" //horizontal offset of hint box from anchor link. No need to change.
var ie=document.all
var ns6=document.getElementById&&!document.all

function getposOffset(what, offsettype){
var totaloffset=(offsettype=="left")? what.offsetLeft : what.offsetTop;
var parentEl=what.offsetParent;
while (parentEl!=null){
totaloffset=(offsettype=="left")? totaloffset+parentEl.offsetLeft : totaloffset+parentEl.offsetTop;
parentEl=parentEl.offsetParent;
}
return totaloffset;
}

function iecompattest(){
return (document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body
}

function clearbrowseredge(obj, whichedge){
var edgeoffset=(whichedge=="rightedge")? parseInt(horizontal_offset)*-1 : parseInt(vertical_offset)*-1
if (whichedge=="rightedge"){
var windowedge=ie && !window.opera? iecompattest().scrollLeft+iecompattest().clientWidth-30 : window.pageXOffset+window.innerWidth-40
dropmenuobj.contentmeasure=dropmenuobj.offsetWidth
if (windowedge-dropmenuobj.x < dropmenuobj.contentmeasure)
edgeoffset=dropmenuobj.contentmeasure+obj.offsetWidth+parseInt(horizontal_offset)
}
else{
var windowedge=ie && !window.opera? iecompattest().scrollTop+iecompattest().clientHeight-15 : window.pageYOffset+window.innerHeight-18
dropmenuobj.contentmeasure=dropmenuobj.offsetHeight
if (windowedge-dropmenuobj.y < dropmenuobj.contentmeasure)
edgeoffset=dropmenuobj.contentmeasure-obj.offsetHeight
}
return edgeoffset
}

function showhint(menucontents, obj, e, tipwidth){
if ((ie||ns6) && document.getElementById("hintbox")){
dropmenuobj=document.getElementById("hintbox")
dropmenuobj.innerHTML=menucontents
dropmenuobj.style.left=dropmenuobj.style.top=-500
if (tipwidth!=""){
dropmenuobj.widthobj=dropmenuobj.style
dropmenuobj.widthobj.width=tipwidth
}
dropmenuobj.x=getposOffset(obj, "left")
dropmenuobj.y=getposOffset(obj, "top")
dropmenuobj.style.left=dropmenuobj.x-clearbrowseredge(obj, "rightedge")+obj.offsetWidth+"px"
dropmenuobj.style.top=dropmenuobj.y-clearbrowseredge(obj, "bottomedge")+"px"
dropmenuobj.style.visibility="visible"
obj.onmouseout=hidetip
}
}

function hidetip(e){
dropmenuobj.style.visibility="hidden"
dropmenuobj.style.left="-500px"
}

function createhintbox(){
var divblock=document.createElement("div")
divblock.setAttribute("id", "hintbox")
document.body.appendChild(divblock)
}

if (window.addEventListener)
window.addEventListener("load", createhintbox, false)
else if (window.attachEvent)
window.attachEvent("onload", createhintbox)
else if (document.getElementById)
window.onload=createhintbox

</script>
ส่วนอันนี้เป็นส่วนของ form
<form>
<b>Username:</b> <input type="text" class="test" /> <a href="#" class="hintanchor" onMouseover="showhint('Please choose a username. Should consist of alphanumeric characters only.', this, event, '150px')">[?]</a><br />
<b>Password:</b>  <input type="text" class="test" /> <a href="#" class="hintanchor" onMouseover="showhint('Enter the desired password. <b>Must</b> be 8 characters or longer.', this, event, '200px')">[?]</a><br />
</form>

วันจันทร์ที่ 19 มีนาคม พ.ศ. 2555

เร่งความเร็วให้กับโค้ด php

การเร่งความเร็วโค้ด PHP (PHP Bench Mark) เป็นปัจจัยหนึ่งที่จะทำให้เว็บของเราเร็วขึ้นได้ ในงานอย่างใดอย่างหนึ่งของ PHP อาจมีหลายฟังก์ชั่นให้เลือกใช้งาน ซึ่งฟังก์ชั่นที่แตกต่างกันของ PHP ย่อมมีขีดความสามารถแตกต่างกัน ดังนั้นการเลือกฟังก์ชั่นที่ดี ตลอดจนการใช้งานฟังก์ชั่นต่างๆอย่างถูกต้องย่อมทำให้เว็บของเราเร็วขึ้นได้

  • for และ while 2 คำสั่งนี้ใช้สำหรับการวนลูป ซึ่ง while จะเร็วกว่า for ครับ
  • echo และ print ใช้ echo แทน print ได้เลยครับ เพราะมันทำงานอย่างเดียวกัน แต่ echo เร็วกว่า เห็นๆ
  • empty และ isset ทั้ง 2 ฟังก์ชั่นนี้ใช้ทดสอบตัวแปรเช่นกัน แต่ทำกลับกัน ซึ่ง empty จะเร็วกว่า isset ครับ แต่ !isset ไม่ได้เร็วกว่า empty นะครับ
  • while(list($key) = each($aHash)) เร็วกว่า foreach($aHash as $key)
  • if เร็วกว่า case เนื่องจาก if เป็นรูปแบบพื้นฐานที่สุดนั่นเอง
  • ' (single quote) และ " (double quote) อันแรกจะเร็วกว่าเล็กน้อย เนื่องจากมันไม่ต้องตรวจหาตัวแปรภายในข้อความ
  • count และ sizeof ใช้สำหรับนับจำนวนแอเรย์ ซึ่ง sizeof จะเร็วกว่า count เล็กน้อย ครับ
  • เราไม่ควรใช้ count ภายใน loop for ครับ เนื่องจากจะทำให้ PHP คำนวณขนาดของตัวแปรทุกครั้ง ซึ่งจะนานกว่าการอ่านจำนวนของตัวแปร เตรียมไว้ก่อนส่งเข้า for
<?php
   // fast
   $size = count($x);
   for ($i = 0 ; $i < $size; $i++) {
   }

   // slow
   for ($i = 0; $i < count($x); $i++) {
   }
?>
  • require และ include  require จะเร็วกว่าเล็กน้อยครับ
  • include_once และ include (ระหว่างที่มี once กับไม่มี) ที่มี once จะเร็วกว่าครับ
  • การทดสอบไฟล์ว่ามีอยู่หรือไม่ก่อนการ include เร็วกว่าการใช้ @ ปิดการแจ้งข้อผิดพลาดเพื่อไม่พบไฟล์ (และหากพบไฟล์ก็ยังเร็วกว่าอยู่ดี)
<?php
   // fast
   if(is_file('inc.php')) {
      include('inc.php');
   }

   // slow
    @include('inc.php');
?>

การปรับแต่งไฟล์ php.ini



การปรับแต่ง php.ini
1. การปรับแต่ง short_open_tag เพื่อให้การประกาศ Tag php แบบสั้นได้ เช่น
      แบบสั้น <?.........?>
     แบบยาว <?php........?>
    ให้แก้ไฟล์ php.ini ส่วนของ short_open_tag จาก Off เป็น On
     short_open_tag = On
2. การปรับแต่ง register_globals เพื่อให้การส่งค่าแบบ GET POST โดยไม่ต้องประกาศ
     ให้แก้ไฟล์ php.ini ส่วนของ register_globals = Off จาก On เป็น Off
     register_globals = Off
3. max_execution_time = 60 เป็นกำหนดเวลาในการ execute ของ script ถ้าเครื่องช้า เพิ่มเวลาให้ได้
4. Cross Site Script คือการ On ไว้ จะทำให้ผู้ไม่ประสงค์ดี สามารถ Upload ไฟล์ที่มีปัญหาขึ้นมา แล้วสั่งให้ Execute ตัวเอง ก่อนจะทำการ DoS ไปยัง Server อื่นๆ ได้
5. magic_quotes_gpc = On – เป็นค่าที่ตั้งเป็น On ไว้เสมอ เพื่อป้องกันการแทรกโค้ดเข้ามาจากหน้าเวบ
6. default_charset = “tis-620″ – แก้ไขให้เป็นภาษาไทยได้ทันทีครับ
7. file_uploads = On – ตั้งค่าเป็น On เพื่อให้สามารถทำการ Upload ผ่าน PHP Scripts ได้
    upload_tmp_dir = – หากต้องการตั้งค่า temporary Directory ให้การ Upload ก็ระบุ path ได้ที่นี่
    upload_max_filesize = 5M – ถ้ามี Ram สูง สามารถเพิ่มขนาดไฟล์ Upload ได้ ค่า Default จะเป็น 2M ทั้งนี้ขึ้นอยู่กับ Ram ที่ระบบมีอยู่ด้วย

วันเสาร์ที่ 17 มีนาคม พ.ศ. 2555

เอา scrollbar ออกจาก textarea ด้วย CSS


<html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-874" />
 <title>css textarea scrollbar </title>
 </head>
 <style type="text/css">
.no_scroll{
overflow:hidden;
}
 </style>
 <body>
 <form id="form1" name="form1" method="post" action="">
   <p>ยังไม่กำหนด CSS  </p>
   <p>
     <textarea name="textarea" cols="40" rows="5"> </textarea>
   </p>
   <p>กำหนด CSS  </p>
   <p>
     <textarea name="textarea" class="no_scroll" cols="40" rows="5"> </textarea>
       </p>
 </form>
 </body>
 </html>

วันศุกร์ที่ 16 มีนาคม พ.ศ. 2555

ซ่อน link ที่แสดงตรง status bar

เทคนิคนี้ใช้กันมากในหลายๆเว็บคือไม่อยากให้เวลานำ mouse ไปวางไว้ที Link แล้วมีการดู URL ตรง Status Bar Script ด้านล่างคือการซ่อนไม่ให้แสดงออกมา ก็ถือว่าดีทีเดียว

นำ Code ส่วนนี้ไปไว้ระหว่าง TAG HEAD
<script>
function hidestatus(){
window.status=''
return true
}

if (document.layers)
document.captureEvents(Event.MOUSEOVER | Event.MOUSEOUT)

document.onmouseover=hidestatus
document.onmouseout=hidestatus
</script>

วันพฤหัสบดีที่ 15 มีนาคม พ.ศ. 2555

การใส่ comma ในช่อง textbox ที่เป็นตัวเลข


<script type="text/javaScript">
//เติม , (คอมมา)
function dokeyup( obj )
{
  var key = event.keyCode;
  if( key != 37 & key != 39 & key != 110 )
  {
    var value = obj.value;
    var svals = value.split( "." ); //แยกทศนิยมออก
    var sval = svals[0]; //ตัวเลขจำนวนเต็ม
 
    var n = 0;
    var result = "";
    var c = "";
    for ( a = sval.length - 1; a >= 0 ; a-- )
    {
      c = sval.charAt(a);
      if ( c != ',' )
      {
        n++;
        if ( n == 4 )
        {
          result = "," + result;
          n = 1;
        };
        result = c + result;
      };
    };
 
    if ( svals[1] )
    {
      result = result + '.' + svals[1];
    };
 
    obj.value = result;
  };
};

//ให้ text รับค่าเป็นตัวเลขอย่างเดียว
function checknumber()
{
  key = event.keyCode;
  if ( key != 46 & ( key < 48 || key > 57 ) )
  {
    event.returnValue = false;
  };
};
</script>

<input name="text1" type="text" value='1200' onkeyup="dokeyup(this);" onchange="dokeyup(this);" onkeypress="checknumber()" size="30" maxlength="30">

ทำให้ textbox รับค่าได้เฉพาะตัวเลข


<input type="text" name="number" onkeypress="checknumber()">

<script language="JavaScript">
function checknumber() {
  key=event.keyCode
  if (key<48 || key>57) {
    event.returnValue = false;
    alert("กรุณากรอกค่า number เป็นตัวเลขเท่านั้น !!");
    number.focus();
}
</script>

การใส่ icon ใน address bar

การใส่ ไอคอนลงใน Address Bar ของ Browser ให้ใส่โค้ดในส่วน HEAD ดังนี้

<HEAD>
  <LINK REL="SHORTCUT ICON" HREF="http://www.mydomain.com/myicon.ico" />
  <TITLE>My Title</TITLE>
</HEAD>

ถ้าวางไอคอนบน root ของระบบให้ใช้ HREF="favicon.ico" และเปลี่ยนไอคอนเป็นชื่อ favicon.ico ด้วย แต่ถ้าวางไว้ที่โฟลเดอร์อื่นหรือใช้ชื่ออื่น ให้อ้าง HREF รวม path ด้วยเช่น HREF="http://www.mydomain.com/myicon.ico"

ให้ใช้ ไอคอนขนาด 16*16 พิกเซลเท่านั้น สามารถสร้างได้จากโปรแกรมสร้าง icon ทั่วไปครับ

โค้ดจาก http://msdn.microsoft.com/library/default.asp?url=/workshop/Author/dhtml/howto/ShortcutIcon.asp

วันพุธที่ 14 มีนาคม พ.ศ. 2555

การทำ input ให้อ่านได้อย่างเดียว

ทำช่อง input ให้อ่านได้อย่างเดียว
<input name="name" type="text" size="20" maxlength="25" value='อ่านอย่างเดียว' readonly="true">

วันจันทร์ที่ 12 มีนาคม พ.ศ. 2555

ตรวจสอบเลขบัตรประจำตัวประชาชน


โค้ดตามนี้เลยครับ
<script language="javascript">

function checkID(id) {

if(id.length != 13) return false;

for(i=0, sum=0; i < 12; i++)

sum += parseFloat(id.charAt(i))*(13-i);

if((11-sum%11)%10!=parseFloat(id.charAt(12))) return false;

return true;

}

function checkForm() {

if(!checkID(document.form1.txtID.value))

alert('เลขประชาชนไม่ถูกต้อง');

}

</script>

การดึงข้อมูล แบบ real time

เป็นการดึงข้อมูลแบบ real time ซึ่งจะเป็นการกำหนดเวลาให้หน้าเวปมีการเปลี่ยนแปลงตามเวลาที่เรากำหนดโดยใช้ jquery ช่วย
โค้ด
ใช้โค้ดนี้เมื่อต้องการแสดงผล
<div id="showData"></div>
โค้ด ajax เพื่อเรียกใช้งาน

<script type="text/javascript" src="js/jquery-1.4.1.min.js"></script>
<script type="text/javascript">
$(function(){
setInterval(function(){ // เขียนฟังก์ชัน javascript ให้ทำงานทุก ๆ 30 วินาที
// 1 วินาที่ เท่า 1000
// คำสั่งที่ต้องการให้ทำงาน ทุก ๆ 3 วินาที
var getData=$.ajax({ // ใช้ ajax ด้วย jQuery ดึงข้อมูลจากฐานข้อมูล
url:"gdata.php",
data:"rev=1",
async:false,
success:function(getData){
$("div#showData").html(getData); // ส่วนที่ 3 นำข้อมูลมาแสดง
}
}).responseText;
},3000);
});
</script>
ส่วนอันนี้คือไฟล์ที่ต้องการแสดงผล

<?php  
header("Content-type:text/html; charset=UTF-8");      
header("Cache-Control: no-store, no-cache, must-revalidate");      
header("Cache-Control: post-check=0, pre-check=0", false);      
if($_GET['rev']==1){
echo date("Y-m-d H:i:s");
exit;
}
?>

การสร้างเมนูหลายภาษา

เป็นตัวอย่างง่ายๆ ในการสร้างเวป 2 ภาษาน่ะครับ
index.php ไฟล์หลักสำหรับทดสอบการแสดง

<?php
// ส่วนกำหนดสำหรับการเรียกใช้เมนูภาษา ตามที่ผู้ใช้เลือก กรณีเริ่มต้น จะเป็นภาษาอังกฤษ
$pathLang=(!isset($_COOKIE['ck_lang']) || $_COOKIE['ck_lang']=="")?"en":$_COOKIE['ck_lang'];
include($pathLang."/index.php");
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
</head>

<body>


<div style="margin:auto;width:600px;">
<br />
<a href="javascript:setLang('th');">Thai</a>
<a href="javascript:setLang('en');">Eng</a>
<br />
<br />
<br />
<a href="#"><?=_Home?></a> |
<a href="#"><?=_About_Us?></a> |
<a href="#"><?=_Contact_Us?></a>

 </div>




<script type="text/javascript">
function setLang(langID){ //ฟังก์ชัน javascript สำหรับกำหนด ตัวแปร cookie ภาษา
var days=365; // กำหนดจำนวนวันที่ต้องการให้จำค่า
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
document.cookie = "ck_lang=" +langID+ "; expires=" + expires + "; path=/";
window.location.reload()
}
</script>

</body>
</html>

อันนี้หน้าเวปภาษาอังกฤษ

<?php
define("_Home","Home");
define("_About_Us","About Us");
define("_Contact_Us","Contact Us");
?>

อันนี้หน้าเวปภาษาไทย

<?php
define("_Home","หน้าแรก");
define("_About_Us","เกี่ยวกับเรา");
define("_Contact_Us","ติดต่อเรา");
?>




วันศุกร์ที่ 9 มีนาคม พ.ศ. 2555

การแสดงข้อมูลให้เห็นในหน้าจอ แต่ไม่เห็นตอนสั่งพิมพ์

หากเราต้องการแสดงข้อมูลให้เห็นเฉพาะในหน้าจออย่างเดียว แต่เวลาสั่งพิมพ์งานไม่ต้องการให้พิมพ์ออกมา สามารถแก้ปัญหาได้โดย
โค้ด

<STYLE type=text/css>

#printable { display: block; }

@media print
{
     #non-printable { display: none; }
     #printable { display: block; }
}

</STYLE>


<DIV id=non-printable>
     <CENTER><FONT color=red><B>สิ่งที่จะให้แสดงออกมาทางหน้าจอ แต่ว่าไม่เห็นเวลา Print หน้านี้ออกมา</B></FONT></CENTER>
</DIV>
<BR>
<DIV id=printable>
     <CENTER><FONT color=blue><B>สิ่งที่จะให้แสดงออกมาทางหน้าจอ และจะเห็นเวลา Print หน้านี้ออกมาด้วย</B></FONT></CENTER>
</DIV>

ซ่อนหรือแสดงข้อมูลในตาราง

เป็นโค้ดที่ใช้ซ่อนหรือแสดงข้อมูลในตาราง โดยคลิกเลือกที่ checkbox
โค้ด

<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-874" />
<title>Untitled Document</title>
</head>

<body>

<table width="100%" border="1" cellpadding="1" cellspacing="1">
<tr>
<td width="14%" valign="top"><input name="cb1" type="checkbox" id="cb1" onClick="if(this.checked){document.all.tb1.style.display='none';}else{document.all.tb1.style.display='';}" value="1"></td>
<td width="86%">
<table width="100%" border="1" cellpadding="1" cellspacing="1" id="tb1" style="display='none';">
<tr>
<td>XXXX</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>XXXX</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>XXXX</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</table>
  </td>
</tr>
<tr>
<td valign="top"><input name="cb2" type="checkbox" id="cb2" value="2" onClick="if(this.checked){document.all.tb2.style.display='none';}else{document.all.tb2.style.display='';}"></td>
<td><table width="100%" border="1" cellpadding="1" cellspacing="1" id="tb2" style="display='none';">
<tr>
<td width="19%">XXXX</td>
<td width="81%"><input type="text" name="textfield4"></td>
</tr>
<tr>
<td>XXXX</td>
<td><input type="text" name="textfield5"></td>
</tr>
<tr>
<td>XXXX</td>
<td><input type="text" name="textfield6"></td>
</tr>
</table>
&nbsp; </td>
</tr>
</table>
</form>

</body>
</html>

การแสดงและซ่อนข้อความ

สามารถเลือกที่จะแสดง หรือซ่อนข้อความได้โดยการคลิกเลือกที่ checkbox
โค้ด

<html>

<body>
<form action="page.cgi" method="post" name="form1" onSubmit="JavaScript:return fncSubmit();">
<input name="txt1" type="text" id="txt1" value="Value">
<input name="rdo1" type="radio" value="Y" checked onClick="javaScript:if(this.checked){document.all.txt1.style.display='';}">
Show
<input name="rdo1" type="radio" value="N" onClick="javaScript:if(this.checked){document.all.txt1.style.display='none';}">
Hide
<br>
<br>
<input name="chk1" type="checkbox" id="chk1" value="Y" checked>
Checkbox
<input name="rdo2" type="radio" value="Y" checked onClick="javaScript:if(this.checked){document.all.chk1.style.display='';}">
Show
<input name="rdo2" type="radio" value="N" onClick="javaScript:if(this.checked){document.all.chk1.style.display='none';}">
Hide<br>
<br>
<table width="196"  border="1" id="tbName">
  <tr>
    <td>&nbsp;</td>
    </tr>
</table>
<input name="rdo3" type="radio" value="Y" checked onClick="javaScript:if(this.checked){document.all.tbName.style.display='';}">
Show
<input name="rdo3" type="radio" value="N" onClick="javaScript:if(this.checked){document.all.tbName.style.display='none';}">
Hide<br>
<br>
<span id="spName">Text</span>
<input name="rdo4" type="radio" value="Y" checked onClick="javaScript:if(this.checked){document.all.spName.style.display='';}">
Show
<input name="rdo4" type="radio" value="N" onClick="javaScript:if(this.checked){document.all.spName.style.display='none';}">
Hide<br>
<br>
<input name="btnSubmit" type="submit" value="Submit" onClick="JavaScript:this.disabled=true;">
</form>
</body>
</html>

การตรึงแนวหัว และคอลัมภ์ของตาราง

เป็นโค้ดสำหรับการตรึงแนวห้วตาราง และคอลัมภ์พร้อม ๆ กันทำให้การดูข้อมูลในตารางดูได้ง่ายขึ้นลองทำดูนะครับ
โค้ด

<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-874" />
<title>Untitled Document</title>
<style type="text/css">

.tableBoxOuter {
width:100%;height:90%; // adjust size of table
background: #FFFFFF;
}

.scrolltable td, th {
font-size: 12px;
margin:0em;
padding-top: 4px;
padding-bottom: 4px;
padding-right: 4px;
padding-left: 4px;
table-layout: automatic;
white-space: nowrap;
}

</style>

<script type="text/javascript">
/* Copyright Richard Cornford 2004 */
var finalizeMe = (function(){
var global = this,base,safe = false,svType = (global.addEventListener && 2)||(global.attachEvent && 3)|| 0;
function addFnc(next, f){function t(ev){if(next)next(ev);f(ev);};t.addItem = function(d){if(f != d.getFunc()){if(next){next.addItem(d);}else{next = d;}}return this;};t.remove = function(d){if(f == d){f = null;return next;}else if(next){next = next.remove(d);}return this;};t.getFunc = function(){return f;};t.finalize = function(){if(next)next = next.finalize();return (f = null);};return t;};
function addFunction(f){if(base){base = base.addItem(addFnc(null, f));}else{base = addFnc(null, f);}};
function ulQue(f){addFunction(f);if(!safe){switch(svType){case 2:global.addEventListener("unload", base, false);safe = true;break;case 3:global.attachEvent("onunload", base);safe = true;break;default:if(global.onunload != base){if(global.onunload)addFunction(global.onunload);global.onunload = base;}break;}}};
ulQue.remove = function(f){if(base)base.remove(f);};
function finalize(){if(base){base.finalize();switch(svType){case 3:global.detachEvent("onunload", base);break;case 2:global.removeEventListener("unload", base, false);break;default:global.onunload = null;break;}base = null;}safe = false;};
ulQue(finalize);return ulQue;
})();


var InitializeMe = (function(){
var global = this,base = null,safe = false;
var listenerType = (global.addEventListener && 2)||(global.attachEvent && 3)|| 0;
function getStackFunc(next, funcRef, arg1,arg2,arg3,arg4){function l(ev){funcRef((ev?ev:global.event), arg1,arg2,arg3,arg4);if(next)next = next(ev);return (funcRef = null);};l.addItem = function(d){if(next){next.addItem(d);}else{next = d;}};return l;};
return (function(funcRef, arg1,arg2,arg3,arg4){if(base){base.addItem(getStackFunc(null, funcRef, arg1,arg2,arg3,arg4));}else{base = getStackFunc(null, funcRef, arg1,arg2,arg3,arg4);}if(!safe){switch(listenerType){case 2:global.addEventListener("load", base, false);safe = true;break;case 3:global.attachEvent("onload", base);safe = true;break;default:if(global.onload != base){if(global.onload){base.addItem(getStackFunc(null, global.onload));}global.onload = base;}break;}}});
})();
var queryStrings = (function(out){
    if(typeof location != 'undefined'){
        var temp = location.search||location.href||'';
        var nvp, ofSet;
        if((ofSet = temp.indexOf('?')) > -1){
            temp = temp.split("#")[0];
            temp = temp.substring((ofSet+1), temp.length);
            var workAr = temp.split('&');
            for(var c = workAr.length;c--;){
                nvp = workAr[c].split('=');
                if(nvp.length > 1){out[nvp[0]] = nvp[1];}
            }
        }
    }
    return out;
})({});

var TimedQue = (function(){
var base, timer;
var interval = 60;
var newFncs = null;
function addFnc(next, f){function t(){next = next&&next();if(f()){return t;}else{f = null;return next;}}t.addItem = function(d){if(next){next.addItem(d);}else{next = d;}return this;};t.finalize = function(){return ((next)&&(next = next.finalize())||(f = null));};return t;}
function tmQue(fc){if(newFncs){newFncs = newFncs.addItem(addFnc(null, fc));}else{newFncs = addFnc(null, fc);}if(!timer){timer = setTimeout(tmQue.act, interval);}}
tmQue.act = function(){var fn = newFncs, strt = new Date().getTime();if(fn){newFncs = null;if(base){base.addItem(fn);}else{base = fn;}}base = base&&base();if(base||newFncs){var t = interval - (new Date().getTime() - strt);timer = setTimeout(tmQue.act, ((t > 0)?t:1));}else{timer = null;}};
tmQue.act.toString = function(){return 'TimedQue.act()';};
tmQue.finalize = function(){timer = timer&&clearTimeout(timer);base = base&&base.finalize();newFncs = null;};
return tmQue;
})();

var getElementWithId = (function(){if(document.getElementById){return (function(id){return document.getElementById(id);});}else if(document.all){return (function(id){return document.all[id];});}return (function(id){return null;});})();

function getSimpleExtPxIn(el){
var temp, temp2, tick = 0, getBorders = retFalse, doCompStyle = retFalse,defaultView,objList = [];
function retFalse(){return false;}
retFalse.elTest = retFalse;
retFalse.iY = retFalse.iX = retFalse.y = retFalse.x = retFalse.w = retFalse.h = retFalse.bb = retFalse.bt = retFalse.bl = retFalse.br = 0;
function retThis(){return retThis;}
function gCompStyleBorders(p, el){doCompStyle(p, defaultView.getComputedStyle(el, '' ));}
function doComputedStyleFloat(p, cs){p.bt = (cs.getPropertyCSSValue('border-top-width').getFloatValue(5));p.bl = (cs.getPropertyCSSValue('border-left-width').getFloatValue(5));p.br = (cs.getPropertyCSSValue('border-right-width').getFloatValue(5));p.bb = (cs.getPropertyCSSValue('border-bottom-width').getFloatValue(5));}
function doComputedStyleValue(p, cs){p.bt = Math.ceil(parseFloat(s.getPropertyValue('border-top-width')))|0;p.bl = Math.ceil(parseFloat(s.getPropertyValue('border-left-width')))|0;p.br = Math.ceil(parseFloat(s.getPropertyValue('border-right-width')))|0;p.bb = Math.ceil(parseFloat(s.getPropertyValue('border-bottom-width')))|0;}
function gClientBorders(p, el){if(el.clientWidth||el.clientHeight){p.bb = (el.offsetHeight - (el.clientHeight + (p.bt = el.clientTop|0)))|0;p.br = (el.offsetWidth - (el.clientWidth + (p.bl = el.clientLeft|0)))|0;}}
function getInterfaceObj(el){var lastTick = NaN;var offsetParent = getSimpleExtPxInFn(el.offsetParent)||retFalse;function p(doTick){if(doTick){tick = (1+tick)%0xEFFFFFFF;}if(tick != lastTick){lastTick = tick;offsetParent();getBorders(p, el);p.iY = (p.y = (offsetParent.iY + (el.offsetTop|0))) + p.bt;p.iX = (p.x = (offsetParent.iX + (el.offsetLeft|0))) + p.bl;p.w = el.offsetWidth|0;p.h = el.offsetHeight|0;}return p;}p.elTest = function(elmnt){return (elmnt == el);};p.iY = p.iX = p.w = p.h = p.y = p.x = p.bb = p.bt = p.bl = p.br = 0;return (objList[objList.length] = p);}
function getSimpleExtPxInFn(el){if((!el)||(el == document)){return retFalse;}for(var c = objList.length;c--;){if(objList[c].elTest(el)){return objList[c];}}return getInterfaceObj(el);}
function setSpecialObj(el){var lastTick = NaN;function p(doTick){if(doTick){tick = (1+tick)%0xEFFFFFFF;}return p;}p.elTest = function(elmnt){return (elmnt == el);};p.iY = p.iX = p.w = p.h = p.y = p.x = p.bb = p.bt = p.bl = p.br = 0;objList[objList.length] = p;}
if((typeof el.offsetParent != 'undefined')&&(typeof el.offsetTop == 'number')&&(typeof el.offsetWidth == 'number')){if((typeof el.clientTop == 'number')&&(typeof el.clientWidth == 'number')){getBorders = gClientBorders;}else if((defaultView = document.defaultView)&&defaultView.getComputedStyle &&(temp = defaultView.getComputedStyle(el, '' ))&&(((temp.getPropertyCSSValue)&&(temp2 = temp.getPropertyCSSValue('border-top-width'))&&(temp2.getFloatValue)&&(doCompStyle = doComputedStyleFloat))||((temp.getPropertyValue)&&(doCompStyle = doComputedStyleValue)))){getBorders = gCompStyleBorders;temp2 = temp = null;}if(document.documentElement){setSpecialObj(document.documentElement);}if(document.body){setSpecialObj(document.body);}return (getSimpleExtPxIn = getSimpleExtPxInFn)(el);}else{retThis.elTest = retFalse;retThis.iY = retThis.iX = retThis.y = retThis.x = retThis.w = retThis.h = retThis.bb = retThis.bt = retThis.bl = retThis.br = NaN;return (getSimpleExtPxIn = retThis);}
}

function getNewFILCFncStac(fnc){function getNewFnc(f){var next = null;function t(a){next = next&&next(a);return (f(a))?t:next;}t.finalize = function(){next = next&&next.finalize();return (f = null);};t.addItem = function(d){if(f != d){if(next){next.addItem(d);}else{next = getNewFnc(d);}}return this;};return t;}var base = getNewFnc(fnc);fnc = function(a){base = base&&base(a);};fnc.addItem = function(d){if(base){base.addItem(d)}else{base = getNewFnc(d);}};fnc.finalize = function(){return (base = base&&base.finalize());};return fnc;}

function GlobalEventMonitor(eventName, functinRef){
var finalize, global = this;
var monitors = {};
var onName = ['on',''];
function mainMonitor(eventName, functinRef){
var monitor = monitors[eventName];
if(monitor){
monitor(functinRef);
}else{
setEventMonitor(eventName, functinRef);
}
}
function setListener(eventName, longName, fncStack){
global.addEventListener(eventName, fncStack, false);
return true;
}
function setListener_aE(eventName, longName, fncStack){
global.attachEvent(longName, fncStack);
return true;
}
function oldHandler(f){return (function(e){f(e);return true;});}
function retFalse(){return false;}
function setEventMonitor(eventName, functinRef){
var fncStack, longName;
onName[1] = eventName;
longName = onName.join('');
function main(funcRef){
if(funcRef){
fncStack.addItem(funcRef);
globalCheck();
}
}
function globalCheck(){
if(global[longName] != fncStack){
if(global[longName]){
fncStack.addItem(oldHandler(global[longName]));
}
global[longName] = fncStack;
}
}
fncStack = getNewFILCFncStac(functinRef);
if(setListener(eventName, longName, fncStack)){
globalCheck = retFalse;
}else{
globalCheck();
}
finalize.addItem(fncStack.finalize);
monitors[eventName] = main;
functinRef = null;
}
if(!global.addEventListener){
if(global.attachEvent){
setListener = setListener_aE;
}else{
setListener = retFalse;
}
}
finalizeMe((finalize = getNewFILCFncStac(
function(){
finalize = monitors = null;
})
));
(GlobalEventMonitor = mainMonitor)(eventName, functinRef);
functinRef = null;
}

var tableScroll = (function(){
var global = this, finalise, tableList = {};
var notOnScroll = true, notAbort = true;
var overrideStyles = {
margin:[{keys:['margin','marginBottom','marginLeft','marginRight','marginTop'],value:'0px'}],
padding:[{keys:['padding','paddingBottom','paddingLeft','paddingRight','paddingTop'],value:'0px'}],
border:[
{keys:['border','borderBottom','borderLeft','borderRight','borderTop'],value:'0px none #FFFFFF'},
{keys:['borderWidth','borderLeftWidth','borderRightWidth','borderBottomWidth','borderTopWidth'],value:'0px'},
{keys:['borderStyle','borderRightStyle','borderLeftStyle','borderBottomStyle','borderTopStyle'],value:'none'}
],
overflow:[{keys:['overflow'],value:'hidden'}],
positionRel:[{keys:['position'],value:'relative'}],
positionAbs:[{keys:['position'],value:'absolute'}],
top:[{keys:['top'],value:'0px'}],
left:[{keys:['left'],value:'0px'}],
zIndex:[{keys:['zIndex'],value:2}]
};
function setStyleProps(styleObj){
var data, dArray;
for(var c = 1;c < arguments.length;c++){
if((data = overrideStyles[arguments[c]])){
for(var d = data.length;d--;){
dArray = data[d].keys;
for(var e = dArray.length;e--;){
styleObj[dArray[e]] = data[d].value;
}
}
}
}
return true;
}
function setClass(el,val){
if(el.setAttribute){el.setAttribute('class',val);}
return (el.className = val);
}
function retFalse(){return false;}
function TableScroll(id){
var midAbsDiv, parent, vHeaderAbsStyle, vHeaderRelStyle, hHeaderAbsStyle, hHeaderRelStyle;
var midAbsDivStyle, midAbsinerDivStyle, inRelDivStyle, outRelDivDim;
var lastScrollTop = NaN, lastScrollLeft = NaN, lastWidth = NaN, lastHeight = NaN, tableDim, table = getElementWithId(id);
var midRelinerDivStyle, midRelinerDiv, testCellDim;
function position(){
var nh,nw,size,th,tw,cellWidth,celHeight,st = midAbsDiv.scrollTop, sl = midAbsDiv.scrollLeft, h = outRelDivDim(true).h, w = outRelDivDim.w;
if((size = ((w != lastWidth)||(h != lastHeight)))||(st != lastScrollTop)||(sl != lastScrollLeft)){
hHeaderRelStyle.left = (((cellWidth = (testCellDim().x - tableDim().iX)) + (lastScrollLeft = sl)) * -1)+'px';//position
vHeaderRelStyle.top = (((celHeight = (testCellDim.y - tableDim.iY)) + (lastScrollTop = st)) * -1)+'px';
if(size){
vHeaderRelStyle.width = vHeaderAbsStyle.width = midAbsDivStyle.left = hHeaderAbsStyle.left = (cellWidth+'px');
hHeaderRelStyle.height = hHeaderAbsStyle.height = midAbsDivStyle.top = vHeaderAbsStyle.top = (celHeight+'px');
inRelDivStyle.left = (cellWidth * -1)+'px';
inRelDivStyle.top = (celHeight * -1)+'px';
midRelinerDivStyle.width = midAbsinerDivStyle.width = ((tw = tableDim.w) - cellWidth)+'px';
midRelinerDivStyle.height = midAbsinerDivStyle.height = ((th = tableDim.h) - celHeight)+'px';
midAbsDivStyle.height = vHeaderAbsStyle.height = (((nh = ((lastHeight = h) - celHeight)) > celHeight)?nh:celHeight)+'px';
midAbsDivStyle.width = hHeaderAbsStyle.width = (((nw = ((lastWidth = w) - cellWidth)) > cellWidth)?nw:cellWidth)+'px';
hHeaderRelStyle.width = inRelDivStyle.width = tw + 'px';
vHeaderRelStyle.height = inRelDivStyle.height = th + 'px';
}
}
return notOnScroll;
}
function onScroll(){
notOnScroll = false;
position();
}
function onSize(){
position();
return true;
}
finalise.addItem(function(){
testCellDim = midRelinerDivStyle = midRelinerDiv =
midAbsinerDivStyle =  tableDim = vHeaderAbsStyle = vHeaderRelStyle = hHeaderAbsStyle = hHeaderRelStyle = inRelDivStyle = outRelDivDim = midAbsDiv = parent = table = null;
})
if(
table&&
(typeof table.scrollTop == 'number')&&
(typeof table.offsetHeight == 'number')&&
table.tagName&&
table.appendChild&&
table.cloneNode&&
table.getAttribute&&
table.getElementsByTagName&&
(parent = table.parentNode)&&
parent.insertBefore
  ){
InitializeMe(function(){
var newTable, testCell;
var vHeaderAbs, vHeaderRel, hHeaderAbs, hHeaderRel,outRelDiv, midAbsinerDiv, inRelDiv;
if(
(notAbort)&&
(testCell = table.getElementsByTagName('td')[0])&&
(newTable = table.cloneNode(true))&&
(outRelDiv = document.createElement('DIV'))&&
(setClass(outRelDiv, 'tableBoxOuter'))&&
(midAbsDiv = document.createElement('DIV'))&&
(midRelinerDiv = document.createElement('DIV'))&&
(midAbsinerDiv = document.createElement('DIV'))&&
(inRelDiv = document.createElement('DIV'))&&
(vHeaderAbs = document.createElement('DIV'))&&
(vHeaderRel = document.createElement('DIV'))&&
(hHeaderAbs = document.createElement('DIV'))&&
(hHeaderRel = document.createElement('DIV'))&&
(setStyleProps(outRelDiv.style, 'positionRel', 'padding'))&&
(midAbsDivStyle = midAbsDiv.style)&&
(setStyleProps(midAbsDivStyle, 'positionAbs', 'padding', 'margin', 'border', 'zIndex'))&&
(midRelinerDivStyle = midRelinerDiv.style)&&
(setStyleProps(midRelinerDivStyle, 'positionRel', 'padding', 'margin', 'border', 'top', 'left'))&&
(midAbsinerDivStyle = midAbsinerDiv.style)&&
(setStyleProps(midAbsinerDivStyle, 'positionAbs', 'overflow', 'padding', 'margin', 'border', 'top', 'left'))&&
(inRelDivStyle = inRelDiv.style)&&
(setStyleProps(inRelDivStyle, 'positionRel', 'padding', 'margin', 'border', 'top', 'left'))&&
(vHeaderAbsStyle = vHeaderAbs.style)&&
(setStyleProps(vHeaderAbsStyle, 'positionAbs', 'overflow', 'padding', 'margin', 'border', 'top', 'left', 'zIndex'))&&
(vHeaderRelStyle = vHeaderRel.style)&&
(setStyleProps(vHeaderRelStyle, 'positionRel', 'padding', 'margin', 'border', 'top', 'left'))&&
(hHeaderAbsStyle = hHeaderAbs.style)&&
(setStyleProps(hHeaderAbsStyle, 'positionAbs', 'overflow', 'padding', 'margin', 'border', 'top', 'left', 'zIndex'))&&
(hHeaderRelStyle = hHeaderRel.style)&&
(setStyleProps(hHeaderRelStyle, 'positionRel', 'padding', 'margin', 'border', 'top', 'left'))&&
(setStyleProps(table.style, 'margin'))&&
(midAbsDiv.appendChild(midRelinerDiv))&&
(midRelinerDiv.appendChild(midAbsinerDiv))&&
(midAbsinerDiv.appendChild(inRelDiv))&&
(outRelDiv.appendChild(midAbsDiv))&&
(vHeaderAbs.appendChild(vHeaderRel))&&
(hHeaderAbs.appendChild(hHeaderRel))&&
(outRelDiv.appendChild(vHeaderAbs))&&
(outRelDiv.appendChild(hHeaderAbs))&&
(parent.insertBefore(outRelDiv, table))&&
(!isNaN((outRelDivDim = getSimpleExtPxIn(outRelDiv)).w))&&
(inRelDiv.appendChild(table))&&
(!isNaN((testCellDim = getSimpleExtPxIn(testCell)).w))&&
(!isNaN((tableDim = getSimpleExtPxIn(table)).w))&&
(hHeaderRel.appendChild(newTable))&&
(newTable = table.cloneNode(true))&&
(vHeaderRel.appendChild(newTable))
  ){
midAbsDivStyle.overflow = 'scroll';
if(midAbsDiv.addEventListener){
midAbsDiv.addEventListener('scroll', onScroll, false);
}else if(midAbsDiv.attachEvent){
midAbsDiv.attachEvent('onscroll', onScroll);
}else{
midAbsDiv.onscroll = onScroll;
}
GlobalEventMonitor('resize', onSize);
position();
TimedQue(position);
}else{
notAbort = false;
}
});
}else{
notAbort = false;
}
return true;
}
function main(){
var id;
for(var c = 0;c < arguments.length;c++){
id = arguments[c];
if(notAbort&&!tableList[id]){
tableList[id] = TableScroll(id);
}
}
}
if(
(!global.queryStrings||!queryStrings['noTableScroll'])&&
global.setTimeout&&
global.document&&
document.createElement
){
finalizeMe((finalise = getNewFILCFncStac(function(){
finalise = tableList = null;
})));
return main;
}else{
return retFalse;
}
})();
</script>
</head>

<body>
<table class=scrolltable id=mainTable width="100%" border="1" cellspacing="1" cellpadding="2">
  <thead><tr>
    <th rowspan="2">a</th>
    <th colspan="3">b</th>
    <th colspan="2">f</th>
    <th rowspan="2">i</th>
  </tr>
  <tr>
    <th>c</th>
    <th>d</th>
    <th>e</th>
    <th>g</th>
    <th>h</th>
  </tr></thead>
  <tr>
    <th>1</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>2</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>3</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>4</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>5</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>6</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>7</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>8</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>9</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>10</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>11</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>12</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>13</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>14</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>15</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>16</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>17</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>18</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>19</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>20</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>21</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>22</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>23</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>24</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>25</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>26</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>27</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>28</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>29</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>30</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>31</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>32</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>33</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>34</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>35</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>36</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th><p>37</p>    </th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>38</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>39</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>40</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>41</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>42</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>43</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>44</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>45</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>46</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>47</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
  <tr>
    <th>48</th>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
    <td>&nbsp;</td>
  </tr>
</table>
</body>
</html>
<script type="text/javascript">
if(typeof tableScroll == 'function'){tableScroll('mainTable');}
</script>

ตรวจสอบค่าที่กรอกใน textbox

เป็นตัวอย่างในการตรวจสอบค่าที่กรอกใน textbox ว่าตรงกับที่เรากำหนดหรือไม่ ลองนำไปประยุกต์ใช้กันนะ
โค้ด

<script type="text/javascript">
function checkform()
{
submitResult = false;

eUsername = document.getElementById('txtUsername');
ePassword = document.getElementById('txtPassword');
eConfirm = document.getElementById('txtConfirm');
select7 = document.getElementById('select7');
textfield = document.getElementById('textfield');
eEmail = document.getElementById('txtEmail');
date = document.getElementById('date');
desline = document.getElementById('desline');
// toline = document.getElementById('toline');
// select2 = document.getElementById('select2');
// select3 = document.getElementById('select3');
select4 = document.getElementById('select4');
select6 = document.getElementById('select6');
ePhone = document.getElementById('txtPhone');
textfield2 = document.getElementById('textfield2');

if((eUsername.value != '') && (ePassword.value != ''))
{
submitResult = true;

if(submitResult && (eUsername.value.length < 6))
{
submitResult = false;
alert('กรุณากรอก Username อย่างน้อย 6 หลัก');
}
if(submitResult && !eUsername.value.match(/^[\wก-ฮะ-์]+$/))
{
submitResult = false;
alert('กรุณากรอก Username ด้วยตัวเลขหรือตัวอักษรเท่านั้น\nไม่มีการเว้นวรรค และใช้เครื่องหมายใดๆ');
}
if(submitResult && !ePassword.value.match(/^[\wก-ฮะ-์]+$/))
{
submitResult = false;
alert('กรุณากรอก Password ด้วยตัวเลขหรือตัวอักษรเท่านั้น\nไม่มีการเว้นวรรค และใช้เครื่องหมายใดๆ');
}
if(submitResult && (ePassword.value != eConfirm.value))
{
submitResult = false;
alert('กรุณายืนยัน Password ให้ถูกต้องตรงกัน');
}

if(submitResult && (select7.value == ""))
{
submitResult = false;
alert('กรุณาระบุรุ่นรถยนต์ที่ต้องการทดลองขับ');
}
if(submitResult && (textfield.value == ""))
{
submitResult = false;
alert('กรุณาระบุชื่อ และนามสกุล');
}
if(submitResult && (textfield2.value == ""))
{
submitResult = false;
alert('กรุณาระบุเบอร์โทรศัพท์');
}
if(submitResult && (date.value == "" ))
{
submitResult = false;
alert('กรุณาระบุวันที่');
}
if(submitResult && (date.value == desline.value))
{
submitResult = false;
alert('กรุณาเลือกจองล่วงหน้า1วัน หรือมากว่านั้น แต่ไม่เกิน 2 เดือน');
}
//if(submitResult && (date.value < toline.value))
// {
// submitResult = false;
// alert('ระยะการจองต้องไม่เกิน 2 เดือน');
// }

// if(submitResult && (select2.value == ""))
// {
// submitResult = false;
// alert('กรุณาระบุเดือน');
// }
// if(submitResult && (select3.value == ""))
// {
// submitResult = false;
// alert('กรุณาระบุปี');
//}
if(submitResult && (select4.value == ""))
{
submitResult = false;
alert('กรุณาระบุเวลาที่ต้องการทดลองขับ');
}
if(submitResult && (select6.value == ""))
{
submitResult = false;
alert('กรุณาระบุพื้นที่ต้องการทดลองขับ');
}
if(submitResult && (eEmail.value.length == 0) && (ePhone.value.length == 0) && (textfield2.value.length == 0))
{
submitResult = false;
alert('กรุณากรอก E-mail หรือ กรอกเบอร์โทรศัพท์ในกรณีที่ไม่มี E-mail ');
}
if(submitResult && (textfield2.value.length > 0) && (textfield2.value.length < 10))
{
submitResult = false;
alert('กรุณากรอกเบอร์โทรศัพท์มือถือให้ครบ 10 หลัก');
}
if(submitResult && (textfield2.value.substring(0,2) != "08"))
{
submitResult = false;
alert('เบอร์โทรศัพท์ของคุณรูปแบบไม่ถูกต้อง กรุณาขึ้นต้นด้วย "08" เช่น 081 หรือ 0812345678');
}
if(submitResult && (eEmail.value.length > 0) && !eEmail.value.match(/^[\w][\w\-\.]*\@[\w][\w\-]*(\.[\w][\w\-]*)+([\s,]+[\w][\w\-\.]*\@[\w][\w\-]*(\.[\w][\w\-]*)+)?$/))
{
submitResult = false;
alert('กรุณากรอก Email ให้ถูกต้อง');
}
if(submitResult && (eEmail.value.length > 0) && eEmail.value.match(/@example\.com/))
{
submitResult = false;
alert('e-mail ที่ท่านแจ้งไม่ถูกต้อง\nเนื่องจาก @example.com เป็น e-mail ตัวอย่าง ไม่มีอยู่จริง\nหากท่านไม่มี e-mail ไม่จำเป็นต้องกรอกข้อความในส่วนนี้');
}
if(submitResult && (eEmail.value.length > 0) && eEmail.value.match(/@example\.co.th/))
{
submitResult = false;
alert('e-mail ที่ท่านแจ้งไม่ถูกต้อง\nเนื่องจาก @example.co.th เป็น e-mail ตัวอย่าง\nหากท่านไม่มี e-mail ไม่จำเป็นต้องกรอกข้อความในส่วนนี้');
}
if(submitResult && (eEmail.value.length > 0) && eEmail.value.match(/^www/))
{
if(!confirm('โดยปรกติ E-mail จะไม่นำหน้าด้วย www\nยืนยัน E-mail "' + eEmail.value + '" หรือไม่?'))
submitResult = false;
}
}
else
{
alert('กรุณากรอก Username และ Password');
}

/*if(submitResult)
{
alert('ผ่านการตรวจสอบ');
submitResult = false;
}*/

return submitResult;
}

</script>

วันพฤหัสบดีที่ 8 มีนาคม พ.ศ. 2555

การทำตารางให้สามารถเรียงลำดับได้ โดยคลิกที่ชื่อหัวตาราง
โค้ด

<head>
<script src="sorttable.js"></script>
</head>
<body>
<table border="1" class="sortable">
<thead>
<tr><th>Person</th><th>Monthly pay</th></tr>
</thead>
<tbody>
<tr><td>Jan Molby</td>
<td>10</td>
</tr>
<tr><td>Steve Nicol</td>
<td>20</td>
</tr>
<tr><td>Steve McMahon</td>
<td>30</td>
</tr>
<tr><td>John Barnes</td>
<td>40</td>
</tr>
</tbody>
<tfoot>
<tr><td>TOTAL</td>
<td>100</td>
</tr>
</tfoot>
</table>
</body>

อันนี้ไฟล์ sorttable.js
/*
  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
  Add class="sortable" to any table you'd like to make sortable
  Click on the headers to sort
  
  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;

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;
    // kill the timer
    if (_timer) clearInterval(_timer);
    
    if (!document.createElement || !document.getElementsByTagName) return;
    
    sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;
    
    forEach(document.getElementsByTagName('table'), function(table) {
      if (table.className.search(/\bsortable\b/) != -1) {
        sorttable.makeSortable(table);
      }
    });
    
  },
  
  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[i].className.search(/\bsortbottom\b/) != -1) {
        sortbottomrows[sortbottomrows.length] = table.rows[i];
      }
    }
    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[i]);
      }
      delete sortbottomrows;
    }
    
    // work through each column and calculate its type
    headrow = table.tHead.rows[0].cells;
    for (var i=0; i<headrow.length; i++) {
      // manually override the type with a sorttable_type attribute
      if (!headrow[i].className.match(/\bsorttable_nosort\b/)) { // skip this col
        mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
        if (mtch) { override = mtch[1]; }
     if (mtch && typeof sorttable["sort_"+override] == 'function') {
       headrow[i].sorttable_sortfunction = sorttable["sort_"+override];
     } else {
       headrow[i].sorttable_sortfunction = sorttable.guessType(table,i);
     }
     // make it clickable to sort
     headrow[i].sorttable_columnindex = i;
     headrow[i].sorttable_tbody = table.tBodies[0];
     dean_addEvent(headrow[i],"click", function(e) {

          if (this.className.search(/\bsorttable_sorted\b/) != -1) {
            // if we're already sorted by this column, just 
            // reverse the table, which is quicker
            sorttable.reverse(this.sorttable_tbody);
            this.className = this.className.replace('sorttable_sorted',
                                                    'sorttable_sorted_reverse');
            this.removeChild(document.getElementById('sorttable_sortfwdind'));
            sortrevind = document.createElement('span');
            sortrevind.id = "sorttable_sortrevind";
            sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;';
            this.appendChild(sortrevind);
            return;
          }
          if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
            // if we're already sorted by this column in reverse, just 
            // re-reverse the table, which is quicker
            sorttable.reverse(this.sorttable_tbody);
            this.className = this.className.replace('sorttable_sorted_reverse',
                                                    'sorttable_sorted');
            this.removeChild(document.getElementById('sorttable_sortrevind'));
            sortfwdind = document.createElement('span');
            sortfwdind.id = "sorttable_sortfwdind";
            sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
            this.appendChild(sortfwdind);
            return;
          }
          
          // remove sorttable_sorted classes
          theadrow = this.parentNode;
          forEach(theadrow.childNodes, function(cell) {
            if (cell.nodeType == 1) { // an element
              cell.className = cell.className.replace('sorttable_sorted_reverse','');
              cell.className = cell.className.replace('sorttable_sorted','');
            }
          });
          sortfwdind = document.getElementById('sorttable_sortfwdind');
          if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
          sortrevind = document.getElementById('sorttable_sortrevind');
          if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
          
          this.className += ' sorttable_sorted';
          sortfwdind = document.createElement('span');
          sortfwdind.id = "sorttable_sortfwdind";
          sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25BE;';
          this.appendChild(sortfwdind);

       // build an array to sort. This is a Schwartzian transform thing,
       // i.e., we "decorate" each row with the actual sort key,
       // sort based on the sort keys, and then put the rows back in order
       // which is a lot faster because you only do getInnerText once per row
       row_array = [];
       col = this.sorttable_columnindex;
       rows = this.sorttable_tbody.rows;
       for (var j=0; j<rows.length; j++) {
         row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]];
       }
       /* If you want a stable sort, uncomment the following line */
       //sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
       /* and comment out this one */
       row_array.sort(this.sorttable_sortfunction);
       
       tb = this.sorttable_tbody;
       for (var j=0; j<row_array.length; j++) {
         tb.appendChild(row_array[j][1]);
       }
       
       delete row_array;
     });
   }
    }
  },
  
  guessType: function(table, column) {
    // guess the type of a column based on its first non-blank row
    sortfn = sorttable.sort_alpha;
    for (var i=0; i<table.tBodies[0].rows.length; i++) {
      text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
      if (text != '') {
        if (text.match(/^-?[ฃ$ค]?[\d,.]+%?$/)) {
          return sorttable.sort_numeric;
        }
        // check for a date: dd/mm/yyyy or dd/mm/yy 
        // can have / or . or - as separator
        // can be mm/dd as well
        possdate = text.match(sorttable.DATE_RE)
        if (possdate) {
          // looks like a date
          first = parseInt(possdate[1]);
          second = parseInt(possdate[2]);
          if (first > 12) {
            // definitely dd/mm
            return sorttable.sort_ddmm;
          } else if (second > 12) {
            return sorttable.sort_mmdd;
          } else {
            // looks like a date, but we can't tell which, so assume
            // that it's dd/mm (English imperialism!) and keep looking
            sortfn = sorttable.sort_ddmm;
          }
        }
      }
    }
    return sortfn;
  },
  
  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.
    
    hasInputs = (typeof node.getElementsByTagName == 'function') &&
                 node.getElementsByTagName('input').length;
    
    if (node.getAttribute("sorttable_customkey") != null) {
      return node.getAttribute("sorttable_customkey");
    }
    else if (typeof node.textContent != 'undefined' && !hasInputs) {
      return node.textContent.replace(/^\s+|\s+$/g, '');
    }
    else if (typeof node.innerText != 'undefined' && !hasInputs) {
      return node.innerText.replace(/^\s+|\s+$/g, '');
    }
    else if (typeof node.text != 'undefined' && !hasInputs) {
      return node.text.replace(/^\s+|\s+$/g, '');
    }
    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;
        case 1:
        case 11:
          var innerText = '';
          for (var i = 0; i < node.childNodes.length; i++) {
            innerText += sorttable.getInnerText(node.childNodes[i]);
          }
          return innerText.replace(/^\s+|\s+$/g, '');
          break;
        default:
          return '';
      }
    }
  },
  
  reverse: function(tbody) {
    // reverse the rows in a tbody
    newrows = [];
    for (var i=0; i<tbody.rows.length; i++) {
      newrows[newrows.length] = tbody.rows[i];
    }
    for (var i=newrows.length-1; i>=0; i--) {
       tbody.appendChild(newrows[i]);
    }
    delete newrows;
  },
  
  /* sort functions
     each sort function takes two parameters, a and b
     you are comparing a[0] and b[0] */
  sort_numeric: function(a,b) {
    aa = parseFloat(a[0].replace(/[^0-9.-]/g,''));
    if (isNaN(aa)) aa = 0;
    bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); 
    if (isNaN(bb)) bb = 0;
    return aa-bb;
  },
  sort_alpha: function(a,b) {
    if (a[0]==b[0]) return 0;
    if (a[0]<b[0]) return -1;
    return 1;
  },
  sort_ddmm: function(a,b) {
    mtch = a[0].match(sorttable.DATE_RE);
    y = mtch[3]; m = mtch[2]; d = mtch[1];
    if (m.length == 1) m = '0'+m;
    if (d.length == 1) d = '0'+d;
    dt1 = y+m+d;
    mtch = b[0].match(sorttable.DATE_RE);
    y = mtch[3]; m = mtch[2]; d = mtch[1];
    if (m.length == 1) m = '0'+m;
    if (d.length == 1) d = '0'+d;
    dt2 = y+m+d;
    if (dt1==dt2) return 0;
    if (dt1<dt2) return -1;
    return 1;
  },
  sort_mmdd: function(a,b) {
    mtch = a[0].match(sorttable.DATE_RE);
    y = mtch[3]; d = mtch[2]; m = mtch[1];
    if (m.length == 1) m = '0'+m;
    if (d.length == 1) d = '0'+d;
    dt1 = y+m+d;
    mtch = b[0].match(sorttable.DATE_RE);
    y = mtch[3]; d = mtch[2]; m = mtch[1];
    if (m.length == 1) m = '0'+m;
    if (d.length == 1) d = '0'+d;
    dt2 = y+m+d;
    if (dt1==dt2) return 0;
    if (dt1<dt2) return -1;
    return 1;
  },
  
  shaker_sort: function(list, comp_func) {
    // A stable sort function to allow multi-level sorting of data
    // see: http://en.wikipedia.org/wiki/Cocktail_sort
    // thanks to Joseph Nahmias
    var b = 0;
    var t = list.length - 1;
    var swap = true;

    while(swap) {
        swap = false;
        for(var i = b; i < t; ++i) {
            if ( comp_func(list[i], list[i+1]) > 0 ) {
                var q = list[i]; list[i] = list[i+1]; list[i+1] = q;
                swap = true;
            }
        } // for
        t--;

        if (!swap) break;

        for(var i = t; i > b; --i) {
            if ( comp_func(list[i], list[i-1]) < 0 ) {
                var q = list[i]; list[i] = list[i-1]; list[i-1] = q;
                swap = true;
            }
        } // for
        b++;

    } // while(swap)
  }  
}

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

// Dean Edwards/Matthias Miller/John Resig

/* for Mozilla/Opera9 */
if (document.addEventListener) {
    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 @*/

/* 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);
}

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

// written by Dean Edwards, 2005
// 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;
}
};
// 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);
// 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[i];
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;
};
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
Array.forEach = function(array, block, context) {
for (var i = 0; i < array.length; i++) {
block.call(context, array[i], i, array);
}
};
}

// 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) {
var resolve = Object; // default
if (object instanceof Function) {
// functions have a "length" property
resolve = Function;
} else if (object.forEach instanceof Function) {
// the object implements a custom forEach method so use that
object.forEach(block, context);
return;
} else if (typeof object == "string") {
// the object is a string
resolve = String;
} else if (typeof object.length == "number") {
// the object is array-like
resolve = Array;
}
resolve.forEach(object, block, context);
}
};