omniboard_jqtouch 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/MIT-LICENSE +19 -0
  2. data/README.rdoc +21 -0
  3. data/lib/omniboard_jqtouch.rb +11 -0
  4. data/lib/public/iphone/404.html +26 -0
  5. data/lib/public/iphone/422.html +26 -0
  6. data/lib/public/iphone/500.html +26 -0
  7. data/lib/public/iphone/favicon.ico +0 -0
  8. data/lib/public/iphone/images/rails.png +0 -0
  9. data/lib/public/iphone/javascripts/application.js +51 -0
  10. data/lib/public/iphone/javascripts/jqtouch.js +634 -0
  11. data/lib/public/iphone/javascripts/jqtouch.min.js +1 -0
  12. data/lib/public/iphone/javascripts/jquery-1.4.3.js +6883 -0
  13. data/lib/public/iphone/robots.txt +5 -0
  14. data/lib/public/iphone/stylesheets/jqtouch.css +373 -0
  15. data/lib/public/iphone/stylesheets/themes/apple/img/backButton.png +0 -0
  16. data/lib/public/iphone/stylesheets/themes/apple/img/blueButton.png +0 -0
  17. data/lib/public/iphone/stylesheets/themes/apple/img/cancel.png +0 -0
  18. data/lib/public/iphone/stylesheets/themes/apple/img/chevron.png +0 -0
  19. data/lib/public/iphone/stylesheets/themes/apple/img/grayButton.png +0 -0
  20. data/lib/public/iphone/stylesheets/themes/apple/img/listArrowSel.png +0 -0
  21. data/lib/public/iphone/stylesheets/themes/apple/img/listGroup.png +0 -0
  22. data/lib/public/iphone/stylesheets/themes/apple/img/loading.gif +0 -0
  23. data/lib/public/iphone/stylesheets/themes/apple/img/on_off.png +0 -0
  24. data/lib/public/iphone/stylesheets/themes/apple/img/pinstripes.png +0 -0
  25. data/lib/public/iphone/stylesheets/themes/apple/img/selection.png +0 -0
  26. data/lib/public/iphone/stylesheets/themes/apple/img/thumb.png +0 -0
  27. data/lib/public/iphone/stylesheets/themes/apple/img/toggle.png +0 -0
  28. data/lib/public/iphone/stylesheets/themes/apple/img/toggleOn.png +0 -0
  29. data/lib/public/iphone/stylesheets/themes/apple/img/toolButton.png +0 -0
  30. data/lib/public/iphone/stylesheets/themes/apple/img/toolbar.png +0 -0
  31. data/lib/public/iphone/stylesheets/themes/apple/img/whiteButton.png +0 -0
  32. data/lib/public/iphone/stylesheets/themes/apple/theme.css +677 -0
  33. data/lib/public/iphone/stylesheets/themes/apple/theme.min.css +1 -0
  34. data/lib/public/iphone/stylesheets/themes/jqt/img/back_button.png +0 -0
  35. data/lib/public/iphone/stylesheets/themes/jqt/img/back_button_clicked.png +0 -0
  36. data/lib/public/iphone/stylesheets/themes/jqt/img/button.png +0 -0
  37. data/lib/public/iphone/stylesheets/themes/jqt/img/button_clicked.png +0 -0
  38. data/lib/public/iphone/stylesheets/themes/jqt/img/chevron.png +0 -0
  39. data/lib/public/iphone/stylesheets/themes/jqt/img/chevron_circle.png +0 -0
  40. data/lib/public/iphone/stylesheets/themes/jqt/img/grayButton.png +0 -0
  41. data/lib/public/iphone/stylesheets/themes/jqt/img/loading.gif +0 -0
  42. data/lib/public/iphone/stylesheets/themes/jqt/img/on_off.png +0 -0
  43. data/lib/public/iphone/stylesheets/themes/jqt/img/rowhead.png +0 -0
  44. data/lib/public/iphone/stylesheets/themes/jqt/img/toggle.png +0 -0
  45. data/lib/public/iphone/stylesheets/themes/jqt/img/toggleOn.png +0 -0
  46. data/lib/public/iphone/stylesheets/themes/jqt/img/toolbar.png +0 -0
  47. data/lib/public/iphone/stylesheets/themes/jqt/img/whiteButton.png +0 -0
  48. data/lib/public/iphone/stylesheets/themes/jqt/theme.css +527 -0
  49. data/lib/public/iphone/stylesheets/themes/jqt/theme.min.css +1 -0
  50. data/lib/views/application.erb +49 -0
  51. metadata +127 -0
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 Matt Yoho
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,21 @@
1
+ == OmniboardJqTouch
2
+
3
+ OmniboardjQTouch is a simple companion app for the Omniboard application
4
+ built on jQTouch for use with the iPhone. It is meant to be mounted as a
5
+ Rack endpoint inside of a Rails 3 application.
6
+
7
+
8
+ === In the Rails App
9
+
10
+ Add the following to the Gemfile:
11
+
12
+ gem 'omniboard_jqtouch', '~> 0.2.0'
13
+
14
+ And add this entry to the routes file:
15
+
16
+ scope '/iphone' do
17
+ match '(*path)', :to => OmniboardJqTouch
18
+ end
19
+
20
+
21
+
@@ -0,0 +1,11 @@
1
+ require 'sinatra/base'
2
+ require 'erb'
3
+
4
+ class OmniboardJqTouch < Sinatra::Base
5
+ set :root, File.dirname(__FILE__)
6
+
7
+ get '/iphone' do
8
+ erb :application
9
+ end
10
+
11
+ end
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/404.html -->
21
+ <div class="dialog">
22
+ <h1>The page you were looking for doesn't exist.</h1>
23
+ <p>You may have mistyped the address or the page may have moved.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/422.html -->
21
+ <div class="dialog">
22
+ <h1>The change you wanted was rejected.</h1>
23
+ <p>Maybe you tried to change something you didn't have access to.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/500.html -->
21
+ <div class="dialog">
22
+ <h1>We're sorry, but something went wrong.</h1>
23
+ <p>We've been notified about this issue and we'll take a look at it shortly.</p>
24
+ </div>
25
+ </body>
26
+ </html>
File without changes
@@ -0,0 +1,51 @@
1
+ $.fn.extend({
2
+ storeApiKey: function() {
3
+ $('#home').data('apiKey', this.val());
4
+ }
5
+ });
6
+
7
+ function apiKey() {
8
+ return $('#home').data('apiKey');
9
+ };
10
+
11
+ $(function(){
12
+
13
+ // Handle orientation change
14
+ $('body').bind('turn', function(e, data){
15
+ $('#orient').html('Orientation: ' + data.orientation);
16
+ });
17
+
18
+ // Verify user wants to open a new window
19
+ $('a[target="_blank"]').click(function() {
20
+ if (confirm('This link opens in a new window.')) {
21
+ return true;
22
+ } else {
23
+ $(this).removeClass('active');
24
+ return false;
25
+ }
26
+ });
27
+
28
+ // Jump to projects page if API key present
29
+ $('#home').bind('pageAnimationStart', function(e, info){
30
+ if ($(this).data('api_key')) {
31
+ $('.home a[href="#project"]').click();
32
+ }
33
+ });
34
+
35
+ $('#projects').
36
+ bind('pageAnimationStart', function(e, info){
37
+ $('#home input#api_key').storeApiKey();
38
+ }).
39
+ bind('pageAnimationEnd', function(e, info){
40
+ var container = $(this).find('#listing');
41
+ var token = {auth_token: apiKey()};
42
+ $.get('api/projects?auth_token='+token.auth_token, {}, function(data) {
43
+ $('ul', container).replaceWith('<ul></ul>');
44
+ for(var i = 0; i < data.length; i++) {
45
+ $('ul', container).append('<li><h2>'+data[i].project.name+'</h2>' +
46
+ '<p>' +data[i].project.description+'</p></li>');
47
+ }
48
+ });
49
+ });
50
+
51
+ });
@@ -0,0 +1,634 @@
1
+ /*
2
+
3
+ _/ _/_/ _/_/_/_/_/ _/
4
+ _/ _/ _/ _/_/ _/ _/ _/_/_/ _/_/_/
5
+ _/ _/ _/_/ _/ _/ _/ _/ _/ _/ _/ _/
6
+ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/
7
+ _/ _/_/ _/ _/ _/_/ _/_/_/ _/_/_/ _/ _/
8
+ _/
9
+ _/
10
+
11
+ Created by David Kaneda <http://www.davidkaneda.com>
12
+ Documentation and issue tracking on Google Code <http://code.google.com/p/jqtouch/>
13
+
14
+ Special thanks to Jonathan Stark <http://jonathanstark.com/>
15
+ and pinch/zoom <http://www.pinchzoom.com/>
16
+
17
+ (c) 2009 by jQTouch project members.
18
+ See LICENSE.txt for license.
19
+
20
+ $Revision: 109 $
21
+ $Date: 2009-10-06 12:23:30 -0400 (Tue, 06 Oct 2009) $
22
+ $LastChangedBy: davidcolbykaneda $
23
+
24
+ */
25
+
26
+ (function($) {
27
+ $.jQTouch = function(options) {
28
+
29
+ // Set support values
30
+ $.support.WebKitCSSMatrix = (typeof WebKitCSSMatrix == "object");
31
+ $.support.touch = (typeof Touch == "object");
32
+ $.support.WebKitAnimationEvent = (typeof WebKitTransitionEvent == "object");
33
+
34
+ // Initialize internal variables
35
+ var $body,
36
+ $head=$('head'),
37
+ hist=[],
38
+ newPageCount=0,
39
+ jQTSettings={},
40
+ hashCheck,
41
+ currentPage,
42
+ orientation,
43
+ isMobileWebKit = RegExp(" Mobile/").test(navigator.userAgent),
44
+ tapReady=true,
45
+ lastAnimationTime=0,
46
+ touchSelectors=[],
47
+ publicObj={},
48
+ extensions=$.jQTouch.prototype.extensions,
49
+ defaultAnimations=['slide','flip','slideup','swap','cube','pop','dissolve','fade','back'],
50
+ animations=[],
51
+ hairextensions='';
52
+
53
+ // Get the party started
54
+ init(options);
55
+
56
+ function init(options) {
57
+
58
+ var defaults = {
59
+ addGlossToIcon: true,
60
+ backSelector: '.back, .cancel, .goback',
61
+ cacheGetRequests: true,
62
+ cubeSelector: '.cube',
63
+ dissolveSelector: '.dissolve',
64
+ fadeSelector: '.fade',
65
+ fixedViewport: true,
66
+ flipSelector: '.flip',
67
+ formSelector: 'form',
68
+ fullScreen: true,
69
+ fullScreenClass: 'fullscreen',
70
+ icon: null,
71
+ touchSelector: 'a, .touch',
72
+ popSelector: '.pop',
73
+ preloadImages: false,
74
+ slideSelector: 'body > * > ul li a',
75
+ slideupSelector: '.slideup',
76
+ startupScreen: null,
77
+ statusBar: 'default', // other options: black-translucent, black
78
+ submitSelector: '.submit',
79
+ swapSelector: '.swap',
80
+ useAnimations: true,
81
+ useFastTouch: true // Experimental.
82
+ };
83
+ jQTSettings = $.extend({}, defaults, options);
84
+
85
+ // Preload images
86
+ if (jQTSettings.preloadImages) {
87
+ for (var i = jQTSettings.preloadImages.length - 1; i >= 0; i--){
88
+ (new Image()).src = jQTSettings.preloadImages[i];
89
+ };
90
+ }
91
+ // Set icon
92
+ if (jQTSettings.icon) {
93
+ var precomposed = (jQTSettings.addGlossToIcon) ? '' : '-precomposed';
94
+ hairextensions += '<link rel="apple-touch-icon' + precomposed + '" href="' + jQTSettings.icon + '" />';
95
+ }
96
+ // Set startup screen
97
+ if (jQTSettings.startupScreen) {
98
+ hairextensions += '<link rel="apple-touch-startup-image" href="' + jQTSettings.startupScreen + '" />';
99
+ }
100
+ // Set viewport
101
+ if (jQTSettings.fixedViewport) {
102
+ hairextensions += '<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;"/>';
103
+ }
104
+ // Set full-screen
105
+ if (jQTSettings.fullScreen) {
106
+ hairextensions += '<meta name="apple-mobile-web-app-capable" content="yes" />';
107
+ if (jQTSettings.statusBar) {
108
+ hairextensions += '<meta name="apple-mobile-web-app-status-bar-style" content="' + jQTSettings.statusBar + '" />';
109
+ }
110
+ }
111
+ if (hairextensions) $head.append(hairextensions);
112
+
113
+ // Initialize on document load:
114
+ $(document).ready(function(){
115
+
116
+ // Add extensions
117
+ for (var i in extensions)
118
+ {
119
+ var fn = extensions[i];
120
+ if ($.isFunction(fn))
121
+ {
122
+ $.extend(publicObj, fn(publicObj));
123
+ }
124
+ }
125
+
126
+ // Add animations
127
+ for (var i in defaultAnimations)
128
+ {
129
+ var name = defaultAnimations[i];
130
+ var selector = jQTSettings[name + 'Selector'];
131
+ if (typeof(selector) == 'string') {
132
+ addAnimation({name:name, selector:selector});
133
+ }
134
+ }
135
+
136
+ touchSelectors.push('input');
137
+ touchSelectors.push(jQTSettings.touchSelector);
138
+ touchSelectors.push(jQTSettings.backSelector);
139
+ touchSelectors.push(jQTSettings.submitSelector);
140
+ $(touchSelectors.join(', ')).css('-webkit-touch-callout', 'none');
141
+ $(jQTSettings.backSelector).tap(liveTap);
142
+ $(jQTSettings.submitSelector).tap(submitParentForm);
143
+
144
+ $body = $('body');
145
+
146
+ if (jQTSettings.fullScreenClass && window.navigator.standalone == true) {
147
+ $body.addClass(jQTSettings.fullScreenClass + ' ' + jQTSettings.statusBar);
148
+ }
149
+
150
+ // Create custom live events
151
+ $body
152
+ .bind('touchstart', handleTouch)
153
+ .bind('orientationchange', updateOrientation)
154
+ .trigger('orientationchange')
155
+ .submit(submitForm);
156
+
157
+ if (jQTSettings.useFastTouch && $.support.touch)
158
+ {
159
+ $body.click(function(e){
160
+ var $el = $(e.target);
161
+ if ($el.attr('target') == '_blank' || $el.attr('rel') == 'external' || $el.is('input[type="checkbox"]'))
162
+ {
163
+ return true;
164
+ } else {
165
+ return false;
166
+ }
167
+ });
168
+
169
+ // This additionally gets rid of form focusses
170
+ $body.mousedown(function(e){
171
+ var timeDiff = (new Date()).getTime() - lastAnimationTime;
172
+ if (timeDiff < 200)
173
+ {
174
+ return false;
175
+ }
176
+ });
177
+ }
178
+
179
+ // Make sure exactly one child of body has "current" class
180
+ if ($('body > .current').length == 0) {
181
+ currentPage = $('body > *:first');
182
+ } else {
183
+ currentPage = $('body > .current:first');
184
+ $('body > .current').removeClass('current');
185
+ }
186
+
187
+ // Go to the top of the "current" page
188
+ $(currentPage).addClass('current');
189
+ location.hash = $(currentPage).attr('id');
190
+ addPageToHistory(currentPage);
191
+ scrollTo(0, 0);
192
+ dumbLoopStart();
193
+ });
194
+ }
195
+
196
+ // PUBLIC FUNCTIONS
197
+ function goBack(to) {
198
+ // Init the param
199
+ if (hist.length > 1) {
200
+ var numberOfPages = Math.min(parseInt(to || 1, 10), hist.length-1);
201
+
202
+ // Search through the history for an ID
203
+ if( isNaN(numberOfPages) && typeof(to) === "string" && to != '#' ) {
204
+ for( var i=1, length=hist.length; i < length; i++ ) {
205
+ if( '#' + hist[i].id === to ) {
206
+ numberOfPages = i;
207
+ break;
208
+ }
209
+ }
210
+ }
211
+
212
+ // If still nothing, assume one
213
+ if( isNaN(numberOfPages) || numberOfPages < 1 ) {
214
+ numberOfPages = 1;
215
+ };
216
+
217
+ // Grab the current page for the "from" info
218
+ var animation = hist[0].animation;
219
+ var fromPage = hist[0].page;
220
+
221
+ // Remove all pages in front of the target page
222
+ hist.splice(0, numberOfPages);
223
+
224
+ // Grab the target page
225
+ var toPage = hist[0].page;
226
+
227
+ // Make the animations
228
+ animatePages(fromPage, toPage, animation, true);
229
+
230
+ return publicObj;
231
+ } else {
232
+ console.error('No pages in history.');
233
+ return false;
234
+ }
235
+ }
236
+ function goTo(toPage, animation) {
237
+ var fromPage = hist[0].page;
238
+
239
+ if (typeof(toPage) === 'string') {
240
+ toPage = $(toPage);
241
+ }
242
+ if (typeof(animation) === 'string') {
243
+ for (var i = animations.length - 1; i >= 0; i--){
244
+ if (animations[i].name === animation)
245
+ {
246
+ animation = animations[i];
247
+ break;
248
+ }
249
+ }
250
+ }
251
+ if (animatePages(fromPage, toPage, animation)) {
252
+ addPageToHistory(toPage, animation);
253
+ return publicObj;
254
+ }
255
+ else
256
+ {
257
+ console.error('Could not animate pages.');
258
+ return false;
259
+ }
260
+ }
261
+ function getOrientation() {
262
+ return orientation;
263
+ }
264
+
265
+ // PRIVATE FUNCTIONS
266
+ function liveTap(e){
267
+
268
+ // Grab the clicked element
269
+ var $el = $(e.target);
270
+
271
+ if ($el.attr('nodeName')!=='A'){
272
+ $el = $el.parent('a');
273
+ }
274
+
275
+ var target = $el.attr('target'),
276
+ hash = $el.attr('hash'),
277
+ animation=null;
278
+
279
+ if (tapReady == false || !$el.length) {
280
+ console.warn('Not able to tap element.')
281
+ return false;
282
+ }
283
+
284
+ if ($el.attr('target') == '_blank' || $el.attr('rel') == 'external')
285
+ {
286
+ return true;
287
+ }
288
+
289
+ // Figure out the animation to use
290
+ for (var i = animations.length - 1; i >= 0; i--){
291
+ if ($el.is(animations[i].selector)) {
292
+ animation = animations[i];
293
+ break;
294
+ }
295
+ };
296
+
297
+ // User clicked an internal link, fullscreen mode
298
+ if (target == '_webapp') {
299
+ window.location = $el.attr('href');
300
+ }
301
+ // User clicked a back button
302
+ else if ($el.is(jQTSettings.backSelector)) {
303
+ goBack(hash);
304
+ }
305
+ // Branch on internal or external href
306
+ else if (hash && hash!='#') {
307
+ $el.addClass('active');
308
+ goTo($(hash).data('referrer', $el), animation);
309
+ } else {
310
+ $el.addClass('loading active');
311
+ showPageByHref($el.attr('href'), {
312
+ animation: animation,
313
+ callback: function(){
314
+ $el.removeClass('loading'); setTimeout($.fn.unselect, 250, $el);
315
+ },
316
+ $referrer: $el
317
+ });
318
+ }
319
+ return false;
320
+ }
321
+ function addPageToHistory(page, animation) {
322
+ // Grab some info
323
+ var pageId = page.attr('id');
324
+
325
+ // Prepend info to page history
326
+ hist.unshift({
327
+ page: page,
328
+ animation: animation,
329
+ id: pageId
330
+ });
331
+ }
332
+ function animatePages(fromPage, toPage, animation, backwards) {
333
+ // Error check for target page
334
+ if(toPage.length === 0){
335
+ $.fn.unselect();
336
+ console.error('Target element is missing.');
337
+ return false;
338
+ }
339
+
340
+ // Collapse the keyboard
341
+ $(':focus').blur();
342
+
343
+ // Make sure we are scrolled up to hide location bar
344
+ scrollTo(0, 0);
345
+
346
+ // Define callback to run after animation completes
347
+ var callback = function(event){
348
+
349
+ if (animation)
350
+ {
351
+ toPage.removeClass('in reverse ' + animation.name);
352
+ fromPage.removeClass('current out reverse ' + animation.name);
353
+ }
354
+ else
355
+ {
356
+ fromPage.removeClass('current');
357
+ }
358
+
359
+ toPage.trigger('pageAnimationEnd', { direction: 'in' });
360
+ fromPage.trigger('pageAnimationEnd', { direction: 'out' });
361
+
362
+ clearInterval(dumbLoop);
363
+ currentPage = toPage;
364
+ location.hash = currentPage.attr('id');
365
+ dumbLoopStart();
366
+
367
+ var $originallink = toPage.data('referrer');
368
+ if ($originallink) {
369
+ $originallink.unselect();
370
+ }
371
+ lastAnimationTime = (new Date()).getTime();
372
+ tapReady = true;
373
+ }
374
+
375
+ fromPage.trigger('pageAnimationStart', { direction: 'out' });
376
+ toPage.trigger('pageAnimationStart', { direction: 'in' });
377
+
378
+ if ($.support.WebKitAnimationEvent && animation && jQTSettings.useAnimations) {
379
+ toPage.one('webkitAnimationEnd', callback);
380
+ tapReady = false;
381
+ toPage.addClass(animation.name + ' in current ' + (backwards ? ' reverse' : ''));
382
+ fromPage.addClass(animation.name + ' out' + (backwards ? ' reverse' : ''));
383
+ } else {
384
+ toPage.addClass('current');
385
+ callback();
386
+ }
387
+
388
+ return true;
389
+ }
390
+ function dumbLoopStart() {
391
+ dumbLoop = setInterval(function(){
392
+ var curid = currentPage.attr('id');
393
+ if (location.hash == '') {
394
+ location.hash = '#' + curid;
395
+ } else if (location.hash != '#' + curid) {
396
+ try {
397
+ goBack(location.hash)
398
+ } catch(e) {
399
+ console.error('Unknown hash change.');
400
+ }
401
+ }
402
+ }, 100);
403
+ }
404
+ function insertPages(nodes, animation) {
405
+ var targetPage = null;
406
+ $(nodes).each(function(index, node){
407
+ var $node = $(this);
408
+ if (!$node.attr('id')) {
409
+ $node.attr('id', 'page-' + (++newPageCount));
410
+ }
411
+ $node.appendTo($body);
412
+ if ($node.hasClass('current') || !targetPage ) {
413
+ targetPage = $node;
414
+ }
415
+ });
416
+ if (targetPage !== null) {
417
+ goTo(targetPage, animation);
418
+ return targetPage;
419
+ }
420
+ else
421
+ {
422
+ return false;
423
+ }
424
+ }
425
+ function showPageByHref(href, options) {
426
+ var defaults = {
427
+ data: null,
428
+ method: 'GET',
429
+ animation: null,
430
+ callback: null,
431
+ $referrer: null
432
+ };
433
+
434
+ var settings = $.extend({}, defaults, options);
435
+
436
+ if (href != '#')
437
+ {
438
+ $.ajax({
439
+ url: href,
440
+ data: settings.data,
441
+ type: settings.method,
442
+ success: function (data, textStatus) {
443
+ var firstPage = insertPages(data, settings.animation);
444
+ if (firstPage)
445
+ {
446
+ if (settings.method == 'GET' && jQTSettings.cacheGetRequests && settings.$referrer)
447
+ {
448
+ settings.$referrer.attr('href', '#' + firstPage.attr('id'));
449
+ }
450
+ if (settings.callback) {
451
+ settings.callback(true);
452
+ }
453
+ }
454
+ },
455
+ error: function (data) {
456
+ if (settings.$referrer) settings.$referrer.unselect();
457
+ if (settings.callback) {
458
+ settings.callback(false);
459
+ }
460
+ }
461
+ });
462
+ }
463
+ else if ($referrer)
464
+ {
465
+ $referrer.unselect();
466
+ }
467
+ }
468
+ function submitForm(e, callback){
469
+ var $form = (typeof(e)==='string') ? $(e) : $(e.target);
470
+
471
+ if ($form.length && $form.is(jQTSettings.formSelector) && $form.attr('action')) {
472
+ showPageByHref($form.attr('action'), {
473
+ data: $form.serialize(),
474
+ method: $form.attr('method') || "POST",
475
+ animation: animations[0] || null,
476
+ callback: callback
477
+ });
478
+ return false;
479
+ }
480
+ return true;
481
+ }
482
+ function submitParentForm(e){
483
+ var $form = $(this).closest('form');
484
+ if ($form.length)
485
+ {
486
+ evt = jQuery.Event("submit");
487
+ evt.preventDefault();
488
+ $form.trigger(evt);
489
+ return false;
490
+ }
491
+ return true;
492
+ }
493
+ function addAnimation(animation) {
494
+ if (typeof(animation.selector) == 'string' && typeof(animation.name) == 'string') {
495
+ animations.push(animation);
496
+ $(animation.selector).tap(liveTap);
497
+ touchSelectors.push(animation.selector);
498
+ }
499
+ }
500
+ function updateOrientation() {
501
+ orientation = window.innerWidth < window.innerHeight ? 'profile' : 'landscape';
502
+ $body.removeClass('profile landscape').addClass(orientation).trigger('turn', {orientation: orientation});
503
+ // scrollTo(0, 0);
504
+ }
505
+ function handleTouch(e) {
506
+
507
+ var $el = $(e.target);
508
+
509
+ // Only handle touchSelectors
510
+ if (!$(e.target).is(touchSelectors.join(', ')))
511
+ {
512
+ var $link = $(e.target).closest('a');
513
+
514
+ if ($link.length){
515
+ $el = $link;
516
+ } else {
517
+ return;
518
+ }
519
+ }
520
+ if (event)
521
+ {
522
+ var hoverTimeout = null,
523
+ startX = event.changedTouches[0].clientX,
524
+ startY = event.changedTouches[0].clientY,
525
+ startTime = (new Date).getTime(),
526
+ deltaX = 0,
527
+ deltaY = 0,
528
+ deltaT = 0;
529
+
530
+ // Let's bind these after the fact, so we can keep some internal values
531
+ $el.bind('touchmove', touchmove).bind('touchend', touchend);
532
+
533
+ hoverTimeout = setTimeout(function(){
534
+ $el.makeActive();
535
+ }, 100);
536
+
537
+ }
538
+
539
+ // Private touch functions (TODO: insert dirty joke)
540
+ function touchmove(e) {
541
+
542
+ updateChanges();
543
+ var absX = Math.abs(deltaX);
544
+ var absY = Math.abs(deltaY);
545
+
546
+ // Check for swipe
547
+ if (absX > absY && (absX > 35) && deltaT < 1000) {
548
+ $el.trigger('swipe', {direction: (deltaX < 0) ? 'left' : 'right'}).unbind('touchmove touchend');
549
+ } else if (absY > 1) {
550
+ $el.removeClass('active');
551
+ }
552
+
553
+ clearTimeout(hoverTimeout);
554
+ }
555
+
556
+ function touchend(){
557
+ updateChanges();
558
+
559
+ if (deltaY === 0 && deltaX === 0) {
560
+ $el.makeActive();
561
+ // New approach:
562
+ // Fake the double click?
563
+ // TODO: Try with all click events (no tap)
564
+ // if (deltaT < 40)
565
+ // {
566
+ // setTimeout(function(){
567
+ // $el.trigger('touchstart')
568
+ // .trigger('touchend');
569
+ // }, 0);
570
+ // }
571
+ $el.trigger('tap');
572
+ } else {
573
+ $el.removeClass('active');
574
+ }
575
+ $el.unbind('touchmove touchend');
576
+ clearTimeout(hoverTimeout);
577
+ }
578
+
579
+ function updateChanges(){
580
+ var first = event.changedTouches[0] || null;
581
+ deltaX = first.pageX - startX;
582
+ deltaY = first.pageY - startY;
583
+ deltaT = (new Date).getTime() - startTime;
584
+ }
585
+
586
+ } // End touch handler
587
+
588
+ // Public jQuery Fns
589
+ $.fn.unselect = function(obj) {
590
+ if (obj) {
591
+ obj.removeClass('active');
592
+ } else {
593
+ $('.active').removeClass('active');
594
+ }
595
+ }
596
+ $.fn.makeActive = function(){
597
+ return $(this).addClass('active');
598
+ }
599
+ $.fn.swipe = function(fn) {
600
+ if ($.isFunction(fn))
601
+ {
602
+ return this.each(function(i, el){
603
+ $(el).bind('swipe', fn);
604
+ });
605
+ }
606
+ }
607
+ $.fn.tap = function(fn){
608
+ if ($.isFunction(fn))
609
+ {
610
+ var tapEvent = (jQTSettings.useFastTouch && $.support.touch) ? 'tap' : 'click';
611
+ return $(this).live(tapEvent, fn);
612
+ } else {
613
+ $(this).trigger('tap');
614
+ }
615
+ }
616
+
617
+ publicObj = {
618
+ getOrientation: getOrientation,
619
+ goBack: goBack,
620
+ goTo: goTo,
621
+ addAnimation: addAnimation,
622
+ submitForm: submitForm
623
+ }
624
+
625
+ return publicObj;
626
+ }
627
+
628
+ // Extensions directly manipulate the jQTouch object, before it's initialized.
629
+ $.jQTouch.prototype.extensions = [];
630
+ $.jQTouch.addExtension = function(extension){
631
+ $.jQTouch.prototype.extensions.push(extension);
632
+ }
633
+
634
+ })(jQuery);