emoji-dropdown.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import DropdownBase from "shared/components/dropdown.js";
  2. import { __ } from 'i18n';
  3. import { _converse, api, converse } from "@converse/headless/core";
  4. import { html } from "lit";
  5. import { initStorage } from '@converse/headless/utils/storage.js';
  6. import { until } from 'lit/directives/until.js';
  7. const u = converse.env.utils;
  8. export default class EmojiDropdown extends DropdownBase {
  9. static get properties() {
  10. return {
  11. chatview: { type: Object }
  12. };
  13. }
  14. constructor () {
  15. super();
  16. // This is an optimization, we lazily render the emoji picker, otherwise tests slow to a crawl.
  17. this.render_emojis = false;
  18. }
  19. initModel () {
  20. if (!this.init_promise) {
  21. this.init_promise = (async () => {
  22. await api.emojis.initialize()
  23. const id = `converse.emoji-${_converse.bare_jid}-${this.chatview.model.get('jid')}`;
  24. this.model = new _converse.EmojiPicker({'id': id});
  25. initStorage(this.model, id);
  26. await new Promise(resolve => this.model.fetch({'success': resolve, 'error': resolve}));
  27. // We never want still be in the autocompleting state upon page load
  28. this.model.set({'autocompleting': null, 'ac_position': null});
  29. })();
  30. }
  31. return this.init_promise;
  32. }
  33. render() {
  34. const is_groupchat = this.chatview.model.get('type') === _converse.CHATROOMS_TYPE;
  35. const color = is_groupchat ? '--muc-toolbar-btn-color' : '--chat-toolbar-btn-color';
  36. return html`
  37. <div class="dropup">
  38. <button class="toggle-emojis"
  39. title="${__('Insert emojis')}"
  40. data-toggle="dropdown"
  41. aria-haspopup="true"
  42. aria-expanded="false">
  43. <converse-icon
  44. color="var(${color})"
  45. class="fa fa-smile "
  46. path-prefix="${api.settings.get('assets_path')}"
  47. size="1em"></converse-icon>
  48. </button>
  49. <div class="dropdown-menu">
  50. ${until(this.initModel().then(() => html`
  51. <converse-emoji-picker
  52. .chatview=${this.chatview}
  53. .model=${this.model}
  54. @emojiSelected=${() => this.hideMenu()}
  55. ?render_emojis=${this.render_emojis}
  56. current_category="${this.model.get('current_category') || ''}"
  57. current_skintone="${this.model.get('current_skintone') || ''}"
  58. query="${this.model.get('query') || ''}"
  59. ></converse-emoji-picker>`), '')}
  60. </div>
  61. </div>`;
  62. }
  63. connectedCallback () {
  64. super.connectedCallback();
  65. this.render_emojis = false;
  66. }
  67. toggleMenu (ev) {
  68. ev.stopPropagation();
  69. ev.preventDefault();
  70. if (u.hasClass('show', this.menu)) {
  71. if (u.ancestor(ev.target, '.toggle-emojis')) {
  72. this.hideMenu();
  73. }
  74. } else {
  75. this.showMenu();
  76. }
  77. }
  78. async showMenu () {
  79. await this.initModel();
  80. if (!this.render_emojis) {
  81. // Trigger an update so that emojis are rendered
  82. this.render_emojis = true;
  83. this.requestUpdate();
  84. await this.updateComplete;
  85. }
  86. super.showMenu();
  87. setTimeout(() => this.querySelector('.emoji-search')?.focus());
  88. }
  89. }
  90. api.elements.define('converse-emoji-dropdown', EmojiDropdown);