Clean-up header and footer handling code.
[hacks/simpleWebSlides.git] / simpleWebSlides.js
1 /*
2   Namespace object.
3 */
4
5 var 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
22     self.slideActivate = function (o) {
23         if (!(o.hasClass("sws-active-slide"))){
24             o.removeClass("sws-inactive-slide").addClass("sws-active-slide");
25         };
26     };
27
28     self.slideDeactivate = function (o) {
29         if (!(o.hasClass("sws-inactive-slide"))){
30             o.removeClass("sws-active-slide").addClass("sws-inactive-slide");
31         };
32     };
33
34     self.slideChange = function (from, to) {
35         var canvas = $(".sws-canvas");
36         self.slideDeactivate($(canvas[from]));
37         self.slideActivate($(canvas[to]));
38     };
39
40     self.objectActivate = function (o) {
41         if (!(o.hasClass("sws-active-object"))){
42             o.removeClass("sws-inactive-object").addClass("sws-active-object");
43             o.css({'visibility':'visible'});
44         };
45     };
46
47     self.objectDeactivate = function (o) {
48         o.css({'visibility':'hidden', 'display':''});
49         if (!(o.hasClass("sws-inactive-object"))){
50             o.addClass("sws-inactive-object").removeClass("sws-active-object");
51         };
52     };
53     self.updateFooter = function (o) {
54         var footer = o.find(".sws-footer");
55         if (footer.length && (footer.children("*").length == 0)) {
56             var i = SWS.Presentation.getCurrentSlide();
57             var cur = $( "<span class='sws-current-slide-number'>"
58                          + (i + 1)
59                          +"</span>");
60             var sep = $( "<span class='sws-slide-num-sep' />");
61             var tot = $( "<span class='sws-current-slide-number'>"
62                          + (SWS.Presentation.getNumSlides())
63                          +"</span>");
64             footer.append(cur).append(sep).append(tot);
65         };
66     };
67     self.updateHeader = function (o) {};
68 };
69
70
71 SWS.Effects = new function () {
72     var self = this;
73     self.objectDeactivateFadeOut = function (o) {
74         o.fadeOut(150, function () { SWS.Utils.objectDeactivate(o)});
75     };
76
77     self.objectActivateFadeIn = function (o) {
78         SWS.Utils.objectActivate(o);
79         o.fadeIn(150);
80     };
81
82     self.slideChangeHorizontalSlide = function (from, to) {
83         var f = SWS.Presentation.getSlide(from);
84         var t = SWS.Presentation.getSlide(to);
85         if (from < to) {
86             t.css('left', '100%');
87             SWS.Utils.slideActivate(t);
88             f.animate({ 'left': '-100%' }, 250, function () { SWS.Utils.slideDeactivate(f); });
89             t.animate({ 'left': '0%' }, 250);
90         } else {
91             t.css('left', '-100%');
92             SWS.Utils.slideActivate(t);
93             f.animate({ 'left': '100%' }, 250, function () { SWS.Utils.slideDeactivate(f); });
94             t.animate({ 'left': '0%' }, 250);
95         };
96     };
97
98
99     self.slideChangeVerticalSlide = function (from, to) {
100         var f = SWS.Presentation.getSlide(from);
101         var t = SWS.Presentation.getSlide(to);
102         if (from < to) {
103             t.css('top', '100%');
104             SWS.Utils.slideActivate(t);
105             f.animate({ 'top': '-100%' }, 250, function () { SWS.Utils.slideDeactivate(f); });
106             t.animate({ 'top': '0%' }, 250);
107         } else {
108             t.css('top', '-100%');
109             SWS.Utils.slideActivate(t);
110             f.animate({ 'top': '100%' }, 250, function () { SWS.Utils.slideDeactivate(f); });
111             t.animate({ 'top': '0%' }, 250);
112         };
113     };
114
115 };
116
117 /*
118   Representation of intervals of positive integers.
119
120 SWS.Interval = new function (init) {
121
122     var self = this;
123     self.data = new Array();
124     self.parseString(s) {
125         var elems = s.split("_");
126         for(var i = 0; i < elems.length; i++){
127             var bounds = elems[i].split("-");
128             if (bounds.length > 2) continue;
129             if (SWS.isUndefined(bounds[1])) bounds[1] = bounds[0];
130             if (!(isFinite(bounds[0]) && isFinite(bounds[1]))) continue;
131
132             self.add(+(bounds[0]), +(bounds[1]));
133         };
134 7C
135     };
136     self.add(x, y) {
137         if (SWS.isUndefined(y) && isFinite(x)) self.add(x,x);
138
139
140
141
142     };
143 5B
144
145
146     };
147 };
148 */
149
150 SWS.Presentation = new function () {
151
152
153     var self = this;
154
155     var templates = {};
156
157
158     //TODO: clean-up;
159     var _total_slides;
160     var _initialized = false;
161     var _animations_running = false;
162
163     var _slide_callbacks = new Array ();
164
165
166
167
168     //Public methods
169     self.setTemplate = function (tn, fn) {
170         templates[tn] = fn;
171     };
172
173     self.getNumSlides = function () { return _total_slides; };
174
175     self.getSlide = function(i) {
176         return $($(".sws-canvas")[i]);
177     };
178
179     self.registerCallback = function (i, f) {
180         if (_initialized) return;
181         //jQuery does not seem to work well
182         //on a partial DOM
183
184         var slide_num = $(".sws-slide").length - 1;
185
186         SWS.Utils.push2(_slide_callbacks, slide_num,{ 'fn': f, 'frame': i });
187
188     };
189
190     if (typeof(Storage)!=="undefined"){
191         self.getCurrentSlide = function () {
192             //unary + casts to integer
193             var i = +(sessionStorage.current_slide);
194             if (!(i >= 0 && i < self.getNumSlides())){
195                 return 0;
196             } else {
197                 return i;
198             };
199         };
200
201         self.setCurrentSlide = function (i) {
202             sessionStorage.current_slide = i;
203         };
204
205     } else {
206         var _current_slide = 0;
207         self.getCurrentSlide = function () { return _current_slide; };
208         self.setCurrentSlide = function (i) { _current_slide = i; };
209
210     };
211     self.firstSlide = function () { return 0; };
212     self.lastSlide = function () { return self.getNumSlides() - 1; };
213
214     self.refresh = function () {
215         /* block upcoming input event until all animation are finished */
216         _animations_running = true;
217
218         var canvas = $(".sws-canvas");
219         var from_slide_num = canvas.index($(".sws-active-slide"));
220         var to_slide_num = self.getCurrentSlide();
221         var watch_slide_anim = false;
222         var to_slide = $(canvas[to_slide_num]);
223         var slide_change = !_initialized || (from_slide_num != to_slide_num);
224
225         var info = to_slide.data("sws-frame-info");
226         if (slide_change) {
227             //Launch a slide transition:
228             templates['sws-slide-change'](from_slide_num, to_slide_num);
229             watch_slide_anim = true;
230             templates['sws-update-header'](to_slide);
231             templates['sws-update-footer'](to_slide);
232             for (var i = 0; i < info.callbacks.at_slide.length;i++){
233                 info.callbacks.at_slide[i](to_slide);
234             };
235         };
236
237
238         var cur = info.current;
239         var custom = info.custom;
240         var real_slide = to_slide.children(".sws-slide");
241         real_slide.find("*").add(real_slide).each (function (i) {
242             var fcur = "f" + cur;
243             var frameset = $(this).data("sws-frame-set") || {};
244             if (frameset[fcur])
245                 templates['sws-object-activate']($(this));
246             else
247                 templates['sws-object-deactivate']($(this));
248         });
249
250         var callbacks;
251         if (callbacks = info.callbacks.at_frame[self.getCurrentFrame()]){
252             for (var k = 0; k < callbacks.length; k++)
253                 callbacks[k]($(to_slide));
254         };
255
256         var to_watch = $(to_slide).find("*");
257         if (watch_slide_anim) {
258             to_watch = to_watch.add(to_slide).add($(canvas[from_slide_num]));
259         };
260
261         to_watch.find("*").promise().done(function() {
262             _animations_running = false;
263         });
264     };
265
266     self.nextSlide = function () {
267         self.setCurrentSlide(Math.min(self.getCurrentSlide()+1,
268                                       self.lastSlide()));
269     };
270
271     self.previousSlide = function () {
272         self.setCurrentSlide(Math.max(self.getCurrentSlide()-1,
273                                       self.firstSlide()));
274     };
275
276     self.getFrameInfo = function () {
277
278         var i = self.getCurrentSlide();
279         var canvas = $($(".sws-canvas")[i]);
280         var infos = canvas.data("sws-frame-info");
281         return infos;
282     };
283     self.getCurrentFrame = function () { return self.getFrameInfo().current; };
284     self.setCurrentFrame = function (i) { self.getFrameInfo().current = i; };
285     self.firstFrame = function () { return 0; };
286     self.lastFrame = function () { return self.getFrameInfo().last; };
287
288     self.nextFrame = function () {
289         self.setCurrentFrame(Math.min(self.getCurrentFrame()+1,
290                                       self.lastFrame()));
291
292     };
293     self.previousFrame = function () {
294         self.setCurrentFrame(Math.max(self.getCurrentFrame()-1,
295                                        self.firstFrame()));
296     };
297
298     self.next = function () {
299         var i = self.getCurrentFrame();
300         if (i == self.lastFrame())
301             self.nextSlide();
302         else
303             self.nextFrame();
304     };
305
306     self.previous = function () {
307         var i = self.getCurrentFrame();
308         if (i == self.firstFrame())
309             self.previousSlide();
310         else
311             self.previousFrame();
312     };
313
314     self.inputHandler = function (event) {
315         if (_animations_running) return;
316         switch (event.which) {
317         case 36:/* Home */
318             self.firstSlide();
319             break;
320
321         case 35:/* End */
322             self.lastSlide();
323             break;
324
325         case 32: /* space */
326         case 39: /* -> */
327         case 1: /* mouse button 1 */
328             self.next();
329             break;
330         case 34: /* PgDown */
331         case 78: /* n */
332             self.nextSlide();
333             break;
334         case 8: /* backspace */
335         case 37: /* <-   */
336             self.previous();
337             break;
338         case 33: /* PgUp */
339         case 80: /* p */
340             self.previousSlide();
341             break;
342         default:
343             return;
344         };
345         self.refresh();
346     };
347
348
349
350     function init_canvas(canvas, custom) {
351         var cur_frame = 0;
352         var last_frame = canvas.find(".sws-pause").length;
353         //Add all regular elements to the frame list
354         var slide = $(canvas.children(".sws-slide")[0]);
355
356         var callbacks = { at_slide : new Array(),
357                           at_frame : new Array() }
358
359         if (SWS.Utils.isUndefined(custom)) {
360             custom = new Array ();
361         };
362         for (var i = 0; i < custom.length; i++) {
363             if (isFinite(custom[i].frame))
364                 SWS.Utils.push2(callbacks.at_frame, +(custom[i].frame), custom[i].fn);
365             else if (custom[i].frame == "slide")
366                 callbacks.at_slide.push(custom[i].fn);
367         };
368
369         slide.find("*").add(slide).each(function(i) {
370             if ($(this).filter('*[class*="sws-onslide-"]').length) {
371             } else {
372                 if ($(this).hasClass("sws-pause"))  cur_frame++;
373                 var o = {};
374                 for (var j = cur_frame; j <= last_frame; j++)
375                     o[ "f" + j ] = true;
376                 $(this).data("sws-frame-set", o);
377             };
378         });
379
380         canvas.data("sws-frame-info", { current: 0,
381                                         last: last_frame,
382                                         callbacks: callbacks
383                                       });
384
385     };
386
387     function init () {
388
389         _total_slides = $(".sws-slide").length;
390
391         $(document).keydown(self.inputHandler);
392         $(document).mousedown(self.inputHandler);
393
394         var cur = self.getCurrentSlide();
395         $(".sws-slide").each (function (i) {
396             var par = $(this).parent();
397
398             $(this).remove();
399             var canvas = $('<div class="sws-canvas"/>');
400
401             if (!($(this).hasClass("sws-option-noheader"))) {
402                 canvas.append($('<div class="sws-header"/>'));
403             };
404             $(this).find('script[type="text/javascript"]').remove();
405             canvas.append($(this));
406             if (!($(this).hasClass("sws-option-nofooter"))) {
407                 canvas.append($('<div class="sws-footer"/>'));
408             };
409             par.append(canvas);
410
411             if (i == cur) {
412                 canvas
413                     .addClass("sws-active-slide")
414                     .removeClass("sws-inacitve-slide");
415             } else {
416                 canvas
417                     .addClass("sws-inactive-slide")
418                     .removeClass("sws-active-slide");
419             };
420             init_canvas(canvas,_slide_callbacks[i]);
421
422         });
423         _slide_callbacks = null; /* avoid a leak */
424         self.refresh();
425         _initialized = true;
426
427     };
428
429     self.init = function () {
430         $(document).ready(init);
431     };
432
433
434
435     self.setTemplate('sws-object-activate', SWS.Utils.objectActivate);
436     self.setTemplate('sws-object-deactivate', SWS.Utils.objectDeactivate);
437     self.setTemplate('sws-slide-change', SWS.Utils.slideChange);
438     self.setTemplate('sws-update-footer', SWS.Utils.updateFooter);
439     self.setTemplate('sws-update-header', SWS.Utils.updateHeader);
440
441 };