toloframework
Version:
Javascript/HTML/CSS compiler for Firefox OS or nodewebkit apps using modules in the nodejs style.
509 lines (431 loc) • 14.1 kB
JavaScript
;
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
/** @module tfw.gestures */
require('tfw.gestures', function (require, module, exports) {
var _ = function () {
var D = {
"en": {},
"fr": {}
},
X = require("$").intl;
function _() {
return X(D, arguments);
}
_.all = D;
return _;
}();
"use strict";
/**
* @param {dom} element
* @param {function} events - Shortcut for `{ tap: ... }`.
* @param {function} events.tap { x, y }
* @param {function} events.doubletap { x, y }
* @param {function} events.drag { x, y, x0, y0, vx, vy }
* @param {function} events.dragstart { x, y }
* @param {function} events.dragend { x, y, x0, y0 }
* @param {function} events.wheel { x, y, delta }
*/
module.exports = getGesture;
var HANDLERS = {
tap: onTap,
doubletap: onDoubletap,
drag: onDrag,
dragstart: onDragStart,
dragend: onDragEnd,
move: onMove,
down: onDown,
up: onUp,
wheel: onWheel
},
SYMBOL = Symbol('__tfw.gestures__'),
// Webkit and Opera still use 'mousewheel' event type.
WHEEL_EVENT = function () {
// Modern browsers support "wheel"
if ("onwheel" in document.createElement("div")) return "wheel"; // Webkit and IE support at least "mousewheel"
if (typeof document.onmousewheel !== 'undefined') return "mousewheel"; // let's assume that remaining browsers are older Firefox
return "DOMMouseScroll";
}(),
SUPPORTED_EVENTS = Object.keys(HANDLERS);
var Hammer = require("external.hammer");
var Gesture =
/*#__PURE__*/
function () {
function Gesture(element) {
_classCallCheck(this, Gesture);
Object.defineProperty(this, '$', {
writable: false,
value: element,
configurable: false
});
this._events = {}; // Last time a touch start occurs. This is used to prevent onmousedown to be triggered if a
// touchstart has been processed.
this._touchstart = 0;
}
/**
* Two syntaxes: on( name, slot, args) or on( slot, args ).
* In the second case, name is 'tap'.
*
* @param {string|function} arg1 - name or slot.
* @param {function|any} arg2 - slot or args.
* @param {any} arg3 - args or undefined.
* @returns {object} this.
*/
_createClass(Gesture, [{
key: "on",
value: function on(arg1, arg2, arg3) {
var syntax1 = typeof arg1 === 'function',
name = syntax1 ? "tap" : arg1,
slot = syntax1 ? arg1 : arg2,
args = syntax1 ? arg2 : arg3;
try {
ensureValidGestureNameAndSlot(name, slot);
HANDLERS[name].call(this, doRegister.bind(this), slot, args);
return this;
} catch (ex) {
console.error("[Gesture.on( name, slot, args )]");
console.error(" name", name);
console.error(" slot", slot);
console.error(" args", args);
console.error(" ERROR", ex);
throw Error(ex);
}
}
}]);
return Gesture;
}();
/**
* Return the associated gesture object. If it does not exist, create it.
*
* @param {[type]} element_ [description]
* @returns {[type]} [description]
*/
function getGesture(element_) {
var element = ensureDom(element_);
if (!element[SYMBOL]) element[SYMBOL] = new Gesture(element);
return element[SYMBOL];
}
/**
* We map a chain of responsability to each hammer event we need to deal with.
* When an item of that chain returns `true` that means it will take the responsability and we do
* not ask the others.
*/
function handlerWithChainOfResponsability(eventName, evt) {
var chain = this._events[eventName].chain;
for (var i = 0; i < chain.length; i++) {
var responsible = chain[i];
if (responsible(evt) === true) return;
}
}
/**
* Add a responsability item in the chain of a hammer event.
*/
function doRegister(event, responsible) {
var hammerEvent = getEventNameForPrefix(event, "hammer.");
if (hammerEvent && !this._hammer) {
this._hammer = new Hammer(this.$, {
domEvents: true
}); // To get domEvents.stopPropagation() available.
this._hammer.domEvents = true;
}
var eventDef = this._events[event];
if (!eventDef) {
var handler = handlerWithChainOfResponsability.bind(this, event);
eventDef = {
chain: [],
handler: handler
};
if (hammerEvent) this._hammer.on(hammerEvent, handler);else this.$.addEventListener(event, handler);
this._events[event] = eventDef;
}
eventDef.chain.push(responsible);
}
function ensureValidGestureNameAndSlot(name, slot) {
if (typeof name !== 'string') {
throw Error("[Gestures.on] `name` must be a string: " + JSON(name) + "!");
}
if (SUPPORTED_EVENTS.indexOf(name) === -1) {
throw Error("Unknown gesture's name `" + name + "`!\n" + "Available names are: " + SUPPORTED_EVENTS.join(", ") + ".");
}
if (typeof slot !== 'function') {
throw Error("Gesture `" + name + "` must have a function as slot!");
}
}
function ensureDom(dom) {
if (dom instanceof Node) return dom;
if (dom === undefined || dom === null) {
throw Error("Not a valid DOM element!", dom);
}
if (dom.$ instanceof Node) return dom.$;
if (dom.element instanceof Node) return dom.element;
if (typeof dom === 'string') {
var elem = document.getElementById(dom);
if (!elem) {
console.error("There is no DOM element with this ID: `" + dom + "`");
}
return elem;
}
if (typeof dom.element === 'function') return dom.element();
return dom;
}
;
function setHammerXY(elem, evt) {
var x, y; // Hammer's attributes.
x = evt.center.x;
y = evt.center.y;
var rect = elem.getBoundingClientRect();
evt.x = x - rect.left;
evt.y = y - rect.top;
}
function setXY(elem, evt) {
var x, y; // Browser's attributes.
x = evt.clientX;
y = evt.clientY;
var rect = elem.getBoundingClientRect();
return {
x: x - rect.left,
y: y - rect.top
};
}
function setHammerVxVy(elem, evt) {
evt.vx = evt.x - this._dragX;
evt.vy = evt.y - this._dragY;
evt.x0 = evt.x - evt.deltaX;
evt.y0 = evt.y - evt.deltaY;
this._dragX = evt.x;
this._dragY = evt.y;
}
function onTap(register, slot, args) {
var that = this;
register('hammer.tap', function (evt) {
if (evt.tapCount !== 1) return false;
setHammerXY(that.$, evt);
slot({
x: evt.x,
y: evt.y,
target: evt.target,
preventDefault: evt.preventDefault.bind(evt)
});
return true;
});
}
function onDoubletap(register, slot, args) {
var that = this;
register('hammer.tap', function (evt) {
if (evt.tapCount !== 2) return false;
setHammerXY(that.$, evt);
slot({
x: evt.x,
y: evt.y,
target: evt.target,
preventDefault: evt.preventDefault.bind(evt)
});
return true;
});
}
function onWheel(register, slot, args) {
var that = this;
register(WHEEL_EVENT, function (evt) {
var newEvt = setXY(that.$, evt);
newEvt.delta = evt.deltaY;
if (typeof newEvt.delta !== 'number') {
// IE 11.
newEvt.delta = -evt.wheelDelta;
}
newEvt.preventDefault = evt.preventDefault.bind(evt);
newEvt.stopPropagation = evt.stopPropagation.bind(evt);
slot(newEvt);
});
}
function onMove(register, slot) {
var that = this;
register('mousemove', function (evt) {
var newEvt = setXY(that.$, evt);
newEvt.preventDefault = evt.preventDefault.bind(evt);
newEvt.stopPropagation = evt.stopPropagation.bind(evt);
newEvt.event = evt;
slot(newEvt);
});
}
/**
* Dragging is moving while touching.
*
* @this Gesture
* @param {function} register - Hammer register function.
* @param {function} slot - Function to call when the event occurs.
* @param {any} args - Any argument to send to the slot.
* @returns {undefined}
*/
function onDrag(register, slot, args) {
var that = this;
register('hammer.pan', function (evt) {
if (evt.isFinal) return false;
setHammerXY(that.$, evt);
if (typeof that._dragX === 'undefined') {
that._dragX = evt.x;
that._dragY = evt.y;
that._dragStart = true;
}
setHammerVxVy.call(that, that.$, evt);
var domEvt = evt.srcEvent;
slot({
x: evt.x,
y: evt.y,
x0: evt.x0,
y0: evt.y0,
vx: evt.vx,
vy: evt.vy,
sx: evt.velocityX,
sy: evt.velocityY,
event: evt,
target: evt.target,
buttons: getButtons(evt),
preventDefault: domEvt.preventDefault.bind(domEvt),
stopPropagation: domEvt.stopImmediatePropagation.bind(domEvt)
}, args);
return true;
});
}
/**
* Get the information on buttons pressed.
* This is a cumulative value because several buttons can be pressed at the same time:
* 1: left mouse button.
* 2: right mouse button.
* 4: middle mouse button.
* Then, if the result is 3 (1+2), it means that the left and the right mouse buttons are pressed.
*
* @param {object} hammerEvent - Hammer event.
* @param {integer} hammerEvent.srcEvent.buttons - The information we need.
* @returns {integer} A betwise OR of the pressed buttons.
*/
function getButtons(hammerEvent) {
if (!hammerEvent || !hammerEvent.srcEvent) return 0;
var buttons = hammerEvent.srcEvent.buttons;
if (typeof buttons === 'number') return buttons;
return 0;
}
function onDragEnd(register, slot, args) {
var that = this;
register('hammer.panend', function (evt) {
setHammerXY(that.$, evt);
setHammerVxVy.call(that, that.$, evt);
var domEvt = evt.srcEvent;
slot({
x: evt.x,
y: evt.y,
x0: evt.x0,
y0: evt.y0,
target: evt.target,
preventDefault: domEvt.preventDefault.bind(domEvt),
stopPropagation: domEvt.stopImmediatePropagation.bind(domEvt)
});
delete that._dragX;
delete that._dragY;
return true;
});
}
function onDragStart(register, slot, args) {
var that = this;
register('hammer.panstart', function (evt) {
console.log("START");
setHammerXY.call(that, that.$, evt);
var domEvt = evt.srcEvent;
slot({
x: evt.x,
y: evt.y,
target: evt.target,
preventDefault: domEvt.preventDefault.bind(domEvt),
stopPropagation: domEvt.stopImmediatePropagation.bind(domEvt)
});
return true;
});
}
function onDown(register, slot, args) {
var that = this;
register("touchstart", function (evt) {
if (!evt.changedTouches || evt.changedTouches.length < 1) return false;
var touch = evt.changedTouches[0];
var rect = that.$.getBoundingClientRect();
try {
slot({
x: touch.clientX - rect.left,
y: touch.clientY - rect.top,
preventDefault: evt.preventDefault.bind(evt),
stopPropagation: evt.stopPropagation.bind(evt)
});
} catch (ex) {
console.error(ex);
}
return true;
});
register("mousedown", function (evt) {
var now = Date.now();
if (now - that._touchstart < 350) {
evt.preventDefault();
evt.stopPropagation();
return false;
}
var rect = that.$.getBoundingClientRect();
try {
slot({
x: evt.clientX - rect.left,
y: evt.clientY - rect.top,
preventDefault: evt.preventDefault.bind(evt),
stopPropagation: evt.stopPropagation.bind(evt)
});
} catch (ex) {
console.error(ex);
}
that._touchstart = 0;
return true;
});
}
function onUp(register, slot, args) {
var that = this;
register("touchend", function (evt) {
if (!evt.changedTouches || evt.changedTouches.length < 1) return false;
var touch = evt.changedTouches[0];
var rect = that.$.getBoundingClientRect();
try {
slot({
x: touch.clientX - rect.left,
y: touch.clientY - rect.top,
preventDefault: evt.preventDefault.bind(evt),
stopPropagation: evt.stopPropagation.bind(evt)
});
} catch (ex) {
console.error(ex);
}
that._touchstart = Date.now();
return true;
});
register("mouseup", function (evt) {
if (that._touchstart > 0) {
evt.preventDefault();
evt.stopPropagation();
return false;
}
var rect = that.$.getBoundingClientRect();
try {
slot({
x: evt.clientX - rect.left,
y: evt.clientY - rect.top,
preventDefault: evt.preventDefault.bind(evt),
stopPropagation: evt.stopPropagation.bind(evt)
});
} catch (ex) {
console.error(ex);
}
that._touchstart = 0;
return true;
});
}
function getEventNameForPrefix(text, prefix) {
if (text.substr(0, prefix.length) == prefix) {
return text.substr(prefix.length);
}
return null;
}
module.exports._ = _;
});