diff --git a/.gitignore b/.gitignore index cf832ddd..82d8bba0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store dist/*.js +node_modules \ No newline at end of file diff --git a/README.md b/README.md index 4e188acf..2ccafb8b 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,17 @@ iScroll v4.1.9 - 2011-08-03 The overflow:scroll for mobile webkit. Project started because webkit for iPhone does not provide a native way to scroll content inside a fixed size (width/height) div. So basically it was impossible to have a fixed header/footer and a scrolling central area. Until now. Read more at [cubiq.org](http://cubiq.org). +## Ender support +Using [Ender](http://ender.no.de), add it to your existing build + + $ ender add iscroll + +Use it like this: + +``` js +var myScroll = $('#doc').iScroll(options) +``` + ## Credits and Special thanks iScroll is evolving thank to the help of all those who sent suggestions, bug reports and ideas on [github](https://github.com/cubiq/iscroll), my [blog](http://cubiq.org) and [googlecode](http://code.google.com/p/iscroll-js/). This is by no means the work of a sole man. diff --git a/examples/ender/ender.js b/examples/ender/ender.js new file mode 100644 index 00000000..bb99e0c0 --- /dev/null +++ b/examples/ender/ender.js @@ -0,0 +1,1602 @@ +/*! + * ============================================================= + * Ender: open module JavaScript framework (https://ender.no.de) + * Build: ender build qwery domready ../../ + * ============================================================= + */ + +/*! + * Ender-JS: open module JavaScript framework (client-lib) + * copyright Dustin Diaz & Jacob Thornton 2011 (@ded @fat) + * https://ender.no.de + * License MIT + */ +!function (context) { + + // a global object for node.js module compatiblity + // ============================================ + + context['global'] = context; + + // Implements simple module system + // losely based on CommonJS Modules spec v1.1.1 + // ============================================ + + var modules = {}; + + function require (identifier) { + var module = modules[identifier] || window[identifier]; + if (!module) throw new Error("Requested module '" + identifier + "' has not been defined."); + return module; + } + + function provide (name, what) { + return modules[name] = what; + } + + context['provide'] = provide; + context['require'] = require; + + // Implements Ender's $ global access object + // ========================================= + + function aug(o, o2) { + for (var k in o2) { + k != 'noConflict' && k != '_VERSION' && (o[k] = o2[k]); + } + return o; + } + + function boosh(s, r, els) { + // string || node || nodelist || window + if (ender._select && (typeof s == 'string' || s.nodeName || s.length && 'item' in s || s == window)) { + els = ender._select(s, r); + els.selector = s; + } else { + els = isFinite(s.length) ? s : [s]; + } + return aug(els, boosh); + } + + function ender(s, r) { + return boosh(s, r); + } + + aug(ender, { + _VERSION: '0.2.5', + ender: function (o, chain) { + aug(chain ? boosh : ender, o); + }, + fn: context.$ && context.$.fn || {} // for easy compat to jQuery plugins + }); + + aug(boosh, { + forEach: function (fn, scope, i) { + // opt out of native forEach so we can intentionally call our own scope + // defaulting to the current item and be able to return self + for (i = 0, l = this.length; i < l; ++i) { + i in this && fn.call(scope || this[i], this[i], i, this); + } + // return self for chaining + return this; + }, + $: ender // handy reference to self + }); + + var old = context.$; + ender.noConflict = function () { + context.$ = old; + return this; + }; + + (typeof module !== 'undefined') && module.exports && (module.exports = ender); + // use subscript notation as extern for Closure compilation + context['ender'] = context['$'] = context['ender'] || ender; + +}(this); + +!function () { + + var module = { exports: {} }, exports = module.exports; + + /*! + * Qwery - A Blazing Fast query selector engine + * https://github.com/ded/qwery + * copyright Dustin Diaz & Jacob Thornton 2011 + * MIT License + */ + + !function (name, definition) { + if (typeof define == 'function') define(definition) + else if (typeof module != 'undefined') module.exports = definition() + else this[name] = definition() + }('qwery', function () { + var context = this + , doc = document + , c, i, j, k, l, m, o, p, r, v + , el, node, found, classes, item, items, token + , html = doc.documentElement + , id = /#([\w\-]+)/ + , clas = /\.[\w\-]+/g + , idOnly = /^#([\w\-]+$)/ + , classOnly = /^\.([\w\-]+)$/ + , tagOnly = /^([\w\-]+)$/ + , tagAndOrClass = /^([\w]+)?\.([\w\-]+)$/ + , normalizr = /\s*([\s\+\~>])\s*/g + , splitters = /[\s\>\+\~]/ + , splittersMore = /(?![\s\w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^'"]*\]|[\s\w\+\-]*\))/ + , specialChars = /([.*+?\^=!:${}()|\[\]\/\\])/g + , simple = /^([a-z0-9]+)?(?:([\.\#]+[\w\-\.#]+)?)/ + , attr = /\[([\w\-]+)(?:([\|\^\$\*\~]?\=)['"]?([ \w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^]+)["']?)?\]/ + , pseudo = /:([\w\-]+)(\(['"]?([\s\w\+\-]+)['"]?\))?/ + , dividers = new RegExp('(' + splitters.source + ')' + splittersMore.source, 'g') + , tokenizr = new RegExp(splitters.source + splittersMore.source) + , chunker = new RegExp(simple.source + '(' + attr.source + ')?' + '(' + pseudo.source + ')?') + , walker = { + ' ': function (node) { + return node && node !== html && node.parentNode + } + , '>': function (node, contestant) { + return node && node.parentNode == contestant.parentNode && node.parentNode; + } + , '~': function (node) { + return node && node.previousSibling; + } + , '+': function (node, contestant, p1, p2) { + if (!node) { + return false; + } + p1 = previous(node); + p2 = previous(contestant); + return p1 && p2 && p1 == p2 && p1; + } + } + function cache() { + this.c = {} + } + cache.prototype = { + g: function (k) { + return this.c[k] || undefined + } + , s: function (k, v) { + this.c[k] = v + return v + } + } + + var classCache = new cache() + , cleanCache = new cache() + , attrCache = new cache() + , tokenCache = new cache() + + function flatten(ar) { + r = [] + for (i = 0, l = ar.length; i < l; i++) { + if (arrayLike(ar[i])) { + r = r.concat(ar[i]) + } else { + r.push(ar[i]) + } + } + return r + } + + function previous(n) { + while (n = n.previousSibling) { + if (n.nodeType == 1) { + break; + } + } + return n + } + + function q(query) { + return query.match(chunker) + } + + // this next method expect at most these args + // given => div.hello[title="world"]:foo('bar') + + // div.hello[title="world"]:foo('bar'), div, .hello, [title="world"], title, =, world, :foo('bar'), foo, ('bar'), bar] + + function interpret(whole, tag, idsAndClasses, wholeAttribute, attribute, qualifier, value, wholePseudo, pseudo, wholePseudoVal, pseudoVal) { + var m, c, k; + if (tag && this.tagName.toLowerCase() !== tag) { + return false + } + if (idsAndClasses && (m = idsAndClasses.match(id)) && m[1] !== this.id) { + return false + } + if (idsAndClasses && (classes = idsAndClasses.match(clas))) { + for (i = classes.length; i--;) { + c = classes[i].slice(1) + if (!(classCache.g(c) || classCache.s(c, new RegExp('(^|\\s+)' + c + '(\\s+|$)'))).test(this.className)) { + return false + } + } + } + if (pseudo && qwery.pseudos[pseudo] && !qwery.pseudos[pseudo](this, pseudoVal)) { + return false + } + if (wholeAttribute && !value) { + o = this.attributes + for (k in o) { + if (Object.prototype.hasOwnProperty.call(o, k) && (o[k].name || k) == attribute) { + return this + } + } + } + if (wholeAttribute && !checkAttr(qualifier, this.getAttribute(attribute) || '', value)) { + return false + } + return this + } + + function clean(s) { + return cleanCache.g(s) || cleanCache.s(s, s.replace(specialChars, '\\$1')) + } + + function checkAttr(qualify, actual, val) { + switch (qualify) { + case '=': + return actual == val + case '^=': + return actual.match(attrCache.g('^=' + val) || attrCache.s('^=' + val, new RegExp('^' + clean(val)))) + case '$=': + return actual.match(attrCache.g('$=' + val) || attrCache.s('$=' + val, new RegExp(clean(val) + '$'))) + case '*=': + return actual.match(attrCache.g(val) || attrCache.s(val, new RegExp(clean(val)))) + case '~=': + return actual.match(attrCache.g('~=' + val) || attrCache.s('~=' + val, new RegExp('(?:^|\\s+)' + clean(val) + '(?:\\s+|$)'))) + case '|=': + return actual.match(attrCache.g('|=' + val) || attrCache.s('|=' + val, new RegExp('^' + clean(val) + '(-|$)'))) + } + return 0 + } + + function _qwery(selector) { + var r = [], ret = [], i, j = 0, k, l, m, p, token, tag, els, root, intr, item, children + , tokens = tokenCache.g(selector) || tokenCache.s(selector, selector.split(tokenizr)) + , dividedTokens = selector.match(dividers), dividedToken + tokens = tokens.slice(0) // this makes a copy of the array so the cached original is not effected + + if (!tokens.length) return r + + token = tokens.pop() + root = tokens.length && (m = tokens[tokens.length - 1].match(idOnly)) ? doc.getElementById(m[1]) : doc + + if (!root) return r + + intr = q(token) + els = dividedTokens && /^[+~]$/.test(dividedTokens[dividedTokens.length - 1]) ? function (r) { + while (root = root.nextSibling) { + root.nodeType == 1 && (intr[1] ? intr[1] == root.tagName.toLowerCase() : 1) && r.push(root) + } + return r + }([]) : + root.getElementsByTagName(intr[1] || '*') + for (i = 0, l = els.length; i < l; i++) if (item = interpret.apply(els[i], intr)) r[j++] = item + if (!tokens.length) return r + + // loop through all descendent tokens + for (j = 0, l = r.length, k = 0; j < l; j++) { + p = r[j] + // loop through each token backwards crawling up tree + for (i = tokens.length; i--;) { + // loop through parent nodes + while (p = walker[dividedTokens[i]](p, r[j])) { + if (found = interpret.apply(p, q(tokens[i]))) break; + } + } + found && (ret[k++] = r[j]) + } + return ret + } + + function isNode(el) { + return (el && el.nodeType && (el.nodeType == 1 || el.nodeType == 9)) + } + + function uniq(ar) { + var a = [], i, j; + label: + for (i = 0; i < ar.length; i++) { + for (j = 0; j < a.length; j++) { + if (a[j] == ar[i]) { + continue label; + } + } + a[a.length] = ar[i] + } + return a + } + + function arrayLike(o) { + return (typeof o === 'object' && isFinite(o.length)) + } + + function normalizeRoot(root) { + if (!root) return doc + if (typeof root == 'string') return qwery(root)[0] + if (arrayLike(root)) return root[0] + return root + } + + function qwery(selector, _root) { + var root = normalizeRoot(_root) + + if (!root || !selector) return [] + if (selector === window || isNode(selector)) { + return !_root || (selector !== window && isNode(root) && isAncestor(selector, root)) ? [selector] : [] + } + if (selector && arrayLike(selector)) return flatten(selector) + if (m = selector.match(idOnly)) return (el = doc.getElementById(m[1])) ? [el] : [] + if (m = selector.match(tagOnly)) return flatten(root.getElementsByTagName(m[1])) + return select(selector, root) + } + + var isAncestor = 'compareDocumentPosition' in html ? + function (element, container) { + return (container.compareDocumentPosition(element) & 16) == 16; + } : 'contains' in html ? + function (element, container) { + container = container == doc || container == window ? html : container + return container !== element && container.contains(element) + } : + function (element, container) { + while (element = element.parentNode) if (element === container) return 1 + return 0 + }, + + supportsCSS3 = function () { + if (!doc.querySelector || !doc.querySelectorAll) return false + + try { return (doc.querySelectorAll(':nth-of-type(1)').length > 0) } + catch (e) { return false } + }(), + + select = supportsCSS3 ? + function (selector, root) { + if (doc.getElementsByClassName && (m = selector.match(classOnly))) { + return flatten((root).getElementsByClassName(m[1])); + } + return flatten((root).querySelectorAll(selector)) + } : + function (selector, root) { + selector = selector.replace(normalizr, '$1') + var result = [], element, collection, collections = [], i + if (m = selector.match(tagAndOrClass)) { + items = root.getElementsByTagName(m[1] || '*'); + r = classCache.g(m[2]) || classCache.s(m[2], new RegExp('(^|\\s+)' + m[2] + '(\\s+|$)')); + for (i = 0, l = items.length, j = 0; i < l; i++) { + r.test(items[i].className) && (result[j++] = items[i]); + } + return result + } + for (i = 0, items = selector.split(','), l = items.length; i < l; i++) { + collections[i] = _qwery(items[i]) + } + for (i = 0, l = collections.length; i < l && (collection = collections[i]); i++) { + var ret = collection + if (root !== doc) { + ret = [] + for (j = 0, m = collection.length; j < m && (element = collection[j]); j++) { + // make sure element is a descendent of root + isAncestor(element, root) && ret.push(element) + } + } + result = result.concat(ret) + } + return uniq(result) + } + + qwery.uniq = uniq + qwery.pseudos = {} + + var old = context.qwery + qwery.noConflict = function () { + context.qwery = old + return this + } + + return qwery + }) + + provide("qwery", module.exports); + + !function (doc, $) { + var q = require('qwery') + , table = 'table' + , nodeMap = { + thead: table + , tbody: table + , tfoot: table + , tr: 'tbody' + , th: 'tr' + , td: 'tr' + , fieldset: 'form' + , option: 'select' + } + function create(node, root) { + var tag = /^<([^\s>]+)/.exec(node)[1] + , el = (root || doc).createElement(nodeMap[tag] || 'div'), els = [] + el.innerHTML = node + var nodes = el.childNodes + el = el.firstChild + els.push(el) + while (el = el.nextSibling) (el.nodeType == 1) && els.push(el) + return els + } + + $._select = function (s, r) { + return /^\s* that[dir + 'ScrollbarMaxScroll']) { + if (!that.options.fixedScrollbar) { + size = that[dir + 'ScrollbarIndicatorSize'] - m.round((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; + } + + if (that.absDistX < 6 && that.absDistY < 6) { + that.distX += deltaX; + that.distY += deltaY; + that.absDistX = m.abs(that.distX); + that.absDistY = m.abs(that.distY); + + 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(m.round(newPosX), m.round(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 ('detail' in e) { + wheelDeltaX = wheelDeltaY = -e.detail * 3; + } else { + wheelDeltaX = wheelDeltaY = -e.wheelDelta; + } + + 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; + + 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: m.round(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= 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= 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 = m.round(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 = m.round(that.scroller.offsetWidth * that.scale); + that.scrollerH = m.round((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= 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 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; + + 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 || 400); + }, + + 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; + + })(); + + + provide("iscroll", module.exports); + + !function ($, iScroll) { + $.ender({ + iScroll: function (options) { + return new iScroll(this[0], options) + } + }, true) + }(ender, require('iscroll').iScroll) + +}(); \ No newline at end of file diff --git a/examples/ender/ender.min.js b/examples/ender/ender.min.js new file mode 100644 index 00000000..c7fcaff4 --- /dev/null +++ b/examples/ender/ender.min.js @@ -0,0 +1,27 @@ +/*! + * ============================================================= + * Ender: open module JavaScript framework (https://ender.no.de) + * Build: ender build qwery domready ../../ + * ============================================================= + */ + + +/*! + * Ender-JS: open module JavaScript framework (client-lib) + * copyright Dustin Diaz & Jacob Thornton 2011 (@ded @fat) + * https://ender.no.de + * License MIT + */ +!function(a){function c(a){var c=b[a]||window[a];if(!c)throw new Error("Requested module '"+a+"' has not been defined.");return c}function d(a,c){return b[a]=c}function e(a,b){for(var c in b)c!="noConflict"&&c!="_VERSION"&&(a[c]=b[c]);return a}function f(a,b,c){return g._select&&(typeof a=="string"||a.nodeName||a.length&&"item"in a||a==window)?(c=g._select(a,b),c.selector=a):c=isFinite(a.length)?a:[a],e(c,f)}function g(a,b){return f(a,b)}a.global=a;var b={};a.provide=d,a.require=c,e(g,{_VERSION:"0.2.5",ender:function(a,b){e(b?f:g,a)},fn:a.$&&a.$.fn||{}}),e(f,{forEach:function(a,b,c){for(c=0,l=this.length;c])\s*/g,B=/[\s\>\+\~]/,C=/(?![\s\w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^'"]*\]|[\s\w\+\-]*\))/,D=/([.*+?\^=!:${}()|\[\]\/\\])/g,E=/^([a-z0-9]+)?(?:([\.\#]+[\w\-\.#]+)?)/,F=/\[([\w\-]+)(?:([\|\^\$\*\~]?\=)['"]?([ \w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^]+)["']?)?\]/,G=/:([\w\-]+)(\(['"]?([\s\w\+\-]+)['"]?\))?/,H=new RegExp("("+B.source+")"+C.source,"g"),I=new RegExp(B.source+C.source),J=new RegExp(E.source+"("+F.source+")?"+"("+G.source+")?"),K={" ":function(a){return a&&a!==t&&a.parentNode},">":function(a,b){return a&&a.parentNode==b.parentNode&&a.parentNode},"~":function(a){return a&&a.previousSibling},"+":function(a,b,c,d){return a?(c=R(a),d=R(b),c&&d&&c==d&&c):!1}};L.prototype={g:function(a){return this.c[a]||undefined},s:function(a,b){return this.c[a]=b,b}};var M=new L,N=new L,O=new L,P=new L,ba="compareDocumentPosition"in t?function(a,b){return(b.compareDocumentPosition(a)&16)==16}:"contains"in t?function(a,c){return c=c==b||c==window?t:c,c!==a&&c.contains(a)}:function(a,b){while(a=a.parentNode)if(a===b)return 1;return 0},bb=function(){if(!b.querySelector||!b.querySelectorAll)return!1;try{return b.querySelectorAll(":nth-of-type(1)").length>0}catch(a){return!1}}(),bc=bb?function(a,c){return b.getElementsByClassName&&(h=a.match(x))?Q(c.getElementsByClassName(h[1])):Q(c.querySelectorAll(a))}:function(a,c){a=a.replace(A,"$1");var d=[],f,i,j=[],l;if(h=a.match(z)){r=c.getElementsByTagName(h[1]||"*"),k=M.g(h[2])||M.s(h[2],new RegExp("(^|\\s+)"+h[2]+"(\\s+|$)"));for(l=0,g=r.length,e=0;l]+)/.exec(b)[1],f=(c||a).createElement(e[d]||"div"),g=[];f.innerHTML=b;var h=f.childNodes;f=f.firstChild,g.push(f);while(f=f.nextSibling)f.nodeType==1&&g.push(f);return g}var c=require("qwery"),d="table",e={thead:d,tbody:d,tfoot:d,tr:"tbody",th:"tr",td:"tr",fieldset:"form",option:"select"};b._select=function(a,b){return/^\s*e[b+"ScrollbarMaxScroll"]&&(e.options.fixedScrollbar?f=e[b+"ScrollbarMaxScroll"]:(g=e[b+"ScrollbarIndicatorSize"]-a.round((f-e[b+"ScrollbarMaxScroll"])*3),g<8&&(g=8),e[b+"ScrollbarIndicator"].style[b=="h"?"width":"height"]=g+"px",f=e[b+"ScrollbarMaxScroll"]+(e[b+"ScrollbarIndicatorSize"]-g))),e[b+"ScrollbarWrapper"].style[c+"TransitionDelay"]="0",e[b+"ScrollbarWrapper"].style.opacity=d&&e.options.hideScrollbar?"0":"1",e[b+"ScrollbarIndicator"].style[c+"Transform"]=s+(b=="h"?f+"px,0":"0,"+f+"px")+t},_start:function(b){var d=this,f=e?b.touches[0]:b,g,h,i,j,k;if(!d.enabled)return;d.options.onBeforeScrollStart&&d.options.onBeforeScrollStart.call(d,b),(d.options.useTransition||d.options.zoom)&&d._transitionTime(0),d.moved=!1,d.animating=!1,d.zoomed=!1,d.distX=0,d.distY=0,d.absDistX=0,d.absDistY=0,d.dirX=0,d.dirY=0,d.options.zoom&&e&&b.touches.length>1&&(j=a.abs(b.touches[0].pageX-b.touches[1].pageX),k=a.abs(b.touches[0].pageY-b.touches[1].pageY),d.touchesDistStart=a.sqrt(j*j+k*k),d.originX=a.abs(b.touches[0].pageX+b.touches[1].pageX-d.wrapperOffsetLeft*2)/2-d.x,d.originY=a.abs(b.touches[0].pageY+b.touches[1].pageY-d.wrapperOffsetTop*2)/2-d.y,d.options.onZoomStart&&d.options.onZoomStart.call(d,b));if(d.options.momentum){d.options.useTransform?(g=getComputedStyle(d.scroller,null)[c+"Transform"].replace(/[^0-9-.,]/g,"").split(","),h=g[4]*1,i=g[5]*1):(h=getComputedStyle(d.scroller,null).left.replace(/[^0-9-]/g,"")*1,i=getComputedStyle(d.scroller,null).top.replace(/[^0-9-]/g,"")*1);if(h!=d.x||i!=d.y)d.options.useTransition?d._unbind("webkitTransitionEnd"):l(d.aniTime),d.steps=[],d._pos(h,i)}d.absStartX=d.x,d.absStartY=d.y,d.startX=d.x,d.startY=d.y,d.pointX=f.pageX,d.pointY=f.pageY,d.startTime=b.timeStamp||Date.now(),d.options.onScrollStart&&d.options.onScrollStart.call(d,b),d._bind(o),d._bind(p),d._bind(q)},_move:function(b){var d=this,f=e?b.touches[0]:b,g=f.pageX-d.pointX,h=f.pageY-d.pointY,i=d.x+g,j=d.y+h,k,l,m,n=b.timeStamp||Date.now();d.options.onBeforeScrollMove&&d.options.onBeforeScrollMove.call(d,b);if(d.options.zoom&&e&&b.touches.length>1){k=a.abs(b.touches[0].pageX-b.touches[1].pageX),l=a.abs(b.touches[0].pageY-b.touches[1].pageY),d.touchesDist=a.sqrt(k*k+l*l),d.zoomed=!0,m=1/d.touchesDistStart*d.touchesDist*this.scale,md.options.zoomMax&&(m=2*d.options.zoomMax*Math.pow(.5,d.options.zoomMax/m)),d.lastScale=m/this.scale,i=this.originX-this.originX*d.lastScale+this.x,j=this.originY-this.originY*d.lastScale+this.y,this.scroller.style[c+"Transform"]=s+i+"px,"+j+"px"+t+" scale("+m+")",d.options.onZoom&&d.options.onZoom.call(d,b);return}d.pointX=f.pageX,d.pointY=f.pageY;if(i>0||i=0||d.maxScrollX>=0?0:d.maxScrollX;if(j>d.minScrollY||j=d.minScrollY||d.maxScrollY>=0?d.minScrollY:d.maxScrollY;if(d.absDistX<6&&d.absDistY<6){d.distX+=g,d.distY+=h,d.absDistX=a.abs(d.distX),d.absDistY=a.abs(d.distY);return}d.options.lockDirection&&(d.absDistX>d.absDistY+5?(j=d.y,h=0):d.absDistY>d.absDistX+5&&(i=d.x,g=0)),d.moved=!0,d._pos(i,j),d.dirX=g>0?-1:g<0?1:0,d.dirY=h>0?-1:h<0?1:0,n-d.startTime>300&&(d.startTime=n,d.startX=d.x,d.startY=d.y),d.options.onScrollMove&&d.options.onScrollMove.call(d,b)},_end:function(b){if(e&&b.touches.length!=0)return;var d=this,f=e?b.changedTouches[0]:b,g,h,i={dist:0,time:0},j={dist:0,time:0},k=(b.timeStamp||Date.now())-d.startTime,l=d.x,m=d.y,n,r,u,v,w;d._unbind(o),d._unbind(p),d._unbind(q),d.options.onBeforeScrollEnd&&d.options.onBeforeScrollEnd.call(d,b);if(d.zoomed){w=d.scale*d.lastScale,w=Math.max(d.options.zoomMin,w),w=Math.min(d.options.zoomMax,w),d.lastScale=w/d.scale,d.scale=w,d.x=d.originX-d.originX*d.lastScale+d.x,d.y=d.originY-d.originY*d.lastScale+d.y,d.scroller.style[c+"TransitionDuration"]="200ms",d.scroller.style[c+"Transform"]=s+d.x+"px,"+d.y+"px"+t+" scale("+d.scale+")",d.zoomed=!1,d.refresh(),d.options.onZoomEnd&&d.options.onZoomEnd.call(d,b);return}if(!d.moved){e&&(d.doubleTapTimer&&d.options.zoom?(clearTimeout(d.doubleTapTimer),d.doubleTapTimer=null,d.options.onZoomStart&&d.options.onZoomStart.call(d,b),d.zoom(d.pointX,d.pointY,d.scale==1?d.options.doubleTapZoom:1),d.options.onZoomEnd&&setTimeout(function(){d.options.onZoomEnd.call(d,b)},200)):d.doubleTapTimer=setTimeout(function(){d.doubleTapTimer=null,g=f.target;while(g.nodeType!=1)g=g.parentNode;g.tagName!="SELECT"&&g.tagName!="INPUT"&&g.tagName!="TEXTAREA"&&(h=document.createEvent("MouseEvents"),h.initMouseEvent("click",!0,!0,b.view,1,f.screenX,f.screenY,f.clientX,f.clientY,b.ctrlKey,b.altKey,b.shiftKey,b.metaKey,0,null),h._fake=!0,g.dispatchEvent(h))},d.options.zoom?250:0)),d._resetPos(200),d.options.onTouchEnd&&d.options.onTouchEnd.call(d,b);return}if(k<300&&d.options.momentum){i=l?d._momentum(l-d.startX,k,-d.x,d.scrollerW-d.wrapperW+d.x,d.options.bounce?d.wrapperW:0):i,j=m?d._momentum(m-d.startY,k,-d.y,d.maxScrollY<0?d.scrollerH-d.wrapperH+d.y-d.minScrollY:0,d.options.bounce?d.wrapperH:0):j,l=d.x+i.dist,m=d.y+j.dist;if(d.x>0&&l>0||d.xd.minScrollY&&m>d.minScrollY||d.y=0?0:b.x=b.minScrollY||b.maxScrollY>0?b.minScrollY:b.yb.options.zoomMax&&(g=b.options.zoomMax),g!=b.scale&&(!b.wheelZoomCount&&b.options.onZoomStart&&b.options.onZoomStart.call(b,a),b.wheelZoomCount++,b.zoom(a.pageX,a.pageY,g,400),setTimeout(function(){b.wheelZoomCount--,!b.wheelZoomCount&&b.options.onZoomEnd&&b.options.onZoomEnd.call(b,a)},400));return}e=b.x+c,f=b.y+d,e>0?e=0:eb.minScrollY?f=b.minScrollY:f=e+f.time){b._pos(f.x,f.y),b.animating=!1,b.options.onAnimationEnd&&b.options.onAnimationEnd.call(b),b._startAni();return}i=(i-e)/f.time-1,g=a.sqrt(1-i*i),j=(f.x-c)*g+c,l=(f.y-d)*g+d,b._pos(j,l),b.animating&&(b.aniTime=k(h))},h()},_transitionTime:function(a){a+="ms",this.scroller.style[c+"TransitionDuration"]=a,this.hScrollbar&&(this.hScrollbarIndicator.style[c+"TransitionDuration"]=a),this.vScrollbar&&(this.vScrollbarIndicator.style[c+"TransitionDuration"]=a)},_momentum:function(b,c,d,e,f){var g=6e-4,h=a.abs(b)/c,i=h*h/(2*g),j=0,k=0;return b>0&&i>d?(k=f/(6/(i/h*g)),d=d+k,h=h*d/i,i=d):b<0&&i>e&&(k=f/(6/(i/h*g)),e=e+k,h=h*e/i,i=e),i=i*(b<0?-1:1),j=h/g,{dist:i,time:a.round(j)}},_offset:function(a){var b=-a.offsetLeft,c=-a.offsetTop;while(a=a.offsetParent)b-=a.offsetLeft,c-=a.offsetTop;return a!=this.wrapper&&(b*=this.scale,c*=this.scale),{left:b,top:c}},_snap:function(b,c){var d=this,e,f,g,h,i,j;g=d.pagesX.length-1;for(e=0,f=d.pagesX.length;e=d.pagesX[e]){g=e;break}g==d.currPageX&&g>0&&d.dirX<0&&g--,b=d.pagesX[g],i=a.abs(b-d.pagesX[d.currPageX]),i=i?a.abs(d.x-b)/i*500:0,d.currPageX=g,g=d.pagesY.length-1;for(e=0;e=d.pagesY[e]){g=e;break}return g==d.currPageY&&g>0&&d.dirY<0&&g--,c=d.pagesY[g],j=a.abs(c-d.pagesY[d.currPageY]),j=j?a.abs(d.y-c)/j*500:0,d.currPageY=g,h=a.round(a.max(i,j))||200,{x:b,y:c,time:h}},_bind:function(a,b,c){(b||this.scroller).addEventListener(a,this,!!c)},_unbind:function(a,b,c){(b||this.scroller).removeEventListener(a,this,!!c)},destroy:function(){var a=this;a.scroller.style[c+"Transform"]="",a.hScrollbar=!1,a.vScrollbar=!1,a._scrollbar("h"),a._scrollbar("v"),a._unbind(m,window),a._unbind(n),a._unbind(o),a._unbind(p),a._unbind(q),a.options.hasTouch&&(a._unbind("mouseout",a.wrapper),a._unbind(r)),a.options.useTransition&&a._unbind("webkitTransitionEnd"),a.options.checkDOMChanges&&clearInterval(a.checkDOMTime),a.options.onDestroy&&a.options.onDestroy.call(a)},refresh:function(){var b=this,d,e,f,g,h=0,i=0;b.scaleb.wrapperH),b.hScrollbar=b.hScroll&&b.options.hScrollbar,b.vScrollbar=b.vScroll&&b.options.vScrollbar&&b.scrollerH>b.wrapperH,d=b._offset(b.wrapper),b.wrapperOffsetLeft=-d.left,b.wrapperOffsetTop=-d.top;if(typeof b.options.snap=="string"){b.pagesX=[],b.pagesY=[],g=b.scroller.querySelectorAll(b.options.snap);for(e=0,f=g.length;e=b.maxScrollX)b.pagesX[i]=h,h=h-b.wrapperW,i++;b.maxScrollX%b.wrapperW&&(b.pagesX[b.pagesX.length]=b.maxScrollX-b.pagesX[b.pagesX.length-1]+b.pagesX[b.pagesX.length-1]),h=0,i=0,b.pagesY=[];while(h>=b.maxScrollY)b.pagesY[i]=h,h=h-b.wrapperH,i++;b.maxScrollY%b.wrapperH&&(b.pagesY[b.pagesY.length]=b.maxScrollY-b.pagesY[b.pagesY.length-1]+b.pagesY[b.pagesY.length-1])}b._scrollbar("h"),b._scrollbar("v"),b.zoomed||(b.scroller.style[c+"TransitionDuration"]="0",b._resetPos(200))},scrollTo:function(a,b,c,d){var e=this,f=a,g,h;e.stop(),f.length||(f=[{x:a,y:b,time:c,relative:d}]);for(g=0,h=f.length;g0?0:e.leftd.minScrollY?d.minScrollY:e.topd.pagesX.length-1?d.pagesX.length-1:a,b=b<0?0:b>d.pagesY.length-1?d.pagesY.length-1:b,d.currPageX=a,d.currPageY=b,e=d.pagesX[a],f=d.pagesY[b]):(e=-d.wrapperW*a,f=-d.wrapperH*b,e0?0:f.xf.minScrollY?f.minScrollY:f.y + + + + + + +iScroll demo: Carousel + + + + + + + +
+
+
    +
  • 1. A robot may not injure a human being or, through inaction, allow a human being to come to harm.
  • +
  • 2. A robot must obey any orders given to it by human beings, except where such orders would conflict with the First Law.
  • +
  • 3. A robot must protect its own existence as long as such protection does not conflict with the First or Second Law.
  • +
  • Zeroth Law: A robot may not harm humanity, or, by inaction, allow humanity to come to harm.
  • +
  • Lyuben Dilov's Forth law: A robot must establish its identity as a robot in all cases.
  • +
  • Harry Harrison's Forth law: A robot must reproduce. As long as such reproduction does not interfere with the First or Second or Third Law.
  • +
  • Nikola Kesarovski's Fifth law: A robot must know it is a robot.
  • +
+
+
+ + + \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 00000000..86831f29 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "iscroll" + , "description": "smooth scrolling for mobile webkit" + , "version": "4.1.9" + , "homepage": "http://cubiq.org/iscroll-4" + , "author": "Matteo Spinelli <> (http://cubiq.org)" + , "keywords": ["ender", "iscroll", "scrolling", "webkit", "iphone", "android"] + , "main": "./src/iscroll.js" + , "ender": "./src/ender.js" + , "repository": { + "type": "git" + , "url": "https://github.com/cubiq/iscroll.git" + } +} \ No newline at end of file diff --git a/src/ender.js b/src/ender.js new file mode 100644 index 00000000..4c64f8af --- /dev/null +++ b/src/ender.js @@ -0,0 +1,7 @@ +!function ($, iScroll) { + $.ender({ + iScroll: function (options) { + return new iScroll(this[0], options) + } + }, true) +}(ender, require('iscroll').iScroll) \ No newline at end of file diff --git a/src/iscroll.js b/src/iscroll.js index b600400c..86a27946 100644 --- a/src/iscroll.js +++ b/src/iscroll.js @@ -105,7 +105,13 @@ var m = Math, onZoom: null, onZoomEnd: null }; - + // Helpers FIX ANDROID BUG! + // translate3d and scale doesn't work together! + // Ignoring 3d ONLY WHEN YOU SET that.zoom + if ( that.zoom && isAndroid ){ + trnOpen = 'translate('; + trnClose = ')'; + } // User defined options for (i in options) that.options[i] = options[i];