The Web page:

You can try these examples using my pre installed CGI script at dougrice.plus.com as used in the examples below.

Cut and paste the code below ( downto the perl script ) into a file called test.htm and save it to your desktop. Open it and it will include in the data from my guest book:
http://ccgi.dougrice.plus.com/gb/gbookFXXX.js

Now edit the code in function gbF() to use the data as you wish!

<html>
<body>
<script>

function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){

  self.document.write( 
    "<Tr>"+
    "<TD >"+ name+ "</TD><TD >"+ email+"</TD><TD >"+ postedOn+"</TD>"+
    "<TD >"+ IPaddress+ "</TD>"+
    "<TD >"+ userfield1+"</TD><TD >"+ userfield2+	"</TD>"+
    "<TD >"+ userfield3+"</TD><TD >"+ userfield4+	"</TD>"+
    "<TD >"+ comments+	"</TD>"+
    "</TR>"
  )
}

</script>

<h4> One line of the table </h4>

<table border=2 >

<script language="JavaScript" > 

 gbF( 
   "name","email","postedOn", "127.0.0.1",
   "userfield1", "userfield2", "userfield3", "userfield4",
   "comments"
 );

</script>
</table>

<h4> Now include the data from the guestbook </h4>

<table border=2 >
<!-- local guestbook in same place as guestbook.asp --> 
 <script  language = "JavaScript" type = "text/javascript" 
 src = "./gbookFXXX.js" > 

 </script>

<!-- remote guestbook-->
 <script  language = "JavaScript" type = "text/javascript" 
 src = "http://ccgi.dougrice.plus.com/gb/gbookFXXX.js" > 
 </script>

</table> </body> </html>


The Web page - Last Entry First

<html>
<head>
<link rel="stylesheet" href="../club.css">
</head>
<body>
<script>
var opStr = ""
function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
  //self.document.write( name+" , "+ postedOn +","+ IPaddress +" ; " )
  thisEntry =
    "<Tr>"+
    "<TD >"+ name+ "</TD><TD >"+ email+"</TD><TD >"+ postedOn+"</TD>"+
    "<TD >"+ IPaddress+ "</TD>"+
    "</TR><TR>"+
    "<TD >"+ userfield1+"</TD><TD >"+ userfield2+	"</TD>"+
    "<TD >"+ userfield3+"</TD><TD >"+ userfield4+	"</TD>"+
    "</TR><TR>"+
    "<TD colspan=5 class=code ><pre>"+ comments+	"</pre></TD>"+
    "</TR>"
  

  //self.document.write( thisEntry )
  // if you want last entry first, prepend onto a string for display later.
  opStr = thisEntry  + opStr

}

</script>

<h4> One line of the table </h4>

<table border=2 >

<script language="JavaScript" > 

 gbF( 
   "name","email","postedOn", "127.0.0.1",
   "userfield1", "userfield2", "userfield3", "userfield4",
   "comments"
 );

</script>
</table>

<h4> Now include the data from the guestbook, and display last entry first </h4>


<!-- local guestbook in same place as guestbook.asp --> 
<script> loading	= "http://ccgi.dougrice.plus.com/gb/gbookFXXX.js" </script>
<script  language = "JavaScript"  src = "http://ccgi.dougrice.plus.com/gb/gbookFXXX.js"  type = "text/javascript">  </script>

<!-- Now Dump the Table -->
<table border=2 >
<script>
  self.document.write( opStr )
</script>
</table>

</body>
</html>


The Perl Script: guestbook.pl

Cut and paste the code below into a file called guestbook.pl.

FTP this file to your web server's CGI area as TEXT, and set file permissions to execute (-rwxr-xr-x).

You will need to configure the examples to point to this script.

You will need to configure the script below to a directory that wish to save you guestbook in and can write to.

Now modify the examples to include your guestbook.

This script saves to a file gbookF<guestbook>.js where guestbook is passed up with the form.

The perl script at dougrice.plus.net saves to:
http://ccgi.dougrice.plus.com/gb/gbookF<guestbook>.js

Where <guestbook> is the value in the form field: guestbook

#!/usr/bin/perl
#!perl
#
##############################################################################
#Guestbook that appends form Data as JavaScript Functions
#
# control form fields:
# 	guestbook 	used in file name
#       loadnextpage 	if defined use URL in nextpage to replace this page.
#       nextpage	URL to replace 
#
# To install this code. Copy this into a file called guestbook.pl
# FTP up to your Web server from your PC as a TEXT file.
# NOTE: I have found that AUTO sometimes does not work, 
# as the .pl extenstion causes it to be thought of as BINARY 
# and some CGI perl imterpreters do not like CRLF
# 
# Now ensure that the file permissions are set to execute
# NOTE: Don't forget to set the file permissions to execute (-rwxr-xr-x) 
# NOTE: Upload as TEXT or ASCII. Auto sometimes does not work if perl is installed on the PC.
# NOTE: If you get Internal server error, check that your path to perl above is correct.
# NOTE: If you get Internal server error, check that your FTP up script as TEXT
# NOTE: If you get Internal Server error, check if your file paths are correct.
#Doug Rice, Copyright 2002,2003
##############################################################################


# If you are getting Interal server error messages,
# use the code below to pipe  script errors to the browser
use CGI::Carp ( fatalsToBrowser);


#
# Protect script from Spin and Limit to using FORM type= post
# It is possible to spin this if you use  href="?ok" >return
# or Location: ?ok
#
# http://ccgi.dougrice.plus.com/cgi-bin/guestbook.pl?ok
# and Location: ?ok 
# caused a spin which was difficult to stop.
#
#

if ( $ENV{'CONTENT_TYPE'} ){


} else {

  # else print a page to thank form submission.
  # Print Beginning of HTML
  print "Content-Type: text/html\n\n"  ;
  print '<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=us-ascii"><title>Thank You - test</title></head>' ;
  print "<body><h1>Thank You For your interest. It has not been possible to proceed, this time.</h1>\n" ;
  print "</body></html>";
  exit;


  print "<H3>ENV{'HTTP_REFERER': $ENV{'HTTP_REFERER'} </H3>";
  print "<H3>ENV{'CONTENT_TYPE'}:$ENV{'CONTENT_TYPE'} </H3>";
  
  print "\n" . '========== @ENV - foreach =========='."\n<pre>";
  foreach $key (sort(keys %ENV)) {
    print "\n$key," . '=' .  $ENV{ $key } ;
  }

  print "</pre></body></html>";

  exit;
}




# Alternatively code like:
# uncomment line below to view compiler errors 
#
#BEGIN { 
#$| = 1; 
#open (STDERR, ">&STDOUT"); 
#print "Content-type: text/html\n\n<pre>\n"; 
#} 


# Use Socket to reverse DNS IP address 
use Socket;

#
# Try and reverse lookup IP address.
#
($name, $aliases, $addrtype, $length, @addrs) = gethostbyaddr( inet_aton( $ENV{'REMOTE_ADDR'} ), PF_INET );




# specify  the path to the guestbook file  gbookFXXXX.js
# XXXX is value of hidden form field:  guestbook 
#
# Ensure that gbookFXXXX.js has write permissions
#
# if the directory has execute permissions, this script will create gbookFXXXX.js


# You cannot include the file from the cgi-bin directory: 
# /usr/lib/cgi-bin

# Save the file in:
# /var/www/html/gb
# Webpage would include the guestbook from the cgi webserver address
#<script  language = "JavaScript" type = "text/javascript" 
#   src = "http://127.0.0.1/gb/gbookFXXX.js" >  
#</script >


# so save in an adjacent branch 
# or the relative path to a directory called gb
$guestbookjsf  = './../gb/gbookF';

#
# Find out where the documents are stored. 
# One should work.
#
# On  CGI servers I can use: $ENV{'C_DOCUMENT_ROOT'}
# On plus.net CGI server I had to use: $ENV{'C_DOCUMENT_ROOT'}
#
$doc_root = $ENV{'DOCUMENT_ROOT'}.$ENV{'C_DOCUMENT_ROOT'};
$guestbookjsf  = $doc_root.'/gb/gbookF';

#
#
# =============================================
# SEC 2.0 - process FORM fields sent using POST
# =============================================
#
# Get the input, i.e the form fields pushed up to the CGI script. 
#
# If POST read STDIN
# If GET  decode QUERY_STRING
#

# Get the input, i.e the form fields pushed up to the CGI script.
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});

#Combine the query string and form fields
# Split the name-value pairs
@pairs = split(/&/, $ENV{'QUERY_STRING'}."&".$buffer );

foreach $pair (@pairs) {

   ($name, $value) = split(/=/, $pair);

   # Un-Webify plus signs and %-encoding
   $value =~ tr/+/ /;
   # Leave the value mostly escaped as JavaScript can unescape easily.

   # Convert CR LF and LF to <BR>\ at the end of the line
   $value =~ s/%0D//g;
   $value =~ s/%0A/<BR>\\\n/g;


   # Convert \ " and ''
   $value =~ s/%5C/\\\\/g;
   $value =~ s/%22/\\"/g;
   $value =~ s/%27/\\'/g;

   $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
   $FORMJS{$name} = $value;
}


  #
  # Use email to validate user and filter spam 
  #
  $unlock = 'lock'; 

  if ( $FORMJS{'email'} eq 'dem0@dem0' ){
    $unlock = 'unlock';
    # blank off email to hide what worked
    $FORMJS{'email'}     = '';

    # force to one guest book
    # $FORMJS{'guestbook'} = 'XXX';
  }

  #if ( $FORMJS{'email'} eq 'env' ){
  #  print "\n" . '========== @ENV - foreach =========='."\n";
  #  foreach $key (sort(keys %ENV)) {
  #    print "\n$key," . '=' .  $ENV{ $key } ;
  #  }  
  #}


  if ( $unlock eq 'unlock' ){

	# If unlock make guestbook files RW
    #
    # print `chmod 660 ../public/gb/gbook*.js` ; 
    # print `chmod 660 /var/www/html/gb/gbook*.js` ;
    # run chmod on server to make files read write   
    # print `$unlockcmd $guestbookjsf$FORMJS{'guestbook'}.js` ;     
  }




$date ="26 oct 2002 09:00;"; # date formatted so that JavaScript can parse it
&setDate();

  # take form fields and wrap them in the JavaScript Function call and append it onto the end of "gbookF$FORMJS{'guestbook'}.js"

  # Take the form fields and output them wrapped in the format:

  #gbF( 
  #"name","email"," sun 23/Jun/2002 at 20: 52: 0 ","127.0.0.1",
  #"userfield1",
  #"userfield2",
  #"userfield3",
  #"userfield4",
  #"comments"
  #);

  $N = $FORMJS{'guestbook'};

  open (GUESTFJS,">>$guestbookjsf$N.js") || &file_error( GUESTJS, "$guestbookjsf$N.js" ); 

  #Lock file while updating file to prevent race conddition update.
  # This has not been a big problem as the script does not take long.
  # A simple edit was needed to remove corrupted posts.
  
  # This blocks if file is locked, and removed when script ends.

  flock GUESTFJS, 2 || &file_error( GUESTJS, "lock: $guestbookjsf$N.js" );
  # get time stamp 
  &setDate();

  # record which page and what browser was used.
  print GUESTFJS "// Added by gbook.pl  $ENV{'HTTP_REFERER'} \n";
  print GUESTFJS "// HTTP_USER_AGENT:  $ENV{'HTTP_USER_AGENT'} \n";


  print GUESTFJS "gbF( \n";
  print GUESTFJS "\"$FORMJS{'name'}\",";
  print GUESTFJS "\"$FORMJS{'email'}\",";
  print GUESTFJS "\"$date\",";
  print GUESTFJS "\"$ENV{'REMOTE_ADDR'}\",\n";
  print GUESTFJS "\"$FORMJS{'userfield1'}\",\n";
  print GUESTFJS "\"$FORMJS{'userfield2'}\",\n";
  print GUESTFJS "\"$FORMJS{'userfield3'}\",\n";
  print GUESTFJS "\"$FORMJS{'userfield4'}\",\n";
  print GUESTFJS "\"$FORMJS{'comments'}\"\n";
  print GUESTFJS ");\n";
  close (GUESTFJS);



  if ( $FORMJS{'loadnextpage'} ){

    # Print Out Initial Output Location Heading
    print "Location: $FORMJS{'nextpage'}\n\n";
    exit;
  }


  # =============================================
  # SEC 2.0 - Exit  inline code
  # =============================================

  #
  # Exit script and reload page submitting form
  # 
  # remove ?query string and send a new one which can indicate problems
  # if URL ends 
  # ?ok  - successfull
  # 
  ($fromURL, $fromQuerystring) = split(/\?/,$ENV{'HTTP_REFERER'} );
  $qs = "?ok";
  
  # WARNING: Location: ?ok   Do not allow this. It spun Edge and filled up log file and MAXED out DiskQuota !

  #print "Location: $fromURL$qs \n\n";
  #exit;





  # else print a page to thank form submission.
  # Print Beginning of HTML
  print "Content-Type: text/html\n\n";
  print "<html><head><title>Thank You</title></head>\n";
  print "<body><h1>Thank You For your submission</h1>\n";
  print "<H1><A HREF=$FORMJS{'nextpage'}"."?reload"." target=_top > return... <A></H1>";
  print '</body></html>';

  exit;


#######################
# Subroutines

# file_error - call if problems opening files
sub file_error {

    local($FH, $fileName) = @_; 


    #
    # Exit script and reload page submitting form
    # 
    # remove ?query string and send a new one which can indicate problems
    # if URL ends 
    # ?ok  - successfull
    # 
    # WARNING 
    # I had an idea to use HTTP_REFERER and append ?ok to return to the calling page and add an exit code.
    #
    # if I called 192.168.1.x/gb.php there is no HTTP_REFERER and I got too many redirects
    #  - Edge does not like Location: ?ok 
    #


    ($fromURL, $fromQuerystring) = split(/\?/,$ENV{'HTTP_REFERER'} );
    $qs = "?error:file:$fileName ";
  
    print "Location: $fromURL$qs \n\n";
    exit;


    # Print Beginning of HTML
    print "Content-Type: text/html\n\n";
    print "<html><head><title>Thank You</title></head><body>\n";
    print "<H1>Error Opening File $fileName:, press back</h1> \n";
    print "Your data has not been added, press back <P>\n";

    print "If you can log into the server, check file permissions\n";
    print '</body></htmr>';
    exit;
}

################################################################
# setDate setup $date to string that javascript can parse using:  now= new Date( postedOn )
#

sub setDate {

# Get the Date for Entry
# output date so that the web pages can be use the javascript:  now= new Date( postedOn )

#IE 5 formats toUTCString():		Tue, 25 Jun 2002 05:47:32 UTC
#Netscape Navigator toUTCString():	Tue, 25 Jun 2002 05:49:59 GMT

#($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);		   
#  0     1     2    3     4     5    6     7     8
@t = localtime();
@days=  ('Sun','Mon','Tue','Wed','Thu','Fri','Sat','Sun');
@months=('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
$fullYear=1900+$t[5];
#toUTCString():		#Tue, 25 Jun 2002 05:47:32 UTC
$date = "$days[$t[6]], $t[3] $months[$t[4]] $fullYear ".substr("0".$t[2],-2,2).":".substr("0".$t[1],-2,2).":".substr("0".$t[0],-2,2)." UTC+0100";

}


The PHP Script:

This script below saves to gbookFXXX.js file in the directory that the script is run in. XXX in the value passed up in form field guestbook.

http://ccgi.dougrice.plus.com/guestbook.php?guestbook=XXX


<?PHP
//	guestbook.php - Guestbook script the saves the data wrapped in JavaScript function calls.
// copyright 2002 douglas rice.
// This script takes the data from the form fields.
// and wraps it in a JavaScript Function Call:
// gbF( "name","email",postedOn,IPaddress,"userfield1","userfield2","userfield3","userfield4","comments", ).

// After appending the data the URL in form field: nextpage replaces the page.
//
// This uses the same form fields as the BTOpenWorld Guestbook.
//



$guestbook  = $_REQUEST["guestbook" ];
$name 	    = $_REQUEST["name"];
$email      = $_REQUEST["email"];
$userfield1 = $_REQUEST["userfield1"];
$userfield2 = $_REQUEST["userfield2"];
$userfield3 = $_REQUEST["userfield3"];
$userfield4 = $_REQUEST["userfield4"];
$comments   = $_REQUEST["comments"];
$nextpage   = $_REQUEST["nextpage"];


function esc ( $s ) {
// escape characters that are code to Java Script, and HTML
// PHP escapes " and ' by default, so no need for call to // $ss = addslashes ( $s );
$ss = $s;
// //CRLF and LF	//HTML specials

$search = array ( "'\r'", "'\n'",	"'&'", "'<'", "'>'" );
$replace = array ( "\\r\\\r", "",	"&amp;", "&lt;", "&gt;" );
// Uses regular expressions to remove 
return preg_replace ($search, $replace, $ss );

}

$date=gmstrftime ("%d %b %Y %H:%M:%S");

// append to the file gbookF + the name specified by $guestbook + .js
$fp = fopen ("./gbookF$guestbook.js", "a+b");

fputs($fp,"gbF(\n");

fputs($fp,"'".esc( $name )."',\n '".esc( $email )."',\n '$date',\n '".getenv ( "REMOTE_ADDR" )."',\n");

// output the 4 user fields and comments
fputs($fp,"'".esc( $userfield1 )."',\n '".esc( $userfield2 )."',\n");
fputs($fp,"'".esc( $userfield3 )."',\n '".esc( $userfield4 )."',\n");
fputs($fp,"'".esc( $comments )."'\n");
fputs($fp,");\n\n");

fclose($fp);

// reload the page with the URL provided in next page.
header("Location: $nextpage\n\n\n" );

//WARNING 
// I had an idea to use HTTP_REFERER and append ?ok to return to the calling page and add an exit code.
//
// if I called 192.168.1.x/gb.php there is no HTTP_REFERER and I got too many redirects
// - Edge does not like Location: ?ok 
//

// I tried adding ?ok but did not have a valid HTTP_REFERER 
// This and spun EDGE and filled up my file gbookF.js and I ran out of disk Quota 
//header("Location: ?ok\n\n\n" );

exit;
?>

Copy the code above into a file called guestbook.php and upload to your web server where you can run php pages.

I upload mine to http://ccgi.dougrice.plus.com/demo . You then need to point the guestbook form action to this PHP page.

<form name="F1" action="http://ccgi.dougrice.plus.com/demo/guestbook.php" method="POST" >
<input type="text" name="guestbook" size="20" value="XXX" >
</form>

Upload a file called gbookFXXX.js to http://ccgi.dougrice.plus.com/demo and make the file permissions writable.

Include the file: gbookFXXX.js in your web page using :

<!-- remote guestbook-->
<script> 
function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments)
{ // YOU WRITE THE BODY OF THIS FUNCTION TO EXTRACT THE DATA IN YOU GUEST BOOK
self.document.write( name+ ","+ email+","+ postedOn+","+ IPaddress+ "<BR>"+ 
 userfield1+","+ userfield2+","+userfield3+","+ userfield4+","+comments+"<P>" ) 
} </script>
<!-- Include remote guestbook-->
<script src = "http://ccgi.dougrice.plus.com/demo/gbookFXXX.js" language = "JavaScript" type = "text/javascript" >
</script>

The PHP Script loads the data serverside and downloads it inline.

An alternative to the cache busting code above is to use PHP server side, possibly with password controlled login.

<!--
<script>
now = new Date()
/* try some cache busting append the time to the URL to make it different, so the URL is not cached. */

self.document.write( '<scr'+'ipt src=https://www.adastralsailing.org.uk/apsc/gb/gbookFBookings_.js?'+now.getTime()+'  language="JavaScript"> </scr'+'ipt>' )

</script>
-->

<script>
<?php
// only include data if logged in.

if ( $_SESSION["loggedin"] === "loggedin"){
  // Read a file into a string
  $str = file_get_contents("gb/gbookFBookings_.js");

  // Check for errors
  if ($str === false) {
  // Handle error
  echo "Error reading file";
  } else {
  // Print the file contents
  echo $str;
  }
}  
?>
</script>

Using gbF() serverside

It is possible to use the idea in the PHP script, but the security MUST be considered

<?php

function gbF( $name,$email,$postedOn,$IPaddress,$userfield1,$userfield2,$userfield3,$userfield4,$comments){
   // supply your own code to filter and load the data.   
   echo "==";
   echo $name."\n";
   echo $postedOn."\n";
};
    
?>


gbF(
'Doug Rice',
 'ok@ok.com',
 '27 Mar 2024 08:04:53',
 '212.56.108.219',
'book|2024_Mar_5|day|trailer|other|6.50|ref:#938806|',
 'skipper,crewList',
'',
 '',
''
);

gbF(
'Doug Rice',
 'ok@ok.com',
 '27 Mar 2024 17:53:49',
 '212.56.108.219',
'book|2024_Mar_4|am|Hartley|private|10.16|ref:#921593|',
 'skipper,crewList',
'',
 '',
''
);

?>

The code below loads from a file, but it does not call the PHP gbF()


<?php require 'gb/gbookFBookings_.js';
?>

This still needs testing.

Using php allows SESSION variables to be used server side to control user access

see https://www.w3schools.com/PHP/php_sessions.asp


The ASP Script:

This script below saves to gbookFXXX.js file in the directory that the script is run in. XXX in the value passed up in form field guestbook.
<% @ LANGUAGE="VBSCRIPT" %>
<%
 OPTION EXPLICIT
 DIM L_Guestbook, count, CursorType, intMID,objConn ,rst, strProvider, strQuery, StrSort

' NOTE: This script escapes   ' " \ CR or LF which would corrupt JavaScript.


   Function strip( ByVal s)
     s = replace(s,chr( 92 ),Chr( 92 ) & Chr( 92 )) ' first double up any \

     s = replace(s,chr( 39 ),Chr( 92 ) & Chr( 39 )) ' now escape ' 
     s = replace(s,chr( 34 ),Chr( 92 ) & Chr( 34 )) ' now escape "

     ' Not really sure about how to escape < > &lt; and &gt;
     ' s = replace(s,"<","&lt;") ' now escape <
     ' s = replace(s,">","&gt;") ' now escape >

	 ' now replace CR LF and LF  
     s = replace(s,vbCr,"")
     s = replace(s,vbLf,"<BR>\"+vbCr+vbLf)

     strip = s
     
   End Function


    Const ForReading = 1, ForWriting = 2, ForAppending = 8

    Const TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0

    Dim fs, f, ts, s, gbook
    
    Set fs = CreateObject("Scripting.FileSystemObject")

    gbook = server.mappath("gbookF"& request.Form("guestbook")&".js")

    if (  not fs.FileExists( gbook ) ) Then
		fs.CreateTextFile gbook             'Create a file
    
    End If

    Set ts = fs.OpenTextFile( gbook, ForAppending,TristateFalse)

' gbF(
'  "name",
'  "email",
'  " Mon 5/Nov/2001 at 18: 3: 37 ", ' date script run
'  "132.146.89.88",
'  "userfield1",
'  "userfield2",
'  "userfield3",
'  "userfield4",
'  ""
'  );

    ts.WriteLine( "gbF(  ")
    ts.WriteLine( "'" & strip (  request.Form("name")       ) & "',")
    ts.WriteLine( "'" & strip (  request.Form("email")      ) & "',")
    ts.WriteLine( "'" & now                        & "',")
    ts.WriteLine( "'" & Request.ServerVariables("REMOTE_ADDR")  & "',") 
    ts.WriteLine( "'" & strip (  request.Form("userfield1") ) & "',")
    ts.WriteLine( "'" & strip (  request.Form("userfield2") ) & "',")
    ts.WriteLine( "'" & strip (  request.Form("userfield3") ) & "',")
    ts.WriteLine( "'" & strip (  request.Form("userfield4") ) & "',")

    ts.WriteLine( "'" & strip (  request.Form("comments")   ) & "'")
    ts.WriteLine( ");" )
    ts.WriteLine( " " )

    ts.Close

    response.redirect request.Form("nextpage")

%>


The Form:

Cut and paste the code below into a file called form.htm, and save to your desktop and open form.htm.

When you press the submit button it append the form fields to:

http://ccgi.dougrice.plus.com/gb/gbookFXXX.js 

using:

 action="http://ccgi.dougrice.plus.com/cgi-bin/guestbook.pl"

Change the action to point to your CGI script.

( You can try this out using my guestbook http://ccgi.dougrice.plus.com/gb/gbookFXXX.js for now! )

 

<html>
<head>
<title>Simple Form</title>
<link rel="stylesheet" href="../club.css">
</head>
<body>
<H2>Minimal Form</h2>
<!-- select which server script you are going to use.
<form name="F1" action="guestbook.asp" method="POST" >
<form name="F1" action="guestbook.php" method="POST" >
-->
<form name="F1" action="http://ccgi.dougrice.plus.com/cgi-bin/guestbook.pl"        method="POST" >
<input type="text" name="name" value="name" size="20" > :name<BR>
<input type="text" name="email" value="email" size="20" > :email<BR>

<input type="text" name="userfield1" value="userfield1" size="20" > :userfield1<BR>
<input type="text" name="userfield2" value="userfield2" size="20" > :userfield2<BR> 
<input type="text" name="userfield3" value="userfield3" size="20" > :userfield3<BR>
<input type="text" name="userfield4" value="userfield4" size="20" > :userfield4<BR>

Please enter any comments:-
<textarea name="comments" rows="2" cols="80"></textarea>

<HR>
Control Fields (Normally hidden):-<BR>
<input type="text" name="guestbook" size="20" value="XXX" onFocus="focusB1()" >guestbook. The form fields are appended to gbookFXXX.js<BR>
<input type="text" name="nextpage" size="70" value="http://www.dougrice.plus.com/hp/gbbook/simple/codeDump.htm" onFocus="focusB1()" >nextpage - replaces this form<BR>
<input type="text" name="loadnextpage" size="70" value="loadnextpage" onFocus="focusB1()" >loadnextpage - flag <BR>
<input type="submit" name="B1" value="Submit">
</form>
The form above appends the form fields to gbookFXXX.js formatted using CGI Script guestbook.pl or guestbook.asp
<pre>
gbF(
"name",
"email",
" Mon 5/Nov/2001 at 18: 3: 37 ", ' date script run
"132.146.89.88",
"userfield1",
"userfield2",
"userfield3",
"userfield4",
"comments"
);
</pre>
</body>
</html>

Extras: The following code is required to make the pages run smoothly.

 

Download, Sort and Select Data

// function call back for data stored in guestbook.
function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
  gbA[ count ] = new GB( name,email,postedOn,IPaddress,
                         userfield1,userfield2,userfield3,userfield4, comments 
                        );
  count++
}

// Function used by sort.
function sortCallbackFn( a, b ) {

  if ( a.userfield1 != b.userfield1 ) {
    if ( a.userfield1 > b.userfield1 ){ return 1 }
    if ( a.userfield1 < b.userfield1 ){ return -1 }
    return 1
  }
  return ( b.count*1.0 - a.count*1.0 )
}

</script>

<h4> Guestbook data, as loaded </h4>
<script> loading	= "./gbookFXXX.js" </script>
<script language = "JavaScript" src = "./gbookFXXX.js" type = "text/javascript"> </script>

<script> loading	= "http://ccgi.dougrice.plus.com/gb/gbookFXXX.js" </script>
<script language = "JavaScript" src = "http://ccgi.dougrice.plus.com/gb/gbookFXXX.js" type = "text/javascript"> </script>

<h4> Now Sort the data by Userfield1, then reversed submit order </h4>

<script>
gbA.sort( sortCallbackFn )
</script>

Display Data in a Table.

opStr ="<table>"
for( I=0; I< gbA.length ; I++ ){

  opStr = opStr+
    "<tr><td><B><A href='javascript:pop("+I+")'>"+ gbA[ I ].name +"</A></B>"+"<BR>"+gbA[ I ].email+
    "<br>" + gbA[ I ].postedOn+
    "</td><td>"	+ gbA[ I ].userfield1+
    "</td><td>" + gbA[ I ].userfield2+
    "</td><td>" + gbA[ I ].userfield3+
    "</td><td>" + gbA[ I ].userfield4+
    "</td></tr>" +
    "<tr><td colspan=5>"+ gbA[ I ].comments +
    "</td></tr>"

  }
  opStr ="</table>"

  self.document.write( opStr )

 

Force a Reload of updated data. example form

<form name="F1" action="guestbook.asp" method="POST" onSubmit="return validate()">
  <input type="text" name="name" value="name" size="20" > :name - set up by cookie<BR>
  <input type="text" name="email" value="email" size="20" > :email - set up by cookie<BR>
</form>
<script>
// for the session iis sends first cookie = to what was assignd to document.cookie
// However IIS sends up anothe cookie for the ASP script, so split on "; " 

window.status = document.cookie

// split cookies
var cookiesA = document.cookie.split("; ") // split on ; and space
var cookieA = new Array()
// set up defaults 
cookieA[ "name" ] = "name"
cookieA[ "email" ] = ""

// break out the cookies into an associative array index by the string. 
for ( I=0 ; I < cookiesA.length ; I++ ){
  nvA = cookiesA[ I ].split("=")
  cookieA[ nvA[0] ] = nvA[1]
  //alert( nvA[0]+"="+cookieA[ nvA[0] ] )
}

if ( cookieA[ "reload" ] == "needed" ){
  document.cookie="reload=done"
  alert("reload needed ... reloading")
  document.location.reload( 1==1 )
}
var F1 = window.document.forms["F1"]
// This is picked up from a cookie
F1.name.value = cookieA[ 'name' ]
F1.email.value = cookieA[ 'email' ]

function validate(){
var F1 = window.document.forms["F1"]
  if ( ( F1.name.value == "name" ) || ( F1.name.value == "undefined" ) ) {
    alert(' Please change the name and email address..')
    F1.name.focus()
    F1.name.select()
    return false
  }
  // 
  document.cookie="name="+ F1.name.value  + "; expires=" + expiry.toGMTString()
  document.cookie="email="+F1.email.value + "; expires=" + expiry.toGMTString()
  
  document.cookie="reload=needed"
  return true
}
</script>

Form Populate - part fill the form.

function pop( gbA_row ){
  // pict up the data from the sorted array and fill in the update form.
  var F1 = window.document.forms["F1"]
  var record = gbA[ gbA_row ]	

  // This is picked up from a cookie
  F1.name.value = cookieA[ 'name' ]
  F1.email.value = cookieA[ 'email' ]

  F1.userfield1.value = record.userfield1
  F1.userfield2.value = record.userfield2
  F1.userfield3.value = record.userfield3
  F1.userfield4.value = record.userfield4
  F1.comments.value = record.comments.replace( /<BR>/g,"\n" )
  // focus on end and start of file to display form on screen.
  F1.comments.focus()
  F1.name.focus()
}

 

The Perl Script Extras - date, credits and password:

#
# setDate setup $date to string that javascript can parse using:  now= new Date( postedOn )
#

sub setDate {

# Get the Date for Entry
# output date so that the web pages can be use the javascript:  now= new Date( postedOn )

#IE 5 formats toUTCString():		Tue, 25 Jun 2002 05:47:32 UTC
#Netscape Navigator toUTCString():	Tue, 25 Jun 2002 05:49:59 GMT

#($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);		   
#  0     1     2    3     4     5    6     7     8
@t = localtime();
@days=  ('Sun','Mon','Tue','Wed','Thu','Fri','Sat','Sun');
@months=('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
$fullYear=1900+$t[5];
#toUTCString():		#Tue, 25 Jun 2002 05:47:32 UTC
$date = "$days[$t[6]], $t[3] $months[$t[4]] $fullYear ".substr("0".$t[2],-2,2).":".substr("0".$t[1],-2,2).":".substr("0".$t[0],-2,2)." UTC+0100";

}


#-----------------------------------------------------------------
# Check the credits
sub checkCreditLevel {
  $creditfile    = $ENV{'DOCUMENT_ROOT'}.'/credits.js';

  open (CREDITFILE,$creditfile ) || &file_error( CREDITFILE,$creditfile ); 

  @CREDIT_LINES=<CREDITFILE>;
  close(CREDITFILE);
  $CREDIT_SIZE=@CREDIT_LINES;

  foreach $memRow (@CREDIT_LINES){
   ($name, $value)  = split(/=/, $memRow);
   #print "$name, $value<P>\n";
   $CREDITSA{$name} = $value;
  }

  # if blank create
  if ( $CREDITSA{'credits'} eq '' ) {
    $CREDITSA{'credits'}=1000;
  }

  $credits = $CREDITSA{'credits'}-1;
  #print "This guestbook server has $credits credits left<P>\n";

  # if fraudlently set to -ve value
  if ( $credits > 1000 ) {
    $credits=1000;
  }

  open (CREDITFILE,">$creditfile" ) || &file_error( CREDITFILE,$creditfile ); 
  print CREDITFILE "credits=$credits\n";
  close(CREDITFILE);

  if ( $credits < 0  ) {
    #print "<h1> Credits run out, data not appended  </h1>";

    exit;
  }
} 
#-----------------------------------------------------

# Password protect submission

# read passwords into associative array, but only if password equal to old password

# store the passwords  in a file called password.txt in $ENV{'DOCUMENT_ROOT'}
#each line formatted
#
#guestbook,password,oldpassword,check
#
# new passwords can be appended and are only changed is old password matches e.g

#Bug,newpassword,,check
#Bug,newpassword2,newpassword,check
#AotherBook,password,,check



#GBOOK=password
# Get Membership details 

sub checkPassword {
  $passwordfile  = $ENV{'DOCUMENT_ROOT'}.'/password.txt';
  if ( -e $passwordfile ) {
    open (PASSWORDFILE,$passwordfile ) ||     &file_error( PASSWORDFILE, $passwordfile ); 
    #    die "Can't Open $passwordfile: $!\n";

    @PASSWORD_LINES=<PASSWORDFILE>;
    close(PASSWORDFILE);
    $PASSWORD_SIZE=@PASSWORD_LINES;

    foreach $memRow (@PASSWORD_LINES){
      ($guestbook, $password,$oldpassword,$check) = split(/,/, $memRow);
      # only update password if oldpassword is a valid password.
      if ( $oldpassword eq $PASSWORDSA{$guestbook} ){
        $PASSWORDSA{$guestbook} = $password;
      } 
      if ( "1" eq "2" ) {
         # Debug output to test Updating password list
        print "Content-Type: text/html\n\n";
        print "<html><head><title>Password problem</title></head><body>\n";
        #print "<h1>Old password :$oldpassword: for :$guestbook: not found: </h1>\n";
        print "<h1>looking for: $PASSWORDSA{$guestbook}</h1>\n";
        print '</body></htmr>\n';
        exit;
      }
    }

    $password      = $FORMJS{'password'};
    $guestbook     = $FORMJS{'guestbook'};
    $validpassword = $PASSWORDSA{$guestbook};

    #&file_error( CREDITFILE,$creditfile."|$password|$guestbook|$validpassword|" ); 

    if ( $password ne $validpassword )  {
 
      $PASSWORDSA{$name} = $value;

      # Print Beginning of HTML
      print "Content-Type: text/html\n\n";
      print "<html><head><title>Thank You</title></head><body>\n";
      print "<h1>INVALID PASSWORD for guestbook:$guestbook: </h1>\n";
      #print "<h1> wanted:$validpassword: got :$password: </h1>\n";
      foreach $memRow (@PASSWORD_LINES){
        ($name, $value) = split(/,/, $memRow);
        #print "<body><h1>PASSWORDS :$PASSWORDSA{$name}:$name:$value:, press back </h1>\n";

        $PASSWORDSA{$name} = $value;
      }
      #print "<body><h1>Wanted :$validpassword:, press back </h1>\n";
      print "<body><h1>Your data has not been added, press back </h1>\n";
      print "<H1><A HREF=$FORM{'nextpage'} target=_top > return... <A></H1>";
      print '</body></htmr>\n';
      exit;
    }
  }
}

 


Sorted Guestbook, with update form :

<html>
<head>
<title>Sorted Guestbook, with update form</title>
<link rel="stylesheet" href="../club.css">
</head>
<body>
<h1>Sorted Guestbook, with update form</h1>
<script>

// define array to store guestbook data in.
var count          = 0
var gbA            = new Array()
var loading		   = ""

// function adds data to an array.
function GB( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
	this.name       = name
	this.email      = email
	this.postedOn   = postedOn
	this.IPaddress  = IPaddress
	this.userfield1 = userfield1
	this.userfield2 = userfield2
	this.userfield3 = userfield3
	this.userfield4 = userfield4
	this.comments   = comments
	
    // add extra fields, as data is loaded
	this.count      = count
	lastUpdated     = name+", "+email+" at "+postedOn+" updating "+ userfield4 + ":" + userfield1 
	// sort Key for sort on dates
	var date = new Date( userfield1 )
	if ( isNaN( date ) ) {
	  if ( isNaN( userfield1 ) ) {
	    date = new Date( "1 aug 3000")
	    this.date = date
	    this.sortKey = date.valueOf()
	  } else {
	    this.sortKey = userfield1*1.0	
	  }
	} else {
	  this.date = date
	  this.sortKey = date.valueOf()
	}
	return this
}

// function call back for data stored in guestbook.
function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
    gbA[ count ] = new GB(  
        name,email,postedOn,IPaddress,
        userfield1,userfield2,userfield3,userfield4,
        comments
	);
    count++

    // display data as it is loaded - remove 
    opStr = 
    "<PRE>"+
           
	  "<PRE>"+
	  
	  "gbF( //from: "+loading+"\n"+
	  "  \""+unescape(name)+"\","+
	  "  \""+unescape(email)+"\","+
	  "  \""+unescape(postedOn)+"\","+
	  "  \""+unescape(IPaddress)+"\",\n"+
	  "  \""+unescape(userfield1)+"\","+
	  "  \""+unescape(userfield2)+"\","+
	  "  \""+unescape(userfield3)+"\","+
	  "  \""+unescape(userfield4)+"\",\n"+
	  "  \""+comments.replace(/<BR>/gi,"&lt;BR&gt;\\")+"\"\n"+
	  "  );\n"+
	  "" + "</PRE>" 


    // self.document.write( opStr )

}

// Function used by sort.
function sortCallbackFn( a, b ) {

  if ( ( a.sortKey - b.sortKey ) != 0 ) {
    return ( a.sortKey - b.sortKey )
  }

  if ( a.userfield1 != b.userfield1 ) {
    if ( a.userfield1 > b.userfield1 ){ return  1 }
    if ( a.userfield1 < b.userfield1 ){ return -1 }
    return 1
  }
  
  return ( b.count*1.0 - a.count*1.0 )
}
</script>

<script> loading	= "http://ccgi.dougrice.plus.com/gb/gbookFXXX.js" </script>
<script  language = "JavaScript"  src = "http://ccgi.dougrice.plus.com/gb/gbookFXXX.js"  type = "text/javascript">  </script>

<h4> Now display Guestbook data sorted alphabetically by Userfield1, then reversed submit order  </h4>

<script>
   gbA.sort( sortCallbackFn )
</script>

<table border=2 >
<script>

 
 var opStr = "<tr><th><B><A href=''> link +</A></B><BR>email<br>postedOn"+
	"</th><th>userfield1"+
	"</th><th>userfield2"+
	"</th><th>userfield3"+
	"</th><th>userfield4"+
	"</th></tr>" +
	"<tr><th colspan=5>comments" +
	"</th></tr>"



 for( I=0; I< gbA.length ; I++ ){
 	
   opStr = opStr+
   		"<tr><td><B><A href='javascript:pop("+I+")'>"+  gbA[ I ].name +"</A></B>"+"<BR>"+gbA[ I ].email+
   		"<br>"   + 	gbA[ I ].postedOn+
   		"</td><td>"	 +	gbA[ I ].userfield1+
   		"</td><td>"  +  gbA[ I ].userfield2+
   		"</td><td>"  +  gbA[ I ].userfield3+
   		"</td><td>"  +  gbA[ I ].userfield4+
   		"</td></tr>" +
//   		"<tr><td colspan=5><PRE>"+ gbA[ I ].comments+"</td></tr>"
		// print out comments, convert <BR> to \n so that copy works.
   		"<tr><td colspan=5 class=code ><PRE>"+ gbA[ I ].comments.replace(/<BR>/gi,"\n") + "</PRE></TD></TR>"+
		""
   		"</td></tr>"
   		
 }

 self.document.write( opStr )


// pick up cookies for reload, and name and email
  var today  = new Date();
  var expiry = new Date(today.getTime() + 365 * 24 * 60 * 60 * 1000);
  //var expiry = new Date(today.getTime() +   1 *  1 *  5 * 60 * 1000);

  // for the session iis sends first cookie = to what was assignd to document.cookie
  // However IIS sends up anothe cookie for the ASP script, so split on "; " 
  
  window.status = document.cookie
  
  // split cookies
  var cookiesA = document.cookie.split("; ")  // split on ; and space
  var cookieA  = new Array()
  // set up defaults 
  cookieA[ "name" ] = "name"
  cookieA[ "email" ] = ""

  // break out the cookies into an associative array index by the string.  	
  for ( I=0 ; I < cookiesA.length ; I++ ){
    nvA = cookiesA[ I ].split("=")
    cookieA[ nvA[0] ] = nvA[1]
    //alert( nvA[0]+"="+cookieA[ nvA[0] ] )
  }

  if ( cookieA[ "reload" ] == "needed" ){
  	document.cookie="reload=done"
  	alert("reload needed ... reloading")
  	document.location.reload( 1==1 )
  }


 function pop( gbA_row ){
   // pict up the data from the assorted file and fill in the update form.
   var F1 = window.document.forms["F1"]
   var record = gbA[ gbA_row ]	 

   // This is picked up from a cookie
   F1.name.value       =  cookieA[ 'name'  ]
   F1.email.value      =  cookieA[ 'email' ]

   F1.userfield1.value =  record.userfield1
   F1.userfield2.value =  record.userfield2
   F1.userfield3.value =  record.userfield3
   F1.userfield4.value =  record.userfield4
   F1.comments.value   =  record.comments.replace( /<BR>/gi,"\n" )
   // focus on end and start of file to display form on screen.
   F1.comments.focus()
   F1.name.focus()
  }


  function validate(){
    var F1 = window.document.forms["F1"]

    if ( ( F1.name.value == "name" ) || ( F1.name.value == "undefined" ) ) {
      alert(' Please change the name and email address..')
      F1.name.focus()
      F1.name.select()
      return false
    }
    // 
    document.cookie="name="+F1.name.value   + ";expires=" + expiry.toGMTString()
    document.cookie="email="+F1.email.value + ";expires=" + expiry.toGMTString()

    document.cookie="reload=needed"
    return true
  }

</script> 

</table>
<h4> Update form </h4>
<script>
self.document.write( "Cookies: "+document.cookie +"<p>" )
</script>


Click of the name above to use existing data, or edit the data below:-<BR>
<!--
<form name="F1" action="http://ccgi.dougrice.plus.com/gb/guestbook.php" method="POST" onSubmit="return validate()">
-->
<form name="F1" action="http://ccgi.dougrice.plus.com/cgi-bin/guestbook.pl" method="POST" onSubmit="return validate()">
<input type="text" name="name" value="name" size="20" > :name - set up by cookie<BR>
<input type="text" name="email" value="email" size="20" > :email - set up by cookie<BR>

If Userfield1 is a valid date / time then sort as date else if a valid number sort as a number, else sort alphabetically, then reversed submit order<BR>

<input type="text" name="userfield1" value="userfield1" size="20" > :userfield1 ( valid date is dd mmm yyyy hh:mm:ss )<P>


<input type="text" name="userfield2" value="userfield2" size="20" > :userfield2<BR> 
<input type="text" name="userfield3" value="userfield3" size="20" > :userfield3<BR>
<input type="text" name="userfield4" value="userfield4" size="20" > :userfield4<BR>

Please enter any comments:-<BR>
<textarea name="comments" rows="5" cols="80"></textarea>:comments<BR>

<HR>
Control Fields (Normally hidden):-<BR>
<input type="text" name="guestbook" size="20" value="XXX" onFocus="focusB1()" >guestbook. The form fields are appended to gbookFXXX.js<BR>
<input type="text" name="nextpage" size="50" value="http://www.dougrice.plus.com/hp/gbbook/simple/codeSorted.htm" onFocus="focusB1()" >nextpage - replaces this form<BR>
<input type="text" name="loadnextpage" size="50" value="loadnextpage" onFocus="focusB1()" >loadnextpage - flag <BR>
<input type="submit" name="B1" value="Submit -using guestbook.pl  on apache based cgi.dougrice.plus.com" onClick="submitPl()">
<input type="submit" name="B2" value="Submit -using guestbook.php on apache based cgi.dougrice.plus.com" onClick="submitPl2()">

<A href="http://ccgi.dougrice.plus.com/cgi-bin/gb.pl" > env </A>

<script>
  // add a button to allow user to use an Active-X function to write the form to a local file
  if ( self.location.protocol == "file:" ){
    self.document.write('<BR>If running IE5.5 locally use Active - X to :<BR><input type="Button" name="B4" value="Append to local file: gbookFXXX.js" onClick="javascript:AXopFile(\'F1\')">')
  }
</script>



</form>

<script>


   var F1 = window.document.forms["F1"]
   // This is picked up from a cookie
   F1.name.value       =  cookieA[ 'name'  ]
   F1.email.value      =  cookieA[ 'email' ]

   // if running locally
   if ( self.location.protocol == "file:" ){
     var s = self.location.pathname 
     var s1 = s.replace( /codeSorted.htm/g,"gbookF"+F1.guestbook.value+".js" )  	// remove file name
     F1.B4.value = " Add to the local disk file: " + s1
   }


  function submitPl( formName ){
    validate();
    var f = window.document.forms[ "F1" ]   
    F1.action="http://ccgi.dougrice.plus.com/cgi-bin/guestbook.pl"
    //F1.action="http://localhost/cgi-bin/guestbook.pl"
    F1.target="popup"
    //F1.nextpage.value=location
    //F1.submit()
    return ( 1==1 )
  }

  function submitPl2( formName ){
    validate();
    var f = window.document.forms[ "F1" ]   
    F1.action="http://ccgi.dougrice.plus.com/gb/guestbook.php"

    F1.target="popup"
    //F1.nextpage.value=location
    //F1.submit()
    return ( 1==1 )
  }



function strip ( s ) {
s= s.replace( /\\/g,"\\\\")
s= s.replace( /\"/g,"\\\"")
s= s.replace( /\'/g,"\\\'")
s= s.replace( /\n/g,"<BR>\\n")
s= s.replace( /\r/g,"")
return s
}

function focusB1( formName ){
var f = window.document.forms[ "F1" ]
f.B1.focus()
}


function AXopFile( formName ){
// Function that uses Active X to emulate remote ASP server
var f = window.document.forms[ "F1" ] 
var fs,s;
var now = new Date()
var s
validate();
s = self.location.pathname	// gives /D:\data\hp\gbbook\DHRsorted.htm
s = s.replace( /\//g,"") // remove leading /
s = s.replace( /codeSorted.htm/g,"gbookF"+f.guestbook.value+".js" ) // remove file name
gbook=s
alert( "Add to local File:\n"+gbook )

var fs = new ActiveXObject("Scripting.FileSystemObject");

if ( ! fs.FileExists( gbook ) ) {
fs.CreateTextFile( gbook )
}

var ts = fs.OpenTextFile( gbook ,8 , 0 );

ts.WriteLine("//Appended using Active X.");

ts.WriteLine( "gbF( ")
ts.WriteLine( "'" + strip ( f.name.value ) + "',")
ts.WriteLine( "'" + strip ( f.email.value ) + "',")
ts.WriteLine( "'" + now + "',")
ts.WriteLine( "'127.0.0.1'," )
ts.WriteLine( "'" + strip ( f.userfield1.value ) + "',")
ts.WriteLine( "'" + strip ( f.userfield2.value ) + "',")
ts.WriteLine( "'" + strip ( f.userfield3.value ) + "',")
ts.WriteLine( "'" + strip ( f.userfield4.value ) + "',")
ts.WriteLine( "'" + strip ( f.comments.value ) + "'" )
ts.WriteLine( ");" )
ts.WriteLine( " " )

ts.Close();

location.reload( 1==1 )
}

</script>
</body>
</html>

Sorted (Numerically / alphabetically ) Guestbook, with update form :

<html>
<title>Sorted Guestbook, with update form</title>
<head>
<link rel="stylesheet" href="../club.css">
</head>

<body>
<h1>Sorted Guestbook, with update form</h1>
<script>

// define array to store guestbook data in.
var count = 0
var gbA = new Array()
var loading	= ""
var lastUserfield1=""

// function adds data to an array.
function GB( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
  this.name = name
  this.email = email
  this.postedOn = postedOn
  this.IPaddress = IPaddress
  this.userfield1 = userfield1
  this.userfield2 = userfield2
  this.userfield3 = userfield3
  this.userfield4 = userfield4
  this.comments = comments

  // add extra fields, as data is loaded
  this.count = count

  // sort Key for sort on numeric then dates the alphabetic
  var date = new Date( userfield1 )
  this.sortKeyAlpha = ""
  // sortKeyType is sorted first and are A,D,N, use lower case to sort after Upper case	
  // if you want numbers,alpha,dates use types a,d,N as N < a < d
  if ( isNaN( date ) ) {
    // not a date
    if ( isNaN( userfield1 ) ) {
      // alphabetic
      this.date = new Date( "1 aug 3000" )
      this.sortKeyType="a" 
      this.sortKey  = 0.0 
      this.sortKeyAlpha = userfield1.toUpperCase()
    } else {
      //numeric
      this.sortKeyType="N"
      this.date = new Date( "1 aug 3000" )
      this.sortKey = userfield1*1.0
    }
  } else {
    //date
    this.sortKeyType="d"
    this.sortKey = date.valueOf()
  }

  lastUpdated = name+", "+email+" at "+postedOn+" updating "+ userfield4 + ":" + userfield1 
  return this
}

// function call back for data stored in guestbook.
function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
  gbA[ count ] = new GB( 
    name,email,postedOn,IPaddress,
    userfield1,userfield2,userfield3,userfield4,
    comments
  );
  count++
}
  // Function used by sort.

function sortCallbackFn( a, b ) {
  if ( a.userfield1 != b.userfield1 ) {
    if ( a.userfield1 > b.userfield1 ){ return 1 }
    if ( a.userfield1 < b.userfield1 ){ return -1 }
    return 1
  }
  return ( b.count*1.0 - a.count*1.0 )
}

// Function used by sort.
function sortCallbackFn2( a, b ) {
  // sort into Alpha,Dates,Numbers first.
  if ( a.sortKeyType != b.sortKeyType ) { 
    if ( a.sortKeyType > b.sortKeyType ) {
      return 1
    }  
    return -1
  } 
  // item sorted down to Alpha,Date,Number
  if ( a.sortKey*1.0 == b.sortKey*1.0 ){
    if ( a.sortKeyAlpha == b.sortKeyAlpha ) {
      return -( a.count*1.0 - b.count*1.0 )
    } 
    if ( a.sortKeyAlpha > b.sortKeyAlpha ) {
      return 1
    }  
    return -1
  } else {
    return ( a.sortKey*1.0 - b.sortKey*1.0 )  
  }
}

</script>

<script> loading	= "./gbookFXXX.js" </script>
<script language = "JavaScript" src = "./gbookFXXX.js" type = "text/javascript"> </script>

<script> loading	= "http://ccgi.dougrice.plus.com/gb/gbookFXXX.js" </script>
<script language = "JavaScript" src = "http://ccgi.dougrice.plus.com/gb/gbookFXXX.js" type = "text/javascript"> </script>

Now display Guestbook data sorted by Userfield1 (ranked Number,alpha,date then sorted), then reversed submit order <P>
<script>
  gbA.sort( sortCallbackFn2 )
</script>

<table border=2 >
<script>
var opStr = ""
for( I=0; I< gbA.length ; I++ ){

  if ( lastUserfield1 != gbA[ I ].userfield1 ) {
    opStr = opStr+"<TR><TH colspan=5 >"+gbA[ I ].userfield1+"</TH></TR>"
  }
  lastUserfield1 = gbA[ I ].userfield1
  opStr = opStr+
    "<tr><td><B><A href='javascript:pop("+I+")'>"+ gbA[ I ].name +"</A></B>"+"<BR>"+gbA[ I ].email+
    " ("+gbA[ I ].IPaddress+")"+
    "<br>" + gbA[ I ].postedOn+
    "</td><td>"	+ gbA[ I ].userfield1+
    "</td><td>" + gbA[ I ].userfield2+
    "</td><td>" + gbA[ I ].userfield3+
    "</td><td>" + gbA[ I ].userfield4+
    "</td></tr>" +
    "<tr><td colspan=5 class=code ><PRE>"+ gbA[ I ].comments.replace(/<BR>/gi,"\n") +"</pre></td></tr>"+
    ""

}

self.document.write( opStr )


// pick up cookies for reload, and name and email
var today = new Date();
var expiry = new Date(today.getTime() + 365 * 24 * 60 * 60 * 1000);
//var expiry = new Date(today.getTime() + 1 * 1 * 5 * 60 * 1000);

// for the session iis sends first cookie = to what was assignd to document.cookie
// However IIS sends up anothe cookie for the ASP script, so split on "; " 

window.status = document.cookie

// split cookies
var cookiesA = document.cookie.split("; ") // split on ; and space
var cookieA = new Array()
// set up defaults 
cookieA[ "name" ] = "name"
cookieA[ "email" ] = ""

// break out the cookies into an associative array index by the string. 
for ( I=0 ; I < cookiesA.length ; I++ ){
  nvA = cookiesA[ I ].split("=")
  cookieA[ nvA[0] ] = nvA[1]
  //alert( nvA[0]+"="+cookieA[ nvA[0] ] )
}

if ( cookieA[ "reload" ] == "needed" ){
  document.cookie="reload=done"
  alert("reload needed ... reloading")
  document.location.reload( 1==1 )
}


function pop( gbA_row ){
  // pict up the data from the assorted file and fill in the update form.
  var F1 = window.document.forms["F1"]
  var record = gbA[ gbA_row ]	

  // This is picked up from a cookie
  F1.name.value = cookieA[ 'name' ]
  F1.email.value = cookieA[ 'email' ]

  F1.userfield1.value = record.userfield1
  F1.userfield2.value = record.userfield2
  F1.userfield3.value = record.userfield3
  F1.userfield4.value = record.userfield4
  F1.comments.value = record.comments.replace( /<BR>/g,"\n" )
  // focus on end and start of file to display form on screen.
  F1.comments.focus()
  F1.name.focus()
}


function validate(){
  var F1 = window.document.forms["F1"]

  if ( ( F1.name.value == "name" ) || ( F1.name.value == "undefined" ) ) {
    alert(' Please change the name and email address..')
    F1.name.focus()
    F1.name.select()
    return false
  }
  // 
  document.cookie="name="+ F1.name.value  + "; expires=" + expiry.toGMTString()
  document.cookie="email="+F1.email.value + "; expires=" + expiry.toGMTString()

  document.cookie="reload=needed"
  return true
}
</script> 

</table>
<h4> Update form </h4>

Click of the name above to use existing data, or edit the data below:-<BR>
<form name="F1" action="guestbook.asp" method="POST" onSubmit="return validate()">
<input type="text" name="name" value="name" size="20" > :name - set up by cookie<BR>
<input type="text" name="email" value="email" size="20" > :email - set up by cookie<BR>
<input type="text" name="userfield1" value="userfield1" size="20" > :userfield1<BR>
<input type="text" name="userfield2" value="userfield2" size="20" > :userfield2<BR> 
<input type="text" name="userfield3" value="userfield3" size="20" > :userfield3<BR>
<input type="text" name="userfield4" value="userfield4" size="20" > :userfield4<BR>

Please enter any comments:-<BR>
<textarea name="comments" rows="5" cols="80"></textarea>:comments<BR>

<HR>
Control Fields (Normally hidden):-<BR>
<input type="text" name="guestbook" size="20" value="XXX" onFocus="focusB1()" >guestbook. The form fields are appended to gbookFXXX.js<BR>
<input type="text" name="nextpage" size="50" value="http://www.dougrice.plus.com/hp/gbbook/simple/codeSortedNA.htm" onFocus="focusB1()" >nextpage - replaces this form<BR>
<input type="text" name="loadnextpage" size="50" value="loadnextpage" onFocus="focusB1()" >loadnextpage - flag <BR>
<input type="submit" name="B2" value="Submit -using guestbook.pl on apache based dougrice.plus.com" onClick="javaScript:submitPl()">

<script>
// add a button to allow user to use an Active-X function to write the form to a local file
if ( self.location.protocol == "file:" ){
  self.document.write('<BR>If running IE5.5 locally use Active - X to :<BR><input type="Button" name="B4" value="Append to local file: gbookFXXX.js" onClick="javascript:AXopFile(\'F1\')">')
}
</script>

</form>

<script>


var F1 = window.document.forms["F1"]
// This is picked up from a cookie
F1.name.value = cookieA[ 'name' ]
F1.email.value = cookieA[ 'email' ]

// if running locally
if ( self.location.protocol == "file:" ){
  var s = self.location.pathname 
  var s1 = s.replace( /codeSorted.htm/g,"gbookF"+F1.guestbook.value+".js" ) // remove file name
  F1.B4.value = " Add to the local disk file: " + s1
}


function submitPl( formName ){
  validate();
  var f = window.document.forms[ "F1" ] 
  F1.action="http://ccgi.dougrice.plus.com/cgi-bin/guestbook.pl"
//  F1.action="http://localhost/cgi-bin/guestbook.pl"
  F1.target="popup"

  F1.nextpage.value=location

  F1.submit()
  return ( 1==1 )
}



function strip ( s ) {
  s= s.replace( /\\/g,"\\\\")
  s= s.replace( /\"/g,"\\\"")
  s= s.replace( /\'/g,"\\\'")
  s= s.replace( /\n/g,"<BR>\\n")
  s= s.replace( /\r/g,"")
  return s
}

function focusB1( formName ){
  // Function that uses Active X to emulate remote ASP server
  var f = window.document.forms[ "F1" ]
  f.B1.focus()
}


function AXopFile( formName ){
  // Function that uses Active X to emulate remote ASP server
  var f = window.document.forms[ "F1" ] 
  var fs,s;
  var now = new Date()
  var s
  validate();
  s = self.location.pathname	// gives /D:\data\hp\gbbook\DHRsorted.htm
  s = s.replace( /\//g,"") // remove leading /
  s = s.replace( /codeSorted.htm/g,"gbookF"+f.guestbook.value+".js" ) // remove file name
  gbook=s
  alert( "Add to local File:\n"+gbook )

  var fs = new ActiveXObject("Scripting.FileSystemObject");

  if ( ! fs.FileExists( gbook ) ) {
    fs.CreateTextFile( gbook )
  }

  var ts = fs.OpenTextFile( gbook ,8 , 0 );

  ts.WriteLine("//Appended using Active X.");

  ts.WriteLine( "gbF( ")
  ts.WriteLine( "'" + strip ( f.name.value ) + "',")
  ts.WriteLine( "'" + strip ( f.email.value ) + "',")
  ts.WriteLine( "'" + now + "',")
  ts.WriteLine( "'127.0.0.1'," )
  ts.WriteLine( "'" + strip ( f.userfield1.value ) + "',")
  ts.WriteLine( "'" + strip ( f.userfield2.value ) + "',")
  ts.WriteLine( "'" + strip ( f.userfield3.value ) + "',")
  ts.WriteLine( "'" + strip ( f.userfield4.value ) + "',")
  ts.WriteLine( "'" + strip ( f.comments.value ) + "'" )
  ts.WriteLine( ");" )
  ts.WriteLine( " " )

  ts.Close();

  location.reload( 1==1 )
}
</script>
</body>
</html>

Collated Page codewebpagecollate.htm

<html>
<head>
<link rel="stylesheet" href="../club.css">
</head>
<body>
<script>

var gbA = new Array()
var count

function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
  var r = new Object()

  	r.name       = name
	r.email      = email
	r.postedOn   = postedOn
	r.IPaddress  = IPaddress
	r.userfield1 = userfield1
	r.userfield2 = userfield2
	r.userfield3 = userfield3
	r.userfield4 = userfield4
	r.comments   = comments
	r.link	     = ""

        // add extra fields, as data is loaded
	r.count      = count

	var index =  userfield1

	// Is this a new item, 
	//  if so store in gbA, 
	//else 
	//  prepend this record onto front of the list.

        if ( typeof( gbA[ index ] ) =="undefined" ){
 	  gbA[ index ] = r
        } else {
          // copy old object into r.link 
	  // This forms a linked list, with oldest at the end.
          r.link = gbA[ index ]
          gbA[ index ] = r

	}
        count=count+1
	return this
}

function displayRow( r ){
    self.document.write( 
      "<Tr>"+
        "<TD >"+ r.name+ "</TD><TD >"+ r.email+"</TD><TD >"+ r.postedOn+"</TD>"+
        "<TD >"+ r.IPaddress+ "</TD>"+
      "</TR>"+
      "<TR>"+
        "<TD ><B>"+ r.userfield1+"</B></TD><TD >"+ r.userfield2+	"</TD>"+
        "<TD >"+ r.userfield3+"</TD><TD >"+ r.userfield4+	"</TD>"+
      "</TR>"+
      "<TR>"+
        "<TD></TD><TD colspan = 7 class=code ><PRE>" + r.comments.replace(/<BR>/gi,"\n") + "</PRE></TD>"+
      "</TR>"
    )
}


</script>


<h4> The data from the guestbook is Collated by userfield1</h4>
This page uses an associative array gbA indexed by userfield1 gbA[ userfield1 ]<P>

A linked list is used to prepend the latest instance of gbA[ userfield1 ]. <P>
The list is sorted before presentation.

<table border=2 >

<script  language = "JavaScript"  src = "http://ccgi.dougrice.plus.com/gb/gbookFXXX.js"  type = "text/javascript">  </script>

<script>

  var indexA = new Array()
  count=0
  for( I in gbA ){
    indexA[ count ] = I
    count 	    = count + 1	
  }
  indexA.sort()

  for( var cnt=0; cnt < indexA.length; cnt++ ){
    var r = gbA[ indexA[cnt] ]
  
    self.document.write( "<TR><TH colspan = 8>&nbsp;<B>"+ r.userfield1+"</B> </TH></TR>" )
    displayRow( r )
    var sr=r

    // walk down the linked list 	
    while( sr.link != "" ){
	r=sr.link
        displayRow( r )
	sr=sr.link
    }
  }
</script>
</table>

</body>
</html>

Collated Page codewebpagetables.htm

<html>
<head>
<link rel="stylesheet" href="../club.css">
</head>
<body>
<script>

var gbA = new Array()
var count = 0
var indexA = new Array()

function gbF( name,email,postedOn,IPaddress,userfield1,userfield2,userfield3,userfield4,comments){
  var r = new Object()

  	r.name       = name
	r.email      = email
	r.postedOn   = postedOn
	r.IPaddress  = IPaddress
	r.userfield1 = userfield1
	r.userfield2 = userfield2
	r.userfield3 = userfield3
	r.userfield4 = userfield4
	r.comments   = comments
	r.link	     = ""

    	// add extra fields, as data is loaded
	var index =  userfield1
	// Is this a new item, 	if so store in gbA, else prepend this record onto front of the list.
        if ( typeof( gbA[ index ] ) =="undefined" ){
 	  gbA[ index ] = r
	  // also save index in an array so that it can be sorted ising indexA.sort()
	  indexA[ indexA.length ] = index
        } else {	
          // copy old object into r.link 
	  // This forms a linked list, with oldest at the end.
          r.link = gbA[ index ]
          gbA[ index ] = r
	}
        count=count+1
	return this
}

function displayRow( r ){
    self.document.write( 
      "<Tr>"+
        "<TD >"+ r.name+ "</TD><TD >"+ r.email+"</TD><TD >"+ r.postedOn+"</TD>"+
        "<TD >"+ r.IPaddress+ "</TD>"+
      "</TR>"+
      "<TR>"+
        "<TD ><B>"+ r.userfield1+"</B></TD><TD >"+ r.userfield2+	"</TD>"+
        "<TD >"+ r.userfield3+"</TD><TD >"+ r.userfield4+	"</TD>"+
      "</TR>"+
      "<TR>"+
        "<TD></TD><TD colspan = 7 class=code ><PRE>" + r.comments.replace(/<BR>/gi,"\n") + "</PRE></TD>"+
      "</TR>"
    )
}
</script>

<h4> The data from the guestbook is Collated by userfield1</h4>
This page uses an associative array gbA indexed by userfield1 gbA[ userfield1 ]<P>
A linked list is used to prepend the latest instance of gbA[ userfield1 ]. <P>
The list is sorted ( alphbetically and case sensitive ) before presentation.<P>
When displayed a speparate table is used for each value of USERFIELD1. Use the links below to jump to the table.<P>

<table border=2 >
<!-- local guestbook in same place as guestbook.asp --> 

<script  language = "JavaScript"  src = "http://ccgi.dougrice.plus.com/gb/gbookFXXX.js"  type = "text/javascript">  </script>

<script>
  indexA.sort()
  for( var cnt=0; cnt < indexA.length; cnt++ ){
    self.document.write( "<A href=#T" + cnt + ">" + indexA[ cnt ] + "<A> | " )
  }
  for( var cnt=0; cnt < indexA.length; cnt++ ){
    var r = gbA[ indexA[cnt] ]
    self.document.write( "<H4> <A name=T"+cnt+">"+r.userfield1+"<H4>" )
    self.document.write( "<table>" ) 	
    displayRow( r )
    var sr=r
    // walk down the linked list 	
    while( sr.link != "" ){
	r=sr.link
        displayRow( r )
	sr=sr.link
    }
    self.document.write( "</table>" ) 	
  }
</script>
</body>
</html>