Browse Source

Improved inline bots support

Closes #1019
master
Igor Zhukov 9 years ago
parent
commit
981ffb35dd
  1. 59
      app/js/controllers.js
  2. 42
      app/js/directives.js
  3. 9
      app/js/lib/ng_utils.js
  4. 33
      app/js/message_composer.js
  5. 7
      app/js/services.js
  6. 27
      app/less/app.less
  7. 42
      app/partials/desktop/inline_results.html

59
app/js/controllers.js

@ -2269,6 +2269,9 @@ angular.module('myApp.controllers', ['myApp.i18n'])
$scope.draftMessage.text = ''; $scope.draftMessage.text = '';
$scope.$broadcast('ui_peer_draft'); $scope.$broadcast('ui_peer_draft');
} }
delete $scope.draftMessage.inlineProgress;
$scope.$broadcast('inline_results', false);
} }
function applyDraftAttachment (e, attachment) { function applyDraftAttachment (e, attachment) {
@ -2396,8 +2399,6 @@ angular.module('myApp.controllers', ['myApp.i18n'])
return cancelEvent($event); return cancelEvent($event);
} }
var inlineUsernameRegex = /^@([a-zA-Z\d_]{1,32})( | )([\s\S]*)$/;
var lastInlineBot = false;
function onMessageChange(newVal) { function onMessageChange(newVal) {
// console.log('ctrl text changed', newVal); // console.log('ctrl text changed', newVal);
// console.trace('ctrl text changed', newVal); // console.trace('ctrl text changed', newVal);
@ -2411,34 +2412,65 @@ angular.module('myApp.controllers', ['myApp.i18n'])
backupDraftObj['draft' + $scope.curDialog.peerID] = newVal; backupDraftObj['draft' + $scope.curDialog.peerID] = newVal;
Storage.set(backupDraftObj); Storage.set(backupDraftObj);
// console.log(dT(), 'draft save', 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); var inlineUsernameRegex = /^@([a-zA-Z\d_]{1,32})( | )([\s\S]*)$/;
if (matches) { var getInlineResultsTO = false;
$scope.draftMessage.inlineProgress = true; 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]; var username = matches[1];
$scope.draftMessage.inlineProgress = true;
AppPeersManager.resolveInlineMention(username).then(function (inlineBot) { AppPeersManager.resolveInlineMention(username).then(function (inlineBot) {
if (curJump != jump) {
return;
}
$scope.$broadcast('inline_placeholder', { $scope.$broadcast('inline_placeholder', {
prefix: '@' + username + matches[2], prefix: '@' + username + matches[2],
placeholder: inlineBot.placeholder placeholder: inlineBot.placeholder
}); });
if (getInlineResultsTO) {
$timeout.cancel(getInlineResultsTO);
}
getInlineResultsTO = $timeout(function () {
AppInlineBotsManager.getInlineResults(inlineBot.id, matches[3], '').then(function (botResults) { AppInlineBotsManager.getInlineResults(inlineBot.id, matches[3], '').then(function (botResults) {
getInlineResultsTO = false;
if (curJump != jump) {
return;
}
botResults.text = message;
$scope.$broadcast('inline_results', botResults); $scope.$broadcast('inline_results', botResults);
delete $scope.draftMessage.inlineProgress; delete $scope.draftMessage.inlineProgress;
}, function () { }, function () {
$scope.$broadcast('inline_results', false);
delete $scope.draftMessage.inlineProgress; delete $scope.draftMessage.inlineProgress;
}); });
}, 500);
}, function () { }, function () {
delete $scope.draftMessage.inlinePlaceholder; $scope.$broadcast('inline_results', false);
delete $scope.draftMessage.inlineProgress; 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);
}
}
function onTyping () { function onTyping () {
if (AppPeersManager.isChannel($scope.curDialog.peerID) && if (AppPeersManager.isChannel($scope.curDialog.peerID) &&
@ -2499,7 +2531,6 @@ angular.module('myApp.controllers', ['myApp.i18n'])
fwdsSend(); fwdsSend();
} }
delete $scope.draftMessage.sticker; delete $scope.draftMessage.sticker;
resetDraft();
} }
function onCommandSelected (command) { function onCommandSelected (command) {

42
app/js/directives.js

@ -1533,19 +1533,21 @@ angular.module('myApp.directives', ['myApp.filters'])
} }
}); });
var richTextarea = composer.richTextareaEl[0];
if (richTextarea) {
$(richTextarea).on('keydown keyup', updateHeight);
}
$scope.$on('inline_results', function (e, inlineResults) { $scope.$on('inline_results', function (e, inlineResults) {
var w = 180; if (inlineResults) {
var h = 50; var w = ((richTextarea || messageField).offsetWidth || 382) - 2;
var h = 80;
AppInlineBotsManager.regroupWrappedResults(inlineResults.results, w, h); AppInlineBotsManager.regroupWrappedResults(inlineResults.results, w, h);
setZeroTimeout(function () { setZeroTimeout(function () {
composer.showInlineSuggestions(inlineResults); composer.setInlineSuggestions(inlineResults);
});
}); });
var richTextarea = composer.richTextareaEl[0];
if (richTextarea) {
$(richTextarea).on('keydown keyup', updateHeight);
} }
});
$scope.$on('inline_placeholder', function(e, data) { $scope.$on('inline_placeholder', function(e, data) {
composer.setInlinePlaceholder(data.prefix, data.placeholder); 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&center=' + $scope.point['lat'] + ',' + $scope.point['long'] + '&zoom=15&size='+width+'x'+height+'&scale=2&key=' + apiKey; 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) { ExternalResourcesManager.downloadByURL(src).then(function (url) {
element.attr('src', url.valueOf()); 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 { return {
templateUrl: templateUrl('inline_results'), templateUrl: templateUrl('inline_results'),
@ -3414,10 +3416,28 @@ angular.module('myApp.directives', ['myApp.filters'])
$scope.$watch('botResults.results', function (results) { $scope.$watch('botResults.results', function (results) {
angular.forEach(results, function (result) { angular.forEach(results, function (result) {
if (result.thumb_url && !result.thumbUrl) { 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; 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
};
}
}) })
}); });
} }

9
app/js/lib/ng_utils.js

@ -966,7 +966,7 @@ angular.module('izhukov.utils', [])
.service('ExternalResourcesManager', function ($q, $http, $sce) { .service('ExternalResourcesManager', function ($q, $http, $sce) {
var urlPromises = {}; var urlPromises = {};
function downloadImage (url) { function downloadByURL (url) {
if (urlPromises[url] !== undefined) { if (urlPromises[url] !== undefined) {
return urlPromises[url]; return urlPromises[url];
} }
@ -976,11 +976,16 @@ angular.module('izhukov.utils', [])
window.URL = window.URL || window.webkitURL; window.URL = window.URL || window.webkitURL;
var url = window.URL.createObjectURL(response.data); var url = window.URL.createObjectURL(response.data);
return $sce.trustAsResourceUrl(url); return $sce.trustAsResourceUrl(url);
}, function (error) {
if (!Config.modes.chrome_packed) {
return $q.when($sce.trustAsResourceUrl(url));
}
return $q.reject(error);
}); });
} }
return { return {
downloadImage: downloadImage downloadByURL: downloadByURL
} }
}) })

33
app/js/message_composer.js

@ -954,9 +954,6 @@ MessageComposer.prototype.restoreSelection = function () {
MessageComposer.prototype.checkAutocomplete = function (forceFull) { MessageComposer.prototype.checkAutocomplete = function (forceFull) {
if (this.autocompleteShown && this.autoCompleteScope.type == 'inline') {
return;
}
var pos, value; var pos, value;
if (this.richTextareaEl) { if (this.richTextareaEl) {
var textarea = this.richTextareaEl[0]; var textarea = this.richTextareaEl[0];
@ -973,6 +970,13 @@ MessageComposer.prototype.checkAutocomplete = function (forceFull) {
var value = textarea.value; var value = textarea.value;
} }
if (value &&
this.curInlineResults &&
this.curInlineResults.text == value) {
this.showInlineSuggestions(this.curInlineResults);
return;
};
if (!forceFull) { if (!forceFull) {
value = value.substr(0, pos); value = value.substr(0, pos);
} }
@ -1412,52 +1416,63 @@ MessageComposer.prototype.renderSuggestions = function () {
MessageComposer.prototype.showEmojiSuggestions = function (codes) { MessageComposer.prototype.showEmojiSuggestions = function (codes) {
var self = this; var self = this;
this.autoCompleteScope.$apply(function () { setZeroTimeout(function () {
self.autoCompleteScope.$apply(function () {
self.autoCompleteScope.type = 'emoji'; self.autoCompleteScope.type = 'emoji';
self.autoCompleteScope.emojiCodes = codes; self.autoCompleteScope.emojiCodes = codes;
}); });
onContentLoaded(function () { onContentLoaded(function () {
self.renderSuggestions(); self.renderSuggestions();
}); });
});
} }
MessageComposer.prototype.showMentionSuggestions = function (users) { MessageComposer.prototype.showMentionSuggestions = function (users) {
var self = this; var self = this;
this.autoCompleteScope.$apply(function () { setZeroTimeout(function () {
self.autoCompleteScope.$apply(function () {
self.autoCompleteScope.type = 'mentions'; self.autoCompleteScope.type = 'mentions';
self.autoCompleteScope.mentionUsers = users; self.autoCompleteScope.mentionUsers = users;
}); });
onContentLoaded(function () { onContentLoaded(function () {
self.renderSuggestions(); self.renderSuggestions();
}); });
});
} }
MessageComposer.prototype.showCommandsSuggestions = function (commands) { MessageComposer.prototype.showCommandsSuggestions = function (commands) {
var self = this; var self = this;
this.autoCompleteScope.$apply(function () { setZeroTimeout(function () {
self.autoCompleteScope.$apply(function () {
self.autoCompleteScope.type = 'commands'; self.autoCompleteScope.type = 'commands';
self.autoCompleteScope.commands = commands; self.autoCompleteScope.commands = commands;
}); });
onContentLoaded(function () { onContentLoaded(function () {
self.renderSuggestions(); self.renderSuggestions();
}); });
});
} }
MessageComposer.prototype.showInlineSuggestions = function (botResults) { MessageComposer.prototype.showInlineSuggestions = function (botResults) {
if (!botResults || !botResults.results.length) { if (!botResults || !botResults.results.length) {
if (this.autocompleteShown && this.autoCompleteScope.type == 'inline') {
this.hideSuggestions(); this.hideSuggestions();
}
return; return;
} }
var self = this; var self = this;
this.autoCompleteScope.$apply(function () { setZeroTimeout(function () {
self.autoCompleteScope.$apply(function () {
self.autoCompleteScope.type = 'inline'; self.autoCompleteScope.type = 'inline';
self.autoCompleteScope.botResults = botResults; self.autoCompleteScope.botResults = botResults;
}); });
onContentLoaded(function () { onContentLoaded(function () {
self.renderSuggestions(); self.renderSuggestions();
}); });
});
}
MessageComposer.prototype.setInlineSuggestions = function (botResults) {
this.curInlineResults = botResults;
this.checkAutocomplete();
} }
MessageComposer.prototype.updatePosition = function () { MessageComposer.prototype.updatePosition = function () {

7
app/js/services.js

@ -2118,7 +2118,9 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
downloadPromise.then(function (blob) { downloadPromise.then(function (blob) {
if (blob) { if (blob) {
FileManager.getFileCorrectUrl(blob, doc.mime_type).then(function (url) { 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; historyDoc.downloaded = true;
} }
@ -2609,7 +2611,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
bot: AppUsersManager.getUserInput(botID), bot: AppUsersManager.getUserInput(botID),
query: query, query: query,
offset: offset offset: offset
}).then(function(botResults) { }, {timeout: 1, stopTime: -1, noErrorBox: true}).then(function(botResults) {
var queryID = botResults.query_id; var queryID = botResults.query_id;
delete botResults._; delete botResults._;
delete botResults.flags; delete botResults.flags;
@ -2671,7 +2673,6 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils'])
angular.forEach(ratios, function (ratio) { angular.forEach(ratios, function (ratio) {
var w = ratio * rowH; var w = ratio * rowH;
curW += w; curW += w;
console.log(curCnt, w, curW, rowW);
if (!curCnt || curCnt < 4 && curW < (rowW * 1.1)) { if (!curCnt || curCnt < 4 && curW < (rowW * 1.1)) {
curCnt++; curCnt++;
} else { } else {

27
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 { .inline_result_wrap {
display: block;
}
.inline_result_gif,
.inline_result_photo {
display: inline-block; display: inline-block;
} }
.inline_result_article { .inline_result_article {
@ -3185,11 +3192,23 @@ _:-ms-lang(x), .composer_rich_textarea:empty:focus:before {
font-weight: bold; font-weight: bold;
} }
.inline_result_gif {
display: inline-block; .composer_dropdown > li.inline_result_gif > a,
} .composer_dropdown > li.inline_result_photo > a {
.composer_dropdown > li > a.inline_result_gif {
padding: 0; 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;
} }

42
app/partials/desktop/inline_results.html

@ -1,11 +1,42 @@
<ul class="inline_results_wrap composer_dropdown"> <ul class="inline_results_wrap composer_dropdown">
<li class="inline_result_wrap" ng-class="" ng-repeat="result in botResults.results track by result.qID" ng-switch="result.type"> <li class="inline_result_wrap" ng-class="'inline_result_' + result.type" ng-repeat="result in botResults.results track by result.qID" ng-switch="result.type">
<a ng-switch-when="gif" class="inline_result_gif img_gif_with_progress_wrap" data-inlineid="{{result.qID}}">
<div class="img_gif_image_wrap" ng-switch="result._"> <a ng-switch-when="gif" class="img_gif_with_progress_wrap" data-inlineid="{{result.qID}}" ng-style="::{width: result.thumbW, height: result.thumbH}" ng-switch="result._">
<img ng-switch-when="botInlineMediaResultDocument" class="img_gif_thumb" my-load-thumb thumb="result.document.thumb" width="{{result.thumbW}}" height="{{result.thumbH}}" /> <div ng-switch-when="botInlineMediaResultDocument" ng-switch="result.document.url !== undefined" class="inline_result_gif_mtproto">
<img ng-switch-default ng-if="result.thumbUrl !== undefined" class="img_gif_thumb" ng- width="{{result.thumbW}}" height="{{result.thumbH}}" ng-src="{{result.thumbUrl}}" /> <div ng-switch-when="true" ng-switch="result.document.mime_type == 'video/mp4'">
<video ng-switch-when="true" width="{{result.thumbW}}" height="{{result.thumbH}}" loop autoplay class="img_gif_video">
<source ng-src="{{result.document.url}}" type="video/mp4">
</video>
<img ng-switch-default class="img_gif_image" ng-src="{{result.document.url}}" width="{{result.thumbW}}" height="{{result.thumbH}}" />
</div>
<div ng-switch-default class="img_gif_image_wrap">
<img class="img_gif_thumb" my-load-thumb thumb="result.document.thumb" width="{{result.thumbW}}" height="{{result.thumbH}}" />
</div>
</div>
<div ng-switch-default ng-switch="result.contentUrl !== undefined" class="inline_result_gif_http">
<div ng-switch-when="true" ng-switch="result.content_type == 'video/mp4'">
<video ng-switch-when="true" width="{{result.thumbW}}" height="{{result.thumbH}}" loop autoplay class="img_gif_video">
<source ng-src="{{result.contentUrl}}" type="video/mp4">
</video>
<img ng-switch-default class="img_gif_image" ng-src="{{result.contentUrl}}" width="{{result.thumbW}}" height="{{result.thumbH}}" />
</div>
<img ng-switch-default ng-if="result.thumbUrl !== undefined" class="img_gif_thumb" width="{{result.thumbW}}" height="{{result.thumbH}}" ng-src="{{result.thumbUrl}}" />
</div>
</a>
<a ng-switch-when="photo" data-inlineid="{{result.qID}}" ng-style="::{width: result.thumbW, height: result.thumbH}" ng-switch="result._">
<div ng-switch-when="botInlineMediaResultPhoto" class="inline_result_photo_mtproto">
<img
class="inline_result_photo_image"
my-load-thumb
thumb="result.thumb"
/>
</div>
<div ng-switch-default ng-switch="result.contentUrl !== undefined" class="inline_result_photo_http">
<img ng-switch-default ng-if="result.thumbUrl !== undefined" class="inline_result_photo_image" width="{{result.thumbW}}" height="{{result.thumbH}}" ng-src="{{result.thumbUrl}}" />
</div> </div>
</a> </a>
<a ng-switch-default class="inline_result_article clearfix" data-inlineid="{{result.qID}}"> <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"> <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}}"/> <img ng-switch-when="true" class="inline_article_thumb" ng-src="{{result.thumbUrl}}"/>
@ -17,5 +48,6 @@
<div class="inline_article_url" ng-if="::result.url.length > 0" ng-bind="::result.url"></div> <div class="inline_article_url" ng-if="::result.url.length > 0" ng-bind="::result.url"></div>
</div> </div>
</a> </a>
</li> </li>
</ul> </ul>
Loading…
Cancel
Save