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