define(["lib/jquery", "lib/underscore", "common/util/check", "common/util/binding_list"], function( $, _, check, BindingList) {
"use strict";
// scrolls of less than this many pixels will be ignored
var SCROLL_THRESHOLD = 5;
/**
* Makes an element scrollable.
*
* @param {string | DOMElement | jQuery} el
* Scrollable element. Can be a CSS selector, a DOM element, or a
* jQuery object.
*
* @param {Number} [numFingers]
* The number of fingers used to scroll. Defaults to 3.
*
* @class Represents a scrollable element.
*
* @property {Boolean} enabled Whether this Scrollable is enabled.
*
* @name Lens.Components.Scrollable
*/
var Scrollable = function(el, numFingers) {
check(el, check.Match.Elementish);
check(numFingers, check.Match.Optional(Number));
var self = {};
var enabled = true;
var scrollSubscribers = BindingList();
var eventHandler = function(evt) {
if(!self.enabled) {
return;
}
var touches = evt.targetTouches;
if(touches.length >= numFingers) {
var startScrollY = el.scrollTop();
var startScrollX = el.scrollLeft();
// keep track of previous dx and dy so we can respect the threshold
var prevDy = touches.dy;
var prevDx = touches.dx;
// bind to the mover handler
touches.moved(function() {
if(Math.abs(prevDy - touches.dy) > SCROLL_THRESHOLD) {
el.scrollTop(startScrollY - touches.dy);
prevDy = touches.dy;
scrollSubscribers.callAll();
}
if(Math.abs(prevDx - touches.dx) > SCROLL_THRESHOLD) {
el.scrollLeft(startScrollX - touches.dx);
prevDx = touches.dx;
scrollSubscribers.callAll();
}
});
evt.stopPropagation();
}
};
Object.defineProperty(self, "enabled", { get: function() { return enabled; } });
/**
* Enables the scrollable. Scrollables start out enabled, so you only
* need to call this if you've disabled the Scrollable with `disable`.
*/
self.enable = function() {
el = $(el);
el[0].addEventListener("lens:touchstart", eventHandler, true);
enabled = true;
};
/**
* Disables the scrollable. The scrollable will no longer move when
* touched.
*/
self.disable = function() {
el = $(el);
el[0].removeEventListener("lens:touchstart", eventHandler, true);
enabled = false;
};
/**
* Registers a function to be called whenever scrolling occurs.
*
* @param {Function} callback
* The function to call. Gets one {@link Scrollable} as an
* argument.
*
* @return {Binding} A Binding that allows this handler to be cleared.
*/
self.onScroll = function(callback) {
check(callback, Function);
return scrollSubscribers.add(callback);
};
if(!numFingers) {
numFingers = 3;
}
$(function(){
self.enable();
});
Object.freeze(self);
return self;
};
Lens._addMember(Scrollable, "Scrollable", Lens.Components);
return Scrollable;
});