Permalink
Browse files

Updates

  • Loading branch information...
1 parent 445beaa commit e578db6b188bd89168f3a29fed2a137369142a8c @ccoenraets ccoenraets committed Nov 5, 2012
Showing with 1,249 additions and 5,958 deletions.
  1. +0 −20 config.xml
  2. +2 −77 css/styles.css
  3. +3 −4 index.html
  4. +1 −9 js/main.js
  5. +0 −5,814 lib/cordova-2.1.0.js
  6. +1,080 −0 lib/iscroll.js
  7. +163 −34 readme.md
View
20 config.xml
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<widget xmlns = "http://www.w3.org/ns/widgets"
- xmlns:gap = "http://phonegap.com/ns/1.0"
- id = "org.coenraets.employeedirectory"
- versionCode="10"
- version = "1.1.0">
-
- <!-- versionCode is optional and Android only -->
-
- <name>Employee Directory</name>
-
- <description>
- A simple employee directory application
- </description>
-
- <author href="http://coenraets.org" email="ccoenraets@gmail.com">
- Christophe Coenraets
- </author>
-
-</widget>
View
79 css/styles.css
@@ -14,7 +14,7 @@ body {
}
.header {
- background: #c9c9c9;
+ background: #666;
-webkit-background-size: 1px 44px;
-moz-background-size: 1px 44px;
-ms-background-size: 1px 44px;
@@ -33,7 +33,6 @@ body {
padding: 0;
text-align: center;
font-size: 20px;
- /*text-shadow: 0 -1px rgba(0, 0, 0, .4);*/
margin: 0;
white-space: nowrap;
text-overflow: ellipsis;
@@ -96,25 +95,6 @@ li {
padding: 10px;
}
-.scroll {
- -webkit-box-flex: 1;
- -moz-box-flex: 1;
- box-flex: 1;
- overflow: auto;
- -webkit-overflow-scrolling: touch;
- display: -webkit-box;
- display: -moz-box;
- display: box;
- -webkit-box-orient: vertical;
- -moz-box-orient: vertical;
- box-orient: vertical;
- position: absolute;
- top: 84px;
- bottom: 0px;
- left: 0px;
- right: 0px;
-}
-
ul {
margin: 0;
padding: 0;
@@ -138,29 +118,17 @@ li {
}
li>a {
- /*font-size: 15px;*/
- /*line-height: 1.3em;*/
color: #000;
display: block;
padding: 5px;
text-decoration: none;
- /*-webkit-tap-highlight-color: rgba(0, 0, 0, 0);*/
- /*display: -webkit-box;*/
- /*display: -moz-box;*/
- /*display: box;*/
width: 100%;
-webkit-box-flex: 1;
-moz-box-flex: 1;
box-flex: 1;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
- /*background-image: -webkit-gradient(linear, left top, left bottom, from(#4286f5), to(#194fdb));*/
- /*background-image: -webkit-linear-gradient(top, #4286f5, #194fdb);*/
- /*background-image: -moz-linear-gradient(top, #4286f5, #194fdb);*/
- /*background-image: -ms-linear-gradient(top, #4286f5, #194fdb);*/
- /*background-image: -o-linear-gradient(top, #4286f5, #194fdb);*/
- /*background-image: linear-gradient(top, #4286f5, #194fdb);*/
background-position: -10px 0;
background-repeat: no-repeat;
-webkit-background-size: 10px 100%;
@@ -174,16 +142,6 @@ li>a * {
pointer-events: none;
}
-li>a.tappable-active {
- color: #fff;
- background-color: #4286f5;
- background-repeat: repeat-x;
-}
-
-li>a.tappable-active * {
- color: #fff;
-}
-
.button {
-moz-box-shadow:inset 0px 1px 0px 0px #ffffff;
-webkit-box-shadow:inset 0px 1px 0px 0px #ffffff;
@@ -198,51 +156,18 @@ li>a.tappable-active * {
border:1px solid #dcdcdc;
display:inline-block;
color:#666666;
- /*font-family:arial;*/
font-size:14px;
- /*font-weight:bold;*/
- /*padding:6px 24px;*/
text-decoration:none;
text-shadow:1px 1px 0px #ffffff;
}
+
.button:hover {
background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #dfdfdf), color-stop(1, #ededed) );
background:-moz-linear-gradient( center top, #dfdfdf 5%, #ededed 100% );
filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#dfdfdf', endColorstr='#ededed');
background-color:#dfdfdf;
}
-.button:active {
- /*position:relative;*/
- /*top:1px;*/
-}
-
-.page {
- position: absolute;
- width: 100%;
- height: 100%;
- /*background-color: #ddd;*/
- -webkit-transform:translate3d(0,0,0);
-}
-
-.stage-center {
- top: 0;
- left: 0;
-}
-
-.stage-left {
- left: -100%;
-}
-
-.stage-right {
- left: 100%;
-}
-
-.transition {
- -moz-transition-duration: .375s;
- -webkit-transition-duration: .375s;
- -o-transition-duration: .375s;
-}
h1 {
font-size: 18px;
View
7 index.html
@@ -3,13 +3,12 @@
<div class='header'><h1>Home</h1></div>
<div class='search-view'>
- <input class='search-key'/>
- <ul class='employee-list'></ul>
+<input class='search-key' type="text"/>
+<ul class='employee-list'></ul>
</div>
-<script src="phonegap.js"></script>
<script src="lib/jquery-1.8.2.min.js"></script>
-<script src="js/storage/websql-store.js"></script>
+<script src="js/storage/memory-store.js"></script>
<script src="js/main.js"></script>
</body>
View
10 js/main.js
@@ -1,13 +1,5 @@
var app = {
- showAlert: function (message, title) {
- if (navigator.notification) {
- navigator.notification.alert(message, null, title, 'OK');
- } else {
- alert(title ? (title + ": " + message) : message);
- }
- },
-
findByName: function() {
console.log('findByName');
this.store.findByName($('.search-key').val(), function(employees) {
@@ -22,7 +14,7 @@ var app = {
},
initialize: function() {
- this.store = new WebSqlStore();
+ this.store = new MemoryStore();
$('.search-key').on('keyup', $.proxy(this.findByName, this));
}
View
5,814 lib/cordova-2.1.0.js
0 additions, 5,814 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
1,080 lib/iscroll.js
@@ -0,0 +1,1080 @@
+/*!
+ * iScroll v4.1.9 ~ Copyright (c) 2011 Matteo Spinelli, http://cubiq.org
+ * Released under MIT license, http://cubiq.org/license
+ */
+(function(){
+var m = Math,
+ mround = function (r) { return r >> 0; },
+ vendor = (/webkit/i).test(navigator.appVersion) ? 'webkit' :
+ (/firefox/i).test(navigator.userAgent) ? 'Moz' :
+ (/trident/i).test(navigator.userAgent) ? 'ms' :
+ 'opera' in window ? 'O' : '',
+
+ // Browser capabilities
+ isAndroid = (/android/gi).test(navigator.appVersion),
+ isIDevice = (/iphone|ipad/gi).test(navigator.appVersion),
+ isPlaybook = (/playbook/gi).test(navigator.appVersion),
+ isTouchPad = (/hp-tablet/gi).test(navigator.appVersion),
+
+ has3d = 'WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix(),
+ hasTouch = 'ontouchstart' in window && !isTouchPad,
+ hasTransform = vendor + 'Transform' in document.documentElement.style,
+ hasTransitionEnd = isIDevice || isPlaybook,
+
+ nextFrame = (function() {
+ return window.requestAnimationFrame
+ || window.webkitRequestAnimationFrame
+ || window.mozRequestAnimationFrame
+ || window.oRequestAnimationFrame
+ || window.msRequestAnimationFrame
+ || function(callback) { return setTimeout(callback, 1); };
+ })(),
+ cancelFrame = (function () {
+ return window.cancelRequestAnimationFrame
+ || window.webkitCancelAnimationFrame
+ || window.webkitCancelRequestAnimationFrame
+ || window.mozCancelRequestAnimationFrame
+ || window.oCancelRequestAnimationFrame
+ || window.msCancelRequestAnimationFrame
+ || clearTimeout;
+ })(),
+
+ // Events
+ RESIZE_EV = 'onorientationchange' in window ? 'orientationchange' : 'resize',
+ START_EV = hasTouch ? 'touchstart' : 'mousedown',
+ MOVE_EV = hasTouch ? 'touchmove' : 'mousemove',
+ END_EV = hasTouch ? 'touchend' : 'mouseup',
+ CANCEL_EV = hasTouch ? 'touchcancel' : 'mouseup',
+ WHEEL_EV = vendor == 'Moz' ? 'DOMMouseScroll' : 'mousewheel',
+
+ // Helpers
+ trnOpen = 'translate' + (has3d ? '3d(' : '('),
+ trnClose = has3d ? ',0)' : ')',
+
+ // Constructor
+ iScroll = function (el, options) {
+ var that = this,
+ doc = document,
+ i;
+
+ that.wrapper = typeof el == 'object' ? el : doc.getElementById(el);
+ that.wrapper.style.overflow = 'hidden';
+ that.scroller = that.wrapper.children[0];
+
+ // Default options
+ that.options = {
+ hScroll: true,
+ vScroll: true,
+ x: 0,
+ y: 0,
+ bounce: true,
+ bounceLock: false,
+ momentum: true,
+ lockDirection: true,
+ useTransform: true,
+ useTransition: false,
+ topOffset: 0,
+ checkDOMChanges: false, // Experimental
+
+ // Scrollbar
+ hScrollbar: true,
+ vScrollbar: true,
+ fixedScrollbar: isAndroid,
+ hideScrollbar: isIDevice,
+ fadeScrollbar: isIDevice && has3d,
+ scrollbarClass: '',
+
+ // Zoom
+ zoom: false,
+ zoomMin: 1,
+ zoomMax: 4,
+ doubleTapZoom: 2,
+ wheelAction: 'scroll',
+
+ // Snap
+ snap: false,
+ snapThreshold: 1,
+
+ // Events
+ onRefresh: null,
+ onBeforeScrollStart: function (e) { e.preventDefault(); },
+ onScrollStart: null,
+ onBeforeScrollMove: null,
+ onScrollMove: null,
+ onBeforeScrollEnd: null,
+ onScrollEnd: null,
+ onTouchEnd: null,
+ onDestroy: null,
+ onZoomStart: null,
+ onZoom: null,
+ onZoomEnd: null
+ };
+
+ // User defined options
+ for (i in options) that.options[i] = options[i];
+
+ // Set starting position
+ that.x = that.options.x;
+ that.y = that.options.y;
+
+ // Normalize options
+ that.options.useTransform = hasTransform ? that.options.useTransform : false;
+ that.options.hScrollbar = that.options.hScroll && that.options.hScrollbar;
+ that.options.vScrollbar = that.options.vScroll && that.options.vScrollbar;
+ that.options.zoom = that.options.useTransform && that.options.zoom;
+ that.options.useTransition = hasTransitionEnd && that.options.useTransition;
+
+ // Helpers FIX ANDROID BUG!
+ // translate3d and scale doesn't work together!
+ // Ignoring 3d ONLY WHEN YOU SET that.options.zoom
+ if ( that.options.zoom && isAndroid ){
+ trnOpen = 'translate(';
+ trnClose = ')';
+ }
+
+ // Set some default styles
+ that.scroller.style[vendor + 'TransitionProperty'] = that.options.useTransform ? '-' + vendor.toLowerCase() + '-transform' : 'top left';
+ that.scroller.style[vendor + 'TransitionDuration'] = '0';
+ that.scroller.style[vendor + 'TransformOrigin'] = '0 0';
+ if (that.options.useTransition) that.scroller.style[vendor + 'TransitionTimingFunction'] = 'cubic-bezier(0.33,0.66,0.66,1)';
+
+ if (that.options.useTransform) that.scroller.style[vendor + 'Transform'] = trnOpen + that.x + 'px,' + that.y + 'px' + trnClose;
+ else that.scroller.style.cssText += ';position:absolute;top:' + that.y + 'px;left:' + that.x + 'px';
+
+ if (that.options.useTransition) that.options.fixedScrollbar = true;
+
+ that.refresh();
+
+ that._bind(RESIZE_EV, window);
+ that._bind(START_EV);
+ if (!hasTouch) {
+ that._bind('mouseout', that.wrapper);
+ if (that.options.wheelAction != 'none')
+ that._bind(WHEEL_EV);
+ }
+
+ if (that.options.checkDOMChanges) that.checkDOMTime = setInterval(function () {
+ that._checkDOMChanges();
+ }, 500);
+ };
+
+// Prototype
+iScroll.prototype = {
+ enabled: true,
+ x: 0,
+ y: 0,
+ steps: [],
+ scale: 1,
+ currPageX: 0, currPageY: 0,
+ pagesX: [], pagesY: [],
+ aniTime: null,
+ wheelZoomCount: 0,
+
+ handleEvent: function (e) {
+ var that = this;
+ switch(e.type) {
+ case START_EV:
+ if (!hasTouch && e.button !== 0) return;
+ that._start(e);
+ break;
+ case MOVE_EV: that._move(e); break;
+ case END_EV:
+ case CANCEL_EV: that._end(e); break;
+ case RESIZE_EV: that._resize(); break;
+ case WHEEL_EV: that._wheel(e); break;
+ case 'mouseout': that._mouseout(e); break;
+ case 'webkitTransitionEnd': that._transitionEnd(e); break;
+ }
+ },
+
+ _checkDOMChanges: function () {
+ if (this.moved || this.zoomed || this.animating ||
+ (this.scrollerW == this.scroller.offsetWidth * this.scale && this.scrollerH == this.scroller.offsetHeight * this.scale)) return;
+
+ this.refresh();
+ },
+
+ _scrollbar: function (dir) {
+ var that = this,
+ doc = document,
+ bar;
+
+ if (!that[dir + 'Scrollbar']) {
+ if (that[dir + 'ScrollbarWrapper']) {
+ if (hasTransform) that[dir + 'ScrollbarIndicator'].style[vendor + 'Transform'] = '';
+ that[dir + 'ScrollbarWrapper'].parentNode.removeChild(that[dir + 'ScrollbarWrapper']);
+ that[dir + 'ScrollbarWrapper'] = null;
+ that[dir + 'ScrollbarIndicator'] = null;
+ }
+
+ return;
+ }
+
+ if (!that[dir + 'ScrollbarWrapper']) {
+ // Create the scrollbar wrapper
+ bar = doc.createElement('div');
+
+ if (that.options.scrollbarClass) bar.className = that.options.scrollbarClass + dir.toUpperCase();
+ else bar.style.cssText = 'position:absolute;z-index:100;' + (dir == 'h' ? 'height:7px;bottom:1px;left:2px;right:' + (that.vScrollbar ? '7' : '2') + 'px' : 'width:7px;bottom:' + (that.hScrollbar ? '7' : '2') + 'px;top:2px;right:1px');
+
+ bar.style.cssText += ';pointer-events:none;-' + vendor + '-transition-property:opacity;-' + vendor + '-transition-duration:' + (that.options.fadeScrollbar ? '350ms' : '0') + ';overflow:hidden;opacity:' + (that.options.hideScrollbar ? '0' : '1');
+
+ that.wrapper.appendChild(bar);
+ that[dir + 'ScrollbarWrapper'] = bar;
+
+ // Create the scrollbar indicator
+ bar = doc.createElement('div');
+ if (!that.options.scrollbarClass) {
+ bar.style.cssText = 'position:absolute;z-index:100;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);-' + vendor + '-background-clip:padding-box;-' + vendor + '-box-sizing:border-box;' + (dir == 'h' ? 'height:100%' : 'width:100%') + ';-' + vendor + '-border-radius:3px;border-radius:3px';
+ }
+ bar.style.cssText += ';pointer-events:none;-' + vendor + '-transition-property:-' + vendor + '-transform;-' + vendor + '-transition-timing-function:cubic-bezier(0.33,0.66,0.66,1);-' + vendor + '-transition-duration:0;-' + vendor + '-transform:' + trnOpen + '0,0' + trnClose;
+ if (that.options.useTransition) bar.style.cssText += ';-' + vendor + '-transition-timing-function:cubic-bezier(0.33,0.66,0.66,1)';
+
+ that[dir + 'ScrollbarWrapper'].appendChild(bar);
+ that[dir + 'ScrollbarIndicator'] = bar;
+ }
+
+ if (dir == 'h') {
+ that.hScrollbarSize = that.hScrollbarWrapper.clientWidth;
+ that.hScrollbarIndicatorSize = m.max(mround(that.hScrollbarSize * that.hScrollbarSize / that.scrollerW), 8);
+ that.hScrollbarIndicator.style.width = that.hScrollbarIndicatorSize + 'px';
+ that.hScrollbarMaxScroll = that.hScrollbarSize - that.hScrollbarIndicatorSize;
+ that.hScrollbarProp = that.hScrollbarMaxScroll / that.maxScrollX;
+ } else {
+ that.vScrollbarSize = that.vScrollbarWrapper.clientHeight;
+ that.vScrollbarIndicatorSize = m.max(mround(that.vScrollbarSize * that.vScrollbarSize / that.scrollerH), 8);
+ that.vScrollbarIndicator.style.height = that.vScrollbarIndicatorSize + 'px';
+ that.vScrollbarMaxScroll = that.vScrollbarSize - that.vScrollbarIndicatorSize;
+ that.vScrollbarProp = that.vScrollbarMaxScroll / that.maxScrollY;
+ }
+
+ // Reset position
+ that._scrollbarPos(dir, true);
+ },
+
+ _resize: function () {
+ var that = this;
+ setTimeout(function () { that.refresh(); }, isAndroid ? 200 : 0);
+ },
+
+ _pos: function (x, y) {
+ if (this.zoomed) return;
+
+ x = this.hScroll ? x : 0;
+ y = this.vScroll ? y : 0;
+
+ if (this.options.useTransform) {
+ this.scroller.style[vendor + 'Transform'] = trnOpen + x + 'px,' + y + 'px' + trnClose + ' scale(' + this.scale + ')';
+ } else {
+ x = mround(x);
+ y = mround(y);
+ this.scroller.style.left = x + 'px';
+ this.scroller.style.top = y + 'px';
+ }
+
+ this.x = x;
+ this.y = y;
+
+ this._scrollbarPos('h');
+ this._scrollbarPos('v');
+ },
+
+ _scrollbarPos: function (dir, hidden) {
+ var that = this,
+ pos = dir == 'h' ? that.x : that.y,
+ size;
+
+ if (!that[dir + 'Scrollbar']) return;
+
+ pos = that[dir + 'ScrollbarProp'] * pos;
+
+ if (pos < 0) {
+ if (!that.options.fixedScrollbar) {
+ size = that[dir + 'ScrollbarIndicatorSize'] + mround(pos * 3);
+ if (size < 8) size = 8;
+ that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px';
+ }
+ pos = 0;
+ } else if (pos > that[dir + 'ScrollbarMaxScroll']) {
+ if (!that.options.fixedScrollbar) {
+ size = that[dir + 'ScrollbarIndicatorSize'] - mround((pos - that[dir + 'ScrollbarMaxScroll']) * 3);
+ if (size < 8) size = 8;
+ that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px';
+ pos = that[dir + 'ScrollbarMaxScroll'] + (that[dir + 'ScrollbarIndicatorSize'] - size);
+ } else {
+ pos = that[dir + 'ScrollbarMaxScroll'];
+ }
+ }
+
+ that[dir + 'ScrollbarWrapper'].style[vendor + 'TransitionDelay'] = '0';
+ that[dir + 'ScrollbarWrapper'].style.opacity = hidden && that.options.hideScrollbar ? '0' : '1';
+ that[dir + 'ScrollbarIndicator'].style[vendor + 'Transform'] = trnOpen + (dir == 'h' ? pos + 'px,0' : '0,' + pos + 'px') + trnClose;
+ },
+
+ _start: function (e) {
+ var that = this,
+ point = hasTouch ? e.touches[0] : e,
+ matrix, x, y,
+ c1, c2;
+
+ if (!that.enabled) return;
+
+ if (that.options.onBeforeScrollStart) that.options.onBeforeScrollStart.call(that, e);
+
+ if (that.options.useTransition || that.options.zoom) that._transitionTime(0);
+
+ that.moved = false;
+ that.animating = false;
+ that.zoomed = false;
+ that.distX = 0;
+ that.distY = 0;
+ that.absDistX = 0;
+ that.absDistY = 0;
+ that.dirX = 0;
+ that.dirY = 0;
+
+ // Gesture start
+ if (that.options.zoom && hasTouch && e.touches.length > 1) {
+ c1 = m.abs(e.touches[0].pageX-e.touches[1].pageX);
+ c2 = m.abs(e.touches[0].pageY-e.touches[1].pageY);
+ that.touchesDistStart = m.sqrt(c1 * c1 + c2 * c2);
+
+ that.originX = m.abs(e.touches[0].pageX + e.touches[1].pageX - that.wrapperOffsetLeft * 2) / 2 - that.x;
+ that.originY = m.abs(e.touches[0].pageY + e.touches[1].pageY - that.wrapperOffsetTop * 2) / 2 - that.y;
+
+ if (that.options.onZoomStart) that.options.onZoomStart.call(that, e);
+ }
+
+ if (that.options.momentum) {
+ if (that.options.useTransform) {
+ // Very lame general purpose alternative to CSSMatrix
+ matrix = getComputedStyle(that.scroller, null)[vendor + 'Transform'].replace(/[^0-9-.,]/g, '').split(',');
+ x = matrix[4] * 1;
+ y = matrix[5] * 1;
+ } else {
+ x = getComputedStyle(that.scroller, null).left.replace(/[^0-9-]/g, '') * 1;
+ y = getComputedStyle(that.scroller, null).top.replace(/[^0-9-]/g, '') * 1;
+ }
+
+ if (x != that.x || y != that.y) {
+ if (that.options.useTransition) that._unbind('webkitTransitionEnd');
+ else cancelFrame(that.aniTime);
+ that.steps = [];
+ that._pos(x, y);
+ }
+ }
+
+ that.absStartX = that.x; // Needed by snap threshold
+ that.absStartY = that.y;
+
+ that.startX = that.x;
+ that.startY = that.y;
+ that.pointX = point.pageX;
+ that.pointY = point.pageY;
+
+ that.startTime = e.timeStamp || Date.now();
+
+ if (that.options.onScrollStart) that.options.onScrollStart.call(that, e);
+
+ that._bind(MOVE_EV);
+ that._bind(END_EV);
+ that._bind(CANCEL_EV);
+ },
+
+ _move: function (e) {
+ var that = this,
+ point = hasTouch ? e.touches[0] : e,
+ deltaX = point.pageX - that.pointX,
+ deltaY = point.pageY - that.pointY,
+ newX = that.x + deltaX,
+ newY = that.y + deltaY,
+ c1, c2, scale,
+ timestamp = e.timeStamp || Date.now();
+
+ if (that.options.onBeforeScrollMove) that.options.onBeforeScrollMove.call(that, e);
+
+ // Zoom
+ if (that.options.zoom && hasTouch && e.touches.length > 1) {
+ c1 = m.abs(e.touches[0].pageX - e.touches[1].pageX);
+ c2 = m.abs(e.touches[0].pageY - e.touches[1].pageY);
+ that.touchesDist = m.sqrt(c1*c1+c2*c2);
+
+ that.zoomed = true;
+
+ scale = 1 / that.touchesDistStart * that.touchesDist * this.scale;
+
+ if (scale < that.options.zoomMin) scale = 0.5 * that.options.zoomMin * Math.pow(2.0, scale / that.options.zoomMin);
+ else if (scale > that.options.zoomMax) scale = 2.0 * that.options.zoomMax * Math.pow(0.5, that.options.zoomMax / scale);
+
+ that.lastScale = scale / this.scale;
+
+ newX = this.originX - this.originX * that.lastScale + this.x,
+ newY = this.originY - this.originY * that.lastScale + this.y;
+
+ this.scroller.style[vendor + 'Transform'] = trnOpen + newX + 'px,' + newY + 'px' + trnClose + ' scale(' + scale + ')';
+
+ if (that.options.onZoom) that.options.onZoom.call(that, e);
+ return;
+ }
+
+ that.pointX = point.pageX;
+ that.pointY = point.pageY;
+
+ // Slow down if outside of the boundaries
+ if (newX > 0 || newX < that.maxScrollX) {
+ newX = that.options.bounce ? that.x + (deltaX / 2) : newX >= 0 || that.maxScrollX >= 0 ? 0 : that.maxScrollX;
+ }
+ if (newY > that.minScrollY || newY < that.maxScrollY) {
+ newY = that.options.bounce ? that.y + (deltaY / 2) : newY >= that.minScrollY || that.maxScrollY >= 0 ? that.minScrollY : that.maxScrollY;
+ }
+
+ that.distX += deltaX;
+ that.distY += deltaY;
+ that.absDistX = m.abs(that.distX);
+ that.absDistY = m.abs(that.distY);
+
+ if (that.absDistX < 6 && that.absDistY < 6) {
+ return;
+ }
+
+ // Lock direction
+ if (that.options.lockDirection) {
+ if (that.absDistX > that.absDistY + 5) {
+ newY = that.y;
+ deltaY = 0;
+ } else if (that.absDistY > that.absDistX + 5) {
+ newX = that.x;
+ deltaX = 0;
+ }
+ }
+
+ that.moved = true;
+ that._pos(newX, newY);
+ that.dirX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
+ that.dirY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
+
+ if (timestamp - that.startTime > 300) {
+ that.startTime = timestamp;
+ that.startX = that.x;
+ that.startY = that.y;
+ }
+
+ if (that.options.onScrollMove) that.options.onScrollMove.call(that, e);
+ },
+
+ _end: function (e) {
+ if (hasTouch && e.touches.length != 0) return;
+
+ var that = this,
+ point = hasTouch ? e.changedTouches[0] : e,
+ target, ev,
+ momentumX = { dist:0, time:0 },
+ momentumY = { dist:0, time:0 },
+ duration = (e.timeStamp || Date.now()) - that.startTime,
+ newPosX = that.x,
+ newPosY = that.y,
+ distX, distY,
+ newDuration,
+ snap,
+ scale;
+
+ that._unbind(MOVE_EV);
+ that._unbind(END_EV);
+ that._unbind(CANCEL_EV);
+
+ if (that.options.onBeforeScrollEnd) that.options.onBeforeScrollEnd.call(that, e);
+
+ if (that.zoomed) {
+ scale = that.scale * that.lastScale;
+ scale = Math.max(that.options.zoomMin, scale);
+ scale = Math.min(that.options.zoomMax, scale);
+ that.lastScale = scale / that.scale;
+ that.scale = scale;
+
+ that.x = that.originX - that.originX * that.lastScale + that.x;
+ that.y = that.originY - that.originY * that.lastScale + that.y;
+
+ that.scroller.style[vendor + 'TransitionDuration'] = '200ms';
+ that.scroller.style[vendor + 'Transform'] = trnOpen + that.x + 'px,' + that.y + 'px' + trnClose + ' scale(' + that.scale + ')';
+
+ that.zoomed = false;
+ that.refresh();
+
+ if (that.options.onZoomEnd) that.options.onZoomEnd.call(that, e);
+ return;
+ }
+
+ if (!that.moved) {
+ if (hasTouch) {
+ if (that.doubleTapTimer && that.options.zoom) {
+ // Double tapped
+ clearTimeout(that.doubleTapTimer);
+ that.doubleTapTimer = null;
+ if (that.options.onZoomStart) that.options.onZoomStart.call(that, e);
+ that.zoom(that.pointX, that.pointY, that.scale == 1 ? that.options.doubleTapZoom : 1);
+ if (that.options.onZoomEnd) {
+ setTimeout(function() {
+ that.options.onZoomEnd.call(that, e);
+ }, 200); // 200 is default zoom duration
+ }
+ } else {
+ that.doubleTapTimer = setTimeout(function () {
+ that.doubleTapTimer = null;
+
+ // Find the last touched element
+ target = point.target;
+ while (target.nodeType != 1) target = target.parentNode;
+
+ if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') {
+ ev = document.createEvent('MouseEvents');
+ ev.initMouseEvent('click', true, true, e.view, 1,
+ point.screenX, point.screenY, point.clientX, point.clientY,
+ e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
+ 0, null);
+ ev._fake = true;
+ target.dispatchEvent(ev);
+ }
+ }, that.options.zoom ? 250 : 0);
+ }
+ }
+
+ that._resetPos(200);
+
+ if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
+ return;
+ }
+
+ if (duration < 300 && that.options.momentum) {
+ momentumX = newPosX ? that._momentum(newPosX - that.startX, duration, -that.x, that.scrollerW - that.wrapperW + that.x, that.options.bounce ? that.wrapperW : 0) : momentumX;
+ momentumY = newPosY ? that._momentum(newPosY - that.startY, duration, -that.y, (that.maxScrollY < 0 ? that.scrollerH - that.wrapperH + that.y - that.minScrollY : 0), that.options.bounce ? that.wrapperH : 0) : momentumY;
+
+ newPosX = that.x + momentumX.dist;
+ newPosY = that.y + momentumY.dist;
+
+ if ((that.x > 0 && newPosX > 0) || (that.x < that.maxScrollX && newPosX < that.maxScrollX)) momentumX = { dist:0, time:0 };
+ if ((that.y > that.minScrollY && newPosY > that.minScrollY) || (that.y < that.maxScrollY && newPosY < that.maxScrollY)) momentumY = { dist:0, time:0 };
+ }
+
+ if (momentumX.dist || momentumY.dist) {
+ newDuration = m.max(m.max(momentumX.time, momentumY.time), 10);
+
+ // Do we need to snap?
+ if (that.options.snap) {
+ distX = newPosX - that.absStartX;
+ distY = newPosY - that.absStartY;
+ if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) { that.scrollTo(that.absStartX, that.absStartY, 200); }
+ else {
+ snap = that._snap(newPosX, newPosY);
+ newPosX = snap.x;
+ newPosY = snap.y;
+ newDuration = m.max(snap.time, newDuration);
+ }
+ }
+
+ that.scrollTo(mround(newPosX), mround(newPosY), newDuration);
+
+ if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
+ return;
+ }
+
+ // Do we need to snap?
+ if (that.options.snap) {
+ distX = newPosX - that.absStartX;
+ distY = newPosY - that.absStartY;
+ if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) that.scrollTo(that.absStartX, that.absStartY, 200);
+ else {
+ snap = that._snap(that.x, that.y);
+ if (snap.x != that.x || snap.y != that.y) that.scrollTo(snap.x, snap.y, snap.time);
+ }
+
+ if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
+ return;
+ }
+
+ that._resetPos(200);
+ if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
+ },
+
+ _resetPos: function (time) {
+ var that = this,
+ resetX = that.x >= 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x,
+ resetY = that.y >= that.minScrollY || that.maxScrollY > 0 ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y;
+
+ if (resetX == that.x && resetY == that.y) {
+ if (that.moved) {
+ that.moved = false;
+ if (that.options.onScrollEnd) that.options.onScrollEnd.call(that); // Execute custom code on scroll end
+ }
+
+ if (that.hScrollbar && that.options.hideScrollbar) {
+ if (vendor == 'webkit') that.hScrollbarWrapper.style[vendor + 'TransitionDelay'] = '300ms';
+ that.hScrollbarWrapper.style.opacity = '0';
+ }
+ if (that.vScrollbar && that.options.hideScrollbar) {
+ if (vendor == 'webkit') that.vScrollbarWrapper.style[vendor + 'TransitionDelay'] = '300ms';
+ that.vScrollbarWrapper.style.opacity = '0';
+ }
+
+ return;
+ }
+
+ that.scrollTo(resetX, resetY, time || 0);
+ },
+
+ _wheel: function (e) {
+ var that = this,
+ wheelDeltaX, wheelDeltaY,
+ deltaX, deltaY,
+ deltaScale;
+
+ if ('wheelDeltaX' in e) {
+ wheelDeltaX = e.wheelDeltaX / 12;
+ wheelDeltaY = e.wheelDeltaY / 12;
+ } else if('wheelDelta' in e) {
+ wheelDeltaX = wheelDeltaY = e.wheelDelta / 12;
+ } else if ('detail' in e) {
+ wheelDeltaX = wheelDeltaY = -e.detail * 3;
+ } else {
+ return;
+ }
+
+ if (that.options.wheelAction == 'zoom') {
+ deltaScale = that.scale * Math.pow(2, 1/3 * (wheelDeltaY ? wheelDeltaY / Math.abs(wheelDeltaY) : 0));
+ if (deltaScale < that.options.zoomMin) deltaScale = that.options.zoomMin;
+ if (deltaScale > that.options.zoomMax) deltaScale = that.options.zoomMax;
+
+ if (deltaScale != that.scale) {
+ if (!that.wheelZoomCount && that.options.onZoomStart) that.options.onZoomStart.call(that, e);
+ that.wheelZoomCount++;
+
+ that.zoom(e.pageX, e.pageY, deltaScale, 400);
+
+ setTimeout(function() {
+ that.wheelZoomCount--;
+ if (!that.wheelZoomCount && that.options.onZoomEnd) that.options.onZoomEnd.call(that, e);
+ }, 400);
+ }
+
+ return;
+ }
+
+ deltaX = that.x + wheelDeltaX;
+ deltaY = that.y + wheelDeltaY;
+
+ if (deltaX > 0) deltaX = 0;
+ else if (deltaX < that.maxScrollX) deltaX = that.maxScrollX;
+
+ if (deltaY > that.minScrollY) deltaY = that.minScrollY;
+ else if (deltaY < that.maxScrollY) deltaY = that.maxScrollY;
+
+ if(that.maxScrollY < 0){
+ that.scrollTo(deltaX, deltaY, 0);
+ }
+ },
+
+ _mouseout: function (e) {
+ var t = e.relatedTarget;
+
+ if (!t) {
+ this._end(e);
+ return;
+ }
+
+ while (t = t.parentNode) if (t == this.wrapper) return;
+
+ this._end(e);
+ },
+
+ _transitionEnd: function (e) {
+ var that = this;
+
+ if (e.target != that.scroller) return;
+
+ that._unbind('webkitTransitionEnd');
+
+ that._startAni();
+ },
+
+
+ /**
+ *
+ * Utilities
+ *
+ */
+ _startAni: function () {
+ var that = this,
+ startX = that.x, startY = that.y,
+ startTime = Date.now(),
+ step, easeOut,
+ animate;
+
+ if (that.animating) return;
+
+ if (!that.steps.length) {
+ that._resetPos(400);
+ return;
+ }
+
+ step = that.steps.shift();
+
+ if (step.x == startX && step.y == startY) step.time = 0;
+
+ that.animating = true;
+ that.moved = true;
+
+ if (that.options.useTransition) {
+ that._transitionTime(step.time);
+ that._pos(step.x, step.y);
+ that.animating = false;
+ if (step.time) that._bind('webkitTransitionEnd');
+ else that._resetPos(0);
+ return;
+ }
+
+ animate = function () {
+ var now = Date.now(),
+ newX, newY;
+
+ if (now >= startTime + step.time) {
+ that._pos(step.x, step.y);
+ that.animating = false;
+ if (that.options.onAnimationEnd) that.options.onAnimationEnd.call(that); // Execute custom code on animation end
+ that._startAni();
+ return;
+ }
+
+ now = (now - startTime) / step.time - 1;
+ easeOut = m.sqrt(1 - now * now);
+ newX = (step.x - startX) * easeOut + startX;
+ newY = (step.y - startY) * easeOut + startY;
+ that._pos(newX, newY);
+ if (that.animating) that.aniTime = nextFrame(animate);
+ };
+
+ animate();
+ },
+
+ _transitionTime: function (time) {
+ time += 'ms';
+ this.scroller.style[vendor + 'TransitionDuration'] = time;
+ if (this.hScrollbar) this.hScrollbarIndicator.style[vendor + 'TransitionDuration'] = time;
+ if (this.vScrollbar) this.vScrollbarIndicator.style[vendor + 'TransitionDuration'] = time;
+ },
+
+ _momentum: function (dist, time, maxDistUpper, maxDistLower, size) {
+ var deceleration = 0.0006,
+ speed = m.abs(dist) / time,
+ newDist = (speed * speed) / (2 * deceleration),
+ newTime = 0, outsideDist = 0;
+
+ // Proportinally reduce speed if we are outside of the boundaries
+ if (dist > 0 && newDist > maxDistUpper) {
+ outsideDist = size / (6 / (newDist / speed * deceleration));
+ maxDistUpper = maxDistUpper + outsideDist;
+ speed = speed * maxDistUpper / newDist;
+ newDist = maxDistUpper;
+ } else if (dist < 0 && newDist > maxDistLower) {
+ outsideDist = size / (6 / (newDist / speed * deceleration));
+ maxDistLower = maxDistLower + outsideDist;
+ speed = speed * maxDistLower / newDist;
+ newDist = maxDistLower;
+ }
+
+ newDist = newDist * (dist < 0 ? -1 : 1);
+ newTime = speed / deceleration;
+
+ return { dist: newDist, time: mround(newTime) };
+ },
+
+ _offset: function (el) {
+ var left = -el.offsetLeft,
+ top = -el.offsetTop;
+
+ while (el = el.offsetParent) {
+ left -= el.offsetLeft;
+ top -= el.offsetTop;
+ }
+
+ if (el != this.wrapper) {
+ left *= this.scale;
+ top *= this.scale;
+ }
+
+ return { left: left, top: top };
+ },
+
+ _snap: function (x, y) {
+ var that = this,
+ i, l,
+ page, time,
+ sizeX, sizeY;
+
+ // Check page X
+ page = that.pagesX.length - 1;
+ for (i=0, l=that.pagesX.length; i<l; i++) {
+ if (x >= that.pagesX[i]) {
+ page = i;
+ break;
+ }
+ }
+ if (page == that.currPageX && page > 0 && that.dirX < 0) page--;
+ x = that.pagesX[page];
+ sizeX = m.abs(x - that.pagesX[that.currPageX]);
+ sizeX = sizeX ? m.abs(that.x - x) / sizeX * 500 : 0;
+ that.currPageX = page;
+
+ // Check page Y
+ page = that.pagesY.length-1;
+ for (i=0; i<page; i++) {
+ if (y >= that.pagesY[i]) {
+ page = i;
+ break;
+ }
+ }
+ if (page == that.currPageY && page > 0 && that.dirY < 0) page--;
+ y = that.pagesY[page];
+ sizeY = m.abs(y - that.pagesY[that.currPageY]);
+ sizeY = sizeY ? m.abs(that.y - y) / sizeY * 500 : 0;
+ that.currPageY = page;
+
+ // Snap with constant speed (proportional duration)
+ time = mround(m.max(sizeX, sizeY)) || 200;
+
+ return { x: x, y: y, time: time };
+ },
+
+ _bind: function (type, el, bubble) {
+ (el || this.scroller).addEventListener(type, this, !!bubble);
+ },
+
+ _unbind: function (type, el, bubble) {
+ (el || this.scroller).removeEventListener(type, this, !!bubble);
+ },
+
+
+ /**
+ *
+ * Public methods
+ *
+ */
+ destroy: function () {
+ var that = this;
+
+ that.scroller.style[vendor + 'Transform'] = '';
+
+ // Remove the scrollbars
+ that.hScrollbar = false;
+ that.vScrollbar = false;
+ that._scrollbar('h');
+ that._scrollbar('v');
+
+ // Remove the event listeners
+ that._unbind(RESIZE_EV, window);
+ that._unbind(START_EV);
+ that._unbind(MOVE_EV);
+ that._unbind(END_EV);
+ that._unbind(CANCEL_EV);
+
+ if (!that.options.hasTouch) {
+ that._unbind('mouseout', that.wrapper);
+ that._unbind(WHEEL_EV);
+ }
+
+ if (that.options.useTransition) that._unbind('webkitTransitionEnd');
+
+ if (that.options.checkDOMChanges) clearInterval(that.checkDOMTime);
+
+ if (that.options.onDestroy) that.options.onDestroy.call(that);
+ },
+
+ refresh: function () {
+ var that = this,
+ offset,
+ i, l,
+ els,
+ pos = 0,
+ page = 0;
+
+ if (that.scale < that.options.zoomMin) that.scale = that.options.zoomMin;
+ that.wrapperW = that.wrapper.clientWidth || 1;
+ that.wrapperH = that.wrapper.clientHeight || 1;
+
+ that.minScrollY = -that.options.topOffset || 0;
+ that.scrollerW = mround(that.scroller.offsetWidth * that.scale);
+ that.scrollerH = mround((that.scroller.offsetHeight + that.minScrollY) * that.scale);
+ that.maxScrollX = that.wrapperW - that.scrollerW;
+ that.maxScrollY = that.wrapperH - that.scrollerH + that.minScrollY;
+ that.dirX = 0;
+ that.dirY = 0;
+
+ if (that.options.onRefresh) that.options.onRefresh.call(that);
+
+ that.hScroll = that.options.hScroll && that.maxScrollX < 0;
+ that.vScroll = that.options.vScroll && (!that.options.bounceLock && !that.hScroll || that.scrollerH > that.wrapperH);
+
+ that.hScrollbar = that.hScroll && that.options.hScrollbar;
+ that.vScrollbar = that.vScroll && that.options.vScrollbar && that.scrollerH > that.wrapperH;
+
+ offset = that._offset(that.wrapper);
+ that.wrapperOffsetLeft = -offset.left;
+ that.wrapperOffsetTop = -offset.top;
+
+ // Prepare snap
+ if (typeof that.options.snap == 'string') {
+ that.pagesX = [];
+ that.pagesY = [];
+ els = that.scroller.querySelectorAll(that.options.snap);
+ for (i=0, l=els.length; i<l; i++) {
+ pos = that._offset(els[i]);
+ pos.left += that.wrapperOffsetLeft;
+ pos.top += that.wrapperOffsetTop;
+ that.pagesX[i] = pos.left < that.maxScrollX ? that.maxScrollX : pos.left * that.scale;
+ that.pagesY[i] = pos.top < that.maxScrollY ? that.maxScrollY : pos.top * that.scale;
+ }
+ } else if (that.options.snap) {
+ that.pagesX = [];
+ while (pos >= that.maxScrollX) {
+ that.pagesX[page] = pos;
+ pos = pos - that.wrapperW;
+ page++;
+ }
+ if (that.maxScrollX%that.wrapperW) that.pagesX[that.pagesX.length] = that.maxScrollX - that.pagesX[that.pagesX.length-1] + that.pagesX[that.pagesX.length-1];
+
+ pos = 0;
+ page = 0;
+ that.pagesY = [];
+ while (pos >= that.maxScrollY) {
+ that.pagesY[page] = pos;
+ pos = pos - that.wrapperH;
+ page++;
+ }
+ if (that.maxScrollY%that.wrapperH) that.pagesY[that.pagesY.length] = that.maxScrollY - that.pagesY[that.pagesY.length-1] + that.pagesY[that.pagesY.length-1];
+ }
+
+ // Prepare the scrollbars
+ that._scrollbar('h');
+ that._scrollbar('v');
+
+ if (!that.zoomed) {
+ that.scroller.style[vendor + 'TransitionDuration'] = '0';
+ that._resetPos(200);
+ }
+ },
+
+ scrollTo: function (x, y, time, relative) {
+ var that = this,
+ step = x,
+ i, l;
+
+ that.stop();
+
+ if (!step.length) step = [{ x: x, y: y, time: time, relative: relative }];
+
+ for (i=0, l=step.length; i<l; i++) {
+ if (step[i].relative) { step[i].x = that.x - step[i].x; step[i].y = that.y - step[i].y; }
+ that.steps.push({ x: step[i].x, y: step[i].y, time: step[i].time || 0 });
+ }
+
+ that._startAni();
+ },
+
+ scrollToElement: function (el, time) {
+ var that = this, pos;
+ el = el.nodeType ? el : that.scroller.querySelector(el);
+ if (!el) return;
+
+ pos = that._offset(el);
+ pos.left += that.wrapperOffsetLeft;
+ pos.top += that.wrapperOffsetTop;
+
+ pos.left = pos.left > 0 ? 0 : pos.left < that.maxScrollX ? that.maxScrollX : pos.left;
+ pos.top = pos.top > that.minScrollY ? that.minScrollY : pos.top < that.maxScrollY ? that.maxScrollY : pos.top;
+ time = time === undefined ? m.max(m.abs(pos.left)*2, m.abs(pos.top)*2) : time;
+
+ that.scrollTo(pos.left, pos.top, time);
+ },
+
+ scrollToPage: function (pageX, pageY, time) {
+ var that = this, x, y;
+
+ time = time === undefined ? 400 : time;
+
+ if (that.options.onScrollStart) that.options.onScrollStart.call(that);
+
+ if (that.options.snap) {
+ pageX = pageX == 'next' ? that.currPageX+1 : pageX == 'prev' ? that.currPageX-1 : pageX;
+ pageY = pageY == 'next' ? that.currPageY+1 : pageY == 'prev' ? that.currPageY-1 : pageY;
+
+ pageX = pageX < 0 ? 0 : pageX > that.pagesX.length-1 ? that.pagesX.length-1 : pageX;
+ pageY = pageY < 0 ? 0 : pageY > that.pagesY.length-1 ? that.pagesY.length-1 : pageY;
+
+ that.currPageX = pageX;
+ that.currPageY = pageY;
+ x = that.pagesX[pageX];
+ y = that.pagesY[pageY];
+ } else {
+ x = -that.wrapperW * pageX;
+ y = -that.wrapperH * pageY;
+ if (x < that.maxScrollX) x = that.maxScrollX;
+ if (y < that.maxScrollY) y = that.maxScrollY;
+ }
+
+ that.scrollTo(x, y, time);
+ },
+
+ disable: function () {
+ this.stop();
+ this._resetPos(0);
+ this.enabled = false;
+
+ // If disabled after touchstart we make sure that there are no left over events
+ this._unbind(MOVE_EV);
+ this._unbind(END_EV);
+ this._unbind(CANCEL_EV);
+ },
+
+ enable: function () {
+ this.enabled = true;
+ },
+
+ stop: function () {
+ if (this.options.useTransition) this._unbind('webkitTransitionEnd');
+ else cancelFrame(this.aniTime);
+ this.steps = [];
+ this.moved = false;
+ this.animating = false;
+ },
+
+ zoom: function (x, y, scale, time) {
+ var that = this,
+ relScale = scale / that.scale;
+
+ if (!that.options.useTransform) return;
+
+ that.zoomed = true;
+ time = time === undefined ? 200 : time;
+ x = x - that.wrapperOffsetLeft - that.x;
+ y = y - that.wrapperOffsetTop - that.y;
+ that.x = x - x * relScale + that.x;
+ that.y = y - y * relScale + that.y;
+
+ that.scale = scale;
+ that.refresh();
+
+ that.x = that.x > 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x;
+ that.y = that.y > that.minScrollY ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y;
+
+ that.scroller.style[vendor + 'TransitionDuration'] = time + 'ms';
+ that.scroller.style[vendor + 'Transform'] = trnOpen + that.x + 'px,' + that.y + 'px' + trnClose + ' scale(' + scale + ')';
+ that.zoomed = false;
+ },
+
+ isReady: function () {
+ return !this.moved && !this.zoomed && !this.animating;
+ }
+};
+
+if (typeof exports !== 'undefined') exports.iScroll = iScroll;
+else window.iScroll = iScroll;
+
+})();
View
197 readme.md
@@ -19,14 +19,14 @@ To change the local persistence mechanism for the application:
## Part 2: Building with PhoneGap Build ##
-1. Create an account on http://build.phonegap.com if you don't already have one.
+1. If you don't already have one, create an account on http://build.phonegap.com.
2. Create a new application on PhoneGap Build. Either point to a GitHub repository, or zip up your phonegap-workshop directory and upload it to PhoneGap Build.
3. Click the **Ready to build** button
-4. Using a QR Code reader application, install the App on your device.
+4. When the build process completes, use a QR Code reader app to install the Employee Directory application on your device.
-To configure build preferences:
+To fine tune your build preferences:
-1. In the phonegap-workshop directory, add a config.xml file defined as follows (make the necessary adjustments: id, author, etc.):
+1. In the phonegap-workshop directory, add a config.xml file defined as follows (make the necessary adjustments for id, author, etc.):
```xml
<?xml version="1.0" encoding="UTF-8"?>
@@ -49,7 +49,7 @@ To configure build preferences:
</widget>
```
2. If you used the GitHub approach, sync with GitHub and click the **Update Code** button in PhoneGap Build.
- If you sed the zip file approach, zip up zip up your phonegap-workshop directory and upload the new version to PhoneGap Build
+ If you used the zip file approach, zip up your phonegap-workshop directory and upload the new version to PhoneGap Build
## Part 3: Using Native Notification ##
@@ -59,6 +59,8 @@ To configure build preferences:
<script src="phonegap.js"></script>
```
+ NOTE: A platform specific phonegap.js is injected by PhoneGap Build at build time. In other words, phonegaps.js doesn't need to be (and shouldn't be) present in your project folder.
+
2. In main.js, define a function named showAlert() inside the app object. If _navigator.notification_ is available, use its alert() function. Otherwise, use the default browser alert() function.
```javascript
@@ -117,13 +119,19 @@ To configure build preferences:
Modify index.html as follows:
-1. Create an HTML template to render the Home View:
+1. Add a script tag to include the handlebar.js library:
+
+ ```html
+ <script src="lib/handlebars.js"></script>
+ ````
+
+2. Create an HTML template to render the Home View:
```html
<script id="home-tpl" type="text/x-handlebars-template">
- <div class='header'><h1>Home</h1></div>
- <div class='search-bar'><input class='search-key' type="search"/></div>
- <ul class='employee-list'></ul>
+ <div class='header'><h1>Home</h1></div>
+ <div class='search-bar'><input class='search-key' type="search"/></div>
+ <ul class='employee-list'></ul>
</script>
```
@@ -132,7 +140,7 @@ Modify index.html as follows:
```html
<script id="employee-li-tpl" type="text/x-handlebars-template">
{{#.}}
- <li><a href="#employees/{{this.id}}">{{this.firstName}} {{this.lastName}}</a></li>
+ <li><a href="#employees/{{this.id}}">{{this.firstName}} {{this.lastName}}<br/>{{this.title}}</a></li>
{{/.}}
</script>
```
@@ -166,6 +174,8 @@ Modify main.js as follows:
}
```
+4. Test the application.
+
## Part 6: Creating a View Class ##
#### Step 1: Create the HomeView Class ####
@@ -189,7 +199,7 @@ Modify main.js as follows:
HomeView.liTemplate = Handlebars.compile($("#employee-li-tpl").html());
```
-3. Define an initialize() function inside the HomeView class. Define a div wrapper for the view. The div wrapper is used to attach the view related events. Invoke the initialize() function inside the HomeView constructor function.
+3. Define an initialize() function inside the HomeView class. Define a div wrapper for the view. The div wrapper is used to attach the view-related events. Invoke the initialize() function inside the HomeView constructor function.
```javascript
var HomeView = function(store) {
@@ -229,9 +239,15 @@ Modify main.js as follows:
#### Step 2: Using the HomeView class ####
-1. Remove the renderHomeView() function from the app object.
-2. Remove the findByName() function from the app object.
-3. Modify the initialize function() to display the Home View using the HomeView class:
+1. In index.html, add a script tag to include HomeView.js:
+
+ ```html
+ <script src="js/HomeView.js"></script>
+ ```
+
+2. Remove the renderHomeView() function from the app object.
+3. Remove the findByName() function from the app object.
+4. Modify the initialize function() to display the Home View using the HomeView class:
```javascript
initialize: function() {
@@ -242,23 +258,25 @@ Modify main.js as follows:
}
```
-## Part 7: Implementing Touch-Based Scrolling ##
+## Part 7: Adding Styles and Touch-Based Scrolling ##
#### Step 1: Style the Application ####
1. Add the Source Sans Pro font definition to the head of index.html
```javascript
- <script src="../css/source-sans-pro.js"></script>
+ <script src="css/source-sans-pro.js"></script>
```
2. Add styles.css to the head of index.html
```javascript
- <link href="../css/styles.css" rel="stylesheet">
+ <link href="css/styles.css" rel="stylesheet">
```
-3. Test the application. Specifically, test the list behavior when the list is bigger than the browser window (or the screen)
+3. I index.html, modify the home-tpl template: change the search-key input type from _text_ to _search_.
+
+4. Test the application. Specifically, test the list behavior when the list is bigger than the browser window (or the screen)
#### Step 2: Native Scrolling Approach ####
@@ -289,8 +307,74 @@ Modify main.js as follows:
#### Step 3: iScroll Approach ####
+1. Add a script tag to include the iscroll.js library:
+
+ ```html
+ <script src="lib/iscroll.js"></script>
+ ```
+
+2. In HomeView.js, modify the findByName() function: Instantiate an iScroll object to scroll the list of employees returned. If the iScroll object already exists (), simply refresh it to adapt it to the new size of the list.
+
+ ```javascript
+ this.findByName = function() {
+ store.findByName($('.search-key').val(), function(employees) {
+ $('.employee-list').html(HomeView.liTemplate(employees));
+ if (self.iscroll) {
+ console.log('Refresh iScroll');
+ self.iscroll.refresh();
+ } else {
+ console.log('New iScroll');
+ self.iscroll = new iScroll($('.scroll', self.el)[0], {hScrollbar: false, vScrollbar: false });
+ }
+ });
+ };
+
+ ```
+
+
+## Part 8: Highlighting Tapped or Clicked UI Elements ##
+
+1. In styles.css, add a _tappable-active_ class definition for _tapped_ or _clicked_ list item links. The class simply highlights the item with a blue background:
-## Part 8: Routing to Multiple Views ##
+ ```css
+ li>a.tappable-active {
+ color: #fff;
+ background-color: #4286f5;
+ }
+ ```
+
+2. In main.js, define a registerEvents() function inside the app object. Add a the _tappable_active_ class to the selected (_tapped_ or _clicked_) list item:
+
+ ```javascript
+ registerEvents: function() {
+ var self = this;
+ // Check of browser supports touch events...
+ if (document.documentElement.hasOwnProperty('ontouchstart')) {
+ // ... if yes: register touch event listener to change the "selected" state of the item
+ $('body').on('touchstart', 'a', function(event) {
+ $(event.target).addClass('tappable-active');
+ });
+ $('body').on('touchend', 'a', function(event) {
+ $(event.target).removeClass('tappable-active');
+ });
+ } else {
+ // ... if not: register mouse events instead
+ $('body').on('mousedown', 'a', function(event) {
+ $(event.target).addClass('tappable-active');
+ });
+ $('body').on('mouseup', 'a', function(event) {
+ $(event.target).removeClass('tappable-active');
+ });
+ }
+ }
+ ```
+
+3. Invoke the registerEvents() function from within the app object's initialize() function.
+
+4. Test the application.
+
+
+## Part 9: Routing to Multiple Views ##
#### Step 1: Create the employee template ####
@@ -300,7 +384,7 @@ Open index.html and add a template to render a detailed employee view:
<script id="employee-tpl" type="text/x-handlebars-template">
<div class='header'><a href='#' class="button header-button header-button-left">Back</a><h1>Details</h1></div>
<div class='details'>
- <img id='image' src='../img/{{firstName}}_{{lastName}}.jpg' style="float:left;margin:10px;"/>
+ <img id='image' src='img/{{firstName}}_{{lastName}}.jpg' style="float:left;margin:10px;"/>
<h1>{{firstName}} {{lastName}}</h1>
<h2>{{title}}</h2>
<ul>
@@ -366,13 +450,13 @@ Open index.html and add a template to render a detailed employee view:
this.detailsURL = /^#employees\/(\d{1,})/;
```
-4. In the app's registerEvents() function, add an event listener to listen to URL hash tag changes:
+2. In the app's registerEvents() function, add an event listener to listen to URL hash tag changes:
```javascript
$(window).on('hashchange', $.proxy(this.route, this));
```
-5. In the app object, define a route() function to route the app to the appropriate view:
+3. In the app object, define a route() function to route requests to the appropriate view:
- If there is no hash tag in the URL: display the HomeView
- If there is a has tag matching the pattern for an employee details URL: display an EmployeeView for the specified employee.
@@ -393,12 +477,26 @@ Open index.html and add a template to render a detailed employee view:
}
```
-6. Test the application.
+4. Modify the initialize() function to call the route() function:
+
+
+ ```javascript
+ initialize: function() {
+ var self = this;
+ this.detailsURL = /^#employees\/(\d{1,})/;
+ this.registerEvents();
+ this.store = new MemoryStore(function() {
+ self.route();
+ });
+ }
+ ```
+
+5. Test the application.
-## Part 9: Using the Location API ##
+## Part 10: Using the Location API ##
-1. In index.html, add the following list item to the employee template:
+1. In index.html, add the following list item to the employee-tpl template:
```html
<li><a href="#" class="add-location-btn">Add Location</a></li>
@@ -424,13 +522,13 @@ Open index.html and add a template to render a detailed employee view:
alert('Error getting location');
});
return false;
- }
+ };
```
4. Test the Application
-## Part 10: Using the Contacts API ##
+## Part 11: Using the Contacts API ##
1. In index.html, add the following list item to the employee template:
@@ -462,12 +560,12 @@ Open index.html and add a template to render a detailed employee view:
contact.phoneNumbers = phoneNumbers;
contact.save();
return false;
- }
+ };
```
4. Test the Application
-## Part 11: Using the Camera API ##
+## Part 12: Using the Camera API ##
1. In index.html, add the following list item to the employee template:
@@ -513,9 +611,40 @@ Open index.html and add a template to render a detailed employee view:
4. Test the Application
-## Part 12: Sliding Pages with CSS Transitions ##
+## Part 13: Sliding Pages with CSS Transitions ##
+
+1. Add the following classes to styles.css:
+
+ ```css
+ .page {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ -webkit-transform:translate3d(0,0,0);
+ }
+
+ .stage-center {
+ top: 0;
+ left: 0;
+ }
+
+ .stage-left {
+ left: -100%;
+ }
+
+ .stage-right {
+ left: 100%;
+ }
+
+ .transition {
+ -moz-transition-duration: .375s;
+ -webkit-transition-duration: .375s;
+ -o-transition-duration: .375s;
+ }
+ ```
+
-1. Inside the app object, define a slidePage() function implemented as follows:
+2. Inside the app object, define a slidePage() function implemented as follows:
```javascript
slidePage: function(page) {
@@ -558,7 +687,7 @@ Open index.html and add a template to render a detailed employee view:
}
```
-2. Modify the route() function as follows:
+3. Modify the route() function as follows:
```javascript
route: function() {
@@ -583,11 +712,11 @@ Open index.html and add a template to render a detailed employee view:
```
-More topics:
+## More topics ##
- Conditional css
- Touch vs click
- Viewport
- Testing
- External template loader
-- Plugins
+- Plugins

0 comments on commit e578db6

Please sign in to comment.