Fossil SCM
Implemented the first version of the JavaScript tutorial chooser in www/server/index.html, complete with fallbacks for the noscript case, optional display of the static document matrix, and pretty CSS transitions between the states.
Commit
0cbdbc725c36744f50ca02e4ae211aa43aa5f279c36af7a95f690ca8a6bb8eac
Parent
a7610e42732f3b1…
1 file changed
+127
-6
+127
-6
| --- www/server/index.html | ||
| +++ www/server/index.html | ||
| @@ -1,8 +1,8 @@ | ||
| 1 | 1 | <div class='fossil-doc' data-title="How To Configure A Fossil Server"> |
| 2 | 2 | |
| 3 | -<style> | |
| 3 | +<style type="text/css" nonce="$NONCE"> | |
| 4 | 4 | p { |
| 5 | 5 | margin-left: 4em; |
| 6 | 6 | margin-right: 3em; |
| 7 | 7 | } |
| 8 | 8 | |
| @@ -15,10 +15,24 @@ | ||
| 15 | 15 | } |
| 16 | 16 | |
| 17 | 17 | ol, ul { |
| 18 | 18 | margin-left: 3em; |
| 19 | 19 | } |
| 20 | + | |
| 21 | + a#all { | |
| 22 | + font-size: 90%; | |
| 23 | + margin-left: 1em; | |
| 24 | + } | |
| 25 | + | |
| 26 | + div#tutpick.show { | |
| 27 | + max-height: 99em; | |
| 28 | + transition: max-height 1000ms ease-in; | |
| 29 | + } | |
| 30 | + div#tutpick { | |
| 31 | + max-height: 0; | |
| 32 | + overflow: hidden; | |
| 33 | + } | |
| 20 | 34 | |
| 21 | 35 | th.fep { |
| 22 | 36 | background-color: #e8e8e8; |
| 23 | 37 | min-width: 3em; |
| 24 | 38 | padding: 0.4em; |
| @@ -115,10 +129,15 @@ | ||
| 115 | 129 | |
| 116 | 130 | <p>We've broken the configuration for each method out into a series of |
| 117 | 131 | sub-articles. Some of these are generic, while others depend on |
| 118 | 132 | particular operating systems or front-end software:</p> |
| 119 | 133 | |
| 134 | +<div id="tutpick"></div> | |
| 135 | + | |
| 136 | +<!-- Define alternative to JS tutorial picker below. When updating this | |
| 137 | + table, update "matrix" in the JS code below to match! --> | |
| 138 | +<noscript id="tutmatrix"> | |
| 120 | 139 | <table style="margin-left: 6em;"> |
| 121 | 140 | <tr> |
| 122 | 141 | <th class="host">⇩ OS / Method ⇨</th> |
| 123 | 142 | <th class="fep">none</th> |
| 124 | 143 | <th class="fep">inetd</th> |
| @@ -183,19 +202,121 @@ | ||
| 183 | 202 | documents linked above: Apple’s <tt>launchd</tt>, Linux’s |
| 184 | 203 | <tt>systemd</tt>, Solaris’ SMF, etc. We would welcome <a |
| 185 | 204 | href="contribute.wiki">contributions</a> to cover these as well. We also |
| 186 | 205 | welcome contributions to fill gaps (<font size="-2">❌</font>) in the table |
| 187 | 206 | above. </p> |
| 207 | +</noscript> | |
| 188 | 208 | |
| 189 | 209 | |
| 190 | 210 | <h2 id="more">Further Details</h2> |
| 191 | 211 | |
| 192 | 212 | <ul> |
| 193 | - <li> <a id="chroot" href="../chroot.md">The Server Chroot Jail</a> | |
| 194 | - <li><a id="loadmgmt" href="../loadmgmt.md">Managing Server Load</a> | |
| 195 | - <li><a id="tls" href="../ssl.wiki">Securing a Repository with TLS</a> | |
| 213 | + <li><a id="chroot" href="../chroot.md" >The Server Chroot Jail</a> | |
| 214 | + <li><a id="loadmgmt" href="../loadmgmt.md" >Managing Server Load</a> | |
| 215 | + <li><a id="tls" href="../ssl.wiki" >Securing a Repository with TLS</a> | |
| 196 | 216 | <li><a id="ext" href="../serverext.wiki">CGI Server Extensions</a> |
| 197 | - <li><a id="about" href="../aboutcgi.wiki">How CGI Works In Fossil</a> | |
| 198 | - <li><a id="sync" href="../sync.wiki">The Fossil Sync Protocol</a> | |
| 217 | + <li><a id="about" href="../aboutcgi.wiki" >How CGI Works In Fossil</a> | |
| 218 | + <li><a id="sync" href="../sync.wiki" >The Fossil Sync Protocol</a> | |
| 199 | 219 | </ul> |
| 200 | 220 | |
| 201 | 221 | </div> |
| 222 | + | |
| 223 | +<script type="text/javascript" nonce="$NONCE"> | |
| 224 | + (function() { | |
| 225 | + // Define data structure analog to <table> above. Matrix elements | |
| 226 | + // can have one of these constant values or a string for a one-off | |
| 227 | + // custom value. Values outside the <table> above go at the end of | |
| 228 | + // the rows we define here. | |
| 229 | + const YES = 1; // host-specific doc provided | |
| 230 | + const IFA = 2; // inherit doc from "any" | |
| 231 | + const NO = 3; // method invalid or undocumented for this host OS | |
| 232 | + const methods = [ | |
| 233 | + "none", "inetd", "stunnel", "CGI", "SCGI", "althttpd", "proxy", "service" | |
| 234 | + ]; | |
| 235 | + const matrix = { | |
| 236 | + "any OS": [ YES, YES, YES, YES, YES, YES, NO, NO ], | |
| 237 | + "Debian or Ubuntu": [ IFA, IFA, IFA, IFA, IFA, IFA, "nginx", NO ], | |
| 238 | + "Windows": [ NO, NO, YES, YES, NO, NO, "IIS", NO ], | |
| 239 | + } | |
| 240 | + const osNames = Object.keys(matrix).sort((e) => { | |
| 241 | + return e.toLowerCase() | |
| 242 | + }).map((longName, i) => { | |
| 243 | + var shortName = longName.toLowerCase().split(' ')[0]; | |
| 244 | + return [ longName, shortName ]; | |
| 245 | + }); | |
| 246 | + const osNameMap = Object.fromEntries(osNames); | |
| 247 | + //console.log("OS name map: " + JSON.stringify(osNameMap)); | |
| 248 | + | |
| 249 | + // Build initial tutorial chooser HTML, and insert it into doc where | |
| 250 | + // the static HTML <table> matrix normally goes. | |
| 251 | + var html = '<p><b>I want to run Fossil on</b> <select id="os">'; | |
| 252 | + for (var os of osNames) { | |
| 253 | + const longName = os[0]; | |
| 254 | + const shortName = os[1]; | |
| 255 | + html += '<option name="' + shortName + '">' + longName + '</option>'; | |
| 256 | + } | |
| 257 | + html += '</select> <b>underneath</b> <select id="fep"></select>' | |
| 258 | + html += '<a id="all">SHOW ALL</a></p>'; | |
| 259 | + const picker = document.querySelector('div#tutpick'); | |
| 260 | + picker.innerHTML = html; | |
| 261 | + picker.classList.add('show'); | |
| 262 | + | |
| 263 | + // Slide noscript <table> in place of JS tutorial chooser on | |
| 264 | + // "SHOW ALL" click. | |
| 265 | + document.querySelector('a#all').addEventListener('click', () => { | |
| 266 | + picker.classList.remove('show'); | |
| 267 | + picker.innerHTML = document.querySelector('#tutmatrix').innerHTML; | |
| 268 | + setTimeout(() => { | |
| 269 | + // Let doc update to set new height, so transition happens. | |
| 270 | + picker.classList.add('show'); | |
| 271 | + }, 10); | |
| 272 | + }); | |
| 273 | + | |
| 274 | + // Attach event handlers to drop-downs. Have to wait until the page | |
| 275 | + // loads, else we'll get null back from querySelector(('select#foo')). | |
| 276 | + window.addEventListener('load', () => { | |
| 277 | + // Set up the FEP choice drop-down on initial page load and | |
| 278 | + // update it when the OS choice drop-down changes. | |
| 279 | + const osSel = document.querySelector('select#os'); | |
| 280 | + const fepSel = document.querySelector('select#fep'); | |
| 281 | + function osClickHandler() { | |
| 282 | + var osLong = osSel.value; | |
| 283 | + var osShort = osNameMap[osLong]; | |
| 284 | + | |
| 285 | + var html = '<option>---</option>'; | |
| 286 | + matrix[osLong].forEach((choice, i) => { | |
| 287 | + var mu; | |
| 288 | + if (typeof(choice) === 'string') { | |
| 289 | + mu = choice; | |
| 290 | + choice = YES; | |
| 291 | + } | |
| 292 | + else { | |
| 293 | + mu = methods[i]; | |
| 294 | + } | |
| 295 | + const ml = mu.toLowerCase(); | |
| 296 | + | |
| 297 | + if (choice != NO) { | |
| 298 | + if (choice == YES) { | |
| 299 | + html += '<option value="' + osShort + '/' + ml + '.md">'; | |
| 300 | + } | |
| 301 | + else if (choice == IFA) { | |
| 302 | + html += '<option value="any/' + ml + '.md">'; | |
| 303 | + } | |
| 304 | + html += mu + '</option>'; | |
| 305 | + } | |
| 306 | + }); | |
| 307 | + | |
| 308 | + fepSel.innerHTML = html; | |
| 309 | + } | |
| 310 | + osSel.addEventListener('change', osClickHandler); | |
| 311 | + osClickHandler(); // load fepSel initial content | |
| 312 | + | |
| 313 | + // Go to selected document when user changes FEP drop-down | |
| 314 | + fepSel.addEventListener('change', () => { | |
| 315 | + var doc = fepSel.value; | |
| 316 | + if (doc) location.href = doc; | |
| 317 | + // else it's the --- entry, either because we just reloaded the | |
| 318 | + // <option> set or because the user re-selected it. | |
| 319 | + }); | |
| 320 | + }); | |
| 321 | + })(); | |
| 322 | +</script> | |
| 202 | 323 |
| --- www/server/index.html | |
| +++ www/server/index.html | |
| @@ -1,8 +1,8 @@ | |
| 1 | <div class='fossil-doc' data-title="How To Configure A Fossil Server"> |
| 2 | |
| 3 | <style> |
| 4 | p { |
| 5 | margin-left: 4em; |
| 6 | margin-right: 3em; |
| 7 | } |
| 8 | |
| @@ -15,10 +15,24 @@ | |
| 15 | } |
| 16 | |
| 17 | ol, ul { |
| 18 | margin-left: 3em; |
| 19 | } |
| 20 | |
| 21 | th.fep { |
| 22 | background-color: #e8e8e8; |
| 23 | min-width: 3em; |
| 24 | padding: 0.4em; |
| @@ -115,10 +129,15 @@ | |
| 115 | |
| 116 | <p>We've broken the configuration for each method out into a series of |
| 117 | sub-articles. Some of these are generic, while others depend on |
| 118 | particular operating systems or front-end software:</p> |
| 119 | |
| 120 | <table style="margin-left: 6em;"> |
| 121 | <tr> |
| 122 | <th class="host">⇩ OS / Method ⇨</th> |
| 123 | <th class="fep">none</th> |
| 124 | <th class="fep">inetd</th> |
| @@ -183,19 +202,121 @@ | |
| 183 | documents linked above: Apple’s <tt>launchd</tt>, Linux’s |
| 184 | <tt>systemd</tt>, Solaris’ SMF, etc. We would welcome <a |
| 185 | href="contribute.wiki">contributions</a> to cover these as well. We also |
| 186 | welcome contributions to fill gaps (<font size="-2">❌</font>) in the table |
| 187 | above. </p> |
| 188 | |
| 189 | |
| 190 | <h2 id="more">Further Details</h2> |
| 191 | |
| 192 | <ul> |
| 193 | <li> <a id="chroot" href="../chroot.md">The Server Chroot Jail</a> |
| 194 | <li><a id="loadmgmt" href="../loadmgmt.md">Managing Server Load</a> |
| 195 | <li><a id="tls" href="../ssl.wiki">Securing a Repository with TLS</a> |
| 196 | <li><a id="ext" href="../serverext.wiki">CGI Server Extensions</a> |
| 197 | <li><a id="about" href="../aboutcgi.wiki">How CGI Works In Fossil</a> |
| 198 | <li><a id="sync" href="../sync.wiki">The Fossil Sync Protocol</a> |
| 199 | </ul> |
| 200 | |
| 201 | </div> |
| 202 |
| --- www/server/index.html | |
| +++ www/server/index.html | |
| @@ -1,8 +1,8 @@ | |
| 1 | <div class='fossil-doc' data-title="How To Configure A Fossil Server"> |
| 2 | |
| 3 | <style type="text/css" nonce="$NONCE"> |
| 4 | p { |
| 5 | margin-left: 4em; |
| 6 | margin-right: 3em; |
| 7 | } |
| 8 | |
| @@ -15,10 +15,24 @@ | |
| 15 | } |
| 16 | |
| 17 | ol, ul { |
| 18 | margin-left: 3em; |
| 19 | } |
| 20 | |
| 21 | a#all { |
| 22 | font-size: 90%; |
| 23 | margin-left: 1em; |
| 24 | } |
| 25 | |
| 26 | div#tutpick.show { |
| 27 | max-height: 99em; |
| 28 | transition: max-height 1000ms ease-in; |
| 29 | } |
| 30 | div#tutpick { |
| 31 | max-height: 0; |
| 32 | overflow: hidden; |
| 33 | } |
| 34 | |
| 35 | th.fep { |
| 36 | background-color: #e8e8e8; |
| 37 | min-width: 3em; |
| 38 | padding: 0.4em; |
| @@ -115,10 +129,15 @@ | |
| 129 | |
| 130 | <p>We've broken the configuration for each method out into a series of |
| 131 | sub-articles. Some of these are generic, while others depend on |
| 132 | particular operating systems or front-end software:</p> |
| 133 | |
| 134 | <div id="tutpick"></div> |
| 135 | |
| 136 | <!-- Define alternative to JS tutorial picker below. When updating this |
| 137 | table, update "matrix" in the JS code below to match! --> |
| 138 | <noscript id="tutmatrix"> |
| 139 | <table style="margin-left: 6em;"> |
| 140 | <tr> |
| 141 | <th class="host">⇩ OS / Method ⇨</th> |
| 142 | <th class="fep">none</th> |
| 143 | <th class="fep">inetd</th> |
| @@ -183,19 +202,121 @@ | |
| 202 | documents linked above: Apple’s <tt>launchd</tt>, Linux’s |
| 203 | <tt>systemd</tt>, Solaris’ SMF, etc. We would welcome <a |
| 204 | href="contribute.wiki">contributions</a> to cover these as well. We also |
| 205 | welcome contributions to fill gaps (<font size="-2">❌</font>) in the table |
| 206 | above. </p> |
| 207 | </noscript> |
| 208 | |
| 209 | |
| 210 | <h2 id="more">Further Details</h2> |
| 211 | |
| 212 | <ul> |
| 213 | <li><a id="chroot" href="../chroot.md" >The Server Chroot Jail</a> |
| 214 | <li><a id="loadmgmt" href="../loadmgmt.md" >Managing Server Load</a> |
| 215 | <li><a id="tls" href="../ssl.wiki" >Securing a Repository with TLS</a> |
| 216 | <li><a id="ext" href="../serverext.wiki">CGI Server Extensions</a> |
| 217 | <li><a id="about" href="../aboutcgi.wiki" >How CGI Works In Fossil</a> |
| 218 | <li><a id="sync" href="../sync.wiki" >The Fossil Sync Protocol</a> |
| 219 | </ul> |
| 220 | |
| 221 | </div> |
| 222 | |
| 223 | <script type="text/javascript" nonce="$NONCE"> |
| 224 | (function() { |
| 225 | // Define data structure analog to <table> above. Matrix elements |
| 226 | // can have one of these constant values or a string for a one-off |
| 227 | // custom value. Values outside the <table> above go at the end of |
| 228 | // the rows we define here. |
| 229 | const YES = 1; // host-specific doc provided |
| 230 | const IFA = 2; // inherit doc from "any" |
| 231 | const NO = 3; // method invalid or undocumented for this host OS |
| 232 | const methods = [ |
| 233 | "none", "inetd", "stunnel", "CGI", "SCGI", "althttpd", "proxy", "service" |
| 234 | ]; |
| 235 | const matrix = { |
| 236 | "any OS": [ YES, YES, YES, YES, YES, YES, NO, NO ], |
| 237 | "Debian or Ubuntu": [ IFA, IFA, IFA, IFA, IFA, IFA, "nginx", NO ], |
| 238 | "Windows": [ NO, NO, YES, YES, NO, NO, "IIS", NO ], |
| 239 | } |
| 240 | const osNames = Object.keys(matrix).sort((e) => { |
| 241 | return e.toLowerCase() |
| 242 | }).map((longName, i) => { |
| 243 | var shortName = longName.toLowerCase().split(' ')[0]; |
| 244 | return [ longName, shortName ]; |
| 245 | }); |
| 246 | const osNameMap = Object.fromEntries(osNames); |
| 247 | //console.log("OS name map: " + JSON.stringify(osNameMap)); |
| 248 | |
| 249 | // Build initial tutorial chooser HTML, and insert it into doc where |
| 250 | // the static HTML <table> matrix normally goes. |
| 251 | var html = '<p><b>I want to run Fossil on</b> <select id="os">'; |
| 252 | for (var os of osNames) { |
| 253 | const longName = os[0]; |
| 254 | const shortName = os[1]; |
| 255 | html += '<option name="' + shortName + '">' + longName + '</option>'; |
| 256 | } |
| 257 | html += '</select> <b>underneath</b> <select id="fep"></select>' |
| 258 | html += '<a id="all">SHOW ALL</a></p>'; |
| 259 | const picker = document.querySelector('div#tutpick'); |
| 260 | picker.innerHTML = html; |
| 261 | picker.classList.add('show'); |
| 262 | |
| 263 | // Slide noscript <table> in place of JS tutorial chooser on |
| 264 | // "SHOW ALL" click. |
| 265 | document.querySelector('a#all').addEventListener('click', () => { |
| 266 | picker.classList.remove('show'); |
| 267 | picker.innerHTML = document.querySelector('#tutmatrix').innerHTML; |
| 268 | setTimeout(() => { |
| 269 | // Let doc update to set new height, so transition happens. |
| 270 | picker.classList.add('show'); |
| 271 | }, 10); |
| 272 | }); |
| 273 | |
| 274 | // Attach event handlers to drop-downs. Have to wait until the page |
| 275 | // loads, else we'll get null back from querySelector(('select#foo')). |
| 276 | window.addEventListener('load', () => { |
| 277 | // Set up the FEP choice drop-down on initial page load and |
| 278 | // update it when the OS choice drop-down changes. |
| 279 | const osSel = document.querySelector('select#os'); |
| 280 | const fepSel = document.querySelector('select#fep'); |
| 281 | function osClickHandler() { |
| 282 | var osLong = osSel.value; |
| 283 | var osShort = osNameMap[osLong]; |
| 284 | |
| 285 | var html = '<option>---</option>'; |
| 286 | matrix[osLong].forEach((choice, i) => { |
| 287 | var mu; |
| 288 | if (typeof(choice) === 'string') { |
| 289 | mu = choice; |
| 290 | choice = YES; |
| 291 | } |
| 292 | else { |
| 293 | mu = methods[i]; |
| 294 | } |
| 295 | const ml = mu.toLowerCase(); |
| 296 | |
| 297 | if (choice != NO) { |
| 298 | if (choice == YES) { |
| 299 | html += '<option value="' + osShort + '/' + ml + '.md">'; |
| 300 | } |
| 301 | else if (choice == IFA) { |
| 302 | html += '<option value="any/' + ml + '.md">'; |
| 303 | } |
| 304 | html += mu + '</option>'; |
| 305 | } |
| 306 | }); |
| 307 | |
| 308 | fepSel.innerHTML = html; |
| 309 | } |
| 310 | osSel.addEventListener('change', osClickHandler); |
| 311 | osClickHandler(); // load fepSel initial content |
| 312 | |
| 313 | // Go to selected document when user changes FEP drop-down |
| 314 | fepSel.addEventListener('change', () => { |
| 315 | var doc = fepSel.value; |
| 316 | if (doc) location.href = doc; |
| 317 | // else it's the --- entry, either because we just reloaded the |
| 318 | // <option> set or because the user re-selected it. |
| 319 | }); |
| 320 | }); |
| 321 | })(); |
| 322 | </script> |
| 323 |