Mercurial > hg > Papers > 2014 > taninari-master
comparison presen/js/jquery.slideshow.js @ 27:57a92ff9540c
add presen files
author | Taninari YU <you@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 04 Feb 2014 04:04:10 +0900 (2014-02-03) |
parents | |
children |
comparison
equal
deleted
inserted
replaced
26:aec4085dd5db | 27:57a92ff9540c |
---|---|
1 | |
2 var Slideshow = { | |
3 | |
4 settings: { | |
5 debug: true | |
6 }, | |
7 | |
8 isProjection: false, // are we in projection (slideshow) mode (in contrast to screen (outline) mode)? | |
9 snum: 1, // current slide # (non-zero based index e.g. starting with 1) | |
10 smax: 1, // max number of slides | |
11 incpos: 0, // current step in slide | |
12 steps: null, | |
13 | |
14 $slides: null, | |
15 $stylesProjection: null, | |
16 $stylesScreen: null, | |
17 | |
18 slideClasses: [ 'far-past', 'past', 'current', 'next', 'far-next' ] | |
19 }; | |
20 | |
21 | |
22 /************************************ | |
23 * lets you define your own "global" transition function | |
24 * passes in a reference to from and to slide wrapped in jQuery wrapper | |
25 * | |
26 * see jquery.slideshow.transition.js for more examples | |
27 */ | |
28 | |
29 Slideshow.transition = function( $from, $to ) { | |
30 // do nothing here; by default lets use css3 for transition effects | |
31 } | |
32 | |
33 | |
34 Slideshow.debug = function( msg ) { | |
35 if( this.settings.debug && window.console && window.console.log ) | |
36 window.console.log( '[debug] ' + msg ); | |
37 } | |
38 | |
39 | |
40 Slideshow.init = function( options ) { | |
41 | |
42 this.settings = $.extend({ | |
43 mode : 'slideshow', // slideshow | outline | autoplay | |
44 titleSelector : 'h1', | |
45 slideSelector : '.slide', // dummy (not yet working) | |
46 stepSelector : '.step', // dummy (not yet working) | |
47 debug : false, | |
48 normalize : true // normalize selectors (that is, allow aliases | |
49 // e.g. build,action,etc. for step and so on) | |
50 }, options || {}); | |
51 | |
52 this.isProjection = false; // are we in projection (slideshow) mode (in contrast to screen (outline) mode)? | |
53 this.snum = 1; // current slide # (non-zero based index e.g. starting with 1) | |
54 this.smax = 1; // max number of slides | |
55 this.incpos = 0; // current step in slide | |
56 this.steps = null; | |
57 | |
58 if( this.settings.normalize == true ) | |
59 this.normalize(); | |
60 | |
61 this.$slides = $( '.slide' ); | |
62 | |
63 this.smax = this.$slides.length; | |
64 | |
65 this.addSlideIds(); | |
66 this.steps = this.collectSteps(); | |
67 this.updateSlides(); // mark slides w/ far-past,past,current,next,far-next | |
68 | |
69 // $stylesProjection holds all styles (<link rel="stylesheet"> or <style> w/ media type projection) | |
70 // $stylesScreen holds all styles (<link rel="stylesheet"> or <style> w/ media type screen) | |
71 | |
72 // add workaround for chrome | |
73 // use screen,projection instead of projection | |
74 // (without projection inline style tag gets not parsed into a styleSheet accesible via JavaScript) | |
75 | |
76 this.$stylesProjection = $( 'link[media*=projection], style[media*=projection]' ).not('[rel*=less]').not('[type*=less]'); | |
77 this.$stylesScreen = $( 'link[media*=screen], style[media*=screen]' ).not('[media*=projection]').not('[rel*=less]').not('[type*=less]') ; | |
78 | |
79 $( document ).trigger( 'slideshow.init' ); // fire init for addons | |
80 | |
81 this.addClicker(); | |
82 | |
83 | |
84 // opera is the only browser currently supporting css projection mode | |
85 this.notOperaFix(); | |
86 | |
87 // store possible slidenumber from hash */ | |
88 // todo: use regex to extract number | |
89 // might be #slide1 or just #1 | |
90 | |
91 var gotoSlideNum = parseInt( window.location.hash.substring(1) ); | |
92 this.debug( "gotoSlideNum=" + gotoSlideNum ); | |
93 | |
94 if( !isNaN( gotoSlideNum )) | |
95 { | |
96 this.debug( "restoring slide on (re)load #: " + gotoSlideNum ); | |
97 this.goTo( gotoSlideNum ); | |
98 } | |
99 | |
100 if( this.settings.mode == 'outline' ) | |
101 this.toggle(); | |
102 | |
103 $( document ).trigger( 'slideshow.start' ); // fire start for addons | |
104 | |
105 $( document ).on( 'keyup', $.proxy( Slideshow.keys, this )); | |
106 } // end init() | |
107 | |
108 | |
109 Slideshow.normalize = function() { | |
110 | |
111 // check for .presentation aliases, that is, .deck, .slides | |
112 $( '.deck, .slides' ).addClass( 'presentation' ); | |
113 | |
114 // add slide class to immediate children | |
115 // todo: use autoslide option that lets you turn on/off option? | |
116 $( '.presentation' ).children().addClass( 'slide' ); | |
117 | |
118 // todo: scope with .slide?? e.g .slide .incremental | |
119 // todo: make removing "old" class an option?? | |
120 | |
121 // check for .step aliases, that is, .incremental, .delayed, .action, .build | |
122 $( '.incremental, .delayed, .action, .build' ).addClass( 'step' ); | |
123 | |
124 // check for .notes aliases, that is, .note, .handout | |
125 $( '.note, .handout' ).addClass( 'notes' ); | |
126 | |
127 } | |
128 | |
129 Slideshow.notOperaFix = function() { | |
130 // 1) switch media type from projection to screen | |
131 | |
132 var self = this; // NOTE: jquery binds this in .each to element | |
133 | |
134 this.$stylesProjection.each( function(i) { | |
135 var styleProjection = this; | |
136 // note: no longer used; workaround for chrome needs screen,projection to make it work (thus, no need to switch to screen) | |
137 // styleProjection.media = 'screen'; | |
138 styleProjection.disabled = true; | |
139 | |
140 self.debug( "notOperaFix - stylesProjection["+i+"] switching media type from projection to screen" ); | |
141 } ); | |
142 | |
143 this.isProjection = false; | |
144 | |
145 // 2) disable screen styles and enable projection styles (thus, switch into projection mode) | |
146 this.toggle(); | |
147 | |
148 // now we should be in project mode | |
149 } // end notOperatFix() | |
150 | |
151 | |
152 Slideshow.toggle = function() { | |
153 // todo: use settings.isProjection for state tracking | |
154 // and change disable accordingly (plus assert that all styles are in the state as expected) | |
155 | |
156 // toggle between projection (slide show) mode | |
157 // and screen (outline) mode | |
158 | |
159 var self = this; // NOTE: jquery binds this in .each to element | |
160 | |
161 this.$stylesProjection.each( function(i) { | |
162 var styleProjection = this; | |
163 | |
164 styleProjection.disabled = !styleProjection.disabled; | |
165 | |
166 self.debug( "toggle - stylesProjection["+i+"] disabled? " + styleProjection.disabled ); | |
167 }); | |
168 | |
169 this.$stylesScreen.each( function(i) { | |
170 var styleScreen = this; | |
171 | |
172 styleScreen.disabled = !styleScreen.disabled; | |
173 | |
174 self.debug( "toggle - stylesScreen["+i+"] disabled? " + styleScreen.disabled ); | |
175 | |
176 // update isProjection flag | |
177 self.isProjection = styleScreen.disabled; | |
178 }); | |
179 | |
180 /* | |
181 * note: code no longer needed; using (adding/removing) css classes hide/show) | |
182 * | |
183 | |
184 if( this.isProjection ) | |
185 { | |
186 this.$slides.each( function(i) { | |
187 if( i == (self.snum-1) ) | |
188 $(this).show(); | |
189 else | |
190 $(this).hide(); | |
191 }); | |
192 } | |
193 else | |
194 { | |
195 this.$slides.show(); | |
196 } | |
197 */ | |
198 } // end toggle() | |
199 | |
200 | |
201 Slideshow.updatePermaLink = function() | |
202 { | |
203 // todo: unify hash marks??; use #1 for div ids instead of #slide1? | |
204 window.location.hash = '#'+ this.snum; | |
205 } | |
206 | |
207 Slideshow.goTo = function( target ) | |
208 { | |
209 if( target > this.smax || target == this.snum ) | |
210 return; | |
211 | |
212 this.go( target - this.snum ); | |
213 } | |
214 | |
215 Slideshow.go = function( dir ) | |
216 { | |
217 this.debug( 'go: ' + dir ); | |
218 | |
219 if( dir == 0 ) return; /* same slide; nothing to do */ | |
220 | |
221 var cid = '#slide' + this.snum; /* current slide (selector) id */ | |
222 var csteps = this.steps[ this.snum-1 ]; /* current slide steps array */ | |
223 | |
224 /* remove all step and stepcurrent classes from current slide */ | |
225 if( csteps.length > 0) { | |
226 $( csteps ).each( function() { | |
227 $(this).removeClass( 'step' ).removeClass( 'stepcurrent' ); | |
228 } ); | |
229 } | |
230 | |
231 /* set snum to next slide */ | |
232 this.snum += dir; | |
233 if( this.snum > this.smax ) this.snum = this.smax; | |
234 if( this.snum < 1 ) this.snum = 1; | |
235 | |
236 var nid = '#slide' + this.snum; /* next slide (selector) id */ | |
237 var nsteps = this.steps[this.snum-1]; /* next slide steps array */ | |
238 | |
239 if( dir < 0 ) /* go backwards? */ | |
240 { | |
241 this.incpos = nsteps.length; | |
242 /* mark last step as current step */ | |
243 if( nsteps.length > 0 ) | |
244 $( nsteps[this.incpos-1] ).addClass( 'stepcurrent' ); | |
245 } | |
246 else /* go forwards? */ | |
247 { | |
248 this.incpos = 0; | |
249 if( nsteps.length > 0 ) { | |
250 $( nsteps ).each( function() { | |
251 $(this).addClass( 'step' ).removeClass( 'stepcurrent' ); | |
252 } ); | |
253 } | |
254 } | |
255 | |
256 if( !(cid == nid) ) { | |
257 this.updateSlides(); | |
258 | |
259 this.debug( "transition from " + cid + " to " + nid ); | |
260 this.transition( $( cid ), $( nid ) ); | |
261 | |
262 // only fire change event if slide changes | |
263 $( document ).trigger( 'slideshow.change', [$( cid ), $( nid )]); | |
264 } | |
265 | |
266 this.updatePermaLink(); | |
267 } // end go() | |
268 | |
269 | |
270 Slideshow.updateSlideClass = function( $slide, className ) | |
271 { | |
272 if( className ) | |
273 $slide.addClass( className ); | |
274 | |
275 for( var i in this.slideClasses ) | |
276 { | |
277 if( className != this.slideClasses[i] ) | |
278 $slide.removeClass( this.slideClasses[i] ); | |
279 } | |
280 } | |
281 | |
282 Slideshow.updateSlides = function() | |
283 { | |
284 var self = this; | |
285 this.$slides.each( function( i ) { | |
286 switch( i ) { | |
287 case (self.snum-1)-2: | |
288 self.updateSlideClass( $(this), 'far-past' ); | |
289 break; | |
290 case (self.snum-1)-1: | |
291 self.updateSlideClass( $(this), 'past' ); | |
292 break; | |
293 case (self.snum-1): | |
294 self.updateSlideClass( $(this), 'current' ); | |
295 break; | |
296 case (self.snum-1)+1: | |
297 self.updateSlideClass( $(this), 'next' ); | |
298 break; | |
299 case (self.snum-1)+2: | |
300 self.updateSlideClass( $(this), 'far-next' ); | |
301 break; | |
302 default: | |
303 self.updateSlideClass( $(this) ); | |
304 break; | |
305 } | |
306 }); | |
307 } | |
308 | |
309 | |
310 | |
311 Slideshow.subgo = function( dir ) | |
312 { | |
313 this.debug( 'subgo: ' + dir + ', incpos before: ' + this.incpos + ', after: ' + (this.incpos+dir) ); | |
314 | |
315 var csteps = this.steps[this.snum-1]; /* current slide steps array */ | |
316 | |
317 if( dir > 0) | |
318 { /* go forward? */ | |
319 if( this.incpos > 0 ) | |
320 $( csteps[this.incpos-1] ).removeClass( 'stepcurrent' ); | |
321 $( csteps[this.incpos] ).removeClass( 'step').addClass( 'stepcurrent' ); | |
322 this.incpos++; | |
323 } | |
324 else | |
325 { /* go backwards? */ | |
326 this.incpos--; | |
327 $( csteps[this.incpos] ).removeClass( 'stepcurrent' ).addClass( 'step' ); | |
328 if( this.incpos > 0 ) | |
329 $( csteps[this.incpos-1] ).addClass( 'stepcurrent' ); | |
330 } | |
331 } // end subgo() | |
332 | |
333 | |
334 Slideshow.keys = function( key ) | |
335 { | |
336 this.debug( "enter keys()" ); | |
337 | |
338 if( !key ) { | |
339 key = event; | |
340 key.which = key.keyCode; | |
341 } | |
342 if( key.which == 84 ) { | |
343 this.toggle(); // toggle between project and screen css media mode | |
344 return; | |
345 } | |
346 if( this.isProjection ) { | |
347 switch( key.which ) { | |
348 case 32: // spacebar | |
349 case 34: // page down | |
350 case 39: // rightkey | |
351 case 40: // downkey | |
352 | |
353 var csteps = this.steps[this.snum-1]; /* current slide steps array */ | |
354 | |
355 if( !csteps || this.incpos >= csteps.length ) { | |
356 this.go(1); | |
357 } else { | |
358 this.subgo(1); | |
359 } | |
360 break; | |
361 case 33: // page up | |
362 case 37: // leftkey | |
363 case 38: // upkey | |
364 | |
365 if( !this.steps[this.snum-1] || this.incpos <= 0 ) { | |
366 this.go(-1); | |
367 } else { | |
368 this.subgo(-1); | |
369 } | |
370 break; | |
371 case 36: // home | |
372 this.goTo(1); | |
373 break; | |
374 case 35: // end | |
375 this.goTo( this.smax ); | |
376 break; | |
377 case 68: // d | |
378 this.toggleDebug(); | |
379 break; | |
380 } | |
381 $( document ).trigger( 'slideshow.keys', key ); | |
382 } | |
383 } // end keys() | |
384 | |
385 | |
386 Slideshow.toggleDebug = function() | |
387 { | |
388 this.settings.debug = !this.settings.debug; | |
389 this.doDebug(); | |
390 } | |
391 | |
392 Slideshow.doDebug = function() | |
393 { | |
394 if( this.settings.debug == true ) | |
395 { | |
396 $( document ).trigger( 'slideshow.debug.on' ); | |
397 } | |
398 else | |
399 { | |
400 $( document ).trigger( 'slideshow.debug.off' ); | |
401 } | |
402 } | |
403 | |
404 Slideshow.collectStepsWorker = function(obj) | |
405 { | |
406 var self = this; // NOTE: jquery binds this in .each,.click, etc to element | |
407 | |
408 var steps = []; | |
409 if( !obj ) | |
410 return steps; | |
411 | |
412 $(obj).children().each( function() { | |
413 if( $(this).hasClass( 'step' ) ) { | |
414 | |
415 self.debug( 'step found for ' + this.tagName ); | |
416 $(this).removeClass( 'step' ); | |
417 | |
418 /* don't add enclosing list; instead add step class to all list items/children */ | |
419 if( $(this).is( 'ol,ul' ) ) { | |
420 self.debug( ' ol or ul found; adding auto steps' ); | |
421 $(this).children().addClass( 'step' ); | |
422 } | |
423 else | |
424 { | |
425 steps.push( this ) | |
426 } | |
427 } | |
428 steps = steps.concat( self.collectStepsWorker( this ) ); | |
429 }); | |
430 | |
431 return steps; | |
432 } // end collectStepWorkers | |
433 | |
434 Slideshow.collectSteps = function() | |
435 { | |
436 var self = this; // NOTE: jquery binds this in .each,.click, etc to element | |
437 | |
438 var steps = []; | |
439 | |
440 this.$slides.each( function(i) { | |
441 self.debug ( 'collectSteps for ' + this.id + ':' ); | |
442 steps[i] = self.collectStepsWorker( this ); | |
443 }); | |
444 | |
445 $( steps ).each( function(i) { | |
446 self.debug( 'slide ' + (i+1) + ': found ' + this.length + ' steps' ); | |
447 }); | |
448 | |
449 return steps; | |
450 } // end collectSteps() | |
451 | |
452 | |
453 Slideshow.addClicker = function() | |
454 { | |
455 var self = this; // NOTE: jquery binds this in .each,.click, etc to element | |
456 | |
457 // if you click on heading of slide -> go to next slide (or next step) | |
458 | |
459 $( this.settings.titleSelector, this.$slides ).click( function( ev ) { | |
460 if(ev.which != 1) return; // only process left clicks (e.g 1; middle and rightclick use 2 and 3) | |
461 | |
462 if( !self.isProjection ) // suspend clicker in outline view (just slideshow view) | |
463 return; | |
464 | |
465 var csteps = self.steps[self.snum-1]; // current slide steps array | |
466 if ( !csteps || self.incpos >= csteps.length ) | |
467 self.go(1); | |
468 else | |
469 self.subgo(1); | |
470 }); | |
471 | |
472 | |
473 $( this.settings.titleSelector, this.$slides ).on('contextmenu', function() { | |
474 if( !self.isProjection ) // suspend clicker in outline view (just slideshow view) | |
475 return; | |
476 | |
477 var csteps = self.steps[self.snum-1]; // current slide steps array | |
478 if ( !csteps || self.incpos >= csteps.length ) | |
479 self.go(-1); | |
480 else | |
481 self.subgo(-1); | |
482 | |
483 return false; | |
484 } ); | |
485 } // end addClicker() | |
486 | |
487 | |
488 Slideshow.addSlideIds = function() { | |
489 this.$slides.each( function(i) { | |
490 this.id = 'slide'+(i+1); | |
491 }); | |
492 } | |
493 | |
494 | |
495 Slideshow.addStyles = function() { | |
496 this.debug( 'add builtin css via inline style elements' ); | |
497 | |
498 var styleProjection = | |
499 "<style media='screen,projection'> \n"+ | |
500 " .slide { display: block; } \n"+ | |
501 " .notes { display: none; } \n"+ | |
502 " .layout { display: block; } \n"+ | |
503 "</style>"; | |
504 | |
505 var styleScreen = | |
506 "<style media='screen'> \n"+ | |
507 "/**** \n"+ | |
508 " * hide layout stuff (header, footer, navLinks, navList etc.) \n"+ | |
509 " */ \n"+ | |
510 " \n"+ | |
511 " .layout * { display: none; } \n"+ | |
512 "</style>"; | |
513 | |
514 var stylePrint = | |
515 "<style media='print'> \n"+ | |
516 " \n"+ | |
517 " .slide { display: block !important; } \n"+ | |
518 " .layout, .layout * { display: none !important; } \n"+ | |
519 " \n"+ | |
520 "/****** \n"+ | |
521 " * Turn on print-specific stuff/classes \n"+ | |
522 " */ \n"+ | |
523 " \n"+ | |
524 " .extra { display: block !important; } \n"+ | |
525 "</style>"; | |
526 | |
527 // note: use prepend (not append) to make sure this | |
528 // styles come first (and do not overrule user supplied styles) | |
529 | |
530 $( 'head' ).prepend( styleProjection ); | |
531 $( 'head' ).prepend( styleScreen ); | |
532 $( 'head' ).prepend( stylePrint ); | |
533 } | |
534 | |
535 Slideshow.addStyles(); |