/** * Kendo UI v2016.1.112 (http://www.telerik.com/kendo-ui) * Copyright 2016 Telerik AD. All rights reserved. * * Kendo UI commercial licenses may be obtained at * http://www.telerik.com/purchase/license-agreement/kendo-ui-complete * If you do not own a commercial license, this file shall be governed by the trial license terms. */ (function (f, define) { define('kendo.userevents', ['kendo.core'], f); }(function () { var __meta__ = { id: 'userevents', name: 'User Events', category: 'framework', depends: ['core'], hidden: true }; (function ($, undefined) { var kendo = window.kendo, support = kendo.support, document = window.document, Class = kendo.Class, Observable = kendo.Observable, now = $.now, extend = $.extend, OS = support.mobileOS, invalidZeroEvents = OS && OS.android, DEFAULT_MIN_HOLD = 800, DEFAULT_THRESHOLD = support.browser.msie ? 5 : 0, PRESS = 'press', HOLD = 'hold', SELECT = 'select', START = 'start', MOVE = 'move', END = 'end', CANCEL = 'cancel', TAP = 'tap', RELEASE = 'release', GESTURESTART = 'gesturestart', GESTURECHANGE = 'gesturechange', GESTUREEND = 'gestureend', GESTURETAP = 'gesturetap'; var THRESHOLD = { 'api': 0, 'touch': 0, 'mouse': 9, 'pointer': 9 }; var ENABLE_GLOBAL_SURFACE = !support.touch || support.mouseAndTouchPresent; function touchDelta(touch1, touch2) { var x1 = touch1.x.location, y1 = touch1.y.location, x2 = touch2.x.location, y2 = touch2.y.location, dx = x1 - x2, dy = y1 - y2; return { center: { x: (x1 + x2) / 2, y: (y1 + y2) / 2 }, distance: Math.sqrt(dx * dx + dy * dy) }; } function getTouches(e) { var touches = [], originalEvent = e.originalEvent, currentTarget = e.currentTarget, idx = 0, length, changedTouches, touch; if (e.api) { touches.push({ id: 2, event: e, target: e.target, currentTarget: e.target, location: e, type: 'api' }); } else if (e.type.match(/touch/)) { changedTouches = originalEvent ? originalEvent.changedTouches : []; for (length = changedTouches.length; idx < length; idx++) { touch = changedTouches[idx]; touches.push({ location: touch, event: e, target: touch.target, currentTarget: currentTarget, id: touch.identifier, type: 'touch' }); } } else if (support.pointers || support.msPointers) { touches.push({ location: originalEvent, event: e, target: e.target, currentTarget: currentTarget, id: originalEvent.pointerId, type: 'pointer' }); } else { touches.push({ id: 1, event: e, target: e.target, currentTarget: currentTarget, location: e, type: 'mouse' }); } return touches; } var TouchAxis = Class.extend({ init: function (axis, location) { var that = this; that.axis = axis; that._updateLocationData(location); that.startLocation = that.location; that.velocity = that.delta = 0; that.timeStamp = now(); }, move: function (location) { var that = this, offset = location['page' + that.axis], timeStamp = now(), timeDelta = timeStamp - that.timeStamp || 1; if (!offset && invalidZeroEvents) { return; } that.delta = offset - that.location; that._updateLocationData(location); that.initialDelta = offset - that.startLocation; that.velocity = that.delta / timeDelta; that.timeStamp = timeStamp; }, _updateLocationData: function (location) { var that = this, axis = that.axis; that.location = location['page' + axis]; that.client = location['client' + axis]; that.screen = location['screen' + axis]; } }); var Touch = Class.extend({ init: function (userEvents, target, touchInfo) { extend(this, { x: new TouchAxis('X', touchInfo.location), y: new TouchAxis('Y', touchInfo.location), type: touchInfo.type, useClickAsTap: userEvents.useClickAsTap, threshold: userEvents.threshold || THRESHOLD[touchInfo.type], userEvents: userEvents, target: target, currentTarget: touchInfo.currentTarget, initialTouch: touchInfo.target, id: touchInfo.id, pressEvent: touchInfo, _moved: false, _finished: false }); }, press: function () { this._holdTimeout = setTimeout($.proxy(this, '_hold'), this.userEvents.minHold); this._trigger(PRESS, this.pressEvent); }, _hold: function () { this._trigger(HOLD, this.pressEvent); }, move: function (touchInfo) { var that = this; if (that._finished) { return; } that.x.move(touchInfo.location); that.y.move(touchInfo.location); if (!that._moved) { if (that._withinIgnoreThreshold()) { return; } if (!UserEvents.current || UserEvents.current === that.userEvents) { that._start(touchInfo); } else { return that.dispose(); } } if (!that._finished) { that._trigger(MOVE, touchInfo); } }, end: function (touchInfo) { this.endTime = now(); if (this._finished) { return; } this._finished = true; this._trigger(RELEASE, touchInfo); if (this._moved) { this._trigger(END, touchInfo); } else { if (!this.useClickAsTap) { this._trigger(TAP, touchInfo); } } clearTimeout(this._holdTimeout); this.dispose(); }, dispose: function () { var userEvents = this.userEvents, activeTouches = userEvents.touches; this._finished = true; this.pressEvent = null; clearTimeout(this._holdTimeout); activeTouches.splice($.inArray(this, activeTouches), 1); }, skip: function () { this.dispose(); }, cancel: function () { this.dispose(); }, isMoved: function () { return this._moved; }, _start: function (touchInfo) { clearTimeout(this._holdTimeout); this.startTime = now(); this._moved = true; this._trigger(START, touchInfo); }, _trigger: function (name, touchInfo) { var that = this, jQueryEvent = touchInfo.event, data = { touch: that, x: that.x, y: that.y, target: that.target, event: jQueryEvent }; if (that.userEvents.notify(name, data)) { jQueryEvent.preventDefault(); } }, _withinIgnoreThreshold: function () { var xDelta = this.x.initialDelta, yDelta = this.y.initialDelta; return Math.sqrt(xDelta * xDelta + yDelta * yDelta) <= this.threshold; } }); function withEachUpEvent(callback) { var downEvents = kendo.eventMap.up.split(' '), idx = 0, length = downEvents.length; for (; idx < length; idx++) { callback(downEvents[idx]); } } var UserEvents = Observable.extend({ init: function (element, options) { var that = this, filter, ns = kendo.guid(); options = options || {}; filter = that.filter = options.filter; that.threshold = options.threshold || DEFAULT_THRESHOLD; that.minHold = options.minHold || DEFAULT_MIN_HOLD; that.touches = []; that._maxTouches = options.multiTouch ? 2 : 1; that.allowSelection = options.allowSelection; that.captureUpIfMoved = options.captureUpIfMoved; that.useClickAsTap = !options.fastTap && !support.delayedClick(); that.eventNS = ns; element = $(element).handler(that); Observable.fn.init.call(that); extend(that, { element: element, surface: options.global && ENABLE_GLOBAL_SURFACE ? $(document.documentElement) : $(options.surface || element), stopPropagation: options.stopPropagation, pressed: false }); that.surface.handler(that).on(kendo.applyEventMap('move', ns), '_move').on(kendo.applyEventMap('up cancel', ns), '_end'); element.on(kendo.applyEventMap('down', ns), filter, '_start'); if (that.useClickAsTap) { element.on(kendo.applyEventMap('click', ns), filter, '_click'); } if (support.pointers || support.msPointers) { if (support.browser.version < 11) { element.css('-ms-touch-action', 'pinch-zoom double-tap-zoom'); } else { element.css('touch-action', 'pan-y'); } } if (options.preventDragEvent) { element.on(kendo.applyEventMap('dragstart', ns), kendo.preventDefault); } element.on(kendo.applyEventMap('mousedown', ns), filter, { root: element }, '_select'); if (that.captureUpIfMoved && support.eventCapture) { var surfaceElement = that.surface[0], preventIfMovingProxy = $.proxy(that.preventIfMoving, that); withEachUpEvent(function (eventName) { surfaceElement.addEventListener(eventName, preventIfMovingProxy, true); }); } that.bind([ PRESS, HOLD, TAP, START, MOVE, END, RELEASE, CANCEL, GESTURESTART, GESTURECHANGE, GESTUREEND, GESTURETAP, SELECT ], options); }, preventIfMoving: function (e) { if (this._isMoved()) { e.preventDefault(); } }, destroy: function () { var that = this; if (that._destroyed) { return; } that._destroyed = true; if (that.captureUpIfMoved && support.eventCapture) { var surfaceElement = that.surface[0]; withEachUpEvent(function (eventName) { surfaceElement.removeEventListener(eventName, that.preventIfMoving); }); } that.element.kendoDestroy(that.eventNS); that.surface.kendoDestroy(that.eventNS); that.element.removeData('handler'); that.surface.removeData('handler'); that._disposeAll(); that.unbind(); delete that.surface; delete that.element; delete that.currentTarget; }, capture: function () { UserEvents.current = this; }, cancel: function () { this._disposeAll(); this.trigger(CANCEL); }, notify: function (eventName, data) { var that = this, touches = that.touches; if (this._isMultiTouch()) { switch (eventName) { case MOVE: eventName = GESTURECHANGE; break; case END: eventName = GESTUREEND; break; case TAP: eventName = GESTURETAP; break; } extend(data, { touches: touches }, touchDelta(touches[0], touches[1])); } return this.trigger(eventName, extend(data, { type: eventName })); }, press: function (x, y, target) { this._apiCall('_start', x, y, target); }, move: function (x, y) { this._apiCall('_move', x, y); }, end: function (x, y) { this._apiCall('_end', x, y); }, _isMultiTouch: function () { return this.touches.length > 1; }, _maxTouchesReached: function () { return this.touches.length >= this._maxTouches; }, _disposeAll: function () { var touches = this.touches; while (touches.length > 0) { touches.pop().dispose(); } }, _isMoved: function () { return $.grep(this.touches, function (touch) { return touch.isMoved(); }).length; }, _select: function (e) { if (!this.allowSelection || this.trigger(SELECT, { event: e })) { e.preventDefault(); } }, _start: function (e) { var that = this, idx = 0, filter = that.filter, target, touches = getTouches(e), length = touches.length, touch, which = e.which; if (which && which > 1 || that._maxTouchesReached()) { return; } UserEvents.current = null; that.currentTarget = e.currentTarget; if (that.stopPropagation) { e.stopPropagation(); } for (; idx < length; idx++) { if (that._maxTouchesReached()) { break; } touch = touches[idx]; if (filter) { target = $(touch.currentTarget); } else { target = that.element; } if (!target.length) { continue; } touch = new Touch(that, target, touch); that.touches.push(touch); touch.press(); if (that._isMultiTouch()) { that.notify('gesturestart', {}); } } }, _move: function (e) { this._eachTouch('move', e); }, _end: function (e) { this._eachTouch('end', e); }, _click: function (e) { var data = { touch: { initialTouch: e.target, target: $(e.currentTarget), endTime: now(), x: { location: e.pageX, client: e.clientX }, y: { location: e.pageY, client: e.clientY } }, x: e.pageX, y: e.pageY, target: $(e.currentTarget), event: e, type: 'tap' }; if (this.trigger('tap', data)) { e.preventDefault(); } }, _eachTouch: function (methodName, e) { var that = this, dict = {}, touches = getTouches(e), activeTouches = that.touches, idx, touch, touchInfo, matchingTouch; for (idx = 0; idx < activeTouches.length; idx++) { touch = activeTouches[idx]; dict[touch.id] = touch; } for (idx = 0; idx < touches.length; idx++) { touchInfo = touches[idx]; matchingTouch = dict[touchInfo.id]; if (matchingTouch) { matchingTouch[methodName](touchInfo); } } }, _apiCall: function (type, x, y, target) { this[type]({ api: true, pageX: x, pageY: y, clientX: x, clientY: y, target: $(target || this.element)[0], stopPropagation: $.noop, preventDefault: $.noop }); } }); UserEvents.defaultThreshold = function (value) { DEFAULT_THRESHOLD = value; }; UserEvents.minHold = function (value) { DEFAULT_MIN_HOLD = value; }; kendo.getTouches = getTouches; kendo.touchDelta = touchDelta; kendo.UserEvents = UserEvents; }(window.kendo.jQuery)); return window.kendo; }, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) { (a3 || a2)(); }));