function AnalyseAlbumViewModel() { var self = this; self.imagesFailed = ko.observableArray(); self.imagesToAnalyse = 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) { // changes[0].value is an instance of AnalyseImageViewModel var item = changes[0].value; $.ajax( item.url(), { 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); } 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 '; if (!self.isPending()) { 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.isSubmitting = false; /* 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.replace(':number', self.photoIDs().length), title: language.delete_bulk_confirm_title.replace(':number', self.photoIDs().length), 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 = $('') .attr('name', 'album_id') .addClass('form-control'); for (var i = 0; i < albums.length; i++) { var 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: $('
').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.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); }; }