1/*! 2Deck JS - deck.core 3Copyright (c) 2011 Caleb Troughton 4Dual licensed under the MIT license and GPL license. 5https://github.com/imakewebthings/deck.js/blob/master/MIT-license.txt 6https://github.com/imakewebthings/deck.js/blob/master/GPL-license.txt 7*/ 8 9/* 10The deck.core module provides all the basic functionality for creating and 11moving through a deck. It does so by applying classes to indicate the state of 12the deck and its slides, allowing CSS to take care of the visual representation 13of each state. It also provides methods for navigating the deck and inspecting 14its state, as well as basic key bindings for going to the next and previous 15slides. More functionality is provided by wholly separate extension modules 16that use the API provided by core. 17*/ 18(function($, deck, document, undefined) { 19 var slides, // Array of all the uh, slides... 20 current, // Array index of the current slide 21 $container, // Keeping this cached 22 23 events = { 24 /* 25 This event fires whenever the current slide changes, whether by way of 26 next, prev, or go. The callback function is passed two parameters, from 27 and to, equal to the indices of the old slide and the new slide 28 respectively. If preventDefault is called on the event within this handler 29 the slide change does not occur. 30 31 $(document).bind('deck.change', function(event, from, to) { 32 alert('Moving from slide ' + from + ' to ' + to); 33 }); 34 */ 35 change: 'deck.change', 36 37 /* 38 This event fires at the beginning of deck initialization, after the options 39 are set but before the slides array is created. This event makes a good hook 40 for preprocessing extensions looking to modify the deck. 41 */ 42 beforeInitialize: 'deck.beforeInit', 43 44 /* 45 This event fires at the end of deck initialization. Extensions should 46 implement any code that relies on user extensible options (key bindings, 47 element selectors, classes) within a handler for this event. Native 48 events associated with Deck JS should be scoped under a .deck event 49 namespace, as with the example below: 50 51 var $d = $(document); 52 $.deck.defaults.keys.myExtensionKeycode = 70; // 'h' 53 $d.bind('deck.init', function() { 54 $d.bind('keydown.deck', function(event) { 55 if (event.which === $.deck.getOptions().keys.myExtensionKeycode) { 56 // Rock out 57 } 58 }); 59 }); 60 */ 61 initialize: 'deck.init' 62 }, 63 64 options = {}, 65 $d = $(document), 66 67 /* 68 Internal function. Updates slide and container classes based on which 69 slide is the current slide. 70 */ 71 updateStates = function() { 72 var oc = options.classes, 73 osc = options.selectors.container,
74 old = $container.data('onSlide'), 75 $all = $(); 76 77 // Container state 78 $container.removeClass(oc.onPrefix + old) 79 .addClass(oc.onPrefix + current) 80 .data('onSlide', current); 81 82 // Remove and re-add child-current classes for nesting 83 $('.' + oc.current).parentsUntil(osc).removeClass(oc.childCurrent); 84 slides[current].parentsUntil(osc).addClass(oc.childCurrent); 85 86 // Remove previous states 87 $.each(slides, function(i, el) { 88 $all = $all.add(el); 89 }); 90 $all.removeClass([ 91 oc.before, 92 oc.previous, 93 oc.current, 94 oc.next, 95 oc.after 96 ].join(" ")); 97 98 // Add new states back in 99 slides[current].addClass(oc.current); 100 if (current > 0) { 101 slides[current-1].addClass(oc.previous); 102 } 103 if (current + 1 < slides.length) { 104 slides[current+1].addClass(oc.next); 105 } 106 if (current > 1) { 107 $.each(slides.slice(0, current - 1), function(i, el) { 108 el.addClass(oc.before); 109 }); 110 } 111 if (current + 2 < slides.length) { 112 $.each(slides.slice(current+2), function(i, el) { 113 el.addClass(oc.after); 114 }); 115 } 116 }, 117 118 /* Methods exposed in the jQuery.deck namespace */ 119 methods = { 120 121 /* 122 jQuery.deck(selector, options) 123 124 selector: string | jQuery | array 125 options: object, optional 126 127 Initializes the deck, using each element matched by selector as a slide. 128 May also be passed an array of string selectors or jQuery objects, in 129 which case each selector in the array is considered a slide. The second 130 parameter is an optional options object which will extend the default 131 values. 132 133 $.deck('.slide'); 134 135 or 136 137 $.deck([ 138 '#first-slide', 139 '#second-slide', 140 '#etc' 141 ]); 142 */ 143 init: function(elements, opts) { 144 var startTouch, 145 tolerance, 146 esp = function(e) { 147 e.stopPropagation(); 148 }; 149 150 options = $.extend(true, {}, $[deck].defaults, opts); 151 slides = []; 152 current = 0; 153 $container = $(options.selectors.container); 154 tolerance = options.touch.swipeTolerance; 155 156 // Pre init event for preprocessing hooks 157 $d.trigger(events.beforeInitialize); 158 159 // Hide the deck while states are being applied to kill transitions 160 $container.addClass(options.classes.loading); 161 162 // Fill slides array depending on parameter type 163 if ($.isArray(elements)) { 164 $.each(elements, function(i, e) { 165 slides.push($(e)); 166 }); 167 } 168 else { 169 $(elements).each(function(i, e) { 170 slides.push($(e)); 171 }); 172 } 173 174 /* Remove any previous bindings, and rebind key events */ 175 $d.unbind('keydown.deck').bind('keydown.deck', function(e) { 176 if (e.which === options.keys.next || $.inArray(e.which, options.keys.next) > -1) { 177 methods.next(); 178 e.preventDefault(); 179 } 180 else if (e.which === options.keys.previous || $.inArray(e.which, options.keys.previous) > -1) { 181 methods.prev(); 182 e.preventDefault(); 183 } 184 }) 185 /* Stop propagation of key events within editable elements */ 186 .undelegate('input, textarea, select, button, meter, progress, [contentEditable]', 'keydown', esp) 187 .delegate('input, textarea, select, button, meter, progress, [contentEditable]', 'keydown', esp); 188 189 /* Bind touch events for swiping between slides on touch devices */ 190 $container.unbind('touchstart.deck').bind('touchstart.deck', function(e) { 191 if (!startTouch) { 192 startTouch = $.extend({}, e.originalEvent.targetTouches[0]); 193 } 194 }) 195 .unbind('touchmove.deck').bind('touchmove.deck', function(e) { 196 $.each(e.originalEvent.changedTouches, function(i, t) { 197 if (startTouch && t.identifier === startTouch.identifier) { 198 if (t.screenX - startTouch.screenX > tolerance || t.screenY - startTouch.screenY > tolerance) { 199 $[deck]('prev'); 200 startTouch = undefined; 201 } 202 else if (t.screenX - startTouch.screenX < -1 * tolerance || t.screenY - startTouch.screenY < -1 * tolerance) { 203 $[deck]('next'); 204 startTouch = undefined; 205 } 206 return false; 207 } 208 }); 209 e.preventDefault(); 210 }) 211 .unbind('touchend.deck').bind('touchend.deck', function(t) { 212 $.each(t.originalEvent.changedTouches, function(i, t) { 213 if (startTouch && t.identifier === startTouch.identifier) { 214 startTouch = undefined; 215 } 216 }); 217 }) 218 .scrollLeft(0).scrollTop(0); 219 220 /* 221 Kick iframe videos, which dont like to redraw w/ transforms. 222 Remove this if Webkit ever fixes it. 223 */ 224 $.each(slides, function(i, $el) { 225 $el.unbind('webkitTransitionEnd.deck').bind('webkitTransitionEnd.deck', 226 function(event) { 227 if ($el.hasClass($[deck]('getOptions').classes.current)) { 228 var embeds = $(this).find('iframe').css('opacity', 0); 229 window.setTimeout(function() { 230 embeds.css('opacity', 1); 231 }, 100); 232 } 233 }); 234 }); 235 236 if (slides.length) { 237 updateStates(); 238 } 239 240 // Show deck again now that slides are in place 241 $container.removeClass(options.classes.loading); 242 $d.trigger(events.initialize); 243 }, 244 245 /* 246 jQuery.deck('go', index) 247 248 index: integer | string 249 250 Moves to the slide at the specified index if index is a number. Index is 251 0-based, so $.deck('go', 0); will move to the first slide. If index is a 252 string this will move to the slide with the specified id. If index is out 253 of bounds or doesn't match a slide id the call is ignored. 254 */ 255 go: function(index) { 256 var e = $.Event(events.change), 257 ndx; 258 259 /* Number index, easy. */ 260 if (typeof index === 'number' && index >= 0 && index < slides.length) { 261 ndx = index; 262 } 263 /* Id string index, search for it and set integer index */ 264 else if (typeof index === 'string') { 265 $.each(slides, function(i, $slide) { 266 if ($slide.attr('id') === index) { 267 ndx = i; 268 return false;
269 } 270 }); 271 }; 272 273 /* Out of bounds, id doesn't exist, illegal input, eject */ 274 if (typeof ndx === 'undefined') return; 275 276 $d.trigger(e, [current, ndx]); 277 if (e.isDefaultPrevented()) { 278 /* Trigger the event again and undo the damage done by extensions. */ 279 $d.trigger(events.change, [ndx, current]); 280 } 281 else { 282 current = ndx; 283 updateStates(); 284 } 285 }, 286 287 /* 288 jQuery.deck('next') 289 290 Moves to the next slide. If the last slide is already active, the call 291 is ignored. 292 */ 293 next: function() { 294 methods.go(current+1); 295 }, 296 297 /* 298 jQuery.deck('prev') 299 300 Moves to the previous slide. If the first slide is already active, the 301 call is ignored. 302 */ 303 prev: function() { 304 methods.go(current-1); 305 }, 306 307 /* 308 jQuery.deck('getSlide', index) 309 310 index: integer, optional 311 312 Returns a jQuery object containing the slide at index. If index is not 313 specified, the current slide is returned. 314 */ 315 getSlide: function(index) { 316 var i = typeof index !== 'undefined' ? index : current; 317 if (typeof i != 'number' || i < 0 || i >= slides.length) return null; 318 return slides[i]; 319 }, 320 321 /* 322 jQuery.deck('getSlides') 323 324 Returns all slides as an array of jQuery objects. 325 */ 326 getSlides: function() { 327 return slides; 328 }, 329 330 /* 331 jQuery.deck('getContainer') 332 333 Returns a jQuery object containing the deck container as defined by the 334 container option. 335 */ 336 getContainer: function() { 337 return $container; 338 }, 339 340 /* 341 jQuery.deck('getOptions') 342 343 Returns the options object for the deck, including any overrides that 344 were defined at initialization. 345 */ 346 getOptions: function() { 347 return options; 348 }, 349 350 /* 351 jQuery.deck('extend', name, method) 352 353 name: string 354 method: function 355 356 Adds method to the deck namespace with the key of name. This doesnât 357 give access to any private member data â public methods must still be 358 used within method â but lets extension authors piggyback on the deck 359 namespace rather than pollute jQuery. 360 361 $.deck('extend', 'alert', function(msg) { 362 alert(msg); 363 }); 364 365 // Alerts 'boom' 366 $.deck('alert', 'boom'); 367 */ 368 extend: function(name, method) { 369 methods[name] = method; 370 } 371 }; 372 373 /* jQuery extension */ 374 $[deck] = function(method, arg) { 375 if (methods[method]) { 376 return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 377 } 378 else { 379 return methods.init(method, arg); 380 } 381 }; 382 383 /* 384 The default settings object for a deck. All deck extensions should extend 385 this object to add defaults for any of their options. 386 387 options.classes.after 388 This class is added to all slides that appear after the 'next' slide. 389 390 options.classes.before 391 This class is added to all slides that appear before the 'previous' 392 slide. 393 394 options.classes.childCurrent 395 This class is added to all elements in the DOM tree between the 396 'current' slide and the deck container. For standard slides, this is 397 mostly seen and used for nested slides. 398 399 options.classes.current 400 This class is added to the current slide. 401 402 options.classes.loading 403 This class is applied to the deck container during loading phases and is 404 primarily used as a way to short circuit transitions between states 405 where such transitions are distracting or unwanted. For example, this 406 class is applied during deck initialization and then removed to prevent 407 all the slides from appearing stacked and transitioning into place 408 on load. 409 410 options.classes.next 411 This class is added to the slide immediately following the 'current' 412 slide. 413 414 options.classes.onPrefix 415 This prefix, concatenated with the current slide index, is added to the 416 deck container as you change slides. 417 418 options.classes.previous 419 This class is added to the slide immediately preceding the 'current' 420 slide. 421 422 options.selectors.container 423 Elements matched by this CSS selector will be considered the deck 424 container. The deck container is used to scope certain states of the 425 deck, as with the onPrefix option, or with extensions such as deck.goto 426 and deck.menu. 427 428 options.keys.next 429 The numeric keycode used to go to the next slide. 430 431 options.keys.previous 432 The numeric keycode used to go to the previous slide. 433 434 options.touch.swipeTolerance 435 The number of pixels the users finger must travel to produce a swipe 436 gesture. 437 */ 438 $[deck].defaults = { 439 classes: { 440 after: 'deck-after', 441 before: 'deck-before', 442 childCurrent: 'deck-child-current', 443 current: 'deck-current', 444 loading: 'deck-loading', 445 next: 'deck-next', 446 onPrefix: 'on-slide-', 447 previous: 'deck-previous' 448 }, 449 450 selectors: { 451 container: '.deck-container' 452 }, 453 454 keys: { 455 // enter, space, page down, right arrow, down arrow, 456 next: [13, 32, 34, 39, 40], 457 // backspace, page up, left arrow, up arrow 458 previous: [8, 33, 37, 38] 459 }, 460 461 touch: { 462 swipeTolerance: 60 463 } 464 }; 465 466 $d.ready(function() { 467 $('html').addClass('ready'); 468 }); 469 470 /* 471 FF + Transforms + Flash video don't get along... 472 Firefox will reload and start playing certain videos after a 473 transform. Blanking the src when a previously shown slide goes out 474 of view prevents this. 475 */ 476 $d.bind('deck.change', function(e, from, to) { 477 var oldFrames = $[deck]('getSlide', from).find('iframe'), 478 newFrames = $[deck]('getSlide', to).find('iframe'); 479 480 oldFrames.each(function() { 481 var $this = $(this), 482 curSrc = $this.attr('src'); 483 484 if(curSrc) { 485 $this.data('deck-src', curSrc).attr('src', ''); 486 } 487 }); 488 489 newFrames.each(function() { 490 var $this = $(this), 491 originalSrc = $this.data('deck-src'); 492 493 if (originalSrc) { 494 $this.attr('src', originalSrc); 495 } 496 }); 497 }); 498})(jQuery, 'deck', document);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.