From 981ffb35dd8631a117046b59235bdcc7d432dbe0 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Mon, 1 Feb 2016 21:04:55 +0300 Subject: [PATCH] Improved inline bots support Closes #1019 --- app/js/controllers.js | 81 ++++++++++++++++-------- app/js/directives.js | 44 +++++++++---- app/js/lib/ng_utils.js | 9 ++- app/js/message_composer.js | 75 +++++++++++++--------- app/js/services.js | 7 +- app/less/app.less | 27 ++++++-- app/partials/desktop/inline_results.html | 42 ++++++++++-- 7 files changed, 204 insertions(+), 81 deletions(-) diff --git a/app/js/controllers.js b/app/js/controllers.js index 1347fdba..58c049b0 100644 --- a/app/js/controllers.js +++ b/app/js/controllers.js @@ -2269,6 +2269,9 @@ angular.module('myApp.controllers', ['myApp.i18n']) $scope.draftMessage.text = ''; $scope.$broadcast('ui_peer_draft'); } + + delete $scope.draftMessage.inlineProgress; + $scope.$broadcast('inline_results', false); } function applyDraftAttachment (e, attachment) { @@ -2396,8 +2399,6 @@ angular.module('myApp.controllers', ['myApp.i18n']) return cancelEvent($event); } - var inlineUsernameRegex = /^@([a-zA-Z\d_]{1,32})( | )([\s\S]*)$/; - var lastInlineBot = false; function onMessageChange(newVal) { // console.log('ctrl text changed', newVal); // console.trace('ctrl text changed', newVal); @@ -2411,33 +2412,64 @@ angular.module('myApp.controllers', ['myApp.i18n']) backupDraftObj['draft' + $scope.curDialog.peerID] = newVal; Storage.set(backupDraftObj); // console.log(dT(), 'draft save', backupDraftObj); + } else { + Storage.remove('draft' + $scope.curDialog.peerID); + // console.log(dT(), 'draft delete', 'draft' + $scope.curDialog.peerID); + } + checkInlinePattern(newVal); + } - var matches = newVal.match(inlineUsernameRegex); - if (matches) { - $scope.draftMessage.inlineProgress = true; - var username = matches[1]; - AppPeersManager.resolveInlineMention(username).then(function (inlineBot) { - $scope.$broadcast('inline_placeholder', { - prefix: '@' + username + matches[2], - placeholder: inlineBot.placeholder - }); - AppInlineBotsManager.getInlineResults(inlineBot.id, matches[3], '').then(function (botResults) { - $scope.$broadcast('inline_results', botResults); - delete $scope.draftMessage.inlineProgress; - }, function () { - delete $scope.draftMessage.inlineProgress; - }); + var inlineUsernameRegex = /^@([a-zA-Z\d_]{1,32})( | )([\s\S]*)$/; + var getInlineResultsTO = false; + var jump = 0; + + function checkInlinePattern (message) { + if (getInlineResultsTO) { + $timeout.cancel(getInlineResultsTO); + } + var curJump = ++jump; + if (!message || !message.length) { + delete $scope.draftMessage.inlineProgress; + $scope.$broadcast('inline_results', false); + return; + } + var matches = message.match(inlineUsernameRegex); + if (!matches) { + delete $scope.draftMessage.inlineProgress; + $scope.$broadcast('inline_results', false); + return; + } + var username = matches[1]; + $scope.draftMessage.inlineProgress = true; + AppPeersManager.resolveInlineMention(username).then(function (inlineBot) { + if (curJump != jump) { + return; + } + $scope.$broadcast('inline_placeholder', { + prefix: '@' + username + matches[2], + placeholder: inlineBot.placeholder + }); + if (getInlineResultsTO) { + $timeout.cancel(getInlineResultsTO); + } + getInlineResultsTO = $timeout(function () { + AppInlineBotsManager.getInlineResults(inlineBot.id, matches[3], '').then(function (botResults) { + getInlineResultsTO = false; + if (curJump != jump) { + return; + } + botResults.text = message; + $scope.$broadcast('inline_results', botResults); + delete $scope.draftMessage.inlineProgress; }, function () { - delete $scope.draftMessage.inlinePlaceholder; + $scope.$broadcast('inline_results', false); delete $scope.draftMessage.inlineProgress; }); - } - } else { - Storage.remove('draft' + $scope.curDialog.peerID); - delete $scope.draftMessage.inlinePlaceholder; + }, 500); + }, function () { + $scope.$broadcast('inline_results', false); delete $scope.draftMessage.inlineProgress; - // console.log(dT(), 'draft delete', 'draft' + $scope.curDialog.peerID); - } + }); } function onTyping () { @@ -2499,7 +2531,6 @@ angular.module('myApp.controllers', ['myApp.i18n']) fwdsSend(); } delete $scope.draftMessage.sticker; - resetDraft(); } function onCommandSelected (command) { diff --git a/app/js/directives.js b/app/js/directives.js index 44429727..48e8cf4f 100755 --- a/app/js/directives.js +++ b/app/js/directives.js @@ -1533,20 +1533,22 @@ angular.module('myApp.directives', ['myApp.filters']) } }); - $scope.$on('inline_results', function (e, inlineResults) { - var w = 180; - var h = 50; - AppInlineBotsManager.regroupWrappedResults(inlineResults.results, w, h); - setZeroTimeout(function () { - composer.showInlineSuggestions(inlineResults); - }); - }); - var richTextarea = composer.richTextareaEl[0]; if (richTextarea) { $(richTextarea).on('keydown keyup', updateHeight); } + $scope.$on('inline_results', function (e, inlineResults) { + if (inlineResults) { + var w = ((richTextarea || messageField).offsetWidth || 382) - 2; + var h = 80; + AppInlineBotsManager.regroupWrappedResults(inlineResults.results, w, h); + setZeroTimeout(function () { + composer.setInlineSuggestions(inlineResults); + }); + } + }); + $scope.$on('inline_placeholder', function(e, data) { composer.setInlinePlaceholder(data.prefix, data.placeholder); }); @@ -2284,7 +2286,7 @@ angular.module('myApp.directives', ['myApp.filters']) var src = 'https://maps.googleapis.com/maps/api/staticmap?sensor=false¢er=' + $scope.point['lat'] + ',' + $scope.point['long'] + '&zoom=15&size='+width+'x'+height+'&scale=2&key=' + apiKey; - ExternalResourcesManager.downloadImage(src).then(function (url) { + ExternalResourcesManager.downloadByURL(src).then(function (url) { element.attr('src', url.valueOf()); }); } @@ -3402,7 +3404,7 @@ angular.module('myApp.directives', ['myApp.filters']) }) - .directive('myInlineResults', function (ExternalResourcesManager) { + .directive('myInlineResults', function (AppPhotosManager, ExternalResourcesManager, AppDocsManager) { return { templateUrl: templateUrl('inline_results'), @@ -3414,10 +3416,28 @@ angular.module('myApp.directives', ['myApp.filters']) $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) { + ExternalResourcesManager.downloadByURL(result.thumb_url).then(function (url) { result.thumbUrl = url; }); } + if (result.type == 'gif' && result.content_url && !result.contentUrl) { + ExternalResourcesManager.downloadByURL(result.content_url).then(function (url) { + result.contentUrl = url; + }); + } + if (result.type == 'gif' && result.document) { + AppDocsManager.downloadDoc(result.document.id); + } + if (result.type == 'photo' && result.photo) { + var photoSize = AppPhotosManager.choosePhotoSize(result.photo, result.thumbW, result.thumbH), + dim = calcImageInBox(photoSize.w, photoSize.h, result.thumbW, result.thumbH); + result.thumb = { + width: dim.w, + height: dim.h, + location: photoSize.location, + size: photoSize.size + }; + } }) }); } diff --git a/app/js/lib/ng_utils.js b/app/js/lib/ng_utils.js index 6898d8ee..de37b647 100644 --- a/app/js/lib/ng_utils.js +++ b/app/js/lib/ng_utils.js @@ -966,7 +966,7 @@ angular.module('izhukov.utils', []) .service('ExternalResourcesManager', function ($q, $http, $sce) { var urlPromises = {}; - function downloadImage (url) { + function downloadByURL (url) { if (urlPromises[url] !== undefined) { return urlPromises[url]; } @@ -976,11 +976,16 @@ angular.module('izhukov.utils', []) window.URL = window.URL || window.webkitURL; var url = window.URL.createObjectURL(response.data); return $sce.trustAsResourceUrl(url); + }, function (error) { + if (!Config.modes.chrome_packed) { + return $q.when($sce.trustAsResourceUrl(url)); + } + return $q.reject(error); }); } return { - downloadImage: downloadImage + downloadByURL: downloadByURL } }) diff --git a/app/js/message_composer.js b/app/js/message_composer.js index cc9a273f..367bd918 100644 --- a/app/js/message_composer.js +++ b/app/js/message_composer.js @@ -954,9 +954,6 @@ MessageComposer.prototype.restoreSelection = function () { MessageComposer.prototype.checkAutocomplete = function (forceFull) { - if (this.autocompleteShown && this.autoCompleteScope.type == 'inline') { - return; - } var pos, value; if (this.richTextareaEl) { var textarea = this.richTextareaEl[0]; @@ -973,6 +970,13 @@ MessageComposer.prototype.checkAutocomplete = function (forceFull) { var value = textarea.value; } + if (value && + this.curInlineResults && + this.curInlineResults.text == value) { + this.showInlineSuggestions(this.curInlineResults); + return; + }; + if (!forceFull) { value = value.substr(0, pos); } @@ -1412,54 +1416,65 @@ MessageComposer.prototype.renderSuggestions = function () { MessageComposer.prototype.showEmojiSuggestions = function (codes) { var self = this; - this.autoCompleteScope.$apply(function () { - self.autoCompleteScope.type = 'emoji'; - self.autoCompleteScope.emojiCodes = codes; - }); - onContentLoaded(function () { - self.renderSuggestions(); + setZeroTimeout(function () { + self.autoCompleteScope.$apply(function () { + self.autoCompleteScope.type = 'emoji'; + self.autoCompleteScope.emojiCodes = codes; + }); + onContentLoaded(function () { + self.renderSuggestions(); + }); }); } MessageComposer.prototype.showMentionSuggestions = function (users) { var self = this; - this.autoCompleteScope.$apply(function () { - self.autoCompleteScope.type = 'mentions'; - self.autoCompleteScope.mentionUsers = users; - }); - onContentLoaded(function () { - self.renderSuggestions(); + setZeroTimeout(function () { + self.autoCompleteScope.$apply(function () { + self.autoCompleteScope.type = 'mentions'; + self.autoCompleteScope.mentionUsers = users; + }); + onContentLoaded(function () { + self.renderSuggestions(); + }); }); } MessageComposer.prototype.showCommandsSuggestions = function (commands) { var self = this; - this.autoCompleteScope.$apply(function () { - self.autoCompleteScope.type = 'commands'; - self.autoCompleteScope.commands = commands; - }); - onContentLoaded(function () { - self.renderSuggestions(); + setZeroTimeout(function () { + self.autoCompleteScope.$apply(function () { + self.autoCompleteScope.type = 'commands'; + self.autoCompleteScope.commands = commands; + }); + onContentLoaded(function () { + self.renderSuggestions(); + }); }); } MessageComposer.prototype.showInlineSuggestions = function (botResults) { if (!botResults || !botResults.results.length) { - if (this.autocompleteShown && this.autoCompleteScope.type == 'inline') { - this.hideSuggestions(); - } + this.hideSuggestions(); return; } var self = this; - this.autoCompleteScope.$apply(function () { - self.autoCompleteScope.type = 'inline'; - self.autoCompleteScope.botResults = botResults; - }); - onContentLoaded(function () { - self.renderSuggestions(); + setZeroTimeout(function () { + self.autoCompleteScope.$apply(function () { + self.autoCompleteScope.type = 'inline'; + self.autoCompleteScope.botResults = botResults; + }); + onContentLoaded(function () { + self.renderSuggestions(); + }); }); } +MessageComposer.prototype.setInlineSuggestions = function (botResults) { + this.curInlineResults = botResults; + this.checkAutocomplete(); +} + MessageComposer.prototype.updatePosition = function () { var offset = (this.richTextareaEl || this.textareaEl).offset(); var height = this.scroller.updateHeight(); diff --git a/app/js/services.js b/app/js/services.js index 0f304503..3038720a 100755 --- a/app/js/services.js +++ b/app/js/services.js @@ -2118,7 +2118,9 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) downloadPromise.then(function (blob) { if (blob) { FileManager.getFileCorrectUrl(blob, doc.mime_type).then(function (url) { - historyDoc.url = $sce.trustAsResourceUrl(url); + var trustedUrl = $sce.trustAsResourceUrl(url); + historyDoc.url = trustedUrl; + doc.url = trustedUrl; }) historyDoc.downloaded = true; } @@ -2609,7 +2611,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) bot: AppUsersManager.getUserInput(botID), query: query, offset: offset - }).then(function(botResults) { + }, {timeout: 1, stopTime: -1, noErrorBox: true}).then(function(botResults) { var queryID = botResults.query_id; delete botResults._; delete botResults.flags; @@ -2671,7 +2673,6 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) angular.forEach(ratios, function (ratio) { var w = ratio * rowH; curW += w; - console.log(curCnt, w, curW, rowW); if (!curCnt || curCnt < 4 && curW < (rowW * 1.1)) { curCnt++; } else { diff --git a/app/less/app.less b/app/less/app.less index de58e83d..f8e43dcd 100644 --- a/app/less/app.less +++ b/app/less/app.less @@ -3153,7 +3153,14 @@ _:-ms-lang(x), .composer_rich_textarea:empty:focus:before { } } +.inline_results_wrap { + line-height: 0; +} .inline_result_wrap { + display: block; +} +.inline_result_gif, +.inline_result_photo { display: inline-block; } .inline_result_article { @@ -3185,11 +3192,23 @@ _:-ms-lang(x), .composer_rich_textarea:empty:focus:before { font-weight: bold; } -.inline_result_gif { - display: inline-block; -} -.composer_dropdown > li > a.inline_result_gif { + +.composer_dropdown > li.inline_result_gif > a, +.composer_dropdown > li.inline_result_photo > a { padding: 0; + line-height: 0; + display: block; + overflow: hidden; +} +.inline_result_gif .img_gif_video, +.inline_result_photo .inline_result_photo_image { + object-fit: cover; +} +.inline_result_gif_mtproto, +.inline_result_gif_http, +.inline_result_photo_mtproto, +.inline_result_photo_http { + pointer-events: none; } diff --git a/app/partials/desktop/inline_results.html b/app/partials/desktop/inline_results.html index 3ea3ea5c..161fe0a7 100644 --- a/app/partials/desktop/inline_results.html +++ b/app/partials/desktop/inline_results.html @@ -1,11 +1,42 @@ \ No newline at end of file