com.cordova.admob
Version:
Google AdMob plugin for Cordova, Phonegap and Intel XDK ,support ios and android,support admob v1 and admob v2 ,Monetize your app with one javascript line.simple and easy to use api.build on admob ios 7.6 and admob android sdk 8 project home:https
1,332 lines (1,213 loc) • 264 kB
JavaScript
/*! intel-appframework - v2.1.0 - 2014-03-26 */
/**
* af.actionsheet - an actionsheet for html5 mobile apps
* Copyright 2012 - Intel
*/
/* EXAMPLE
You can pass in an HTML string that will get rendered
$(document.body).actionsheet('<a >Back</a><a onclick="alert(\'hi\');" >Show Alert 3</a><a onclick="alert(\'goodbye\');">Show Alert 4</a>');
You can also use an arra of objects to show each item. There are three propertyes
text - the text to display
cssClasses - extra css classes
handler - click handler function
$(document.body).actionsheet(
[{
text: 'back',
cssClasses: 'red',
handler: function () {
$.ui.goBack();
}
}, {
text: 'show alert 5',
cssClasses: 'blue',
handler: function () {
alert("hi");
}
}, {
text: 'show alert 6',
cssClasses: '',
handler: function () {
alert("goodbye");
}
}]
);
*/
/* global af*/
(function($) {
"use strict";
$.fn.actionsheet = function(opts) {
var tmp;
for (var i = 0; i < this.length; i++) {
tmp = new actionsheet(this[i], opts);
}
return this.length === 1 ? tmp : this;
};
var actionsheet = (function() {
var actionsheet = function(elID, opts) {
if (typeof elID === "string" || elID instanceof String) {
this.el = document.getElementById(elID);
} else {
this.el = elID;
}
if (!this.el) {
window.alert("Could not find element for actionsheet " + elID);
return;
}
if (this instanceof actionsheet) {
if (typeof(opts) === "object") {
for (var j in opts) {
this[j] = opts[j];
}
}
} else {
return new actionsheet(elID, opts);
}
// try {
var that = this;
var markStart = "<div id='af_actionsheet'><div style='width:100%'>";
var markEnd = "</div></div>";
var markup;
var noop=function(){};
if (typeof opts === "string") {
markup = $(markStart + opts + "<a href='javascript:;' class='cancel'>Cancel</a>" + markEnd);
} else if (typeof opts === "object") {
markup = $(markStart + markEnd);
var container = $(markup.children().get(0));
opts.push({
text: "Cancel",
cssClasses: "cancel"
});
for (var i = 0; i < opts.length; i++) {
var item = $("<a href='javascript:;'>" + (opts[i].text || "TEXT NOT ENTERED") + "</a>");
item[0].onclick = (opts[i].handler || noop);
if (opts[i].cssClasses && opts[i].cssClasses.length > 0)
item.addClass(opts[i].cssClasses);
container.append(item);
}
}
$(elID).find("#af_actionsheet").remove();
$(elID).find("#af_action_mask").remove();
$(elID).append(markup);
markup.vendorCss("Transition", "all 0ms");
markup.cssTranslate("0,0");
markup.css("top", window.innerHeight + "px");
this.el.style.overflow = "hidden";
markup.on("click", "a", function() {
that.hideSheet();
return false;
});
this.activeSheet = markup;
$(elID).append("<div id='af_action_mask' style='position:absolute;top:0px;left:0px;right:0px;bottom:0px;z-index:9998;background:rgba(0,0,0,.4)'/>");
setTimeout(function() {
markup.vendorCss("Transition", "all 300ms");
markup.cssTranslate("0," + (-(markup.height())) + "px");
}, 10);
$("#af_action_mask").bind("touchstart touchmove touchend click",function(e){
e.preventDefault();
e.stopPropagation();
});
};
actionsheet.prototype = {
activeSheet: null,
hideSheet: function() {
var that = this;
this.activeSheet.off("click", "a", function() {
that.hideSheet();
});
$(this.el).find("#af_action_mask").unbind("click").remove();
this.activeSheet.vendorCss("Transition", "all 0ms");
var markup = this.activeSheet;
var theEl = this.el;
setTimeout(function() {
markup.vendorCss("Transition", "all 300ms");
markup.cssTranslate("0,0px");
setTimeout(function() {
markup.remove();
markup = null;
theEl.style.overflow = "none";
}, 500);
}, 10);
}
};
return actionsheet;
})();
})(af);
/**
* af.css3animate - a css3 animation library that supports chaning/callbacks
* Copyright 2013 - Intel
*/
/* EXAMPLE
$("#animate").css3Animate({
width: "100px",
height: "100px",
x: "20%",
y: "30%",
time: "1000ms",
opacity: .5,
callback: function () {
//execute when finished
}
});
//Chain animations
$("#animate").css3Animate({
x: 20,
y: 30,
time: "300ms",
callback: function () {
$("#animate").css3Animate({
x: 20,
y: 30,
time: "500ms",
previous: true,
callback: function () {
reset();
}
});
}
});
*/
/* global af*/
/* global numOnly*/
(function($) {
"use strict";
var cache = [];
var objId = function(obj) {
if (!obj.afCSS3AnimateId) obj.afCSS3AnimateId = $.uuid();
return obj.afCSS3AnimateId;
};
var getEl = function(elID) {
if (typeof elID === "string" || elID instanceof String) {
return document.getElementById(elID);
} else if ($.is$(elID)) {
return elID[0];
} else {
return elID;
}
};
var getCSS3Animate = function(obj, options) {
var tmp, id, el = getEl(obj);
//first one
id = objId(el);
if (cache[id]) {
cache[id].animate(options);
tmp = cache[id];
} else {
tmp = css3Animate(el, options);
cache[id] = tmp;
}
return tmp;
};
$.fn.css3Animate = function(opts) {
//keep old callback system - backwards compatibility - should be deprecated in future versions
if (!opts.complete && opts.callback) opts.complete = opts.callback;
//first on
var tmp = getCSS3Animate(this[0], opts);
opts.complete = null;
opts.sucess = null;
opts.failure = null;
for (var i = 1; i < this.length; i++) {
tmp.link(this[i], opts);
}
return tmp;
};
$.css3AnimateQueue = function() {
return new css3Animate.queue();
};
var translateOpen = $.feat.cssTransformStart;
var translateClose = $.feat.cssTransformEnd;
var transitionEnd = $.feat.cssPrefix.replace(/-/g, "") + "TransitionEnd";
transitionEnd = ($.os.fennec || $.feat.cssPrefix === "" || $.os.ie) ? "transitionend" : transitionEnd;
transitionEnd = transitionEnd.replace(transitionEnd.charAt(0), transitionEnd.charAt(0).toLowerCase());
var css3Animate = (function() {
var css3Animate = function(elID, options) {
if (!(this instanceof css3Animate)) return new css3Animate(elID, options);
//start doing stuff
this.callbacksStack = [];
this.activeEvent = null;
this.countStack = 0;
this.isActive = false;
this.el = elID;
this.linkFinishedProxy = $.proxy(this.linkFinished, this);
if (!this.el) return;
this.animate(options);
var that = this;
af(this.el).bind("destroy", function() {
var id = that.el.afCSS3AnimateId;
that.callbacksStack = [];
if (cache[id]) delete cache[id];
});
};
css3Animate.prototype = {
animate: function(options) {
//cancel current active animation on this object
if (this.isActive) this.cancel();
this.isActive = true;
if (!options) {
window.alert("Please provide configuration options for animation of " + this.el.id);
return;
}
var classMode = !! options.addClass;
var scale, time;
var timeNum = numOnly(options.time);
if (classMode) {
//class defines properties being changed
if (options.removeClass) {
af(this.el).replaceClass(options.removeClass, options.addClass);
} else {
af(this.el).addClass(options.addClass);
}
} else {
//property by property
if (timeNum === 0) options.time = 0;
if (!options.y) options.y = 0;
if (!options.x) options.x = 0;
if (options.previous) {
var cssMatrix = new $.getCssMatrix(this.el);
options.y += numOnly(cssMatrix.f);
options.x += numOnly(cssMatrix.e);
}
if (!options.origin) options.origin = "0% 0%";
if (!options.scale) options.scale = "1";
if (!options.rotateY) options.rotateY = "0";
if (!options.rotateX) options.rotateX = "0";
if (!options.skewY) options.skewY = "0";
if (!options.skewX) options.skewX = "0";
if (!options.timingFunction) options.timingFunction = "linear";
//check for percent or numbers
if (typeof(options.x) === "number" || (options.x.indexOf("%") === -1 && options.x.toLowerCase().indexOf("px") === -1 && options.x.toLowerCase().indexOf("deg") === -1)) options.x = parseInt(options.x, 10) + "px";
if (typeof(options.y) === "number" || (options.y.indexOf("%") === -1 && options.y.toLowerCase().indexOf("px") === -1 && options.y.toLowerCase().indexOf("deg") === -1)) options.y = parseInt(options.y, 10) + "px";
var trans = "translate" + translateOpen + (options.x) + "," + (options.y) + translateClose + " scale(" + parseFloat(options.scale) + ") rotate(" + options.rotateX + ")";
if (!$.os.opera)
trans += " rotateY(" + options.rotateY + ")";
trans += " skew(" + options.skewX + "," + options.skewY + ")";
this.el.style[$.feat.cssPrefix + "Transform"] = trans;
this.el.style[$.feat.cssPrefix + "BackfaceVisibility"] = "hidden";
var properties = $.feat.cssPrefix + "Transform";
if (options.opacity !== undefined) {
this.el.style.opacity = options.opacity;
properties += ", opacity";
}
if (options.width) {
this.el.style.width = options.width;
properties = "all";
}
if (options.height) {
this.el.style.height = options.height;
properties = "all";
}
this.el.style[$.feat.cssPrefix + "TransitionProperty"] = "all";
if (("" + options.time).indexOf("s") === -1) {
scale = "ms";
time = options.time + scale;
} else if (options.time.indexOf("ms") !== -1) {
scale = "ms";
time = options.time;
} else {
scale = "s";
time = options.time + scale;
}
if (options.delay) {
this.el.style[$.feat.cssPrefix + "TransitionDelay"] = options.delay;
}
this.el.style[$.feat.cssPrefix + "TransitionDuration"] = time;
this.el.style[$.feat.cssPrefix + "TransitionTimingFunction"] = options.timingFunction;
this.el.style[$.feat.cssPrefix + "TransformOrigin"] = options.origin;
}
//add callback to the stack
this.callbacksStack.push({
complete: options.complete,
success: options.success,
failure: options.failure
});
this.countStack++;
var that = this,
duration;
var style = window.getComputedStyle(this.el);
if (classMode) {
//get the duration
duration = style[$.feat.cssPrefix + "TransitionDuration"];
timeNum = numOnly(duration);
options.time = timeNum;
if (duration.indexOf("ms") !== -1) {
scale = "ms";
} else {
scale = "s";
options.time *= 1000;
}
}
//finish asap
if (timeNum === 0 || (scale === "ms" && timeNum < 5) || style.display === "none") {
//the duration is nearly 0 or the element is not displayed, finish immediatly
$.asap($.proxy(this.finishAnimation, this, [false]));
//this.finishAnimation();
//set transitionend event
} else {
//setup the event normally
this.activeEvent = function(event) {
clearTimeout(that.timeout);
that.finishAnimation(event);
that.el.removeEventListener(transitionEnd, that.activeEvent, false);
};
that.timeout = setTimeout(this.activeEvent, numOnly(options.time) + 50);
this.el.addEventListener(transitionEnd, this.activeEvent, false);
}
},
addCallbackHook: function(callback) {
if (callback) this.callbacksStack.push(callback);
this.countStack++;
return this.linkFinishedProxy;
},
linkFinished: function(canceled) {
if (canceled) this.cancel();
else this.finishAnimation();
},
finishAnimation: function(event) {
if (event && event.preventDefault) event.preventDefault();
if (!this.isActive) return;
this.countStack--;
if (this.countStack === 0) this.fireCallbacks(false);
},
fireCallbacks: function(canceled) {
this.clearEvents();
//keep callbacks after cleanup
// (if any of the callbacks overrides this object, callbacks will keep on fire as expected)
var callbacks = this.callbacksStack;
//cleanup
this.cleanup();
//fire all callbacks
for (var i = 0; i < callbacks.length; i++) {
var complete = callbacks[i].complete;
var success = callbacks[i].success;
var failure = callbacks[i].failure;
//fire callbacks
if (typeof(complete) === "function") complete(canceled);
//success/failure
if (canceled && typeof(failure) === "function") failure();
else if (typeof(success) === "function") success();
}
},
cancel: function() {
if (!this.isActive) return;
this.fireCallbacks(true); //fire failure callbacks
},
cleanup: function() {
this.callbacksStack = [];
this.isActive = false;
this.countStack = 0;
},
clearEvents: function() {
if (this.activeEvent) {
this.el.removeEventListener(transitionEnd, this.activeEvent, false);
}
this.activeEvent = null;
},
link: function(elID, opts) {
var callbacks = {
complete: opts.complete,
success: opts.success,
failure: opts.failure
};
opts.complete = this.addCallbackHook(callbacks);
opts.success = null;
opts.failure = null;
//run the animation with the replaced callbacks
getCSS3Animate(elID, opts);
//set the old callback back in the obj to avoid strange stuff
opts.complete = callbacks.complete;
opts.success = callbacks.success;
opts.failure = callbacks.failure;
return this;
}
};
return css3Animate;
})();
css3Animate.queue = function() {
return {
elements: [],
push: function(el) {
this.elements.push(el);
},
pop: function() {
return this.elements.pop();
},
run: function() {
var that = this;
if (this.elements.length === 0) return;
if (typeof(this.elements[0]) === "function") {
var func = this.shift();
func();
}
if (this.elements.length === 0) return;
var params = this.shift();
if (this.elements.length > 0) {
params.complete = function(canceled) {
if (!canceled) that.run();
};
}
css3Animate(document.getElementById(params.id), params);
},
shift: function() {
return this.elements.shift();
}
};
};
})(af);
/**
* @license MIT - https://github.com/darius/requestAnimationFrame/commit/4f27a5a21902a883330da4663bea953b2f96cb15#diff-9879d6db96fd29134fc802214163b95a
http://paulirish.com/2011/requestanimationframe-for-smart-animating/
http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
MIT license
Adapted from https://gist.github.com/paulirish/1579671 which derived from
http://paulirish.com/2011/requestanimationframe-for-smart-animating/
http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
requestAnimationFrame polyfill by Erik Möller.
Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavič, Darius Bacon
*/
if (!Date.now)
Date.now = function() {
"use strict";
return new Date().getTime();
};
(function() {
"use strict";
var vendors = ["webkit", "moz","ms"];
for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
var vp = vendors[i];
window.requestAnimationFrame = window[vp+"RequestAnimationFrame"];
window.cancelAnimationFrame = (window[vp+"CancelAnimationFrame"] || window[vp+"CancelRequestAnimationFrame"]);
}
if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) || !window.requestAnimationFrame || !window.cancelAnimationFrame) {
var lastTime = 0;
window.requestAnimationFrame = function(callback) {
var now = Date.now();
var nextTime = Math.max(lastTime + 16, now);
return setTimeout(function() { callback(lastTime = nextTime); },
nextTime - now);
};
window.cancelAnimationFrame = clearTimeout;
}
}());
/**
* af.animate - an experimental animation library that uses matrices and requestAnimationFrame
* Only supports x/y now and is used by the scroller library
* Copyright 2013 - Intel
*/
(function($) {
"use strict";
var cache = [];
var objId = function(obj) {
if (!obj.afAnimateId) obj.afAnimateId = $.uuid();
return obj.afAnimateId;
};
var getEl = function(elID) {
if (typeof elID === "string" || elID instanceof String) {
return document.getElementById(elID);
} else if ($.is$(elID)) {
return elID[0];
} else {
return elID;
}
};
var getAnimate = function(obj, options) {
var tmp, id, el = getEl(obj);
//first one
id = objId(el);
if (cache[id]) {
if(options)
cache[id].animate(options);
tmp = cache[id];
} else {
tmp = Animate(el, options);
cache[id] = tmp;
}
return tmp;
};
$.fn.animate = function(opts) {
var tmp = getAnimate(this[0], opts);
return tmp;
};
var Animate = function(elID, options) {
if (!(this instanceof Animate)) return new Animate(elID, options);
this.el=elID;
//start doing stuff
if (!this.el) return;
if(options)
this.animate(options);
var that = this;
af(this.el).bind("destroy", function() {
var id = that.el.afAnimateId;
if (cache[id]) delete cache[id];
});
};
Animate.prototype = {
animationTimer:null,
isAnimating:false,
startX:0,
startY:0,
runTime:0,
endX:0,
endY:0,
currX:0,
currY:0,
animationStartTime:0,
pauseTime:0,
completeCB:null,
easingFn:"linear",
animateOpts:{},
updateCb:null,
animate: function(options) {
var that=this;
if(that.isAnimating) return;
that.isAnimating=true;
window.cancelAnimationFrame(that.animationTimer);
if (!options) {
options={
x:0,
y:0,
duration:0
};
}
this.easingFn=options.easing||"linear";
this.completeCB=options.complete||null;
this.updateCB=options.update||null;
this.runTime=numOnly(options.duration);
options.complete&&(delete options.complete);
this.animateOpts=options;
this.startTime=Date.now();
this.startMatrix=$.getCssMatrix(this.el);
if(this.runTime===0)
this.doAnimate();
},
start:function(){
this.doAnimate();
},
doAnimate:function(){
var now = Date.now(), nextX, nextY,easeStep,that=this;
if (this.runTime===0||(now >= this.startTime + this.runTime)) {
that.setPosition(this.animateOpts.x,this.animateOpts.y);
that.isAnimating = false;
if(this.updateCB)
this.updateCB({x:this.animateOpts.x,y:this.animateOpts.y});
if(this.completeCB)
this.completeCB();
return;
}
now = (now - this.startTime) / this.runTime;
now=now>1?1:now;
easeStep = tweens[this.easingFn](now);
nextX = (this.animateOpts.x - this.startMatrix.e) * easeStep + this.startMatrix.e;
nextY = (this.animateOpts.y - this.startMatrix.f) * easeStep + this.startMatrix.f;
this.setPosition(nextX,nextY);
if(this.updateCB)
this.updateCB({x:nextX,y:nextY});
if (this.isAnimating)
this.animationTimer = window.requestAnimationFrame(function(){that.doAnimate();});
},
setPosition:function(x,y){
this.el.style[$.feat.cssPrefix+"Transform"]="matrix3d( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, "+x+", "+y+", 0, 1 )";
this.currX=x;
this.currY=y;
},
stop:function(){
this.isAnimating=false;
window.cancelAnimationFrame(this.animationTimer);
this.pauseTime=Date.now()-this.startTime;
},
resume:function(){
this.isAnimating=true;
this.startTime=Date.now()-this.pauseTime;
this.doAnimate();
}
};
var tweens = {
linear:function (k) {
return k;
},
easeOutSine:function (k) {
return Math.sin(k * Math.PI / 2 );
}
};
})(af);
/**
* af.passwordBox - password box replacement for html5 mobile apps on android due to a bug with CSS3 translate3d
* @copyright 2011 - Intel
*/
/* global af*/
(function ($) {
"use strict";
$.passwordBox = function () {
return new passwordBox();
};
var passwordBox = function () {
this.oldPasswords = {};
};
passwordBox.prototype = {
showPasswordPlainText: false,
getOldPasswords: function (elID) {
// if ($.os.android == false) return; - iOS users seem to want this too, so we'll let everyone join the party
var container = elID && document.getElementById(elID) ? document.getElementById(elID) : document;
if (!container) {
window.alert("Could not find container element for passwordBox " + elID);
return;
}
var sels = container.getElementsByTagName("input");
for (var i = 0; i < sels.length; i++) {
if (sels[i].type !== "password") continue;
if($.os.webkit){
sels[i].type = "text";
$(sels[i]).vendorCss("TextSecurity","disc");
}
}
},
changePasswordVisiblity: function (what, id) {
what = parseInt(what,10);
var theEl = document.getElementById(id);
if (what === 1) { //show
$(theEl).vendorCss("TextSecurity","none");
} else {
$(theEl).vendorCss("TextSecurity","disc");
}
if(!$.os.webkit) {
if(what === 1)
theEl.type="text";
else
theEl.type="password";
}
theEl = null;
}
};
})(af);
/**
* af.scroller
* created by Intel with modifications by Carlos Ouro @ Badoo and Intel
* Supports iOS native touch scrolling
* Optimizations and bug improvements by Intel
* @copyright Intel
*/
/* global numOnly*/
(function ($) {
"use strict";
var HIDE_REFRESH_TIME = 325; // hide animation of pull2ref duration in ms
var cache = [];
var objId = function (obj) {
if (!obj.afScrollerId) obj.afScrollerId = $.uuid();
return obj.afScrollerId;
};
$.fn.scroller = function (opts) {
var tmp, id;
for (var i = 0; i < this.length; i++) {
//cache system
id = objId(this[i]);
if (!cache[id]) {
if (!opts) opts = {};
if (!$.feat.nativeTouchScroll) opts.useJsScroll = true;
tmp = scroller(this[i], opts);
cache[id] = tmp;
} else {
tmp = cache[id];
}
}
return this.length === 1 ? tmp : this;
};
var boundTouchLayer = false;
function checkConsistency(id) {
if (!cache[id].el) {
delete cache[id];
return false;
}
return true;
}
function bindTouchLayer() {
//use a single bind for all scrollers
if ($.os.android && !$.os.chrome && $.os.webkit) {
var androidFixOn = false;
//connect to touchLayer to detect editMode
$.bind($.touchLayer, ["cancel-enter-edit", "exit-edit"], function () {
if (androidFixOn) {
androidFixOn = false;
//dehactivate on scroller
for (var el in cache)
if (checkConsistency(el) && cache[el].androidFormsMode) cache[el].stopFormsMode();
}
});
}
boundTouchLayer = true;
}
var scroller = (function () {
var jsScroller, nativeScroller;
//initialize and js/native mode selector
var scroller = function (elID, opts) {
var el;
if (!boundTouchLayer && $.touchLayer && $.isObject($.touchLayer)) bindTouchLayer();
else if (!$.touchLayer || !$.isObject($.touchLayer)) $.touchLayer = {};
if (typeof elID === "string" || elID instanceof String) {
el = document.getElementById(elID);
} else {
el = elID;
}
if (!el) {
window.alert("Could not find element for scroller " + elID);
return;
}
var checkClassEl=$(el);
if(opts.hasParent)
checkClassEl=checkClassEl.parent();
if(checkClassEl.hasClass("x-scroll"))
opts.horizontalScroll=true;
if(checkClassEl.hasClass("y-scroll"))
opts.verticalScroll=true;
if ($.os.desktop)
return new scrollerCore(el, opts);
else if (opts.useJsScroll) return new jsScroller(el, opts);
return new nativeScroller(el, opts);
};
//parent abstract class (common functionality)
var scrollerCore = function (el, opts) {
this.el = el;
this.afEl = $(this.el);
for (var j in opts) {
this[j] = opts[j];
}
};
scrollerCore.prototype = {
//core default properties
refresh: false,
refreshContent: "Pull to Refresh",
refreshHangTimeout: 2000,
refreshHeight: 60,
refreshElement: null,
refreshCancelCB: null,
refreshRunning: false,
scrollTop: 0,
scrollLeft: 0,
preventHideRefresh: true,
verticalScroll: true,
horizontalScroll: false,
refreshTriggered: false,
moved: false,
eventsActive: false,
rememberEventsActive: false,
scrollingLocked: false,
autoEnable: true,
blockFormsFix: false,
loggedPcentY: 0,
loggedPcentX: 0,
infinite: false,
infiniteEndCheck: false,
infiniteTriggered: false,
scrollSkip: false,
scrollTopInterval: null,
scrollLeftInterval: null,
bubbles:true,
lockBounce:false,
initScrollProgress:false,
_scrollTo: function (params, time) {
time = parseInt(time, 10);
if (time === 0 || isNaN(time)) {
this.el.scrollTop = Math.abs(params.y);
this.el.scrollLeft = Math.abs(params.x);
return;
}
var singleTick = 10;
var distPerTick = (this.el.scrollTop - params.y) / Math.ceil(time / singleTick);
var distLPerTick = (this.el.scrollLeft - params.x) / Math.ceil(time / singleTick);
var self = this;
var toRunY = Math.ceil(this.el.scrollTop - params.y) / distPerTick;
var toRunX = Math.ceil(this.el.scrollLeft - params.x) / distPerTick;
var xRun =0, yRun = 0;
self.scrollTopInterval = window.setInterval(function () {
self.el.scrollTop -= distPerTick;
yRun++;
if (yRun >= toRunY) {
self.el.scrollTop = params.y;
clearInterval(self.scrollTopInterval);
}
}, singleTick);
self.scrollLeftInterval = window.setInterval(function () {
self.el.scrollLeft -= distLPerTick;
xRun++;
if (xRun >= toRunX) {
self.el.scrollLeft = params.x;
clearInterval(self.scrollLeftInterval);
}
}, singleTick);
},
enable: function () {},
disable: function () {},
hideScrollbars: function () {},
addPullToRefresh: function () {},
/**
* We do step animations for "native" - iOS is acceptable and desktop browsers are fine
* instead of css3
*/
_scrollToTop: function (time) {
this._scrollTo({
x: 0,
y: 0
}, time);
},
_scrollToBottom: function (time) {
this._scrollTo({
x: 0,
y: this.el.scrollHeight - this.el.offsetHeight
}, time);
},
scrollToBottom: function (time) {
return this._scrollToBottom(time);
},
scrollToTop: function (time) {
return this._scrollToTop(time);
},
//methods
init: function (el, opts) {
this.el = el;
this.afEl = $(this.el);
this.defaultProperties();
for (var j in opts) {
this[j] = opts[j];
}
//assign self destruct
var that = this;
var orientationChangeProxy = function (e) {
//no need to readjust if disabled...
if (that.eventsActive && !$.feat.nativeTouchScroll&&(!$.ui || ($.ui.activeDiv === that.container)) ) {
that.adjustScroll();
}
};
this.afEl.bind("destroy", function () {
that.disable(true); //with destroy notice
var id = that.el.afScrollerId;
if (cache[id]) delete cache[id];
$.unbind($.touchLayer, "orientationchange-reshape", orientationChangeProxy);
});
$.bind($.touchLayer, "orientationchange-reshape", orientationChangeProxy);
$(window).bind("resize", orientationChangeProxy);
},
needsFormsFix: function (focusEl) {
return this.useJsScroll && this.isEnabled() && this.el.style.display !== "none" && $(focusEl).closest(this.afEl).size() > 0;
},
handleEvent: function (e) {
if (!this.scrollingLocked) {
switch (e.type) {
case "touchstart":
clearInterval(this.scrollTopInterval);
this.preventHideRefresh = !this.refreshRunning; // if it's not running why prevent it xD
this.moved = false;
this.onTouchStart(e);
if(!this.bubbles)
e.stopPropagation();
break;
case "touchmove":
this.onTouchMove(e);
if(!this.bubbles)
e.stopPropagation();
break;
case "touchend":
this.onTouchEnd(e);
if(!this.bubbles)
e.stopPropagation();
break;
case "scroll":
this.onScroll(e);
break;
}
}
},
coreAddPullToRefresh: function (rEl) {
if (rEl) this.refreshElement = rEl;
//Add the pull to refresh text. Not optimal but keeps from others overwriting the content and worrying about italics
//add the refresh div
var afEl;
if (this.refreshElement === null) {
var orginalEl = document.getElementById(this.container.id + "_pulldown");
if (orginalEl !== null) {
afEl = $(orginalEl);
} else {
afEl = $("<div id='" + this.container.id + "_pulldown' class='afscroll_refresh' style='position:relative;height:60px;text-align:center;line-height:60px;font-weight:bold;'>" + this.refreshContent + "</div>");
}
} else {
afEl = $(this.refreshElement);
}
var el = afEl.get(0);
this.refreshContainer = $("<div style='overflow:hidden;height:0;width:100%;display:none;background:inherit;-webkit-backface-visibility: hidden !important;'></div>");
$(this.el).prepend(this.refreshContainer.prepend(el));
this.refreshContainer = this.refreshContainer[0];
},
fireRefreshRelease: function (triggered) {
if (!this.refresh || !triggered) return;
this.setRefreshContent("Refreshing...");
var autoCancel = $.trigger(this, "refresh-release", [triggered]) !== false;
this.preventHideRefresh = false;
this.refreshRunning = true;
if (autoCancel) {
var that = this;
if (this.refreshHangTimeout > 0) this.refreshCancelCB = setTimeout(function () {
that.hideRefresh();
}, this.refreshHangTimeout);
}
},
setRefreshContent: function (content) {
$(this.container).find(".afscroll_refresh").html(content);
},
lock: function () {
if (this.scrollingLocked) return;
this.scrollingLocked = true;
this.rememberEventsActive = this.eventsActive;
if (this.eventsActive) {
this.disable();
}
},
unlock: function () {
if (!this.scrollingLocked) return;
this.scrollingLocked = false;
if (this.rememberEventsActive) {
this.enable();
}
},
scrollToItem: function (el, where) { //TODO: add functionality for x position
if (!$.is$(el)) el = $(el);
var newTop,itemPos,panelTop,itemTop;
if (where === "bottom") {
itemPos = el.offset();
newTop = itemPos.top - this.afEl.offset().bottom + itemPos.height;
newTop += 4; //add a small space
} else {
itemTop = el.offset().top;
newTop = itemTop - document.body.scrollTop;
panelTop = this.afEl.offset().top;
if (document.body.scrollTop < panelTop) {
newTop -= panelTop;
}
newTop -= 4; //add a small space
}
this.scrollBy({
y: newTop,
x: 0
}, 0);
},
setPaddings: function (top, bottom) {
var el = $(this.el);
var curTop = numOnly(el.css("paddingTop"));
el.css("paddingTop", top + "px").css("paddingBottom", bottom + "px");
//don't let padding mess with scroll
this.scrollBy({
y: top - curTop,
x: 0
});
},
//freak of mathematics, but for our cases it works
divide: function (a, b) {
return b !== 0 ? a / b : 0;
},
isEnabled: function () {
return this.eventsActive;
},
addInfinite: function () {
this.infinite = true;
},
clearInfinite: function () {
this.infiniteTriggered = false;
this.scrollSkip = true;
},
scrollTo:function (pos, time) {
return this._scrollTo(pos, time);
},
updateP2rHackPosition:function(){}
};
//extend to jsScroller and nativeScroller (constructs)
jsScroller = function (el, opts) {
this.init(el, opts);
if(opts.hasParent)
this.container = this.el.parentNode;
else {
//copy/etc
var $div=$.create("div",{});
$div.append($(this.el).contents());
$(this.el).append($div);
this.container=this.el;
this.el=$div.get(0);
}
this.container.afScrollerId = el.afScrollerId;
this.afEl = $(this.container);
if (this.container.style.overflow !== "hidden") this.container.style.overflow = "hidden";
this.addPullToRefresh(null, true);
if(opts.autoEnable)
this.autoEnable=opts.autoEnable;
if (this.autoEnable) this.enable(true);
var scrollDiv;
//create vertical scroll
if (this.verticalScroll && this.verticalScroll === true && this.scrollBars === true) {
scrollDiv = createScrollBar(5, 20);
scrollDiv.style.top = "0px";
if (this.vScrollCSS) scrollDiv.className = this.vScrollCSS;
//scrollDiv.style.opacity = "0";
scrollDiv.style.display="none";
this.container.appendChild(scrollDiv);
this.vscrollBar = scrollDiv;
scrollDiv = null;
}
//create horizontal scroll
if (this.horizontalScroll && this.horizontalScroll === true && this.scrollBars === true) {
scrollDiv = createScrollBar(20, 5);
scrollDiv.style.bottom = "0px";
if (this.hScrollCSS) scrollDiv.className = this.hScrollCSS;
//scrollDiv.style.opacity = "0";
scrollDiv.style.display="none";
this.container.appendChild(scrollDiv);
this.hscrollBar = scrollDiv;
scrollDiv = null;
}
if (this.horizontalScroll) this.el.style.cssFloat = "left";
this.el.hasScroller = true;
};
nativeScroller = function (el, opts) {
if(opts.nativeParent){
el=el.parentNode;
}
this.init(el, opts);
var $el = $(el);
if (opts.replaceParent === true) {
var oldParent = $el.parent();
$el.css("height", oldParent.height()).css("width", oldParent.width());
$el.insertBefore($el.parent());
//$el.parent().parent().append($el);
oldParent.remove();
}
this.container = this.el;
$el.css("-webkit-overflow-scrolling", "touch");
if(opts.autoEnable)
this.autoEnable=opts.autoEnable;
if(this.autoEnable)
this.enable();
};
nativeScroller.prototype = new scrollerCore();
jsScroller.prototype = new scrollerCore();
///Native scroller
nativeScroller.prototype.defaultProperties = function () {
this.refreshContainer = null;
this.dY = this.cY = 0;
this.dX = this.cX = 0;
this.cancelPropagation = false;
this.loggedPcentY = 0;
this.loggedPcentX = 0;
this.xReset=0;
this.yReset=0;
var that = this;
this.adjustScrollOverflowProxy = function () {
that.afEl.css("overflow", "auto");
that.afEl.parent().css("overflow","hidden");
};
};
nativeScroller.prototype.enable = function (firstExecution) {
if (this.eventsActive) return;
this.eventsActive = true;
//unlock overflow
this.el.style.overflow = "auto";
//this.el.parentNode.style.overflow="hidden";
//set current scroll
if (!firstExecution) this.adjustScroll();
//set events
this.el.addEventListener("touchstart", this, false);
this.el.addEventListener("scroll", this, false);
this.updateP2rHackPosition();
};
nativeScroller.prototype.disable = function (destroy) {
if (!this.eventsActive) return;
//log current scroll
this.logPos(this.el.scrollLeft, this.el.scrollTop);
//lock overflow
if (!destroy&&!$.ui) {
this.el.style.overflow = "hidden";
}
//remove events
this.el.removeEventListener("touchstart", this, false);
this.el.removeEventListener("touchmove", this, false);
this.el.removeEventListener("touchend", this, false);
this.el.removeEventListener("scroll", this, false);
this.eventsActive = false;
};
nativeScroller.prototype.addPullToRefresh = function (el, leaveRefresh) {
if (!leaveRefresh) this.refresh = true;
if (this.refresh && this.refresh === true) {
this.coreAddPullToRefresh(el);
this.refreshContainer.style.position = "absolute";
this.refreshContainer.style.top = "-60px";
this.refreshContainer.style.height = "60px";
this.refreshContainer.style.display = "block";
this.updateP2rHackPosition();
}
};
nativeScroller.prototype.updateP2rHackPosition=function(){
if(!this.refresh)
return $(this.el).find(".p2rhack").remove();
var el=$(this.el).find(".p2rhack");
if(el.length === 0){
$(this.el).append("<div class='p2rhack' style='position:absolute;width:1px;height:1px;opacity:0;background:transparent;z-index:-1;-webkit-transform:translate3d(-1px,0,0);'></div>");
el=$(this.el).find(".p2rhack");
}
el.css("top",this.el.scrollHeight+this.refreshHeight+1+"px");
};
nativeScroller.prototype.onTouchStart = function (e) {
this.lastScrollInfo= {
top:0
};
this.xReset=this.yReset=0;
if(this.verticalScroll){
if(this.el.scrollTop===0&&this.refresh){
this.el.scrollTop=1;
this.yReset=-1;
}
if(this.el.scrollTop===(this.el.scrollHeight - this.el.clientHeight)&&this.infinite){
this.el.scrollTop-=1;
this.yReset=1;
}
}
if(this.horizontalScroll){
if(this.el.scrollLeft===0){
this.el.scrollLeft=1;
this.xReset=-1;
}
if(this.el.scrollLeft===(this.el.scrollWidth-this.el.clientWidth)){
this.el.scrollLeft-=1;
this.xReset=1;
}
}
if (this.refreshCancelCB) clearTimeout(this.refreshCancelCB);
//get refresh ready
if(this.refresh)
this.el.addEventListener("touchend",this,false);
this.el.addEventListener("touchmove", this,false);
this.dY = e.touches[0].pageY;
this.dX = e.touches[0].pageX;
this.startTop=this.el.scrollTop;
this.startLeft=this.el.scrollLeft;
if (this.refresh || this.infinite) {
if (this.refresh && this.dY < 0) {
this.showRefresh();
}
}
};
nativeScroller.prototype.onTouchMove = function (e) {
var newcY = e.touches[0].pageY - this.dY;
var newcX = e.touches[0].pageX - this.dX;
//var scorllTop
var atTop=(this.el.scrollHeight-this.el.scrollTop)===this.el.clientHeight&&newcY<0;
var atRight=(this.el.scrollWidth-this.el.scrollLeft)===this.el.clientWidth&&newcX<0;
var preventDefault=e.target.tagName.toLowerCase()!=="input";
if(this.verticalScroll){
if(this.startTop===0&&this.el.scrollTop===0&&newcY>0)
preventDefault&&e.preventDefault();
}
if(this.horizontalScroll&&this.startTop===0&&this.el.scrollLeft===0&&newcX>0){
preventDefault&&e.preventDefault();
}
if(this.verticalScroll&&atTop){
preventDefault&&e.preventDefault();
}
if(this.horizontalScroll&&atRight){
preventDefault&&e.preventDefault();
}
if (!this.moved) {
$.trigger(this, "scrollstart", [this.el,{x:newcX,y:newcY}]);
$.trigger($.touchLayer, "scrollst