Datasheet interface
[ Previous: How I'm writing pages out ]
[ Top: To-do manager ]
[ Next: Interpreting the results that wftk sends back ]
For working with datasheets, I'm defining two procedures: datasheet_getvalue
goes to the datasheet associated with a process and retrieves a data value, and
datasheet_setvalue
sets the named value. (And of course does other XML
maintenance, like create the file if necessary.)
These functions will be used in the task/process show and update functions.
There are two global settings we'll need:
These functions, by the way, are based on my
command-line XML utilities to simplify the
Tcl end. The xmltools are written on James Clark's
expat, a nice, solid XML parser.
These functions are in turn called by datasheet_showdata
, which, given a process
ID and optional task ID, iterates down the list of data to display data attached to the
named task or to the process if the task is not supplied. The same function is used to
generate either an editing form or a simple static view. The output is organized into
table rows of two columns; this output is assumed to be assigned to a tag, so that the
table element itself will be supplied elsewhere (usually on the format page.)
In addition to the basic functions, I'm defining one URL handler, setvalue; setvalue will
take a process and task ID and information about the value or values, and create it or replace
it using datasheet_setvalue
. The corresponding use of
datasheet_getvalue
is kind of here and there throughout the show screens.
|
ns_register_proc GET $todomgr_root/setvalue setvalue
ns_register_proc POST $todomgr_root/setvalue setvalue
See URL handler setvalue
|
URL handler setvalue
This proc handles value setting operations by making calls to datasheet_setvalue
.
Obviously this isn't the most efficient way of handling things, but it works, and it's
extremely modular, so it should be easy to maintain. In the interests of scalability, we'll
want to investigate more integrated approaches to datasheet maintenance.
|
proc setvalue {conn ignore} {
set form [ns_conn form $conn]
if {$form == ""} {
set tags(title) "No parameters given"
set tags(body) "You can't set a value without giving the value."
return [todomgr_pageout $conn message.html]
}
set process [ns_set get $form process]
set task [ns_set get $form task]
set newname [ns_set get $form newname]
if [string compare "" $newname] {
datasheet_setvalue $process $task $newname [ns_set get $form type] ""
return [ns_returnredirect $conn [ns_set get $form back]
}
set size [ns_set size $form]
for {set i 0} {$i < $size} {incr i} {
if {-1 < [lsearch {process task back newname type} [ns_set key $form $i]]} { continue }
datasheet_setvalue $process $task [ns_set key $form $i] "" [ns_set value $form $i]
}
return [ns_returnredirect $conn [ns_set get $form back]]
}
|
Definition of datasheet_getvalue
The getvalue procedure must not only retrieve the value, but format it as an appropriate
field as well so that we can include it into a form for update. The active
parameter governs whether the caller wants a form field or just a value; the return
from the proc is a list consisting of name, type, and the value or field insert.
I have the feeling that paragraph didn't make a lot of sense, so I'll probably come back
and rewrite it later.
At any rate, the data values attached to a task or directly to the process are accessed
not by name, but by number. This allows a form to be built by scanning up until a blank
return. The return value is a list consisting of the data item's: id, type, value, the
HTML needed to edit the value, and a full list of attributes attached to the element.
Note the gyrations required to detect an empty data element (i.e. a data value with a
value of the empty string.) Sheesh.
|
proc datasheet_getvalue {process task number {active 0}} {
global todomgr_datasheets
global todomgr_xmltools
set datasheet "$todomgr_datasheets/$process"
if ![file exists $datasheet] return ""
set loc datasheet
if [string compare $task ""] { append loc ".task\[$task\]" }
append loc ".data($number)"
set data [exec $todomgr_xmltools/xmlsnip $loc $datasheet]
if {0 == [regexp ^<(\[^<\]*)> $data tag bits]} { return "" }
if [string match */ $bits] {
set data ""
regsub /$ $bits "" bits
} else {
regsub ^<\[^<\]*> $data "" data
regsub <\[^>\]*>$ $data "" data
}
set fields [list]
set id ""
set type ""
set bits [split [join [lrange [split $bits] 1 end]] =]
set name [lindex $bits 0]
foreach bit [lrange $bits 1 end] {
set bit [split $bit \"]
lappend fields [list $name [lindex $bit 1]]
switch $name {
id { set id [lindex $bit 1] }
type { set type [lindex $bit 1] }
}
set name [string trim [lindex $bit 2]]
}
switch $type {
string { set html "<input name=\"$id\" value=\"$data\">" }
text { set html "<textarea name=\"$id\" rows=5 cols=40>$data</textarea>" }
default { set html "<input name=\"$id\" value=\"$data\">" }
}
return [list $id $type $data $html $fields]
}
|
Definition of datasheet_showdata
The datasheet_showdata
is used from the task and process screens to build the
form necessary to edit attached data (or simply to view it otherwise). If the action is
edit
, then it needs the back
parameter to give to the setvalue
URL handler as a redirect target.
|
proc datasheet_showdata {action back process task} {
set retval ""
set i 0
while (1) {
set d [datasheet_getvalue $process $task $i]
incr i
if ![string compare "" [lindex $d 0]] { break }
if {$action == "edit"} {
append retval "<tr><td>[lindex $d 0]:</td><td>[lindex $d 3]</td></tr>\n"
} else {
append retval "<tr><td>[lindex $d 0]:</td><td>[lindex $d 2]</td></tr>\n"
}
}
if {$action == "edit" && $retval != ""} {
set retval "<form action=setvalue method=post>\n$retval"
append retval "<input type=hidden name=process value=\"$process\">\n"
append retval "<input type=hidden name=task value=\"$task\">\n"
append retval "<input type=hidden name=back value=\"$back\">\n"
append retval "<tr><td colspan=2><center>"
append retval "<input type=submit value=\"Update values\"></center></td></tr>\n"
append retval "</form>\n"
}
return $retval
}
|
Definition of datasheet_setvalue
To set the value, we have to
- Make sure there's a file there
- If this is a task value, make sure the task has an entry in the datasheet
- Make sure there's a value there
- Finally, replace (or insert) the value.
Not too onerous, eh?
|
proc datasheet_setvalue {process task name type value} {
if ![string compare "" $process] { return }
regsub -all "\"" $name ' name
global todomgr_datasheets
global todomgr_xmltools
set datasheet "$todomgr_datasheets/$process"
set loc datasheet
if [string compare $task ""] { append loc ".task\[$task\]" }
if ![file exists $datasheet] {
exec $todomgr_xmltools/xmlcreate datasheet > $datasheet
}
if [string compare $task ""] {
set taskloc [exec $todomgr_xmltools/xmlsnip -otl datasheet.task\[$task\] $datasheet]
if ![string compare $taskloc ""] {
exec mv $datasheet $datasheet.~
set pipe [open "|$todomgr_xmltools/xmlinsert aftercontent datasheet $datasheet.~ > $datasheet" w]
puts $pipe ""
puts $pipe ""
close $pipe
}
}
set dataloc [exec $todomgr_xmltools/xmlsnip -otl $loc.data\[$name\] $datasheet]
if [string compare $dataloc ""] {
exec mv $datasheet $datasheet.~
regsub -all " " $name "\\ " n
set cmd "|$todomgr_xmltools/xmlreplace -m $loc.data\[$n\] $datasheet.~ > $datasheet"
set pipe [open $cmd w]
puts -nonewline $pipe $value
close $pipe
} else {
exec mv $datasheet $datasheet.~
set cmd "|$todomgr_xmltools/xmlinsert aftercontent $loc $datasheet.~ > $datasheet"
set pipe [open $cmd w]
puts $pipe "$value"
close $pipe
}
}
|
[ Previous: How I'm writing pages out ]
[ Top: To-do manager ]
[ Next: Interpreting the results that wftk sends back ]
This code and documentation are released under the terms of the GNU license. They are
additionally copyright (c) 2000, Vivtek. All rights reserved except those explicitly
granted under the terms of the GNU license.
|