Html+css Pulldown Load 下拉刷新 Item1 Item2 Item3 Item4 Item5 Item6 Item7 Item8 Item9 Item10 Item11 Item12 Item13 Item14 Item15 Item16 Item17 Item18 Item19 Item20 Item1 Item2 Item3 Item4 Item5 Item6 Item7 Item8 Item9 Item10 Item11 Item1
Pulldown Load
下拉刷新
- Item1
- Item2
- Item3
- Item4
- Item5
- Item6
- Item7
- Item8
- Item9
- Item10
- Item11
- Item12
- Item13
- Item14
- Item15
- Item16
- Item17
- Item18
- Item19
- Item20
- Item1
- Item2
- Item3
- Item4
- Item5
- Item6
- Item7
- Item8
- Item9
- Item10
- Item11
- Item12
- Item13
- Item14
- Item15
- Item16
- Item17
- Item18
- Item19
- Item20
/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */
(function (window, document, Math) {
var rAF = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) { window.setTimeout(callback, 1000 / 60); };
var utils = (function () {
var me = {};
var _elementStyle = document.createElement('div').style;
var _vendor = (function () {
var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
transform,
i = 0,
l = vendors.length;
for ( ; i < l; i++ ) {
transform = vendors[i] + 'ransform';
if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
}
return false;
})();
function _prefixStyle (style) {
if ( _vendor === false ) return false;
if ( _vendor === '' ) return style;
return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
}
me.getTime = Date.now || function getTime () { return new Date().getTime(); };
me.extend = function (target, obj) {
for ( var i in obj ) {
target[i] = obj[i];
}
};
me.addEvent = function (el, type, fn, capture) {
el.addEventListener(type, fn, !!capture);
};
me.removeEvent = function (el, type, fn, capture) {
el.removeEventListener(type, fn, !!capture);
};
me.prefixPointerEvent = function (pointerEvent) {
return window.MSPointerEvent ?
'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8):
pointerEvent;
};
me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
var distance = current - start,
speed = Math.abs(distance) / time,
destination,
duration;
deceleration = deceleration === undefined ? 0.0006 : deceleration;
destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
duration = speed / deceleration;
if ( destination < lowerMargin ) {
destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
distance = Math.abs(destination - current);
duration = distance / speed;
} else if ( destination > 0 ) {
destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
distance = Math.abs(current) + destination;
duration = distance / speed;
}
return {
destination: Math.round(destination),
duration: duration
};
};
var _transform = _prefixStyle('transform');
me.extend(me, {
hasTransform: _transform !== false,
hasPerspective: _prefixStyle('perspective') in _elementStyle,
hasTouch: 'ontouchstart' in window,
hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed
hasTransition: _prefixStyle('transition') in _elementStyle
});
/*
This should find all Android browsers lower than build 535.19 (both stock browser and webview)
- galaxy S2 is ok
- 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1`
- 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
- galaxy S3 is badAndroid (stock brower, webview)
`AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
- galaxy S4 is badAndroid (stock brower, webview)
`AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
- galaxy S5 is OK
`AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
- galaxy S6 is OK
`AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
*/
me.isBadAndroid = (function() {
var appVersion = window.navigator.appVersion;
// Android browser is not a chrome browser.
if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) {
var safariVersion = appVersion.match(/Safari\/(\d+.\d)/);
if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) {
return parseFloat(safariVersion[1]) < 535.19;
} else {
return true;
}
} else {
return false;
}
})();
me.extend(me.style = {}, {
transform: _transform,
transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
transitionDuration: _prefixStyle('transitionDuration'),
transitionDelay: _prefixStyle('transitionDelay'),
transformOrigin: _prefixStyle('transformOrigin')
});
me.hasClass = function (e, c) {
var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
return re.test(e.className);
};
me.addClass = function (e, c) {
if ( me.hasClass(e, c) ) {
return;
}
var newclass = e.className.split(' ');
newclass.push(c);
e.className = newclass.join(' ');
};
me.removeClass = function (e, c) {
if ( !me.hasClass(e, c) ) {
return;
}
var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
e.className = e.className.replace(re, ' ');
};
me.offset = function (el) {
var left = -el.offsetLeft,
top = -el.offsetTop;
// jshint -W084
while (el = el.offsetParent) {
left -= el.offsetLeft;
top -= el.offsetTop;
}
// jshint +W084
return {
left: left,
top: top
};
};
me.preventDefaultException = function (el, exceptions) {
for ( var i in exceptions ) {
if ( exceptions[i].test(el[i]) ) {
return true;
}
}
return false;
};
me.extend(me.eventType = {}, {
touchstart: 1,
touchmove: 1,
touchend: 1,
mousedown: 2,
mousemove: 2,
mouseup: 2,
pointerdown: 3,
pointermove: 3,
pointerup: 3,
MSPointerDown: 3,
MSPointerMove: 3,
MSPointerUp: 3
});
me.extend(me.ease = {}, {
quadratic: {
style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
fn: function (k) {
return k * ( 2 - k );
}
},
circular: {
style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1)
fn: function (k) {
return Math.sqrt( 1 - ( --k * k ) );
}
},
back: {
style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
fn: function (k) {
var b = 4;
return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
}
},
bounce: {
style: '',
fn: function (k) {
if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
return 7.5625 * k * k;
} else if ( k < ( 2 / 2.75 ) ) {
return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
} else if ( k < ( 2.5 / 2.75 ) ) {
return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
} else {
return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
}
}
},
elastic: {
style: '',
fn: function (k) {
var f = 0.22,
e = 0.4;
if ( k === 0 ) { return 0; }
if ( k == 1 ) { return 1; }
return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
}
}
});
me.tap = function (e, eventName) {
var ev = document.createEvent('Event');
ev.initEvent(eventName, true, true);
ev.pageX = e.pageX;
ev.pageY = e.pageY;
e.target.dispatchEvent(ev);
};
me.click = function (e) {
var target = e.target,
ev;
if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) {
ev = document.createEvent('MouseEvents');
ev.initMouseEvent('click', true, true, e.view, 1,
target.screenX, target.screenY, target.clientX, target.clientY,
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
0, null);
ev._constructed = true;
target.dispatchEvent(ev);
}
};
return me;
})();
function IScroll (el, options) {
this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
this.scroller = this.wrapper.children[0];
this.scrollerStyle = this.scroller.style; // cache style for better performance
this.options = {
resizeScrollbars: true,
mouseWheelSpeed: 20,
snapThreshold: 0.334,
// INSERT POINT: OPTIONS
disablePointer : !utils.hasPointer,
disableTouch : utils.hasPointer || !utils.hasTouch,
disableMouse : utils.hasPointer || utils.hasTouch,
startX: 0,
startY: 0,
scrollY: true,
directionLockThreshold: 5,
momentum: true,
bounce: true,
bounceTime: 600,
bounceEasing: '',
preventDefault: true,
preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/ },
HWCompositing: true,
useTransition: true,
useTransform: true,
bindToWrapper: typeof window.onmousedown === "undefined"
};
for ( var i in options ) {
this.options[i] = options[i];
}
// Normalize options
this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';
this.options.useTransition = utils.hasTransition && this.options.useTransition;
this.options.useTransform = utils.hasTransform && this.options.useTransform;
this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;
// If you want eventPassthrough I have to lock one of the axes
this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;
// With eventPassthrough we also need lockDirection mechanism
this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;
this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;
this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;
if ( this.options.tap === true ) {
this.options.tap = 'tap';
}
if ( this.options.shrinkScrollbars == 'scale' ) {
this.options.useTransition = false;
}
this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;
if ( this.options.probeType == 3 ) {
this.options.useTransition = false; }
// INSERT POINT: NORMALIZATION
// Some defaults
this.x = 0;
this.y = 0;
this.directionX = 0;
this.directionY = 0;
this._events = {};
// INSERT POINT: DEFAULTS
this._init();
this.refresh();
this.scrollTo(this.options.startX, this.options.startY);
this.enable();
}
IScroll.prototype = {
version: '5.2.0',
_init: function () {
this._initEvents();
if ( this.options.scrollbars || this.options.indicators ) {
this._initIndicators();
}
if ( this.options.mouseWheel ) {
this._initWheel();
}
if ( this.options.snap ) {
this._initSnap();
}
if ( this.options.keyBindings ) {
this._initKeys();
}
// INSERT POINT: _init
},
destroy: function () {
this._initEvents(true);
clearTimeout(this.resizeTimeout);
this.resizeTimeout = null;
this._execEvent('destroy');
},
_transitionEnd: function (e) {
if ( e.target != this.scroller || !this.isInTransition ) {
return;
}
this._transitionTime();
if ( !this.resetPosition(this.options.bounceTime) ) {
this.isInTransition = false;
this._execEvent('scrollEnd');
}
},
_start: function (e) {
// React to left mouse button only
if ( utils.eventType[e.type] != 1 ) {
// for button property
// http://unixpapa.com/js/mouse.html
var button;
if (!e.which) {
/* IE case */
button = (e.button < 2) ? 0 :
((e.button == 4) ? 1 : 2);
} else {
/* All others */
button = e.button;
}
if ( button !== 0 ) {
return;
}
}
if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
return;
}
if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
e.preventDefault();
}
var point = e.touches ? e.touches[0] : e,
pos;
this.initiated = utils.eventType[e.type];
this.moved = false;
this.distX = 0;
this.distY = 0;
this.directionX = 0;
this.directionY = 0;
this.directionLocked = 0;
this.startTime = utils.getTime();
if ( this.options.useTransition && this.isInTransition ) {
this._transitionTime();
this.isInTransition = false;
pos = this.getComputedPosition();
this._translate(Math.round(pos.x), Math.round(pos.y));
this._execEvent('scrollEnd');
} else if ( !this.options.useTransition && this.isAnimating ) {
this.isAnimating = false;
this._execEvent('scrollEnd');
}
this.startX = this.x;
this.startY = this.y;
this.absStartX = this.x;
this.absStartY = this.y;
this.pointX = point.pageX;
this.pointY = point.pageY;
this._execEvent('beforeScrollStart');
},
_move: function (e) {
if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
return;
}
if ( this.options.preventDefault ) { // increases performance on Android? TODO: check!
e.preventDefault();
}
var point = e.touches ? e.touches[0] : e,
deltaX = point.pageX - this.pointX,
deltaY = point.pageY - this.pointY,
timestamp = utils.getTime(),
newX, newY,
absDistX, absDistY;
this.pointX = point.pageX;
this.pointY = point.pageY;
this.distX += deltaX;
this.distY += deltaY;
absDistX = Math.abs(this.distX);
absDistY = Math.abs(this.distY);
// We need to move at least 10 pixels for the scrolling to initiate
if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
return;
}
// If you are scrolling in one direction lock the other
if ( !this.directionLocked && !this.options.freeScroll ) {
if ( absDistX > absDistY + this.options.directionLockThreshold ) {
this.directionLocked = 'h'; // lock horizontally
} else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
this.directionLocked = 'v'; // lock vertically
} else {
this.directionLocked = 'n'; // no lock
}
}
if ( this.directionLocked == 'h' ) {
if ( this.options.eventPassthrough == 'vertical' ) {
e.preventDefault();
} else if ( this.options.eventPassthrough == 'horizontal' ) {
this.initiated = false;
return;
}
deltaY = 0;
} else if ( this.directionLocked == 'v' ) {
if ( this.options.eventPassthrough == 'horizontal' ) {
e.preventDefault();
} else if ( this.options.eventPassthrough == 'vertical' ) {
this.initiated = false;
return;
}
deltaX = 0;
}
deltaX = this.hasHorizontalScroll ? deltaX : 0;
deltaY = this.hasVerticalScroll ? deltaY : 0;
newX = this.x + deltaX;
newY = this.y + deltaY;
// Slow down if outside of the boundaries
if ( newX > 0 || newX < this.maxScrollX ) {
newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
}
if ( newY > 0 || newY < this.maxScrollY ) {
newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
}
this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
if ( !this.moved ) {
this._execEvent('scrollStart');
}
this.moved = true;
this._translate(newX, newY);
/* REPLACE START: _move */
if ( timestamp - this.startTime > 300 ) {
this.startTime = timestamp;
this.startX = this.x;
this.startY = this.y;
if ( this.options.probeType == 1 ) {
this._execEvent('scroll');
}
}
if ( this.options.probeType > 1 ) {
this._execEvent('scroll');
}
/* REPLACE END: _move */
},
_end: function (e) {
if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
return;
}
if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
e.preventDefault();
}
var point = e.changedTouches ? e.changedTouches[0] : e,
momentumX,
momentumY,
duration = utils.getTime() - this.startTime,
newX = Math.round(this.x),
newY = Math.round(this.y),
distanceX = Math.abs(newX - this.startX),
distanceY = Math.abs(newY - this.startY),
time = 0,
easing = '';
this.isInTransition = 0;
this.initiated = 0;
this.endTime = utils.getTime();
// reset if we are outside of the boundaries
if ( this.resetPosition(this.options.bounceTime) ) {
return;
}
this.scrollTo(newX, newY); // ensures that the last position is rounded
// we scrolled less than 10 pixels
if ( !this.moved ) {
if ( this.options.tap ) {
utils.tap(e, this.options.tap);
}
if ( this.options.click ) {
utils.click(e);
}
this._execEvent('scrollCancel');
return;
}
if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) {
this._execEvent('flick');
return;
}
// start momentum animation if needed
if ( this.options.momentum && duration < 300 ) {
momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration) : { destination: newX, duration: 0 };
momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { destination: newY, duration: 0 };
newX = momentumX.destination;
newY = momentumY.destination;
time = Math.max(momentumX.duration, momentumY.duration);
this.isInTransition = 1;
}
if ( this.options.snap ) {
var snap = this._nearestSnap(newX, newY);
this.currentPage = snap;
time = this.options.snapSpeed || Math.max(
Math.max(
Math.min(Math.abs(newX - snap.x), 1000),
Math.min(Math.abs(newY - snap.y), 1000)
), 300);
newX = snap.x;
newY = snap.y;
this.directionX = 0;
this.directionY = 0;
easing = this.options.bounceEasing;
}
// INSERT POINT: _end
if ( newX != this.x || newY != this.y ) {
// change easing function when scroller goes out of the boundaries
if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {
easing = utils.ease.quadratic;
}
this.scrollTo(newX, newY, time, easing);
return;
}
this._execEvent('scrollEnd');
},
_resize: function () {
var that = this;
clearTimeout(this.resizeTimeout);
this.resizeTimeout = setTimeout(function () {
that.refresh();
}, this.options.resizePolling);
},
resetPosition: function (time) {
var x = this.x,
y = this.y;
time = time || 0;
if ( !this.hasHorizontalScroll || this.x > 0 ) {
x = 0;
} else if ( this.x < this.maxScrollX ) {
x = this.maxScrollX;
}
if ( !this.hasVerticalScroll || this.y > 0 ) {
y = 0;
} else if ( this.y < this.maxScrollY ) {
y = this.maxScrollY;
}
if ( x == this.x && y == this.y ) {
return false;
}
this.scrollTo(x, y, time, this.options.bounceEasing);
return true;
},
disable: function () {
this.enabled = false;
},
enable: function () {
this.enabled = true;
},
refresh: function () {
var rf = this.wrapper.offsetHeight; // Force reflow
this.wrapperWidth = this.wrapper.clientWidth;
this.wrapperHeight = this.wrapper.clientHeight;
/* REPLACE START: refresh */
this.scrollerWidth = this.scroller.offsetWidth;
this.scrollerHeight = this.scroller.offsetHeight;
this.maxScrollX = this.wrapperWidth - this.scrollerWidth;
this.maxScrollY = this.wrapperHeight - this.scrollerHeight;
/* REPLACE END: refresh */
this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0;
this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0;
if ( !this.hasHorizontalScroll ) {
this.maxScrollX = 0;
this.scrollerWidth = this.wrapperWidth;
}
if ( !this.hasVerticalScroll ) {
this.maxScrollY = 0;
this.scrollerHeight = this.wrapperHeight;
}
this.endTime = 0;
this.directionX = 0;
this.directionY = 0;
this.wrapperOffset = utils.offset(this.wrapper);
this._execEvent('refresh');
this.resetPosition();
// INSERT POINT: _refresh
},
on: function (type, fn) {
if ( !this._events[type] ) {
this._events[type] = [];
}
this._events[type].push(fn);
},
off: function (type, fn) {
if ( !this._events[type] ) {
return;
}
var index = this._events[type].indexOf(fn);
if ( index > -1 ) {
this._events[type].splice(index, 1);
}
},
_execEvent: function (type) {
if ( !this._events[type] ) {
return;
}
var i = 0,
l = this._events[type].length;
if ( !l ) {
return;
}
for ( ; i < l; i++ ) {
this._events[type][i].apply(this, [].slice.call(arguments, 1));
}
},
scrollBy: function (x, y, time, easing) {
x = this.x + x;
y = this.y + y;
time = time || 0;
this.scrollTo(x, y, time, easing);
},
scrollTo: function (x, y, time, easing) {
easing = easing || utils.ease.circular;
this.isInTransition = this.options.useTransition && time > 0;
var transitionType = this.options.useTransition && easing.style;
if ( !time || transitionType ) {
if(transitionType) {
this._transitionTimingFunction(easing.style);
this._transitionTime(time);
}
this._translate(x, y);
} else {
this._animate(x, y, time, easing.fn);
}
},
scrollToElement: function (el, time, offsetX, offsetY, easing) {
el = el.nodeType ? el : this.scroller.querySelector(el);
if ( !el ) {
return;
}
var pos = utils.offset(el);
pos.left -= this.wrapperOffset.left;
pos.top -= this.wrapperOffset.top;
// if offsetX/Y are true we center the element to the screen
if ( offsetX === true ) {
offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
}
if ( offsetY === true ) {
offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
}
pos.left -= offsetX || 0;
pos.top -= offsetY || 0;
pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top;
time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time;
this.scrollTo(pos.left, pos.top, time, easing);
},
_transitionTime: function (time) {
time = time || 0;
var durationProp = utils.style.transitionDuration;
this.scrollerStyle[durationProp] = time + 'ms';
if ( !time && utils.isBadAndroid ) {
this.scrollerStyle[durationProp] = '0.0001ms';
// remove 0.0001ms
var self = this;
rAF(function() {
if(self.scrollerStyle[durationProp] === '0.0001ms') {
self.scrollerStyle[durationProp] = '0s';
}
});
}
if ( this.indicators ) {
for ( var i = this.indicators.length; i--; ) {
this.indicators[i].transitionTime(time);
}
}
// INSERT POINT: _transitionTime
},
_transitionTimingFunction: function (easing) {
this.scrollerStyle[utils.style.transitionTimingFunction] = easing;
if ( this.indicators ) {
for ( var i = this.indicators.length; i--; ) {
this.indicators[i].transitionTimingFunction(easing);
}
}
// INSERT POINT: _transitionTimingFunction
},
_translate: function (x, y) {
if ( this.options.useTransform ) {
/* REPLACE START: _translate */
this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
/* REPLACE END: _translate */
} else {
x = Math.round(x);
y = Math.round(y);
this.scrollerStyle.left = x + 'px';
this.scrollerStyle.top = y + 'px';
}
this.x = x;
this.y = y;
if ( this.indicators ) {
for ( var i = this.indicators.length; i--; ) {
this.indicators[i].updatePosition();
}
}
// INSERT POINT: _translate
},
_initEvents: function (remove) {
var eventType = remove ? utils.removeEvent : utils.addEvent,
target = this.options.bindToWrapper ? this.wrapper : window;
eventType(window, 'orientationchange', this);
eventType(window, 'resize', this);
if ( this.options.click ) {
eventType(this.wrapper, 'click', this, true);
}
if ( !this.options.disableMouse ) {
eventType(this.wrapper, 'mousedown', this);
eventType(target, 'mousemove', this);
eventType(target, 'mousecancel', this);
eventType(target, 'mouseup', this);
}
if ( utils.hasPointer && !this.options.disablePointer ) {
eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);
eventType(target, utils.prefixPointerEvent('pointermove'), this);
eventType(target, utils.prefixPointerEvent('pointercancel'), this);
eventType(target, utils.prefixPointerEvent('pointerup'), this);
}
if ( utils.hasTouch && !this.options.disableTouch ) {
eventType(this.wrapper, 'touchstart', this);
eventType(target, 'touchmove', this);
eventType(target, 'touchcancel', this);
eventType(target, 'touchend', this);
}
eventType(this.scroller, 'transitionend', this);
eventType(this.scroller, 'webkitTransitionEnd', this);
eventType(this.scroller, 'oTransitionEnd', this);
eventType(this.scroller, 'MSTransitionEnd', this);
},
getComputedPosition: function () {
var matrix = window.getComputedStyle(this.scroller, null),
x, y;
if ( this.options.useTransform ) {
matrix = matrix[utils.style.transform].split(')')[0].split(', ');
x = +(matrix[12] || matrix[4]);
y = +(matrix[13] || matrix[5]);
} else {
x = +matrix.left.replace(/[^-\d.]/g, '');
y = +matrix.top.replace(/[^-\d.]/g, '');
}
return { x: x, y: y };
},
_initIndicators: function () {
var interactive = this.options.interactiveScrollbars,
customStyle = typeof this.options.scrollbars != 'string',
indicators = [],
indicator;
var that = this;
this.indicators = [];
if ( this.options.scrollbars ) {
// Vertical scrollbar
if ( this.options.scrollY ) {
indicator = {
el: createDefaultScrollbar('v', interactive, this.options.scrollbars),
interactive: interactive,
defaultScrollbars: true,
customStyle: customStyle,
resize: this.options.resizeScrollbars,
shrink: this.options.shrinkScrollbars,
fade: this.options.fadeScrollbars,
listenX: false
};
this.wrapper.appendChild(indicator.el);
indicators.push(indicator);
}
// Horizontal scrollbar
if ( this.options.scrollX ) {
indicator = {
el: createDefaultScrollbar('h', interactive, this.options.scrollbars),
interactive: interactive,
defaultScrollbars: true,
customStyle: customStyle,
resize: this.options.resizeScrollbars,
shrink: this.options.shrinkScrollbars,
fade: this.options.fadeScrollbars,
listenY: false
};
this.wrapper.appendChild(indicator.el);
indicators.push(indicator);
}
}
if ( this.options.indicators ) {
// TODO: check concat compatibility
indicators = indicators.concat(this.options.indicators);
}
for ( var i = indicators.length; i--; ) {
this.indicators.push( new Indicator(this, indicators[i]) );
}
// TODO: check if we can use array.map (wide compatibility and performance issues)
function _indicatorsMap (fn) {
if (that.indicators) {
for ( var i = that.indicators.length; i--; ) {
fn.call(that.indicators[i]);
}
}
}
if ( this.options.fadeScrollbars ) {
this.on('scrollEnd', function () {
_indicatorsMap(function () {
this.fade();
});
});
this.on('scrollCancel', function () {
_indicatorsMap(function () {
this.fade();
});
});
this.on('scrollStart', function () {
_indicatorsMap(function () {
this.fade(1);
});
});
this.on('beforeScrollStart', function () {
_indicatorsMap(function () {
this.fade(1, true);
});
});
}
this.on('refresh', function () {
_indicatorsMap(function () {
this.refresh();
});
});
this.on('destroy', function () {
_indicatorsMap(function () {
this.destroy();
});
delete this.indicators;
});
},
_initWheel: function () {
utils.addEvent(this.wrapper, 'wheel', this);
utils.addEvent(this.wrapper, 'mousewheel', this);
utils.addEvent(this.wrapper, 'DOMMouseScroll', this);
this.on('destroy', function () {
clearTimeout(this.wheelTimeout);
this.wheelTimeout = null;
utils.removeEvent(this.wrapper, 'wheel', this);
utils.removeEvent(this.wrapper, 'mousewheel', this);
utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);
});
},
_wheel: function (e) {
if ( !this.enabled ) {
return;
}
e.preventDefault();
var wheelDeltaX, wheelDeltaY,
newX, newY,
that = this;
if ( this.wheelTimeout === undefined ) {
that._execEvent('scrollStart');
}
// Execute the scrollEnd event after 400ms the wheel stopped scrolling
clearTimeout(this.wheelTimeout);
this.wheelTimeout = setTimeout(function () {
if(!that.options.snap) {
that._execEvent('scrollEnd');
}
that.wheelTimeout = undefined;
}, 400);
if ( 'deltaX' in e ) {
if (e.deltaMode === 1) {
wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed;
wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed;
} else {
wheelDeltaX = -e.deltaX;
wheelDeltaY = -e.deltaY;
}
} else if ( 'wheelDeltaX' in e ) {
wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;
wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;
} else if ( 'wheelDelta' in e ) {
wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;
} else if ( 'detail' in e ) {
wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;
} else {
return;
}
wheelDeltaX *= this.options.invertWheelDirection;
wheelDeltaY *= this.options.invertWheelDirection;
if ( !this.hasVerticalScroll ) {
wheelDeltaX = wheelDeltaY;
wheelDeltaY = 0;
}
if ( this.options.snap ) {
newX = this.currentPage.pageX;
newY = this.currentPage.pageY;
if ( wheelDeltaX > 0 ) {
newX--;
} else if ( wheelDeltaX < 0 ) {
newX++;
}
if ( wheelDeltaY > 0 ) {
newY--;
} else if ( wheelDeltaY < 0 ) {
newY++;
}
this.goToPage(newX, newY);
return;
}
newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);
newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);
this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0;
this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0;
if ( newX > 0 ) {
newX = 0;
} else if ( newX < this.maxScrollX ) {
newX = this.maxScrollX;
}
if ( newY > 0 ) {
newY = 0;
} else if ( newY < this.maxScrollY ) {
newY = this.maxScrollY;
}
this.scrollTo(newX, newY, 0);
if ( this.options.probeType > 1 ) {
this._execEvent('scroll');
}
// INSERT POINT: _wheel
},
_initSnap: function () {
this.currentPage = {};
if ( typeof this.options.snap == 'string' ) {
this.options.snap = this.scroller.querySelectorAll(this.options.snap);
}
this.on('refresh', function () {
var i = 0, l,
m = 0, n,
cx, cy,
x = 0, y,
stepX = this.options.snapStepX || this.wrapperWidth,
stepY = this.options.snapStepY || this.wrapperHeight,
el;
this.pages = [];
if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) {
return;
}
if ( this.options.snap === true ) {
cx = Math.round( stepX / 2 );
cy = Math.round( stepY / 2 );
while ( x > -this.scrollerWidth ) {
this.pages[i] = [];
l = 0;
y = 0;
while ( y > -this.scrollerHeight ) {
this.pages[i][l] = {
x: Math.max(x, this.maxScrollX),
y: Math.max(y, this.maxScrollY),
width: stepX,
height: stepY,
cx: x - cx,
cy: y - cy
};
y -= stepY;
l++;
}
x -= stepX;
i++;
}
} else {
el = this.options.snap;
l = el.length;
n = -1;
for ( ; i < l; i++ ) {
if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) {
m = 0;
n++;
}
if ( !this.pages[m] ) {
this.pages[m] = [];
}
x = Math.max(-el[i].offsetLeft, this.maxScrollX);
y = Math.max(-el[i].offsetTop, this.maxScrollY);
cx = x - Math.round(el[i].offsetWidth / 2);
cy = y - Math.round(el[i].offsetHeight / 2);
this.pages[m][n] = {
x: x,
y: y,
width: el[i].offsetWidth,
height: el[i].offsetHeight,
cx: cx,
cy: cy
};
if ( x > this.maxScrollX ) {
m++;
}
}
}
this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);
// Update snap threshold if needed
if ( this.options.snapThreshold % 1 === 0 ) {
this.snapThresholdX = this.options.snapThreshold;
this.snapThresholdY = this.options.snapThreshold;
} else {
this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);
this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);
}
});
this.on('flick', function () {
var time = this.options.snapSpeed || Math.max(
Math.max(
Math.min(Math.abs(this.x - this.startX), 1000),
Math.min(Math.abs(this.y - this.startY), 1000)
), 300);
this.goToPage(
this.currentPage.pageX + this.directionX,
this.currentPage.pageY + this.directionY,
time
);
});
},
_nearestSnap: function (x, y) {
if ( !this.pages.length ) {
return { x: 0, y: 0, pageX: 0, pageY: 0 };
}
var i = 0,
l = this.pages.length,
m = 0;
// Check if we exceeded the snap threshold
if ( Math.abs(x - this.absStartX) < this.snapThresholdX &&
Math.abs(y - this.absStartY) < this.snapThresholdY ) {
return this.currentPage;
}
if ( x > 0 ) {
x = 0;
} else if ( x < this.maxScrollX ) {
x = this.maxScrollX;
}
if ( y > 0 ) {
y = 0;
} else if ( y < this.maxScrollY ) {
y = this.maxScrollY;
}
for ( ; i < l; i++ ) {
if ( x >= this.pages[i][0].cx ) {
x = this.pages[i][0].x;
break;
}
}
l = this.pages[i].length;
for ( ; m < l; m++ ) {
if ( y >= this.pages[0][m].cy ) {
y = this.pages[0][m].y;
break;
}
}
if ( i == this.currentPage.pageX ) {
i += this.directionX;
if ( i < 0 ) {
i = 0;
} else if ( i >= this.pages.length ) {
i = this.pages.length - 1;
}
x = this.pages[i][0].x;
}
if ( m == this.currentPage.pageY ) {
m += this.directionY;
if ( m < 0 ) {
m = 0;
} else if ( m >= this.pages[0].length ) {
m = this.pages[0].length - 1;
}
y = this.pages[0][m].y;
}
return {
x: x,
y: y,
pageX: i,
pageY: m
};
},
goToPage: function (x, y, time, easing) {
easing = easing || this.options.bounceEasing;
if ( x >= this.pages.length ) {
x = this.pages.length - 1;
} else if ( x < 0 ) {
x = 0;
}
if ( y >= this.pages[x].length ) {
y = this.pages[x].length - 1;
} else if ( y < 0 ) {
y = 0;
}
var posX = this.pages[x][y].x,
posY = this.pages[x][y].y;
time = time === undefined ? this.options.snapSpeed || Math.max(
Math.max(
Math.min(Math.abs(posX - this.x), 1000),
Math.min(Math.abs(posY - this.y), 1000)
), 300) : time;
this.currentPage = {
x: posX,
y: posY,
pageX: x,
pageY: y
};
this.scrollTo(posX, posY, time, easing);
},
next: function (time, easing) {
var x = this.currentPage.pageX,
y = this.currentPage.pageY;
x++;
if ( x >= this.pages.length && this.hasVerticalScroll ) {
x = 0;
y++;
}
this.goToPage(x, y, time, easing);
},
prev: function (time, easing) {
var x = this.currentPage.pageX,
y = this.currentPage.pageY;
x--;
if ( x < 0 && this.hasVerticalScroll ) {
x = 0;
y--;
}
this.goToPage(x, y, time, easing);
},
_initKeys: function (e) {
// default key bindings
var keys = {
pageUp: 33,
pageDown: 34,
end: 35,
home: 36,
left: 37,
up: 38,
right: 39,
down: 40
};
var i;
// if you give me characters I give you keycode
if ( typeof this.options.keyBindings == 'object' ) {
for ( i in this.options.keyBindings ) {
if ( typeof this.options.keyBindings[i] == 'string' ) {
this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCodeAt(0);
}
}
} else {
this.options.keyBindings = {};
}
for ( i in keys ) {
this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];
}
utils.addEvent(window, 'keydown', this);
this.on('destroy', function () {
utils.removeEvent(window, 'keydown', this);
});
},
_key: function (e) {
if ( !this.enabled ) {
return;
}
var snap = this.options.snap, // we are using this alot, better to cache it
newX = snap ? this.currentPage.pageX : this.x,
newY = snap ? this.currentPage.pageY : this.y,
now = utils.getTime(),
prevTime = this.keyTime || 0,
acceleration = 0.250,
pos;
if ( this.options.useTransition && this.isInTransition ) {
pos = this.getComputedPosition();
this._translate(Math.round(pos.x), Math.round(pos.y));
this.isInTransition = false;
}
this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;
switch ( e.keyCode ) {
case this.options.keyBindings.pageUp:
if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
newX += snap ? 1 : this.wrapperWidth;
} else {
newY += snap ? 1 : this.wrapperHeight;
}
break;
case this.options.keyBindings.pageDown:
if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
newX -= snap ? 1 : this.wrapperWidth;
} else {
newY -= snap ? 1 : this.wrapperHeight;
}
break;
case this.options.keyBindings.end:
newX = snap ? this.pages.length-1 : this.maxScrollX;
newY = snap ? this.pages[0].length-1 : this.maxScrollY;
break;
case this.options.keyBindings.home:
newX = 0;
newY = 0;
break;
case this.options.keyBindings.left:
newX += snap ? -1 : 5 + this.keyAcceleration>>0;
break;
case this.options.keyBindings.up:
newY += snap ? 1 : 5 + this.keyAcceleration>>0;
break;
case this.options.keyBindings.right:
newX -= snap ? -1 : 5 + this.keyAcceleration>>0;
break;
case this.options.keyBindings.down:
newY -= snap ? 1 : 5 + this.keyAcceleration>>0;
break;
default:
return;
}
if ( snap ) {
this.goToPage(newX, newY);
return;
}
if ( newX > 0 ) {
newX = 0;
this.keyAcceleration = 0;
} else if ( newX < this.maxScrollX ) {
newX = this.maxScrollX;
this.keyAcceleration = 0;
}
if ( newY > 0 ) {
newY = 0;
this.keyAcceleration = 0;
} else if ( newY < this.maxScrollY ) {
newY = this.maxScrollY;
this.keyAcceleration = 0;
}
this.scrollTo(newX, newY, 0);
this.keyTime = now;
},
_animate: function (destX, destY, duration, easingFn) {
var that = this,
startX = this.x,
startY = this.y,
startTime = utils.getTime(),
destTime = startTime + duration;
function step () {
var now = utils.getTime(),
newX, newY,
easing;
if ( now >= destTime ) {
that.isAnimating = false;
that._translate(destX, destY);
if ( !that.resetPosition(that.options.bounceTime) ) {
that._execEvent('scrollEnd');
}
return;
}
now = ( now - startTime ) / duration;
easing = easingFn(now);
newX = ( destX - startX ) * easing + startX;
newY = ( destY - startY ) * easing + startY;
that._translate(newX, newY);
if ( that.isAnimating ) {
rAF(step);
}
if ( that.options.probeType == 3 ) {
that._execEvent('scroll');
}
}
this.isAnimating = true;
step();
},
handleEvent: function (e) {
switch ( e.type ) {
case 'touchstart':
case 'pointerdown':
case 'MSPointerDown':
case 'mousedown':
this._start(e);
break;
case 'touchmove':
case 'pointermove':
case 'MSPointerMove':
case 'mousemove':
this._move(e);
break;
case 'touchend':
case 'pointerup':
case 'MSPointerUp':
case 'mouseup':
case 'touchcancel':
case 'pointercancel':
case 'MSPointerCancel':
case 'mousecancel':
this._end(e);
break;
case 'orientationchange':
case 'resize':
this._resize();
break;
case 'transitionend':
case 'webkitTransitionEnd':
case 'oTransitionEnd':
case 'MSTransitionEnd':
this._transitionEnd(e);
break;
case 'wheel':
case 'DOMMouseScroll':
case 'mousewheel':
this._wheel(e);
break;
case 'keydown':
this._key(e);
break;
case 'click':
if ( this.enabled && !e._constructed && !utils.preventDefaultException(e.target, this.options.preventDefaultException)) {
e.preventDefault();
e.stopPropagation();
}
break;
}
}
};
function createDefaultScrollbar (direction, interactive, type) {
var scrollbar = document.createElement('div'),
indicator = document.createElement('div');
if ( type === true ) {
scrollbar.style.cssText = 'position:absolute;z-index:9999';
indicator.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px';
}
indicator.className = 'iScrollIndicator';
if ( direction == 'h' ) {
if ( type === true ) {
scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
indicator.style.height = '100%';
}
scrollbar.className = 'iScrollHorizontalScrollbar';
} else {
if ( type === true ) {
scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
indicator.style.width = '100%';
}
scrollbar.className = 'iScrollVerticalScrollbar';
}
scrollbar.style.cssText += ';overflow:hidden';
if ( !interactive ) {
scrollbar.style.pointerEvents = 'none';
}
scrollbar.appendChild(indicator);
return scrollbar;
}
function Indicator (scroller, options) {
this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
this.wrapperStyle = this.wrapper.style;
this.indicator = this.wrapper.children[0];
this.indicatorStyle = this.indicator.style;
this.scroller = scroller;
this.options = {
listenX: true,
listenY: true,
interactive: false,
resize: true,
defaultScrollbars: false,
shrink: false,
fade: false,
speedRatioX: 0,
speedRatioY: 0
};
for ( var i in options ) {
this.options[i] = options[i];
}
this.sizeRatioX = 1;
this.sizeRatioY = 1;
this.maxPosX = 0;
this.maxPosY = 0;
if ( this.options.interactive ) {
if ( !this.options.disableTouch ) {
utils.addEvent(this.indicator, 'touchstart', this);
utils.addEvent(window, 'touchend', this);
}
if ( !this.options.disablePointer ) {
utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this);
}
if ( !this.options.disableMouse ) {
utils.addEvent(this.indicator, 'mousedown', this);
utils.addEvent(window, 'mouseup', this);
}
}
if ( this.options.fade ) {
this.wrapperStyle[utils.style.transform] = this.scroller.translateZ;
var durationProp = utils.style.transitionDuration;
this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms';
// remove 0.0001ms
var self = this;
if(utils.isBadAndroid) {
rAF(function() {
if(self.wrapperStyle[durationProp] === '0.0001ms') {
self.wrapperStyle[durationProp] = '0s';
}
});
}
this.wrapperStyle.opacity = '0';
}
}
Indicator.prototype = {
handleEvent: function (e) {
switch ( e.type ) {
case 'touchstart':
case 'pointerdown':
case 'MSPointerDown':
case 'mousedown':
this._start(e);
break;
case 'touchmove':
case 'pointermove':
case 'MSPointerMove':
case 'mousemove':
this._move(e);
break;
case 'touchend':
case 'pointerup':
case 'MSPointerUp':
case 'mouseup':
case 'touchcancel':
case 'pointercancel':
case 'MSPointerCancel':
case 'mousecancel':
this._end(e);
break;
}
},
destroy: function () {
if ( this.options.fadeScrollbars ) {
clearTimeout(this.fadeTimeout);
this.fadeTimeout = null;
}
if ( this.options.interactive ) {
utils.removeEvent(this.indicator, 'touchstart', this);
utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
utils.removeEvent(this.indicator, 'mousedown', this);
utils.removeEvent(window, 'touchmove', this);
utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
utils.removeEvent(window, 'mousemove', this);
utils.removeEvent(window, 'touchend', this);
utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this);
utils.removeEvent(window, 'mouseup', this);
}
if ( this.options.defaultScrollbars ) {
this.wrapper.parentNode.removeChild(this.wrapper);
}
},
_start: function (e) {
var point = e.touches ? e.touches[0] : e;
e.preventDefault();
e.stopPropagation();
this.transitionTime();
this.initiated = true;
this.moved = false;
this.lastPointX = point.pageX;
this.lastPointY = point.pageY;
this.startTime = utils.getTime();
if ( !this.options.disableTouch ) {
utils.addEvent(window, 'touchmove', this);
}
if ( !this.options.disablePointer ) {
utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this);
}
if ( !this.options.disableMouse ) {
utils.addEvent(window, 'mousemove', this);
}
this.scroller._execEvent('beforeScrollStart');
},
_move: function (e) {
var point = e.touches ? e.touches[0] : e,
deltaX, deltaY,
newX, newY,
timestamp = utils.getTime();
if ( !this.moved ) {
this.scroller._execEvent('scrollStart');
}
this.moved = true;
deltaX = point.pageX - this.lastPointX;
this.lastPointX = point.pageX;
deltaY = point.pageY - this.lastPointY;
this.lastPointY = point.pageY;
newX = this.x + deltaX;
newY = this.y + deltaY;
this._pos(newX, newY);
if ( this.scroller.options.probeType == 1 && timestamp - this.startTime > 300 ) {
this.startTime = timestamp;
this.scroller._execEvent('scroll');
} else if ( this.scroller.options.probeType > 1 ) {
this.scroller._execEvent('scroll');
}
// INSERT POINT: indicator._move
e.preventDefault();
e.stopPropagation();
},
_end: function (e) {
if ( !this.initiated ) {
return;
}
this.initiated = false;
e.preventDefault();
e.stopPropagation();
utils.removeEvent(window, 'touchmove', this);
utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
utils.removeEvent(window, 'mousemove', this);
if ( this.scroller.options.snap ) {
var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y);
var time = this.options.snapSpeed || Math.max(
Math.max(
Math.min(Math.abs(this.scroller.x - snap.x), 1000),
Math.min(Math.abs(this.scroller.y - snap.y), 1000)
), 300);
if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) {
this.scroller.directionX = 0;
this.scroller.directionY = 0;
this.scroller.currentPage = snap;
this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing);
}
}
if ( this.moved ) {
this.scroller._execEvent('scrollEnd');
}
},
transitionTime: function (time) {
time = time || 0;
var durationProp = utils.style.transitionDuration;
this.indicatorStyle[durationProp] = time + 'ms';
if ( !time && utils.isBadAndroid ) {
this.indicatorStyle[durationProp] = '0.0001ms';
// remove 0.0001ms
var self = this;
rAF(function() {
if(self.indicatorStyle[durationProp] === '0.0001ms') {
self.indicatorStyle[durationProp] = '0s';
}
});
}
},
transitionTimingFunction: function (easing) {
this.indicatorStyle[utils.style.transitionTimingFunction] = easing;
},
refresh: function () {
this.transitionTime();
if ( this.options.listenX && !this.options.listenY ) {
this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
} else if ( this.options.listenY && !this.options.listenX ) {
this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
} else {
this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
}
if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) {
utils.addClass(this.wrapper, 'iScrollBothScrollbars');
utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');
if ( this.options.defaultScrollbars && this.options.customStyle ) {
if ( this.options.listenX ) {
this.wrapper.style.right = '8px';
} else {
this.wrapper.style.bottom = '8px';
}
}
} else {
utils.removeClass(this.wrapper, 'iScrollBothScrollbars');
utils.addClass(this.wrapper, 'iScrollLoneScrollbar');
if ( this.options.defaultScrollbars && this.options.customStyle ) {
if ( this.options.listenX ) {
this.wrapper.style.right = '2px';
} else {
this.wrapper.style.bottom = '2px';
}
}
}
var r = this.wrapper.offsetHeight; // force refresh
if ( this.options.listenX ) {
this.wrapperWidth = this.wrapper.clientWidth;
if ( this.options.resize ) {
this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);
this.indicatorStyle.width = this.indicatorWidth + 'px';
} else {
this.indicatorWidth = this.indicator.clientWidth;
}
this.maxPosX = this.wrapperWidth - this.indicatorWidth;
if ( this.options.shrink == 'clip' ) {
this.minBoundaryX = -this.indicatorWidth + 8;
this.maxBoundaryX = this.wrapperWidth - 8;
} else {
this.minBoundaryX = 0;
this.maxBoundaryX = this.maxPosX;
}
this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
}
if ( this.options.listenY ) {
this.wrapperHeight = this.wrapper.clientHeight;
if ( this.options.resize ) {
this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);
this.indicatorStyle.height = this.indicatorHeight + 'px';
} else {
this.indicatorHeight = this.indicator.clientHeight;
}
this.maxPosY = this.wrapperHeight - this.indicatorHeight;
if ( this.options.shrink == 'clip' ) {
this.minBoundaryY = -this.indicatorHeight + 8;
this.maxBoundaryY = this.wrapperHeight - 8;
} else {
this.minBoundaryY = 0;
this.maxBoundaryY = this.maxPosY;
}
this.maxPosY = this.wrapperHeight - this.indicatorHeight;
this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
}
this.updatePosition();
},
updatePosition: function () {
var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,
y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;
if ( !this.options.ignoreBoundaries ) {
if ( x < this.minBoundaryX ) {
if ( this.options.shrink == 'scale' ) {
this.width = Math.max(this.indicatorWidth + x, 8);
this.indicatorStyle.width = this.width + 'px';
}
x = this.minBoundaryX;
} else if ( x > this.maxBoundaryX ) {
if ( this.options.shrink == 'scale' ) {
this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);
this.indicatorStyle.width = this.width + 'px';
x = this.maxPosX + this.indicatorWidth - this.width;
} else {
x = this.maxBoundaryX;
}
} else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) {
this.width = this.indicatorWidth;
this.indicatorStyle.width = this.width + 'px';
}
if ( y < this.minBoundaryY ) {
if ( this.options.shrink == 'scale' ) {
this.height = Math.max(this.indicatorHeight + y * 3, 8);
this.indicatorStyle.height = this.height + 'px';
}
y = this.minBoundaryY;
} else if ( y > this.maxBoundaryY ) {
if ( this.options.shrink == 'scale' ) {
this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);
this.indicatorStyle.height = this.height + 'px';
y = this.maxPosY + this.indicatorHeight - this.height;
} else {
y = this.maxBoundaryY;
}
} else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) {
this.height = this.indicatorHeight;
this.indicatorStyle.height = this.height + 'px';
}
}
this.x = x;
this.y = y;
if ( this.scroller.options.useTransform ) {
this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;
} else {
this.indicatorStyle.left = x + 'px';
this.indicatorStyle.top = y + 'px';
}
},
_pos: function (x, y) {
if ( x < 0 ) {
x = 0;
} else if ( x > this.maxPosX ) {
x = this.maxPosX;
}
if ( y < 0 ) {
y = 0;
} else if ( y > this.maxPosY ) {
y = this.maxPosY;
}
x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;
y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;
this.scroller.scrollTo(x, y);
},
fade: function (val, hold) {
if ( hold && !this.visible ) {
return;
}
clearTimeout(this.fadeTimeout);
this.fadeTimeout = null;
var time = val ? 250 : 500,
delay = val ? 0 : 300;
val = val ? '1' : '0';
this.wrapperStyle[utils.style.transitionDuration] = time + 'ms';
this.fadeTimeout = setTimeout((function (val) {
this.wrapperStyle.opacity = val;
this.visible = +val;
}).bind(this, val), delay);
}
};
IScroll.utils = utils;
if ( typeof module != 'undefined' && module.exports ) {
module.exports = IScroll;
} else if ( typeof define == 'function' && define.amd ) {
define( function () { return IScroll; } );
} else {
window.IScroll = IScroll;
}
})(window, document, Math);
/*
* array parmeter
* obj 触发的位置后追加内容html
* url 下拉刷新的路径
* @return true 执行成功 false 执行失败
*/
function ajaxSlide(parmeter=Array()){
var obj = parmeter["obj"];
var html = parmeter["html"];
var url = parmeter["url"];
// 获取浏览器的高度
document.body.style.height = Math.max(document.documentElement.clientHeight, window.innerHeight || 0) + 'px';
var pullDown = $("#PullDown");
pullUp = $("#PullUp");
isPullDowned = false; // 上拉动标记
ispullUped = false; // 下拉动标记
var myScroll = new IScroll('#MyScroller', {
probeType: 3,
// 鼠标滚轮事件
mouseWheel: true,
preventDefault: false,
fadeScrollbars: true,
// 点击事件建议用tap代替
});
myScroll.on('scroll', function() {
var height = this.y,
bottomHeight = this.maxScrollY - height;
// 控制下拉显示
if (height >= 60) {
pullDown.show();
isPullDowned = true;
return;
}
else if (height < 60 && height >= 0) {
pullDown.hide();
return;
}
// 控制上拉显示
if (bottomHeight >= 60) {
pullUp.show();
ispullUped = true;
return;
}
else if (bottomHeight < 60 && bottomHeight >= 0) {
pullUp.hide();
return;
}
});
myScroll.on('scrollEnd', function() { // 滚动结束
if (isPullDowned) { // 如果达到触发条件,则执行加载
isPullDowned = false;
url == undefined ? url=undefined:window.location.href=url; //跳转路径
myScroll.refresh();
}
if(ispullUped){
ispullUped = false;
obj == undefined ? obj=undefined:html == undefined ? html=undefined:obj.append(html);//在固定位置追加html
myScroll.refresh();
}
});
return false;
}
logo.php html实例
Pulldown Load
下拉刷新
- Item1
- Item2
- Item3
- Item4
- Item5
- Item6
- Item7
- Item8
- Item9
- Item10
- Item11
- Item12
- Item13
- Item14
- Item15
- Item16
- Item17
- Item18
- Item19
- Item20
- Item1
- Item2
- Item3
- Item4
- Item5
- Item6
- Item7
- Item8
- Item9
- Item10
- Item11
- Item12
- Item13
- Item14
- Item15
- Item16
- Item17
- Item18
- Item19
- Item20
/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */
(function (window, document, Math) {
var rAF = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) { window.setTimeout(callback, 1000 / 60); };
var utils = (function () {
var me = {};
var _elementStyle = document.createElement('div').style;
var _vendor = (function () {
var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
transform,
i = 0,
l = vendors.length;
for ( ; i < l; i++ ) {
transform = vendors[i] + 'ransform';
if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
}
return false;
})();
function _prefixStyle (style) {
if ( _vendor === false ) return false;
if ( _vendor === '' ) return style;
return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
}
me.getTime = Date.now || function getTime () { return new Date().getTime(); };
me.extend = function (target, obj) {
for ( var i in obj ) {
target[i] = obj[i];
}
};
me.addEvent = function (el, type, fn, capture) {
el.addEventListener(type, fn, !!capture);
};
me.removeEvent = function (el, type, fn, capture) {
el.removeEventListener(type, fn, !!capture);
};
me.prefixPointerEvent = function (pointerEvent) {
return window.MSPointerEvent ?
'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8):
pointerEvent;
};
me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
var distance = current - start,
speed = Math.abs(distance) / time,
destination,
duration;
deceleration = deceleration === undefined ? 0.0006 : deceleration;
destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
duration = speed / deceleration;
if ( destination < lowerMargin ) {
destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
distance = Math.abs(destination - current);
duration = distance / speed;
} else if ( destination > 0 ) {
destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
distance = Math.abs(current) + destination;
duration = distance / speed;
}
return {
destination: Math.round(destination),
duration: duration
};
};
var _transform = _prefixStyle('transform');
me.extend(me, {
hasTransform: _transform !== false,
hasPerspective: _prefixStyle('perspective') in _elementStyle,
hasTouch: 'ontouchstart' in window,
hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed
hasTransition: _prefixStyle('transition') in _elementStyle
});
/*
This should find all Android browsers lower than build 535.19 (both stock browser and webview)
- galaxy S2 is ok
- 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1`
- 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
- galaxy S3 is badAndroid (stock brower, webview)
`AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
- galaxy S4 is badAndroid (stock brower, webview)
`AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`
- galaxy S5 is OK
`AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
- galaxy S6 is OK
`AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`
*/
me.isBadAndroid = (function() {
var appVersion = window.navigator.appVersion;
// Android browser is not a chrome browser.
if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) {
var safariVersion = appVersion.match(/Safari\/(\d+.\d)/);
if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) {
return parseFloat(safariVersion[1]) < 535.19;
} else {
return true;
}
} else {
return false;
}
})();
me.extend(me.style = {}, {
transform: _transform,
transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
transitionDuration: _prefixStyle('transitionDuration'),
transitionDelay: _prefixStyle('transitionDelay'),
transformOrigin: _prefixStyle('transformOrigin')
});
me.hasClass = function (e, c) {
var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
return re.test(e.className);
};
me.addClass = function (e, c) {
if ( me.hasClass(e, c) ) {
return;
}
var newclass = e.className.split(' ');
newclass.push(c);
e.className = newclass.join(' ');
};
me.removeClass = function (e, c) {
if ( !me.hasClass(e, c) ) {
return;
}
var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
e.className = e.className.replace(re, ' ');
};
me.offset = function (el) {
var left = -el.offsetLeft,
top = -el.offsetTop;
// jshint -W084
while (el = el.offsetParent) {
left -= el.offsetLeft;
top -= el.offsetTop;
}
// jshint +W084
return {
left: left,
top: top
};
};
me.preventDefaultException = function (el, exceptions) {
for ( var i in exceptions ) {
if ( exceptions[i].test(el[i]) ) {
return true;
}
}
return false;
};
me.extend(me.eventType = {}, {
touchstart: 1,
touchmove: 1,
touchend: 1,
mousedown: 2,
mousemove: 2,
mouseup: 2,
pointerdown: 3,
pointermove: 3,
pointerup: 3,
MSPointerDown: 3,
MSPointerMove: 3,
MSPointerUp: 3
});
me.extend(me.ease = {}, {
quadratic: {
style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
fn: function (k) {
return k * ( 2 - k );
}
},
circular: {
style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1)
fn: function (k) {
return Math.sqrt( 1 - ( --k * k ) );
}
},
back: {
style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
fn: function (k) {
var b = 4;
return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
}
},
bounce: {
style: '',
fn: function (k) {
if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
return 7.5625 * k * k;
} else if ( k < ( 2 / 2.75 ) ) {
return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
} else if ( k < ( 2.5 / 2.75 ) ) {
return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
} else {
return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
}
}
},
elastic: {
style: '',
fn: function (k) {
var f = 0.22,
e = 0.4;
if ( k === 0 ) { return 0; }
if ( k == 1 ) { return 1; }
return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
}
}
});
me.tap = function (e, eventName) {
var ev = document.createEvent('Event');
ev.initEvent(eventName, true, true);
ev.pageX = e.pageX;
ev.pageY = e.pageY;
e.target.dispatchEvent(ev);
};
me.click = function (e) {
var target = e.target,
ev;
if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) {
ev = document.createEvent('MouseEvents');
ev.initMouseEvent('click', true, true, e.view, 1,
target.screenX, target.screenY, target.clientX, target.clientY,
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
0, null);
ev._constructed = true;
target.dispatchEvent(ev);
}
};
return me;
})();
function IScroll (el, options) {
this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;
this.scroller = this.wrapper.children[0];
this.scrollerStyle = this.scroller.style; // cache style for better performance
this.options = {
resizeScrollbars: true,
mouseWheelSpeed: 20,
snapThreshold: 0.334,
// INSERT POINT: OPTIONS
disablePointer : !utils.hasPointer,
disableTouch : utils.hasPointer || !utils.hasTouch,
disableMouse : utils.hasPointer || utils.hasTouch,
startX: 0,
startY: 0,
scrollY: true,
directionLockThreshold: 5,
momentum: true,
bounce: true,
bounceTime: 600,
bounceEasing: '',
preventDefault: true,
preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/ },
HWCompositing: true,
useTransition: true,
useTransform: true,
bindToWrapper: typeof window.onmousedown === "undefined"
};
for ( var i in options ) {
this.options[i] = options[i];
}
// Normalize options
this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';
this.options.useTransition = utils.hasTransition && this.options.useTransition;
this.options.useTransform = utils.hasTransform && this.options.useTransform;
this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;
// If you want eventPassthrough I have to lock one of the axes
this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;
// With eventPassthrough we also need lockDirection mechanism
this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;
this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;
this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;
if ( this.options.tap === true ) {
this.options.tap = 'tap';
}
if ( this.options.shrinkScrollbars == 'scale' ) {
this.options.useTransition = false;
}
this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;
if ( this.options.probeType == 3 ) {
this.options.useTransition = false; }
// INSERT POINT: NORMALIZATION
// Some defaults
this.x = 0;
this.y = 0;
this.directionX = 0;
this.directionY = 0;
this._events = {};
// INSERT POINT: DEFAULTS
this._init();
this.refresh();
this.scrollTo(this.options.startX, this.options.startY);
this.enable();
}
IScroll.prototype = {
version: '5.2.0',
_init: function () {
this._initEvents();
if ( this.options.scrollbars || this.options.indicators ) {
this._initIndicators();
}
if ( this.options.mouseWheel ) {
this._initWheel();
}
if ( this.options.snap ) {
this._initSnap();
}
if ( this.options.keyBindings ) {
this._initKeys();
}
// INSERT POINT: _init
},
destroy: function () {
this._initEvents(true);
clearTimeout(this.resizeTimeout);
this.resizeTimeout = null;
this._execEvent('destroy');
},
_transitionEnd: function (e) {
if ( e.target != this.scroller || !this.isInTransition ) {
return;
}
this._transitionTime();
if ( !this.resetPosition(this.options.bounceTime) ) {
this.isInTransition = false;
this._execEvent('scrollEnd');
}
},
_start: function (e) {
// React to left mouse button only
if ( utils.eventType[e.type] != 1 ) {
// for button property
// http://unixpapa.com/js/mouse.html
var button;
if (!e.which) {
/* IE case */
button = (e.button < 2) ? 0 :
((e.button == 4) ? 1 : 2);
} else {
/* All others */
button = e.button;
}
if ( button !== 0 ) {
return;
}
}
if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
return;
}
if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
e.preventDefault();
}
var point = e.touches ? e.touches[0] : e,
pos;
this.initiated = utils.eventType[e.type];
this.moved = false;
this.distX = 0;
this.distY = 0;
this.directionX = 0;
this.directionY = 0;
this.directionLocked = 0;
this.startTime = utils.getTime();
if ( this.options.useTransition && this.isInTransition ) {
this._transitionTime();
this.isInTransition = false;
pos = this.getComputedPosition();
this._translate(Math.round(pos.x), Math.round(pos.y));
this._execEvent('scrollEnd');
} else if ( !this.options.useTransition && this.isAnimating ) {
this.isAnimating = false;
this._execEvent('scrollEnd');
}
this.startX = this.x;
this.startY = this.y;
this.absStartX = this.x;
this.absStartY = this.y;
this.pointX = point.pageX;
this.pointY = point.pageY;
this._execEvent('beforeScrollStart');
},
_move: function (e) {
if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
return;
}
if ( this.options.preventDefault ) { // increases performance on Android? TODO: check!
e.preventDefault();
}
var point = e.touches ? e.touches[0] : e,
deltaX = point.pageX - this.pointX,
deltaY = point.pageY - this.pointY,
timestamp = utils.getTime(),
newX, newY,
absDistX, absDistY;
this.pointX = point.pageX;
this.pointY = point.pageY;
this.distX += deltaX;
this.distY += deltaY;
absDistX = Math.abs(this.distX);
absDistY = Math.abs(this.distY);
// We need to move at least 10 pixels for the scrolling to initiate
if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
return;
}
// If you are scrolling in one direction lock the other
if ( !this.directionLocked && !this.options.freeScroll ) {
if ( absDistX > absDistY + this.options.directionLockThreshold ) {
this.directionLocked = 'h'; // lock horizontally
} else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
this.directionLocked = 'v'; // lock vertically
} else {
this.directionLocked = 'n'; // no lock
}
}
if ( this.directionLocked == 'h' ) {
if ( this.options.eventPassthrough == 'vertical' ) {
e.preventDefault();
} else if ( this.options.eventPassthrough == 'horizontal' ) {
this.initiated = false;
return;
}
deltaY = 0;
} else if ( this.directionLocked == 'v' ) {
if ( this.options.eventPassthrough == 'horizontal' ) {
e.preventDefault();
} else if ( this.options.eventPassthrough == 'vertical' ) {
this.initiated = false;
return;
}
deltaX = 0;
}
deltaX = this.hasHorizontalScroll ? deltaX : 0;
deltaY = this.hasVerticalScroll ? deltaY : 0;
newX = this.x + deltaX;
newY = this.y + deltaY;
// Slow down if outside of the boundaries
if ( newX > 0 || newX < this.maxScrollX ) {
newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
}
if ( newY > 0 || newY < this.maxScrollY ) {
newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
}
this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
if ( !this.moved ) {
this._execEvent('scrollStart');
}
this.moved = true;
this._translate(newX, newY);
/* REPLACE START: _move */
if ( timestamp - this.startTime > 300 ) {
this.startTime = timestamp;
this.startX = this.x;
this.startY = this.y;
if ( this.options.probeType == 1 ) {
this._execEvent('scroll');
}
}
if ( this.options.probeType > 1 ) {
this._execEvent('scroll');
}
/* REPLACE END: _move */
},
_end: function (e) {
if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
return;
}
if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
e.preventDefault();
}
var point = e.changedTouches ? e.changedTouches[0] : e,
momentumX,
momentumY,
duration = utils.getTime() - this.startTime,
newX = Math.round(this.x),
newY = Math.round(this.y),
distanceX = Math.abs(newX - this.startX),
distanceY = Math.abs(newY - this.startY),
time = 0,
easing = '';
this.isInTransition = 0;
this.initiated = 0;
this.endTime = utils.getTime();
// reset if we are outside of the boundaries
if ( this.resetPosition(this.options.bounceTime) ) {
return;
}
this.scrollTo(newX, newY); // ensures that the last position is rounded
// we scrolled less than 10 pixels
if ( !this.moved ) {
if ( this.options.tap ) {
utils.tap(e, this.options.tap);
}
if ( this.options.click ) {
utils.click(e);
}
this._execEvent('scrollCancel');
return;
}
if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) {
this._execEvent('flick');
return;
}
// start momentum animation if needed
if ( this.options.momentum && duration < 300 ) {
momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration) : { destination: newX, duration: 0 };
momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { destination: newY, duration: 0 };
newX = momentumX.destination;
newY = momentumY.destination;
time = Math.max(momentumX.duration, momentumY.duration);
this.isInTransition = 1;
}
if ( this.options.snap ) {
var snap = this._nearestSnap(newX, newY);
this.currentPage = snap;
time = this.options.snapSpeed || Math.max(
Math.max(
Math.min(Math.abs(newX - snap.x), 1000),
Math.min(Math.abs(newY - snap.y), 1000)
), 300);
newX = snap.x;
newY = snap.y;
this.directionX = 0;
this.directionY = 0;
easing = this.options.bounceEasing;
}
// INSERT POINT: _end
if ( newX != this.x || newY != this.y ) {
// change easing function when scroller goes out of the boundaries
if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {
easing = utils.ease.quadratic;
}
this.scrollTo(newX, newY, time, easing);
return;
}
this._execEvent('scrollEnd');
},
_resize: function () {
var that = this;
clearTimeout(this.resizeTimeout);
this.resizeTimeout = setTimeout(function () {
that.refresh();
}, this.options.resizePolling);
},
resetPosition: function (time) {
var x = this.x,
y = this.y;
time = time || 0;
if ( !this.hasHorizontalScroll || this.x > 0 ) {
x = 0;
} else if ( this.x < this.maxScrollX ) {
x = this.maxScrollX;
}
if ( !this.hasVerticalScroll || this.y > 0 ) {
y = 0;
} else if ( this.y < this.maxScrollY ) {
y = this.maxScrollY;
}
if ( x == this.x && y == this.y ) {
return false;
}
this.scrollTo(x, y, time, this.options.bounceEasing);
return true;
},
disable: function () {
this.enabled = false;
},
enable: function () {
this.enabled = true;
},
refresh: function () {
var rf = this.wrapper.offsetHeight; // Force reflow
this.wrapperWidth = this.wrapper.clientWidth;
this.wrapperHeight = this.wrapper.clientHeight;
/* REPLACE START: refresh */
this.scrollerWidth = this.scroller.offsetWidth;
this.scrollerHeight = this.scroller.offsetHeight;
this.maxScrollX = this.wrapperWidth - this.scrollerWidth;
this.maxScrollY = this.wrapperHeight - this.scrollerHeight;
/* REPLACE END: refresh */
this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0;
this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0;
if ( !this.hasHorizontalScroll ) {
this.maxScrollX = 0;
this.scrollerWidth = this.wrapperWidth;
}
if ( !this.hasVerticalScroll ) {
this.maxScrollY = 0;
this.scrollerHeight = this.wrapperHeight;
}
this.endTime = 0;
this.directionX = 0;
this.directionY = 0;
this.wrapperOffset = utils.offset(this.wrapper);
this._execEvent('refresh');
this.resetPosition();
// INSERT POINT: _refresh
},
on: function (type, fn) {
if ( !this._events[type] ) {
this._events[type] = [];
}
this._events[type].push(fn);
},
off: function (type, fn) {
if ( !this._events[type] ) {
return;
}
var index = this._events[type].indexOf(fn);
if ( index > -1 ) {
this._events[type].splice(index, 1);
}
},
_execEvent: function (type) {
if ( !this._events[type] ) {
return;
}
var i = 0,
l = this._events[type].length;
if ( !l ) {
return;
}
for ( ; i < l; i++ ) {
this._events[type][i].apply(this, [].slice.call(arguments, 1));
}
},
scrollBy: function (x, y, time, easing) {
x = this.x + x;
y = this.y + y;
time = time || 0;
this.scrollTo(x, y, time, easing);
},
scrollTo: function (x, y, time, easing) {
easing = easing || utils.ease.circular;
this.isInTransition = this.options.useTransition && time > 0;
var transitionType = this.options.useTransition && easing.style;
if ( !time || transitionType ) {
if(transitionType) {
this._transitionTimingFunction(easing.style);
this._transitionTime(time);
}
this._translate(x, y);
} else {
this._animate(x, y, time, easing.fn);
}
},
scrollToElement: function (el, time, offsetX, offsetY, easing) {
el = el.nodeType ? el : this.scroller.querySelector(el);
if ( !el ) {
return;
}
var pos = utils.offset(el);
pos.left -= this.wrapperOffset.left;
pos.top -= this.wrapperOffset.top;
// if offsetX/Y are true we center the element to the screen
if ( offsetX === true ) {
offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
}
if ( offsetY === true ) {
offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
}
pos.left -= offsetX || 0;
pos.top -= offsetY || 0;
pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top;
time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time;
this.scrollTo(pos.left, pos.top, time, easing);
},
_transitionTime: function (time) {
time = time || 0;
var durationProp = utils.style.transitionDuration;
this.scrollerStyle[durationProp] = time + 'ms';
if ( !time && utils.isBadAndroid ) {
this.scrollerStyle[durationProp] = '0.0001ms';
// remove 0.0001ms
var self = this;
rAF(function() {
if(self.scrollerStyle[durationProp] === '0.0001ms') {
self.scrollerStyle[durationProp] = '0s';
}
});
}
if ( this.indicators ) {
for ( var i = this.indicators.length; i--; ) {
this.indicators[i].transitionTime(time);
}
}
// INSERT POINT: _transitionTime
},
_transitionTimingFunction: function (easing) {
this.scrollerStyle[utils.style.transitionTimingFunction] = easing;
if ( this.indicators ) {
for ( var i = this.indicators.length; i--; ) {
this.indicators[i].transitionTimingFunction(easing);
}
}
// INSERT POINT: _transitionTimingFunction
},
_translate: function (x, y) {
if ( this.options.useTransform ) {
/* REPLACE START: _translate */
this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
/* REPLACE END: _translate */
} else {
x = Math.round(x);
y = Math.round(y);
this.scrollerStyle.left = x + 'px';
this.scrollerStyle.top = y + 'px';
}
this.x = x;
this.y = y;
if ( this.indicators ) {
for ( var i = this.indicators.length; i--; ) {
this.indicators[i].updatePosition();
}
}
// INSERT POINT: _translate
},
_initEvents: function (remove) {
var eventType = remove ? utils.removeEvent : utils.addEvent,
target = this.options.bindToWrapper ? this.wrapper : window;
eventType(window, 'orientationchange', this);
eventType(window, 'resize', this);
if ( this.options.click ) {
eventType(this.wrapper, 'click', this, true);
}
if ( !this.options.disableMouse ) {
eventType(this.wrapper, 'mousedown', this);
eventType(target, 'mousemove', this);
eventType(target, 'mousecancel', this);
eventType(target, 'mouseup', this);
}
if ( utils.hasPointer && !this.options.disablePointer ) {
eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);
eventType(target, utils.prefixPointerEvent('pointermove'), this);
eventType(target, utils.prefixPointerEvent('pointercancel'), this);
eventType(target, utils.prefixPointerEvent('pointerup'), this);
}
if ( utils.hasTouch && !this.options.disableTouch ) {
eventType(this.wrapper, 'touchstart', this);
eventType(target, 'touchmove', this);
eventType(target, 'touchcancel', this);
eventType(target, 'touchend', this);
}
eventType(this.scroller, 'transitionend', this);
eventType(this.scroller, 'webkitTransitionEnd', this);
eventType(this.scroller, 'oTransitionEnd', this);
eventType(this.scroller, 'MSTransitionEnd', this);
},
getComputedPosition: function () {
var matrix = window.getComputedStyle(this.scroller, null),
x, y;
if ( this.options.useTransform ) {
matrix = matrix[utils.style.transform].split(')')[0].split(', ');
x = +(matrix[12] || matrix[4]);
y = +(matrix[13] || matrix[5]);
} else {
x = +matrix.left.replace(/[^-\d.]/g, '');
y = +matrix.top.replace(/[^-\d.]/g, '');
}
return { x: x, y: y };
},
_initIndicators: function () {
var interactive = this.options.interactiveScrollbars,
customStyle = typeof this.options.scrollbars != 'string',
indicators = [],
indicator;
var that = this;
this.indicators = [];
if ( this.options.scrollbars ) {
// Vertical scrollbar
if ( this.options.scrollY ) {
indicator = {
el: createDefaultScrollbar('v', interactive, this.options.scrollbars),
interactive: interactive,
defaultScrollbars: true,
customStyle: customStyle,
resize: this.options.resizeScrollbars,
shrink: this.options.shrinkScrollbars,
fade: this.options.fadeScrollbars,
listenX: false
};
this.wrapper.appendChild(indicator.el);
indicators.push(indicator);
}
// Horizontal scrollbar
if ( this.options.scrollX ) {
indicator = {
el: createDefaultScrollbar('h', interactive, this.options.scrollbars),
interactive: interactive,
defaultScrollbars: true,
customStyle: customStyle,
resize: this.options.resizeScrollbars,
shrink: this.options.shrinkScrollbars,
fade: this.options.fadeScrollbars,
listenY: false
};
this.wrapper.appendChild(indicator.el);
indicators.push(indicator);
}
}
if ( this.options.indicators ) {
// TODO: check concat compatibility
indicators = indicators.concat(this.options.indicators);
}
for ( var i = indicators.length; i--; ) {
this.indicators.push( new Indicator(this, indicators[i]) );
}
// TODO: check if we can use array.map (wide compatibility and performance issues)
function _indicatorsMap (fn) {
if (that.indicators) {
for ( var i = that.indicators.length; i--; ) {
fn.call(that.indicators[i]);
}
}
}
if ( this.options.fadeScrollbars ) {
this.on('scrollEnd', function () {
_indicatorsMap(function () {
this.fade();
});
});
this.on('scrollCancel', function () {
_indicatorsMap(function () {
this.fade();
});
});
this.on('scrollStart', function () {
_indicatorsMap(function () {
this.fade(1);
});
});
this.on('beforeScrollStart', function () {
_indicatorsMap(function () {
this.fade(1, true);
});
});
}
this.on('refresh', function () {
_indicatorsMap(function () {
this.refresh();
});
});
this.on('destroy', function () {
_indicatorsMap(function () {
this.destroy();
});
delete this.indicators;
});
},
_initWheel: function () {
utils.addEvent(this.wrapper, 'wheel', this);
utils.addEvent(this.wrapper, 'mousewheel', this);
utils.addEvent(this.wrapper, 'DOMMouseScroll', this);
this.on('destroy', function () {
clearTimeout(this.wheelTimeout);
this.wheelTimeout = null;
utils.removeEvent(this.wrapper, 'wheel', this);
utils.removeEvent(this.wrapper, 'mousewheel', this);
utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);
});
},
_wheel: function (e) {
if ( !this.enabled ) {
return;
}
e.preventDefault();
var wheelDeltaX, wheelDeltaY,
newX, newY,
that = this;
if ( this.wheelTimeout === undefined ) {
that._execEvent('scrollStart');
}
// Execute the scrollEnd event after 400ms the wheel stopped scrolling
clearTimeout(this.wheelTimeout);
this.wheelTimeout = setTimeout(function () {
if(!that.options.snap) {
that._execEvent('scrollEnd');
}
that.wheelTimeout = undefined;
}, 400);
if ( 'deltaX' in e ) {
if (e.deltaMode === 1) {
wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed;
wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed;
} else {
wheelDeltaX = -e.deltaX;
wheelDeltaY = -e.deltaY;
}
} else if ( 'wheelDeltaX' in e ) {
wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;
wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;
} else if ( 'wheelDelta' in e ) {
wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;
} else if ( 'detail' in e ) {
wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;
} else {
return;
}
wheelDeltaX *= this.options.invertWheelDirection;
wheelDeltaY *= this.options.invertWheelDirection;
if ( !this.hasVerticalScroll ) {
wheelDeltaX = wheelDeltaY;
wheelDeltaY = 0;
}
if ( this.options.snap ) {
newX = this.currentPage.pageX;
newY = this.currentPage.pageY;
if ( wheelDeltaX > 0 ) {
newX--;
} else if ( wheelDeltaX < 0 ) {
newX++;
}
if ( wheelDeltaY > 0 ) {
newY--;
} else if ( wheelDeltaY < 0 ) {
newY++;
}
this.goToPage(newX, newY);
return;
}
newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);
newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);
this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0;
this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0;
if ( newX > 0 ) {
newX = 0;
} else if ( newX < this.maxScrollX ) {
newX = this.maxScrollX;
}
if ( newY > 0 ) {
newY = 0;
} else if ( newY < this.maxScrollY ) {
newY = this.maxScrollY;
}
this.scrollTo(newX, newY, 0);
if ( this.options.probeType > 1 ) {
this._execEvent('scroll');
}
// INSERT POINT: _wheel
},
_initSnap: function () {
this.currentPage = {};
if ( typeof this.options.snap == 'string' ) {
this.options.snap = this.scroller.querySelectorAll(this.options.snap);
}
this.on('refresh', function () {
var i = 0, l,
m = 0, n,
cx, cy,
x = 0, y,
stepX = this.options.snapStepX || this.wrapperWidth,
stepY = this.options.snapStepY || this.wrapperHeight,
el;
this.pages = [];
if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) {
return;
}
if ( this.options.snap === true ) {
cx = Math.round( stepX / 2 );
cy = Math.round( stepY / 2 );
while ( x > -this.scrollerWidth ) {
this.pages[i] = [];
l = 0;
y = 0;
while ( y > -this.scrollerHeight ) {
this.pages[i][l] = {
x: Math.max(x, this.maxScrollX),
y: Math.max(y, this.maxScrollY),
width: stepX,
height: stepY,
cx: x - cx,
cy: y - cy
};
y -= stepY;
l++;
}
x -= stepX;
i++;
}
} else {
el = this.options.snap;
l = el.length;
n = -1;
for ( ; i < l; i++ ) {
if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) {
m = 0;
n++;
}
if ( !this.pages[m] ) {
this.pages[m] = [];
}
x = Math.max(-el[i].offsetLeft, this.maxScrollX);
y = Math.max(-el[i].offsetTop, this.maxScrollY);
cx = x - Math.round(el[i].offsetWidth / 2);
cy = y - Math.round(el[i].offsetHeight / 2);
this.pages[m][n] = {
x: x,
y: y,
width: el[i].offsetWidth,
height: el[i].offsetHeight,
cx: cx,
cy: cy
};
if ( x > this.maxScrollX ) {
m++;
}
}
}
this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);
// Update snap threshold if needed
if ( this.options.snapThreshold % 1 === 0 ) {
this.snapThresholdX = this.options.snapThreshold;
this.snapThresholdY = this.options.snapThreshold;
} else {
this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);
this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);
}
});
this.on('flick', function () {
var time = this.options.snapSpeed || Math.max(
Math.max(
Math.min(Math.abs(this.x - this.startX), 1000),
Math.min(Math.abs(this.y - this.startY), 1000)
), 300);
this.goToPage(
this.currentPage.pageX + this.directionX,
this.currentPage.pageY + this.directionY,
time
);
});
},
_nearestSnap: function (x, y) {
if ( !this.pages.length ) {
return { x: 0, y: 0, pageX: 0, pageY: 0 };
}
var i = 0,
l = this.pages.length,
m = 0;
// Check if we exceeded the snap threshold
if ( Math.abs(x - this.absStartX) < this.snapThresholdX &&
Math.abs(y - this.absStartY) < this.snapThresholdY ) {
return this.currentPage;
}
if ( x > 0 ) {
x = 0;
} else if ( x < this.maxScrollX ) {
x = this.maxScrollX;
}
if ( y > 0 ) {
y = 0;
} else if ( y < this.maxScrollY ) {
y = this.maxScrollY;
}
for ( ; i < l; i++ ) {
if ( x >= this.pages[i][0].cx ) {
x = this.pages[i][0].x;
break;
}
}
l = this.pages[i].length;
for ( ; m < l; m++ ) {
if ( y >= this.pages[0][m].cy ) {
y = this.pages[0][m].y;
break;
}
}
if ( i == this.currentPage.pageX ) {
i += this.directionX;
if ( i < 0 ) {
i = 0;
} else if ( i >= this.pages.length ) {
i = this.pages.length - 1;
}
x = this.pages[i][0].x;
}
if ( m == this.currentPage.pageY ) {
m += this.directionY;
if ( m < 0 ) {
m = 0;
} else if ( m >= this.pages[0].length ) {
m = this.pages[0].length - 1;
}
y = this.pages[0][m].y;
}
return {
x: x,
y: y,
pageX: i,
pageY: m
};
},
goToPage: function (x, y, time, easing) {
easing = easing || this.options.bounceEasing;
if ( x >= this.pages.length ) {
x = this.pages.length - 1;
} else if ( x < 0 ) {
x = 0;
}
if ( y >= this.pages[x].length ) {
y = this.pages[x].length - 1;
} else if ( y < 0 ) {
y = 0;
}
var posX = this.pages[x][y].x,
posY = this.pages[x][y].y;
time = time === undefined ? this.options.snapSpeed || Math.max(
Math.max(
Math.min(Math.abs(posX - this.x), 1000),
Math.min(Math.abs(posY - this.y), 1000)
), 300) : time;
this.currentPage = {
x: posX,
y: posY,
pageX: x,
pageY: y
};
this.scrollTo(posX, posY, time, easing);
},
next: function (time, easing) {
var x = this.currentPage.pageX,
y = this.currentPage.pageY;
x++;
if ( x >= this.pages.length && this.hasVerticalScroll ) {
x = 0;
y++;
}
this.goToPage(x, y, time, easing);
},
prev: function (time, easing) {
var x = this.currentPage.pageX,
y = this.currentPage.pageY;
x--;
if ( x < 0 && this.hasVerticalScroll ) {
x = 0;
y--;
}
this.goToPage(x, y, time, easing);
},
_initKeys: function (e) {
// default key bindings
var keys = {
pageUp: 33,
pageDown: 34,
end: 35,
home: 36,
left: 37,
up: 38,
right: 39,
down: 40
};
var i;
// if you give me characters I give you keycode
if ( typeof this.options.keyBindings == 'object' ) {
for ( i in this.options.keyBindings ) {
if ( typeof this.options.keyBindings[i] == 'string' ) {
this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCodeAt(0);
}
}
} else {
this.options.keyBindings = {};
}
for ( i in keys ) {
this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];
}
utils.addEvent(window, 'keydown', this);
this.on('destroy', function () {
utils.removeEvent(window, 'keydown', this);
});
},
_key: function (e) {
if ( !this.enabled ) {
return;
}
var snap = this.options.snap, // we are using this alot, better to cache it
newX = snap ? this.currentPage.pageX : this.x,
newY = snap ? this.currentPage.pageY : this.y,
now = utils.getTime(),
prevTime = this.keyTime || 0,
acceleration = 0.250,
pos;
if ( this.options.useTransition && this.isInTransition ) {
pos = this.getComputedPosition();
this._translate(Math.round(pos.x), Math.round(pos.y));
this.isInTransition = false;
}
this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;
switch ( e.keyCode ) {
case this.options.keyBindings.pageUp:
if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
newX += snap ? 1 : this.wrapperWidth;
} else {
newY += snap ? 1 : this.wrapperHeight;
}
break;
case this.options.keyBindings.pageDown:
if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {
newX -= snap ? 1 : this.wrapperWidth;
} else {
newY -= snap ? 1 : this.wrapperHeight;
}
break;
case this.options.keyBindings.end:
newX = snap ? this.pages.length-1 : this.maxScrollX;
newY = snap ? this.pages[0].length-1 : this.maxScrollY;
break;
case this.options.keyBindings.home:
newX = 0;
newY = 0;
break;
case this.options.keyBindings.left:
newX += snap ? -1 : 5 + this.keyAcceleration>>0;
break;
case this.options.keyBindings.up:
newY += snap ? 1 : 5 + this.keyAcceleration>>0;
break;
case this.options.keyBindings.right:
newX -= snap ? -1 : 5 + this.keyAcceleration>>0;
break;
case this.options.keyBindings.down:
newY -= snap ? 1 : 5 + this.keyAcceleration>>0;
break;
default:
return;
}
if ( snap ) {
this.goToPage(newX, newY);
return;
}
if ( newX > 0 ) {
newX = 0;
this.keyAcceleration = 0;
} else if ( newX < this.maxScrollX ) {
newX = this.maxScrollX;
this.keyAcceleration = 0;
}
if ( newY > 0 ) {
newY = 0;
this.keyAcceleration = 0;
} else if ( newY < this.maxScrollY ) {
newY = this.maxScrollY;
this.keyAcceleration = 0;
}
this.scrollTo(newX, newY, 0);
this.keyTime = now;
},
_animate: function (destX, destY, duration, easingFn) {
var that = this,
startX = this.x,
startY = this.y,
startTime = utils.getTime(),
destTime = startTime + duration;
function step () {
var now = utils.getTime(),
newX, newY,
easing;
if ( now >= destTime ) {
that.isAnimating = false;
that._translate(destX, destY);
if ( !that.resetPosition(that.options.bounceTime) ) {
that._execEvent('scrollEnd');
}
return;
}
now = ( now - startTime ) / duration;
easing = easingFn(now);
newX = ( destX - startX ) * easing + startX;
newY = ( destY - startY ) * easing + startY;
that._translate(newX, newY);
if ( that.isAnimating ) {
rAF(step);
}
if ( that.options.probeType == 3 ) {
that._execEvent('scroll');
}
}
this.isAnimating = true;
step();
},
handleEvent: function (e) {
switch ( e.type ) {
case 'touchstart':
case 'pointerdown':
case 'MSPointerDown':
case 'mousedown':
this._start(e);
break;
case 'touchmove':
case 'pointermove':
case 'MSPointerMove':
case 'mousemove':
this._move(e);
break;
case 'touchend':
case 'pointerup':
case 'MSPointerUp':
case 'mouseup':
case 'touchcancel':
case 'pointercancel':
case 'MSPointerCancel':
case 'mousecancel':
this._end(e);
break;
case 'orientationchange':
case 'resize':
this._resize();
break;
case 'transitionend':
case 'webkitTransitionEnd':
case 'oTransitionEnd':
case 'MSTransitionEnd':
this._transitionEnd(e);
break;
case 'wheel':
case 'DOMMouseScroll':
case 'mousewheel':
this._wheel(e);
break;
case 'keydown':
this._key(e);
break;
case 'click':
if ( this.enabled && !e._constructed ) {
e.preventDefault();
e.stopPropagation();
}
break;
}
}
};
function createDefaultScrollbar (direction, interactive, type) {
var scrollbar = document.createElement('div'),
indicator = document.createElement('div');
if ( type === true ) {
scrollbar.style.cssText = 'position:absolute;z-index:9999';
indicator.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px';
}
indicator.className = 'iScrollIndicator';
if ( direction == 'h' ) {
if ( type === true ) {
scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';
indicator.style.height = '100%';
}
scrollbar.className = 'iScrollHorizontalScrollbar';
} else {
if ( type === true ) {
scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';
indicator.style.width = '100%';
}
scrollbar.className = 'iScrollVerticalScrollbar';
}
scrollbar.style.cssText += ';overflow:hidden';
if ( !interactive ) {
scrollbar.style.pointerEvents = 'none';
}
scrollbar.appendChild(indicator);
return scrollbar;
}
function Indicator (scroller, options) {
this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;
this.wrapperStyle = this.wrapper.style;
this.indicator = this.wrapper.children[0];
this.indicatorStyle = this.indicator.style;
this.scroller = scroller;
this.options = {
listenX: true,
listenY: true,
interactive: false,
resize: true,
defaultScrollbars: false,
shrink: false,
fade: false,
speedRatioX: 0,
speedRatioY: 0
};
for ( var i in options ) {
this.options[i] = options[i];
}
this.sizeRatioX = 1;
this.sizeRatioY = 1;
this.maxPosX = 0;
this.maxPosY = 0;
if ( this.options.interactive ) {
if ( !this.options.disableTouch ) {
utils.addEvent(this.indicator, 'touchstart', this);
utils.addEvent(window, 'touchend', this);
}
if ( !this.options.disablePointer ) {
utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this);
}
if ( !this.options.disableMouse ) {
utils.addEvent(this.indicator, 'mousedown', this);
utils.addEvent(window, 'mouseup', this);
}
}
if ( this.options.fade ) {
this.wrapperStyle[utils.style.transform] = this.scroller.translateZ;
var durationProp = utils.style.transitionDuration;
this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms';
// remove 0.0001ms
var self = this;
if(utils.isBadAndroid) {
rAF(function() {
if(self.wrapperStyle[durationProp] === '0.0001ms') {
self.wrapperStyle[durationProp] = '0s';
}
});
}
this.wrapperStyle.opacity = '0';
}
}
Indicator.prototype = {
handleEvent: function (e) {
switch ( e.type ) {
case 'touchstart':
case 'pointerdown':
case 'MSPointerDown':
case 'mousedown':
this._start(e);
break;
case 'touchmove':
case 'pointermove':
case 'MSPointerMove':
case 'mousemove':
this._move(e);
break;
case 'touchend':
case 'pointerup':
case 'MSPointerUp':
case 'mouseup':
case 'touchcancel':
case 'pointercancel':
case 'MSPointerCancel':
case 'mousecancel':
this._end(e);
break;
}
},
destroy: function () {
if ( this.options.fadeScrollbars ) {
clearTimeout(this.fadeTimeout);
this.fadeTimeout = null;
}
if ( this.options.interactive ) {
utils.removeEvent(this.indicator, 'touchstart', this);
utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);
utils.removeEvent(this.indicator, 'mousedown', this);
utils.removeEvent(window, 'touchmove', this);
utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
utils.removeEvent(window, 'mousemove', this);
utils.removeEvent(window, 'touchend', this);
utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this);
utils.removeEvent(window, 'mouseup', this);
}
if ( this.options.defaultScrollbars ) {
this.wrapper.parentNode.removeChild(this.wrapper);
}
},
_start: function (e) {
var point = e.touches ? e.touches[0] : e;
e.preventDefault();
e.stopPropagation();
this.transitionTime();
this.initiated = true;
this.moved = false;
this.lastPointX = point.pageX;
this.lastPointY = point.pageY;
this.startTime = utils.getTime();
if ( !this.options.disableTouch ) {
utils.addEvent(window, 'touchmove', this);
}
if ( !this.options.disablePointer ) {
utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this);
}
if ( !this.options.disableMouse ) {
utils.addEvent(window, 'mousemove', this);
}
this.scroller._execEvent('beforeScrollStart');
},
_move: function (e) {
var point = e.touches ? e.touches[0] : e,
deltaX, deltaY,
newX, newY,
timestamp = utils.getTime();
if ( !this.moved ) {
this.scroller._execEvent('scrollStart');
}
this.moved = true;
deltaX = point.pageX - this.lastPointX;
this.lastPointX = point.pageX;
deltaY = point.pageY - this.lastPointY;
this.lastPointY = point.pageY;
newX = this.x + deltaX;
newY = this.y + deltaY;
this._pos(newX, newY);
if ( this.scroller.options.probeType == 1 && timestamp - this.startTime > 300 ) {
this.startTime = timestamp;
this.scroller._execEvent('scroll');
} else if ( this.scroller.options.probeType > 1 ) {
this.scroller._execEvent('scroll');
}
// INSERT POINT: indicator._move
e.preventDefault();
e.stopPropagation();
},
_end: function (e) {
if ( !this.initiated ) {
return;
}
this.initiated = false;
e.preventDefault();
e.stopPropagation();
utils.removeEvent(window, 'touchmove', this);
utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);
utils.removeEvent(window, 'mousemove', this);
if ( this.scroller.options.snap ) {
var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y);
var time = this.options.snapSpeed || Math.max(
Math.max(
Math.min(Math.abs(this.scroller.x - snap.x), 1000),
Math.min(Math.abs(this.scroller.y - snap.y), 1000)
), 300);
if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) {
this.scroller.directionX = 0;
this.scroller.directionY = 0;
this.scroller.currentPage = snap;
this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing);
}
}
if ( this.moved ) {
this.scroller._execEvent('scrollEnd');
}
},
transitionTime: function (time) {
time = time || 0;
var durationProp = utils.style.transitionDuration;
this.indicatorStyle[durationProp] = time + 'ms';
if ( !time && utils.isBadAndroid ) {
this.indicatorStyle[durationProp] = '0.0001ms';
// remove 0.0001ms
var self = this;
rAF(function() {
if(self.indicatorStyle[durationProp] === '0.0001ms') {
self.indicatorStyle[durationProp] = '0s';
}
});
}
},
transitionTimingFunction: function (easing) {
this.indicatorStyle[utils.style.transitionTimingFunction] = easing;
},
refresh: function () {
this.transitionTime();
if ( this.options.listenX && !this.options.listenY ) {
this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';
} else if ( this.options.listenY && !this.options.listenX ) {
this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';
} else {
this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';
}
if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) {
utils.addClass(this.wrapper, 'iScrollBothScrollbars');
utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');
if ( this.options.defaultScrollbars && this.options.customStyle ) {
if ( this.options.listenX ) {
this.wrapper.style.right = '8px';
} else {
this.wrapper.style.bottom = '8px';
}
}
} else {
utils.removeClass(this.wrapper, 'iScrollBothScrollbars');
utils.addClass(this.wrapper, 'iScrollLoneScrollbar');
if ( this.options.defaultScrollbars && this.options.customStyle ) {
if ( this.options.listenX ) {
this.wrapper.style.right = '2px';
} else {
this.wrapper.style.bottom = '2px';
}
}
}
var r = this.wrapper.offsetHeight; // force refresh
if ( this.options.listenX ) {
this.wrapperWidth = this.wrapper.clientWidth;
if ( this.options.resize ) {
this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);
this.indicatorStyle.width = this.indicatorWidth + 'px';
} else {
this.indicatorWidth = this.indicator.clientWidth;
}
this.maxPosX = this.wrapperWidth - this.indicatorWidth;
if ( this.options.shrink == 'clip' ) {
this.minBoundaryX = -this.indicatorWidth + 8;
this.maxBoundaryX = this.wrapperWidth - 8;
} else {
this.minBoundaryX = 0;
this.maxBoundaryX = this.maxPosX;
}
this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));
}
if ( this.options.listenY ) {
this.wrapperHeight = this.wrapper.clientHeight;
if ( this.options.resize ) {
this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);
this.indicatorStyle.height = this.indicatorHeight + 'px';
} else {
this.indicatorHeight = this.indicator.clientHeight;
}
this.maxPosY = this.wrapperHeight - this.indicatorHeight;
if ( this.options.shrink == 'clip' ) {
this.minBoundaryY = -this.indicatorHeight + 8;
this.maxBoundaryY = this.wrapperHeight - 8;
} else {
this.minBoundaryY = 0;
this.maxBoundaryY = this.maxPosY;
}
this.maxPosY = this.wrapperHeight - this.indicatorHeight;
this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));
}
this.updatePosition();
},
updatePosition: function () {
var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,
y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;
if ( !this.options.ignoreBoundaries ) {
if ( x < this.minBoundaryX ) {
if ( this.options.shrink == 'scale' ) {
this.width = Math.max(this.indicatorWidth + x, 8);
this.indicatorStyle.width = this.width + 'px';
}
x = this.minBoundaryX;
} else if ( x > this.maxBoundaryX ) {
if ( this.options.shrink == 'scale' ) {
this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);
this.indicatorStyle.width = this.width + 'px';
x = this.maxPosX + this.indicatorWidth - this.width;
} else {
x = this.maxBoundaryX;
}
} else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) {
this.width = this.indicatorWidth;
this.indicatorStyle.width = this.width + 'px';
}
if ( y < this.minBoundaryY ) {
if ( this.options.shrink == 'scale' ) {
this.height = Math.max(this.indicatorHeight + y * 3, 8);
this.indicatorStyle.height = this.height + 'px';
}
y = this.minBoundaryY;
} else if ( y > this.maxBoundaryY ) {
if ( this.options.shrink == 'scale' ) {
this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);
this.indicatorStyle.height = this.height + 'px';
y = this.maxPosY + this.indicatorHeight - this.height;
} else {
y = this.maxBoundaryY;
}
} else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) {
this.height = this.indicatorHeight;
this.indicatorStyle.height = this.height + 'px';
}
}
this.x = x;
this.y = y;
if ( this.scroller.options.useTransform ) {
this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;
} else {
this.indicatorStyle.left = x + 'px';
this.indicatorStyle.top = y + 'px';
}
},
_pos: function (x, y) {
if ( x < 0 ) {
x = 0;
} else if ( x > this.maxPosX ) {
x = this.maxPosX;
}
if ( y < 0 ) {
y = 0;
} else if ( y > this.maxPosY ) {
y = this.maxPosY;
}
x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;
y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;
this.scroller.scrollTo(x, y);
},
fade: function (val, hold) {
if ( hold && !this.visible ) {
return;
}
clearTimeout(this.fadeTimeout);
this.fadeTimeout = null;
var time = val ? 250 : 500,
delay = val ? 0 : 300;
val = val ? '1' : '0';
this.wrapperStyle[utils.style.transitionDuration] = time + 'ms';
this.fadeTimeout = setTimeout((function (val) {
this.wrapperStyle.opacity = val;
this.visible = +val;
}).bind(this, val), delay);
}
};
IScroll.utils = utils;
if ( typeof module != 'undefined' && module.exports ) {
module.exports = IScroll;
} else if ( typeof define == 'function' && define.amd ) {
define( function () { return IScroll; } );
} else {
window.IScroll = IScroll;
}
})(window, document, Math);
/*
* array parmeter
* obj 触发的位置后追加内容html
* url 下拉刷新的路径
* @return true 执行成功 false 执行失败
*/
function ajaxSlide(parmeter=Array()){
var obj = parmeter["obj"];
var html = parmeter["html"];
var url = parmeter["url"];
// 获取浏览器的高度
document.body.style.height = Math.max(document.documentElement.clientHeight, window.innerHeight || 0) + 'px';
var pullDown = $("#PullDown");
pullUp = $("#PullUp");
isPullDowned = false; // 上拉动标记
ispullUped = false; // 下拉动标记
var myScroll = new IScroll('#MyScroller', {
probeType: 3,
// 鼠标滚轮事件
mouseWheel: true,
preventDefault: false,
fadeScrollbars: true,
// 点击事件建议用tap代替
click:true,
});
myScroll.on('scroll', function() {
var height = this.y,
bottomHeight = this.maxScrollY - height;
// 控制下拉显示
if (height >= 60) {
pullDown.show();
isPullDowned = true;
return;
}
else if (height < 60 && height >= 0) {
pullDown.hide();
return;
}
// 控制上拉显示
if (bottomHeight >= 60) {
pullUp.show();
ispullUped = true;
return;
}
else if (bottomHeight < 60 && bottomHeight >= 0) {
pullUp.hide();
return;
}
});
myScroll.on('scrollEnd', function() { // 滚动结束
if (isPullDowned) { // 如果达到触发条件,则执行加载
isPullDowned = false;
url == undefined ? url=undefined:window.location.href=url; //跳转路径
myScroll.refresh();
}
if(ispullUped){
ispullUped = false;
obj == undefined ? obj=undefined:html == undefined ? html=undefined:obj.append(html);//在固定位置追加html
myScroll.refresh();
}
});
return false;
}
jquery-1.8.3.js
/*!
* jQuery JavaScript Library v1.8.3
* http://jquery.com/
*
* Includes Sizzle.js
* http://sizzlejs.com/
*
* Copyright 2012 jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
* Date: Tue Nov 13 2012 08:20:33 GMT-0500 (Eastern Standard Time)
*/
(function( window, undefined ) {
var
// A central reference to the root jQuery(document)
rootjQuery,
// The deferred used on DOM ready
readyList,
// Use the correct document accordingly with window argument (sandbox)
document = window.document,
location = window.location,
navigator = window.navigator,
// Map over jQuery in case of overwrite
_jQuery = window.jQuery,
// Map over the $ in case of overwrite
_$ = window.$,
// Save a reference to some core methods
core_push = Array.prototype.push,
core_slice = Array.prototype.slice,
core_indexOf = Array.prototype.indexOf,
core_toString = Object.prototype.toString,
core_hasOwn = Object.prototype.hasOwnProperty,
core_trim = String.prototype.trim,
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
},
// Used for matching numbers
core_pnum = /[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,
// Used for detecting and trimming whitespace
core_rnotwhite = /\S/,
core_rspace = /\s+/,
// Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
// A simple way to check for HTML strings
// Prioritize #id over
to avoid XSS via location.hash (#9521)
rquickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
// Match a standalone tag
rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
// JSON RegExp
rvalidchars = /^[\],:{}\s]*$/,
rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,
// Matches dashed string for camelizing
rmsPrefix = /^-ms-/,
rdashAlpha = /-([\da-z])/gi,
// Used by jQuery.camelCase as callback to replace()
fcamelCase = function( all, letter ) {
return ( letter + "" ).toUpperCase();
},
// The ready event handler and self cleanup method
DOMContentLoaded = function() {
if ( document.addEventListener ) {
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
jQuery.ready();
} else if ( document.readyState === "complete" ) {
// we're here because readyState === "complete" in oldIE
// which is good enough for us to call the dom ready!
document.detachEvent( "onreadystatechange", DOMContentLoaded );
jQuery.ready();
}
},
// [[Class]] -> type pairs
class2type = {};
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function( selector, context, rootjQuery ) {
var match, elem, ret, doc;
// Handle $(""), $(null), $(undefined), $(false)
if ( !selector ) {
return this;
}
// Handle $(DOMElement)
if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
}
// Handle HTML strings
if ( typeof selector === "string" ) {
if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [ null, selector, null ];
} else {
match = rquickExpr.exec( selector );
}
// Match html or make sure no context is specified for #id
if ( match && (match[1] || !context) ) {
// HANDLE: $(html) -> $(array)
if ( match[1] ) {
context = context instanceof jQuery ? context[0] : context;
doc = ( context && context.nodeType ? context.ownerDocument || context : document );
// scripts is true for back-compat
selector = jQuery.parseHTML( match[1], doc, true );
if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
this.attr.call( selector, context, true );
}
return jQuery.merge( this, selector );
// HANDLE: $(#id)
} else {
elem = document.getElementById( match[2] );
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
if ( elem && elem.parentNode ) {
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
}
// Otherwise, we inject the element directly into the jQuery object
this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;
}
// HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
return ( context || rootjQuery ).find( selector );
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return this.constructor( context ).find( selector );
}
// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
if ( selector.selector !== undefined ) {
this.selector = selector.selector;
this.context = selector.context;
}
return jQuery.makeArray( selector, this );
},
// Start with an empty selector
selector: "",
// The current version of jQuery being used
jquery: "1.8.3",
// The default length of a jQuery object is 0
length: 0,
// The number of elements contained in the matched element set
size: function() {
return this.length;
},
toArray: function() {
return core_slice.call( this );
},
// Get the Nth element in the matched element set OR
// Get the whole matched element set as a clean array
get: function( num ) {
return num == null ?
// Return a 'clean' array
this.toArray() :
// Return just the object
( num < 0 ? this[ this.length + num ] : this[ num ] );
},
// Take an array of elements and push it onto the stack
// (returning the new matched element set)
pushStack: function( elems, name, selector ) {
// Build a new jQuery matched element set
var ret = jQuery.merge( this.constructor(), elems );
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
ret.context = this.context;
if ( name === "find" ) {
ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
} else if ( name ) {
ret.selector = this.selector + "." + name + "(" + selector + ")";
}
// Return the newly-formed element set
return ret;
},
// Execute a callback for every element in the matched set.
// (You can seed the arguments with an array of args, but this is
// only used internally.)
each: function( callback, args ) {
return jQuery.each( this, callback, args );
},
ready: function( fn ) {
// Add the callback
jQuery.ready.promise().done( fn );
return this;
},
eq: function( i ) {
i = +i;
return i === -1 ?
this.slice( i ) :
this.slice( i, i + 1 );
},
first: function() {
return this.eq( 0 );
},
last: function() {
return this.eq( -1 );
},
slice: function() {
return this.pushStack( core_slice.apply( this, arguments ),
"slice", core_slice.call(arguments).join(",") );
},
map: function( callback ) {
return this.pushStack( jQuery.map(this, function( elem, i ) {
return callback.call( elem, i, elem );
}));
},
end: function() {
return this.prevObject || this.constructor(null);
},
// For internal use only.
// Behaves like an Array's method, not like a jQuery method.
push: core_push,
sort: [].sort,
splice: [].splice
};
// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// extend jQuery itself if only one argument is passed
if ( length === i ) {
target = this;
--i;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
jQuery.extend({
noConflict: function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
}
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
return jQuery;
},
// Is the DOM ready to be used? Set to true once it occurs.
isReady: false,
// A counter to track how many items to wait for before
// the ready event fires. See #6781
readyWait: 1,
// Hold (or release) the ready event
holdReady: function( hold ) {
if ( hold ) {
jQuery.readyWait++;
} else {
jQuery.ready( true );
}
},
// Handle when the DOM is ready
ready: function( wait ) {
// Abort if there are pending holds or we're already ready
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
return;
}
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( !document.body ) {
return setTimeout( jQuery.ready, 1 );
}
// Remember that the DOM is ready
jQuery.isReady = true;
// If a normal DOM Ready event fired, decrement, and wait if need be
if ( wait !== true && --jQuery.readyWait > 0 ) {
return;
}
// If there are functions bound, to execute
readyList.resolveWith( document, [ jQuery ] );
// Trigger any bound ready events
if ( jQuery.fn.trigger ) {
jQuery( document ).trigger("ready").off("ready");
}
},
// See test/unit/core.js for details concerning isFunction.
// Since version 1.3, DOM methods and functions like alert
// aren't supported. They return false on IE (#2968).
isFunction: function( obj ) {
return jQuery.type(obj) === "function";
},
isArray: Array.isArray || function( obj ) {
return jQuery.type(obj) === "array";
},
isWindow: function( obj ) {
return obj != null && obj == obj.window;
},
isNumeric: function( obj ) {
return !isNaN( parseFloat(obj) ) && isFinite( obj );
},
type: function( obj ) {
return obj == null ?
String( obj ) :
class2type[ core_toString.call(obj) ] || "object";
},
isPlainObject: function( obj ) {
// Must be an Object.
// Because of IE, we also have to check the presence of the constructor property.
// Make sure that DOM nodes and window objects don't pass through, as well
if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
return false;
}
try {
// Not own constructor property must be Object
if ( obj.constructor &&
!core_hasOwn.call(obj, "constructor") &&
!core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
return false;
}
} catch ( e ) {
// IE8,9 Will throw exceptions on certain host objects #9897
return false;
}
// Own properties are enumerated firstly, so to speed up,
// if last one is own, then all properties are own.
var key;
for ( key in obj ) {}
return key === undefined || core_hasOwn.call( obj, key );
},
isEmptyObject: function( obj ) {
var name;
for ( name in obj ) {
return false;
}
return true;
},
error: function( msg ) {
throw new Error( msg );
},
// data: string of html
// context (optional): If specified, the fragment will be created in this context, defaults to document
// scripts (optional): If true, will include scripts passed in the html string
parseHTML: function( data, context, scripts ) {
var parsed;
if ( !data || typeof data !== "string" ) {
return null;
}
if ( typeof context === "boolean" ) {
scripts = context;
context = 0;
}
context = context || document;
// Single tag
if ( (parsed = rsingleTag.exec( data )) ) {
return [ context.createElement( parsed[1] ) ];
}
parsed = jQuery.buildFragment( [ data ], context, scripts ? null : [] );
return jQuery.merge( [],
(parsed.cacheable ? jQuery.clone( parsed.fragment ) : parsed.fragment).childNodes );
},
parseJSON: function( data ) {
if ( !data || typeof data !== "string") {
return null;
}
// Make sure leading/trailing whitespace is removed (IE can't handle it)
data = jQuery.trim( data );
// Attempt to parse using the native JSON parser first
if ( window.JSON && window.JSON.parse ) {
return window.JSON.parse( data );
}
// Make sure the incoming data is actual JSON
// Logic borrowed from http://json.org/json2.js
if ( rvalidchars.test( data.replace( rvalidescape, "@" )
.replace( rvalidtokens, "]" )
.replace( rvalidbraces, "")) ) {
return ( new Function( "return " + data ) )();
}
jQuery.error( "Invalid JSON: " + data );
},
// Cross-browser xml parsing
parseXML: function( data ) {
var xml, tmp;
if ( !data || typeof data !== "string" ) {
return null;
}
try {
if ( window.DOMParser ) { // Standard
tmp = new DOMParser();
xml = tmp.parseFromString( data , "text/xml" );
} else { // IE
xml = new ActiveXObject( "Microsoft.XMLDOM" );
xml.async = "false";
xml.loadXML( data );
}
} catch( e ) {
xml = undefined;
}
if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
jQuery.error( "Invalid XML: " + data );
}
return xml;
},
noop: function() {},
// Evaluates a script in a global context
// Workarounds based on findings by Jim Driscoll
// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
globalEval: function( data ) {
if ( data && core_rnotwhite.test( data ) ) {
// We use execScript on Internet Explorer
// We use an anonymous function so that context is window
// rather than jQuery in Firefox
( window.execScript || function( data ) {
window[ "eval" ].call( window, data );
} )( data );
}
},
// Convert dashed to camelCase; used by the css and data modules
// Microsoft forgot to hump their vendor prefix (#9572)
camelCase: function( string ) {
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
},
nodeName: function( elem, name ) {
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
},
// args is for internal usage only
each: function( obj, callback, args ) {
var name,
i = 0,
length = obj.length,
isObj = length === undefined || jQuery.isFunction( obj );
if ( args ) {
if ( isObj ) {
for ( name in obj ) {
if ( callback.apply( obj[ name ], args ) === false ) {
break;
}
}
} else {
for ( ; i < length; ) {
if ( callback.apply( obj[ i++ ], args ) === false ) {
break;
}
}
}
// A special, fast, case for the most common use of each
} else {
if ( isObj ) {
for ( name in obj ) {
if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) {
break;
}
}
} else {
for ( ; i < length; ) {
if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) {
break;
}
}
}
}
return obj;
},
// Use native String.trim function wherever possible
trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
function( text ) {
return text == null ?
"" :
core_trim.call( text );
} :
// Otherwise use our own trimming functionality
function( text ) {
return text == null ?
"" :
( text + "" ).replace( rtrim, "" );
},
// results is for internal usage only
makeArray: function( arr, results ) {
var type,
ret = results || [];
if ( arr != null ) {
// The window, strings (and functions) also have 'length'
// Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
type = jQuery.type( arr );
if ( arr.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( arr ) ) {
core_push.call( ret, arr );
} else {
jQuery.merge( ret, arr );
}
}
return ret;
},
inArray: function( elem, arr, i ) {
var len;
if ( arr ) {
if ( core_indexOf ) {
return core_indexOf.call( arr, elem, i );
}
len = arr.length;
i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
for ( ; i < len; i++ ) {
// Skip accessing in sparse arrays
if ( i in arr && arr[ i ] === elem ) {
return i;
}
}
}
return -1;
},
merge: function( first, second ) {
var l = second.length,
i = first.length,
j = 0;
if ( typeof l === "number" ) {
for ( ; j < l; j++ ) {
first[ i++ ] = second[ j ];
}
} else {
while ( second[j] !== undefined ) {
first[ i++ ] = second[ j++ ];
}
}
first.length = i;
return first;
},
grep: function( elems, callback, inv ) {
var retVal,
ret = [],
i = 0,
length = elems.length;
inv = !!inv;
// Go through the array, only saving the items
// that pass the validator function
for ( ; i < length; i++ ) {
retVal = !!callback( elems[ i ], i );
if ( inv !== retVal ) {
ret.push( elems[ i ] );
}
}
return ret;
},
// arg is for internal usage only
map: function( elems, callback, arg ) {
var value, key,
ret = [],
i = 0,
length = elems.length,
// jquery objects are treated as arrays
isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
// Go through the array, translating each of the items to their
if ( isArray ) {
for ( ; i < length; i++ ) {
value = callback( elems[ i ], i, arg );
if ( value != null ) {
ret[ ret.length ] = value;
}
}
// Go through every key on the object,
} else {
for ( key in elems ) {
value = callback( elems[ key ], key, arg );
if ( value != null ) {
ret[ ret.length ] = value;
}
}
}
// Flatten any nested arrays
return ret.concat.apply( [], ret );
},
// A global GUID counter for objects
guid: 1,
// Bind a function to a context, optionally partially applying any
// arguments.
proxy: function( fn, context ) {
var tmp, args, proxy;
if ( typeof context === "string" ) {
tmp = fn[ context ];
context = fn;
fn = tmp;
}
// Quick check to determine if target is callable, in the spec
// this throws a TypeError, but we will just return undefined.
if ( !jQuery.isFunction( fn ) ) {
return undefined;
}
// Simulated bind
args = core_slice.call( arguments, 2 );
proxy = function() {
return fn.apply( context, args.concat( core_slice.call( arguments ) ) );
};
// Set the guid of unique handler to the same of original handler, so it can be removed
proxy.guid = fn.guid = fn.guid || jQuery.guid++;
return proxy;
},
// Multifunctional method to get and set values of a collection
// The value/s can optionally be executed if it's a function
access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
var exec,
bulk = key == null,
i = 0,
length = elems.length;
// Sets many values
if ( key && typeof key === "object" ) {
for ( i in key ) {
jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
}
chainable = 1;
// Sets one value
} else if ( value !== undefined ) {
// Optionally, function values get executed if exec is true
exec = pass === undefined && jQuery.isFunction( value );
if ( bulk ) {
// Bulk operations only iterate when executing function values
if ( exec ) {
exec = fn;
fn = function( elem, key, value ) {
return exec.call( jQuery( elem ), value );
};
// Otherwise they run against the entire set
} else {
fn.call( elems, value );
fn = null;
}
}
if ( fn ) {
for (; i < length; i++ ) {
fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
}
}
chainable = 1;
}
return chainable ?
elems :
// Gets
bulk ?
fn.call( elems ) :
length ? fn( elems[0], key ) : emptyGet;
},
now: function() {
return ( new Date() ).getTime();
}
});
jQuery.ready.promise = function( obj ) {
if ( !readyList ) {
readyList = jQuery.Deferred();
// Catch cases where $(document).ready() is called after the browser event has already occurred.
// we once tried to use readyState "interactive" here, but it caused issues like the one
// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
if ( document.readyState === "complete" ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
setTimeout( jQuery.ready, 1 );
// Standards-based browsers support DOMContentLoaded
} else if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
window.addEventListener( "load", jQuery.ready, false );
// If IE event model is used
} else {
// Ensure firing before onload, maybe late but safe also for iframes
document.attachEvent( "onreadystatechange", DOMContentLoaded );
// A fallback to window.onload, that will always work
window.attachEvent( "onload", jQuery.ready );
// If IE and not a frame
// continually check to see if the document is ready
var top = false;
try {
top = window.frameElement == null && document.documentElement;
} catch(e) {}
if ( top && top.doScroll ) {
(function doScrollCheck() {
if ( !jQuery.isReady ) {
try {
// Use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
top.doScroll("left");
} catch(e) {
return setTimeout( doScrollCheck, 50 );
}
// and execute any waiting functions
jQuery.ready();
}
})();
}
}
}
return readyList.promise( obj );
};
// Populate the class2type map
jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
});
// All jQuery objects should point back to these
rootjQuery = jQuery(document);
// String to Object options format cache
var optionsCache = {};
// Convert String-formatted options into Object-formatted ones and store in cache
function createOptions( options ) {
var object = optionsCache[ options ] = {};
jQuery.each( options.split( core_rspace ), function( _, flag ) {
object[ flag ] = true;
});
return object;
}
/*
* Create a callback list using the following parameters:
*
* options: an optional list of space-separated options that will change how
* the callback list behaves or a more traditional option object
*
* By default a callback list will act like an event callback list and can be
* "fired" multiple times.
*
* Possible options:
*
* once: will ensure the callback list can only be fired once (like a Deferred)
*
* memory: will keep track of previous values and will call any callback added
* after the list has been fired right away with the latest "memorized"
* values (like a Deferred)
*
* unique: will ensure a callback can only be added once (no duplicate in the list)
*
* stopOnFalse: interrupt callings when a callback returns false
*
*/
jQuery.Callbacks = function( options ) {
// Convert options from String-formatted to Object-formatted if needed
// (we check in cache first)
options = typeof options === "string" ?
( optionsCache[ options ] || createOptions( options ) ) :
jQuery.extend( {}, options );
var // Last fire value (for non-forgettable lists)
memory,
// Flag to know if list was already fired
fired,
// Flag to know if list is currently firing
firing,
// First callback to fire (used internally by add and fireWith)
firingStart,
// End of the loop when firing
firingLength,
// Index of currently firing callback (modified by remove if needed)
firingIndex,
// Actual callback list
list = [],
// Stack of fire calls for repeatable lists
stack = !options.once && [],
// Fire callbacks
fire = function( data ) {
memory = options.memory && data;
fired = true;
firingIndex = firingStart || 0;
firingStart = 0;
firingLength = list.length;
firing = true;
for ( ; list && firingIndex < firingLength; firingIndex++ ) {
if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
memory = false; // To prevent further calls using add
break;
}
}
firing = false;
if ( list ) {
if ( stack ) {
if ( stack.length ) {
fire( stack.shift() );
}
} else if ( memory ) {
list = [];
} else {
self.disable();
}
}
},
// Actual Callbacks object
self = {
// Add a callback or a collection of callbacks to the list
add: function() {
if ( list ) {
// First, we save the current length
var start = list.length;
(function add( args ) {
jQuery.each( args, function( _, arg ) {
var type = jQuery.type( arg );
if ( type === "function" ) {
if ( !options.unique || !self.has( arg ) ) {
list.push( arg );
}
} else if ( arg && arg.length && type !== "string" ) {
// Inspect recursively
add( arg );
}
});
})( arguments );
// Do we need to add the callbacks to the
// current firing batch?
if ( firing ) {
firingLength = list.length;
// With memory, if we're not firing then
// we should call right away
} else if ( memory ) {
firingStart = start;
fire( memory );
}
}
return this;
},
// Remove a callback from the list
remove: function() {
if ( list ) {
jQuery.each( arguments, function( _, arg ) {
var index;
while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
list.splice( index, 1 );
// Handle firing indexes
if ( firing ) {
if ( index <= firingLength ) {
firingLength--;
}
if ( index <= firingIndex ) {
firingIndex--;
}
}
}
});
}
return this;
},
// Control if a given callback is in the list
has: function( fn ) {
return jQuery.inArray( fn, list ) > -1;
},
// Remove all callbacks from the list
empty: function() {
list = [];
return this;
},
// Have the list do nothing anymore
disable: function() {
list = stack = memory = undefined;
return this;
},
// Is it disabled?
disabled: function() {
return !list;
},
// Lock the list in its current state
lock: function() {
stack = undefined;
if ( !memory ) {
self.disable();
}
return this;
},
// Is it locked?
locked: function() {
return !stack;
},
// Call all callbacks with the given context and arguments
fireWith: function( context, args ) {
args = args || [];
args = [ context, args.slice ? args.slice() : args ];
if ( list && ( !fired || stack ) ) {
if ( firing ) {
stack.push( args );
} else {
fire( args );
}
}
return this;
},
// Call all the callbacks with the given arguments
fire: function() {
self.fireWith( this, arguments );
return this;
},
// To know if the callbacks have already been called at least once
fired: function() {
return !!fired;
}
};
return self;
};
jQuery.extend({
Deferred: function( func ) {
var tuples = [
// action, add listener, listener list, final state
[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
[ "notify", "progress", jQuery.Callbacks("memory") ]
],
state = "pending",
promise = {
state: function() {
return state;
},
always: function() {
deferred.done( arguments ).fail( arguments );
return this;
},
then: function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
return jQuery.Deferred(function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
var action = tuple[ 0 ],
fn = fns[ i ];
// deferred[ done | fail | progress ] for forwarding actions to newDefer
deferred[ tuple[1] ]( jQuery.isFunction( fn ) ?
function() {
var returned = fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise()
.done( newDefer.resolve )
.fail( newDefer.reject )
.progress( newDefer.notify );
} else {
newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
}
} :
newDefer[ action ]
);
});
fns = null;
}).promise();
},
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function( obj ) {
return obj != null ? jQuery.extend( obj, promise ) : promise;
}
},
deferred = {};
// Keep pipe for back-compat
promise.pipe = promise.then;
// Add list-specific methods
jQuery.each( tuples, function( i, tuple ) {
var list = tuple[ 2 ],
stateString = tuple[ 3 ];
// promise[ done | fail | progress ] = list.add
promise[ tuple[1] ] = list.add;
// Handle state
if ( stateString ) {
list.add(function() {
// state = [ resolved | rejected ]
state = stateString;
// [ reject_list | resolve_list ].disable; progress_list.lock
}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
}
// deferred[ resolve | reject | notify ] = list.fire
deferred[ tuple[0] ] = list.fire;
deferred[ tuple[0] + "With" ] = list.fireWith;
});
// Make the deferred a promise
promise.promise( deferred );
// Call given func if any
if ( func ) {
func.call( deferred, deferred );
}
// All done!
return deferred;
},
// Deferred helper
when: function( subordinate /* , ..., subordinateN */ ) {
var i = 0,
resolveValues = core_slice.call( arguments ),
length = resolveValues.length,
// the count of uncompleted subordinates
remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
// Update function for both resolve and progress values
updateFunc = function( i, contexts, values ) {
return function( value ) {
contexts[ i ] = this;
values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
if( values === progressValues ) {
deferred.notifyWith( contexts, values );
} else if ( !( --remaining ) ) {
deferred.resolveWith( contexts, values );
}
};
},
progressValues, progressContexts, resolveContexts;
// add listeners to Deferred subordinates; treat others as resolved
if ( length > 1 ) {
progressValues = new Array( length );
progressContexts = new Array( length );
resolveContexts = new Array( length );
for ( ; i < length; i++ ) {
if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
resolveValues[ i ].promise()
.done( updateFunc( i, resolveContexts, resolveValues ) )
.fail( deferred.reject )
.progress( updateFunc( i, progressContexts, progressValues ) );
} else {
--remaining;
}
}
}
// if we're not waiting on anything, resolve the master
if ( !remaining ) {
deferred.resolveWith( resolveContexts, resolveValues );
}
return deferred.promise();
}
});
jQuery.support = (function() {
var support,
all,
a,
select,
opt,
input,
fragment,
eventName,
i,
isSupported,
clickFn,
div = document.createElement("div");
// Setup
div.setAttribute( "className", "t" );
div.innerHTML = "
a
";
// Support tests won't run in some limited or non-browser environments
all = div.getElementsByTagName("*");
a = div.getElementsByTagName("a")[ 0 ];
if ( !all || !a || !all.length ) {
return {};
}
// First batch of tests
select = document.createElement("select");
opt = select.appendChild( document.createElement("option") );
input = div.getElementsByTagName("input")[ 0 ];
a.style.cssText = "top:1px;float:left;opacity:.5";
support = {
// IE strips leading whitespace when .innerHTML is used
leadingWhitespace: ( div.firstChild.nodeType === 3 ),
// Make sure that tbody elements aren't automatically inserted
// IE will insert them into empty tables
tbody: !div.getElementsByTagName("tbody").length,
// Make sure that link elements get serialized correctly by innerHTML
// This requires a wrapper element in IE
htmlSerialize: !!div.getElementsByTagName("link").length,
// Get the style information from getAttribute
// (IE uses .cssText instead)
style: /top/.test( a.getAttribute("style") ),
// Make sure that URLs aren't manipulated
// (IE normalizes it by default)
hrefNormalized: ( a.getAttribute("href") === "/a" ),
// Make sure that element opacity exists
// (IE uses filter instead)
// Use a regex to work around a WebKit issue. See #5145
opacity: /^0.5/.test( a.style.opacity ),
// Verify style float existence
// (IE uses styleFloat instead of cssFloat)
cssFloat: !!a.style.cssFloat,
// Make sure that if no value is specified for a checkbox
// that it defaults to "on".
// (WebKit defaults to "" instead)
checkOn: ( input.value === "on" ),
// Make sure that a selected-by-default option has a working selected property.
// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
optSelected: opt.selected,
// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
getSetAttribute: div.className !== "t",
// Tests for enctype support on a form (#6743)
enctype: !!document.createElement("form").enctype,
// Makes sure cloning an html5 element does not cause problems
// Where outerHTML is undefined, this still works
html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>
",
// jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
boxModel: ( document.compatMode === "CSS1Compat" ),
// Will be defined later
submitBubbles: true,
changeBubbles: true,
focusinBubbles: false,
deleteExpando: true,
noCloneEvent: true,
inlineBlockNeedsLayout: false,
shrinkWrapBlocks: false,
reliableMarginRight: true,
boxSizingReliable: true,
pixelPosition: false
};
// Make sure checked status is properly cloned
input.checked = true;
support.noCloneChecked = input.cloneNode( true ).checked;
// Make sure that the options inside disabled selects aren't marked as disabled
// (WebKit marks them as disabled)
select.disabled = true;
support.optDisabled = !opt.disabled;
// Test to see if it's possible to delete an expando from an element
// Fails in Internet Explorer
try {
delete div.test;
} catch( e ) {
support.deleteExpando = false;
}
if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
div.attachEvent( "onclick", clickFn = function() {
// Cloning a node shouldn't copy over any
// bound event handlers (IE does this)
support.noCloneEvent = false;
});
div.cloneNode( true ).fireEvent("onclick");
div.detachEvent( "onclick", clickFn );
}
// Check if a radio maintains its value
// after being appended to the DOM
input = document.createElement("input");
input.value = "t";
input.setAttribute( "type", "radio" );
support.radioValue = input.value === "t";
input.setAttribute( "checked", "checked" );
// #11217 - WebKit loses check when the name is after the checked attribute
input.setAttribute( "name", "t" );
div.appendChild( input );
fragment = document.createDocumentFragment();
fragment.appendChild( div.lastChild );
// WebKit doesn't clone checked state correctly in fragments
support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
// Check if a disconnected checkbox will retain its checked
// value of true after appended to the DOM (IE6/7)
support.appendChecked = input.checked;
fragment.removeChild( input );
fragment.appendChild( div );
// Technique from Juriy Zaytsev
// http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
// We only care about the case where non-standard event systems
// are used, namely in IE. Short-circuiting here helps us to
// avoid an eval call (in setAttribute) which can cause CSP
// to go haywire. See: https://developer.mozilla.org/en/Security/CSP
if ( div.attachEvent ) {
for ( i in {
submit: true,
change: true,
focusin: true
}) {
eventName = "on" + i;
isSupported = ( eventName in div );
if ( !isSupported ) {
div.setAttribute( eventName, "return;" );
isSupported = ( typeof div[ eventName ] === "function" );
}
support[ i + "Bubbles" ] = isSupported;
}
}
// Run tests that need a body at doc ready
jQuery(function() {
var container, div, tds, marginDiv,
divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;",
body = document.getElementsByTagName("body")[0];
if ( !body ) {
// Return for frameset docs that don't have a body
return;
}
container = document.createElement("div");
container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px";
body.insertBefore( container, body.firstChild );
// Construct the test element
div = document.createElement("div");
container.appendChild( div );
// Check if table cells still have offsetWidth/Height when they are set
// to display:none and there are still other visible table cells in a
// table row; if so, offsetWidth/Height are not reliable for use when
// determining if an element has been hidden directly using
// display:none (it is still safe to use offsets if a parent element is
// hidden; don safety goggles and see bug #4512 for more information).
// (only IE 8 fails this test)
div.innerHTML = "
t
";
tds = div.getElementsByTagName("td");
tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
isSupported = ( tds[ 0 ].offsetHeight === 0 );
tds[ 0 ].style.display = "";
tds[ 1 ].style.display = "none";
// Check if empty table cells still have offsetWidth/Height
// (IE <= 8 fail this test)
support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
// Check box-sizing and margin behavior
div.innerHTML = "";
div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
support.boxSizing = ( div.offsetWidth === 4 );
support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
// NOTE: To any future maintainer, we've window.getComputedStyle
// because jsdom on node.js will break without it.
if ( window.getComputedStyle ) {
support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
// Check if div with explicit width and no margin-right incorrectly
// gets computed margin-right based on width of container. For more
// info see bug #3333
// Fails in WebKit before Feb 2011 nightlies
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
marginDiv = document.createElement("div");
marginDiv.style.cssText = div.style.cssText = divReset;
marginDiv.style.marginRight = marginDiv.style.width = "0";
div.style.width = "1px";
div.appendChild( marginDiv );
support.reliableMarginRight =
!parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
}
if ( typeof div.style.zoom !== "undefined" ) {
// Check if natively block-level elements act like inline-block
// elements when setting their display to 'inline' and giving
// them layout
// (IE < 8 does this)
div.innerHTML = "";
div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
// Check if elements with layout shrink-wrap their children
// (IE 6 does this)
div.style.display = "block";
div.style.overflow = "visible";
div.innerHTML = "";
div.firstChild.style.width = "5px";
support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
container.style.zoom = 1;
}
// Null elements to avoid leaks in IE
body.removeChild( container );
container = div = tds = marginDiv = null;
});
// Null elements to avoid leaks in IE
fragment.removeChild( div );
all = a = select = opt = input = fragment = div = null;
return support;
})();
var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
rmultiDash = /([A-Z])/g;
jQuery.extend({
cache: {},
deletedIds: [],
// Remove at next major release (1.9/2.0)
uuid: 0,
// Unique for each copy of jQuery on the page
// Non-digits removed to match rinlinejQuery
expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
// The following elements throw uncatchable exceptions if you
// attempt to add expando properties to them.
noData: {
"embed": true,
// Ban all objects except for Flash (which handle expandos)
"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
"applet": true
},
hasData: function( elem ) {
elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
return !!elem && !isEmptyDataObject( elem );
},
data: function( elem, name, data, pvt /* Internal Use Only */ ) {
if ( !jQuery.acceptData( elem ) ) {
return;
}
var thisCache, ret,
internalKey = jQuery.expando,
getByName = typeof name === "string",
// We have to handle DOM nodes and JS objects differently because IE6-7
// can't GC object references properly across the DOM-JS boundary
isNode = elem.nodeType,
// Only DOM nodes need the global jQuery cache; JS object data is
// attached directly to the object so GC can occur automatically
cache = isNode ? jQuery.cache : elem,
// Only defining an ID for JS objects if its cache already exists allows
// the code to shortcut on the same path as a DOM node with no cache
id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
// Avoid doing any more work than we need to when trying to get data on an
// object that has no data at all
if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
return;
}
if ( !id ) {
// Only DOM nodes need a new unique ID for each element since their data
// ends up in the global cache
if ( isNode ) {
elem[ internalKey ] = id = jQuery.deletedIds.pop() || jQuery.guid++;
} else {
id = internalKey;
}
}
if ( !cache[ id ] ) {
cache[ id ] = {};
// Avoids exposing jQuery metadata on plain JS objects when the object
// is serialized using JSON.stringify
if ( !isNode ) {
cache[ id ].toJSON = jQuery.noop;
}
}
// An object can be passed to jQuery.data instead of a key/value pair; this gets
// shallow copied over onto the existing cache
if ( typeof name === "object" || typeof name === "function" ) {
if ( pvt ) {
cache[ id ] = jQuery.extend( cache[ id ], name );
} else {
cache[ id ].data = jQuery.extend( cache[ id ].data, name );
}
}
thisCache = cache[ id ];
// jQuery data() is stored in a separate object inside the object's internal data
// cache in order to avoid key collisions between internal data and user-defined
// data.
if ( !pvt ) {
if ( !thisCache.data ) {
thisCache.data = {};
}
thisCache = thisCache.data;
}
if ( data !== undefined ) {
thisCache[ jQuery.camelCase( name ) ] = data;
}
// Check for both converted-to-camel and non-converted data property names
// If a data property was specified
if ( getByName ) {
// First Try to find as-is property data
ret = thisCache[ name ];
// Test for null|undefined property data
if ( ret == null ) {
// Try to find the camelCased property
ret = thisCache[ jQuery.camelCase( name ) ];
}
} else {
ret = thisCache;
}
return ret;
},
removeData: function( elem, name, pvt /* Internal Use Only */ ) {
if ( !jQuery.acceptData( elem ) ) {
return;
}
var thisCache, i, l,
isNode = elem.nodeType,
// See jQuery.data for more information
cache = isNode ? jQuery.cache : elem,
id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
// If there is already no cache entry for this object, there is no
// purpose in continuing
if ( !cache[ id ] ) {
return;
}
if ( name ) {
thisCache = pvt ? cache[ id ] : cache[ id ].data;
if ( thisCache ) {
// Support array or space separated string names for data keys
if ( !jQuery.isArray( name ) ) {
// try the string as a key before any manipulation
if ( name in thisCache ) {
name = [ name ];
} else {
// split the camel cased version by spaces unless a key with the spaces exists
name = jQuery.camelCase( name );
if ( name in thisCache ) {
name = [ name ];
} else {
name = name.split(" ");
}
}
}
for ( i = 0, l = name.length; i < l; i++ ) {
delete thisCache[ name[i] ];
}
// If there is no data left in the cache, we want to continue
// and let the cache object itself get destroyed
if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
return;
}
}
}
// See jQuery.data for more information
if ( !pvt ) {
delete cache[ id ].data;
// Don't destroy the parent cache unless the internal data object
// had been the only thing left in it
if ( !isEmptyDataObject( cache[ id ] ) ) {
return;
}
}
// Destroy the cache
if ( isNode ) {
jQuery.cleanData( [ elem ], true );
// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
} else if ( jQuery.support.deleteExpando || cache != cache.window ) {
delete cache[ id ];
// When all else fails, null
} else {
cache[ id ] = null;
}
},
// For internal use only.
_data: function( elem, name, data ) {
return jQuery.data( elem, name, data, true );
},
// A method for determining if a DOM node can handle the data expando
acceptData: function( elem ) {
var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
// nodes accept data unless otherwise specified; rejection can be conditional
return !noData || noData !== true && elem.getAttribute("classid") === noData;
}
});
jQuery.fn.extend({
data: function( key, value ) {
var parts, part, attr, name, l,
elem = this[0],
i = 0,
data = null;
// Gets all values
if ( key === undefined ) {
if ( this.length ) {
data = jQuery.data( elem );
if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
attr = elem.attributes;
for ( l = attr.length; i < l; i++ ) {
name = attr[i].name;
if ( !name.indexOf( "data-" ) ) {
name = jQuery.camelCase( name.substring(5) );
dataAttr( elem, name, data[ name ] );
}
}
jQuery._data( elem, "parsedAttrs", true );
}
}
return data;
}
// Sets multiple values
if ( typeof key === "object" ) {
return this.each(function() {
jQuery.data( this, key );
});
}
parts = key.split( ".", 2 );
parts[1] = parts[1] ? "." + parts[1] : "";
part = parts[1] + "!";
return jQuery.access( this, function( value ) {
if ( value === undefined ) {
data = this.triggerHandler( "getData" + part, [ parts[0] ] );
// Try to fetch any internally stored data first
if ( data === undefined && elem ) {
data = jQuery.data( elem, key );
data = dataAttr( elem, key, data );
}
return data === undefined && parts[1] ?
this.data( parts[0] ) :
data;
}
parts[1] = value;
this.each(function() {
var self = jQuery( this );
self.triggerHandler( "setData" + part, parts );
jQuery.data( this, key, value );
self.triggerHandler( "changeData" + part, parts );
});
}, null, value, arguments.length > 1, null, false );
},
removeData: function( key ) {
return this.each(function() {
jQuery.removeData( this, key );
});
}
});
function dataAttr( elem, key, data ) {
// If nothing was found internally, try to fetch any
// data from the HTML5 data-* attribute
if ( data === undefined && elem.nodeType === 1 ) {
var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
data = elem.getAttribute( name );
if ( typeof data === "string" ) {
try {
data = data === "true" ? true :
data === "false" ? false :
data === "null" ? null :
// Only convert to a number if it doesn't change the string
+data + "" === data ? +data :
rbrace.test( data ) ? jQuery.parseJSON( data ) :
data;
} catch( e ) {}
// Make sure we set the data so it isn't changed later
jQuery.data( elem, key, data );
} else {
data = undefined;
}
}
return data;
}
// checks a cache object for emptiness
function isEmptyDataObject( obj ) {
var name;
for ( name in obj ) {
// if the public data object is empty, the private is still empty
if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
continue;
}
if ( name !== "toJSON" ) {
return false;
}
}
return true;
}
jQuery.extend({
queue: function( elem, type, data ) {
var queue;
if ( elem ) {
type = ( type || "fx" ) + "queue";
queue = jQuery._data( elem, type );
// Speed up dequeue by getting out quickly if this is just a lookup
if ( data ) {
if ( !queue || jQuery.isArray(data) ) {
queue = jQuery._data( elem, type, jQuery.makeArray(data) );
} else {
queue.push( data );
}
}
return queue || [];
}
},
dequeue: function( elem, type ) {
type = type || "fx";
var queue = jQuery.queue( elem, type ),
startLength = queue.length,
fn = queue.shift(),
hooks = jQuery._queueHooks( elem, type ),
next = function() {
jQuery.dequeue( elem, type );
};
// If the fx queue is dequeued, always remove the progress sentinel
if ( fn === "inprogress" ) {
fn = queue.shift();
startLength--;
}
if ( fn ) {
// Add a progress sentinel to prevent the fx queue from being
// automatically dequeued
if ( type === "fx" ) {
queue.unshift( "inprogress" );
}
// clear up the last queue stop function
delete hooks.stop;
fn.call( elem, next, hooks );
}
if ( !startLength && hooks ) {
hooks.empty.fire();
}
},
// not intended for public consumption - generates a queueHooks object, or returns the current one
_queueHooks: function( elem, type ) {
var key = type + "queueHooks";
return jQuery._data( elem, key ) || jQuery._data( elem, key, {
empty: jQuery.Callbacks("once memory").add(function() {
jQuery.removeData( elem, type + "queue", true );
jQuery.removeData( elem, key, true );
})
});
}
});
jQuery.fn.extend({
queue: function( type, data ) {
var setter = 2;
if ( typeof type !== "string" ) {
data = type;
type = "fx";
setter--;
}
if ( arguments.length < setter ) {
return jQuery.queue( this[0], type );
}
return data === undefined ?
this :
this.each(function() {
var queue = jQuery.queue( this, type, data );
// ensure a hooks for this queue
jQuery._queueHooks( this, type );
if ( type === "fx" && queue[0] !== "inprogress" ) {
jQuery.dequeue( this, type );
}
});
},
dequeue: function( type ) {
return this.each(function() {
jQuery.dequeue( this, type );
});
},
// Based off of the plugin by Clint Helfers, with permission.
// http://blindsignals.com/index.php/2009/07/jquery-delay/
delay: function( time, type ) {
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
type = type || "fx";
return this.queue( type, function( next, hooks ) {
var timeout = setTimeout( next, time );
hooks.stop = function() {
clearTimeout( timeout );
};
});
},
clearQueue: function( type ) {
return this.queue( type || "fx", [] );
},
// Get a promise resolved when queues of a certain type
// are emptied (fx is the type by default)
promise: function( type, obj ) {
var tmp,
count = 1,
defer = jQuery.Deferred(),
elements = this,
i = this.length,
resolve = function() {
if ( !( --count ) ) {
defer.resolveWith( elements, [ elements ] );
}
};
if ( typeof type !== "string" ) {
obj = type;
type = undefined;
}
type = type || "fx";
while( i-- ) {
tmp = jQuery._data( elements[ i ], type + "queueHooks" );
if ( tmp && tmp.empty ) {
count++;
tmp.empty.add( resolve );
}
}
resolve();
return defer.promise( obj );
}
});
var nodeHook, boolHook, fixSpecified,
rclass = /[\t\r\n]/g,
rreturn = /\r/g,
rtype = /^(?:button|input)$/i,
rfocusable = /^(?:button|input|object|select|textarea)$/i,
rclickable = /^a(?:rea|)$/i,
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
getSetAttribute = jQuery.support.getSetAttribute;
jQuery.fn.extend({
attr: function( name, value ) {
return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
},
removeAttr: function( name ) {
return this.each(function() {
jQuery.removeAttr( this, name );
});
},
prop: function( name, value ) {
return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
},
removeProp: function( name ) {
name = jQuery.propFix[ name ] || name;
return this.each(function() {
// try/catch handles cases where IE balks (such as removing a property on window)
try {
this[ name ] = undefined;
delete this[ name ];
} catch( e ) {}
});
},
addClass: function( value ) {
var classNames, i, l, elem,
setClass, c, cl;
if ( jQuery.isFunction( value ) ) {
return this.each(function( j ) {
jQuery( this ).addClass( value.call(this, j, this.className) );
});
}
if ( value && typeof value === "string" ) {
classNames = value.split( core_rspace );
for ( i = 0, l = this.length; i < l; i++ ) {
elem = this[ i ];
if ( elem.nodeType === 1 ) {
if ( !elem.className && classNames.length === 1 ) {
elem.className = value;
} else {
setClass = " " + elem.className + " ";
for ( c = 0, cl = classNames.length; c < cl; c++ ) {
if ( setClass.indexOf( " " + classNames[ c ] + " " ) < 0 ) {
setClass += classNames[ c ] + " ";
}
}
elem.className = jQuery.trim( setClass );
}
}
}
}
return this;
},
removeClass: function( value ) {
var removes, className, elem, c, cl, i, l;
if ( jQuery.isFunction( value ) ) {
return this.each(function( j ) {
jQuery( this ).removeClass( value.call(this, j, this.className) );
});
}
if ( (value && typeof value === "string") || value === undefined ) {
removes = ( value || "" ).split( core_rspace );
for ( i = 0, l = this.length; i < l; i++ ) {
elem = this[ i ];
if ( elem.nodeType === 1 && elem.className ) {
className = (" " + elem.className + " ").replace( rclass, " " );
// loop over each item in the removal list
for ( c = 0, cl = removes.length; c < cl; c++ ) {
// Remove until there is nothing to remove,
while ( className.indexOf(" " + removes[ c ] + " ") >= 0 ) {
className = className.replace( " " + removes[ c ] + " " , " " );
}
}
elem.className = value ? jQuery.trim( className ) : "";
}
}
}
return this;
},
toggleClass: function( value, stateVal ) {
var type = typeof value,
isBool = typeof stateVal === "boolean";
if ( jQuery.isFunction( value ) ) {
return this.each(function( i ) {
jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
});
}
return this.each(function() {
if ( type === "string" ) {
// toggle individual class names
var className,
i = 0,
self = jQuery( this ),
state = stateVal,
classNames = value.split( core_rspace );
while ( (className = classNames[ i++ ]) ) {
// check each className given, space separated list
state = isBool ? state : !self.hasClass( className );
self[ state ? "addClass" : "removeClass" ]( className );
}
} else if ( type === "undefined" || type === "boolean" ) {
if ( this.className ) {
// store className if set
jQuery._data( this, "__className__", this.className );
}
// toggle whole className
this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
}
});
},
hasClass: function( selector ) {
var className = " " + selector + " ",
i = 0,
l = this.length;
for ( ; i < l; i++ ) {
if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
return true;
}
}
return false;
},
val: function( value ) {
var hooks, ret, isFunction,
elem = this[0];
if ( !arguments.length ) {
if ( elem ) {
hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
return ret;
}
ret = elem.value;
return typeof ret === "string" ?
// handle most common string cases
ret.replace(rreturn, "") :
// handle cases where value is null/undef or number
ret == null ? "" : ret;
}
return;
}
isFunction = jQuery.isFunction( value );
return this.each(function( i ) {
var val,
self = jQuery(this);
if ( this.nodeType !== 1 ) {
return;
}
if ( isFunction ) {
val = value.call( this, i, self.val() );
} else {
val = value;
}
// Treat null/undefined as ""; convert numbers to string
if ( val == null ) {
val = "";
} else if ( typeof val === "number" ) {
val += "";
} else if ( jQuery.isArray( val ) ) {
val = jQuery.map(val, function ( value ) {
return value == null ? "" : value + "";
});
}
hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
// If set returns undefined, fall back to normal setting
if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
this.value = val;
}
});
}
});
jQuery.extend({
valHooks: {
option: {
get: function( elem ) {
// attributes.value is undefined in Blackberry 4.7 but
// uses .value. See #6932
var val = elem.attributes.value;
return !val || val.specified ? elem.value : elem.text;
}
},
select: {
get: function( elem ) {
var value, option,
options = elem.options,
index = elem.selectedIndex,
one = elem.type === "select-one" || index < 0,
values = one ? null : [],
max = one ? index + 1 : options.length,
i = index < 0 ?
max :
one ? index : 0;
// Loop through all the selected options
for ( ; i < max; i++ ) {
option = options[ i ];
// oldIE doesn't update selected after form reset (#2551)
if ( ( option.selected || i === index ) &&
// Don't return options that are disabled or in a disabled optgroup
( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
// Get the specific value for the option
value = jQuery( option ).val();
// We don't need an array for one selects
if ( one ) {
return value;
}
// Multi-Selects return an array
values.push( value );
}
}
return values;
},
set: function( elem, value ) {
var values = jQuery.makeArray( value );
jQuery(elem).find("option").each(function() {
this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
});
if ( !values.length ) {
elem.selectedIndex = -1;
}
return values;
}
}
},
// Unused in 1.8, left in so attrFn-stabbers won't die; remove in 1.9
attrFn: {},
attr: function( elem, name, value, pass ) {
var ret, hooks, notxml,
nType = elem.nodeType;
// don't get/set attributes on text, comment and attribute nodes
if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
return;
}
if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) {
return jQuery( elem )[ name ]( value );
}
// Fallback to prop when attributes are not supported
if ( typeof elem.getAttribute === "undefined" ) {
return jQuery.prop( elem, name, value );
}
notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
// All attributes are lowercase
// Grab necessary hook if one is defined
if ( notxml ) {
name = name.toLowerCase();
hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
}
if ( value !== undefined ) {
if ( value === null ) {
jQuery.removeAttr( elem, name );
return;
} else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
return ret;
} else {
elem.setAttribute( name, value + "" );
return value;
}
} else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
return ret;
} else {
ret = elem.getAttribute( name );
// Non-existent attributes return null, we normalize to undefined
return ret === null ?
undefined :
ret;
}
},
removeAttr: function( elem, value ) {
var propName, attrNames, name, isBool,
i = 0;
if ( value && elem.nodeType === 1 ) {
attrNames = value.split( core_rspace );
for ( ; i < attrNames.length; i++ ) {
name = attrNames[ i ];
if ( name ) {
propName = jQuery.propFix[ name ] || name;
isBool = rboolean.test( name );
// See #9699 for explanation of this approach (setting first, then removal)
// Do not do this for boolean attributes (see #10870)
if ( !isBool ) {
jQuery.attr( elem, name, "" );
}
elem.removeAttribute( getSetAttribute ? name : propName );
// Set corresponding property to false for boolean attributes
if ( isBool && propName in elem ) {
elem[ propName ] = false;
}
}
}
}
},
attrHooks: {
type: {
set: function( elem, value ) {
// We can't allow the type property to be changed (since it causes problems in IE)
if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
jQuery.error( "type property can't be changed" );
} else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
// Setting the type on a radio button after the value resets the value in IE6-9
// Reset value to it's default in case type is set after value
// This is for element creation
var val = elem.value;
elem.setAttribute( "type", value );
if ( val ) {
elem.value = val;
}
return value;
}
}
},
// Use the value property for back c
