Commit b7150010 authored by JC Brand's avatar JC Brand

Move emoji-picker out so that its width can expand

parent 9ee8a6e8
......@@ -12,99 +12,105 @@
a.toggle-smiley {
padding: 0;
}
.emoji-picker.toolbar-menu {
min-width: 23rem;
padding-top: 0;
padding-bottom: 0;
background-color: var(--chat-head-color);
.emoji-picker__container {
display: flex;
flex-direction: column;
overflow-y: hidden;
background: white;
.emoji-picker__lists {
height: 100%;
overflow-y: auto;
.emoji-category__heading {
cursor: auto;
color: var(--subdued-color);
font-size: var(--font-size);
padding: 0.5em 0 0 0.5em;
}
display: flex;
flex-direction: column;
}
.emoji-skintone-picker {
display: flex;
label {
margin: 0;
padding: 0 0.5em;
white-space: nowrap;
font-size: var(--font-size-small);
color: var(--heading-color);
}
li {
padding: 0 0.25em;
}
padding: 0.5em 0;
background-color: var(--chat-head-color);
width: auto;
font-size: var(--font-size);
}
}
}
.emoji-picker.toolbar-menu {
width: 100%;
padding-top: 0;
padding-bottom: 0;
background-color: var(--chat-head-color);
overflow-y: hidden;
background: white;
.emoji-picker__lists {
height: 8em;
overflow-y: auto;
.emoji-category__heading {
cursor: auto;
color: var(--subdued-color);
font-size: var(--font-size);
padding: 0.5em 0 0 0.5em;
}
ul {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
display: flex;
flex-direction: column;
}
.emoji-skintone-picker {
display: flex;
label {
margin: 0;
padding: 0 0.5em;
white-space: nowrap;
font-size: var(--font-size-small);
color: var(--heading-color);
}
ul {
display: flex;
flex-direction: row;
flex-wrap: wrap;
li {
padding: 0 0.25em;
}
.emoji-picker {
background-color: white;
padding: 0.5em;
li {
margin-left: 0;
cursor: pointer;
list-style: none;
position: relative;
&.insert-emoji {
margin: 0;
height: 32px;
width: 32px;
}
padding: 0.5em 0;
background-color: var(--chat-head-color);
width: auto;
font-size: var(--font-size);
}
.emoji-picker {
background-color: white;
padding: 0.5em;
li {
margin-left: 0;
cursor: pointer;
list-style: none;
position: relative;
&.insert-emoji {
margin: 0;
height: 32px;
width: 32px;
&.picked {
background-color: var(--highlight-color);
}
a {
&:hover {
background-color: var(--highlight-color);
}
font-size: var(--font-size-huge);
}
&.picked {
background-color: var(--highlight-color);
}
a {
&:hover {
background-color: var(--highlight-color);
}
font-size: var(--font-size-huge);
}
}
.emoji-picker__header {
display: flex;
flex-direction: column;
padding-top: 0.5em;
background-color: var(--chat-head-color);
.emoji-search {
width: auto;
margin: 0.25em;
height: 2em;
font-size: var(--font-size-small);
}
ul {
display: flex;
flex-direction: row;
justify-content: space-between;
}
}
.emoji-picker__header {
display: flex;
flex-direction: column;
padding-top: 0.5em;
background-color: var(--chat-head-color);
.emoji-search {
width: auto;
margin: 0.25em;
height: 2em;
font-size: var(--font-size-small);
}
ul {
display: flex;
flex-direction: row;
.emoji-category {
&.picked {
background-color: white;
border: 1px var(--chat-head-color) solid;
border-bottom: none;
}
padding: 0.25em;
font-size: var(--font-size-huge);
&:hover {
background-color: var(--highlight-color);
}
}
.emoji-category {
&.picked {
background-color: white;
border: 1px var(--chat-head-color) solid;
border-bottom: none;
}
padding: 0.25em;
font-size: var(--font-size-huge);
&:hover {
background-color: var(--highlight-color);
}
}
}
......@@ -113,23 +119,19 @@
}
.chatroom {
.sendXMPPMessage {
.toggle-smiley {
.emoji-picker.toolbar-menu {
background-color: var(--chatroom-head-color);
.emoji-picker__container {
background: white;
.emoji-skintone-picker {
background-color: var(--chatroom-head-color);
}
.emoji-picker__header {
background-color: var(--chatroom-head-color);
.emoji-category {
&.picked {
border: 1px var(--chatroom-head-color) solid;
border-bottom: none;
}
}
.emoji-picker.toolbar-menu {
background-color: var(--chatroom-head-color);
background: white;
.emoji-skintone-picker {
background-color: var(--chatroom-head-color);
}
.emoji-picker__header {
background-color: var(--chatroom-head-color);
ul {
.emoji-category {
&.picked {
border: 1px var(--chatroom-head-color) solid;
border-bottom: none;
}
}
}
......@@ -138,62 +140,57 @@
}
}
#conversejs.converse-embedded,
#conversejs.converse-overlayed {
.emoji-picker__container {
height: var(--embedded-emoji-picker-height);
}
}
#conversejs.converse-overlayed {
.emoji-picker__container {
height: var(--overlayed-emoji-picker-height);
}
.chatbox {
.sendXMPPMessage {
.toggle-smiley {
.emoji-picker.toolbar-menu {
li {
&.insert-emoji {
height: 20px;
width: 20px;
}
}
.emoji-picker__container {
.emoji-picker {
.insert-emoji {
a {
font-size: var(--font-size);
}
}
}
.emoji-skintone-picker {
font-size: var(--font-size-small);
}
.emoji-picker__header {
.emoji-category {
font-size: var(--font-size-small);
}
}
.emoji-picker.toolbar-menu {
li {
&.insert-emoji {
height: 20px;
width: 20px;
}
}
.emoji-picker {
.insert-emoji {
a {
font-size: var(--font-size);
}
}
}
.emoji-skintone-picker {
font-size: var(--font-size-small);
}
.emoji-picker__header {
.emoji-category {
font-size: var(--font-size-small);
}
}
.emoji-picker__lists {
height: 7em;
}
}
}
}
#conversejs.converse-fullscreen {
.emoji-picker__container {
height: var(--fullpage-emoji-picker-height);
}
.chatbox {
.sendXMPPMessage {
.toggle-smiley {
.emoji-category {
padding-left: 0.2em;
padding-right: 0.2em;
}
.toggle-smiley {
}
.emoji-picker.toolbar-menu {
.emoji-picker__lists {
height: 12em;
}
}
}
}
@include media-breakpoint-up(m) {
#conversejs {
.chatbox {
.emoji-picker.toolbar-menu {
max-width: 40em;
}
}
}
}
......@@ -446,8 +446,8 @@
view.insertIntoTextArea('hello world');
expect(counter.textContent).toBe('188');
toolbar.querySelector('li.toggle-smiley').click();
const picker = await u.waitUntil(() => view.el.querySelector('.toggle-smiley .emoji-picker__container'));
toolbar.querySelector('a.toggle-smiley').click();
const picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__lists'));
const item = await u.waitUntil(() => picker.querySelector('.emoji-picker li.insert-emoji'));
item.click()
expect(counter.textContent).toBe('179');
......
......@@ -24,18 +24,14 @@
await test_utils.openChatBoxFor(_converse, contact_jid);
const view = _converse.chatboxviews.get(contact_jid);
const toolbar = view.el.querySelector('ul.chat-toolbar');
expect(toolbar.querySelectorAll('li.toggle-smiley').length).toBe(1);
spyOn(view, 'toggleEmojiMenu').and.callThrough();
view.delegateEvents(); // We need to rebind all events otherwise our spy won't be called
toolbar.querySelector('li.toggle-smiley').click();
await u.waitUntil(() => u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker__container')));
const picker = await u.waitUntil(() => view.el.querySelector('.toggle-smiley .emoji-picker__container'));
expect(toolbar.querySelectorAll('li.toggle-smiley__container').length).toBe(1);
toolbar.querySelector('a.toggle-smiley').click();
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
const picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'));
const item = await u.waitUntil(() => picker.querySelector('.emoji-picker li.insert-emoji'));
item.click()
expect(view.el.querySelector('textarea.chat-textarea').value).toBe(':smiley: ');
toolbar.querySelector('li.toggle-smiley').click(); // Close the panel again
toolbar.querySelector('a.toggle-smiley').click(); // Close the panel again
done();
}));
......@@ -59,8 +55,8 @@
'key': 'Tab'
}
view.onKeyDown(tab_event);
await u.waitUntil(() => u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker__container')));
let picker = await u.waitUntil(() => view.el.querySelector('.toggle-smiley .emoji-picker__container'));
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
let picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'));
const input = picker.querySelector('.emoji-search');
expect(input.value).toBe(':gri');
let visible_emojis = sizzle('.insert-emoji:not(.hidden)', picker);
......@@ -98,8 +94,8 @@
textarea.value = ':use';
view.onKeyDown(tab_event);
await u.waitUntil(() => u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker__container')));
picker = await u.waitUntil(() => view.el.querySelector('.toggle-smiley .emoji-picker__container'));
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'));
expect(input.value).toBe(':use');
visible_emojis = sizzle('.insert-emoji:not(.hidden)', picker);
expect(visible_emojis.length).toBe(0);
......@@ -114,12 +110,13 @@
const muc_jid = 'lounge@montague.lit';
await test_utils.openAndEnterChatRoom(_converse, muc_jid, 'romeo');
const view = _converse.chatboxviews.get(muc_jid);
const toolbar = view.el.querySelector('ul.chat-toolbar');
expect(toolbar.querySelectorAll('li.toggle-smiley').length).toBe(1);
toolbar.querySelector('li.toggle-smiley').click();
await u.waitUntil(() => u.isVisible(view.el.querySelector('.toggle-smiley .emoji-picker__container')));
const picker = await u.waitUntil(() => view.el.querySelector('.toggle-smiley .emoji-picker__container'));
expect(toolbar.querySelectorAll('.toggle-smiley__container').length).toBe(1);
toolbar.querySelector('.toggle-smiley').click();
await u.waitUntil(() => u.isVisible(view.el.querySelector('.emoji-picker__lists')));
const picker = await u.waitUntil(() => view.el.querySelector('.emoji-picker__container'));
const input = picker.querySelector('.emoji-search');
expect(sizzle('.insert-emoji:not(.hidden)', picker).length).toBe(1591);
......
......@@ -2921,15 +2921,12 @@
spyOn(window, 'confirm').and.callFake(() => true);
await test_utils.openAndEnterChatRoom(_converse, 'lounge@montague.lit', 'romeo');
const view = _converse.chatboxviews.get('lounge@montague.lit');
const textarea = view.el.querySelector('.chat-textarea');
textarea.value = '/clear';
let textarea = view.el.querySelector('.chat-textarea');
const enter = { 'target': textarea, 'preventDefault': function preventDefault () {}, 'keyCode': 13 };
view.onKeyDown(enter);
textarea.value = '/help';
view.onKeyDown(enter);
let info_messages = Array.prototype.slice.call(view.el.querySelectorAll('.chat-info'), 0);
let info_messages = sizzle('.chat-info:not(.chat-event)', view.el);
expect(info_messages.length).toBe(20);
expect(info_messages.pop().textContent.trim()).toBe('/voice: Allow muted user to post messages');
expect(info_messages.pop().textContent.trim()).toBe('/topic: Set groupchat subject (alias for /subject)');
......@@ -2954,6 +2951,7 @@
const occupant = view.model.occupants.findWhere({'jid': _converse.bare_jid});
occupant.set('affiliation', 'admin');
textarea = view.el.querySelector('.chat-textarea');
textarea.value = '/clear';
view.onKeyDown(enter);
textarea.value = '/help';
......@@ -2969,6 +2967,8 @@
occupant.set('affiliation', 'member');
textarea.value = '/clear';
view.onKeyDown(enter);
await u.waitUntil(() => sizzle('.chat-info:not(.chat-event)', view.el).length === 0);
textarea.value = '/help';
view.onKeyDown(enter);
info_messages = sizzle('.chat-info', view.el).slice(1);
......@@ -2977,8 +2977,11 @@
expect(commands).toEqual(["/clear", "/help", "/kick", "/me", "/modtools", "/mute", "/nick", "/register", "/subject", "/topic", "/voice"]);
occupant.set('role', 'participant');
textarea = view.el.querySelector('.chat-textarea');
textarea.value = '/clear';
view.onKeyDown(enter);
await u.waitUntil(() => sizzle('.chat-info:not(.chat-event)', view.el).length === 0);
textarea.value = '/help';
view.onKeyDown(enter);
info_messages = sizzle('.chat-info', view.el).slice(1);
......
......@@ -318,7 +318,7 @@ converse.plugins.add('converse-chatview', {
},
renderMessageForm () {
const form_container = this.el.querySelector('.bottom-panel');
const form_container = this.el.querySelector('.message-form-container');
form_container.innerHTML = tpl_chatbox_message_form(
Object.assign(this.model.toJSON(), {
'message_limit': _converse.message_limit,
......
......@@ -43,12 +43,6 @@ converse.plugins.add('converse-emoji-views', {
this.emoji_dropdown.toggle();
}
this.__super__.onEnterPressed.apply(this, arguments);
}
},
ChatRoomView: {
events: {
'click .toggle-smiley': 'toggleEmojiMenu'
},
onKeyDown (ev) {
......@@ -63,6 +57,12 @@ converse.plugins.add('converse-emoji-views', {
}
return this.__super__.onKeyDown.call(this, ev);
}
},
ChatRoomView: {
events: {
'click .toggle-smiley': 'toggleEmojiMenu'
}
}
},
......@@ -85,10 +85,7 @@ converse.plugins.add('converse-emoji-views', {
const emoji_aware_chat_view = {
async autocompleteInPicker (input, value) {
if (this.emoji_dropdown === undefined) {
this.createEmojiDropdown();
}
await _converse.api.waitUntil('emojisInitialized');
await this.createEmojiDropdown();
this.emoji_picker_view.model.set({
'autocompleting': value,
'position': input.selectionStart
......@@ -99,49 +96,47 @@ converse.plugins.add('converse-emoji-views', {
createEmojiPicker () {
if (!_converse.emojipicker) {
const storage = _converse.config.get('storage'),
id = `converse.emoji-${_converse.bare_jid}`;
const id = `converse.emoji-${_converse.bare_jid}`;
_converse.emojipicker = new _converse.EmojiPicker({'id': id});
_converse.emojipicker.browserStorage = _converse.createStore(id, storage);
_converse.emojipicker.browserStorage = _converse.createStore(id);
_converse.emojipicker.fetch();
}
this.emoji_picker_view = new _converse.EmojiPickerView({'model': _converse.emojipicker});
this.emoji_picker_view.chatview = this;
this.insertEmojiPicker();
},
createEmojiDropdown () {
const dropdown_el = this.el.querySelector('.toggle-smiley.dropup');
this.emoji_dropdown = new bootstrap.Dropdown(dropdown_el, true);
this.emoji_dropdown.el = dropdown_el;
async createEmojiDropdown () {
if (!this.emoji_dropdown) {
await _converse.api.waitUntil('emojisInitialized');
const el = this.el.querySelector('.emoji-picker');
this.emoji_dropdown = new bootstrap.Dropdown(el, true);
this.emoji_dropdown.el = el;
}
},
async toggleEmojiMenu (ev) {
if (this.emoji_dropdown === undefined) {
ev.stopPropagation();
this.createEmojiDropdown();
this.emoji_dropdown.toggle();
await _converse.api.waitUntil('emojisInitialized');
this.emoji_picker_view.setScrollPosition();
}
ev.stopPropagation();
await this.createEmojiDropdown();
this.emoji_dropdown.toggle();
this.emoji_picker_view.setScrollPosition();
},
insertEmojiPicker () {
const picker_el = this.el.querySelector('.emoji-picker');
if (picker_el !== null) {
picker_el.innerHTML = '';
picker_el.appendChild(this.emoji_picker_view.el);
}
const el = this.el.querySelector('.emoji-picker__container');
el.innerHTML = '';
el.appendChild(this.emoji_picker_view.el);
}
};
Object.assign(_converse.ChatBoxView.prototype, emoji_aware_chat_view);
_converse.EmojiPickerView = Backbone.VDOMView.extend({
className: 'emoji-picker__container',
className: 'emoji-picker',
events: {
'click .emoji-picker__header li.emoji-category': 'chooseCategory',
'click .emoji-skintone-picker li.emoji-skintone': 'chooseSkinTone',
'click .toggle-smiley ul.emoji-picker li': 'insertEmoji',
'click .emoji-picker li': 'insertEmoji',
'keydown .emoji-search': 'onKeyDown'
},
......@@ -153,11 +148,10 @@ converse.plugins.add('converse-emoji-views', {
this.listenTo(this.model, 'change:current_category', this.render)
await _converse.api.waitUntil('emojisInitialized');
this.render();
_converse.api.trigger('emojiPickerViewInitialized');
},
toHTML () {
const html = tpl_emojis(
return tpl_emojis(
Object.assign(
this.model.toJSON(), {
'__': __,
......@@ -173,7 +167,6 @@ converse.plugins.add('converse-emoji-views', {
}
)
);
return html;
},
afterRender () {
......@@ -246,7 +239,9 @@ converse.plugins.add('converse-emoji-views', {
const position = this.model.get('position');
this.model.set({'autocompleting': null, 'position': null});
this.chatview.insertIntoTextArea(value, replace, false, position);
this.chatview.emoji_dropdown.toggle();
if (this.chatview.emoji_dropdown) {
this.chatview.emoji_dropdown.toggle();
}
this.filter('', true);
},
......@@ -350,7 +345,6 @@ converse.plugins.add('converse-emoji-views', {
const html = tpl_emoji_button({'tooltip_insert_smiley': __('Insert emojis')});
view.el.querySelector('.chat-toolbar').insertAdjacentHTML('afterBegin', html);
view.createEmojiPicker();
view.insertEmojiPicker();
}
});
}
......
......@@ -711,13 +711,11 @@ converse.plugins.add('converse-muc-views', {
renderBottomPanel () {
const container = this.el.querySelector('.bottom-panel');
if (this.model.features.get('moderated') && this.model.getOwnRole() === 'visitor') {
container.innerHTML = tpl_chatroom_bottom_panel({'__': __});
} else {
if (!container.firstElementChild || !container.querySelector('.sendXMPPMessage')) {
this.renderMessageForm();
this.initMentionAutoComplete();
}
const can_edit = !(this.model.features.get('moderated') && this.model.getOwnRole() === 'visitor');
container.innerHTML = tpl_chatroom_bottom_panel({__, can_edit});
if (can_edit) {
this.renderMessageForm();
this.initMentionAutoComplete();
}
},
......
<div class="chat-area col">
<div class="chat-content {[ if (o.show_send_button) { ]}chat-content-sendbutton{[ } ]}" aria-live="polite"></div>
<div class="bottom-panel"/>
<div class="bottom-panel"></div>
</div>
<div class="flyout box-flyout">
<div class="chat-body">
<div class="chat-content {[ if (o.show_send_button) { ]}chat-content-sendbutton{[ } ]}" aria-live="polite"></div>
<div class="bottom-panel"></div>
<div class="bottom-panel">
<div class="emoji-picker__container dropup"></div>
<div class="message-form-container">
</div>
</div>
</div>
<div class="message-form-container">
<div class="new-msgs-indicator hidden">▼ {{{ o.unread_msgs }}} ▼</div>
<form class="sendXMPPMessage">
{[ if (o.show_toolbar) { ]}
......@@ -22,4 +21,3 @@
{[ } ]}
</div>
</form>
</div>
{[ if (o.can_edit) { ]}
<div class="emoji-picker__container dropup"></div>
<div class="message-form-container">
{[ } else { ]}
<div class="muc-bottom-panel">{{{o.__("You're not allowed to send messages in this room")}}}</div>
{[ } ]}
<li class="toggle-toolbar-menu toggle-smiley dropup">
<a class="toggle-smiley far fa-smile" title="{{{o.tooltip_insert_smiley}}}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></a>
<div class="emoji-picker dropdown-menu toolbar-menu"></div>
<li class="toggle-toolbar-menu toggle-smiley__container">
<a class="toggle-smiley far fa-smile"
title="{{{o.tooltip_insert_smiley}}}"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"></a>
</li>
<div class="emoji-picker__container">
<div class="emoji-picker dropdown-menu toolbar-menu">
<div class="emoji-picker__header">
<input class="form-control emoji-search" name="emoji-search" placeholder="{{{o.__('Search')}}}"/>
{[ if (!o.query) { ]}
......
......@@ -506,6 +506,9 @@ u.isInDOM = function (el) {
}
u.isVisible = function (el) {
if (el === null) {
return false;
}
if (u.hasClass('hidden', el)) {
return false;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment