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": {
|
"selectAContact": {
|
||||||
"message": "Select a contact or group to start chatting."
|
"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": {
|
"replyingToYourself": {
|
||||||
"message": "Replying to Yourself",
|
"message": "Replying to Yourself",
|
||||||
"description": "Shown in iOS theme when you quote yourself"
|
"description": "Shown in iOS theme when you quote yourself"
|
||||||
|
|
|
@ -297,8 +297,13 @@
|
||||||
<span class='timer'></span>
|
<span class='timer'></span>
|
||||||
</div>
|
</div>
|
||||||
{{ #hoverIcon }}
|
{{ #hoverIcon }}
|
||||||
<div class='hover-icon-container'>
|
<div class='menu-container menu'>
|
||||||
<span class='dots-horizontal-icon'></span>
|
<div class='menu-anchor'>
|
||||||
|
<span class='dots-horizontal-icon'></span>
|
||||||
|
<ul class='menu-list'>
|
||||||
|
<li class='reply'>{{ reply }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ /hoverIcon }}
|
{{ /hoverIcon }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
/* global _: false */
|
/* global _: false */
|
||||||
/* global emoji_util: false */
|
/* global emoji_util: false */
|
||||||
/* global Mustache: false */
|
/* global Mustache: false */
|
||||||
|
/* global $: false */
|
||||||
|
|
||||||
// eslint-disable-next-line func-names
|
// eslint-disable-next-line func-names
|
||||||
(function () {
|
(function () {
|
||||||
|
@ -216,7 +217,8 @@
|
||||||
'click .status': 'select',
|
'click .status': 'select',
|
||||||
'click .some-failed': 'select',
|
'click .some-failed': 'select',
|
||||||
'click .error-message': 'select',
|
'click .error-message': 'select',
|
||||||
'click .hover-icon-container': 'onReply',
|
'click .menu-container': 'showMenu',
|
||||||
|
'click .menu-list .reply': 'onReply',
|
||||||
},
|
},
|
||||||
retryMessage() {
|
retryMessage() {
|
||||||
const retrys = _.filter(
|
const retrys = _.filter(
|
||||||
|
@ -227,6 +229,23 @@
|
||||||
this.model.resend(number);
|
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() {
|
onReply() {
|
||||||
this.model.trigger('reply', this.model);
|
this.model.trigger('reply', this.model);
|
||||||
},
|
},
|
||||||
|
@ -428,6 +447,7 @@
|
||||||
innerBubbleClasses: this.isImageWithoutCaption() ? '' : 'with-tail',
|
innerBubbleClasses: this.isImageWithoutCaption() ? '' : 'with-tail',
|
||||||
hoverIcon: !hasErrors,
|
hoverIcon: !hasErrors,
|
||||||
hasAttachments,
|
hasAttachments,
|
||||||
|
reply: i18n('replyToMessage'),
|
||||||
}, this.render_partials()));
|
}, this.render_partials()));
|
||||||
this.timeStampView.setElement(this.$('.timestamp'));
|
this.timeStampView.setElement(this.$('.timestamp'));
|
||||||
this.timeStampView.update();
|
this.timeStampView.update();
|
||||||
|
|
|
@ -353,26 +353,46 @@ li.entry .error-icon-container {
|
||||||
|
|
||||||
&:hover .error-message { display: inline-block; }
|
&:hover .error-message { display: inline-block; }
|
||||||
}
|
}
|
||||||
li.entry .hover-icon-container {
|
li.entry .menu-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: calc(100% + 5px);
|
left: calc(100% + 5px);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
visibility: hidden;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
.dots-horizontal-icon {
|
.menu-anchor {
|
||||||
display: block;
|
position: relative;
|
||||||
height: 100%;
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
li.entry:hover .hover-icon-container {
|
.dots-horizontal-icon {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.entry:hover .dots-horizontal-icon {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
li.entry.outgoing .menu-container {
|
||||||
|
left: auto;
|
||||||
|
right: calc(100% + 5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.incoming .menu-list {
|
||||||
|
left: 0;
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.error-icon {
|
.error-icon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: $error-icon-size;
|
width: $error-icon-size;
|
||||||
|
@ -557,10 +577,6 @@ span.status {
|
||||||
left: auto;
|
left: auto;
|
||||||
right: calc(100% + 5px);
|
right: calc(100% + 5px);
|
||||||
}
|
}
|
||||||
.hover-icon-container {
|
|
||||||
left: auto;
|
|
||||||
right: calc(100% + 5px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar, .bubble {
|
.avatar, .bubble {
|
||||||
float: right;
|
float: right;
|
||||||
|
|
|
@ -232,8 +232,13 @@
|
||||||
<span class='timer'></span>
|
<span class='timer'></span>
|
||||||
</div>
|
</div>
|
||||||
{{ #hoverIcon }}
|
{{ #hoverIcon }}
|
||||||
<div class='hover-icon-container'>
|
<div class='menu-container menu'>
|
||||||
<span class='dots-horizontal-icon'></span>
|
<div class='menu-anchor'>
|
||||||
|
<span class='dots-horizontal-icon'></span>
|
||||||
|
<ul class='menu-list'>
|
||||||
|
<li class='reply'>{{ reply }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ /hoverIcon }}
|
{{ /hoverIcon }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -52,8 +52,13 @@ window.Whisper.View.Templates = {
|
||||||
<span class='timer'></span>
|
<span class='timer'></span>
|
||||||
</div>
|
</div>
|
||||||
{{ #hoverIcon }}
|
{{ #hoverIcon }}
|
||||||
<div class='hover-icon-container'>
|
<div class='menu-container menu'>
|
||||||
<span class='dots-horizontal-icon'></span>
|
<div class='menu-anchor'>
|
||||||
|
<span class='dots-horizontal-icon'></span>
|
||||||
|
<ul class='menu-list'>
|
||||||
|
<li class='reply'>{{ reply }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ /hoverIcon }}
|
{{ /hoverIcon }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -161,10 +161,17 @@ export class Quote extends React.Component<Props, {}> {
|
||||||
return null;
|
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.
|
// We need the container to give us the flexibility to implement the iOS design.
|
||||||
return (
|
return (
|
||||||
<div className="close-container">
|
<div className="close-container">
|
||||||
<div className="close-button" onClick={onClose}></div>
|
<div className="close-button" onClick={onClick}></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue