From 74da0c8f55fe5fc4a779f5d465e080497f916872 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Thu, 2 Jul 2015 23:09:04 +0300 Subject: [PATCH] make commands autocomplete work --- app/js/controllers.js | 13 ++++++- app/js/directives.js | 29 +++++---------- app/js/lib/utils.js | 16 +++++++++ app/js/message_composer.js | 73 +++++++++++++++++++++++++++----------- app/less/app.less | 2 +- 5 files changed, 91 insertions(+), 42 deletions(-) diff --git a/app/js/controllers.js b/app/js/controllers.js index 5838bb36..9e0b489e 100644 --- a/app/js/controllers.js +++ b/app/js/controllers.js @@ -1761,6 +1761,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) $scope.$watch('draftMessage.text', onMessageChange); $scope.$watch('draftMessage.files', onFilesSelected); $scope.$watch('draftMessage.sticker', onStickerSelected); + $scope.$watch('draftMessage.command', onCommandSelected); function sendMessage (e) { $scope.$broadcast('ui_message_before_send'); @@ -1866,7 +1867,6 @@ angular.module('myApp.controllers', ['myApp.i18n']) }) }); - console.log(commandsList, commandsIndex); safeReplaceObject($scope.commands, { list: commandsList, index: commandsIndex @@ -1970,6 +1970,17 @@ angular.module('myApp.controllers', ['myApp.i18n']) } delete $scope.draftMessage.sticker; } + + function onCommandSelected (command) { + if (!command) { + return; + } + AppMessagesManager.sendText($scope.curDialog.peerID, command); + delete $scope.draftMessage.sticker; + delete $scope.draftMessage.text; + $scope.$broadcast('ui_message_send'); + $scope.$broadcast('ui_peer_draft'); + } }) .controller('AppLangSelectController', function ($scope, _, Storage, ErrorService, AppRuntimeManager) { diff --git a/app/js/directives.js b/app/js/directives.js index 6677f9ab..2251dd18 100755 --- a/app/js/directives.js +++ b/app/js/directives.js @@ -563,7 +563,7 @@ angular.module('myApp.directives', ['myApp.filters']) onContentLoaded(function () { var selectedDialog = $(scrollableWrap).find('.active a.im_dialog')[0]; if (selectedDialog) { - scrollToDialog(selectedDialog.parentNode); + scrollToNode(scrollableWrap, selectedDialog.parentNode, dialogsWrap); } }); }); @@ -621,7 +621,7 @@ angular.module('myApp.directives', ['myApp.filters']) if (nextDialogWrap) { $(nextDialogWrap).find('a').trigger('mousedown'); - scrollToDialog(nextDialogWrap); + scrollToNode(scrollableWrap, nextDialogWrap, dialogsWrap); } return cancelEvent(e); @@ -681,29 +681,13 @@ angular.module('myApp.directives', ['myApp.filters']) } if (nextDialogWrap) { - scrollToDialog(nextDialogWrap); + scrollToNode(scrollableWrap, nextDialogWrap, dialogsWrap); } return cancelEvent(e); } } - function scrollToDialog(dialogWrap) { - var elTop = dialogWrap.offsetTop - 15, - elHeight = dialogWrap.offsetHeight + 30, - scrollTop = scrollableWrap.scrollTop, - viewportHeight = scrollableWrap.clientHeight; - - if (scrollTop > elTop) { // we are below the dialog to scroll - scrollableWrap.scrollTop = elTop; - $(dialogsWrap).nanoScroller({flash: true}); - } - else if (scrollTop < elTop + elHeight - viewportHeight) { // we are over the dialog to scroll - scrollableWrap.scrollTop = elTop + elHeight - viewportHeight; - $(dialogsWrap).nanoScroller({flash: true}); - } - } - } @@ -1379,7 +1363,12 @@ angular.module('myApp.directives', ['myApp.filters']) mentions: $scope.mentions, commands: $scope.commands, onMessageSubmit: onMessageSubmit, - onFilePaste: onFilePaste + onFilePaste: onFilePaste, + onCommandSend: function (command) { + $scope.$apply(function () { + $scope.draftMessage.command = command; + }); + } }); var richTextarea = composer.richTextareaEl[0]; diff --git a/app/js/lib/utils.js b/app/js/lib/utils.js index daa63d25..a07c859c 100644 --- a/app/js/lib/utils.js +++ b/app/js/lib/utils.js @@ -222,6 +222,22 @@ function setRichFocus(field, selectNode) { } } +function scrollToNode (scrollable, node, scroller) { + var elTop = node.offsetTop - 15, + elHeight = node.offsetHeight + 30, + scrollTop = scrollable.scrollTop, + viewportHeight = scrollable.clientHeight; + + if (scrollTop > elTop) { // we are below the node to scroll + scrollable.scrollTop = elTop; + $(scroller).nanoScroller({flash: true}); + } + else if (scrollTop < elTop + elHeight - viewportHeight) { // we are over the node to scroll + scrollable.scrollTop = elTop + elHeight - viewportHeight; + $(scroller).nanoScroller({flash: true}); + } +} + function onContentLoaded (cb) { setZeroTimeout(cb); } diff --git a/app/js/message_composer.js b/app/js/message_composer.js index d9242a00..c2155e7c 100644 --- a/app/js/message_composer.js +++ b/app/js/message_composer.js @@ -498,7 +498,7 @@ function MessageComposer (textarea, options) { var self = this; this.autoCompleteEl.on('mousedown', function (e) { e = e.originalEvent || e; - var target = $(e.target), mention, code; + var target = $(e.target), mention, code, command; if (target[0].tagName != 'A') { target = $(target[0].parentNode); } @@ -509,9 +509,13 @@ function MessageComposer (textarea, options) { EmojiHelper.pushPopularEmoji(code); } if (mention = target.attr('data-mention')) { - if (self.onMentionSelected) { - self.onMentionSelected(mention); + self.onMentionSelected(mention); + } + if (command = target.attr('data-command')) { + if (self.onCommandSelected) { + self.onCommandSelected(command); } + self.hideSuggestions(); } return cancelEvent(e); }); @@ -525,6 +529,7 @@ function MessageComposer (textarea, options) { this.mentions = options.mentions; this.commands = options.commands; this.getPeerImage = options.getPeerImage; + this.onCommandSend = options.onCommandSend; } MessageComposer.prototype.setUpInput = function () { @@ -533,7 +538,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 () { @@ -610,7 +615,7 @@ MessageComposer.prototype.onKeyEvent = function (e) { if (nextWrap) { $(nextWrap).find('a').addClass('composer_autocomplete_option_active'); if (!Config.Mobile) { - this.autoCompleteScrollerEl.nanoScroller({scrollTop: nextWrap.offsetTop}) + scrollToNode(this.autoCompleteEl[0], nextWrap, this.autoCompleteScrollerEl); } return cancelEvent(e); } @@ -619,7 +624,7 @@ MessageComposer.prototype.onKeyEvent = function (e) { var childNodes = this.autoCompleteEl[0].childNodes; var nextWrap = childNodes[next ? 0 : childNodes.length - 1]; if (!Config.Mobile) { - this.autoCompleteScrollerEl.nanoScroller({scrollTop: nextWrap.offsetTop}) + scrollToNode(this.autoCompleteEl[0], nextWrap, this.autoCompleteScrollerEl); } $(nextWrap).find('a').addClass('composer_autocomplete_option_active'); @@ -631,17 +636,21 @@ MessageComposer.prototype.onKeyEvent = function (e) { if (!currentSelected.length && e.keyCode == 9) { currentSelected = $(this.autoCompleteEl[0].childNodes[0]).find('a'); } - var code, mention; + var code, mention, command; 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); + this.onMentionSelected(mention); + return cancelEvent(e); + } + if (command = currentSelected.attr('data-command')) { + if (this.onCommandSelected) { + this.onCommandSelected(command, e.keyCode == 9); } + return cancelEvent(e); } checkSubmit = true; } @@ -729,9 +738,9 @@ MessageComposer.prototype.checkAutocomplete = function () { return; } this.previousQuery = matches[0]; - var query = SearchIndexManager.cleanSearchText(matches[2]); + var query = SearchIndexManager.cleanSearchText(matches[3]); - if (matches[1] == '@') { // mentions + if (matches[2] == '@') { // mentions if (this.mentions && this.mentions.index) { if (query.length) { var foundObject = SearchIndexManager.search(query, this.mentions.index); @@ -755,7 +764,7 @@ MessageComposer.prototype.checkAutocomplete = function () { this.hideSuggestions(); } } - else if (matches[1] == '/') { // commands + else if (!matches[1] && matches[2] == '/') { // commands if (this.commands && this.commands.index) { if (query.length) { var foundObject = SearchIndexManager.search(query, this.commands.index); @@ -779,7 +788,7 @@ MessageComposer.prototype.checkAutocomplete = function () { this.hideSuggestions(); } } - else { // emoji + else if (matches[2] == ':') { // emoji EmojiHelper.getPopularEmoji((function (popular) { if (query.length) { var found = EmojiHelper.searchEmojis(query); @@ -1014,6 +1023,25 @@ MessageComposer.prototype.onMentionSelected = function (username) { this.onChange(); } +MessageComposer.prototype.onCommandSelected = function (command, isTab) { + if (isTab) { + if (this.richTextareaEl) { + this.richTextareaEl.html(encodeEntities(command) + ' '); + setRichFocus(this.richTextareaEl[0]); + } + else { + var textarea = this.textareaEl[0]; + textarea.value = command + ' '; + setFieldSelection(textarea); + } + } else { + this.onCommandSend(command); + } + + this.hideSuggestions(); + this.onChange(); +} + MessageComposer.prototype.onChange = function (e) { if (this.richTextareaEl) { delete this.keyupStarted; @@ -1110,7 +1138,7 @@ MessageComposer.prototype.showEmojiSuggestions = function (codes) { MessageComposer.prototype.showMentionSuggestions = function (users) { var html = []; var user; - var count = Math.min(5, users.length); + var count = users.length; var i; for (i = 0; i < count; i++) { @@ -1128,12 +1156,12 @@ MessageComposer.prototype.showMentionSuggestions = function (users) { MessageComposer.prototype.showCommandsSuggestions = function (commands) { var html = []; var command; - var count = Math.min(5, commands.length); + var count = Math.min(200, commands.length); var i; for (i = 0; i < count; i++) { command = commands[i]; - html.push('
  • ' + command.value + '' + command.description + '
  • '); + html.push('
  • ' + encodeEntities(command.value) + '' + encodeEntities(command.description) + '
  • '); } this.renderSuggestions(html); @@ -1153,13 +1181,18 @@ MessageComposer.prototype.showCommandsSuggestions = function (commands) { MessageComposer.prototype.updatePosition = function () { var offset = (this.richTextareaEl || this.textareaEl).offset(); - var height = this.autoCompleteWrapEl.outerHeight(); var width = (this.richTextareaEl || this.textareaEl).outerWidth(); - this.autoCompleteWrapEl.css({top: offset.top - height, left: offset.left, width: width - 2}); + var contentHeight = this.autoCompleteEl[0].firstChild.clientHeight * this.autoCompleteEl[0].childNodes.length; + var height = Math.min(180, contentHeight); + this.autoCompleteWrapEl.css({ + top: offset.top - height, + left: offset.left, + width: width - 2, + height: height + }); } MessageComposer.prototype.hideSuggestions = function () { - return; this.autoCompleteWrapEl.hide(); delete this.autocompleteShown; } diff --git a/app/less/app.less b/app/less/app.less index 3b39feec..ced11974 100644 --- a/app/less/app.less +++ b/app/less/app.less @@ -2424,7 +2424,7 @@ a.composer_emoji_btn { border-radius: 0; margin-top: -5px; - height: 180px; + margin-left: -1px; } .composer_dropdown_scroller { }