Fossil SCM

Add a hamburger menu that brings up an overlaid /sitemap to the default skin.

drh 2018-09-11 00:10 trunk merge
Commit 9c887998ca54c0ca8f4c4331ac600e27dfd1eeb14180c434a62486a4a38e401c
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -83,10 +83,11 @@
8383
border:1px solid #eaeaea;
8484
border-radius:5px;
8585
overflow-x: auto;
8686
overflow-y: hidden;
8787
white-space: nowrap;
88
+ z-index: 21; /* just above hbdrop */
8889
}
8990
9091
.mainmenu a {
9192
text-decoration:none;
9293
color: #777;
@@ -95,10 +96,24 @@
9596
.mainmenu a.active,
9697
.mainmenu a:hover {
9798
color: #000;
9899
border-bottom:2px solid #D26911;
99100
}
101
+
102
+div#hbdrop {
103
+ background-color: white;
104
+ border: 1px solid black;
105
+ border-top: white;
106
+ border-radius: 0 0 0.5em 0.5em;
107
+ display: none;
108
+ font-size: 80%;
109
+ left: 2em;
110
+ width: 90%;
111
+ padding-right: 1em;
112
+ position: absolute;
113
+ z-index: 20; /* just below mainmenu, but above timeline bubbles */
114
+}
100115
101116
.submenu {
102117
font-size: .7em;
103118
padding: 10px;
104119
border-bottom: 1px solid #ccc;
105120
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -83,10 +83,11 @@
83 border:1px solid #eaeaea;
84 border-radius:5px;
85 overflow-x: auto;
86 overflow-y: hidden;
87 white-space: nowrap;
 
88 }
89
90 .mainmenu a {
91 text-decoration:none;
92 color: #777;
@@ -95,10 +96,24 @@
95 .mainmenu a.active,
96 .mainmenu a:hover {
97 color: #000;
98 border-bottom:2px solid #D26911;
99 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
101 .submenu {
102 font-size: .7em;
103 padding: 10px;
104 border-bottom: 1px solid #ccc;
105
--- skins/default/css.txt
+++ skins/default/css.txt
@@ -83,10 +83,11 @@
83 border:1px solid #eaeaea;
84 border-radius:5px;
85 overflow-x: auto;
86 overflow-y: hidden;
87 white-space: nowrap;
88 z-index: 21; /* just above hbdrop */
89 }
90
91 .mainmenu a {
92 text-decoration:none;
93 color: #777;
@@ -95,10 +96,24 @@
96 .mainmenu a.active,
97 .mainmenu a:hover {
98 color: #000;
99 border-bottom:2px solid #D26911;
100 }
101
102 div#hbdrop {
103 background-color: white;
104 border: 1px solid black;
105 border-top: white;
106 border-radius: 0 0 0.5em 0.5em;
107 display: none;
108 font-size: 80%;
109 left: 2em;
110 width: 90%;
111 padding-right: 1em;
112 position: absolute;
113 z-index: 20; /* just below mainmenu, but above timeline bubbles */
114 }
115
116 .submenu {
117 font-size: .7em;
118 padding: 10px;
119 border-bottom: 1px solid #ccc;
120
--- skins/default/footer.txt
+++ skins/default/footer.txt
@@ -1,5 +1,131 @@
11
<div class="footer">
22
This page was generated in about
33
<th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
44
Fossil $release_version $manifest_version $manifest_date
55
</div>
6
+
7
+<th1>
8
+ html "<script nonce='$nonce'>"
9
+ html " (function() { var home='$home'; "
10
+</th1>
11
+ var panel = document.getElementById("hbdrop");
12
+ if (!panel) return; // site admin might've nuked it
13
+ var panelBorder = panel.style.border;
14
+ var animate = panel.style.hasOwnProperty('transition');
15
+ var animMS = 400;
16
+
17
+ // Calculate panel height despite its being hidden at call time.
18
+ // Based on https://stackoverflow.com/a/29047447/142454
19
+ var panelHeight; // computed on sitemap load
20
+ function calculatePanelHeight() {
21
+ // Get initial panel styles so we can restore them below.
22
+ var es = window.getComputedStyle(panel),
23
+ edis = es.display,
24
+ epos = es.position,
25
+ evis = es.visibility;
26
+
27
+ // Restyle the panel so we can measure its height while invisible.
28
+ panel.style.visibility = 'hidden';
29
+ panel.style.position = 'absolute';
30
+ panel.style.display = 'block';
31
+ panelHeight = panel.offsetHeight + 'px';
32
+
33
+ // Revert styles now that job is done.
34
+ panel.style.display = edis;
35
+ panel.style.position = epos;
36
+ panel.style.visibility = evis;
37
+ }
38
+
39
+ // Show the panel by changing the panel height, which kicks off the
40
+ // slide-open/closed transition set up in the XHR onload handler.
41
+ //
42
+ // Schedule the change for a near-future time in case this is the
43
+ // first call, where the div was initially invisible. That causes
44
+ // the browser to consider the height change as part of the same
45
+ // state change as the visibility change, so it doesn't see a state
46
+ // *transition*, hence never kicks off the *CSS* transition:
47
+ //
48
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions#JavaScript_examples
49
+ function showPanel() {
50
+ if (animate) {
51
+ setTimeout(function() {
52
+ panel.style.maxHeight = panelHeight;
53
+ panel.style.border = panelBorder;
54
+ }, 40); // 25ms is insufficient with Firefox 62
55
+ }
56
+ else {
57
+ panel.style.display = 'block';
58
+ }
59
+ }
60
+
61
+ // Return true if the panel is showing.
62
+ function panelShowing() {
63
+ if (animate) {
64
+ return panel.style.maxHeight == panelHeight;
65
+ }
66
+ else {
67
+ return panel.style.display == 'block';
68
+ }
69
+ }
70
+
71
+ // Click handler for the hamburger button.
72
+ var needSitemapHTML = true;
73
+ document.querySelector("div.mainmenu > a").onclick = function() {
74
+ if (panelShowing()) {
75
+ // Transition back to hidden state.
76
+ if (animate) {
77
+ panel.style.maxHeight = '0';
78
+ setTimeout(function() {
79
+ // Browsers show a 1px high border line when maxHeight == 0,
80
+ // our "hidden" state, so hide the borders in that state, too.
81
+ panel.style.border = 'none';
82
+ }, animMS);
83
+ }
84
+ else {
85
+ panel.style.display = 'none';
86
+ }
87
+ }
88
+ else if (needSitemapHTML) {
89
+ // Only get it once per page load: it isn't likely to
90
+ // change on us.
91
+ var xhr = new XMLHttpRequest();
92
+ xhr.onload = function() {
93
+ var doc = xhr.responseXML;
94
+ if (doc) {
95
+ var sm = doc.querySelector("ul#sitemap");
96
+ if (sm && xhr.status == 200) {
97
+ // Got sitemap. Insert it into the drop-down panel.
98
+ needSitemapHTML = false;
99
+ panel.innerHTML = sm.outerHTML;
100
+ if (window.setAllHrefs) {
101
+ setAllHrefs(); // don't need anti-robot defense here
102
+ }
103
+
104
+ // Display the panel
105
+ if (animate) {
106
+ // Set up a CSS transition to animate the panel open and
107
+ // closed. Only needs to be done once per page load.
108
+ // Based on https://stackoverflow.com/a/29047447/142454
109
+ calculatePanelHeight();
110
+ panel.style.transition = 'max-height ' +
111
+ (animMS / 1000) + 's ease-in-out';
112
+ panel.style.overflowY = 'hidden';
113
+ panel.style.maxHeight = '0';
114
+ showPanel();
115
+ }
116
+ panel.style.display = 'block';
117
+ }
118
+ }
119
+ // else, can't parse response as HTML or XML
120
+ }
121
+ xhr.open("GET", home + "/sitemap");
122
+ xhr.responseType = "document";
123
+ xhr.send();
124
+ }
125
+ else {
126
+ showPanel(); // just show what we built above
127
+ }
128
+ return false; // prevent browser from acting on <a> click
129
+ }
130
+ })();
131
+</script>
6132
--- skins/default/footer.txt
+++ skins/default/footer.txt
@@ -1,5 +1,131 @@
1 <div class="footer">
2 This page was generated in about
3 <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
4 Fossil $release_version $manifest_version $manifest_date
5 </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
--- skins/default/footer.txt
+++ skins/default/footer.txt
@@ -1,5 +1,131 @@
1 <div class="footer">
2 This page was generated in about
3 <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by
4 Fossil $release_version $manifest_version $manifest_date
5 </div>
6
7 <th1>
8 html "<script nonce='$nonce'>"
9 html " (function() { var home='$home'; "
10 </th1>
11 var panel = document.getElementById("hbdrop");
12 if (!panel) return; // site admin might've nuked it
13 var panelBorder = panel.style.border;
14 var animate = panel.style.hasOwnProperty('transition');
15 var animMS = 400;
16
17 // Calculate panel height despite its being hidden at call time.
18 // Based on https://stackoverflow.com/a/29047447/142454
19 var panelHeight; // computed on sitemap load
20 function calculatePanelHeight() {
21 // Get initial panel styles so we can restore them below.
22 var es = window.getComputedStyle(panel),
23 edis = es.display,
24 epos = es.position,
25 evis = es.visibility;
26
27 // Restyle the panel so we can measure its height while invisible.
28 panel.style.visibility = 'hidden';
29 panel.style.position = 'absolute';
30 panel.style.display = 'block';
31 panelHeight = panel.offsetHeight + 'px';
32
33 // Revert styles now that job is done.
34 panel.style.display = edis;
35 panel.style.position = epos;
36 panel.style.visibility = evis;
37 }
38
39 // Show the panel by changing the panel height, which kicks off the
40 // slide-open/closed transition set up in the XHR onload handler.
41 //
42 // Schedule the change for a near-future time in case this is the
43 // first call, where the div was initially invisible. That causes
44 // the browser to consider the height change as part of the same
45 // state change as the visibility change, so it doesn't see a state
46 // *transition*, hence never kicks off the *CSS* transition:
47 //
48 // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions#JavaScript_examples
49 function showPanel() {
50 if (animate) {
51 setTimeout(function() {
52 panel.style.maxHeight = panelHeight;
53 panel.style.border = panelBorder;
54 }, 40); // 25ms is insufficient with Firefox 62
55 }
56 else {
57 panel.style.display = 'block';
58 }
59 }
60
61 // Return true if the panel is showing.
62 function panelShowing() {
63 if (animate) {
64 return panel.style.maxHeight == panelHeight;
65 }
66 else {
67 return panel.style.display == 'block';
68 }
69 }
70
71 // Click handler for the hamburger button.
72 var needSitemapHTML = true;
73 document.querySelector("div.mainmenu > a").onclick = function() {
74 if (panelShowing()) {
75 // Transition back to hidden state.
76 if (animate) {
77 panel.style.maxHeight = '0';
78 setTimeout(function() {
79 // Browsers show a 1px high border line when maxHeight == 0,
80 // our "hidden" state, so hide the borders in that state, too.
81 panel.style.border = 'none';
82 }, animMS);
83 }
84 else {
85 panel.style.display = 'none';
86 }
87 }
88 else if (needSitemapHTML) {
89 // Only get it once per page load: it isn't likely to
90 // change on us.
91 var xhr = new XMLHttpRequest();
92 xhr.onload = function() {
93 var doc = xhr.responseXML;
94 if (doc) {
95 var sm = doc.querySelector("ul#sitemap");
96 if (sm && xhr.status == 200) {
97 // Got sitemap. Insert it into the drop-down panel.
98 needSitemapHTML = false;
99 panel.innerHTML = sm.outerHTML;
100 if (window.setAllHrefs) {
101 setAllHrefs(); // don't need anti-robot defense here
102 }
103
104 // Display the panel
105 if (animate) {
106 // Set up a CSS transition to animate the panel open and
107 // closed. Only needs to be done once per page load.
108 // Based on https://stackoverflow.com/a/29047447/142454
109 calculatePanelHeight();
110 panel.style.transition = 'max-height ' +
111 (animMS / 1000) + 's ease-in-out';
112 panel.style.overflowY = 'hidden';
113 panel.style.maxHeight = '0';
114 showPanel();
115 }
116 panel.style.display = 'block';
117 }
118 }
119 // else, can't parse response as HTML or XML
120 }
121 xhr.open("GET", home + "/sitemap");
122 xhr.responseType = "document";
123 xhr.send();
124 }
125 else {
126 showPanel(); // just show what we built above
127 }
128 return false; // prevent browser from acting on <a> click
129 }
130 })();
131 </script>
132
--- skins/default/header.txt
+++ skins/default/header.txt
@@ -17,10 +17,11 @@
1717
html "<a href='$home$url' class='active $cls'>$name</a>\n"
1818
} else {
1919
html "<a href='$home$url' class='$cls'>$name</a>\n"
2020
}
2121
}
22
+html "<a href='#'>&#9776;</a>"
2223
menulink $index_page Home {}
2324
if {[anycap jor]} {
2425
menulink /timeline Timeline {}
2526
}
2627
if {[hascap oh]} {
@@ -39,13 +40,10 @@
3940
if {[hascap j]} {
4041
menulink /wiki Wiki wideonly
4142
}
4243
if {[hascap s]} {
4344
menulink /setup Admin {}
44
- menulink /sitemap More... wideonly
4545
} elseif {[hascap a]} {
4646
menulink /setup_ulist Users {}
47
- menulink /sitemap More... {}
48
-} else {
49
- menulink /sitemap More... {}
5047
}
5148
</th1></div>
49
+<div id='hbdrop'></div>
5250
5351
ADDED skins/default/script.txt
--- skins/default/header.txt
+++ skins/default/header.txt
@@ -17,10 +17,11 @@
17 html "<a href='$home$url' class='active $cls'>$name</a>\n"
18 } else {
19 html "<a href='$home$url' class='$cls'>$name</a>\n"
20 }
21 }
 
22 menulink $index_page Home {}
23 if {[anycap jor]} {
24 menulink /timeline Timeline {}
25 }
26 if {[hascap oh]} {
@@ -39,13 +40,10 @@
39 if {[hascap j]} {
40 menulink /wiki Wiki wideonly
41 }
42 if {[hascap s]} {
43 menulink /setup Admin {}
44 menulink /sitemap More... wideonly
45 } elseif {[hascap a]} {
46 menulink /setup_ulist Users {}
47 menulink /sitemap More... {}
48 } else {
49 menulink /sitemap More... {}
50 }
51 </th1></div>
 
52
53 DDED skins/default/script.txt
--- skins/default/header.txt
+++ skins/default/header.txt
@@ -17,10 +17,11 @@
17 html "<a href='$home$url' class='active $cls'>$name</a>\n"
18 } else {
19 html "<a href='$home$url' class='$cls'>$name</a>\n"
20 }
21 }
22 html "<a href='#'>&#9776;</a>"
23 menulink $index_page Home {}
24 if {[anycap jor]} {
25 menulink /timeline Timeline {}
26 }
27 if {[hascap oh]} {
@@ -39,13 +40,10 @@
40 if {[hascap j]} {
41 menulink /wiki Wiki wideonly
42 }
43 if {[hascap s]} {
44 menulink /setup Admin {}
 
45 } elseif {[hascap a]} {
46 menulink /setup_ulist Users {}
 
 
 
47 }
48 </th1></div>
49 <div id='hbdrop'></div>
50
51 DDED skins/default/script.txt
--- a/skins/default/script.txt
+++ b/skins/default/script.txt
@@ -0,0 +1,6 @@
1
+
2
+ (animMS / 1000) + home='$home'; "000) + 'That causes
3
+ // the browser to consider the height change as part of the same
4
+ // state change as the visibility change, so it doesn't see a state
5
+ // *transition*, hence never kicks off the *CSS*home + "/sitemap");
6
+ (animMS / 1000) + '+ 'GE);
--- a/skins/default/script.txt
+++ b/skins/default/script.txt
@@ -0,0 +1,6 @@
 
 
 
 
 
 
--- a/skins/default/script.txt
+++ b/skins/default/script.txt
@@ -0,0 +1,6 @@
1
2 (animMS / 1000) + home='$home'; "000) + 'That causes
3 // the browser to consider the height change as part of the same
4 // state change as the visibility change, so it doesn't see a state
5 // *transition*, hence never kicks off the *CSS*home + "/sitemap");
6 (animMS / 1000) + '+ 'GE);
+2 -3
--- src/sitemap.c
+++ src/sitemap.c
@@ -45,12 +45,11 @@
4545
4646
login_check_credentials();
4747
srchFlags = search_restrict(SRCH_ALL);
4848
style_header("Site Map");
4949
style_adunit_config(ADUNIT_RIGHT_OK);
50
- @ <div class="columns" style="column-width:20em">
51
- @ <ul>
50
+ @ <ul id="sitemap" class="columns" style="column-width:20em">
5251
@ <li>%z(href("%R/home"))Home Page</a>
5352
for(i=0; i<sizeof(aExtra)/sizeof(aExtra[0]); i++){
5453
char *z = db_get(aExtra[i].zProperty,0);
5554
if( z==0 || z[0]==0 ) continue;
5655
if( !inSublist ){
@@ -210,8 +209,8 @@
210209
}
211210
@ <li>%z(href("%R/hash-color-test"))Page to experiment with the automatic
212211
@ colors assigned to branch names</a>
213212
@ <li>%z(href("%R/test-captcha"))Random ASCII-art Captcha image</a></li>
214213
@ </ul></li>
215
- @ </ul></div>
214
+ @ </ul>
216215
style_footer();
217216
}
218217
--- src/sitemap.c
+++ src/sitemap.c
@@ -45,12 +45,11 @@
45
46 login_check_credentials();
47 srchFlags = search_restrict(SRCH_ALL);
48 style_header("Site Map");
49 style_adunit_config(ADUNIT_RIGHT_OK);
50 @ <div class="columns" style="column-width:20em">
51 @ <ul>
52 @ <li>%z(href("%R/home"))Home Page</a>
53 for(i=0; i<sizeof(aExtra)/sizeof(aExtra[0]); i++){
54 char *z = db_get(aExtra[i].zProperty,0);
55 if( z==0 || z[0]==0 ) continue;
56 if( !inSublist ){
@@ -210,8 +209,8 @@
210 }
211 @ <li>%z(href("%R/hash-color-test"))Page to experiment with the automatic
212 @ colors assigned to branch names</a>
213 @ <li>%z(href("%R/test-captcha"))Random ASCII-art Captcha image</a></li>
214 @ </ul></li>
215 @ </ul></div>
216 style_footer();
217 }
218
--- src/sitemap.c
+++ src/sitemap.c
@@ -45,12 +45,11 @@
45
46 login_check_credentials();
47 srchFlags = search_restrict(SRCH_ALL);
48 style_header("Site Map");
49 style_adunit_config(ADUNIT_RIGHT_OK);
50 @ <ul id="sitemap" class="columns" style="column-width:20em">
 
51 @ <li>%z(href("%R/home"))Home Page</a>
52 for(i=0; i<sizeof(aExtra)/sizeof(aExtra[0]); i++){
53 char *z = db_get(aExtra[i].zProperty,0);
54 if( z==0 || z[0]==0 ) continue;
55 if( !inSublist ){
@@ -210,8 +209,8 @@
209 }
210 @ <li>%z(href("%R/hash-color-test"))Page to experiment with the automatic
211 @ colors assigned to branch names</a>
212 @ <li>%z(href("%R/test-captcha"))Random ASCII-art Captcha image</a></li>
213 @ </ul></li>
214 @ </ul>
215 style_footer();
216 }
217
+9 -4
--- src/skins.c
+++ src/skins.c
@@ -55,13 +55,15 @@
5555
{ "Khaki, No Logo", "khaki", 0 },
5656
{ "Ardoise", "ardoise", 0 },
5757
};
5858
5959
/*
60
-** A skin consists of four "files" named here:
60
+** A skin consists of five "files" named here:
6161
*/
62
-static const char *azSkinFile[] = { "css", "header", "footer", "details" };
62
+static const char *azSkinFile[] = {
63
+ "css", "header", "footer", "details", "js"
64
+};
6365
6466
/*
6567
** Alternative skins can be specified in the CGI script or by options
6668
** on the "http", "ui", and "server" commands. The alternative skin
6769
** name must be one of the aBuiltinSkin[].zLabel names. If there is
@@ -149,11 +151,11 @@
149151
150152
/*
151153
** The following routines return the various components of the skin
152154
** that should be used for the current run.
153155
**
154
-** zWhat is one of: "css", "header", "footer", "details".
156
+** zWhat is one of: "css", "header", "footer", "details", "js"
155157
*/
156158
const char *skin_get(const char *zWhat){
157159
const char *zOut;
158160
char *z;
159161
if( iDraftSkin ){
@@ -691,11 +693,11 @@
691693
** WEBPAGE: setup_skinedit
692694
**
693695
** Edit aspects of a skin determined by the w= query parameter.
694696
** Requires Setup privileges.
695697
**
696
-** w=NUM -- 0=CSS, 1=footer, 2=header, 3=details
698
+** w=NUM -- 0=CSS, 1=footer, 2=header, 3=details, 4=js
697699
** sk=NUM -- the draft skin number
698700
*/
699701
void setup_skinedit(void){
700702
static const struct sSkinAddr {
701703
const char *zFile;
@@ -704,10 +706,11 @@
704706
} aSkinAttr[] = {
705707
/* 0 */ { "css", "CSS", "CSS", },
706708
/* 1 */ { "footer", "Page Footer", "Footer", },
707709
/* 2 */ { "header", "Page Header", "Header", },
708710
/* 3 */ { "details", "Display Details", "Details", },
711
+ /* 4 */ { "js", "JavaScript", "Script", },
709712
};
710713
const char *zBasis; /* The baseline file */
711714
const char *zOrig; /* Original content prior to editing */
712715
const char *zContent; /* Content after editing */
713716
const char *zDflt; /* Default content */
@@ -1016,10 +1019,12 @@
10161019
@ Header</a>
10171020
@ <li><a href='%R/setup_skinedit?w=1&sk=%d(iSkin)' target='_blank'>\
10181021
@ Footer</a>
10191022
@ <li><a href='%R/setup_skinedit?w=3&sk=%d(iSkin)' target='_blank'>\
10201023
@ Details</a>
1024
+ @ <li><a href='%R/setup_skinedit?w=4&sk=%d(iSkin)' target='_blank'>\
1025
+ @ Javascript</a> (optional)
10211026
@ </ul>
10221027
}
10231028
@
10241029
@ <a name='step5'></a>
10251030
@ <h1>Step 5: Verify The Draft Skin</h1>
10261031
--- src/skins.c
+++ src/skins.c
@@ -55,13 +55,15 @@
55 { "Khaki, No Logo", "khaki", 0 },
56 { "Ardoise", "ardoise", 0 },
57 };
58
59 /*
60 ** A skin consists of four "files" named here:
61 */
62 static const char *azSkinFile[] = { "css", "header", "footer", "details" };
 
 
63
64 /*
65 ** Alternative skins can be specified in the CGI script or by options
66 ** on the "http", "ui", and "server" commands. The alternative skin
67 ** name must be one of the aBuiltinSkin[].zLabel names. If there is
@@ -149,11 +151,11 @@
149
150 /*
151 ** The following routines return the various components of the skin
152 ** that should be used for the current run.
153 **
154 ** zWhat is one of: "css", "header", "footer", "details".
155 */
156 const char *skin_get(const char *zWhat){
157 const char *zOut;
158 char *z;
159 if( iDraftSkin ){
@@ -691,11 +693,11 @@
691 ** WEBPAGE: setup_skinedit
692 **
693 ** Edit aspects of a skin determined by the w= query parameter.
694 ** Requires Setup privileges.
695 **
696 ** w=NUM -- 0=CSS, 1=footer, 2=header, 3=details
697 ** sk=NUM -- the draft skin number
698 */
699 void setup_skinedit(void){
700 static const struct sSkinAddr {
701 const char *zFile;
@@ -704,10 +706,11 @@
704 } aSkinAttr[] = {
705 /* 0 */ { "css", "CSS", "CSS", },
706 /* 1 */ { "footer", "Page Footer", "Footer", },
707 /* 2 */ { "header", "Page Header", "Header", },
708 /* 3 */ { "details", "Display Details", "Details", },
 
709 };
710 const char *zBasis; /* The baseline file */
711 const char *zOrig; /* Original content prior to editing */
712 const char *zContent; /* Content after editing */
713 const char *zDflt; /* Default content */
@@ -1016,10 +1019,12 @@
1016 @ Header</a>
1017 @ <li><a href='%R/setup_skinedit?w=1&sk=%d(iSkin)' target='_blank'>\
1018 @ Footer</a>
1019 @ <li><a href='%R/setup_skinedit?w=3&sk=%d(iSkin)' target='_blank'>\
1020 @ Details</a>
 
 
1021 @ </ul>
1022 }
1023 @
1024 @ <a name='step5'></a>
1025 @ <h1>Step 5: Verify The Draft Skin</h1>
1026
--- src/skins.c
+++ src/skins.c
@@ -55,13 +55,15 @@
55 { "Khaki, No Logo", "khaki", 0 },
56 { "Ardoise", "ardoise", 0 },
57 };
58
59 /*
60 ** A skin consists of five "files" named here:
61 */
62 static const char *azSkinFile[] = {
63 "css", "header", "footer", "details", "js"
64 };
65
66 /*
67 ** Alternative skins can be specified in the CGI script or by options
68 ** on the "http", "ui", and "server" commands. The alternative skin
69 ** name must be one of the aBuiltinSkin[].zLabel names. If there is
@@ -149,11 +151,11 @@
151
152 /*
153 ** The following routines return the various components of the skin
154 ** that should be used for the current run.
155 **
156 ** zWhat is one of: "css", "header", "footer", "details", "js"
157 */
158 const char *skin_get(const char *zWhat){
159 const char *zOut;
160 char *z;
161 if( iDraftSkin ){
@@ -691,11 +693,11 @@
693 ** WEBPAGE: setup_skinedit
694 **
695 ** Edit aspects of a skin determined by the w= query parameter.
696 ** Requires Setup privileges.
697 **
698 ** w=NUM -- 0=CSS, 1=footer, 2=header, 3=details, 4=js
699 ** sk=NUM -- the draft skin number
700 */
701 void setup_skinedit(void){
702 static const struct sSkinAddr {
703 const char *zFile;
@@ -704,10 +706,11 @@
706 } aSkinAttr[] = {
707 /* 0 */ { "css", "CSS", "CSS", },
708 /* 1 */ { "footer", "Page Footer", "Footer", },
709 /* 2 */ { "header", "Page Header", "Header", },
710 /* 3 */ { "details", "Display Details", "Details", },
711 /* 4 */ { "js", "JavaScript", "Script", },
712 };
713 const char *zBasis; /* The baseline file */
714 const char *zOrig; /* Original content prior to editing */
715 const char *zContent; /* Content after editing */
716 const char *zDflt; /* Default content */
@@ -1016,10 +1019,12 @@
1019 @ Header</a>
1020 @ <li><a href='%R/setup_skinedit?w=1&sk=%d(iSkin)' target='_blank'>\
1021 @ Footer</a>
1022 @ <li><a href='%R/setup_skinedit?w=3&sk=%d(iSkin)' target='_blank'>\
1023 @ Details</a>
1024 @ <li><a href='%R/setup_skinedit?w=4&sk=%d(iSkin)' target='_blank'>\
1025 @ Javascript</a> (optional)
1026 @ </ul>
1027 }
1028 @
1029 @ <a name='step5'></a>
1030 @ <h1>Step 5: Verify The Draft Skin</h1>
1031
+47 -21
--- src/style.c
+++ src/style.c
@@ -402,10 +402,37 @@
402402
@ <link rel="stylesheet" href="$stylesheet_url" type="text/css" \
403403
@ media="screen" />
404404
@ </head>
405405
@ <body>
406406
;
407
+
408
+/*
409
+** Initialize all the default TH1 variables
410
+*/
411
+static void style_init_th1_vars(const char *zTitle){
412
+ Th_Store("nonce", style_nonce());
413
+ Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
414
+ Th_Store("project_description", db_get("project-description",""));
415
+ if( zTitle ) Th_Store("title", zTitle);
416
+ Th_Store("baseurl", g.zBaseURL);
417
+ Th_Store("secureurl", login_wants_https_redirect()? g.zHttpsURL: g.zBaseURL);
418
+ Th_Store("home", g.zTop);
419
+ Th_Store("index_page", db_get("index-page","/home"));
420
+ if( local_zCurrentPage==0 ) style_set_current_page("%T", g.zPath);
421
+ Th_Store("current_page", local_zCurrentPage);
422
+ Th_Store("csrf_token", g.zCsrfToken);
423
+ Th_Store("release_version", RELEASE_VERSION);
424
+ Th_Store("manifest_version", MANIFEST_VERSION);
425
+ Th_Store("manifest_date", MANIFEST_DATE);
426
+ Th_Store("compiler_name", COMPILER_NAME);
427
+ url_var("stylesheet", "css", "style.css");
428
+ image_url_var("logo");
429
+ image_url_var("background");
430
+ if( !login_is_nobody() ){
431
+ Th_Store("login", g.zLogin);
432
+ }
433
+}
407434
408435
/*
409436
** Draw the header.
410437
*/
411438
void style_header(const char *zTitleFormat, ...){
@@ -423,31 +450,11 @@
423450
@ <!DOCTYPE html>
424451
425452
if( g.thTrace ) Th_Trace("BEGIN_HEADER<br />\n", -1);
426453
427454
/* Generate the header up through the main menu */
428
- Th_Store("nonce", style_nonce());
429
- Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
430
- Th_Store("project_description", db_get("project-description",""));
431
- Th_Store("title", zTitle);
432
- Th_Store("baseurl", g.zBaseURL);
433
- Th_Store("secureurl", login_wants_https_redirect()? g.zHttpsURL: g.zBaseURL);
434
- Th_Store("home", g.zTop);
435
- Th_Store("index_page", db_get("index-page","/home"));
436
- if( local_zCurrentPage==0 ) style_set_current_page("%T", g.zPath);
437
- Th_Store("current_page", local_zCurrentPage);
438
- Th_Store("csrf_token", g.zCsrfToken);
439
- Th_Store("release_version", RELEASE_VERSION);
440
- Th_Store("manifest_version", MANIFEST_VERSION);
441
- Th_Store("manifest_date", MANIFEST_DATE);
442
- Th_Store("compiler_name", COMPILER_NAME);
443
- url_var("stylesheet", "css", "style.css");
444
- image_url_var("logo");
445
- image_url_var("background");
446
- if( !login_is_nobody() ){
447
- Th_Store("login", g.zLogin);
448
- }
455
+ style_init_th1_vars(zTitle);
449456
if( sqlite3_strlike("%<body%", zHeader, 0)!=0 ){
450457
Th_Render(zDfltHeader);
451458
}
452459
if( g.thTrace ) Th_Trace("BEGIN_HEADER_SCRIPT<br />\n", -1);
453460
Th_Render(zHeader);
@@ -848,10 +855,29 @@
848855
zSelector = g.argv[3];
849856
found = containsSelector(blob_str(&css), zSelector);
850857
fossil_print("%s %s\n", zSelector, found ? "found" : "not found");
851858
blob_reset(&css);
852859
}
860
+
861
+/*
862
+** WEBPAGE: script.js
863
+**
864
+** Return the "Javascript" content for the current skin (if there is any)
865
+*/
866
+void page_script_js(void){
867
+ const char *zScript = skin_get("js");
868
+ if( P("test") ){
869
+ /* Render the script as plain-text for testing purposes, if the "test"
870
+ ** query parameter is present */
871
+ cgi_set_content_type("text/plain");
872
+ }else{
873
+ /* Default behavior is to return javascript */
874
+ cgi_set_content_type("application/javascript");
875
+ }
876
+ style_init_th1_vars(0);
877
+ Th_Render(zScript?zScript:"");
878
+}
853879
854880
855881
/*
856882
** WEBPAGE: style.css
857883
**
858884
--- src/style.c
+++ src/style.c
@@ -402,10 +402,37 @@
402 @ <link rel="stylesheet" href="$stylesheet_url" type="text/css" \
403 @ media="screen" />
404 @ </head>
405 @ <body>
406 ;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
407
408 /*
409 ** Draw the header.
410 */
411 void style_header(const char *zTitleFormat, ...){
@@ -423,31 +450,11 @@
423 @ <!DOCTYPE html>
424
425 if( g.thTrace ) Th_Trace("BEGIN_HEADER<br />\n", -1);
426
427 /* Generate the header up through the main menu */
428 Th_Store("nonce", style_nonce());
429 Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
430 Th_Store("project_description", db_get("project-description",""));
431 Th_Store("title", zTitle);
432 Th_Store("baseurl", g.zBaseURL);
433 Th_Store("secureurl", login_wants_https_redirect()? g.zHttpsURL: g.zBaseURL);
434 Th_Store("home", g.zTop);
435 Th_Store("index_page", db_get("index-page","/home"));
436 if( local_zCurrentPage==0 ) style_set_current_page("%T", g.zPath);
437 Th_Store("current_page", local_zCurrentPage);
438 Th_Store("csrf_token", g.zCsrfToken);
439 Th_Store("release_version", RELEASE_VERSION);
440 Th_Store("manifest_version", MANIFEST_VERSION);
441 Th_Store("manifest_date", MANIFEST_DATE);
442 Th_Store("compiler_name", COMPILER_NAME);
443 url_var("stylesheet", "css", "style.css");
444 image_url_var("logo");
445 image_url_var("background");
446 if( !login_is_nobody() ){
447 Th_Store("login", g.zLogin);
448 }
449 if( sqlite3_strlike("%<body%", zHeader, 0)!=0 ){
450 Th_Render(zDfltHeader);
451 }
452 if( g.thTrace ) Th_Trace("BEGIN_HEADER_SCRIPT<br />\n", -1);
453 Th_Render(zHeader);
@@ -848,10 +855,29 @@
848 zSelector = g.argv[3];
849 found = containsSelector(blob_str(&css), zSelector);
850 fossil_print("%s %s\n", zSelector, found ? "found" : "not found");
851 blob_reset(&css);
852 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
853
854
855 /*
856 ** WEBPAGE: style.css
857 **
858
--- src/style.c
+++ src/style.c
@@ -402,10 +402,37 @@
402 @ <link rel="stylesheet" href="$stylesheet_url" type="text/css" \
403 @ media="screen" />
404 @ </head>
405 @ <body>
406 ;
407
408 /*
409 ** Initialize all the default TH1 variables
410 */
411 static void style_init_th1_vars(const char *zTitle){
412 Th_Store("nonce", style_nonce());
413 Th_Store("project_name", db_get("project-name","Unnamed Fossil Project"));
414 Th_Store("project_description", db_get("project-description",""));
415 if( zTitle ) Th_Store("title", zTitle);
416 Th_Store("baseurl", g.zBaseURL);
417 Th_Store("secureurl", login_wants_https_redirect()? g.zHttpsURL: g.zBaseURL);
418 Th_Store("home", g.zTop);
419 Th_Store("index_page", db_get("index-page","/home"));
420 if( local_zCurrentPage==0 ) style_set_current_page("%T", g.zPath);
421 Th_Store("current_page", local_zCurrentPage);
422 Th_Store("csrf_token", g.zCsrfToken);
423 Th_Store("release_version", RELEASE_VERSION);
424 Th_Store("manifest_version", MANIFEST_VERSION);
425 Th_Store("manifest_date", MANIFEST_DATE);
426 Th_Store("compiler_name", COMPILER_NAME);
427 url_var("stylesheet", "css", "style.css");
428 image_url_var("logo");
429 image_url_var("background");
430 if( !login_is_nobody() ){
431 Th_Store("login", g.zLogin);
432 }
433 }
434
435 /*
436 ** Draw the header.
437 */
438 void style_header(const char *zTitleFormat, ...){
@@ -423,31 +450,11 @@
450 @ <!DOCTYPE html>
451
452 if( g.thTrace ) Th_Trace("BEGIN_HEADER<br />\n", -1);
453
454 /* Generate the header up through the main menu */
455 style_init_th1_vars(zTitle);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
456 if( sqlite3_strlike("%<body%", zHeader, 0)!=0 ){
457 Th_Render(zDfltHeader);
458 }
459 if( g.thTrace ) Th_Trace("BEGIN_HEADER_SCRIPT<br />\n", -1);
460 Th_Render(zHeader);
@@ -848,10 +855,29 @@
855 zSelector = g.argv[3];
856 found = containsSelector(blob_str(&css), zSelector);
857 fossil_print("%s %s\n", zSelector, found ? "found" : "not found");
858 blob_reset(&css);
859 }
860
861 /*
862 ** WEBPAGE: script.js
863 **
864 ** Return the "Javascript" content for the current skin (if there is any)
865 */
866 void page_script_js(void){
867 const char *zScript = skin_get("js");
868 if( P("test") ){
869 /* Render the script as plain-text for testing purposes, if the "test"
870 ** query parameter is present */
871 cgi_set_content_type("text/plain");
872 }else{
873 /* Default behavior is to return javascript */
874 cgi_set_content_type("application/javascript");
875 }
876 style_init_th1_vars(0);
877 Th_Render(zScript?zScript:"");
878 }
879
880
881 /*
882 ** WEBPAGE: style.css
883 **
884
+30 -1
--- src/th_main.c
+++ src/th_main.c
@@ -1300,10 +1300,38 @@
13001300
}else{
13011301
Th_SetResult(interp, "repository unavailable", -1);
13021302
return TH_ERROR;
13031303
}
13041304
}
1305
+
1306
+/*
1307
+** TH1 command: styleScript
1308
+**
1309
+** Render the configured javascript for the selected skin
1310
+*/
1311
+static int styleScriptCmd(
1312
+ Th_Interp *interp,
1313
+ void *p,
1314
+ int argc,
1315
+ const char **argv,
1316
+ int *argl
1317
+){
1318
+ if( argc!=1 ){
1319
+ return Th_WrongNumArgs(interp, "styleScript");
1320
+ }
1321
+ if( Th_IsRepositoryOpen() ){
1322
+ const char *zScript = skin_get("js");
1323
+ if( zScript==0 ) zScript = "";
1324
+ Th_Render(zScript);
1325
+ Th_SetResult(interp, 0, 0);
1326
+ return TH_OK;
1327
+ }else{
1328
+ Th_SetResult(interp, "repository unavailable", -1);
1329
+ return TH_ERROR;
1330
+ }
1331
+}
1332
+
13051333
13061334
/*
13071335
** TH1 command: artifact ID ?FILENAME?
13081336
**
13091337
** Attempts to locate the specified artifact and return its contents. An
@@ -1984,12 +2012,13 @@
19842012
{"render", renderCmd, 0},
19852013
{"repository", repositoryCmd, 0},
19862014
{"searchable", searchableCmd, 0},
19872015
{"setParameter", setParameterCmd, 0},
19882016
{"setting", settingCmd, 0},
1989
- {"styleHeader", styleHeaderCmd, 0},
19902017
{"styleFooter", styleFooterCmd, 0},
2018
+ {"styleHeader", styleHeaderCmd, 0},
2019
+ {"styleScript", styleScriptCmd, 0},
19912020
{"tclReady", tclReadyCmd, 0},
19922021
{"trace", traceCmd, 0},
19932022
{"stime", stimeCmd, 0},
19942023
{"unversioned", unversionedCmd, 0},
19952024
{"utime", utimeCmd, 0},
19962025
--- src/th_main.c
+++ src/th_main.c
@@ -1300,10 +1300,38 @@
1300 }else{
1301 Th_SetResult(interp, "repository unavailable", -1);
1302 return TH_ERROR;
1303 }
1304 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1305
1306 /*
1307 ** TH1 command: artifact ID ?FILENAME?
1308 **
1309 ** Attempts to locate the specified artifact and return its contents. An
@@ -1984,12 +2012,13 @@
1984 {"render", renderCmd, 0},
1985 {"repository", repositoryCmd, 0},
1986 {"searchable", searchableCmd, 0},
1987 {"setParameter", setParameterCmd, 0},
1988 {"setting", settingCmd, 0},
1989 {"styleHeader", styleHeaderCmd, 0},
1990 {"styleFooter", styleFooterCmd, 0},
 
 
1991 {"tclReady", tclReadyCmd, 0},
1992 {"trace", traceCmd, 0},
1993 {"stime", stimeCmd, 0},
1994 {"unversioned", unversionedCmd, 0},
1995 {"utime", utimeCmd, 0},
1996
--- src/th_main.c
+++ src/th_main.c
@@ -1300,10 +1300,38 @@
1300 }else{
1301 Th_SetResult(interp, "repository unavailable", -1);
1302 return TH_ERROR;
1303 }
1304 }
1305
1306 /*
1307 ** TH1 command: styleScript
1308 **
1309 ** Render the configured javascript for the selected skin
1310 */
1311 static int styleScriptCmd(
1312 Th_Interp *interp,
1313 void *p,
1314 int argc,
1315 const char **argv,
1316 int *argl
1317 ){
1318 if( argc!=1 ){
1319 return Th_WrongNumArgs(interp, "styleScript");
1320 }
1321 if( Th_IsRepositoryOpen() ){
1322 const char *zScript = skin_get("js");
1323 if( zScript==0 ) zScript = "";
1324 Th_Render(zScript);
1325 Th_SetResult(interp, 0, 0);
1326 return TH_OK;
1327 }else{
1328 Th_SetResult(interp, "repository unavailable", -1);
1329 return TH_ERROR;
1330 }
1331 }
1332
1333
1334 /*
1335 ** TH1 command: artifact ID ?FILENAME?
1336 **
1337 ** Attempts to locate the specified artifact and return its contents. An
@@ -1984,12 +2012,13 @@
2012 {"render", renderCmd, 0},
2013 {"repository", repositoryCmd, 0},
2014 {"searchable", searchableCmd, 0},
2015 {"setParameter", setParameterCmd, 0},
2016 {"setting", settingCmd, 0},
 
2017 {"styleFooter", styleFooterCmd, 0},
2018 {"styleHeader", styleHeaderCmd, 0},
2019 {"styleScript", styleScriptCmd, 0},
2020 {"tclReady", tclReadyCmd, 0},
2021 {"trace", traceCmd, 0},
2022 {"stime", stimeCmd, 0},
2023 {"unversioned", unversionedCmd, 0},
2024 {"utime", utimeCmd, 0},
2025

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button