emojipaletterenderer.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Emoji Palette renderer implementation.
  16. *
  17. */
  18. goog.provide('goog.ui.emoji.EmojiPaletteRenderer');
  19. goog.require('goog.a11y.aria');
  20. goog.require('goog.asserts');
  21. goog.require('goog.dom.NodeType');
  22. goog.require('goog.dom.TagName');
  23. goog.require('goog.dom.classlist');
  24. goog.require('goog.style');
  25. goog.require('goog.ui.PaletteRenderer');
  26. goog.require('goog.ui.emoji.Emoji');
  27. /**
  28. * Renders an emoji palette.
  29. *
  30. * @param {?string} defaultImgUrl Url of the img that should be used to fill up
  31. * the cells in the emoji table, to prevent jittering. Will be stretched
  32. * to the emoji cell size. A good image is a transparent dot.
  33. * @constructor
  34. * @extends {goog.ui.PaletteRenderer}
  35. */
  36. goog.ui.emoji.EmojiPaletteRenderer = function(defaultImgUrl) {
  37. goog.ui.PaletteRenderer.call(this);
  38. this.defaultImgUrl_ = defaultImgUrl;
  39. };
  40. goog.inherits(goog.ui.emoji.EmojiPaletteRenderer, goog.ui.PaletteRenderer);
  41. /**
  42. * Globally unique ID sequence for cells rendered by this renderer class.
  43. * @type {number}
  44. * @private
  45. */
  46. goog.ui.emoji.EmojiPaletteRenderer.cellId_ = 0;
  47. /**
  48. * Url of the img that should be used for cells in the emoji palette that are
  49. * not filled with emoji, i.e., after all the emoji have already been placed
  50. * on a page.
  51. *
  52. * @type {?string}
  53. * @private
  54. */
  55. goog.ui.emoji.EmojiPaletteRenderer.prototype.defaultImgUrl_ = null;
  56. /** @override */
  57. goog.ui.emoji.EmojiPaletteRenderer.getCssClass = function() {
  58. return goog.getCssName('goog-ui-emojipalette');
  59. };
  60. /**
  61. * Creates a palette item from the given emoji data.
  62. *
  63. * @param {goog.dom.DomHelper} dom DOM helper for constructing DOM elements.
  64. * @param {string} id Goomoji id for the emoji.
  65. * @param {goog.ui.emoji.SpriteInfo} spriteInfo Spriting info for the emoji.
  66. * @param {string} displayUrl URL of the image served for this cell, whether
  67. * an individual emoji image or a sprite.
  68. * @return {!HTMLDivElement} The palette item for this emoji.
  69. */
  70. goog.ui.emoji.EmojiPaletteRenderer.prototype.createPaletteItem = function(
  71. dom, id, spriteInfo, displayUrl) {
  72. var el;
  73. if (spriteInfo) {
  74. var cssClass = spriteInfo.getCssClass();
  75. if (cssClass) {
  76. el = dom.createDom(goog.dom.TagName.DIV, cssClass);
  77. } else {
  78. el = this.buildElementFromSpriteMetadata(dom, spriteInfo, displayUrl);
  79. }
  80. } else {
  81. el = dom.createDom(goog.dom.TagName.IMG, {'src': displayUrl});
  82. }
  83. var outerdiv = dom.createDom(
  84. goog.dom.TagName.DIV, goog.getCssName('goog-palette-cell-wrapper'), el);
  85. outerdiv.setAttribute(goog.ui.emoji.Emoji.ATTRIBUTE, id);
  86. outerdiv.setAttribute(goog.ui.emoji.Emoji.DATA_ATTRIBUTE, id);
  87. return /** @type {!HTMLDivElement} */ (outerdiv);
  88. };
  89. /**
  90. * Modifies a palette item containing an animated emoji, in response to the
  91. * animated emoji being successfully downloaded.
  92. *
  93. * @param {Element} item The palette item to update.
  94. * @param {Image} animatedImg An Image object containing the animated emoji.
  95. */
  96. goog.ui.emoji.EmojiPaletteRenderer.prototype.updateAnimatedPaletteItem =
  97. function(item, animatedImg) {
  98. // An animated emoji is one that had sprite info for a static version and is
  99. // now being updated. See createPaletteItem for the structure of the palette
  100. // items we're modifying.
  101. var inner = /** @type {Element} */ (item.firstChild);
  102. goog.asserts.assert(inner);
  103. // The first case is a palette item with a CSS class representing the sprite,
  104. // and an animated emoji.
  105. var classes = goog.dom.classlist.get(inner);
  106. if (classes && classes.length == 1) {
  107. inner.className = '';
  108. }
  109. goog.style.setStyle(inner, {
  110. 'width': animatedImg.width,
  111. 'height': animatedImg.height,
  112. 'background-image': 'url(' + animatedImg.src + ')',
  113. 'background-position': '0 0'
  114. });
  115. };
  116. /**
  117. * Builds the inner contents of a palette item out of sprite metadata.
  118. *
  119. * @param {goog.dom.DomHelper} dom DOM helper for constructing DOM elements.
  120. * @param {goog.ui.emoji.SpriteInfo} spriteInfo The metadata to create the css
  121. * for the sprite.
  122. * @param {string} displayUrl The URL of the image for this cell.
  123. * @return {HTMLDivElement} The inner element for a palette item.
  124. */
  125. goog.ui.emoji.EmojiPaletteRenderer.prototype.buildElementFromSpriteMetadata =
  126. function(dom, spriteInfo, displayUrl) {
  127. var width = spriteInfo.getWidthCssValue();
  128. var height = spriteInfo.getHeightCssValue();
  129. var x = spriteInfo.getXOffsetCssValue();
  130. var y = spriteInfo.getYOffsetCssValue();
  131. var el = dom.createDom(goog.dom.TagName.DIV);
  132. goog.style.setStyle(el, {
  133. 'width': width,
  134. 'height': height,
  135. 'background-image': 'url(' + displayUrl + ')',
  136. 'background-repeat': 'no-repeat',
  137. 'background-position': x + ' ' + y
  138. });
  139. return /** @type {!HTMLDivElement} */ (el);
  140. };
  141. /** @override */
  142. goog.ui.emoji.EmojiPaletteRenderer.prototype.createCell = function(node, dom) {
  143. // Create a cell with the default img if we're out of items, in order to
  144. // prevent jitter in the table. If there's no default img url, just create an
  145. // empty div, to prevent trying to fetch a null url.
  146. if (!node) {
  147. var elem = this.defaultImgUrl_ ?
  148. dom.createDom(goog.dom.TagName.IMG, {src: this.defaultImgUrl_}) :
  149. dom.createDom(goog.dom.TagName.DIV);
  150. node = dom.createDom(
  151. goog.dom.TagName.DIV, goog.getCssName('goog-palette-cell-wrapper'),
  152. elem);
  153. }
  154. var cell = dom.createDom(
  155. goog.dom.TagName.TD, {
  156. 'class': goog.getCssName(this.getCssClass(), 'cell'),
  157. // Cells must have an ID, for accessibility, so we generate one here.
  158. 'id': this.getCssClass() + '-cell-' +
  159. goog.ui.emoji.EmojiPaletteRenderer.cellId_++
  160. },
  161. node);
  162. goog.a11y.aria.setRole(cell, 'gridcell');
  163. return cell;
  164. };
  165. /**
  166. * Returns the item corresponding to the given node, or null if the node is
  167. * neither a palette cell nor part of a palette item.
  168. * @param {goog.ui.Palette} palette Palette in which to look for the item.
  169. * @param {Node} node Node to look for.
  170. * @return {Node} The corresponding palette item (null if not found).
  171. * @override
  172. */
  173. goog.ui.emoji.EmojiPaletteRenderer.prototype.getContainingItem = function(
  174. palette, node) {
  175. var root = palette.getElement();
  176. while (node && node.nodeType == goog.dom.NodeType.ELEMENT && node != root) {
  177. if (node.tagName == goog.dom.TagName.TD) {
  178. return node.firstChild;
  179. }
  180. node = node.parentNode;
  181. }
  182. return null;
  183. };