popupemojipicker.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. // Copyright 2007 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 Popup Emoji Picker implementation. This provides a UI widget
  16. * for choosing an emoji from a grid of possible choices. The widget is a popup,
  17. * so it is suitable for a toolbar, for instance the TrogEdit toolbar.
  18. *
  19. * @see ../demos/popupemojipicker.html for an example of how to instantiate
  20. * an emoji picker.
  21. *
  22. * See goog.ui.emoji.EmojiPicker in emojipicker.js for more details.
  23. *
  24. * Based on goog.ui.PopupColorPicker (popupcolorpicker.js).
  25. *
  26. * @see ../../demos/popupemojipicker.html
  27. */
  28. goog.provide('goog.ui.emoji.PopupEmojiPicker');
  29. goog.require('goog.events.EventType');
  30. goog.require('goog.positioning.AnchoredPosition');
  31. goog.require('goog.positioning.Corner');
  32. goog.require('goog.ui.Component');
  33. goog.require('goog.ui.Popup');
  34. goog.require('goog.ui.emoji.EmojiPicker');
  35. /**
  36. * Constructs a popup emoji picker widget.
  37. *
  38. * @param {string} defaultImgUrl Url of the img that should be used to fill up
  39. * the cells in the emoji table, to prevent jittering. Should be the same
  40. * size as the emoji.
  41. * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper.
  42. * @extends {goog.ui.Component}
  43. * @constructor
  44. * @final
  45. */
  46. goog.ui.emoji.PopupEmojiPicker = function(defaultImgUrl, opt_domHelper) {
  47. goog.ui.Component.call(this, opt_domHelper);
  48. this.emojiPicker_ =
  49. new goog.ui.emoji.EmojiPicker(defaultImgUrl, opt_domHelper);
  50. this.addChild(this.emojiPicker_);
  51. this.getHandler().listen(
  52. this.emojiPicker_, goog.ui.Component.EventType.ACTION,
  53. this.onEmojiPicked_);
  54. };
  55. goog.inherits(goog.ui.emoji.PopupEmojiPicker, goog.ui.Component);
  56. /**
  57. * Instance of an emoji picker control.
  58. * @type {goog.ui.emoji.EmojiPicker}
  59. * @private
  60. */
  61. goog.ui.emoji.PopupEmojiPicker.prototype.emojiPicker_ = null;
  62. /**
  63. * Instance of goog.ui.Popup used to manage the behavior of the emoji picker.
  64. * @type {goog.ui.Popup}
  65. * @private
  66. */
  67. goog.ui.emoji.PopupEmojiPicker.prototype.popup_ = null;
  68. /**
  69. * Reference to the element that triggered the last popup.
  70. * @type {Element}
  71. * @private
  72. */
  73. goog.ui.emoji.PopupEmojiPicker.prototype.lastTarget_ = null;
  74. /**
  75. * Whether the emoji picker can accept focus.
  76. * @type {boolean}
  77. * @private
  78. */
  79. goog.ui.emoji.PopupEmojiPicker.prototype.focusable_ = true;
  80. /**
  81. * If true, then the emojipicker will toggle off if it is already visible.
  82. * Default is true.
  83. * @type {boolean}
  84. * @private
  85. */
  86. goog.ui.emoji.PopupEmojiPicker.prototype.toggleMode_ = true;
  87. /**
  88. * Adds a group of emoji to the picker.
  89. *
  90. * @param {string|Element} title Title for the group.
  91. * @param {Array<Array<?>>} emojiGroup A new group of emoji to be added. Each
  92. * internal array contains [emojiUrl, emojiId].
  93. */
  94. goog.ui.emoji.PopupEmojiPicker.prototype.addEmojiGroup = function(
  95. title, emojiGroup) {
  96. this.emojiPicker_.addEmojiGroup(title, emojiGroup);
  97. };
  98. /**
  99. * Sets whether the emoji picker should toggle if it is already open.
  100. * @param {boolean} toggle The toggle mode to use.
  101. */
  102. goog.ui.emoji.PopupEmojiPicker.prototype.setToggleMode = function(toggle) {
  103. this.toggleMode_ = toggle;
  104. };
  105. /**
  106. * Gets whether the emojipicker is in toggle mode
  107. * @return {boolean} toggle.
  108. */
  109. goog.ui.emoji.PopupEmojiPicker.prototype.getToggleMode = function() {
  110. return this.toggleMode_;
  111. };
  112. /**
  113. * Sets whether loading of images should be delayed until after dom creation.
  114. * Thus, this function must be called before {@link #createDom}. If set to true,
  115. * the client must call {@link #loadImages} when they wish the images to be
  116. * loaded.
  117. *
  118. * @param {boolean} shouldDelay Whether to delay loading the images.
  119. */
  120. goog.ui.emoji.PopupEmojiPicker.prototype.setDelayedLoad = function(
  121. shouldDelay) {
  122. if (this.emojiPicker_) {
  123. this.emojiPicker_.setDelayedLoad(shouldDelay);
  124. }
  125. };
  126. /**
  127. * Sets whether the emoji picker can accept focus.
  128. * @param {boolean} focusable Whether the emoji picker should accept focus.
  129. */
  130. goog.ui.emoji.PopupEmojiPicker.prototype.setFocusable = function(focusable) {
  131. this.focusable_ = focusable;
  132. if (this.emojiPicker_) {
  133. // TODO(user): In next revision sort the behavior of passing state to
  134. // children correctly
  135. this.emojiPicker_.setFocusable(focusable);
  136. }
  137. };
  138. /**
  139. * Sets the URL prefix for the emoji URLs.
  140. *
  141. * @param {string} urlPrefix Prefix that should be prepended to all URLs.
  142. */
  143. goog.ui.emoji.PopupEmojiPicker.prototype.setUrlPrefix = function(urlPrefix) {
  144. this.emojiPicker_.setUrlPrefix(urlPrefix);
  145. };
  146. /**
  147. * Sets the location of the tabs in relation to the emoji grids. This should
  148. * only be called before the picker has been rendered.
  149. *
  150. * @param {goog.ui.TabPane.TabLocation} tabLocation The location of the tabs.
  151. */
  152. goog.ui.emoji.PopupEmojiPicker.prototype.setTabLocation = function(
  153. tabLocation) {
  154. this.emojiPicker_.setTabLocation(tabLocation);
  155. };
  156. /**
  157. * Sets the number of rows per grid in the emoji picker. This should only be
  158. * called before the picker has been rendered.
  159. *
  160. * @param {number} numRows Number of rows per grid.
  161. */
  162. goog.ui.emoji.PopupEmojiPicker.prototype.setNumRows = function(numRows) {
  163. this.emojiPicker_.setNumRows(numRows);
  164. };
  165. /**
  166. * Sets the number of columns per grid in the emoji picker. This should only be
  167. * called before the picker has been rendered.
  168. *
  169. * @param {number} numCols Number of columns per grid.
  170. */
  171. goog.ui.emoji.PopupEmojiPicker.prototype.setNumColumns = function(numCols) {
  172. this.emojiPicker_.setNumColumns(numCols);
  173. };
  174. /**
  175. * Sets the progressive rendering aspect of this emojipicker. Must be called
  176. * before createDom to have an effect.
  177. *
  178. * @param {boolean} progressive Whether the picker should render progressively.
  179. */
  180. goog.ui.emoji.PopupEmojiPicker.prototype.setProgressiveRender = function(
  181. progressive) {
  182. if (this.emojiPicker_) {
  183. this.emojiPicker_.setProgressiveRender(progressive);
  184. }
  185. };
  186. /**
  187. * Returns the number of emoji groups in this picker.
  188. *
  189. * @return {number} The number of emoji groups in this picker.
  190. */
  191. goog.ui.emoji.PopupEmojiPicker.prototype.getNumEmojiGroups = function() {
  192. return this.emojiPicker_.getNumEmojiGroups();
  193. };
  194. /**
  195. * Causes the emoji imgs to be loaded into the picker. Used for delayed loading.
  196. */
  197. goog.ui.emoji.PopupEmojiPicker.prototype.loadImages = function() {
  198. if (this.emojiPicker_) {
  199. this.emojiPicker_.loadImages();
  200. }
  201. };
  202. /** @override */
  203. goog.ui.emoji.PopupEmojiPicker.prototype.createDom = function() {
  204. goog.ui.emoji.PopupEmojiPicker.superClass_.createDom.call(this);
  205. this.emojiPicker_.createDom();
  206. this.getElement().className = goog.getCssName('goog-ui-popupemojipicker');
  207. this.getElement().appendChild(this.emojiPicker_.getElement());
  208. this.popup_ = new goog.ui.Popup(this.getElement());
  209. this.getElement().unselectable = 'on';
  210. };
  211. /** @override */
  212. goog.ui.emoji.PopupEmojiPicker.prototype.disposeInternal = function() {
  213. goog.ui.emoji.PopupEmojiPicker.superClass_.disposeInternal.call(this);
  214. this.emojiPicker_ = null;
  215. this.lastTarget_ = null;
  216. if (this.popup_) {
  217. this.popup_.dispose();
  218. this.popup_ = null;
  219. }
  220. };
  221. /**
  222. * Attaches the popup emoji picker to an element.
  223. *
  224. * @param {Element} element The element to attach to.
  225. */
  226. goog.ui.emoji.PopupEmojiPicker.prototype.attach = function(element) {
  227. // TODO(user): standardize event type, popups should use MOUSEDOWN, but
  228. // currently apps are using click.
  229. this.getHandler().listen(element, goog.events.EventType.CLICK, this.show_);
  230. };
  231. /**
  232. * Detatches the popup emoji picker from an element.
  233. *
  234. * @param {Element} element The element to detach from.
  235. */
  236. goog.ui.emoji.PopupEmojiPicker.prototype.detach = function(element) {
  237. this.getHandler().unlisten(element, goog.events.EventType.CLICK, this.show_);
  238. };
  239. /**
  240. * @return {goog.ui.emoji.EmojiPicker} The emoji picker instance.
  241. */
  242. goog.ui.emoji.PopupEmojiPicker.prototype.getEmojiPicker = function() {
  243. return this.emojiPicker_;
  244. };
  245. /**
  246. * Returns whether the Popup dismisses itself when the user clicks outside of
  247. * it.
  248. * @return {boolean} Whether the Popup autohides on an external click.
  249. */
  250. goog.ui.emoji.PopupEmojiPicker.prototype.getAutoHide = function() {
  251. return !!this.popup_ && this.popup_.getAutoHide();
  252. };
  253. /**
  254. * Sets whether the Popup dismisses itself when the user clicks outside of it -
  255. * must be called after the Popup has been created (in createDom()),
  256. * otherwise it does nothing.
  257. *
  258. * @param {boolean} autoHide Whether to autohide on an external click.
  259. */
  260. goog.ui.emoji.PopupEmojiPicker.prototype.setAutoHide = function(autoHide) {
  261. if (this.popup_) {
  262. this.popup_.setAutoHide(autoHide);
  263. }
  264. };
  265. /**
  266. * Returns the region inside which the Popup dismisses itself when the user
  267. * clicks, or null if it was not set. Null indicates the entire document is
  268. * the autohide region.
  269. * @return {Element} The DOM element for autohide, or null if it hasn't been
  270. * set.
  271. */
  272. goog.ui.emoji.PopupEmojiPicker.prototype.getAutoHideRegion = function() {
  273. return this.popup_ && this.popup_.getAutoHideRegion();
  274. };
  275. /**
  276. * Sets the region inside which the Popup dismisses itself when the user
  277. * clicks - must be called after the Popup has been created (in createDom()),
  278. * otherwise it does nothing.
  279. *
  280. * @param {Element} element The DOM element for autohide.
  281. */
  282. goog.ui.emoji.PopupEmojiPicker.prototype.setAutoHideRegion = function(element) {
  283. if (this.popup_) {
  284. this.popup_.setAutoHideRegion(element);
  285. }
  286. };
  287. /**
  288. * Returns the {@link goog.ui.PopupBase} from this picker. Returns null if the
  289. * popup has not yet been created.
  290. *
  291. * NOTE: This should *ONLY* be called from tests. If called before createDom(),
  292. * this should return null.
  293. *
  294. * @return {goog.ui.PopupBase?} The popup, or null if it hasn't been created.
  295. */
  296. goog.ui.emoji.PopupEmojiPicker.prototype.getPopup = function() {
  297. return this.popup_;
  298. };
  299. /**
  300. * @return {Element} The last element that triggered the popup.
  301. */
  302. goog.ui.emoji.PopupEmojiPicker.prototype.getLastTarget = function() {
  303. return this.lastTarget_;
  304. };
  305. /**
  306. * @return {goog.ui.emoji.Emoji} The currently selected emoji.
  307. */
  308. goog.ui.emoji.PopupEmojiPicker.prototype.getSelectedEmoji = function() {
  309. return this.emojiPicker_.getSelectedEmoji();
  310. };
  311. /**
  312. * Handles click events on the element this picker is attached to and shows the
  313. * emoji picker in a popup.
  314. *
  315. * @param {goog.events.BrowserEvent} e The browser event.
  316. * @private
  317. */
  318. goog.ui.emoji.PopupEmojiPicker.prototype.show_ = function(e) {
  319. if (this.popup_.isOrWasRecentlyVisible() && this.toggleMode_ &&
  320. this.lastTarget_ == e.currentTarget) {
  321. this.popup_.setVisible(false);
  322. return;
  323. }
  324. this.lastTarget_ = /** @type {Element} */ (e.currentTarget);
  325. this.popup_.setPosition(
  326. new goog.positioning.AnchoredPosition(
  327. this.lastTarget_, goog.positioning.Corner.BOTTOM_LEFT));
  328. this.popup_.setVisible(true);
  329. };
  330. /**
  331. * Handles selection of an emoji.
  332. *
  333. * @param {goog.events.Event} e The event object.
  334. * @private
  335. */
  336. goog.ui.emoji.PopupEmojiPicker.prototype.onEmojiPicked_ = function(e) {
  337. this.popup_.setVisible(false);
  338. };