diff --git a/app/js/controllers.js b/app/js/controllers.js
index 698302d5..6e9b7ad7 100644
--- a/app/js/controllers.js
+++ b/app/js/controllers.js
@@ -2099,6 +2099,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
};
$scope.mentions = {};
$scope.commands = {};
+ $scope.inlineResults = {};
$scope.$watch('draftMessage.text', onMessageChange);
$scope.$watch('draftMessage.files', onFilesSelected);
$scope.$watch('draftMessage.sticker', onStickerSelected);
@@ -2389,7 +2390,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
return cancelEvent($event);
}
- var inlineUsernameRegex = /^@([a-zA-Z\d_]{1,32}) /;
+ var inlineUsernameRegex = /^@([a-zA-Z\d_]{1,32}) ([\s\S]*)$/;
var lastInlineBot = false;
function onMessageChange(newVal) {
// console.log('ctrl text changed', newVal);
@@ -2405,16 +2406,27 @@ angular.module('myApp.controllers', ['myApp.i18n'])
Storage.set(backupDraftObj);
// console.log(dT(), 'draft save', backupDraftObj);
- var matches;
- if (matches = newVal.match(inlineUsernameRegex)) {
- AppPeersManager.resolveInlineMention(matches[1]).then(function (placeholder) {
- $scope.draftMessage.inlinePlaceholder = placeholder;
+ var matches = newVal.match(inlineUsernameRegex);
+ if (matches) {
+ $scope.draftMessage.inlineProgress = true;
+ AppPeersManager.resolveInlineMention(matches[1]).then(function (inlineBot) {
+ $scope.draftMessage.inlinePlaceholder = inlineBot.placeholder;
+ AppMessagesManager.getInlineResults(inlineBot.id, matches[2], '').then(function (botResults) {
+ $scope.inlineResults = botResults;
+ console.log('results', botResults);
+ delete $scope.draftMessage.inlineProgress;
+ }, function () {
+ delete $scope.draftMessage.inlineProgress;
+ });
}, function () {
-
- })
+ delete $scope.draftMessage.inlinePlaceholder;
+ delete $scope.draftMessage.inlineProgress;
+ });
}
} else {
Storage.remove('draft' + $scope.curDialog.peerID);
+ delete $scope.draftMessage.inlinePlaceholder;
+ delete $scope.draftMessage.inlineProgress;
// console.log(dT(), 'draft delete', 'draft' + $scope.curDialog.peerID);
}
}
diff --git a/app/js/directives.js b/app/js/directives.js
index f3eb85d9..da49bd58 100755
--- a/app/js/directives.js
+++ b/app/js/directives.js
@@ -1517,16 +1517,11 @@ angular.module('myApp.directives', ['myApp.filters'])
getSendOnEnter: function () {
return sendOnEnter;
},
- getPeerImage: function (element, peerID, noReplace) {
- if (cachedPeerPhotos[peerID] && !noReplace) {
- element.replaceWith(cachedPeerPhotos[peerID]);
- return;
- }
+ dropdownDirective: function (element, callback) {
var scope = $scope.$new(true);
- scope.peerID = peerID;
- peerPhotoCompiled(scope, function (clonedElement) {
- cachedPeerPhotos[peerID] = clonedElement;
+ $compile('
')(scope, function (clonedElement) {
element.replaceWith(clonedElement);
+ callback(scope, clonedElement);
});
},
mentions: $scope.mentions,
@@ -3289,7 +3284,7 @@ angular.module('myApp.directives', ['myApp.filters'])
var width = attrs.width || element.width() || 40;
var stroke = attrs.stroke || (width / 2 * 0.14);
var center = width / 2;
- var radius = center - stroke;
+ var radius = center - (stroke / 2);
// Doesn't work without unique id for every gradient
var curNum = ++num;
@@ -3345,3 +3340,63 @@ angular.module('myApp.directives', ['myApp.filters'])
};
})
+
+ .directive('myComposerDropdown', function () {
+
+ return {
+ templateUrl: templateUrl('composer_dropdown')
+ }
+ })
+
+ .directive('myEmojiSuggestions', function () {
+
+ return {
+ link: function($scope, element, attrs) {
+ $scope.$watchCollection('emojiCodes', function (codes) {
+ // var codes = $scope.$eval(attrs.myEmojiSuggestions);
+ var html = [];
+ var iconSize = Config.Mobile ? 26 : 20;
+
+ var emoticonCode, emoticonData, spritesheet, pos, categoryIndex;
+ var count = Math.min(5, codes.length);
+ var i, x, y;
+
+ for (i = 0; i < count; i++) {
+ emoticonCode = codes[i];
+ if (emoticonCode.code) {
+ emoticonCode = emoticonCode.code;
+ }
+ if (emoticonData = Config.Emoji[emoticonCode]) {
+ spritesheet = EmojiHelper.spritesheetPositions[emoticonCode];
+ categoryIndex = spritesheet[0];
+ pos = spritesheet[1];
+ x = iconSize * spritesheet[3];
+ y = iconSize * spritesheet[2];
+ html.push(':' + encodeEntities(emoticonData[1][0]) + ':');
+ }
+ }
+ onContentLoaded(function () {
+ element.html(html);
+ });
+ });
+ }
+ };
+
+ })
+
+ .directive('myInlineResults', function () {
+
+ return {
+ templateUrl: templateUrl('inline_results'),
+ scope: {
+ botResults: '=myInlineResults'
+ },
+
+ link: function ($scope, element, attrs) {
+ $scope.$watch('botResults.results.length', function (show) {
+ console.log($scope.botResults, show);
+ });
+ }
+ }
+ })
+
diff --git a/app/js/message_composer.js b/app/js/message_composer.js
index 1ba65ce3..cf04c492 100644
--- a/app/js/message_composer.js
+++ b/app/js/message_composer.js
@@ -674,38 +674,19 @@ EmojiPanel.prototype.update = function () {
function MessageComposer (textarea, options) {
+ var self = this;
+
this.textareaEl = $(textarea);
this.setUpInput();
this.autoCompleteWrapEl = $('').appendTo(document.body);
- this.autoCompleteEl = $('').appendTo(this.autoCompleteWrapEl);
+ var autoCompleteEl = $('').appendTo(this.autoCompleteWrapEl);
- this.scroller = new Scroller(this.autoCompleteEl, {maxHeight: 180});
-
- var self = this;
- this.autoCompleteEl.on('mousedown', function (e) {
- e = e.originalEvent || e;
- var target = $(e.target), mention, code, command;
- if (target[0].tagName != 'A') {
- target = $(target[0].parentNode);
- }
- if (code = target.attr('data-code')) {
- if (self.onEmojiSelected) {
- self.onEmojiSelected(code, true);
- }
- EmojiHelper.pushPopularEmoji(code);
- }
- if (mention = target.attr('data-mention')) {
- self.onMentionSelected(mention);
- }
- if (command = target.attr('data-command')) {
- if (self.onCommandSelected) {
- self.onCommandSelected(command);
- }
- self.hideSuggestions();
- }
- return cancelEvent(e);
+ options.dropdownDirective(div, function (scope, autoCompleteEl) {
+ self.autoCompleteEl = autoCompleteEl;
+ self.autoCompleteScope = scope;
+ self.setUpAutoComplete();
});
this.isActive = false;
@@ -714,10 +695,9 @@ function MessageComposer (textarea, options) {
this.onMessageSubmit = options.onMessageSubmit;
this.getSendOnEnter = options.getSendOnEnter;
this.onFilePaste = options.onFilePaste;
+ this.onCommandSend = options.onCommandSend;
this.mentions = options.mentions;
this.commands = options.commands;
- this.getPeerImage = options.getPeerImage;
- this.onCommandSend = options.onCommandSend;
}
MessageComposer.autoCompleteRegEx = /(\s|^)(:|@|\/)([A-Za-z0-9\-\+\*@_]*)$/;
@@ -738,6 +718,35 @@ MessageComposer.prototype.setUpInput = function () {
}
}
+MessageComposer.prototype.setUpAutoComplete = function () {
+ this.scroller = new Scroller(this.autoCompleteEl, {maxHeight: 180});
+
+ var self = this;
+ this.autoCompleteEl.on('mousedown', function (e) {
+ e = e.originalEvent || e;
+ var target = $(e.target), mention, code, command;
+ if (target[0].tagName != 'A') {
+ target = $(target[0].parentNode);
+ }
+ if (code = target.attr('data-code')) {
+ if (self.onEmojiSelected) {
+ self.onEmojiSelected(code, true);
+ }
+ EmojiHelper.pushPopularEmoji(code);
+ }
+ if (mention = target.attr('data-mention')) {
+ self.onMentionSelected(mention);
+ }
+ if (command = target.attr('data-command')) {
+ if (self.onCommandSelected) {
+ self.onCommandSelected(command);
+ }
+ self.hideSuggestions();
+ }
+ return cancelEvent(e);
+ });
+}
+
MessageComposer.prototype.setUpRich = function () {
this.textareaEl.hide();
this.richTextareaEl = $('');
@@ -1353,8 +1362,7 @@ MessageComposer.prototype.blur = function () {
}
}
-MessageComposer.prototype.renderSuggestions = function (html) {
- this.autoCompleteEl.html(html.join(''));
+MessageComposer.prototype.renderSuggestions = function () {
this.autoCompleteWrapEl.show();
this.scroller.reinit();
this.updatePosition();
@@ -1362,72 +1370,35 @@ MessageComposer.prototype.renderSuggestions = function (html) {
}
MessageComposer.prototype.showEmojiSuggestions = function (codes) {
- var html = [];
- var iconSize = Config.Mobile ? 26 : 20;
-
- var emoticonCode, emoticonData, spritesheet, pos, categoryIndex;
- var count = Math.min(5, codes.length);
- var i, x, y;
-
- for (i = 0; i < count; i++) {
- emoticonCode = codes[i];
- if (emoticonCode.code) {
- emoticonCode = emoticonCode.code;
- }
- if (emoticonData = Config.Emoji[emoticonCode]) {
- spritesheet = EmojiHelper.spritesheetPositions[emoticonCode];
- categoryIndex = spritesheet[0];
- pos = spritesheet[1];
- x = iconSize * spritesheet[3];
- y = iconSize * spritesheet[2];
- html.push(':' + encodeEntities(emoticonData[1][0]) + ':');
- }
- }
-
- this.renderSuggestions(html);
+ var self = this;
+ this.autoCompleteScope.$apply(function () {
+ self.autoCompleteScope.type = 'emoji';
+ self.autoCompleteScope.emojiCodes = codes;
+ });
+ onContentLoaded(function () {
+ self.renderSuggestions();
+ });
}
MessageComposer.prototype.showMentionSuggestions = function (users) {
- var html = [];
- var user;
- var count = users.length;
- var i;
-
- for (i = 0; i < count; i++) {
- user = users[i];
- html.push('' + user.rFullName + '@' + user.username + '');
- }
-
- 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.autoCompleteScope.$apply(function () {
+ self.autoCompleteScope.type = 'mentions';
+ self.autoCompleteScope.mentionUsers = users;
+ });
+ onContentLoaded(function () {
+ self.renderSuggestions();
});
}
MessageComposer.prototype.showCommandsSuggestions = function (commands) {
- var html = [];
- var command;
- var count = Math.min(200, commands.length);
- var i;
-
- for (i = 0; i < count; i++) {
- command = commands[i];
- html.push('' + encodeEntities(command.value) + '' + command.rDescription + '');
- }
-
- 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);
+ this.autoCompleteScope.$apply(function () {
+ self.autoCompleteScope.type = 'commands';
+ self.autoCompleteScope.commands = commands;
+ });
+ onContentLoaded(function () {
+ self.renderSuggestions();
});
}
diff --git a/app/js/messages_manager.js b/app/js/messages_manager.js
index 41fbb4e8..dd9d3007 100644
--- a/app/js/messages_manager.js
+++ b/app/js/messages_manager.js
@@ -3010,7 +3010,31 @@ angular.module('myApp.services')
};
}
})
- })
+ });
+
+ var inlineResults = {};
+ function getInlineResults (botID, query, offset) {
+ return MtpApiManager.invokeApi('messages.getInlineBotResults', {
+ bot: AppUsersManager.getUserInput(botID),
+ query: query,
+ offset: offset
+ }).then(function(botResults) {
+ var queryID = botResults.query_id;
+ delete botResults._;
+ delete botResults.flags;
+ delete botResults.query_id;
+ angular.forEach(botResults.results, function (result) {
+ var qID = queryID + '_' + result.id;
+ result.qID = qID;
+
+ result.rTitle = RichTextProcessor.wrapRichText(result.title, {noLinebreaks: true, noLinks: true});
+ result.rDescription = RichTextProcessor.wrapRichText(result.description, {noLinebreaks: true, noLinks: true});
+
+ inlineResults[qID] = result;
+ });
+ return botResults;
+ });
+ }
return {
getConversations: getConversations,
@@ -3033,6 +3057,7 @@ angular.module('myApp.services')
getMessagePeer: getMessagePeer,
getMessageThumb: getMessageThumb,
clearDialogCache: clearDialogCache,
+ getInlineResults: getInlineResults,
wrapForDialog: wrapForDialog,
wrapForHistory: wrapForHistory,
wrapReplyMarkup: wrapReplyMarkup,
diff --git a/app/js/services.js b/app/js/services.js
index 42fcb126..3da6163d 100755
--- a/app/js/services.js
+++ b/app/js/services.js
@@ -949,7 +949,10 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
if (peerID > 0) {
var bot = AppUsersManager.getUser(peerID);
if (bot.pFlags.bot && bot.bot_inline_placeholder !== undefined) {
- return bot.bot_inline_placeholder;
+ return qSync.when({
+ id: peerID,
+ placeholder: bot.bot_inline_placeholder
+ });
}
}
return $q.reject();
diff --git a/app/less/app.less b/app/less/app.less
index 681ecf98..cb853137 100644
--- a/app/less/app.less
+++ b/app/less/app.less
@@ -434,6 +434,10 @@ a {
animation: infinite_rotation 0.8s linear infinite;
}
+ .composer_progress_icon & {
+ stroke: rgba(0,0,0,0.3);
+ }
+
.progress-arc-percent & {
stroke: #FFF;
stroke: rgba(255,255,255,0.95);
@@ -449,14 +453,23 @@ a {
.stop0 {
stop-opacity: 1.0;
stop-color: #68a4d1;
+ .composer_progress_icon & {
+ stop-color: rgba(0,0,0,0.3);
+ }
}
.stop60 {
stop-opacity: 1.0;
stop-color: #68a4d1;
+ .composer_progress_icon & {
+ stop-color: rgba(0,0,0,0.3);
+ }
}
.stop100 {
stop-opacity: 0.0;
stop-color: #68a4d1;
+ .composer_progress_icon & {
+ stop-color: rgba(0,0,0,0.3);
+ }
}
/* Infinite rotation */
@@ -2485,7 +2498,27 @@ img.img_fullsize {
}
/* Message composer */
+.composer_progress_icon {
+ display: block;
+ opacity: 0;
+ position: absolute;
+ right: 3px;
+ top: 2px;
+ cursor: pointer;
+ padding: 0;
+
+ width: 22px;
+ height: 22px;
+ margin-top: 1px;
+ transition: opacity cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.2s;
+ pointer-events: none;
+
+ .composer_progress_enabled & {
+ opacity: 1;
+ }
+}
.composer_emoji_insert_btn {
+ opacity: 1;
display: block;
position: absolute;
right: 3px;
@@ -2496,7 +2529,13 @@ img.img_fullsize {
width: 22px;
height: 22px;
margin-top: 1px;
+ transition: opacity cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.2s;
+
+ .composer_progress_enabled & {
+ opacity: 0;
+ }
}
+
.icon-emoji {
display: inline-block;
width: 22px;
@@ -3093,6 +3132,46 @@ _:-ms-lang(x), .composer_rich_textarea:empty:focus:before {
}
}
+.im_send_form_inline_results {
+ position: relative;
+ display: none;
+}
+.inline_results_wrap {
+ position: absolute;
+ bottom: 0;
+ background: #FFF;
+ border: 0;
+
+ .box-shadow(0px 1px 1px 0px rgba(60,75,87,0.27));
+
+ // margin-top: -5px;
+ // margin-left: -1px;
+ // position: static;
+ display: block;
+ float: none;
+ top: auto;
+ left: auto;
+ border: 0;
+ border-radius: 0;
+ padding: 0;
+ margin: 0;
+ z-index: auto;
+}
+
+.inline_result_wrap {
+ display: block;
+ font-size: 13px;
+ line-height: 15px;
+ padding: 4px 10px;
+ color: #52719a;
+
+ &:hover,
+ &.composer_autocomplete_option_active {
+ color: #52719a;
+ background: #f2f6fa;
+ }
+}
+
.error_modal_window {
.modal-dialog {
diff --git a/app/partials/desktop/composer_dropdown.html b/app/partials/desktop/composer_dropdown.html
new file mode 100644
index 00000000..3cc9dab6
--- /dev/null
+++ b/app/partials/desktop/composer_dropdown.html
@@ -0,0 +1,27 @@
+
\ No newline at end of file
diff --git a/app/partials/desktop/im.html b/app/partials/desktop/im.html
index 22a72e87..a46d2238 100644
--- a/app/partials/desktop/im.html
+++ b/app/partials/desktop/im.html
@@ -182,7 +182,9 @@
-