'''What is it?''' I don't know about you, but I find that the most tedious and error-prone part of building a web site of any size is keeping all the links pointing the right way. Thus, I wrote WBuilder to help partially automate the process. ---- '''What does it do?''' The idea is that WBuilder makes it trivial to build a web site with a simple hierachical structure. Just create whatever folders you want, and populate them with *.wb files. Each such file contains some commands for WBuilder itself, and then an incomplete HTML page. WBuilder turns each *.wb file into a real HTML web page, and crosslinks them all automatically. And that is all. ---- '''Detailed Operation''' Each *.wb file becomes a normal HTML file (*.html). WBuilder does this by gluing some (hard-coded) stuff onto the top and bottom of the file. (If nothing else, this means you don't have to type in the 5-mile-long DOCTYPE declaration!) As coded, the headers added include an XHTML-strict DOCTYPE, and a reference to a stylesheet Root.css in the current folder. (But you could change that if you wanted.) Also puts the time of processing, the version of WBuilder, and some links to the W3C validator(s) on the bottom of the page. (Again, you could change if it you wanted.) In addition to this, every single page is given "breadcrumbs" - links that point to every page visited to get to this point. (Due to the strictly hierachical structure, there is only 1 possible path to each page.) On top of that, in every folder a file called Root.html is generated, which links to every file in the current folder, and the Root.html file in every subfolder (if any). (Last but not least, I have just finished a total rewrite of WBuilder to make it ''incremental''. That is, now it only generates ''altered'' pages, in a similar way to the "make" program recompiling C files...) ---- '''Source Code''' The source code consists of 6 seperate files: * libWrite.tcl (Contains the hard-coded HTML stuff.) * libFile.tcl (Contains a few trivial file utilities.) * libProcess.tcl (Slurps up the *.wb files and generates multiple *.tmp files from their contents.) * libBuild.tcl (Reads in *.tmp files and builds *.html files from them.) * libCompile.tcl (Does all the complex dependency chasing to rebuild ''only changed files''!) * WBuilder200.tcl (WBuilder v2.00 main script. [source]'s the other files and presents a nice clickable GUI.) The one you'll probably want to edit is libWrite.tcl. Note that the code contains a slight amount of weirdness because it's designed to be run by [FreeWrap]! And very few comments. And probably lots of stuff that could be done better. Top of File: '''libWrite.tcl''' proc WriteHead {Handle Title Scripts} \ { puts $Handle {} puts $Handle {} puts $Handle {} puts $Handle " Orphi.net: $Title" puts $Handle { } foreach Script $Scripts {puts $Handle " "} puts $Handle {} puts $Handle {} puts $Handle {} puts $Handle "

$Title

" puts $Handle {} } proc WriteBreadcrumbs {Handle Title Crumbs} \ { puts $Handle {} puts $Handle {} } proc WriteLinks {Handle Links} \ { puts $Handle {} puts $Handle {} } proc WriteTail {Handle} \ { global Version set DateTime [clock format [clock seconds] -format "%I:%M %p (%Z) on %a %d-%b-%Y"] puts $Handle {
} puts $Handle {} puts $Handle {

} puts $Handle "Built by WBuilder $Version at $DateTime." puts $Handle {

} puts $Handle {} puts $Handle {

} puts $Handle {} puts $Handle {Valid XHTML 1.0 Strict} puts $Handle {} puts $Handle {} puts $Handle {Valid CSS} puts $Handle {} puts $Handle {

} puts $Handle {} puts $Handle {} puts $Handle {} } Bottom of File: '''libWrite.tcl''' Top of File: '''libFile.tcl''' proc FContents {filename} \ { set IN [open $filename r] set Out [read -nonewline $IN] close $IN return $Out } proc FEmpty {filename} \ { set OUT [open $filename w] close $OUT } proc FWrite {filename data} \ { set OUT [open $filename w] puts $OUT $data close $OUT } Bottom of File: '''libFile.tcl''' Top of File: '''libProcess.tcl''' proc Process {filename} \ { puts "->Process: $filename" set IN [open "$filename.wb" r] set Title "(No Title)" set Scripts [list] while {![eof $IN]} \ { set Line [gets $IN] if {$Line=="#"} {break} set Line [split $Line ":"] set Key [lindex $Line 0] set Val [lindex $Line 1] if {$Key=="Title"} {set Title $Val} if {$Key=="Script"} {lappend Scripts $Val} } FWrite "$filename.title.tmp" $Title FWrite "$filename.scripts.tmp" $Scripts FWrite "$filename.data.tmp" [read $IN] close $IN } Bottom of File: '''libProcess.tcl''' Top of File: '''libBuild.tcl''' proc Build {filename} \ { set RootMode "no" if {[file tail $filename] == "Root"} {set RootMode "yes"} puts "->Build: $filename (Root Mode = $RootMode)" set Dir [file dirname $filename] set Title [FContents "$filename.title.tmp"] set Scripts [FContents "$filename.scripts.tmp"] set Crumbs [FContents [file join $Dir "Crumbs.tmp"]] if {!$RootMode} {lappend Crumbs [list "Root.html" [FContents [file join $Dir "Root.title.tmp"]]]} set OUT [open $filename.html w] WriteHead $OUT $Title $Scripts WriteBreadcrumbs $OUT $Title $Crumbs if {$RootMode} {WriteLinks $OUT [CollectLinks $Dir]} puts $OUT [FContents "$filename.data.tmp"] WriteTail $OUT close $OUT } proc CollectLinks {dirname} \ { puts "--->CollectLinks: $dirname" set Out [list] set Subs [glob -nocomplain -types d -directory $dirname -tails *] set Subs [lsort -ascii $Subs] foreach Sub $Subs \ { set File [file join $Sub "Root.html"] set Title [FContents [file join $dirname $Sub "Root.title.tmp"]] lappend Out [list $File $Title] } set Files [glob -nocomplain -types f -directory $dirname -tails *.wb] set Files [lsort -ascii $Files] foreach File $Files \ { if {$File=="Root.wb"} {continue} set Root [file rootname $File] set F "$Root.html" set T [FContents [file join $dirname "$Root.title.tmp"]] lappend Out [list $F $T] } return $Out } proc MakeCrumbs {dirname} \ { puts "->MakeCrumbs: $dirname" set Parent [file dirname $dirname] set Crumbs [FContents [file join $Parent "Crumbs.tmp"]] lappend Crumbs [list "Root.html" [FContents [file join $Parent "Root.title.tmp"]]] set Out [list] foreach Crumb $Crumbs \ { set File [lindex $Crumb 0] set Title [lindex $Crumb 1] set File [file join ".." $File] lappend Out [list $File $Title] } FWrite [file join $dirname "Crumbs.tmp"] $Out } Bottom of File: '''libBuild.tcl''' Top of File: '''libCompile.tcl''' proc Compile {dirname top} \ { puts "Compile: $dirname (Top = $top)" # Generate Crumbs.tmp set Crumbs [file join $dirname "Crumbs.tmp"] if {$top=="yes"} \ { UpdateIf [list] $Crumbs "FEmpty $Crumbs" } \ { set Parent [file dirname $dirname] set P1 [file join $Parent "Crumbs.tmp"] set P2 [file join $Parent "Root.title.tmp"] UpdateIf [list $P1 $P2] $Crumbs "MakeCrumbs $dirname" } # Check Root.wb exists set Root [file join $dirname "Root"] UpdateIf [list] "$Root.wb" "FEmpty \"$Root.wb\"" # Generate *.tmp set Files [glob -nocomplain -types f -directory $dirname *.wb] foreach File $Files \ { set F [file rootname $File] UpdateIf [list "$F.wb"] "$F.title.tmp" "Process $F" } # Generate *.html (except Root.html) foreach File $Files \ { set F [file rootname $File] if {[file tail $F]=="Root"} {continue} UpdateIf [list "$F.title.tmp"] "$F.html" "Build $F" } # Compile all subfolders set Subs [glob -nocomplain -types d -directory $dirname *] foreach Sub $Subs {Compile $Sub no ; lappend Files [file join $Sub "Root.wb"]} # Generate Root.html UpdateIf [concat $Files [list $Crumbs]] "$Root.html" "Build $Root" } proc UpdateIf {sources target command} \ { if {![file exists $target]} {eval $command ; return} set Time1 [file mtime $target] foreach Source $sources \ { if {$Time1 < [file mtime $Source]} {eval $command ; return} } } proc Clean {root_dir} \ { puts "Clean: $root_dir" set Subs [glob -nocomplain -types d -directory $root_dir *] foreach Sub $Subs {Clean $Sub} set Files [glob -nocomplain -types f -directory $root_dir *.tmp] foreach File $Files {file delete $File} set Files [glob -nocomplain -types f -directory $root_dir *.html] foreach File $Files {file delete $File} } Bottom of File: '''libCompile.tcl''' Top of File: '''WBuilder200.tcl''' set Version "2.00" set Date "03-Sep2-2006" set PATH "/Orphi/Tcl-Tk/WBuilder/v2" source "$PATH/libWrite.tcl" source "$PATH/libFile.tcl" source "$PATH/libProcess.tcl" source "$PATH/libBuild.tcl" source "$PATH/libCompile.tcl" proc Export {Src Dst} \ { puts "Export: $Src -> $Dst" if {![file exists $Dst]} {file mkdir $Dst} set Files [glob -nocomplain -types f -directory $Src *] foreach File $Files \ { if {[file extension $File]==".tmp"} {continue} if {[file extension $File]==".wb"} {continue} set FF [file tail $File] set DF [file join $Dst $FF] set Time1 [file mtime $File] set Time2 0 if {[file exists $DF]} {set Time2 [file mtime $DF]} if {$Time1 > $Time2} {puts "-->Copy $File" ; file copy -force $File $Dst} } set Subs [glob -nocomplain -types d -directory $Src *] foreach Sub $Subs \ { Export $Sub [file join $Dst [file tail $Sub]] } } proc DoIt {} \ { Compile "Src" "yes" puts "\n" Export "Src" "Dst" puts "\n\n" } console show console title "WBuilder $Version ($Date)" wm title . "WBuilder $Version" label .date -text "Written $Date" -font "Times 8 roman" button .go -text "Compile" -font "Times 12 roman" -bg #00FF00 -command {DoIt} button .clean -text "Clean" -font "Times 12 roman" -bg #FF0000 -command {Clean Src ; puts "\n"} button .quit -text "Quit" -font "Times 12 roman" -bg #0000FF -command {exit} pack .date -side top pack .go -side left pack .clean -side left pack .quit -side left Bottom of File: '''WBuilder200.tcl''' ---- '''Usage''' Put all 6 *.tcl files in the same place. Create a subfolder there called "Src", and put some *.wb files in there. Here is an example file: Title:This is a test #

Just checking to make sure this works!

Now start up a Tcl/Tk interpreter and [source] the file WBuilder200.tcl. (Should source the other files; you'll likely have to play with the silly hard-coded pathnames neccessary to make it work with [FreeWrap].) If it's working, you should get 3 buttons: Compile, Clean, Quit. Presumably the last button is self-explanetory. (?) The Compile button will scan the Src folder for *.wb files. For each such file, a matching *.html file will be created. If it doesn't already exist, an empty file Root.wb is created. This is the "index" page, if you like. The corresponding HTML page will link to every file in the whole folder. Next a folder called "Dst" is created, and every file in Src that is ''not'' a *.wb or *.tmp file is copied there. Upload this to your web server and go! You can also create subfolders and put *.wb files in there too. Note that all "root" pages list subfolders in ASCII order, then files in the same folder in ASCII order. (ASCII order of ''page titles'', but filenames.) If you edit any *.wb files and hit Compile again, it ''should'' recompile ''just that file'' (and also any "root" pages that mention it). BTW, the Clean button just deletes all the *.tmp files and the generated *.html files. If you do this, everything gets regenerated next time you compile... ---- '''Credits:''' Created by [The Mathematical Orchid]. ---- [Category Internet]