From 847b7df54e2b56b86292de68ee85aeaae56e1ed1 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Wed, 12 Nov 2014 20:06:35 +0300 Subject: [PATCH] IE10+ fixes Textfield height Unsupported media modal Download blobs --- app/css/app.css | 6 +- app/js/controllers.js | 2 +- app/js/directives.js | 103 ++++++++++++++++++++++---- app/js/lib/mtproto_wrapper.js | 16 ++-- app/js/lib/ng_utils.js | 22 ++++-- app/js/locales/en-us.json | 2 + app/js/services.js | 41 +++++----- app/partials/desktop/error_modal.html | 2 + 8 files changed, 141 insertions(+), 53 deletions(-) diff --git a/app/css/app.css b/app/css/app.css index 7397619b..a0d8f423 100644 --- a/app/css/app.css +++ b/app/css/app.css @@ -1963,12 +1963,14 @@ img.img_fullsize { } .emoji-wysiwyg-editor { + box-sizing: content-box; font-size: 12px; margin-bottom: 10px; padding: 6px; - min-height: 50px; + min-height: 34px; height: auto; - max-height: 300px; + width: auto; + max-height: 284px; overflow: auto; line-height: 17px; diff --git a/app/js/controllers.js b/app/js/controllers.js index afd351c5..8471c4d9 100644 --- a/app/js/controllers.js +++ b/app/js/controllers.js @@ -1791,7 +1791,7 @@ angular.module('myApp.controllers', ['myApp.i18n']) }; $scope.download = function () { - $rootScope.downloadVideo($scope.videoID) + AppVideoManager.saveVideoFile($scope.videoID); }; $scope.$on('history_delete', function (e, historyUpdate) { diff --git a/app/js/directives.js b/app/js/directives.js index 6d75cf97..d2422419 100644 --- a/app/js/directives.js +++ b/app/js/directives.js @@ -1270,7 +1270,7 @@ angular.module('myApp.directives', ['myApp.filters']) } }) - .directive('myLoadThumb', function(MtpApiFileManager) { + .directive('myLoadThumb', function(MtpApiFileManager, FileManager) { return { link: link, @@ -1282,15 +1282,15 @@ angular.module('myApp.directives', ['myApp.filters']) function link ($scope, element, attrs) { var counter = 0; - var cachedSrc = MtpApiFileManager.getCachedFile( + var cachedBlob = MtpApiFileManager.getCachedFile( $scope.thumb && $scope.thumb.location && !$scope.thumb.location.empty && $scope.thumb.location ); - if (cachedSrc) { - element.attr('src', cachedSrc); + if (cachedBlob) { + element.attr('src', FileManager.getUrl(cachedBlob, 'image/jpeg')); } if ($scope.thumb && $scope.thumb.width && $scope.thumb.height) { element.attr('width', $scope.thumb.width); @@ -1311,9 +1311,9 @@ angular.module('myApp.directives', ['myApp.filters']) return; } - var cachedSrc = MtpApiFileManager.getCachedFile(newLocation); - if (cachedSrc) { - element.attr('src', cachedSrc); + var cachedBlob = MtpApiFileManager.getCachedFile(newLocation); + if (cachedBlob) { + element.attr('src', FileManager.getUrl(cachedBlob, 'image/jpeg')); cleanup(); return; } @@ -1322,9 +1322,9 @@ angular.module('myApp.directives', ['myApp.filters']) element.attr('src', $scope.thumb.placeholder || 'img/blank.gif'); } - MtpApiFileManager.downloadSmallFile($scope.thumb.location).then(function (url) { + MtpApiFileManager.downloadSmallFile($scope.thumb.location).then(function (blob) { if (counterSaved == counter) { - element.attr('src', url); + element.attr('src', FileManager.getUrl(blob, 'image/jpeg')); cleanup(); } }, function (e) { @@ -1348,7 +1348,7 @@ angular.module('myApp.directives', ['myApp.filters']) }) - .directive('myLoadFullPhoto', function(MtpApiFileManager, _) { + .directive('myLoadFullPhoto', function(MtpApiFileManager, FileManager, _) { return { link: link, @@ -1402,10 +1402,10 @@ angular.module('myApp.directives', ['myApp.filters']) $scope.progress = {enabled: true, percent: 0}; - apiPromise.then(function (url) { + apiPromise.then(function (blob) { if (curJump == jump) { $scope.progress.enabled = false; - imgElement.src = url; + imgElement.src = FileManager.getUrl(blob, 'image/jpeg'); resize(); } }, function (e) { @@ -1431,7 +1431,7 @@ angular.module('myApp.directives', ['myApp.filters']) }) - .directive('myLoadVideo', function($sce, AppVideoManager, _) { + .directive('myLoadVideo', function($sce, AppVideoManager, ErrorService, _) { return { link: link, @@ -1448,6 +1448,35 @@ angular.module('myApp.directives', ['myApp.filters']) downloadPromise.then(function () { $scope.$emit('ui_height'); + onContentLoaded(function () { + var videoEl = $('video', element)[0]; + if (videoEl) { + var errorAlready = false; + var onVideoError = function (event) { + if (errorAlready) { + return; + } + if (!event.target || + !event.target.error || + event.target.error.code == event.target.error.MEDIA_ERR_DECODE || + event.target.error.code == event.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED) { + errorAlready = true; + ErrorService.show({ + error: { + type: 'MEDIA_TYPE_NOT_SUPPORTED', + originalError: event.target && event.target.error + } + }); + } + }; + + videoEl.addEventListener('error', onVideoError, true); + $(videoEl).on('$destroy', function () { + errorAlready = true; + videoEl.removeEventListener('error', onVideoError); + }); + } + }); }, function (e) { console.log('Download video failed', e, $scope.video); @@ -1516,7 +1545,7 @@ angular.module('myApp.directives', ['myApp.filters']) } }) - .directive('myLoadDocument', function(MtpApiFileManager, AppDocsManager) { + .directive('myLoadDocument', function(MtpApiFileManager, AppDocsManager, FileManager) { return { link: link, @@ -1567,7 +1596,8 @@ angular.module('myApp.directives', ['myApp.filters']) var checkSizesInt; var realImageWidth, realImageHeight; - AppDocsManager.downloadDoc($scope.document.id).then(function (url) { + AppDocsManager.downloadDoc($scope.document.id).then(function (blob) { + var url = FileManager.getUrl(blob, $scope.document.mime_type); var image = new Image(); var limit = 100; // 2 sec var checkSizes = function (e) { @@ -2012,7 +2042,7 @@ angular.module('myApp.directives', ['myApp.filters']) } }) - .directive('myAudioPlayer', function ($timeout, $q, Storage, AppAudioManager, AppDocsManager) { + .directive('myAudioPlayer', function ($timeout, $q, Storage, AppAudioManager, AppDocsManager, ErrorService) { var currentPlayer = false; var audioVolume = 0.5; @@ -2023,6 +2053,20 @@ angular.module('myApp.directives', ['myApp.filters']) } }); + var onAudioError = function (event) { + if (!event.target || + !event.target.error || + event.target.error.code == event.target.error.MEDIA_ERR_DECODE || + event.target.error.code == event.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED) { + ErrorService.show({ + error: { + type: 'MEDIA_TYPE_NOT_SUPPORTED', + originalError: event.target && event.target.error + } + }); + } + }; + return { link: link, scope: { @@ -2077,6 +2121,33 @@ angular.module('myApp.directives', ['myApp.filters']) downloadPromise.then(function () { onContentLoaded(function () { + var audioEl = $('audio', element)[0]; + if (audioEl) { + var errorAlready = false; + var onAudioError = function (event) { + if (errorAlready) { + return; + } + if (!event.target || + !event.target.error || + event.target.error.code == event.target.error.MEDIA_ERR_DECODE || + event.target.error.code == event.target.error.MEDIA_ERR_SRC_NOT_SUPPORTED) { + errorAlready = true; + ErrorService.show({ + error: { + type: 'MEDIA_TYPE_NOT_SUPPORTED', + originalError: event.target && event.target.error + } + }); + } + }; + + audioEl.addEventListener('error', onAudioError, true); + $(audioEl).on('$destroy', function () { + errorAlready = true; + audioEl.removeEventListener('error', onAudioError); + }); + } checkPlayer($scope.mediaPlayer.player); $scope.mediaPlayer.player.setVolume(audioVolume); $scope.mediaPlayer.player.play(); diff --git a/app/js/lib/mtproto_wrapper.js b/app/js/lib/mtproto_wrapper.js index 2f9b57a7..85bc59eb 100644 --- a/app/js/lib/mtproto_wrapper.js +++ b/app/js/lib/mtproto_wrapper.js @@ -328,7 +328,7 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto']) if (!cachedSavePromises[fileName]) { cachedSavePromises[fileName] = getFileStorage().saveFile(fileName, bytes).then(function (blob) { - return cachedDownloads[fileName] = FileManager.getUrl(blob, mimeType); + return cachedDownloads[fileName] = blob; }); } return cachedSavePromises[fileName]; @@ -350,7 +350,7 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto']) var fileStorage = getFileStorage(); return cachedDownloadPromises[fileName] = fileStorage.getFile(fileName).then(function (blob) { - return cachedDownloads[fileName] = FileManager.getUrl(blob, mimeType); + return cachedDownloads[fileName] = blob; }, function () { var downloadPromise = downloadRequest(location.dc_id, function () { // console.log('next small promise'); @@ -368,7 +368,7 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto']) return fileStorage.getFileWriter(fileName, mimeType).then(function (fileWriter) { return downloadPromise.then(function (result) { return FileManager.write(fileWriter, result.bytes).then(function () { - return cachedDownloads[fileName] = FileManager.getUrl(fileWriter.finalize(), mimeType); + return cachedDownloads[fileName] = fileWriter.finalize(); }); }); }); @@ -400,10 +400,8 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto']) if (cachedPromise) { if (toFileEntry) { - return cachedPromise.then(function (url) { - return fileStorage.getFile(fileName).then(function (blob) { - return FileManager.copy(blob, toFileEntry); - }); + return cachedPromise.then(function (blob) { + return FileManager.copy(blob, toFileEntry); }) } return cachedPromise; @@ -430,7 +428,7 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto']) deferred.resolve(); }, errorHandler); } else { - deferred.resolve(cachedDownloads[fileName] = FileManager.getUrl(blob, mimeType)); + deferred.resolve(cachedDownloads[fileName] = blob); } }, function () { var fileWriterPromise = toFileEntry ? FileManager.getFileWriter(toFileEntry) : fileStorage.getFileWriter(fileName, mimeType); @@ -476,7 +474,7 @@ angular.module('izhukov.mtproto.wrapper', ['izhukov.utils', 'izhukov.mtproto']) if (toFileEntry) { deferred.resolve(); } else { - deferred.resolve(cachedDownloads[fileName] = FileManager.getUrl(fileWriter.finalize(), mimeType)); + deferred.resolve(cachedDownloads[fileName] = fileWriter.finalize()); } } else { deferred.notify({done: offset + limit, total: size}); diff --git a/app/js/lib/ng_utils.js b/app/js/lib/ng_utils.js index 710d9158..0ff18629 100644 --- a/app/js/lib/ng_utils.js +++ b/app/js/lib/ng_utils.js @@ -182,11 +182,13 @@ angular.module('izhukov.utils', []) return 'data:' + mimeType + ';base64,' + bytesToBase64(fileData); } - function downloadFile (url, mimeType, fileName) { - // if (Config.Mobile) { - // window.open(url, '_blank'); - // return; - // } + function downloadFile (blob, mimeType, fileName) { + if (window.navigator && navigator.msSaveBlob !== undefined) { + window.navigator.msSaveBlob(blob, fileName); + } + + var url = getUrl(blob, mimeType); + var anchor = $('Download') .css({position: 'absolute', top: 1, left: 1}) .attr('href', url) @@ -194,8 +196,14 @@ angular.module('izhukov.utils', []) .attr('download', fileName) .appendTo('body'); - anchor[0].dataset.downloadurl = [mimeType, fileName, url].join(':'); - anchor[0].click(); + if (anchor[0].dataset) { + anchor[0].dataset.downloadurl = [mimeType, fileName, url].join(':'); + } + try { + anchor[0].click(); + } catch (e) { + window.open(url, '_blank'); + } $timeout(function () { anchor.remove(); }, 100); diff --git a/app/js/locales/en-us.json b/app/js/locales/en-us.json index 8ace5986..36f40fbc 100644 --- a/app/js/locales/en-us.json +++ b/app/js/locales/en-us.json @@ -204,6 +204,7 @@ "error_modal_flood_title": "Too fast", "error_modal_internal_title": "Server error", "error_modal_alert": "Alert", + "error_modal_media_not_supported_title": "Unsupported media", "error_modal_network_description": "Please check your internet connection.", "error_modal_firstname_invali_description": "The first name you entered is invalid.", @@ -218,6 +219,7 @@ "error_modal_username_invalid_description": "Sorry, this username is not allowed.", "error_modal_phonebook_required_description": "Telegram needs access to phonebook to import contacts.", "error_modal_username_occupied_description": "Sorry, this username is already taken.", + "error_modal_media_not_supported_description": "Your browser cannot play this media file. Try downloading the file and opening it in a standalone player.", "error_modal_bad_request_description": "One of the params is missing or invalid.", "error_modal_unauthorized_description": "This action requires authorization access. Please {login-link: log in}.", diff --git a/app/js/services.js b/app/js/services.js index 7b77e75f..a1aae2cf 100644 --- a/app/js/services.js +++ b/app/js/services.js @@ -602,7 +602,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) } }) -.service('AppMessagesManager', function ($q, $rootScope, $location, $filter, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, SearchIndexManager, PeersSelectService,Storage, _) { +.service('AppMessagesManager', function ($q, $rootScope, $location, $filter, ApiUpdatesManager, AppUsersManager, AppChatsManager, AppPeersManager, AppPhotosManager, AppVideoManager, AppDocsManager, AppAudioManager, MtpApiManager, MtpApiFileManager, RichTextProcessor, NotificationsManager, SearchIndexManager, PeersSelectService,Storage, FileManager, _) { var messagesStorage = {}; var messagesForHistory = {}; @@ -1883,8 +1883,8 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) notification.tag = peerString; if (notificationPhoto.location && !notificationPhoto.location.empty) { - MtpApiFileManager.downloadSmallFile(notificationPhoto.location, notificationPhoto.size).then(function (url) { - notification.image = url; + MtpApiFileManager.downloadSmallFile(notificationPhoto.location, notificationPhoto.size).then(function (blob) { + notification.image = FileManager.getUrl(blob, 'image/jpeg'); if (message.unread) { NotificationsManager.notify(notification); @@ -2337,7 +2337,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) fullPhotoSize.location.dc_id, inputFileLocation, fullPhotoSize.size, { mime: mimeType, toFileEntry: writableFileEntry - }).then(function (url) { + }).then(function () { // console.log('file save done'); }, function (e) { console.log('photo download failed', e); @@ -2346,8 +2346,8 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) }, function () { MtpApiFileManager.downloadFile( fullPhotoSize.location.dc_id, inputFileLocation, fullPhotoSize.size, {mime: mimeType} - ).then(function (url) { - FileManager.download(url, mimeType, fileName); + ).then(function (blob) { + FileManager.download(blob, mimeType, fileName); }, function (e) { console.log('photo download failed', e); }); @@ -2487,6 +2487,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) function downloadVideo (videoID, toFileEntry) { var video = videos[videoID], historyVideo = videosForHistory[videoID] || video || {}, + mimeType = video.mime_type || 'video/ogg', inputFileLocation = { _: 'inputVideoFileLocation', id: videoID, @@ -2496,11 +2497,12 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) historyVideo.progress = {enabled: !historyVideo.downloaded, percent: 1, total: video.size}; var downloadPromise = MtpApiFileManager.downloadFile(video.dc_id, inputFileLocation, video.size, { - mime: video.mime_type || 'video/ogg', + mime: mimeType, toFileEntry: toFileEntry }); - downloadPromise.then(function (url) { + downloadPromise.then(function (blob) { + var url = FileManager.getUrl(blob, mimeType); delete historyVideo.progress; historyVideo.url = $sce.trustAsResourceUrl(url); historyVideo.downloaded = true; @@ -2533,8 +2535,8 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) downloadVideo(videoID, writableFileEntry); } }, function () { - downloadVideo(videoID).then(function (url) { - FileManager.download(url, mimeType, fileName); + downloadVideo(videoID).then(function (blob) { + FileManager.download(blob, mimeType, fileName); }); }); } @@ -2606,7 +2608,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) doc.thumb = thumb; doc.canDownload = !(window.chrome && chrome.fileSystem && chrome.fileSystem.chooseEntry); - doc.withPreview = doc.canDownload && doc.mime_type.match(/^(image\/|application\/pdf)/) ? 1 : 0; + doc.withPreview = doc.canDownload && doc.mime_type.match(/^(image\/)/) ? 1 : 0; if (isGif && doc.thumb) { doc.isSpecial = 'gif'; @@ -2654,7 +2656,8 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) toFileEntry: toFileEntry }); - downloadPromise.then(function (url) { + downloadPromise.then(function (blob) { + var url = FileManager.getUrl(blob, doc.mime_type); delete historyDoc.progress; historyDoc.url = $sce.trustAsResourceUrl(url); historyDoc.downloaded = true; @@ -2698,8 +2701,8 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) downloadDoc(docID, writableFileEntry); } }, function () { - downloadDoc(docID).then(function (url) { - FileManager.download(url, doc.mime_type, doc.file_name); + downloadDoc(docID).then(function (blob) { + FileManager.download(blob, doc.mime_type, doc.file_name); }); }); } @@ -2755,6 +2758,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) function downloadAudio (audioID, toFileEntry) { var audio = audios[audioID], historyAudio = audiosForHistory[audioID] || audio || {}, + mimeType = audio.mime_type || 'audio/ogg', inputFileLocation = { _: 'inputAudioFileLocation', id: audioID, @@ -2764,11 +2768,12 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) historyAudio.progress = {enabled: !historyAudio.downloaded, percent: 1, total: audio.size}; var downloadPromise = MtpApiFileManager.downloadFile(audio.dc_id, inputFileLocation, audio.size, { - mime: audio.mime_type || 'audio/ogg', + mime: mimeType, toFileEntry: toFileEntry }); - downloadPromise.then(function (url) { + downloadPromise.then(function (blob) { + var url = FileManager.getUrl(blob, mimeType); delete historyAudio.progress; historyAudio.url = $sce.trustAsResourceUrl(url); historyAudio.downloaded = true; @@ -2801,8 +2806,8 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) downloadAudio(audioID, writableFileEntry); } }, function () { - downloadAudio(audioID).then(function (url) { - FileManager.download(url, mimeType, fileName); + downloadAudio(audioID).then(function (blob) { + FileManager.download(blob, mimeType, fileName); }); }); } diff --git a/app/partials/desktop/error_modal.html b/app/partials/desktop/error_modal.html index c3f2ca78..11886535 100644 --- a/app/partials/desktop/error_modal.html +++ b/app/partials/desktop/error_modal.html @@ -5,6 +5,7 @@