Fossil

Check-in [90bd6675]
Login

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

Overview
Comment:Using CSS transitions to mimic jQuery's slideUp/Down() transitions. This probably restricts browser compatibility still further above the XHR issue noted in the earlier checkin on this branch. According to MDN, we're probably restricted to IE 10+ with this, and maybe not even that due to not using vendor-specific extensions for the transitional browser versions.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | js-hamburger-menu
Files: files | file ages | folders
SHA3-256: 90bd66750d539aebc817f906fe8b75dfcf72c4603ec14fbf8b80acf6095773e2
User & Date: wyoung 2018-09-10 08:48:34
Context
2018-09-10
09:02
Increased the transition delay to make the initial drop-down animation happen in Firefox 62. check-in: 8918a8a8 user: wyoung tags: js-hamburger-menu
08:48
Using CSS transitions to mimic jQuery's slideUp/Down() transitions. This probably restricts browser compatibility still further above the XHR issue noted in the earlier checkin on this branch. According to MDN, we're probably restricted to IE 10+ with this, and maybe not even that due to not using vendor-specific extensions for the transitional browser versions. check-in: 90bd6675 user: wyoung tags: js-hamburger-menu
07:17
Converted JS hamburger button menu code to use standard JS only, no jQuery.

Temporarily lost the animation with this change: I'm checking this in separately to make the difference between this and the jQuery version clearer.

Not sure how portable it is yet; I wouldn't be surprised if it broke on old IE, since we're using xhr.onload instead of the horrid mess that is xhr.onreadystatechange. check-in: 113ba3d9 user: wyoung tags: js-hamburger-menu

Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to skins/default/footer.txt.

     5      5   </div>
     6      6   
     7      7   <th1>
     8      8     html "<script nonce='$nonce'>"
     9      9     html "  (function() { var home='$home'; "
    10     10   </th1>
    11     11       var panel = document.getElementById("hbdrop");
           12  +    var panelBorder = panel.style.border;
           13  +
           14  +    // Calculate panel height despite its being hidden at call time.
           15  +    // Based on https://stackoverflow.com/a/29047447/142454
           16  +    var panelHeight;  // computed on sitemap load
           17  +    function calculatePanelHeight() {
           18  +      // Get initial panel styles so we can restore them below.
           19  +      var es   = window.getComputedStyle(panel),
           20  +          edis = es.display,
           21  +          epos = es.position,
           22  +          evis = es.visibility;
           23  +
           24  +      // Restyle the panel so we can measure its height while invisible.
           25  +      panel.style.visibility = 'hidden';
           26  +      panel.style.position   = 'absolute';
           27  +      panel.style.display    = 'block';
           28  +      panelHeight = panel.offsetHeight + 'px';
    12     29   
    13         -    panel.onclick = panel.hide = function() {
    14         -      panel.style.display = 'none';
           30  +      // Revert styles now that job is done.
           31  +      panel.style.display    = edis;
           32  +      panel.style.position   = epos;
           33  +      panel.style.visibility = evis;
    15     34       }
    16         -    panel.show = function() {
    17         -      panel.style.display = 'block';
           35  +
           36  +    // Show the panel by changing the panel height, which kicks off the
           37  +    // slide-open/closed transition set up in the XHR onload handler.
           38  +    //
           39  +    // Schedule the change for a near-future time in case this is the
           40  +    // first call, where the div was initially invisible.  That causes
           41  +    // the browser to consider the height change as part of the same
           42  +    // state change as the visibility change, so it doesn't see a state
           43  +    // *transition*, hence never kicks off the *CSS* transition:
           44  +    //
           45  +    // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions#JavaScript_examples
           46  +    function showPanel() {
           47  +      setTimeout(function() {
           48  +        panel.style.maxHeight = panelHeight;
           49  +        panel.style.border    = panelBorder;
           50  +      }, 10);
    18     51       }
    19     52   
           53  +    // Click handler for the hamburger button.
    20     54       var needSitemapHTML = true;
    21     55       document.querySelector("div.mainmenu > a").onclick = function() {
    22         -      if (panel.style.display == 'block') {
    23         -        // Hamburger button clicked a second time.
    24         -        panel.hide();
           56  +      if (panel.style.maxHeight == panelHeight) {
           57  +        // Hamburger button clicked while panel visible.  Trigger the
           58  +        // transition back to hidden state.
           59  +        panel.style.maxHeight = '0';
           60  +        setTimeout(function() {
           61  +          // Browsers show a 1px high line when maxHeight == 0, so
           62  +          // temporarily hide the borders while hidden.
           63  +          panel.style.border = 'none';
           64  +        }, 300);
    25     65         }
    26     66         else if (needSitemapHTML) {
    27     67           // Only get it once per page load: it isn't likely to
    28     68           // change on us.
    29     69           var xhr = new XMLHttpRequest();
    30     70           xhr.onload = function() {
    31     71             var doc = xhr.responseXML;
    32     72             if (doc) {
    33     73               var sm = doc.querySelector("ul#sitemap");
    34     74               if (sm && xhr.status == 200) {
           75  +              // Got sitemap.  Insert it into the drop-down panel.
    35     76                 needSitemapHTML = false;
    36     77                 panel.innerHTML = sm.outerHTML;
    37     78                 if (window.setAllHrefs) {
    38     79                   setAllHrefs();   // don't need anti-robot defense here
    39     80                 }
    40         -              panel.show();
           81  +
           82  +              // Set up the CSS transition to animate the panel open and
           83  +              // closed.  Only needs to be done once per page load.
           84  +              // Based on https://stackoverflow.com/a/29047447/142454
           85  +              calculatePanelHeight();
           86  +              panel.style.transition = 'max-height 0.5s ease-in-out';
           87  +              panel.style.overflowY  = 'hidden';
           88  +              panel.style.maxHeight  = '0';
           89  +              panel.style.display    = 'block';
           90  +
           91  +              // Kick off the transition
           92  +              showPanel();
    41     93               }
    42     94             }
    43     95             // else, can't parse response as HTML or XML
    44     96           }
    45     97           xhr.open("GET", home + "/sitemap");
    46     98           xhr.responseType = "document";
    47     99           xhr.send();
    48    100         }
    49    101         else {
    50         -        panel.show();   // just show what we built above
          102  +        showPanel();   // just show what we built above
    51    103         }
    52    104         return false;  // prevent browser from acting on <a> click
    53    105       }
    54    106     })();
    55    107   </script>