The following package uses tclhttpd templates (tml pages)and metakit to store and retrieve web form information. Tclhhtpd "proxies" form submissions/requests, thus giving a multiuser and pseudo "acidity" to metakit. Formkit's main use is to create webforms are sequentially used either to submit information or to display information retrived from a metakit database. Usually, one would create a "nice" looking form in an html editor, and then add the formkit specific stuff into it. Also demonstrated is the use of cookies within tclhttpd, wherein the table position is stored and passed around from form to form. The demo provided uses one table per form, although that could be modified, and works under the premise that tables are related through their row position, e.g "record 5 in table a is related to record 5 in table b". Note there is minimal error checking, and that the procs could be cleaned up alot, and the approach used is that a form is either "refered" or "self-posted". If refered, it is either a new entry, or an "edit" thus it should display information based on row position (extracted from the cookie). If self-posted, the form has to write its contents, and re-direct..... So to run the demo stuff, Put the pkgIndex and formkit files in tclhttpd's lib or custom dir Package require formkit source demo.tcl to create an empty db Point your browser to the htdocs directory where the index, zero, first and second .tml files reside Anyway, hope this is of use, and happy new year nicolas boretos #####pkgIndex.tcl##### package ifneeded formkit 0.1 [list source [file join $dir formkit.tcl]] #####end of pkgIndex.tcl #####formkit.tcl##### package provide formkit 0.1 #Boretos, 2002 namespace eval formkit { namespace export * } proc formkit::lock {db view} { if {$::env(HTTP_REFERER) != "[eval join {http://$::env(HTTP_HOST)$::page(url)}]"} { ####Form is refered, so lock record#### mk::row append locked.records db $db view $view position [Doc_Cookie position] } else { ####Form is self-posted, data has been written, so unlock record##### catch {mk::row delete locked.records![mk::select locked.records db $db view $view position [Doc_Cookie position]]} } } proc formkit::init {db view next_page} { if {$::env(HTTP_REFERER) == "[eval join {http://$::env(HTTP_HOST)$::page(url)}]"} { if {[lindex $::page(query) 1] == ""} { #####Means a new record, so set a table position cookie #### Doc_SetCookie -name position -value [mk::view size $db.$view] #####Write this record into the locked.records table##### #####It will have to be unlocked in the meta_page_done proc ::formkit::lock $db $view #####mk::row append locked.records db $db view $view position [mk::view size $db.$view] ##### and write the position, thus incrementing the actual table sizefor the next access##### mk::row append $db.$view position [mk::view size $db.$view] #####Redirect to the next page##### Doc_Redirect $next_page } else { #####Check to see if desired record exists##### #####This relies on the record position being first in the query data##### if {[expr {[lindex $::page(query) 1] >= [mk::view size $db.$view]}]} { set html "" append html "No Such Record" return $html } else { #####Check to see if desired record is locked, if not lock it##### if {[mk::select locked.records db $db view $view position [lindex $::page(query) 1]] == ""} { mk::row append locked.records db $db view $view position [lindex $::page(query) 1] } else { set html "" append html "Record Is Currently Locked, Try Another Record" return $html } #####Set a table position cookie### #####The position cookie relies on having the position as the first element #####in the query data, so design page accordingly### Doc_SetCookie -name position -value [lindex $::page(query) 1] #####Redirect to the next page##### Doc_Redirect $next_page } } } } ####This is used in all subsequent forms/pages excluding the last form proc formkit::page {db view next_page} { if {$::env(HTTP_REFERER) != "[eval join {http://$::env(HTTP_HOST)$::page(url)}]"} { ####Form is refered, lock the record and read values from the db.view to be displayed on the form#### ::formkit::lock $db $view eval mk::set $db.$view![Doc_Cookie position] position [Doc_Cookie position] foreach {name value} [mk::get $db.$view![Doc_Cookie position]] { upvar $name $name set $name $value } } else { ####Form is self-posted, so read the page values, write to the db, and redirect##### ####Add for correct display checkbox state and edit (resubmit) the value if necessary#### foreach i [mk::view info $db.$view] { set before($i) "" } eval mk::set $db.$view![Doc_Cookie position] [array get before] foreach {name value} $::page(query) { set $name $value lappend field_values $name $value } eval mk::set $db.$view![Doc_Cookie position] $field_values #####Comment the following if a commit is not desired for every page mk::file commit $db unset field_values unset before #####Unlock current record ::formkit::lock $db $view Doc_Redirect $next_page } } ####This is used in the last form/page proc formkit::done {db view next_page unlock_view} { if {$::env(HTTP_REFERER) != "[eval join {http://$::env(HTTP_HOST)$::page(url)}]"} { ####Form is refered, lock the record and read values from the db.view to be displayed on the form#### ::formkit::lock $db $view mk::set $db.$view![Doc_Cookie position] position [Doc_Cookie position] foreach {name value} [mk::get $db.$view![Doc_Cookie position]] { upvar $name $name set $name $value } } else { ####Form is self-posted, so write the page values, unlock record and redirect##### ####Add for correct display of checkbox state and edit (resubmit) the value if necessary#### foreach i [mk::view info $db.$view] { set before($i) "" } eval mk::set $db.$view![Doc_Cookie position] [array get before] foreach {name value} $::page(query) { set $name $value lappend field_values $name $value } eval mk::set $db.$view![Doc_Cookie position] $field_values #####Comment the following if a commit is not desired for every page mk::file commit $db unset field_values unset before #####Unlock current record ::formkit::lock $db $view #####Unlock the "main" view that was locked with meta_page_init###### catch {mk::row delete locked.records![mk::select locked.records db $db view $unlock_view position [Doc_Cookie position]]} Doc_Redirect $next_page } } #####Helper procs for check/radio box### proc formkit::checkbox {db view name value} { if {[mk::get $db.$view![Doc_Cookie position] $name] == $value} {return checked} } proc formkit::radio {db view name value} { if {[mk::get $db.$view![Doc_Cookie position] $name] == $value} {return checked} } ######end of formkit.tcl##### ######demo.tcl##### package require Mk4tcl #Open an in-memory file to store locked metakit records mk::file open locked mk::view layout locked.records {db view position} #Open and define our datafile mk::file open people people.dat mk::view layout people.names {position first last c1 c2} mk::view layout people.information {position email notes} #####end of demo.tcl #####Sample forms####### ####index.tml#### [ Doc_Dynamic ] Welcome

Enter Record Number to Edit, Or Submit to Add a New Record

#######end of index.tml##### #####zero.tml##### [ Doc_Dynamic ] [ ::formkit::init people names first.tml ] Zero.tml

######end of zero.tml#### ######first.tml##### [ package require formkit Doc_Dynamic ] [ ::formkit::page people names second.tml ] [ puts $page(query) ] First.tml

First Name

Last Name

OK

male

female

######end of first.tml##### ####second.tml##### [ Doc_Dynamic ] [ ::formkit::done people information index.tml names ] Second

email

notes

#######end of second.tml#####