Fix scale on load not firing sometimes
[deck.js.git] / extensions / scale / deck.scale.js
blobe0ae8e26c88cb32d2ac60dc4a125c56ac755dc1d
1 /*!
2 Deck JS - deck.scale
3 Copyright (c) 2011-2012 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
7 */
9 /*
10 This module adds automatic scaling to the deck.  Slides are scaled down
11 using CSS transforms to fit within the deck container. If the container is
12 big enough to hold the slides without scaling, no scaling occurs. The user
13 can disable and enable scaling with a keyboard shortcut.
15 Note: CSS transforms may make Flash videos render incorrectly.  Presenters
16 that need to use video may want to disable scaling to play them.  HTML5 video
17 works fine.
19 (function($, undefined) {
20   var $document = $(document);
21   var $window = $(window);
22   var baseHeight, timer, rootSlides;
24   /*
25   Internal function to do all the dirty work of scaling the slides.
26   */
27   var scaleDeck = function() {
28     var options = $.deck('getOptions');
29     var $container = $.deck('getContainer');
30     var baseHeight = options.baseHeight;
32     if (!baseHeight) {
33       baseHeight = $container.height();
34     }
36     // Scale each slide down if necessary (but don't scale up)
37     $.each(rootSlides, function(i, $slide) {
38       var slideHeight = $slide.innerHeight();
39       var $scaler = $slide.find('.' + options.classes.scaleSlideWrapper);
40       var shouldScale = $container.hasClass(options.classes.scale);
41       var scale = shouldScale ? baseHeight / slideHeight : 1;
43       if (scale === 1) {
44         $scaler.css('transform', '');
45       }
46       else {
47         $scaler.css('transform', 'scale(' + scale + ')');
48         window.setTimeout(function() {
49           $container.scrollTop(0)
50         }, 1);
51       }
52     });
53   };
55   var populateRootSlides = function() {
56     var options = $.deck('getOptions');
57     var slideTest = $.map([
58       options.classes.before,
59       options.classes.previous,
60       options.classes.current,
61       options.classes.next,
62       options.classes.after
63     ], function(el, i) {
64       return '.' + el;
65     }).join(', ');
67     rootSlides = [];
68     $.each($.deck('getSlides'), function(i, $slide) {
69       var $parentSlides = $slide.parentsUntil(
70         options.selectors.container,
71         slideTest
72       );
73       if (!$parentSlides.length) {
74         rootSlides.push($slide);
75       }
76     });
77   };
79   var wrapRootSlideContent = function() {
80     var options = $.deck('getOptions');
81     var wrap = '<div class="' + options.classes.scaleSlideWrapper + '"/>';
82     $.each(rootSlides, function(i, $slide) {
83       $slide.children().wrapAll(wrap);
84     });
85   };
87   var scaleOnResizeAndLoad = function() {
88     var options = $.deck('getOptions');
90     $window.unbind('resize.deckscale');
91     $window.bind('resize.deckscale', function() {
92       window.clearTimeout(timer);
93       timer = window.setTimeout(scaleDeck, options.scaleDebounce);
94     });
95     $.deck('enableScale');
96     $window.unbind('load.deckscale');
97     $window.bind('load.deckscale', scaleDeck);
98   };
100   var bindKeyEvents = function() {
101     var options = $.deck('getOptions');
102     $document.unbind('keydown.deckscale');
103     $document.bind('keydown.deckscale', function(event) {
104       var isKey = event.which === options.keys.scale;
105       isKey = isKey || $.inArray(event.which, options.keys.scale) > -1;
106       if (isKey) {
107         $.deck('toggleScale');
108         event.preventDefault();
109       }
110     });
111   };
113   /*
114   Extends defaults/options.
116   options.classes.scale
117     This class is added to the deck container when scaling is enabled.
118     It is enabled by default when the module is included.
120   options.classes.scaleSlideWrapper
121     Scaling is done using a wrapper around the contents of each slide. This
122     class is applied to that wrapper.
124   options.keys.scale
125     The numeric keycode used to toggle enabling and disabling scaling.
127   options.baseHeight
128     When baseHeight is falsy, as it is by default, the deck is scaled in
129     proportion to the height of the deck container. You may instead specify
130     a height as a number of px, and slides will be scaled against this
131     height regardless of the container size.
133   options.scaleDebounce
134     Scaling on the browser resize event is debounced. This number is the
135     threshold in milliseconds. You can learn more about debouncing here:
136     http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
138   */
139   $.extend(true, $.deck.defaults, {
140     classes: {
141       scale: 'deck-scale',
142       scaleSlideWrapper: 'deck-slide-scaler'
143     },
145     keys: {
146       scale: 83 // s
147     },
149     baseHeight: null,
150     scaleDebounce: 200
151   });
153   /*
154   jQuery.deck('disableScale')
156   Disables scaling and removes the scale class from the deck container.
157   */
158   $.deck('extend', 'disableScale', function() {
159     $.deck('getContainer').removeClass($.deck('getOptions').classes.scale);
160     scaleDeck();
161   });
163   /*
164   jQuery.deck('enableScale')
166   Enables scaling and adds the scale class to the deck container.
167   */
168   $.deck('extend', 'enableScale', function() {
169     $.deck('getContainer').addClass($.deck('getOptions').classes.scale);
170     scaleDeck();
171   });
173   /*
174   jQuery.deck('toggleScale')
176   Toggles between enabling and disabling scaling.
177   */
178   $.deck('extend', 'toggleScale', function() {
179     var $container = $.deck('getContainer');
180     var isScaled = $container.hasClass($.deck('getOptions').classes.scale);
181     $.deck(isScaled? 'disableScale' : 'enableScale');
182   });
184   $document.bind('deck.init', function() {
185     populateRootSlides();
186     wrapRootSlideContent();
187     scaleOnResizeAndLoad();
188     bindKeyEvents();
189   });
190 })(jQuery, 'deck', this);