Browse Source

Photos download, packaged app improvements

master
Igor Zhukov 10 years ago
parent
commit
2d50db467f
  1. 10
      app/css/app.css
  2. 67
      app/index.html
  3. 22
      app/js/controllers.js
  4. 2
      app/js/directives.js
  5. 63
      app/js/init.js
  6. 221
      app/js/lib/mtproto.js
  7. 80
      app/js/services.js
  8. 3
      app/manifest.json
  9. 6
      app/partials/head.html
  10. 1
      app/partials/photo_modal.html
  11. 6
      app/partials/welcome.html

10
app/css/app.css

@ -3,12 +3,14 @@ @@ -3,12 +3,14 @@
html {
display: none;
background: #dee4e9 url(../img/bg_tile.png) 0 0 repeat;
overflow: visible;
/*background-size: 300px 468px;*/
}
body {
color: #000;
background: none;
font: 12px/18px "Lucida Grande", "Lucida Sans Unicode", Arial, Helvetica, Verdana, sans-serif;
overflow: visible;
/*-webkit-font-smoothing: antialiased;*/
}
.font-light {
@ -71,6 +73,10 @@ input[type="number"]::-webkit-inner-spin-button { @@ -71,6 +73,10 @@ input[type="number"]::-webkit-inner-spin-button {
margin: 0;
}
input[type="number"] {
-moz-appearance:textfield;
}
.btn-success {
color: #ffffff;
@ -312,9 +318,7 @@ input[type="number"]::-webkit-inner-spin-button { @@ -312,9 +318,7 @@ input[type="number"]::-webkit-inner-spin-button {
.modal-backdrop {
background: #111111;
}
.modal-backdrop.in {
opacity: 0.25;
opacity: 0.25 !important;
}
.modal.fade .modal-dialog {

67
app/index.html

@ -20,72 +20,6 @@ @@ -20,72 +20,6 @@
<meta property="og:site_name" content="Webogram">
<meta property="og:description" content="Welcome to an experimental web-client of Telegram messenger. See https://github.com/zhukov/webogram for more info.">
<script type="text/javascript">
(function () {
// Prevent click-jacking
try {
if (self == top) {
document.documentElement.style.display = 'block';
} else {
top.location = self.location;
}
} catch (e) {console.error('CJ protection', e)};
window.safeConfirm = function (params, callback) {
if (typeof params === 'string') {
params = {message: params};
}
var result = false
try {
result = confirm(params.message);
} catch (e) {
result = true;
}
setTimeout(function () {callback(result)}, 10);
};
if (!window.applicationCache || !window.addEventListener) {
return;
}
var appCache = window.applicationCache,
declined = false,
updateTimeout = false,
scheduleUpdate = function (delay) {
clearTimeout(updateTimeout);
updateTimeout = setTimeout(function () {
try {
appCache.update();
} catch (ex) {
console.log('appCache.update: ' + ex);
}
}, delay || 300000);
},
attach = function () {
appCache.addEventListener('updateready', function(e) {
if (appCache.status == appCache.UPDATEREADY) {
if (!declined) {
safeConfirm({type: 'WEBOGRAM_UPDATED_RELOAD', message: 'A new version of Webogram is available. Load it?'}, function (result) {
if (result) {
window.location.reload();
} else {
declined = true;
}
});
scheduleUpdate();
}
}
}, false);
appCache.addEventListener('noupdate', function () {scheduleUpdate()}, false);
appCache.addEventListener('error', function () {scheduleUpdate()}, false);
};
scheduleUpdate(3000);
window.addEventListener('load', attach);
})();
</script>
</head>
<body>
@ -93,6 +27,7 @@ @@ -93,6 +27,7 @@
<!-- build:js js/app.js -->
<script type="text/javascript" src="vendor/console-polyfill/console-polyfill.js"></script>
<script type="text/javascript" src="js/init.js"></script>
<script type="text/javascript" src="vendor/jquery/jquery.min.js"></script>
<script type="text/javascript" src="vendor/jquery.nanoscroller/nanoscroller.js"></script>
<script type="text/javascript" src="vendor/jquery.emojiarea/jquery.emojiarea.js"></script>

22
app/js/controllers.js

@ -427,16 +427,18 @@ angular.module('myApp.controllers', []) @@ -427,16 +427,18 @@ angular.module('myApp.controllers', [])
}
AppMessagesManager.getDialogs($scope.search.query, maxID).then(function (dialogsResult) {
offset += dialogsResult.dialogs.length;
maxID = dialogsResult.dialogs[dialogsResult.dialogs.length - 1].top_message;
hasMore = dialogsResult.count === null || offset < dialogsResult.count;
if (dialogsResult.dialogs.length) {
offset += dialogsResult.dialogs.length;
maxID = dialogsResult.dialogs[dialogsResult.dialogs.length - 1].top_message;
hasMore = dialogsResult.count === null || offset < dialogsResult.count;
angular.forEach(dialogsResult.dialogs, function (dialog) {
peersInDialogs[dialog.peerID] = true;
$scope.dialogs.push(AppMessagesManager.wrapForDialog(dialog.top_message, dialog.unread_count));
});
angular.forEach(dialogsResult.dialogs, function (dialog) {
peersInDialogs[dialog.peerID] = true;
$scope.dialogs.push(AppMessagesManager.wrapForDialog(dialog.top_message, dialog.unread_count));
});
$scope.$broadcast('ui_dialogs_append');
$scope.$broadcast('ui_dialogs_append');
}
});
};
@ -1081,6 +1083,10 @@ angular.module('myApp.controllers', []) @@ -1081,6 +1083,10 @@ angular.module('myApp.controllers', [])
});
};
$scope.download = function () {
AppPhotosManager.downloadPhoto($scope.photoID);
};
$scope.$on('history_delete', function (e, historyUpdate) {
console.log(dT(), 'delete', historyUpdate);

2
app/js/directives.js

@ -833,7 +833,7 @@ angular.module('myApp.directives', ['myApp.filters']) @@ -833,7 +833,7 @@ angular.module('myApp.directives', ['myApp.filters'])
}
}
var downloadPromise = MtpApiFileManager.downloadFile($scope.video.dc_id, inputLocation, $scope.video.size, null, {mime: 'video/mp4'});
var downloadPromise = MtpApiFileManager.downloadFile($scope.video.dc_id, inputLocation, $scope.video.size, {mime: 'video/mp4'});
downloadPromise.then(function (url) {
$scope.progress.enabled = false;

63
app/js/init.js

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
(function () {
// Prevent click-jacking
try {
if (window.chrome && chrome.app && chrome.app.window || self == top) {
document.documentElement.style.display = 'block';
} else {
top.location = self.location;
}
} catch (e) {console.error('CJ protection', e)};
window.safeConfirm = function (params, callback) {
if (typeof params === 'string') {
params = {message: params};
}
var result = false
try {
result = confirm(params.message);
} catch (e) {
result = true;
}
setTimeout(function () {callback(result)}, 10);
};
if (!window.applicationCache || !window.addEventListener) {
return;
}
var appCache = window.applicationCache,
declined = false,
updateTimeout = false,
scheduleUpdate = function (delay) {
clearTimeout(updateTimeout);
updateTimeout = setTimeout(function () {
try {
appCache.update();
} catch (ex) {
console.log('appCache.update: ' + ex);
}
}, delay || 300000);
},
attach = function () {
appCache.addEventListener('updateready', function(e) {
if (appCache.status == appCache.UPDATEREADY) {
if (!declined) {
safeConfirm({type: 'WEBOGRAM_UPDATED_RELOAD', message: 'A new version of Webogram is available. Load it?'}, function (result) {
if (result) {
window.location.reload();
} else {
declined = true;
}
});
scheduleUpdate();
}
}
}, false);
appCache.addEventListener('noupdate', function () {scheduleUpdate()}, false);
appCache.addEventListener('error', function () {scheduleUpdate()}, false);
};
scheduleUpdate(3000);
window.addEventListener('load', attach);
})();

221
app/js/lib/mtproto.js

@ -1005,12 +1005,12 @@ factory('MtpDcConfigurator', function () { @@ -1005,12 +1005,12 @@ factory('MtpDcConfigurator', function () {
var dcOptions = window._testMode
? [
{id: 1, host: '173.240.5.253', port: 80},
{id: 2, host: '109.239.131.195', port: 80},
{id: 2, host: '149.154.167.40', port: 80},
{id: 3, host: '174.140.142.5', port: 80}
]
: [
{id: 1, host: '173.240.5.1', port: 80},
{id: 2, host: '109.239.131.193', port: 80},
{id: 2, host: '149.154.167.5', port: 80},
{id: 3, host: '174.140.142.6', port: 80},
{id: 4, host: '31.210.235.12', port: 80},
{id: 5, host: '116.51.22.2', port: 80},
@ -2832,7 +2832,7 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { @@ -2832,7 +2832,7 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) {
deferred.reject();
};
if (false) { // is file bytes
if (bytes instanceof Blob) { // is file bytes
fileWriter.write(bytes);
} else {
fileWriter.write(new Blob([bytesToArrayBuffer(bytes)]));
@ -2841,6 +2841,23 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { @@ -2841,6 +2841,23 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) {
return deferred.promise;
}
function fileCopyTo (fromFileEntry, toFileEntry) {
var deferred = $q.defer();
toFileEntry.createWriter(function (fileWriter) {
fileWriteBytes(fileWriter, fromFileEntry).then(function () {
deferred.resolve(fileWriter);
}, function (e) {
fileWriter.truncate(0);
deferred.reject(e);
});
}, function (e) {
deferred.reject(e);
});
return deferred.promise;
}
function getFileName(location) {
switch (location._) {
case 'inputVideoFileLocation':
@ -2982,14 +2999,15 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { @@ -2982,14 +2999,15 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) {
return cachedDownloadPromises[fileName] = deferred.promise;
}
function downloadFile (dcID, location, size, fileEntry, options) {
function downloadFile (dcID, location, size, options) {
options = options || {};
console.log(dT(), 'Dload file', dcID, location, size);
var fileName = getFileName(location),
toFileEntry = options.toFileEntry || null,
cachedPromise = cachedSavePromises[fileName] || cachedDownloadPromises[fileName];
if (cachedPromise) {
if (!toFileEntry && cachedPromise) {
return cachedPromise;
}
@ -3049,7 +3067,11 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { @@ -3049,7 +3067,11 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) {
if (isFinal) {
// console.timeEnd(fileName + ' ' + (size / 1024));
resolved = true;
deferred.resolve(cachedDownloads[fileName] = fileEntry.toURL(options.mime || 'image/jpeg'));
if (toFileEntry) {
deferred.resolve();
} else {
deferred.resolve(cachedDownloads[fileName] = fileEntry.toURL(options.mime || 'image/jpeg'));
}
} else {
// console.log('notify', {done: offset + limit, total: size});
deferred.notify({done: offset + limit, total: size});
@ -3070,90 +3092,104 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { @@ -3070,90 +3092,104 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) {
};
if (fileEntry) {
saveToFileEntry(fileEntry);
} else {
requestFS().then(function () {
cachedFs.root.getFile(fileName, {create: false}, function(fileEntry) {
fileEntry.file(function(file) {
// console.log(dT(), 'Check size', file.size, size);
if (file.size >= size/* && false*/) {
resolved = true;
requestFS().then(function () {
cachedFs.root.getFile(fileName, {create: false}, function(fileEntry) {
fileEntry.file(function(file) {
// console.log(dT(), 'Check size', file.size, size);
if (file.size >= size/* && false*/) {
resolved = true;
if (toFileEntry) {
fileCopyTo(file, toFileEntry).then(function () {
deferred.resolve();
})
} else {
deferred.resolve(cachedDownloads[fileName] = fileEntry.toURL());
}
} else {
// setTimeout(function () {
console.log('File bad size', file, size);
if (toFileEntry) {
saveToFileEntry(toFileEntry);
} else {
// setTimeout(function () {
console.log('File bad size', file, size);
cachedFs.root.getFile(fileName, {create: true}, saveToFileEntry, errorHandler)
// }, 10000);
}
}, errorHandler);
}, function () {
cachedFs.root.getFile(fileName, {create: true}, saveToFileEntry, errorHandler)
});
// }, 10000);
}
}, errorHandler);
}, function () {
if (toFileEntry) {
saveToFileEntry(toFileEntry);
} else {
cachedFs.root.getFile(fileName, {create: true}, saveToFileEntry, errorHandler)
}
});
}, function () {
var blobParts = [];
var limit = size > 30400 ? 524288 : 4096;
var writeBlobPromise = $q.when(),
writeBlobDeferred;
for (var offset = 0; offset < size; offset += limit) {
writeBlobDeferred = $q.defer();
(function (isFinal, offset, writeBlobDeferred, writeBlobPromise) {
return downloadRequest(dcID, function () {
if (toFileEntry) {
return saveToFileEntry(toFileEntry);
}
var blobParts = [];
var limit = size > 30400 ? 524288 : 4096;
var writeBlobPromise = $q.when(),
writeBlobDeferred;
for (var offset = 0; offset < size; offset += limit) {
writeBlobDeferred = $q.defer();
(function (isFinal, offset, writeBlobDeferred, writeBlobPromise) {
return downloadRequest(dcID, function () {
if (canceled) {
return $q.when();
}
return MtpApiManager.invokeApi('upload.getFile', {
location: location,
offset: offset,
limit: limit
}, {
dcID: dcID,
fileDownload: true,
createNetworker: true
});
}, 6).then(function (result) {
writeBlobPromise.then(function () {
if (canceled) {
return $q.when();
}
return MtpApiManager.invokeApi('upload.getFile', {
location: location,
offset: offset,
limit: limit
}, {
dcID: dcID,
fileDownload: true,
createNetworker: true
});
}, 6).then(function (result) {
writeBlobPromise.then(function () {
if (canceled) {
return $q.when();
}
try {
blobParts.push(bytesToArrayBuffer(result.bytes));
writeBlobDeferred.resolve();
if (isFinal) {
try {
var blob = new Blob(blobParts, {type: options.mime || 'image/jpeg'});
} catch (e) {
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
var bb = new BlobBuilder;
angular.forEach(blobParts, function(blobPart) {
bb.append(blobPart);
});
var blob = bb.getBlob(options.mime || 'image/jpeg');
}
try {
blobParts.push(bytesToArrayBuffer(result.bytes));
writeBlobDeferred.resolve();
if (isFinal) {
try {
var blob = new Blob(blobParts, {type: options.mime || 'image/jpeg'});
} catch (e) {
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
var bb = new BlobBuilder;
angular.forEach(blobParts, function(blobPart) {
bb.append(blobPart);
});
var blob = bb.getBlob(options.mime || 'image/jpeg');
}
window.URL = window.URL || window.webkitURL;
resolved = true;
deferred.resolve(cachedDownloads[fileName] = URL.createObjectURL(blob));
} else {
deferred.notify({done: offset + limit, total: size});
};
} catch (e) {
errorHandler(e);
}
}, errorHandler);
window.URL = window.URL || window.webkitURL;
resolved = true;
deferred.resolve(cachedDownloads[fileName] = URL.createObjectURL(blob));
} else {
deferred.notify({done: offset + limit, total: size});
};
} catch (e) {
errorHandler(e);
}
}, errorHandler);
});
});
})(offset + limit >= size, offset, writeBlobDeferred, writeBlobPromise);
})(offset + limit >= size, offset, writeBlobDeferred, writeBlobPromise);
writeBlobPromise = writeBlobDeferred.promise;
writeBlobPromise = writeBlobDeferred.promise;
}
}
});
}
});
deferred.promise.cancel = function () {
if (!canceled && !resolved) {
@ -3163,37 +3199,12 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) { @@ -3163,37 +3199,12 @@ factory('MtpApiFileManager', function (MtpApiManager, $q, $window) {
}
}
return cachedDownloadPromises[fileName] = deferred.promise;
}
function writeFile (file) {
console.log(dT(), 'Write file', file);
var fileName = getTempFileName(file);
var deferred = $q.defer(),
cacheFileWriter,
errorHandler = function (error) {
console.log('fail');
deferred.reject(error);
if (cacheFileWriter) cacheFileWriter.truncate(0);
errorHandler = angular.noop;
};
if (!toFileEntry) {
cachedDownloadPromises[fileName] = deferred.promise;
}
requestFS().then(function () {
cachedFs.root.getFile(fileName, {create: false}, function(fileEntry) {
deferred.resolve(fileEntry);
}, function () {
cachedFs.root.getFile(fileName, {create: true}, function(fileEntry) {
fileEntry.createWriter(function (fileWriter) {
cacheFileWriter = fileWriter;
fileWriteBytes(fileWriter, file).then(function () {
deferred.resolve(fileEntry);
}, errorHandler);
}, errorHandler);
});
});
});
};
return deferred.promise;
}
function uploadFile (file) {
var fileSize = file.size,

80
app/js/services.js

@ -1975,7 +1975,7 @@ angular.module('myApp.services', []) @@ -1975,7 +1975,7 @@ angular.module('myApp.services', [])
}
})
.service('AppPhotosManager', function ($modal, $window, $rootScope, MtpApiFileManager, AppUsersManager) {
.service('AppPhotosManager', function ($modal, $window, $timeout, $rootScope, MtpApiFileManager, AppUsersManager) {
var photos = {};
function savePhoto (apiPhoto) {
@ -2123,6 +2123,65 @@ angular.module('myApp.services', []) @@ -2123,6 +2123,65 @@ angular.module('myApp.services', [])
});
}
function downloadPhoto (photoID) {
var photo = photos[photoID],
ext = 'jpg',
mimeType = 'image/jpeg',
fileName = 'photo' + photoID + '.' + ext,
fullWidth = $(window).width() - 36,
fullHeight = $($window).height() - 150,
fullPhotoSize = choosePhotoSize(photo, fullWidth, fullHeight),
inputFileLocation = {
_: 'inputFileLocation',
volume_id: fullPhotoSize.location.volume_id,
local_id: fullPhotoSize.location.local_id,
secret: fullPhotoSize.location.secret
};
if (window.chrome && chrome.fileSystem && chrome.fileSystem.chooseEntry) {
chrome.fileSystem.chooseEntry({
type: 'saveFile',
suggestedName: fileName,
accepts: [{
mimeTypes: [mimeType],
extensions: [ext]
}]
}, function (writableFileEntry) {
var downloadPromise = MtpApiFileManager.downloadFile(fullPhotoSize.location.dc_id, inputFileLocation, fullPhotoSize.size, {
mime: mimeType,
toFileEntry: writableFileEntry
});
downloadPromise.then(function (url) {
console.log('file save done');
}, function (e) {
console.log('photo download failed', e);
});
});
} else {
var downloadPromise = MtpApiFileManager.downloadFile(fullPhotoSize.location.dc_id, inputFileLocation, fullPhotoSize.size, {mime: mimeType});
downloadPromise.then(function (url) {
var a = $('<a>Download</a>')
.css({position: 'absolute', top: 1, left: 1})
.attr('href', url)
.attr('target', '_blank')
.attr('download', fileName)
.appendTo('body');
a[0].dataset.downloadurl = [mimeType, fileName, url].join(':');
a[0].click();
$timeout(function () {
a.remove();
}, 100);
}, function (e) {
console.log('photo download failed', e);
});
}
};
$rootScope.openPhoto = openPhoto;
@ -2131,7 +2190,8 @@ angular.module('myApp.services', []) @@ -2131,7 +2190,8 @@ angular.module('myApp.services', [])
preloadPhoto: preloadPhoto,
wrapForHistory: wrapForHistory,
wrapForFull: wrapForFull,
openPhoto: openPhoto
openPhoto: openPhoto,
downloadPhoto: downloadPhoto
}
})
@ -2263,7 +2323,10 @@ angular.module('myApp.services', []) @@ -2263,7 +2323,10 @@ angular.module('myApp.services', [])
extensions: [ext]
}]
}, function (writableFileEntry) {
var downloadPromise = MtpApiFileManager.downloadFile(video.dc_id, inputFileLocation, video.size, writableFileEntry, {mime: mimeType});
var downloadPromise = MtpApiFileManager.downloadFile(video.dc_id, inputFileLocation, video.size, {
mime: mimeType,
toFileEntry: writableFileEntry
});
downloadPromise.then(function (url) {
delete historyVideo.progress;
console.log('file save done');
@ -2275,7 +2338,7 @@ angular.module('myApp.services', []) @@ -2275,7 +2338,7 @@ angular.module('myApp.services', [])
historyVideo.progress.cancel = downloadPromise.cancel;
});
} else {
var downloadPromise = MtpApiFileManager.downloadFile(video.dc_id, inputFileLocation, video.size, null, {mime: mimeType});
var downloadPromise = MtpApiFileManager.downloadFile(video.dc_id, inputFileLocation, video.size, {mime: mimeType});
downloadPromise.then(function (url) {
delete historyVideo.progress;
@ -2404,7 +2467,10 @@ angular.module('myApp.services', []) @@ -2404,7 +2467,10 @@ angular.module('myApp.services', [])
extensions: [ext]
}]
}, function (writableFileEntry) {
var downloadPromise = MtpApiFileManager.downloadFile(doc.dc_id, inputFileLocation, doc.size, writableFileEntry, {mime: doc.mime_type});
var downloadPromise = MtpApiFileManager.downloadFile(doc.dc_id, inputFileLocation, doc.size, {
mime: doc.mime_type,
toFileEntry: writableFileEntry
});
downloadPromise.then(function (url) {
delete historyDoc.progress;
@ -2417,7 +2483,7 @@ angular.module('myApp.services', []) @@ -2417,7 +2483,7 @@ angular.module('myApp.services', [])
historyDoc.progress.cancel = downloadPromise.cancel;
});
} else {
var downloadPromise = MtpApiFileManager.downloadFile(doc.dc_id, inputFileLocation, doc.size, null, {mime: doc.mime_type});
var downloadPromise = MtpApiFileManager.downloadFile(doc.dc_id, inputFileLocation, doc.size, {mime: doc.mime_type});
downloadPromise.then(function (url) {
delete historyDoc.progress;
@ -2496,7 +2562,7 @@ angular.module('myApp.services', []) @@ -2496,7 +2562,7 @@ angular.module('myApp.services', [])
$rootScope.$broadcast('history_update');
}
var downloadPromise = MtpApiFileManager.downloadFile(audio.dc_id, inputFileLocation, audio.size, null, {mime: 'audio/ogg'});
var downloadPromise = MtpApiFileManager.downloadFile(audio.dc_id, inputFileLocation, audio.size, {mime: 'audio/ogg'});
downloadPromise.then(function (url) {
delete historyAudio.progress;

3
app/manifest.json

@ -12,7 +12,8 @@ @@ -12,7 +12,8 @@
"notifications",
"webview",
{"fileSystem": ["write"]},
"storage"
"storage",
"unlimitedStorage"
],
"icons": {
"16": "img/icons/icon16.png",

6
app/partials/head.html

@ -13,15 +13,15 @@ @@ -13,15 +13,15 @@
</div>
<div class="navbar-collapse collapse">
<div class="navbar-collapse collapse" ng-switch="offline">
<ul ng-if="offline" class="nav navbar-nav navbar-offline">
<ul ng-switch-when="true" class="nav navbar-nav navbar-offline">
<li ng-show="!offlineConnecting"><span class="navbar-offline-text">Waiting for network<span my-loading-dots></span></span></li>
<li ng-show="!offlineConnecting"><a href="" ng-click="retryOnline()">Retry</a></li>
<li ng-show="offlineConnecting"><span class="navbar-offline-text">Connecting<span my-loading-dots></span></span></li>
</ul>
<ul ng-if="!offline" class="nav navbar-nav navbar-right">
<ul ng-switch-default class="nav navbar-nav navbar-right">
<li ng-if="isLoggedIn"><a href="" ng-click="openContacts()">Contacts</a></li>
<li ng-if="isLoggedIn"><a href="" ng-click="openSettings()">Settings</a></li>
<li ng-if="isLoggedIn"><a href="" ng-click="logOut()">Log Out</a></li>

1
app/partials/photo_modal.html

@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
<div class="photo_modal_image_wrap" my-load-full-photo full-photo="photo.full" thumb-location="photo.thumb.location" ng-click="nav.next()"> </div>
<div class="media_modal_actions pull-right" ng-if="messageID">
<a href="" class="media_modal_action_link" ng-click="download()">Download</a>
<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>

6
app/partials/welcome.html

@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
<div class="container-fluid">
<div class="row">
<div class="col-md-4">
<div class="col-md-4 col-sm-4">
<div class="welcome_footer_card_wrap row">
<div class="welcome_footer_card welcome_footer_card_messaging"></div>
<h4>Fast messaging</h4>
@ -30,7 +30,7 @@ @@ -30,7 +30,7 @@
</div>
</div>
<div class="col-md-4">
<div class="col-md-4 col-sm-4">
<div class="welcome_footer_card_wrap">
<div class="welcome_footer_card welcome_footer_card_filesharing"></div>
<h4>Easy file sharing</h4>
@ -38,7 +38,7 @@ @@ -38,7 +38,7 @@
</div>
</div>
<div class="col-md-4">
<div class="col-md-4 col-sm-4">
<div class="welcome_footer_card_wrap">
<div class="welcome_footer_card welcome_footer_card_powerful"></div>
<h4>Powerful tools</h4>

Loading…
Cancel
Save