3 Copyright (c) 2011 Caleb Troughton
4 Dual licensed under the MIT license and GPL license.
5 https://github.com/imakewebthings/deck.js/blob/master/MIT-license.txt
6 https://github.com/imakewebthings/deck.js/blob/master/GPL-license.txt
10 The deck.core module provides all the basic functionality for creating and
11 moving through a deck. It does so by applying classes to indicate the state of
12 the deck and its slides, allowing CSS to take care of the visual representation
13 of each state. It also provides methods for navigating the deck and inspecting
14 its state, as well as basic key bindings for going to the next and previous
15 slides. More functionality is provided by wholly separate extension modules
16 that use the API provided by core.
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
25 This event fires at the beginning of a slide change, before the actual
26 change occurs. Its purpose is to give extension authors a way to prevent
27 the slide change from occuring. This is done by calling preventDefault
28 on the event object within this event. If that is done, the deck.change
29 event will never be fired and the slide will not change.
31 beforeChange
: 'deck.beforeChange',
34 This event fires whenever the current slide changes, whether by way of
35 next, prev, or go. The callback function is passed two parameters, from
36 and to, equal to the indices of the old slide and the new slide
37 respectively. If preventDefault is called on the event within this handler
38 the slide change does not occur.
40 $(document).bind('deck.change', function(event, from, to) {
41 alert('Moving from slide ' + from + ' to ' + to);
44 change
: 'deck.change',
47 This event fires at the beginning of deck initialization, after the options
48 are set but before the slides array is created. This event makes a good hook
49 for preprocessing extensions looking to modify the deck.
51 beforeInitialize
: 'deck.beforeInit',
54 This event fires at the end of deck initialization. Extensions should
55 implement any code that relies on user extensible options (key bindings,
56 element selectors, classes) within a handler for this event. Native
57 events associated with Deck JS should be scoped under a .deck event
58 namespace, as with the example below:
61 $.deck.defaults.keys.myExtensionKeycode = 70; // 'h'
62 $d.bind('deck.init', function() {
63 $d.bind('keydown.deck', function(event) {
64 if (event.which === $.deck.getOptions().keys.myExtensionKeycode) {
70 initialize
: 'deck.init'
77 Internal function. Updates slide and container classes based on which
78 slide is the current slide.
80 updateStates = function() {
81 var oc
= options
.classes
,
82 osc
= options
.selectors
.container
,
83 old
= $container
.data('onSlide'),
87 $container
.removeClass(oc
.onPrefix
+ old
)
88 .addClass(oc
.onPrefix
+ current
)
89 .data('onSlide', current
);
91 // Remove and re-add child-current classes for nesting
92 $('.' + oc
.current
).parentsUntil(osc
).removeClass(oc
.childCurrent
);
93 slides
[current
].parentsUntil(osc
).addClass(oc
.childCurrent
);
95 // Remove previous states
96 $.each(slides
, function(i
, el
) {
107 // Add new states back in
108 slides
[current
].addClass(oc
.current
);
110 slides
[current
-1].addClass(oc
.previous
);
112 if (current
+ 1 < slides
.length
) {
113 slides
[current
+1].addClass(oc
.next
);
116 $.each(slides
.slice(0, current
- 1), function(i
, el
) {
117 el
.addClass(oc
.before
);
120 if (current
+ 2 < slides
.length
) {
121 $.each(slides
.slice(current
+2), function(i
, el
) {
122 el
.addClass(oc
.after
);
127 /* Methods exposed in the jQuery.deck namespace */
131 jQuery.deck(selector, options)
133 selector: string | jQuery | array
134 options: object, optional
136 Initializes the deck, using each element matched by selector as a slide.
137 May also be passed an array of string selectors or jQuery objects, in
138 which case each selector in the array is considered a slide. The second
139 parameter is an optional options object which will extend the default
152 init: function(elements
, opts
) {
159 options
= $.extend(true, {}, $[deck
].defaults
, opts
);
162 $container
= $(options
.selectors
.container
);
163 tolerance
= options
.touch
.swipeTolerance
;
165 // Pre init event for preprocessing hooks
166 $d
.trigger(events
.beforeInitialize
);
168 // Hide the deck while states are being applied to kill transitions
169 $container
.addClass(options
.classes
.loading
);
171 // Fill slides array depending on parameter type
172 if ($.isArray(elements
)) {
173 $.each(elements
, function(i
, e
) {
178 $(elements
).each(function(i
, e
) {
183 /* Remove any previous bindings, and rebind key events */
184 $d
.unbind('keydown.deck').bind('keydown.deck', function(e
) {
185 if (e
.which
=== options
.keys
.next
|| $.inArray(e
.which
, options
.keys
.next
) > -1) {
189 else if (e
.which
=== options
.keys
.previous
|| $.inArray(e
.which
, options
.keys
.previous
) > -1) {
194 /* Stop propagation of key events within editable elements */
195 .undelegate('input, textarea, select, button, meter, progress, [contentEditable]', 'keydown', esp
)
196 .delegate('input, textarea, select, button, meter, progress, [contentEditable]', 'keydown', esp
);
198 /* Bind touch events for swiping between slides on touch devices */
199 $container
.unbind('touchstart.deck').bind('touchstart.deck', function(e
) {
201 startTouch
= $.extend({}, e
.originalEvent
.targetTouches
[0]);
204 .unbind('touchmove.deck').bind('touchmove.deck', function(e
) {
205 $.each(e
.originalEvent
.changedTouches
, function(i
, t
) {
206 if (startTouch
&& t
.identifier
=== startTouch
.identifier
) {
207 if (t
.screenX
- startTouch
.screenX
> tolerance
|| t
.screenY
- startTouch
.screenY
> tolerance
) {
209 startTouch
= undefined;
211 else if (t
.screenX
- startTouch
.screenX
< -1 * tolerance
|| t
.screenY
- startTouch
.screenY
< -1 * tolerance
) {
213 startTouch
= undefined;
220 .unbind('touchend.deck').bind('touchend.deck', function(t
) {
221 $.each(t
.originalEvent
.changedTouches
, function(i
, t
) {
222 if (startTouch
&& t
.identifier
=== startTouch
.identifier
) {
223 startTouch
= undefined;
227 .scrollLeft(0).scrollTop(0);
230 Kick iframe videos, which dont like to redraw w/ transforms.
231 Remove this if Webkit ever fixes it.
233 $.each(slides
, function(i
, $el
) {
234 $el
.unbind('webkitTransitionEnd.deck').bind('webkitTransitionEnd.deck',
236 if ($el
.hasClass($[deck
]('getOptions').classes
.current
)) {
237 var embeds
= $(this).find('iframe').css('opacity', 0);
238 window
.setTimeout(function() {
239 embeds
.css('opacity', 1);
249 // Show deck again now that slides are in place
250 $container
.removeClass(options
.classes
.loading
);
251 $d
.trigger(events
.initialize
);
255 jQuery.deck('go', index)
257 index: integer | string
259 Moves to the slide at the specified index if index is a number. Index is
260 0-based, so $.deck('go', 0); will move to the first slide. If index is a
261 string this will move to the slide with the specified id. If index is out
262 of bounds or doesn't match a slide id the call is ignored.
264 go: function(index
) {
265 var e
= $.Event(events
.beforeChange
),
268 /* Number index, easy. */
269 if (typeof index
=== 'number' && index
>= 0 && index
< slides
.length
) {
272 /* Id string index, search for it and set integer index */
273 else if (typeof index
=== 'string') {
274 $.each(slides
, function(i
, $slide
) {
275 if ($slide
.attr('id') === index
) {
282 /* Out of bounds, id doesn't exist, illegal input, eject */
283 if (typeof ndx
=== 'undefined') return;
285 /* Trigger beforeChange. If nothing prevents the change, trigger
287 $d
.trigger(e
, [current
, ndx
]);
288 if (!e
.isDefaultPrevented()) {
289 $d
.trigger(events
.change
, [current
, ndx
]);
298 Moves to the next slide. If the last slide is already active, the call
302 methods
.go(current
+1);
308 Moves to the previous slide. If the first slide is already active, the
312 methods
.go(current
-1);
316 jQuery.deck('getSlide', index)
318 index: integer, optional
320 Returns a jQuery object containing the slide at index. If index is not
321 specified, the current slide is returned.
323 getSlide: function(index
) {
324 var i
= typeof index
!== 'undefined' ? index
: current
;
325 if (typeof i
!= 'number' || i
< 0 || i
>= slides
.length
) return null;
330 jQuery.deck('getSlides')
332 Returns all slides as an array of jQuery objects.
334 getSlides: function() {
339 jQuery.deck('getContainer')
341 Returns a jQuery object containing the deck container as defined by the
344 getContainer: function() {
349 jQuery.deck('getOptions')
351 Returns the options object for the deck, including any overrides that
352 were defined at initialization.
354 getOptions: function() {
359 jQuery.deck('extend', name, method)
364 Adds method to the deck namespace with the key of name. This doesn’t
365 give access to any private member data — public methods must still be
366 used within method — but lets extension authors piggyback on the deck
367 namespace rather than pollute jQuery.
369 $.deck('extend', 'alert', function(msg) {
374 $.deck('alert', 'boom');
376 extend: function(name
, method
) {
377 methods
[name
] = method
;
381 /* jQuery extension */
382 $[deck
] = function(method
, arg
) {
383 if (methods
[method
]) {
384 return methods
[method
].apply(this, Array
.prototype.slice
.call(arguments
, 1));
387 return methods
.init(method
, arg
);
392 The default settings object for a deck. All deck extensions should extend
393 this object to add defaults for any of their options.
395 options.classes.after
396 This class is added to all slides that appear after the 'next' slide.
398 options.classes.before
399 This class is added to all slides that appear before the 'previous'
402 options.classes.childCurrent
403 This class is added to all elements in the DOM tree between the
404 'current' slide and the deck container. For standard slides, this is
405 mostly seen and used for nested slides.
407 options.classes.current
408 This class is added to the current slide.
410 options.classes.loading
411 This class is applied to the deck container during loading phases and is
412 primarily used as a way to short circuit transitions between states
413 where such transitions are distracting or unwanted. For example, this
414 class is applied during deck initialization and then removed to prevent
415 all the slides from appearing stacked and transitioning into place
419 This class is added to the slide immediately following the 'current'
422 options.classes.onPrefix
423 This prefix, concatenated with the current slide index, is added to the
424 deck container as you change slides.
426 options.classes.previous
427 This class is added to the slide immediately preceding the 'current'
430 options.selectors.container
431 Elements matched by this CSS selector will be considered the deck
432 container. The deck container is used to scope certain states of the
433 deck, as with the onPrefix option, or with extensions such as deck.goto
437 The numeric keycode used to go to the next slide.
439 options.keys.previous
440 The numeric keycode used to go to the previous slide.
442 options.touch.swipeTolerance
443 The number of pixels the users finger must travel to produce a swipe
449 before
: 'deck-before',
450 childCurrent
: 'deck-child-current',
451 current
: 'deck-current',
452 loading
: 'deck-loading',
454 onPrefix
: 'on-slide-',
455 previous
: 'deck-previous'
459 container
: '.deck-container'
463 // enter, space, page down, right arrow, down arrow,
464 next
: [13, 32, 34, 39, 40],
465 // backspace, page up, left arrow, up arrow
466 previous
: [8, 33, 37, 38]
474 $d
.ready(function() {
475 $('html').addClass('ready');
477 })(jQuery
, 'deck', document
);