// talk_slides.js
// 
// navigation for slides in Donhost talks
// 
// assumptions:
//   * The page initially loads in slides list view, using a style-sheet with
//     id="SlidesListStylesheet".
//   * There is an alternative style-sheet for the slideshow view, with
//     id="SlideshowStylesheet".
//   * There is something which runs SwitchToSlideshow() to switch from the
//     slides list view to the slideshow view.
//   * Every slide is a block with class="Slide", and initially has display:
//     none.
//   * Each slide is numbered consecutively with id="S1", id="S2", ...
//   * The contents of the splash screen is in a block with id="Splash", which
//     initially has display: block;
//   * There is a block with id="BreakAlert", which initially has display:
//     none.
//   * <img> elements initially have their sources set to sources for the
//     slides list view, with filenames such as 2h_foo.png.  Images for the
//     slideshow view exist with filenames such as 2d_foo.png (replacing the
//     "h" with "d" after the number).  The dimensions of the slideshow images
//     are stored in the SlideShowImageWidth and SlideShowImageHeight arrays,
//     with indices corresponding to the numbers in the filenames.
// 
// by Smylers, for GBdirect <Smylers@stripey.com>
// 
// This file is placed in the public domain.  You may do what you wish with it.


// Keeping navigation disabled (while in the slide list view) until
// specifically activated (by switching to the slideshow view):
var NavigationEnabled = false;
var CurrentSlide = 0;
var Splash = true;


function DisplaySlide(NewSlide)
// displays the specified slide, hiding whatever is on screen currently
{

  var Old;
  if (Splash)
  {
    Old = document.getElementById('Splash');
    Splash = false;
  }
  else
  {
    Old = document.getElementById('S' + CurrentSlide);
  }
  Old.style.display = 'none';

  // The current slide may be scrolled down the screen, so ensure the new one
  // is displayed from the top:
  window.scrollTo(0, 0);

  CurrentSlide = NewSlide;
  document.getElementById('S' + CurrentSlide).style.display = 'block';

  // Display the break alert if this is the last or penultimate slide, that is
  // if a slide numbered 2 more than the current one doesn't exist:
  document.getElementById('BreakAlert').style.display =
      document.getElementById('S' + (CurrentSlide + 2)) ? 'none' : 'block';

} // DisplaySlide()


function DisplaySplash()
// displays the splash screen
{

  document.getElementById('Splash').style.display = 'block';
  document.getElementById('S' + CurrentSlide).style.display = 'none';
  document.getElementById('BreakAlert').style.display = 'none';
  Splash = true;

} // DisplaySplash()


var Count = 0;
var JumpedFromSlide = 0;

function Keystroke(Event)
// handles a keystroke event for navigating through slides
{

  // If navigation hasn't been enabled, then don't do anything.  Also, anything
  // with a modifier is passed on to the browser:
  if (!NavigationEnabled
      || Event.altKey || Event.ctrlKey || Event.shiftKey || Event.metaKey)
  {
    return true;
  }

  var KeyCode = Event.which;
  var Key = String.fromCharCode(KeyCode).toUpperCase();

  // prefix count:
  if (Key >= '0' && Key <= '9')
  {
    Count = Count * 10 + Number(Key);
  }

  else
  {
    // N or Space for next slide:
    if (Key == 'N' || Key == ' ')
    {
      Next();
    }

    // P or BkSpc for previous slide:
    else if (Key == 'P' || KeyCode == 8)
    {
      Prev();
    }

    // S for jumping to a particular slide, by number:
    else if (Key == 'S')
    {
      var NewSlide = Count || window.prompt('Slide number?');
      if (NewSlide && document.getElementById('S' + NewSlide))
      {
        JumpedFromSlide = CurrentSlide;
        DisplaySlide(NewSlide);
      }
    }

    // R for returning after jumping with S:
    else if (Key == 'R')
    {
      if (JumpedFromSlide)
      {
        var NewSlide = JumpedFromSlide;
        JumpedFromSlide = CurrentSlide;
        DisplaySlide(NewSlide);
      }
    }

    // If none of the above then pass it on to the browser:
    else
    {
      return true;
    }

    // Reset the count after any of these keystrokes (whether it's been used or
    // not):
    Count = 0;

  } // test for a non-counting keystroke

  // Since we're here, it must have been a keystroke that we handled above so
  // discourage the browser from trying to do anything with it itself:
  Event.preventBubble();
  return false;
}

// Send all keystrokes to the above handler:
window.onkeypress = Keystroke;


function Click(Event)
// handles mouse-click events for navigation
{

  // If navigation hasn't been enabled, then don't do anything.  Also, anything
  // with a modifier is passed on to the browser:
  if (!NavigationEnabled
      || Event.altKey || Event.ctrlKey || Event.shiftKey || Event.metaKey)
  {
    return true;
  }

  var Button = Event.button;

  // left button for next slide:
  if (Button == 0)
  {
    Next();
  }

  // right button for previous slide (though this doesn't seem to be working):
  else if (Button == 2)
  {
    Prev();
  }

  // Any other button is passed to the browser to deal with:
  else
  {
    return true;
  }

  // If we're here then we dealt with the click above, so discourage the
  // browser from doing anything with it:
  Event.preventBubble();
  return false;
} // Click()

// Send all clicks to the above handler: */
window.onclick = Click;


function SwitchToSlideshow()
// switches to the slideshow view and enables the JavaScript navigation
{

  // Swap the style-sheets:
  document.getElementById('SlidesListStylesheet').disabled = true;
  document.getElementById('SlideshowStylesheet').disabled = false;

  // The images in the slides will have shrunken ('half-size') dimensions to
  // fit into the slide list view.  Replace each one with an equivalent
  // ('double-size') suitable for the slideshow view:
  for (var i = 0; i < document.images.length; i++) with (document.images[i])
  {

    // A half-size image has a names such as 2h_foo.png.  This could be
    // transformed to the double-size version using String.replace, but there
    // doesn't seem to be any way of getting the values of $1 et al out of that
    // method (for use below with the sizes).  So instead grab all the parts of
    // the complete path, for reconstituting by hand:
    var Matched = src.match(/^(.*\/)(\d+)h(_[^\/]+)$/);

    // Only continue if this is indeed an image from a slide, not a standard
    // part of the formatting:
    if (Matched)
    {

      // The double-size filename is like the half-size one but with 'd'
      // instead of 'h':
      src = Matched[1] + Matched[2] + 'd' + Matched[3];

      // Remove the title, which indicates that the image can be zoomed in in
      // the slide-list view:
      title = '';

      // Set the dimensions for the double-size version, which will be stored
      // in a couple of arrays in the page, indexed by image number:
      width = SlideShowImageWidth[Matched[2]];
      height = SlideShowImageHeight[Matched[2]];
    }

  } // loop through each image

  NavigationEnabled = true;

} // SwitchToSlideshow()


var LastSlide = 1;


function Next()
// move to the next screen
{

  if (Splash)
  {
    DisplaySlide(1);
  }
  else
  {
    var NewSlide = CurrentSlide + 1;
    if (document.getElementById('S' + NewSlide))
    {
      DisplaySlide(NewSlide);
    }

    // After the last slide, display the splash screen again, noting the
    // current slide number for the purposes of moving 'backwards' from there
    // to the last slide in the future:
    else
    {
      LastSlide = CurrentSlide;
      DisplaySplash();
    }
  }

}


function Prev()
// move to the previous screen
{

  if (Splash)
  {
    DisplaySlide(LastSlide);
  }
  else if (CurrentSlide == 1)
  {
    DisplaySplash();
  }
  else
  {
    DisplaySlide(CurrentSlide - 1);
  }

}

