Browse Source

Improved inline bots support

Closes #1019
master
Igor Zhukov 8 years ago
parent
commit
981ffb35dd
  1. 81
      app/js/controllers.js
  2. 44
      app/js/directives.js
  3. 9
      app/js/lib/ng_utils.js
  4. 75
      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

81
app/js/controllers.js

@ -2269,6 +2269,9 @@ angular.module('myApp.controllers', ['myApp.i18n']) @@ -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']) @@ -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']) @@ -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']) @@ -2499,7 +2531,6 @@ angular.module('myApp.controllers', ['myApp.i18n'])
fwdsSend();
}
delete $scope.draftMessage.sticker;
resetDraft();
}
function onCommandSelected (command) {

44
app/js/directives.js

@ -1533,20 +1533,22 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -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']) @@ -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;
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']) @@ -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']) @@ -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
};
}
})
});
}

9
app/js/lib/ng_utils.js

@ -966,7 +966,7 @@ angular.module('izhukov.utils', []) @@ -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', []) @@ -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
}
})

75
app/js/message_composer.js

@ -954,9 +954,6 @@ MessageComposer.prototype.restoreSelection = function () { @@ -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) { @@ -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 () { @@ -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();

7
app/js/services.js

@ -2118,7 +2118,9 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) @@ -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']) @@ -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']) @@ -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 {

27
app/less/app.less

@ -3153,7 +3153,14 @@ _:-ms-lang(x), .composer_rich_textarea:empty:focus:before { @@ -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 { @@ -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;
}

42
app/partials/desktop/inline_results.html

@ -1,11 +1,42 @@ @@ -1,11 +1,42 @@
<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">
<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._">
<img ng-switch-when="botInlineMediaResultDocument" class="img_gif_thumb" my-load-thumb thumb="result.document.thumb" width="{{result.thumbW}}" height="{{result.thumbH}}" />
<img ng-switch-default ng-if="result.thumbUrl !== undefined" class="img_gif_thumb" ng- width="{{result.thumbW}}" height="{{result.thumbH}}" ng-src="{{result.thumbUrl}}" />
<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="img_gif_with_progress_wrap" data-inlineid="{{result.qID}}" ng-style="::{width: result.thumbW, height: result.thumbH}" ng-switch="result._">
<div ng-switch-when="botInlineMediaResultDocument" ng-switch="result.document.url !== undefined" class="inline_result_gif_mtproto">
<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>
</a>
<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}}"/>
@ -17,5 +48,6 @@ @@ -17,5 +48,6 @@
<div class="inline_article_url" ng-if="::result.url.length > 0" ng-bind="::result.url"></div>
</div>
</a>
</li>
</ul>
Loading…
Cancel
Save