# http://benn7:8015/manual_nv2/2_30_3/main1.htm
# file://c:/htdocs/manual_nv2/2_30_3/main1.htm
# ------------------------------------------------------------
# Copyright (c) 2017-2017
# Q.W.Page Associates Inc.
# www.qwpage.com
# All rights reserved.
# ------------------------------------------------------------
/* {
Notes about paths.
All files for a manual edition are placed in the same folder:
c:/htdocs/manual_nv2/2_30_2
Each release has it's own folder. We didn't add release date to the folder
so that we could change the date at the last minute without needing to
rebuild the manual.
Each page filename is $PageId.htm. The path to the file is therefore relative.
Each image is an auto-incremented number with the image extension. Image
tags can reference the image file using a relative path.
*/ }
::itcl::class ::qw::browser_tree_builder {
protected variable _help_structure ""; # The help structure that we are compiling into a binary .chm file.
protected variable _root_directory ""; # Directory of target compiled binary .chm file.
protected variable _root_page_id "";
protected variable _initial_page_path "";
protected variable _directory ""; # Directory of target compiled binary .chm file.
protected variable _name ""; # Name of target compiled binary .chm file.
protected variable _path_list ""; # List of paths to every html page in the source help structure.
protected variable _page_id_by_path_array; # Array of page ids indexed by page path.
protected variable _bodies_by_path_array; # Array of formatted bodies indexed by page path.
protected variable _chtml_title "NewViews Help";
protected variable _formatter "";
protected variable _generator "qw help generator";
protected variable _sargs "";
protected variable _command "";
# protected variable _url "benn7"; # http://benn7:8015/paned_demo2.htm
protected variable _destination_folder "";
protected variable _source_folder "";
# protected variable _url_prefix "http://benn7:8015/manual_nv2/2_30_3";
protected variable _url_prefix "";
protected variable _rebuild_everything 1;
protected variable _max_levels 1000; # i.e. infinity
protected variable _html_extension htm;
# protected variable _url_prefix "file://c:/htdocs/manual_nv2/2_30_3";
# protected variable _saved_current_directory "";
method constructor {} {
::array set _page_id_by_path_array {};
::array set _bodies_by_path_array {};
}
destructor {
::if {$_formatter ne ""} {
::itcl::delete object $_formatter;
::set _formatter "";
}
}
method process_pages {sargs} {
/* {
We start by getting a list of paths to every page in the help structure.
Each page has a unique id obtained from its .id field, or
for now, if there is no .id, it is generated from the structure field id.
*/ }
::set rwb1_debug 0;
::set PathList [::sargs::select_field .structure $_help_structure .field ".title"];
::foreach Path $PathList {
/* {
We select only those pages that are a hit.
*/ }
::set Tags [::sargs::get $_help_structure ${Path}.tags];
::if {[chtml_page_tags_hit [::sargs::get $_help_structure ${Path}]]} {
::lappend _path_list $Path;
}
}
::if {$rwb1_debug} {
::set i 0;
::foreach Path $_path_list {
::puts "rwb1_debug,2223.0,_path_list\[$i\]==$Path";
::incr i;
}
}
::foreach Path $_path_list {
# ::qw::warning "314120050324083416" "Encountered help page with no id,title==[::sargs::get $_help_structure $Path.title]";
::if {[::sargs::get $_help_structure $Path.id] eq ""} {
/* {
Some pages forgot to set an .id so we set it from the last element
in its path which should be unique id anyway.
*/ }
::sargs::var::set _help_structure $Path.id [::lindex [::split $Path /] end];
}
/* {
We now have a path. Set that path in the page.
*/ }
::sargs::var::set _help_structure $Path.path $Path;
::set Page [::sargs::get $_help_structure $Path];
::set PageId [::sargs::get $Page .id];
# don't see how this is consistent with anything
# ::if {[::info exists _page_id_by_path_array($PageId)]} {::qw::throw "Encountered duplicate page id \"$PageId\".";}
::if {$Path eq ""} {
::set Path "root";
::set _root_page_id $PageId;
}
::set _page_id_by_path_array($Path) $PageId;
::qw::try {
::sargs::var::+= Page $_sargs;
::if {$_rebuild_everything} {
::set RenderedPage [$_formatter page_render $Page];
} else {
::set RenderedPage $Page;
}
/* {
::sargs::var::set RenderedPage .body [::subst {
This is page id - $PageId
Page Id $PageId
}];
*/ }
} catch Exception {
::qw::throw [::qw::exception::parent $Exception "Could not render the page identified by path \"$Path\"."];
}
::set _bodies_by_path_array($Path) [::sargs::get $RenderedPage .body];
}
::if {$rwb1_debug} {
# ::puts "rwb1_debug,_help_structure==\n[::sargs::format $_help_structure]";
}
::if ${_rebuild_everything} {
::set CarcassList [::glob -nocomplain -- [::file join $_destination_folder *.*]];
::foreach Carcass $CarcassList {
::file_delete -force -- Carcass;
}
::foreach Path $_path_list {
::if {$Path eq ""} {
::set Path "root";
}
::set Handle [::open [::file join $_destination_folder $_page_id_by_path_array($Path).$_html_extension] w+];
::puts -nonewline $Handle $_bodies_by_path_array($Path);
::close $Handle;
}
}
}
method check_images {} {
/* {
Gets the list of used images and the list of all images in the help folder
and determines which ones are never actually used. Write these to a sub-folder.
*/ }
::return;
::set UsedImages "";
::foreach {SrcPath DstName} [$_formatter images] {
::lappend UsedImages [::string tolower [::file tail $SrcPath]];
}
::set Folder [::file join c:/ qw_manual_216];
::set ImagesInDirectory "";
::foreach Pattern {*.jpg *.gif *.png *.bmp} {
::foreach Path [::glob [::file join $Folder $Pattern]] {
::lappend ImagesInDirectory [::string tolower [::file tail $Path]];
}
}
::set Result [::qw::intersect3 $UsedImages $ImagesInDirectory];
::set ImagesUsedButNotFound [::lindex $Result 0];
::set UnusedImages [::lindex $Result 2];
::puts "Images used but not found:"
::set Handle [::open [::file join $Folder images_used_but_not_found.txt] w+];
::foreach Image $ImagesUsedButNotFound {
::puts "$Image";
::puts $Handle "$Image";
}
::close $Handle;
::set OldFolder [::file join $Folder images_unreferenced];
::file mkdir $OldFolder;
::puts "Images found but not used:"
::set Handle [::open [::file join $Folder images_unused.txt] w+];
::foreach File $UnusedImages {
::puts $Handle "$File";
::set Name [::file tail $File];
::puts "Moving and deleting $File";
::file copy -force [::file join $Folder $File] [::file join $OldFolder $Name];
::file delete -force -- [::file join $Folder $File];
}
/* {
::foreach Image $UnusedImages {
::puts $Handle "$Image";
::set Name [::file tail $Image];
::set Files [::glob -nocomplain [::file join $Folder [::file rootname $Image]].*];
::foreach File $Files {
::puts "Moving and deleting $File";
::file copy -force $File [::file join $OldFolder [::file tail $File]];
::file delete -force -- File;
}
}
*/ }
}
method generate_webpage_header {} {
/* {
*/ }
/* {
defaults: {
resizable: true
}
*/ }
/* {
The following was working. We then copied them all into htdocs/jquery
2.38.0
The following link stopped working.
http://layout.jquery-dev.com/lib/js/jquery.layout-latest.js
Replaced it with the following link:
https://cdnjs.cloudflare.com/ajax/libs/jquery-layout/1.4.3/jquery.layout.min.js
Ward found the problem and the solution.
*/ }
::set WindowTitle [::sargs::get $_sargs .window_title];
::if {$WindowTitle eq ""} {
::set WindowTitle "NewViews Help";
}
::return [::subst {
$WindowTitle
}];
}
method generate_webpage_footer {} {
/* {
We set the event listener on the root item in the help tree. This
item is a LI element and all other LI elements are below it in the
DOM tree. Therefore the root receives all events. Otherwise we would
need a separate listener on every LI node in the tree.
*/ }
::set PageId $_root_page_id;
::set OnScripts [::subst -nocommands {
jQuery('#$PageId').click(function(Event) {
var Current=this;
/*
current - is the elelent the event handler was attached to
target - the mouse clicked on this element
*/
var Target=Event.target;
var PageId=Target.id.substr(0,Target.id.indexOf("_"));
var Element=jQuery('#'+PageId)[0];
/*
We have the element. Now let's use ajax to load it.
Note that we have to put in some checks. The element is an LI
and maybe we could add a class or other local information to help
identify it.
*/
var Url='$_url_prefix/'+Element.id+'.$_html_extension';
jQuery('#center_pane').attr("src",Url);
});
}];
::return [::subst -nocommands {
}];
}
method generate_center_pane {} {
::return {
The Center Pane
The right of the people to be secure in their persons, houses, papers,
and effects against unreasonable searches and seizures shall not be violated, and no Warrants shall issue but
upon probable cause, supported by Oath or affirmation, and particularly
describing the place to be searched and the persons
or things to be seized.
}
}
method generate_north_pane {} {
::return {
The North Pane
The right of the people to be secure in their persons, houses, papers,
and effects against unreasonable searches and seizures shall not be violated, and no Warrants shall issue but
upon probable cause, supported by Oath or affirmation, and particularly
describing the place to be searched and the persons
or things to be seized.
The right of the people to be secure in their persons, houses, papers,
and effects against unreasonable searches and seizures shall not be violated, and no Warrants shall issue but
upon probable cause, supported by Oath or affirmation, and particularly
describing the place to be searched and the persons
or things to be seized.
}
}
method generate_east_pane {} {
::return {
The East Pane
The right of the people to be secure in their persons, houses, papers,
and effects against unreasonable searches and seizures shall not be violated, and no Warrants shall issue but
upon probable cause, supported by Oath or affirmation, and particularly
describing the place to be searched and the persons
or things to be seized.
}
}
method generate_west_pane {} {
::return {
The West Pane
The right of the people to be secure in their persons, houses, papers,
and effects against unreasonable searches and seizures shall not be violated, and no Warrants shall issue but
upon probable cause, supported by Oath or affirmation, and particularly
describing the place to be searched and the persons
or things to be seized.
}
}
method generate_south_pane {} {
::return {
The South Pane
The right of the people to be secure in their persons, houses, papers,
and effects against unreasonable searches and seizures shall not be violated, and no Warrants shall issue but
upon probable cause, supported by Oath or affirmation, and particularly
describing the place to be searched and the persons
or things to be seized.
}
}
method generate_multipane_webpage {sargs} {
::set rwb1_debug 0;
/* {
This is the content of the main page.
*/ }
# ------------------------------------------------------------
# Root page (in addition to being a branch page)
# ------------------------------------------------------------
::if {$rwb1_debug} {::puts "rwb1_debug,generate_multipane,1000.0";}
::set WebPage "";
::append WebPage [generate_webpage_header];
::if {$rwb1_debug} {::puts "rwb1_debug,generate_multipane,1000.1";}
/* {
::append WebPage [::subst {
}];
*/ }
::if {$rwb1_debug} {::puts "rwb1_debug,generate_multipane,1000.7";}
::append WebPage [generate_webpage_footer];
::if {$rwb1_debug} {::puts "rwb1_debug,generate_multipane,1000.8";}
# ::append WebPage $HelpTree;
# ::append WebPage $HelpPage;
# ::append WebPage $MultipaneFooter;
::set FilePath [::file join $_destination_folder main1.$_html_extension]
::set Handle [::open $FilePath w+];
::puts -nonewline $Handle "$WebPage";
::close $Handle;
::if {$rwb1_debug} {::puts "rwb1_debug,generate_multipane,1000.9";}
}
method generate_help_tree {sargs} {
/* {
Usage: generate_help_tree .path $Path .level $Level;
.path - path to current tree node. Empty implies root page.
.level - current level in tree, used when debugging to limit depth
for faster turnaround
Creates a hierarchy using ul and li tags.
Root node 1
Child node 1
Child node 2
Root node 2
*/ }
/* {
Once an instance is ready you can invoke methods on it. There is a list of
available methods in the API documentation. The three examples below do
exactly the same thing:
jQuery('button').on('click', function () {
jQuery('#jstree').jstree(true).select_node('child_node_1');
jQuery('#jstree').jstree('select_node', 'child_node_1');
$.jstree.reference('#jstree').select_node('child_node_1');
});
class="jstree-open"
*/ }
::set rwb1_debug 0;
::set Icon "https://www.jstree.com/tree.png";
::set Icon "$_url_prefix/jstree/images/moTreeC.gif";
#rwb_debug - rwb_todo we have to fix this, maybe copy into destination folder
# may have to come out of the vfs
::set Icon "file://c:/htdocs/jstree/images/moTreeC.gif";
::set Path [::sargs::get $sargs .path];
::set Level [::sargs::integer_get $sargs .level];
/* {
::switch -- $_url {
"benn7" {
::set Icon "http://benn7:8015/jstree/images/moTreeC.gif";
}
default {
::set Icon "file://c:/htdocs/jstree/images/moTreeC.gif";
}
}
*/ }
::if {$rwb1_debug} {::puts "rwb1_debug,jstree_generate,1000.0";}
::if {$Path eq ""} {
::set SubNameList [::sargs::subs .structure $_help_structure];
} else {
::set SubNameList [::sargs::subs .structure [::sargs::get $_help_structure $Path]];
}
::if {$rwb1_debug} {::puts "rwb1_debug,jstree_generate,1000.1";}
::set Result "";
::if {$rwb1_debug} {::puts "rwb1_debug,jstree_generate,1000.2";}
::set Title [::sargs::get $_help_structure $Path.title];
::set PageId [::sargs::get $_help_structure $Path.id];
::if {$rwb1_debug} {::puts "rwb1_debug,jstree_generate,1000.3,Path==$Path";}
# onclick="alert('Page $PageId about to load');jQuery('center_pane').load('file://c:/htdocs/web_manual/$PageId.htm');"
# onclick="console.log('Page $PageId about to load');"
# onclick="jQuery('#center_pane').load('file://c:/htdocs/web_manual/$PageId.htm');"
::if {$Level>=$_max_levels||[::llength $SubNameList]==0} {
# ------------------------------------------------------------
# Leaf page.
# ------------------------------------------------------------
::if {$rwb1_debug} {::puts "rwb1_debug,jstree_generate,1000.4";}
::if {$Path eq ""} {
# ------------------------------------------------------------
# Root leaf page.
# ------------------------------------------------------------
/* {
Leaf page that is also root. Only one page in the tree.
*/ }
::append Result [::subst {
$Title
}];
::return $Result;
}
# ------------------------------------------------------------
# Non-root leaf page.
# ------------------------------------------------------------
/* {
Leaf page that is also root. Root slightly different because it
is given class "jstree-open", so it will be expanded.
*/ }
::append Result [::subst {
}];
::append Result "\n";
::if {$rwb1_debug} {::puts "rwb1_debug,jstree_generate,1000.5";}
::return $Result;
}
::if {$rwb1_debug} {::puts "rwb1_debug,jstree_generate,1000.6";}
::if {$Path eq ""} {
# ------------------------------------------------------------
# Root branch page.
# ------------------------------------------------------------
/* {
Branch page that is also root. Root slightly different because it
is given class "jstree-open", so it will be expanded.
*/ }
::append Result "
\n";
::append Result [::subst {
$Title
}];
::foreach SubName $SubNameList {
::append Result [[::qw::methodname] .path $Path$SubName .level [::expr {$Level+1}]];
}
::append Result [::subst {