From a6e5aa9e4043fbee9aa04b9a3aeeeaa9baabd8c8 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Wed, 9 Apr 2014 22:31:19 +0200 Subject: [PATCH] Implement #225 - shared photos navigation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also fixed fetching Vector<…> results --- app/css/app.css | 47 +++++- app/img/icons/CloseHover_1x.png | Bin 789 -> 0 bytes app/img/icons/CloseHover_2x.png | Bin 1496 -> 0 bytes app/img/icons/Close_1x.png | Bin 783 -> 0 bytes app/img/icons/Close_2x.png | Bin 1515 -> 0 bytes app/img/icons/PhotoControls.png | Bin 0 -> 2411 bytes app/img/icons/PhotoControls_1x.png | Bin 0 -> 1255 bytes app/js/controllers.js | 122 +++++++++++++- app/js/directives.js | 153 ++++++++++++------ app/js/lib/mtproto.js | 52 +++++- app/js/services.js | 57 ++++++- app/partials/confirm_modal.html | 6 +- app/partials/message.html | 2 +- app/partials/photo_modal.html | 13 +- app/partials/video_modal.html | 9 +- .../ui-bootstrap-custom-tpls-0.10.0.js | 7 +- webogram.sublime-project | 2 +- 17 files changed, 397 insertions(+), 73 deletions(-) delete mode 100755 app/img/icons/CloseHover_1x.png delete mode 100755 app/img/icons/CloseHover_2x.png delete mode 100755 app/img/icons/Close_1x.png delete mode 100755 app/img/icons/Close_2x.png create mode 100644 app/img/icons/PhotoControls.png create mode 100644 app/img/icons/PhotoControls_1x.png diff --git a/app/css/app.css b/app/css/app.css index 67f66afc..c987b565 100644 --- a/app/css/app.css +++ b/app/css/app.css @@ -339,13 +339,13 @@ input[type="number"]::-webkit-inner-spin-button { height: 100%; } .modal_close { - background: url(../img/icons/CloseHover_2x.png) 0 0 no-repeat; - background-size: 33px 33px; + background: url(../img/icons/PhotoControls.png) 0 -53px no-repeat; + background-size: 33px 86px; width: 33px; height: 33px; float: right; margin: 60px 30px 0 0; - opacity: 0.5; + opacity: 0.6; pointer-events: none; -webkit-transition : .2s; @@ -354,7 +354,40 @@ input[type="number"]::-webkit-inner-spin-button { transition : .2s; } .modal_close_wrap:hover .modal_close { - opacity: 1; + opacity: 0.85; +} + + +.modal_prev_wrap { + cursor: pointer; + position: fixed; + top: 0; + left: 0; + width: 50%; + height: 100%; +} +.modal_prev { + background: url(../img/icons/PhotoControls.png) 0 0 no-repeat; + background-size: 33px 86px; + width: 33px; + height: 33px; + float: left; + margin: 60px 0 0 30px; + opacity: 0.6; + pointer-events: none; + + -webkit-transition : .2s; + -moz-transition : .2s; + -o-transition : .2s; + transition : .2s; +} +.modal_prev_wrap:hover .modal_prev { + opacity: 0.85; +} + +.is_1x .modal_close, +.is_1x .modal_prev { + background-image: url(../img/icons/PhotoControls_1x.png); } .text-invisible { @@ -1849,6 +1882,12 @@ img.img_fullsize { color: #777; margin: 20px 0 0; } +.media_modal_actions { + margin-top: 20px; +} +.media_modal_action_link { + margin-left: 15px; +} .media_modal_author { font-weight: bold; } diff --git a/app/img/icons/CloseHover_1x.png b/app/img/icons/CloseHover_1x.png deleted file mode 100755 index 3f319431a52666606976c30baf14428b298650bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 789 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 diff --git a/app/img/icons/Close_2x.png b/app/img/icons/Close_2x.png deleted file mode 100755 index 1a892be1dd5019f6fbbd5526872994c85ea9c46c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1515 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

y*uXt^2CU z&VUXz0abkGnap6ehQ%&da)(X5(BQj%$;T)0#UW>wNE$qa9J|3)4G9Ukglct#yO5uA z(y$f+%SZRK}$b=3+F-*{SD+A|CSz;Plol9u-PZKHsW z>55?cgE+)8Y5vjsM~Z2ufrA-O42j;O=W$pWF><;Vfk2oQ6`?AfK-q*nEc1xgKVSdM3MazFc7;t1o|>EcH$FaIP$k z_KdV{6*q14gN;6>F?hzDa2R>5Z)>lLa1#i_(y#KFd6$yITS0BDN6~ z7;3=8A;IP7{T>`(Vx+qCRw~{vVC3Wb<0nqoEr?*Hq~&A(v&mY_Z^AH!|IHy!QR?dI znDZ$`@z-kuSSlJCozzAAG>|vinjhOTWl%i*Z6lIMoL^X5Te}(%5a4J9*IYjG5Rs#L z^5jX#h?e@~);>qJU#ipRH6UoM|BU_Pbienb{TUFvY(Q01XtW!LH#aMIH#`2W>;61G*m zS{IKC$A)B$l$c#GUeJH|iAM~Xvaf%5zr*b7_ki5+Q^ z6>>s*nbx5nkOx|TrlD^<9s2!#!KU;NDQq^Ih?k>KA(Ws4*af{oU(;F_szLxD7cZxw zM8SA0La)%LTNeak4|EpF70e0xRl@)o;f1h67udX;9g|SMKXATfAY!4576C}{0SqtH zAkLdO1#0mUAn)WL@}LSKJh1~k1PCo@K@7MNON{o|*4B1vbab@AZnuk^P3XF^z&|LC zv7}=NpsA^;p|G&9xV5$QgpQ^eNC5|>=^$N!;*A1`q8QuL)AOjhy85xsE0~ygEs|GdISKZ+hH+=?FsuL03gK%k?fBk07W7}#6=K*!XdI8p&9k{_2&q{ z>-Bn?o16PhOkASK4kMaTTU&e2?RL+_$Hyo2_4QpZDk@4a31W*Nd^}eoBW_eyR^B3z z@l*8cGE$3D4O$H4gz)QW8NQZoLfsGnm3b;Vfn{-?KWLdwQ7S=S-jJ&D zzb-~Fkd%Pu6Hb;!!Zafea_fb##E64Ncp)q|;uw@7L|BYC=!F_Y*o-*nog75ijW}A; z1i@v*RaI4`W@TmB^?Zv)8+}F`b=KY8eRFVdu#p#}uC6XkYLk+ZqU0iEKnEoVnvw#g z4#&pE);u1M8vuDcAOz6W)pf(^bS6$sO-(N^FK?+_ULZlJ8ga9;vzsL)CAa71=00nI z1Of~U3_L3qd`28?V7!S)4n$=G+szSNMjUNmtE;O^ zym=rHL}LT{W5h{^8hX8~l)~xPXzYeY+KdaoO_<0Uadc0}oiW2^#6dG^M}EtVIOx4r z-C?N_$7&DmGSGA*j@75SYf;mTIF^_~dNg3zh=aUlKcC<-;*=_IC5T@F3;;Ny5Zk9+ Rph5ru002ovPDHLkV1j#`CsP0b literal 0 HcmV?d00001 diff --git a/app/js/controllers.js b/app/js/controllers.js index a7063577..1ae73404 100644 --- a/app/js/controllers.js +++ b/app/js/controllers.js @@ -866,8 +866,128 @@ angular.module('myApp.controllers', []) } }) - .controller('PhotoModalController', function ($scope, AppPhotosManager) { + .controller('PhotoModalController', function ($q, $scope, $rootScope, $modalInstance, AppPhotosManager, AppMessagesManager, AppPeersManager, PeersSelectService, ErrorService) { + $scope.photo = AppPhotosManager.wrapForFull($scope.photoID); + $scope.nav = {}; + + var peerID = AppMessagesManager.getMessagePeer(AppMessagesManager.getMessage($scope.messageID)), + inputPeer = AppPeersManager.getInputPeerByID(peerID), + inputQuery = '', + inputFilter = {_: 'inputMessagesFilterPhotos'}, + list = [$scope.messageID], + maxID = $scope.messageID, + hasMore = true; + + updatePrevNext(); + + AppMessagesManager.getSearch(inputPeer, inputQuery, inputFilter, 0, 1000).then(function (searchCachedResult) { + // console.log(dT(), 'search cache', searchCachedResult); + if (searchCachedResult.history.indexOf($scope.messageID) >= 0) { + list = searchCachedResult.history; + maxID = list[list.length - 1]; + + updatePrevNext(); + } + // console.log(dT(), list, maxID); + }); + + + var jump = 0; + function movePosition (sign) { + var curIndex = list.indexOf($scope.messageID), + index = curIndex >= 0 ? curIndex + sign : 0, + curJump = ++jump; + + var promise = index >= list.length ? loadMore() : $q.when(); + promise.then(function () { + if (curJump != jump) { + return; + } + + $scope.messageID = list[index]; + $scope.photoID = AppMessagesManager.getMessage($scope.messageID).media.photo.id; + $scope.photo = AppPhotosManager.wrapForFull($scope.photoID); + + updatePrevNext(); + }); + }; + + var loadingPromise = false; + function loadMore () { + if (loadingPromise) return loadingPromise; + + return loadingPromise = AppMessagesManager.getSearch(inputPeer, inputQuery, inputFilter, maxID).then(function (searchResult) { + maxID = searchResult.history[searchResult.history.length - 1]; + list = list.concat(searchResult.history); + + hasMore = searchResult.history.length || list.length < searchResult.count; + updatePrevNext(); + loadingPromise = false; + }); + }; + + function updatePrevNext () { + var index = list.indexOf($scope.messageID); + $scope.nav.hasNext = hasMore || index < list.length - 1; + $scope.nav.hasPrev = index > 0; + }; + + $scope.nav.next = function () { + if (!$scope.nav.hasNext) { + return false; + } + + movePosition(+1); + }; + + $scope.nav.prev = function () { + if (!$scope.nav.hasPrev) { + return false; + } + movePosition(-1); + }; + + $scope.forward = function () { + var messageID = $scope.messageID; + PeersSelectService.selectPeer().then(function (peerString) { + var peerID = AppPeersManager.getPeerID(peerString); + AppMessagesManager.forwardMessages(peerID, [messageID]).then(function () { + $rootScope.$broadcast('history_focus', {peerString: peerString}); + }); + }); + }; + + $scope.delete = function () { + var messageID = $scope.messageID; + ErrorService.confirm({type: 'MESSAGE_DELETE'}).then(function () { + AppMessagesManager.deleteMessages([messageID]); + }); + }; + + + $scope.$on('history_delete', function (e, historyUpdate) { + console.log(dT(), 'delete', historyUpdate); + if (historyUpdate.peerID == peerID) { + if (historyUpdate.msgs[$scope.messageID]) { + if ($scope.nav.hasNext) { + $scope.nav.next(); + } else if ($scope.nav.hasPrev) { + $scope.nav.prev(); + } else { + return $modalInstance.dismiss(); + } + } + var newList = []; + for (var i = 0; i < list.length; i++) { + if (!historyUpdate.msgs[list[i]]) { + newList.push(list[i]); + } + }; + list = newList; + } + }); + }) .controller('VideoModalController', function ($scope, AppVideoManager) { diff --git a/app/js/directives.js b/app/js/directives.js index 601a4925..81d1a3a1 100644 --- a/app/js/directives.js +++ b/app/js/directives.js @@ -683,19 +683,18 @@ angular.module('myApp.directives', ['myApp.filters']) link: link, transclude: true, template: - '

\ + '
\
\ -
\ -
\ -
\ - {{progress.percent}}% Complete (success)\ +
\ +
\ +
\
\
\
\
\ \
\ @@ -711,53 +710,68 @@ angular.module('myApp.directives', ['myApp.filters']) function link ($scope, element, attrs) { - var imgElement = $('img', element); + var imgElement = $('img', element)[0], + resizeElements = $('.img_fullsize_with_progress_wrap', element) + .add('.img_fullsize_progress_wrap', element) + .add($(imgElement)), + resize = function () { + resizeElements.css({width: $scope.fullPhoto.width, height: $scope.fullPhoto.height}); + $scope.$emit('ui_height'); + }; - imgElement - .attr('src', MtpApiFileManager.getCachedFile($scope.thumbLocation) || 'img/blank.gif') - .addClass('thumb_blurred') - .addClass('thumb_blur_animation'); + var jump = 0; + $scope.$watchCollection('fullPhoto.location', function () { + var cachedSrc = MtpApiFileManager.getCachedFile($scope.thumbLocation), + curJump = ++jump; - if (!$scope.fullPhoto.location) { - return; - } + if (cachedSrc) { + imgElement.src = cachedSrc; + resize(); + } else { + imgElement.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; + } + if (!$scope.fullPhoto.location) { + return; + } - var apiPromise; - if ($scope.fullPhoto.size) { - var inputLocation = { - _: 'inputFileLocation', - volume_id: $scope.fullPhoto.location.volume_id, - local_id: $scope.fullPhoto.location.local_id, - secret: $scope.fullPhoto.location.secret - }; - apiPromise = MtpApiFileManager.downloadFile($scope.fullPhoto.location.dc_id, inputLocation, $scope.fullPhoto.size); - } else { - apiPromise = MtpApiFileManager.downloadSmallFile($scope.fullPhoto.location); - } + var apiPromise; + if ($scope.fullPhoto.size) { + var inputLocation = { + _: 'inputFileLocation', + volume_id: $scope.fullPhoto.location.volume_id, + local_id: $scope.fullPhoto.location.local_id, + secret: $scope.fullPhoto.location.secret + }; + apiPromise = MtpApiFileManager.downloadFile($scope.fullPhoto.location.dc_id, inputLocation, $scope.fullPhoto.size); + } else { + apiPromise = MtpApiFileManager.downloadSmallFile($scope.fullPhoto.location); + } - $scope.progress = {enabled: true, percent: 1}; + $scope.progress = {enabled: true, percent: 0}; - apiPromise.then(function (url) { - $scope.progress.enabled = false; - imgElement - .attr('src', url) - .removeClass('thumb_blurred'); + apiPromise.then(function (url) { + if (curJump == jump) { + $scope.progress.enabled = false; + imgElement.src = url; + resize(); + } + }, function (e) { + console.log('Download image failed', e, $scope.fullPhoto.location); + $scope.progress.enabled = false; - }, function (e) { - console.log('Download image failed', e, $scope.fullPhoto.location); - $scope.progress.enabled = false; + if (e && e.type == 'FS_BROWSER_UNSUPPORTED') { + $scope.error = {html: 'Your browser doesn\'t support LocalFileSystem feature which is needed to display this image.
Please, install Google Chrome or use mobile app instead.'}; + } else { + $scope.error = {text: 'Download failed', error: e}; + } + }, function (progress) { + $scope.progress.percent = Math.max(1, Math.floor(100 * progress.done / progress.total)); + }); + }) - if (e && e.type == 'FS_BROWSER_UNSUPPORTED') { - $scope.error = {html: 'Your browser doesn\'t support LocalFileSystem feature which is needed to display this image.
Please, install Google Chrome or use mobile app instead.'}; - } else { - $scope.error = {text: 'Download failed', error: e}; - } - }, function (progress) { - $scope.progress.percent = Math.max(1, Math.floor(100 * progress.done / progress.total)); - }); + resize(); } - }) @@ -771,9 +785,7 @@ angular.module('myApp.directives', ['myApp.filters'])
\
\
\ -
\ - {{progress.percent}}% Complete (success)\ -
\ +
\
\
\
\ @@ -975,6 +987,44 @@ angular.module('myApp.directives', ['myApp.filters']) }) + .directive('myModalNav', function () { + + return { + link: link + }; + + function link($scope, element, attrs) { + + var onKeyDown = function (event) { + var target = event.target; + if (target && (target.tagName == 'INPUT' || target.tagName == 'TEXTAREA')) { + return false; + } + + switch (event.keyCode) { + case 39: // right + case 32: // space + case 34: // pg down + case 40: // down + $scope.$eval(attrs.next); + break; + + case 37: // left + case 33: // pg up + case 38: // up + $scope.$eval(attrs.prev); + break; + } + }; + + $(document).on('keydown', onKeyDown); + + $scope.$on('$destroy', function () { + $(document).off('keydown', onKeyDown); + }); + }; + }) + .directive('myModalPosition', function ($window, $timeout) { @@ -993,9 +1043,12 @@ angular.module('myApp.directives', ['myApp.filters']) } else { $(element[0].parentNode).css('marginTop', ''); } - $timeout(function () { - $(element[0].parentNode).addClass('modal-content-animated'); - }, 300); + + if (attrs.animation != 'no') { + $timeout(function () { + $(element[0].parentNode).addClass('modal-content-animated'); + }, 300); + } }; onContentLoaded(updateMargin); diff --git a/app/js/lib/mtproto.js b/app/js/lib/mtproto.js index 024b6eaa..6a335219 100644 --- a/app/js/lib/mtproto.js +++ b/app/js/lib/mtproto.js @@ -638,6 +638,8 @@ TLSerialization.prototype.storeMethod = function (methodName, params) { angular.forEach(methodData.params, function (param) { self.storeObject(params[param.name], param.type, methodName + '[' + param.name + ']'); }); + + return methodData.type; }; TLSerialization.prototype.storeObject = function (obj, type, field) { @@ -707,6 +709,8 @@ TLSerialization.prototype.storeObject = function (obj, type, field) { angular.forEach(constructorData.params, function (param) { self.storeObject(obj[param.name], param.type, field + '[' + predicate + '][' + param.name + ']'); }); + + return constructorData.type; }; @@ -715,6 +719,7 @@ function TLDeserialization (buffer, options) { options = options || {}; this.offset = 0; // in bytes + this.override = options.override || {}; this.buffer = buffer; this.intView = new Uint32Array(this.buffer); @@ -961,12 +966,16 @@ TLDeserialization.prototype.fetchObject = function (type, field) { predicate = constructorData.predicate; - var result = {'_': predicate}; + var result = {'_': predicate}, + self = this; - var self = this; - angular.forEach(constructorData.params, function (param) { - result[param.name] = self.fetchObject(param.type, field + '[' + predicate + '][' + param.name + ']'); - }); + if (this.override[predicate]) { + this.override[predicate].apply(this, [result, field + '[' + predicate + ']']); + } else { + angular.forEach(constructorData.params, function (param) { + result[param.name] = self.fetchObject(param.type, field + '[' + predicate + '][' + param.name + ']'); + }); + } if (fallback) { this.mtproto = true; @@ -1773,7 +1782,7 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato serializer.storeLong(options.afterMessageID, 'msg_id'); } - serializer.storeMethod(method, params); + options.resultType = serializer.storeMethod(method, params); var messageID = MtpMessageIdGenerator.generateID(), seqNo = this.generateSeqNo(), @@ -2215,7 +2224,36 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato } var buffer = bytesToArrayBuffer(messageBody); - var deserializer = new TLDeserialization(buffer, {mtproto: true}); + var deserializerOptions = { + mtproto: true, + override: { + message: function (result, field) { + result.msg_id = this.fetchLong(field + '[msg_id]'); + result.seqno = this.fetchInt(field + '[seqno]'); + result.bytes = this.fetchInt(field + '[bytes]'); + + var offset = this.getOffset(); + + try { + result.body = this.fetchObject('Object', field + '[body]'); + } catch (e) { + result.body = {_: 'parse_error', error: e}; + } + this.offset = offset + result.bytes; + // console.log(dT(), 'override message', result); + }, + rpc_result: function (result, field) { + result.req_msg_id = this.fetchLong(field + '[req_msg_id]'); + + var sentMessage = self.sentMessages[result.req_msg_id], + type = sentMessage && sentMessage.resultType || 'Object'; + + result.result = this.fetchObject(type, field + '[result]'); + // console.log(dT(), 'override rpc_result', type, result); + } + } + }; + var deserializer = new TLDeserialization(buffer, deserializerOptions); var response = deserializer.fetchObject('', 'INPUT'); diff --git a/app/js/services.js b/app/js/services.js index 44fc373f..40149691 100644 --- a/app/js/services.js +++ b/app/js/services.js @@ -886,6 +886,54 @@ angular.module('myApp.services', []) } function getSearch (inputPeer, query, inputFilter, maxID, limit) { + var foundMsgs = []; + + if (!maxID && !query) { + var peerID = AppPeersManager.getPeerID(inputPeer), + historyStorage = historiesStorage[peerID]; + + if (historyStorage !== undefined && historyStorage.history.length) { + var neededContents = {}, + neededLimit = limit || 20, + i, message; + + switch (inputFilter._) { + case 'inputMessagesFilterPhotos': + neededContents['messageMediaPhoto'] = true; + break; + + case 'inputMessagesFilterVideo': + neededContents['messageMediaVideo'] = true; + break; + + case 'inputMessagesFilterPhotoVideo': + neededContents['messageMediaPhoto'] = true; + neededContents['messageMediaVideo'] = true; + break; + + case 'inputMessagesFilterDocument': + neededContents['messageMediaDocument'] = true; + break; + } + for (i = 0; i < historyStorage.history.length; i++) { + message = messagesStorage[historyStorage.history[i]]; + if (message.media && neededContents[message.media._]) { + foundMsgs.push(message.id); + if (foundMsgs.length >= neededLimit) { + break; + } + } + } + } + } + + if (foundMsgs.length || limit == 1000) { + return $q.when({ + count: null, + history: foundMsgs + }); + } + return MtpApiManager.invokeApi('messages.search', { peer: inputPeer, q: query || '', @@ -903,7 +951,7 @@ angular.module('myApp.services', []) ? searchResult.count : searchResult.messages.length; - var foundMsgs = []; + foundMsgs = []; angular.forEach(searchResult.messages, function (message) { foundMsgs.push(message.id); }); @@ -915,6 +963,10 @@ angular.module('myApp.services', []) }); } + function getMessage (messageID) { + return messagesStorage[messageID] || {deleted: true}; + } + function deleteMessages (messageIDs) { return MtpApiManager.invokeApi('messages.deleteMessages', { id: messageIDs @@ -1874,6 +1926,7 @@ angular.module('myApp.services', []) getDialogs: getDialogs, getHistory: getHistory, getSearch: getSearch, + getMessage: getMessage, readHistory: readHistory, flushHistory: flushHistory, deleteMessages: deleteMessages, @@ -2011,6 +2064,8 @@ angular.module('myApp.services', []) full.height = fullPhotoSize.h; } + full.modalWidth = Math.max(full.width, Math.min(400, fullWidth)); + full.location = fullPhotoSize.location; full.size = fullPhotoSize.size; } diff --git a/app/partials/confirm_modal.html b/app/partials/confirm_modal.html index 80143612..e551d89c 100644 --- a/app/partials/confirm_modal.html +++ b/app/partials/confirm_modal.html @@ -14,9 +14,8 @@ when="{'one': 'Are you sure to send file from clipboard?', 'other': 'Are you sure to send {} files from clipboard?'}"> - - Are you sure to send file(s) from clipboard? - + Are you sure to send file(s) from clipboard? + Are you sure to delete the message?
@@ -31,6 +30,7 @@ Delete Chat Send Send + Delete OK
diff --git a/app/partials/message.html b/app/partials/message.html index 983a5bcd..c6fefd44 100644 --- a/app/partials/message.html +++ b/app/partials/message.html @@ -92,7 +92,7 @@
- + +
diff --git a/app/partials/video_modal.html b/app/partials/video_modal.html index ac9f6d05..280f23a4 100644 --- a/app/partials/video_modal.html +++ b/app/partials/video_modal.html @@ -4,7 +4,14 @@
-

From: , {{video.date | dateOrTime}}

+
+ Forward + Delete +
+ +

+ , {{video.date | dateOrTime}} +

diff --git a/app/vendor/ui-bootstrap/ui-bootstrap-custom-tpls-0.10.0.js b/app/vendor/ui-bootstrap/ui-bootstrap-custom-tpls-0.10.0.js index bef93ffb..6488a3dc 100644 --- a/app/vendor/ui-bootstrap/ui-bootstrap-custom-tpls-0.10.0.js +++ b/app/vendor/ui-bootstrap/ui-bootstrap-custom-tpls-0.10.0.js @@ -300,7 +300,8 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition']) restrict: 'EA', scope: { index: '@', - animate: '=' + animate: '=', + nav: '=' }, replace: true, transclude: true, @@ -447,6 +448,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition']) angularDomEl.attr('window-class', modal.windowClass); angularDomEl.attr('index', openedWindows.length() - 1); angularDomEl.attr('animate', 'animate'); + angularDomEl.attr('nav', 'nav'); angularDomEl.html(modal.content); var modalDomEl = $compile(angularDomEl)(modal.scope); @@ -1074,6 +1076,9 @@ angular.module("template/modal/backdrop.html", []).run(["$templateCache", functi angular.module("template/modal/window.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/modal/window.html", "
\n" + + "
\n" + + "
\n" + + "
\n" + "
\n" + "
\n" + "
\n" + diff --git a/webogram.sublime-project b/webogram.sublime-project index b5b7952f..87cf2142 100644 --- a/webogram.sublime-project +++ b/webogram.sublime-project @@ -5,7 +5,7 @@ "follow_symlinks": true, "path": ".", "folder_exclude_patterns": ["*dist", "node_modules", "releases"], - "file_exclude_patterns": ["*.zip"] + "file_exclude_patterns": ["*.zip", "templates.js"] } ] }