Index: third_party/google_input_tools/src/chrome/os/inputview/handler/pointeractionbundle.js |
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/handler/pointeractionbundle.js b/third_party/google_input_tools/src/chrome/os/inputview/handler/pointeractionbundle.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2d83e9fd4a0a0b259cc7a2dbdcfd60617c11952b |
--- /dev/null |
+++ b/third_party/google_input_tools/src/chrome/os/inputview/handler/pointeractionbundle.js |
@@ -0,0 +1,447 @@ |
+// Copyright 2014 The ChromeOS IME Authors. All Rights Reserved. |
+// limitations under the License. |
+// See the License for the specific language governing permissions and |
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+// distributed under the License is distributed on an "AS-IS" BASIS, |
+// Unless required by applicable law or agreed to in writing, software |
+// |
+// http://www.apache.org/licenses/LICENSE-2.0 |
+// |
+// You may obtain a copy of the License at |
+// you may not use this file except in compliance with the License. |
+// Licensed under the Apache License, Version 2.0 (the "License"); |
+// |
+goog.provide('i18n.input.chrome.inputview.handler.PointerActionBundle'); |
+ |
+goog.require('goog.Timer'); |
+goog.require('goog.dom'); |
+goog.require('goog.events.EventTarget'); |
+goog.require('goog.events.EventType'); |
+goog.require('goog.math.Coordinate'); |
+goog.require('i18n.input.chrome.inputview.SwipeDirection'); |
+goog.require('i18n.input.chrome.inputview.events.DragEvent'); |
+goog.require('i18n.input.chrome.inputview.events.EventType'); |
+goog.require('i18n.input.chrome.inputview.events.PointerEvent'); |
+goog.require('i18n.input.chrome.inputview.events.SwipeEvent'); |
+goog.require('i18n.input.chrome.inputview.handler.SwipeState'); |
+ |
+ |
+ |
+goog.scope(function() { |
+ |
+ |
+ |
+/** |
+ * The handler for long press. |
+ * |
+ * @param {!Node} target The target for this pointer event. |
+ * @param {goog.events.EventTarget=} opt_parentEventTarget The parent event |
+ * target. |
+ * @constructor |
+ * @extends {goog.events.EventTarget} |
+ */ |
+i18n.input.chrome.inputview.handler.PointerActionBundle = function(target, |
+ opt_parentEventTarget) { |
+ goog.base(this); |
+ this.setParentEventTarget(opt_parentEventTarget || null); |
+ |
+ /** |
+ * The target. |
+ * |
+ * @type {i18n.input.chrome.inputview.elements.Element} |
+ * @private |
+ */ |
+ this.view_ = this.getView_(target); |
+ |
+ /** |
+ * The swipe offset. |
+ * |
+ * @type {!i18n.input.chrome.inputview.handler.SwipeState} |
+ * @private |
+ */ |
+ this.swipeState_ = new i18n.input.chrome.inputview.handler.SwipeState(); |
+}; |
+goog.inherits(i18n.input.chrome.inputview.handler.PointerActionBundle, |
+ goog.events.EventTarget); |
+var PointerActionBundle = i18n.input.chrome.inputview.handler. |
+ PointerActionBundle; |
+ |
+ |
+/** |
+ * The current target after the touch point is moved. |
+ * |
+ * @type {!Node | Element} |
+ * @private |
+ */ |
+PointerActionBundle.prototype.currentTarget_; |
+ |
+ |
+/** |
+ * How many milli-seconds to evaluate a double click event. |
+ * |
+ * @type {number} |
+ * @private |
+ */ |
+PointerActionBundle.DOUBLE_CLICK_INTERVAL_ = 500; |
+ |
+ |
+/** |
+ * The timer ID. |
+ * |
+ * @type {number} |
+ * @private |
+ */ |
+PointerActionBundle.prototype.longPressTimer_; |
+ |
+ |
+/** |
+ * The minimum swipe distance. |
+ * |
+ * @type {number} |
+ * @private |
+ */ |
+PointerActionBundle.MINIMUM_SWIPE_DISTANCE_ = 20; |
+ |
+ |
+/** |
+ * The timestamp of the pointer down. |
+ * |
+ * @type {number} |
+ * @private |
+ */ |
+PointerActionBundle.prototype.pointerDownTimeStamp_ = 0; |
+ |
+ |
+/** |
+ * The timestamp of the pointer up. |
+ * |
+ * @type {number} |
+ * @private |
+ */ |
+PointerActionBundle.prototype.pointerUpTimeStamp_ = 0; |
+ |
+ |
+/** |
+ * True if it is double clicking. |
+ * |
+ * @type {boolean} |
+ * @private |
+ */ |
+PointerActionBundle.prototype.isDBLClicking_ = false; |
+ |
+ |
+/** |
+ * True if it is long pressing. |
+ * |
+ * @type {boolean} |
+ * @private |
+ */ |
+PointerActionBundle.prototype.isLongPressing_ = false; |
+ |
+ |
+/** |
+ * True if it is flickering. |
+ * |
+ * @type {boolean} |
+ * @private |
+ */ |
+PointerActionBundle.prototype.isFlickering_ = false; |
+ |
+ |
+/** |
+ * Gets the view. |
+ * |
+ * @param {Node} target . |
+ * @return {i18n.input.chrome.inputview.elements.Element} . |
+ * @private |
+ */ |
+PointerActionBundle.prototype.getView_ = function(target) { |
+ if (!target) { |
+ return null; |
+ } |
+ var element = /** @type {!Element} */ (target); |
+ var view = element['view']; |
+ while (!view && element) { |
+ view = element['view']; |
+ element = goog.dom.getParentElement(element); |
+ } |
+ return view; |
+}; |
+ |
+ |
+/** |
+ * Handles touchmove event for one target. |
+ * |
+ * @param {!Event} touchEvent . |
+ */ |
+PointerActionBundle.prototype.handleTouchMove = function(touchEvent) { |
+ var direction = 0; |
+ var deltaX = this.swipeState_.previousX == 0 ? 0 : (touchEvent.pageX - |
+ this.swipeState_.previousX); |
+ var deltaY = this.swipeState_.previousY == 0 ? 0 : |
+ (touchEvent.pageY - this.swipeState_.previousY); |
+ this.swipeState_.offsetX += deltaX; |
+ this.swipeState_.offsetY += deltaY; |
+ this.dispatchEvent(new i18n.input.chrome.inputview.events.DragEvent( |
+ this.view_, direction, /** @type {!Node} */ (touchEvent.target), |
+ touchEvent.pageX, touchEvent.pageY, deltaX, deltaY)); |
+ |
+ var minimumSwipeDist = PointerActionBundle. |
+ MINIMUM_SWIPE_DISTANCE_; |
+ |
+ if (this.swipeState_.offsetX > minimumSwipeDist) { |
+ direction |= i18n.input.chrome.inputview.SwipeDirection.RIGHT; |
+ this.swipeState_.offsetX = 0; |
+ } else if (this.swipeState_.offsetX < -minimumSwipeDist) { |
+ direction |= i18n.input.chrome.inputview.SwipeDirection.LEFT; |
+ this.swipeState_.offsetX = 0; |
+ } |
+ |
+ if (Math.abs(deltaY) > Math.abs(deltaX)) { |
+ if (this.swipeState_.offsetY > minimumSwipeDist) { |
+ direction |= i18n.input.chrome.inputview.SwipeDirection.DOWN; |
+ this.swipeState_.offsetY = 0; |
+ } else if (this.swipeState_.offsetY < -minimumSwipeDist) { |
+ direction |= i18n.input.chrome.inputview.SwipeDirection.UP; |
+ this.swipeState_.offsetY = 0; |
+ } |
+ } |
+ |
+ this.swipeState_.previousX = touchEvent.pageX; |
+ this.swipeState_.previousY = touchEvent.pageY; |
+ |
+ if (direction > 0) { |
+ // If there is any movement, cancel the longpress timer. |
+ goog.Timer.clear(this.longPressTimer_); |
+ this.dispatchEvent(new i18n.input.chrome.inputview.events.SwipeEvent( |
+ this.view_, direction, /** @type {!Node} */ (touchEvent.target), |
+ touchEvent.pageX, touchEvent.pageY)); |
+ var currentTargetView = this.getView_(this.currentTarget_); |
+ if (this.view_) { |
+ this.isFlickering_ = !this.isLongPressing_ && !!(this.view_.pointerConfig. |
+ flickerDirection & direction) && currentTargetView == this.view_; |
+ } |
+ } |
+ |
+ this.maybeSwitchTarget_(touchEvent); |
+}; |
+ |
+ |
+/** |
+ * If the target is switched to a new one, sends out a pointer_over for the new |
+ * target and sends out a pointer_out for the old target. |
+ * |
+ * @param {!Event | !goog.events.BrowserEvent} e . |
+ * @private |
+ */ |
+PointerActionBundle.prototype.maybeSwitchTarget_ = function(e) { |
+ if (!this.isFlickering_) { |
+ var pageOffset = this.getPageOffset_(e); |
+ var actualTarget = document.elementFromPoint(pageOffset.x, pageOffset.y); |
+ var currentTargetView = this.getView_(this.currentTarget_); |
+ var actualTargetView = this.getView_(actualTarget); |
+ if (currentTargetView != actualTargetView) { |
+ if (currentTargetView) { |
+ this.dispatchEvent(new i18n.input.chrome.inputview.events.PointerEvent( |
+ currentTargetView, |
+ i18n.input.chrome.inputview.events.EventType.POINTER_OUT, |
+ this.currentTarget_, pageOffset.x, pageOffset.y)); |
+ } |
+ if (actualTargetView) { |
+ this.dispatchEvent(new i18n.input.chrome.inputview.events.PointerEvent( |
+ actualTargetView, |
+ i18n.input.chrome.inputview.events.EventType.POINTER_OVER, |
+ actualTarget, pageOffset.x, pageOffset.y)); |
+ } |
+ this.currentTarget_ = actualTarget; |
+ } |
+ } |
+}; |
+ |
+ |
+/** |
+ * Handles pointer up, e.g., mouseup/touchend. |
+ * |
+ * @param {!goog.events.BrowserEvent} e The event. |
+ */ |
+PointerActionBundle.prototype.handlePointerUp = function(e) { |
+ goog.Timer.clear(this.longPressTimer_); |
+ var pageOffset = this.getPageOffset_(e); |
+ this.dispatchEvent(new i18n.input.chrome.inputview.events.PointerEvent( |
+ this.view_, i18n.input.chrome.inputview.events.EventType.LONG_PRESS_END, |
+ e.target, pageOffset.x, pageOffset.y)); |
+ if (this.isDBLClicking_) { |
+ this.dispatchEvent(new i18n.input.chrome.inputview.events.PointerEvent( |
+ this.view_, i18n.input.chrome.inputview.events.EventType. |
+ DOUBLE_CLICK_END, e.target, pageOffset.x, pageOffset.y)); |
+ } else if (!(this.isLongPressing_ && this.view_.pointerConfig. |
+ longPressWithoutPointerUp)) { |
+ if (this.isLongPressing_) { |
+ // If the finger didn't move but it triggers a longpress, it could cause |
+ // a target switch, so checks it here. |
+ this.maybeSwitchTarget_(e); |
+ } |
+ var view = this.getView_(this.currentTarget_); |
+ var target = this.currentTarget_; |
+ if (this.isFlickering_) { |
+ view = this.view_; |
+ target = e.target; |
+ } |
+ if (view) { |
+ this.pointerUpTimeStamp_ = new Date().getTime(); |
+ this.dispatchEvent(new i18n.input.chrome.inputview.events.PointerEvent( |
+ view, i18n.input.chrome.inputview.events.EventType.POINTER_UP, |
+ target, pageOffset.x, pageOffset.y, this.pointerUpTimeStamp_)); |
+ } |
+ } |
+ if (this.getView_(this.currentTarget_) == this.view_) { |
+ this.dispatchEvent(new i18n.input.chrome.inputview.events.PointerEvent( |
+ this.view_, i18n.input.chrome.inputview.events.EventType.CLICK, |
+ e.target, pageOffset.x, pageOffset.y)); |
+ } |
+ this.isDBLClicking_ = false; |
+ this.isLongPressing_ = false; |
+ this.isFlickering_ = false; |
+ this.swipeState_.reset(); |
+ |
+ e.preventDefault(); |
+ if (this.view_ && this.view_.pointerConfig.stopEventPropagation) { |
+ e.stopPropagation(); |
+ } |
+}; |
+ |
+ |
+/** |
+ * Cancel double click recognition on this target. |
+ */ |
+PointerActionBundle.prototype.cancelDoubleClick = function() { |
+ this.pointerDownTimeStamp_ = 0; |
+}; |
+ |
+ |
+/** |
+ * Handles pointer down, e.g., mousedown/touchstart. |
+ * |
+ * @param {!goog.events.BrowserEvent} e The event. |
+ */ |
+PointerActionBundle.prototype.handlePointerDown = function(e) { |
+ this.currentTarget_ = e.target; |
+ goog.Timer.clear(this.longPressTimer_); |
+ if (e.type != goog.events.EventType.MOUSEDOWN) { |
+ // Don't trigger long press for mouse event. |
+ this.maybeTriggerKeyDownLongPress_(e); |
+ } |
+ this.maybeHandleDBLClick_(e); |
+ if (!this.isDBLClicking_) { |
+ var pageOffset = this.getPageOffset_(e); |
+ this.dispatchEvent(new i18n.input.chrome.inputview.events.PointerEvent( |
+ this.view_, i18n.input.chrome.inputview.events.EventType.POINTER_DOWN, |
+ e.target, pageOffset.x, pageOffset.y, this.pointerDownTimeStamp_)); |
+ } |
+ |
+ if (this.view_ && this.view_.pointerConfig.preventDefault) { |
+ e.preventDefault(); |
+ } |
+ if (this.view_ && this.view_.pointerConfig.stopEventPropagation) { |
+ e.stopPropagation(); |
+ } |
+}; |
+ |
+ |
+/** |
+ * Gets the page offset from the event which may be mouse event or touch event. |
+ * |
+ * @param {!goog.events.BrowserEvent | !TouchEvent | !Event} e . |
+ * @return {!goog.math.Coordinate} . |
+ * @private |
+ */ |
+PointerActionBundle.prototype.getPageOffset_ = function(e) { |
+ if (e.pageX && e.pageY) { |
+ return new goog.math.Coordinate(e.pageX, e.pageY); |
+ } |
+ |
+ if (!e.getBrowserEvent) { |
+ return new goog.math.Coordinate(0, 0); |
+ } |
+ |
+ var nativeEvt = e.getBrowserEvent(); |
+ if (nativeEvt.pageX && nativeEvt.pageY) { |
+ return new goog.math.Coordinate(nativeEvt.pageX, nativeEvt.pageY); |
+ } |
+ |
+ |
+ var touchEventList = nativeEvt['changedTouches']; |
+ if (!touchEventList || touchEventList.length == 0) { |
+ touchEventList = nativeEvt['touches']; |
+ } |
+ if (touchEventList && touchEventList.length > 0) { |
+ var touchEvent = touchEventList[0]; |
+ return new goog.math.Coordinate(touchEvent.pageX, touchEvent.pageY); |
+ } |
+ |
+ return new goog.math.Coordinate(0, 0); |
+}; |
+ |
+ |
+/** |
+ * Maybe triggers the long press timer when pointer down. |
+ * |
+ * @param {!goog.events.BrowserEvent} e The event. |
+ * @private |
+ */ |
+PointerActionBundle.prototype.maybeTriggerKeyDownLongPress_ = function(e) { |
+ if (this.view_ && (this.view_.pointerConfig.longPressWithPointerUp || |
+ this.view_.pointerConfig.longPressWithoutPointerUp)) { |
+ this.longPressTimer_ = goog.Timer.callOnce( |
+ goog.bind(this.triggerLongPress_, this, e), |
+ this.view_.pointerConfig.longPressDelay, this); |
+ } |
+}; |
+ |
+ |
+/** |
+ * Maybe handle the double click. |
+ * |
+ * @param {!goog.events.BrowserEvent} e . |
+ * @private |
+ */ |
+PointerActionBundle.prototype.maybeHandleDBLClick_ = function(e) { |
+ if (this.view_ && this.view_.pointerConfig.dblClick) { |
+ var timeInMs = new Date().getTime(); |
+ var interval = this.view_.pointerConfig.dblClickDelay || |
+ PointerActionBundle.DOUBLE_CLICK_INTERVAL_; |
+ var nativeEvt = e.getBrowserEvent(); |
+ if ((timeInMs - this.pointerDownTimeStamp_) < interval) { |
+ this.dispatchEvent(new i18n.input.chrome.inputview.events.PointerEvent( |
+ this.view_, i18n.input.chrome.inputview.events.EventType.DOUBLE_CLICK, |
+ e.target, nativeEvt.pageX, nativeEvt.pageY)); |
+ this.isDBLClicking_ = true; |
+ } |
+ this.pointerDownTimeStamp_ = timeInMs; |
+ } |
+}; |
+ |
+ |
+/** |
+ * Triggers long press event. |
+ * |
+ * @param {!goog.events.BrowserEvent} e The event. |
+ * @private |
+ */ |
+PointerActionBundle.prototype.triggerLongPress_ = function(e) { |
+ var nativeEvt = e.getBrowserEvent(); |
+ this.dispatchEvent(new i18n.input.chrome.inputview.events.PointerEvent( |
+ this.view_, i18n.input.chrome.inputview.events.EventType.LONG_PRESS, |
+ e.target, nativeEvt.pageX, nativeEvt.pageY)); |
+ this.isLongPressing_ = true; |
+}; |
+ |
+ |
+/** @override */ |
+PointerActionBundle.prototype.disposeInternal = function() { |
+ goog.dispose(this.longPressTimer_); |
+ |
+ goog.base(this, 'disposeInternal'); |
+}; |
+ |
+}); // goog.scope |