chui-rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +1 -0
  7. data/chui-rails.gemspec +23 -0
  8. data/lib/chui/rails.rb +7 -0
  9. data/lib/chui/rails/version.rb +5 -0
  10. data/vendor/assets/images/app-icons/app.png +0 -0
  11. data/vendor/assets/images/app-icons/browser.png +0 -0
  12. data/vendor/assets/images/app-icons/mail.png +0 -0
  13. data/vendor/assets/images/app-icons/music.png +0 -0
  14. data/vendor/assets/images/app-icons/weather.png +0 -0
  15. data/vendor/assets/images/icons/Camera.svg +55 -0
  16. data/vendor/assets/images/icons/Documents.svg +71 -0
  17. data/vendor/assets/images/icons/Download.svg +8 -0
  18. data/vendor/assets/images/icons/Favorite.svg +25 -0
  19. data/vendor/assets/images/icons/Head_phones.svg +32 -0
  20. data/vendor/assets/images/icons/android.svg +15 -0
  21. data/vendor/assets/images/icons/arrow_down.svg +6 -0
  22. data/vendor/assets/images/icons/arrow_left.svg +6 -0
  23. data/vendor/assets/images/icons/arrow_right.svg +6 -0
  24. data/vendor/assets/images/icons/arrow_up.svg +6 -0
  25. data/vendor/assets/images/icons/down.svg +13 -0
  26. data/vendor/assets/images/icons/left.svg +13 -0
  27. data/vendor/assets/images/icons/right.svg +13 -0
  28. data/vendor/assets/images/icons/up.svg +13 -0
  29. Harm.jpg +0 -0
  30. data/vendor/assets/images/music/Imagine Dragons.jpg +0 -0
  31. data/vendor/assets/images/music/Kiss.jpg +0 -0
  32. data/vendor/assets/images/music/Permanent.jpg +0 -0
  33. data/vendor/assets/images/music/The Olms.jpg +0 -0
  34. data/vendor/assets/images/music/Willy Moon.jpg +0 -0
  35. data/vendor/assets/javascripts/chui-3.7.0.js +2796 -0
  36. data/vendor/assets/javascripts/chui-3.7.0.min.js +9 -0
  37. data/vendor/assets/stylesheets/chui-android-3.7.0.css +2970 -0
  38. data/vendor/assets/stylesheets/chui-android-3.7.0.min.css +8 -0
  39. data/vendor/assets/stylesheets/chui-ios-3.7.0.css +2614 -0
  40. data/vendor/assets/stylesheets/chui-ios-3.7.0.min.css +8 -0
  41. data/vendor/assets/stylesheets/chui-win-3.7.0.css +2375 -0
  42. data/vendor/assets/stylesheets/chui-win-3.7.0.min.css +8 -0
  43. metadata +113 -0
Harm.jpg ADDED
Binary file
@@ -0,0 +1,2796 @@
1
+ /*
2
+ pO\
3
+ 6 /\
4
+ /OO\
5
+ /OOOO\
6
+ /OOOOOO\
7
+ (OOOOOOOO)
8
+ \:~==~:/
9
+
10
+ ChocolateChip-UI
11
+ ChUI.js
12
+ Copyright 2014 Sourcebits www.sourcebits.com
13
+ License: MIT
14
+ Version: 3.7.0
15
+ */
16
+ window.CHUIJSLIB;
17
+ if(window.jQuery) {
18
+ window.CHUIJSLIB = window.jQuery;
19
+ } else if (window.$chocolatechipjs) {
20
+ window.CHUIJSLIB = window.$chocolatechipjs;
21
+ }
22
+ (function($) {
23
+
24
+ $.extend({
25
+ ///////////////
26
+ // Create Uuid:
27
+ ///////////////
28
+ UuidBit : 1,
29
+
30
+ Uuid : function() {
31
+ this.UuidBit++;
32
+ return Date.now().toString(36) + this.UuidBit;
33
+ },
34
+
35
+ ///////////////////////////
36
+ // Concat array of strings:
37
+ ///////////////////////////
38
+ concat : function ( args ) {
39
+ return (args instanceof Array) ? args.join('') : [].slice.apply(arguments).join('');
40
+ },
41
+ ////////////////////////////
42
+ // Version of each that uses
43
+ // regular parameter order:
44
+ ////////////////////////////
45
+ forEach : function ( obj, callback, args ) {
46
+ function isArraylike( obj ) {
47
+ var length = obj.length,
48
+ type = typeof obj;
49
+ if ( type === "function" || obj === window ) {
50
+ return false;
51
+ }
52
+ if ( obj.nodeType === 1 && length ) {
53
+ return true;
54
+ }
55
+ return type === "array" || length === 0 ||
56
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj;
57
+ }
58
+ var value,
59
+ i = 0,
60
+ length = obj.length,
61
+ isArray = isArraylike( obj );
62
+ if ( args ) {
63
+ if ( isArray ) {
64
+ for ( ; i < length; i++ ) {
65
+ value = callback.apply( obj[ i ], args );
66
+ if ( value === false ) {
67
+ break;
68
+ }
69
+ }
70
+ } else {
71
+ for ( i in obj ) {
72
+ value = callback.apply( obj[ i ], args );
73
+ if ( value === false ) {
74
+ break;
75
+ }
76
+ }
77
+ }
78
+ // A special, fast, case for the most common use of each
79
+ } else {
80
+ if ( isArray ) {
81
+ for ( ; i < length; i++ ) {
82
+ value = callback.call( obj[ i ], obj[ i ], i );
83
+ if ( value === false ) {
84
+ break;
85
+ }
86
+ }
87
+ } else {
88
+ for ( i in obj ) {
89
+ value = callback.call( obj[ i ], obj[ i ], i );
90
+ if ( value === false ) {
91
+ break;
92
+ }
93
+ }
94
+ }
95
+ }
96
+ }
97
+ });
98
+
99
+ $.fn.extend({
100
+
101
+ ///////////////////////////////////
102
+ // forEach method for jQuery to
103
+ // preserve normal parameter order.
104
+ ///////////////////////////////////
105
+ forEach : function( callback, args ) {
106
+ var $this = this;
107
+ return $.forEach( $this, callback, args );
108
+ },
109
+
110
+ //////////////////////
111
+ // Return element that
112
+ // matches selector:
113
+ //////////////////////
114
+ iz : function ( selector ) {
115
+ if (window.jQuery) {
116
+ var ret = $();
117
+ this.forEach(function(ctx) {
118
+ if ($(ctx).is(selector)) {
119
+ ret.push(ctx);
120
+ }
121
+ });
122
+ return ret;
123
+
124
+ } else if (window.$chocolatechipjs) {
125
+ return this.is(selector);
126
+ }
127
+ },
128
+ //////////////////////////////
129
+ // Return element that doesn't
130
+ // match selector:
131
+ //////////////////////////////
132
+ iznt : function ( selector ) {
133
+ if (window.jQuery) {
134
+ return this.not(selector);
135
+ } else if (window.$chocolatechipjs) {
136
+ return this.isnt(selector);
137
+ }
138
+ },
139
+
140
+ ///////////////////////////////////
141
+ // Return element whose descendants
142
+ // match selector:
143
+ ///////////////////////////////////
144
+ haz : function ( selector ) {
145
+ return this.has(selector);
146
+ },
147
+
148
+ ///////////////////////////////////
149
+ // Return element whose descendants
150
+ // don't match selector:
151
+ ///////////////////////////////////
152
+ haznt : function ( selector ) {
153
+ if (window.jQuery) {
154
+ var ret = $();
155
+ this.forEach(function(ctx) {
156
+ if (!$(ctx).has(selector)[0]) {
157
+ ret.push(ctx);
158
+ }
159
+ });
160
+ return ret;
161
+ } else if (window.$chocolatechipjs) {
162
+ return this.hasnt(selector);
163
+ }
164
+ },
165
+ //////////////////////////////////////
166
+ // Return element that has class name:
167
+ //////////////////////////////////////
168
+ hazClass : function ( className ) {
169
+ if (window.jQuery) {
170
+ var ret = $();
171
+ this.forEach(function(ctx) {
172
+ if ($(ctx).hasClass(className)) {
173
+ ret.push(ctx);
174
+ }
175
+ });
176
+ return ret;
177
+ } else if(window.$chocolatechipjs) {
178
+ return this.hasClass(className);
179
+ }
180
+ },
181
+ //////////////////////////////
182
+ // Return element that doesn't
183
+ // have class name:
184
+ //////////////////////////////
185
+ hazntClass : function ( className ) {
186
+ if (window.jQuery) {
187
+ var ret = $();
188
+ this.forEach(function(ctx) {
189
+ if (!$(ctx).hasClass(className)) {
190
+ ret.push(ctx);
191
+ }
192
+ });
193
+ return ret;
194
+ } else if (window.$chocolatechipjs) {
195
+ var ret = [];
196
+ this.forEach(function(ctx) {
197
+ if (ctx.classList.contains(className)) {
198
+ ret.push(ctx);
199
+ }
200
+ });
201
+ return ret;
202
+ }
203
+ },
204
+ /////////////////////////////////////
205
+ // Return element that has attribute:
206
+ /////////////////////////////////////
207
+ hazAttr : function ( property ) {
208
+ if (window.jQuery) {
209
+ var ret = $();
210
+ this.forEach(function(ctx){
211
+ if ($(ctx).attr(property)) {
212
+ ret.push(ctx);
213
+ }
214
+ });
215
+ return ret;
216
+ } else if (window.$chocolatechipjs) {
217
+ var ret = [];
218
+
219
+ return ret;
220
+ }
221
+ },
222
+ //////////////////////////
223
+ // Return element that
224
+ // doesn't have attribute:
225
+ //////////////////////////
226
+ hazntAttr : function ( property ) {
227
+ if (window.jQuery) {
228
+ var ret = $();
229
+ this.forEach(function(ctx){
230
+ if (!$(ctx).attr(property)) {
231
+ ret.push(ctx);
232
+ }
233
+ });
234
+ return ret;
235
+ } else if (window.$chocolatechipjs) {
236
+ var ret = [];
237
+ if (!ctx.hasAttribute(property)){
238
+ ret.push(ctx);
239
+ }
240
+ return ret;
241
+ }
242
+ }
243
+ });
244
+
245
+
246
+ $.extend({
247
+ eventStart : null,
248
+ eventEnd : null,
249
+ eventMove : null,
250
+ eventCancel : null,
251
+ // Define min-length for gesture detection:
252
+ gestureLength : 30
253
+ });
254
+
255
+ $(function() {
256
+ //////////////////////////
257
+ // Setup Event Variables:
258
+ //////////////////////////
259
+ // Pointer events for IE10 and WP8:
260
+ if (window.navigator.pointerEnabled) {
261
+ $.eventStart = 'pointerdown';
262
+ $.eventEnd = 'pointerup';
263
+ $.eventMove = 'pointermove';
264
+ $.eventCancel = 'pointercancel';
265
+ // Pointer events for IE10 and WP8:
266
+ } else if (window.navigator.msPointerEnabled) {
267
+ $.eventStart = 'MSPointerDown';
268
+ $.eventEnd = 'MSPointerUp';
269
+ $.eventMove = 'MSPointerMove';
270
+ $.eventCancel = 'MSPointerCancel';
271
+ // Touch events for iOS & Android:
272
+ } else if ('ontouchstart' in window) {
273
+ $.eventStart = 'touchstart';
274
+ $.eventEnd = 'touchend';
275
+ $.eventMove = 'touchmove';
276
+ $.eventCancel = 'touchcancel';
277
+ // Mouse events for desktop:
278
+ } else {
279
+ $.eventStart = 'mousedown';
280
+ $.eventEnd = 'click';
281
+ $.eventMove = 'mousemove';
282
+ $.eventCancel = 'mouseout';
283
+ }
284
+ });
285
+
286
+
287
+ $.extend({
288
+ isiPhone : /iphone/img.test(navigator.userAgent),
289
+ isiPad : /ipad/img.test(navigator.userAgent),
290
+ isiPod : /ipod/img.test(navigator.userAgent),
291
+ isiOS : /ip(hone|od|ad)/img.test(navigator.userAgent),
292
+ isAndroid : (/android/img.test(navigator.userAgent) && !/trident/img.test(navigator.userAgent)),
293
+ isWebOS : /webos/img.test(navigator.userAgent),
294
+ isBlackberry : /blackberry/img.test(navigator.userAgent),
295
+ isTouchEnabled : ('createTouch' in document),
296
+ isOnline : navigator.onLine,
297
+ isStandalone : navigator.standalone,
298
+ isiOS6 : navigator.userAgent.match(/OS 6/i),
299
+ isiOS7 : navigator.userAgent.match(/OS 7/i),
300
+ isWin : /trident/img.test(navigator.userAgent),
301
+ isWinPhone : (/trident/img.test(navigator.userAgent) && /mobile/img.test(navigator.userAgent)),
302
+ isIE10 : navigator.userAgent.match(/msie 10/i),
303
+ isIE11 : navigator.userAgent.match(/msie 11/i),
304
+ isWebkit : navigator.userAgent.match(/webkit/),
305
+ isMobile : /mobile/img.test(navigator.userAgent),
306
+ isDesktop : !(/mobile/img.test(navigator.userAgent)),
307
+ isSafari : (!/Chrome/img.test(navigator.userAgent) && /Safari/img.test(navigator.userAgent) && !/android/img.test(navigator.userAgent)),
308
+ isChrome : /Chrome/img.test(navigator.userAgent),
309
+ isNativeAndroid : (/android/i.test(navigator.userAgent) && /webkit/i.test(navigator.userAgent) && !/chrome/i.test(navigator.userAgent))
310
+ });
311
+
312
+
313
+
314
+ /////////////////////////////
315
+ // Determine browser version:
316
+ /////////////////////////////
317
+ $.extend({
318
+ browserVersion : function ( ) {
319
+ var n = navigator.appName;
320
+ var ua = navigator.userAgent;
321
+ var temp;
322
+ var m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
323
+ if (m && (temp = ua.match(/version\/([\.\d]+)/i))!== null) m[2]= temp[1];
324
+ m = m ? [m[1], m[2]]: [n, navigator.appVersion, '-?'];
325
+ return m[1];
326
+ }
327
+ });
328
+
329
+ $(function() {
330
+ ////////////////////////////////
331
+ // Added classes for client side
332
+ // os-specific styles:
333
+ ////////////////////////////////
334
+ $.body = $('body');
335
+
336
+ if ((/android/img.test(navigator.userAgent)) && (/webkit/img.test(navigator.userAgent) ) && (!/Chrome/img.test(navigator.userAgent))) {
337
+ $.body.addClass('isNativeAndroidBrowser');
338
+ }
339
+ if ($.isWin) {
340
+ $.body.addClass('isWindows');
341
+ } else if ($.isiOS) {
342
+ $.body.addClass('isiOS');
343
+ } else if ($.isAndroid) {
344
+ $.body.addClass('isAndroid');
345
+ }
346
+ if ($.isSafari && parseInt($.browserVersion(), 10) === 6) {
347
+ $.body.addClass('isSafari6');
348
+ }
349
+ if ($.isNativeAndroid) {
350
+ $.body.addClass('isNativeAndroidBrowser');
351
+ }
352
+ });
353
+
354
+
355
+ //////////////////////////////////////////////////////
356
+ // Swipe Gestures for ChocolateChip-UI.
357
+ // Includes mouse gestures for desktop compatibility.
358
+ //////////////////////////////////////////////////////
359
+ var touch = {};
360
+ var touchTimeout;
361
+ var swipeTimeout;
362
+ var tapTimeout;
363
+ var longTapDelay = 750;
364
+ var singleTapDelay = 150;
365
+ var longTapTimeout;
366
+ function parentIfText(node) {
367
+ return 'tagName' in node ? node : node.parentNode;
368
+ }
369
+ function swipeDirection(x1, x2, y1, y2) {
370
+ return Math.abs(x1 - x2) >=
371
+ Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'left' : 'right') : (y1 - y2 > 0 ? 'up' : 'down');
372
+ }
373
+ function longTap() {
374
+ longTapTimeout = null;
375
+ if (touch.last) {
376
+ try {
377
+ if (touch && touch.el) {
378
+ touch.el.trigger('longtap');
379
+ touch = {};
380
+ }
381
+ } catch(err) { }
382
+ }
383
+ }
384
+ function cancelLongTap() {
385
+ if (longTapTimeout) clearTimeout(longTapTimeout);
386
+ longTapTimeout = null;
387
+ }
388
+ function cancelAll() {
389
+ if (touchTimeout) clearTimeout(touchTimeout);
390
+ if (tapTimeout) clearTimeout(tapTimeout);
391
+ if (swipeTimeout) clearTimeout(swipeTimeout);
392
+ if (longTapTimeout) clearTimeout(longTapTimeout);
393
+ touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null;
394
+ touch = {};
395
+ }
396
+ $(function(){
397
+ var now;
398
+ var delta;
399
+ var body = $(document.body);
400
+ var twoTouches = false;
401
+ body.on($.eventStart, function(e) {
402
+ now = Date.now();
403
+ delta = now - (touch.last || now);
404
+ if (e.originalEvent) e = e.originalEvent;
405
+
406
+ // Handle MSPointer Events:
407
+ if (window.navigator.msPointerEnabled || window.navigator.pointerEnabled) {
408
+ if (window && window.jQuery && $ === window.jQuery) {
409
+ if (e.originalEvent && !e.originalEvent.isPrimary) return;
410
+ } else {
411
+ if (!e.isPrimary) return;
412
+ }
413
+ e = e.originalEvent ? e.originalEvent : e;
414
+ body.on('MSHoldVisual', function (e) {
415
+ e.preventDefault();
416
+ });
417
+ touch.el = $(parentIfText(e.target));
418
+ touchTimeout && clearTimeout(touchTimeout);
419
+ touch.x1 = e.pageX;
420
+ touch.y1 = e.pageY;
421
+ twoTouches = false;
422
+ } else {
423
+ if ($.eventStart === 'mousedown') {
424
+ touch.el = $(parentIfText(e.target));
425
+ touchTimeout && clearTimeout(touchTimeout);
426
+ touch.x1 = e.pageX;
427
+ touch.y1 = e.pageY;
428
+ twoTouches = false;
429
+ } else {
430
+ // User to detect two or more finger gestures:
431
+ if (e.touches.length === 1) {
432
+ touch.el = $(parentIfText(e.touches[0].target));
433
+ touchTimeout && clearTimeout(touchTimeout);
434
+ touch.x1 = e.touches[0].pageX;
435
+ touch.y1 = e.touches[0].pageY;
436
+ if (e.targetTouches.length === 2) {
437
+ twoTouches = true;
438
+ } else {
439
+ twoTouches = false;
440
+ }
441
+ }
442
+ }
443
+ }
444
+ if (delta > 0 && delta <= 250) {
445
+ touch.isDoubleTap = true;
446
+ }
447
+ touch.last = now;
448
+ longTapTimeout = setTimeout(longTap, longTapDelay);
449
+ });
450
+ body.on($.eventMove, function(e) {
451
+ if (e.originalEvent) e = e.originalEvent;
452
+ if (window.navigator.msPointerEnabled) {
453
+ if (window && window.jQuery && $ === window.jQuery) {
454
+ if (e.originalEvent && !e.originalEvent.isPrimary) return;
455
+ } else {
456
+ if (!e.isPrimary) return;
457
+ }
458
+ e = e.originalEvent ? e.originalEvent : e;
459
+ cancelLongTap();
460
+ touch.x2 = e.pageX;
461
+ touch.y2 = e.pageY;
462
+ } else {
463
+ cancelLongTap();
464
+ if ($.eventMove === 'mousemove') {
465
+ touch.x2 = e.pageX;
466
+ touch.y2 = e.pageY;
467
+ } else {
468
+ // One finger gesture:
469
+ if (e.touches.length === 1) {
470
+ touch.x2 = e.touches[0].pageX;
471
+ touch.y2 = e.touches[0].pageY;
472
+ }
473
+ }
474
+ }
475
+ if ($.isAndroid) {
476
+ $.gestureLength = 10;
477
+ if (!!touch.el) {
478
+ // Swipe detection:
479
+ if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > $.gestureLength) ||
480
+ (touch.y2 && Math.abs(touch.y1 - touch.y2) > $.gestureLength)) {
481
+ swipeTimeout = setTimeout(function() {
482
+ e.preventDefault();
483
+ if (touch && touch.el) {
484
+ touch.el.trigger('swipe');
485
+ touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)));
486
+ touch = {};
487
+ }
488
+ }, 0);
489
+ // Normal tap:
490
+ } else if ('last' in touch) {
491
+ // Delay by one tick so we can cancel the 'tap' event if 'scroll' fires:
492
+ tapTimeout = setTimeout(function() {
493
+ // Trigger universal 'tap' with the option to cancelTouch():
494
+ if (touch && touch.el) {
495
+ touch.el.trigger('tap');
496
+ }
497
+ // Trigger double tap immediately:
498
+ if (touch && touch.isDoubleTap) {
499
+ if (touch && touch.el) {
500
+ touch.el.trigger('doubletap');
501
+ touch = {};
502
+ }
503
+ } else {
504
+ // Trigger single tap after singleTapDelay:
505
+ touchTimeout = setTimeout(function(){
506
+ touchTimeout = null;
507
+ if (touch && touch.el) {
508
+ touch.el.trigger('singletap');
509
+ touch = {};
510
+ return false;
511
+ }
512
+ }, singleTapDelay);
513
+ }
514
+ }, 0);
515
+ }
516
+ } else { return; }
517
+ }
518
+ });
519
+ body.on($.eventEnd, function(e) {
520
+ if (window.navigator.msPointerEnabled) {
521
+ if (window && window.jQuery && $ === window.jQuery) {
522
+ if (e.originalEvent && !e.originalEvent.isPrimary) return;
523
+ } else {
524
+ if (!e.isPrimary) return;
525
+ }
526
+ }
527
+ cancelLongTap();
528
+ if (!!touch.el) {
529
+ // Swipe detection:
530
+ if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > $.gestureLength) ||
531
+ (touch.y2 && Math.abs(touch.y1 - touch.y2) > $.gestureLength)) {
532
+ swipeTimeout = setTimeout(function() {
533
+ if (touch && touch.el) {
534
+ touch.el.trigger('swipe');
535
+ touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)));
536
+ touch = {};
537
+ }
538
+ }, 0);
539
+ // Normal tap:
540
+ } else if ('last' in touch) {
541
+ // Delay by one tick so we can cancel the 'tap' event if 'scroll' fires:
542
+ tapTimeout = setTimeout(function() {
543
+ // Trigger universal 'tap' with the option to cancelTouch():
544
+ if (touch && touch.el) {
545
+ touch.el.trigger('tap');
546
+ }
547
+ // Trigger double tap immediately:
548
+ if (touch && touch.isDoubleTap) {
549
+ if (touch && touch.el) {
550
+ touch.el.trigger('doubletap');
551
+ touch = {};
552
+ }
553
+ } else {
554
+ // Trigger single tap after singleTapDelay:
555
+ touchTimeout = setTimeout(function(){
556
+ touchTimeout = null;
557
+ if (touch && touch.el) {
558
+ touch.el.trigger('singletap');
559
+ touch = {};
560
+ return false;
561
+ }
562
+ }, singleTapDelay);
563
+ }
564
+ }, 0);
565
+ }
566
+ } else { return; }
567
+ });
568
+ body.on('touchcancel', cancelAll);
569
+ });
570
+ ['swipe', 'swipeleft', 'swiperight', 'swipeup', 'swipedown', 'doubletap', 'tap', 'singletap', 'longtap'].forEach(function(method){
571
+ // Add gesture events to ChocolateChipJS:
572
+ $.fn.extend({
573
+ method : function(callback){
574
+ return this.on(method, callback);
575
+ }
576
+ });
577
+ });
578
+
579
+
580
+ /////////////////////////////////////////
581
+ // Set classes for desktop compatibility:
582
+ /////////////////////////////////////////
583
+ $.extend({
584
+ UIDesktopCompat : function ( ) {
585
+ if ($.isDesktop && $.isSafari) {
586
+ $('body').addClass('isiOS').addClass('isDesktopSafari isDesktop');
587
+ } else if ($.isDesktop && $.isChrome) {
588
+ $('body').addClass('isAndroid').addClass('isDesktopChrome isDesktop');
589
+ }
590
+ }
591
+ });
592
+ $(function() {
593
+ $.UIDesktopCompat();
594
+ });
595
+
596
+
597
+ $(function() {
598
+ $.body = $('body');
599
+
600
+ //////////////////////
601
+ // Add the global nav:
602
+ //////////////////////
603
+ if (!$.body[0].classList.contains('splitlayout')) {
604
+ $('body').prepend("<nav id='global-nav'></nav>");
605
+ }
606
+
607
+ /////////////////////////////////////////////////
608
+ // Fix Split Layout to display properly on phone:
609
+ /////////////////////////////////////////////////
610
+ if ($.body[0].classList.contains('splitlayout')) {
611
+ if (window.innerWidth < 768) {
612
+ $('meta[name=viewport]').attr('content','width=device-width, initial-scale=0.45, maximum-scale=2, user-scalable=yes');
613
+ }
614
+ }
615
+
616
+ /////////////////////////////////////////////////////////
617
+ // Add class to nav when button on right.
618
+ // This allows us to adjust the nav h1 for small screens.
619
+ /////////////////////////////////////////////////////////
620
+ $('h1').each(function(idx, ctx) {
621
+ if (ctx.nextElementSibling && ctx.nextElementSibling.nodeName === 'A') {
622
+ ctx.classList.add('buttonOnRight');
623
+ }
624
+ });
625
+
626
+ //////////////////////////////////////////
627
+ // Get any toolbars and adjust the bottom
628
+ // of their corresponding articles:
629
+ //////////////////////////////////////////
630
+ $('.toolbar').prev('article').addClass('has-toolbar');
631
+
632
+ if ($.isiOS && $.isStandalone) {
633
+ $.body[0].classList.add('isStandalone');
634
+ }
635
+ });
636
+
637
+
638
+ /////////////////////////
639
+ // Hide and show navbars:
640
+ /////////////////////////
641
+ $.extend({
642
+ UIHideNavBar : function () {
643
+ $('nav').hide();
644
+ $.body.addClass('hide-navbars');
645
+ },
646
+
647
+ UIShowNavBar : function () {
648
+ $('nav').show();
649
+ $.body.removeClass('hide-navbars');
650
+ }
651
+ });
652
+
653
+
654
+ $.extend({
655
+ subscriptions : {},
656
+
657
+ // Topic: string defining topic: /some/topic
658
+ // Data: a string, number, array or object.
659
+ subscribe : function (topic, callback) {
660
+ if (!$.subscriptions[topic]) {
661
+ $.subscriptions[topic] = [];
662
+ }
663
+ var token = ($.Uuid());
664
+ $.subscriptions[topic].push({
665
+ token: token,
666
+ callback: callback
667
+ });
668
+ return token;
669
+ },
670
+
671
+ unsubscribe : function ( token ) {
672
+ setTimeout(function() {
673
+ for (var m in $.subscriptions) {
674
+ if ($.subscriptions[m]) {
675
+ for (var i = 0, len = $.subscriptions[m].length; i < len; i++) {
676
+ if ($.subscriptions[m][i].token === token) {
677
+ $.subscriptions[m].splice(i, 1);
678
+ return token;
679
+ }
680
+ }
681
+ }
682
+ }
683
+ return false;
684
+ });
685
+ },
686
+
687
+ publish : function ( topic, args ) {
688
+ if (!$.subscriptions[topic]) {
689
+ return false;
690
+ }
691
+ setTimeout(function () {
692
+ var len = $.subscriptions[topic] ? $.subscriptions[topic].length : 0;
693
+ while (len--) {
694
+ $.subscriptions[topic][len].callback(topic, args);
695
+ }
696
+ return true;
697
+ });
698
+ return true;
699
+ }
700
+ });
701
+
702
+
703
+ ////////////////////////////////////
704
+ // Create custom navigationend event
705
+ ////////////////////////////////////
706
+ function triggerNavigationEvent(target) {
707
+ var transition;
708
+ var tansitionDuration;
709
+ if ('transition' in document.body.style) {
710
+ transition = 'transition-duration';
711
+ } else if ('-webkit-transition' in document.body.style){
712
+ transition = '-webkit-transition-duration';
713
+ }
714
+ function determineDurationType (duration) {
715
+ if (/m/.test(duration)) {
716
+ return parseFloat(duration);
717
+ } else if (/s/.test(duration)) {
718
+ return parseFloat(duration) * 100;
719
+ }
720
+ }
721
+ tansitionDuration = determineDurationType($('article').eq(0).css(transition));
722
+
723
+ setTimeout(function() {
724
+ $(target).trigger({type: 'navigationend'});
725
+ }, tansitionDuration);
726
+ }
727
+ $.extend({
728
+ ////////////////////////////////////////////////
729
+ // Manage location.hash for client side routing:
730
+ ////////////////////////////////////////////////
731
+ UITrackHashNavigation : function ( url, delimiter ) {
732
+ url = url || true;
733
+ $.UISetHashOnUrl($.UINavigationHistory[$.UINavigationHistory.length-1], delimiter);
734
+ },
735
+ /////////////////////////////////////////////////////
736
+ // Set the hash according to where the user is going:
737
+ /////////////////////////////////////////////////////
738
+ UISetHashOnUrl : function ( url, delimiter ) {
739
+ delimiter = delimiter || '#/';
740
+ var hash;
741
+ if (/^#/.test(url)) {
742
+ hash = delimiter + (url.split('#')[1]);
743
+ } else {
744
+ hash = delimiter + url;
745
+ }
746
+ if ($.isAndroid) {
747
+ if (/#/.test(url)) {
748
+ url = url.split('#')[1];
749
+ }
750
+ if (/\//.test(url)) {
751
+ url = url.split('/')[1];
752
+ }
753
+ window.location.hash = '#/' + url;
754
+ } else {
755
+ window.history.replaceState('Object', 'Title', hash);
756
+ }
757
+ },
758
+ //////////////////////////////////////
759
+ // Navigate Back to Non-linear Article
760
+ //////////////////////////////////////
761
+ UIGoBackToArticle : function ( articleID ) {
762
+ var historyIndex = $.UINavigationHistory.indexOf(articleID);
763
+ var currentArticle = $('article.current');
764
+ var destination = $(articleID);
765
+ var currentToolbar;
766
+ var destinationToolbar;
767
+ if ($.UINavigationHistory.length === 0) {
768
+ destination = $('article:first-of-type');
769
+ $.UINavigationHistory.push('#' + destination[0].id);
770
+ }
771
+ var prevArticles;
772
+ if ($.UINavigationHistory.length > 1) {
773
+ prevArticles = $.UINavigationHistory.splice(historyIndex+1);
774
+ } else {
775
+ prevArticles = $('article.previous');
776
+ }
777
+ $.publish('chui/navigateBack/leave', currentArticle[0].id);
778
+ $.publish('chui/navigateBack/enter', destination[0].id);
779
+ currentArticle[0].scrollTop = 0;
780
+ destination[0].scrollTop = 0;
781
+ if (prevArticles.length) {
782
+ $.forEach(prevArticles, function(ctx) {
783
+ $(ctx).removeClass('previous').addClass('next');
784
+ $(ctx).prev().removeClass('previous').addClass('next');
785
+ });
786
+ }
787
+ currentToolbar = currentArticle.next().hazClass('toolbar');
788
+ destinationToolbar = destination.next().hazClass('toolbar');
789
+ destination.removeClass('previous next').addClass('current');
790
+ destination.prev().removeClass('previous next').addClass('current');
791
+ destinationToolbar.removeClass('previous next').addClass('current');
792
+ currentArticle.removeClass('current').addClass('next');
793
+ currentArticle.prev().removeClass('current').addClass('next');
794
+ currentToolbar.removeClass('current').addClass('next');
795
+ $('.toolbar.previous').removeClass('previous').addClass('next');
796
+ $.UISetHashOnUrl($.UINavigationHistory[$.UINavigationHistory.length-1]);
797
+ triggerNavigationEvent(destination);
798
+ },
799
+ ////////////////////////////////////
800
+ // Navigate Back to Previous Article
801
+ ////////////////////////////////////
802
+ UIGoBack : function () {
803
+ var histLen = $.UINavigationHistory.length;
804
+ var currentArticle = $('article.current');
805
+ var destination = $($.UINavigationHistory[histLen-2]);
806
+ var currentToolbar;
807
+ var destinationToolbar;
808
+ if (histLen === 0) {
809
+ destination = $('article:first-of-type');
810
+ $.UINavigationHistory.push('#' + destination[0].id);
811
+ }
812
+ $.publish('chui/navigateBack/leave', currentArticle[0].id);
813
+ $.publish('chui/navigateBack/enter', destination[0].id);
814
+ currentArticle[0].scrollTop = 0;
815
+ destination[0].scrollTop = 0;
816
+ currentToolbar = currentArticle.next().hazClass('toolbar');
817
+ destinationToolbar = destination.next().hazClass('toolbar');
818
+ destination.removeClass('previous').addClass('current');
819
+ destination.prev().removeClass('previous').addClass('current');
820
+ destinationToolbar.removeClass('previous').addClass('current');
821
+ currentArticle.removeClass('current').addClass('next');
822
+ currentArticle.prev().removeClass('current').addClass('next');
823
+ currentToolbar.removeClass('current').addClass('next');
824
+ $.UISetHashOnUrl($.UINavigationHistory[histLen-2]);
825
+ if ($.UINavigationHistory.length === 1) return;
826
+ $.UINavigationHistory.pop();
827
+ triggerNavigationEvent(destination);
828
+ },
829
+ isNavigating : false,
830
+
831
+ ///////////////////////////////
832
+ // Navigate to Specific Article
833
+ ///////////////////////////////
834
+ UIGoToArticle : function ( destination ) {
835
+ if ($.isNavigating) return;
836
+ $.isNavigating = true;
837
+ var current = $('article.current');
838
+ var currentNav = current.prev();
839
+ destination = $(destination);
840
+ var destinationID = '#' + destination[0].id;
841
+ var destinationNav = destination.prev();
842
+ var currentToolbar;
843
+ var destinationToolbar;
844
+ var navigationClass = 'next previous';
845
+ $.publish('chui/navigate/leave', current[0].id);
846
+ $.UINavigationHistory.push(destinationID);
847
+ $.publish('chui/navigate/enter', destination[0].id);
848
+ current[0].scrollTop = 0;
849
+ destination[0].scrollTop = 0;
850
+ currentToolbar = current.next().hazClass('toolbar');
851
+ destinationToolbar = destination.next().hazClass('toolbar');
852
+ current.removeClass('current').addClass('previous');
853
+ currentNav.removeClass('current').addClass('previous');
854
+ currentToolbar.removeClass('current').addClass('previous');
855
+ destination.removeClass(navigationClass).addClass('current');
856
+ destinationNav.removeClass(navigationClass).addClass('current');
857
+ destinationToolbar.removeClass(navigationClass).addClass('current');
858
+
859
+ $.UISetHashOnUrl(destination[0].id);
860
+ setTimeout(function() {
861
+ $.isNavigating = false;
862
+ }, 500);
863
+ triggerNavigationEvent(destination);
864
+ }
865
+ });
866
+ ///////////////////
867
+ // Init navigation:
868
+ ///////////////////
869
+ $(function() {
870
+ //////////////////////////////////////////
871
+ // Set first value for navigation history:
872
+ //////////////////////////////////////////
873
+ $.extend({
874
+ UINavigationHistory : ["#" + $('article').eq(0).attr('id')]
875
+ });
876
+ ///////////////////////////////////////////////////////////
877
+ // Make sure that navs and articles have navigation states:
878
+ ///////////////////////////////////////////////////////////
879
+ $('nav:not(#global-nav)').forEach(function(ctx, idx) {
880
+ // Prevent if splitlayout for tablets:
881
+ if ($('body')[0].classList.contains('splitlayout')) return;
882
+ if (idx === 0) {
883
+ ctx.classList.add('current');
884
+ } else {
885
+ ctx.classList.add('next');
886
+ }
887
+ });
888
+
889
+ $('article').forEach(function(ctx, idx) {
890
+ // Prevent if splitlayout for tablets:
891
+ if ($('body')[0].classList.contains('splitlayout')) return;
892
+ if ($('body')[0].classList.contains('slide-out-app')) return;
893
+ if (idx === 0) {
894
+ ctx.classList.add('current');
895
+ } else {
896
+ ctx.classList.add('next');
897
+ }
898
+ });
899
+ ///////////////////////////
900
+ // Initialize Back Buttons:
901
+ ///////////////////////////
902
+ $('body').on('singletap', 'a.back', function() {
903
+ if (this.classList.contains('back')) {
904
+ $.UIGoBack();
905
+ }
906
+ });
907
+
908
+ ////////////////////////////////
909
+ // Handle navigation list items:
910
+ ////////////////////////////////
911
+ $('body').on('singletap doubletap', 'li', function() {
912
+ var $this = $(this);
913
+ if ($.isNavigating) return;
914
+ if (!this.hasAttribute('data-goto')) return;
915
+ if (!this.getAttribute('data-goto')) return;
916
+ if (!document.getElementById(this.getAttribute('data-goto'))) return;
917
+ if ($(this).parent()[0].classList.contains('deletable')) return;
918
+ $this.addClass('selected');
919
+ var destinationHref = '#' + this.getAttribute('data-goto');
920
+ $(destinationHref).addClass('navigable');
921
+ setTimeout(function() {
922
+ $this.removeClass('selected');
923
+ }, 500);
924
+ var destination = $(destinationHref);
925
+ $.UIGoToArticle(destination);
926
+ });
927
+ $('li[data-goto]').forEach(function(ctx) {
928
+ $(ctx).closest('article').addClass('navigable');
929
+ var navigable = '#' + ctx.getAttribute('data-goto');
930
+ $(navigable).addClass('navigable');
931
+ });
932
+
933
+ /////////////////////////////////////
934
+ // Init navigation url hash tracking:
935
+ /////////////////////////////////////
936
+ // If there's more than one article:
937
+ if ($('article').eq(1)[0]) {
938
+ $.UISetHashOnUrl($('article').eq(0)[0].id);
939
+ }
940
+ /////////////////////////////////////////////////////////
941
+ // Stop rubber banding when dragging down on nav:
942
+ /////////////////////////////////////////////////////////
943
+ $('nav').on($.eventStart, function(e) {
944
+ e.preventDefault();
945
+ });
946
+ });
947
+
948
+
949
+ $(function() {
950
+ ///////////////////////////////////
951
+ // Initialize singletap on buttons:
952
+ ///////////////////////////////////
953
+ $('body').on('singletap', '.button', function() {
954
+ var $this = $(this);
955
+ if ($this.parent('.segmented')[0]) return;
956
+ if ($this.parent('.tabbar')[0]) return;
957
+ if ($.isDesktop) return;
958
+ $this.addClass('selected');
959
+ setTimeout(function() {
960
+ $this.removeClass('selected');
961
+ }, 500);
962
+ });
963
+ });
964
+
965
+
966
+ $.fn.extend({
967
+ /////////////////////////
968
+ // Block Screen with Mask
969
+ /////////////////////////
970
+ UIBlock : function ( opacity ) {
971
+ opacity = opacity ? " style='opacity:" + opacity + "'" : " style='opacity: .5;'";
972
+ $(this).before("<div class='mask'" + opacity + "></div>");
973
+ $('article.current').attr('aria-hidden',true);
974
+ return this;
975
+ },
976
+
977
+ //////////////////////////
978
+ // Remove Mask from Screen
979
+ //////////////////////////
980
+ UIUnblock : function ( ) {
981
+ $('.mask').remove();
982
+ $('article.current').removeAttr('aria-hidden');
983
+ return this;
984
+ }
985
+ });
986
+
987
+
988
+ $.fn.extend({
989
+ //////////////////////////////
990
+ // Center an Element on Screen
991
+ //////////////////////////////
992
+ UICenter : function ( position ) {
993
+ var position = position;
994
+ if (!this[0]) return;
995
+ var $this = $(this);
996
+ var parent = $this.parent();
997
+ if (position) {
998
+ $(this.css('position', position));
999
+ } else if ($this.css('position') === 'absolute') {
1000
+ position = 'absolute';
1001
+ } else {
1002
+ position = 'relative';
1003
+ }
1004
+ var height, width, parentHeight, parentWidth;
1005
+ if (position === 'absolute') {
1006
+ height = $this[0].clientHeight;
1007
+ width = $this[0].clientWidth;
1008
+ parentHeight = parent[0].clientHeight;
1009
+ parentWidth = parent[0].clientWidth;
1010
+ } else {
1011
+ height = parseInt($this.css('height'),10);
1012
+ width = parseInt($this.css('width'),10);
1013
+ parentHeight = parseInt(parent.css('height'),10);
1014
+ parentWidth = parseInt(parent.css('width'),10);
1015
+ $(this).css({'margin-left': 'auto', 'margin-right': 'auto'});
1016
+ }
1017
+ var tmpTop, tmpLeft;
1018
+ if (parent[0].nodeName === 'body') {
1019
+ tmpTop = ((window.innerHeight /2) + window.pageYOffset) - height /2 + 'px';
1020
+ tmpLeft = ((window.innerWidth / 2) - (width / 2) + 'px');
1021
+ } else {
1022
+ tmpTop = (parentHeight /2) - (height /2) + 'px';
1023
+ tmpLeft = (parentWidth / 2) - (width / 2) + 'px';
1024
+ }
1025
+ if (position !== 'absolute') tmpLeft = 0;
1026
+ // if (parseInt(tmpLeft,10) <= 0) tmpLeft = '10px';
1027
+ $this.css({left: tmpLeft, top: tmpTop});
1028
+ }
1029
+ });
1030
+
1031
+
1032
+ $.fn.extend({
1033
+ ////////////////////////
1034
+ // Create Busy indicator
1035
+ ////////////////////////
1036
+ /*
1037
+ var options = {
1038
+ color: 'red',
1039
+ size: '80px',
1040
+ position: 'right'
1041
+ }
1042
+ */
1043
+ UIBusy : function ( options ) {
1044
+ var count = 1;
1045
+ options = options || {};
1046
+ var settings = {
1047
+ size: 43,
1048
+ color: '#000',
1049
+ position: false,
1050
+ duration: '2s'
1051
+ };
1052
+ $.extend(settings, options);
1053
+ var $this = this;
1054
+ var spinner;
1055
+ // For iOS:
1056
+ var iOSBusy = function() {
1057
+ var webkitAnim = {'-webkit-animation-duration': settings.duration};
1058
+ spinner = $('<span class="busy"></span>');
1059
+ $(spinner).css({'background-color': settings.color, 'height': settings.size, 'width': settings.size});
1060
+ $(spinner).css(webkitAnim);
1061
+ $(spinner).attr('role','progressbar');
1062
+ if (settings.position) $(spinner).addClass(settings.position);
1063
+ $this.append(spinner);
1064
+ return this;
1065
+ };
1066
+ // For Android:
1067
+ var androidBusy = function() {
1068
+ settings.id = $.Uuid();
1069
+ var androidActivityIndicator = null;
1070
+ var position = settings.position ? (' ' + settings.position) : '';
1071
+ if ($.isNativeAndroid) {
1072
+ androidActivityIndicator = '<svg class="busy' + position + '" version="1.1" id="' + settings.id + '" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve"><g><path fill="none" stroke="' + settings.color + '" stroke-width="10" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M74.2,65c2.7-4.4,4.3-9.5,4.3-15c0-15.7-12.8-28.5-28.5-28.5S21.5,34.3,21.5,50c0,5.5,1.6,10.6,4.3,15"/></g><polyline fill="none" stroke="' + settings.color + '" stroke-width="10" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="89.4,56.1 74.3,65 65.4,49.9 "/></svg>';
1073
+
1074
+ $this.append(androidActivityIndicator);
1075
+ return;
1076
+ } else {
1077
+ androidActivityIndicator = '<svg id="'+ settings.id +'" class="busy' + position + '" x="0px" y="0px" viewBox="0 0 100 100"><circle stroke="url(#SVGID_1_)" cx="50" cy="50" r="28.5"/></svg>';
1078
+ $this.append(androidActivityIndicator);
1079
+ $this.addClass('hasActivityIndicator');
1080
+ if (settings.position) {
1081
+ $('#' + settings.id).addClass(settings.position);
1082
+ }
1083
+ if (options.color) {
1084
+ $('#' + settings.id).find('circle').css('stroke', options.color);
1085
+ }
1086
+ $('#' + settings.id).css({'height': settings.size + 'px', 'width': settings.size + 'px'});
1087
+ }
1088
+ return $('#' + settings.id);
1089
+ };
1090
+ // For Windows 8/WP8:
1091
+ var winBusy = function() {
1092
+ spinner = $('<progress class="busy"></progress>');
1093
+ $(spinner).css({ 'color': settings.color });
1094
+ $(spinner).attr('role','progressbar');
1095
+ $(spinner).addClass('win-ring');
1096
+ if (settings.position) $(spinner).addClass(settings.position);
1097
+ $this.append(spinner);
1098
+ return this;
1099
+ };
1100
+ // Create Busy control for appropriate OS:
1101
+ if ($.isWin) {
1102
+ winBusy(options);
1103
+ } else if ($.isAndroid || $.isChrome) {
1104
+ androidBusy(options);
1105
+ } else if ($.isiOS || $.isSafari) {
1106
+ iOSBusy(options);
1107
+ }
1108
+ }
1109
+ });
1110
+
1111
+
1112
+ $.extend({
1113
+ ///////////////
1114
+ // Create Popup
1115
+ ///////////////
1116
+ UIPopup : function( options ) {
1117
+ /*
1118
+ options {
1119
+ id: 'alertID',
1120
+ title: 'Alert',
1121
+ message: 'This is a message from me to you.',
1122
+ cancelButton: 'Cancel',
1123
+ continueButton: 'Go Ahead',
1124
+ callback: function() { // do nothing }
1125
+ }
1126
+ */
1127
+ if (!options) return;
1128
+ var id = options.id || $.Uuid();
1129
+ var title = options.title ? '<header><h1>' + options.title + '</h1></header>' : '';
1130
+ var message = options.message ? '<p role="note">' + options.message + '</p>' : '';
1131
+ var cancelButton = options.cancelButton ? '<a href="javascript:void(null)" class="button cancel" role="button">' + options.cancelButton + '</a>' : '';
1132
+ var continueButton = options.continueButton ? '<a href="javascript:void(null)" class="button continue" role="button">' + options.continueButton + '</a>' : '';
1133
+ var callback = options.callback || $.noop;
1134
+ var padding = options.empty ? ' noTitle' : '';
1135
+ var panelOpen, panelClose;
1136
+ var popup = $.concat('<div class="popup closed', padding, '" role="alertdialog" id="', id, '"><div class="panel">', title, message, '</div><footer>', cancelButton, continueButton, '</footer>', panelClose, '</div>');
1137
+
1138
+ $('body').append(popup);
1139
+ if (callback && continueButton) {
1140
+ $('.popup').find('.continue').on($.eventStart, function() {
1141
+ $('.popup').UIPopupClose();
1142
+ callback.call(callback);
1143
+ });
1144
+ }
1145
+
1146
+ $.UICenterPopup();
1147
+ setTimeout(function() {
1148
+ $('body').find('.popup').removeClass('closed');
1149
+ }, 200);
1150
+ $('body').find('.popup').UIBlock('0.5');
1151
+ var events = $.eventStart + ' singletap ' + $.eventEnd;
1152
+ $('.mask').on(events, function(e) {
1153
+ e.stopPropagation();
1154
+ });
1155
+ },
1156
+
1157
+ //////////////////////////////////////////
1158
+ // Center Popups When Orientation Changes:
1159
+ //////////////////////////////////////////
1160
+ UICenterPopup : function ( ) {
1161
+ var popup = $('.popup');
1162
+ if (!popup[0]) return;
1163
+ var tmpTop = ((window.innerHeight /2) + window.pageYOffset) - (popup[0].clientHeight /2) + 'px';
1164
+ var tmpLeft;
1165
+ if (window.innerWidth === 320) {
1166
+ tmpLeft = '10px';
1167
+ } else {
1168
+ tmpLeft = Math.floor((window.innerWidth - 318) /2) + 'px';
1169
+ }
1170
+ if ($.isWin) {
1171
+ popup.css({top: tmpTop});
1172
+ } else {
1173
+ popup.css({left: tmpLeft, top: tmpTop});
1174
+ }
1175
+ }
1176
+ });
1177
+ $.fn.extend({
1178
+ //////////////
1179
+ // Close Popup
1180
+ //////////////
1181
+ UIPopupClose : function ( ) {
1182
+ if (!this && !this.classList.contains('popup')) return;
1183
+ $(this).UIUnblock();
1184
+ $(this).remove();
1185
+ }
1186
+ });
1187
+ $(function() {
1188
+ //////////////////////////
1189
+ // Handle Closing Popups:
1190
+ //////////////////////////
1191
+ $('body').on($.eventStart, '.cancel', function() {
1192
+ if ($(this).closest('.popup')[0]) {
1193
+ $(this).closest('.popup').UIPopupClose();
1194
+ }
1195
+ });
1196
+ /////////////////////////////////////////////////
1197
+ // Reposition popups on window resize:
1198
+ /////////////////////////////////////////////////
1199
+ $(window).on('resize', function() {
1200
+ $.UICenterPopup();
1201
+ });
1202
+ });
1203
+
1204
+
1205
+ $.extend({
1206
+ /////////////////
1207
+ // Create Popover
1208
+ /////////////////
1209
+ /*
1210
+ id: myUniqueID,
1211
+ title: 'Great',
1212
+ callback: myCallback,
1213
+ */
1214
+ UIPopover : function ( options ) {
1215
+ options = options || {};
1216
+ var settings = {
1217
+ id: $.Uuid(),
1218
+ callback: $.noop,
1219
+ title: '',
1220
+ };
1221
+ $.extend(settings, options);
1222
+ if (options && options.content) {
1223
+ settings.content = options.content;
1224
+ } else {
1225
+ settings.content = '';
1226
+ }
1227
+ var header = '<header><h1>' + settings.title + '</h1></header>';
1228
+ var popover = '<div class="popover" id="' + settings.id + '">' + header + '<section></section></div>';
1229
+ var popoverID = '#' + settings.id;
1230
+
1231
+ // Calculate position of popover relative to the button that opened it:
1232
+ var _calcPopPos = function (element) {
1233
+ var offset = $(element).offset();
1234
+ var left = offset.left;
1235
+ var calcLeft;
1236
+ var calcTop;
1237
+ var popover = $(popoverID);
1238
+ var popoverOffset = popover.offset();
1239
+ calcLeft = popoverOffset.left;
1240
+ calcTop = offset.top + $(element)[0].clientHeight;
1241
+ if ((popover.width() + offset.left) > window.innerWidth) {
1242
+ popover.css({
1243
+ 'left': ((window.innerWidth - popover.width())-20) + 'px',
1244
+ 'top': (calcTop + 20) + 'px'
1245
+ });
1246
+ } else {
1247
+ popover.css({'left': left + 'px', 'top': (calcTop + 20) + 'px'});
1248
+ }
1249
+ };
1250
+
1251
+ if ($('.mask')[0]) {
1252
+ $.UIPopoverClose();
1253
+ $('body').UIUnblock();
1254
+ return;
1255
+ }
1256
+ $('body').append(popover);
1257
+ if ($.isWin) {
1258
+ $(popoverID).addClass('open');
1259
+ }
1260
+ $(popoverID).data('triggerEl', settings.trigger);
1261
+ $(popoverID).find('section').append(settings.content);
1262
+ settings.callback.call(settings.callback, settings.trigger);
1263
+ _calcPopPos(settings.trigger);
1264
+ $('.popover').UIBlock('.5');
1265
+
1266
+ }
1267
+ });
1268
+ $.extend({
1269
+ ///////////////////////////////////////
1270
+ // Align the Popover Before Showing it:
1271
+ ///////////////////////////////////////
1272
+ UIAlignPopover : function () {
1273
+ var popover = $('.popover');
1274
+ if (!popover.length) return;
1275
+ var triggerID = popover.data('triggerEl');
1276
+ var offset = $(triggerID).offset();
1277
+ var left = offset.left;
1278
+ if (($(popover).width() + offset.left) > window.innerWidth) {
1279
+ popover.css({
1280
+ 'left': ((window.innerWidth - $(popover).width())-20) + 'px'
1281
+ });
1282
+ } else {
1283
+ popover.css({'left': left + 'px'});
1284
+ }
1285
+ }
1286
+ });
1287
+ $.extend({
1288
+ UIPopoverClose : function ( ) {
1289
+ $('body').UIUnblock();
1290
+ $('.popover').css('visibility','hidden');
1291
+ setTimeout(function() {
1292
+ $('.popover').remove();
1293
+ },10);
1294
+ }
1295
+ });
1296
+ $(function() {
1297
+ /////////////////////////////////////////////////
1298
+ // Reposition popovers on window resize:
1299
+ /////////////////////////////////////////////////
1300
+ $(window).on('resize', function() {
1301
+ $.UIAlignPopover();
1302
+ });
1303
+ var events = $.eventStart + ' singletap ' + $.eventEnd;
1304
+ $('body').on(events, '.mask', function(e) {
1305
+ if (!$('.popover')[0]) {
1306
+ if (e && e.nodeType === 1) return;
1307
+ e.stopPropogation();
1308
+ } else {
1309
+ $.UIPopoverClose();
1310
+ }
1311
+ });
1312
+ });
1313
+
1314
+
1315
+ $.fn.extend({
1316
+ ///////////////////////////////
1317
+ // Initialize Segmented Control
1318
+ ///////////////////////////////
1319
+ UISegmented : function ( options ) {
1320
+ /*
1321
+ var options = {
1322
+ selected: 0,
1323
+ callback: function() { alert('Boring!'); }
1324
+ }
1325
+ */
1326
+ if ($(this).hazClass('paging').length) return;
1327
+ var callback = (options && options.callback) ? options.callback : $.noop;
1328
+ var selected = (options && options.selected > 0) ? options.selected : 0;
1329
+ this.find('a').forEach(function(ctx, idx) {
1330
+ $(ctx).find('a').attr('role','radio');
1331
+ if (idx === selected) {
1332
+ ctx.setAttribute('aria-checked', 'true');
1333
+ ctx.classList.add('selected');
1334
+ }
1335
+ });
1336
+ this.on('singletap', '.button', function(e) {
1337
+ var $this = $(this);
1338
+ if (this.parentNode.classList.contains('paging')) return;
1339
+ $this.siblings('a').removeClass('selected');
1340
+ $this.siblings('a').removeAttr('aria-checked');
1341
+ $this.addClass('selected');
1342
+ $this.attr('aria-checked', true);
1343
+ callback.call(this, e);
1344
+ });
1345
+ }
1346
+ });
1347
+ $.extend({
1348
+ ///////////////////////////
1349
+ // Create Segmented Control
1350
+ ///////////////////////////
1351
+ UICreateSegmented : function ( options ) {
1352
+ /*
1353
+ options = {
1354
+ id : '#myId',
1355
+ className : 'special' || '',
1356
+ labels : ['first','second','third'],
1357
+ selected: 0
1358
+ }
1359
+ */
1360
+ var segmented;
1361
+ var id = (options && options.id) ? options.id : $.Uuid();
1362
+ var className = (options && options.className) ? options.className : '';
1363
+ var labels = (options && options.labels) ? options.labels : [];
1364
+ var selected = (options && options.selected) ? options.selected : 0;
1365
+ var _segmented = ['<div class="segmented'];
1366
+ if (className) _segmented.push(' ' + className);
1367
+ _segmented.push('">');
1368
+ labels.forEach(function(ctx, idx) {
1369
+ _segmented.push('<a role="radio" class="button');
1370
+ _segmented.push('"');
1371
+ _segmented.push('>');
1372
+ _segmented.push(ctx);
1373
+ _segmented.push('</a>');
1374
+ });
1375
+ _segmented.push('</div>');
1376
+ segmented = $(_segmented.join(''));
1377
+ segmented.attr('id', id);
1378
+ return segmented;
1379
+ }
1380
+ });
1381
+
1382
+
1383
+ $.fn.extend({
1384
+ ////////////////////////////////////////////
1385
+ // Allow Segmented Control to toggle panels
1386
+ ////////////////////////////////////////////
1387
+ UIPanelToggle : function ( panel, callback ) {
1388
+ var panels;
1389
+ var selected = 0;
1390
+ selected = this.children().hazClass('selected').index() || 0;
1391
+ if (panel instanceof Array) {
1392
+ panels = panel.children('div');
1393
+ } else if (typeof panel === 'string') {
1394
+ panels = $(panel).children('div');
1395
+ }
1396
+ panels.eq(selected).siblings().css({display: 'none'});
1397
+ if (callback) callback.apply(this, arguments);
1398
+ this.on($.eventEnd, 'a', function() {
1399
+ panels.eq($(this).index()).css({display:'block'})
1400
+ .siblings().css('display','none');
1401
+ });
1402
+
1403
+ this.on('singletap', '.button', function() {
1404
+ var $this = $(this);
1405
+ if (this.parentNode.classList.contains('paging')) return;
1406
+ $this.siblings('a').removeClass('selected');
1407
+ $this.siblings('a').removeAttr('aria-checked');
1408
+ $this.addClass('selected');
1409
+ $this.attr('aria-checked', true);
1410
+ });
1411
+ }
1412
+ });
1413
+
1414
+
1415
+ $.extend({
1416
+ ///////////////////////
1417
+ // Setup Paging Control
1418
+ ///////////////////////
1419
+ UIPaging : function ( ) {
1420
+ var currentArticle = $('.segmented.paging').closest('nav').next();
1421
+ if ($('.segmented.paging').hazClass('horizontal').length) {
1422
+ currentArticle.addClass('horizontal');
1423
+ } else if ($('.segmented.paging').hazClass('vertical').length) {
1424
+ currentArticle.addClass('vertical');
1425
+ }
1426
+
1427
+ currentArticle.children().eq(0).addClass('current');
1428
+ currentArticle.children().eq(0).siblings().addClass('next');
1429
+ var sections = function() {
1430
+ return currentArticle.children().length;
1431
+ };
1432
+ var pageBack = function($this) {
1433
+ if (sections() === 1) return;
1434
+ $this.next().removeClass('selected');
1435
+ $this.addClass('selected');
1436
+ var currentSection;
1437
+ currentSection = $('section.current');
1438
+ if (currentSection.index() === 0) {
1439
+ currentSection.removeClass('current');
1440
+ currentArticle.children().eq(sections() - 1).addClass('current').removeClass('next');
1441
+ currentArticle.children().eq(sections() - 1).siblings().removeClass('next').addClass('previous');
1442
+ } else {
1443
+ currentSection.removeClass('current').addClass('next');
1444
+ currentSection.prev().removeClass('previous').addClass('current');
1445
+ }
1446
+ setTimeout(function() {
1447
+ $this.removeClass('selected');
1448
+ }, 250);
1449
+ };
1450
+ var pageForward = function ($this) {
1451
+ if (sections() === 1) return;
1452
+ $this.prev().removeClass('selected');
1453
+ $this.addClass('selected');
1454
+ var currentSection;
1455
+ if ($this[0].classList.contains('disabled')) return;
1456
+ currentSection = $('section.current');
1457
+ if (currentSection.index() === sections() - 1) {
1458
+ // start again!
1459
+ currentSection.removeClass('current');
1460
+ currentArticle.children().eq(0).addClass('current').removeClass('previous');
1461
+ currentArticle.children().eq(0).siblings().removeClass('previous').addClass('next');
1462
+ } else {
1463
+ currentSection.removeClass('current').addClass('previous');
1464
+ currentSection.next().removeClass('next').addClass('current');
1465
+ }
1466
+ setTimeout(function() {
1467
+ $this.removeClass('selected');
1468
+ }, 250);
1469
+ };
1470
+ $('.segmented.paging').on($.eventStart, '.button:first-of-type', function() {
1471
+ pageBack($(this));
1472
+ });
1473
+ $('.segmented.paging').on($.eventStart, '.button:last-of-type', function() {
1474
+ pageForward($(this));
1475
+ });
1476
+ // Handle swipe gestures for paging:
1477
+ if ($('article.paging.horizontal')[0]) {
1478
+ $('article.paging').on('swiperight', function() {
1479
+ pageBack($('.button:first-of-type'));
1480
+ });
1481
+ $('article.paging').on('swipeleft', function() {
1482
+ pageForward($('.button:last-of-type'));
1483
+ });
1484
+ }
1485
+ if ($('article.paging.vertical')[0]) {
1486
+ $('article.paging').on('swipeup', function() {
1487
+ pageBack($('.button:first-of-type'));
1488
+ });
1489
+ $('article.paging').on('swipeudown', function() {
1490
+ pageForward($('.button:last-of-type'));
1491
+ });
1492
+ }
1493
+ }
1494
+ });
1495
+
1496
+
1497
+ $.fn.extend({
1498
+ ////////////////////////////
1499
+ // Initialize Editable List,
1500
+ // allows moving items and
1501
+ // deleting them.
1502
+ ////////////////////////////
1503
+ UIEditList : function ( options ) {
1504
+ /*
1505
+ options = {
1506
+ editLabel : labelName,
1507
+ doneLabel : labelName,
1508
+ deleteLabel : labelName,
1509
+ callback : callback (Tapping "Done" fires this),
1510
+ deletable: false (no deletables),
1511
+ movable: false (no movables)
1512
+ }
1513
+ */
1514
+ var settings = {
1515
+ editLabel : 'Edit',
1516
+ doneLabel : 'Done',
1517
+ deleteLabel : 'Delete',
1518
+ callback : $.noop,
1519
+ deletable: true,
1520
+ movable: true
1521
+ };
1522
+ if (!options) {
1523
+ return;
1524
+ }
1525
+ $.extend(settings, options);
1526
+
1527
+ if (!settings.deletable && !settings.movable) {
1528
+ return;
1529
+ }
1530
+
1531
+ var editLabel = settings.editLabel;
1532
+ var doneLabel = settings.doneLabel;
1533
+ var deleteLabel = settings.deleteLabel;
1534
+ var placement = settings.placement;
1535
+ var callback = settings.callback;
1536
+
1537
+ var deleteButton;
1538
+ var editButton;
1539
+ var deletionIndicator;
1540
+ var button;
1541
+ var dispelDeletable = 'swiperight';
1542
+ var enableDeletable = 'swipeleft';
1543
+ var moveUpIndicator;
1544
+ var moveDownIndicator;
1545
+ var dir = $('html').attr('dir');
1546
+ dir = dir ? dir.toLowerCase() : '';
1547
+ if (dir === 'rtl') {
1548
+ dispelDeletable = 'swipeleft';
1549
+ enableDeletable = 'swiperight';
1550
+ }
1551
+ // Windows uses an icon for the delete button:
1552
+ if ($.isWin) deleteLabel = '';
1553
+ var height = $('li').eq(0)[0].clientHeight;
1554
+
1555
+ if (settings.deletable) {
1556
+ deleteButton = $.concat('<a href="javascript:void(null)" class="button delete">', deleteLabel, '</a>');
1557
+ deletionIndicator = '<span class="deletion-indicator"></span>';
1558
+ $(this).addClass('deletable');
1559
+ }
1560
+ if (settings.movable) {
1561
+ var moveUpIndicator = "<span class='move-up'></span>";
1562
+ var moveDownIndicator = "<span class='move-down'></span>";
1563
+ $(this).addClass('editable');
1564
+ }
1565
+ editButton = $.concat('<a href="javascript:void(null)" class="button edit">', editLabel, '</a>');
1566
+ if (!$(this).closest('article').prev().find('.edit')[0] && !$(this).closest('article').prev().find('.done')[0]) {
1567
+ $(this).closest('article').prev().append(editButton);
1568
+ }
1569
+
1570
+ button = $(this).closest('article').prev().find('.edit');
1571
+ $(this).find('li').forEach(function(ctx) {
1572
+ if (!$(ctx).has('.deletion-indicator').length) {
1573
+ if (settings.deletable) {
1574
+ $(ctx).prepend(deletionIndicator);
1575
+ }
1576
+ if (settings.movable) {
1577
+ $(ctx).append(moveUpIndicator);
1578
+ $(ctx).append(moveDownIndicator);
1579
+ }
1580
+ if (settings.deletable) {
1581
+ $(ctx).append(deleteButton);
1582
+ }
1583
+ }
1584
+ });
1585
+
1586
+ var listData = [];
1587
+ this.find('li').each(function(_, ctx) {
1588
+ listData.push($(ctx).attr('data-ui-value'));
1589
+ });
1590
+
1591
+ // Callback to setup indicator interactions:
1592
+ var setupDeletability = function(callback, list, button) {
1593
+ $(function() {
1594
+ button.on('singletap', function() {
1595
+ var $this = this;
1596
+
1597
+ // When button is in "Edit" state:
1598
+ if (this.classList.contains('edit')) {
1599
+ setTimeout(function() {
1600
+ $this.classList.remove('edit');
1601
+ $this.classList.add('done');
1602
+ $($this).text(settings.doneLabel);
1603
+ $(list).addClass('showIndicators');
1604
+ });
1605
+
1606
+ // When button is in "Done" state:
1607
+ } else if (this.classList.contains('done')) {
1608
+ // Execute callback if edit was performed:
1609
+ //========================================
1610
+ if ($(list).data('list-edit')) {
1611
+ callback.call(callback, $this);
1612
+ }
1613
+ setTimeout(function() {
1614
+ $this.classList.remove('done');
1615
+ $this.classList.add('edit');
1616
+ $($this).text(settings.editLabel);
1617
+ $(list).removeClass('showIndicators');
1618
+ $(list).find('li').removeClass('selected');
1619
+ });
1620
+ }
1621
+ });
1622
+
1623
+ // Handle deletion indicators:
1624
+ $(list).off('singletap', '.deletion-indicator');
1625
+ $(list).on('singletap', '.deletion-indicator', function() {
1626
+ if ($(this).parent('li').hazClass('selected').length) {
1627
+ $(this).parent('li').removeClass('selected');
1628
+ return;
1629
+ } else {
1630
+ $(this).parent('li').addClass('selected');
1631
+ }
1632
+ });
1633
+
1634
+ // Handle swipe gestures:
1635
+ $(list).on(dispelDeletable, 'li', function() {
1636
+ // If no deletables, disable swipes:
1637
+ if (!settings.deletable) return;
1638
+ // Else reveal delete button:
1639
+ $(this).removeClass('selected');
1640
+ });
1641
+
1642
+ $(list).on(enableDeletable, 'li', function() {
1643
+ // If no deletables, disable swipes:
1644
+ if (!settings.deletable) return;
1645
+ // Else reveal delete button:
1646
+ $(this).addClass('selected');
1647
+ });
1648
+
1649
+ // Move list item up:
1650
+ $(list).on('singletap', '.move-up', function(e) {
1651
+ var item = $(this).closest('li');
1652
+ if (item.is('li:first-child')) {
1653
+ return;
1654
+ } else {
1655
+ // Mark list as edited:
1656
+ $(list).data('list-edit', true);
1657
+ var clone = $(this).closest('li').clone();
1658
+ item.prev().before(clone);
1659
+ item.remove();
1660
+ }
1661
+ });
1662
+
1663
+ // Move list item down:
1664
+ $(list).on('singletap', '.move-down', function(e) {
1665
+ var item = $(this).closest('li');
1666
+ if (item.is('li:last-child')) {
1667
+ return;
1668
+ } else {
1669
+ // Mark list as edited:
1670
+ $(list).data('list-edit', true);
1671
+ var clone = $(this).closest('li').clone();
1672
+ item.next().after(clone);
1673
+ item.remove();
1674
+ }
1675
+ });
1676
+
1677
+ // Handle deletion of list item:
1678
+ $(list).on('singletap', '.delete', function() {
1679
+ var $this = this;
1680
+ // Mark list as edited:
1681
+ $(list).data('list-edit', true);
1682
+ var direction = '-1000%';
1683
+ if ($('html').attr('dir') === 'rtl') direction = '1000%';
1684
+ $(this).siblings().css({'-webkit-transform': 'translate3d(' + direction + ',0,0)', '-webkit-transition': 'all 1s ease-out'});
1685
+ setTimeout(function() {
1686
+ $($this).parent().remove();
1687
+ }, 500);
1688
+ });
1689
+ });
1690
+ };
1691
+ // Initialize the editable list:
1692
+ return setupDeletability(settings.callback, $(this), button);
1693
+ }
1694
+
1695
+ });
1696
+
1697
+
1698
+ $.fn.extend({
1699
+ /////////////////////////
1700
+ // Initialize Select List
1701
+ /////////////////////////
1702
+ /*
1703
+ // For default selection use zero-based integer:
1704
+ options = {
1705
+ name : name // used on radio buttons as group name, defaults to uuid.
1706
+ selected : integer,
1707
+ callback : callback
1708
+ // callback example:
1709
+ function () {
1710
+ // this is the selected list item:
1711
+ console.log($(this).text());
1712
+ }
1713
+ }
1714
+ */
1715
+ UISelectList : function (options) {
1716
+ var name = (options && options.name) ? options.name : $.Uuid();
1717
+ var list = this[0];
1718
+ list.classList.add('select');
1719
+ $(list).find('li').forEach(function(ctx, idx) {
1720
+ var value = ctx.getAttribute("data-select-value") !== null ? ctx.getAttribute("data-select-value") : "";
1721
+ ctx.setAttribute('role', 'radio');
1722
+ $(ctx).removeClass('selected').find('input').removeAttr('checked');
1723
+ if (options && options.selected === idx) {
1724
+ ctx.setAttribute('aria-checked', 'true');
1725
+ ctx.classList.add('selected');
1726
+ if (!$(ctx).find('input')[0]) {
1727
+ $(ctx).append('<input type="radio" checked="checked" name="' + name + '" value="' + value +'">');
1728
+ } else {
1729
+ $(ctx).find('input').prop('checked',true).attr('value', value);
1730
+ }
1731
+ } else {
1732
+ if (!$(ctx).find('input')[0]) {
1733
+ $(ctx).append('<input type="radio" name="' + name + '" value="' + value +'">');
1734
+ }
1735
+ }
1736
+ });
1737
+ $(list).on('singletap', 'li', function() {
1738
+ var item = this;
1739
+ $(item).siblings('li').removeClass('selected');
1740
+ $(item).siblings('li').removeAttr('aria-checked');
1741
+ $(item).siblings('li').find('input').removeAttr('checked');
1742
+ $(item).addClass('selected');
1743
+ item.setAttribute('aria-checked', true);
1744
+ $(item).find('input').prop('checked',true);
1745
+ if (options && options.callback) {
1746
+ options.callback.apply(this, arguments);
1747
+ }
1748
+ });
1749
+ }
1750
+ });
1751
+
1752
+
1753
+ $.extend({
1754
+ ///////////////////////////////////////////////
1755
+ // UISheet: Create an Overlay for Buttons, etc.
1756
+ ///////////////////////////////////////////////
1757
+ /*
1758
+ var options {
1759
+ id : 'starTrek',
1760
+ listClass :'enterprise',
1761
+ background: 'transparent',
1762
+ }
1763
+ */
1764
+ UISheet : function ( options ) {
1765
+ var id = $.Uuid();
1766
+ var listClass = '';
1767
+ var background = '';
1768
+ if (options) {
1769
+ id = options.id ? options.id : id;
1770
+ listClass = options.listClass ? ' ' + options.listClass : '';
1771
+ background = ' style="background-color:' + options.background + ';" ' || '';
1772
+ }
1773
+ var sheet = '<div id="' + id + '" class="sheet' + listClass + '"><div class="handle"></div><section class="scroller-vertical"></section></div>';
1774
+ $('body').append(sheet);
1775
+ $('.sheet .handle').on($.eventStart, function() {
1776
+ $.UIHideSheet();
1777
+ });
1778
+ },
1779
+ UIShowSheet : function ( ) {
1780
+ $('article.current').addClass('blurred');
1781
+ if ($.isAndroid || $.isChrome) {
1782
+ $('.sheet').css('display','block');
1783
+ setTimeout(function() {
1784
+ $('.sheet').addClass('opened');
1785
+ }, 20);
1786
+ } else {
1787
+ $('.sheet').addClass('opened');
1788
+ }
1789
+ },
1790
+ UIHideSheet : function ( ) {
1791
+ $('.sheet').removeClass('opened');
1792
+ $('article.current').addClass('removeBlurSlow');
1793
+ setTimeout(function() {
1794
+ $('article').removeClass('blurred');
1795
+ $('article').removeClass('removeBlurSlow');
1796
+ },500);
1797
+ }
1798
+ });
1799
+
1800
+
1801
+ $.extend({
1802
+ ////////////////////////////////////////////////
1803
+ // Create Slideout with toggle button.
1804
+ // Use $.UISlideout.populate to polate slideout.
1805
+ // See widget-factor.js for details.
1806
+ ////////////////////////////////////////////////
1807
+ /*
1808
+ var options = {
1809
+ position: position,
1810
+ dynamic: false,
1811
+ callback: $.noop
1812
+ };
1813
+ */
1814
+ UISlideout : function ( options ) {
1815
+ var position, dynamic, callback = $.noop;
1816
+ if (options && options.position) {
1817
+ position = options.position;
1818
+ } else {
1819
+ position = 'left';
1820
+ }
1821
+ if (options && options.dynamic) {
1822
+ dynamic = options.dynamic;
1823
+ } else {
1824
+ dynamic = false;
1825
+ }
1826
+ if (options && options.callback) {
1827
+ callback = options.callback;
1828
+ }
1829
+ var slideoutButton = $("<a class='button slide-out-button' href='javascript:void(null)'></a>");
1830
+ var slideOut = '<div class="slide-out"><section></section></div>';
1831
+ $('article').removeClass('next');
1832
+ $('article').removeClass('current');
1833
+ $('article').prev().removeClass('next');
1834
+ $('article').prev().removeClass('current');
1835
+ $('body').append(slideOut);
1836
+ $('body').addClass('slide-out-app');
1837
+ $('article:first-of-type').addClass('show');
1838
+ $('article:first-of-type').prev().addClass('show');
1839
+ $('#global-nav').append(slideoutButton);
1840
+ $('.slide-out-button').on($.eventStart, function() {
1841
+ $('.slide-out').toggleClass('open');
1842
+ });
1843
+ if (!dynamic) {
1844
+ $('.slide-out').on('singletap', 'li', function() {
1845
+ var whichArticle = '#' + $(this).attr('data-show-article');
1846
+ $.UINavigationHistory[0] = whichArticle;
1847
+ $.UISetHashOnUrl(whichArticle);
1848
+ $.publish('chui/navigate/leave', $('article.show')[0].id);
1849
+ $.publish('chui/navigate/enter', whichArticle);
1850
+ $('.slide-out').removeClass('open');
1851
+ $('article').removeClass('show');
1852
+ $('article').prev().removeClass('show');
1853
+ $(whichArticle).addClass('show');
1854
+ $(whichArticle).prev().addClass('show');
1855
+ });
1856
+ } else {
1857
+ $('.slide-out').on('singletap', 'li', function() {
1858
+ callback(this);
1859
+ });
1860
+ }
1861
+ }
1862
+ });
1863
+ $.extend($.UISlideout, {
1864
+ /////////////////////////////////////////////////////////////////
1865
+ // Method to populate a slideout with actionable items.
1866
+ // The argument is an array of objects consisting of a key/value.
1867
+ // The key will be the id of the article to be shown.
1868
+ // The value is the title for the list item.
1869
+ // [{music:'Music'},{docs:'Documents'},{recipes:'Recipes'}]
1870
+ /////////////////////////////////////////////////////////////////
1871
+ populate: function( args ) {
1872
+ var slideout = $('.slide-out');
1873
+ if (!slideout[0]) return;
1874
+ if (!$.isArray(args)) {
1875
+ return;
1876
+ } else {
1877
+ slideout.find('section').append('<ul class="list"></ul>');
1878
+ var list = slideout.find('ul');
1879
+ args.forEach(function(ctx) {
1880
+ for (var key in ctx) {
1881
+ if (key === 'header') {
1882
+ list.append('<li class="slideout-header"><h2>'+ctx[key]+'</h2></li>');
1883
+ } else {
1884
+ list.append('<li data-show-article="' + key + '"><h3>' + ctx[key] + '</h3></li>');
1885
+ }
1886
+ }
1887
+ });
1888
+ }
1889
+ }
1890
+ });
1891
+
1892
+
1893
+ $.fn.extend({
1894
+ /////////////////
1895
+ // Create stepper
1896
+ /////////////////
1897
+ /*
1898
+ var options = {
1899
+ start: 0,
1900
+ end: 10,
1901
+ defaultValue: 3
1902
+ }
1903
+ */
1904
+ UIStepper : function (options) {
1905
+ if (!options) return [];
1906
+ if (!options.start) return [];
1907
+ if (!options.end) return [];
1908
+ var stepper = $(this);
1909
+ var start = options.start;
1910
+ var end = options.end;
1911
+ var defaultValue = options.defaultValue ? options.defaultValue : options.start;
1912
+ var increaseSymbol = '+';
1913
+ var decreaseSymbol = '-';
1914
+ if ($.isWin) {
1915
+ increaseSymbol = '';
1916
+ decreaseSymbol = '';
1917
+ }
1918
+ var decreaseButton = '<a href="javascript:void(null)" class="button decrease">' + decreaseSymbol + '</a>';
1919
+ var label = '<label>' + defaultValue + '</label><input type="text" value="' + defaultValue + '">';
1920
+ var increaseButton = '<a href="javascript:void(null)" class="button increase">' + increaseSymbol + '</a>';
1921
+ stepper.append(decreaseButton + label + increaseButton);
1922
+ stepper.data('ui-value', {start: start, end: end, defaultValue: defaultValue});
1923
+
1924
+ var decreaseStepperValue = function() {
1925
+ var currentValue = stepper.find('input').val();
1926
+ var value = stepper.data('ui-value');
1927
+ var start = value.start;
1928
+ var newValue;
1929
+ if (currentValue <= start) {
1930
+ $(this).addClass('disabled');
1931
+ } else {
1932
+ newValue = Number(currentValue) - 1;
1933
+ stepper.find('.button:last-of-type').removeClass('disabled');
1934
+ stepper.find('label').text(newValue);
1935
+ stepper.find('input')[0].value = newValue;
1936
+ if (currentValue === start) {
1937
+ $(this).addClass('disabled');
1938
+ }
1939
+ }
1940
+ };
1941
+
1942
+ var increaseStepperValue = function() {
1943
+ var currentValue = stepper.find('input').val();
1944
+ var value = stepper.data('ui-value');
1945
+ var end = value.end;
1946
+ var newValue;
1947
+ if (currentValue >= end) {
1948
+ $(this).addClass('disabled');
1949
+ } else {
1950
+ newValue = Number(currentValue) + 1;
1951
+ stepper.find('.button:first-of-type').removeClass('disabled');
1952
+ stepper.find('label').text(newValue);
1953
+ stepper.find('input')[0].value = newValue;
1954
+ if (currentValue === end) {
1955
+ $(this).addClass('disabled');
1956
+ }
1957
+ }
1958
+ };
1959
+ stepper.find('.button:first-of-type').on('singletap', function() {
1960
+ decreaseStepperValue.call(this, stepper);
1961
+ });
1962
+ stepper.find('.button:last-of-type').on('singletap', function() {
1963
+ increaseStepperValue.call(this, stepper);
1964
+ });
1965
+ }
1966
+ });
1967
+ $.extend({
1968
+ ///////////////////////////////////////////
1969
+ // Pass the id of the stepper to reset.
1970
+ // It's value will be reset to the default.
1971
+ ///////////////////////////////////////////
1972
+ // Pass it the id of the stepper:
1973
+ UIResetStepper : function ( stepper ) {
1974
+ var defaultValue = stepper.data('ui-value').defaultValue;
1975
+ stepper.find('label').html(defaultValue);
1976
+ stepper.find('input')[0].value = defaultValue;
1977
+ }
1978
+ });
1979
+
1980
+
1981
+ $.fn.extend({
1982
+ ////////////////////////////
1983
+ // Initialize Switch Control
1984
+ ////////////////////////////
1985
+ UISwitch : function ( ) {
1986
+ var hasThumb = false;
1987
+ this.forEach(function(ctx, idx) {
1988
+ ctx.setAttribute('role','checkbox');
1989
+ if ($(ctx).data('ui-setup') === true) return;
1990
+ if (!ctx.querySelector('input')) {
1991
+ ctx.insertAdjacentHTML('afterBegin', '<input type="checkbox">');
1992
+ }
1993
+ if (ctx.classList.contains('on')) {
1994
+ ctx.querySelector('input').setAttribute('checked', 'checked');
1995
+ }
1996
+ if (ctx.querySelector('em')) hasThumb = true;
1997
+ if (!hasThumb) {
1998
+ ctx.insertAdjacentHTML('afterBegin', '<em></em>');
1999
+ }
2000
+ $(ctx).on('singletap', function() {
2001
+ var checkbox = ctx.querySelector('input');
2002
+ if (ctx.classList.contains('on')) {
2003
+ ctx.classList.remove('on');
2004
+ ctx.removeAttribute('aria-checked');
2005
+ checkbox.removeAttribute('checked');
2006
+ } else {
2007
+ ctx.classList.add('on');
2008
+ checkbox.setAttribute('checked', 'checked');
2009
+ ctx.setAttribute('aria-checked', true);
2010
+ }
2011
+ });
2012
+ $(ctx).on('swipeleft', function() {
2013
+ var checkbox = ctx.querySelector('input');
2014
+ if (ctx.classList.contains('on')) {
2015
+ ctx.classList.remove('on');
2016
+ ctx.removeAttribute('aria-checked');
2017
+ checkbox.removeAttribute('checked');
2018
+ }
2019
+ });
2020
+ $(ctx).on('swiperight', function() {
2021
+ var checkbox = ctx.querySelector('input');
2022
+ if (!ctx.classList.contains('on')) {
2023
+ ctx.classList.add('on');
2024
+ checkbox.setAttribute('checked', 'checked');
2025
+ ctx.setAttribute('aria-checked', true);
2026
+ }
2027
+ });
2028
+ $(ctx).data('ui-setup', true);
2029
+ });
2030
+ }
2031
+ });
2032
+ $.extend({
2033
+ ////////////////////////
2034
+ // Create Switch Control
2035
+ ////////////////////////
2036
+ UICreateSwitch : function ( options ) {
2037
+ /* options = {
2038
+ id : '#myId',
2039
+ name: 'fruit.mango'
2040
+ state : 'on' || 'off' //(off is default),
2041
+ value : 'Mango' || '',
2042
+ callback : callback
2043
+ }
2044
+ */
2045
+ var id = options ? options.id : $.Uuid();
2046
+ var name = options && options.name ? (' name="' + options.name + '"') : '';
2047
+ var value= options && options.value ? (' value="' + options.value + '"') : '';
2048
+ var state = (options && options.state === 'on') ? (' ' + options.state) : '';
2049
+ var checked = (options && options.state === 'on') ? ' checked="checked"' : '';
2050
+ var _switch = $.concat('<span class="switch', state,
2051
+ '" id="', id, '"><em></em>','<input type="checkbox"',
2052
+ name, checked, value, '></span>');
2053
+ return $(_switch);
2054
+ }
2055
+ });
2056
+ $(function() {
2057
+ //////////////////////////
2058
+ // Handle Existing Switches:
2059
+ //////////////////////////
2060
+ $('.switch').UISwitch();
2061
+ });
2062
+
2063
+
2064
+ document.addEventListener('touchstart', function (e) {
2065
+ var parent = e.target,
2066
+ i = 0;
2067
+
2068
+ for (i = 0; i < 10; i += 1) {
2069
+ if (parent !== null) {
2070
+ if (parent.className !== undefined) {
2071
+ if (parent.className.match('navigable')) {
2072
+ if (parent.scrollTop === 0) {
2073
+ parent.scrollTop = 1;
2074
+ } else if ((parent.scrollTop + parent.offsetHeight) === parent.scrollHeight) {
2075
+ parent.scrollTop = parent.scrollTop - 1;
2076
+ }
2077
+ }
2078
+ }
2079
+ parent = parent.parentNode;
2080
+ }
2081
+ }
2082
+ });
2083
+
2084
+
2085
+ $.extend({
2086
+ ///////////////////////////////////////////
2087
+ // Creates a Tab Bar for Toggling Articles:
2088
+ ///////////////////////////////////////////
2089
+ UITabbar : function ( options ) {
2090
+ /*
2091
+ var options = {
2092
+ id: 'mySpecialTabbar',
2093
+ tabs: 4,
2094
+ labels: ["Refresh", "Add", "Info", "Downloads", "Favorite"],
2095
+ icons: ["refresh", "add", "info", "downloads", "favorite"],
2096
+ selected: 2
2097
+ }
2098
+ */
2099
+ if (!options) return;
2100
+ var settings = {
2101
+ id : $.Uuid(),
2102
+ selected : 0
2103
+ };
2104
+ $.extend(settings, options);
2105
+ $('body').addClass('hasTabBar');
2106
+ if ($.isiOS6) $('body').addClass('isiOS6');
2107
+ var tabbar = '<div class="tabbar" id="' + settings.id + '">';
2108
+ var icon = ($.isiOS || $.isSafari) ? '<span class="icon"></span>' : '';
2109
+ var articles = $('article');
2110
+ for (var i = 0; i < settings.tabs; i++) {
2111
+ tabbar += '<a class="button ' + settings.icons[i];
2112
+ if (settings.selected === i+1) {
2113
+ tabbar += ' selected';
2114
+ }
2115
+ tabbar += '">' + icon + '<label>' + settings.labels[i] + '</label></a>';
2116
+ }
2117
+ tabbar += '</div>';
2118
+ $('body').append(tabbar);
2119
+
2120
+ //////////////////////////////////////////////////////
2121
+ // Add article id as history data attribute to button:
2122
+ //////////////////////////////////////////////////////
2123
+ $('#' + settings.id).find('.button').each(function(idx, ctx){
2124
+ $(ctx).data('history', ['#' + articles.eq(idx)[0].id]);
2125
+ });
2126
+ $('nav').removeClass('current').addClass('next');
2127
+ $('#global-nav').removeClass('next');
2128
+ $('nav').eq(settings.selected).removeClass('next').addClass('current');
2129
+ $('article').removeClass('current').addClass('next');
2130
+ $('article').eq(settings.selected-1).removeClass('next').addClass('current');
2131
+
2132
+ // Setup events on tabs:
2133
+ $('.tabbar').on('singletap', '.button', function() {
2134
+ var $this = this;
2135
+ var index;
2136
+ var id;
2137
+ $.publish('chui/navigate/leave', $('article.current')[0].id);
2138
+
2139
+ //////////////////////////////////////////////////
2140
+ // Set the data attribute for the current history:
2141
+ //////////////////////////////////////////////////
2142
+ $(this).siblings('.selected').data('history', $.UINavigationHistory);
2143
+
2144
+ $this.classList.add('selected');
2145
+ $($this).siblings('a').removeClass('selected');
2146
+ index = $(this).index();
2147
+ $('article.previous').removeClass('previous').addClass('next');
2148
+ $('nav.previous').removeClass('previous').addClass('next');
2149
+
2150
+ /////////////////////////////////////////////////////////////////
2151
+ // Update the history array with the current tabs stored history:
2152
+ /////////////////////////////////////////////////////////////////
2153
+ var history = $(this).data('history');
2154
+
2155
+ ///////////////////////////////////////////////
2156
+ // If the history array has more than one item,
2157
+ // we know that it is a navigation link.
2158
+ ///////////////////////////////////////////////
2159
+ if (history.length > 1) {
2160
+ $('article.current').removeClass('current').addClass('next');
2161
+ $('nav.current').removeClass('current').addClass('next');
2162
+
2163
+ /////////////////////////////////////////////////
2164
+ // Set saved state of navigation list to current:
2165
+ /////////////////////////////////////////////////
2166
+ $(history[history.length-1]).removeClass('next').addClass('current');
2167
+ $(history[history.length-1]).prev().removeClass('next').addClass('current');
2168
+
2169
+ ////////////////////////////////////////////////////
2170
+ // Set state for earlier screens of navigation list:
2171
+ ////////////////////////////////////////////////////
2172
+ var prevScreens = history.length-1;
2173
+ for (var i = 0; i < prevScreens; i++) {
2174
+ $(history[i]).removeClass('next').addClass('previous');
2175
+ $(history[i]).prev().removeClass('next').addClass('previous');
2176
+ }
2177
+
2178
+ ////////////////////////////////////////////////
2179
+ // Otherwise, since the array has only one item,
2180
+ // we are dealing with a single tabbar panel.
2181
+ ////////////////////////////////////////////////
2182
+ } else {
2183
+ $('article.current').removeClass('current').addClass('next');
2184
+ $('nav.current').removeClass('current').addClass('next');
2185
+ $('article').eq(index).removeClass('next').addClass('current');
2186
+ $('nav').eq(index+1).removeClass('next').addClass('current');
2187
+ }
2188
+
2189
+ id = $('article').eq(index)[0].id;
2190
+ $.publish('chui/navigate/enter', id);
2191
+
2192
+ // Set the chosen tab article's scroll to top:
2193
+ //============================================
2194
+ $('article').forEach(function(ctx) {
2195
+ if (window.jQuery) {
2196
+ $(ctx).scrollTop(0);
2197
+ } else if (window.$chocolatechipjs) {
2198
+ ctx.scrollTop = 0;
2199
+ }
2200
+ });
2201
+ $.UISetHashOnUrl('#'+id);
2202
+ $.UINavigationHistory = $(this).data('history');
2203
+ });
2204
+ }
2205
+ });
2206
+
2207
+
2208
+ $.extend({
2209
+ /////////////////////////////
2210
+ // Templating:
2211
+ /////////////////////////////
2212
+ templates : {},
2213
+
2214
+ template : function ( tmpl, variable ) {
2215
+ var regex;
2216
+ variable = variable || 'data';
2217
+ regex = /\[\[=([\s\S]+?)\]\]/g;
2218
+ var template = new Function(variable,
2219
+ "var p=[];" + "p.push('" + tmpl
2220
+ .replace(/[\r\t\n]/g, " ")
2221
+ .split("'").join("\\'")
2222
+ .replace(regex,"',$1,'")
2223
+ .split('[[').join("');")
2224
+ .split(']]').join("p.push('") + "');" +
2225
+ "return p.join('');");
2226
+ return template;
2227
+ }
2228
+ });
2229
+
2230
+
2231
+ /////////////////////////
2232
+ // Create a search input:
2233
+ /////////////////////////
2234
+ /*
2235
+ $.UISearch({
2236
+ articleId: '#products',
2237
+ id: 'productSearch',
2238
+ placeholder: 'Find a product',
2239
+ results: 5
2240
+ })
2241
+ */
2242
+ $.extend({
2243
+ UISearch : function(options) {
2244
+ var article = options && options.articleId || $('article').eq(0);
2245
+ var searchID = options && options.id || $.Uuid();
2246
+ var placeholder = options && options.placeholder || 'search';
2247
+ var results = options && options.results || 1;
2248
+ var widget = '<div class="searchBar"><input placeholder="' + placeholder +'" type="search" results="' + results + '" id="'+ searchID + '"></div>';
2249
+ $(article).find('section').prepend(widget);
2250
+ if ($.isWin) {
2251
+ $(article).prev().append(widget);
2252
+ $('#' + searchID).parent().append('<span class="searchGlyph">&#xe11A;</span>');
2253
+ }
2254
+ }
2255
+ });
2256
+
2257
+
2258
+ //////////////////////////////////
2259
+ // Initialize a swipeable carousel:
2260
+ //////////////////////////////////
2261
+ $(function() {
2262
+ var UICarousel = (function () {
2263
+ var discoverVendorStyle = document.createElement('div').style,
2264
+ vendor = (function () {
2265
+ var vendors = 't,webkitT'.split(',');
2266
+ var l = vendors.length;
2267
+ var t;
2268
+ for ( var i = 0 ; i < l; i++ ) {
2269
+ t = vendors[i] + 'ransform';
2270
+ if ( t in discoverVendorStyle ) {
2271
+ return vendors[i].substr(0, vendors[i].length - 1);
2272
+ }
2273
+ }
2274
+ return false;
2275
+ })(),
2276
+ cssVendor = vendor ? '-' + vendor.toLowerCase() + '-' : '',
2277
+ transform = prefixStyle('transform'),
2278
+ transitionDuration = prefixStyle('transitionDuration'),
2279
+ hasTouch = 'ontouchstart' in window;
2280
+ var startEvent = $.eventStart;
2281
+ var moveEvent = $.eventMove;
2282
+ var endEvent = $.eventEnd;
2283
+ var cancelEvent = $.eventCancel;
2284
+ var transitionEndEvent = (function () {
2285
+ if ( vendor === false ) return false;
2286
+ var transitionEnd = {
2287
+ '': 'transitionend',
2288
+ 'webkit': 'webkitTransitionEnd'
2289
+ };
2290
+ return transitionEnd[vendor];
2291
+ })(),
2292
+
2293
+ UICarousel = function ( options ) {
2294
+ if (!options) return;
2295
+ var ul, li, className;
2296
+ this.carouselContainer = typeof options.target === 'string' ? document.querySelector(options.target) : options.target;
2297
+ this.options = {
2298
+ panels: options.panels || 3,
2299
+ snapThreshold: null,
2300
+ loop: options.loop || true
2301
+ };
2302
+ // Adjustment for RTL carousels:
2303
+ if ($.isRTL) {
2304
+ options.loop = true;
2305
+ }
2306
+ // Include user's options:
2307
+ for (var i in options) this.options[i] = options[i];
2308
+ this.carouselContainer.style.overflow = 'hidden';
2309
+ this.carouselContainer.style.position = 'relative';
2310
+ this.carouselPanels = [];
2311
+ ul = document.createElement('ul');
2312
+ ul.className = 'carousel-track';
2313
+ ul.style.cssText = 'position:relative;top:0;height:100%;width:100%;' + cssVendor + 'transition-duration:0;' + cssVendor + 'transform:translateZ(0);' + cssVendor + 'transition-timing-function:ease-out';
2314
+ this.carouselContainer.appendChild(ul);
2315
+ this.track = ul;
2316
+ this.refreshSize();
2317
+ var whichPanelIndex;
2318
+ for (var j = -1; j < 2; j++) {
2319
+ li = document.createElement('li');
2320
+ li.id = 'carousel-panel-' + (j + 1);
2321
+ li.style.cssText = cssVendor + 'transform:translateZ(0);position:absolute;top:0;height:100%;width:100%;left:' + j * 100 + '%';
2322
+ whichPanelIndex = j === -1 ? this.options.panels - 1 : j;
2323
+ $(li).data('upcomingPanelIndex', whichPanelIndex);
2324
+ if (!this.options.loop && j === -1) li.style.visibility = 'hidden';
2325
+ this.track.appendChild(li);
2326
+ this.carouselPanels.push(li);
2327
+ }
2328
+ className = this.carouselPanels[1].className;
2329
+ this.carouselPanels[1].className = !className ? 'carousel-panel-active' : className + ' carousel-panel-active';
2330
+ this.carouselContainer.addEventListener(startEvent, this, false);
2331
+ this.carouselContainer.addEventListener(moveEvent, this, false);
2332
+ this.carouselContainer.addEventListener(endEvent, this, false);
2333
+ this.track.addEventListener(transitionEndEvent, this, false);
2334
+ var pagination;
2335
+ if (options.pagination) {
2336
+ pagination = document.createElement('ul');
2337
+ pagination.className = 'pagination';
2338
+ for (var k = 0; k < this.options.panels.length; k++) {
2339
+ li = document.createElement('li');
2340
+ if (k === 0) {
2341
+ li.className = 'selected';
2342
+ }
2343
+ pagination.appendChild(li);
2344
+ }
2345
+ if (window.$chocolatechipjs) {
2346
+ this.carouselContainer.insertAdjacentElement('afterEnd', pagination);
2347
+ } else {
2348
+ $(this.carouselContainer).after(pagination);
2349
+ }
2350
+ }
2351
+ };
2352
+ UICarousel.prototype = {
2353
+ currentPanel: 1,
2354
+ x: 0,
2355
+ panel: 0,
2356
+ customEvents: [],
2357
+
2358
+ onSlide: function (fn) {
2359
+ this.carouselContainer.addEventListener('carousel-panel-move', fn, false);
2360
+ this.customEvents.push(['move', fn]);
2361
+ },
2362
+ destroy: function () {
2363
+ while ( this.customEvents.length ) {
2364
+ this.carouselContainer.removeEventListener('carousel-panel-' + this.customEvents[0][0], this.customEvents[0][1], false);
2365
+ this.customEvents.shift();
2366
+ }
2367
+ // Remove event listeners:
2368
+ this.carouselContainer.removeEventListener(startEvent, this, false);
2369
+ this.carouselContainer.removeEventListener(moveEvent, this, false);
2370
+ this.carouselContainer.removeEventListener(endEvent, this, false);
2371
+ this.track.removeEventListener(transitionEndEvent, this, false);
2372
+ },
2373
+ refreshSize: function () {
2374
+ this.carouselContainerWidth = this.carouselContainer.clientWidth;
2375
+ this.carouselContainerHeight = this.carouselContainer.clientHeight;
2376
+ this.panelWidth = this.carouselContainerWidth;
2377
+ this.maxX = -this.options.panels * this.panelWidth + this.carouselContainerWidth;
2378
+ this.snapThreshold = this.options.snapThreshold === null ?
2379
+ Math.round(this.panelWidth * 0.15) :
2380
+ /%/.test(this.options.snapThreshold) ?
2381
+ Math.round(this.panelWidth * this.options.snapThreshold.replace('%', '') / 100) :
2382
+ this.options.snapThreshold;
2383
+ },
2384
+
2385
+ updatePanelCount: function (n) {
2386
+ this.options.panels = n;
2387
+ this.maxX = -this.options.panels * this.panelWidth + this.carouselContainerWidth;
2388
+ },
2389
+
2390
+ goToPanel: function (p) {
2391
+ this.carouselPanels[this.currentPanel].className = this.carouselPanels[this.currentPanel].className.replace(/(^|\s)carousel-panel-active(\s|$)/, '');
2392
+ p = p < 0 ? 0 : p > this.options.panels-1 ? this.options.panels - 1 : p;
2393
+ console.log('p: ' , p);
2394
+ this.panel = p;
2395
+ this.track.style[transitionDuration] = '0s';
2396
+ this.getPosition(-p * this.panelWidth);
2397
+ this.currentPanel = (this.panel + 1) - Math.floor((this.panel + 1) / 3) * 3;
2398
+ this.carouselPanels[this.currentPanel].className = this.carouselPanels[this.currentPanel].className + ' carousel-panel-active';
2399
+ if (this.currentPanel === 0) {
2400
+ this.carouselPanels[2].style.left = this.panel * 100 - 100 + '%';
2401
+ this.carouselPanels[0].style.left = this.panel * 100 + '%';
2402
+ this.carouselPanels[1].style.left = this.panel * 100 + 100 + '%';
2403
+ $(this.carouselPanels[2]).data('upcomingPanelIndex', this.panel === 0 ? this.options.panels - 1 : this.panel - 1);
2404
+ $(this.carouselPanels[0]).data('upcomingPanelIndex', this.panel);
2405
+ $(this.carouselPanels[1]).data('upcomingPanelIndex', this.panel === this.options.panels - 1 ? 0 : this.panel + 1);
2406
+ } else if (this.currentPanel === 1) {
2407
+ this.carouselPanels[0].style.left = this.panel * 100 - 100 + '%';
2408
+ this.carouselPanels[1].style.left = this.panel * 100 + '%';
2409
+ this.carouselPanels[2].style.left = this.panel * 100 + 100 + '%';
2410
+ $(this.carouselPanels[0]).data('upcomingPanelIndex', this.panel === 0 ? this.options.panels - 1 : this.panel - 1);
2411
+ $(this.carouselPanels[1]).data('upcomingPanelIndex', this.panel);
2412
+ $(this.carouselPanels[2]).data('upcomingPanelIndex', this.panel === this.options.panels - 1 ? 0 : this.panel + 1);
2413
+ } else {
2414
+ this.carouselPanels[1].style.left = this.panel * 100 - 100 + '%';
2415
+ this.carouselPanels[2].style.left = this.panel * 100 + '%';
2416
+ this.carouselPanels[0].style.left = this.panel * 100 + 100 + '%';
2417
+ $(this.carouselPanels[1]).data('upcomingPanelIndex', this.panel === 0 ? this.options.panels - 1 : this.panel - 1);
2418
+ $(this.carouselPanels[2]).data('upcomingPanelIndex', this.panel);
2419
+ $(this.carouselPanels[0]).data('upcomingPanelIndex', this.panel === this.options.panels - 1 ? 0 : this.panel + 1);
2420
+ }
2421
+ this.slide();
2422
+ },
2423
+ handleEvent: function (e) {
2424
+ switch (e.type) {
2425
+ case startEvent:
2426
+ this.start(e);
2427
+ break;
2428
+ case moveEvent:
2429
+ this.move(e);
2430
+ break;
2431
+ case cancelEvent:
2432
+ case endEvent:
2433
+ this.end(e);
2434
+ break;
2435
+ }
2436
+ },
2437
+ getPosition: function (x) {
2438
+ this.x = x;
2439
+ this.track.style[transform] = 'translate(' + x + 'px,0) translateZ(0)';
2440
+ },
2441
+ resize: function () {
2442
+ this.refreshSize();
2443
+ this.track.style[transitionDuration] = '0s';
2444
+ this.getPosition(-this.panel * this.panelWidth);
2445
+ },
2446
+ start: function (e) {
2447
+ if (this.initiated) return;
2448
+ var point = hasTouch ? e.touches[0] : e;
2449
+ this.initiated = true;
2450
+ this.moved = false;
2451
+ this.thresholdExceeded = false;
2452
+ this.startX = point.pageX;
2453
+ this.startY = point.pageY;
2454
+ this.pointX = point.pageX;
2455
+ this.pointY = point.pageY;
2456
+ this.stepsX = 0;
2457
+ this.stepsY = 0;
2458
+ this.directionX = 0;
2459
+ this.directionLocked = false;
2460
+ this.track.style[transitionDuration] = '0s';
2461
+ this.event('touchstart');
2462
+ },
2463
+
2464
+ move: function (e) {
2465
+ if (!this.initiated) return;
2466
+ var point = hasTouch ? e.touches[0] : e;
2467
+ var deltaX = point.pageX - this.pointX;
2468
+ var deltaY = point.pageY - this.pointY;
2469
+ var newX = this.x + deltaX;
2470
+ var dist = Math.abs(point.pageX - this.startX);
2471
+ this.moved = true;
2472
+ this.pointX = point.pageX;
2473
+ this.pointY = point.pageY;
2474
+ this.directionX = deltaX > 0 ? 1 : deltaX < 0 ? -1 : 0;
2475
+ this.stepsX += Math.abs(deltaX);
2476
+ this.stepsY += Math.abs(deltaY);
2477
+ // Use buffer to calculate direction of swipe:
2478
+ if (this.stepsX < 10 && this.stepsY < 10) {
2479
+ return;
2480
+ }
2481
+ // If scrolling vertically, cancel:
2482
+ if (!this.directionLocked && this.stepsY > this.stepsX) {
2483
+ this.initiated = false;
2484
+ return;
2485
+ }
2486
+ e.preventDefault();
2487
+ this.directionLocked = true;
2488
+ if (!this.options.loop && (newX > 0 || newX < this.maxX)) {
2489
+ newX = this.x + (deltaX / 2);
2490
+ }
2491
+ this.getPosition(newX);
2492
+ },
2493
+
2494
+ end: function (e) {
2495
+ if (!this.initiated) return;
2496
+ var point = hasTouch ? e.changedTouches[0] : e;
2497
+ var dist = Math.abs(point.pageX - this.startX);
2498
+ this.initiated = false;
2499
+ if (!this.moved) return;
2500
+ if (!this.options.loop && (this.x > 0 || this.x < this.maxX)) {
2501
+ dist = 0;
2502
+ }
2503
+ // Check if exceeded snap threshold:
2504
+ if (dist < this.snapThreshold) {
2505
+ this.track.style[transitionDuration] = Math.floor(300 * dist / this.snapThreshold) + 'ms';
2506
+ this.getPosition(-this.panel * this.panelWidth);
2507
+ return;
2508
+ }
2509
+ this.checkPosition();
2510
+ },
2511
+
2512
+ checkPosition: function () {
2513
+ var panelMove;
2514
+ var pageFlipIndex;
2515
+ var className;
2516
+ this.carouselPanels[this.currentPanel].className = '';
2517
+ // Slide the panel:
2518
+ if (this.directionX > 0) {
2519
+ this.panel = -Math.ceil(this.x / this.panelWidth);
2520
+ this.currentPanel = (this.panel + 1) - Math.floor((this.panel + 1) / 3) * 3;
2521
+ panelMove = this.currentPanel - 1;
2522
+ panelMove = panelMove < 0 ? 2 : panelMove;
2523
+ this.carouselPanels[panelMove].style.left = this.panel * 100 - 100 + '%';
2524
+ pageFlipIndex = this.panel - 1;
2525
+ } else {
2526
+ this.panel = -Math.floor(this.x / this.panelWidth);
2527
+ this.currentPanel = (this.panel + 1) - Math.floor((this.panel + 1) / 3) * 3;
2528
+ panelMove = this.currentPanel + 1;
2529
+ panelMove = panelMove > 2 ? 0 : panelMove;
2530
+ this.carouselPanels[panelMove].style.left = this.panel * 100 + 100 + '%';
2531
+ pageFlipIndex = this.panel + 1;
2532
+ }
2533
+ // Add active class to current panel:
2534
+ className = this.carouselPanels[this.currentPanel].className;
2535
+ /(^|\s)carousel-panel-active(\s|$)/.test(className) || (this.carouselPanels[this.currentPanel].className = !className ? 'carousel-panel-active' : className + ' carousel-panel-active');
2536
+ className = this.carouselPanels[panelMove].className;
2537
+ pageFlipIndex = pageFlipIndex - Math.floor(pageFlipIndex / this.options.panels) * this.options.panels;
2538
+ $(this.carouselPanels[panelMove]).data('upcomingPanelIndex', pageFlipIndex);
2539
+ // Index to be loaded in the newly moved panel:
2540
+ var newX = -this.panel * this.panelWidth;
2541
+ this.track.style[transitionDuration] = Math.floor(500 * Math.abs(this.x - newX) / this.panelWidth) + 'ms';
2542
+ // Hide the next panel if looping disabled:
2543
+ if (!this.options.loop) {
2544
+ this.carouselPanels[panelMove].style.visibility = newX === 0 || newX === this.maxX ? 'hidden' : '';
2545
+ }
2546
+ if (this.x === newX) {
2547
+ this.slide();
2548
+ } else {
2549
+ this.getPosition(newX);
2550
+ this.slide();
2551
+ }
2552
+ },
2553
+
2554
+ slide: function () {
2555
+ this.event('move');
2556
+ },
2557
+ event: function (type) {
2558
+ var ev = document.createEvent("Event");
2559
+ ev.initEvent('carousel-panel-' + type, true, true);
2560
+ this.carouselContainer.dispatchEvent(ev);
2561
+ }
2562
+ };
2563
+ function prefixStyle (style) {
2564
+ if ( vendor === '' ) return style;
2565
+ style = style.charAt(0).toUpperCase() + style.substr(1);
2566
+ return vendor + style;
2567
+ }
2568
+ return UICarousel;
2569
+ })();
2570
+ /*
2571
+ options = {
2572
+ target : (container of carousel),
2573
+ panels: (array of content for panels),
2574
+ loop: true/false
2575
+ }
2576
+ */
2577
+ $.extend({
2578
+ UISetupCarousel : function ( options ) {
2579
+ // Method to adjust panel content for RTL:
2580
+ function reverseList ( array ) {
2581
+ var a = array.shift(0);
2582
+ array.reverse();
2583
+ array.unshift(a);
2584
+ return array;
2585
+ }
2586
+ if (!options) return;
2587
+ options.loop = options.loop || false;
2588
+ var carousel = new UICarousel({
2589
+ target: options.target,
2590
+ panels: options.panels.length,
2591
+ loop: options.loop,
2592
+ pagination: options.pagination
2593
+ });
2594
+ $(options.target).data('carousel', carousel);
2595
+ // Reverse array of data if RTL:
2596
+ if ($.isRTL) options.panels = reverseList(options.panels);
2597
+ var panel;
2598
+ // Load initial data:
2599
+ for (var i = 0; i < 3; i++) {
2600
+ panel = (i === 0) ? options.panels.length - 1 : i - 1;
2601
+ carousel.carouselPanels[i].innerHTML = options.panels[Number(panel)];
2602
+ }
2603
+ var index = 0;
2604
+ var pagination = $(options.target).next('.pagination');
2605
+ carousel.onSlide(function () {
2606
+ for (var i = 0; i < 3; i++) {
2607
+ var upcoming = $(carousel.carouselPanels[i]).data('upcomingPanelIndex');
2608
+ carousel.carouselPanels[i].innerHTML = options.panels[Number(upcoming)];
2609
+ }
2610
+ index = $('.carousel-panel-active').data('upcomingPanelIndex');
2611
+ pagination.find('li').removeClass('selected');
2612
+ // Handle pagination differently if RTL:
2613
+ if ($.isRTL) {
2614
+ pagination.find('li').removeClass('selected');
2615
+ if (index < 1) {
2616
+ pagination.find('li').eq(0).addClass('selected');
2617
+ } else {
2618
+ pagination.find('li').eq(options.panels.length - index).addClass('selected');
2619
+ }
2620
+ } else {
2621
+ pagination.find('li').eq(index).addClass('selected');
2622
+ }
2623
+ });
2624
+ $(options.target).on('mousedown', 'img', function() {return false;});
2625
+ var width = $(options.target).css('width');
2626
+ pagination.css('width', width);
2627
+ pagination.on('click', 'li', function() {
2628
+ $(this).siblings('li').removeClass('selected');
2629
+ $(this).addClass('selected');
2630
+ var goto = 0;
2631
+ // Handle pagination differently if RTL:
2632
+ if ($.isRTL) {
2633
+ var reverse = $(this).parent().children('li').length;
2634
+ if ($(this).index() === 0) {
2635
+ carousel.goToPanel(0);
2636
+ } else {
2637
+ goto = reverse - $(this).index();
2638
+ carousel.goToPanel(goto);
2639
+ }
2640
+ $(this).siblings('li').removeClass('selected');
2641
+ $(this).addClass('selected');
2642
+ } else {
2643
+ if ($(this).index() === 0) {
2644
+ carousel.goToPanel(0);
2645
+ } else {
2646
+ carousel.goToPanel($(this).index());
2647
+ }
2648
+ }
2649
+ });
2650
+ }
2651
+ });
2652
+ });
2653
+
2654
+
2655
+ $.fn.extend({
2656
+ UIRange : function () {
2657
+ if ($.isWin) return;
2658
+ if (this[0].nodeName !== 'INPUT') return;
2659
+ var input = $(this);
2660
+ var newPlace;
2661
+ var width = input.width();
2662
+ var newPoint = (input.val() - input.attr("min")) / (input.attr("max") - input.attr("min"));
2663
+ var offset = -1.3;
2664
+ if (newPoint < 0) {
2665
+ newPlace = 0;
2666
+ } else if (newPoint > 1) {
2667
+ newPlace = width;
2668
+ } else {
2669
+ newPlace = width * newPoint + offset; offset -= newPoint;
2670
+ }
2671
+ input.css({'background-size': Math.round(newPlace) + 'px 10px'});
2672
+ }
2673
+ });
2674
+ $(function() {
2675
+ $('input[type=range]').forEach(function(ctx) {
2676
+ $(ctx).UIRange();
2677
+ });
2678
+ $('body').on('input', 'input[type=range]', function() {
2679
+ $(this).UIRange();
2680
+ });
2681
+ });
2682
+
2683
+
2684
+ // Widget to enable styled select boxes (pickers):
2685
+ $.extend({
2686
+ UISelectBox: function() {
2687
+ var showSelectBox = function (element) {
2688
+ var event;
2689
+ event = document.createEvent('MouseEvents');
2690
+ event.initMouseEvent('mousedown', true, true, window);
2691
+ element.dispatchEvent(event);
2692
+ };
2693
+ if (!$.isDesktop && $.isiOS) {
2694
+ $('.select-box-label').forEach(function(ctx) {
2695
+ var label = $(ctx);
2696
+ var select = label.prev();
2697
+ if (!select[0].id) {
2698
+ select.attr('id', $.Uuid());
2699
+ }
2700
+ select.trigger('singletap');
2701
+ label.text(select.val());
2702
+ label.attr('for', select.attr('id'));
2703
+ });
2704
+ $('.select-box select').on('change', function() {
2705
+ $(this).next().text($(this).val());
2706
+ });
2707
+ } else if (!$.isDesktop) {
2708
+ var showDropdown = function (element) {
2709
+ var event;
2710
+ event = document.createEvent('MouseEvents');
2711
+ event.initMouseEvent('mousedown', true, true, window);
2712
+ element.dispatchEvent(event);
2713
+ };
2714
+ if (!$.isDesktop) {
2715
+ $('.select-box-label').forEach(function(ctx) {
2716
+ if (!ctx.id) {
2717
+ $(ctx).prev().attr('id', $.Uuid());
2718
+ }
2719
+ var val = $(ctx).siblings('select').val();
2720
+ $(ctx).text(val);
2721
+ });
2722
+ $('.select-box select').on('change', function() {
2723
+ var val = $(this).find("option:selected").text();
2724
+ var $this = $(this);
2725
+ $this.next('label').text($(this).val());
2726
+ $this.siblings('label').text(val);
2727
+ });
2728
+ $('body').on('singletap', '.select-box-label', function() {
2729
+ showDropdown($('select')[0]);
2730
+ });
2731
+ }
2732
+ }
2733
+ }
2734
+ });
2735
+ $(function() {
2736
+ $.UISelectBox();
2737
+ });
2738
+
2739
+
2740
+ ///////////////////////////////////////
2741
+ // Initialize horizontal scroll panels:
2742
+ ///////////////////////////////////////
2743
+ $.fn.extend({
2744
+ UIHorizontalScrollPanel : function () {
2745
+ return this.each(function() {
2746
+ var scrollPanel = $(this).find('ul');
2747
+ var panelsWidth = 0;
2748
+ scrollPanel.find('li').each(function(_, ctx) {
2749
+ panelsWidth += parseInt($(ctx).outerWidth(true));
2750
+ });
2751
+ var parentPadding = (parseInt($(this).css('padding-left')) + parseInt($(this).css('padding-right')));
2752
+ scrollPanel.css('width', (panelsWidth + (parentPadding + parentPadding / 2)));
2753
+ });
2754
+ }
2755
+ });
2756
+
2757
+
2758
+ //////////////////////////////////////////
2759
+ // Plugin to setup automatic data binding:
2760
+ //////////////////////////////////////////
2761
+ $.extend($, {
2762
+ UIBindData : function () {
2763
+
2764
+ var controllers = $('[data-controller]');
2765
+ var broadcasts = [];
2766
+
2767
+ // Define function to create broadcasts:
2768
+ //======================================
2769
+ var createBroadcaster = function(controller) {
2770
+ var broadcast = 'data-binding-' + $(controller).attr('data-controller');
2771
+ broadcasts.push(broadcast);
2772
+ };
2773
+
2774
+ // Loop controllers, create broadcasts,
2775
+ // subscribe models to broadcasts:
2776
+ //=====================================
2777
+ controllers.each(function(idx, ctx) {
2778
+ var model = $(ctx).attr('data-controller');
2779
+ createBroadcaster(ctx);
2780
+ // Subscribe and update elements with data:
2781
+ $.subscribe(broadcasts[idx], function(event, value) {
2782
+ var element = '[data-model=' + model + ']';
2783
+ $(element).text(value);
2784
+ });
2785
+ });
2786
+
2787
+ // Bind events to controllers to publish broadcasts:
2788
+ //==================================================
2789
+ $('body').on('input change', '[data-controller]', function(event) {
2790
+ var broadcast = 'data-binding-' + $(this).attr('data-controller');
2791
+ $.publish(broadcast, $(this).val());
2792
+ });
2793
+ }
2794
+ });
2795
+
2796
+ })(window.CHUIJSLIB);