// 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 Emoji Palette implementation. This provides a UI widget for * choosing an emoji from a palette of possible choices. EmojiPalettes are * contained within EmojiPickers. * * See ../demos/popupemojipicker.html for an example of how to instantiate * an emoji picker. * * Based on goog.ui.ColorPicker (colorpicker.js). * */ goog.provide('goog.ui.emoji.EmojiPalette'); goog.require('goog.events.EventType'); goog.require('goog.net.ImageLoader'); goog.require('goog.ui.Palette'); goog.require('goog.ui.emoji.Emoji'); goog.require('goog.ui.emoji.EmojiPaletteRenderer'); /** * A page of emoji to be displayed in an EmojiPicker. * * @param {Array>} emoji List of emoji for this page. * @param {?string=} opt_urlPrefix Prefix that should be prepended to all URL. * @param {goog.ui.PaletteRenderer=} opt_renderer Renderer used to render or * decorate the palette; defaults to {@link goog.ui.PaletteRenderer}. * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper. * @extends {goog.ui.Palette} * @constructor * @final */ goog.ui.emoji.EmojiPalette = function( emoji, opt_urlPrefix, opt_renderer, opt_domHelper) { goog.ui.Palette.call( this, null, opt_renderer || new goog.ui.emoji.EmojiPaletteRenderer(null), opt_domHelper); /** * All the different emoji that this palette can display. Maps emoji ids * (string) to the goog.ui.emoji.Emoji for that id. * * @type {Object} * @private */ this.emojiCells_ = {}; /** * Map of emoji id to index into this.emojiCells_. * * @type {Object} * @private */ this.emojiMap_ = {}; /** * List of the animated emoji in this palette. Each internal array is of type * [HTMLDivElement, goog.ui.emoji.Emoji], and represents the palette item * for that animated emoji, and the Emoji object. * * @type {Array>} * @private */ this.animatedEmoji_ = []; this.urlPrefix_ = opt_urlPrefix || ''; /** * Palette items that are displayed on this page of the emoji picker. Each * item is a div wrapped around a div or an img. * * @type {Array} * @private */ this.emoji_ = this.getEmojiArrayFromProperties_(emoji); this.setContent(this.emoji_); }; goog.inherits(goog.ui.emoji.EmojiPalette, goog.ui.Palette); /** * Indicates a prefix that should be prepended to all URLs of images in this * emojipalette. This provides an optimization if the URLs are long, so that * the client does not have to send a long string for each emoji. * * @type {string} * @private */ goog.ui.emoji.EmojiPalette.prototype.urlPrefix_ = ''; /** * Whether the emoji images have been loaded. * * @type {boolean} * @private */ goog.ui.emoji.EmojiPalette.prototype.imagesLoaded_ = false; /** * Image loader for loading animated emoji. * * @type {goog.net.ImageLoader} * @private */ goog.ui.emoji.EmojiPalette.prototype.imageLoader_; /** * Helps create an array of emoji palette items from an array of emoji * properties. Each element will be either a div with background-image set to * a sprite, or an img element pointing directly to an emoji, and all elements * are wrapped with an outer div for alignment issues (i.e., this allows * centering the inner div). * * @param {Object} emojiGroup The group of emoji for this page. * @return {!Array} The emoji items. * @private */ goog.ui.emoji.EmojiPalette.prototype.getEmojiArrayFromProperties_ = function( emojiGroup) { var emojiItems = []; for (var i = 0; i < emojiGroup.length; i++) { var url = emojiGroup[i][0]; var id = emojiGroup[i][1]; var spriteInfo = emojiGroup[i][2]; var displayUrl = spriteInfo ? spriteInfo.getUrl() : this.urlPrefix_ + url; var item = this.getRenderer().createPaletteItem( this.getDomHelper(), id, spriteInfo, displayUrl); emojiItems.push(item); var emoji = new goog.ui.emoji.Emoji(url, id); this.emojiCells_[id] = emoji; this.emojiMap_[id] = i; // Keep track of sprited emoji that are animated, for later loading. if (spriteInfo && spriteInfo.isAnimated()) { this.animatedEmoji_.push([item, emoji]); } } // Create the image loader now so that tests can access it before it has // started loading images. if (this.animatedEmoji_.length > 0) { this.imageLoader_ = new goog.net.ImageLoader(); } this.imagesLoaded_ = true; return emojiItems; }; /** * Sends off requests for all the animated emoji and replaces their static * sprites when the images are done downloading. */ goog.ui.emoji.EmojiPalette.prototype.loadAnimatedEmoji = function() { if (this.animatedEmoji_.length > 0) { for (var i = 0; i < this.animatedEmoji_.length; i++) { var emoji = /** @type {goog.ui.emoji.Emoji} */ (this.animatedEmoji_[i][1]); var url = this.urlPrefix_ + emoji.getUrl(); this.imageLoader_.addImage(emoji.getId(), url); } this.getHandler().listen( this.imageLoader_, goog.events.EventType.LOAD, this.handleImageLoad_); this.imageLoader_.start(); } }; /** * Handles image load events from the ImageLoader. * * @param {goog.events.Event} e The event object. * @private */ goog.ui.emoji.EmojiPalette.prototype.handleImageLoad_ = function(e) { var id = e.target.id; var url = e.target.src; // Just to be safe, we check to make sure we have an id and src url from // the event target, which the ImageLoader sets to an Image object. if (id && url) { var item = this.emoji_[this.emojiMap_[id]]; if (item) { this.getRenderer().updateAnimatedPaletteItem(item, e.target); } } }; /** * Returns the image loader that this palette uses. Used for testing. * * @return {goog.net.ImageLoader} the image loader. */ goog.ui.emoji.EmojiPalette.prototype.getImageLoader = function() { return this.imageLoader_; }; /** @override */ goog.ui.emoji.EmojiPalette.prototype.disposeInternal = function() { goog.ui.emoji.EmojiPalette.superClass_.disposeInternal.call(this); if (this.imageLoader_) { this.imageLoader_.dispose(); this.imageLoader_ = null; } this.animatedEmoji_ = null; this.emojiCells_ = null; this.emojiMap_ = null; this.emoji_ = null; }; /** * Returns a goomoji id from an img or the containing td, or null if none * exists for that element. * * @param {Element} el The element to get the Goomoji id from. * @return {?string} A goomoji id from an img or the containing td, or null if * none exists for that element. * @private */ goog.ui.emoji.EmojiPalette.prototype.getGoomojiIdFromElement_ = function(el) { if (!el) { return null; } var item = this.getRenderer().getContainingItem(this, el); if (item) { return item.getAttribute(goog.ui.emoji.Emoji.ATTRIBUTE) != '' ? item.getAttribute(goog.ui.emoji.Emoji.ATTRIBUTE) : item.getAttribute(goog.ui.emoji.Emoji.DATA_ATTRIBUTE); } return null; }; /** * @return {goog.ui.emoji.Emoji} The currently selected emoji from this palette. */ goog.ui.emoji.EmojiPalette.prototype.getSelectedEmoji = function() { var elem = /** @type {Element} */ (this.getSelectedItem()); var goomojiId = this.getGoomojiIdFromElement_(elem); return this.emojiCells_[goomojiId]; }; /** * @return {number} The number of emoji managed by this palette. */ goog.ui.emoji.EmojiPalette.prototype.getNumberOfEmoji = function() { return this.emojiCells_.length; }; /** * Returns the index of the specified emoji within this palette. * * @param {string} id Id of the emoji to look up. * @return {number} The index of the specified emoji within this palette. */ goog.ui.emoji.EmojiPalette.prototype.getEmojiIndex = function(id) { return this.emojiMap_[id]; };