Check-in [3e88960bb1]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:improve twv demo, again
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 3e88960bb152df7b369bf606db359f31769719ae
User & Date: chw 2019-06-13 10:46:03
Context
2019-06-13
12:53
update DiffUtilTcl to version 0.4.1 check-in: 00d59d6925 user: chw tags: trunk
10:46
improve twv demo, again check-in: 3e88960bb1 user: chw tags: trunk
07:46
fix pkg index template in tclcan check-in: 086eeca314 user: chw tags: trunk
Changes

Changes to undroid/tsb/examples/cheatsheet.tsb.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28



29
30
31
32
33
34
35
36
37






38
39
40



41
42
43
44
45
46
47
48

49

50


51
52
53
54



55
56




57
58
59
60
61
62
63
64
65
66
67
68
69
70

71
1 {h3 "Taygete Scrap Book Cheat Sheet"} 2 {h4 "Important (internal) global variables"} 3 {table 1 [info global {[A-Z]*}]} 4 {#HTML
<dl>
 <dt><b>ID</b></dt>
 <dd>The current input field during evaluation, an integer number.</dd>
 <dt><b>W</b></dt>
 <dd>The Webview for displaying the page.</dd>
 <dt><b>H</b></dt>
 <dd>The history array of input fields, keys are integer numbers starting from 1.</dd>
</dl>} 5 {# current state of history array
table 2 [array get H]} 6 {h4 "Useful procs in the global namespace"} 7 {info proc *} 8 {#HTML
<dl>
 <dt><code><b>parray</b> arrayname ?pattern?</code></dt>
 <dd>Pretty print an array using <code><b>puts</b></code> and thus outputs
     after the corresponding input field.</dd><br>
 <dt><code><b>htmlraw</b> html ?hidden?</code></dt>
 <dd>Output raw HTML after the corresponding input field, if <code>hidden</code>
     is true, auto-hide the input field.</dd><br>
 <dt><code><b>gets</b></code>, <code><b>read</b></code></dt>
 <dd>Overriden, reading from <code>stdin</code> channel yields empty
     string.</dd><br>
 <dt><code><b>puts</b></code></dt>
 <dd>Overriden, writing to <code>stdout</code>/<code>stderr</code> channels
     outputs after the corresponding input field.</dd><br>
 <dt><code><b>h1</b> string</code>, <code><b>h2..h5</b></code></dt>
 <dd>Format a HTML header after the correspondig input field, auto-hide
     the input field.</dd><br>
 <dt><code><b>hr</b></code></dt>
 <dd>Format a horizontal ruler, auto-hide the input field.</dd><br>



 <dt><code><b>img</b> ?filename import mime?</code></dt>
 <dd>Format a HTML IMG given <code>filename</code>, if file name omitted,
     present file selection. If <code>import</code> is true, the image is
     inlined. If the mime type of the image is unknown it can be specified
     with the <code>mime</code> parameter.</dd><br>
 <dt><code><b>img_from_binary</b> data mime ?hidden?</code></dt>
 <dd>Format a HTML IMG given the byte array <code>data</code> and mime
     type <code>mime</code>. If <code>hidden</code> is false, the corresponding
     input field is not auto-hidden.</dd><br>






 <dt><code><b>table</b> ncols data</code></dt>
 <dd>Format a HTML table, <code>ncols</code> gives the number of columns,
     if negative, use the first <code>-ncols</code> items as header columns.</dd>



</dl>} 9 {h4 "Useful procs in the tsb namespace"} 10 {info proc tsb::*} 11 {#HTML
<dl>
 <dt><code><b>tsb::load</b> ?filename?</code></dt>
 <dd>Load page from given <code>filename</code>, if file name omitted, present file selection.</dd><br>
 <dt><code><b>tsb::save</b> ?filename?</code></dt>
 <dd>Save page to given <code>filename</code>, if file name omitted, present file selection.</dd><br>
 <dt><code><b>tsb::canvas</b> ?-width w -height h?</code></dt>
 <dd>Creates a <code>canvas</code> emulation implementing enough methods for Plotchart, returns a widget command.</dd><br>

 <dt><code><b>tsb::canvascmd</b> cmd ...</code></dt>

 <dd>Implementation of the canvas widget command, supports <code>create</code>, <code>delete</code> and other methods plus method <code>svg</code> which renders the canvas as SVG after the corresponding input field.</dd><br>


 <dt><code><b>tsb::clear</b></code></dt>
 <dd>Clears the entire page.</dd><br>
 <dt><code><b>tsb::eval</b> id</code></dt>
 <dd>Re-evaluates field with number <code>id</code>.</dd><br>



 <dt><code><b>tsb::print</b></code></dt>
 <dd>Opens the print dialog to print the page.</dd>




</dl>} 12 {h4 "Input Fields"} 13 {#HTML
<p>Input fields have a label of the form <code>in(&lt;number&gt;)</code> where the
number is the index in the history array. Arbitraty text can be entered which
however should be valid Tcl code, except the very first line is <code>#HTML</code>
or <code>#MARKDOWN</code>, in which case the following lines should be valid HTML
or Markdown text, respectively. The input field is evaluated when
<code>&lt;Shift&gt;-&lt;Return&gt;</code> is pressed.</p>

<p>Depending on the command evaluation the input field is sometimes hidden.
A double click on the corresponding output field(s) makes the input field visible
and thus editable, again.</p>} 14 {h4 "Output Fields"} 15 {#HTML
<p>Each input field has two corresponding output fields which are visible/non-empty
depending on context. One output field receives preformatted text, either the result
or the error message of a command evaluation. The other output field receives HTML,

e.g. for displaying an image or for the <code>#HTML</code> form from the input field.</p>} 16 {tsb::save cheatsheet.tsb}
|








|

<
<
<
<
<
<



<
<
<





>
>
>









>
>
>
>
>
>
|
|
<
>
>
>
|

<
<
<
<

|
>

>
|
>
>




>
>
>

|
>
>
>
>






|







>
|
1
2
3
4
5
6
7
8
9
10
11






12
13
14



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

40
41
42
43
44




45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
1 {h3 "Taygete Scrap Book Cheat Sheet"} 2 {h4 "Important (internal) global variables"} 3 {table {{global variable}} [info global {[A-Z]*}]} 4 {#HTML
<dl>
 <dt><b>ID</b></dt>
 <dd>The current input field during evaluation, an integer number.</dd>
 <dt><b>W</b></dt>
 <dd>The Webview for displaying the page.</dd>
 <dt><b>H</b></dt>
 <dd>The history array of input fields, keys are integer numbers starting from 1.</dd>
</dl>} 5 {# current state of history array
table {key value} [array get H]} 6 {h4 "Useful procs in the global namespace"} 7 {lsort [info proc {[a-z]*}]} 8 {#HTML
<dl>






 <dt><code><b>gets</b></code>, <code><b>read</b></code></dt>
 <dd>Overriden, reading from <code>stdin</code> channel yields empty
     string.</dd><br>



 <dt><code><b>h1</b> string</code>, <code><b>h2..h5</b></code></dt>
 <dd>Format a HTML header after the correspondig input field, auto-hide
     the input field.</dd><br>
 <dt><code><b>hr</b></code></dt>
 <dd>Format a horizontal ruler, auto-hide the input field.</dd><br>
 <dt><code><b>htmlraw</b> html ?hidden?</code></dt>
 <dd>Output raw HTML after the corresponding input field, if <code>hidden</code>
     is true, auto-hide the input field.</dd><br>
 <dt><code><b>img</b> ?filename import mime?</code></dt>
 <dd>Format a HTML IMG given <code>filename</code>, if file name omitted,
     present file selection. If <code>import</code> is true, the image is
     inlined. If the mime type of the image is unknown it can be specified
     with the <code>mime</code> parameter.</dd><br>
 <dt><code><b>img_from_binary</b> data mime ?hidden?</code></dt>
 <dd>Format a HTML IMG given the byte array <code>data</code> and mime
     type <code>mime</code>. If <code>hidden</code> is false, the corresponding
     input field is not auto-hidden.</dd><br>
 <dt><code><b>parray</b> arrayname ?pattern?</code></dt>
 <dd>Pretty print an array using <code><b>puts</b></code> and thus outputs
     after the corresponding input field.</dd><br>
 <dt><code><b>puts</b></code></dt>
 <dd>Overriden, writing to <code>stdout</code>/<code>stderr</code> channels
     outputs after the corresponding input field.</dd><br>
 <dt><code><b>table</b> colinfo data</code></dt>
 <dd>Format a HTML table, <code>colinfo</code> gives the number of columns, if it's

     an integer; if negative, the first <code>-colinfo</code> items are used in the
     header row. If <code>colinfo</code> is a list, it specifies the column headers
     directly.</dd>
</dl>} 9 {h4 "Useful procs in the tsb namespace"} 10 {lsort [info proc tsb::*]} 11 {#HTML
<dl>




 <dt><code><b>tsb::canvas</b> ?-width w -height h?</code></dt>
 <dd>Creates a <code>canvas</code> emulation implementing enough methods
     for Plotchart, returns a widget command.</dd><br>
 <dt><code><b>tsb::canvascmd</b> cmd ...</code></dt>
 <dd>Implementation of the canvas widget command, supports
     <code>create</code>, <code>delete</code> and other methods plus
     method <code>svg</code> which renders the canvas as SVG after
     the corresponding input field.</dd><br>
 <dt><code><b>tsb::clear</b></code></dt>
 <dd>Clears the entire page.</dd><br>
 <dt><code><b>tsb::eval</b> id</code></dt>
 <dd>Re-evaluates field with number <code>id</code>.</dd><br>
 <dt><code><b>tsb::load</b> ?filename?</code></dt>
 <dd>Load page from given <code>filename</code>, if file name omitted,
     present file selection.</dd><br>
 <dt><code><b>tsb::print</b></code></dt>
 <dd>Opens the print dialog to print the page. Platform dependent,
     on Windows use <code>&lt;Control-p&gt;</code> from keyboard instead.</dd><br>
 <dt><code><b>tsb::save</b> ?filename?</code></dt>
 <dd>Save page to given <code>filename</code>, if file name omitted,
     present file selection.</dd>
</dl>} 12 {h4 "Input Fields"} 13 {#HTML
<p>Input fields have a label of the form <code>in(&lt;number&gt;)</code> where the
number is the index in the history array. Arbitraty text can be entered which
however should be valid Tcl code, except the very first line is <code>#HTML</code>
or <code>#MARKDOWN</code>, in which case the following lines should be valid HTML
or Markdown text, respectively. The input field is evaluated when
<code>&lt;Shift-Return&gt;</code> is pressed.</p>

<p>Depending on the command evaluation the input field is sometimes hidden.
A double click on the corresponding output field(s) makes the input field visible
and thus editable, again.</p>} 14 {h4 "Output Fields"} 15 {#HTML
<p>Each input field has two corresponding output fields which are visible/non-empty
depending on context. One output field receives preformatted text, either the result
or the error message of a command evaluation. The other output field receives HTML,
e.g. for displaying an image or for the <code>#HTML</code> and <code>#MARKDOWN</code>
formats from the input field.</p>} 16 {tsb::save cheatsheet.tsb}

Changes to undroid/tsb/tsb.tcl.

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

136
137





138
139
140
141
142
143
144
145
146
147

148
149
150
151



152
153
154
155
156

157
158
159
160
161
162
163
...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
...
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
...
698
699
700
701
702
703
704
705



706


707
708
709
710
711
712
713


714




715
716
717
718
719
720
721

















722
723
724



725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742

743
744
745
746
747
748
749
...
831
832
833
834
835
836
837
838
839
840
841
842
843
844


845
846
847
848

849
850





851
852
853
854
855
856
857
858
859
860
861
862
863
...
914
915
916
917
918
919
920
921
922
923
924

925
926
927
928
929
930
931
...
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
	if {$hidden} {
	    $::W call Inhide $::ID 1
	}
    }
    return
}

# Quote angle brackets and double quotes for HTML output.

proc ::tsb::htmlquote {str} {
    regsub -all -- "&" $str "\\&amp;" str
    regsub -all -- "<" $str "\\&lt;" str
    regsub -all -- ">" $str "\\&gt;" str
    regsub -all -- "\"" $str "\\&quot;" str
    return $str
}

# Simple HTML table formatter. If number of columns is negative,
# make a header, otherwise all columns are uniform.


proc table {ncols data} {





    if {$ncols == 0} {
	return
    }
    set ret "<table style='border: 1px solid;"
    append ret " margin-left: 1em; border-collapse: collapse; width: 90%'>"
    if {$ncols < 0} {
	set ncols [expr {0 - $ncols}]
	append ret "<tr>"
	for {set i 0} {$i < $ncols} {incr i} {
	    append ret "<th style='border: 1px solid;'><pre>" \

		[::tsb::htmlquote [lindex $data $i]] "</pre></th>"
	}
	append ret "</tr>"
	set data [lrange $data $ncols end]



    }
    while {[llength $data]} {
	append ret "<tr>"
	for {set i 0} {$i < $ncols} {incr i} {
	    append ret "<td style='border: 1px solid;'><pre>" \

		[::tsb::htmlquote [lindex $data $i]] "</pre></td>"
	}
	append ret "</tr>"
	set data [lrange $data $ncols end]
    }
    append ret "</table><br>"
    htmlraw $ret
................................................................................
    ::tsb::loadh [array get ::H]
}

proc ::tsb::reload {args} {
    after cancel ::tsb::reload0
    after idle ::tsb::reload0
}
 
# Clear page.

proc ::tsb::clear {} {
    variable inload
    if {$inload} {
	return
    }
................................................................................
# Evaluate field.

proc ::tsb::eval {id} {
    tailcall $::W call Feval $id
}

# Print page; on Windows seems not to work, but pressing
# <Control-p> opens the printer dialog.

proc ::tsb::print {} {
    tailcall $::W call window.print()
}

# A minimal canvas emulation for plotchart. The svg method
# produces SVG into the current (output) field.
................................................................................

namespace eval ::tsb {

    # JS core functions assembled from various pieces into a big string.

    variable D

    set D {<html><head>}



    


    if {$::tcl_platform(platform) eq "windows"} {
	append D {
	    <style>
	    body {
		font-family: Arial, Tahoma, sans-serif, Helvetica; font-size: 90%;
	    }
	    </style>


	}




    } else {
	append doc {
	    <style>
	    body {
		font-family: sans-serif, Helvetica; font-size: 90%;
	    }
	    </style>

















	}
    }




    append D {
	<script type="text/javascript">

	var msLike = /MSIE|Trident|Edge/i.test(navigator.userAgent);

	if (!msLike && !window.external) {
	    /* See also webview.h */
	    window.external = {
		invoke: function(str) {
		    window.webkit.messageHandlers.external.postMessage(str);
		}
	    };
	}
	
	var needsClear = new Array();

	var RunTcl = function(str) { window.external.invoke(str); };


	var Gtimer = window.setInterval(function() {
	    window.external.invoke("0 ::tsb::ping\n");
	}, 20);

	var Wclear = function(id) {
	    if (!needsClear[id]) {
		return;
................................................................................
	};

	var Feval = function(id) {
	    var input = document.getElementById('code' + id);
	    needsClear[id] = true;
	    RunTcl("" + id + " " + input.value);
	};
    
	var Field = function(id) {
	    var div = document.createElement('div');
	    div.classname = 'field';
	    var html = '<div class="field" id="in' + id + '">';
	    html += '<label for="code' + id + '"';
	    if (!msLike) {


		html += ' style="vertical-align:10px; font-family:monospace;"'
	    }
	    html += '>  in(' + id + ')  </label>';
	    html += '<textarea id="code' + id + '" rows="1"';

	    html += ' style="width:90%; resize:none;';
	    html += ' font-family:monospace; overflow:hidden">';





	    html += '</textarea></div><div class="field"';
	    html += ' id="out' + id + '-pre"';
	    if (msLike) {
		html += ' style="word-break:break-all"'
	    } else {
		html += ' style="overflow-wrap:break-word"'
	    }
	    html += '><pre></pre></div>';
	    html += '<div class="field" id="out' + id + '-raw"></div>';
	    div.innerHTML = html;
	    document.body.appendChild(div);
	    needsClear[id] = null;
	    var input = document.getElementById('code' + id);
................................................................................
	};

	/* Is this really needed? */
	window.addEventListener('unload', function(event) {
	    window.clearInterval(Gtimer);
	    Gtimer = null;
	});
				
	</script>
    }


    append D {</head><body></body></html>}

    # The URL to be displayed.
    # Windows:   data:text/html,<html><head><script>window.external.invoke("0 ::tsb::reload");</script></head></html>
    # MacOS:     data:text/html,<html><head><script>window.external.invoke("0 ::tsb::reload");</script></head></html>
    # WebkitGtk: data:text/html,<html><head><script>window.webkit.messageHandlers.extern.postMessage("0 ::tsb::reload");</script></head></html>

................................................................................
# which triggers ::tsb::reload which does the rest, but see
# the ::tsb::ready block below.

set W [::twv::new -width 800 -height 600 -title $::tsb::title \
	   -url $::tsb::U -resizable 1 -debug 0 \
	   -callback ::tsb::call_from_js]

# On Windows this seems needed.

if {!$::tsb::ready} {
    ::tsb::reload0
}

# Enter webview event loop.

$W run

# Done.

exit 0







|


|
<
<
<
<


|
|
>


>
>
>
>
>









|
>




>
>
>




|
>







 







|







 







|







 







|
>
>
>
|
>
>


<

|

<
>
>
|
>
>
>
>

|
<



<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



>
>
>













|




>







 







|





|
>
>
|



>
|
|
>
>
>
>
>
|


|

|







 







|



>







 







|





|






117
118
119
120
121
122
123
124
125
126
127




128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
...
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
...
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
...
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720

721
722
723

724
725
726
727
728
729
730
731
732

733
734
735

736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
...
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
...
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
....
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
	if {$hidden} {
	    $::W call Inhide $::ID 1
	}
    }
    return
}

# Quote angle brackets et.al. for HTML output.

proc ::tsb::htmlquote {str} {
    return [string map {& \&amp; < \&lt; > \&gt; "\"" \&quot;} $str]




}

# Simple HTML table formatter. If "ncols" is negative,
# make a header, otherwise omit headers. If "ncols" is
# not an integer it's taken as header list.

proc table {ncols data} {
    if {![string is integer $ncols]} {
	set tdata $data
	set data $ncols
	set ncols [expr {0 - [llength $data]}]
    }
    if {$ncols == 0} {
	return
    }
    set ret "<table style='border: 1px solid;"
    append ret " margin-left: 1em; border-collapse: collapse; width: 90%'>"
    if {$ncols < 0} {
	set ncols [expr {0 - $ncols}]
	append ret "<tr>"
	for {set i 0} {$i < $ncols} {incr i} {
	    append ret "<th style='border: 1px solid;'>" \
		"<pre style='margin: 0.25em;'>" \
		[::tsb::htmlquote [lindex $data $i]] "</pre></th>"
	}
	append ret "</tr>"
	set data [lrange $data $ncols end]
    }
    if {[info exists tdata]} {
	set data $tdata
    }
    while {[llength $data]} {
	append ret "<tr>"
	for {set i 0} {$i < $ncols} {incr i} {
	    append ret "<td style='border: 1px solid;'>" \
		"<pre style='margin: 0.25em;'>" \
		[::tsb::htmlquote [lindex $data $i]] "</pre></td>"
	}
	append ret "</tr>"
	set data [lrange $data $ncols end]
    }
    append ret "</table><br>"
    htmlraw $ret
................................................................................
    ::tsb::loadh [array get ::H]
}

proc ::tsb::reload {args} {
    after cancel ::tsb::reload0
    after idle ::tsb::reload0
}

# Clear page.

proc ::tsb::clear {} {
    variable inload
    if {$inload} {
	return
    }
................................................................................
# Evaluate field.

proc ::tsb::eval {id} {
    tailcall $::W call Feval $id
}

# Print page; on Windows seems not to work, but pressing
# <Control-p> opens the printer dialog at least.

proc ::tsb::print {} {
    tailcall $::W call window.print()
}

# A minimal canvas emulation for plotchart. The svg method
# produces SVG into the current (output) field.
................................................................................

namespace eval ::tsb {

    # JS core functions assembled from various pieces into a big string.

    variable D

    # HEAD
    set D {<!DOCTYPE html><html lang="en"><head>}
    append D {<meta charset="utf-8">}
    append D {<meta http-equiv="X-UA-Compatible" content="IE=edge">}

    # STYLE, CSS
    append D {<style>}
    if {$::tcl_platform(platform) eq "windows"} {
	append D {

	    body {
		font-family: Arial, Tahoma, Helvetica, sans-serif; font-size: 90%;
	    }

	    pre, code {
		font-family: Consolas, monospace; font-size: 90%;
	    }
	    textarea {
		font-size: 100%;
	    }
	}
    } else {
	append D {

	    body {
		font-family: sans-serif, Helvetica; font-size: 90%;
	    }

	}
    }

    append D {
	textarea {
	    border: 1px solid #AAAAAA;
	    margin: 5px 1px 3px 0px;
	    outline: none;
	    padding: 3px 0px 3px 3px;
	    -webkit-transition: all 0.05s ease-in-out;
            -ms-transition: all 0.05s ease-in-out;
	}
	textarea:focus {
	    border: 1px solid rgba(81, 203, 238, 1);
	    box-shadow: 0 0 6px rgba(81, 203, 238, 1);
	    margin: 5px 1px 3px 0px;
	    padding: 3px 0px 3px 3px;
	}
    }

    append D {</style>}

    # SCRIPT
    append D {
	<script type="text/javascript">

	var msLike = /MSIE|Trident|Edge/i.test(navigator.userAgent);

	if (!msLike && !window.external) {
	    /* See also webview.h */
	    window.external = {
		invoke: function(str) {
		    window.webkit.messageHandlers.external.postMessage(str);
		}
	    };
	}

	var needsClear = new Array();

	var RunTcl = function(str) { window.external.invoke(str); };

	/* The 2nd sin: this drives the Tcl event loop. */
	var Gtimer = window.setInterval(function() {
	    window.external.invoke("0 ::tsb::ping\n");
	}, 20);

	var Wclear = function(id) {
	    if (!needsClear[id]) {
		return;
................................................................................
	};

	var Feval = function(id) {
	    var input = document.getElementById('code' + id);
	    needsClear[id] = true;
	    RunTcl("" + id + " " + input.value);
	};

	var Field = function(id) {
	    var div = document.createElement('div');
	    div.classname = 'field';
	    var html = '<div class="field" id="in' + id + '">';
	    html += '<label for="code' + id + '"';
	    if (msLike) {
		html += ' style="font-family: Consolas, sans-serif;"';
	    } else {
		html += ' style="vertical-align: 10px; font-family: monospace;"';
	    }
	    html += '>  in(' + id + ')  </label>';
	    html += '<textarea id="code' + id + '" rows="1"';
	    if (msLike) {
		html += ' style="width: 90%; resize: none;';
		html += ' font-family: Consolas, monospace;';
		html += ' overflow: hidden">';
	    } else {
		html += ' style="width: 90%; resize: none;';
		html += ' font-family: monospace; overflow: hidden"';
	    }
	    html += '></textarea></div><div class="field"';
	    html += ' id="out' + id + '-pre"';
	    if (msLike) {
		html += ' style="word-wrap: break-word;"';
	    } else {
		html += ' style="overflow-wrap: break-word;"';
	    }
	    html += '><pre></pre></div>';
	    html += '<div class="field" id="out' + id + '-raw"></div>';
	    div.innerHTML = html;
	    document.body.appendChild(div);
	    needsClear[id] = null;
	    var input = document.getElementById('code' + id);
................................................................................
	};

	/* Is this really needed? */
	window.addEventListener('unload', function(event) {
	    window.clearInterval(Gtimer);
	    Gtimer = null;
	});

	</script>
    }

    # BODY (empty), END
    append D {</head><body></body></html>}

    # The URL to be displayed.
    # Windows:   data:text/html,<html><head><script>window.external.invoke("0 ::tsb::reload");</script></head></html>
    # MacOS:     data:text/html,<html><head><script>window.external.invoke("0 ::tsb::reload");</script></head></html>
    # WebkitGtk: data:text/html,<html><head><script>window.webkit.messageHandlers.extern.postMessage("0 ::tsb::reload");</script></head></html>

................................................................................
# which triggers ::tsb::reload which does the rest, but see
# the ::tsb::ready block below.

set W [::twv::new -width 800 -height 600 -title $::tsb::title \
	   -url $::tsb::U -resizable 1 -debug 0 \
	   -callback ::tsb::call_from_js]

# On Windows this seems the way to load, maybe timing?

if {!$::tsb::ready} {
    ::tsb::reload0
}

# Enter the webview event loop.

$W run

# Done.

exit 0