The Default demo shows basic Snap.js functionality
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla non erat ac leo ultrices blandit sed vel risus. Pellentesque facilisis blandit auctor. Maecenas vestibulum vulputate tincidunt. Mauris nec quam libero. Fusce eget ligula non leo varius condimentum quis ac elit. Donec id urna ut neque semper ultrices. Proin ut suscipit felis. Nullam neque felis, ullamcorper scelerisque volutpat vel, vehicula vehicula neque. Aenean scelerisque elit ac erat sagittis ullamcorper.
This demo has the menu on the right side disabled
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla non erat ac leo ultrices blandit sed vel risus. Pellentesque facilisis blandit auctor. Maecenas vestibulum vulputate tincidunt. Mauris nec quam libero. Fusce eget ligula non leo varius condimentum quis ac elit. Donec id urna ut neque semper ultrices. Proin ut suscipit felis. Nullam neque felis, ullamcorper scelerisque volutpat vel, vehicula vehicula neque. Aenean scelerisque elit ac erat sagittis ullamcorper.
The Default demo shows basic Snap.js functionality
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla non erat ac leo ultrices blandit sed vel risus. Pellentesque facilisis blandit auctor. Maecenas vestibulum vulputate tincidunt. Mauris nec quam libero. Fusce eget ligula non leo varius condimentum quis ac elit. Donec id urna ut neque semper ultrices. Proin ut suscipit felis. Nullam neque felis, ullamcorper scelerisque volutpat vel, vehicula vehicula neque. Aenean scelerisque elit ac erat sagittis ullamcorper.
You can define the width of your app's sliding space
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla non erat ac leo ultrices blandit sed vel risus. Pellentesque facilisis blandit auctor. Maecenas vestibulum vulputate tincidunt. Mauris nec quam libero. Fusce eget ligula non leo varius condimentum quis ac elit. Donec id urna ut neque semper ultrices. Proin ut suscipit felis. Nullam neque felis, ullamcorper scelerisque volutpat vel, vehicula vehicula neque. Aenean scelerisque elit ac erat sagittis ullamcorper.
The class names demo shows how you can utilize the classess added by Snap.js to adjust hidden content. In this case, we're showing the same menu on both sides of the app via CSS and classess.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla non erat ac leo ultrices blandit sed vel risus. Pellentesque facilisis blandit auctor. Maecenas vestibulum vulputate tincidunt. Mauris nec quam libero. Fusce eget ligula non leo varius condimentum quis ac elit. Donec id urna ut neque semper ultrices. Proin ut suscipit felis. Nullam neque felis, ullamcorper scelerisque volutpat vel, vehicula vehicula neque. Aenean scelerisque elit ac erat sagittis ullamcorper.
Toggles are easy to create. Snap.js gives you the state of the pane and allows you to make decisions simply.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla non erat ac leo ultrices blandit sed vel risus. Pellentesque facilisis blandit auctor. Maecenas vestibulum vulputate tincidunt. Mauris nec quam libero. Fusce eget ligula non leo varius condimentum quis ac elit. Donec id urna ut neque semper ultrices. Proin ut suscipit felis. Nullam neque felis, ullamcorper scelerisque volutpat vel, vehicula vehicula neque. Aenean scelerisque elit ac erat sagittis ullamcorper.
Data attributes can be used to define elements that you want to have prevent sliding of a pane (maybe a photo slider, etc)
38 |Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla non erat ac leo ultrices blandit sed vel risus. Pellentesque facilisis blandit auctor. Maecenas vestibulum vulputate tincidunt. Mauris nec quam libero. Fusce eget ligula non leo varius condimentum quis ac elit. Donec id urna ut neque semper ultrices. Proin ut suscipit felis. Nullam neque felis, ullamcorper scelerisque volutpat vel, vehicula vehicula neque. Aenean scelerisque elit ac erat sagittis ullamcorper.
39 |Data attributes can be used to define elements that you want to have prevent sliding of a pane (maybe a photo slider, etc)
38 |Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla non erat ac leo ultrices blandit sed vel risus. Pellentesque facilisis blandit auctor. Maecenas vestibulum vulputate tincidunt. Mauris nec quam libero. Fusce eget ligula non leo varius condimentum quis ac elit. Donec id urna ut neque semper ultrices. Proin ut suscipit felis. Nullam neque felis, ullamcorper scelerisque volutpat vel, vehicula vehicula neque. Aenean scelerisque elit ac erat sagittis ullamcorper.
39 |Expanding is when the app disappears completely and the entire app's drawer takes up the usable space. Good for searching
42 |Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla non erat ac leo ultrices blandit sed vel risus. Pellentesque facilisis blandit auctor. Maecenas vestibulum vulputate tincidunt. Mauris nec quam libero. Fusce eget ligula non leo varius condimentum quis ac elit. Donec id urna ut neque semper ultrices. Proin ut suscipit felis. Nullam neque felis, ullamcorper scelerisque volutpat vel, vehicula vehicula neque. Aenean scelerisque elit ac erat sagittis ullamcorper.
43 |You can update the settings of an instantiated snap object by calling the settings method.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla non erat ac leo ultrices blandit sed vel risus. Pellentesque facilisis blandit auctor. Maecenas vestibulum vulputate tincidunt. Mauris nec quam libero. Fusce eget ligula non leo varius condimentum quis ac elit. Donec id urna ut neque semper ultrices. Proin ut suscipit felis. Nullam neque felis, ullamcorper scelerisque volutpat vel, vehicula vehicula neque. Aenean scelerisque elit ac erat sagittis ullamcorper.
Thanks for downloading Ratchet. This is an example HTML page that's linked up to compiled Ratchet CSS and JS, has the proper meta tags and the HTML structure. Need some more help before you start filling this with your own content? Check out some Ratchet resorces:
107 |
9 |
10 | * [Features](#features)
11 | * [Support](#support)
12 | * [Installation](#installation)
13 | * [Usage](#usage)
14 | * [Settings & Defaults](#settings-and-defaults)
15 | * [Public Methods](#public-methods)
16 | * [Gotchas](#gotchas)
17 | * [FAQ's](#faq)
18 | * [Compliments](#compliments)
19 | * [Licensing](#licensing)
20 | * [Extras](#extras)
21 |
22 | ## Features
23 | * Library Independent
24 | * High Customization
25 | * Flick Support
26 | * User Intent Detection
27 | * Disable Hyperextension
28 | * Event Hooks
29 | * CSS3 Powered Animations with IE fallbacks
30 | * Drag Support
31 | * Drag Handle Support
32 | * Programatic API
33 | * "No-Drag" Elements
34 | * Definable Easing Mode
35 | * Enable/Disable Events
36 | * Disabled Sides (left or right)
37 | * Supports [Ratchet](http://maker.github.com/ratchet/) (with templates!)
38 |
39 | ## Support
40 | * Firefox 10+
41 | * Wide Webkit Support (including Android WebKit 2.3.X)
42 | * IE 10
43 | * IE 9 Supports Toggling, Dragging but no Transitions
44 | * IE 7/8 Supports Toggling but no dragging or Transitions
45 |
46 | ## Installation
47 |
48 | As standalone just include the file in a script tag:
49 |
50 | ```html
51 |
52 | ```
53 |
54 | As a web component do:
55 |
56 | ```shell
57 | $ component install jakiestfu/Snap.js
58 | ```
59 |
60 | ## Usage
61 |
62 | ```javascript
63 | var snapper = new Snap({
64 | element: document.getElementById('content')
65 | });
66 | ```
67 |
68 | ## Settings and Defaults
69 | ```javascript
70 | settings = {
71 | element: null,
72 | dragger: null,
73 | disable: 'none',
74 | addBodyClasses: true,
75 | hyperextensible: true,
76 | resistance: 0.5,
77 | flickThreshold: 50,
78 | transitionSpeed: 0.3,
79 | easing: 'ease',
80 | maxPosition: 266,
81 | minPosition: -266,
82 | tapToClose: true,
83 | touchToDrag: true,
84 | slideIntent: 40,
85 | minDragDistance: 5
86 | }
87 | ```
88 |
89 | * `element`: The element which the user will be sliding side to side
90 | * `dragger`: The element which the user will be using to slide the target element side to side
91 | * `disable`: String, set to 'left' or 'right' to disable the respective side
92 | * `addBodyClasses`: Add classes to the body to signify which side is being opened
93 | * `hyperextensible`: If false, pane may not be slide past the minPosition and maxPosition
94 | * `resistance`: The cooeficcient used to slow sliding when user has passed max or min threshold
95 | * `flickThreshold`: Number of pixels the user needs to swiftly travel to activate a "flick" open
96 | * `transitionSpeed`: The speed at which the pane slides open or closed
97 | * `easing`: The CSS3 Easing method you want to use for transitions
98 | * `maxPosition`: Maximum number of pixels the pane may be slid to the right
99 | * `minPosition`: Maximum number of pixels the pane may be slid to the left
100 | * `tapToClose`: If true, tapping an open pane will close it
101 | * `touchToDrag`: If true, dragging the target `settings.element` will open/close the pane
102 | * `minDragDistance`: The minimum amount of pixels the user needs to drag within the `slideIntent` degrees to move the pane
103 | * `slideIntent`: The number of degrees the user must initiate sliding in towards the left or right (see diagram below)
104 |
105 | Notes on Slide Intent: The slide intent is an int between 0 and 90, and represents the degrees in the first quadrant of a circle that you would like to have mirrored on the X *and* Y axis. For example, if you have 40 set as your `slideIntent` value, the user would only be able to slide the pane by dragging in the blue area in the diagram below. Once intent has been defined, it will not change until the user releases.
106 |
107 |
108 |
109 |
110 | ## Public Methods
111 |
112 | ### `open`: Opens the pane to the specified side
113 |
114 | ```javascript
115 | snapper.open('left');
116 | // OR
117 | snapper.open('right');
118 | ```
119 |
120 | ### `close`: Closes the pane
121 |
122 | ```javascript
123 | snapper.close();
124 | ```
125 |
126 | ### `expand`: Opens the pane entirely
127 |
128 | ```javascript
129 | snapper.expand('left');
130 | // OR
131 | snapper.expand('right');
132 | ```
133 |
134 | ### `disable`: Disables sliding events
135 |
136 | ```javascript
137 | snapper.disable();
138 | ```
139 |
140 | ### `enable`: Enables sliding events after disabling
141 |
142 | ```javascript
143 | snapper.enable();
144 | ```
145 |
146 | ### `on`: Adds an event hook
147 |
148 | ```javascript
149 | snapper.on('start', function(){
150 | // Do Something
151 | });
152 | ```
153 | The available methods to hook into are as follows:
154 |
155 | * `start`: Fired when touching down on the draggable pane and it begins to move
156 | * `drag`: Fired when the pane has been moved or slid
157 | * `end`: Fired when the pane has been let go of
158 | * `animating`: Fired when the pane is animating
159 | * `animated`: Fired when the pane is finished it's animations
160 | * `ignore`: Fired when trying to drag the pane but ended up dragging on an ignored element
161 | * `close`: Fired when close is called directly or if tapToClose is set to true
162 | * `open`: Fired when the menu is opened
163 | * `expandLeft`: Fired on expand('left')
164 | * `expandRight`: Fired on expand('right')
165 | * `enable`: Fired on enable
166 | * `disable`: Fired on disable
167 |
168 | ### `off`: Removes an event hook
169 |
170 | ```javascript
171 | snapper.off('drag');
172 | ```
173 | The event names listed above apply for the `off` method.
174 |
175 |
176 | ### `settings`: Updates the settings for an already instantiated object
177 | ```javascript
178 | snapper.settings({yourSettings});
179 | ```
180 | Currently, `settings.element`, `settings.touchToDrag` cannot be updated. To update the element, instantiate a new object. To allow listening to a drag, use `snapper.enable()`
181 |
182 | ### `state`: Returns detailed information about the state of the pane
183 |
184 | ```javascript
185 | var data = snapper.state();
186 | ```
187 | The data returned from the `state` method will look like the following:
188 |
189 | ```javascript
190 | {
191 | state: "closed", // State of the Pane
192 | info:{
193 | opening: "left", // Side which user intends to open
194 | towards: "right", // Direction user is dragging towards
195 | hyperExtending: false, // True if user is pulling past predefined bounds
196 | halfway: false, // True if pane is at least halfway open
197 | flick: false, // True if user has moved pane X amount of pixels in the open/close direction without changing directions
198 | translation:{
199 | absolute: 20, // Pixels pane has translated
200 | relative: 21, // Pixels pane has translated relative to starting translation
201 | sinceDirectionChange: 10, // Pixels pane has translated since the direction of the pane has changed
202 | percentage: 40.571649 // The percentage that the Pane is open. Good or animating other things
203 | }
204 | }
205 | }
206 | ```
207 |
208 | ## Gotchas
209 |
210 | ### Layout
211 | The layout itself is what most people will have a hard time emulating, so the simplest approach I have found is as follows:
212 |
213 | Two absolute elements, one to represent *all* the content, and another to represent *all* the drawers. The content has a higher z-index than the drawers. Within the drawers element, it's direct children should represent the containers for the drawers, these should be `fixed` or `absolute`. Assigning classes to your drawers to specify which side it is on is recommended. All absolutely positioned elements should have 0 for `top, left, right, bottom` properties, excluding your panes which will have `auto` set to their respective sides and a width assigned. The width of your drawers is usually the same number you want to use for `minPosition` and `maxPosition`
214 |
215 | ```html
216 | div.drawers {position: absolute;}
217 | div.left-drawer {position: absolute;}
218 | [content]
219 | div.right-drawer {position: absolute;}
220 | [content]
221 | div#content {position: absolute;}
222 | [top-bars]
223 | [content] {overflow: auto}
224 | [bottom-bars]
225 | ```
226 |
227 | A sample layout is found in demo/apps/default.html.
228 |
229 | ### Independent Scrolling
230 | Some CSS is required to get some smooth ass scrolling. Utilize the CSS below to apply this to any of your elements:
231 | ```css
232 | .scrollable{
233 | overflow: auto;
234 | -webkit-transition-property: top, bottom;
235 | transition-property: top, bottom;
236 | -webkit-transition-duration: .2s, .2s;
237 | transition-duration: .2s, .2s;
238 | -webkit-transition-timing-function: linear, linear;
239 | transition-timing-function: linear, linear;
240 | -webkit-overflow-scrolling: touch;
241 | }
242 | ```
243 |
244 | ### Z-Indeces and Display
245 | Because of the nature of this code, drawers are just kind of stacked behind the content. To bring the proper drawer to the front, you can hook into Snaps.js' CSS classes:
246 |
247 | With `addBodyClasses` set to `true` in your initialize options, one of the two classess will be added to the body tag: `.snapjs-left` or `.snapjs-right`, depending on which pane is being open, respectively. This being said, you can apply your CSS like the following to show the proper drawers:
248 |
249 | ```css
250 | .snapjs-right .left-drawer,
251 | .snapjs-left .right-drawer {
252 | display: none;
253 | }
254 | ```
255 |
256 | ## FAQ
257 |
258 | ### - How do I make a toggle button?
259 | Toggles have been a popular request, but rather than bog the library down with additional methods, you can utilize the powerful API of Snap.js to create your own toggle. Toggles can be done like the following:
260 |
261 | ```javascript
262 | myToggleButton.addEventListener('click', function(){
263 |
264 | if( snapper.state().state=="left" ){
265 | snapper.close();
266 | } else {
267 | snapper.open('left');
268 | }
269 |
270 | });
271 | ```
272 |
273 | ### - How do I disable Snap.js dragging for my touch slider?
274 | Snap.js supports cascading cancellation of events via a data attribute `data-snap-ignore`. If you were to use a slider, your markup might look like the following:
275 |
276 | ```html
277 |
286 | ```
287 |
288 | All interactions on children elements of the element with the `data-snap-ignore` attribute will have their Snap.js events ignored.
289 |
290 |
291 | ### - I am using Push.js from Ratchet, I keep losing my events on my elements, how can I fix this?
292 | Simple. As wack as Push.js is (yes, it is in desperate need of attention as of v1.0.0), we can still solve this problem with it's only callback, `'push'`.
293 |
294 | ```javascript
295 | // The function that will initialize your Snap.js instance
296 | var doSnap = function(){
297 | if(window.snapper){
298 | // Snap.js already exists, we just need to re-bind events
299 | window.snapper.enable();
300 | } else {
301 | // Initialize Snap.js
302 | window.snapper = new Snap({
303 | element: document.getElementById('content')
304 | });
305 | }
306 | };
307 |
308 | window.addEventListener('push', doSnap);
309 | doSnap();
310 | ```
311 |
312 | ### - Snap.js works on my Android device but i cannot scroll the content in my drawers, what gives?
313 | Older Android devices (and iPhone as well) do not have native support for overflow scrolling. To solve this, you may use the wonderful library called [iScroll](https://github.com/cubiq/iscroll)
314 |
315 | ### - `transform: translate3d()` breaks my fixed child elements, how can I solve this?
316 | [This is a problem with Chromium](https://code.google.com/p/chromium/issues/detail?id=20574) and should be fixed soon. I would advise not having your direct children element set to fixed, that may possibly solve your problem.
317 |
318 | ### - I am experiencing a weird flicker when the CSS transform is applied
319 | To solve the flicker, apply the following CSS to the element in question
320 | ```css
321 | #content{
322 | backface-visibility:hidden;
323 | -webkit-backface-visibility:hidden; /* Chrome and Safari */
324 | -moz-backface-visibility:hidden; /* Firefox */
325 | -ms-backface-visibility:hidden; /* Internet Explorer 10+ */
326 | }
327 | ```
328 |
329 | ## Compliments
330 |
331 | This code attempts to make your webapp's feel more "native". These other repos go well with it, too!
332 |
333 | * [Snap.js](https://github.com/jakiestfu/Snap.js)
334 | * [AppScroll.js](https://github.com/jakiestfu/AppScroll)
335 | * [fastclick](https://github.com/ftlabs/fastclick)
336 |
337 | ## Licensing
338 |
339 | MIT, dawg
340 |
--------------------------------------------------------------------------------
/demo/apps/ratchet/ratchet.js:
--------------------------------------------------------------------------------
1 | /**
2 | * ==================================
3 | * Ratchet v1.0.0
4 | * Licensed under The MIT License
5 | * http://opensource.org/licenses/MIT
6 | * ==================================
7 | */
8 |
9 | /* ----------------------------------
10 | * POPOVER v1.0.0
11 | * Licensed under The MIT License
12 | * http://opensource.org/licenses/MIT
13 | * ---------------------------------- */
14 |
15 | !function () {
16 |
17 | var popover;
18 |
19 | var findPopovers = function (target) {
20 | var i, popovers = document.querySelectorAll('a');
21 | for (; target && target !== document; target = target.parentNode) {
22 | for (i = popovers.length; i--;) { if (popovers[i] === target) return target; }
23 | }
24 | };
25 |
26 | var onPopoverHidden = function () {
27 | document.body.removeChild(backdrop);
28 | popover.style.display = 'none';
29 | popover.removeEventListener('webkitTransitionEnd', onPopoverHidden);
30 | }
31 |
32 | var backdrop = function () {
33 | var element = document.createElement('div');
34 |
35 | element.classList.add('backdrop');
36 |
37 | element.addEventListener('touchend', function () {
38 | popover.addEventListener('webkitTransitionEnd', onPopoverHidden);
39 | popover.classList.remove('visible');
40 | });
41 |
42 | return element;
43 | }();
44 |
45 | var getPopover = function (e) {
46 | var anchor = findPopovers(e.target);
47 |
48 | if (!anchor || !anchor.hash) return;
49 |
50 | popover = document.querySelector(anchor.hash);
51 |
52 | if (!popover || !popover.classList.contains('popover')) return;
53 |
54 | return popover;
55 | }
56 |
57 | window.addEventListener('touchend', function (e) {
58 | var popover = getPopover(e);
59 |
60 | if (!popover) return;
61 |
62 | popover.style.display = 'block';
63 | popover.offsetHeight;
64 | popover.classList.add('visible');
65 |
66 | popover.parentNode.appendChild(backdrop);
67 | });
68 |
69 | window.addEventListener('click', function (e) { if (getPopover(e)) e.preventDefault(); });
70 |
71 | }();
72 | /* ----------------------------------
73 | * PUSH v1.0.0
74 | * Licensed under The MIT License
75 | * inspired by chris's jquery.pjax.js
76 | * http://opensource.org/licenses/MIT
77 | * ---------------------------------- */
78 |
79 | !function () {
80 |
81 | var noop = function () {};
82 |
83 |
84 | // Pushstate cacheing
85 | // ==================
86 |
87 | var isScrolling;
88 | var maxCacheLength = 20;
89 | var cacheMapping = sessionStorage;
90 | var domCache = {};
91 | var transitionMap = {
92 | 'slide-in' : 'slide-out',
93 | 'slide-out' : 'slide-in',
94 | 'fade' : 'fade'
95 | };
96 | var bars = {
97 | bartab : '.bar-tab',
98 | bartitle : '.bar-title',
99 | barfooter : '.bar-footer',
100 | barheadersecondary : '.bar-header-secondary'
101 | }
102 |
103 | var cacheReplace = function (data, updates) {
104 | PUSH.id = data.id;
105 | if (updates) data = getCached(data.id);
106 | cacheMapping[data.id] = JSON.stringify(data);
107 | window.history.replaceState(data.id, data.title, data.url);
108 | domCache[data.id] = document.body.cloneNode(true);
109 | };
110 |
111 | var cachePush = function () {
112 | var id = PUSH.id;
113 |
114 | var cacheForwardStack = JSON.parse(cacheMapping.cacheForwardStack || '[]');
115 | var cacheBackStack = JSON.parse(cacheMapping.cacheBackStack || '[]');
116 |
117 | cacheBackStack.push(id);
118 |
119 | while (cacheForwardStack.length) delete cacheMapping[cacheForwardStack.shift()];
120 | while (cacheBackStack.length > maxCacheLength) delete cacheMapping[cacheBackStack.shift()];
121 |
122 | window.history.pushState(null, '', cacheMapping[PUSH.id].url);
123 |
124 | cacheMapping.cacheForwardStack = JSON.stringify(cacheForwardStack);
125 | cacheMapping.cacheBackStack = JSON.stringify(cacheBackStack);
126 | };
127 |
128 | var cachePop = function (id, direction) {
129 | var forward = direction == 'forward';
130 | var cacheForwardStack = JSON.parse(cacheMapping.cacheForwardStack || '[]');
131 | var cacheBackStack = JSON.parse(cacheMapping.cacheBackStack || '[]');
132 | var pushStack = forward ? cacheBackStack : cacheForwardStack;
133 | var popStack = forward ? cacheForwardStack : cacheBackStack;
134 |
135 | if (PUSH.id) pushStack.push(PUSH.id);
136 | popStack.pop();
137 |
138 | cacheMapping.cacheForwardStack = JSON.stringify(cacheForwardStack);
139 | cacheMapping.cacheBackStack = JSON.stringify(cacheBackStack);
140 | };
141 |
142 | var getCached = function (id) {
143 | return JSON.parse(cacheMapping[id] || null) || {};
144 | };
145 |
146 | var getTarget = function (e) {
147 | var target = findTarget(e.target);
148 |
149 | if (
150 | ! target
151 | || e.which > 1
152 | || e.metaKey
153 | || e.ctrlKey
154 | || isScrolling
155 | || location.protocol !== target.protocol
156 | || location.host !== target.host
157 | || !target.hash && /#/.test(target.href)
158 | || target.hash && target.href.replace(target.hash, '') === location.href.replace(location.hash, '')
159 | || target.getAttribute('data-ignore') == 'push'
160 | ) return;
161 |
162 | return target;
163 | };
164 |
165 |
166 | // Main event handlers (touchend, popstate)
167 | // ==========================================
168 |
169 | var touchend = function (e) {
170 | var target = getTarget(e);
171 |
172 | if (!target) return;
173 |
174 | e.preventDefault();
175 |
176 | PUSH({
177 | url : target.href,
178 | hash : target.hash,
179 | timeout : target.getAttribute('data-timeout'),
180 | transition : target.getAttribute('data-transition')
181 | });
182 | };
183 |
184 | var popstate = function (e) {
185 | var key;
186 | var barElement;
187 | var activeObj;
188 | var activeDom;
189 | var direction;
190 | var transition;
191 | var transitionFrom;
192 | var transitionFromObj;
193 | var id = e.state;
194 |
195 | if (!id || !cacheMapping[id]) return;
196 |
197 | direction = PUSH.id < id ? 'forward' : 'back';
198 |
199 | cachePop(id, direction);
200 |
201 | activeObj = getCached(id);
202 | activeDom = domCache[id];
203 |
204 | if (activeObj.title) document.title = activeObj.title;
205 |
206 | if (direction == 'back') {
207 | transitionFrom = JSON.parse(direction == 'back' ? cacheMapping.cacheForwardStack : cacheMapping.cacheBackStack);
208 | transitionFromObj = getCached(transitionFrom[transitionFrom.length - 1]);
209 | } else {
210 | transitionFromObj = activeObj;
211 | }
212 |
213 | if (direction == 'back' && !transitionFromObj.id) return PUSH.id = id;
214 |
215 | transition = direction == 'back' ? transitionMap[transitionFromObj.transition] : transitionFromObj.transition;
216 |
217 | if (!activeDom) {
218 | return PUSH({
219 | id : activeObj.id,
220 | url : activeObj.url,
221 | title : activeObj.title,
222 | timeout : activeObj.timeout,
223 | transition : transition,
224 | ignorePush : true
225 | });
226 | }
227 |
228 | if (transitionFromObj.transition) {
229 | activeObj = extendWithDom(activeObj, '.content', activeDom.cloneNode(true));
230 | for (key in bars) {
231 | barElement = document.querySelector(bars[key])
232 | if (activeObj[key]) swapContent(activeObj[key], barElement);
233 | else if (barElement) barElement.parentNode.removeChild(barElement);
234 | }
235 | }
236 |
237 | swapContent(
238 | (activeObj.contents || activeDom).cloneNode(true),
239 | document.querySelector('.content'),
240 | transition
241 | );
242 |
243 | PUSH.id = id;
244 |
245 | document.body.offsetHeight; // force reflow to prevent scroll
246 | };
247 |
248 |
249 | // Core PUSH functionality
250 | // =======================
251 |
252 | var PUSH = function (options) {
253 | var key;
254 | var data = {};
255 | var xhr = PUSH.xhr;
256 |
257 | options.container = options.container || options.transition ? document.querySelector('.content') : document.body;
258 |
259 | for (key in bars) {
260 | options[key] = options[key] || document.querySelector(bars[key]);
261 | }
262 |
263 | if (xhr && xhr.readyState < 4) {
264 | xhr.onreadystatechange = noop;
265 | xhr.abort()
266 | }
267 |
268 | xhr = new XMLHttpRequest();
269 | xhr.open('GET', options.url, true);
270 | xhr.setRequestHeader('X-PUSH', 'true');
271 |
272 | xhr.onreadystatechange = function () {
273 | if (options._timeout) clearTimeout(options._timeout);
274 | if (xhr.readyState == 4) xhr.status == 200 ? success(xhr, options) : failure(options.url);
275 | };
276 |
277 | if (!PUSH.id) {
278 | cacheReplace({
279 | id : +new Date,
280 | url : window.location.href,
281 | title : document.title,
282 | timeout : options.timeout,
283 | transition : null
284 | });
285 | }
286 |
287 | if (options.timeout) {
288 | options._timeout = setTimeout(function () { xhr.abort('timeout'); }, options.timeout);
289 | }
290 |
291 | xhr.send();
292 |
293 | if (xhr.readyState && !options.ignorePush) cachePush();
294 | };
295 |
296 |
297 | // Main XHR handlers
298 | // =================
299 |
300 | var success = function (xhr, options) {
301 | var key;
302 | var barElement;
303 | var data = parseXHR(xhr, options);
304 |
305 | if (!data.contents) return locationReplace(options.url);
306 |
307 | if (data.title) document.title = data.title;
308 |
309 | if (options.transition) {
310 | for (key in bars) {
311 | barElement = document.querySelector(bars[key])
312 | if (data[key]) swapContent(data[key], barElement);
313 | else if (barElement) barElement.parentNode.removeChild(barElement);
314 | }
315 | }
316 |
317 | swapContent(data.contents, options.container, options.transition, function () {
318 | cacheReplace({
319 | id : options.id || +new Date,
320 | url : data.url,
321 | title : data.title,
322 | timeout : options.timeout,
323 | transition : options.transition
324 | }, options.id);
325 | triggerStateChange();
326 | });
327 |
328 | if (!options.ignorePush && window._gaq) _gaq.push(['_trackPageview']) // google analytics
329 | if (!options.hash) return;
330 | };
331 |
332 | var failure = function (url) {
333 | throw new Error('Could not get: ' + url)
334 | };
335 |
336 |
337 | // PUSH helpers
338 | // ============
339 |
340 | var swapContent = function (swap, container, transition, complete) {
341 | var enter;
342 | var containerDirection;
343 | var swapDirection;
344 |
345 | if (!transition) {
346 | if (container) container.innerHTML = swap.innerHTML;
347 | else if (swap.classList.contains('content')) document.body.appendChild(swap);
348 | else document.body.insertBefore(swap, document.querySelector('.content'));
349 | } else {
350 | enter = /in$/.test(transition);
351 |
352 | if (transition == 'fade') {
353 | container.classList.add('in');
354 | container.classList.add('fade');
355 | swap.classList.add('fade');
356 | }
357 |
358 | if (/slide/.test(transition)) {
359 | swap.classList.add(enter ? 'right' : 'left');
360 | swap.classList.add('slide');
361 | container.classList.add('slide');
362 | }
363 |
364 | container.parentNode.insertBefore(swap, container);
365 | }
366 |
367 | if (!transition) complete && complete();
368 |
369 | if (transition == 'fade') {
370 | container.offsetWidth; // force reflow
371 | container.classList.remove('in');
372 | container.addEventListener('webkitTransitionEnd', fadeContainerEnd);
373 |
374 | function fadeContainerEnd() {
375 | container.removeEventListener('webkitTransitionEnd', fadeContainerEnd);
376 | swap.classList.add('in');
377 | swap.addEventListener('webkitTransitionEnd', fadeSwapEnd);
378 | }
379 | function fadeSwapEnd () {
380 | swap.removeEventListener('webkitTransitionEnd', fadeSwapEnd);
381 | container.parentNode.removeChild(container);
382 | swap.classList.remove('fade');
383 | swap.classList.remove('in');
384 | complete && complete();
385 | }
386 | }
387 |
388 | if (/slide/.test(transition)) {
389 | container.offsetWidth; // force reflow
390 | swapDirection = enter ? 'right' : 'left'
391 | containerDirection = enter ? 'left' : 'right'
392 | container.classList.add(containerDirection);
393 | swap.classList.remove(swapDirection);
394 | swap.addEventListener('webkitTransitionEnd', slideEnd);
395 |
396 | function slideEnd() {
397 | swap.removeEventListener('webkitTransitionEnd', slideEnd);
398 | swap.classList.remove('slide');
399 | swap.classList.remove(swapDirection);
400 | container.parentNode.removeChild(container);
401 | complete && complete();
402 | }
403 | }
404 | };
405 |
406 | var triggerStateChange = function () {
407 | var e = new CustomEvent('push', {
408 | detail: { state: getCached(PUSH.id) },
409 | bubbles: true,
410 | cancelable: true
411 | });
412 |
413 | window.dispatchEvent(e);
414 | };
415 |
416 | var findTarget = function (target) {
417 | var i, toggles = document.querySelectorAll('a');
418 | for (; target && target !== document; target = target.parentNode) {
419 | for (i = toggles.length; i--;) { if (toggles[i] === target) return target; }
420 | }
421 | };
422 |
423 | var locationReplace = function (url) {
424 | window.history.replaceState(null, '', '#');
425 | window.location.replace(url);
426 | };
427 |
428 | var parseURL = function (url) {
429 | var a = document.createElement('a'); a.href = url; return a;
430 | };
431 |
432 | var extendWithDom = function (obj, fragment, dom) {
433 | var i;
434 | var result = {};
435 |
436 | for (i in obj) result[i] = obj[i];
437 |
438 | Object.keys(bars).forEach(function (key) {
439 | var el = dom.querySelector(bars[key]);
440 | if (el) el.parentNode.removeChild(el);
441 | result[key] = el;
442 | });
443 |
444 | result.contents = dom.querySelector(fragment);
445 |
446 | return result;
447 | };
448 |
449 | var parseXHR = function (xhr, options) {
450 | var head;
451 | var body;
452 | var data = {};
453 | var responseText = xhr.responseText;
454 |
455 | data.url = options.url;
456 |
457 | if (!responseText) return data;
458 |
459 | if (/]*>([\s\S.]*)<\/head>/i)[0]
463 | body.innerHTML = responseText.match(/]*>([\s\S.]*)<\/body>/i)[0]
464 | } else {
465 | head = body = document.createElement('div');
466 | head.innerHTML = responseText;
467 | }
468 |
469 | data.title = head.querySelector('title');
470 | data.title = data.title && data.title.innerText.trim();
471 |
472 | if (options.transition) data = extendWithDom(data, '.content', body);
473 | else data.contents = body;
474 |
475 | return data;
476 | };
477 |
478 |
479 | // Attach PUSH event handlers
480 | // ==========================
481 |
482 | window.addEventListener('touchstart', function () { isScrolling = false; });
483 | window.addEventListener('touchmove', function () { isScrolling = true; })
484 | window.addEventListener('touchend', touchend);
485 | window.addEventListener('click', function (e) { if (getTarget(e)) e.preventDefault(); });
486 | window.addEventListener('popstate', popstate);
487 |
488 | }();/* ----------------------------------
489 | * TABS v1.0.0
490 | * Licensed under The MIT License
491 | * http://opensource.org/licenses/MIT
492 | * ---------------------------------- */
493 |
494 | !function () {
495 | var getTarget = function (target) {
496 | var i, popovers = document.querySelectorAll('.segmented-controller li a');
497 | for (; target && target !== document; target = target.parentNode) {
498 | for (i = popovers.length; i--;) { if (popovers[i] === target) return target; }
499 | }
500 | };
501 |
502 | window.addEventListener("touchend", function (e) {
503 | var activeTab;
504 | var activeBody;
505 | var targetBody;
506 | var targetTab;
507 | var className = 'active';
508 | var classSelector = '.' + className;
509 | var targetAnchor = getTarget(e.target);
510 |
511 | if (!targetAnchor) return;
512 |
513 | targetTab = targetAnchor.parentNode;
514 | activeTab = targetTab.parentNode.querySelector(classSelector);
515 |
516 | if (activeTab) activeTab.classList.remove(className);
517 |
518 | targetTab.classList.add(className);
519 |
520 | if (!targetAnchor.hash) return;
521 |
522 | targetBody = document.querySelector(targetAnchor.hash);
523 |
524 | if (!targetBody) return;
525 |
526 | activeBody = targetBody.parentNode.querySelector(classSelector);
527 |
528 | if (activeBody) activeBody.classList.remove(className);
529 |
530 | targetBody.classList.add(className)
531 | });
532 |
533 | window.addEventListener('click', function (e) { if (getTarget(e.target)) e.preventDefault(); });
534 | }();/* ----------------------------------
535 | * SLIDER v1.0.0
536 | * Licensed under The MIT License
537 | * Adapted from Brad Birdsall's swipe
538 | * http://opensource.org/licenses/MIT
539 | * ---------------------------------- */
540 |
541 | !function () {
542 |
543 | var pageX;
544 | var pageY;
545 | var slider;
546 | var deltaX;
547 | var deltaY;
548 | var offsetX;
549 | var lastSlide;
550 | var startTime;
551 | var resistance;
552 | var sliderWidth;
553 | var slideNumber;
554 | var isScrolling;
555 | var scrollableArea;
556 |
557 | var getSlider = function (target) {
558 | var i, sliders = document.querySelectorAll('.slider ul');
559 | for (; target && target !== document; target = target.parentNode) {
560 | for (i = sliders.length; i--;) { if (sliders[i] === target) return target; }
561 | }
562 | }
563 |
564 | var getScroll = function () {
565 | var translate3d = slider.style.webkitTransform.match(/translate3d\(([^,]*)/);
566 | return parseInt(translate3d ? translate3d[1] : 0)
567 | };
568 |
569 | var setSlideNumber = function (offset) {
570 | var round = offset ? (deltaX < 0 ? 'ceil' : 'floor') : 'round';
571 | slideNumber = Math[round](getScroll() / ( scrollableArea / slider.children.length) );
572 | slideNumber += offset;
573 | slideNumber = Math.min(slideNumber, 0);
574 | slideNumber = Math.max(-(slider.children.length - 1), slideNumber);
575 | }
576 |
577 | var onTouchStart = function (e) {
578 | slider = getSlider(e.target);
579 |
580 | if (!slider) return;
581 |
582 | var firstItem = slider.querySelector('li');
583 |
584 | scrollableArea = firstItem.offsetWidth * slider.children.length;
585 | isScrolling = undefined;
586 | sliderWidth = slider.offsetWidth;
587 | resistance = 1;
588 | lastSlide = -(slider.children.length - 1);
589 | startTime = +new Date;
590 | pageX = e.touches[0].pageX;
591 | pageY = e.touches[0].pageY;
592 |
593 | setSlideNumber(0);
594 |
595 | slider.style['-webkit-transition-duration'] = 0;
596 | };
597 |
598 | var onTouchMove = function (e) {
599 | if (e.touches.length > 1 || !slider) return; // Exit if a pinch || no slider
600 |
601 | deltaX = e.touches[0].pageX - pageX;
602 | deltaY = e.touches[0].pageY - pageY;
603 | pageX = e.touches[0].pageX;
604 | pageY = e.touches[0].pageY;
605 |
606 | if (typeof isScrolling == 'undefined') {
607 | isScrolling = Math.abs(deltaY) > Math.abs(deltaX);
608 | }
609 |
610 | if (isScrolling) return;
611 |
612 | offsetX = (deltaX / resistance) + getScroll();
613 |
614 | e.preventDefault();
615 |
616 | resistance = slideNumber == 0 && deltaX > 0 ? (pageX / sliderWidth) + 1.25 :
617 | slideNumber == lastSlide && deltaX < 0 ? (Math.abs(pageX) / sliderWidth) + 1.25 : 1;
618 |
619 | slider.style.webkitTransform = 'translate3d(' + offsetX + 'px,0,0)';
620 | };
621 |
622 | var onTouchEnd = function (e) {
623 | if (!slider || isScrolling) return;
624 |
625 | setSlideNumber(
626 | (+new Date) - startTime < 1000 && Math.abs(deltaX) > 15 ? (deltaX < 0 ? -1 : 1) : 0
627 | );
628 |
629 | offsetX = slideNumber * sliderWidth;
630 |
631 | slider.style['-webkit-transition-duration'] = '.2s';
632 | slider.style.webkitTransform = 'translate3d(' + offsetX + 'px,0,0)';
633 |
634 | e = new CustomEvent('slide', {
635 | detail: { slideNumber: Math.abs(slideNumber) },
636 | bubbles: true,
637 | cancelable: true
638 | });
639 |
640 | slider.parentNode.dispatchEvent(e);
641 | };
642 |
643 | window.addEventListener('touchstart', onTouchStart);
644 | window.addEventListener('touchmove', onTouchMove);
645 | window.addEventListener('touchend', onTouchEnd);
646 |
647 | }();
648 | /* ----------------------------------
649 | * TOGGLE v1.0.0
650 | * Licensed under The MIT License
651 | * http://opensource.org/licenses/MIT
652 | * ---------------------------------- */
653 |
654 | !function () {
655 |
656 | var start = {};
657 | var touchMove = false;
658 | var distanceX = false;
659 | var toggle = false;
660 |
661 | var findToggle = function (target) {
662 | var i, toggles = document.querySelectorAll('.toggle');
663 | for (; target && target !== document; target = target.parentNode) {
664 | for (i = toggles.length; i--;) { if (toggles[i] === target) return target; }
665 | }
666 | }
667 |
668 | window.addEventListener('touchstart', function (e) {
669 | e = e.originalEvent || e;
670 |
671 | toggle = findToggle(e.target);
672 |
673 | if (!toggle) return;
674 |
675 | var handle = toggle.querySelector('.toggle-handle');
676 | var toggleWidth = toggle.offsetWidth;
677 | var handleWidth = handle.offsetWidth;
678 | var offset = toggle.classList.contains('active') ? toggleWidth - handleWidth : 0;
679 |
680 | start = { pageX : e.touches[0].pageX - offset, pageY : e.touches[0].pageY };
681 | touchMove = false;
682 |
683 | // todo: probably should be moved to the css
684 | toggle.style['-webkit-transition-duration'] = 0;
685 | });
686 |
687 | window.addEventListener('touchmove', function (e) {
688 | e = e.originalEvent || e;
689 |
690 | if (e.touches.length > 1) return; // Exit if a pinch
691 |
692 | if (!toggle) return;
693 |
694 | var handle = toggle.querySelector('.toggle-handle');
695 | var current = e.touches[0];
696 | var toggleWidth = toggle.offsetWidth;
697 | var handleWidth = handle.offsetWidth;
698 | var offset = toggleWidth - handleWidth;
699 |
700 | touchMove = true;
701 | distanceX = current.pageX - start.pageX;
702 |
703 | if (Math.abs(distanceX) < Math.abs(current.pageY - start.pageY)) return;
704 |
705 | e.preventDefault();
706 |
707 | if (distanceX < 0) return handle.style.webkitTransform = 'translate3d(0,0,0)';
708 | if (distanceX > offset) return handle.style.webkitTransform = 'translate3d(' + offset + 'px,0,0)';
709 |
710 | handle.style.webkitTransform = 'translate3d(' + distanceX + 'px,0,0)';
711 |
712 | toggle.classList[(distanceX > (toggleWidth/2 - handleWidth/2)) ? 'add' : 'remove']('active');
713 | });
714 |
715 | window.addEventListener('touchend', function (e) {
716 | if (!toggle) return;
717 |
718 | var handle = toggle.querySelector('.toggle-handle');
719 | var toggleWidth = toggle.offsetWidth;
720 | var handleWidth = handle.offsetWidth;
721 | var offset = toggleWidth - handleWidth;
722 | var slideOn = (!touchMove && !toggle.classList.contains('active')) || (touchMove && (distanceX > (toggleWidth/2 - handleWidth/2)));
723 |
724 | if (slideOn) handle.style.webkitTransform = 'translate3d(' + offset + 'px,0,0)';
725 | else handle.style.webkitTransform = 'translate3d(0,0,0)';
726 |
727 | toggle.classList[slideOn ? 'add' : 'remove']('active');
728 |
729 | e = new CustomEvent('toggle', {
730 | detail: { isActive: slideOn },
731 | bubbles: true,
732 | cancelable: true
733 | });
734 |
735 | toggle.dispatchEvent(e);
736 |
737 | touchMove = false;
738 | toggle = false;
739 | });
740 |
741 | }();
742 |
--------------------------------------------------------------------------------
/snap.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Snap.js
3 | *
4 | * Copyright 2013, Jacob Kelley - http://jakiestfu.com/
5 | * Released under the MIT Licence
6 | * http://opensource.org/licenses/MIT
7 | *
8 | * Github: http://github.com/jakiestfu/Snap.js/
9 | * Version: 1.9.3
10 | */
11 | /*jslint browser: true*/
12 | /*global define, module, ender*/
13 | (function(win, doc) {
14 | 'use strict';
15 | var Snap = Snap || function(userOpts) {
16 | var settings = {
17 | element: null,
18 | dragger: null,
19 | disable: 'none',
20 | addBodyClasses: true,
21 | hyperextensible: true,
22 | resistance: 0.5,
23 | flickThreshold: 50,
24 | transitionSpeed: 0.3,
25 | easing: 'ease',
26 | maxPosition: 266,
27 | minPosition: -266,
28 | tapToClose: true,
29 | touchToDrag: true,
30 | slideIntent: 40, // degrees
31 | minDragDistance: 5
32 | },
33 | cache = {
34 | simpleStates: {
35 | opening: null,
36 | towards: null,
37 | hyperExtending: null,
38 | halfway: null,
39 | flick: null,
40 | translation: {
41 | absolute: 0,
42 | relative: 0,
43 | sinceDirectionChange: 0,
44 | percentage: 0
45 | }
46 | }
47 | },
48 | eventList = {},
49 | utils = {
50 | hasTouch: ('ontouchstart' in doc.documentElement || win.navigator.msPointerEnabled),
51 | eventType: function(action) {
52 | var eventTypes = {
53 | down: (utils.hasTouch ? 'touchstart' : 'mousedown'),
54 | move: (utils.hasTouch ? 'touchmove' : 'mousemove'),
55 | up: (utils.hasTouch ? 'touchend' : 'mouseup'),
56 | out: (utils.hasTouch ? 'touchcancel' : 'mouseout')
57 | };
58 | return eventTypes[action];
59 | },
60 | page: function(t, e){
61 | return (utils.hasTouch && e.touches.length && e.touches[0]) ? e.touches[0]['page'+t] : e['page'+t];
62 | },
63 | klass: {
64 | has: function(el, name){
65 | return (el.className).indexOf(name) !== -1;
66 | },
67 | add: function(el, name){
68 | if(!utils.klass.has(el, name) && settings.addBodyClasses){
69 | el.className += " "+name;
70 | }
71 | },
72 | remove: function(el, name){
73 | if(settings.addBodyClasses){
74 | el.className = (el.className).replace(name, "").replace(/^\s+|\s+$/g, '');
75 | }
76 | }
77 | },
78 | dispatchEvent: function(type) {
79 | if (typeof eventList[type] === 'function') {
80 | return eventList[type].call();
81 | }
82 | },
83 | vendor: function(){
84 | var tmp = doc.createElement("div"),
85 | prefixes = 'webkit Moz O ms'.split(' '),
86 | i;
87 | for (i in prefixes) {
88 | if (typeof tmp.style[prefixes[i] + 'Transition'] !== 'undefined') {
89 | return prefixes[i];
90 | }
91 | }
92 | },
93 | transitionCallback: function(){
94 | return (cache.vendor==='Moz' || cache.vendor==='ms') ? 'transitionend' : cache.vendor+'TransitionEnd';
95 | },
96 | canTransform: function(){
97 | return typeof settings.element.style[cache.vendor+'Transform'] !== 'undefined';
98 | },
99 | deepExtend: function(destination, source) {
100 | var property;
101 | for (property in source) {
102 | if (source[property] && source[property].constructor && source[property].constructor === Object) {
103 | destination[property] = destination[property] || {};
104 | utils.deepExtend(destination[property], source[property]);
105 | } else {
106 | destination[property] = source[property];
107 | }
108 | }
109 | return destination;
110 | },
111 | angleOfDrag: function(x, y) {
112 | var degrees, theta;
113 | // Calc Theta
114 | theta = Math.atan2(-(cache.startDragY - y), (cache.startDragX - x));
115 | if (theta < 0) {
116 | theta += 2 * Math.PI;
117 | }
118 | // Calc Degrees
119 | degrees = Math.floor(theta * (180 / Math.PI) - 180);
120 | if (degrees < 0 && degrees > -180) {
121 | degrees = 360 - Math.abs(degrees);
122 | }
123 | return Math.abs(degrees);
124 | },
125 | events: {
126 | addEvent: function addEvent(element, eventName, func) {
127 | if (element.addEventListener) {
128 | return element.addEventListener(eventName, func, false);
129 | } else if (element.attachEvent) {
130 | return element.attachEvent("on" + eventName, func);
131 | }
132 | },
133 | removeEvent: function addEvent(element, eventName, func) {
134 | if (element.addEventListener) {
135 | return element.removeEventListener(eventName, func, false);
136 | } else if (element.attachEvent) {
137 | return element.detachEvent("on" + eventName, func);
138 | }
139 | },
140 | prevent: function(e) {
141 | if (e.preventDefault) {
142 | e.preventDefault();
143 | } else {
144 | e.returnValue = false;
145 | }
146 | }
147 | },
148 | parentUntil: function(el, attr) {
149 | var isStr = typeof attr === 'string';
150 | while (el.parentNode) {
151 | if (isStr && el.getAttribute && el.getAttribute(attr)){
152 | return el;
153 | } else if(!isStr && el === attr){
154 | return el;
155 | }
156 | el = el.parentNode;
157 | }
158 | return null;
159 | }
160 | },
161 | action = {
162 | translate: {
163 | get: {
164 | matrix: function(index) {
165 |
166 | if( !utils.canTransform() ){
167 | return parseInt(settings.element.style.left, 10);
168 | } else {
169 | var matrix = win.getComputedStyle(settings.element)[cache.vendor+'Transform'].match(/\((.*)\)/),
170 | ieOffset = 8;
171 | if (matrix) {
172 | matrix = matrix[1].split(',');
173 | if(matrix.length===16){
174 | index+=ieOffset;
175 | }
176 | return parseInt(matrix[index], 10);
177 | }
178 | return 0;
179 | }
180 | }
181 | },
182 | easeCallback: function(){
183 | settings.element.style[cache.vendor+'Transition'] = '';
184 | cache.translation = action.translate.get.matrix(4);
185 | cache.easing = false;
186 | clearInterval(cache.animatingInterval);
187 |
188 | if(cache.easingTo===0){
189 | utils.klass.remove(doc.body, 'snapjs-right');
190 | utils.klass.remove(doc.body, 'snapjs-left');
191 | }
192 |
193 | utils.dispatchEvent('animated');
194 | utils.events.removeEvent(settings.element, utils.transitionCallback(), action.translate.easeCallback);
195 | },
196 | easeTo: function(n) {
197 |
198 | if( !utils.canTransform() ){
199 | cache.translation = n;
200 | action.translate.x(n);
201 | } else {
202 | cache.easing = true;
203 | cache.easingTo = n;
204 |
205 | settings.element.style[cache.vendor+'Transition'] = 'all ' + settings.transitionSpeed + 's ' + settings.easing;
206 |
207 | cache.animatingInterval = setInterval(function() {
208 | utils.dispatchEvent('animating');
209 | }, 1);
210 |
211 | utils.events.addEvent(settings.element, utils.transitionCallback(), action.translate.easeCallback);
212 | action.translate.x(n);
213 | }
214 | if(n===0){
215 | settings.element.style[cache.vendor+'Transform'] = '';
216 | }
217 | },
218 | x: function(n) {
219 | if( (settings.disable==='left' && n>0) ||
220 | (settings.disable==='right' && n<0)
221 | ){ return; }
222 |
223 | if( !settings.hyperextensible ){
224 | if( n===settings.maxPosition || n>settings.maxPosition ){
225 | n=settings.maxPosition;
226 | } else if( n===settings.minPosition || n