Index: third_party/google_input_tools/src/chrome/os/inputview/elements/content/emojiview.js |
diff --git a/third_party/google_input_tools/src/chrome/os/inputview/elements/content/emojiview.js b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/emojiview.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..239650be78f392e526b0385c9bf6b80b56175d62 |
--- /dev/null |
+++ b/third_party/google_input_tools/src/chrome/os/inputview/elements/content/emojiview.js |
@@ -0,0 +1,423 @@ |
+// 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.elements.content.EmojiView'); |
+ |
+goog.require('goog.array'); |
+goog.require('goog.dom.classlist'); |
+goog.require('i18n.input.chrome.inputview.Css'); |
+goog.require('i18n.input.chrome.inputview.SpecNodeName'); |
+goog.require('i18n.input.chrome.inputview.elements.ElementType'); |
+goog.require('i18n.input.chrome.inputview.elements.content.KeysetView'); |
+goog.require('i18n.input.chrome.inputview.events.EventType'); |
+goog.require('i18n.input.chrome.inputview.handler.PointerHandler'); |
+ |
+ |
+goog.scope(function() { |
+var ElementType = i18n.input.chrome.inputview.elements.ElementType; |
+var EventType = i18n.input.chrome.inputview.events.EventType; |
+var KeysetView = i18n.input.chrome.inputview.elements.content.KeysetView; |
+var PointerHandler = i18n.input.chrome.inputview.handler.PointerHandler; |
+var Css = i18n.input.chrome.inputview.Css; |
+var SpecNodeName = i18n.input.chrome.inputview.SpecNodeName; |
+var ExtendedLayout = i18n.input.chrome.inputview.elements.layout.ExtendedLayout; |
+var PageIndicator = i18n.input.chrome.inputview.elements.content.PageIndicator; |
+ |
+ |
+ |
+/** |
+ * The emoji view. |
+ * |
+ * @param {!Object} keyData The data includes soft key definition and key |
+ * mapping. |
+ * @param {!Object} layoutData The layout definition. |
+ * @param {string} keyboardCode The keyboard code. |
+ * @param {string} languageCode The language code. |
+ * @param {!i18n.input.chrome.inputview.Model} model The model. |
+ * @param {string} name The Input Tool name. |
+ * @param {!goog.events.EventTarget=} opt_eventTarget . |
+ * @param {i18n.input.chrome.inputview.Adapter=} opt_adapter . |
+ * @constructor |
+ * @extends {KeysetView} |
+ */ |
+i18n.input.chrome.inputview.elements.content.EmojiView = function(keyData, |
+ layoutData, keyboardCode, languageCode, model, name, opt_eventTarget, |
+ opt_adapter) { |
+ i18n.input.chrome.inputview.elements.content.EmojiView.base(this, |
+ 'constructor', keyData, layoutData, keyboardCode, languageCode, model, |
+ name, opt_eventTarget, opt_adapter); |
+ |
+ /** |
+ * The number of keys per emoji page. |
+ * |
+ * @private {number} |
+ */ |
+ this.keysPerPage_ = 27; |
+ |
+ /** |
+ * The number of tabbar keys. |
+ * |
+ * @private {number} |
+ */ |
+ this.totalTabbars_ = keyData[SpecNodeName.TEXT].length; |
+ |
+ /** |
+ * The first page offset of each category. |
+ * |
+ * @private {!Array.<number>} |
+ */ |
+ this.pageOffsets_ = []; |
+ |
+ /** |
+ * The number of pages for each category. |
+ * |
+ * @private {!Array.<number>} |
+ */ |
+ this.pagesInCategory_ = []; |
+ |
+ // Calculate the emojiPageoffset_ and totalPages_ according to keydata. |
+ var pageNum = 0; |
+ for (var i = 0, len = keyData[SpecNodeName.TEXT].length; i < len; ++i) { |
+ this.pageOffsets_.push(pageNum); |
+ pageNum += Math.ceil( |
+ keyData[SpecNodeName.TEXT][i].length / this.keysPerPage_); |
+ } |
+ |
+ /** |
+ * The category of each emoji page. |
+ * |
+ * @private {!Array.<number>} |
+ */ |
+ this.pageToCategory_ = []; |
+ |
+ // Calculate the pageToCategory_ according to keydata. |
+ for (var i = 0, len = keyData[SpecNodeName.TEXT].length; i < len; ++i) { |
+ var lenJ = Math.ceil( |
+ keyData[SpecNodeName.TEXT][i].length / this.keysPerPage_); |
+ for (var j = 0; j < lenJ; ++j) { |
+ this.pageToCategory_.push(i); |
+ } |
+ this.pagesInCategory_.push(lenJ); |
+ } |
+ |
+ /** |
+ * The list of recent used emoji. |
+ * |
+ * @private {Array.<string>} |
+ */ |
+ this.recentEmojiList_ = []; |
+ |
+ /** |
+ * The emoji keys on the recent page. |
+ * |
+ * @private {Array.<i18n.input.chrome.inputview.elements.content.EmojiKey>} |
+ */ |
+ this.recentEmojiKeys_ = []; |
+ |
+ /** |
+ * The tabbars of the emoji view. |
+ * |
+ * @private {Array.<i18n.input.chrome.inputview.elements.content.TabBarKey>} |
+ */ |
+ this.tabbarKeys_ = []; |
+}; |
+var EmojiView = i18n.input.chrome.inputview.elements.content.EmojiView; |
+goog.inherits(EmojiView, KeysetView); |
+ |
+ |
+/** |
+ * The emoji rows of the emoji slider. |
+ * |
+ * @private {!i18n.input.chrome.inputview.elements.layout.ExtendedLayout} |
+ */ |
+EmojiView.prototype.emojiRows_; |
+ |
+ |
+/** |
+ * The indicator of the emoji page index. |
+ * |
+ * @private {!i18n.input.chrome.inputview.elements.content.PageIndicator} |
+ */ |
+EmojiView.prototype.pageIndicator_; |
+ |
+ |
+/** |
+ * Whether it is a drag event. |
+ * |
+ * @type {boolean} |
+ */ |
+EmojiView.prototype.isDragging = false; |
+ |
+ |
+/** |
+ * Whether it is a drag event. |
+ * |
+ * @private {number} |
+ */ |
+EmojiView.prototype.categoryID_ = 0; |
+ |
+ |
+/** |
+ * The timestamp of the last pointer down event. |
+ * |
+ * @private {number} |
+ */ |
+EmojiView.prototype.pointerDownTimeStamp_ = 0; |
+ |
+ |
+/** |
+ * The drag distance of a drag event. |
+ * |
+ * @private {number} |
+ */ |
+EmojiView.prototype.dragDistance_ = 0; |
+ |
+ |
+/** |
+ * The maximal required time interval for quick emoji page swipe in ms. |
+ * |
+ * @private {number} |
+ */ |
+EmojiView.EMOJI_DRAG_INTERVAL_ = 300; |
+ |
+ |
+/** |
+ * The minimal required drag distance for quick emoji page swipe in px. |
+ * |
+ * @private {number} |
+ */ |
+EmojiView.EMOJI_DRAG_DISTANCE_ = 60; |
+ |
+ |
+/** @private {!PointerHandler} */ |
+EmojiView.prototype.pointerHandler_; |
+ |
+ |
+/** @override */ |
+EmojiView.prototype.createDom = function() { |
+ goog.base(this, 'createDom'); |
+ var elem = this.getElement(); |
+ if (elem) { |
+ this.pointerHandler_ = new PointerHandler(elem); |
+ } |
+ this.getHandler(). |
+ listen(this.pointerHandler_, EventType.POINTER_DOWN, |
+ this.onPointerDown_). |
+ listen(this.pointerHandler_, EventType.POINTER_UP, this.onPointerUp_). |
+ listen(this.pointerHandler_, EventType.DRAG, this.onDragEvent_). |
+ listen(this.pointerHandler_, EventType.LONG_PRESS, this.onLongPress_); |
+ this.emojiRows_ = |
+ /** @type {!ExtendedLayout} */ (this.getChildViewById('emojiRows')); |
+ this.pageIndicator_ = |
+ /** @type {!PageIndicator} */ |
+ (this.getChildViewById('indicator-background')); |
+ for (var i = 0; i < this.keysPerPage_; i++) { |
+ this.recentEmojiKeys_.push( |
+ /** @type {!i18n.input.chrome.inputview.elements.content.EmojiKey} */ |
+ (this.getChildViewById('emojikey' + i))); |
+ } |
+ for (var i = 0; i < this.totalTabbars_; i++) { |
+ this.tabbarKeys_.push( |
+ /** @type {!i18n.input.chrome.inputview.elements.content.TabBarKey} */ |
+ (this.getChildViewById('Tabbar' + i))); |
+ } |
+}; |
+ |
+ |
+/** |
+ * Handles the pointer down event. |
+ * |
+ * @param {!i18n.input.chrome.inputview.events.PointerEvent} e . |
+ * @private |
+ */ |
+EmojiView.prototype.onPointerDown_ = function(e) { |
+ var view = e.view; |
+ if (view.type == ElementType.EMOJI_KEY) { |
+ this.pointerDownTimeStamp_ = e.timestamp; |
+ this.dragDistance_ = 0; |
+ return; |
+ } |
+}; |
+ |
+ |
+/** |
+ * Handles the pointer up event. |
+ * |
+ * @param {!i18n.input.chrome.inputview.events.PointerEvent} e . |
+ * @private |
+ */ |
+EmojiView.prototype.onPointerUp_ = function(e) { |
+ var view = e.view; |
+ switch (view.type) { |
+ case ElementType.EMOJI_KEY: |
+ if (this.isDragging) { |
+ var interval = e.timestamp - this.pointerDownTimeStamp_; |
+ if (interval < EmojiView.EMOJI_DRAG_INTERVAL_ && |
+ Math.abs(this.dragDistance_) >= EmojiView.EMOJI_DRAG_DISTANCE_) { |
+ this.adjustMarginLeft_(this.dragDistance_); |
+ } else { |
+ this.adjustMarginLeft_(); |
+ } |
+ |
+ this.isDragging = false; |
+ } else if (view.text != '') { |
+ this.setRecentEmoji_(view.text); |
+ } |
+ this.update(); |
+ return; |
+ case ElementType.TAB_BAR_KEY: |
+ this.updateCategory_(view); |
+ this.updateTabbarBorder_(); |
+ return; |
+ } |
+}; |
+ |
+ |
+/** |
+ * Handles the drag event. |
+ * |
+ * @param {!i18n.input.chrome.inputview.events.PointerEvent} e . |
+ * @private |
+ */ |
+EmojiView.prototype.onDragEvent_ = function(e) { |
+ var view = e.view; |
+ this.isDragging = true; |
+ if (view.type == ElementType.EMOJI_KEY) { |
+ this.setEmojiMarginLeft_(e.deltaX); |
+ this.dragDistance_ += e.deltaX; |
+ } |
+}; |
+ |
+ |
+/** |
+ * Handles the long press event. |
+ * |
+ * @param {!i18n.input.chrome.inputview.events.PointerEvent} e . |
+ * @private |
+ */ |
+EmojiView.prototype.onLongPress_ = function(e) { |
+ var view = e.view; |
+ view.setHighlighted(this.isDragging == false && view.text != ''); |
+}; |
+ |
+ |
+/** @override */ |
+EmojiView.prototype.disposeInternal = function() { |
+ goog.dispose(this.pointerHandler_); |
+ |
+ goog.base(this, 'disposeInternal'); |
+}; |
+ |
+ |
+/** |
+ * Set the margin left of the emoji slider. |
+ * |
+ * @param {number} deltaX The margin left value. |
+ * @private |
+ */ |
+EmojiView.prototype.setEmojiMarginLeft_ = function(deltaX) { |
+ this.emojiRows_.slide(deltaX); |
+ this.pageIndicator_.slide(-deltaX, |
+ this.pagesInCategory_[this.categoryID_]); |
+}; |
+ |
+ |
+/** |
+ * Update the current emoji category. |
+ * |
+ * @param {i18n.input.chrome.inputview.elements.Element} view The view. |
+ * @private |
+ */ |
+EmojiView.prototype.updateCategory_ = function(view) { |
+ this.categoryID_ = view.toCategory; |
+ this.emojiRows_.updateCategory(this.pageOffsets_[this.categoryID_]); |
+ this.pageIndicator_.gotoPage(0, |
+ this.pagesInCategory_[this.categoryID_]); |
+ this.updateTabbarBorder_(); |
+}; |
+ |
+ |
+/** |
+ * Adjust the margin left to the nearest page. |
+ * |
+ * @param {number=} opt_distance The distance to adjust to. |
+ * @private |
+ */ |
+EmojiView.prototype.adjustMarginLeft_ = function(opt_distance) { |
+ var pageNum = this.emojiRows_.adjustMarginLeft(opt_distance); |
+ this.categoryID_ = this.pageToCategory_[pageNum]; |
+ this.pageIndicator_.gotoPage( |
+ pageNum - this.pageOffsets_[this.categoryID_], |
+ this.pagesInCategory_[this.categoryID_]); |
+ this.updateTabbarBorder_(); |
+ |
+}; |
+ |
+ |
+/** |
+ * Clear all the states for the emoji. |
+ * |
+ */ |
+EmojiView.prototype.clearEmojiStates = function() { |
+ this.categoryID_ = 1; |
+ this.emojiRows_.updateCategory(1); |
+ this.pageIndicator_.gotoPage(0, this.pagesInCategory_[1]); |
+ this.updateTabbarBorder_(); |
+}; |
+ |
+ |
+/** |
+ * Sets the recent emoji. |
+ * |
+ * @param {string} text The recent emoji text. |
+ * @private |
+ */ |
+EmojiView.prototype.setRecentEmoji_ = function(text) { |
+ goog.array.insertAt(this.recentEmojiList_, text, 0); |
+ goog.array.removeDuplicates(this.recentEmojiList_); |
+ var len = this.recentEmojiList_.length; |
+ for (var i = 0; i < this.keysPerPage_; i++) { |
+ var newText = i < len ? this.recentEmojiList_[i] : ''; |
+ this.recentEmojiKeys_[i].updateText(newText); |
+ } |
+}; |
+ |
+ |
+/** |
+ * Update the tabbar's border. |
+ * |
+ * @private |
+ */ |
+EmojiView.prototype.updateTabbarBorder_ = function() { |
+ for (var i = 0, len = this.totalTabbars_; i < len; i++) { |
+ this.tabbarKeys_[i].updateBorder(this.categoryID_); |
+ } |
+}; |
+ |
+ |
+/** @override */ |
+EmojiView.prototype.activate = function(rawKeyset) { |
+ this.adapter.setEmojiInputToolCode(); |
+ goog.dom.classlist.add(this.getElement().parentElement.parentElement, |
+ Css.EMOJI); |
+ this.clearEmojiStates(); |
+}; |
+ |
+ |
+/** @override */ |
+EmojiView.prototype.deactivate = function(rawKeyset) { |
+ this.adapter.unsetEmojiInputToolCode(); |
+ goog.dom.classlist.remove(this.getElement().parentElement.parentElement, |
+ Css.EMOJI); |
+}; |
+}); // goog.scope |