// Copyright 2007 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS-IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /** * @fileoverview Popup Emoji Picker implementation. This provides a UI widget * for choosing an emoji from a grid of possible choices. The widget is a popup, * so it is suitable for a toolbar, for instance the TrogEdit toolbar. * * @see ../demos/popupemojipicker.html for an example of how to instantiate * an emoji picker. * * See goog.ui.emoji.EmojiPicker in emojipicker.js for more details. * * Based on goog.ui.PopupColorPicker (popupcolorpicker.js). * * @see ../../demos/popupemojipicker.html */ goog.provide('goog.ui.emoji.PopupEmojiPicker'); goog.require('goog.events.EventType'); goog.require('goog.positioning.AnchoredPosition'); goog.require('goog.positioning.Corner'); goog.require('goog.ui.Component'); goog.require('goog.ui.Popup'); goog.require('goog.ui.emoji.EmojiPicker'); /** * Constructs a popup emoji picker widget. * * @param {string} defaultImgUrl Url of the img that should be used to fill up * the cells in the emoji table, to prevent jittering. Should be the same * size as the emoji. * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper. * @extends {goog.ui.Component} * @constructor * @final */ goog.ui.emoji.PopupEmojiPicker = function(defaultImgUrl, opt_domHelper) { goog.ui.Component.call(this, opt_domHelper); this.emojiPicker_ = new goog.ui.emoji.EmojiPicker(defaultImgUrl, opt_domHelper); this.addChild(this.emojiPicker_); this.getHandler().listen( this.emojiPicker_, goog.ui.Component.EventType.ACTION, this.onEmojiPicked_); }; goog.inherits(goog.ui.emoji.PopupEmojiPicker, goog.ui.Component); /** * Instance of an emoji picker control. * @type {goog.ui.emoji.EmojiPicker} * @private */ goog.ui.emoji.PopupEmojiPicker.prototype.emojiPicker_ = null; /** * Instance of goog.ui.Popup used to manage the behavior of the emoji picker. * @type {goog.ui.Popup} * @private */ goog.ui.emoji.PopupEmojiPicker.prototype.popup_ = null; /** * Reference to the element that triggered the last popup. * @type {Element} * @private */ goog.ui.emoji.PopupEmojiPicker.prototype.lastTarget_ = null; /** * Whether the emoji picker can accept focus. * @type {boolean} * @private */ goog.ui.emoji.PopupEmojiPicker.prototype.focusable_ = true; /** * If true, then the emojipicker will toggle off if it is already visible. * Default is true. * @type {boolean} * @private */ goog.ui.emoji.PopupEmojiPicker.prototype.toggleMode_ = true; /** * Adds a group of emoji to the picker. * * @param {string|Element} title Title for the group. * @param {Array>} emojiGroup A new group of emoji to be added. Each * internal array contains [emojiUrl, emojiId]. */ goog.ui.emoji.PopupEmojiPicker.prototype.addEmojiGroup = function( title, emojiGroup) { this.emojiPicker_.addEmojiGroup(title, emojiGroup); }; /** * Sets whether the emoji picker should toggle if it is already open. * @param {boolean} toggle The toggle mode to use. */ goog.ui.emoji.PopupEmojiPicker.prototype.setToggleMode = function(toggle) { this.toggleMode_ = toggle; }; /** * Gets whether the emojipicker is in toggle mode * @return {boolean} toggle. */ goog.ui.emoji.PopupEmojiPicker.prototype.getToggleMode = function() { return this.toggleMode_; }; /** * Sets whether loading of images should be delayed until after dom creation. * Thus, this function must be called before {@link #createDom}. If set to true, * the client must call {@link #loadImages} when they wish the images to be * loaded. * * @param {boolean} shouldDelay Whether to delay loading the images. */ goog.ui.emoji.PopupEmojiPicker.prototype.setDelayedLoad = function( shouldDelay) { if (this.emojiPicker_) { this.emojiPicker_.setDelayedLoad(shouldDelay); } }; /** * Sets whether the emoji picker can accept focus. * @param {boolean} focusable Whether the emoji picker should accept focus. */ goog.ui.emoji.PopupEmojiPicker.prototype.setFocusable = function(focusable) { this.focusable_ = focusable; if (this.emojiPicker_) { // TODO(user): In next revision sort the behavior of passing state to // children correctly this.emojiPicker_.setFocusable(focusable); } }; /** * Sets the URL prefix for the emoji URLs. * * @param {string} urlPrefix Prefix that should be prepended to all URLs. */ goog.ui.emoji.PopupEmojiPicker.prototype.setUrlPrefix = function(urlPrefix) { this.emojiPicker_.setUrlPrefix(urlPrefix); }; /** * Sets the location of the tabs in relation to the emoji grids. This should * only be called before the picker has been rendered. * * @param {goog.ui.TabPane.TabLocation} tabLocation The location of the tabs. */ goog.ui.emoji.PopupEmojiPicker.prototype.setTabLocation = function( tabLocation) { this.emojiPicker_.setTabLocation(tabLocation); }; /** * Sets the number of rows per grid in the emoji picker. This should only be * called before the picker has been rendered. * * @param {number} numRows Number of rows per grid. */ goog.ui.emoji.PopupEmojiPicker.prototype.setNumRows = function(numRows) { this.emojiPicker_.setNumRows(numRows); }; /** * Sets the number of columns per grid in the emoji picker. This should only be * called before the picker has been rendered. * * @param {number} numCols Number of columns per grid. */ goog.ui.emoji.PopupEmojiPicker.prototype.setNumColumns = function(numCols) { this.emojiPicker_.setNumColumns(numCols); }; /** * Sets the progressive rendering aspect of this emojipicker. Must be called * before createDom to have an effect. * * @param {boolean} progressive Whether the picker should render progressively. */ goog.ui.emoji.PopupEmojiPicker.prototype.setProgressiveRender = function( progressive) { if (this.emojiPicker_) { this.emojiPicker_.setProgressiveRender(progressive); } }; /** * Returns the number of emoji groups in this picker. * * @return {number} The number of emoji groups in this picker. */ goog.ui.emoji.PopupEmojiPicker.prototype.getNumEmojiGroups = function() { return this.emojiPicker_.getNumEmojiGroups(); }; /** * Causes the emoji imgs to be loaded into the picker. Used for delayed loading. */ goog.ui.emoji.PopupEmojiPicker.prototype.loadImages = function() { if (this.emojiPicker_) { this.emojiPicker_.loadImages(); } }; /** @override */ goog.ui.emoji.PopupEmojiPicker.prototype.createDom = function() { goog.ui.emoji.PopupEmojiPicker.superClass_.createDom.call(this); this.emojiPicker_.createDom(); this.getElement().className = goog.getCssName('goog-ui-popupemojipicker'); this.getElement().appendChild(this.emojiPicker_.getElement()); this.popup_ = new goog.ui.Popup(this.getElement()); this.getElement().unselectable = 'on'; }; /** @override */ goog.ui.emoji.PopupEmojiPicker.prototype.disposeInternal = function() { goog.ui.emoji.PopupEmojiPicker.superClass_.disposeInternal.call(this); this.emojiPicker_ = null; this.lastTarget_ = null; if (this.popup_) { this.popup_.dispose(); this.popup_ = null; } }; /** * Attaches the popup emoji picker to an element. * * @param {Element} element The element to attach to. */ goog.ui.emoji.PopupEmojiPicker.prototype.attach = function(element) { // TODO(user): standardize event type, popups should use MOUSEDOWN, but // currently apps are using click. this.getHandler().listen(element, goog.events.EventType.CLICK, this.show_); }; /** * Detatches the popup emoji picker from an element. * * @param {Element} element The element to detach from. */ goog.ui.emoji.PopupEmojiPicker.prototype.detach = function(element) { this.getHandler().unlisten(element, goog.events.EventType.CLICK, this.show_); }; /** * @return {goog.ui.emoji.EmojiPicker} The emoji picker instance. */ goog.ui.emoji.PopupEmojiPicker.prototype.getEmojiPicker = function() { return this.emojiPicker_; }; /** * Returns whether the Popup dismisses itself when the user clicks outside of * it. * @return {boolean} Whether the Popup autohides on an external click. */ goog.ui.emoji.PopupEmojiPicker.prototype.getAutoHide = function() { return !!this.popup_ && this.popup_.getAutoHide(); }; /** * Sets whether the Popup dismisses itself when the user clicks outside of it - * must be called after the Popup has been created (in createDom()), * otherwise it does nothing. * * @param {boolean} autoHide Whether to autohide on an external click. */ goog.ui.emoji.PopupEmojiPicker.prototype.setAutoHide = function(autoHide) { if (this.popup_) { this.popup_.setAutoHide(autoHide); } }; /** * Returns the region inside which the Popup dismisses itself when the user * clicks, or null if it was not set. Null indicates the entire document is * the autohide region. * @return {Element} The DOM element for autohide, or null if it hasn't been * set. */ goog.ui.emoji.PopupEmojiPicker.prototype.getAutoHideRegion = function() { return this.popup_ && this.popup_.getAutoHideRegion(); }; /** * Sets the region inside which the Popup dismisses itself when the user * clicks - must be called after the Popup has been created (in createDom()), * otherwise it does nothing. * * @param {Element} element The DOM element for autohide. */ goog.ui.emoji.PopupEmojiPicker.prototype.setAutoHideRegion = function(element) { if (this.popup_) { this.popup_.setAutoHideRegion(element); } }; /** * Returns the {@link goog.ui.PopupBase} from this picker. Returns null if the * popup has not yet been created. * * NOTE: This should *ONLY* be called from tests. If called before createDom(), * this should return null. * * @return {goog.ui.PopupBase?} The popup, or null if it hasn't been created. */ goog.ui.emoji.PopupEmojiPicker.prototype.getPopup = function() { return this.popup_; }; /** * @return {Element} The last element that triggered the popup. */ goog.ui.emoji.PopupEmojiPicker.prototype.getLastTarget = function() { return this.lastTarget_; }; /** * @return {goog.ui.emoji.Emoji} The currently selected emoji. */ goog.ui.emoji.PopupEmojiPicker.prototype.getSelectedEmoji = function() { return this.emojiPicker_.getSelectedEmoji(); }; /** * Handles click events on the element this picker is attached to and shows the * emoji picker in a popup. * * @param {goog.events.BrowserEvent} e The browser event. * @private */ goog.ui.emoji.PopupEmojiPicker.prototype.show_ = function(e) { if (this.popup_.isOrWasRecentlyVisible() && this.toggleMode_ && this.lastTarget_ == e.currentTarget) { this.popup_.setVisible(false); return; } this.lastTarget_ = /** @type {Element} */ (e.currentTarget); this.popup_.setPosition( new goog.positioning.AnchoredPosition( this.lastTarget_, goog.positioning.Corner.BOTTOM_LEFT)); this.popup_.setVisible(true); }; /** * Handles selection of an emoji. * * @param {goog.events.Event} e The event object. * @private */ goog.ui.emoji.PopupEmojiPicker.prototype.onEmojiPicked_ = function(e) { this.popup_.setVisible(false); };