0
|
1 /*!
|
|
2 Deck JS - deck.menu
|
|
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
|
|
7 */
|
|
8
|
|
9 /*
|
|
10 This module adds the methods and key binding to show and hide a menu of all
|
|
11 slides in the deck. The deck menu state is indicated by the presence of a class
|
|
12 on the deck container.
|
|
13 */
|
|
14 (function($, deck, undefined) {
|
|
15 var $d = $(document),
|
|
16 rootSlides; // Array of top level slides
|
|
17
|
|
18 /*
|
|
19 Extends defaults/options.
|
|
20
|
|
21 options.classes.menu
|
|
22 This class is added to the deck container when showing the slide menu.
|
|
23
|
|
24 options.keys.menu
|
|
25 The numeric keycode used to toggle between showing and hiding the slide
|
|
26 menu.
|
|
27
|
|
28 options.touch.doubletapWindow
|
|
29 Two consecutive touch events within this number of milliseconds will
|
|
30 be considered a double tap, and will toggle the menu on touch devices.
|
|
31 */
|
|
32 $.extend(true, $[deck].defaults, {
|
|
33 classes: {
|
|
34 menu: 'deck-menu'
|
|
35 },
|
|
36
|
|
37 keys: {
|
|
38 menu: 77 // m
|
|
39 },
|
|
40
|
|
41 touch: {
|
|
42 doubletapWindow: 400
|
|
43 }
|
|
44 });
|
|
45
|
|
46 /*
|
|
47 jQuery.deck('showMenu')
|
|
48
|
|
49 Shows the slide menu by adding the class specified by the menu class option
|
|
50 to the deck container.
|
|
51 */
|
|
52 $[deck]('extend', 'showMenu', function() {
|
|
53 var $c = $[deck]('getContainer'),
|
|
54 opts = $[deck]('getOptions');
|
|
55
|
|
56 if ($c.hasClass(opts.classes.menu)) return;
|
|
57
|
|
58 // Hide through loading class to short-circuit transitions (perf)
|
|
59 $c.addClass([opts.classes.loading, opts.classes.menu].join(' '));
|
|
60
|
|
61 /* Forced to do this in JS until CSS learns second-grade math. Save old
|
|
62 style value for restoration when menu is hidden. */
|
|
63 if (Modernizr.csstransforms) {
|
|
64 $.each(rootSlides, function(i, $slide) {
|
|
65 $slide.data('oldStyle', $slide.attr('style'));
|
|
66 $slide.css({
|
|
67 'position': 'absolute',
|
|
68 'left': ((i % 4) * 25) + '%',
|
|
69 'top': (Math.floor(i / 4) * 25) + '%'
|
|
70 });
|
|
71 });
|
|
72 }
|
|
73
|
|
74 // Need to ensure the loading class renders first, then remove
|
|
75 window.setTimeout(function() {
|
|
76 $c.removeClass(opts.classes.loading)
|
|
77 .scrollTop($[deck]('getSlide').offset().top);
|
|
78 }, 0);
|
|
79 });
|
|
80
|
|
81 /*
|
|
82 jQuery.deck('hideMenu')
|
|
83
|
|
84 Hides the slide menu by removing the class specified by the menu class
|
|
85 option from the deck container.
|
|
86 */
|
|
87 $[deck]('extend', 'hideMenu', function() {
|
|
88 var $c = $[deck]('getContainer'),
|
|
89 opts = $[deck]('getOptions');
|
|
90
|
|
91 if (!$c.hasClass(opts.classes.menu)) return;
|
|
92
|
|
93 $c.removeClass(opts.classes.menu);
|
|
94 $c.addClass(opts.classes.loading);
|
|
95
|
|
96 /* Restore old style value */
|
|
97 if (Modernizr.csstransforms) {
|
|
98 $.each(rootSlides, function(i, $slide) {
|
|
99 var oldStyle = $slide.data('oldStyle');
|
|
100
|
|
101 $slide.attr('style', oldStyle ? oldStyle : '');
|
|
102 });
|
|
103 }
|
|
104
|
|
105 window.setTimeout(function() {
|
|
106 $c.removeClass(opts.classes.loading).scrollTop(0);
|
|
107 }, 0);
|
|
108 });
|
|
109
|
|
110 /*
|
|
111 jQuery.deck('toggleMenu')
|
|
112
|
|
113 Toggles between showing and hiding the slide menu.
|
|
114 */
|
|
115 $[deck]('extend', 'toggleMenu', function() {
|
|
116 $[deck]('getContainer').hasClass($[deck]('getOptions').classes.menu) ?
|
|
117 $[deck]('hideMenu') : $[deck]('showMenu');
|
|
118 });
|
|
119
|
|
120 $d.bind('deck.init', function() {
|
|
121 var opts = $[deck]('getOptions'),
|
|
122 touchEndTime = 0,
|
|
123 currentSlide,
|
|
124 slideTest = $.map([
|
|
125 opts.classes.before,
|
|
126 opts.classes.previous,
|
|
127 opts.classes.current,
|
|
128 opts.classes.next,
|
|
129 opts.classes.after
|
|
130 ], function(el, i) {
|
|
131 return '.' + el;
|
|
132 }).join(', ');
|
|
133
|
|
134 // Build top level slides array
|
|
135 rootSlides = [];
|
|
136 $.each($[deck]('getSlides'), function(i, $el) {
|
|
137 if (!$el.parentsUntil(opts.selectors.container, slideTest).length) {
|
|
138 rootSlides.push($el);
|
|
139 }
|
|
140 });
|
|
141
|
|
142 // Bind key events
|
|
143 $d.unbind('keydown.deckmenu').bind('keydown.deckmenu', function(e) {
|
|
144 if (e.which === opts.keys.menu || $.inArray(e.which, opts.keys.menu) > -1) {
|
|
145 $[deck]('toggleMenu');
|
|
146 e.preventDefault();
|
|
147 }
|
|
148 });
|
|
149
|
|
150 // Double tap to toggle slide menu for touch devices
|
|
151 $[deck]('getContainer').unbind('touchstart.deckmenu').bind('touchstart.deckmenu', function(e) {
|
|
152 currentSlide = $[deck]('getSlide');
|
|
153 })
|
|
154 .unbind('touchend.deckmenu').bind('touchend.deckmenu', function(e) {
|
|
155 var now = Date.now();
|
|
156
|
|
157 // Ignore this touch event if it caused a nav change (swipe)
|
|
158 if (currentSlide !== $[deck]('getSlide')) return;
|
|
159
|
|
160 if (now - touchEndTime < opts.touch.doubletapWindow) {
|
|
161 $[deck]('toggleMenu');
|
|
162 e.preventDefault();
|
|
163 }
|
|
164 touchEndTime = now;
|
|
165 });
|
|
166
|
|
167 // Selecting slides from the menu
|
|
168 $.each($[deck]('getSlides'), function(i, $s) {
|
|
169 $s.unbind('click.deckmenu').bind('click.deckmenu', function(e) {
|
|
170 if (!$[deck]('getContainer').hasClass(opts.classes.menu)) return;
|
|
171
|
|
172 $[deck]('go', i);
|
|
173 $[deck]('hideMenu');
|
|
174 e.stopPropagation();
|
|
175 e.preventDefault();
|
|
176 });
|
|
177 });
|
|
178 })
|
|
179 .bind('deck.change', function(e, from, to) {
|
|
180 var container = $[deck]('getContainer');
|
|
181
|
|
182 if (container.hasClass($[deck]('getOptions').classes.menu)) {
|
|
183 container.scrollTop($[deck]('getSlide', to).offset().top);
|
|
184 }
|
|
185 });
|
|
186 })(jQuery, 'deck');
|
|
187
|