Supported mentions
This commit is contained in:
parent
c38717ec21
commit
d8acf048d2
@ -2190,7 +2190,7 @@ a.composer_emoji_btn:hover {
|
||||
color: #52719a;
|
||||
}
|
||||
.composer_dropdown li a:hover,
|
||||
.composer_dropdown li a.composer_emoji_option_active {
|
||||
.composer_dropdown li a.composer_autocomplete_option_active {
|
||||
color: #52719a;
|
||||
background: #f2f6fa;
|
||||
}
|
||||
@ -2200,6 +2200,19 @@ a.composer_emoji_btn:hover {
|
||||
margin-left: 15px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.composer_mention_option {
|
||||
line-height: 20px;
|
||||
}
|
||||
.composer_user_mention {
|
||||
color: #808080;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.composer_dropdown li a:hover .composer_user_mention,
|
||||
.composer_dropdown li a.composer_autocomplete_option_active .composer_user_mention {
|
||||
color: #698192;
|
||||
}
|
||||
|
||||
.composer_sticker_btn {
|
||||
width: 67px;
|
||||
height: 67px;
|
||||
|
@ -1519,7 +1519,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
$scope.$on('user_update', angular.noop);
|
||||
})
|
||||
|
||||
.controller('AppImSendController', function ($scope, $timeout, MtpApiManager, Storage, AppPeersManager, AppDocsManager, AppMessagesManager, ApiUpdatesManager, MtpApiFileManager) {
|
||||
.controller('AppImSendController', function ($scope, $timeout, MtpApiManager, Storage, AppChatsManager, AppUsersManager, AppPeersManager, AppDocsManager, AppMessagesManager, ApiUpdatesManager, MtpApiFileManager) {
|
||||
|
||||
$scope.$watch('curDialog.peer', resetDraft);
|
||||
$scope.$on('user_update', angular.noop);
|
||||
@ -1529,6 +1529,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
$scope.$on('ui_typing', onTyping);
|
||||
|
||||
$scope.draftMessage = {text: '', send: sendMessage, replyClear: replyClear};
|
||||
$scope.mentions = {};
|
||||
$scope.$watch('draftMessage.text', onMessageChange);
|
||||
$scope.$watch('draftMessage.files', onFilesSelected);
|
||||
$scope.$watch('draftMessage.sticker', onStickerSelected);
|
||||
@ -1573,8 +1574,38 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
return cancelEvent(e);
|
||||
}
|
||||
|
||||
function updateMentions () {
|
||||
var peerID = $scope.curDialog.peerID;
|
||||
|
||||
if (!peerID || peerID > 0) {
|
||||
safeReplaceObject($scope.mentions, {});
|
||||
$scope.$broadcast('mentions_update');
|
||||
return;
|
||||
}
|
||||
AppChatsManager.getChatFull(-peerID).then(function (chatFull) {
|
||||
var participantsVector = (chatFull.participants || {}).participants || [];
|
||||
|
||||
var mentionUsers = [];
|
||||
var mentionIndex = SearchIndexManager.createIndex();
|
||||
|
||||
angular.forEach(participantsVector, function (participant) {
|
||||
var user = AppUsersManager.getUser(participant.user_id);
|
||||
if (user.username) {
|
||||
mentionUsers.push(user);
|
||||
SearchIndexManager.indexObject(user.id, AppUsersManager.getUserSearchText(user.id), mentionIndex);
|
||||
}
|
||||
});
|
||||
|
||||
safeReplaceObject($scope.mentions, {
|
||||
users: mentionUsers,
|
||||
index: mentionIndex
|
||||
});
|
||||
$scope.$broadcast('mentions_update');
|
||||
});
|
||||
}
|
||||
|
||||
function resetDraft (newPeer) {
|
||||
updateMentions();
|
||||
replyClear();
|
||||
|
||||
if (newPeer) {
|
||||
@ -1651,7 +1682,6 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
|
||||
var doc = AppDocsManager.getDoc(newVal);
|
||||
if (doc.id && doc.access_hash) {
|
||||
console.log('sticker', doc);
|
||||
var inputMedia = {
|
||||
_: 'inputMediaDocument',
|
||||
id: {
|
||||
|
@ -1150,7 +1150,8 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
return {
|
||||
link: link,
|
||||
scope: {
|
||||
draftMessage: '='
|
||||
draftMessage: '=',
|
||||
mentions: '='
|
||||
}
|
||||
};
|
||||
|
||||
@ -1201,6 +1202,7 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
getSendOnEnter: function () {
|
||||
return sendOnEnter;
|
||||
},
|
||||
mentions: $scope.mentions,
|
||||
onMessageSubmit: onMessageSubmit,
|
||||
onFilePaste: onFilePaste
|
||||
});
|
||||
@ -1300,6 +1302,10 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
})
|
||||
});
|
||||
|
||||
$scope.$on('mentions_update', function () {
|
||||
composer.onMentionsUpdated();
|
||||
});
|
||||
|
||||
var sendAwaiting = false;
|
||||
$scope.$on('ui_message_before_send', function () {
|
||||
sendAwaiting = true;
|
||||
|
@ -234,7 +234,7 @@ EmojiTooltip.prototype.createTooltip = function () {
|
||||
this.contentEl.on('mousedown', function (e) {
|
||||
e = e.originalEvent || e;
|
||||
var target = $(e.target), code, sticker;
|
||||
if (target.hasClass('emoji') || target.hasClass('composer_sticker_image')) {
|
||||
if (target[0].tagName != 'A') {
|
||||
target = $(target[0].parentNode);
|
||||
}
|
||||
if (code = target.attr('data-code')) {
|
||||
@ -382,7 +382,7 @@ function EmojiPanel (containerEl, options) {
|
||||
this.containerEl.on('mousedown', function (e) {
|
||||
e = e.originalEvent || e;
|
||||
var target = $(e.target), code;
|
||||
if (target.hasClass('emoji')) {
|
||||
if (target[0].tagName != 'A') {
|
||||
target = $(target[0].parentNode);
|
||||
}
|
||||
if (code = target.attr('data-code')) {
|
||||
@ -436,8 +436,8 @@ function MessageComposer (textarea, options) {
|
||||
var self = this;
|
||||
this.autoCompleteEl.on('mousedown', function (e) {
|
||||
e = e.originalEvent || e;
|
||||
var target = $(e.target), code;
|
||||
if (target.hasClass('emoji') || target.hasClass('composer_emoji_shortcut')) {
|
||||
var target = $(e.target), mention, code;
|
||||
if (target[0].tagName != 'A') {
|
||||
target = $(target[0].parentNode);
|
||||
}
|
||||
if (code = target.attr('data-code')) {
|
||||
@ -446,6 +446,11 @@ function MessageComposer (textarea, options) {
|
||||
}
|
||||
EmojiHelper.pushPopularEmoji(code);
|
||||
}
|
||||
if (mention = target.attr('data-mention')) {
|
||||
if (self.onMentionSelected) {
|
||||
self.onMentionSelected(mention);
|
||||
}
|
||||
}
|
||||
return cancelEvent(e);
|
||||
});
|
||||
|
||||
@ -455,6 +460,7 @@ function MessageComposer (textarea, options) {
|
||||
this.onMessageSubmit = options.onMessageSubmit;
|
||||
this.getSendOnEnter = options.getSendOnEnter;
|
||||
this.onFilePaste = options.onFilePaste;
|
||||
this.mentions = options.mentions;
|
||||
}
|
||||
|
||||
MessageComposer.prototype.setUpInput = function () {
|
||||
@ -463,6 +469,7 @@ MessageComposer.prototype.setUpInput = function () {
|
||||
} else {
|
||||
this.setUpPlaintext();
|
||||
}
|
||||
this.autoCompleteRegEx = /(?:\s|^)(:|@)([A-Za-z0-9\-\+\*_]*)$/;
|
||||
}
|
||||
|
||||
MessageComposer.prototype.setUpRich = function () {
|
||||
@ -530,34 +537,39 @@ MessageComposer.prototype.onKeyEvent = function (e) {
|
||||
if (this.autocompleteShown) {
|
||||
if (e.keyCode == 38 || e.keyCode == 40) { // UP / DOWN
|
||||
var next = e.keyCode == 40;
|
||||
var currentSelected = $(this.autoCompleteEl).find('.composer_emoji_option_active');
|
||||
var currentSelected = $(this.autoCompleteEl).find('.composer_autocomplete_option_active');
|
||||
|
||||
if (currentSelected.length) {
|
||||
var currentSelectedWrap = currentSelected[0].parentNode;
|
||||
var nextWrap = currentSelectedWrap[next ? 'nextSibling' : 'previousSibling'];
|
||||
currentSelected.removeClass('composer_emoji_option_active');
|
||||
currentSelected.removeClass('composer_autocomplete_option_active');
|
||||
if (nextWrap) {
|
||||
$(nextWrap).find('a').addClass('composer_emoji_option_active');
|
||||
$(nextWrap).find('a').addClass('composer_autocomplete_option_active');
|
||||
return cancelEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
var childNodes = this.autoCompleteEl[0].childNodes;
|
||||
var nextWrap = childNodes[next ? 0 : childNodes.length - 1];
|
||||
$(nextWrap).find('a').addClass('composer_emoji_option_active');
|
||||
$(nextWrap).find('a').addClass('composer_autocomplete_option_active');
|
||||
|
||||
return cancelEvent(e);
|
||||
}
|
||||
|
||||
if (e.keyCode == 13) { // ENTER
|
||||
var currentSelected = $(this.autoCompleteEl).find('.composer_emoji_option_active')/* ||
|
||||
$(this.autoCompleteEl).childNodes[0].find('a')*/;
|
||||
var code = currentSelected.attr('data-code');
|
||||
if (code) {
|
||||
var currentSelected = $(this.autoCompleteEl).find('.composer_autocomplete_option_active');
|
||||
var code, mention;
|
||||
if (code = currentSelected.attr('data-code')) {
|
||||
this.onEmojiSelected(code, true);
|
||||
EmojiHelper.pushPopularEmoji(code);
|
||||
return cancelEvent(e);
|
||||
}
|
||||
if (mention = currentSelected.attr('data-mention')) {
|
||||
if (this.onMentionSelected) {
|
||||
this.onMentionSelected(mention);
|
||||
return cancelEvent(e);
|
||||
}
|
||||
}
|
||||
checkSubmit = true;
|
||||
}
|
||||
}
|
||||
@ -638,13 +650,39 @@ MessageComposer.prototype.checkAutocomplete = function () {
|
||||
|
||||
value = value.substr(0, pos);
|
||||
|
||||
var matches = value.match(/(?:\s|^):([A-Za-z0-9\-\+\*_]*)$/);
|
||||
var matches = value.match(this.autoCompleteRegEx);
|
||||
if (matches) {
|
||||
if (this.previousQuery == matches[0]) {
|
||||
return;
|
||||
}
|
||||
this.previousQuery = matches[0];
|
||||
var query = SearchIndexManager.cleanSearchText(matches[1]);
|
||||
var query = SearchIndexManager.cleanSearchText(matches[2]);
|
||||
|
||||
if (matches[1] == '@') { // mentions
|
||||
if (this.mentions && this.mentions.index) {
|
||||
if (query.length) {
|
||||
var foundObject = SearchIndexManager.search(query, this.mentions.index);
|
||||
var foundUsers = [];
|
||||
var user;
|
||||
for (var i = 0, length = this.mentions.users.length; i < length; i++) {
|
||||
user = this.mentions.users[i];
|
||||
if (foundObject[user.id]) {
|
||||
foundUsers.push(user);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var foundUsers = this.mentions.users;
|
||||
}
|
||||
if (foundUsers.length) {
|
||||
this.showMentionSuggestions(foundUsers);
|
||||
} else {
|
||||
this.hideSuggestions();
|
||||
}
|
||||
} else {
|
||||
this.hideSuggestions();
|
||||
}
|
||||
}
|
||||
else { // emoji
|
||||
EmojiHelper.getPopularEmoji((function (popular) {
|
||||
if (query.length) {
|
||||
var found = EmojiHelper.searchEmojis(query);
|
||||
@ -671,6 +709,7 @@ MessageComposer.prototype.checkAutocomplete = function () {
|
||||
}
|
||||
}).bind(this));
|
||||
}
|
||||
}
|
||||
else {
|
||||
delete this.previousQuery;
|
||||
this.hideSuggestions();
|
||||
@ -819,6 +858,65 @@ MessageComposer.prototype.onEmojiSelected = function (code, autocomplete) {
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
MessageComposer.prototype.onMentionsUpdated = function (username) {
|
||||
delete this.previousQuery;
|
||||
if (this.isActive) {
|
||||
this.checkAutocomplete();
|
||||
}
|
||||
}
|
||||
|
||||
MessageComposer.prototype.onMentionSelected = function (username) {
|
||||
if (this.richTextareaEl) {
|
||||
var textarea = this.richTextareaEl[0];
|
||||
if (!this.isActive) {
|
||||
if (!this.restoreSelection()) {
|
||||
setRichFocus(textarea);
|
||||
}
|
||||
}
|
||||
var valueCaret = getRichValueWithCaret(textarea);
|
||||
var fullValue = valueCaret[0];
|
||||
var pos = valueCaret[1] >= 0 ? valueCaret[1] : fullValue.length;
|
||||
var suffix = fullValue.substr(pos);
|
||||
var prefix = fullValue.substr(0, pos);
|
||||
var matches = prefix.match(/@([A-Za-z0-9\-\+\*_]*)$/);
|
||||
|
||||
var newValuePrefix;
|
||||
if (matches && matches[0]) {
|
||||
newValuePrefix = prefix.substr(0, matches.index) + '@' + username;
|
||||
} else {
|
||||
newValuePrefix = prefix + '@' + username;
|
||||
}
|
||||
textarea.value = newValue;
|
||||
|
||||
this.selId = (this.selId || 0) + 1;
|
||||
var html = this.getRichHtml(newValuePrefix) + ' <span id="composer_sel' + this.selId + '"></span>' + this.getRichHtml(suffix);
|
||||
|
||||
this.richTextareaEl.html(html);
|
||||
setRichFocus(textarea, $('#composer_sel' + this.selId)[0]);
|
||||
}
|
||||
else {
|
||||
var textarea = this.textareaEl[0];
|
||||
var fullValue = textarea.value;
|
||||
var pos = this.isActive ? getFieldSelection(textarea) : fullValue.length;
|
||||
var suffix = fullValue.substr(pos);
|
||||
var prefix = fullValue.substr(0, pos);
|
||||
var matches = prefix.match(/@([A-Za-z0-9\-\+\*_]*)$/);
|
||||
|
||||
if (matches && matches[0]) {
|
||||
var newValue = prefix.substr(0, matches.index) + '@' + username + ' ' + suffix;
|
||||
var newPos = matches.index + username.length + 2;
|
||||
} else {
|
||||
var newValue = prefix + ':' + username + ': ' + suffix;
|
||||
var newPos = prefix.length + username.length + 2;
|
||||
}
|
||||
textarea.value = newValue;
|
||||
setFieldSelection(textarea, newPos);
|
||||
}
|
||||
|
||||
this.hideSuggestions();
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
MessageComposer.prototype.onChange = function (e) {
|
||||
if (this.richTextareaEl) {
|
||||
delete this.keyupStarted;
|
||||
@ -900,6 +998,23 @@ MessageComposer.prototype.showEmojiSuggestions = function (codes) {
|
||||
this.autocompleteShown = true;
|
||||
}
|
||||
|
||||
MessageComposer.prototype.showMentionSuggestions = function (users) {
|
||||
var html = [];
|
||||
var user;
|
||||
var count = Math.min(5, users.length);
|
||||
var i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
user = users[i];
|
||||
html.push('<li><a class="composer_mention_option" data-mention="' + user.username + '"><span class="composer_user_name">' + user.rFullName + '</span><span class="composer_user_mention">@' + user.username + '</span></a></li>');
|
||||
}
|
||||
|
||||
this.autoCompleteEl.html(html.join(''));
|
||||
this.autoCompleteEl.show();
|
||||
this.updatePosition();
|
||||
this.autocompleteShown = true;
|
||||
}
|
||||
|
||||
MessageComposer.prototype.updatePosition = function () {
|
||||
var offset = (this.richTextareaEl || this.textareaEl).offset();
|
||||
var height = this.autoCompleteEl.outerHeight();
|
||||
|
@ -111,7 +111,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
|
||||
if (apiUser.first_name) {
|
||||
apiUser.rFirstName = RichTextProcessor.wrapRichText(apiUser.first_name, {noLinks: true, noLinebreaks: true});
|
||||
apiUser.rFullName = RichTextProcessor.wrapRichText(apiUser.first_name + ' ' + (apiUser.last_name || ''), {noLinks: true, noLinebreaks: true});
|
||||
apiUser.rFullName = apiUser.last_name ? RichTextProcessor.wrapRichText(apiUser.first_name + ' ' + (apiUser.last_name || ''), {noLinks: true, noLinebreaks: true}) : apiUser.rFirstName;
|
||||
} else {
|
||||
apiUser.rFirstName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || apiUser.rPhone || _('user_first_name_deleted');
|
||||
apiUser.rFullName = RichTextProcessor.wrapRichText(apiUser.last_name, {noLinks: true, noLinebreaks: true}) || apiUser.rPhone || _('user_name_deleted');
|
||||
@ -926,8 +926,9 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
dialog.top_message > maxSeenID
|
||||
) {
|
||||
var message = getMessage(dialog.top_message);
|
||||
var notifyPeer = message.flags & 16 ? message.from_id : peerID;
|
||||
if (message.unread && !message.out) {
|
||||
NotificationsManager.getPeerMuted(peerID).then(function (muted) {
|
||||
NotificationsManager.getPeerMuted(notifyPeer).then(function (muted) {
|
||||
if (!muted) {
|
||||
Storage.get('notify_nopreview').then(function (no_preview) {
|
||||
notifyAboutMessage(message, no_preview);
|
||||
@ -1233,7 +1234,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
pts_count: affectedMessages.pts_count
|
||||
}
|
||||
});
|
||||
return deletedMessageIDs;
|
||||
return messageIDs;
|
||||
});
|
||||
}
|
||||
|
||||
@ -1386,8 +1387,6 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
}
|
||||
|
||||
function sendText(peerID, text, options) {
|
||||
|
||||
console.log(peerID, text, options);
|
||||
if (!angular.isString(text) || !text.length) {
|
||||
return;
|
||||
}
|
||||
|
@ -162,7 +162,7 @@
|
||||
</a>
|
||||
<a class="pull-left im_panel_own_photo" my-peer-photolink="ownID" img-class="im_panel_own_photo" watch="true" ng-click="openSettings()" no-open="true"></a>
|
||||
|
||||
<form my-send-form draft-message="draftMessage" class="im_send_form" ng-class="{im_send_form_empty: !draftMessage.text.length}">
|
||||
<form my-send-form draft-message="draftMessage" mentions="mentions" class="im_send_form" ng-class="{im_send_form_empty: !draftMessage.text.length}">
|
||||
|
||||
<div class="im_send_reply_wrap" ng-if="draftMessage.replyToMessage != null">
|
||||
<a class="im_send_reply_cancel" ng-click="draftMessage.replyClear()"><i class="icon icon-reply-bar"></i><i class="icon icon-reply-bar"></i></a>
|
||||
|
Loading…
x
Reference in New Issue
Block a user