Browse Source

Added basic inline bots support

master
Igor Zhukov 8 years ago
parent
commit
040da24417
  1. 55
      app/js/controllers.js
  2. 35
      app/js/directives.js
  3. 5
      app/js/lib/ng_utils.js
  4. 12
      app/js/lib/utils.js
  5. 102
      app/js/message_composer.js
  6. 104
      app/js/messages_manager.js
  7. 2
      app/js/services.js
  8. 88
      app/less/app.less
  9. 2
      app/partials/desktop/composer_dropdown.html
  10. 2
      app/partials/desktop/im.html
  11. 16
      app/partials/desktop/inline_results.html
  12. 2
      app/partials/desktop/message.html

55
app/js/controllers.js

@ -1056,6 +1056,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -1056,6 +1056,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.selectedReply = selectedReply;
$scope.selectedCancel = selectedCancel;
$scope.selectedFlush = selectedFlush;
$scope.selectInlineBot = selectInlineBot;
$scope.startBot = startBot;
$scope.cancelBot = cancelBot;
@ -1572,13 +1573,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -1572,13 +1573,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
target.className.indexOf('im_message_body') != -1) {
break;
}
if (target.tagName == 'A' ||
target.onclick ||
target.getAttribute('ng-click')) {
return false;
}
var events = $._data(target, 'events');
if (events && (events.click || events.mousedown)) {
if (target.tagName == 'A' || hasOnlick(target)) {
return false;
}
target = target.parentNode;
@ -1663,6 +1658,11 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -1663,6 +1658,11 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.$broadcast('messages_select');
}
function selectInlineBot (botID, $event) {
$scope.$broadcast('inline_bot_select', botID);
return cancelEvent($event);
}
function selectedCancel (noBroadcast) {
$scope.selectedMsgs = {};
$scope.selectedCount = 0;
@ -2099,11 +2099,11 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -2099,11 +2099,11 @@ 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);
$scope.$watch('draftMessage.command', onCommandSelected);
$scope.$watch('draftMessage.inlineResultID', onInlineResultSelected);
$scope.$on('history_reply_markup', function (e, peerData) {
if (peerData.peerID == $scope.curDialog.peerID) {
@ -2111,6 +2111,12 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -2111,6 +2111,12 @@ angular.module('myApp.controllers', ['myApp.i18n'])
}
});
$scope.$on('inline_bot_select', function (e, botID) {
var bot = AppUsersManager.getUser(botID);
$scope.draftMessage.text = '@' + bot.username + ' ';;
$scope.$broadcast('ui_peer_draft', {focus: true});
});
$scope.replyKeyboardToggle = replyKeyboardToggle;
$scope.toggleSlash = toggleSlash;
@ -2390,7 +2396,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -2390,7 +2396,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
return cancelEvent($event);
}
var inlineUsernameRegex = /^@([a-zA-Z\d_]{1,32}) ([\s\S]*)$/;
var inlineUsernameRegex = /^@([a-zA-Z\d_]{1,32})( | )([\s\S]*)$/;
var lastInlineBot = false;
function onMessageChange(newVal) {
// console.log('ctrl text changed', newVal);
@ -2409,11 +2415,14 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -2409,11 +2415,14 @@ angular.module('myApp.controllers', ['myApp.i18n'])
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);
var username = matches[1];
AppPeersManager.resolveInlineMention(username).then(function (inlineBot) {
$scope.$broadcast('inline_placeholder', {
prefix: '@' + username + matches[2],
placeholder: inlineBot.placeholder
});
AppMessagesManager.getInlineResults(inlineBot.id, matches[3], '').then(function (botResults) {
$scope.$broadcast('inline_results', botResults);
delete $scope.draftMessage.inlineProgress;
}, function () {
delete $scope.draftMessage.inlineProgress;
@ -2502,6 +2511,24 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -2502,6 +2511,24 @@ angular.module('myApp.controllers', ['myApp.i18n'])
delete $scope.draftMessage.sticker;
delete $scope.draftMessage.text;
delete $scope.draftMessage.command;
delete $scope.draftMessage.inlineResultID;
$scope.$broadcast('ui_message_send');
$scope.$broadcast('ui_peer_draft');
}
function onInlineResultSelected (qID) {
if (!qID) {
return;
}
var options = {
replyToMsgID: $scope.draftMessage.replyToMessage && $scope.draftMessage.replyToMessage.mid
};
AppMessagesManager.sendInlineResult($scope.curDialog.peerID, qID, options);
resetDraft();
delete $scope.draftMessage.sticker;
delete $scope.draftMessage.text;
delete $scope.draftMessage.command;
delete $scope.draftMessage.inlineResultID;
$scope.$broadcast('ui_message_send');
$scope.$broadcast('ui_peer_draft');
}

35
app/js/directives.js

@ -1516,7 +1516,7 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -1516,7 +1516,7 @@ angular.module('myApp.directives', ['myApp.filters'])
},
dropdownDirective: function (element, callback) {
var scope = $scope.$new(true);
$compile('<div my-composer-dropdown></div>')(scope, function (clonedElement) {
var clonedElement = $compile('<div><div my-composer-dropdown></div></div>')(scope, function (clonedElement, scope) {
element.replaceWith(clonedElement);
callback(scope, clonedElement);
});
@ -1524,6 +1524,7 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -1524,6 +1524,7 @@ angular.module('myApp.directives', ['myApp.filters'])
mentions: $scope.mentions,
commands: $scope.commands,
onMessageSubmit: onMessageSubmit,
onInlineResultSend: onInlineResultSend,
onFilePaste: onFilePaste,
onCommandSend: function (command) {
$scope.$apply(function () {
@ -1532,11 +1533,21 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -1532,11 +1533,21 @@ angular.module('myApp.directives', ['myApp.filters'])
}
});
$scope.$on('inline_results', function (e, inlineResults) {
setZeroTimeout(function () {
composer.showInlineSuggestions(inlineResults);
});
});
var richTextarea = composer.richTextareaEl[0];
if (richTextarea) {
$(richTextarea).on('keydown keyup', updateHeight);
}
$scope.$on('inline_placeholder', function(e, data) {
composer.setInlinePlaceholder(data.prefix, data.placeholder);
});
fileSelects.on('change', function () {
var self = this;
$scope.$apply(function () {
@ -1573,6 +1584,12 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -1573,6 +1584,12 @@ angular.module('myApp.directives', ['myApp.filters'])
return cancelEvent(e);
}
function onInlineResultSend (qID) {
$scope.$apply(function () {
$scope.draftMessage.inlineResultID = qID;
});
}
function updateValue () {
if (richTextarea) {
composer.onChange();
@ -2265,7 +2282,7 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -2265,7 +2282,7 @@ angular.module('myApp.directives', ['myApp.filters'])
var src = 'https://maps.googleapis.com/maps/api/staticmap?sensor=false&center=' + $scope.point['lat'] + ',' + $scope.point['long'] + '&zoom=15&size='+width+'x'+height+'&scale=2&key=' + apiKey;
ExternalResourcesManager.downloadImage(src).then(function (url) {
element.attr('src', url);
element.attr('src', url.valueOf());
});
}
@ -2765,7 +2782,7 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -2765,7 +2782,7 @@ angular.module('myApp.directives', ['myApp.filters'])
}
};
if (element[0].tagName == 'A') {
if (element[0].tagName == 'A' && !hasOnlick(element[0])) {
element.on('click', function () {
if (peerID > 0) {
AppUsersManager.openUser(peerID, override);
@ -3382,7 +3399,7 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -3382,7 +3399,7 @@ angular.module('myApp.directives', ['myApp.filters'])
})
.directive('myInlineResults', function () {
.directive('myInlineResults', function (ExternalResourcesManager) {
return {
templateUrl: templateUrl('inline_results'),
@ -3391,8 +3408,14 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -3391,8 +3408,14 @@ angular.module('myApp.directives', ['myApp.filters'])
},
link: function ($scope, element, attrs) {
$scope.$watch('botResults.results.length', function (show) {
// console.log($scope.botResults, show);
$scope.$watch('botResults.results', function (results) {
angular.forEach(results, function (result) {
if (result.thumb_url && !result.thumbUrl) {
ExternalResourcesManager.downloadImage(result.thumb_url).then(function (url) {
result.thumbUrl = url;
});
}
})
});
}
}

5
app/js/lib/ng_utils.js

@ -963,7 +963,7 @@ angular.module('izhukov.utils', []) @@ -963,7 +963,7 @@ angular.module('izhukov.utils', [])
};
})
.service('ExternalResourcesManager', function ($q, $http) {
.service('ExternalResourcesManager', function ($q, $http, $sce) {
var urlPromises = {};
function downloadImage (url) {
@ -974,7 +974,8 @@ angular.module('izhukov.utils', []) @@ -974,7 +974,8 @@ angular.module('izhukov.utils', [])
return urlPromises[url] = $http.get(url, {responseType: 'blob', transformRequest: null})
.then(function (response) {
window.URL = window.URL || window.webkitURL;
return window.URL.createObjectURL(response.data);
var url = window.URL.createObjectURL(response.data);
return $sce.trustAsResourceUrl(url);
});
}

12
app/js/lib/utils.js

@ -60,6 +60,18 @@ function cancelEvent (event) { @@ -60,6 +60,18 @@ function cancelEvent (event) {
return false;
}
function hasOnlick (element) {
if (element.onclick ||
element.getAttribute('ng-click')) {
return true;
}
var events = $._data(element, 'events');
if (events && (events.click || events.mousedown)) {
return true;
}
return false;
}
function getScrollWidth() {
var outer = $('<div>').css({
position: 'absolute',

102
app/js/message_composer.js

@ -683,8 +683,8 @@ function MessageComposer (textarea, options) { @@ -683,8 +683,8 @@ function MessageComposer (textarea, options) {
this.autoCompleteWrapEl = $('<div class="composer_dropdown_wrap"></div>').appendTo(document.body);
var autoCompleteEl = $('<div></div>').appendTo(this.autoCompleteWrapEl);
options.dropdownDirective(autoCompleteEl, function (scope, autoCompleteEl) {
self.autoCompleteEl = autoCompleteEl;
options.dropdownDirective(autoCompleteEl, function (scope, newAutoCompleteEl) {
self.autoCompleteEl = newAutoCompleteEl;
self.autoCompleteScope = scope;
self.setUpAutoComplete();
});
@ -696,6 +696,7 @@ function MessageComposer (textarea, options) { @@ -696,6 +696,7 @@ function MessageComposer (textarea, options) {
this.getSendOnEnter = options.getSendOnEnter;
this.onFilePaste = options.onFilePaste;
this.onCommandSend = options.onCommandSend;
this.onInlineResultSend = options.onInlineResultSend;
this.mentions = options.mentions;
this.commands = options.commands;
}
@ -704,6 +705,10 @@ MessageComposer.autoCompleteRegEx = /(\s|^)(:|@|\/)([A-Za-z0-9\-\+\*@_]*)$/; @@ -704,6 +705,10 @@ MessageComposer.autoCompleteRegEx = /(\s|^)(:|@|\/)([A-Za-z0-9\-\+\*@_]*)$/;
MessageComposer.prototype.setUpInput = function () {
this.inlinePlaceholderWrap = $('<div class="im_inline_placeholder_wrap"></div>').prependTo(this.textareaEl[0].parentNode);
this.inlinePlaceholderPrefixEl = $('<span class="im_inline_placeholder_prefix"></span>').appendTo(this.inlinePlaceholderWrap);
this.inlinePlaceholderEl = $('<span class="im_inline_placeholder"></span>').appendTo(this.inlinePlaceholderWrap);
if ('contentEditable' in document.body) {
this.setUpRich();
} else {
@ -718,13 +723,27 @@ MessageComposer.prototype.setUpInput = function () { @@ -718,13 +723,27 @@ MessageComposer.prototype.setUpInput = function () {
}
}
MessageComposer.prototype.setInlinePlaceholder = function (prefix, placeholder) {
this.inlinePlaceholderPrefix = prefix
this.inlinePlaceholderPrefixEl.html(encodeEntities(prefix));
this.inlinePlaceholderEl.html(encodeEntities(placeholder));
}
MessageComposer.prototype.updateInlinePlaceholder = function () {
var prefix = this.inlinePlaceholderPrefix;
if (prefix) {
var value = this.textareaEl.val();
this.inlinePlaceholderWrap.toggle(value == prefix);
}
}
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;
var target = $(e.target), mention, code, command, inlineID;
if (target[0].tagName != 'A') {
target = $(target[0].parentNode);
}
@ -743,6 +762,12 @@ MessageComposer.prototype.setUpAutoComplete = function () { @@ -743,6 +762,12 @@ MessageComposer.prototype.setUpAutoComplete = function () {
}
self.hideSuggestions();
}
if (inlineID = target.attr('data-inlineid')) {
if (self.onInlineResultSend) {
self.onInlineResultSend(inlineID);
}
self.hideSuggestions();
}
return cancelEvent(e);
});
}
@ -778,7 +803,7 @@ MessageComposer.prototype.onKeyEvent = function (e) { @@ -778,7 +803,7 @@ MessageComposer.prototype.onKeyEvent = function (e) {
if (this.keyupStarted === undefined) {
this.keyupStarted = now;
}
if (now - this.keyupStarted > 10000) {
if (now - this.keyupStarted > 3000 || true) {
this.onChange();
}
else {
@ -786,6 +811,8 @@ MessageComposer.prototype.onKeyEvent = function (e) { @@ -786,6 +811,8 @@ MessageComposer.prototype.onKeyEvent = function (e) {
if (this.wasEmpty != !length) {
this.wasEmpty = !this.wasEmpty;
this.onChange();
} else if (this.inlinePlaceholderPrefix) {
this.onChange();
} else {
this.updateValueTO = setTimeout(this.onChange.bind(this), 1000);
}
@ -812,48 +839,57 @@ MessageComposer.prototype.onKeyEvent = function (e) { @@ -812,48 +839,57 @@ 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_autocomplete_option_active');
if (currentSelected.length) {
var currentSelectedWrap = currentSelected[0].parentNode;
var nextWrap = currentSelectedWrap[next ? 'nextSibling' : 'previousSibling'];
currentSelected.removeClass('composer_autocomplete_option_active');
if (nextWrap) {
$(nextWrap).find('a').addClass('composer_autocomplete_option_active');
this.scroller.scrollToNode(nextWrap);
var currentSel = $(this.autoCompleteEl).find('li.composer_autocomplete_option_active');
var allLIs = Array.prototype.slice.call($(this.autoCompleteEl).find('li'));
var nextSel;
if (currentSel.length) {
var pos = allLIs.indexOf(currentSel[0]);
var nextPos = pos + (next ? 1 : -1);
nextSel = allLIs[nextPos];
currentSel.removeClass('composer_autocomplete_option_active');
if (nextSel) {
$(nextSel).addClass('composer_autocomplete_option_active');
this.scroller.scrollToNode(nextSel);
return cancelEvent(e);
}
}
var childNodes = this.autoCompleteEl[0].childNodes;
var nextWrap = childNodes[next ? 0 : childNodes.length - 1];
this.scroller.scrollToNode(nextWrap);
$(nextWrap).find('a').addClass('composer_autocomplete_option_active');
nextSel = allLIs[next ? 0 : allLIs.length - 1];
this.scroller.scrollToNode(nextSel);
$(nextSel).addClass('composer_autocomplete_option_active');
return cancelEvent(e);
}
if (e.keyCode == 13 || e.keyCode == 9) { // Enter or Tab
var currentSelected = $(this.autoCompleteEl).find('.composer_autocomplete_option_active');
if (!currentSelected.length && e.keyCode == 9) {
currentSelected = $(this.autoCompleteEl[0].childNodes[0]).find('a');
var currentSel = $(this.autoCompleteEl).find('li.composer_autocomplete_option_active');
if (!currentSel.length && e.keyCode == 9) {
currentSel = $(this.autoCompleteEl).find('li:first');
}
currentSel = currentSel.find('a:first');
var code, mention, command;
if (code = currentSelected.attr('data-code')) {
if (code = currentSel.attr('data-code')) {
this.onEmojiSelected(code, true);
EmojiHelper.pushPopularEmoji(code);
return cancelEvent(e);
}
if (mention = currentSelected.attr('data-mention')) {
if (mention = currentSel.attr('data-mention')) {
this.onMentionSelected(mention);
return cancelEvent(e);
}
if (command = currentSelected.attr('data-command')) {
if (command = currentSel.attr('data-command')) {
if (this.onCommandSelected) {
this.onCommandSelected(command, e.keyCode == 9);
}
return cancelEvent(e);
}
if (inlineID = target.attr('data-inlineid')) {
if (self.onInlineResultSend) {
self.onInlineResultSend(inlineID);
}
return cancelEvent(e);
}
checkSubmit = true;
}
}
@ -1283,6 +1319,7 @@ MessageComposer.prototype.onChange = function (e) { @@ -1283,6 +1319,7 @@ MessageComposer.prototype.onChange = function (e) {
delete this.keyupStarted;
this.textareaEl.val(getRichValue(this.richTextareaEl[0])).trigger('change');
}
this.updateInlinePlaceholder();
}
MessageComposer.prototype.getEmojiHtml = function (code, emoji) {
@ -1402,10 +1439,26 @@ MessageComposer.prototype.showCommandsSuggestions = function (commands) { @@ -1402,10 +1439,26 @@ MessageComposer.prototype.showCommandsSuggestions = function (commands) {
});
}
MessageComposer.prototype.showInlineSuggestions = function (botResults) {
if (!botResults || !botResults.results.length) {
if (this.autocompleteShown && this.autoCompleteScope.type == 'inline') {
this.hideSuggestions();
}
return;
}
var self = this;
this.autoCompleteScope.$apply(function () {
self.autoCompleteScope.type = 'inline';
self.autoCompleteScope.botResults = botResults;
});
onContentLoaded(function () {
self.renderSuggestions();
});
}
MessageComposer.prototype.updatePosition = function () {
var offset = (this.richTextareaEl || this.textareaEl).offset();
var height = this.scroller.updateHeight();
console.log(dT(), 'pos', height);
var width = $((this.richTextareaEl || this.textareaEl)[0].parentNode).outerWidth();
this.autoCompleteWrapEl.css({
top: offset.top - height,
@ -1416,6 +1469,7 @@ MessageComposer.prototype.updatePosition = function () { @@ -1416,6 +1469,7 @@ MessageComposer.prototype.updatePosition = function () {
}
MessageComposer.prototype.hideSuggestions = function () {
// return;
this.autoCompleteWrapEl.hide();
delete this.autocompleteShown;
}

104
app/js/messages_manager.js

@ -1294,10 +1294,12 @@ angular.module('myApp.services') @@ -1294,10 +1294,12 @@ angular.module('myApp.services')
isChannel = AppPeersManager.isChannel(peerID),
isMegagroup = isChannel && AppPeersManager.isMegagroup(peerID),
asChannel = isChannel && !isMegagroup ? true : false,
entities = [],
entities = options.entities || [],
message;
text = RichTextProcessor.parseMarkdown(text, entities);
if (!options.viaBotID) {
text = RichTextProcessor.parseMarkdown(text, entities);
}
if (historyStorage === undefined) {
historyStorage = historiesStorage[peerID] = {count: null, history: [], pending: []};
@ -1331,6 +1333,7 @@ angular.module('myApp.services') @@ -1331,6 +1333,7 @@ angular.module('myApp.services')
message: text,
random_id: randomIDS,
reply_to_msg_id: replyToMsgID,
via_bot_id: options.viaBotID,
entities: entities,
views: asChannel && 1,
pending: true
@ -1362,21 +1365,35 @@ angular.module('myApp.services') @@ -1362,21 +1365,35 @@ angular.module('myApp.services')
if (replyToMsgID) {
flags |= 1;
}
if (entities.length) {
flags |= 8;
}
if (asChannel) {
flags |= 16;
}
var apiPromise;
if (options.viaBotID) {
console.warn(options);
apiPromise = MtpApiManager.invokeApi('messages.sendInlineBotResult', {
flags: flags,
peer: AppPeersManager.getInputPeerByID(peerID),
random_id: randomID,
reply_to_msg_id: getMessageLocalID(replyToMsgID),
query_id: options.queryID,
id: options.resultID
}, sentRequestOptions);
} else {
if (entities.length) {
flags |= 8;
}
apiPromise = MtpApiManager.invokeApi('messages.sendMessage', {
flags: flags,
peer: AppPeersManager.getInputPeerByID(peerID),
message: text,
random_id: randomID,
reply_to_msg_id: getMessageLocalID(replyToMsgID),
entities: entities
}, sentRequestOptions)
}
// console.log(flags, entities);
MtpApiManager.invokeApi('messages.sendMessage', {
flags: flags,
peer: AppPeersManager.getInputPeerByID(peerID),
message: text,
random_id: randomID,
reply_to_msg_id: getMessageLocalID(replyToMsgID),
entities: entities
}, sentRequestOptions).then(function (updates) {
apiPromise.then(function (updates) {
if (updates._ == 'updateShortSentMessage') {
message.flags = updates.flags;
message.date = updates.date;
@ -1424,6 +1441,31 @@ angular.module('myApp.services') @@ -1424,6 +1441,31 @@ angular.module('myApp.services')
pendingByRandomID[randomIDS] = [peerID, messageID];
};
function sendInlineResult (peerID, qID, options) {
var inlineResult = inlineResults[qID];
if (inlineResult === undefined) {
return false;
}
var splitted = qID.split('_');
var queryID = splitted.shift();
var resultID = splitted.join('_');
options = options || {};
options.viaBotID = inlineResult.botID;
options.queryID = queryID;
options.resultID = resultID;
if (inlineResult.send_message._ == 'botInlineMessageText') {
options.entities = inlineResult.send_message.entities;
sendText(peerID, inlineResult.send_message.message, options);
} else {
sendOther(peerID, {
_: 'messageMediaPending',
size: 0,
progress: {percent: 33, total: 0}
}, options);
}
}
function sendFile(peerID, file, options) {
options = options || {};
var messageID = tempID--,
@ -1654,6 +1696,10 @@ angular.module('myApp.services') @@ -1654,6 +1696,10 @@ angular.module('myApp.services')
'document': doc
};
break;
case 'messageMediaPending':
media = inputMedia;
break;
}
var flags = 0;
@ -1687,6 +1733,7 @@ angular.module('myApp.services') @@ -1687,6 +1733,7 @@ angular.module('myApp.services')
media: media,
random_id: randomIDS,
reply_to_msg_id: replyToMsgID,
via_bot_id: options.viaBotID,
views: asChannel && 1,
pending: true
};
@ -1721,13 +1768,27 @@ angular.module('myApp.services') @@ -1721,13 +1768,27 @@ angular.module('myApp.services')
sentRequestOptions.afterMessageID = pendingAfterMsgs[peerID].messageID;
}
MtpApiManager.invokeApi('messages.sendMedia', {
flags: flags,
peer: AppPeersManager.getInputPeerByID(peerID),
media: inputMedia,
random_id: randomID,
reply_to_msg_id: getMessageLocalID(replyToMsgID)
}, sentRequestOptions).then(function (updates) {
var apiPromise;
if (options.viaBotID) {
console.warn(options);
apiPromise = MtpApiManager.invokeApi('messages.sendInlineBotResult', {
flags: flags,
peer: AppPeersManager.getInputPeerByID(peerID),
random_id: randomID,
reply_to_msg_id: getMessageLocalID(replyToMsgID),
query_id: options.queryID,
id: options.resultID
}, sentRequestOptions);
} else {
apiPromise = MtpApiManager.invokeApi('messages.sendMedia', {
flags: flags,
peer: AppPeersManager.getInputPeerByID(peerID),
media: inputMedia,
random_id: randomID,
reply_to_msg_id: getMessageLocalID(replyToMsgID)
}, sentRequestOptions);
}
apiPromise.then(function (updates) {
ApiUpdatesManager.processUpdateMessage(updates);
}, function (error) {
toggleError(true);
@ -3026,9 +3087,11 @@ angular.module('myApp.services') @@ -3026,9 +3087,11 @@ angular.module('myApp.services')
angular.forEach(botResults.results, function (result) {
var qID = queryID + '_' + result.id;
result.qID = qID;
result.botID = botID;
result.rTitle = RichTextProcessor.wrapRichText(result.title, {noLinebreaks: true, noLinks: true});
result.rDescription = RichTextProcessor.wrapRichText(result.description, {noLinebreaks: true, noLinks: true});
result.initials = (result.url || result.title || result.type || '').substr(0, 1)
inlineResults[qID] = result;
});
@ -3058,6 +3121,7 @@ angular.module('myApp.services') @@ -3058,6 +3121,7 @@ angular.module('myApp.services')
getMessageThumb: getMessageThumb,
clearDialogCache: clearDialogCache,
getInlineResults: getInlineResults,
sendInlineResult: sendInlineResult,
wrapForDialog: wrapForDialog,
wrapForHistory: wrapForHistory,
wrapReplyMarkup: wrapReplyMarkup,

2
app/js/services.js

@ -833,7 +833,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) @@ -833,7 +833,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
}
})
.service('AppPeersManager', function (qSync, AppUsersManager, AppChatsManager, MtpApiManager) {
.service('AppPeersManager', function ($q, qSync, AppUsersManager, AppChatsManager, MtpApiManager) {
function getInputPeer (peerString) {
var firstChar = peerString.charAt(0),

88
app/less/app.less

@ -1440,12 +1440,14 @@ a.im_dialog_selected { @@ -1440,12 +1440,14 @@ a.im_dialog_selected {
margin: 10px 0;
}
.im_message_author,
.im_message_fwd_author {
.im_message_fwd_author,
.im_message_via_author {
color: #3a6d99;
font-weight: bold;
}
.non_osx .im_message_author,
.non_osx .im_message_fwd_author {
.non_osx .im_message_fwd_author,
.non_osx .im_message_via_author {
font-size: 12px;
}
.im_message_author_via {
@ -2368,6 +2370,18 @@ textarea.im_message_field { @@ -2368,6 +2370,18 @@ textarea.im_message_field {
height: 50px;
resize: none;
}
.im_inline_placeholder_wrap {
position: absolute;
left: 0;
margin-top: 2px;
white-space: nowrap
}
.im_inline_placeholder_prefix {
visibility: hidden;
}
.im_inline_placeholder {
color: #999;
}
.icon-online {
background: #6ec26d;
@ -2858,6 +2872,7 @@ a.composer_emoji_btn { @@ -2858,6 +2872,7 @@ a.composer_emoji_btn {
border-radius: 0;
margin-top: -5px;
margin-left: -1px;
width: 180px;
}
.composer_dropdown {
@ -2881,9 +2896,10 @@ a.composer_emoji_btn { @@ -2881,9 +2896,10 @@ a.composer_emoji_btn {
}
li a:hover,
li a.composer_autocomplete_option_active {
li.composer_autocomplete_option_active a {
color: #52719a;
background: #f2f6fa;
text-decoration: none;
}
}
@ -2903,7 +2919,7 @@ a.composer_emoji_btn { @@ -2903,7 +2919,7 @@ a.composer_emoji_btn {
.composer_dropdown {
li a:hover .composer_user_mention,
li a.composer_autocomplete_option_active .composer_user_mention {
li.composer_autocomplete_option_active a .composer_user_mention {
color: #698192;
}
}
@ -2962,7 +2978,7 @@ a.composer_emoji_btn { @@ -2962,7 +2978,7 @@ a.composer_emoji_btn {
text-overflow: ellipsis;
}
a.composer_command_option:hover .composer_command_desc,
a.composer_command_option.composer_autocomplete_option_active .composer_command_desc {
.composer_autocomplete_option_active a.composer_command_option .composer_command_desc {
color: #698192;
}
.composer_command_desc .emoji {
@ -3132,44 +3148,36 @@ _:-ms-lang(x), .composer_rich_textarea:empty:focus:before { @@ -3132,44 +3148,36 @@ _:-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;
.inline_result_wrap {
display: block;
float: none;
top: auto;
left: auto;
border: 0;
border-radius: 0;
padding: 0;
margin: 0;
z-index: auto;
}
.inline_result_wrap {
.inline_result_article {
display: block;
font-size: 13px;
line-height: 15px;
padding: 4px 10px;
color: #52719a;
&:hover,
&.composer_autocomplete_option_active {
color: #52719a;
background: #f2f6fa;
}
}
.inline_article_thumb_wrap {
width: 50px;
height: 50px;
margin-right: 10px;
pointer-events: none;
}
.inline_article_thumb {
max-width: 50px;
max-height: 50px;
line-height: 0;
}
.inline_article_thumb_initials {
background: rgba(0,0,0, 0.05);
line-height: 50px;
text-align: center;
font-size: 25px;
text-transform: uppercase;
}
.inline_article_content_wrap {
overflow: hidden;
pointer-events: none;
}
.inline_article_title {
font-weight: bold;
}

2
app/partials/desktop/composer_dropdown.html

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<div ng-switch="type">
<ul ng-switch-when="mentions" class="composer_dropdown">
<li ng-repeat="user in users">
<li ng-repeat="user in mentionUsers">
<a class="composer_mention_option" data-mention="{{user.username}}">
<span class="composer_user_photo" my-peer-photolink="user.id" img-class="composer_user_photo"></span>
<span class="composer_user_name" ng-bind-html="user.rFullName"></span>

2
app/partials/desktop/im.html

@ -203,7 +203,7 @@ @@ -203,7 +203,7 @@
<a class="composer_keyboard_btn" ng-show="historyState.replyKeyboard._ == 'replyKeyboardMarkup'" ng-mousedown="replyKeyboardToggle($event)" ng-class="!historyState.replyKeyboard.pFlags.hidden ? 'active' : ''"><i class="icon icon-keyboard"></i></a>
<div class="im_send_dropbox_wrap" my-i18n="im_photos_drop_text"></div>
<textarea ng-model="draftMessage.text" class="form-control im_message_field no_outline" dir="auto"></textarea>
<textarea ng-model="draftMessage.text" class="form-control im_message_field no_outline" dir="auto" ng-trim="false"></textarea>
</div>
<div class="im_send_buttons_wrap clearfix">

16
app/partials/desktop/inline_results.html

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
<div class="inline_results_wrap">
<div class="inline_result_wrap" ng-repeat="result in botResults.results track by result.qID" ng-switch="result.type">
<div ng-switch-default class="inline_result_">
<div class="inline_article_thumb_wrap pull-left" ng-switch="result.thumbUrl.length > 0">
<img ng-switch-when="true" ng-src="{{result.thumbUrl}}"/>
<ul class="inline_results_wrap composer_dropdown">
<li class="inline_result_wrap" ng-repeat="result in botResults.results track by result.qID" ng-switch="result.type">
<a ng-switch-default class="inline_result_article clearfix" data-inlineid="{{result.qID}}">
<div class="inline_article_thumb_wrap pull-left" ng-switch="result.thumbUrl !== undefined">
<img ng-switch-when="true" class="inline_article_thumb" ng-src="{{result.thumbUrl}}"/>
<div ng-switch-default class="inline_article_thumb_initials" ng-bind="result.initials"></div>
</div>
<div class="inline_article_content_wrap">
@ -10,6 +10,6 @@ @@ -10,6 +10,6 @@
<div class="inline_article_description" ng-if="::result.description.length > 0" ng-bind-html="::result.rDescription"></div>
<div class="inline_article_url" ng-if="::result.url.length > 0" ng-bind="::result.url"></div>
</div>
</div>
</div>
</div>
</a>
</li>
</ul>

2
app/partials/desktop/message.html

@ -44,7 +44,7 @@ @@ -44,7 +44,7 @@
<div class="im_message_body" ng-class="::{im_message_body_media: historyMessage._ == 'message' &amp;&amp; historyMessage.media ? true : false}">
<a class="im_message_author" my-peer-link="historyMessage.fromID" short="historyMessage.toID > 0" color="historyMessage.toID < 0" no-watch="true"></a><span ng-if="::historyMessage.viaBotID && !historyMessage.fwdFromID" class="im_message_author_via" my-i18n="message_via_bot"><my-i18n-param name="bot"><a class="im_message_fwd_author" my-peer-link="historyMessage.viaBotID" username="true" no-watch="true"></a></my-i18n-param></span>
<a class="im_message_author" my-peer-link="historyMessage.fromID" short="historyMessage.toID > 0" color="historyMessage.toID < 0" no-watch="true"></a><span ng-if="::historyMessage.viaBotID && !historyMessage.fwdFromID" class="im_message_author_via" my-i18n="message_via_bot"><my-i18n-param name="bot"><a class="im_message_fwd_author" my-peer-link="historyMessage.viaBotID" username="true" no-watch="true" ng-click="selectInlineBot(historyMessage.viaBotID, $event)"></a></my-i18n-param></span>
<a class="im_message_reply_wrap" my-reply-message="historyMessage.reply_to_msg" ng-if="::historyMessage.reply_to_mid"></a>

Loading…
Cancel
Save