add DACHFest to index
[slides.git] / fosdem2017 / slides.js
1 /******************************
2  * JavaScript for talk slides *
3  *      by Robert Kaiser      *
4  *      <kairo@kairo.at>      *
5  *     (for FOSDEM 2011)      *
6  ******************************/
7
8 var slides = {};
9 var articleNodes;
10 var currentSlide;
11 var currentIdx;
12 var defaultIdx = 1; // set to slide index to show by default
13 var firstIdx = 2; // set no value if to use first available
14 var lastIdx; // set no value if to use first available
15
16 var pageTitle, headerText, subHeaderText;
17 var navPrev, navNext, navPrevNolink, navNextNolink;
18
19 // Slide timer - color variation of headerText
20 // Up to 2/3 of that time, use "ontime" styling, then "neartime" until this is reached, "overtime" after that.
21 var slideSeconds = 2 * 60;
22
23 // Called when the document has been loaded.
24 function docLoaded() {
25   pageTitle = document.getElementsByTagName("title")[0];
26   headerText = document.getElementById("header-text");
27   subHeaderText = document.getElementById("subheader-text");
28   navPrev = document.getElementById("nav-prev");
29   navNext = document.getElementById("nav-next");
30   navPrevNolink = document.getElementById("nav-prev-nolink");
31   navNextNolink = document.getElementById("nav-next-nolink");
32   articleNodes = document.getElementsByTagName("article");
33
34   if (!firstIdx)
35     firstIdx = 0;
36   if (!lastIdx)
37     lastIdx = articleNodes.length - 1;
38
39   // Get a list of all slides (articles).
40   subHeaderText.textContent = articleNodes.length + " slides...";
41   for (var i = 0; i < articleNodes.length; ++i) {
42     subHeaderText.textContent = "Indexing slide " + i + " / " + articleNodes.length;
43     if (!articleNodes[i].id)
44       articleNodes[i].id = "slide_" + i;
45
46     slides[articleNodes[i].id] =
47        {"idx": i,
48         "name": articleNodes[i].id,
49         "title": articleNodes[i].title ? articleNodes[i].title : articleNodes[i].id,
50         "obj": articleNodes[i]};
51
52     if (location.hash.length &&
53         (location.hash == "#" + articleNodes[i].id || location.hash == "#" + i)) {
54       articleNodes[i].setAttribute("aria-selected", "true");
55       currentSlide = slides[articleNodes[i].id];
56       currentIdx = i;
57     }
58   }
59
60   if (!currentSlide) {
61     currentIdx = defaultIdx;
62     currentSlide = slides[articleNodes[currentIdx].id];
63     currentSlide.obj.setAttribute("aria-selected", "true");
64     location.hash = "#" + currentSlide.name;
65   }
66   updateDisplay();
67 }
68
69 // Called when the hash part of the location changes.
70 function locationHashChanged() {
71   if (location.hash.length > 1) {
72     var hashtag = location.hash.substring(1);
73     // If not a number, treat as ID
74     if (isNaN(hashtag) && slides[hashtag]) {
75       currentSlide.obj.removeAttribute("aria-selected");
76       currentSlide = slides[hashtag];
77       currentIdx = currentSlide.idx;
78       currentSlide.obj.setAttribute("aria-selected", "true");
79       updateDisplay();
80     }
81     else if (articleNodes[hashtag]) {
82       currentSlide.obj.removeAttribute("aria-selected");
83       currentIdx = hashtag;
84       currentSlide = slides[articleNodes[currentIdx].id];
85       currentSlide.obj.setAttribute("aria-selected", "true");
86       updateDisplay();
87     }
88   }
89 }
90 window.onhashchange = locationHashChanged;
91
92 // Update the display after we updated what slide is shown.
93 function updateDisplay() {
94   if (currentIdx >= firstIdx && currentIdx <= lastIdx &&
95       currentSlide.name != "toc")
96     subHeaderText.textContent = (currentIdx - firstIdx + 1) + "/" +
97                                 (lastIdx - firstIdx + 1) + " - " +
98                                 currentSlide.title;
99   else
100     subHeaderText.textContent = currentSlide.title;
101   pageTitle.textContent = headerText.textContent + ": " + currentSlide.title;
102   if (currentIdx > firstIdx && currentSlide.name != "toc") {
103     navPrev.hidden = false;
104     navPrev.href = "#" + articleNodes[currentIdx - 1].id;
105     navPrevNolink.hidden = true;
106   }
107   else {
108     navPrev.hidden = true;
109     navPrevNolink.hidden = false;
110   }
111   if (currentIdx < lastIdx && currentSlide.name != "toc") {
112     navNext.hidden = false;
113     navNext.href = "#" + articleNodes[currentIdx + 1].id;
114     navNextNolink.hidden = true;
115   }
116   else {
117     navNext.hidden = true;
118     navNextNolink.hidden = false;
119   }
120   headerText.className = "";
121   slideStart = new Date();
122   if (currentSlide.name == "toc")
123     createTOC();
124   else
125     setTimeout("timerFired()", timerMSec);
126 }
127
128 // Create TOC list.
129 function createTOC() {
130  var list = document.getElementById("toc-list");
131  if (!list.getElementsByTagName("li").length) {
132    for (var slide in slides) {
133      if (slide != "toc") {
134        var item = document.createElement("li");
135        var link = document.createElement("a");
136        var slideHeaders = slides[slide].obj.getElementsByTagName("h1");
137        if (slideHeaders.length)
138          link.textContent = slideHeaders[0].textContent;
139        else
140          link.textContent = slides[slide].title;
141        link.href = "#" + slides[slide].name;
142        item.appendChild(link);
143        list.appendChild(item);
144      }
145    }
146  }
147 }
148
149 // Do timed color variation on slides.
150 function timerFired() {
151   var slideCurrent = new Date();
152   var secondsDiff = Math.round((slideCurrent.getTime() - slideStart.getTime()) / 1000);
153   if (secondsDiff >= slideSeconds) {
154     headerText.className = "overtime";
155   }
156   else if (secondsDiff >= Math.round(2 * slideSeconds / 3)) {
157     headerText.className = "ontime";
158     setTimeout("timerFired()", timerMSec);
159   }
160   else if (secondsDiff >= Math.round(slideSeconds / 3)) {
161     headerText.className = "neartime";
162     setTimeout("timerFired()", timerMSec);
163   }
164   else {
165     // We should never come here, but if we do, go into a 100ms loop until we get over the upcoming step.
166     setTimeout("timerFired()", 100);
167   }
168 }
169 var slideStart = new Date();
170 var timerMSec = 1000 * (slideSeconds / 3);
171 setTimeout("timerFired()", timerMSec);
172
173 // Keyboard/click nav functionality, mostly inherited from FOSDEM 2007.
174 (function() {
175   function go(where) {
176     where = where || "next";
177     var navElem = document.getElementById("nav-" + where);
178     if (!navElem.hidden)
179       window.location.href = navElem.href;
180   }
181
182   function handleClick(e) {
183     e = e || event;
184     var target = (window.event) ? e.srcElement : e.target;
185     if (e.which == 1 && target.nodeName != "A" && target.nodeName != "VIDEO")
186       go("next");
187   }
188
189   function handleKeyPress(e) {
190     e = e || event;
191     switch (e.keyCode) {
192       // See https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode#Constants_for_keyCode_value
193       case e.DOM_VK_LEFT:
194       case e.DOM_VK_DOWN:
195       case e.DOM_VK_PAGE_DOWN:
196       case e.DOM_VK_H: //8bitdo Zero "X"
197         go("prev"); break;
198       case e.DOM_VK_RIGHT:
199       case e.DOM_VK_UP:
200       case e.DOM_VK_PAGE_UP:
201       case e.DOM_VK_J: //8bitdo Zero "B"
202         go("next"); break;
203       case e.DOM_VK_HOME:
204         go("start"); break;
205       case e.DOM_VK_END:
206         go("toc"); break;
207     }
208   }
209
210   window.onclick = handleClick;
211   window.onkeypress = handleKeyPress;
212 })();