///
///
/*
@author Dan Gidman (danatcofo at gmail dot com)
released under GNU General Public License v3
http://www.gnu.org/licenses/gpl.html
version 2.4
*/
(function (jQuery) {
// #region Constants
// data keys
var k = "$autoscroll", ek = "$tAutoscroll", ik = "$autoscrollInterval", lk = "$edgeAutoscroll", mk = "$lastEdgeAutoscroll",
// angle enum
G = { up: 90.0, left: 180.0, right: 360.0, upleft: 135.0, upright: 45.0, downleft: 225.0, downright: 315.0, leftup: 135.0, rightup: 45.0, leftdown: 225.0, rightdown: 315.0, down: 270.0 },
// #endregion
// #region Methods
// available M defaults to init
M = {
init: function (s) {
return this.each(function () {
if (d(this)) jQuery(this).data(k, V(jQuery.extend(d(this), s)));
else {
jQuery(this).data(k, V(jQuery.extend({ e: false, fr: false }, jQuery.fn.autoscroll.defaults.settings, s)));
jQuery(this).hover(function () {
var c = d(this);
if (c) {
if (c.scroll) {
_I(this);
jQuery(this).stop(true);
}
c.e = true;
}
}, function () {
var c = d(this);
if (c && c.e) {
if (c.scroll) I(this);
c.e = false;
}
});
I(this);
}
});
},
destroy: function () {
return this.each(function () {
if (d(this)) {
_I(this);
jQuery(this).stop(true).data(ik, null).data(k, null).data(ek, null);
}
});
},
delay: function (t) {
return this.each(function () {
var c = d(this);
if (c && c.scroll) {
jQuery(this).autoscroll("pause")
jQuery(this).oneTime(t || jQuery.fn.autoscroll.defaults.delay, k, function () {
jQuery(this).autoscroll("resume");
});
}
});
},
fastforward: function (s) { return FR(this, "f", s); },
rewind: function (s) { return FR(this, "r", s); },
pause: function () {
return this.each(function () {
var c = d(this);
if (c && c.scroll) {
c.scroll = false;
jQuery(this).stop(true);
_I(this);
}
});
},
resume: function () {
return this.each(function () {
var c = d(this);
if (c) {
c.scroll = true;
I(this);
}
});
},
reverse: function () {
return this.each(function () {
var c = d(this);
if (c && (c.direction += 180.0) > 360.0) c.direction -= 360.0;
jQuery(this).stop(true);
});
},
toggle: function () {
return this.each(function () {
var c = d(this);
if (c)
if (c.scroll) jQuery(this).autoscroll("pause");
else jQuery(this).autoscroll("resume");
});
},
get: function () {
return this.each(function () {
if (d(this)) return d(this);
});
},
addpausesource: function (e) {
if (typeof e == "undefined") return this;
if (!(e instanceof jQuery))
if ((e = jQuery(e)).length == 0) return this;
var s = this.selector;
e.each(function () {
jQuery(this).hover(function () {
jQuery(s).each(function () {
var c = d(this);
if (c) {
if (c.scroll) {
_I(this);
jQuery(this).stop(true);
}
c.e = true;
}
});
}, function () {
jQuery(s).each(function () {
var c = d(this);
if (c && c.e) {
if (c.scroll) I(this);
c.e = false;
}
});
});
});
return this;
}
},
// #endregion
// #region Utilities
// interval handler
I = function (e) {
jQuery(e).data(ik, setInterval(function () {
var l, c = d(e);
if (c) {
if (typeof c.onEvaluate == "function") c.onEvaluate.apply(e);
if (!D(e)) {
if (c.scroll && !c.e && !c.fr) {
if ((l = jQuery(e).data(ek)) && !E(l, c)) jQuery(e).stop(true).animate(S(c.step, c.direction, e), 1000, "linear");
else jQuery(e).animate(S(c.step, c.direction), 1000, "linear");
}
}
jQuery(e).data(ek, jQuery.extend(true, {}, c));
}
}, 50));
},
_I = function (e) {
clearInterval(jQuery(e).data(ik));
},
// get data
d = function (e) { return jQuery(e).data(k); },
// step equality
E = function (a, b) { return a.step === b.step && a.direction === b.direction && a.scroll === b.scroll; },
// ff and rw handler
FR = function (a, r, s) {
var f = V(jQuery.extend(jQuery.fn.autoscroll.defaults.ffrw, s));
return a.each(function () {
var c = d(this);
if (c) {
var scroll = c.scroll, b = c.direction;
c.fr = true;
if (r == "r" && (b += 180.0) > 360.0) b -= 360.0;
if (c.scroll) _I(this);
jQuery(this).stop(true).animate(S(f.step, b), f.speed, "swing", function () { d(this).fr = false; if (c.scroll) I(this); });
}
});
},
// validation
V = function (s) {
if (jQuery.inArray(typeof s.scroll, ["undefined", "boolean"]) < 0)
jQuery.error("scroll is not a boolean");
if (jQuery.inArray(typeof s.step, ["undefined", "number"]) < 0 && isNaN(s.step = Number(s.step)))
jQuery.error("step is not a valid number");
if (s.direction) s.direction = A(s.direction);
return s;
},
// conversions
d2r = function (a) { return a * Math.PI / 180.0; },
// angle handler
A = function (a) {
if (typeof a === "string" && isNaN(Number(a)))
if (G[a]) a = G[a];
else if (a.indexOf("rad") == a.length - 3 && !isNaN(a = Number(a.substring(0, a.length - 3)))) a = a * 180.0 / Math.PI;
if (isNaN(a = Number(a))) jQuery.error("Invalid direction on jQuery.autoscroll");
while (a < 0.0) a += 360.0;
return a;
},
// step handler
S = function (s, a) {
var x = Math.round(s * Math.cos(a = d2r(a))),
y = Math.round(s * Math.sin(a)) * -1,
$t = arguments[2];
return ($t && jQuery($t).length > 0) ?
{ scrollTop: $t.scrollTop + y, scrollLeft: $t.scrollLeft + x} :
{ scrollTop: ((y < 0) ? "-=" : "+=") + Math.abs(y), scrollLeft: ((x < 0) ? "-=" : "+=") + Math.abs(x) };
},
// edge handler
D = function (e) {
var c = d(e);
if (c && typeof c.onEdge == "function") {
var c2 = jQuery(e).data(lk) || { x: null, y: null },
s = c.step,
l = e.scrollLeft,
v = d2r(c.direction),
x = Math.round(s * Math.cos(v)),
nl = l + x,
t = e.scrollTop,
y = Math.round(s * Math.sin(v)) * -1
nt = t + y,
_e = jQuery(e).data(mk);
// left edge
if (l > nl && l == 0) {
if (!c2.x || c2.x != "left") c2.x = "left";
}
// right edge
else if (l < nl && l == e.scrollWidth - e.clientWidth) {
if (!c2.x || c2.x != "right") c2.x = "right";
}
else c2.x = null;
// top edge
if (t > nt && t == 0) {
if (!c2.y || c2.y != "top") c2.y = "top";
}
// bottom edge
else if (t < nt && t == e.scrollHeight - e.clientHeight) {
if (!c2.y || c2.y != "bottom") c2.y = "bottom";
}
else c2.y = null;
try {
if (!_e || (c2.x && c2.x != _e.x) || (c2.y && c2.y != _e.y)) {
c.onEdge.apply(e, [c2]);
return true;
}
}
catch ($e) { throw $e; }
finally {
jQuery(e).data(mk, jQuery.extend(true, {}, c2)).data(lk, c2);
}
}
return false;
};
// #endregion
// #region Public
// main
jQuery.fn.autoscroll = function (a, b) {
/// Autoscroll scrollable elements.
if (M[a]) return M[a].apply(this, Array.prototype.slice.call(arguments, 1));
else if (typeof a === 'object' || !a) return M.init.apply(this, arguments);
else jQuery.error('Method ' + a + ' does not exist on jQuery.autoscroll');
};
// defaults
jQuery.fn.autoscroll.defaults = { settings: { step: 50, scroll: true, direction: "down" }, delay: 5000, ffrw: { speed: "fast", step: 100} };
// #endregion
})(jQuery);