624 lines
19 KiB
JavaScript
624 lines
19 KiB
JavaScript
function AnalyseAlbumViewModel() {
|
|
var self = this;
|
|
|
|
self.imagesFailed = ko.observableArray();
|
|
self.imagesToAnalyse = ko.observableArray();
|
|
self.imagesInProgress = ko.observableArray();
|
|
self.imagesRecentlyCompleted = ko.observableArray();
|
|
self.numberSuccessful = ko.observable(0);
|
|
self.numberFailed = ko.observable(0);
|
|
|
|
self.numberTotal = ko.computed(function () {
|
|
return self.imagesToAnalyse().length;
|
|
});
|
|
|
|
self.failedPercentage = ko.computed(function () {
|
|
return ((self.numberFailed() / self.numberTotal()) * 100).toFixed(2) + '%';
|
|
});
|
|
self.successfulPercentage = ko.computed(function () {
|
|
return ((self.numberSuccessful() / self.numberTotal()) * 100).toFixed(2) + '%';
|
|
});
|
|
|
|
self.isCompleted = ko.computed(function () {
|
|
return self.numberTotal() > 0 && (self.numberSuccessful() + self.numberFailed() >= self.numberTotal());
|
|
});
|
|
|
|
// When an image is added to the array, automatically issue it for analysis
|
|
self.imagesToAnalyse.subscribe(function (changes) {
|
|
// We only care about additions
|
|
if (changes[0].status !== 'added')
|
|
{
|
|
return;
|
|
}
|
|
|
|
// changes[0].value is an instance of AnalyseImageViewModel
|
|
var item = changes[0].value;
|
|
$.ajax(
|
|
item.url(),
|
|
{
|
|
beforeSend: function() {
|
|
self.imagesInProgress.push(item);
|
|
},
|
|
dataType: 'json',
|
|
error: function (xhr, textStatus, errorThrown) {
|
|
self.numberFailed(self.numberFailed() + 1);
|
|
self.imagesFailed.push({
|
|
'name': item.name(),
|
|
'reason': textStatus
|
|
});
|
|
item.isSuccessful(false);
|
|
item.isPending(false);
|
|
},
|
|
method: 'POST',
|
|
success: function (data) {
|
|
if (data.is_successful) {
|
|
self.numberSuccessful(self.numberSuccessful() + 1);
|
|
item.isSuccessful(true);
|
|
item.isPending(false);
|
|
|
|
// Push into our "recently completed" array
|
|
self.imagesRecentlyCompleted.push(item);
|
|
self.imagesInProgress.remove(item);
|
|
|
|
// Remove it again after a few seconds
|
|
window.setTimeout(function() {
|
|
self.imagesRecentlyCompleted.remove(item);
|
|
}, 2000);
|
|
}
|
|
else {
|
|
self.numberFailed(self.numberFailed() + 1);
|
|
self.imagesFailed.push({
|
|
'name': item.name(),
|
|
'reason': data.message
|
|
});
|
|
item.isSuccessful(false);
|
|
item.isPending(false);
|
|
}
|
|
}
|
|
}
|
|
);
|
|
}, null, 'arrayChange');
|
|
}
|
|
|
|
function AnalyseImageViewModel(image_info) {
|
|
var self = this;
|
|
|
|
self.isPending = ko.observable(true);
|
|
self.isSuccessful = ko.observable(false);
|
|
self.name = ko.observable(image_info.name);
|
|
self.photoID = ko.observable(image_info.photo_id);
|
|
self.url = ko.observable(image_info.url);
|
|
|
|
self.iconClass = ko.computed(function () {
|
|
var string = 'fa fa-fw fa-';
|
|
|
|
if (self.isPending()) {
|
|
string += 'refresh';
|
|
}
|
|
else {
|
|
string += (self.isSuccessful() ? 'check text-success' : 'times text-danger')
|
|
}
|
|
|
|
return string;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* This model is used by admin/show_album.blade.php to handle photo changes.
|
|
* @param album_id ID of the album the photos are in
|
|
* @param language Array containing language strings
|
|
* @param urls Array containing URLs
|
|
* @constructor
|
|
*/
|
|
function EditPhotosViewModel(album_id, language, urls) {
|
|
var self = this;
|
|
|
|
self.albums = ko.observableArray();
|
|
self.bulkModifyMethod = ko.observable();
|
|
self.photoIDs = ko.observableArray();
|
|
self.photoIDsAvailable = ko.observableArray();
|
|
self.isSubmitting = false;
|
|
self.selectAllInAlbum = ko.observable(0);
|
|
|
|
// When a photo is un-selected, remove the "select all in album" flag as the user has overridden the selection
|
|
self.photoIDs.subscribe(function (changes)
|
|
{
|
|
if (changes[0].status !== 'deleted')
|
|
{
|
|
return;
|
|
}
|
|
|
|
self.selectAllInAlbum(0);
|
|
}, null, 'arrayChange');
|
|
|
|
/* Called when the Apply button on the "bulk apply selected actions" form is clicked */
|
|
self.bulkModifySelected = function()
|
|
{
|
|
if (self.isSubmitting)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
var bulk_form = $('form#bulk-modify-form');
|
|
|
|
if (self.bulkModifyMethod() == 'change_album')
|
|
{
|
|
// Prompt for the new album to move to
|
|
self.promptForNewAlbum(function(dialog) {
|
|
var album_id = $('select', dialog).val();
|
|
$('input[name="new-album-id"]', bulk_form).val(album_id);
|
|
|
|
self.isSubmitting = true;
|
|
$('button[name="bulk-apply"]', bulk_form).click();
|
|
_bt_showLoadingModal();
|
|
});
|
|
|
|
return false;
|
|
}
|
|
else if (self.bulkModifyMethod() == 'delete')
|
|
{
|
|
// Prompt for a confirmation - are you sure?!
|
|
bootbox.dialog({
|
|
message: language.delete_bulk_confirm_message,
|
|
title: language.delete_bulk_confirm_title,
|
|
buttons: {
|
|
cancel: {
|
|
label: language.action_cancel,
|
|
className: "btn-default"
|
|
},
|
|
confirm: {
|
|
label: language.action_delete,
|
|
className: "btn-danger",
|
|
callback: function() {
|
|
self.isSubmitting = true;
|
|
$('button[name="bulk-apply"]', bulk_form).click();
|
|
_bt_showLoadingModal();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
return false;
|
|
}
|
|
|
|
// All other methods submit the form as normal
|
|
return true;
|
|
};
|
|
|
|
self.changeAlbum = function()
|
|
{
|
|
self.selectPhotoSingle(this);
|
|
|
|
var photo_id = self.photoIDs()[0];
|
|
self.photoIDs.removeAll();
|
|
|
|
self.promptForNewAlbum(function(dialog) {
|
|
var album_id = $('select', dialog).val();
|
|
$.post(urls.move_photo.replace(/\/0$/, '/' + photo_id), { 'new_album_id': album_id }, function()
|
|
{
|
|
window.location.reload();
|
|
});
|
|
_bt_showLoadingModal();
|
|
});
|
|
|
|
return false;
|
|
};
|
|
|
|
self.delete = function() {
|
|
self.selectPhotoSingle(this);
|
|
|
|
var photo_id = self.photoIDs()[0];
|
|
self.photoIDs.removeAll();
|
|
|
|
bootbox.dialog({
|
|
message: language.delete_confirm_message,
|
|
title: language.delete_confirm_title,
|
|
buttons: {
|
|
cancel: {
|
|
label: language.action_cancel,
|
|
className: "btn-default"
|
|
},
|
|
confirm: {
|
|
label: language.action_delete,
|
|
className: "btn-danger",
|
|
callback: function() {
|
|
var url = urls.delete_photo;
|
|
url = url.replace(/\/0$/, '/' + photo_id);
|
|
|
|
$('.loading', parent).show();
|
|
|
|
$.post(url, {'_method': 'DELETE'}, function(data)
|
|
{
|
|
window.location.reload();
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
return false;
|
|
};
|
|
|
|
self.flip = function(horizontal, vertical, parent)
|
|
{
|
|
var url = urls.flip_photo;
|
|
url = url.replace('/0/', '/' + self.photoIDs()[0] + '/');
|
|
|
|
if (horizontal)
|
|
{
|
|
url = url.replace(/\/-1\//, '/1/');
|
|
}
|
|
else
|
|
{
|
|
url = url.replace(/\/-1\//, '/0/');
|
|
}
|
|
|
|
if (vertical)
|
|
{
|
|
url = url.replace(/\/-2$/, '/1');
|
|
}
|
|
else
|
|
{
|
|
url = url.replace(/\/-2$/, '/0');
|
|
}
|
|
|
|
$('.loading', parent).show();
|
|
$.post(url, function()
|
|
{
|
|
var image = $('img.photo-thumbnail', parent);
|
|
var originalUrl = image.data('original-src');
|
|
image.attr('src', originalUrl + "&_=" + new Date().getTime());
|
|
|
|
$('.loading', parent).hide();
|
|
});
|
|
|
|
self.photoIDs.removeAll();
|
|
};
|
|
|
|
self.flipBoth = function() {
|
|
self.selectPhotoSingle(this);
|
|
self.flip(true, true, $(this).parents('.photo'));
|
|
|
|
return false;
|
|
};
|
|
|
|
self.flipHorizontal = function() {
|
|
self.selectPhotoSingle(this);
|
|
self.flip(true, false, $(this).parents('.photo'));
|
|
|
|
return false;
|
|
};
|
|
|
|
self.flipVertical = function() {
|
|
self.selectPhotoSingle(this);
|
|
self.flip(false, true, $(this).parents('.photo'));
|
|
|
|
return false;
|
|
};
|
|
|
|
self.promptForNewAlbum = function(callback_on_selected)
|
|
{
|
|
var albums = self.albums();
|
|
var select = $('<select/>')
|
|
.attr('name', 'album_id')
|
|
.addClass('form-control');
|
|
|
|
for (var i = 0; i < albums.length; i++)
|
|
{
|
|
var option = $('<option/>')
|
|
.attr('value', albums[i].id)
|
|
.html(albums[i].name)
|
|
.appendTo(select);
|
|
|
|
// Pre-select the current album
|
|
if (album_id == albums[i].id)
|
|
{
|
|
option.attr('selected', 'selected');
|
|
}
|
|
}
|
|
|
|
bootbox.dialog({
|
|
message: $('<p/>').html(language.change_album_message).prop('outerHTML') + select.prop('outerHTML'),
|
|
title: language.change_album_title,
|
|
buttons:
|
|
{
|
|
cancel:
|
|
{
|
|
label: language.action_cancel,
|
|
className: 'btn-default'
|
|
},
|
|
confirm:
|
|
{
|
|
label: language.action_continue,
|
|
className: 'btn-success',
|
|
callback: function()
|
|
{
|
|
callback_on_selected(this);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
self.regenerateThumbnails = function()
|
|
{
|
|
self.selectPhotoSingle(this);
|
|
var parent = $(this).parents('.photo');
|
|
|
|
var url = urls.regenerate_thumbnails;
|
|
url = url.replace(/\/0$/, '/' + self.photoIDs()[0]);
|
|
|
|
$('.loading', parent).show();
|
|
$.post(url, function()
|
|
{
|
|
var image = $('img.photo-thumbnail', parent);
|
|
var originalUrl = image.data('original-src');
|
|
image.attr('src', originalUrl + "&_=" + new Date().getTime());
|
|
|
|
$('.loading', parent).hide();
|
|
});
|
|
|
|
self.photoIDs.removeAll();
|
|
return false;
|
|
};
|
|
|
|
self.rotate = function(angle, parent)
|
|
{
|
|
var url = urls.rotate_photo;
|
|
url = url.replace('/0/', '/' + self.photoIDs()[0] + '/');
|
|
url = url.replace(/\/1$/, '/' + angle);
|
|
|
|
$('.loading', parent).show();
|
|
$.post(url, function()
|
|
{
|
|
var image = $('img.photo-thumbnail', parent);
|
|
var originalUrl = image.data('original-src');
|
|
image.attr('src', originalUrl + "&_=" + new Date().getTime());
|
|
|
|
$('.loading', parent).hide();
|
|
self.photoIDs.removeAll();
|
|
});
|
|
|
|
self.photoIDs.removeAll();
|
|
};
|
|
|
|
self.rotateLeft = function()
|
|
{
|
|
self.selectPhotoSingle(this);
|
|
self.rotate(90, $(this).parents('.photo'));
|
|
|
|
return false;
|
|
};
|
|
|
|
self.rotateRight = function()
|
|
{
|
|
self.selectPhotoSingle(this);
|
|
self.rotate(270, $(this).parents('.photo'));
|
|
|
|
return false;
|
|
};
|
|
|
|
self.selectAll = function() {
|
|
bootbox.dialog({
|
|
title: language.select_all_choice_title,
|
|
message: language.select_all_choice_message,
|
|
buttons: {
|
|
select_all: {
|
|
label: language.select_all_choice_all_action,
|
|
className: 'btn-default',
|
|
callback: function()
|
|
{
|
|
self.selectAllInAlbum(1);
|
|
for (i = 0; i < self.photoIDsAvailable().length; i++)
|
|
{
|
|
self.photoIDs.push(self.photoIDsAvailable()[i]);
|
|
}
|
|
}
|
|
},
|
|
select_visible: {
|
|
label: language.select_all_choice_visible_action,
|
|
className: 'btn-primary',
|
|
callback: function()
|
|
{
|
|
self.selectAllInAlbum(0);
|
|
for (photoID in self.photoIDsAvailable())
|
|
{
|
|
self.photoIDs.push(photoID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
return false;
|
|
};
|
|
|
|
self.selectNone = function() {
|
|
self.photoIDs.removeAll();
|
|
self.selectAllInAlbum(0);
|
|
|
|
return false;
|
|
};
|
|
|
|
self.selectPhotoSingle = function (link_item) {
|
|
// Get the photo ID from the clicked link
|
|
var parent = $(link_item).parents('.photo');
|
|
var photo_id = $(parent).data('photo-id');
|
|
|
|
// Save the photo ID
|
|
self.photoIDs.removeAll();
|
|
self.photoIDs.push(photo_id);
|
|
|
|
// Hide the dropdown
|
|
$(link_item).dropdown('toggle');
|
|
};
|
|
}
|
|
|
|
function SlideShowViewModel(required_timeout_ms) {
|
|
var self = this;
|
|
|
|
self.current = ko.observable();
|
|
self.currentIndex = ko.observable(0);
|
|
self.images = ko.observableArray();
|
|
self.interval = null;
|
|
|
|
self.isRunning = ko.observable(false);
|
|
self.isPaused = ko.observable(false);
|
|
|
|
self.changeCurrentImage = function(photo_id)
|
|
{
|
|
for (var i = 0; i < self.images().length; i++)
|
|
{
|
|
var this_image = self.images()[i];
|
|
if (this_image.id == photo_id)
|
|
{
|
|
self.current(this_image);
|
|
self.currentIndex(i);
|
|
window.clearInterval(self.interval);
|
|
self.interval = window.setInterval(self.rotateNextImage, required_timeout_ms);
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
self.continueSlideshow = function() {
|
|
self.isPaused(false);
|
|
self.interval = window.setInterval(self.rotateNextImage, required_timeout_ms);
|
|
};
|
|
|
|
self.pauseSlideshow = function() {
|
|
self.isPaused(true);
|
|
window.clearInterval(self.interval);
|
|
};
|
|
|
|
self.rotateNextImage = function() {
|
|
var next_index = self.currentIndex() + 1;
|
|
if (next_index >= self.images().length)
|
|
{
|
|
next_index = 0;
|
|
}
|
|
|
|
self.current(self.images()[next_index]);
|
|
self.currentIndex(next_index);
|
|
};
|
|
|
|
self.startSlideshow = function() {
|
|
if (self.images().length <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
self.interval = window.setInterval(self.rotateNextImage, required_timeout_ms);
|
|
|
|
self.current(self.images()[0]);
|
|
self.isRunning(true);
|
|
};
|
|
}
|
|
|
|
function StorageLocationsViewModel() {
|
|
var self = this;
|
|
|
|
self.selectedLocation = ko.observable(true);
|
|
}
|
|
|
|
/**
|
|
* This model is used by admin/show_album.blade.php to handle photo uploads.
|
|
* @param album_id ID of the album the photos are being uploaded to
|
|
* @param queue_token Unique token of the upload queue to save the photos to
|
|
* @param language Array containing language strings
|
|
* @param urls Array containing URLs
|
|
* @constructor
|
|
*/
|
|
function UploadPhotosViewModel(album_id, queue_token, language, urls) {
|
|
var self = this;
|
|
|
|
self.currentStatus = ko.observable('');
|
|
self.imagesFailed = ko.observable(0);
|
|
self.imagesUploaded = ko.observable(0);
|
|
self.imagesTotal = ko.observable(0);
|
|
self.isBulkUploadInProgress = ko.observable(false);
|
|
self.isUploadInProgress = ko.observable(false);
|
|
self.statusMessages = ko.observableArray();
|
|
|
|
self.failedPercentage = ko.computed(function () {
|
|
return ((self.imagesFailed() / self.imagesTotal()) * 100).toFixed(2) + '%';
|
|
});
|
|
|
|
// This method is called when an image is uploaded - regardless if it fails or not
|
|
self.onUploadCompleted = function () {
|
|
self.currentStatus(language.upload_status
|
|
.replace(':current', (self.imagesUploaded() + self.imagesFailed()))
|
|
.replace(':total', self.imagesTotal()));
|
|
|
|
if ((self.imagesFailed() + self.imagesUploaded()) >= self.imagesTotal()) {
|
|
self.isUploadInProgress(false);
|
|
|
|
if (self.imagesFailed() == 0 && self.imagesUploaded() > 0) {
|
|
window.location = urls.analyse;
|
|
}
|
|
}
|
|
};
|
|
|
|
// This method is called when an uploaded image fails
|
|
self.onUploadFailed = function (data, file_name) {
|
|
self.imagesFailed(self.imagesFailed() + 1);
|
|
self.statusMessages.push({
|
|
'message_class': 'text-danger',
|
|
'message_text': language.image_failed.replace(':file_name', file_name)
|
|
});
|
|
self.onUploadCompleted();
|
|
};
|
|
|
|
// This method is called when an uploaded image succeeds
|
|
self.onUploadSuccessful = function (data, file_name) {
|
|
if (data.is_successful) {
|
|
self.imagesUploaded(self.imagesUploaded() + 1);
|
|
// Don't add to statusMessages() array so user only sees errors
|
|
/*self.statusMessages.push({
|
|
'message_class': 'text-success',
|
|
'message_text': language.image_uploaded.replace(':file_name', file_name)
|
|
});*/
|
|
self.onUploadCompleted();
|
|
}
|
|
else {
|
|
self.onUploadFailed(data, file_name);
|
|
}
|
|
};
|
|
|
|
self.startUpload = function (number_images) {
|
|
self.currentStatus('');
|
|
self.statusMessages.removeAll();
|
|
self.imagesUploaded(0);
|
|
self.imagesFailed(0);
|
|
self.imagesTotal(number_images);
|
|
self.isUploadInProgress(true);
|
|
};
|
|
|
|
self.successfulPercentage = ko.computed(function () {
|
|
return ((self.imagesUploaded() / self.imagesTotal()) * 100).toFixed(2) + '%';
|
|
});
|
|
|
|
self.uploadFile = function uploadImageFile(formObject, imageFile) {
|
|
var formData = new FormData();
|
|
formData.append('album_id', album_id);
|
|
formData.append('queue_token', queue_token);
|
|
formData.append('photo[]', imageFile, imageFile.name);
|
|
|
|
$.ajax(
|
|
{
|
|
contentType: false,
|
|
data: formData,
|
|
error: function (data) {
|
|
self.onUploadFailed(data, imageFile.name);
|
|
},
|
|
method: $(formObject).attr('method'),
|
|
processData: false,
|
|
success: function (data) {
|
|
self.onUploadSuccessful(data, imageFile.name);
|
|
},
|
|
url: $(formObject).attr('action')
|
|
}
|
|
);
|
|
viewModel.isUploadInProgress(true);
|
|
};
|
|
} |