git.iko.soy/typeable/pandoc
on 1.9.4.1 help sign in
321 lines 16 kB history raw
1/* This work is licensed under Creative Commons GNU LGPL License.
3 License: http://creativecommons.org/licenses/LGPL/2.1/
5 Author: Stefan Goessner/2005-2006
6 Web: http://goessner.net/
7*/
8var Slideous = {
9 version: 1.0,
10 // == user customisable ===
11 clickables: { a: true, button: true, img: true, input: true, object: true, textarea: true, select: true, option: true },
12 incrementables: { blockquote: { filter: "self, parent" },
13 dd: { filter: "self, parent" },
14 dt: { filter: "self, parent" },
15 h2: { filter: "self, parent" },
16 h3: { filter: "self, parent" },
17 h4: { filter: "self, parent" },
18 h5: { filter: "self, parent" },
19 h6: { filter: "self, parent" },
20 li: { filter: "self, parent" },
21 p: { filter: "self" },
22 pre: { filter: "self" },
23 img: { filter: "self, parent" },
24 object: { filter: "self, parent" },
25 table: { filter: "self, parent" },
26 td: { filter: "self, parent" },
27 th: { filter: "self, parent" },
28 tr: { filter: "parent, grandparent" }
29 },
30 autoincrementables: { ol: true, ul: true, dl: true },
31 autoincrement: false,
32 statusbar: true,
33 navbuttons: { incfontbutton: function(){Slideous.changefontsize(+Slideous.fontdelta);},
34 decfontbutton: function(){Slideous.changefontsize(-Slideous.fontdelta);},
35 contentbutton: function(){Slideous.gotoslide(Slideous.tocidx(), true, true);},
36 homebutton: function(){Slideous.gotoslide(1, true, true);},
37 prevslidebutton: function(){Slideous.previous(false);},
38 previtembutton: function(){Slideous.previous(true);},
39 nextitembutton: function(){Slideous.next(true);},
40 nextslidebutton: function(){Slideous.next(false);},
41 endbutton: function(){Slideous.gotoslide(Slideous.count,true,true);} },
42 fontsize: 125, // in percent, corresponding to body.font-size in css file
43 fontdelta: 5, // increase/decrease fontsize by this value
44 mousesensitive: true,
45 tocidx: 0,
46 tocitems: { toc: "<li><a href=\"#s{\$slideidx}\">{\$slidetitle}</a></li>",
47 tocbox: "<option value=\"#s{\$slideidx}\" title=\"{\$slidetitle}\">{\$slidetitle}</option>" },
48 keydown: function(evt) {
49 evt = evt || window.event;
50 var key = evt.keyCode || evt.which;
51 if (key && !evt.ctrlKey && !evt.altKey) {
52 switch (key) {
53 case 33: // page up ... previous slide
54 Slideous.previous(false); evt.cancel = !Slideous.showall; break;
55 case 37: // left arrow ... previous item
56 Slideous.previous(true); evt.cancel = !Slideous.showall; break;
57 case 32: // space bar
58 case 39: // right arrow
59 Slideous.next(true); evt.cancel = !Slideous.showall; break;
60 case 13: // carriage return ... next slide
61 case 34: // page down
62 Slideous.next(false); evt.cancel = !Slideous.showall; break;
63 case 35: // end ... last slide (not recognised by opera)
64 Slideous.gotoslide(Slideous.count, true, true); evt.cancel = !Slideous.showall; break;
65 case 36: // home ... first slide (not recognised by opera)
66 Slideous.gotoslide(1, true, true); evt.cancel = !Slideous.showall; break;
67 case 65: // A ... show All
68 case 80: // P ... Print mode
69 Slideous.toggleshowall(!Slideous.showall); evt.cancel = true; break;
70 case 67: // C ... goto contents
71 Slideous.gotoslide(Slideous.tocidx, true, true); evt.cancel = true; break;
72 case 77: // M ... toggle mouse sensitivity
73 Slideous.mousenavigation(Slideous.mousesensitive = !Slideous.mousesensitive); evt.cancel = true; break;
74 case 83: // S ... toggle statusbar
75 Slideous.togglestatusbar(); evt.cancel = true; break;
76 case 61: // + ... increase fontsize
77 case 107:
78 Slideous.changefontsize(+Slideous.fontdelta); evt.cancel = true; break;
79 case 109: // - ... decrease fontsize
80 Slideous.changefontsize(-Slideous.fontdelta); evt.cancel = true; break;
81 default: break;
82 }
83 if (evt.cancel) evt.returnValue = false;
84 }
85 return !evt.cancel;
86 },
88 // == program logic ===
89 count: 0, // # of slides ..
90 curidx: 0, // current slide index ..
91 mousedownpos: null, // last mouse down position ..
92 contentselected: false, // indicates content selection ..
93 showall: true,
94 init: function() {
95 Slideous.curidx = 1;
96 Slideous.importproperties();
97 Slideous.registerslides();
98 document.body.innerHTML = Slideous.injectproperties(document.body.innerHTML);
99 Slideous.buildtocs();
100 Slideous.registeranchors();
101 Slideous.toggleshowall(false);
102 Slideous.updatestatus();
103 document.body.style.fontSize = Slideous.fontsize+"%";
104 document.getElementById("s1").style.display = "block";
105 document.onkeydown = Slideous.keydown;
106 Slideous.mousenavigation(Slideous.mousesensitive);
107 Slideous.registerbuttons();
108 if (window.location.hash)
109 Slideous.gotoslide(window.location.hash.substr(2), true, true);
110 },
111 registerslides: function() {
112 var div = document.getElementsByTagName("div");
113 Slideous.count = 0;
114 for (var i in div)
115 if (Slideous.hasclass(div[i], "slide"))
116 div[i].setAttribute("id", "s"+(++Slideous.count));
117 },
118 registeranchors: function() {
119 var a = document.getElementsByTagName("a"),
120 loc = (window.location.hostname+window.location.pathname).replace(/\\/g, "/");
121 for (var i in a) {
122 if (a[i].href && a[i].href.indexOf(loc) >= 0 && a[i].href.lastIndexOf("#") >= 0) {
123 a[i].href = "javascript:Slideous.gotoslide(" + a[i].href.substr(a[i].href.lastIndexOf("#")+2)+",true,true)";
124 }
125 }
126 },
127 registerbuttons: function() {
128 var button;
129 for (var b in Slideous.navbuttons)
130 if (button = document.getElementById(b))
131 button.onclick = Slideous.navbuttons[b];
132 },
133 importproperties: function() { // from html meta section ..
134 var meta = document.getElementsByTagName("meta"), elem;
135 for (var i in meta)
136 if (meta[i].attributes && meta[i].attributes["name"] && meta[i].attributes["name"].value in Slideous)
137 switch (typeof(Slideous[meta[i].attributes["name"].value])) {
138 case "number": Slideous[meta[i].attributes["name"].value] = parseInt(meta[i].attributes["content"].value); break;
139 case "boolean": Slideous[meta[i].attributes["name"].value] = meta[i].attributes["content"].value == "true" ? true : false; break;
140 default: Slideous[meta[i].attributes["name"].value] = meta[i].attributes["content"].value; break;
141 }
142 },
143 injectproperties: function(str) {
144 var meta = document.getElementsByTagName("meta"), elem;
145 for (var i in meta) {
146 if (meta[i].attributes && meta[i].attributes["name"])
147 str = str.replace(new RegExp("{\\$"+meta[i].attributes["name"].value+"}","g"), meta[i].attributes["content"].value);
148 }
149 return str = str.replace(/{\$generator}/g, "Slideous")
150 .replace(/{\$version}/g, Slideous.version)
151 .replace(/{\$title}/g, document.title)
152 .replace(/{\$slidecount}/g, Slideous.count);
153 },
154 buildtocs: function() {
155 var toc = document.getElementById("toc"), list = "",
156 tocbox = document.getElementById("tocbox");
157 if (toc) {
158 for (var i=0; i<Slideous.count; i++)
159 list += Slideous.tocitems.toc.replace(/{\$slideidx}/g, i+1).replace(/{\$slidetitle}/, document.getElementById("s"+(i+1)).getElementsByTagName("h1")[0].innerHTML);
160 toc.innerHTML = list;
161 while (toc && !Slideous.hasclass(toc, "slide")) toc = toc.parentNode;
162 if (toc) Slideous.tocidx = toc.getAttribute("id").substr(1);
163 }
164 if (tocbox) {
165 tocbox.innerHTML = "";
166 for (var i=0; i<Slideous.count; i++)
167 tocbox.options[tocbox.length] = new Option((i+1)+". "+document.getElementById("s"+(i+1)).getElementsByTagName("h1")[0].innerHTML, "#s"+(i+1));
168 tocbox.onchange = function() { Slideous.gotoslide(this.selectedIndex+1, true, true); };
169 }
170 },
171 next: function(deep) {
172 if (!Slideous.showall) {
173 var slide = document.getElementById("s"+Slideous.curidx),
174 item = Slideous.firstitem(slide, Slideous.isitemhidden);
175 if (deep) { // next item
176 if (item)
177 Slideous.displayitem(item, true);
178 else
179 Slideous.gotoslide(Slideous.curidx+1, false, false);
180 }
181 else if (item) // complete slide ..
182 while (item = Slideous.firstitem(slide, Slideous.isitemhidden))
183 Slideous.displayitem(item, true);
184 else // next slide
185 Slideous.gotoslide(Slideous.curidx+1, true, false);
186 Slideous.updatestatus();
187 }
188 },
189 previous: function(deep) {
190 if (!Slideous.showall) {
191 var slide = document.getElementById("s"+Slideous.curidx);
192 if (deep) {
193 var item = Slideous.lastitem(slide, Slideous.isitemvisible);
194 if (item)
195 Slideous.displayitem(item, false);
196 else
197 Slideous.gotoslide(Slideous.curidx-1, true, false);
198 }
199 else
200 Slideous.gotoslide(Slideous.curidx-1, true, false);
201 Slideous.updatestatus();
202 }
203 },
204 gotoslide: function(i, showitems, updatestatus) {
205 if (!Slideous.showall && i > 0 && i <= Slideous.count && i != Slideous.curidx) {
206 document.getElementById("s"+Slideous.curidx).style.display = "none";
207 var slide = document.getElementById("s"+(Slideous.curidx=i)), item;
208 while (item = Slideous.firstitem(slide, showitems ? Slideous.isitemhidden : Slideous.isitemvisible))
209 Slideous.displayitem(item, showitems);
210 slide.style.display = "block";
211 if (updatestatus)
212 Slideous.updatestatus();
213 }
214 },
215 firstitem: function(root, filter) {
216 var found = filter(root);
217 for (var node=root.firstChild; node!=null && !found; node = node.nextSibling)
218 found = Slideous.firstitem(node, filter);
219 return found;
220 },
221 lastitem: function(root, filter) {
222 var found = null;
223 for (var node=root.lastChild; node!=null && !found; node = node.previousSibling)
224 found = Slideous.lastitem(node, filter);
225 return found || filter(root);
226 },
227 isitem: function(node, visible) {
228 var nodename;
229 return node && node.nodeType == 1 // elements only ..
230 && (nodename=node.nodeName.toLowerCase()) in Slideous.incrementables
231 && ( Slideous.incrementables[nodename].filter.match("\\bself\\b") && (Slideous.hasclass(node, "incremental") || (Slideous.autoincrement && nodename in Slideous.autoincrementables))
232 || Slideous.incrementables[nodename].filter.match("\\bparent\\b") && (Slideous.hasclass(node.parentNode, "incremental") || (Slideous.autoincrement && node.parentNode.nodeName.toLowerCase() in Slideous.autoincrementables))
233 || Slideous.incrementables[nodename].filter.match("\\bgrandparent\\b") && (Slideous.hasclass(node.parentNode.parentNode, "incremental") || (Slideous.autoincrement && node.parentNode.parentNode.nodeName.toLowerCase() in Slideous.autoincrementables))
234 )
235 && (visible ? (node.style.visibility != "hidden")
236 : (node.style.visibility == "hidden"))
237 ? node : null;
238 },
239 isitemvisible: function(node) { return Slideous.isitem(node, true); },
240 isitemhidden: function(node) { return Slideous.isitem(node, false); },
241 displayitem: function(item, show) {
242 if (item) item.style.visibility = (show ? "visible" : "hidden");
243 },
244 updatestatus: function() {
245 if (Slideous.statusbar) {
246 var eos = document.getElementById("eos"),
247 idx = document.getElementById("slideidx"),
248 tocbox = document.getElementById("tocbox");
249 if (eos)
250 eos.style.visibility = Slideous.firstitem(document.getElementById("s"+Slideous.curidx), Slideous.isitemhidden) != null
251 ? "visible" : "hidden";
252 if (idx)
253 idx.innerHTML = Slideous.curidx;
254 if (tocbox)
255 tocbox.selectedIndex = Slideous.curidx-1;
256 }
257 },
258 changefontsize: function(delta) {
259 document.body.style.fontSize = (Slideous.fontsize+=delta)+"%";
260 },
261 togglestatusbar: function() {
262 document.getElementById("statusbar").style.display = (Slideous.statusbar = !Slideous.statusbar) ? "block" : "none";
263 },
264 toggleshowall: function(showall) {
265 var slide, item;
266 for (var i=0; i<Slideous.count; i++) {
267 slide = document.getElementById("s"+(i+1));
268 slide.style.display = showall ? "block" : "none";
269 while (item = Slideous.firstitem(slide, showall ? Slideous.isitemhidden : Slideous.isitemvisible))
270 Slideous.displayitem(item, showall);
271 var divs = slide.getElementsByTagName("div");
272 for (var j in divs)
273 if (Slideous.hasclass(divs[j], "handout"))
274 divs[j].style.display = showall ? "block" : "none";
275 }
276 if (!showall)
277 document.getElementById("s"+Slideous.curidx).style.display = "block";
278 if (Slideous.statusbar)
279 document.getElementById("statusbar").style.display = showall ? "none" : "block";
280 Slideous.showall = showall;
281 },
282 hasclass: function(elem, classname) {
283 var classattr = null;
284 return (classattr=(elem.attributes && elem.attributes["class"]))
285 && classattr.nodeValue.match("\\b"+classname+"\\b");
286 },
287 selectedcontent: function() {
288 return window.getSelection ? window.getSelection().toString()
289 : document.getSelection ? document.getSelection()
290 : document.selection ? document.selection.createRange().text
291 : "";
292 },
293 mousenavigation: function(on) {
294 if (on) {
295 document.onmousedown = Slideous.mousedown;
296 document.onmouseup = Slideous.mouseup;
297 }
298 else
299 document.onmousedown = document.onmouseup = null;
300 },
301 mousepos: function(e) {
302 return e.pageX ? {x: e.pageX, y: e.pageY}
303 : {x: e.x+document.body.scrollLeft, y: e.y+document.body.scrollTop};
304 },
305 mousedown: function(evt) {
306 evt = evt||window.event;
307 Slideous.mousedownpos = Slideous.mousepos(evt);
308 Slideous.contentselected = !!Slideous.selectedcontent() || ((evt.target || evt.srcElement).nodeName.toLowerCase() in Slideous.clickables);
309 return true;
310 },
311 mouseup: function(evt) {
312 evt = evt||window.event;
313 var pos = Slideous.mousepos(evt);
314 if (pos.x == Slideous.mousedownpos.x && pos.y == Slideous.mousedownpos.y && !Slideous.contentselected) {
315 Slideous.next(true);
316 return evt.returnValue = !(evt.cancel = true);
317 }
318 return false;
319 }
320};
321window.onload = Slideous.init;