Fossil SCM
Add a hamburger menu that brings up an overlaid /sitemap to the default skin.
Commit
9c887998ca54c0ca8f4c4331ac600e27dfd1eeb14180c434a62486a4a38e401c
Parent
ed84acb6d28398f…
8 files changed
+15
+126
+2
-4
+6
+2
-3
+9
-4
+47
-21
+30
-1
+15
| --- skins/default/css.txt | ||
| +++ skins/default/css.txt | ||
| @@ -83,10 +83,11 @@ | ||
| 83 | 83 | border:1px solid #eaeaea; |
| 84 | 84 | border-radius:5px; |
| 85 | 85 | overflow-x: auto; |
| 86 | 86 | overflow-y: hidden; |
| 87 | 87 | white-space: nowrap; |
| 88 | + z-index: 21; /* just above hbdrop */ | |
| 88 | 89 | } |
| 89 | 90 | |
| 90 | 91 | .mainmenu a { |
| 91 | 92 | text-decoration:none; |
| 92 | 93 | color: #777; |
| @@ -95,10 +96,24 @@ | ||
| 95 | 96 | .mainmenu a.active, |
| 96 | 97 | .mainmenu a:hover { |
| 97 | 98 | color: #000; |
| 98 | 99 | border-bottom:2px solid #D26911; |
| 99 | 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 | +} | |
| 100 | 115 | |
| 101 | 116 | .submenu { |
| 102 | 117 | font-size: .7em; |
| 103 | 118 | padding: 10px; |
| 104 | 119 | border-bottom: 1px solid #ccc; |
| 105 | 120 |
| --- 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 |
+126
| --- skins/default/footer.txt | ||
| +++ skins/default/footer.txt | ||
| @@ -1,5 +1,131 @@ | ||
| 1 | 1 | <div class="footer"> |
| 2 | 2 | This page was generated in about |
| 3 | 3 | <th1>puts [expr {([utime]+[stime]+1000)/1000*0.001}]</th1>s by |
| 4 | 4 | Fossil $release_version $manifest_version $manifest_date |
| 5 | 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> | |
| 6 | 132 |
| --- 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 |
+2
-4
| --- skins/default/header.txt | ||
| +++ skins/default/header.txt | ||
| @@ -17,10 +17,11 @@ | ||
| 17 | 17 | html "<a href='$home$url' class='active $cls'>$name</a>\n" |
| 18 | 18 | } else { |
| 19 | 19 | html "<a href='$home$url' class='$cls'>$name</a>\n" |
| 20 | 20 | } |
| 21 | 21 | } |
| 22 | +html "<a href='#'>☰</a>" | |
| 22 | 23 | menulink $index_page Home {} |
| 23 | 24 | if {[anycap jor]} { |
| 24 | 25 | menulink /timeline Timeline {} |
| 25 | 26 | } |
| 26 | 27 | if {[hascap oh]} { |
| @@ -39,13 +40,10 @@ | ||
| 39 | 40 | if {[hascap j]} { |
| 40 | 41 | menulink /wiki Wiki wideonly |
| 41 | 42 | } |
| 42 | 43 | if {[hascap s]} { |
| 43 | 44 | menulink /setup Admin {} |
| 44 | - menulink /sitemap More... wideonly | |
| 45 | 45 | } elseif {[hascap a]} { |
| 46 | 46 | menulink /setup_ulist Users {} |
| 47 | - menulink /sitemap More... {} | |
| 48 | -} else { | |
| 49 | - menulink /sitemap More... {} | |
| 50 | 47 | } |
| 51 | 48 | </th1></div> |
| 49 | +<div id='hbdrop'></div> | |
| 52 | 50 | |
| 53 | 51 | 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='#'>☰</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 @@ | ||
| 45 | 45 | |
| 46 | 46 | login_check_credentials(); |
| 47 | 47 | srchFlags = search_restrict(SRCH_ALL); |
| 48 | 48 | style_header("Site Map"); |
| 49 | 49 | 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"> | |
| 52 | 51 | @ <li>%z(href("%R/home"))Home Page</a> |
| 53 | 52 | for(i=0; i<sizeof(aExtra)/sizeof(aExtra[0]); i++){ |
| 54 | 53 | char *z = db_get(aExtra[i].zProperty,0); |
| 55 | 54 | if( z==0 || z[0]==0 ) continue; |
| 56 | 55 | if( !inSublist ){ |
| @@ -210,8 +209,8 @@ | ||
| 210 | 209 | } |
| 211 | 210 | @ <li>%z(href("%R/hash-color-test"))Page to experiment with the automatic |
| 212 | 211 | @ colors assigned to branch names</a> |
| 213 | 212 | @ <li>%z(href("%R/test-captcha"))Random ASCII-art Captcha image</a></li> |
| 214 | 213 | @ </ul></li> |
| 215 | - @ </ul></div> | |
| 214 | + @ </ul> | |
| 216 | 215 | style_footer(); |
| 217 | 216 | } |
| 218 | 217 |
| --- 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 @@ | ||
| 55 | 55 | { "Khaki, No Logo", "khaki", 0 }, |
| 56 | 56 | { "Ardoise", "ardoise", 0 }, |
| 57 | 57 | }; |
| 58 | 58 | |
| 59 | 59 | /* |
| 60 | -** A skin consists of four "files" named here: | |
| 60 | +** A skin consists of five "files" named here: | |
| 61 | 61 | */ |
| 62 | -static const char *azSkinFile[] = { "css", "header", "footer", "details" }; | |
| 62 | +static const char *azSkinFile[] = { | |
| 63 | + "css", "header", "footer", "details", "js" | |
| 64 | +}; | |
| 63 | 65 | |
| 64 | 66 | /* |
| 65 | 67 | ** Alternative skins can be specified in the CGI script or by options |
| 66 | 68 | ** on the "http", "ui", and "server" commands. The alternative skin |
| 67 | 69 | ** name must be one of the aBuiltinSkin[].zLabel names. If there is |
| @@ -149,11 +151,11 @@ | ||
| 149 | 151 | |
| 150 | 152 | /* |
| 151 | 153 | ** The following routines return the various components of the skin |
| 152 | 154 | ** that should be used for the current run. |
| 153 | 155 | ** |
| 154 | -** zWhat is one of: "css", "header", "footer", "details". | |
| 156 | +** zWhat is one of: "css", "header", "footer", "details", "js" | |
| 155 | 157 | */ |
| 156 | 158 | const char *skin_get(const char *zWhat){ |
| 157 | 159 | const char *zOut; |
| 158 | 160 | char *z; |
| 159 | 161 | if( iDraftSkin ){ |
| @@ -691,11 +693,11 @@ | ||
| 691 | 693 | ** WEBPAGE: setup_skinedit |
| 692 | 694 | ** |
| 693 | 695 | ** Edit aspects of a skin determined by the w= query parameter. |
| 694 | 696 | ** Requires Setup privileges. |
| 695 | 697 | ** |
| 696 | -** w=NUM -- 0=CSS, 1=footer, 2=header, 3=details | |
| 698 | +** w=NUM -- 0=CSS, 1=footer, 2=header, 3=details, 4=js | |
| 697 | 699 | ** sk=NUM -- the draft skin number |
| 698 | 700 | */ |
| 699 | 701 | void setup_skinedit(void){ |
| 700 | 702 | static const struct sSkinAddr { |
| 701 | 703 | const char *zFile; |
| @@ -704,10 +706,11 @@ | ||
| 704 | 706 | } aSkinAttr[] = { |
| 705 | 707 | /* 0 */ { "css", "CSS", "CSS", }, |
| 706 | 708 | /* 1 */ { "footer", "Page Footer", "Footer", }, |
| 707 | 709 | /* 2 */ { "header", "Page Header", "Header", }, |
| 708 | 710 | /* 3 */ { "details", "Display Details", "Details", }, |
| 711 | + /* 4 */ { "js", "JavaScript", "Script", }, | |
| 709 | 712 | }; |
| 710 | 713 | const char *zBasis; /* The baseline file */ |
| 711 | 714 | const char *zOrig; /* Original content prior to editing */ |
| 712 | 715 | const char *zContent; /* Content after editing */ |
| 713 | 716 | const char *zDflt; /* Default content */ |
| @@ -1016,10 +1019,12 @@ | ||
| 1016 | 1019 | @ Header</a> |
| 1017 | 1020 | @ <li><a href='%R/setup_skinedit?w=1&sk=%d(iSkin)' target='_blank'>\ |
| 1018 | 1021 | @ Footer</a> |
| 1019 | 1022 | @ <li><a href='%R/setup_skinedit?w=3&sk=%d(iSkin)' target='_blank'>\ |
| 1020 | 1023 | @ Details</a> |
| 1024 | + @ <li><a href='%R/setup_skinedit?w=4&sk=%d(iSkin)' target='_blank'>\ | |
| 1025 | + @ Javascript</a> (optional) | |
| 1021 | 1026 | @ </ul> |
| 1022 | 1027 | } |
| 1023 | 1028 | @ |
| 1024 | 1029 | @ <a name='step5'></a> |
| 1025 | 1030 | @ <h1>Step 5: Verify The Draft Skin</h1> |
| 1026 | 1031 |
| --- 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 @@ | ||
| 402 | 402 | @ <link rel="stylesheet" href="$stylesheet_url" type="text/css" \ |
| 403 | 403 | @ media="screen" /> |
| 404 | 404 | @ </head> |
| 405 | 405 | @ <body> |
| 406 | 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 | +} | |
| 407 | 434 | |
| 408 | 435 | /* |
| 409 | 436 | ** Draw the header. |
| 410 | 437 | */ |
| 411 | 438 | void style_header(const char *zTitleFormat, ...){ |
| @@ -423,31 +450,11 @@ | ||
| 423 | 450 | @ <!DOCTYPE html> |
| 424 | 451 | |
| 425 | 452 | if( g.thTrace ) Th_Trace("BEGIN_HEADER<br />\n", -1); |
| 426 | 453 | |
| 427 | 454 | /* 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); | |
| 449 | 456 | if( sqlite3_strlike("%<body%", zHeader, 0)!=0 ){ |
| 450 | 457 | Th_Render(zDfltHeader); |
| 451 | 458 | } |
| 452 | 459 | if( g.thTrace ) Th_Trace("BEGIN_HEADER_SCRIPT<br />\n", -1); |
| 453 | 460 | Th_Render(zHeader); |
| @@ -848,10 +855,29 @@ | ||
| 848 | 855 | zSelector = g.argv[3]; |
| 849 | 856 | found = containsSelector(blob_str(&css), zSelector); |
| 850 | 857 | fossil_print("%s %s\n", zSelector, found ? "found" : "not found"); |
| 851 | 858 | blob_reset(&css); |
| 852 | 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 | +} | |
| 853 | 879 | |
| 854 | 880 | |
| 855 | 881 | /* |
| 856 | 882 | ** WEBPAGE: style.css |
| 857 | 883 | ** |
| 858 | 884 |
| --- 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 @@ | ||
| 1300 | 1300 | }else{ |
| 1301 | 1301 | Th_SetResult(interp, "repository unavailable", -1); |
| 1302 | 1302 | return TH_ERROR; |
| 1303 | 1303 | } |
| 1304 | 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 | + | |
| 1305 | 1333 | |
| 1306 | 1334 | /* |
| 1307 | 1335 | ** TH1 command: artifact ID ?FILENAME? |
| 1308 | 1336 | ** |
| 1309 | 1337 | ** Attempts to locate the specified artifact and return its contents. An |
| @@ -1984,12 +2012,13 @@ | ||
| 1984 | 2012 | {"render", renderCmd, 0}, |
| 1985 | 2013 | {"repository", repositoryCmd, 0}, |
| 1986 | 2014 | {"searchable", searchableCmd, 0}, |
| 1987 | 2015 | {"setParameter", setParameterCmd, 0}, |
| 1988 | 2016 | {"setting", settingCmd, 0}, |
| 1989 | - {"styleHeader", styleHeaderCmd, 0}, | |
| 1990 | 2017 | {"styleFooter", styleFooterCmd, 0}, |
| 2018 | + {"styleHeader", styleHeaderCmd, 0}, | |
| 2019 | + {"styleScript", styleScriptCmd, 0}, | |
| 1991 | 2020 | {"tclReady", tclReadyCmd, 0}, |
| 1992 | 2021 | {"trace", traceCmd, 0}, |
| 1993 | 2022 | {"stime", stimeCmd, 0}, |
| 1994 | 2023 | {"unversioned", unversionedCmd, 0}, |
| 1995 | 2024 | {"utime", utimeCmd, 0}, |
| 1996 | 2025 |
| --- 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 |