blob: 77518c4b820dad9a14448852fe71ff0960dcc7a5 [file] [log] [blame]
// 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<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<Array<(HTMLDivElement|goog.ui.emoji.Emoji)>>}
* @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<HTMLDivElement>}
* @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<!HTMLDivElement>} 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);
return item ? item.getAttribute(goog.ui.emoji.Emoji.ATTRIBUTE) : 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];
};