Presen

?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>YAPC::Asia 2009 / Asynchronous Programming for (A)synchronous Communication</title>
    <link href="assets/presen.css" rel="stylesheet" type="text/css" media="all" />
</head>
<body>
    <div id="container">
        <div id="topics">TopicsPlaceHolder</div>

    </div>

    <div id="padding"></div>

    <div id="footer">
        <span id="title">SectionTitlePlaceHolder</span>
        <span id="page_info">
            <span id="time">TIME</span> <span id="rest_time">rest time</span> <span id="current_page">current</span>/<span id="total_page">total</span>

        </span>
    </div>

    <script type="text/javascript" src="assets/jquery-1.2.6.js"></script>
    <script type="text/javascript" src="assets/presen.js"></script>
</body>
</html>
var Event = {};
Event.stop = function(e){
    Event.stopAction(e);
    Event.stopEvent(e);
};
Event.stopAction = function(e){
    e.preventDefault ? e.preventDefault() : (e.returnValue = false)
};
Event.stopEvent = function(e){
    e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true)
};

// -------------------------------------------------------------------------

var start_time = new Date();
var Presen = {};
Presen.init = function(data){
    this.data = data;

    this.init_sections();
    this.init_title();
    this.init_page();
    this.rewrite();

    $("#page_info").css('left', (window.innerWidth - 200) + "px");

    $("#total_page").html(Presen.sections.length);

    setInterval(
        Presen.update_footer, 1
    );
};

Presen.init_page = function () {
    if (location.hash == "") {
        this.page = 0;
    } else {
        this.page = Number(location.hash.substr(1));
    }
}

Presen.init_sections = function () {
    var sections = [[]];
    var topic_reg = /^----/;
    $(this.data).each(function (i, line) {
        if (topic_reg.test(line)){
            sections.push([line]);
        } else {
            sections[sections.length-1].push(line);
        }
    });
    this.sections = sections;
};

Presen.init_title = function () {
    var titles = this.sections[0];
    // document.title = titles[0];
    $("#title").html(titles[0]);
};

Presen.has_next = function(){
    return this.page < this.sections.length-1;
};
Presen.next = function(){
    if (!this.has_next()) {
        return;
    }
    this.page++;
    this.rewrite();
};

Presen.has_prev = function(){
    return this.page > 0;
}
Presen.prev = function(){
    if (! this.has_prev()) {
        return; // nop.
    }
    this.page--;
    this.rewrite();
};

Presen.update_footer = function () {
    var now = new Date();
    $("#time").html(now.hms());

    $("#current_page").html((Presen.page+1));

    var rest = parseInt( (now - start_time)/1000 );
    $('#rest_time').html('' + parseInt(rest/60.0) + '.' + parseInt(rest/60.0*100.0)/100.0);

    $("#footer").css('top', (window.innerHeight - 50) + "px");
}

Presen.rewrite = function(){
    var p = this.page;
    $("#topics").html(this.format(this.sections[p]));
    location.hash = "#" + p;
};

Presen.format = function(lines){
    var context = [];
    var mode = "p";
    $(lines).each(function(i, v){
        if (/^----$/.test(v)) {
            return; // page separater
        }

        if(/^(\*\s)/.test(v)){
            context.push(v.replace(/^\*+/, "").tag("h2"));
            return;
        }
        if(/^(\*+)/.test(v)){
            context.push(v.replace(/^\*+/, "").tag("h3"));
            return;
        }
        if(/^\-\-/.test(v)){
            context.push(v.replace(/^\-\-/,"").tag("span", "list_child") + "");
            return;
        }
        if(/^\-/.test(v)){
            context.push(v.replace(/^\-+/,"").tag("span","list"));
            return;
        }
        
        if (/^\>\|\|/.test(v)) {
            mode = "pre";
            context.push("<pre>");
            return;
        }
        if (/^\|\|\</.test(v)) {
            mode = "p";
            context.push("</pre>");
            return;
        }
        
        if (mode=="pre") {
            context.push(v.escapeHTML().tag("span") + "\n");
        } else {
            context.push(v.tag("span") + "<br>");
        }
    });
    return context.join("");
};
Number.prototype.padding = function(n) {
    if (this.toString().length >= n) return this;
    var l = ("" + this).length;
    // alert(Array(1));
    return Array(n).join("0") + this;
};

Date.prototype.hms = function () {
    return '' + this.getHours().padding(2) + ":" + this.getMinutes().padding(2) + ":" + this.getSeconds().padding(2);
}

String.prototype.tag = function(tag, classname){
    return ['<',tag, (classname ? " class='"+classname+"'" : ""), '>',this,'</',tag,'>'].join("");
}

String.prototype.escapeHTML = function () {
    return this.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}

Presen.observe_key_event = function () {
    $(document).keydown(function(e) {
        var s = Event.stop;
        switch(e.keyCode){
            case 82: // r
                location.reload();
                break;
            
            case 80: // p
            case 75: // k
            case 38: Presen.prev();s(e);break;
            
            case 78: // n
            case 74: // j
            case 40: Presen.next();s(e);break;
        }
    });
};

// -------------------------------------------------------------------------

$(function (){
    $.get('main.txt', function (text) {
        try {
            Presen.init(text.split("\n"));
        } catch(e) {
            alert(e) 
        }
    });

    Presen.observe_key_event();
});
body {
    color: #000;
    background: #fff;
    margin: 0;
    padding: 0;
}

body * {
    margin: 0;
    padding : 0;
}

span.list {
    display: list-item;
    margin-left: 2em;
    line-height: 1.5;
    margin-right: 3em;
}
/*
span.list:before {
    content: " ● ";
}
span.list_child:before {
    content: " ○";

}    
*/
span.list_child {
    display: list-item;
    font-size: 0.8em;
    margin-left: 3em;
    margin-right: 3em;
    line-height : 1.5;
    list-style-type: circle;
}

#topics {
    margin: 0;
    margin-bottom: 50px;
    padding: 0;
    /*margin-left: 5px;
    margin-right: 5px;
    margin-top: 0px;
    margin-bottom: 5px;
    */
    text-align : left;
    font-size : 40px;
    font-weight: bold;
}

#topics h2 {
    padding : 10px;
    margin-bottom: 15px;
    font-size : 120%;
    line-height : 1;
    background-color : #ccf;
    border-bottom: 1px solid #000;
    color: black;
    text-align: center;
}


#topics h3 {
    padding : 10px;
    margin-bottom: 15px;
    font-size : 120%;
    line-height : 1;
    background-color : #ccc;
    border-bottom: 1px solid #000;
    color: black;
    text-align: center;
}

#topics pre {
    padding: 5px;
    font-size: 80%;
    margin: 5px;
    background-color: #ccc;
    font-family: monospace;
}

#topics div {
    margin: 1em;
}

/* ------------------------------------------------------------------------- */

#footer {
    position: fixed;
    bottom: 0;
    width: 100%;
    height: 30px;
    padding-top: 3px;
    color : #fff;
    padding-bottom: 1px;
    border-top: 1px solid #0f0;
    background-color: #000000;
}

#footer #page_info {
    position: absolute;
}

B {
    color: red;
    font-size: 150%;
}