cd19624cf316dee042f6d07275414fc69b945aa1
[hacks/simpleWebSlides.git] / simpleWebSlides.js
1 /*
2   Namespace object.
3 */
4
5 var SWS = SWS || {};
6
7
8
9 SWS.Utils = new function () {
10     var self = this;
11
12     self.isUndefined = function (o) { return typeof o == "undefined"; };
13     self.push2 = function (t, i, v) {
14         if ((typeof t[i]) == 'undefined') {
15             t[i] = new Array();
16         };
17         var l = t[i].length;
18         t[i][l] = v;
19     };
20
21     self.isEmpty = function (o) {
22         for(var _ in o) return false;
23         return true;
24     };
25
26     self.parseFrameSpec = function (s) {
27         var elems = s.split("_");
28         var result = {};
29         var min_last = 10000;
30         var max_value = -1;
31         for(var i = 0; i < elems.length; i++){
32             var bounds = elems[i].split("-");
33             if (bounds.length > 2 || bounds.length == 0) return {};
34             if (bounds.length == 1) bounds[1] = bounds[0];
35             var a = parseInt(bounds[0]);
36             var b = parseInt(bounds[1])
37             if (!isFinite(a) || !isFinite(b)) return {};
38             a = Math.min(a, 1000); // don't allow more than 1000 frames/slide
39             b = Math.min(b, 1000);
40             if (b > max_value) max_value = b;
41             for (var j = a; j <= b; j++)
42                 result[j] = true;
43         };
44         return result;
45     };
46
47     self.getParameterByName = function (name) {
48         name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
49         var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
50         results = regex.exec(location.search);
51         return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
52     }
53 };
54
55
56
57
58 SWS.Templates = new function () {
59     var self = this;
60     self.controlPanel = "<div id='sws-control-panel-canvas'><div id='sws-control-panel'>\
61 <div id='sws-control-panel-title-bar'>\
62 <a title='Toggle fullscreen' id='sws-control-panel-fullscreen' class='sws-symbol' onclick='SWS.Presentation.toggleFullScreen();'></a>\
63 <a title='Close panel' id='sws-control-panel-close' onclick='$(\"#sws-control-panel-canvas\").toggle();'>&#x2716;</a>\
64 </div>\
65 <div id='sws-control-panel-options'>\
66 <span title='Change the aspect ratio' class='sws-symbol' >&#x1f4bb;</span><select id='sws-aspect-select' onchange='SWS.Presentation.changeAspect();'>\
67 <option value='sws-aspect-4-3'>4:3</option>\
68 <option value='sws-aspect-16-9'>16:9</option>\
69 <option value='sws-aspect-16-10'>16:10</option>\
70 </select>\
71 <span title='Change the theme' class='sws-symbol'>&#x1f3a8;</span><select id='sws-theme-select' onchange='SWS.Presentation.changeTheme();'></select>\
72 <a onclick='SWS.Presentation.openPrint()' ><span title='Open Print-Out' class='sws-symbol'>&#59158;</span></a>\
73 </div>\
74 <div id='sws-control-panel-navigation'>\
75 <a title='First slide' class='sws-symbol' onclick='SWS.Presentation.goToSlide(SWS.Presentation.firstSlide());' >&#x23ee;</a>\
76 <a title='Previous slide' class='sws-symbol' onclick='SWS.Presentation.previousSlide();SWS.Presentation.refresh();'>&#x23ea;</a>\
77 <a title='Previous step' class='sws-symbol' style='-webkit-transform: scaleX(-1);' onclick='SWS.Presentation.previous();SWS.Presentation.refresh();'>&#x25b6;</a>\
78 <a title='Next step' class='sws-symbol' onclick='SWS.Presentation.next();SWS.Presentation.refresh();'>&#x25b6;</a>\
79 <a title='Next slide' class='sws-symbol' onclick='SWS.Presentation.nextSlide();SWS.Presentation.refresh();'>&#x23e9;</a>\
80 <a title='Last slide' class='sws-symbol' onclick='SWS.Presentation.goToSlide(SWS.Presentation.lastSlide());'>&#x23ed;</a>\
81 <br/>\
82 <span class='sws-symbol'>&#xe4ae;</span><input type='text' id='sws-control-panel-slide-input' oninput='SWS.Presentation.goToSlide($(\"#sws-control-panel-slide-input\").val()-1);'></input><span id='sws-control-panel-total-slides'></span>\
83 <input type='range' title='Navigate the presentation' id='sws-control-panel-navigation-bar' onchange='SWS.Presentation.navigate();' step='1'></input>\
84 </div>\
85 </div>\
86 </div>";
87     self.slideActivate = function (o) {
88         if (!(o.hasClass("sws-active-slide"))){
89             o.removeClass("sws-inactive-slide").addClass("sws-active-slide");
90         };
91     };
92
93     self.slideDeactivate = function (o) {
94         if (!(o.hasClass("sws-inactive-slide"))){
95             o.removeClass("sws-active-slide").addClass("sws-inactive-slide");
96         };
97     };
98
99     self.slideChange = function (from, to) {
100         var canvas = $(".sws-canvas");
101         self.slideDeactivate($(canvas[from]));
102         self.slideActivate($(canvas[to]));
103     };
104
105     self.objectActivate = function (o) {
106         if (!(o.hasClass("sws-active-object"))){
107             o.removeClass("sws-inactive-object").addClass("sws-active-object");
108             return true;
109         };
110         return false;
111     };
112
113     self.objectDeactivate = function (o) {
114         if (!(o.hasClass("sws-inactive-object"))){
115             o.addClass("sws-inactive-object").removeClass("sws-active-object");
116             return true;
117         };
118         return false;
119     };
120
121     self.updateFooter = function (o) {
122         var footer = o.find(".sws-footer");
123         if (footer.length && (footer.children("*").length == 0)) {
124             var i = SWS.Presentation.getCurrentSlide();
125             var cur = $( "<span class='sws-current-slide-number'>"
126                          + (i + 1)
127                          +"</span>");
128             var sep = $( "<span class='sws-slide-num-sep' />");
129             var tot = $( "<span class='sws-last-slide-number'>"
130                          + (SWS.Presentation.getNumSlides())
131                          +"</span>");
132             footer.append(cur).append(sep).append(tot);
133         };
134     };
135     self.updateHeader = function (o) {};
136 };
137 SWS.ConfigBuilder = function () {
138     var self = this;
139     self['sws-object-activate'] = SWS.Templates.objectActivate;
140     self['sws-object-deactivate'] = SWS.Templates.objectDeactivate;
141     self['sws-slide-change'] = SWS.Templates.slideChange;
142     self['sws-update-footer'] = SWS.Templates.updateFooter;
143     self['sws-update-header'] = SWS.Templates.updateHeader;
144 };
145
146 SWS.Defaults = new SWS.ConfigBuilder ();
147
148 SWS.Config = new SWS.ConfigBuilder ();
149
150
151 SWS.Effects = new function () {
152     var self = this;
153
154     self.objectDeactivateFadeOut = function (o) {
155         o.animate({'opacity': '0'}, 200,
156                   function () {
157
158                       SWS.Templates.objectDeactivate(o);
159                   });
160     };
161
162     self.objectActivateFadeIn = function (o) {
163
164         if (SWS.Templates.objectActivate(o)){
165             o.animate({'opacity': '1' }, 200);
166         };
167
168     };
169
170     self.slideChangeHorizontalFlip = function (from, to){
171         var f = SWS.Presentation.getSlide(from);
172         var t = SWS.Presentation.getSlide(to);
173         f.animate({ 'left': '50%', 'width': '0pt', 'opacity':'0' }, 150,
174                   function  () {
175                       SWS.Templates.slideDeactivate(f);
176                       f.css({'left':'0%', 'width': '100%'});
177                       t.css({ 'left': '50%', 'width': '0pt','opacity':'0' });
178                       SWS.Templates.slideActivate(t);
179                       t.animate({'left':'0%', 'width': '100%','opacity':'1'});
180                   });
181     };
182     self.slideChangeFadeOutIn = function (from, to) {
183         var f = SWS.Presentation.getSlide(from);
184         var t = SWS.Presentation.getSlide(to);
185         f.animate({ 'opacity': '0'}, 150,
186                   function () { SWS.Templates.slideDeactivate(f);
187                                 SWS.Templates.slideActivate(t);
188                                 t.css('opacity', '0');
189                                 t.animate({ 'opacity': '1'}, 150);
190                               });
191     };
192     self.slideChangeHorizontalSlide = function (from, to) {
193         var f = SWS.Presentation.getSlide(from);
194         var t = SWS.Presentation.getSlide(to);
195         if (from < to) {
196             t.css('left', '100%');
197             t.css('opacity', '1');
198             SWS.Templates.slideActivate(t);
199             f.animate({ 'left': '-100%' }, 250, function () { SWS.Templates.slideDeactivate(f);
200                                                               f.css('opacity', '0');
201                                                               t.animate({ 'left': '0%' }, 250);
202                                                             });
203         } else {
204             t.css('left', '-100%');
205             SWS.Templates.slideActivate(t);
206             f.animate({ 'left': '100%' }, 250, function () { SWS.Templates.slideDeactivate(f);
207                                                              f.css('opacity', '0');
208                                                            });
209             t.css('opacity', '1');
210             t.animate({ 'left': '0%' }, 250);
211         };
212     };
213
214
215     self.slideChangeVerticalSlide = function (from, to) {
216         var f = SWS.Presentation.getSlide(from);
217         var t = SWS.Presentation.getSlide(to);
218         if (from < to) {
219             t.css('top', '100%');
220             SWS.Templates.slideActivate(t);
221             f.animate({ 'top': '-100%' }, 250, function () { SWS.Templates.slideDeactivate(f); });
222             t.animate({ 'top': '0%' }, 250);
223         } else {
224             t.css('top', '-100%');
225             SWS.Templates.slideActivate(t);
226             f.animate({ 'top': '100%' }, 250, function () { SWS.Templates.slideDeactivate(f); });
227             t.animate({ 'top': '0%' }, 250);
228         };
229     };
230
231 };
232
233 SWS.Fullscreen = new function () {
234     var self = this;
235
236     if (SWS.Utils.isUndefined(document.fullScreen)) {
237         if (SWS.Utils.isUndefined(document.mozfullScreen)) {
238             self.status = function () { return document.webkitIsFullScreen; };
239             self.enter = function(e) {
240                 e.webkitRequestFullScreen();
241             };
242             self.exit = function () {
243                 document.webkitCancelFullScreen();
244             };
245
246         } else {
247             self.status = function () { return document.mozfullScreen; };
248             self.enter = function(e) {
249                 e.mozRequestFullScreen();
250             };
251             self.exit = function () {
252                 document.mozCancelFullScreen();
253             };
254
255         };
256     } else {
257             self.status = function () { return document.fullScreen; };
258             self.enter = function(e) {
259                 e.requestFullScreen();
260             };
261             self.exit = function () {
262                 document.cancelFullScreen();
263             };
264
265     };
266
267
268 };
269
270 SWS.Presentation = new function () {
271
272
273     var self = this;
274
275     //TODO move outside of the Presentation object
276
277
278     var _total_slides;
279     var _initialized = false;
280     var _disable_input_events = false;
281     var _print_mode = false;
282     var _slide_callbacks = new Array ();
283     var _total_steps = -1;
284     var _current_theme = "";
285
286     self.getNumSlides = function () { return _total_slides; };
287
288     self.getSlide = function(i) {
289         return $($(".sws-canvas")[i]);
290     };
291
292     self.registerCallback = function (i, f) {
293         if (_initialized) return;
294         //jQuery does not seem to work well
295         //on a partial DOM
296
297         var slide_num = $(".sws-slide").length - 1;
298
299         SWS.Utils.push2(_slide_callbacks, slide_num,{ 'fn': f, 'frame': i });
300
301     };
302
303     if (typeof(Storage)!=="undefined"){
304         self.getCurrentSlide = function () {
305             //unary + casts to integer
306             var i = +(sessionStorage.getItem("current_slide"));
307             if (!(i >= 0 && i < self.getNumSlides())){
308                 return 0;
309             } else {
310                 return i;
311             };
312         };
313
314         self.setCurrentSlide = function (i) {
315             sessionStorage.setItem("current_slide", i);
316         };
317
318     } else {
319         var _current_slide = 0;
320         self.getCurrentSlide = function () { return _current_slide; };
321         self.setCurrentSlide = function (i) { _current_slide = i; };
322
323     };
324     self.firstSlide = function () { return 0; };
325     self.lastSlide = function () { return self.getNumSlides() - 1; };
326     self.refresh = function () {
327         /* block upcoming input event until all animations are finished */
328         _disable_input_events = true;
329
330         var canvas = $(".sws-canvas");
331         var from_slide_num = canvas.index($(".sws-active-slide"));
332         var to_slide_num = self.getCurrentSlide();
333         var watch_slide_anim = false;
334         var to_slide = $(canvas[to_slide_num]);
335         var from_slide = $(canvas[from_slide_num]);
336         var slide_change = (from_slide_num != to_slide_num);
337
338
339         var info = to_slide.data("sws-frame-info");
340         SWS.Config['sws-update-header'](to_slide);
341         SWS.Config['sws-update-footer'](to_slide);
342
343         if (slide_change) {
344             //Launch a slide transition:
345             SWS.Config['sws-slide-change'](from_slide_num, to_slide_num);
346             watch_slide_anim = true;
347             for (var i = 0; i < info.callbacks.at_slide.length;i++){
348                 info.callbacks.at_slide[i](to_slide);
349             };
350         };
351
352
353         var cur = info.current;
354         var custom = info.custom;
355         var real_slide = to_slide.find(".sws-slide");
356
357         real_slide.find("*").andSelf().each(function (i){
358             var frameset = $(this).data("sws-frame-set") || {};
359             if (frameset[cur])
360                 SWS.Config['sws-object-activate']($(this));
361             else
362                 SWS.Config['sws-object-deactivate']($(this));
363         });
364         var callbacks;
365         if (callbacks = info.callbacks.at_frame[self.getCurrentFrame()]){
366             for (var k = 0; k < callbacks.length; k++)
367                 callbacks[k]($(to_slide));
368         };
369
370         var all = $(from_slide).add(to_slide);
371         all.find("*").addBack().promise().done(function() {
372             _disable_input_events = false;
373         });
374     };
375
376     self.nextSlide = function () {
377         self.setCurrentSlide(Math.min(self.getCurrentSlide()+1,
378                                       self.lastSlide()));
379         self.setCurrentFrame(self.firstFrame());
380     };
381
382     self.previousSlide = function () {
383         self.setCurrentSlide(Math.max(self.getCurrentSlide()-1,
384                                       self.firstSlide()));
385         self.setCurrentFrame(self.firstFrame());
386     };
387
388     self.getFrameInfo = function () {
389
390         var i = self.getCurrentSlide();
391         var canvas = $($(".sws-canvas")[i]);
392         var infos = canvas.data("sws-frame-info");
393         return infos;
394     };
395
396     self.getTotalSteps = function () {
397         if (_total_steps >= 0) return _total_steps;
398         _total_steps = 0;
399         $(".sws-canvas").each(function(i) {
400             var canvas = $($(".sws-canvas")[i]);
401             var infos = canvas.data("sws-frame-info");
402             _total_steps += infos.last + 1;
403         });
404         return _total_steps;
405     };
406
407     self.getCurrentFrame = function () { return self.getFrameInfo().current; };
408     self.setCurrentFrame = function (i) { self.getFrameInfo().current = i; };
409     self.firstFrame = function () { return 0; };
410     self.lastFrame = function () { return self.getFrameInfo().last; };
411
412     self.nextFrame = function () {
413         self.setCurrentFrame(Math.min(self.getCurrentFrame()+1,
414                                       self.lastFrame()));
415
416     };
417     self.previousFrame = function () {
418         self.setCurrentFrame(Math.max(self.getCurrentFrame()-1,
419                                        self.firstFrame()));
420     };
421
422     self.next = function () {
423         var i = self.getCurrentFrame();
424         if (i == self.lastFrame()) {
425             self.nextSlide();
426             self.setCurrentFrame(self.firstFrame());
427         } else
428             self.nextFrame();
429     };
430
431     self.previous = function () {
432         var i = self.getCurrentFrame();
433         if (i == self.firstFrame()){
434             self.previousSlide();
435             self.setCurrentFrame(self.lastFrame());
436         }
437         else
438             self.previousFrame();
439     };
440
441     self.goToSlide = function (s, f) {
442         if (SWS.Utils.isUndefined(f))
443             f = 0;
444         if (!(s >= self.firstSlide() && s <= self.lastSlide())) return;
445         self.setCurrentSlide(s);
446         if (!(f >= self.firstFrame() && f <= self.lastFrame())) f = 0;
447         self.setCurrentFrame(f);
448         self.refresh();
449     };
450
451     self.cycleStyle = function() {
452         var styles = $("head").children('link[rel$="stylesheet"][title]');
453         var j = styles.index(styles.filter(':not(:disabled)'));
454         styles[j].disabled = true;
455         if (++j == styles.length) j = 0;
456         styles[j].disabled = false;
457     };
458
459
460     self.printMode = function () {
461         _print_mode = true;
462         var progress = $("<div style='position:fixed;top:0pt;left:0pt;background:white;color:black;width:100%;height:100vh;z-index:200;' id='sws-print-progress'>Rendering presentation: <span id='sws-percent-progress'></span>%</div>");
463         $("body").append(progress);
464
465         $("html").removeClass("sws-display").addClass("sws-print");
466         self.goToSlide(0,0);
467         var steps = self.getTotalSteps();
468         var total_steps = steps;
469         var loop;
470         loop = function () {
471             if (steps >= 0) {
472                 //Crazy workaround for chromium
473                 ($("link.sws-theme[rel='stylesheet']")[0]).disabled = false;
474                 $(".sws-canvas").find("*").addBack().promise().done(function() {
475                     var percent = ((total_steps - steps) / total_steps) * 100;
476                     $("#sws-percent-progress").text(Math.round(percent));
477                     SWS.Config['sws-slide-change'] = SWS.Templates.slideChange;
478                     self.refresh();
479                     $($(".sws-canvas")[self.getCurrentSlide()]).css('opacity', 1 );
480                     self.next();
481                     steps--;
482                     loop();
483                     })
484             } else {
485                 $("#sws-percent-progress").text(100);
486                 progress.remove();
487             }
488         };
489         loop();
490
491     }
492
493
494     var _xstart = 0;
495     self.inputHandler = function (event) {
496         if (_disable_input_events || _print_mode) return;
497         var code = 0;
498         switch (event.type) {
499         case 'touchstart':
500             _xstart = event.changedTouches[0].clientX;
501             return;
502         case 'touchend':
503
504             var dist = event.changedTouches[0].clientX - _xstart;
505             if (dist > 20) code = 37
506             else if (dist < -20) code = 39
507             else if (!$("#sws-control-panel-canvas").is(":visible")) code = 67;
508             break;
509         case 'keydown':
510             code = event.which;
511             break;
512         default:
513             return;
514         };
515         switch (code) {
516         case 36:/* Home */
517             self.setCurrentSlide(self.firstSlide());
518             break;
519
520         case 35:/* End */
521             self.setCurrentSlide(self.lastSlide());
522             break;
523         case 32: /* space */
524         case 34: /* PgDown */
525         case 39: /* -> */
526             if (self.getCurrentSlide() == self.lastSlide()
527                 && self.getCurrentFrame() == self.lastFrame()) return;
528             self.next();
529             break;
530         case 78: /* n */
531             self.nextSlide();
532             break;
533         case 8: /* backspace */
534         case 33: /* PgUp */
535         case 37: /* <-   */
536             self.previous();
537             break;
538         case 80: /* p */
539             self.previousSlide();
540             break;
541         case 83: /* s */
542                 self.cycleStyle();
543             return;
544         case 67: /* c */
545             $("#sws-control-panel-canvas").toggle();
546
547         default:
548             return;
549         };
550         self.refresh();
551 };
552
553
554
555     function init_canvas(canvas, custom) {
556         var cur_frame = 0;
557         var last_frame = canvas.find(".sws-pause").length;
558         //Add all regular elements to the frame list
559         var slide = $(canvas.find(".sws-slide")[0]);
560
561         var callbacks = { at_slide : new Array(),
562                           at_frame : new Array() }
563
564         if (SWS.Utils.isUndefined(custom)) {
565             custom = new Array ();
566         };
567
568         for (var i = 0; i < custom.length; i++) {
569             if (isFinite(custom[i].frame)){
570                 var num = +(custom[i].frame);
571                 if (num > last_frame) last_frame = num;
572                 SWS.Utils.push2(callbacks.at_frame, num, custom[i].fn);
573             } else if (custom[i].frame == "slide")
574                 callbacks.at_slide.push(custom[i].fn);
575             else {
576                 var frame_set = SWS.Utils.parseFrameSpec(custom[i].frame);
577                 for(var f in frame_set){
578                     if (f > last_frame) last_frame = f;
579                     SWS.Utils.push2(callbacks.at_frame, +(f), custom[i].fn);
580                 };
581             }
582         };
583
584         var specials = $([]);
585
586         slide.find('*[class*="sws-onframe-"]').each(function(_){
587             var cls = $(this).attr('class');
588             var idx = cls.indexOf("sws-onframe-");
589             if (idx >= 0) {
590                 var end = cls.indexOf(" ", idx);
591                 end = (end == -1) ? cls.length : end;
592                 var spec = cls.substring(idx+12, end);
593                 var o = SWS.Utils.parseFrameSpec(spec);
594                 for(var f in o)
595                     if (f > last_frame) last_frame = f;
596                 $(this).find("*").andSelf().each(function(_){
597                     if (!SWS.Utils.isEmpty(o)){
598                         $(this).data("sws-frame-set", o);
599                     }
600                     specials = specials.add($(this));
601                 });
602             };
603         });
604
605         slide.find("*").andSelf().not(specials).each(function(i) {
606             if ($(this).hasClass("sws-pause"))  cur_frame++;
607             var o = {};
608             for (var j = cur_frame; j <= last_frame; j++)
609                 o[ j ] = true;
610             if (!SWS.Utils.isEmpty(o))
611                 $(this).data("sws-frame-set", o);
612         });
613
614         canvas.data("sws-frame-info", { current: 0,
615                                         last: (last_frame - 0), // force cast to integer
616                                         callbacks: callbacks
617                                       });
618
619     };
620
621     /* Forces redrawing the page without reloading */
622     self.redraw = function (f) {
623         if (SWS.Utils.isUndefined(f))
624             $("body").hide().show(400, function () {
625                 $("body").css("display","block");
626                 if (!SWS.Utils.isUndefined(f))
627                     f();
628             });
629     };
630     self.changeAspect = function() {
631         $("html").removeClass("sws-aspect-4-3")
632             .removeClass("sws-aspect-16-9")
633             .removeClass("sws-aspect-16-10")
634             .addClass($("#sws-aspect-select").val());
635         self.redraw();
636     };
637
638     self.getCurrentTheme = function () {
639         var l = $("link.sws-theme[rel='stylesheet']")[0];
640
641         if (l) {
642             return  l.title;
643         } else
644             return ""
645     };
646
647     self.changeTheme = function (name) {
648         var theme_name;
649         if (typeof name === 'undefined')
650             theme_name = $("#sws-theme-select").val()
651         else
652             theme_name = name;
653
654         _current_theme = theme_name;
655         $("link.sws-theme").each (function (i) {
656             var e = this;
657             var title =  e.title;
658             if (title == theme_name) {
659                 e.rel = "stylesheet";
660                 e.disabled = false;
661                 e.media="all";
662             } else {
663                 e.rel = "alternate stylesheet";
664                 e.disabled = true;
665                 e.media="all";
666             };
667         });
668         self.redraw();
669
670     };
671
672     self.openPrint = function () {
673         window.open ("?mode=print&theme=" + self.getCurrentTheme());
674     }
675     var _fullscreen_icon_on = "&#xe746;";
676     var _fullscreen_icon_off = "&#xe744;";
677
678     self.toggleFullScreen = function () {
679         if (SWS.Fullscreen.status()) {
680             SWS.Fullscreen.exit();
681             $("a#sws-control-panel-fullscreen")
682                 .html(_fullscreen_icon_off);
683
684
685
686         } else {
687             SWS.Fullscreen.enter($("body")[0]);
688             $("a#sws-control-panel-fullscreen")
689                 .html(_fullscreen_icon_on);
690         };
691     };
692     function _update_ui() {
693         var nav = $('#sws-control-panel-navigation-bar');
694         nav.val(SWS.Presentation.getCurrentSlide() + 1);
695         $('#sws-control-panel-slide-input').val(nav.val());
696     }
697     self.navigate = function () {
698         self.goToSlide($("#sws-control-panel-navigation-bar").val()-1);
699         _update_ui();
700     };
701
702
703     self.init = function () {
704
705
706         $("html").addClass("sws-display");
707         //$(window).resize(self.redraw);
708
709
710
711         _total_slides = $(".sws-slide").length;
712
713         var cur = self.getCurrentSlide();
714
715         $(".sws-slide").each(function (i) {
716
717             var par = $(this).parent();
718
719
720             $(this).remove();
721             var canvas = $('<div class="sws-canvas"/>');
722
723             if (!($(this).hasClass("sws-option-noheader"))) {
724                 canvas.append($('<div class="sws-header"/>'));
725             };
726             if (!$(this).hasClass("sws-cover")) {
727                 var title = $($(this).find("h1")[0]);
728                 var title_div = $('<div class="sws-title" />');
729                 title_div.append(title);
730                 canvas.append(title_div);
731             }
732             var inner = $('<div class="sws-inner-canvas"/>');
733             var content = $('<div class="sws-content"/>');
734             $(this).find('script[type="text/javascript"]').remove();
735             content.append($(this));
736             inner.append(content);
737             canvas.append(inner);
738
739             if (!($(this).hasClass("sws-option-nofooter"))) {
740                 canvas.append($('<div class="sws-footer"/>'));
741             };
742
743             par.append(canvas);
744
745             if (i == cur) {
746                 canvas
747                     .addClass("sws-active-slide")
748                     .removeClass("sws-inactive-slide");
749             } else {
750                 canvas
751                     .addClass("sws-inactive-slide")
752                     .removeClass("sws-active-slide");
753             };
754             init_canvas(canvas,_slide_callbacks[i]);
755
756         });
757
758         // Initialize the control panel
759         $("body").append($(SWS.Templates.controlPanel));
760         // Fill the theme switcher
761         $("link.sws-theme").each (function (i) {
762             var e = $(this);
763             var opt = "<option value='";
764             opt += e.attr("title");
765             opt += "' ";
766             if (e.attr("rel") == "stylesheet") {
767                 opt+= "selected='selected'";
768             };
769             opt += ">" + e.attr("title") + "</option>";
770             $("#sws-theme-select").append($(opt));
771         });
772         // Set the fullscreen icon
773         if (SWS.Fullscreen.status()) {
774             $("a#sws-control-panel-fullscreen")
775                 .html(_fullscreen_icon_on);
776         } else {
777             $("a#sws-control-panel-fullscreen")
778                 .html(_fullscreen_icon_off);
779         };
780         // Put the navigation range at the correct position
781         var nav = $('#sws-control-panel-navigation-bar');
782         nav.attr("min", SWS.Presentation.firstSlide() + 1);
783         nav.attr("max", SWS.Presentation.lastSlide() + 1);
784         $('#sws-control-panel-total-slides').text('/' + SWS.Presentation.getNumSlides());
785         _update_ui();
786
787         _slide_callbacks = null; /* avoid a leak */
788         var passed_theme = SWS.Utils.getParameterByName("theme");
789         //workaround weird chrome CSS loading bug
790         var f =
791             function () {
792                 if (passed_theme == "")
793                     self.changeTheme();
794                 else
795                     self.changeTheme(passed_theme);
796                 if (SWS.Utils.getParameterByName("mode") == "print") {
797                     self.printMode();
798                 }
799                 else
800                     self.refresh();
801                 $(document).keydown(self.inputHandler);
802                 document.body.addEventListener('touchstart',self.inputHandler, false);
803                 document.body.addEventListener('touchend',self.inputHandler, false);
804
805                 _initialized = true;
806             };
807         setTimeout(f, 100);
808     };
809
810 };