├── img
├── .DS_Store
└── globe.jpg
├── index.html
├── css
├── main.css
└── main.less
└── js
├── main.js
└── zepto.js
/img/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yyx990803/Puzzle-Demo/HEAD/img/.DS_Store
--------------------------------------------------------------------------------
/img/globe.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yyx990803/Puzzle-Demo/HEAD/img/globe.jpg
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Puzzle
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/css/main.css:
--------------------------------------------------------------------------------
1 | *{-webkit-tap-highlight-color:transparent;}
2 | html,body{margin:0;padding:0;background-color:#ddd;-webkit-user-select:none;}
3 | #board{width:288px;height:288px;margin:9px auto;background-color:#ccc;border-radius:2px;padding:2px;-webkit-box-shadow:inset 0 1px 8px rgba(0, 0, 0, 0.2),0 1px 1px rgba(255, 255, 255, 0.5);-moz-box-shadow:inset 0 1px 8px rgba(0, 0, 0, 0.2),0 1px 1px rgba(255, 255, 255, 0.5);box-shadow:inset 0 1px 8px rgba(0, 0, 0, 0.2),0 1px 1px rgba(255, 255, 255, 0.5);}#board .tile{display:block;width:70px;height:70px;position:absolute;overflow:hidden;border:1px solid #eeeeee;-webkit-box-shadow:0 1px 4px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 1px 4px rgba(0, 0, 0, 0.3);box-shadow:0 1px 4px rgba(0, 0, 0, 0.3);-webkit-transition:all 0.15s ease;-moz-transition:all 0.15s ease;-ms-transition:all 0.15s ease;-o-transition:all 0.15s ease;transition:all 0.15s ease;-webkit-backface-visibility:hidden;}#board .tile img{width:288px;height:288px;position:relative;}
4 | #board .tile.drag{-webkit-transition:all 0 cubic-bezier(0, 0, 0.2, 1) !important;-moz-transition:all 0 cubic-bezier(0, 0, 0.2, 1) !important;-ms-transition:all 0 cubic-bezier(0, 0, 0.2, 1) !important;-o-transition:all 0 cubic-bezier(0, 0, 0.2, 1) !important;transition:all 0 cubic-bezier(0, 0, 0.2, 1) !important;}
5 | #shuffle{display:block;color:#666;cursor:pointer;font-family:Helvetica,Arial,sans-serif;font-weight:bold;text-align:center;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);width:290px;margin:9px auto;padding:7px 0;border:1px solid #aaa;border-top-color:#b9b9b9;border-radius:2px;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.15),0 1px 1px rgba(255, 255, 255, 0.5);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.15),0 1px 1px rgba(255, 255, 255, 0.5);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.15),0 1px 1px rgba(255, 255, 255, 0.5);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #f3f3f3), color-stop(100%, #d9d9d9));background:-webkit-linear-gradient(top, #f3f3f3 0%, #d9d9d9 100%);background:-moz-linear-gradient(top, #f3f3f3 0%, #d9d9d9 100%);background:-ms-linear-gradient(top, #f3f3f3 0%, #d9d9d9 100%);background:-o-linear-gradient(top, #f3f3f3 0%, #d9d9d9 100%);background:linear-gradient(top, #f3f3f3 0%, #d9d9d9 100%);}#shuffle:active{background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #dddddd), color-stop(100%, #cccccc));background:-webkit-linear-gradient(top, #dddddd 0%, #cccccc 100%);background:-moz-linear-gradient(top, #dddddd 0%, #cccccc 100%);background:-ms-linear-gradient(top, #dddddd 0%, #cccccc 100%);background:-o-linear-gradient(top, #dddddd 0%, #cccccc 100%);background:linear-gradient(top, #dddddd 0%, #cccccc 100%);}
6 |
--------------------------------------------------------------------------------
/css/main.less:
--------------------------------------------------------------------------------
1 | //Variables
2 | @tileSize: 70px;
3 | @tileBorder: 1px;
4 | @boardSize: (@tileSize + @tileBorder * 2) * 4;
5 | @boardPadding: 2px;
6 |
7 | //Mixins
8 | .transition(@args) {
9 | -webkit-transition: all @args;
10 | -moz-transition: all @args;
11 | -ms-transition: all @args;
12 | -o-transition: all @args;
13 | transition: all @args;
14 | }
15 |
16 | .gradient(@begin, @end) {
17 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,@begin), color-stop(100%,@end)); //iOS 4.3-
18 | background: -webkit-linear-gradient(top, @begin 0%, @end 100%);
19 | background: -moz-linear-gradient(top, @begin 0%, @end 100%);
20 | background: -ms-linear-gradient(top, @begin 0%, @end 100%);
21 | background: -o-linear-gradient(top, @begin 0%, @end 100%);
22 | background: linear-gradient(top, @begin 0%, @end 100%);
23 | }
24 |
25 | //Main
26 | * {
27 | -webkit-tap-highlight-color: transparent;
28 | }
29 |
30 | html, body {
31 | margin: 0;
32 | padding: 0;
33 | background-color: #ddd;
34 | -webkit-user-select: none;
35 | }
36 |
37 | #board {
38 | width: @boardSize;
39 | height: @boardSize;
40 | position: relative;
41 | margin: 9px auto;
42 | background-color: #ccc;
43 | border-radius: 2px;
44 | padding: @boardPadding;
45 | -webkit-box-shadow: inset 0 1px 8px rgba(0, 0, 0, .2), 0 1px 1px rgba(255, 255, 255, .5);
46 | -moz-box-shadow: inset 0 1px 8px rgba(0, 0, 0, .2), 0 1px 1px rgba(255, 255, 255, .5);
47 | box-shadow: inset 0 1px 8px rgba(0, 0, 0, .2), 0 1px 1px rgba(255, 255, 255, .5);
48 | .tile {
49 | display: block;
50 | width: @tileSize;
51 | height: @tileSize;
52 | position: absolute;
53 | overflow: hidden;
54 | border: @tileBorder solid #eee;
55 | -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, .3);
56 | -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, .3);
57 | box-shadow: 0 1px 4px rgba(0, 0, 0, .3);
58 | .transition(.15s ease);
59 | -webkit-backface-visibility: hidden;
60 | img {
61 | width: @boardSize;
62 | height: @boardSize;
63 | position: relative;
64 | }
65 | &.drag {
66 | .transition(0 cubic-bezier(0,0,0.2,1) ~"!important");
67 | }
68 | }
69 | }
70 |
71 | #shuffle {
72 | display: block;
73 | color: #666;
74 | cursor: pointer;
75 | font-family: Helvetica, Arial, sans-serif;
76 | font-weight: bold;
77 | text-align: center;
78 | text-shadow: 0 1px 0 rgba(255, 255, 255, .5);
79 | width: @boardSize + 2px;
80 | margin: 9px auto;
81 | padding: 7px 0;
82 | border: 1px solid #aaa;
83 | border-top-color: #b9b9b9;
84 | border-radius: 2px;
85 | -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .15), 0 1px 1px rgba(255, 255, 255, .5);
86 | -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .15), 0 1px 1px rgba(255, 255, 255, .5);
87 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, .15), 0 1px 1px rgba(255, 255, 255, .5);
88 | .gradient(#f3f3f3, #d9d9d9);
89 | &:active {
90 | .gradient(#ddd, #ccc);
91 | }
92 | }
--------------------------------------------------------------------------------
/js/main.js:
--------------------------------------------------------------------------------
1 | //
2 | // Slider Puzzle for mobile browser (webkit optimized)
3 | // Evan You
4 | // 02-24-2012
5 | //
6 | // Built with Zepto.js
7 | //
8 |
9 | var PUZZLE = (function ($, window, undefined) {
10 | "use strict";
11 |
12 | var animating = false,
13 | tileSize = 72,
14 | animationSpeed = 150,
15 | setTimeout = window.setTimeout,
16 |
17 | // Templates
18 | templates = {
19 | board: function () {
20 | return '';
21 | },
22 | tile: function (id) {
23 | var offsetTop = ~~(id / 4) * -tileSize,
24 | offsetLeft = id % 4 * -tileSize;
25 | return '' +
26 | '

' +
27 | '
';
28 | },
29 | shuffleButton: function () {
30 | return 'Shuffle';
31 | }
32 | },
33 |
34 | // Utility function for vendor prefixes
35 | cssTransform = function (x, y) {
36 | var translation = 'translate(' + x + 'px,' + y + 'px)';
37 | return {
38 | '-webkit-transform': translation,
39 | '-moz-transform': translation,
40 | '-ms-transform': translation,
41 | '-o-transform': translation,
42 | 'transform': translation
43 | };
44 | };
45 |
46 | // The tile object
47 | var Tile = function (id, board) {
48 | this.id = id; // This also stands for the correct position
49 | this.board = board;
50 | this.render();
51 | };
52 |
53 | Tile.prototype = {
54 |
55 | // Render dom element wrapped in Zepto selector
56 | render: function () {
57 | this.el = $(templates.tile(this.id));
58 | },
59 |
60 | // Update and animate to new position
61 | update: function (position) {
62 | this.position = position;
63 | this.x = (position % 4) * tileSize;
64 | this.y = ~~(position / 4) * tileSize;
65 | this.el.data('position', position).css(cssTransform(this.x, this.y));
66 | },
67 |
68 | // Determine the legit move direction
69 | // 0-top, 1-right, 2-bottom, 3-left, -1 if cannot move
70 | getMovableDirection: function () {
71 | var row = ~~(this.position / 4),
72 | col = this.position % 4,
73 | slot = this.board.openSlot;
74 | if (row === slot.row) {
75 | return col < slot.col ? 1 : 3;
76 | } else if (col === slot.col) {
77 | return row < slot.row ? 2 : 0;
78 | } else {
79 | return -1;
80 | }
81 | },
82 |
83 | // Get neighbor with given direction
84 | // returns a tile object if there is a nieghbor
85 | // returns null if the cell in that direction is empty
86 | // implicitly returns undefined if out of bound
87 | getNeighbor: function (direction) {
88 | var n;
89 | switch(direction) {
90 | case 0:
91 | n = this.position - 4;
92 | break;
93 | case 1:
94 | n = this.position + 1;
95 | break;
96 | case 2:
97 | n = this.position + 4;
98 | break;
99 | case 3:
100 | n = this.position - 1;
101 | break;
102 | default:
103 | break;
104 | }
105 | if (n >= 0 && n < 16) {
106 | return this.board.tiles[n];
107 | }
108 | }
109 | };
110 |
111 | // The board object
112 | var Board = function () {
113 | this.buildTiles();
114 | this.shuffle();
115 | this.render();
116 | this.update();
117 | };
118 |
119 | Board.prototype = {
120 |
121 | // Populate the tiles
122 | buildTiles: function () {
123 | // Array holding the tile objects
124 | // The index here determines the actual position on the board
125 | // The empty slot is null
126 | this.tiles = [];
127 | for (var i = 0; i < 15; i++) {
128 | this.tiles.push(new Tile(i, this));
129 | }
130 | this.tiles.push(null);
131 | this.setOpenSlot(15);
132 | },
133 |
134 | // Shuffle the tiles
135 | shuffle: function () {
136 | var i, j, temp;
137 | for (i = this.tiles.length - 1; i > 0; i--) {
138 | j = ~~(Math.random() * (i + 1));
139 | temp = this.tiles[i];
140 | this.tiles[i] = this.tiles[j];
141 | this.tiles[j] = temp;
142 | }
143 | },
144 |
145 | // Render dom element wrapped in Zepto selector
146 | render: function () {
147 | this.el = $(templates.board());
148 | for (var i = 0, j = this.tiles.length; i < j; i++) {
149 | if (this.tiles[i]) {
150 | this.el.append(this.tiles[i].el);
151 | }
152 | }
153 | this.initEvents();
154 | },
155 |
156 | // Delegate touch events on tiles
157 | initEvents: function () {
158 | var board = this,
159 | touch = {}; // Object for holding variables during a touch events cycle
160 | board.el
161 | .delegate('.tile', 'touchstart mousedown', function (e) {
162 | if (!animating && (!e.touches || e.touches.length === 1)) {
163 | touch.tile = board.tiles[$(this).data('position')];
164 | touch.direction = touch.tile.getMovableDirection();
165 | if (touch.direction !== -1) {
166 | touch.legit = true;
167 | touch.axis = touch.direction % 2 === 0; // true:y, false:x
168 |
169 | // Record original position
170 | touch.op = touch.axis ? (e.pageY || e.touches[0].pageY) : (e.pageX || e.touches[0].pageX);
171 |
172 | // Determine bounds and trigger point
173 | switch (touch.direction) {
174 | case 0:
175 | case 3:
176 | touch.lowerBound = -tileSize;
177 | touch.upperBound = 0;
178 | break;
179 | case 1:
180 | case 2:
181 | touch.lowerBound = 0;
182 | touch.upperBound = tileSize;
183 | break;
184 | default:
185 | break;
186 | }
187 | touch.triggerPoint = (touch.upperBound + touch.lowerBound) / 2;
188 |
189 | // Look for other affected tiles
190 | touch.group = [];
191 | var t = touch.tile;
192 | while (t !== null && t !== undefined) {
193 | touch.group.push(t);
194 | t = t.getNeighbor(touch.direction);
195 | }
196 | }
197 | }
198 | })
199 | .delegate('.tile', 'touchmove mousemove', function (e) {
200 | var i, j, dx, dy;
201 | if ((!e.touches || e.touches.length === 1) && touch.legit) {
202 | if (!touch.dragging) {
203 | touch.dragging = true;
204 | for (i = 0, j = touch.group.length; i < j; i++) {
205 | touch.group[i].el.addClass('drag');
206 | }
207 | }
208 |
209 | // Record displacement and limit it to the bounds
210 | var d = (touch.axis ? (e.pageY || e.touches[0].pageY) : (e.pageX || e.touches[0].pageX)) - touch.op;
211 | touch.dp = Math.max(Math.min(d, touch.upperBound), touch.lowerBound);
212 |
213 | // Drag animation
214 | for (i = 0, j = touch.group.length; i < j; i++) {
215 | dx = touch.group[i].x + (touch.axis ? 0 : touch.dp);
216 | dy = touch.group[i].y + (touch.axis ? touch.dp : 0);
217 | touch.group[i].el.css(cssTransform(dx, dy));
218 | }
219 | }
220 | })
221 | .delegate('.tile', 'touchend mouseup', function (e) {
222 | var i, j;
223 | if (touch.legit) {
224 | if (touch.dragging && Math.abs(touch.dp) < Math.abs(touch.triggerPoint)) {
225 | // Dragged but cancelled
226 | // return all tiles to original position
227 | for (i = 0, j = touch.group.length; i < j; i++) {
228 | touch.group[i].el
229 | .removeClass('drag')
230 | .css(cssTransform(touch.group[i].x, touch.group[i].y));
231 | }
232 | board.lock();
233 | } else {
234 | // Triggered a successful move
235 | // move the tile objects to new positions in array
236 | board.tiles[board.openSlot.position] = touch.group[touch.group.length - 1];
237 | for (i = touch.group.length - 1; i >= 0; i--) {
238 | board.tiles[touch.group[i].position] = (i === 0 ? null : touch.group[i-1]);
239 | }
240 | // Animatie
241 | if (touch.dragging) {
242 | for (i = 0, j = touch.group.length; i < j; i++) {
243 | touch.group[i].el.removeClass('drag');
244 | }
245 | }
246 | board.update();
247 | }
248 | }
249 | // Reset
250 | touch = {};
251 | });
252 | },
253 |
254 | // Update tiles/slots according to current positions
255 | update: function () {
256 | this.lock();
257 | for (var i = 0, j = this.tiles.length; i < j; i++) {
258 | if (this.tiles[i]) {
259 | this.tiles[i].update(i);
260 | } else {
261 | this.setOpenSlot(i);
262 | }
263 | }
264 | if (this.gameComplete()) {
265 | var board = this;
266 | setTimeout( function () {
267 | window.alert('Wow you are damn good at slider puzzles... gonna shuffle that so that you can play some more!');
268 | board.shuffle();
269 | board.update();
270 | }, animationSpeed);
271 | }
272 | },
273 |
274 | // Utility function for setting the empty slot
275 | setOpenSlot: function (i) {
276 | this.openSlot = {
277 | position: i,
278 | row: ~~(i / 4),
279 | col: i % 4
280 | };
281 | },
282 |
283 | // Check if all tiles are in correct position
284 | gameComplete: function () {
285 | for (var i = 0, j = this.tiles.length; i < j; i++) {
286 | if (this.tiles[i] && this.tiles[i].id !== i) {
287 | return false;
288 | }
289 | }
290 | return true;
291 | },
292 |
293 | // Prevent all touch events for a given duration
294 | // Used during animation
295 | lock: function () {
296 | animating = true;
297 | setTimeout(function () {
298 | animating = false;
299 | }, animationSpeed);
300 | }
301 | };
302 |
303 | // Expose initialization function
304 | return {
305 | init: function (container) {
306 |
307 | // Prevent mobile browser viewport movement
308 | $(document.body).bind('touchmove', function (e) {
309 | e.preventDefault();
310 | });
311 |
312 | // Create puzzle
313 | var board = new Board(),
314 | shuffleButton = $(templates.shuffleButton()).bind('click', function () {
315 | if (!animating) {
316 | board.shuffle();
317 | board.update();
318 | }
319 | });
320 |
321 | // Append elements to container
322 | $(container).append(board.el).append(shuffleButton);
323 | }
324 | };
325 |
326 | }(Zepto, window));
--------------------------------------------------------------------------------
/js/zepto.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010, 2011 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | (function(undefined){
6 | if (String.prototype.trim === undefined) // fix for iOS 3.2
7 | String.prototype.trim = function(){ return this.replace(/^\s+/, '').replace(/\s+$/, '') };
8 |
9 | // For iOS 3.x
10 | // from https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduce
11 | if (Array.prototype.reduce === undefined)
12 | Array.prototype.reduce = function(fun){
13 | if(this === void 0 || this === null) throw new TypeError();
14 | var t = Object(this), len = t.length >>> 0, k = 0, accumulator;
15 | if(typeof fun != 'function') throw new TypeError();
16 | if(len == 0 && arguments.length == 1) throw new TypeError();
17 |
18 | if(arguments.length >= 2)
19 | accumulator = arguments[1];
20 | else
21 | do{
22 | if(k in t){
23 | accumulator = t[k++];
24 | break;
25 | }
26 | if(++k >= len) throw new TypeError();
27 | } while (true);
28 |
29 | while (k < len){
30 | if(k in t) accumulator = fun.call(undefined, accumulator, t[k], k, t);
31 | k++;
32 | }
33 | return accumulator;
34 | };
35 |
36 | })();
37 | // Zepto.js
38 | // (c) 2010, 2011 Thomas Fuchs
39 | // Zepto.js may be freely distributed under the MIT license.
40 |
41 | var Zepto = (function() {
42 | var undefined, key, $$, classList, emptyArray = [], slice = emptyArray.slice,
43 | document = window.document,
44 | elementDisplay = {}, classCache = {},
45 | getComputedStyle = document.defaultView.getComputedStyle,
46 | cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 },
47 | fragmentRE = /^\s*<(\w+)[^>]*>/,
48 | elementTypes = [1, 9, 11],
49 | adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ],
50 | table = document.createElement('table'),
51 | tableRow = document.createElement('tr'),
52 | containers = {
53 | 'tr': document.createElement('tbody'),
54 | 'tbody': table, 'thead': table, 'tfoot': table,
55 | 'td': tableRow, 'th': tableRow,
56 | '*': document.createElement('div')
57 | },
58 | readyRE = /complete|loaded|interactive/,
59 | classSelectorRE = /^\.([\w-]+)$/,
60 | idSelectorRE = /^#([\w-]+)$/,
61 | tagSelectorRE = /^[\w-]+$/;
62 |
63 | function isF(value) { return ({}).toString.call(value) == "[object Function]" }
64 | function isO(value) { return value instanceof Object }
65 | function isA(value) { return value instanceof Array }
66 | function likeArray(obj) { return typeof obj.length == 'number' }
67 |
68 | function compact(array) { return array.filter(function(item){ return item !== undefined && item !== null }) }
69 | function flatten(array) { return array.length > 0 ? [].concat.apply([], array) : array }
70 | function camelize(str) { return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) }
71 | function dasherize(str){
72 | return str.replace(/::/g, '/')
73 | .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
74 | .replace(/([a-z\d])([A-Z])/g, '$1_$2')
75 | .replace(/_/g, '-')
76 | .toLowerCase();
77 | }
78 | function uniq(array) { return array.filter(function(item,index,array){ return array.indexOf(item) == index }) }
79 |
80 | function classRE(name){
81 | return name in classCache ?
82 | classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)'));
83 | }
84 |
85 | function maybeAddPx(name, value) { return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value; }
86 |
87 | function defaultDisplay(nodeName) {
88 | var element, display;
89 | if (!elementDisplay[nodeName]) {
90 | element = document.createElement(nodeName);
91 | document.body.appendChild(element);
92 | display = getComputedStyle(element, '').getPropertyValue("display");
93 | element.parentNode.removeChild(element);
94 | display == "none" && (display = "block");
95 | elementDisplay[nodeName] = display;
96 | }
97 | return elementDisplay[nodeName];
98 | }
99 |
100 | function fragment(html, name) {
101 | if (name === undefined) fragmentRE.test(html) && RegExp.$1;
102 | if (!(name in containers)) name = '*';
103 | var container = containers[name];
104 | container.innerHTML = '' + html;
105 | return slice.call(container.childNodes);
106 | }
107 |
108 | function Z(dom, selector){
109 | dom = dom || emptyArray;
110 | dom.__proto__ = Z.prototype;
111 | dom.selector = selector || '';
112 | return dom;
113 | }
114 |
115 | function $(selector, context){
116 | if (!selector) return Z();
117 | if (context !== undefined) return $(context).find(selector);
118 | else if (isF(selector)) return $(document).ready(selector);
119 | else if (selector instanceof Z) return selector;
120 | else {
121 | var dom;
122 | if (isA(selector)) dom = compact(selector);
123 | else if (elementTypes.indexOf(selector.nodeType) >= 0 || selector === window)
124 | dom = [selector], selector = null;
125 | else if (fragmentRE.test(selector))
126 | dom = fragment(selector.trim(), RegExp.$1), selector = null;
127 | else if (selector.nodeType && selector.nodeType == 3) dom = [selector];
128 | else dom = $$(document, selector);
129 | return Z(dom, selector);
130 | }
131 | }
132 |
133 | $.extend = function(target){
134 | slice.call(arguments, 1).forEach(function(source) {
135 | for (key in source) target[key] = source[key];
136 | })
137 | return target;
138 | }
139 |
140 | $.qsa = $$ = function(element, selector){
141 | var found;
142 | return (element === document && idSelectorRE.test(selector)) ?
143 | ( (found = element.getElementById(RegExp.$1)) ? [found] : emptyArray ) :
144 | slice.call(
145 | classSelectorRE.test(selector) ? element.getElementsByClassName(RegExp.$1) :
146 | tagSelectorRE.test(selector) ? element.getElementsByTagName(selector) :
147 | element.querySelectorAll(selector)
148 | );
149 | }
150 |
151 | function filtered(nodes, selector){
152 | return selector === undefined ? $(nodes) : $(nodes).filter(selector);
153 | }
154 |
155 | function funcArg(context, arg, idx, payload){
156 | return isF(arg) ? arg.call(context, idx, payload) : arg;
157 | }
158 |
159 | $.isFunction = isF;
160 | $.isObject = isO;
161 | $.isArray = isA;
162 |
163 | $.map = function(elements, callback) {
164 | var value, values = [], i, key;
165 | if (likeArray(elements))
166 | for (i = 0; i < elements.length; i++) {
167 | value = callback(elements[i], i);
168 | if (value != null) values.push(value);
169 | }
170 | else
171 | for (key in elements) {
172 | value = callback(elements[key], key);
173 | if (value != null) values.push(value);
174 | }
175 | return flatten(values);
176 | }
177 |
178 | $.each = function(elements, callback) {
179 | var i, key;
180 | if (likeArray(elements))
181 | for(i = 0; i < elements.length; i++) {
182 | if(callback(i, elements[i]) === false) return elements;
183 | }
184 | else
185 | for(key in elements) {
186 | if(callback(key, elements[key]) === false) return elements;
187 | }
188 | return elements;
189 | }
190 |
191 | $.fn = {
192 | forEach: emptyArray.forEach,
193 | reduce: emptyArray.reduce,
194 | push: emptyArray.push,
195 | indexOf: emptyArray.indexOf,
196 | concat: emptyArray.concat,
197 | map: function(fn){
198 | return $.map(this, function(el, i){ return fn.call(el, i, el) });
199 | },
200 | slice: function(){
201 | return $(slice.apply(this, arguments));
202 | },
203 | ready: function(callback){
204 | if (readyRE.test(document.readyState)) callback($);
205 | else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false);
206 | return this;
207 | },
208 | get: function(idx){ return idx === undefined ? this : this[idx] },
209 | size: function(){ return this.length },
210 | remove: function () {
211 | return this.each(function () {
212 | if (this.parentNode != null) {
213 | this.parentNode.removeChild(this);
214 | }
215 | });
216 | },
217 | each: function(callback){
218 | this.forEach(function(el, idx){ callback.call(el, idx, el) });
219 | return this;
220 | },
221 | filter: function(selector){
222 | return $([].filter.call(this, function(element){
223 | return element.parentNode && $$(element.parentNode, selector).indexOf(element) >= 0;
224 | }));
225 | },
226 | end: function(){
227 | return this.prevObject || $();
228 | },
229 | andSelf:function(){
230 | return this.add(this.prevObject || $())
231 | },
232 | add:function(selector,context){
233 | return $(uniq(this.concat($(selector,context))));
234 | },
235 | is: function(selector){
236 | return this.length > 0 && $(this[0]).filter(selector).length > 0;
237 | },
238 | not: function(selector){
239 | var nodes=[];
240 | if (isF(selector) && selector.call !== undefined)
241 | this.each(function(idx){
242 | if (!selector.call(this,idx)) nodes.push(this);
243 | });
244 | else {
245 | var excludes = typeof selector == 'string' ? this.filter(selector) :
246 | (likeArray(selector) && isF(selector.item)) ? slice.call(selector) : $(selector);
247 | this.forEach(function(el){
248 | if (excludes.indexOf(el) < 0) nodes.push(el);
249 | });
250 | }
251 | return $(nodes);
252 | },
253 | eq: function(idx){
254 | return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1);
255 | },
256 | first: function(){ var el = this[0]; return el && !isO(el) ? el : $(el) },
257 | last: function(){ var el = this[this.length - 1]; return el && !isO(el) ? el : $(el) },
258 | find: function(selector){
259 | var result;
260 | if (this.length == 1) result = $$(this[0], selector);
261 | else result = this.map(function(){ return $$(this, selector) });
262 | return $(result);
263 | },
264 | closest: function(selector, context){
265 | var node = this[0], candidates = $$(context || document, selector);
266 | if (!candidates.length) node = null;
267 | while (node && candidates.indexOf(node) < 0)
268 | node = node !== context && node !== document && node.parentNode;
269 | return $(node);
270 | },
271 | parents: function(selector){
272 | var ancestors = [], nodes = this;
273 | while (nodes.length > 0)
274 | nodes = $.map(nodes, function(node){
275 | if ((node = node.parentNode) && node !== document && ancestors.indexOf(node) < 0) {
276 | ancestors.push(node);
277 | return node;
278 | }
279 | });
280 | return filtered(ancestors, selector);
281 | },
282 | parent: function(selector){
283 | return filtered(uniq(this.pluck('parentNode')), selector);
284 | },
285 | children: function(selector){
286 | return filtered(this.map(function(){ return slice.call(this.children) }), selector);
287 | },
288 | siblings: function(selector){
289 | return filtered(this.map(function(i, el){
290 | return slice.call(el.parentNode.children).filter(function(child){ return child!==el });
291 | }), selector);
292 | },
293 | empty: function(){ return this.each(function(){ this.innerHTML = '' }) },
294 | pluck: function(property){ return this.map(function(){ return this[property] }) },
295 | show: function(){
296 | return this.each(function() {
297 | this.style.display == "none" && (this.style.display = null);
298 | if (getComputedStyle(this, '').getPropertyValue("display") == "none") {
299 | this.style.display = defaultDisplay(this.nodeName)
300 | }
301 | })
302 | },
303 | replaceWith: function(newContent) {
304 | return this.each(function() {
305 | $(this).before(newContent).remove();
306 | });
307 | },
308 | wrap: function(newContent) {
309 | return this.each(function() {
310 | $(this).wrapAll($(newContent)[0].cloneNode(false));
311 | });
312 | },
313 | wrapAll: function(newContent) {
314 | if (this[0]) {
315 | $(this[0]).before(newContent = $(newContent));
316 | newContent.append(this);
317 | }
318 | return this;
319 | },
320 | unwrap: function(){
321 | this.parent().each(function(){
322 | $(this).replaceWith($(this).children());
323 | });
324 | return this;
325 | },
326 | hide: function(){
327 | return this.css("display", "none")
328 | },
329 | toggle: function(setting){
330 | return (setting === undefined ? this.css("display") == "none" : setting) ? this.show() : this.hide();
331 | },
332 | prev: function(){ return $(this.pluck('previousElementSibling')) },
333 | next: function(){ return $(this.pluck('nextElementSibling')) },
334 | html: function(html){
335 | return html === undefined ?
336 | (this.length > 0 ? this[0].innerHTML : null) :
337 | this.each(function (idx) {
338 | var originHtml = this.innerHTML;
339 | $(this).empty().append( funcArg(this, html, idx, originHtml) );
340 | });
341 | },
342 | text: function(text){
343 | return text === undefined ?
344 | (this.length > 0 ? this[0].textContent : null) :
345 | this.each(function(){ this.textContent = text });
346 | },
347 | attr: function(name, value){
348 | var res;
349 | return (typeof name == 'string' && value === undefined) ?
350 | (this.length == 0 ? undefined :
351 | (name == 'value' && this[0].nodeName == 'INPUT') ? this.val() :
352 | (!(res = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : res
353 | ) :
354 | this.each(function(idx){
355 | if (isO(name)) for (key in name) this.setAttribute(key, name[key])
356 | else this.setAttribute(name, funcArg(this, value, idx, this.getAttribute(name)));
357 | });
358 | },
359 | removeAttr: function(name) {
360 | return this.each(function() { this.removeAttribute(name); });
361 | },
362 | data: function(name, value){
363 | return this.attr('data-' + name, value);
364 | },
365 | val: function(value){
366 | return (value === undefined) ?
367 | (this.length > 0 ? this[0].value : null) :
368 | this.each(function(idx){
369 | this.value = funcArg(this, value, idx, this.value);
370 | });
371 | },
372 | offset: function(){
373 | if(this.length==0) return null;
374 | var obj = this[0].getBoundingClientRect();
375 | return {
376 | left: obj.left + window.pageXOffset,
377 | top: obj.top + window.pageYOffset,
378 | width: obj.width,
379 | height: obj.height
380 | };
381 | },
382 | css: function(property, value){
383 | if (value === undefined && typeof property == 'string') {
384 | return(
385 | this.length == 0
386 | ? undefined
387 | : this[0].style[camelize(property)] || getComputedStyle(this[0], '').getPropertyValue(property)
388 | );
389 | }
390 | var css = '';
391 | for (key in property) css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';';
392 | if (typeof property == 'string') css = dasherize(property) + ":" + maybeAddPx(property, value);
393 | return this.each(function() { this.style.cssText += ';' + css });
394 | },
395 | index: function(element){
396 | return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0]);
397 | },
398 | hasClass: function(name){
399 | if (this.length < 1) return false;
400 | else return classRE(name).test(this[0].className);
401 | },
402 | addClass: function(name){
403 | return this.each(function(idx) {
404 | classList = [];
405 | var cls = this.className, newName = funcArg(this, name, idx, cls);
406 | newName.split(/\s+/g).forEach(function(klass) {
407 | if (!$(this).hasClass(klass)) {
408 | classList.push(klass)
409 | }
410 | }, this);
411 | classList.length && (this.className += (cls ? " " : "") + classList.join(" "))
412 | });
413 | },
414 | removeClass: function(name){
415 | return this.each(function(idx) {
416 | if(name === undefined)
417 | return this.className = '';
418 | classList = this.className;
419 | funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass) {
420 | classList = classList.replace(classRE(klass), " ")
421 | });
422 | this.className = classList.trim()
423 | });
424 | },
425 | toggleClass: function(name, when){
426 | return this.each(function(idx){
427 | var newName = funcArg(this, name, idx, this.className);
428 | (when === undefined ? !$(this).hasClass(newName) : when) ?
429 | $(this).addClass(newName) : $(this).removeClass(newName);
430 | });
431 | }
432 | };
433 |
434 | 'filter,add,not,eq,first,last,find,closest,parents,parent,children,siblings'.split(',').forEach(function(property){
435 | var fn = $.fn[property];
436 | $.fn[property] = function() {
437 | var ret = fn.apply(this, arguments);
438 | ret.prevObject = this;
439 | return ret;
440 | }
441 | });
442 |
443 | ['width', 'height'].forEach(function(dimension){
444 | $.fn[dimension] = function(value) {
445 | var offset, Dimension = dimension.replace(/./, function(m) { return m[0].toUpperCase() });
446 | if (value === undefined) return this[0] == window ? window['inner' + Dimension] :
447 | this[0] == document ? document.documentElement['offset' + Dimension] :
448 | (offset = this.offset()) && offset[dimension];
449 | else return this.each(function(idx){
450 | var el = $(this);
451 | el.css(dimension, funcArg(this, value, idx, el[dimension]()));
452 | });
453 | }
454 | });
455 |
456 | function insert(operator, target, node) {
457 | var parent = (operator % 2) ? target : target.parentNode;
458 | parent && parent.insertBefore(node,
459 | !operator ? target.nextSibling : // after
460 | operator == 1 ? parent.firstChild : // prepend
461 | operator == 2 ? target : // before
462 | null); // append
463 | }
464 |
465 | function traverseNode (node, fun) {
466 | fun(node);
467 | for (var key in node.childNodes) {
468 | traverseNode(node.childNodes[key], fun);
469 | }
470 | }
471 |
472 | adjacencyOperators.forEach(function(key, operator) {
473 | $.fn[key] = function(html){
474 | var nodes = isO(html) ? html : fragment(html);
475 | if (!('length' in nodes) || nodes.nodeType) nodes = [nodes];
476 | if (nodes.length < 1) return this;
477 | var size = this.length, copyByClone = size > 1, inReverse = operator < 2;
478 |
479 | return this.each(function(index, target){
480 | for (var i = 0; i < nodes.length; i++) {
481 | var node = nodes[inReverse ? nodes.length-i-1 : i];
482 | traverseNode(node, function (node) {
483 | if (node.nodeName != null && node.nodeName.toUpperCase() === 'SCRIPT' && (!node.type || node.type === 'text/javascript')) {
484 | window['eval'].call(window, node.innerHTML);
485 | }
486 | });
487 | if (copyByClone && index < size - 1) node = node.cloneNode(true);
488 | insert(operator, target, node);
489 | }
490 | });
491 | };
492 |
493 | var reverseKey = (operator % 2) ? key+'To' : 'insert'+(operator ? 'Before' : 'After');
494 | $.fn[reverseKey] = function(html) {
495 | $(html)[key](this);
496 | return this;
497 | };
498 | });
499 |
500 | Z.prototype = $.fn;
501 |
502 | return $;
503 | })();
504 |
505 | window.Zepto = Zepto;
506 | '$' in window || (window.$ = Zepto);
507 | // Zepto.js
508 | // (c) 2010, 2011 Thomas Fuchs
509 | // Zepto.js may be freely distributed under the MIT license.
510 |
511 | (function($){
512 | var $$ = $.qsa, handlers = {}, _zid = 1, specialEvents={};
513 |
514 | specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents';
515 |
516 | function zid(element) {
517 | return element._zid || (element._zid = _zid++);
518 | }
519 | function findHandlers(element, event, fn, selector) {
520 | event = parse(event);
521 | if (event.ns) var matcher = matcherFor(event.ns);
522 | return (handlers[zid(element)] || []).filter(function(handler) {
523 | return handler
524 | && (!event.e || handler.e == event.e)
525 | && (!event.ns || matcher.test(handler.ns))
526 | && (!fn || handler.fn == fn)
527 | && (!selector || handler.sel == selector);
528 | });
529 | }
530 | function parse(event) {
531 | var parts = ('' + event).split('.');
532 | return {e: parts[0], ns: parts.slice(1).sort().join(' ')};
533 | }
534 | function matcherFor(ns) {
535 | return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)');
536 | }
537 |
538 | function eachEvent(events, fn, iterator){
539 | if ($.isObject(events)) $.each(events, iterator);
540 | else events.split(/\s/).forEach(function(type){ iterator(type, fn) });
541 | }
542 |
543 | function add(element, events, fn, selector, getDelegate){
544 | var id = zid(element), set = (handlers[id] || (handlers[id] = []));
545 | eachEvent(events, fn, function(event, fn){
546 | var delegate = getDelegate && getDelegate(fn, event),
547 | callback = delegate || fn;
548 | var proxyfn = function (event) {
549 | var result = callback.apply(element, [event].concat(event.data));
550 | if (result === false) event.preventDefault();
551 | return result;
552 | };
553 | var handler = $.extend(parse(event), {fn: fn, proxy: proxyfn, sel: selector, del: delegate, i: set.length});
554 | set.push(handler);
555 | element.addEventListener(handler.e, proxyfn, false);
556 | });
557 | }
558 | function remove(element, events, fn, selector){
559 | var id = zid(element);
560 | eachEvent(events || '', fn, function(event, fn){
561 | findHandlers(element, event, fn, selector).forEach(function(handler){
562 | delete handlers[id][handler.i];
563 | element.removeEventListener(handler.e, handler.proxy, false);
564 | });
565 | });
566 | }
567 |
568 | $.event = { add: add, remove: remove }
569 |
570 | $.fn.bind = function(event, callback){
571 | return this.each(function(){
572 | add(this, event, callback);
573 | });
574 | };
575 | $.fn.unbind = function(event, callback){
576 | return this.each(function(){
577 | remove(this, event, callback);
578 | });
579 | };
580 | $.fn.one = function(event, callback){
581 | return this.each(function(i, element){
582 | add(this, event, callback, null, function(fn, type){
583 | return function(){
584 | var result = fn.apply(element, arguments);
585 | remove(element, type, fn);
586 | return result;
587 | }
588 | });
589 | });
590 | };
591 |
592 | var returnTrue = function(){return true},
593 | returnFalse = function(){return false},
594 | eventMethods = {
595 | preventDefault: 'isDefaultPrevented',
596 | stopImmediatePropagation: 'isImmediatePropagationStopped',
597 | stopPropagation: 'isPropagationStopped'
598 | };
599 | function createProxy(event) {
600 | var proxy = $.extend({originalEvent: event}, event);
601 | $.each(eventMethods, function(name, predicate) {
602 | proxy[name] = function(){
603 | this[predicate] = returnTrue;
604 | return event[name].apply(event, arguments);
605 | };
606 | proxy[predicate] = returnFalse;
607 | })
608 | return proxy;
609 | }
610 |
611 | // emulates the 'defaultPrevented' property for browsers that have none
612 | function fix(event) {
613 | if (!('defaultPrevented' in event)) {
614 | event.defaultPrevented = false;
615 | var prevent = event.preventDefault;
616 | event.preventDefault = function() {
617 | this.defaultPrevented = true;
618 | prevent.call(this);
619 | }
620 | }
621 | }
622 |
623 | $.fn.delegate = function(selector, event, callback){
624 | return this.each(function(i, element){
625 | add(element, event, callback, selector, function(fn){
626 | return function(e){
627 | var evt, match = $(e.target).closest(selector, element).get(0);
628 | if (match) {
629 | evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element});
630 | return fn.apply(match, [evt].concat([].slice.call(arguments, 1)));
631 | }
632 | }
633 | });
634 | });
635 | };
636 | $.fn.undelegate = function(selector, event, callback){
637 | return this.each(function(){
638 | remove(this, event, callback, selector);
639 | });
640 | }
641 |
642 | $.fn.live = function(event, callback){
643 | $(document.body).delegate(this.selector, event, callback);
644 | return this;
645 | };
646 | $.fn.die = function(event, callback){
647 | $(document.body).undelegate(this.selector, event, callback);
648 | return this;
649 | };
650 |
651 | $.fn.on = function(event, selector, callback){
652 | return selector === undefined || $.isFunction(selector) ?
653 | this.bind(event, selector) : this.delegate(selector, event, callback);
654 | };
655 | $.fn.off = function(event, selector, callback){
656 | return selector === undefined || $.isFunction(selector) ?
657 | this.unbind(event, selector) : this.undelegate(selector, event, callback);
658 | };
659 |
660 | $.fn.trigger = function(event, data){
661 | if (typeof event == 'string') event = $.Event(event);
662 | fix(event);
663 | event.data = data;
664 | return this.each(function(){ this.dispatchEvent(event) });
665 | };
666 |
667 | // triggers event handlers on current element just as if an event occurred,
668 | // doesn't trigger an actual event, doesn't bubble
669 | $.fn.triggerHandler = function(event, data){
670 | var e, result;
671 | this.each(function(i, element){
672 | e = createProxy(typeof event == 'string' ? $.Event(event) : event);
673 | e.data = data; e.target = element;
674 | $.each(findHandlers(element, event.type || event), function(i, handler){
675 | result = handler.proxy(e);
676 | if (e.isImmediatePropagationStopped()) return false;
677 | });
678 | });
679 | return result;
680 | };
681 |
682 | // shortcut methods for `.bind(event, fn)` for each event type
683 | ('focusin focusout load resize scroll unload click dblclick '+
684 | 'mousedown mouseup mousemove mouseover mouseout '+
685 | 'change select keydown keypress keyup error').split(' ').forEach(function(event) {
686 | $.fn[event] = function(callback){ return this.bind(event, callback) };
687 | });
688 |
689 | ['focus', 'blur'].forEach(function(name) {
690 | $.fn[name] = function(callback) {
691 | if (callback) this.bind(name, callback);
692 | else if (this.length) try { this.get(0)[name]() } catch(e){};
693 | return this;
694 | };
695 | });
696 |
697 | $.Event = function(type, props) {
698 | var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true;
699 | if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]);
700 | event.initEvent(type, bubbles, true, null, null, null, null, null, null, null, null, null, null, null, null);
701 | return event;
702 | };
703 |
704 | })(Zepto);
705 | // Zepto.js
706 | // (c) 2010, 2011 Thomas Fuchs
707 | // Zepto.js may be freely distributed under the MIT license.
708 |
709 | (function($){
710 | function detect(ua){
711 | var os = (this.os = {}), browser = (this.browser = {}),
712 | webkit = ua.match(/WebKit\/([\d.]+)/),
713 | android = ua.match(/(Android)\s+([\d.]+)/),
714 | ipad = ua.match(/(iPad).*OS\s([\d_]+)/),
715 | iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/),
716 | webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/),
717 | touchpad = webos && ua.match(/TouchPad/),
718 | blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/);
719 |
720 | if (webkit) browser.version = webkit[1];
721 | browser.webkit = !!webkit;
722 |
723 | if (android) os.android = true, os.version = android[2];
724 | if (iphone) os.ios = true, os.version = iphone[2].replace(/_/g, '.'), os.iphone = true;
725 | if (ipad) os.ios = true, os.version = ipad[2].replace(/_/g, '.'), os.ipad = true;
726 | if (webos) os.webos = true, os.version = webos[2];
727 | if (touchpad) os.touchpad = true;
728 | if (blackberry) os.blackberry = true, os.version = blackberry[2];
729 | }
730 |
731 | // ### $.os
732 | //
733 | // Object containing information about browser platform
734 | //
735 | // *Example:*
736 | //
737 | // $.os.ios // => true if running on Apple iOS
738 | // $.os.android // => true if running on Android
739 | // $.os.webos // => true if running on HP/Palm WebOS
740 | // $.os.touchpad // => true if running on a HP TouchPad
741 | // $.os.version // => string with a version number, e.g.
742 | // "4.0", "3.1.1", "2.1", etc.
743 | // $.os.iphone // => true if running on iPhone
744 | // $.os.ipad // => true if running on iPad
745 | // $.os.blackberry // => true if running on BlackBerry
746 | //
747 | // ### $.browser
748 | //
749 | // *Example:*
750 | //
751 | // $.browser.webkit // => true if the browser is WebKit-based
752 | // $.browser.version // => WebKit version string
753 | detect.call($, navigator.userAgent);
754 |
755 | // make available to unit tests
756 | $.__detect = detect;
757 |
758 | })(Zepto);
759 | // Zepto.js
760 | // (c) 2010, 2011 Thomas Fuchs
761 | // Zepto.js may be freely distributed under the MIT license.
762 |
763 | (function($, undefined){
764 | var prefix = '', eventPrefix, endEventName, endAnimationName,
765 | vendors = {Webkit: 'webkit', Moz: '', O: 'o', ms: 'MS'},
766 | document = window.document, testEl = document.createElement('div'),
767 | supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i;
768 |
769 | function downcase(str) { return str.toLowerCase() }
770 | function normalizeEvent(name) { return eventPrefix ? eventPrefix + name : downcase(name) };
771 |
772 | $.each(vendors, function(vendor, event){
773 | if (testEl.style[vendor + 'TransitionProperty'] !== undefined) {
774 | prefix = '-' + downcase(vendor) + '-';
775 | eventPrefix = event;
776 | return false;
777 | }
778 | });
779 |
780 | $.fx = {
781 | off: (eventPrefix === undefined && testEl.style.transitionProperty === undefined),
782 | cssPrefix: prefix,
783 | transitionEnd: normalizeEvent('TransitionEnd'),
784 | animationEnd: normalizeEvent('AnimationEnd')
785 | };
786 |
787 | $.fn.animate = function(properties, duration, ease, callback){
788 | if ($.isObject(duration))
789 | ease = duration.easing, callback = duration.complete, duration = duration.duration;
790 | if (duration) duration = duration / 1000;
791 | return this.anim(properties, duration, ease, callback);
792 | };
793 |
794 | $.fn.anim = function(properties, duration, ease, callback){
795 | var transforms, cssProperties = {}, key, that = this, wrappedCallback, endEvent = $.fx.transitionEnd;
796 | if (duration === undefined) duration = 0.4;
797 | if ($.fx.off) duration = 0;
798 |
799 | if (typeof properties == 'string') {
800 | // keyframe animation
801 | cssProperties[prefix + 'animation-name'] = properties;
802 | cssProperties[prefix + 'animation-duration'] = duration + 's';
803 | endEvent = $.fx.animationEnd;
804 | } else {
805 | // CSS transitions
806 | for (key in properties)
807 | if (supportedTransforms.test(key)) {
808 | transforms || (transforms = []);
809 | transforms.push(key + '(' + properties[key] + ')');
810 | }
811 | else cssProperties[key] = properties[key];
812 |
813 | if (transforms) cssProperties[prefix + 'transform'] = transforms.join(' ');
814 | if (!$.fx.off) cssProperties[prefix + 'transition'] = 'all ' + duration + 's ' + (ease || '');
815 | }
816 |
817 | wrappedCallback = function(){
818 | var props = {};
819 | props[prefix + 'transition'] = props[prefix + 'animation-name'] = 'none';
820 | $(this).css(props);
821 | callback && callback.call(this);
822 | }
823 | if (duration > 0) this.one(endEvent, wrappedCallback);
824 |
825 | setTimeout(function() {
826 | that.css(cssProperties);
827 | if (duration <= 0) setTimeout(function() {
828 | that.each(function(){ wrappedCallback.call(this) });
829 | }, 0);
830 | }, 0);
831 |
832 | return this;
833 | };
834 |
835 | testEl = null;
836 | })(Zepto);
837 | // Zepto.js
838 | // (c) 2010, 2011 Thomas Fuchs
839 | // Zepto.js may be freely distributed under the MIT license.
840 |
841 | (function($){
842 | var jsonpID = 0,
843 | isObject = $.isObject,
844 | document = window.document,
845 | key,
846 | name;
847 |
848 | // trigger a custom event and return false if it was cancelled
849 | function triggerAndReturn(context, eventName, data) {
850 | var event = $.Event(eventName);
851 | $(context).trigger(event, data);
852 | return !event.defaultPrevented;
853 | }
854 |
855 | // trigger an Ajax "global" event
856 | function triggerGlobal(settings, context, eventName, data) {
857 | if (settings.global) return triggerAndReturn(context || document, eventName, data);
858 | }
859 |
860 | // Number of active Ajax requests
861 | $.active = 0;
862 |
863 | function ajaxStart(settings) {
864 | if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart');
865 | }
866 | function ajaxStop(settings) {
867 | if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop');
868 | }
869 |
870 | // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable
871 | function ajaxBeforeSend(xhr, settings) {
872 | var context = settings.context;
873 | if (settings.beforeSend.call(context, xhr, settings) === false ||
874 | triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false)
875 | return false;
876 |
877 | triggerGlobal(settings, context, 'ajaxSend', [xhr, settings]);
878 | }
879 | function ajaxSuccess(data, xhr, settings) {
880 | var context = settings.context, status = 'success';
881 | settings.success.call(context, data, status, xhr);
882 | triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data]);
883 | ajaxComplete(status, xhr, settings);
884 | }
885 | // type: "timeout", "error", "abort", "parsererror"
886 | function ajaxError(error, type, xhr, settings) {
887 | var context = settings.context;
888 | settings.error.call(context, xhr, type, error);
889 | triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error]);
890 | ajaxComplete(type, xhr, settings);
891 | }
892 | // status: "success", "notmodified", "error", "timeout", "abort", "parsererror"
893 | function ajaxComplete(status, xhr, settings) {
894 | var context = settings.context;
895 | settings.complete.call(context, xhr, status);
896 | triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings]);
897 | ajaxStop(settings);
898 | }
899 |
900 | // Empty function, used as default callback
901 | function empty() {}
902 |
903 | // ### $.ajaxJSONP
904 | //
905 | // Load JSON from a server in a different domain (JSONP)
906 | //
907 | // *Arguments:*
908 | //
909 | // options — object that configure the request,
910 | // see avaliable options below
911 | //
912 | // *Avaliable options:*
913 | //
914 | // url — url to which the request is sent
915 | // success — callback that is executed if the request succeeds
916 | // error — callback that is executed if the server drops error
917 | // context — in which context to execute the callbacks in
918 | //
919 | // *Example:*
920 | //
921 | // $.ajaxJSONP({
922 | // url: 'http://example.com/projects?callback=?',
923 | // success: function (data) {
924 | // projects.push(json);
925 | // }
926 | // });
927 | //
928 | $.ajaxJSONP = function(options){
929 | var callbackName = 'jsonp' + (++jsonpID),
930 | script = document.createElement('script'),
931 | abort = function(){
932 | $(script).remove();
933 | if (callbackName in window) window[callbackName] = empty;
934 | ajaxComplete(xhr, options, 'abort');
935 | },
936 | xhr = { abort: abort }, abortTimeout;
937 |
938 | window[callbackName] = function(data){
939 | clearTimeout(abortTimeout);
940 | $(script).remove();
941 | delete window[callbackName];
942 | ajaxSuccess(data, xhr, options);
943 | };
944 |
945 | script.src = options.url.replace(/=\?/, '=' + callbackName);
946 | $('head').append(script);
947 |
948 | if (options.timeout > 0) abortTimeout = setTimeout(function(){
949 | xhr.abort();
950 | ajaxComplete(xhr, options, 'timeout');
951 | }, options.timeout);
952 |
953 | return xhr;
954 | };
955 |
956 | // ### $.ajaxSettings
957 | //
958 | // AJAX settings
959 | //
960 | $.ajaxSettings = {
961 | // Default type of request
962 | type: 'GET',
963 | // Callback that is executed before request
964 | beforeSend: empty,
965 | // Callback that is executed if the request succeeds
966 | success: empty,
967 | // Callback that is executed the the server drops error
968 | error: empty,
969 | // Callback that is executed on request complete (both: error and success)
970 | complete: empty,
971 | // The context for the callbacks
972 | context: null,
973 | // Whether to trigger "global" Ajax events
974 | global: true,
975 | // Transport
976 | xhr: function () {
977 | return new window.XMLHttpRequest();
978 | },
979 | // MIME types mapping
980 | accepts: {
981 | script: 'text/javascript, application/javascript',
982 | json: 'application/json',
983 | xml: 'application/xml, text/xml',
984 | html: 'text/html',
985 | text: 'text/plain'
986 | },
987 | // Whether the request is to another domain
988 | crossDomain: false,
989 | // Default timeout
990 | timeout: 0
991 | };
992 |
993 | // ### $.ajax
994 | //
995 | // Perform AJAX request
996 | //
997 | // *Arguments:*
998 | //
999 | // options — object that configure the request,
1000 | // see avaliable options below
1001 | //
1002 | // *Avaliable options:*
1003 | //
1004 | // type ('GET') — type of request GET / POST
1005 | // url (window.location) — url to which the request is sent
1006 | // data — data to send to server,
1007 | // can be string or object
1008 | // dataType ('json') — what response type you accept from
1009 | // the server:
1010 | // 'json', 'xml', 'html', or 'text'
1011 | // timeout (0) — request timeout
1012 | // beforeSend — callback that is executed before
1013 | // request send
1014 | // complete — callback that is executed on request
1015 | // complete (both: error and success)
1016 | // success — callback that is executed if
1017 | // the request succeeds
1018 | // error — callback that is executed if
1019 | // the server drops error
1020 | // context — in which context to execute the
1021 | // callbacks in
1022 | //
1023 | // *Example:*
1024 | //
1025 | // $.ajax({
1026 | // type: 'POST',
1027 | // url: '/projects',
1028 | // data: { name: 'Zepto.js' },
1029 | // dataType: 'html',
1030 | // timeout: 100,
1031 | // context: $('body'),
1032 | // success: function (data) {
1033 | // this.append(data);
1034 | // },
1035 | // error: function (xhr, type) {
1036 | // alert('Error!');
1037 | // }
1038 | // });
1039 | //
1040 | $.ajax = function(options){
1041 | var settings = $.extend({}, options || {});
1042 | for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key];
1043 |
1044 | ajaxStart(settings);
1045 |
1046 | if (!settings.crossDomain) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) &&
1047 | RegExp.$2 != window.location.host;
1048 |
1049 | if (/=\?/.test(settings.url)) return $.ajaxJSONP(settings);
1050 |
1051 | if (!settings.url) settings.url = window.location.toString();
1052 | if (settings.data && !settings.contentType) settings.contentType = 'application/x-www-form-urlencoded';
1053 | if (isObject(settings.data)) settings.data = $.param(settings.data);
1054 |
1055 | if (settings.type.match(/get/i) && settings.data) {
1056 | var queryString = settings.data;
1057 | if (settings.url.match(/\?.*=/)) {
1058 | queryString = '&' + queryString;
1059 | } else if (queryString[0] != '?') {
1060 | queryString = '?' + queryString;
1061 | }
1062 | settings.url += queryString;
1063 | }
1064 |
1065 | var mime = settings.accepts[settings.dataType],
1066 | baseHeaders = { },
1067 | protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol,
1068 | xhr = $.ajaxSettings.xhr(), abortTimeout;
1069 |
1070 | if (!settings.crossDomain) baseHeaders['X-Requested-With'] = 'XMLHttpRequest';
1071 | if (mime) baseHeaders['Accept'] = mime;
1072 | settings.headers = $.extend(baseHeaders, settings.headers || {});
1073 |
1074 | xhr.onreadystatechange = function(){
1075 | if (xhr.readyState == 4) {
1076 | clearTimeout(abortTimeout);
1077 | var result, error = false;
1078 | if ((xhr.status >= 200 && xhr.status < 300) || (xhr.status == 0 && protocol == 'file:')) {
1079 | if (mime == 'application/json' && !(/^\s*$/.test(xhr.responseText))) {
1080 | try { result = JSON.parse(xhr.responseText); }
1081 | catch (e) { error = e; }
1082 | }
1083 | else result = xhr.responseText;
1084 | if (error) ajaxError(error, 'parsererror', xhr, settings);
1085 | else ajaxSuccess(result, xhr, settings);
1086 | } else {
1087 | ajaxError(null, 'error', xhr, settings);
1088 | }
1089 | }
1090 | };
1091 |
1092 | xhr.open(settings.type, settings.url, true);
1093 |
1094 | if (settings.contentType) settings.headers['Content-Type'] = settings.contentType;
1095 | for (name in settings.headers) xhr.setRequestHeader(name, settings.headers[name]);
1096 |
1097 | if (ajaxBeforeSend(xhr, settings) === false) {
1098 | xhr.abort();
1099 | return false;
1100 | }
1101 |
1102 | if (settings.timeout > 0) abortTimeout = setTimeout(function(){
1103 | xhr.onreadystatechange = empty;
1104 | xhr.abort();
1105 | ajaxError(null, 'timeout', xhr, settings);
1106 | }, settings.timeout);
1107 |
1108 | xhr.send(settings.data);
1109 | return xhr;
1110 | };
1111 |
1112 | // ### $.get
1113 | //
1114 | // Load data from the server using a GET request
1115 | //
1116 | // *Arguments:*
1117 | //
1118 | // url — url to which the request is sent
1119 | // success — callback that is executed if the request succeeds
1120 | //
1121 | // *Example:*
1122 | //
1123 | // $.get(
1124 | // '/projects/42',
1125 | // function (data) {
1126 | // $('body').append(data);
1127 | // }
1128 | // );
1129 | //
1130 | $.get = function(url, success){ return $.ajax({ url: url, success: success }) };
1131 |
1132 | // ### $.post
1133 | //
1134 | // Load data from the server using POST request
1135 | //
1136 | // *Arguments:*
1137 | //
1138 | // url — url to which the request is sent
1139 | // [data] — data to send to server, can be string or object
1140 | // [success] — callback that is executed if the request succeeds
1141 | // [dataType] — type of expected response
1142 | // 'json', 'xml', 'html', or 'text'
1143 | //
1144 | // *Example:*
1145 | //
1146 | // $.post(
1147 | // '/projects',
1148 | // { name: 'Zepto.js' },
1149 | // function (data) {
1150 | // $('body').append(data);
1151 | // },
1152 | // 'html'
1153 | // );
1154 | //
1155 | $.post = function(url, data, success, dataType){
1156 | if ($.isFunction(data)) dataType = dataType || success, success = data, data = null;
1157 | return $.ajax({ type: 'POST', url: url, data: data, success: success, dataType: dataType });
1158 | };
1159 |
1160 | // ### $.getJSON
1161 | //
1162 | // Load JSON from the server using GET request
1163 | //
1164 | // *Arguments:*
1165 | //
1166 | // url — url to which the request is sent
1167 | // success — callback that is executed if the request succeeds
1168 | //
1169 | // *Example:*
1170 | //
1171 | // $.getJSON(
1172 | // '/projects/42',
1173 | // function (json) {
1174 | // projects.push(json);
1175 | // }
1176 | // );
1177 | //
1178 | $.getJSON = function(url, success){
1179 | return $.ajax({ url: url, success: success, dataType: 'json' });
1180 | };
1181 |
1182 | // ### $.fn.load
1183 | //
1184 | // Load data from the server into an element
1185 | //
1186 | // *Arguments:*
1187 | //
1188 | // url — url to which the request is sent
1189 | // [success] — callback that is executed if the request succeeds
1190 | //
1191 | // *Examples:*
1192 | //
1193 | // $('#project_container').get(
1194 | // '/projects/42',
1195 | // function () {
1196 | // alert('Project was successfully loaded');
1197 | // }
1198 | // );
1199 | //
1200 | // $('#project_comments').get(
1201 | // '/projects/42 #comments',
1202 | // function () {
1203 | // alert('Comments was successfully loaded');
1204 | // }
1205 | // );
1206 | //
1207 | $.fn.load = function(url, success){
1208 | if (!this.length) return this;
1209 | var self = this, parts = url.split(/\s/), selector;
1210 | if (parts.length > 1) url = parts[0], selector = parts[1];
1211 | $.get(url, function(response){
1212 | self.html(selector ?
1213 | $(document.createElement('div')).html(response).find(selector).html()
1214 | : response);
1215 | success && success.call(self);
1216 | });
1217 | return this;
1218 | };
1219 |
1220 | var escape = encodeURIComponent;
1221 |
1222 | function serialize(params, obj, traditional, scope){
1223 | var array = $.isArray(obj);
1224 | $.each(obj, function(key, value) {
1225 | if (scope) key = traditional ? scope : scope + '[' + (array ? '' : key) + ']';
1226 | // handle data in serializeArray() format
1227 | if (!scope && array) params.add(value.name, value.value);
1228 | // recurse into nested objects
1229 | else if (traditional ? $.isArray(value) : isObject(value))
1230 | serialize(params, value, traditional, key);
1231 | else params.add(key, value);
1232 | });
1233 | }
1234 |
1235 | // ### $.param
1236 | //
1237 | // Encode object as a string of URL-encoded key-value pairs
1238 | //
1239 | // *Arguments:*
1240 | //
1241 | // obj — object to serialize
1242 | // [traditional] — perform shallow serialization
1243 | //
1244 | // *Example:*
1245 | //
1246 | // $.param( { name: 'Zepto.js', version: '0.6' } );
1247 | //
1248 | $.param = function(obj, traditional){
1249 | var params = [];
1250 | params.add = function(k, v){ this.push(escape(k) + '=' + escape(v)) };
1251 | serialize(params, obj, traditional);
1252 | return params.join('&').replace('%20', '+');
1253 | };
1254 | })(Zepto);
1255 | // Zepto.js
1256 | // (c) 2010, 2011 Thomas Fuchs
1257 | // Zepto.js may be freely distributed under the MIT license.
1258 |
1259 | (function ($) {
1260 |
1261 | // ### $.fn.serializeArray
1262 | //
1263 | // Encode a set of form elements as an array of names and values
1264 | //
1265 | // *Example:*
1266 | //
1267 | // $('#login_form').serializeArray();
1268 | //
1269 | // returns
1270 | //
1271 | // [
1272 | // {
1273 | // name: 'email',
1274 | // value: 'koss@nocorp.me'
1275 | // },
1276 | // {
1277 | // name: 'password',
1278 | // value: '123456'
1279 | // }
1280 | // ]
1281 | //
1282 | $.fn.serializeArray = function () {
1283 | var result = [], el;
1284 | $( Array.prototype.slice.call(this.get(0).elements) ).each(function () {
1285 | el = $(this);
1286 | var type = el.attr('type');
1287 | if (
1288 | !this.disabled && type != 'submit' && type != 'reset' && type != 'button' &&
1289 | ((type != 'radio' && type != 'checkbox') || this.checked)
1290 | ) {
1291 | result.push({
1292 | name: el.attr('name'),
1293 | value: el.val()
1294 | });
1295 | }
1296 | });
1297 | return result;
1298 | };
1299 |
1300 | // ### $.fn.serialize
1301 | //
1302 | //
1303 | // Encode a set of form elements as a string for submission
1304 | //
1305 | // *Example:*
1306 | //
1307 | // $('#login_form').serialize();
1308 | //
1309 | // returns
1310 | //
1311 | // "email=koss%40nocorp.me&password=123456"
1312 | //
1313 | $.fn.serialize = function () {
1314 | var result = [];
1315 | this.serializeArray().forEach(function (elm) {
1316 | result.push( encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value) );
1317 | });
1318 | return result.join('&');
1319 | };
1320 |
1321 | // ### $.fn.submit
1322 | //
1323 | // Bind or trigger the submit event for a form
1324 | //
1325 | // *Examples:*
1326 | //
1327 | // To bind a handler for the submit event:
1328 | //
1329 | // $('#login_form').submit(function (e) {
1330 | // alert('Form was submitted!');
1331 | // e.preventDefault();
1332 | // });
1333 | //
1334 | // To trigger form submit:
1335 | //
1336 | // $('#login_form').submit();
1337 | //
1338 | $.fn.submit = function (callback) {
1339 | if (callback) this.bind('submit', callback)
1340 | else if (this.length) {
1341 | var event = $.Event('submit');
1342 | this.eq(0).trigger(event);
1343 | if (!event.defaultPrevented) this.get(0).submit()
1344 | }
1345 | return this;
1346 | }
1347 |
1348 | })(Zepto);
1349 | // Zepto.js
1350 | // (c) 2010, 2011 Thomas Fuchs
1351 | // Zepto.js may be freely distributed under the MIT license.
1352 |
1353 | (function($){
1354 | var touch = {}, touchTimeout;
1355 |
1356 | function parentIfText(node){
1357 | return 'tagName' in node ? node : node.parentNode;
1358 | }
1359 |
1360 | function swipeDirection(x1, x2, y1, y2){
1361 | var xDelta = Math.abs(x1 - x2), yDelta = Math.abs(y1 - y2);
1362 | if (xDelta >= yDelta) {
1363 | return (x1 - x2 > 0 ? 'Left' : 'Right');
1364 | } else {
1365 | return (y1 - y2 > 0 ? 'Up' : 'Down');
1366 | }
1367 | }
1368 |
1369 | var longTapDelay = 750;
1370 | function longTap(){
1371 | if (touch.last && (Date.now() - touch.last >= longTapDelay)) {
1372 | $(touch.target).trigger('longTap');
1373 | touch = {};
1374 | }
1375 | }
1376 |
1377 | $(document).ready(function(){
1378 | $(document.body).bind('touchstart', function(e){
1379 | var now = Date.now(), delta = now - (touch.last || now);
1380 | touch.target = parentIfText(e.touches[0].target);
1381 | touchTimeout && clearTimeout(touchTimeout);
1382 | touch.x1 = e.touches[0].pageX;
1383 | touch.y1 = e.touches[0].pageY;
1384 | if (delta > 0 && delta <= 250) touch.isDoubleTap = true;
1385 | touch.last = now;
1386 | setTimeout(longTap, longTapDelay);
1387 | }).bind('touchmove', function(e){
1388 | touch.x2 = e.touches[0].pageX;
1389 | touch.y2 = e.touches[0].pageY;
1390 | }).bind('touchend', function(e){
1391 | if (touch.isDoubleTap) {
1392 | $(touch.target).trigger('doubleTap');
1393 | touch = {};
1394 | } else if (touch.x2 > 0 || touch.y2 > 0) {
1395 | (Math.abs(touch.x1 - touch.x2) > 30 || Math.abs(touch.y1 - touch.y2) > 30) &&
1396 | $(touch.target).trigger('swipe') &&
1397 | $(touch.target).trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)));
1398 | touch.x1 = touch.x2 = touch.y1 = touch.y2 = touch.last = 0;
1399 | } else if ('last' in touch) {
1400 | touchTimeout = setTimeout(function(){
1401 | touchTimeout = null;
1402 | $(touch.target).trigger('tap')
1403 | touch = {};
1404 | }, 250);
1405 | }
1406 | }).bind('touchcancel', function(){ touch = {} });
1407 | });
1408 |
1409 | ['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'longTap'].forEach(function(m){
1410 | $.fn[m] = function(callback){ return this.bind(m, callback) }
1411 | });
1412 | })(Zepto);
1413 |
--------------------------------------------------------------------------------