summaryrefslogtreecommitdiffstats
path: root/doc/backends/deckjs/deck.js/extensions/scale/deck.scale.js
blob: 0e21631880dfdb43d843b32dcf27834376dc2336 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*!
Deck JS - deck.scale
Copyright (c) 2011-2014 Caleb Troughton
Dual licensed under the MIT license.
https://github.com/imakewebthings/deck.js/blob/master/MIT-license.txt
*/

/*
This module adds automatic scaling to the deck.  Slides are scaled down
using CSS transforms to fit within the deck container. If the container is
big enough to hold the slides without scaling, no scaling occurs. The user
can disable and enable scaling with a keyboard shortcut.

Note: CSS transforms may make Flash videos render incorrectly.  Presenters
that need to use video may want to disable scaling to play them.  HTML5 video
works fine.
*/
(function($, undefined) {
  var $document = $(document);
  var $window = $(window);
  var baseHeight, timer, rootSlides;

  /*
  Internal function to do all the dirty work of scaling the slides.
  */
  var scaleDeck = function() {
    var options = $.deck('getOptions');
    var $container = $.deck('getContainer');
    var baseHeight = options.baseHeight;

    if (!baseHeight) {
      baseHeight = $container.height();
    }

    // Scale each slide down if necessary (but don't scale up)
    $.each(rootSlides, function(i, $slide) {
      var slideHeight = $slide.innerHeight();
      var $scaler = $slide.find('.' + options.classes.scaleSlideWrapper);
      var shouldScale = $container.hasClass(options.classes.scale);
      var scale = shouldScale ? baseHeight / slideHeight : 1;

      if (scale === 1) {
        $scaler.css('transform', '');
      }
      else {
        $scaler.css('transform', 'scale(' + scale + ')');
        window.setTimeout(function() {
          $container.scrollTop(0)
        }, 1);
      }
    });
  };

  var populateRootSlides = function() {
    var options = $.deck('getOptions');
    var slideTest = $.map([
      options.classes.before,
      options.classes.previous,
      options.classes.current,
      options.classes.next,
      options.classes.after
    ], function(el, i) {
      return '.' + el;
    }).join(', ');

    rootSlides = [];
    $.each($.deck('getSlides'), function(i, $slide) {
      var $parentSlides = $slide.parentsUntil(
        options.selectors.container,
        slideTest
      );
      if (!$parentSlides.length) {
        rootSlides.push($slide);
      }
    });
  };

  var wrapRootSlideContent = function() {
    var options = $.deck('getOptions');
    var wrap = '<div class="' + options.classes.scaleSlideWrapper + '"/>';
    $.each(rootSlides, function(i, $slide) {
      $slide.children().wrapAll(wrap);
    });
  };

  var scaleOnResizeAndLoad = function() {
    var options = $.deck('getOptions');

    $window.unbind('resize.deckscale');
    $window.bind('resize.deckscale', function() {
      window.clearTimeout(timer);
      timer = window.setTimeout(scaleDeck, options.scaleDebounce);
    });
    $.deck('enableScale');
    $window.unbind('load.deckscale');
    $window.bind('load.deckscale', scaleDeck);
  };

  var bindKeyEvents = function() {
    var options = $.deck('getOptions');
    $document.unbind('keydown.deckscale');
    $document.bind('keydown.deckscale', function(event) {
      var isKey = event.which === options.keys.scale;
      isKey = isKey || $.inArray(event.which, options.keys.scale) > -1;
      if (isKey) {
        $.deck('toggleScale');
        event.preventDefault();
      }
    });
  };

  /*
  Extends defaults/options.

  options.classes.scale
    This class is added to the deck container when scaling is enabled.
    It is enabled by default when the module is included.

  options.classes.scaleSlideWrapper
    Scaling is done using a wrapper around the contents of each slide. This
    class is applied to that wrapper.

  options.keys.scale
    The numeric keycode used to toggle enabling and disabling scaling.

  options.baseHeight
    When baseHeight is falsy, as it is by default, the deck is scaled in
    proportion to the height of the deck container. You may instead specify
    a height as a number of px, and slides will be scaled against this
    height regardless of the container size.

  options.scaleDebounce
    Scaling on the browser resize event is debounced. This number is the
    threshold in milliseconds. You can learn more about debouncing here:
    http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/

  */
  $.extend(true, $.deck.defaults, {
    classes: {
      scale: 'deck-scale',
      scaleSlideWrapper: 'deck-slide-scaler'
    },

    keys: {
      scale: 83 // s
    },

    baseHeight: null,
    scaleDebounce: 200
  });

  /*
  jQuery.deck('disableScale')

  Disables scaling and removes the scale class from the deck container.
  */
  $.deck('extend', 'disableScale', function() {
    $.deck('getContainer').removeClass($.deck('getOptions').classes.scale);
    scaleDeck();
  });

  /*
  jQuery.deck('enableScale')

  Enables scaling and adds the scale class to the deck container.
  */
  $.deck('extend', 'enableScale', function() {
    $.deck('getContainer').addClass($.deck('getOptions').classes.scale);
    scaleDeck();
  });

  /*
  jQuery.deck('toggleScale')

  Toggles between enabling and disabling scaling.
  */
  $.deck('extend', 'toggleScale', function() {
    var $container = $.deck('getContainer');
    var isScaled = $container.hasClass($.deck('getOptions').classes.scale);
    $.deck(isScaled? 'disableScale' : 'enableScale');
  });

  $document.bind('deck.init', function() {
    populateRootSlides();
    wrapRootSlideContent();
    scaleOnResizeAndLoad();
    bindKeyEvents();
  });
})(jQuery, 'deck', this);