Add ability to let dropdown appear at the top, left-aligned

And use that for the last message in the chat history, otherwise the
dropdown is obscured.
This commit is contained in:
JC Brand 2021-07-01 15:02:00 +02:00
parent e675c853f3
commit 3d8852950d
10 changed files with 31 additions and 20 deletions

View File

@ -35,7 +35,7 @@ export default (o) => {
const display_name = o.model.getDisplayName(); const display_name = o.model.getDisplayName();
const tpl_dropdown_btns = () => getDropdownButtons(o.heading_buttons_promise) const tpl_dropdown_btns = () => getDropdownButtons(o.heading_buttons_promise)
.then(btns => btns.length ? html`<converse-dropdown .items=${btns}></converse-dropdown>` : ''); .then(btns => btns.length ? html`<converse-dropdown class="dropleft" .items=${btns}></converse-dropdown>` : '');
const tpl_standalone_btns = () => getStandaloneButtons(o.heading_buttons_promise) const tpl_standalone_btns = () => getStandaloneButtons(o.heading_buttons_promise)
.then(btns => btns.reverse().map(b => until(b, ''))); .then(btns => btns.reverse().map(b => until(b, '')));

View File

@ -12,7 +12,7 @@ export default (o) => {
<div class="chatbox-title__text" title="${o.jid}">${ o.display_name }</div> <div class="chatbox-title__text" title="${o.jid}">${ o.display_name }</div>
</div> </div>
<div class="chatbox-title__buttons row no-gutters"> <div class="chatbox-title__buttons row no-gutters">
${ o.dropdown_btns.length ? html`<converse-dropdown .items=${o.dropdown_btns}></converse-dropdown>` : '' } ${ o.dropdown_btns.length ? html`<converse-dropdown class="dropleft" .items=${o.dropdown_btns}></converse-dropdown>` : '' }
${ o.standalone_btns.length ? tpl_standalone_btns(o) : '' } ${ o.standalone_btns.length ? tpl_standalone_btns(o) : '' }
</div> </div>
</div> </div>

View File

@ -20,7 +20,7 @@ export default (o) => {
</div> </div>
<div class="chatbox-title__buttons row no-gutters"> <div class="chatbox-title__buttons row no-gutters">
${ o.standalone_btns.length ? tpl_standalone_btns(o) : '' } ${ o.standalone_btns.length ? tpl_standalone_btns(o) : '' }
${ o.dropdown_btns.length ? html`<converse-dropdown .items=${o.dropdown_btns}></converse-dropdown>` : '' } ${ o.dropdown_btns.length ? html`<converse-dropdown class="dropleft" .items=${o.dropdown_btns}></converse-dropdown>` : '' }
</div> </div>
</div> </div>
${ show_subject ? html`<p class="chat-head__desc" title="${i18n_hide_topic}"> ${ show_subject ? html`<p class="chat-head__desc" title="${i18n_hide_topic}">

View File

@ -15,6 +15,7 @@ class MessageActions extends CustomElement {
correcting: { type: Boolean }, correcting: { type: Boolean },
editable: { type: Boolean }, editable: { type: Boolean },
hide_url_previews: { type: Boolean }, hide_url_previews: { type: Boolean },
is_newest_message: { type: Boolean },
is_retracted: { type: Boolean }, is_retracted: { type: Boolean },
message_type: { type: String }, message_type: { type: String },
model: { type: Object }, model: { type: Object },
@ -30,7 +31,9 @@ class MessageActions extends CustomElement {
const buttons = await this.getActionButtons(); const buttons = await this.getActionButtons();
const items = buttons.map(b => MessageActions.getActionsDropdownItem(b)); const items = buttons.map(b => MessageActions.getActionsDropdownItem(b));
if (items.length) { if (items.length) {
return html`<converse-dropdown class="chat-msg__actions" .items=${ items }></converse-dropdown>`; return html`<converse-dropdown
class="chat-msg__actions ${this.is_newest_message ? 'dropup dropup--left' : 'dropleft'}"
.items=${ items }></converse-dropdown>`;
} else { } else {
return ''; return '';
} }

View File

@ -200,6 +200,7 @@ export default class Message extends CustomElement {
getDerivedMessageProps () { getDerivedMessageProps () {
const format = api.settings.get('time_format'); const format = api.settings.get('time_format');
return { return {
'is_newest_message': this.model === this.model.collection.last(),
'pretty_time': dayjs(this.model.get('edited') || this.model.get('time')).format(format), 'pretty_time': dayjs(this.model.get('edited') || this.model.get('time')).format(format),
'has_mentions': this.hasMentions(), 'has_mentions': this.hasMentions(),
'hats': getHats(this.model), 'hats': getHats(this.model),

View File

@ -36,10 +36,11 @@ export default (el, o) => {
</div> </div>
<converse-message-actions <converse-message-actions
.model=${el.model} .model=${el.model}
?correcting="${o.correcting}" ?correcting=${o.correcting}
?editable="${o.editable}" ?editable=${o.editable}
?is_retracted="${o.is_retracted}" ?hide_url_previews=${el.model.get('hide_url_previews')}
?hide_url_previews="${el.model.get('hide_url_previews')}" ?is_newest_message=${o.is_newest_message}
?is_retracted=${o.is_retracted}
unfurls="${el.model.get('ogp_metadata')?.length}" unfurls="${el.model.get('ogp_metadata')?.length}"
message_type="${o.message_type}"></converse-message-actions> message_type="${o.message_type}"></converse-message-actions>
</div> </div>

View File

@ -55,7 +55,7 @@ export class ChatToolbar extends CustomElement {
if (this.show_emoji_button) { if (this.show_emoji_button) {
const chatview = _converse.chatboxviews.get(this.model.get('jid')); const chatview = _converse.chatboxviews.get(this.model.get('jid'));
buttons.push(html`<converse-emoji-dropdown .chatview=${chatview}></converse-dropdown>`); buttons.push(html`<converse-emoji-dropdown .chatview=${chatview}></converse-emoji-dropdown>`);
} }
if (this.show_call_button) { if (this.show_call_button) {

View File

@ -17,13 +17,11 @@ export default class Dropdown extends DropdownBase {
render () { render () {
const icon_classes = this.icon_classes || "fa fa-bars"; const icon_classes = this.icon_classes || "fa fa-bars";
return html` return html`
<div class="dropleft"> <button type="button" class="btn btn--transparent btn--standalone" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<button type="button" class="btn btn--transparent btn--standalone" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <i class="${icon_classes} only-icon"></i>
<i class="${icon_classes} only-icon"></i> </button>
</button> <div class="dropdown-menu">
<div class="dropdown-menu"> ${ this.items.map(b => until(b, '')) }
${ this.items.map(b => until(b, '')) }
</div>
</div> </div>
`; `;
} }

View File

@ -19,10 +19,9 @@ export default class DropdownBase extends CustomElement {
firstUpdated () { firstUpdated () {
super.firstUpdated(); super.firstUpdated();
this.menu = this.querySelector('.dropdown-menu'); this.menu = this.querySelector('.dropdown-menu');
this.dropdown = this.firstElementChild; this.button = this.querySelector('button');
this.button = this.dropdown.querySelector('button'); this.addEventListener('click', ev => this.toggleMenu(ev));
this.dropdown.addEventListener('click', ev => this.toggleMenu(ev)); this.addEventListener('keyup', ev => this.handleKeyUp(ev));
this.dropdown.addEventListener('keyup', ev => this.handleKeyUp(ev));
} }
_clickOutside(ev) { _clickOutside(ev) {

View File

@ -10,6 +10,15 @@
direction: ltr; direction: ltr;
z-index: 1031; // One more than bootstrap navbar z-index: 1031; // One more than bootstrap navbar
.dropup {
&.dropup--left {
.dropdown-menu {
right: 100%;
left: auto;
}
}
}
textarea:disabled { textarea:disabled {
background-color: #EEE !important; background-color: #EEE !important;
} }