MessageView: Show menu w/ 'reply to message' on triple-dot click
This commit is contained in:
parent
f4d9ab8ba0
commit
12257e1560
7 changed files with 80 additions and 18 deletions
|
@ -428,6 +428,10 @@
|
|||
"selectAContact": {
|
||||
"message": "Select a contact or group to start chatting."
|
||||
},
|
||||
"replyToMessage": {
|
||||
"message": "Reply to Message",
|
||||
"description": "Shown in triple-dot menu next to message to allow user to start crafting a message with a quotation"
|
||||
},
|
||||
"replyingToYourself": {
|
||||
"message": "Replying to Yourself",
|
||||
"description": "Shown in iOS theme when you quote yourself"
|
||||
|
|
|
@ -297,8 +297,13 @@
|
|||
<span class='timer'></span>
|
||||
</div>
|
||||
{{ #hoverIcon }}
|
||||
<div class='hover-icon-container'>
|
||||
<span class='dots-horizontal-icon'></span>
|
||||
<div class='menu-container menu'>
|
||||
<div class='menu-anchor'>
|
||||
<span class='dots-horizontal-icon'></span>
|
||||
<ul class='menu-list'>
|
||||
<li class='reply'>{{ reply }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{ /hoverIcon }}
|
||||
</div>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
/* global _: false */
|
||||
/* global emoji_util: false */
|
||||
/* global Mustache: false */
|
||||
/* global $: false */
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
(function () {
|
||||
|
@ -216,7 +217,8 @@
|
|||
'click .status': 'select',
|
||||
'click .some-failed': 'select',
|
||||
'click .error-message': 'select',
|
||||
'click .hover-icon-container': 'onReply',
|
||||
'click .menu-container': 'showMenu',
|
||||
'click .menu-list .reply': 'onReply',
|
||||
},
|
||||
retryMessage() {
|
||||
const retrys = _.filter(
|
||||
|
@ -227,6 +229,23 @@
|
|||
this.model.resend(number);
|
||||
});
|
||||
},
|
||||
showMenu(e) {
|
||||
if (this.menuVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.menuVisible = true;
|
||||
e.stopPropagation();
|
||||
|
||||
this.$('.menu-list').show();
|
||||
$(document).one('click', () => {
|
||||
this.hideMenu();
|
||||
});
|
||||
},
|
||||
hideMenu() {
|
||||
this.menuVisible = false;
|
||||
this.$('.menu-list').hide();
|
||||
},
|
||||
onReply() {
|
||||
this.model.trigger('reply', this.model);
|
||||
},
|
||||
|
@ -428,6 +447,7 @@
|
|||
innerBubbleClasses: this.isImageWithoutCaption() ? '' : 'with-tail',
|
||||
hoverIcon: !hasErrors,
|
||||
hasAttachments,
|
||||
reply: i18n('replyToMessage'),
|
||||
}, this.render_partials()));
|
||||
this.timeStampView.setElement(this.$('.timestamp'));
|
||||
this.timeStampView.update();
|
||||
|
|
|
@ -353,26 +353,46 @@ li.entry .error-icon-container {
|
|||
|
||||
&:hover .error-message { display: inline-block; }
|
||||
}
|
||||
li.entry .hover-icon-container {
|
||||
li.entry .menu-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(100% + 5px);
|
||||
height: 100%;
|
||||
|
||||
visibility: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.dots-horizontal-icon {
|
||||
display: block;
|
||||
height: 100%;
|
||||
.menu-anchor {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
li.entry:hover .hover-icon-container {
|
||||
.dots-horizontal-icon {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
li.entry:hover .dots-horizontal-icon {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
li.entry.outgoing .menu-container {
|
||||
left: auto;
|
||||
right: calc(100% + 5px);
|
||||
}
|
||||
|
||||
.incoming .menu-list {
|
||||
left: 0;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
|
||||
.error-icon {
|
||||
display: inline-block;
|
||||
width: $error-icon-size;
|
||||
|
@ -557,10 +577,6 @@ span.status {
|
|||
left: auto;
|
||||
right: calc(100% + 5px);
|
||||
}
|
||||
.hover-icon-container {
|
||||
left: auto;
|
||||
right: calc(100% + 5px);
|
||||
}
|
||||
|
||||
.avatar, .bubble {
|
||||
float: right;
|
||||
|
|
|
@ -232,8 +232,13 @@
|
|||
<span class='timer'></span>
|
||||
</div>
|
||||
{{ #hoverIcon }}
|
||||
<div class='hover-icon-container'>
|
||||
<span class='dots-horizontal-icon'></span>
|
||||
<div class='menu-container menu'>
|
||||
<div class='menu-anchor'>
|
||||
<span class='dots-horizontal-icon'></span>
|
||||
<ul class='menu-list'>
|
||||
<li class='reply'>{{ reply }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{ /hoverIcon }}
|
||||
</div>
|
||||
|
|
|
@ -52,8 +52,13 @@ window.Whisper.View.Templates = {
|
|||
<span class='timer'></span>
|
||||
</div>
|
||||
{{ #hoverIcon }}
|
||||
<div class='hover-icon-container'>
|
||||
<span class='dots-horizontal-icon'></span>
|
||||
<div class='menu-container menu'>
|
||||
<div class='menu-anchor'>
|
||||
<span class='dots-horizontal-icon'></span>
|
||||
<ul class='menu-list'>
|
||||
<li class='reply'>{{ reply }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{ /hoverIcon }}
|
||||
</div>
|
||||
|
|
|
@ -161,10 +161,17 @@ export class Quote extends React.Component<Props, {}> {
|
|||
return null;
|
||||
}
|
||||
|
||||
// We don't want the overall click handler for the quote to fire, so we stop
|
||||
// propagation before handing control to the caller's callback.
|
||||
const onClick = (e: React.MouseEvent<{}>): void => {
|
||||
e.stopPropagation();
|
||||
onClose();
|
||||
};
|
||||
|
||||
// We need the container to give us the flexibility to implement the iOS design.
|
||||
return (
|
||||
<div className="close-container">
|
||||
<div className="close-button" onClick={onClose}></div>
|
||||
<div className="close-button" onClick={onClick}></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue