Browse Source

Implement #225 - shared photos navigation

Also fixed fetching Vector<…> results
master
Igor Zhukov 11 years ago
parent
commit
a6e5aa9e40
  1. 47
      app/css/app.css
  2. BIN
      app/img/icons/CloseHover_1x.png
  3. BIN
      app/img/icons/CloseHover_2x.png
  4. BIN
      app/img/icons/Close_1x.png
  5. BIN
      app/img/icons/Close_2x.png
  6. BIN
      app/img/icons/PhotoControls.png
  7. BIN
      app/img/icons/PhotoControls_1x.png
  8. 122
      app/js/controllers.js
  9. 153
      app/js/directives.js
  10. 52
      app/js/lib/mtproto.js
  11. 57
      app/js/services.js
  12. 6
      app/partials/confirm_modal.html
  13. 2
      app/partials/message.html
  14. 13
      app/partials/photo_modal.html
  15. 9
      app/partials/video_modal.html
  16. 7
      app/vendor/ui-bootstrap/ui-bootstrap-custom-tpls-0.10.0.js
  17. 2
      webogram.sublime-project

47
app/css/app.css

@ -339,13 +339,13 @@ input[type="number"]::-webkit-inner-spin-button {
height: 100%; height: 100%;
} }
.modal_close { .modal_close {
background: url(../img/icons/CloseHover_2x.png) 0 0 no-repeat; background: url(../img/icons/PhotoControls.png) 0 -53px no-repeat;
background-size: 33px 33px; background-size: 33px 86px;
width: 33px; width: 33px;
height: 33px; height: 33px;
float: right; float: right;
margin: 60px 30px 0 0; margin: 60px 30px 0 0;
opacity: 0.5; opacity: 0.6;
pointer-events: none; pointer-events: none;
-webkit-transition : .2s; -webkit-transition : .2s;
@ -354,7 +354,40 @@ input[type="number"]::-webkit-inner-spin-button {
transition : .2s; transition : .2s;
} }
.modal_close_wrap:hover .modal_close { .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 { .text-invisible {
@ -1849,6 +1882,12 @@ img.img_fullsize {
color: #777; color: #777;
margin: 20px 0 0; margin: 20px 0 0;
} }
.media_modal_actions {
margin-top: 20px;
}
.media_modal_action_link {
margin-left: 15px;
}
.media_modal_author { .media_modal_author {
font-weight: bold; font-weight: bold;
} }

BIN
app/img/icons/CloseHover_1x.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 789 B

BIN
app/img/icons/CloseHover_2x.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

BIN
app/img/icons/Close_1x.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 783 B

BIN
app/img/icons/Close_2x.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

BIN
app/img/icons/PhotoControls.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
app/img/icons/PhotoControls_1x.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

122
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.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) { .controller('VideoModalController', function ($scope, AppVideoManager) {

153
app/js/directives.js

@ -683,19 +683,18 @@ angular.module('myApp.directives', ['myApp.filters'])
link: link, link: link,
transclude: true, transclude: true,
template: template:
'<div class="img_fullsize_with_progress_wrap" ng-style="{width: fullPhoto.width + \'px\', height: fullPhoto.height + \'px\'}">\ '<div class="img_fullsize_with_progress_wrap"">\
<div class="img_fullsize_progress_overlay" ng-show="progress.enabled">\ <div class="img_fullsize_progress_overlay" ng-show="progress.enabled">\
<div class="img_fullsize_progress_wrap" ng-style="{width: fullPhoto.width + \'px\', height: fullPhoto.height + \'px\'}">\ <div class="img_fullsize_progress_wrap"">\
<div class="img_fullsize_progress progress tg_progress">\ <div class="img_fullsize_progress progress tg_progress" ng-show="progress.percent > 0">\
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="{{progress.percent}}" aria-valuemin="0" aria-valuemax="100" style="width: {{progress.percent}}%">\ <div class="progress-bar progress-bar-success" ng-style="{width: progress.percent + \'%\'}">\
<span class="sr-only">{{progress.percent}}% Complete (success)</span>\
</div>\ </div>\
</div>\ </div>\
</div>\ </div>\
</div>\ </div>\
<div class="photo_full_wrap">\ <div class="photo_full_wrap">\
<a class="photo_modal_image">\ <a class="photo_modal_image">\
<img class="photo_modal_image" width="{{fullPhoto.width}}" height="{{fullPhoto.height}}" />\ <img class="photo_modal_image"/>\
</a>\ </a>\
</div>\ </div>\
<div class="photo_modal_error_wrap" ng-if="error">\ <div class="photo_modal_error_wrap" ng-if="error">\
@ -711,53 +710,68 @@ angular.module('myApp.directives', ['myApp.filters'])
function link ($scope, element, attrs) { 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 var jump = 0;
.attr('src', MtpApiFileManager.getCachedFile($scope.thumbLocation) || 'img/blank.gif') $scope.$watchCollection('fullPhoto.location', function () {
.addClass('thumb_blurred') var cachedSrc = MtpApiFileManager.getCachedFile($scope.thumbLocation),
.addClass('thumb_blur_animation'); curJump = ++jump;
if (!$scope.fullPhoto.location) { if (cachedSrc) {
return; imgElement.src = cachedSrc;
} resize();
} else {
imgElement.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
}
if (!$scope.fullPhoto.location) {
return;
}
var apiPromise; var apiPromise;
if ($scope.fullPhoto.size) { if ($scope.fullPhoto.size) {
var inputLocation = { var inputLocation = {
_: 'inputFileLocation', _: 'inputFileLocation',
volume_id: $scope.fullPhoto.location.volume_id, volume_id: $scope.fullPhoto.location.volume_id,
local_id: $scope.fullPhoto.location.local_id, local_id: $scope.fullPhoto.location.local_id,
secret: $scope.fullPhoto.location.secret secret: $scope.fullPhoto.location.secret
}; };
apiPromise = MtpApiFileManager.downloadFile($scope.fullPhoto.location.dc_id, inputLocation, $scope.fullPhoto.size); apiPromise = MtpApiFileManager.downloadFile($scope.fullPhoto.location.dc_id, inputLocation, $scope.fullPhoto.size);
} else { } else {
apiPromise = MtpApiFileManager.downloadSmallFile($scope.fullPhoto.location); apiPromise = MtpApiFileManager.downloadSmallFile($scope.fullPhoto.location);
} }
$scope.progress = {enabled: true, percent: 1}; $scope.progress = {enabled: true, percent: 0};
apiPromise.then(function (url) { apiPromise.then(function (url) {
$scope.progress.enabled = false; if (curJump == jump) {
imgElement $scope.progress.enabled = false;
.attr('src', url) imgElement.src = url;
.removeClass('thumb_blurred'); resize();
}
}, function (e) {
console.log('Download image failed', e, $scope.fullPhoto.location);
$scope.progress.enabled = false;
}, function (e) { if (e && e.type == 'FS_BROWSER_UNSUPPORTED') {
console.log('Download image failed', e, $scope.fullPhoto.location); $scope.error = {html: 'Your browser doesn\'t support <a href="https://developer.mozilla.org/en-US/docs/Web/API/LocalFileSystem" target="_blank">LocalFileSystem</a> feature which is needed to display this image.<br/>Please, install <a href="http://google.com/chrome" target="_blank">Google Chrome</a> or use <a href="https://telegram.org/" target="_blank">mobile app</a> instead.'};
$scope.progress.enabled = false; } 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') { resize();
$scope.error = {html: 'Your browser doesn\'t support <a href="https://developer.mozilla.org/en-US/docs/Web/API/LocalFileSystem" target="_blank">LocalFileSystem</a> feature which is needed to display this image.<br/>Please, install <a href="http://google.com/chrome" target="_blank">Google Chrome</a> or use <a href="https://telegram.org/" target="_blank">mobile app</a> instead.'};
} else {
$scope.error = {text: 'Download failed', error: e};
}
}, function (progress) {
$scope.progress.percent = Math.max(1, Math.floor(100 * progress.done / progress.total));
});
} }
}) })
@ -771,9 +785,7 @@ angular.module('myApp.directives', ['myApp.filters'])
<div class="img_fullsize_progress_overlay" ng-show="progress.enabled">\ <div class="img_fullsize_progress_overlay" ng-show="progress.enabled">\
<div class="img_fullsize_progress_wrap" ng-style="{width: video.full.width + \'px\', height: video.full.height + \'px\'}">\ <div class="img_fullsize_progress_wrap" ng-style="{width: video.full.width + \'px\', height: video.full.height + \'px\'}">\
<div class="img_fullsize_progress progress tg_progress">\ <div class="img_fullsize_progress progress tg_progress">\
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="{{progress.percent}}" aria-valuemin="0" aria-valuemax="100" style="width: {{progress.percent}}%">\ <div class="progress-bar progress-bar-success" style="width: {{progress.percent}}%"></div>\
<span class="sr-only">{{progress.percent}}% Complete (success)</span>\
</div>\
</div>\ </div>\
</div>\ </div>\
</div>\ </div>\
@ -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) { .directive('myModalPosition', function ($window, $timeout) {
@ -993,9 +1043,12 @@ angular.module('myApp.directives', ['myApp.filters'])
} else { } else {
$(element[0].parentNode).css('marginTop', ''); $(element[0].parentNode).css('marginTop', '');
} }
$timeout(function () {
$(element[0].parentNode).addClass('modal-content-animated'); if (attrs.animation != 'no') {
}, 300); $timeout(function () {
$(element[0].parentNode).addClass('modal-content-animated');
}, 300);
}
}; };
onContentLoaded(updateMargin); onContentLoaded(updateMargin);

52
app/js/lib/mtproto.js

@ -638,6 +638,8 @@ TLSerialization.prototype.storeMethod = function (methodName, params) {
angular.forEach(methodData.params, function (param) { angular.forEach(methodData.params, function (param) {
self.storeObject(params[param.name], param.type, methodName + '[' + param.name + ']'); self.storeObject(params[param.name], param.type, methodName + '[' + param.name + ']');
}); });
return methodData.type;
}; };
TLSerialization.prototype.storeObject = function (obj, type, field) { TLSerialization.prototype.storeObject = function (obj, type, field) {
@ -707,6 +709,8 @@ TLSerialization.prototype.storeObject = function (obj, type, field) {
angular.forEach(constructorData.params, function (param) { angular.forEach(constructorData.params, function (param) {
self.storeObject(obj[param.name], param.type, field + '[' + predicate + '][' + param.name + ']'); self.storeObject(obj[param.name], param.type, field + '[' + predicate + '][' + param.name + ']');
}); });
return constructorData.type;
}; };
@ -715,6 +719,7 @@ function TLDeserialization (buffer, options) {
options = options || {}; options = options || {};
this.offset = 0; // in bytes this.offset = 0; // in bytes
this.override = options.override || {};
this.buffer = buffer; this.buffer = buffer;
this.intView = new Uint32Array(this.buffer); this.intView = new Uint32Array(this.buffer);
@ -961,12 +966,16 @@ TLDeserialization.prototype.fetchObject = function (type, field) {
predicate = constructorData.predicate; predicate = constructorData.predicate;
var result = {'_': predicate}; var result = {'_': predicate},
self = this;
var self = this; if (this.override[predicate]) {
angular.forEach(constructorData.params, function (param) { this.override[predicate].apply(this, [result, field + '[' + predicate + ']']);
result[param.name] = self.fetchObject(param.type, field + '[' + predicate + '][' + param.name + ']'); } else {
}); angular.forEach(constructorData.params, function (param) {
result[param.name] = self.fetchObject(param.type, field + '[' + predicate + '][' + param.name + ']');
});
}
if (fallback) { if (fallback) {
this.mtproto = true; this.mtproto = true;
@ -1773,7 +1782,7 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato
serializer.storeLong(options.afterMessageID, 'msg_id'); serializer.storeLong(options.afterMessageID, 'msg_id');
} }
serializer.storeMethod(method, params); options.resultType = serializer.storeMethod(method, params);
var messageID = MtpMessageIdGenerator.generateID(), var messageID = MtpMessageIdGenerator.generateID(),
seqNo = this.generateSeqNo(), seqNo = this.generateSeqNo(),
@ -2215,7 +2224,36 @@ factory('MtpNetworkerFactory', function (MtpDcConfigurator, MtpMessageIdGenerato
} }
var buffer = bytesToArrayBuffer(messageBody); 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'); var response = deserializer.fetchObject('', 'INPUT');

57
app/js/services.js

@ -886,6 +886,54 @@ angular.module('myApp.services', [])
} }
function getSearch (inputPeer, query, inputFilter, maxID, limit) { 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', { return MtpApiManager.invokeApi('messages.search', {
peer: inputPeer, peer: inputPeer,
q: query || '', q: query || '',
@ -903,7 +951,7 @@ angular.module('myApp.services', [])
? searchResult.count ? searchResult.count
: searchResult.messages.length; : searchResult.messages.length;
var foundMsgs = []; foundMsgs = [];
angular.forEach(searchResult.messages, function (message) { angular.forEach(searchResult.messages, function (message) {
foundMsgs.push(message.id); foundMsgs.push(message.id);
}); });
@ -915,6 +963,10 @@ angular.module('myApp.services', [])
}); });
} }
function getMessage (messageID) {
return messagesStorage[messageID] || {deleted: true};
}
function deleteMessages (messageIDs) { function deleteMessages (messageIDs) {
return MtpApiManager.invokeApi('messages.deleteMessages', { return MtpApiManager.invokeApi('messages.deleteMessages', {
id: messageIDs id: messageIDs
@ -1874,6 +1926,7 @@ angular.module('myApp.services', [])
getDialogs: getDialogs, getDialogs: getDialogs,
getHistory: getHistory, getHistory: getHistory,
getSearch: getSearch, getSearch: getSearch,
getMessage: getMessage,
readHistory: readHistory, readHistory: readHistory,
flushHistory: flushHistory, flushHistory: flushHistory,
deleteMessages: deleteMessages, deleteMessages: deleteMessages,
@ -2011,6 +2064,8 @@ angular.module('myApp.services', [])
full.height = fullPhotoSize.h; full.height = fullPhotoSize.h;
} }
full.modalWidth = Math.max(full.width, Math.min(400, fullWidth));
full.location = fullPhotoSize.location; full.location = fullPhotoSize.location;
full.size = fullPhotoSize.size; full.size = fullPhotoSize.size;
} }

6
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?'}"> when="{'one': 'Are you sure to send file from clipboard?', 'other': 'Are you sure to send {} files from clipboard?'}">
</ng-pluralize> </ng-pluralize>
</span> </span>
<span ng-switch-when="FILE_CLIPBOARD_PASTE"> <span ng-switch-when="FILE_CLIPBOARD_PASTE">Are you sure to send file(s) from clipboard?</span>
Are you sure to send file(s) from clipboard? <span ng-switch-when="MESSAGE_DELETE">Are you sure to delete the message?</span>
</span>
<span ng-switch-default ng-bind="message || 'Are you sure?'"></span> <span ng-switch-default ng-bind="message || 'Are you sure?'"></span>
</div> </div>
@ -31,6 +30,7 @@
<span ng-switch-when="HISTORY_FLUSH">Delete Chat</span> <span ng-switch-when="HISTORY_FLUSH">Delete Chat</span>
<span ng-switch-when="FILES_CLIPBOARD_PASTE">Send</span> <span ng-switch-when="FILES_CLIPBOARD_PASTE">Send</span>
<span ng-switch-when="FILE_CLIPBOARD_PASTE">Send</span> <span ng-switch-when="FILE_CLIPBOARD_PASTE">Send</span>
<span ng-switch-when="MESSAGE_DELETE">Delete</span>
<span ng-switch-default>OK</span> <span ng-switch-default>OK</span>
</button> </button>
</div> </div>

2
app/partials/message.html

@ -92,7 +92,7 @@
<div bo-if="historyMessage.media &amp;&amp; historyMessage.media._ != 'messageMediaEmpty'" class="im_message_media" ng-switch="historyMessage.media._"> <div bo-if="historyMessage.media &amp;&amp; historyMessage.media._ != 'messageMediaEmpty'" class="im_message_media" ng-switch="historyMessage.media._">
<a ng-switch-when="messageMediaPhoto" class="im_message_photo_thumb" href="" ng-click="openPhoto(historyMessage.media.photo.id)" bo-style="{width: historyMessage.media.photo.thumb.width + 'px'}" ng-mouseover="preloadPhoto(historyMessage.media.photo.id)"> <a ng-switch-when="messageMediaPhoto" class="im_message_photo_thumb" href="" ng-click="openPhoto(historyMessage.media.photo.id, historyMessage.id)" bo-style="{width: historyMessage.media.photo.thumb.width + 'px'}" ng-mouseover="preloadPhoto(historyMessage.media.photo.id)">
<img <img
class="im_message_photo_thumb" class="im_message_photo_thumb"
my-load-thumb my-load-thumb

13
app/partials/photo_modal.html

@ -1,10 +1,17 @@
<div my-modal-width="{{photo.full.width}}" class="media_modal_wrap photo_modal_wrap" my-modal-position> <div my-modal-width="{{photo.full.modalWidth}}" class="media_modal_wrap photo_modal_wrap" my-modal-position animation="no" my-modal-nav next="nav.next()" prev="nav.prev()">
<div class="modal-body"> <div class="modal-body">
<div class="photo_modal_image_wrap" my-load-full-photo full-photo="photo.full" thumb-location="photo.thumb.location" ng-click="$close()"> </div> <div class="photo_modal_image_wrap" my-load-full-photo full-photo="photo.full" thumb-location="photo.thumb.location" ng-click="nav.next()"> </div>
<p class="media_modal_info">From: <span class="media_modal_author" ng-bind-html="photo.fromUser.rFullName" ></span>, {{photo.date | dateOrTime}}</p> <div class="media_modal_actions pull-right">
<a href="" class="media_modal_action_link" ng-click="forward()">Forward</a>
<a href="" class="media_modal_action_link" ng-click="delete()">Delete</a>
</div>
<p class="media_modal_info">
<span class="media_modal_author" ng-bind-html="photo.fromUser.rFullName"></span>, {{photo.date | dateOrTime}}
</p>
</div> </div>

9
app/partials/video_modal.html

@ -4,7 +4,14 @@
<div class="video_modal_image_wrap" my-load-video video="video"></div> <div class="video_modal_image_wrap" my-load-video video="video"></div>
<p class="media_modal_info">From: <span class="media_modal_author" ng-bind-html="video.fromUser.rFullName"></span>, {{video.date | dateOrTime}}</p> <div class="media_modal_actions pull-right">
<a href="" class="media_modal_action_link" ng-click="forward()">Forward</a>
<a href="" class="media_modal_action_link" ng-click="delete()">Delete</a>
</div>
<p class="media_modal_info">
<span class="media_modal_author" ng-bind-html="video.fromUser.rFullName" ></span>, {{video.date | dateOrTime}}
</p>
</div> </div>

7
app/vendor/ui-bootstrap/ui-bootstrap-custom-tpls-0.10.0.js vendored

@ -300,7 +300,8 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
restrict: 'EA', restrict: 'EA',
scope: { scope: {
index: '@', index: '@',
animate: '=' animate: '=',
nav: '='
}, },
replace: true, replace: true,
transclude: true, transclude: true,
@ -447,6 +448,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
angularDomEl.attr('window-class', modal.windowClass); angularDomEl.attr('window-class', modal.windowClass);
angularDomEl.attr('index', openedWindows.length() - 1); angularDomEl.attr('index', openedWindows.length() - 1);
angularDomEl.attr('animate', 'animate'); angularDomEl.attr('animate', 'animate');
angularDomEl.attr('nav', 'nav');
angularDomEl.html(modal.content); angularDomEl.html(modal.content);
var modalDomEl = $compile(angularDomEl)(modal.scope); 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) { angular.module("template/modal/window.html", []).run(["$templateCache", function($templateCache) {
$templateCache.put("template/modal/window.html", $templateCache.put("template/modal/window.html",
"<div tabindex=\"-1\" class=\"modal fade {{ windowClass }}\" ng-class=\"{in: animate}\" ng-style=\"{'z-index': 1050 + index*10, display: 'block'}\" ng-click=\"close($event)\">\n" + "<div tabindex=\"-1\" class=\"modal fade {{ windowClass }}\" ng-class=\"{in: animate}\" ng-style=\"{'z-index': 1050 + index*10, display: 'block'}\" ng-click=\"close($event)\">\n" +
" <div class=\"modal_prev_wrap hidden-xs hidden-sm\" ng-show=\"nav.hasPrev\" ng-click=\"nav.prev($event)\">\n" +
" <div class=\"modal_prev\"></div>\n" +
" </div>\n" +
" <div class=\"modal_close_wrap hidden-xs hidden-sm\" ng-click=\"close($event)\">\n" + " <div class=\"modal_close_wrap hidden-xs hidden-sm\" ng-click=\"close($event)\">\n" +
" <div class=\"modal_close\"></div>\n" + " <div class=\"modal_close\"></div>\n" +
" </div>\n" + " </div>\n" +

2
webogram.sublime-project vendored

@ -5,7 +5,7 @@
"follow_symlinks": true, "follow_symlinks": true,
"path": ".", "path": ".",
"folder_exclude_patterns": ["*dist", "node_modules", "releases"], "folder_exclude_patterns": ["*dist", "node_modules", "releases"],
"file_exclude_patterns": ["*.zip"] "file_exclude_patterns": ["*.zip", "templates.js"]
} }
] ]
} }

Loading…
Cancel
Save