Commands autocomplete draft
This commit is contained in:
parent
f16ce54ae5
commit
fa3e97c6a4
@ -1746,7 +1746,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
$scope.$on('user_update', angular.noop);
|
||||
})
|
||||
|
||||
.controller('AppImSendController', function ($scope, $timeout, MtpApiManager, Storage, AppChatsManager, AppUsersManager, AppPeersManager, AppDocsManager, AppMessagesManager, MtpApiFileManager) {
|
||||
.controller('AppImSendController', function ($scope, $timeout, MtpApiManager, Storage, AppProfileManager, AppChatsManager, AppUsersManager, AppPeersManager, AppDocsManager, AppMessagesManager, MtpApiFileManager) {
|
||||
|
||||
$scope.$watch('curDialog.peer', resetDraft);
|
||||
$scope.$on('user_update', angular.noop);
|
||||
@ -1757,6 +1757,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
|
||||
$scope.draftMessage = {text: '', send: sendMessage, replyClear: replyClear};
|
||||
$scope.mentions = {};
|
||||
$scope.commands = {};
|
||||
$scope.$watch('draftMessage.text', onMessageChange);
|
||||
$scope.$watch('draftMessage.files', onFilesSelected);
|
||||
$scope.$watch('draftMessage.sticker', onStickerSelected);
|
||||
@ -1831,8 +1832,52 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
});
|
||||
}
|
||||
|
||||
function updateCommands () {
|
||||
var peerID = $scope.curDialog.peerID;
|
||||
|
||||
AppProfileManager.getPeerBots(peerID).then(function (peerBots) {
|
||||
if (!peerBots.length) {
|
||||
safeReplaceObject($scope.commands, {});
|
||||
$scope.$broadcast('mentions_update');
|
||||
return;
|
||||
}
|
||||
|
||||
var needMentions = peerBots.length > 1;
|
||||
var commandsList = [];
|
||||
var commandsIndex = SearchIndexManager.createIndex();
|
||||
|
||||
angular.forEach(peerBots, function (peerBot) {
|
||||
var mention = '';
|
||||
if (needMentions) {
|
||||
var bot = AppUsersManager.getUser(peerBot.id);
|
||||
if (bot && bot.username) {
|
||||
mention += '@' + bot.username;
|
||||
}
|
||||
}
|
||||
var botSearchText = AppUsersManager.getUserSearchText(peerBot.id);
|
||||
angular.forEach(peerBot.commands, function (description, command) {
|
||||
var value = '/' + command + mention;
|
||||
commandsList.push({
|
||||
botID: peerBot.id,
|
||||
value: value,
|
||||
description: description
|
||||
});
|
||||
SearchIndexManager.indexObject(value, botSearchText + ' ' + command + ' ' + description, commandsIndex);
|
||||
})
|
||||
});
|
||||
|
||||
console.log(commandsList, commandsIndex);
|
||||
safeReplaceObject($scope.commands, {
|
||||
list: commandsList,
|
||||
index: commandsIndex
|
||||
});
|
||||
$scope.$broadcast('mentions_update');
|
||||
});
|
||||
}
|
||||
|
||||
function resetDraft (newPeer) {
|
||||
updateMentions();
|
||||
updateCommands();
|
||||
replyClear();
|
||||
|
||||
if (newPeer) {
|
||||
|
@ -1295,7 +1295,8 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
link: link,
|
||||
scope: {
|
||||
draftMessage: '=',
|
||||
mentions: '='
|
||||
mentions: '=',
|
||||
commands: '='
|
||||
}
|
||||
};
|
||||
|
||||
@ -1363,8 +1364,8 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
getSendOnEnter: function () {
|
||||
return sendOnEnter;
|
||||
},
|
||||
getPeerImage: function (element, peerID) {
|
||||
if (cachedPeerPhotos[peerID]) {
|
||||
getPeerImage: function (element, peerID, noReplace) {
|
||||
if (cachedPeerPhotos[peerID] && !noReplace) {
|
||||
element.replaceWith(cachedPeerPhotos[peerID]);
|
||||
return;
|
||||
}
|
||||
@ -1376,6 +1377,7 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
});
|
||||
},
|
||||
mentions: $scope.mentions,
|
||||
commands: $scope.commands,
|
||||
onMessageSubmit: onMessageSubmit,
|
||||
onFilePaste: onFilePaste
|
||||
});
|
||||
|
@ -487,7 +487,13 @@ function MessageComposer (textarea, options) {
|
||||
|
||||
this.setUpInput();
|
||||
|
||||
this.autoCompleteEl = $('<ul class="composer_dropdown dropdown-menu"></ul>').appendTo(document.body);
|
||||
this.autoCompleteWrapEl = $('<div class="composer_dropdown_wrap"></div>').appendTo(document.body);
|
||||
this.autoCompleteScrollerEl = $('<div class="composer_dropdown_scroller nano"></div>').appendTo(this.autoCompleteWrapEl);
|
||||
this.autoCompleteEl = $('<ul class="composer_dropdown dropdown-menu nano-content"></ul>').appendTo(this.autoCompleteScrollerEl);
|
||||
|
||||
if (!Config.Mobile) {
|
||||
this.autoCompleteScrollerEl.nanoScroller({preventPageScrolling: true, tabIndex: -1});
|
||||
}
|
||||
|
||||
var self = this;
|
||||
this.autoCompleteEl.on('mousedown', function (e) {
|
||||
@ -517,6 +523,7 @@ function MessageComposer (textarea, options) {
|
||||
this.getSendOnEnter = options.getSendOnEnter;
|
||||
this.onFilePaste = options.onFilePaste;
|
||||
this.mentions = options.mentions;
|
||||
this.commands = options.commands;
|
||||
this.getPeerImage = options.getPeerImage;
|
||||
}
|
||||
|
||||
@ -526,7 +533,7 @@ MessageComposer.prototype.setUpInput = function () {
|
||||
} else {
|
||||
this.setUpPlaintext();
|
||||
}
|
||||
this.autoCompleteRegEx = /(?:\s|^)(:|@)([A-Za-z0-9\-\+\*_]*)$/;
|
||||
this.autoCompleteRegEx = /(?:\s|^)(:|@|\/)([A-Za-z0-9\-\+\*@_]*)$/;
|
||||
}
|
||||
|
||||
MessageComposer.prototype.setUpRich = function () {
|
||||
@ -602,12 +609,18 @@ MessageComposer.prototype.onKeyEvent = function (e) {
|
||||
currentSelected.removeClass('composer_autocomplete_option_active');
|
||||
if (nextWrap) {
|
||||
$(nextWrap).find('a').addClass('composer_autocomplete_option_active');
|
||||
if (!Config.Mobile) {
|
||||
this.autoCompleteScrollerEl.nanoScroller({scrollTop: nextWrap.offsetTop})
|
||||
}
|
||||
return cancelEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
var childNodes = this.autoCompleteEl[0].childNodes;
|
||||
var nextWrap = childNodes[next ? 0 : childNodes.length - 1];
|
||||
if (!Config.Mobile) {
|
||||
this.autoCompleteScrollerEl.nanoScroller({scrollTop: nextWrap.offsetTop})
|
||||
}
|
||||
$(nextWrap).find('a').addClass('composer_autocomplete_option_active');
|
||||
|
||||
return cancelEvent(e);
|
||||
@ -742,6 +755,30 @@ MessageComposer.prototype.checkAutocomplete = function () {
|
||||
this.hideSuggestions();
|
||||
}
|
||||
}
|
||||
else if (matches[1] == '/') { // commands
|
||||
if (this.commands && this.commands.index) {
|
||||
if (query.length) {
|
||||
var foundObject = SearchIndexManager.search(query, this.commands.index);
|
||||
var foundCommands = [];
|
||||
var command;
|
||||
for (var i = 0, length = this.commands.list.length; i < length; i++) {
|
||||
command = this.commands.list[i];
|
||||
if (foundObject[command.value]) {
|
||||
foundCommands.push(command);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var foundCommands = this.commands.list;
|
||||
}
|
||||
if (foundCommands.length) {
|
||||
this.showCommandsSuggestions(foundCommands);
|
||||
} else {
|
||||
this.hideSuggestions();
|
||||
}
|
||||
} else {
|
||||
this.hideSuggestions();
|
||||
}
|
||||
}
|
||||
else { // emoji
|
||||
EmojiHelper.getPopularEmoji((function (popular) {
|
||||
if (query.length) {
|
||||
@ -1028,6 +1065,21 @@ MessageComposer.prototype.focus = function () {
|
||||
}
|
||||
}
|
||||
|
||||
MessageComposer.prototype.renderSuggestions = function (html) {
|
||||
this.autoCompleteEl.html(html.join(''));
|
||||
this.autoCompleteWrapEl.show();
|
||||
|
||||
var self = this;
|
||||
if (!Config.Mobile) {
|
||||
self.autoCompleteScrollerEl.nanoScroller({scroll: 'top'});
|
||||
setTimeout(function () {
|
||||
self.autoCompleteScrollerEl.nanoScroller();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
this.updatePosition();
|
||||
this.autocompleteShown = true;
|
||||
}
|
||||
|
||||
MessageComposer.prototype.showEmojiSuggestions = function (codes) {
|
||||
var html = [];
|
||||
@ -1052,10 +1104,7 @@ MessageComposer.prototype.showEmojiSuggestions = function (codes) {
|
||||
}
|
||||
}
|
||||
|
||||
this.autoCompleteEl.html(html.join(''));
|
||||
this.autoCompleteEl.show();
|
||||
this.updatePosition();
|
||||
this.autocompleteShown = true;
|
||||
this.renderSuggestions(html);
|
||||
}
|
||||
|
||||
MessageComposer.prototype.showMentionSuggestions = function (users) {
|
||||
@ -1069,27 +1118,49 @@ MessageComposer.prototype.showMentionSuggestions = function (users) {
|
||||
html.push('<li><a class="composer_mention_option" data-mention="' + user.username + '"><span class="composer_user_photo" data-user-id="' + user.id + '"></span><span class="composer_user_name">' + user.rFullName + '</span><span class="composer_user_mention">@' + user.username + '</span></a></li>');
|
||||
}
|
||||
|
||||
this.autoCompleteEl.html(html.join(''));
|
||||
|
||||
this.renderSuggestions(html);
|
||||
var self = this;
|
||||
this.autoCompleteEl.find('.composer_user_photo').each(function (k, element) {
|
||||
self.getPeerImage($(element), element.getAttribute('data-user-id'));
|
||||
});
|
||||
}
|
||||
|
||||
this.autoCompleteEl.show();
|
||||
this.updatePosition();
|
||||
this.autocompleteShown = true;
|
||||
MessageComposer.prototype.showCommandsSuggestions = function (commands) {
|
||||
var html = [];
|
||||
var command;
|
||||
var count = Math.min(5, commands.length);
|
||||
var i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
command = commands[i];
|
||||
html.push('<li><a class="composer_command_option" data-command="' + command.value + '"><span class="composer_user_photo" data-user-id="' + command.botID + '"></span><span class="composer_command_value">' + command.value + '</span><span class="composer_command_desc">' + command.description + '</span></a></li>');
|
||||
}
|
||||
|
||||
this.renderSuggestions(html);
|
||||
|
||||
var self = this;
|
||||
var usedImages = {};
|
||||
this.autoCompleteEl.find('.composer_user_photo').each(function (k, element) {
|
||||
var noReplace = true;
|
||||
var botID = element.getAttribute('data-user-id');
|
||||
if (!usedImages[botID]) {
|
||||
usedImages[botID] = true;
|
||||
noReplace = false;
|
||||
}
|
||||
self.getPeerImage($(element), botID, noReplace);
|
||||
});
|
||||
}
|
||||
|
||||
MessageComposer.prototype.updatePosition = function () {
|
||||
var offset = (this.richTextareaEl || this.textareaEl).offset();
|
||||
var height = this.autoCompleteEl.outerHeight();
|
||||
var height = this.autoCompleteWrapEl.outerHeight();
|
||||
var width = (this.richTextareaEl || this.textareaEl).outerWidth();
|
||||
this.autoCompleteEl.css({top: offset.top - height, left: offset.left, width: width - 2});
|
||||
this.autoCompleteWrapEl.css({top: offset.top - height, left: offset.left, width: width - 2});
|
||||
}
|
||||
|
||||
MessageComposer.prototype.hideSuggestions = function () {
|
||||
this.autoCompleteEl.hide();
|
||||
return;
|
||||
this.autoCompleteWrapEl.hide();
|
||||
delete this.autocompleteShown;
|
||||
}
|
||||
|
||||
|
@ -837,7 +837,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
}
|
||||
})
|
||||
|
||||
.service('AppProfileManager', function (AppBotsManager, AppUsersManager, AppPhotosManager, NotificationsManager, MtpApiManager, RichTextProcessor) {
|
||||
.service('AppProfileManager', function ($q, AppUsersManager, AppChatsManager, AppPhotosManager, NotificationsManager, MtpApiManager, RichTextProcessor) {
|
||||
|
||||
var botInfos = {};
|
||||
|
||||
@ -851,6 +851,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
commands[botCommand.command] = botCommand.description;
|
||||
})
|
||||
return botInfos[botID] = {
|
||||
id: botID,
|
||||
version: botInfo.version,
|
||||
shareText: botInfo.share_text,
|
||||
description: botInfo.description,
|
||||
@ -884,40 +885,35 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
getProfile: getProfile
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
.service('AppBotsManager', function (AppUsersManager, AppChatsManager) {
|
||||
|
||||
return {
|
||||
getPeerBots: function (peerID) {
|
||||
var peerBots = [];
|
||||
if (peerID > 0) {
|
||||
var user = AppUsersManager.getUser(peerID);
|
||||
if (!user.pFlags.bot) {
|
||||
return $q.when(peerBots);
|
||||
}
|
||||
return AppUsersManager.getUserFull(peerID).then(function (userFull) {
|
||||
var botInfo = userFull.bot_info;
|
||||
if (botInfo && botInfo._ != 'botInfoEmpty') {
|
||||
peerBots.push(botInfo);
|
||||
}
|
||||
return peerBots;
|
||||
});
|
||||
function getPeerBots (peerID) {
|
||||
var peerBots = [];
|
||||
if (peerID >= 0) {
|
||||
if (!AppUsersManager.isBot(peerID)) {
|
||||
return $q.when(peerBots);
|
||||
}
|
||||
|
||||
return AppChatsManager.getFullChat(-peerID).then(function (chatFull) {
|
||||
angular.forEach(chatFull.bot_info, function (botInfo) {
|
||||
return getProfile(peerID).then(function (userFull) {
|
||||
var botInfo = userFull.bot_info;
|
||||
if (botInfo && botInfo._ != 'botInfoEmpty') {
|
||||
peerBots.push(botInfo);
|
||||
});
|
||||
}
|
||||
return peerBots;
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
return AppChatsManager.getChatFull(-peerID).then(function (chatFull) {
|
||||
angular.forEach(chatFull.bot_info, function (botInfo) {
|
||||
peerBots.push(saveBotInfo(botInfo));
|
||||
});
|
||||
return peerBots;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
getProfile: getProfile,
|
||||
getPeerBots: getPeerBots
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
.service('AppMessagesManager', function ($q, $rootScope, $location, $filter, $timeout, $sce, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, AppWebPagesManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, PeersSelectService, Storage, AppProfileManager, FileManager, TelegramMeWebService, ErrorService, StatusManager, _) {
|
||||
|
@ -2413,15 +2413,33 @@ a.composer_emoji_btn {
|
||||
&.emoji-spritesheet-4 { background-size: 884px 182px; }
|
||||
}
|
||||
|
||||
.composer_dropdown {
|
||||
|
||||
.composer_dropdown_wrap {
|
||||
background: #FFF;
|
||||
display: none;
|
||||
padding: 6px 0;
|
||||
position: absolute;
|
||||
border: 0;
|
||||
|
||||
.box-shadow(0px 1px 1px 0px rgba(60,75,87,0.27));
|
||||
|
||||
border-radius: 0;
|
||||
margin-top: -5px;
|
||||
height: 180px;
|
||||
}
|
||||
.composer_dropdown_scroller {
|
||||
}
|
||||
|
||||
.composer_dropdown {
|
||||
position: static;
|
||||
display: block;
|
||||
float: none;
|
||||
top: auto;
|
||||
left: auto;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
z-index: auto;
|
||||
|
||||
& > li > a {
|
||||
display: block;
|
||||
@ -2473,6 +2491,7 @@ a.composer_emoji_btn {
|
||||
img& {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
span& {
|
||||
@ -2490,6 +2509,33 @@ a.composer_emoji_btn {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.composer_dropdown a.composer_command_option {
|
||||
color: #808080;
|
||||
line-height: 32px;
|
||||
padding-right: 5px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.composer_dropdown .composer_command_value {
|
||||
color: #52719a;
|
||||
display: inline;
|
||||
}
|
||||
.composer_dropdown .composer_command_desc {
|
||||
display: inline;
|
||||
color: #808080;
|
||||
padding-left: 7px;
|
||||
font-weight: normal;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
a.composer_command_option:hover .composer_command_desc,
|
||||
a.composer_command_option.composer_autocomplete_option_active .composer_command_desc {
|
||||
color: #698192;
|
||||
}
|
||||
|
||||
|
||||
.composer_stickerset_title {
|
||||
display: block;
|
||||
// clear: both;
|
||||
|
@ -482,7 +482,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
.composer_emoji_tooltip {
|
||||
.composer_emoji_tooltip,
|
||||
.composer_dropdown_wrap {
|
||||
z-index: 1001;
|
||||
|
||||
.nano > .nano-pane {
|
||||
@ -491,11 +492,18 @@
|
||||
|
||||
& > .nano-slider {
|
||||
background: #d1d1d1;
|
||||
background : rgba(0,0,0,0.17);
|
||||
margin: 0 3px 0 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.composer_dropdown_wrap .nano > .nano-pane {
|
||||
top: 3px;
|
||||
bottom: 3px;
|
||||
right: -1px;
|
||||
}
|
||||
|
||||
.countries_modal_col {
|
||||
.nano {
|
||||
& > .nano-pane {
|
||||
|
@ -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" mentions="mentions" class="im_send_form" ng-class="{im_send_form_empty: !draftMessage.text.length}">
|
||||
<form my-send-form draft-message="draftMessage" mentions="mentions" commands="commands" 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