644 lines
13 KiB
JavaScript
644 lines
13 KiB
JavaScript
/* ShowOff JS Logic */
|
|
|
|
var ShowOff = {};
|
|
|
|
var preso_started = false
|
|
var slidenum = 0
|
|
var slideTotal = 0
|
|
var slides
|
|
var currentSlide
|
|
var totalslides = 0
|
|
var slidesLoaded = false
|
|
var incrSteps = 0
|
|
var incrElem
|
|
var incrCurr = 0
|
|
var incrCode = false
|
|
var debugMode = false
|
|
var gotoSlidenum = 0
|
|
var shiftKeyActive = false
|
|
|
|
var loadSlidesBool
|
|
var loadSlidesPrefix
|
|
|
|
function setupPreso(load_slides, prefix) {
|
|
if (preso_started)
|
|
{
|
|
alert("already started")
|
|
return
|
|
}
|
|
preso_started = true
|
|
|
|
loadSlidesBool = load_slides
|
|
loadSlidesPrefix = prefix
|
|
loadSlides(loadSlidesBool, loadSlidesPrefix)
|
|
|
|
doDebugStuff()
|
|
|
|
// bind event handlers
|
|
document.onkeydown = keyDown
|
|
document.onkeyup = keyUp
|
|
/* window.onresize = resized; */
|
|
/* window.onscroll = scrolled; */
|
|
/* window.onunload = unloaded; */
|
|
|
|
$('body').addSwipeEvents().
|
|
bind('tap', swipeLeft). // next
|
|
bind('swipeleft', swipeLeft). // next
|
|
bind('swiperight', swipeRight); // prev
|
|
}
|
|
|
|
function loadSlides(load_slides, prefix) {
|
|
//load slides offscreen, wait for images and then initialize
|
|
if (load_slides) {
|
|
$("#slides").load("slides", false, function(){
|
|
$("#slides img").batchImageLoad({
|
|
loadingCompleteCallback: initializePresentation(prefix)
|
|
})
|
|
})
|
|
} else {
|
|
$("#slides img").batchImageLoad({
|
|
loadingCompleteCallback: initializePresentation(prefix)
|
|
})
|
|
}
|
|
}
|
|
|
|
function initializePresentation(prefix) {
|
|
// unhide for height to work in static mode
|
|
$("#slides").show();
|
|
|
|
//center slides offscreen
|
|
centerSlides($('#slides > .slide'))
|
|
|
|
//copy into presentation area
|
|
$("#preso").empty()
|
|
$('#slides > .slide').appendTo($("#preso"))
|
|
|
|
//populate vars
|
|
slides = $('#preso > .slide')
|
|
slideTotal = slides.size()
|
|
|
|
//setup manual jquery cycle
|
|
$('#preso').cycle({
|
|
timeout: 0
|
|
})
|
|
|
|
setupMenu()
|
|
if (slidesLoaded) {
|
|
showSlide()
|
|
} else {
|
|
showFirstSlide();
|
|
slidesLoaded = true
|
|
}
|
|
setupSlideParamsCheck();
|
|
sh_highlightDocument(prefix+'/js/sh_lang/', '.min.js')
|
|
$("#preso").trigger("showoff:loaded");
|
|
}
|
|
|
|
function centerSlides(slides) {
|
|
slides.each(function(s, slide) {
|
|
centerSlide(slide)
|
|
})
|
|
}
|
|
|
|
function centerSlide(slide) {
|
|
var slide_content = $(slide).children(".content").first()
|
|
var height = slide_content.height()
|
|
var mar_top = (0.5 * parseFloat($(slide).height())) - (0.5 * parseFloat(height))
|
|
if (mar_top < 0) {
|
|
mar_top = 0
|
|
}
|
|
slide_content.css('margin-top', mar_top)
|
|
}
|
|
|
|
function setupMenu() {
|
|
$('#navmenu').hide();
|
|
|
|
var currSlide = 0
|
|
var menu = new ListMenu()
|
|
|
|
slides.each(function(s, elem) {
|
|
content = $(elem).children(".content")
|
|
shortTxt = $(content).text().substr(0, 20)
|
|
path = $(content).attr('ref').split('/')
|
|
currSlide += 1
|
|
menu.addItem(path, shortTxt, currSlide)
|
|
})
|
|
|
|
$('#navigation').html(menu.getList())
|
|
$('#navmenu').menu({
|
|
content: $('#navigation').html(),
|
|
flyOut: true
|
|
});
|
|
}
|
|
|
|
function checkSlideParameter() {
|
|
if (slideParam = currentSlideFromParams()) {
|
|
slidenum = slideParam;
|
|
}
|
|
}
|
|
|
|
function currentSlideFromParams() {
|
|
var result;
|
|
if (result = window.location.hash.match(/#([0-9]+)/)) {
|
|
return result[result.length - 1] - 1;
|
|
}
|
|
}
|
|
|
|
function setupSlideParamsCheck() {
|
|
var check = function() {
|
|
var currentSlide = currentSlideFromParams();
|
|
if (slidenum != currentSlide) {
|
|
slidenum = currentSlide;
|
|
showSlide();
|
|
}
|
|
setTimeout(check, 100);
|
|
}
|
|
setTimeout(check, 100);
|
|
}
|
|
|
|
function gotoSlide(slideNum) {
|
|
slidenum = parseInt(slideNum)
|
|
if (!isNaN(slidenum)) {
|
|
showSlide()
|
|
}
|
|
}
|
|
|
|
function showFirstSlide() {
|
|
slidenum = 0
|
|
checkSlideParameter();
|
|
showSlide()
|
|
}
|
|
|
|
function showSlide(back_step) {
|
|
|
|
if(slidenum < 0) {
|
|
slidenum = 0
|
|
return
|
|
}
|
|
|
|
if(slidenum > (slideTotal - 1)) {
|
|
slidenum = slideTotal - 1
|
|
return
|
|
}
|
|
|
|
currentSlide = slides.eq(slidenum)
|
|
|
|
var transition = currentSlide.attr('data-transition')
|
|
var fullPage = currentSlide.find(".content").is('.full-page');
|
|
|
|
if (back_step || fullPage) {
|
|
transition = 'none'
|
|
}
|
|
|
|
$('#preso').cycle(slidenum, transition)
|
|
|
|
if (fullPage) {
|
|
$('#preso').css({'width' : '100%', 'overflow' : 'visible'});
|
|
currentSlide.css({'width' : '100%', 'text-align' : 'center', 'overflow' : 'visible'});
|
|
}
|
|
|
|
percent = getSlidePercent()
|
|
$("#slideInfo").text((slidenum + 1) + '/' + slideTotal + ' - ' + percent + '%')
|
|
|
|
if(!back_step) {
|
|
// determine if there are incremental bullets to show
|
|
// unless we are moving backward
|
|
determineIncremental()
|
|
} else {
|
|
incrCurr = 0
|
|
incrSteps = 0
|
|
}
|
|
location.hash = slidenum + 1;
|
|
|
|
removeResults();
|
|
|
|
var currentContent = $(currentSlide).find(".content")
|
|
currentContent.trigger("showoff:show");
|
|
|
|
return getCurrentNotes()
|
|
}
|
|
|
|
function getSlideProgress()
|
|
{
|
|
return (slidenum + 1) + '/' + slideTotal
|
|
}
|
|
|
|
function getCurrentNotes()
|
|
{
|
|
var notes = currentSlide.find("p.notes").text()
|
|
$('#notesInfo').text(notes)
|
|
return notes
|
|
}
|
|
|
|
function getSlidePercent()
|
|
{
|
|
return Math.ceil(((slidenum + 1) / slideTotal) * 100)
|
|
}
|
|
|
|
function determineIncremental()
|
|
{
|
|
incrCurr = 0
|
|
incrCode = false
|
|
incrElem = currentSlide.find(".incremental > ul > li")
|
|
incrSteps = incrElem.size()
|
|
if(incrSteps == 0) {
|
|
// also look for commandline
|
|
incrElem = currentSlide.find(".incremental > pre > code > code")
|
|
incrSteps = incrElem.size()
|
|
incrCode = true
|
|
}
|
|
incrElem.each(function(s, elem) {
|
|
$(elem).css('visibility', 'hidden');
|
|
})
|
|
}
|
|
|
|
function prevStep()
|
|
{
|
|
|
|
var event = jQuery.Event("showoff:prev");
|
|
$(currentSlide).find(".content").trigger(event);
|
|
if (event.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
|
|
slidenum--
|
|
return showSlide(true) // We show the slide fully loaded
|
|
}
|
|
|
|
function nextStep()
|
|
{
|
|
var event = jQuery.Event("showoff:next");
|
|
$(currentSlide).find(".content").trigger(event);
|
|
if (event.isDefaultPrevented()) {
|
|
return;
|
|
}
|
|
|
|
if (incrCurr >= incrSteps) {
|
|
slidenum++
|
|
return showSlide()
|
|
} else {
|
|
elem = incrElem.eq(incrCurr)
|
|
if (incrCode && elem.hasClass('command')) {
|
|
incrElem.eq(incrCurr).css('visibility', 'visible').jTypeWriter({duration:1.0})
|
|
} else {
|
|
incrElem.eq(incrCurr).css('visibility', 'visible')
|
|
}
|
|
incrCurr++
|
|
}
|
|
}
|
|
|
|
function doDebugStuff()
|
|
{
|
|
if (debugMode) {
|
|
$('#debugInfo').show()
|
|
debug('debug mode on')
|
|
} else {
|
|
$('#debugInfo').hide()
|
|
}
|
|
}
|
|
|
|
var notesMode = false
|
|
function toggleNotes()
|
|
{
|
|
notesMode = !notesMode
|
|
if (notesMode) {
|
|
$('#notesInfo').show()
|
|
debug('notes mode on')
|
|
} else {
|
|
$('#notesInfo').hide()
|
|
}
|
|
}
|
|
|
|
function executeAnyCode()
|
|
{
|
|
var $jsCode = $('.execute .sh_javascript code:visible')
|
|
if ($jsCode.length > 0) {
|
|
executeCode.call($jsCode);
|
|
}
|
|
var $rubyCode = $('.execute .sh_ruby code:visible')
|
|
if ($rubyCode.length > 0) {
|
|
executeRuby.call($rubyCode);
|
|
}
|
|
var $coffeeCode = $('.execute .sh_coffeescript code:visible')
|
|
if ($coffeeCode.length > 0) {
|
|
executeCoffee.call($coffeeCode);
|
|
}
|
|
}
|
|
|
|
function debug(data)
|
|
{
|
|
$('#debugInfo').text(data)
|
|
}
|
|
|
|
// See e.g. http://www.quirksmode.org/js/keys.html for keycodes
|
|
function keyDown(event)
|
|
{
|
|
var key = event.keyCode;
|
|
|
|
if (event.ctrlKey || event.altKey || event.metaKey)
|
|
return true;
|
|
|
|
debug('keyDown: ' + key)
|
|
|
|
if (key >= 48 && key <= 57) // 0 - 9
|
|
{
|
|
gotoSlidenum = gotoSlidenum * 10 + (key - 48);
|
|
return true;
|
|
}
|
|
|
|
if (key == 13) {
|
|
if (gotoSlidenum > 0) {
|
|
debug('go to ' + gotoSlidenum);
|
|
slidenum = gotoSlidenum - 1;
|
|
showSlide(true);
|
|
gotoSlidenum = 0;
|
|
} else {
|
|
debug('executeCode');
|
|
executeAnyCode();
|
|
}
|
|
}
|
|
|
|
|
|
if (key == 16) // shift key
|
|
{
|
|
shiftKeyActive = true;
|
|
}
|
|
|
|
if (key == 32) // space bar
|
|
{
|
|
if (shiftKeyActive) {
|
|
prevStep()
|
|
} else {
|
|
nextStep()
|
|
}
|
|
}
|
|
else if (key == 68) // 'd' for debug
|
|
{
|
|
debugMode = !debugMode
|
|
doDebugStuff()
|
|
}
|
|
else if (key == 37 || key == 33 || key == 38) // Left arrow, page up, or up arrow
|
|
{
|
|
prevStep()
|
|
}
|
|
else if (key == 39 || key == 34 || key == 40) // Right arrow, page down, or down arrow
|
|
{
|
|
nextStep()
|
|
}
|
|
else if (key == 82) // R for reload
|
|
{
|
|
if (confirm('really reload slides?')) {
|
|
loadSlides(loadSlidesBool, loadSlidesPrefix)
|
|
showSlide()
|
|
}
|
|
}
|
|
else if (key == 84 || key == 67) // T or C for table of contents
|
|
{
|
|
$('#navmenu').toggle().trigger('click')
|
|
}
|
|
else if (key == 90 || key == 191) // z or ? for help
|
|
{
|
|
$('#help').toggle()
|
|
}
|
|
else if (key == 66 || key == 70) // f for footer (also "b" which is what kensington remote "stop" button sends
|
|
{
|
|
toggleFooter()
|
|
}
|
|
else if (key == 78) // 'n' for notes
|
|
{
|
|
toggleNotes()
|
|
}
|
|
else if (key == 27) // esc
|
|
{
|
|
removeResults();
|
|
}
|
|
else if (key == 80) // 'p' for preshow
|
|
{
|
|
togglePreShow();
|
|
}
|
|
return true
|
|
}
|
|
|
|
function toggleFooter()
|
|
{
|
|
$('#footer').toggle()
|
|
}
|
|
|
|
function keyUp(event) {
|
|
var key = event.keyCode;
|
|
debug('keyUp: ' + key);
|
|
if (key == 16) // shift key
|
|
{
|
|
shiftKeyActive = false;
|
|
}
|
|
}
|
|
|
|
function swipeLeft() {
|
|
nextStep();
|
|
}
|
|
|
|
function swipeRight() {
|
|
prevStep();
|
|
}
|
|
|
|
function ListMenu(s)
|
|
{
|
|
this.slide = s
|
|
this.typeName = 'ListMenu'
|
|
this.itemLength = 0;
|
|
this.items = new Array();
|
|
this.addItem = function (key, text, slide) {
|
|
if (key.length > 1) {
|
|
thisKey = key.shift()
|
|
if (!this.items[thisKey]) {
|
|
this.items[thisKey] = new ListMenu(slide)
|
|
}
|
|
this.items[thisKey].addItem(key, text, slide)
|
|
} else {
|
|
thisKey = key.shift()
|
|
this.items[thisKey] = new ListMenuItem(text, slide)
|
|
}
|
|
}
|
|
this.getList = function() {
|
|
var newMenu = $("<ul>")
|
|
for(var i in this.items) {
|
|
var item = this.items[i]
|
|
var domItem = $("<li>")
|
|
if (item.typeName == 'ListMenu') {
|
|
choice = $("<a rel=\"" + (item.slide - 1) + "\" href=\"#\">" + i + "</a>")
|
|
domItem.append(choice)
|
|
domItem.append(item.getList())
|
|
}
|
|
if (item.typeName == 'ListMenuItem') {
|
|
choice = $("<a rel=\"" + (item.slide - 1) + "\" href=\"#\">" + item.slide + '. ' + item.textName + "</a>")
|
|
domItem.append(choice)
|
|
}
|
|
newMenu.append(domItem)
|
|
}
|
|
return newMenu
|
|
}
|
|
}
|
|
|
|
function ListMenuItem(t, s)
|
|
{
|
|
this.typeName = "ListMenuItem"
|
|
this.slide = s
|
|
this.textName = t
|
|
}
|
|
|
|
var removeResults = function() {
|
|
$('.results').remove();
|
|
};
|
|
|
|
var print = function(text) {
|
|
removeResults();
|
|
var _results = $('<div>').addClass('results').html($.print(text, {max_string:500}));
|
|
$('body').append(_results);
|
|
_results.click(removeResults);
|
|
};
|
|
|
|
function executeCode () {
|
|
result = null;
|
|
var codeDiv = $(this);
|
|
codeDiv.addClass("executing");
|
|
eval(codeDiv.text());
|
|
setTimeout(function() { codeDiv.removeClass("executing");}, 250 );
|
|
if (result != null) print(result);
|
|
}
|
|
$('.execute .sh_javascript code').live("click", executeCode);
|
|
|
|
function executeRuby () {
|
|
var codeDiv = $(this);
|
|
codeDiv.addClass("executing");
|
|
$.get('/eval_ruby', {code: codeDiv.text()}, function(result) {
|
|
if (result != null) print(result);
|
|
codeDiv.removeClass("executing");
|
|
});
|
|
}
|
|
$('.execute .sh_ruby code').live("click", executeRuby);
|
|
|
|
function executeCoffee() {
|
|
result = null;
|
|
var codeDiv = $(this);
|
|
codeDiv.addClass("executing");
|
|
// Coffeescript encapsulates everything, so result must be attached to window.
|
|
var code = codeDiv.text() + ';window.result=result;'
|
|
eval(CoffeeScript.compile(code));
|
|
setTimeout(function() { codeDiv.removeClass("executing");}, 250 );
|
|
if (result != null) print(result);
|
|
}
|
|
$('.execute .sh_coffeescript code').live("click", executeCoffee);
|
|
|
|
/********************
|
|
PreShow Code
|
|
********************/
|
|
|
|
var preshow_seconds = 0;
|
|
var preshow_secondsLeft = 0;
|
|
var preshow_secondsPer = 8;
|
|
var preshow_running = false;
|
|
var preshow_timerRunning = false;
|
|
var preshow_current = 0;
|
|
var preshow_images;
|
|
var preshow_imagesTotal = 0;
|
|
var preshow_des = null;
|
|
|
|
function togglePreShow() {
|
|
if(preshow_running) {
|
|
stopPreShow()
|
|
} else {
|
|
var minutes = prompt("Minutes from now to start")
|
|
preshow_secondsLeft = parseFloat(minutes) * 60
|
|
toggleFooter()
|
|
$.getJSON("preshow_files", false, function(data) {
|
|
$('#preso').after("<div id='preshow'></div><div id='tips'></div><div id='preshow_timer'></div>")
|
|
$.each(data, function(i, n) {
|
|
if(n == "preshow.json") {
|
|
// has a descriptions file
|
|
$.getJSON("/file/_preshow/preshow.json", false, function(data) {
|
|
preshow_des = data
|
|
})
|
|
} else {
|
|
$('#preshow').append('<img ref="' + n + '" src="/file/_preshow/' + n + '"/>')
|
|
}
|
|
})
|
|
startPreShow()
|
|
})
|
|
}
|
|
}
|
|
|
|
function startPreShow() {
|
|
if (!preshow_running) {
|
|
preshow_running = true
|
|
preshow_seconds = 0
|
|
preshow_images = $('#preshow > img')
|
|
preshow_imagesTotal = preshow_images.size()
|
|
nextPreShowImage()
|
|
|
|
if(!preshow_timerRunning) {
|
|
setInterval(function() {
|
|
preshow_timerRunning = true
|
|
if (!preshow_running) { return }
|
|
preshow_seconds++
|
|
preshow_secondsLeft--
|
|
if (preshow_secondsLeft < 0) {
|
|
stopPreShow()
|
|
}
|
|
if (preshow_seconds == preshow_secondsPer) {
|
|
preshow_seconds = 0
|
|
nextPreShowImage()
|
|
}
|
|
addPreShowTips()
|
|
}, 1000)
|
|
}
|
|
}
|
|
}
|
|
|
|
function addPreShowTips() {
|
|
time = secondsToTime(preshow_secondsLeft)
|
|
$('#preshow_timer').text(time + ' to go-time')
|
|
var des = preshow_des && preshow_des[tmpImg.attr("ref")]
|
|
if(des) {
|
|
$('#tips').show()
|
|
$('#tips').text(des)
|
|
} else {
|
|
$('#tips').hide()
|
|
}
|
|
}
|
|
|
|
function secondsToTime(sec) {
|
|
min = Math.floor(sec / 60)
|
|
sec = sec - (min * 60)
|
|
if(sec < 10) {
|
|
sec = "0" + sec
|
|
}
|
|
return min + ":" + sec
|
|
}
|
|
|
|
function stopPreShow() {
|
|
preshow_running = false
|
|
|
|
$('#preshow').remove()
|
|
$('#tips').remove()
|
|
$('#preshow_timer').remove()
|
|
|
|
toggleFooter()
|
|
loadSlides(loadSlidesBool, loadSlidesPrefix);
|
|
}
|
|
|
|
function nextPreShowImage() {
|
|
preshow_current += 1
|
|
if((preshow_current + 1) > preshow_imagesTotal) {
|
|
preshow_current = 0
|
|
}
|
|
|
|
$("#preso").empty()
|
|
tmpImg = preshow_images.eq(preshow_current).clone()
|
|
$(tmpImg).attr('width', '1020')
|
|
$("#preso").html(tmpImg)
|
|
}
|
|
|
|
/********************
|
|
End PreShow Code
|
|
********************/
|