Merge branch 'bots'
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 10 KiB |
@ -64,7 +64,7 @@
|
||||
<script type="text/javascript" src="vendor/zlib/gunzip.min.js"></script>
|
||||
<script type="text/javascript" src="vendor/closure/long.js"></script>
|
||||
<script type="text/javascript" src="vendor/leemon_bigint/bigint.js"></script>
|
||||
<script type="text/javascript" src="vendor/libwebpjs/libwebp-0.2.0.min.js"></script>
|
||||
<script type="text/javascript" src="vendor/libwebpjs/libwebp-0.2.0.js"></script>
|
||||
|
||||
|
||||
<script type="text/javascript" src="js/lib/utils.js"></script>
|
||||
|
@ -160,7 +160,6 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
|
||||
function saveAuth (result) {
|
||||
MtpApiManager.setUserAuth(options.dcID, {
|
||||
expires: result.expires,
|
||||
id: result.user.id
|
||||
});
|
||||
$timeout.cancel(callTimeout);
|
||||
@ -408,9 +407,12 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
|
||||
$scope.$on('$routeUpdate', updateCurDialog);
|
||||
|
||||
var pendingParams = false;
|
||||
$scope.$on('history_focus', function (e, peerData) {
|
||||
$modalStack.dismissAll();
|
||||
if (peerData.peerString == $scope.curDialog.peer && peerData.messageID == $scope.curDialog.messageID) {
|
||||
if (peerData.peerString == $scope.curDialog.peer &&
|
||||
peerData.messageID == $scope.curDialog.messageID &&
|
||||
!peerData.startParam) {
|
||||
$scope.$broadcast(peerData.messageID ? 'ui_history_change_scroll' : 'ui_history_focus');
|
||||
} else {
|
||||
var peerID = AppPeersManager.getPeerID(peerData.peerString);
|
||||
@ -421,7 +423,19 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
peer = '@' + username;
|
||||
}
|
||||
}
|
||||
$location.url('/im?p=' + peer + (peerData.messageID ? '&m=' + peerData.messageID : ''));
|
||||
if (peerData.messageID || peerData.startParam) {
|
||||
pendingParams = {
|
||||
messageID: peerData.messageID,
|
||||
startParam: peerData.startParam
|
||||
};
|
||||
} else {
|
||||
pendingParams = false;
|
||||
}
|
||||
if ($routeParams.p != peer) {
|
||||
$location.url('/im?p=' + peer);
|
||||
} else {
|
||||
updateCurDialog();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -569,21 +583,24 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
} else {
|
||||
lastSearch = false;
|
||||
}
|
||||
var addParams = pendingParams || {};
|
||||
pendingParams = false;
|
||||
addParams.messageID = parseInt(addParams.messageID) || false;
|
||||
addParams.startParam = addParams.startParam || false;
|
||||
|
||||
if ($routeParams.p && $routeParams.p.charAt(0) == '@') {
|
||||
if ($scope.curDialog === undefined) {
|
||||
$scope.curDialog = {};
|
||||
}
|
||||
AppUsersManager.resolveUsername($routeParams.p.substr(1)).then(function (userID) {
|
||||
$scope.curDialog = {
|
||||
peer: AppUsersManager.getUserString(userID),
|
||||
messageID: parseInt($routeParams.m) || false
|
||||
};
|
||||
$scope.curDialog = angular.extend({
|
||||
peer: AppUsersManager.getUserString(userID)
|
||||
}, addParams);
|
||||
});
|
||||
} else {
|
||||
$scope.curDialog = {
|
||||
peer: $routeParams.p || false,
|
||||
messageID: parseInt($routeParams.m) || false
|
||||
};
|
||||
$scope.curDialog = angular.extend({
|
||||
peer: $routeParams.p || false
|
||||
}, addParams);
|
||||
}
|
||||
}
|
||||
|
||||
@ -639,6 +656,9 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
var topMessages = [];
|
||||
var topToDialogs = {};
|
||||
angular.forEach(dialogsUpdated, function (dialog, peerID) {
|
||||
if ($scope.noUsers && peerID > 0) {
|
||||
return;
|
||||
}
|
||||
topToDialogs[dialog.top_message] = dialog;
|
||||
topMessages.push(dialog.top_message);
|
||||
});
|
||||
@ -738,8 +758,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
$location.url(
|
||||
'/im' +
|
||||
($scope.curDialog.peer
|
||||
? '?p=' + $scope.curDialog.peer +
|
||||
($scope.curDialog.messageID ? '&m=' + $scope.curDialog.messageID : '')
|
||||
? '?p=' + $scope.curDialog.peer
|
||||
: ''
|
||||
)
|
||||
);
|
||||
@ -777,7 +796,11 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
return AppMessagesManager.getSearch({_: 'inputPeerEmpty'}, $scope.search.query, {_: 'inputMessagesFilterEmpty'}, maxID);
|
||||
});
|
||||
} else {
|
||||
promise = AppMessagesManager.getDialogs($scope.search.query, maxID);
|
||||
var query = $scope.search.query;
|
||||
if ($scope.noUsers) {
|
||||
query = '%pg ' + (query || '');
|
||||
}
|
||||
promise = AppMessagesManager.getDialogs(query, maxID);
|
||||
}
|
||||
|
||||
return promise.then(function (result) {
|
||||
@ -862,7 +885,10 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasMore && !searchMessages && ($scope.search.query || !$scope.dialogs.length)) {
|
||||
if (!hasMore &&
|
||||
!searchMessages &&
|
||||
!$scope.noUsers &&
|
||||
($scope.search.query || !$scope.dialogs.length)) {
|
||||
showMoreConversations();
|
||||
return;
|
||||
}
|
||||
@ -937,7 +963,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
}, 500);
|
||||
}
|
||||
|
||||
if ($scope.search.query) {
|
||||
if ($scope.search.query && !$scope.noMessages) {
|
||||
searchMessages = true;
|
||||
loadDialogs();
|
||||
}
|
||||
@ -947,7 +973,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
|
||||
.controller('AppImHistoryController', function ($scope, $location, $timeout, $rootScope, MtpApiManager, AppUsersManager, AppChatsManager, AppMessagesManager, AppPeersManager, ApiUpdatesManager, PeersSelectService, IdleManager, StatusManager, ErrorService) {
|
||||
|
||||
$scope.$watch('curDialog', applyDialogSelect);
|
||||
$scope.$watchCollection('curDialog', applyDialogSelect);
|
||||
|
||||
ApiUpdatesManager.attach();
|
||||
IdleManager.start();
|
||||
@ -967,6 +993,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
$scope.selectedReply = selectedReply;
|
||||
$scope.selectedCancel = selectedCancel;
|
||||
$scope.selectedFlush = selectedFlush;
|
||||
$scope.botStart = botStart;
|
||||
|
||||
$scope.toggleEdit = toggleEdit;
|
||||
$scope.toggleMedia = toggleMedia;
|
||||
@ -1007,8 +1034,9 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
var newPeer = newDialog.peer || $scope.curDialog.peer || '';
|
||||
peerID = AppPeersManager.getPeerID(newPeer);
|
||||
|
||||
|
||||
if (peerID == $scope.curDialog.peerID && oldDialog.messageID == newDialog.messageID) {
|
||||
if (peerID == $scope.curDialog.peerID &&
|
||||
oldDialog.messageID == newDialog.messageID &&
|
||||
oldDialog.startParam == newDialog.startParam) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1017,9 +1045,12 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
$scope.curDialog.inputPeer = AppPeersManager.getInputPeer(newPeer);
|
||||
$scope.historyFilter.mediaType = false;
|
||||
|
||||
updateStartBot();
|
||||
selectedCancel(true);
|
||||
|
||||
if (oldDialog.peer && oldDialog.peer == newDialog.peer && newDialog.messageID) {
|
||||
if (oldDialog.peer &&
|
||||
oldDialog.peer == newDialog.peer &&
|
||||
newDialog.messageID) {
|
||||
messageFocusHistory();
|
||||
}
|
||||
else if (peerID) {
|
||||
@ -1108,6 +1139,36 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
}
|
||||
}
|
||||
|
||||
function updateStartBot () {
|
||||
var wasStartBot = $scope.historyState.startBot;
|
||||
if (!peerID ||
|
||||
peerID < 0 ||
|
||||
!AppUsersManager.isBot(peerID) ||
|
||||
$scope.historyFilter.mediaType ||
|
||||
$scope.curDialog.messageID) {
|
||||
$scope.historyState.startBot = false;
|
||||
}
|
||||
else if (
|
||||
$scope.state.empty || (
|
||||
peerHistory &&
|
||||
peerHistory.messages.length == 1 &&
|
||||
peerHistory.messages[0].action &&
|
||||
peerHistory.messages[0].action._ == 'messageActionBotIntro'
|
||||
)
|
||||
) {
|
||||
$scope.historyState.startBot = 2;
|
||||
}
|
||||
else if ($scope.curDialog.startParam) {
|
||||
$scope.historyState.startBot = 1;
|
||||
}
|
||||
else {
|
||||
$scope.historyState.startBot = false;
|
||||
}
|
||||
if (wasStartBot != $scope.historyState.startBot) {
|
||||
$scope.$broadcast('ui_panel_update');
|
||||
}
|
||||
}
|
||||
|
||||
function messageFocusHistory () {
|
||||
var history = historiesQueueFind(peerID);
|
||||
|
||||
@ -1310,6 +1371,8 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
|
||||
AppMessagesManager.readHistory($scope.curDialog.inputPeer);
|
||||
|
||||
updateStartBot();
|
||||
|
||||
}, function () {
|
||||
safeReplaceObject($scope.state, {error: true});
|
||||
});
|
||||
@ -1325,16 +1388,47 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
$scope.$broadcast('ui_history_change');
|
||||
}
|
||||
|
||||
function toggleMessage (messageID, $event) {
|
||||
var target = $event.target,
|
||||
shiftClick = $event.shiftKey;
|
||||
function botStart () {
|
||||
AppMessagesManager.startBot(peerID, 0, $scope.curDialog.startParam);
|
||||
$scope.curDialog.startParam = false;
|
||||
}
|
||||
|
||||
if (shiftClick) {
|
||||
$scope.$broadcast('ui_selection_clear');
|
||||
function toggleMessage (messageID, $event) {
|
||||
if ($scope.historyState.startBot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$scope.historyState.selectActions && !$(target).hasClass('icon-select-tick') && !$(target).hasClass('im_content_message_select_area')) {
|
||||
return false;
|
||||
if (!$scope.historyState.selectActions) {
|
||||
var sel = (
|
||||
window.getSelection && window.getSelection() ||
|
||||
document.getSelection && document.getSelection() ||
|
||||
document.selection && document.selection.createRange().text || ''
|
||||
).toString().replace(/^\s+|\s+$/g, '');
|
||||
if (sel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var target = $event.target;
|
||||
while (target) {
|
||||
if (target.className.indexOf('im_message_outer_wrap') != -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)) {
|
||||
return false;
|
||||
}
|
||||
target = target.parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
var shiftClick = $event.shiftKey;
|
||||
if (shiftClick) {
|
||||
$scope.$broadcast('ui_selection_clear');
|
||||
}
|
||||
|
||||
if ($scope.selectedMsgs[messageID]) {
|
||||
@ -1382,6 +1476,11 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
}
|
||||
|
||||
function selectedCancel (noBroadcast) {
|
||||
if (!noBroadcast &&
|
||||
$scope.curDialog.startParam) {
|
||||
delete $scope.curDialog.startParam;
|
||||
return;
|
||||
}
|
||||
$scope.selectedMsgs = {};
|
||||
$scope.selectedCount = 0;
|
||||
$scope.historyState.selectActions = false;
|
||||
@ -1416,7 +1515,6 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function selectedForward () {
|
||||
if ($scope.selectedCount > 0) {
|
||||
var selectedMessageIDs = [];
|
||||
@ -1493,6 +1591,16 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
loadAfterSync = false;
|
||||
});
|
||||
|
||||
$scope.$on('reply_button_press', function (e, button) {
|
||||
var replyKeyboard = $scope.historyState.replyKeyboard;
|
||||
if (!replyKeyboard) {
|
||||
return;
|
||||
}
|
||||
AppMessagesManager.sendText(peerID, button.text, {
|
||||
replyToMsgID: peerID < 0 && replyKeyboard.id
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
var typingTimeouts = {};
|
||||
$scope.$on('history_append', function (e, addedMessage) {
|
||||
@ -1552,6 +1660,8 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
AppMessagesManager.readHistory($scope.curDialog.inputPeer);
|
||||
});
|
||||
}
|
||||
|
||||
updateStartBot();
|
||||
}
|
||||
});
|
||||
|
||||
@ -1644,6 +1754,8 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
AppMessagesManager.readHistory($scope.curDialog.inputPeer);
|
||||
});
|
||||
}
|
||||
|
||||
updateStartBot();
|
||||
}
|
||||
});
|
||||
|
||||
@ -1673,6 +1785,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
$scope.$broadcast('messages_regroup');
|
||||
if (historyUpdate.peerID == $scope.curDialog.peerID) {
|
||||
$scope.state.empty = !newMessages.length;
|
||||
updateStartBot();
|
||||
}
|
||||
});
|
||||
|
||||
@ -1683,6 +1796,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
history.ids = [];
|
||||
if (dialog.peerID == $scope.curDialog.peerID) {
|
||||
$scope.state.empty = true;
|
||||
updateStartBot();
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1737,7 +1851,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
$scope.$on('user_update', angular.noop);
|
||||
})
|
||||
|
||||
.controller('AppImSendController', function ($scope, $timeout, MtpApiManager, Storage, AppChatsManager, AppUsersManager, AppPeersManager, AppDocsManager, AppMessagesManager, MtpApiFileManager) {
|
||||
.controller('AppImSendController', function ($scope, $timeout, MtpApiManager, Storage, AppProfileManager, AppChatsManager, AppUsersManager, AppPeersManager, AppDocsManager, AppMessagesManager, MtpApiFileManager, RichTextProcessor) {
|
||||
|
||||
$scope.$watch('curDialog.peer', resetDraft);
|
||||
$scope.$on('user_update', angular.noop);
|
||||
@ -1746,11 +1860,28 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
});
|
||||
$scope.$on('ui_typing', onTyping);
|
||||
|
||||
$scope.draftMessage = {text: '', send: sendMessage, replyClear: replyClear};
|
||||
$scope.draftMessage = {
|
||||
text: '',
|
||||
send: sendMessage,
|
||||
replyClear: replyClear
|
||||
};
|
||||
$scope.mentions = {};
|
||||
$scope.commands = {};
|
||||
$scope.$watch('draftMessage.text', onMessageChange);
|
||||
$scope.$watch('draftMessage.files', onFilesSelected);
|
||||
$scope.$watch('draftMessage.sticker', onStickerSelected);
|
||||
$scope.$watch('draftMessage.command', onCommandSelected);
|
||||
|
||||
$scope.$on('history_reply_markup', function (e, peerData) {
|
||||
if (peerData.peerID == $scope.curDialog.peerID) {
|
||||
updateReplyKeyboard();
|
||||
}
|
||||
});
|
||||
|
||||
$scope.replyKeyboardToggle = replyKeyboardToggle;
|
||||
$scope.toggleSlash = toggleSlash;
|
||||
|
||||
var replyToMarkup = false;
|
||||
|
||||
function sendMessage (e) {
|
||||
$scope.$broadcast('ui_message_before_send');
|
||||
@ -1822,9 +1953,53 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
});
|
||||
}
|
||||
|
||||
function updateCommands () {
|
||||
var peerID = $scope.curDialog.peerID;
|
||||
|
||||
AppProfileManager.getPeerBots(peerID).then(function (peerBots) {
|
||||
if (!peerBots.length) {
|
||||
safeReplaceObject($scope.commands, {});
|
||||
$scope.$broadcast('mentions_update');
|
||||
return;
|
||||
}
|
||||
|
||||
var needMentions = peerBots.length > 1;
|
||||
var commandsList = [];
|
||||
var commandsIndex = SearchIndexManager.createIndex();
|
||||
|
||||
angular.forEach(peerBots, function (peerBot) {
|
||||
var mention = '';
|
||||
if (needMentions) {
|
||||
var bot = AppUsersManager.getUser(peerBot.id);
|
||||
if (bot && bot.username) {
|
||||
mention += '@' + bot.username;
|
||||
}
|
||||
}
|
||||
var botSearchText = AppUsersManager.getUserSearchText(peerBot.id);
|
||||
angular.forEach(peerBot.commands, function (description, command) {
|
||||
var value = '/' + command + mention;
|
||||
commandsList.push({
|
||||
botID: peerBot.id,
|
||||
value: value,
|
||||
rDescription: RichTextProcessor.wrapRichText(description, {noLinks: true, noLineBreaks: true})
|
||||
});
|
||||
SearchIndexManager.indexObject(value, botSearchText + ' ' + command + ' ' + description, commandsIndex);
|
||||
})
|
||||
});
|
||||
|
||||
safeReplaceObject($scope.commands, {
|
||||
list: commandsList,
|
||||
index: commandsIndex
|
||||
});
|
||||
$scope.$broadcast('mentions_update');
|
||||
});
|
||||
}
|
||||
|
||||
function resetDraft (newPeer) {
|
||||
updateMentions();
|
||||
updateCommands();
|
||||
replyClear();
|
||||
updateReplyKeyboard();
|
||||
|
||||
if (newPeer) {
|
||||
Storage.get('draft' + $scope.curDialog.peerID).then(function (draftText) {
|
||||
@ -1843,13 +2018,67 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
function replySelect(messageID) {
|
||||
$scope.draftMessage.replyToMessage = AppMessagesManager.wrapForDialog(messageID);
|
||||
$scope.$broadcast('ui_peer_reply');
|
||||
replyToMarkup = false;
|
||||
}
|
||||
|
||||
function replyClear() {
|
||||
var message = $scope.draftMessage.replyToMessage;
|
||||
if (message &&
|
||||
$scope.historyState.replyKeyboard &&
|
||||
$scope.historyState.replyKeyboard.id == message.id &&
|
||||
!$scope.historyState.replyKeyboard.pFlags.hidden) {
|
||||
$scope.historyState.replyKeyboard.pFlags.hidden = true;
|
||||
$scope.$broadcast('ui_keyboard_update');
|
||||
}
|
||||
delete $scope.draftMessage.replyToMessage;
|
||||
$scope.$broadcast('ui_peer_reply');
|
||||
}
|
||||
|
||||
function toggleSlash ($event) {
|
||||
if ($scope.draftMessage.text &&
|
||||
$scope.draftMessage.text.charAt(0) == '/') {
|
||||
$scope.draftMessage.text = '';
|
||||
} else {
|
||||
$scope.draftMessage.text = '/';
|
||||
}
|
||||
$scope.$broadcast('ui_peer_draft');
|
||||
return cancelEvent($event);
|
||||
}
|
||||
|
||||
function updateReplyKeyboard () {
|
||||
var peerID = $scope.curDialog.peerID;
|
||||
var replyKeyboard = AppMessagesManager.getReplyKeyboard(peerID);
|
||||
if (replyKeyboard) {
|
||||
replyKeyboard = AppMessagesManager.wrapReplyMarkup(replyKeyboard);
|
||||
}
|
||||
// console.log('update reply markup', peerID, replyKeyboard);
|
||||
$scope.historyState.replyKeyboard = replyKeyboard;
|
||||
|
||||
var addReplyMessage =
|
||||
replyKeyboard &&
|
||||
!replyKeyboard.hidden &&
|
||||
(replyKeyboard._ == 'replyKeyboardForceReply' ||
|
||||
(replyKeyboard._ == 'replyKeyboardMarkup' && peerID < 0));
|
||||
|
||||
if (addReplyMessage) {
|
||||
replySelect(replyKeyboard.id);
|
||||
replyToMarkup = true;
|
||||
}
|
||||
else if (replyToMarkup) {
|
||||
replyClear();
|
||||
}
|
||||
$scope.$broadcast('ui_keyboard_update');
|
||||
}
|
||||
|
||||
function replyKeyboardToggle ($event) {
|
||||
var replyKeyboard = $scope.historyState.replyKeyboard;
|
||||
if (replyKeyboard) {
|
||||
replyKeyboard.pFlags.hidden = !replyKeyboard.pFlags.hidden;
|
||||
updateReplyKeyboard();
|
||||
}
|
||||
return cancelEvent($event);
|
||||
}
|
||||
|
||||
function onMessageChange(newVal) {
|
||||
// console.log('ctrl text changed', newVal);
|
||||
// console.trace('ctrl text changed', newVal);
|
||||
@ -1916,6 +2145,17 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
}
|
||||
delete $scope.draftMessage.sticker;
|
||||
}
|
||||
|
||||
function onCommandSelected (command) {
|
||||
if (!command) {
|
||||
return;
|
||||
}
|
||||
AppMessagesManager.sendText($scope.curDialog.peerID, command);
|
||||
delete $scope.draftMessage.sticker;
|
||||
delete $scope.draftMessage.text;
|
||||
$scope.$broadcast('ui_message_send');
|
||||
$scope.$broadcast('ui_peer_draft');
|
||||
}
|
||||
})
|
||||
|
||||
.controller('AppLangSelectController', function ($scope, _, Storage, ErrorService, AppRuntimeManager) {
|
||||
@ -2156,8 +2396,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
$scope.nav = {};
|
||||
$scope.canForward = true;
|
||||
|
||||
var inputUser = AppUsersManager.getUserInput($scope.userID),
|
||||
list = [$scope.photoID],
|
||||
var list = [$scope.photoID],
|
||||
maxID = $scope.photoID,
|
||||
preloaded = {},
|
||||
myID = 0,
|
||||
@ -2165,7 +2404,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
|
||||
updatePrevNext();
|
||||
|
||||
AppPhotosManager.getUserPhotos(inputUser, 0, 1000).then(function (userpicCachedResult) {
|
||||
AppPhotosManager.getUserPhotos($scope.userID, 0, 1000).then(function (userpicCachedResult) {
|
||||
if (userpicCachedResult.photos.indexOf($scope.photoID) >= 0) {
|
||||
list = userpicCachedResult.photos;
|
||||
maxID = list[list.length - 1];
|
||||
@ -2234,7 +2473,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
function loadMore () {
|
||||
if (loadingPromise) return loadingPromise;
|
||||
|
||||
return loadingPromise = AppPhotosManager.getUserPhotos(inputUser, maxID).then(function (userpicResult) {
|
||||
return loadingPromise = AppPhotosManager.getUserPhotos($scope.userID, maxID).then(function (userpicResult) {
|
||||
if (userpicResult.photos.length) {
|
||||
maxID = userpicResult.photos[userpicResult.photos.length - 1];
|
||||
list = list.concat(userpicResult.photos);
|
||||
@ -2503,7 +2742,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
|
||||
})
|
||||
|
||||
.controller('UserModalController', function ($scope, $location, $rootScope, $modal, AppUsersManager, MtpApiManager, NotificationsManager, AppPhotosManager, AppMessagesManager, AppPeersManager, PeersSelectService, ErrorService) {
|
||||
.controller('UserModalController', function ($scope, $location, $rootScope, AppProfileManager, $modal, AppUsersManager, MtpApiManager, NotificationsManager, AppPhotosManager, AppMessagesManager, AppPeersManager, PeersSelectService, ErrorService) {
|
||||
|
||||
var peerString = AppUsersManager.getUserString($scope.userID);
|
||||
|
||||
@ -2513,23 +2752,10 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
|
||||
$scope.settings = {notifications: true};
|
||||
|
||||
MtpApiManager.invokeApi('users.getFullUser', {
|
||||
id: AppUsersManager.getUserInput($scope.userID)
|
||||
}).then(function (userFullResult) {
|
||||
if ($scope.override && $scope.override.phone_number) {
|
||||
userFullResult.user.phone = $scope.override.phone_number;
|
||||
if ($scope.override.first_name || $scope.override.last_name) {
|
||||
userFullResult.user.first_name = $scope.override.first_name;
|
||||
userFullResult.user.last_name = $scope.override.last_name;
|
||||
}
|
||||
AppUsersManager.saveApiUser(userFullResult.user);
|
||||
} else {
|
||||
AppUsersManager.saveApiUser(userFullResult.user, true);
|
||||
}
|
||||
AppPhotosManager.savePhoto(userFullResult.profile_photo);
|
||||
$scope.blocked = userFullResult.blocked;
|
||||
AppProfileManager.getProfile($scope.userID, $scope.override).then(function (userFull) {
|
||||
$scope.blocked = userFull.blocked;
|
||||
$scope.bot_info = userFull.bot_info;
|
||||
|
||||
NotificationsManager.savePeerSettings($scope.userID, userFullResult.notify_settings);
|
||||
NotificationsManager.getPeerMuted($scope.userID).then(function (muted) {
|
||||
$scope.settings.notifications = !muted;
|
||||
|
||||
@ -2538,11 +2764,7 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
return false;
|
||||
}
|
||||
NotificationsManager.getPeerSettings($scope.userID).then(function (settings) {
|
||||
if (newValue) {
|
||||
settings.mute_until = 0;
|
||||
} else {
|
||||
settings.mute_until = 2000000000;
|
||||
}
|
||||
settings.mute_until = newValue ? 0 : 2000000000;
|
||||
NotificationsManager.updatePeerSettings($scope.userID, settings);
|
||||
});
|
||||
});
|
||||
@ -2588,6 +2810,26 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
});
|
||||
};
|
||||
|
||||
$scope.inviteToGroup = function () {
|
||||
PeersSelectService.selectPeer({
|
||||
confirm_type: 'INVITE_TO_GROUP',
|
||||
noUsers: true
|
||||
}).then(function (peerString) {
|
||||
var peerID = AppPeersManager.getPeerID(peerString);
|
||||
var chatID = peerID < 0 ? -peerID : 0;
|
||||
AppMessagesManager.startBot($scope.user.id, chatID).then(function () {
|
||||
$rootScope.$broadcast('history_focus', {peerString: peerString});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.sendCommand = function (command) {
|
||||
AppMessagesManager.sendText($scope.userID, '/' + command);
|
||||
$rootScope.$broadcast('history_focus', {
|
||||
peerString: peerString
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleBlock = function (block) {
|
||||
MtpApiManager.invokeApi(block ? 'contacts.block' : 'contacts.unblock', {
|
||||
id: AppUsersManager.getUserInput($scope.userID)
|
||||
@ -2690,11 +2932,9 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
};
|
||||
|
||||
$scope.kickFromGroup = function (userID) {
|
||||
var user = AppUsersManager.getUser(userID);
|
||||
|
||||
MtpApiManager.invokeApi('messages.deleteChatUser', {
|
||||
chat_id: $scope.chatID,
|
||||
user_id: {_: 'inputUserForeign', user_id: userID, access_hash: user.access_hash || '0'}
|
||||
user_id: AppUsersManager.getUserInput(userID)
|
||||
}).then(onChatUpdated);
|
||||
};
|
||||
|
||||
@ -2783,7 +3023,9 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
id: {_: 'inputUserSelf'}
|
||||
}).then(function (userFullResult) {
|
||||
AppUsersManager.saveApiUser(userFullResult.user);
|
||||
AppPhotosManager.savePhoto(userFullResult.profile_photo);
|
||||
AppPhotosManager.savePhoto(userFullResult.profile_photo, {
|
||||
user_id: userFullResult.user.id
|
||||
});
|
||||
});
|
||||
|
||||
$scope.notify = {volume: 0.5};
|
||||
@ -2854,8 +3096,10 @@ angular.module('myApp.controllers', ['myApp.i18n'])
|
||||
crop: {_: 'inputPhotoCropAuto'}
|
||||
}).then(function (updateResult) {
|
||||
AppUsersManager.saveApiUsers(updateResult.users);
|
||||
AppPhotosManager.savePhoto(updateResult.photo);
|
||||
MtpApiManager.getUserID().then(function (id) {
|
||||
AppPhotosManager.savePhoto(updateResult.photo, {
|
||||
user_id: id
|
||||
});
|
||||
ApiUpdatesManager.processUpdateMessage({
|
||||
_: 'updateShort',
|
||||
update: {
|
||||
|
@ -339,6 +339,16 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
};
|
||||
|
||||
function link ($scope, element, attrs) {
|
||||
if (attrs.watch) {
|
||||
$scope.$watch('replyMessage', function () {
|
||||
checkMessage($scope, element);
|
||||
});
|
||||
} else {
|
||||
checkMessage($scope, element);
|
||||
}
|
||||
}
|
||||
|
||||
function checkMessage ($scope, element) {
|
||||
var message = $scope.replyMessage;
|
||||
if (!message.loading) {
|
||||
updateMessage($scope, element);
|
||||
@ -395,7 +405,7 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
var peerID = AppMessagesManager.getMessagePeer(message);
|
||||
var peerString = AppPeersManager.getPeerString(peerID);
|
||||
|
||||
$rootScope.$broadcast('history_focus', {peerString: peerString, messageID: message.id});
|
||||
$rootScope.$broadcast('history_focus', {peerString: peerString, messageID: message.id});
|
||||
|
||||
})
|
||||
}
|
||||
@ -403,6 +413,41 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
|
||||
})
|
||||
|
||||
.directive('myReplyMarkup', function() {
|
||||
|
||||
return {
|
||||
templateUrl: templateUrl('reply_markup'),
|
||||
scope: {
|
||||
'replyMarkup': '=myReplyMarkup'
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
function link ($scope, element, attrs) {
|
||||
var scrollable = $('.reply_markup', element);
|
||||
var scroller = new Scroller(scrollable, {
|
||||
classPrefix: 'reply_markup',
|
||||
maxHeight: 170
|
||||
});
|
||||
$scope.buttonSend = function (button) {
|
||||
$scope.$emit('reply_button_press', button);
|
||||
}
|
||||
|
||||
$scope.$on('ui_keyboard_update', function () {
|
||||
onContentLoaded(function () {
|
||||
scroller.updateHeight();
|
||||
scroller.scrollTo(0);
|
||||
$scope.$emit('ui_panel_update');
|
||||
})
|
||||
});
|
||||
onContentLoaded(function () {
|
||||
scroller.updateHeight();
|
||||
$scope.$emit('ui_panel_update');
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
.directive('myMessagePhoto', function(AppPhotosManager) {
|
||||
return {
|
||||
scope: {
|
||||
@ -563,7 +608,7 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
onContentLoaded(function () {
|
||||
var selectedDialog = $(scrollableWrap).find('.active a.im_dialog')[0];
|
||||
if (selectedDialog) {
|
||||
scrollToDialog(selectedDialog.parentNode);
|
||||
scrollToNode(scrollableWrap, selectedDialog.parentNode, dialogsWrap);
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -621,7 +666,7 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
|
||||
if (nextDialogWrap) {
|
||||
$(nextDialogWrap).find('a').trigger('mousedown');
|
||||
scrollToDialog(nextDialogWrap);
|
||||
scrollToNode(scrollableWrap, nextDialogWrap, dialogsWrap);
|
||||
}
|
||||
|
||||
return cancelEvent(e);
|
||||
@ -681,29 +726,13 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
}
|
||||
|
||||
if (nextDialogWrap) {
|
||||
scrollToDialog(nextDialogWrap);
|
||||
scrollToNode(scrollableWrap, nextDialogWrap, dialogsWrap);
|
||||
}
|
||||
|
||||
return cancelEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToDialog(dialogWrap) {
|
||||
var elTop = dialogWrap.offsetTop - 15,
|
||||
elHeight = dialogWrap.offsetHeight + 30,
|
||||
scrollTop = scrollableWrap.scrollTop,
|
||||
viewportHeight = scrollableWrap.clientHeight;
|
||||
|
||||
if (scrollTop > elTop) { // we are below the dialog to scroll
|
||||
scrollableWrap.scrollTop = elTop;
|
||||
$(dialogsWrap).nanoScroller({flash: true});
|
||||
}
|
||||
else if (scrollTop < elTop + elHeight - viewportHeight) { // we are over the dialog to scroll
|
||||
scrollableWrap.scrollTop = elTop + elHeight - viewportHeight;
|
||||
$(dialogsWrap).nanoScroller({flash: true});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1295,7 +1324,8 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
link: link,
|
||||
scope: {
|
||||
draftMessage: '=',
|
||||
mentions: '='
|
||||
mentions: '=',
|
||||
commands: '='
|
||||
}
|
||||
};
|
||||
|
||||
@ -1363,8 +1393,8 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
getSendOnEnter: function () {
|
||||
return sendOnEnter;
|
||||
},
|
||||
getPeerImage: function (element, peerID) {
|
||||
if (cachedPeerPhotos[peerID]) {
|
||||
getPeerImage: function (element, peerID, noReplace) {
|
||||
if (cachedPeerPhotos[peerID] && !noReplace) {
|
||||
element.replaceWith(cachedPeerPhotos[peerID]);
|
||||
return;
|
||||
}
|
||||
@ -1376,8 +1406,14 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
});
|
||||
},
|
||||
mentions: $scope.mentions,
|
||||
commands: $scope.commands,
|
||||
onMessageSubmit: onMessageSubmit,
|
||||
onFilePaste: onFilePaste
|
||||
onFilePaste: onFilePaste,
|
||||
onCommandSend: function (command) {
|
||||
$scope.$apply(function () {
|
||||
$scope.draftMessage.command = command;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var richTextarea = composer.richTextareaEl[0];
|
||||
@ -1465,6 +1501,9 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
if (!Config.Navigator.touch) {
|
||||
composer.focus();
|
||||
}
|
||||
onContentLoaded(function () {
|
||||
composer.checkAutocomplete(true);
|
||||
});
|
||||
if (emojiTooltip) {
|
||||
emojiTooltip.hide();
|
||||
}
|
||||
@ -1838,8 +1877,10 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
}
|
||||
|
||||
if ($scope.document.url) {
|
||||
$scope.isActive = !$scope.isActive;
|
||||
$scope.$emit('ui_height');
|
||||
onContentLoaded(function () {
|
||||
$scope.isActive = !$scope.isActive;
|
||||
$scope.$emit('ui_height');
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1859,7 +1900,7 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
}
|
||||
})
|
||||
|
||||
.directive('myLoadSticker', function(MtpApiFileManager, FileManager) {
|
||||
.directive('myLoadSticker', function(MtpApiFileManager, FileManager, AppStickersManager) {
|
||||
|
||||
var emptySrc = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
||||
|
||||
@ -1876,13 +1917,7 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
.addClass(attrs.imgClass);
|
||||
|
||||
var setSrc = function (blob) {
|
||||
if (WebpManager.isWebpSupported()) {
|
||||
imgElement.attr('src', FileManager.getUrl(blob, 'image/webp'));
|
||||
return;
|
||||
}
|
||||
FileManager.getByteArray(blob).then(function (bytes) {
|
||||
imgElement.attr('src', WebpManager.getPngUrlFromData(bytes));
|
||||
});
|
||||
imgElement.attr('src', FileManager.getUrl(blob));
|
||||
};
|
||||
|
||||
imgElement.css({
|
||||
@ -1894,12 +1929,16 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
height: $scope.document.thumb.height
|
||||
});
|
||||
|
||||
var smallLocation = $scope.document.thumb.location;
|
||||
var smallLocation = angular.copy($scope.document.thumb.location);
|
||||
smallLocation.sticker = true;
|
||||
|
||||
var fullLocation = {
|
||||
_: 'inputDocumentFileLocation',
|
||||
id: $scope.document.id,
|
||||
access_hash: $scope.document.access_hash,
|
||||
dc_id: $scope.document.dc_id
|
||||
dc_id: $scope.document.dc_id,
|
||||
file_name: $scope.document.file_name,
|
||||
sticker: true
|
||||
};
|
||||
|
||||
|
||||
@ -1932,6 +1971,14 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
console.log('Download sticker failed', e, fullLocation);
|
||||
});
|
||||
}
|
||||
|
||||
if (attrs.open && $scope.document.stickerSetInput) {
|
||||
element
|
||||
.addClass('clickable')
|
||||
.on('click', function () {
|
||||
AppStickersManager.openStickerset($scope.document.stickerSetInput);
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -2415,8 +2462,8 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
update = function () {
|
||||
var user = AppUsersManager.getUser(userID);
|
||||
element
|
||||
.html(statusFilter(user))
|
||||
.toggleClass('status_online', user.status && user.status._ == 'userStatusOnline');
|
||||
.html(statusFilter(user, attrs.botChatPrivacy))
|
||||
.toggleClass('status_online', user.status && user.status._ == 'userStatusOnline' || false);
|
||||
};
|
||||
|
||||
$scope.$watch(attrs.myUserStatus, function (newUserID) {
|
||||
@ -2606,7 +2653,6 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
};
|
||||
|
||||
function link($scope, element, attrs) {
|
||||
|
||||
element.addClass('peer_photo_init');
|
||||
|
||||
var peerID, peer, peerPhoto;
|
||||
@ -2682,6 +2728,7 @@ angular.module('myApp.directives', ['myApp.filters'])
|
||||
}
|
||||
|
||||
$scope.$watch(attrs.myPeerPhotolink, setPeerID);
|
||||
setPeerID($scope.$eval(attrs.myPeerPhotolink));
|
||||
|
||||
if (attrs.watch) {
|
||||
$scope.$on('user_update', function (e, updUserID) {
|
||||
|
@ -31,8 +31,11 @@ angular.module('myApp.filters', ['myApp.i18n'])
|
||||
|
||||
.filter('userStatus', function($filter, _) {
|
||||
var relativeTimeFilter = $filter('relativeTime');
|
||||
return function (user) {
|
||||
var statusType = user && user.status && user.status._ || 'userStatusEmpty';
|
||||
return function (user, botChatPrivacy) {
|
||||
var statusType = user && user.status && user.status._;
|
||||
if (!statusType) {
|
||||
statusType = user.pFlags.bot ? 'userStatusBot' : 'userStatusEmpty';
|
||||
}
|
||||
switch (statusType) {
|
||||
case 'userStatusOnline':
|
||||
return _('user_status_online');
|
||||
@ -49,6 +52,16 @@ angular.module('myApp.filters', ['myApp.i18n'])
|
||||
case 'userStatusLastMonth':
|
||||
return _('user_status_last_month');
|
||||
|
||||
case 'userStatusBot':
|
||||
if (botChatPrivacy) {
|
||||
if (user.pFlags.botNoPrivacy) {
|
||||
return _('user_status_bot_noprivacy');
|
||||
} else {
|
||||
return _('user_status_bot_privacy');
|
||||
}
|
||||
}
|
||||
return _('user_status_bot');
|
||||
|
||||
case 'userStatusEmpty':
|
||||
default:
|
||||
return _('user_status_long_ago');
|
||||
@ -69,7 +82,9 @@ angular.module('myApp.filters', ['myApp.i18n'])
|
||||
var dateFilter = $filter('date');
|
||||
|
||||
return function (timestamp, extended) {
|
||||
|
||||
if (!timestamp) {
|
||||
return '';
|
||||
}
|
||||
var ticks = timestamp * 1000,
|
||||
diff = Math.abs(tsNow() - ticks),
|
||||
format = 'shortTime';
|
||||
@ -157,7 +172,7 @@ angular.module('myApp.filters', ['myApp.i18n'])
|
||||
return size + ' b';
|
||||
}
|
||||
else if (size < 1048576) {
|
||||
return Math.round(size / 1024) + ' Kb';
|
||||
return Math.round(size / 1024) + ' KB';
|
||||
}
|
||||
var mbs = size / 1048576;
|
||||
if (progressing) {
|
||||
|
@ -14,7 +14,7 @@ angular.module('izhukov.mtproto', ['izhukov.utils'])
|
||||
? [
|
||||
{id: 1, host: '149.154.175.10', port: 80},
|
||||
{id: 2, host: '149.154.167.40', port: 80},
|
||||
{id: 3, host: '174.140.142.5', port: 80}
|
||||
{id: 3, host: '149.154.175.117', port: 80}
|
||||
]
|
||||
: [
|
||||
{id: 1, host: '149.154.175.50', port: 80},
|
||||
|
@ -255,7 +255,7 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto'])
|
||||
}
|
||||
})
|
||||
|
||||
.factory('MtpApiFileManager', function (MtpApiManager, $q, FileManager, IdbFileStorage, TmpfsFileStorage, MemoryFileStorage) {
|
||||
.factory('MtpApiFileManager', function (MtpApiManager, $q, qSync, FileManager, IdbFileStorage, TmpfsFileStorage, MemoryFileStorage, WebpManager) {
|
||||
|
||||
var cachedFs = false;
|
||||
var cachedFsPromise = false;
|
||||
@ -318,17 +318,29 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto'])
|
||||
return 'video' + location.id + '.mp4';
|
||||
|
||||
case 'inputDocumentFileLocation':
|
||||
var fileName = (location.file_name || '').split('.', 2);
|
||||
var ext = fileName[1] || '';
|
||||
if (location.sticker && !WebpManager.isWebpSupported()) {
|
||||
ext += '.png';
|
||||
}
|
||||
if (fileName.length) {
|
||||
return fileName[0] + '_' + location.id + '.' + ext;
|
||||
}
|
||||
return 'doc' + location.id;
|
||||
|
||||
case 'inputAudioFileLocation':
|
||||
return 'audio' + location.id;
|
||||
}
|
||||
|
||||
if (!location.volume_id) {
|
||||
console.trace('Empty location', location);
|
||||
default:
|
||||
if (!location.volume_id) {
|
||||
console.trace('Empty location', location);
|
||||
}
|
||||
var ext = 'jpg';
|
||||
if (location.sticker) {
|
||||
ext = WebpManager.isWebpSupported() ? 'webp' : 'png';
|
||||
}
|
||||
return location.volume_id + '_' + location.local_id + '_' + location.secret + '.' + ext;
|
||||
}
|
||||
|
||||
return location.volume_id + '_' + location.local_id + '_' + location.secret + '.jpg';
|
||||
};
|
||||
|
||||
function getTempFileName(file) {
|
||||
@ -374,7 +386,7 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto'])
|
||||
}
|
||||
// console.log('dload small', location);
|
||||
var fileName = getFileName(location),
|
||||
mimeType = 'image/jpeg',
|
||||
mimeType = location.sticker ? 'image/webp' : 'image/jpeg',
|
||||
cachedPromise = cachedSavePromises[fileName] || cachedDownloadPromises[fileName];
|
||||
|
||||
if (cachedPromise) {
|
||||
@ -403,11 +415,20 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto'])
|
||||
});
|
||||
});
|
||||
|
||||
var processDownloaded = function (bytes) {
|
||||
if (!location.sticker || WebpManager.isWebpSupported()) {
|
||||
return qSync.when(bytes);
|
||||
}
|
||||
return WebpManager.getPngBlobFromWebp(bytes);
|
||||
};
|
||||
|
||||
return fileStorage.getFileWriter(fileName, mimeType).then(function (fileWriter) {
|
||||
return downloadPromise.then(function (result) {
|
||||
return FileManager.write(fileWriter, result.bytes).then(function () {
|
||||
return cachedDownloads[fileName] = fileWriter.finalize();
|
||||
});
|
||||
return processDownloaded(result.bytes).then(function (proccessedResult) {
|
||||
return FileManager.write(fileWriter, proccessedResult).then(function () {
|
||||
return cachedDownloads[fileName] = fileWriter.finalize();
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -427,6 +448,16 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto'])
|
||||
|
||||
options = options || {};
|
||||
|
||||
var processSticker = false;
|
||||
if (location.sticker && !WebpManager.isWebpSupported()) {
|
||||
if (options.toFileEntry || size > 524288) {
|
||||
delete location.sticker;
|
||||
} else {
|
||||
processSticker = true;
|
||||
options.mime = 'image/png';
|
||||
}
|
||||
}
|
||||
|
||||
// console.log(dT(), 'Dload file', dcID, location, size);
|
||||
var fileName = getFileName(location),
|
||||
toFileEntry = options.toFileEntry || null,
|
||||
@ -471,6 +502,13 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto'])
|
||||
}, function () {
|
||||
var fileWriterPromise = toFileEntry ? FileManager.getFileWriter(toFileEntry) : fileStorage.getFileWriter(fileName, mimeType);
|
||||
|
||||
var processDownloaded = function (bytes) {
|
||||
if (!processSticker) {
|
||||
return qSync.when(bytes);
|
||||
}
|
||||
return WebpManager.getPngBlobFromWebp(bytes);
|
||||
};
|
||||
|
||||
fileWriterPromise.then(function (fileWriter) {
|
||||
cacheFileWriter = fileWriter;
|
||||
var limit = 524288,
|
||||
@ -513,20 +551,22 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto'])
|
||||
if (canceled) {
|
||||
return $q.when();
|
||||
}
|
||||
return FileManager.write(fileWriter, result.bytes).then(function () {
|
||||
writeFileDeferred.resolve();
|
||||
}, errorHandler).then(function () {
|
||||
if (isFinal) {
|
||||
resolved = true;
|
||||
if (toFileEntry) {
|
||||
deferred.resolve();
|
||||
return processDownloaded(result.bytes).then(function (processedResult) {
|
||||
return FileManager.write(fileWriter, processedResult).then(function () {
|
||||
writeFileDeferred.resolve();
|
||||
}, errorHandler).then(function () {
|
||||
if (isFinal) {
|
||||
resolved = true;
|
||||
if (toFileEntry) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.resolve(cachedDownloads[fileName] = fileWriter.finalize());
|
||||
}
|
||||
} else {
|
||||
deferred.resolve(cachedDownloads[fileName] = fileWriter.finalize());
|
||||
}
|
||||
} else {
|
||||
deferred.notify({done: offset + limit, total: size});
|
||||
};
|
||||
});
|
||||
deferred.notify({done: offset + limit, total: size});
|
||||
};
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
})(offset + limit >= size, offset, writeFileDeferred, writeFilePromise);
|
||||
|
@ -43,7 +43,9 @@ angular.module('izhukov.utils', [])
|
||||
},
|
||||
reject: function (result) {
|
||||
return {then: function (cb, badcb) {
|
||||
return badcb(result);
|
||||
if (badcb) {
|
||||
return badcb(result);
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
@ -205,6 +207,19 @@ angular.module('izhukov.utils', [])
|
||||
return $q.reject(e);
|
||||
}
|
||||
}
|
||||
else if (fileData.file) {
|
||||
var deferred = $q.defer();
|
||||
fileData.file(function (blob) {
|
||||
getByteArray(blob).then(function (result) {
|
||||
deferred.resolve(result);
|
||||
}, function (error) {
|
||||
deferred.reject(error);
|
||||
})
|
||||
}, function (error) {
|
||||
deferred.reject(error);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
return $q.when(fileData);
|
||||
}
|
||||
|
||||
@ -408,6 +423,10 @@ angular.module('izhukov.utils', [])
|
||||
return saveFileBase64(db, fileName, blob);
|
||||
}
|
||||
|
||||
if (!(blob instanceof Blob)) {
|
||||
blob = blobConstruct([blob]);
|
||||
}
|
||||
|
||||
try {
|
||||
var objectStore = db.transaction([dbStoreName], IDBTransaction.READ_WRITE || 'readwrite').objectStore(dbStoreName),
|
||||
request = objectStore.put(blob, fileName);
|
||||
@ -643,6 +662,121 @@ angular.module('izhukov.utils', [])
|
||||
};
|
||||
})
|
||||
|
||||
.service('WebpManager', function (qSync, $q) {
|
||||
var nativeWebpSupport = false;
|
||||
|
||||
var image = new Image();
|
||||
image.onload = function () {
|
||||
nativeWebpSupport = this.width === 2 && this.height === 1;
|
||||
};
|
||||
image.onerror = function () {
|
||||
nativeWebpSupport = false;
|
||||
};
|
||||
image.src = 'data:image/webp;base64,UklGRjIAAABXRUJQVlA4ICYAAACyAgCdASoCAAEALmk0mk0iIiIiIgBoSygABc6zbAAA/v56QAAAAA==';
|
||||
|
||||
var canvas, context;
|
||||
|
||||
function getCanvasFromWebp(data) {
|
||||
var start = tsNow();
|
||||
|
||||
var decoder = new WebPDecoder();
|
||||
|
||||
var config = decoder.WebPDecoderConfig;
|
||||
var buffer = config.j || config.output;
|
||||
var bitstream = config.input;
|
||||
|
||||
if (!decoder.WebPInitDecoderConfig(config)) {
|
||||
console.error('[webpjs] Library version mismatch!');
|
||||
return false;
|
||||
}
|
||||
|
||||
// console.log('[webpjs] status code', decoder.VP8StatusCode);
|
||||
var StatusCode = decoder.VP8StatusCode;
|
||||
|
||||
status = decoder.WebPGetFeatures(data, data.length, bitstream);
|
||||
if (status != (StatusCode.VP8_STATUS_OK || 0)) {
|
||||
console.error('[webpjs] status error', status, StatusCode);
|
||||
}
|
||||
|
||||
var mode = decoder.WEBP_CSP_MODE;
|
||||
buffer.colorspace = mode.MODE_RGBA;
|
||||
buffer.J = 4;
|
||||
|
||||
try {
|
||||
status = decoder.WebPDecode(data, data.length, config);
|
||||
} catch (e) {
|
||||
status = e;
|
||||
}
|
||||
|
||||
ok = (status == 0);
|
||||
if (!ok) {
|
||||
console.error('[webpjs] decoding failed', status, StatusCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
// console.log('[webpjs] decoded: ', buffer.width, buffer.height, bitstream.has_alpha, 'Now saving...');
|
||||
var bitmap = buffer.c.RGBA.ma;
|
||||
|
||||
// console.log('[webpjs] done in ', tsNow() - start);
|
||||
|
||||
if (!bitmap) {
|
||||
return false;
|
||||
}
|
||||
var biHeight = buffer.height;
|
||||
var biWidth = buffer.width;
|
||||
|
||||
if (!canvas || !context) {
|
||||
canvas = document.createElement('canvas');
|
||||
context = canvas.getContext('2d');
|
||||
} else {
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
canvas.height = biHeight;
|
||||
canvas.width = biWidth;
|
||||
|
||||
var output = context.createImageData(canvas.width, canvas.height);
|
||||
var outputData = output.data;
|
||||
|
||||
for (var h = 0; h < biHeight; h++) {
|
||||
for (var w = 0; w < biWidth; w++) {
|
||||
outputData[0+w*4+(biWidth*4)*h] = bitmap[1+w*4+(biWidth*4)*h];
|
||||
outputData[1+w*4+(biWidth*4)*h] = bitmap[2+w*4+(biWidth*4)*h];
|
||||
outputData[2+w*4+(biWidth*4)*h] = bitmap[3+w*4+(biWidth*4)*h];
|
||||
outputData[3+w*4+(biWidth*4)*h] = bitmap[0+w*4+(biWidth*4)*h];
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
context.putImageData(output, 0, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getPngBlobFromWebp (data) {
|
||||
if (!getCanvasFromWebp(data)) {
|
||||
return $q.reject({type: 'WEBP_PROCESS_FAILED'});
|
||||
}
|
||||
if (canvas.toBlob === undefined) {
|
||||
return qSync.when(dataUrlToBlob(canvas.toDataURL('image/png')));
|
||||
}
|
||||
|
||||
var deferred = $q.defer();
|
||||
canvas.toBlob(function (blob) {
|
||||
deferred.resolve(blob);
|
||||
}, 'image/png');
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
return {
|
||||
isWebpSupported: function () {
|
||||
return nativeWebpSupport;
|
||||
},
|
||||
getPngBlobFromWebp: getPngBlobFromWebp
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
.service('CryptoWorker', function ($timeout, $q) {
|
||||
|
||||
var webWorker = false,
|
||||
|
@ -9,14 +9,10 @@ null#56730bcc = Null;
|
||||
|
||||
inputPeerEmpty#7f3b18ea = InputPeer;
|
||||
inputPeerSelf#7da07ec9 = InputPeer;
|
||||
inputPeerContact#1023dbe8 user_id:int = InputPeer;
|
||||
inputPeerForeign#9b447325 user_id:int access_hash:long = InputPeer;
|
||||
inputPeerChat#179be863 chat_id:int = InputPeer;
|
||||
|
||||
inputUserEmpty#b98886cf = InputUser;
|
||||
inputUserSelf#f7c1b13f = InputUser;
|
||||
inputUserContact#86e94f65 user_id:int = InputUser;
|
||||
inputUserForeign#655e74ff user_id:int access_hash:long = InputUser;
|
||||
|
||||
inputPhoneContact#f392b7f4 client_id:long phone:string first_name:string last_name:string = InputContact;
|
||||
|
||||
@ -70,11 +66,6 @@ fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileL
|
||||
fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation;
|
||||
|
||||
userEmpty#200250ba id:int = User;
|
||||
userSelf#1c60e608 id:int first_name:string last_name:string username:string phone:string photo:UserProfilePhoto status:UserStatus = User;
|
||||
userContact#cab35e18 id:int first_name:string last_name:string username:string access_hash:long phone:string photo:UserProfilePhoto status:UserStatus = User;
|
||||
userRequest#d9ccc4ef id:int first_name:string last_name:string username:string access_hash:long phone:string photo:UserProfilePhoto status:UserStatus = User;
|
||||
userForeign#75cf7a8 id:int first_name:string last_name:string username:string access_hash:long photo:UserProfilePhoto status:UserStatus = User;
|
||||
userDeleted#d6016d7a id:int first_name:string last_name:string username:string = User;
|
||||
|
||||
userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
|
||||
userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto;
|
||||
@ -87,7 +78,7 @@ chatEmpty#9ba2d800 id:int = Chat;
|
||||
chat#6e9c9bc7 id:int title:string photo:ChatPhoto participants_count:int date:int left:Bool version:int = Chat;
|
||||
chatForbidden#fb0ccc41 id:int title:string date:int = Chat;
|
||||
|
||||
chatFull#cade0791 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite = ChatFull;
|
||||
chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> = ChatFull;
|
||||
|
||||
chatParticipant#c8d7493e user_id:int inviter_id:int date:int = ChatParticipant;
|
||||
|
||||
@ -98,7 +89,7 @@ chatPhotoEmpty#37c1011c = ChatPhoto;
|
||||
chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto;
|
||||
|
||||
messageEmpty#83e5de54 id:int = Message;
|
||||
message#a7ab1991 flags:# id:int from_id:int to_id:Peer fwd_from_id:flags.2?int fwd_date:flags.2?int reply_to_msg_id:flags.3?int date:int message:string media:MessageMedia = Message;
|
||||
message#c3060325 flags:# id:int from_id:int to_id:Peer fwd_from_id:flags.2?int fwd_date:flags.2?int reply_to_msg_id:flags.3?int date:int message:string media:MessageMedia reply_markup:flags.6?ReplyMarkup = Message;
|
||||
messageService#1d86f70e flags:int id:int from_id:int to_id:Peer date:int action:MessageAction = Message;
|
||||
|
||||
messageMediaEmpty#3ded6320 = MessageMedia;
|
||||
@ -119,14 +110,14 @@ messageActionChatDeleteUser#b2ae9b0c user_id:int = MessageAction;
|
||||
dialog#c1dd804a peer:Peer top_message:int read_inbox_max_id:int unread_count:int notify_settings:PeerNotifySettings = Dialog;
|
||||
|
||||
photoEmpty#2331b22d id:long = Photo;
|
||||
photo#c3838076 id:long access_hash:long user_id:int date:int geo:GeoPoint sizes:Vector<PhotoSize> = Photo;
|
||||
photo#cded42fe id:long access_hash:long date:int sizes:Vector<PhotoSize> = Photo;
|
||||
|
||||
photoSizeEmpty#e17e23c type:string = PhotoSize;
|
||||
photoSize#77bfb61b type:string location:FileLocation w:int h:int size:int = PhotoSize;
|
||||
photoCachedSize#e9a734fa type:string location:FileLocation w:int h:int bytes:bytes = PhotoSize;
|
||||
|
||||
videoEmpty#c10658a8 id:long = Video;
|
||||
video#ee9f4a4d id:long access_hash:long user_id:int date:int duration:int size:int thumb:PhotoSize dc_id:int w:int h:int = Video;
|
||||
video#f72887d3 id:long access_hash:long date:int duration:int mime_type:string size:int thumb:PhotoSize dc_id:int w:int h:int = Video;
|
||||
|
||||
geoPointEmpty#1117dd5f = GeoPoint;
|
||||
geoPoint#2049d70c long:double lat:double = GeoPoint;
|
||||
@ -135,7 +126,7 @@ auth.checkedPhone#811ea28e phone_registered:Bool = auth.CheckedPhone;
|
||||
|
||||
auth.sentCode#efed51d9 phone_registered:Bool phone_code_hash:string send_call_timeout:int is_password:Bool = auth.SentCode;
|
||||
|
||||
auth.authorization#f6b673a4 expires:int user:User = auth.Authorization;
|
||||
auth.authorization#ff036af1 user:User = auth.Authorization;
|
||||
|
||||
auth.exportedAuthorization#df969c2d id:int bytes:bytes = auth.ExportedAuthorization;
|
||||
|
||||
@ -157,7 +148,7 @@ peerNotifySettings#8d5e11ee mute_until:int sound:string show_previews:Bool event
|
||||
|
||||
wallPaper#ccb03657 id:int title:string sizes:Vector<PhotoSize> color:int = WallPaper;
|
||||
|
||||
userFull#771095da user:User link:contacts.Link profile_photo:Photo notify_settings:PeerNotifySettings blocked:Bool real_first_name:string real_last_name:string = UserFull;
|
||||
userFull#5a89ac5b user:User link:contacts.Link profile_photo:Photo notify_settings:PeerNotifySettings blocked:Bool bot_info:BotInfo = UserFull;
|
||||
|
||||
contact#f911c994 user_id:int mutual:Bool = Contact;
|
||||
|
||||
@ -206,6 +197,7 @@ inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter;
|
||||
inputMessagesFilterPhotoVideoDocuments#d95e73bb = MessagesFilter;
|
||||
inputMessagesFilterDocument#9eddf188 = MessagesFilter;
|
||||
inputMessagesFilterAudio#cfc87522 = MessagesFilter;
|
||||
inputMessagesFilterAudioDocuments#5afbf764 = MessagesFilter;
|
||||
|
||||
updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update;
|
||||
updateMessageID#4e90bfd6 id:int random_id:long = Update;
|
||||
@ -240,7 +232,7 @@ photos.photo#20212ca8 photo:Photo users:Vector<User> = photos.Photo;
|
||||
|
||||
upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
|
||||
|
||||
dcOption#2ec2a43c id:int hostname:string ip_address:string port:int = DcOption;
|
||||
dcOption#5d8c6cc flags:# id:int ip_address:string port:int = DcOption;
|
||||
|
||||
config#4e32b894 date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int broadcast_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int disabled_features:Vector<DisabledFeature> = Config;
|
||||
|
||||
@ -335,7 +327,7 @@ inputAudioFileLocation#74dc404d id:long access_hash:long = InputFileLocation;
|
||||
inputDocumentFileLocation#4e45abe9 id:long access_hash:long = InputFileLocation;
|
||||
|
||||
audioEmpty#586988d8 id:long = Audio;
|
||||
audio#c7ac6496 id:long access_hash:long user_id:int date:int duration:int mime_type:string size:int dc_id:int = Audio;
|
||||
audio#f9e35055 id:long access_hash:long date:int duration:int mime_type:string size:int dc_id:int = Audio;
|
||||
|
||||
documentEmpty#36f8c871 id:long = Document;
|
||||
document#f9a39f4f id:long access_hash:long date:int mime_type:string size:int thumb:PhotoSize dc_id:int attributes:Vector<DocumentAttribute> = Document;
|
||||
@ -405,7 +397,7 @@ documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute;
|
||||
documentAttributeAnimated#11b58939 = DocumentAttribute;
|
||||
documentAttributeSticker#3a556302 alt:string stickerset:InputStickerSet = DocumentAttribute;
|
||||
documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute;
|
||||
documentAttributeAudio#51448e5 duration:int = DocumentAttribute;
|
||||
documentAttributeAudio#ded218e0 duration:int title:string performer:string = DocumentAttribute;
|
||||
documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
|
||||
|
||||
messages.stickersNotModified#f1749a22 = messages.Stickers;
|
||||
@ -414,7 +406,7 @@ messages.stickers#8a8ecd32 hash:string stickers:Vector<Document> = messages.Stic
|
||||
stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack;
|
||||
|
||||
messages.allStickersNotModified#e86602c3 = messages.AllStickers;
|
||||
messages.allStickers#5ce352ec hash:string packs:Vector<StickerPack> sets:Vector<StickerSet> documents:Vector<Document> = messages.AllStickers;
|
||||
messages.allStickers#d51dafdb hash:string sets:Vector<StickerSet> = messages.AllStickers;
|
||||
|
||||
disabledFeature#ae636f24 feature:string description:string = DisabledFeature;
|
||||
|
||||
@ -469,10 +461,32 @@ inputStickerSetEmpty#ffb62b95 = InputStickerSet;
|
||||
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
|
||||
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
|
||||
|
||||
stickerSet#a7a43b17 id:long access_hash:long title:string short_name:string = StickerSet;
|
||||
stickerSet#cd303b41 flags:# id:long access_hash:long title:string short_name:string count:int hash:int = StickerSet;
|
||||
|
||||
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
|
||||
|
||||
user#22e49072 flags:# id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int = User;
|
||||
|
||||
botCommand#c27ac8c7 command:string description:string = BotCommand;
|
||||
|
||||
botInfoEmpty#bb2e37ce = BotInfo;
|
||||
botInfo#9cf585d user_id:int version:int share_text:string description:string commands:Vector<BotCommand> = BotInfo;
|
||||
|
||||
keyboardButton#a2fa4880 text:string = KeyboardButton;
|
||||
|
||||
keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
|
||||
|
||||
replyKeyboardHide#a03e5b85 flags:# = ReplyMarkup;
|
||||
replyKeyboardForceReply#f4108aa0 flags:# = ReplyMarkup;
|
||||
replyKeyboardMarkup#3502758c flags:# rows:Vector<KeyboardButtonRow> = ReplyMarkup;
|
||||
|
||||
inputPeerUser#7b8e7de6 user_id:int access_hash:long = InputPeer;
|
||||
|
||||
inputUser#d8292816 user_id:int access_hash:long = InputUser;
|
||||
|
||||
help.appChangelogEmpty#af7e0394 = help.AppChangelog;
|
||||
help.appChangelog#4668e6bd text:string = help.AppChangelog;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@ -524,8 +538,8 @@ messages.deleteHistory#f4f8fb61 peer:InputPeer offset:int = messages.AffectedHis
|
||||
messages.deleteMessages#a5f18925 id:Vector<int> = messages.AffectedMessages;
|
||||
messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
|
||||
messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
|
||||
messages.sendMessage#9add8f26 flags:# peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long = messages.SentMessage;
|
||||
messages.sendMedia#2d7923b1 flags:# peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long = Updates;
|
||||
messages.sendMessage#fc55e6b5 flags:# peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup = messages.SentMessage;
|
||||
messages.sendMedia#c8f16791 flags:# peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates;
|
||||
messages.forwardMessages#55e1728d peer:InputPeer id:Vector<int> random_id:Vector<long> = Updates;
|
||||
messages.getChats#3c6aa187 id:Vector<int> = messages.Chats;
|
||||
messages.getFullChat#3b831c66 chat_id:int = messages.ChatFull;
|
||||
@ -551,7 +565,7 @@ help.getAppUpdate#c812ac7e device_model:string system_version:string app_version
|
||||
help.saveAppLog#6f02f748 events:Vector<InputAppEvent> = Bool;
|
||||
help.getInviteText#a4a95186 lang_code:string = help.InviteText;
|
||||
|
||||
photos.getUserPhotos#b7ee553c user_id:InputUser offset:int max_id:int limit:int = photos.Photos;
|
||||
photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos;
|
||||
|
||||
messages.forwardMessage#33963bf9 peer:InputPeer id:int random_id:long = Updates;
|
||||
messages.sendBroadcast#bf73f4da contacts:Vector<InputUser> random_id:Vector<long> message:string media:InputMedia = Updates;
|
||||
@ -613,6 +627,8 @@ messages.getAllStickers#aa3bc868 hash:string = messages.AllStickers;
|
||||
|
||||
account.updateDeviceLocked#38df3532 period:int = Bool;
|
||||
|
||||
auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization;
|
||||
|
||||
messages.getWebPagePreview#25223e24 message:string = MessageMedia;
|
||||
|
||||
account.getAuthorizations#e320c158 = account.Authorizations;
|
||||
@ -631,5 +647,8 @@ messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite;
|
||||
messages.checkChatInvite#3eadb1bb hash:string = ChatInvite;
|
||||
messages.importChatInvite#6c50051c hash:string = Updates;
|
||||
messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet;
|
||||
messages.installStickerSet#efbbfae9 stickerset:InputStickerSet = Bool;
|
||||
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
|
||||
messages.installStickerSet#7b30c3a6 stickerset:InputStickerSet disabled:Bool = Bool;
|
||||
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
|
||||
messages.startBot#1b3e0ffc bot:InputUser chat_id:int random_id:long start_param:string = Updates;
|
||||
|
||||
help.getAppChangelog#5bab7fb2 device_model:string system_version:string app_version:string lang_code:string = help.AppChangelog;
|
@ -102,6 +102,9 @@ TLSerialization.prototype.storeLong = function (sLong, field) {
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof sLong != 'string') {
|
||||
sLong = sLong ? sLong.toString() : '0';
|
||||
}
|
||||
var divRem = bigStringInt(sLong).divideAndRemainder(bigint(0x100000000));
|
||||
|
||||
this.writeInt(intToUint(divRem[1].intValue()), (field || '') + ':long[low]');
|
||||
|
@ -49,6 +49,21 @@ function cancelEvent (event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getScrollWidth() {
|
||||
var outer = $('<div>').css({
|
||||
position: 'absolute',
|
||||
width: 100,
|
||||
height: 100,
|
||||
overflow: 'scroll',
|
||||
top: -9999
|
||||
}).appendTo($(document.body));
|
||||
|
||||
var scrollbarWidth = outer[0].offsetWidth - outer[0].clientWidth;
|
||||
outer.remove();
|
||||
|
||||
return scrollbarWidth;
|
||||
};
|
||||
|
||||
function onCtrlEnter (textarea, cb) {
|
||||
$(textarea).on('keydown', function (e) {
|
||||
if (e.keyCode == 13 && (e.ctrlKey || e.metaKey)) {
|
||||
@ -222,6 +237,22 @@ function setRichFocus(field, selectNode) {
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToNode (scrollable, node, scroller) {
|
||||
var elTop = node.offsetTop - 15,
|
||||
elHeight = node.offsetHeight + 30,
|
||||
scrollTop = scrollable.scrollTop,
|
||||
viewportHeight = scrollable.clientHeight;
|
||||
|
||||
if (scrollTop > elTop) { // we are below the node to scroll
|
||||
scrollable.scrollTop = elTop;
|
||||
$(scroller).nanoScroller({flash: true});
|
||||
}
|
||||
else if (scrollTop < elTop + elHeight - viewportHeight) { // we are over the node to scroll
|
||||
scrollable.scrollTop = elTop + elHeight - viewportHeight;
|
||||
$(scroller).nanoScroller({flash: true});
|
||||
}
|
||||
}
|
||||
|
||||
function onContentLoaded (cb) {
|
||||
setZeroTimeout(cb);
|
||||
}
|
||||
@ -365,11 +396,15 @@ function versionCompare (ver1, ver2) {
|
||||
}
|
||||
|
||||
function cleanSearchText (text) {
|
||||
var hasTag = text.charAt(0) == '%';
|
||||
text = text.replace(badCharsRe, ' ').replace(trimRe, '');
|
||||
text = text.replace(/[^A-Za-z0-9]/g, function (ch) {
|
||||
return Config.LatinizeMap[ch] || ch;
|
||||
});
|
||||
text = text.toLowerCase();
|
||||
if (hasTag) {
|
||||
text = '%' + text;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
@ -451,102 +486,3 @@ function versionCompare (ver1, ver2) {
|
||||
};
|
||||
|
||||
})(window);
|
||||
|
||||
|
||||
(function (global) {
|
||||
var nativeWebpSupport = false;
|
||||
|
||||
var image = new Image();
|
||||
image.onload = function () {
|
||||
nativeWebpSupport = this.width === 2 && this.height === 1;
|
||||
};
|
||||
image.onerror = function () {
|
||||
nativeWebpSupport = false;
|
||||
};
|
||||
image.src = 'data:image/webp;base64,UklGRjIAAABXRUJQVlA4ICYAAACyAgCdASoCAAEALmk0mk0iIiIiIgBoSygABc6zbAAA/v56QAAAAA==';
|
||||
|
||||
var canvas, context;
|
||||
|
||||
|
||||
function getPngUrlFromData(data) {
|
||||
var start = tsNow();
|
||||
|
||||
var decoder = new WebPDecoder();
|
||||
|
||||
var config = decoder.WebPDecoderConfig;
|
||||
var buffer = config.j;
|
||||
var bitstream = config.input;
|
||||
|
||||
if (!decoder.WebPInitDecoderConfig(config)) {
|
||||
console.error('[webpjs] Library version mismatch!');
|
||||
return false;
|
||||
}
|
||||
|
||||
// console.log('[webpjs] status code', decoder.VP8StatusCode);
|
||||
|
||||
status = decoder.WebPGetFeatures(data, data.length, bitstream);
|
||||
if (status != 0) {
|
||||
console.error('[webpjs] status error', status);
|
||||
}
|
||||
|
||||
var mode = decoder.WEBP_CSP_MODE;
|
||||
buffer.J = 4;
|
||||
|
||||
try {
|
||||
status = decoder.WebPDecode(data, data.length, config);
|
||||
} catch (e) {
|
||||
status = e;
|
||||
}
|
||||
|
||||
ok = (status == 0);
|
||||
if (!ok) {
|
||||
console.error('[webpjs] decoding failed', status);
|
||||
return false;
|
||||
}
|
||||
|
||||
// console.log('[webpjs] decoded: ', buffer.width, buffer.height, bitstream.has_alpha, 'Now saving...');
|
||||
var bitmap = buffer.c.RGBA.ma;
|
||||
|
||||
// console.log('[webpjs] done in ', tsNow() - start);
|
||||
|
||||
if (!bitmap) {
|
||||
return false;
|
||||
}
|
||||
var biHeight = buffer.height;
|
||||
var biWidth = buffer.width;
|
||||
|
||||
if (!canvas || !context) {
|
||||
canvas = document.createElement('canvas');
|
||||
context = canvas.getContext('2d');
|
||||
} else {
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
canvas.height = biHeight;
|
||||
canvas.width = biWidth;
|
||||
|
||||
var output = context.createImageData(canvas.width, canvas.height);
|
||||
var outputData = output.data;
|
||||
|
||||
for (var h = 0; h < biHeight; h++) {
|
||||
for (var w = 0; w < biWidth; w++) {
|
||||
outputData[0+w*4+(biWidth*4)*h] = bitmap[1+w*4+(biWidth*4)*h];
|
||||
outputData[1+w*4+(biWidth*4)*h] = bitmap[2+w*4+(biWidth*4)*h];
|
||||
outputData[2+w*4+(biWidth*4)*h] = bitmap[3+w*4+(biWidth*4)*h];
|
||||
outputData[3+w*4+(biWidth*4)*h] = bitmap[0+w*4+(biWidth*4)*h];
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
context.putImageData(output, 0, 0);
|
||||
|
||||
return canvas.toDataURL('image/png');
|
||||
}
|
||||
|
||||
|
||||
global.WebpManager = {
|
||||
isWebpSupported: function () {
|
||||
return nativeWebpSupport;
|
||||
},
|
||||
getPngUrlFromData: getPngUrlFromData
|
||||
}
|
||||
})(window);
|
||||
|
@ -115,8 +115,12 @@
|
||||
"user_modal_block_user": "Block user",
|
||||
"user_modal_unblock_user": "Unblock user",
|
||||
"user_modal_delete_chat": "Delete chat",
|
||||
"user_modal_add_to_group": "Add to group",
|
||||
"user_modal_info": "Info",
|
||||
"user_modal_phone": "Phone",
|
||||
"user_modal_about": "About",
|
||||
"user_modal_bot_settings": "Settings",
|
||||
"user_modal_bot_help": "Help",
|
||||
"user_modal_username": "Username",
|
||||
"user_modal_settings": "Settings",
|
||||
"user_modal_notifications": "Notifications",
|
||||
@ -144,6 +148,9 @@
|
||||
"user_status_last_week": "last seen within a week",
|
||||
"user_status_last_month": "last seen within a month",
|
||||
"user_status_long_ago": "last seen a long time ago",
|
||||
"user_status_bot": "bot",
|
||||
"user_status_bot_noprivacy": "has access to messages",
|
||||
"user_status_bot_privacy": "has no access to messages",
|
||||
"chat_title_deleted": "DELETED",
|
||||
"format_size_progress_mulitple": "{done} of {total} {parts}",
|
||||
"format_size_progress": "{done} of {total}",
|
||||
@ -274,7 +281,8 @@
|
||||
"message_service_kicked_user": "removed {user}",
|
||||
"message_service_left_group": "left group",
|
||||
"message_service_joined_by_link": "joined group via invite link",
|
||||
"message_service_unsupported_action": "Unsupported action {action}",
|
||||
"message_service_unsupported_action": "unsupported action {action}",
|
||||
"message_service_bot_intro_header": "What can this bot do?",
|
||||
|
||||
"error_modal_warning_title": "Warning",
|
||||
"error_modal_bad_request_title": "Error",
|
||||
@ -390,6 +398,7 @@
|
||||
"im_delete": "Delete {count}",
|
||||
"im_forward": "Forward {count}",
|
||||
"im_reply": "Reply",
|
||||
"im_start": "Start",
|
||||
"im_reply_loading": "Loading{dots}",
|
||||
"im_photos_drop_text": "Drop photos here to send",
|
||||
"im_message_field_placeholder": "Write a message...",
|
||||
|
@ -196,21 +196,6 @@ EmojiTooltip.prototype.onMouseLeave = function (triggerUnshow) {
|
||||
}
|
||||
};
|
||||
|
||||
EmojiTooltip.prototype.getScrollWidth = function() {
|
||||
var outer = $('<div>').css({
|
||||
position: 'absolute',
|
||||
width: 100,
|
||||
height: 100,
|
||||
overflow: 'scroll',
|
||||
top: -9999
|
||||
}).appendTo($(document.body));
|
||||
|
||||
var scrollbarWidth = outer[0].offsetWidth - outer[0].clientWidth;
|
||||
outer.remove();
|
||||
|
||||
return scrollbarWidth;
|
||||
};
|
||||
|
||||
|
||||
|
||||
EmojiTooltip.prototype.createTooltip = function () {
|
||||
@ -219,20 +204,12 @@ EmojiTooltip.prototype.createTooltip = function () {
|
||||
}
|
||||
|
||||
var self = this;
|
||||
this.tooltipEl = $('<div class="composer_emoji_tooltip noselect"><div class="composer_emoji_tooltip_tabs"></div><div class="composer_emoji_tooltip_content_wrap nano mobile_scrollable_wrap"><div class="composer_emoji_tooltip_content nano-content clearfix"></div></div><div class="composer_emoji_tooltip_footer"><a class="composer_emoji_tooltip_settings"></a></div><div class="composer_emoji_tooltip_tail"><i class="icon icon-tooltip-tail"></i></div></div>').appendTo(document.body);
|
||||
this.tooltipEl = $('<div class="composer_emoji_tooltip noselect"><div class="composer_emoji_tooltip_tabs"></div><div class="composer_emoji_tooltip_content clearfix"></div><div class="composer_emoji_tooltip_footer"><a class="composer_emoji_tooltip_settings"></a></div><div class="composer_emoji_tooltip_tail"><i class="icon icon-tooltip-tail"></i></div></div>').appendTo(document.body);
|
||||
|
||||
this.tabsEl = $('.composer_emoji_tooltip_tabs', this.tooltip);
|
||||
this.contentWrapEl = $('.composer_emoji_tooltip_content_wrap', this.tooltip);
|
||||
this.contentEl = $('.composer_emoji_tooltip_content', this.tooltip);
|
||||
this.footerEl = $('.composer_emoji_tooltip_footer', this.tooltip);
|
||||
this.settingsEl = $('.composer_emoji_tooltip_settings', this.tooltip);
|
||||
|
||||
var scrollWidth = this.getScrollWidth();
|
||||
if (scrollWidth > 0) {
|
||||
this.tooltipEl.css({
|
||||
width: parseInt(this.tooltipEl.css('width')) + scrollWidth
|
||||
});
|
||||
}
|
||||
this.tabsEl = $('.composer_emoji_tooltip_tabs', this.tooltipEl);
|
||||
this.contentEl = $('.composer_emoji_tooltip_content', this.tooltipEl);
|
||||
this.footerEl = $('.composer_emoji_tooltip_footer', this.tooltipEl);
|
||||
this.settingsEl = $('.composer_emoji_tooltip_settings', this.tooltipEl);
|
||||
|
||||
angular.forEach(['recent', 'smile', 'flower', 'bell', 'car', 'grid', 'stickers'], function (tabName, tabIndex) {
|
||||
var tab = $('<a class="composer_emoji_tooltip_tab composer_emoji_tooltip_tab_' + tabName + '"></a>')
|
||||
@ -254,9 +231,7 @@ EmojiTooltip.prototype.createTooltip = function () {
|
||||
}
|
||||
});
|
||||
|
||||
if (!Config.Mobile) {
|
||||
this.contentWrapEl.nanoScroller({preventPageScrolling: true, tabIndex: -1});
|
||||
}
|
||||
this.scroller = new Scroller(this.contentEl, {classPrefix: 'composer_emoji_tooltip'});
|
||||
|
||||
this.contentEl.on('mousedown', function (e) {
|
||||
e = e.originalEvent || e;
|
||||
@ -323,13 +298,7 @@ EmojiTooltip.prototype.updateTabContents = function () {
|
||||
|
||||
var renderContent = function () {
|
||||
self.contentEl.html(html.join(''));
|
||||
|
||||
if (!Config.Mobile) {
|
||||
self.contentWrapEl.nanoScroller({scroll: 'top'});
|
||||
setTimeout(function () {
|
||||
self.contentWrapEl.nanoScroller();
|
||||
}, 100);
|
||||
}
|
||||
self.scroller.reinit();
|
||||
}
|
||||
|
||||
if (this.tab == 6) { // Stickers
|
||||
@ -487,12 +456,15 @@ function MessageComposer (textarea, options) {
|
||||
|
||||
this.setUpInput();
|
||||
|
||||
this.autoCompleteEl = $('<ul class="composer_dropdown dropdown-menu"></ul>').appendTo(document.body);
|
||||
this.autoCompleteWrapEl = $('<div class="composer_dropdown_wrap"></div>').appendTo(document.body);
|
||||
this.autoCompleteEl = $('<ul class="composer_dropdown dropdown-menu"></ul>').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;
|
||||
var target = $(e.target), mention, code, command;
|
||||
if (target[0].tagName != 'A') {
|
||||
target = $(target[0].parentNode);
|
||||
}
|
||||
@ -503,9 +475,13 @@ function MessageComposer (textarea, options) {
|
||||
EmojiHelper.pushPopularEmoji(code);
|
||||
}
|
||||
if (mention = target.attr('data-mention')) {
|
||||
if (self.onMentionSelected) {
|
||||
self.onMentionSelected(mention);
|
||||
self.onMentionSelected(mention);
|
||||
}
|
||||
if (command = target.attr('data-command')) {
|
||||
if (self.onCommandSelected) {
|
||||
self.onCommandSelected(command);
|
||||
}
|
||||
self.hideSuggestions();
|
||||
}
|
||||
return cancelEvent(e);
|
||||
});
|
||||
@ -517,16 +493,25 @@ function MessageComposer (textarea, options) {
|
||||
this.getSendOnEnter = options.getSendOnEnter;
|
||||
this.onFilePaste = options.onFilePaste;
|
||||
this.mentions = options.mentions;
|
||||
this.commands = options.commands;
|
||||
this.getPeerImage = options.getPeerImage;
|
||||
this.onCommandSend = options.onCommandSend;
|
||||
}
|
||||
|
||||
MessageComposer.autoCompleteRegEx = /(\s|^)(:|@|\/)([A-Za-z0-9\-\+\*@_]*)$/;
|
||||
|
||||
|
||||
MessageComposer.prototype.setUpInput = function () {
|
||||
if ('contentEditable' in document.body) {
|
||||
this.setUpRich();
|
||||
} else {
|
||||
this.setUpPlaintext();
|
||||
}
|
||||
this.autoCompleteRegEx = /(?:\s|^)(:|@)([A-Za-z0-9\-\+\*_]*)$/;
|
||||
|
||||
var sbWidth = getScrollWidth();
|
||||
if (sbWidth) {
|
||||
(this.richTextareaEl || this.textareaEl).css({marginRight: -sbWidth});
|
||||
}
|
||||
}
|
||||
|
||||
MessageComposer.prototype.setUpRich = function () {
|
||||
@ -602,12 +587,14 @@ MessageComposer.prototype.onKeyEvent = function (e) {
|
||||
currentSelected.removeClass('composer_autocomplete_option_active');
|
||||
if (nextWrap) {
|
||||
$(nextWrap).find('a').addClass('composer_autocomplete_option_active');
|
||||
this.scroller.scrollToNode(nextWrap);
|
||||
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');
|
||||
|
||||
return cancelEvent(e);
|
||||
@ -618,17 +605,21 @@ MessageComposer.prototype.onKeyEvent = function (e) {
|
||||
if (!currentSelected.length && e.keyCode == 9) {
|
||||
currentSelected = $(this.autoCompleteEl[0].childNodes[0]).find('a');
|
||||
}
|
||||
var code, mention;
|
||||
var code, mention, command;
|
||||
if (code = currentSelected.attr('data-code')) {
|
||||
this.onEmojiSelected(code, true);
|
||||
EmojiHelper.pushPopularEmoji(code);
|
||||
return cancelEvent(e);
|
||||
}
|
||||
if (mention = currentSelected.attr('data-mention')) {
|
||||
if (this.onMentionSelected) {
|
||||
this.onMentionSelected(mention);
|
||||
return cancelEvent(e);
|
||||
this.onMentionSelected(mention);
|
||||
return cancelEvent(e);
|
||||
}
|
||||
if (command = currentSelected.attr('data-command')) {
|
||||
if (this.onCommandSelected) {
|
||||
this.onCommandSelected(command, e.keyCode == 9);
|
||||
}
|
||||
return cancelEvent(e);
|
||||
}
|
||||
checkSubmit = true;
|
||||
}
|
||||
@ -692,7 +683,7 @@ MessageComposer.prototype.restoreSelection = function () {
|
||||
|
||||
|
||||
|
||||
MessageComposer.prototype.checkAutocomplete = function () {
|
||||
MessageComposer.prototype.checkAutocomplete = function (forceFull) {
|
||||
if (Config.Mobile) {
|
||||
return false;
|
||||
}
|
||||
@ -708,17 +699,19 @@ MessageComposer.prototype.checkAutocomplete = function () {
|
||||
var value = textarea.value;
|
||||
}
|
||||
|
||||
value = value.substr(0, pos);
|
||||
if (!forceFull) {
|
||||
value = value.substr(0, pos);
|
||||
}
|
||||
|
||||
var matches = value.match(this.autoCompleteRegEx);
|
||||
var matches = value.match(MessageComposer.autoCompleteRegEx);
|
||||
if (matches) {
|
||||
if (this.previousQuery == matches[0]) {
|
||||
return;
|
||||
}
|
||||
this.previousQuery = matches[0];
|
||||
var query = SearchIndexManager.cleanSearchText(matches[2]);
|
||||
var query = SearchIndexManager.cleanSearchText(matches[3]);
|
||||
|
||||
if (matches[1] == '@') { // mentions
|
||||
if (matches[2] == '@') { // mentions
|
||||
if (this.mentions && this.mentions.index) {
|
||||
if (query.length) {
|
||||
var foundObject = SearchIndexManager.search(query, this.mentions.index);
|
||||
@ -742,7 +735,31 @@ MessageComposer.prototype.checkAutocomplete = function () {
|
||||
this.hideSuggestions();
|
||||
}
|
||||
}
|
||||
else { // emoji
|
||||
else if (!matches[1] && matches[2] == '/') { // commands
|
||||
if (this.commands && this.commands.index) {
|
||||
if (query.length) {
|
||||
var foundObject = SearchIndexManager.search(query, this.commands.index);
|
||||
var foundCommands = [];
|
||||
var command;
|
||||
for (var i = 0, length = this.commands.list.length; i < length; i++) {
|
||||
command = this.commands.list[i];
|
||||
if (foundObject[command.value]) {
|
||||
foundCommands.push(command);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var foundCommands = this.commands.list;
|
||||
}
|
||||
if (foundCommands.length) {
|
||||
this.showCommandsSuggestions(foundCommands);
|
||||
} else {
|
||||
this.hideSuggestions();
|
||||
}
|
||||
} else {
|
||||
this.hideSuggestions();
|
||||
}
|
||||
}
|
||||
else if (matches[2] == ':') { // emoji
|
||||
EmojiHelper.getPopularEmoji((function (popular) {
|
||||
if (query.length) {
|
||||
var found = EmojiHelper.searchEmojis(query);
|
||||
@ -977,6 +994,25 @@ MessageComposer.prototype.onMentionSelected = function (username) {
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
MessageComposer.prototype.onCommandSelected = function (command, isTab) {
|
||||
if (isTab) {
|
||||
if (this.richTextareaEl) {
|
||||
this.richTextareaEl.html(encodeEntities(command) + ' ');
|
||||
setRichFocus(this.richTextareaEl[0]);
|
||||
}
|
||||
else {
|
||||
var textarea = this.textareaEl[0];
|
||||
textarea.value = command + ' ';
|
||||
setFieldSelection(textarea);
|
||||
}
|
||||
} else {
|
||||
this.onCommandSend(command);
|
||||
}
|
||||
|
||||
this.hideSuggestions();
|
||||
this.onChange();
|
||||
}
|
||||
|
||||
MessageComposer.prototype.onChange = function (e) {
|
||||
if (this.richTextareaEl) {
|
||||
delete this.keyupStarted;
|
||||
@ -1028,6 +1064,13 @@ MessageComposer.prototype.focus = function () {
|
||||
}
|
||||
}
|
||||
|
||||
MessageComposer.prototype.renderSuggestions = function (html) {
|
||||
this.autoCompleteEl.html(html.join(''));
|
||||
this.autoCompleteWrapEl.show();
|
||||
this.scroller.reinit();
|
||||
this.updatePosition();
|
||||
this.autocompleteShown = true;
|
||||
}
|
||||
|
||||
MessageComposer.prototype.showEmojiSuggestions = function (codes) {
|
||||
var html = [];
|
||||
@ -1052,16 +1095,13 @@ MessageComposer.prototype.showEmojiSuggestions = function (codes) {
|
||||
}
|
||||
}
|
||||
|
||||
this.autoCompleteEl.html(html.join(''));
|
||||
this.autoCompleteEl.show();
|
||||
this.updatePosition();
|
||||
this.autocompleteShown = true;
|
||||
this.renderSuggestions(html);
|
||||
}
|
||||
|
||||
MessageComposer.prototype.showMentionSuggestions = function (users) {
|
||||
var html = [];
|
||||
var user;
|
||||
var count = Math.min(5, users.length);
|
||||
var count = users.length;
|
||||
var i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
@ -1069,27 +1109,53 @@ MessageComposer.prototype.showMentionSuggestions = function (users) {
|
||||
html.push('<li><a class="composer_mention_option" data-mention="' + user.username + '"><span class="composer_user_photo" data-user-id="' + user.id + '"></span><span class="composer_user_name">' + user.rFullName + '</span><span class="composer_user_mention">@' + user.username + '</span></a></li>');
|
||||
}
|
||||
|
||||
this.autoCompleteEl.html(html.join(''));
|
||||
|
||||
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.autoCompleteEl.show();
|
||||
this.updatePosition();
|
||||
this.autocompleteShown = true;
|
||||
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('<li><a class="composer_command_option" data-command="' + encodeEntities(command.value) + '"><span class="composer_user_photo" data-user-id="' + command.botID + '"></span><span class="composer_command_value">' + encodeEntities(command.value) + '</span><span class="composer_command_desc">' + command.rDescription + '</span></a></li>');
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
MessageComposer.prototype.updatePosition = function () {
|
||||
var offset = (this.richTextareaEl || this.textareaEl).offset();
|
||||
var height = this.autoCompleteEl.outerHeight();
|
||||
var width = (this.richTextareaEl || this.textareaEl).outerWidth();
|
||||
this.autoCompleteEl.css({top: offset.top - height, left: offset.left, width: width - 2});
|
||||
var height = this.scroller.updateHeight();
|
||||
this.autoCompleteWrapEl.css({
|
||||
top: offset.top - height,
|
||||
left: offset.left,
|
||||
width: width - 2
|
||||
});
|
||||
this.scroller.update();
|
||||
}
|
||||
|
||||
MessageComposer.prototype.hideSuggestions = function () {
|
||||
this.autoCompleteEl.hide();
|
||||
this.autoCompleteWrapEl.hide();
|
||||
delete this.autocompleteShown;
|
||||
}
|
||||
|
||||
@ -1098,3 +1164,92 @@ MessageComposer.prototype.resetTyping = function () {
|
||||
this.lastLength = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function Scroller(content, options) {
|
||||
options = options || {};
|
||||
var classPrefix = options.classPrefix || 'scroller';
|
||||
|
||||
this.content = $(content);
|
||||
this.content.wrap('<div class="' + classPrefix + '_scrollable_container"><div class="' + classPrefix + '_scrollable_wrap"><div class="' + classPrefix + '_scrollable"></div></div></div>');
|
||||
|
||||
this.scrollable = $(this.content[0].parentNode);
|
||||
this.scroller = $(this.scrollable[0].parentNode);
|
||||
this.wrap = $(this.scroller[0].parentNode);
|
||||
|
||||
this.useNano = options.nano !== undefined ? options.nano : !Config.Mobile;
|
||||
this.maxHeight = options.maxHeight;
|
||||
this.minHeight = options.minHeight;
|
||||
|
||||
if (this.useNano) {
|
||||
this.scrollable.addClass('nano-content');
|
||||
this.scroller.addClass('nano');
|
||||
this.scroller.nanoScroller({preventPageScrolling: true, tabIndex: -1});
|
||||
} else {
|
||||
if (this.maxHeight) {
|
||||
this.wrap.css({maxHeight: this.maxHeight});
|
||||
}
|
||||
if (this.minHeight) {
|
||||
this.wrap.css({minHeight: this.minHeight});
|
||||
}
|
||||
}
|
||||
this.updateHeight();
|
||||
}
|
||||
|
||||
Scroller.prototype.update = function () {
|
||||
if (this.useNano) {
|
||||
$(this.scroller).nanoScroller();
|
||||
}
|
||||
}
|
||||
|
||||
Scroller.prototype.reinit = function () {
|
||||
this.scrollTo(0);
|
||||
if (this.useNano) {
|
||||
setTimeout((function () {
|
||||
this.updateHeight();
|
||||
}).bind(this), 100)
|
||||
}
|
||||
}
|
||||
|
||||
Scroller.prototype.updateHeight = function () {
|
||||
var height;
|
||||
if (this.maxHeight || this.minHeight) {
|
||||
height = this.content[0].offsetHeight;
|
||||
if (this.maxHeight && height > this.maxHeight) {
|
||||
height = this.maxHeight;
|
||||
}
|
||||
if (this.minHeight && height < this.minHeight) {
|
||||
height = this.minHeight;
|
||||
}
|
||||
this.wrap.css({height: height});
|
||||
} else {
|
||||
height = this.scroller[0].offsetHeight;
|
||||
}
|
||||
$(this.scroller).nanoScroller();
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
Scroller.prototype.scrollTo = function (scrollTop) {
|
||||
this.scrollable[0].scrollTop = scrollTop;
|
||||
if (this.useNano) {
|
||||
$(this.scroller).nanoScroller({flash: true});
|
||||
}
|
||||
}
|
||||
|
||||
Scroller.prototype.scrollToNode = function (node) {
|
||||
node = node[0] || node;
|
||||
var elTop = node.offsetTop - 15,
|
||||
elHeight = node.offsetHeight + 30,
|
||||
scrollTop = this.scrollable[0].scrollTop,
|
||||
viewportHeight = this.scrollable[0].clientHeight;
|
||||
|
||||
if (scrollTop > elTop) { // we are below the node to scroll
|
||||
this.scrollTo(elTop);
|
||||
}
|
||||
else if (scrollTop < elTop + elHeight - viewportHeight) { // we are over the node to scroll
|
||||
this.scrollTo(elTop + elHeight - viewportHeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -858,7 +858,7 @@ a.tg_radio_on:hover i.icon-radio {
|
||||
vertical-align: top;
|
||||
margin-right: 18px;
|
||||
|
||||
.image-2x('../img/icons/General.png', 40px, 778px);
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: -5px -10px;
|
||||
}
|
||||
.icon-tg-title {
|
||||
@ -899,7 +899,7 @@ a.tg_radio_on:hover i.icon-radio {
|
||||
margin-left: 12px;
|
||||
margin-top: -1px;
|
||||
|
||||
.image-2x('../img/icons/General.png', 40px, 778px);
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: -18px -50px;
|
||||
}
|
||||
|
||||
@ -1617,7 +1617,7 @@ div.im_message_video_thumb {
|
||||
height: 18px;
|
||||
margin: 12px 15px;
|
||||
|
||||
.image-2x('../img/icons/General.png', 40px, 778px);
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: -14px -509px;
|
||||
|
||||
.im_message_file_button_dl_doc & {
|
||||
@ -1638,7 +1638,7 @@ div.im_message_video_thumb {
|
||||
height: 16px;
|
||||
margin: 13px 16px;
|
||||
|
||||
.image-2x('../img/icons/General.png', 40px, 778px);
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: -13px -611px;
|
||||
}
|
||||
|
||||
@ -1659,8 +1659,9 @@ div.im_message_video_thumb {
|
||||
background-position: -2px -542px;
|
||||
}
|
||||
|
||||
.im_history_selectable {
|
||||
a {
|
||||
.im_history_select_active {
|
||||
a,
|
||||
.clickable {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
@ -1912,6 +1913,22 @@ img.im_message_document_thumb {
|
||||
.im_service_message_wrap {
|
||||
text-align: center;
|
||||
}
|
||||
.im_bot_intro_message_wrap {
|
||||
max-width: 300px;
|
||||
padding: 4px 10px;
|
||||
margin: 10px auto;
|
||||
color: #000;
|
||||
line-height: 1.4;
|
||||
text-align: left;
|
||||
font-size: 13px;
|
||||
}
|
||||
.im_bot_intro_message_header {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
.im_bot_intro_message {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.im_service_message {
|
||||
display: inline-block;
|
||||
min-width: 10px;
|
||||
@ -2040,10 +2057,69 @@ a.im_message_fwd_photo {
|
||||
}
|
||||
.im_message_mymention {
|
||||
background: #fff8cc;
|
||||
/*border-bottom: 1px solid #ffe222;*/
|
||||
/*font-weight: bold;*/
|
||||
}
|
||||
|
||||
.reply_markup_wrap {
|
||||
margin: 15px -2px 0;
|
||||
}
|
||||
.reply_markup_row {
|
||||
padding: 4px 0;
|
||||
&:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
&:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.reply_markup_scrollable_wrap.active-scrollbar & {
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
.reply_markup_button_wrap {
|
||||
display: inline-block;
|
||||
padding: 0 4px;
|
||||
}
|
||||
.reply_markup_button {
|
||||
color: #3a6d99;
|
||||
display: block;
|
||||
width: 100%;
|
||||
background: #f0f4f7;
|
||||
height: 30px;
|
||||
font-size: 13px;
|
||||
margin: 0;
|
||||
padding: 6px 6px;
|
||||
|
||||
.reply_markup_h1 & {
|
||||
height: 170px;
|
||||
}
|
||||
.reply_markup_h2 & {
|
||||
height: 81px;
|
||||
}
|
||||
.reply_markup_h3 & {
|
||||
height: 51px;
|
||||
}
|
||||
.reply_markup_h4 & {
|
||||
height: 36px;
|
||||
}
|
||||
}
|
||||
.reply_markup_button:hover {
|
||||
color: #3a6d99;
|
||||
background: #dfe8f0;
|
||||
}
|
||||
.reply_markup_button_w1 {width: 100%;}
|
||||
.reply_markup_button_w2 {width: 50%;}
|
||||
.reply_markup_button_w3 {width: 33.3333333%;}
|
||||
.reply_markup_button_w4 {width: 25%;}
|
||||
.reply_markup_button_w5 {width: 20%;}
|
||||
.reply_markup_button_w6 {width: 16.6666666%;}
|
||||
.reply_markup_button_w7 {width: 14.2857142%;}
|
||||
.reply_markup_button_w8 {width: 12.5%;}
|
||||
.reply_markup_button_w9 {width: 11.1111111%;}
|
||||
.reply_markup_button_w10 {width: 10%;}
|
||||
.reply_markup_button_w11 {width: 9.09090909%;}
|
||||
.reply_markup_button_w12 {width: 8.33333333%;}
|
||||
|
||||
|
||||
|
||||
.im_history_not_selected,
|
||||
.im_history_empty {
|
||||
visibility: hidden;
|
||||
@ -2206,7 +2282,7 @@ img.img_fullsize {
|
||||
vertical-align: top;
|
||||
opacity: 0.8;
|
||||
|
||||
.image-2x('../img/icons/General.png', 40px, 778px);
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: -9px -335px;
|
||||
}
|
||||
|
||||
@ -2310,14 +2386,11 @@ img.img_fullsize {
|
||||
.composer_emoji_tooltip_tab_stickers {background-position: -9px -361px; }
|
||||
.composer_emoji_tooltip_tab_stickers.active {background-position: -9px -333px; }
|
||||
|
||||
.nano.composer_emoji_tooltip_content_wrap {
|
||||
.composer_emoji_tooltip_scrollable_container {
|
||||
height: 174px;
|
||||
position: relative;
|
||||
}
|
||||
.composer_emoji_tooltip_content {
|
||||
/*position: relative;*/
|
||||
/*overflow: hidden;
|
||||
overflow-y: auto;*/
|
||||
padding-right: 8px;
|
||||
outline: 0!important;
|
||||
}
|
||||
@ -2397,15 +2470,33 @@ a.composer_emoji_btn {
|
||||
&.emoji-spritesheet-4 { background-size: 884px 182px; }
|
||||
}
|
||||
|
||||
.composer_dropdown {
|
||||
|
||||
.composer_dropdown_wrap {
|
||||
background: #FFF;
|
||||
display: none;
|
||||
padding: 6px 0;
|
||||
position: absolute;
|
||||
border: 0;
|
||||
|
||||
.box-shadow(0px 1px 1px 0px rgba(60,75,87,0.27));
|
||||
|
||||
border-radius: 0;
|
||||
margin-top: -5px;
|
||||
margin-left: -1px;
|
||||
}
|
||||
.composer_dropdown_scroller {
|
||||
}
|
||||
|
||||
.composer_dropdown {
|
||||
position: static;
|
||||
display: block;
|
||||
float: none;
|
||||
top: auto;
|
||||
left: auto;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
z-index: auto;
|
||||
|
||||
& > li > a {
|
||||
display: block;
|
||||
@ -2457,6 +2548,7 @@ a.composer_emoji_btn {
|
||||
img& {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
span& {
|
||||
@ -2474,6 +2566,36 @@ a.composer_emoji_btn {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.composer_dropdown a.composer_command_option {
|
||||
color: #808080;
|
||||
line-height: 32px;
|
||||
padding-right: 5px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.composer_dropdown .composer_command_value {
|
||||
color: #52719a;
|
||||
display: inline;
|
||||
}
|
||||
.composer_dropdown .composer_command_desc {
|
||||
display: inline;
|
||||
color: #808080;
|
||||
padding-left: 7px;
|
||||
font-weight: normal;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
a.composer_command_option:hover .composer_command_desc,
|
||||
a.composer_command_option.composer_autocomplete_option_active .composer_command_desc {
|
||||
color: #698192;
|
||||
}
|
||||
.composer_command_desc .emoji {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
|
||||
.composer_stickerset_title {
|
||||
display: block;
|
||||
// clear: both;
|
||||
@ -2558,6 +2680,67 @@ a.composer_emoji_btn {
|
||||
}
|
||||
}
|
||||
|
||||
.composer_command_btn {
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 37px;
|
||||
top: 4px;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
.icon-slash {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
vertical-align: top;
|
||||
opacity: 0.8;
|
||||
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: -10px -790px;
|
||||
|
||||
.composer_command_btn.active & {
|
||||
background-position: -10px -820px;
|
||||
}
|
||||
|
||||
.composer_command_btn:hover & {
|
||||
opacity: 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
.composer_keyboard_btn {
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: 37px;
|
||||
top: 4px;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
.icon-keyboard {
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
vertical-align: top;
|
||||
opacity: 0.8;
|
||||
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: -10px -730px;
|
||||
|
||||
.composer_keyboard_btn.active & {
|
||||
background-position: -10px -760px;
|
||||
}
|
||||
|
||||
.composer_keyboard_btn:hover & {
|
||||
opacity: 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.error_modal_window {
|
||||
.modal-dialog {
|
||||
max-width: 350px;
|
||||
@ -2984,13 +3167,6 @@ a.contacts_modal_contact:hover .md_modal_list_peer_description,
|
||||
}
|
||||
}
|
||||
|
||||
.im_edit_panel_title {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
line-height: 34px;
|
||||
}
|
||||
|
||||
.im_message_focus {
|
||||
.im_message_date,
|
||||
.im_message_document_size,
|
||||
@ -3020,6 +3196,8 @@ a.peer_photo_init {
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
|
||||
.user-select(none);
|
||||
}
|
||||
|
||||
h5 {
|
||||
|
@ -205,7 +205,7 @@
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-top: 3px;
|
||||
.image-2x('../img/icons/General.png', 40px, 778px);
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: -10px -111px;
|
||||
|
||||
}
|
||||
@ -217,7 +217,7 @@
|
||||
margin-top: 2px;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
.image-2x('../img/icons/General.png', 40px, 778px);
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: -11px -135px;
|
||||
}
|
||||
|
||||
@ -228,7 +228,7 @@
|
||||
margin-top: 1px;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
.image-2x('../img/icons/General.png', 40px, 778px);
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: -10px -163px;
|
||||
}
|
||||
|
||||
@ -239,7 +239,7 @@
|
||||
margin-top: 1px;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
.image-2x('../img/icons/General.png', 40px, 778px);
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: -10px -637px;
|
||||
}
|
||||
|
||||
@ -250,7 +250,7 @@
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
|
||||
.image-2x('../img/icons/General.png', 40px, 778px);
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: -10px -193px;
|
||||
}
|
||||
}
|
||||
@ -378,7 +378,7 @@
|
||||
margin-right: 12px;
|
||||
vertical-align: top;
|
||||
|
||||
.image-2x('../img/icons/General.png', 40px, 778px);
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
@ -482,7 +482,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
.composer_emoji_tooltip {
|
||||
.composer_emoji_tooltip,
|
||||
.composer_dropdown_wrap {
|
||||
z-index: 1001;
|
||||
|
||||
.nano > .nano-pane {
|
||||
@ -491,11 +492,18 @@
|
||||
|
||||
& > .nano-slider {
|
||||
background: #d1d1d1;
|
||||
background : rgba(0,0,0,0.17);
|
||||
margin: 0 3px 0 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.composer_dropdown_wrap .nano > .nano-pane {
|
||||
top: 3px;
|
||||
bottom: 3px;
|
||||
right: -1px;
|
||||
}
|
||||
|
||||
.countries_modal_col {
|
||||
.nano {
|
||||
& > .nano-pane {
|
||||
@ -694,6 +702,24 @@ a.footer_link.active:active {
|
||||
}
|
||||
}
|
||||
|
||||
.reply_markup_scrollable_container {
|
||||
.nano > .nano-pane {
|
||||
background: rgba(137, 160, 179, 0.1);
|
||||
right: 2px;
|
||||
width: 3px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
.rounded(1px);
|
||||
|
||||
& > .nano-slider {
|
||||
.rounded(1px);
|
||||
background: #d1d1d1;
|
||||
background: rgba(137, 160, 179, 0.5);
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.im_history {
|
||||
&_no_dialogs_wrap {
|
||||
margin: 122px 170px 60px;
|
||||
@ -772,50 +798,13 @@ a.footer_link.active:active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.icon-message-status {
|
||||
pointer-events: none;
|
||||
background: #4eabf1;
|
||||
border: 0;
|
||||
display: block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 7px;
|
||||
position: absolute;
|
||||
margin-left: -26px;
|
||||
margin-top: 16px;
|
||||
opacity: 0;
|
||||
|
||||
.im_message_unread & {
|
||||
opacity: 1.0;
|
||||
}
|
||||
.im_message_pending & {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.im_message_error_btn {
|
||||
display: none;
|
||||
|
||||
.im_message_error & {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.icon-message-status {
|
||||
background: #da564d;
|
||||
opacity: 0.85;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Messages edit panel */
|
||||
|
||||
.im {
|
||||
&_edit_delete_btn,
|
||||
&_edit_forward_btn,
|
||||
&_edit_reply_btn {
|
||||
&_edit_reply_btn,
|
||||
&_start_btn {
|
||||
border-radius: 2px;
|
||||
padding: 7px 17px;
|
||||
font-weight: bold;
|
||||
@ -825,7 +814,7 @@ a.footer_link.active:active {
|
||||
}
|
||||
|
||||
&_edit_panel_wrap {
|
||||
padding: 0px 0 43px;
|
||||
padding: 0px 0 41px;
|
||||
margin: 0 24px 0 12px;
|
||||
}
|
||||
|
||||
@ -849,6 +838,14 @@ a.footer_link.active:active {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
&_edit_start_actions {
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
&_start_btn {
|
||||
padding: 7px 25px;
|
||||
}
|
||||
|
||||
&_selected_count {
|
||||
color: #b9cfe3;
|
||||
}
|
||||
@ -894,55 +891,114 @@ a.footer_link.active:active {
|
||||
.im_message_selected .im_message_audio_duration,
|
||||
.im_message_selected .im_message_audio_size,
|
||||
.im_message_selected .im_message_fwd_date,
|
||||
.im_history_selectable .im_message_outer_wrap:hover .im_message_date,
|
||||
.im_history_selectable .im_message_outer_wrap:hover .im_message_document_size,
|
||||
.im_history_selectable .im_message_outer_wrap:hover .im_message_audio_duration,
|
||||
.im_history_selectable .im_message_outer_wrap:hover .im_message_audio_size,
|
||||
.im_history_selectable .im_message_outer_wrap:hover .im_message_fwd_date {
|
||||
.im_history_select_active .im_message_outer_wrap:hover .im_message_date,
|
||||
.im_history_select_active .im_message_outer_wrap:hover .im_message_document_size,
|
||||
.im_history_select_active .im_message_outer_wrap:hover .im_message_audio_duration,
|
||||
.im_history_select_active .im_message_outer_wrap:hover .im_message_audio_size,
|
||||
.im_history_select_active .im_message_outer_wrap:hover .im_message_fwd_date {
|
||||
color: #899daf;
|
||||
}
|
||||
|
||||
.im_content_message_select_area {
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
width: 99px;
|
||||
height: 58px;
|
||||
margin: -8px 0 0 -99px;
|
||||
|
||||
.user-select(none);
|
||||
}
|
||||
|
||||
.icon-select-tick {
|
||||
display: none;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
margin: 16px 0 0 40px;
|
||||
|
||||
.image-2x('../img/icons/IconsetW.png', 42px, 1171px);
|
||||
background-position: -9px -516px;
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.im_content_message_select_area {
|
||||
display: block;
|
||||
}
|
||||
.im_message_wrap {
|
||||
position: relative;
|
||||
}
|
||||
.icon-select-tick {
|
||||
.im_message_selected &,
|
||||
.im_history_selectable .im_message_outer_wrap:hover & {
|
||||
position: absolute;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
margin: 9px 0 0 -59px;
|
||||
display: block;
|
||||
|
||||
.image-2x('../img/icons/IconsetW.png', 42px, 1171px);
|
||||
background-position: -9px -481px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.im_message_selected & {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.im_grouped_short &,
|
||||
.im_grouped_short .im_message_outer_wrap:hover & {
|
||||
margin-top: -2px;
|
||||
}
|
||||
.im_message_fwd &,
|
||||
.im_message_outer_wrap:hover .im_message_fwd & {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.im_grouped_fwd &,
|
||||
.im_grouped_fwd .im_message_outer_wrap:hover & {
|
||||
margin-top: 7px;
|
||||
}
|
||||
.im_grouped &,
|
||||
.im_grouped .im_message_outer_wrap:hover & {
|
||||
margin-top: 7px;
|
||||
}
|
||||
.im_grouped_fwd_short &,
|
||||
.im_grouped_fwd_short .im_message_outer_wrap:hover & {
|
||||
margin-top: -5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon-select-tick {
|
||||
.im_message_selected &,
|
||||
.im_history_selectable .im_message_outer_wrap:hover &,
|
||||
.im_content_message_select_area:hover & {
|
||||
display: inline-block;
|
||||
background-position: -9px -481px;
|
||||
.icon-message-status {
|
||||
pointer-events: none;
|
||||
background: #4eabf1;
|
||||
border: 0;
|
||||
display: block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 7px;
|
||||
position: absolute;
|
||||
margin-left: -26px;
|
||||
margin-top: 16px;
|
||||
opacity: 0;
|
||||
|
||||
.im_message_unread & {
|
||||
opacity: 1.0;
|
||||
}
|
||||
.im_message_pending & {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.im_message_selected & {
|
||||
opacity: 1 !important;
|
||||
.im_grouped_short & {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.im_message_fwd & {
|
||||
margin-top: 16px;
|
||||
}
|
||||
.im_grouped_fwd & {
|
||||
margin-top: 13px;
|
||||
}
|
||||
.im_grouped & {
|
||||
margin-top: 13px;
|
||||
}
|
||||
.im_grouped_fwd_short & {
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.im_message_error_btn {
|
||||
display: none;
|
||||
|
||||
.im_message_error & {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.icon-message-status {
|
||||
background: #da564d;
|
||||
opacity: 0.85;
|
||||
pointer-events: auto;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1061,7 +1117,7 @@ a.footer_link.active:active {
|
||||
|
||||
.im_send_panel_wrap {
|
||||
max-width: 554px;
|
||||
padding-bottom: 23px;
|
||||
padding-bottom: 21px;
|
||||
}
|
||||
.im_send_form {
|
||||
max-width: 382px;
|
||||
@ -1123,11 +1179,15 @@ a.im_panel_peer_photo .peer_initials {
|
||||
}
|
||||
|
||||
.im_send_field_wrap {
|
||||
margin-bottom: 15px;
|
||||
margin-bottom: 13px;
|
||||
position: relative;
|
||||
padding-bottom: 2px;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.composer_rich_textarea,
|
||||
.composer_textarea {
|
||||
overflow: none;
|
||||
overflow-y: scroll;
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
@ -1145,6 +1205,10 @@ a.im_panel_peer_photo .peer_initials {
|
||||
outline: none;
|
||||
box-shadow: 0 2px 0 0 #77b7e4;
|
||||
}
|
||||
|
||||
.im_send_field_wrap_2ndbtn & {
|
||||
padding-right: 65px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-paperclip {
|
||||
@ -1155,7 +1219,7 @@ a.im_panel_peer_photo .peer_initials {
|
||||
opacity: 0.8;
|
||||
margin: 0;
|
||||
|
||||
.image-2x('../img/icons/General.png', 40px, 778px);
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: -11px -455px;
|
||||
}
|
||||
|
||||
@ -1204,7 +1268,7 @@ a.im_panel_peer_photo .peer_initials {
|
||||
vertical-align: top;
|
||||
opacity: 0.8;
|
||||
|
||||
.image-2x('../img/icons/General.png', 40px, 778px);
|
||||
.image-2x('../img/icons/General.png', 40px, 848px);
|
||||
background-position: -10px -399px;
|
||||
}
|
||||
|
||||
@ -1227,7 +1291,7 @@ a.im_panel_peer_photo .peer_initials {
|
||||
&_form_wrap {
|
||||
a.im_panel_own_photo,
|
||||
a.im_panel_peer_photo {
|
||||
margin-top: 47px;
|
||||
margin-top: 41px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1730,19 +1794,30 @@ a.im_panel_peer_photo .peer_initials {
|
||||
max-width: 362px;
|
||||
display: inline-block;
|
||||
}
|
||||
.im_message_selected .im_message_outer_wrap,
|
||||
.im_message_focus .im_message_outer_wrap {
|
||||
.im_message_selected .im_message_outer_wrap {
|
||||
background: #f2f6fa;
|
||||
}
|
||||
|
||||
.im_history_selectable {
|
||||
.im_message_outer_wrap {
|
||||
cursor: pointer;
|
||||
.im_message_focus .im_message_outer_wrap {
|
||||
background-color: rgba(242, 246, 250, 1.0);
|
||||
animation-name: im_message_focus_fade;
|
||||
animation-duration: 5s;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #f2f6fa;
|
||||
@keyframes im_message_focus_fade {
|
||||
from {
|
||||
background-color: rgba(242, 246, 250, 1.0);
|
||||
}
|
||||
}
|
||||
to {
|
||||
background-color: rgba(242, 246, 250, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.im_history_selectable .im_message_outer_wrap {
|
||||
cursor: pointer;
|
||||
}
|
||||
.im_history_select_active .im_message_outer_wrap:hover {
|
||||
background: #f2f6fa;
|
||||
}
|
||||
|
||||
.im_message_wrap {
|
||||
@ -1809,42 +1884,8 @@ a.im_panel_peer_photo .peer_initials {
|
||||
}
|
||||
}
|
||||
|
||||
.im_content_message_select_area {
|
||||
.im_grouped_short &,
|
||||
.im_grouped & {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.im_message_fwd & {
|
||||
margin-top: -4px;
|
||||
}
|
||||
|
||||
.im_grouped_fwd .im_message_fwd &,
|
||||
.im_grouped_fwd_short .im_message_fwd & {
|
||||
margin-top: -8px;
|
||||
}
|
||||
|
||||
.im_history_appending & {
|
||||
height: 52px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-select-tick {
|
||||
.im_message_fwd & {
|
||||
margin-top: 12px;
|
||||
}
|
||||
.im_grouped_short & {
|
||||
margin-top: 4px;
|
||||
}
|
||||
.im_grouped_fwd_short & {
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.im_grouped_short .icon-message-status,
|
||||
.im_grouped_fwd_short .icon-message-status {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.im_grouped_fwd .im_message_fwd_from,
|
||||
.im_grouped_fwd_short .im_message_fwd_from {
|
||||
display: none;
|
||||
@ -1859,12 +1900,6 @@ a.im_panel_peer_photo .peer_initials {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.im_grouped_fwd &,
|
||||
.im_grouped_fwd_short & {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.im_grouped_fwd &,
|
||||
.im_grouped_fwd_short & {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
@ -519,7 +519,7 @@ html {
|
||||
border: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.im_history_selectable .im_message_outer_wrap:hover,
|
||||
.im_history_select_active .im_message_outer_wrap:hover,
|
||||
.im_message_selected {
|
||||
background: #e1e9f0;
|
||||
}
|
||||
@ -831,10 +831,10 @@ img.im_message_video_thumb,
|
||||
.im_message_focus .audio_player_duration,
|
||||
.im_message_focus .audio_player_size,
|
||||
.im_message_focus .im_message_fwd_date,
|
||||
.im_history_selectable .im_message_outer_wrap:hover .im_message_document_size,
|
||||
.im_history_selectable .im_message_outer_wrap:hover .audio_player_duration,
|
||||
.im_history_selectable .im_message_outer_wrap:hover .audio_player_size,
|
||||
.im_history_selectable .im_message_outer_wrap:hover .im_message_fwd_date {
|
||||
.im_history_select_active .im_message_outer_wrap:hover .im_message_document_size,
|
||||
.im_history_select_active .im_message_outer_wrap:hover .audio_player_duration,
|
||||
.im_history_select_active .im_message_outer_wrap:hover .audio_player_size,
|
||||
.im_history_select_active .im_message_outer_wrap:hover .im_message_fwd_date {
|
||||
color: #68839c;
|
||||
}
|
||||
|
||||
@ -1077,10 +1077,10 @@ a.im_dialog {
|
||||
.im_message_selected .audio_player_title,
|
||||
.im_message_selected .audio_player_duration,
|
||||
.im_message_selected .audio_player_size,
|
||||
.im_history_selectable .im_message_selected:hover .im_message_document_size,
|
||||
.im_history_selectable .im_message_selected:hover .audio_player_duration,
|
||||
.im_history_selectable .im_message_selected:hover .audio_player_size,
|
||||
.im_history_selectable .im_message_selected:hover .im_message_fwd_date {
|
||||
.im_history_select_active .im_message_selected:hover .im_message_document_size,
|
||||
.im_history_select_active .im_message_selected:hover .audio_player_duration,
|
||||
.im_history_select_active .im_message_selected:hover .audio_player_size,
|
||||
.im_history_select_active .im_message_selected:hover .im_message_fwd_date {
|
||||
color: #fff;
|
||||
}
|
||||
a.im_message_fwd_author {
|
||||
|
@ -7,8 +7,12 @@
|
||||
<span ng-switch-when="true" class="audio_player_duration" ng-bind="mediaPlayer.player.currentTime | durationRemains : (mediaPlayer.player.duration || audio.duration)"></span>
|
||||
<span ng-switch-default class="audio_player_duration" ng-bind="mediaPlayer.player.duration || audio.duration | duration"></span>
|
||||
</div>
|
||||
<a ng-click="download()" class="audio_player_title" ng-switch="::audio.file_name.length > 0">
|
||||
<span ng-switch-when="true" ng-bind="::audio.file_name"></span>
|
||||
<a ng-click="download()" class="audio_player_title" ng-switch="::audio.audioTitle.length > 0 ? 2 : (audio.file_name.length > 0 ? 1 : 0)">
|
||||
<span ng-switch-when="2">
|
||||
<strong ng-bind="::audio.audioPerformer"></strong>
|
||||
<span ng-bind="::(audio.audioPerformer ? '– ' : '') + audio.audioTitle"></span>
|
||||
</span>
|
||||
<span ng-switch-when="1" ng-bind="::audio.file_name"></span>
|
||||
<span ng-switch-default my-i18n="message_attach_audio_message"></span>
|
||||
</a>
|
||||
<i ng-if="::message.media_unread || false" ng-show="message.media_unread" class="icon icon-audio-unread"></i>
|
||||
|
@ -100,7 +100,7 @@
|
||||
<div class="md_modal_list_peer_name">
|
||||
<a class="md_modal_list_peer_name" my-user-link="participant.user_id"></a>
|
||||
</div>
|
||||
<div class="md_modal_list_peer_description" my-user-status="::participant.user_id"></div>
|
||||
<div class="md_modal_list_peer_description" my-user-status="::participant.user_id" bot-chat-privacy="true"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -16,12 +16,12 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="media_modal_info_wrap pull-left" ng-switch="messageID > 0">
|
||||
<div class="media_modal_info_wrap pull-left" ng-if="document.user_id > 0" ng-switch="messageID > 0">
|
||||
<a class="media_modal_author_photo pull-left" my-peer-photolink="document.user_id" img-class="media_modal_author_photo" watch="true"></a>
|
||||
<div class="media_modal_author_name">
|
||||
<a class="media_modal_author" my-user-link="document.user_id" user-watch="true"></a>
|
||||
</div>
|
||||
<div class="media_modal_date">
|
||||
<div class="media_modal_date" ng-if="document.date > 0">
|
||||
<a ng-switch-when="true" class="media_modal_date" ng-click="goToMessage()" ng-bind="document.date | dateOrTime :true"></a>
|
||||
<span ng-switch-default ng-bind="document.date | dateOrTime :true"></span>
|
||||
</div>
|
||||
|
@ -103,7 +103,7 @@
|
||||
<div class="im_history_scrollable_wrap nano-content">
|
||||
|
||||
<div class="im_history_scrollable">
|
||||
<div class="im_history" ng-class="{im_history_selectable: historyState.selectActions}">
|
||||
<div class="im_history" ng-class="{im_history_selectable: !historyState.startBot, im_history_select_active: historyState.selectActions}">
|
||||
<div ng-if="state.empty" class="im_history_empty" ng-switch="state.mayBeHasMore" my-vertical-position="0.25" padding="true">
|
||||
<span ng-switch-when="true">
|
||||
<my-i18n msgid="im_loading_history"></my-i18n><span my-loading-dots></span>
|
||||
@ -140,10 +140,13 @@
|
||||
|
||||
<div class="im_bottom_panel_wrap">
|
||||
|
||||
<div class="im_edit_panel_wrap clearfix" ng-show="historyState.selectActions">
|
||||
<div class="im_edit_panel_wrap clearfix" ng-show="historyState.selectActions || historyState.startBot" ng-switch="historyState.startBot != false">
|
||||
<div class="im_edit_panel_border"></div>
|
||||
<a class="btn btn-md btn-md-primary im_edit_cancel_link" ng-click="selectedCancel()" my-i18n="modal_cancel"></a>
|
||||
<div class="im_edit_selected_actions" my-i18n>
|
||||
<a ng-show="historyState.startBot != 2" class="btn btn-md btn-md-primary im_edit_cancel_link" ng-click="selectedCancel()" my-i18n="modal_cancel"></a>
|
||||
<div class="im_edit_start_actions" ng-switch-when="true">
|
||||
<a class="btn btn-primary im_start_btn" ng-click="botStart()" my-i18n="im_start"></a>
|
||||
</div>
|
||||
<div class="im_edit_selected_actions" ng-switch-default my-i18n>
|
||||
<a class="btn btn-primary im_edit_forward_btn" ng-click="selectedForward()" ng-class="{disabled: !selectedCount}" ng-disabled="!selectedCount" my-i18n-format="im_forward"></a>
|
||||
<a class="btn btn-primary im_edit_delete_btn" ng-click="selectedDelete()" ng-class="{disabled: !selectedCount}" ng-disabled="!selectedCount" my-i18n-format="im_delete"></a>
|
||||
<a class="btn btn-primary im_edit_reply_btn" ng-click="selectedReply()" ng-show="selectedCount == 1"my-i18n="im_reply"></a>
|
||||
@ -151,7 +154,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="im_send_panel_wrap" ng-hide="historyState.selectActions">
|
||||
<div class="im_send_panel_wrap" ng-show="!historyState.selectActions && !historyState.startBot">
|
||||
|
||||
<div class="im_send_form_wrap1">
|
||||
|
||||
@ -162,21 +165,23 @@
|
||||
</a>
|
||||
<a class="pull-left im_panel_own_photo" my-peer-photolink="ownID" img-class="im_panel_own_photo" watch="true" ng-click="openSettings()" no-open="true"></a>
|
||||
|
||||
<form my-send-form draft-message="draftMessage" mentions="mentions" class="im_send_form" ng-class="{im_send_form_empty: !draftMessage.text.length}">
|
||||
<form my-send-form draft-message="draftMessage" mentions="mentions" commands="commands" class="im_send_form" ng-class="{im_send_form_empty: !draftMessage.text.length}">
|
||||
|
||||
<div class="im_send_reply_wrap" ng-if="draftMessage.replyToMessage != null">
|
||||
<a class="im_send_reply_cancel" ng-click="draftMessage.replyClear()"><i class="icon icon-reply-bar"></i><i class="icon icon-reply-bar"></i></a>
|
||||
<div my-reply-message="draftMessage.replyToMessage"></div>
|
||||
<a class="im_send_reply_cancel" ng-mousedown="draftMessage.replyClear()"><i class="icon icon-reply-bar"></i><i class="icon icon-reply-bar"></i></a>
|
||||
<a class="im_message_reply_wrap" my-reply-message="draftMessage.replyToMessage" watch="true"></a>
|
||||
</div>
|
||||
|
||||
<div class="im_send_field_wrap">
|
||||
<div class="im_send_field_wrap" ng-class="historyState.replyKeyboard._ == 'replyKeyboardMarkup' ? 'im_send_field_wrap_2ndbtn' : ''">
|
||||
<a class="composer_emoji_insert_btn"><i class="icon icon-emoji"></i></a>
|
||||
<a class="composer_command_btn" ng-show="!historyState.replyKeyboard && commands.list.length > 0 && !draftMessage.text.length || draftMessage.text[0] == '/'" ng-mousedown="toggleSlash($event)" ng-class="draftMessage.text[0] == '/' ? 'active' : ''"><i class="icon icon-slash"></i></a>
|
||||
<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" placeholder="{{'im_message_field_placeholder' | i18n}}" class="form-control im_message_field no_outline" dir="auto"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="clearfix">
|
||||
<div class="im_send_buttons_wrap clearfix">
|
||||
<button type="submit" class="btn btn-md im_submit" my-i18n="im_submit_message"></button>
|
||||
|
||||
<div class="im_attach pull-left">
|
||||
@ -190,8 +195,12 @@
|
||||
</div>
|
||||
|
||||
<div class="composer_emoji_panel"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="im_send_keyboard_wrap" ng-if="historyState.replyKeyboard._ == 'replyKeyboardMarkup'" ng-show="!historyState.replyKeyboard.pFlags.hidden">
|
||||
<div my-reply-markup="historyState.replyKeyboard"></div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
@ -3,8 +3,12 @@
|
||||
|
||||
<div class="im_message_wrap clearfix" ng-switch="::historyMessage._ == 'messageService'">
|
||||
|
||||
<div class="im_service_message_wrap" ng-switch-when="true">
|
||||
<div class="im_service_message">
|
||||
<div class="im_service_message_wrap" ng-switch-when="true" ng-switch="historyMessage.action._ == 'messageActionBotIntro'">
|
||||
<div ng-switch-when="true" class="im_bot_intro_message_wrap">
|
||||
<div class="im_bot_intro_message_header" my-i18n="message_service_bot_intro_header"></div>
|
||||
<div class="im_bot_intro_message" ng-bind-html="::historyMessage.action.rDescription"></div>
|
||||
</div>
|
||||
<div ng-switch-default class="im_service_message">
|
||||
<a class="im_message_author" my-user-link="historyMessage.from_id" short="!historyMessage.to_id.chat_id" color="historyMessage.to_id.chat_id > 0" no-watch="true"></a>
|
||||
<span class="im_message_service" my-service-message></span>
|
||||
</div>
|
||||
@ -20,9 +24,7 @@
|
||||
</div>
|
||||
|
||||
<div ng-switch-default class="im_content_message_wrap" ng-class="::[historyMessage.out ? 'im_message_out' : 'im_message_in', historyMessage.fwd_from_id > 0 ? 'im_message_fwd' : '']">
|
||||
<div class="im_content_message_select_area">
|
||||
<i class="icon icon-select-tick"></i>
|
||||
</div>
|
||||
<i class="icon icon-select-tick"></i>
|
||||
|
||||
<a class="im_message_error_btn" ng-if="::historyMessage.pending || historyMessage.error || false" ng-click="historyMessage.send()">
|
||||
<i class="icon-message-status" tooltip="Try again"></i>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<div ng-switch-when="gif" my-load-gif document="document"></div>
|
||||
|
||||
<div ng-switch-when="sticker" my-load-sticker document="document"></div>
|
||||
<div ng-switch-when="sticker" my-load-sticker document="document" open="true"></div>
|
||||
|
||||
<div ng-switch-when="audio" class="im_message_audio">
|
||||
<div my-audio-player audio="document"></div>
|
||||
|
@ -22,12 +22,12 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="media_modal_info_wrap pull-left" ng-if="!webpageID">
|
||||
<div class="media_modal_info_wrap pull-left" ng-if="!webpageID && photo.user_id">
|
||||
<a class="media_modal_author_photo pull-left" my-peer-photolink="photo.user_id" img-class="media_modal_author_photo" watch="true"></a>
|
||||
<div class="media_modal_author_name">
|
||||
<a class="media_modal_author" my-user-link="photo.user_id" user-watch="true"></a>
|
||||
</div>
|
||||
<div class="media_modal_date" ng-switch="messageID > 0">
|
||||
<div class="media_modal_date" ng-if="photo.date > 0" ng-switch="messageID > 0">
|
||||
<a ng-switch-when="true" class="media_modal_date" ng-click="goToMessage()" ng-bind="photo.date | dateOrTime :true"></a>
|
||||
<span ng-switch-default ng-bind="photo.date | dateOrTime :true"></span>
|
||||
</div>
|
||||
|
9
app/partials/desktop/reply_markup.html
Normal file
@ -0,0 +1,9 @@
|
||||
<div class="reply_markup_wrap">
|
||||
<div class="reply_markup" ng-class="replyMarkup.splitCount ? 'reply_markup_h' + replyMarkup.splitCount : ''">
|
||||
<div class="reply_markup_row" ng-repeat="row in replyMarkup.rows">
|
||||
<div class="reply_markup_button_wrap" ng-class="'reply_markup_button_w' + row.buttons.length" ng-repeat="button in row.buttons">
|
||||
<button class="btn reply_markup_button" ng-bind-html="::button.rText" ng-click="buttonSend(button)"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -8,6 +8,7 @@
|
||||
class="im_message_reply_thumb"
|
||||
my-load-thumb
|
||||
thumb="thumb"
|
||||
watch="true"
|
||||
/>
|
||||
</div>
|
||||
<div class="im_message_reply_author" ng-switch-default>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<div class="md_modal_title_wrap">
|
||||
<div class="md_modal_actions_wrap clearfix">
|
||||
<a class="md_modal_action md_modal_action_close" ng-click="$close()" my-i18n="modal_close"></a>
|
||||
<a class="md_modal_action" ng-if="user._ == 'userContact'" ng-click="importContact(true)" my-i18n="modal_edit"></a>
|
||||
<a class="md_modal_action" ng-if="user.pFlags.contact" ng-click="importContact(true)" my-i18n="modal_edit"></a>
|
||||
</div>
|
||||
<div class="md_modal_title" my-i18n="user_modal_contact_info"></div>
|
||||
</div>
|
||||
@ -36,6 +36,13 @@
|
||||
<div class="md_modal_iconed_section_wrap md_modal_iconed_section_number" ng-if="user.phone || user.username">
|
||||
<i class="md_modal_section_icon md_modal_section_icon_phone"></i>
|
||||
|
||||
<div class="md_modal_section_param_wrap" ng-if="user.pFlags.bot && bot_info.rAbout">
|
||||
<div class="md_modal_section_param_value">
|
||||
<span ng-bind-html="bot_info.rAbout"></span>
|
||||
</div>
|
||||
<div class="md_modal_section_param_name" my-i18n="user_modal_about"></div>
|
||||
</div>
|
||||
|
||||
<div class="md_modal_section_param_wrap" ng-if="user.phone">
|
||||
<div class="md_modal_section_param_value" ng-bind="user.phone | phoneNumber"></div>
|
||||
<div class="md_modal_section_param_name" my-i18n="user_modal_phone"></div>
|
||||
@ -62,7 +69,19 @@
|
||||
<div class="md_modal_iconed_section_wrap md_modal_iconed_section_link" ng-init="f.showMoreActions = !user.phone.length">
|
||||
<i class="md_modal_section_icon md_modal_section_icon_more"></i>
|
||||
|
||||
<div class="md_modal_section_link_wrap" ng-if="user.phone.length > 0 && user._ != 'userContact' && user._ != 'userSelf'">
|
||||
<div class="md_modal_section_link_wrap" ng-if="user.pFlags.bot && !user.pFlags.botNoGroups">
|
||||
<a class="md_modal_section_link" ng-click="inviteToGroup()" my-i18n="user_modal_add_to_group"></a>
|
||||
</div>
|
||||
|
||||
<div class="md_modal_section_link_wrap" ng-if="bot_info.commands.settings != null">
|
||||
<a class="md_modal_section_link" ng-click="sendCommand('settings')" my-i18n="user_modal_bot_settings"></a>
|
||||
</div>
|
||||
|
||||
<div class="md_modal_section_link_wrap" ng-if="bot_info.commands.help != null">
|
||||
<a class="md_modal_section_link" ng-click="sendCommand('help')" my-i18n="user_modal_bot_help"></a>
|
||||
</div>
|
||||
|
||||
<div class="md_modal_section_link_wrap" ng-if="user.phone.length > 0 && !user.pFlags.contact && !user.pFlags.self">
|
||||
<a class="md_modal_section_link" ng-click="importContact()" my-i18n="user_modal_add_contact"></a>
|
||||
</div>
|
||||
|
||||
@ -70,12 +89,12 @@
|
||||
<a class="md_modal_section_link" ng-click="shareContact()" my-i18n="user_modal_share_contact"></a>
|
||||
</div>
|
||||
|
||||
<div class="md_modal_section_link_wrap" ng-if="f.showMoreActions && user._ == 'userContact'">
|
||||
<div class="md_modal_section_link_wrap" ng-if="f.showMoreActions && user.pFlags.contact">
|
||||
<a class="md_modal_section_link" ng-click="deleteContact()" my-i18n="user_modal_delete_contact"></a>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="md_modal_section_link_wrap" ng-if="f.showMoreActions && user._ != 'userSelf'">
|
||||
<div class="md_modal_section_link_wrap" ng-if="f.showMoreActions && !user.pFlags.self">
|
||||
<a class="md_modal_section_link" ng-click="toggleBlock(!blocked)" ng-switch="blocked">
|
||||
<my-i18n ng-switch-when="true" msgid="user_modal_unblock_user"></my-i18n>
|
||||
<my-i18n ng-switch-default msgid="user_modal_block_user"></my-i18n>
|
||||
|
@ -16,12 +16,12 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="media_modal_info_wrap pull-left" ng-switch="messageID > 0">
|
||||
<div class="media_modal_info_wrap pull-left" ng-if="video.user_id > 0" ng-switch="messageID > 0">
|
||||
<a class="media_modal_author_photo pull-left" my-peer-photolink="video.user_id" img-class="media_modal_author_photo" watch="true"></a>
|
||||
<div class="media_modal_author_name">
|
||||
<a class="media_modal_author" my-user-link="video.user_id" user-watch="true"></a>
|
||||
</div>
|
||||
<div class="media_modal_date">
|
||||
<div class="media_modal_date" ng-if="video.date > 0">
|
||||
<a ng-switch-when="true" class="media_modal_date" ng-click="goToMessage()" ng-bind="video.date | dateOrTime :true"></a>
|
||||
<span ng-switch-default ng-bind="video.date | dateOrTime :true"></span>
|
||||
</div>
|
||||
|
@ -7,8 +7,12 @@
|
||||
<span ng-switch-when="true" class="audio_player_duration" ng-bind="mediaPlayer.player.currentTime | durationRemains : (mediaPlayer.player.duration || audio.duration)"></span>
|
||||
<span ng-switch-default class="audio_player_duration" ng-bind="mediaPlayer.player.duration || audio.duration | duration"></span>
|
||||
</div>
|
||||
<a ng-click="download()" class="audio_player_title" ng-switch="::audio.file_name.length > 0">
|
||||
<span ng-switch-when="true" ng-bind="::audio.file_name"></span>
|
||||
<a ng-click="download()" class="audio_player_title" ng-switch="::audio.audioTitle.length > 0 ? 2 : (audio.file_name.length > 0 ? 1 : 0)">
|
||||
<span ng-switch-when="2">
|
||||
<strong ng-bind="::audio.audioPerformer"></strong>
|
||||
<span ng-bind="::(audio.audioPerformer ? '– ' : '') + audio.audioTitle"></span>
|
||||
</span>
|
||||
<span ng-switch-when="1" ng-bind="::audio.file_name"></span>
|
||||
<span ng-switch-default my-i18n="message_attach_audio_message"></span>
|
||||
</a>
|
||||
<div class="audio_player_meta" ng-if="!audio.downloaded || !(mediaPlayer.player.duration || audio.duration)" ng-switch="audio.progress.enabled">
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<div ng-switch-when="gif" my-load-gif document="document"></div>
|
||||
|
||||
<div ng-switch-when="sticker" my-load-sticker document="document"></div>
|
||||
<div ng-switch-when="sticker" my-load-sticker document="document" open="true"></div>
|
||||
|
||||
<div ng-switch-when="audio" class="im_message_audio">
|
||||
<div my-audio-player audio="document"></div>
|
||||
|
@ -12,7 +12,7 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="media_modal_info_wrap">
|
||||
<div class="media_modal_info_wrap" ng-if="photo.user_id > 0">
|
||||
<a class="media_modal_author" my-user-link="photo.user_id" user-watch="true"></a>
|
||||
<br/>
|
||||
<span class="media_modal_date" ng-bind="photo.date | dateOrTime :true"></span>
|
||||
|
@ -11,13 +11,13 @@
|
||||
<span class="icon-bar"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-if="user._ == 'userContact'">
|
||||
<li ng-if="user.pFlags.contact">
|
||||
<a ng-click="importContact(true)" my-i18n="user_modal_edit_contact"></a>
|
||||
</li>
|
||||
<li ng-if="user._ == 'userContact'">
|
||||
<li ng-if="user.pFlags.contact">
|
||||
<a ng-click="deleteContact()" my-i18n="user_modal_delete_contact"></a>
|
||||
</li>
|
||||
<li ng-if="user.phone.length > 0 && user._ != 'userContact' && user._ != 'userSelf'">
|
||||
<li ng-if="user.phone.length > 0 && !user.pFlags.contact && !user.pFlags.self">
|
||||
<a ng-click="importContact()" my-i18n="user_modal_add_contact"></a>
|
||||
</li>
|
||||
<li>
|
||||
|
@ -12,7 +12,7 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="media_modal_info_wrap">
|
||||
<div class="media_modal_info_wrap" ng-if="video.user_id > 0">
|
||||
<a class="media_modal_author" my-user-link="video.user_id" user-watch="true"></a>
|
||||
<br/>
|
||||
<span class="media_modal_date" ng-bind="video.date | dateOrTime :true"></span>
|
||||
|
@ -743,6 +743,7 @@
|
||||
} else {
|
||||
this.slider.show();
|
||||
}
|
||||
this.$el.toggleClass('active-scrollbar', this.isActive);
|
||||
this.pane.css({
|
||||
opacity: (this.options.alwaysVisible ? 1 : ''),
|
||||
visibility: (this.options.alwaysVisible ? 'visible' : '')
|
||||
|
10321
app/vendor/libwebpjs/libwebp-0.1.13.js
vendored
Normal file
4079
app/vendor/libwebpjs/libwebp-0.2.0.js
vendored
Normal file
@ -1,6 +1,6 @@
|
||||
CACHE MANIFEST
|
||||
|
||||
# 61
|
||||
# 62
|
||||
|
||||
NETWORK:
|
||||
*
|
||||
|