From 19b8bcfc83b0631d0ce1ef64fb26de341a93fa83 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Thu, 2 Jan 2014 10:11:27 +0000 Subject: [PATCH] allow uploading/deleting multiple documents, fixes #1960. replace select option with item aware add button, fixes #1961 --- pandora/document/views.py | 1 + static/js/deleteDocumentDialog.js | 14 +-- static/js/documentsDialog.js | 76 +++++++++-------- static/js/documentsView.js | 17 +--- static/js/uploadDocumentDialog.js | 136 ++++++++++++++++++------------ 5 files changed, 135 insertions(+), 109 deletions(-) diff --git a/pandora/document/views.py b/pandora/document/views.py index c97b3e46..f92532d2 100644 --- a/pandora/document/views.py +++ b/pandora/document/views.py @@ -250,6 +250,7 @@ def upload(request): chunk_id = form.cleaned_data['chunkId'] response = { 'result': 1, + 'id': file.get_id(), 'resultUrl': request.build_absolute_uri(file.get_absolute_url()) } if not file.save_chunk(c, chunk_id, form.cleaned_data['done']): diff --git a/static/js/deleteDocumentDialog.js b/static/js/deleteDocumentDialog.js index 482482f4..8fdac612 100644 --- a/static/js/deleteDocumentDialog.js +++ b/static/js/deleteDocumentDialog.js @@ -1,13 +1,13 @@ // vim: et:ts=4:sw=4:sts=4:ft=javascript 'use strict'; -pandora.ui.deleteDocumentDialog = function(file, callback) { +pandora.ui.deleteDocumentDialog = function(files, callback) { var that = pandora.ui.iconDialog({ buttons: [ Ox.Button({ id: 'keep', - title: Ox._('Keep Document') + title: files.length == 1 ? Ox._('Keep Document') : Ox._('Keep Documents') }).bindEvent({ click: function() { that.close(); @@ -15,19 +15,21 @@ pandora.ui.deleteDocumentDialog = function(file, callback) { }), Ox.Button({ id: 'delete', - title: Ox._('Delete Document') + title: files.length == 1 ? Ox._('Delete Document') : Ox._('Delete Documents') }).bindEvent({ click: function() { that.close(); pandora.api.removeDocument({ - id: file + ids: files }, callback); } }) ], - content: Ox._('Are you sure you want to delete the document "{0}"?', [file]), + content: files.length == 1 + ? Ox._('Are you sure you want to delete the document "{0}"?', [files[0]]) + : Ox._('Are you sure you want to delete {0} documents?', [files.length]), keys: {enter: 'delete', escape: 'keep'}, - title: Ox._('Delete Document') + title: files.length == 1 ? Ox._('Delete Document') : Ox._('Delete {0} Documents', [files.length]) }); return that; diff --git a/static/js/documentsDialog.js b/static/js/documentsDialog.js index 90ad0d5c..323daafe 100644 --- a/static/js/documentsDialog.js +++ b/static/js/documentsDialog.js @@ -2,9 +2,7 @@ 'use strict'; -pandora.ui.documentsDialog = function(options) { - options = options || {}; - +pandora.ui.documentsDialog = function() { var dialogHeight = Math.round((window.innerHeight - 48) * 0.9), dialogWidth = Math.round(window.innerWidth * 0.9), itemWidth = 272 + Ox.UI.SCROLLBAR_SIZE, @@ -155,6 +153,7 @@ pandora.ui.documentsDialog = function(options) { unique: 'id' }) .bindEvent({ + 'delete': deleteDocuments, init: function(data) { $status.html( Ox.toTitleCase(Ox.formatCount(data.items, 'file')) @@ -165,10 +164,8 @@ pandora.ui.documentsDialog = function(options) { }, select: function(data) { selected = data.ids[0]; + $addButton.options({disabled: data.ids.length == 0}); selectFile(); - options.callback && $doneButton.options({ - disabled: !data.ids.length - }); } }), @@ -219,30 +216,36 @@ pandora.ui.documentsDialog = function(options) { .css({float: 'left', margin: '4px'}) .hide() .bindEvent({ - click: deleteFile + click: deleteDocuments }) .appendTo($itemToolbar), + $addButton = Ox.Button({ + disabled: true, + id: 'add', + title: Ox._('Add'), + width: 48 + }).bindEvent({ + click: addDocuments + }), + $doneButton = Ox.Button({ - disabled: !!options.callback, id: 'done', - title: options.callback ? Ox._('Select') : Ox._('Done'), + title: Ox._('Done'), width: 48 }).bindEvent({ click: function() { - options.callback && options.callback($list.options('selected')); that.close(); } }), $uploadButton = Ox.FileButton({ - maxFiles: 1, - title: Ox._('Upload Document...'), + title: Ox._('Upload Documents...'), width: 128 }) .css({float: 'right', margin: '4px'}) .bindEvent({ - click: uploadFile + click: uploadDocuments }) .appendTo($itemToolbar), @@ -309,7 +312,7 @@ pandora.ui.documentsDialog = function(options) { }), that = Ox.Dialog({ - buttons: [$doneButton], + buttons: pandora.user.ui.item ? [$addButton, $doneButton] : [$doneButton], closeButton: true, content: $content, height: dialogHeight, @@ -341,9 +344,24 @@ pandora.ui.documentsDialog = function(options) { that.superClose(); }; - function deleteFile() { - pandora.ui.deleteDocumentDialog($list.options('selected')[0], function() { - Ox.Request.clearCache('findDocuments'); + function addDocuments() { + pandora.api.addDocument({ + item: pandora.user.ui.item, + ids: $list.options('selected') + }, function() { + Ox.Request.clearCache(); + if (pandora.user.ui.itemView == 'documents') { + //fixme just upload list here + //self.$documentsList.reloadList(); + pandora.$ui.contentPanel.replaceElement(1, + pandora.$ui.item = pandora.ui.item()); + } + }); + } + + function deleteDocuments() { + pandora.ui.deleteDocumentDialog($list.options('selected'), function() { + Ox.Request.clearCache(pandora.user.ui.item ? void 0 : 'findDocuments'); $list.reloadList(); }).open(); } @@ -528,28 +546,18 @@ pandora.ui.documentsDialog = function(options) { } : query}); } - function uploadFile(data) { - pandora.ui.uploadDocumentDialog(data.files[0], function(file) { - Ox.Request.clearCache('findDocuments'); - pandora.api.findDocuments({ - positions: [file.id], - query: $list.options('query'), - sort: $list.options('sort'), - }, function(data) { + function uploadDocuments(data) { + pandora.ui.uploadDocumentDialog(data.files, function(files) { + if (files) { + Ox.Request.clearCache('findDocuments'); $list.bindEventOnce({ load: function() { - $list.options({selected: [file.id]}); + $list.options({selected: [files.ids]}); // selectFile(file.id); } }); - if (data.data.positions[file.id] > -1) { - $list.reloadList(); - } else { - $list.options({ - query: {conditions: [], operator: '&'} - }); - } - }); + $list.reloadList(); + } }).open(); } diff --git a/static/js/documentsView.js b/static/js/documentsView.js index 44d5d0d7..03334bd6 100644 --- a/static/js/documentsView.js +++ b/static/js/documentsView.js @@ -148,22 +148,7 @@ pandora.ui.documentsView = function(options, self) { }); function addDocuments() { - pandora.$ui.documentsDialog = pandora.ui.documentsDialog({ - callback: function(ids) { - if (ids) { - pandora.api.addDocument({ - item: pandora.user.ui.item, - ids: ids - }, function() { - Ox.Request.clearCache(); - //fixme just upload list here - //self.$documentsList.reloadList(); - pandora.$ui.contentPanel.replaceElement(1, - pandora.$ui.item = pandora.ui.item()); - }); - } - } - }).open(); + pandora.$ui.documentsDialog = pandora.ui.documentsDialog().open(); } function renderPreview() { diff --git a/static/js/uploadDocumentDialog.js b/static/js/uploadDocumentDialog.js index 18d910c9..023e661b 100644 --- a/static/js/uploadDocumentDialog.js +++ b/static/js/uploadDocumentDialog.js @@ -1,16 +1,17 @@ // vim: et:ts=4:sw=4:sts=4:ft=javascript 'use strict'; -pandora.ui.uploadDocumentDialog = function(file, callback) { +pandora.ui.uploadDocumentDialog = function(files, callback) { - var extension = file.name.split('.').pop().toLowerCase(), + var extensions = files.map(function(file) { + return file.name.split('.').pop().toLowerCase() + }), - extensions = ['gif', 'jpg', 'jpeg', 'pdf', 'png'], + supportedExtensions = ['gif', 'jpg', 'jpeg', 'pdf', 'png'], - filename = file.name.split('.').slice(0, -1).join('.') + '.' - + (extension == 'jpeg' ? 'jpg' : extension), + filename, - id = pandora.user.username + ':' + filename, + ids = [], upload, @@ -19,7 +20,7 @@ pandora.ui.uploadDocumentDialog = function(file, callback) { $content = Ox.Element().css({margin: '16px'}), $text = $('
') - .html(Ox._('Uploading {0}', [file.name])) + .html(Ox._('Uploading {0}', [files[0].name])) .appendTo($content), $progress = Ox.Progressbar({ @@ -43,10 +44,10 @@ pandora.ui.uploadDocumentDialog = function(file, callback) { var title = this.options('title'); $uploadDialog.close(); if (title == Ox._('Cancel Upload')) { - upload.abort(); + upload && upload.abort(); } else if (title == Ox._('Done')) { callback({ - id: id + ids: ids }); } } @@ -56,57 +57,49 @@ pandora.ui.uploadDocumentDialog = function(file, callback) { height: 112, keys: {escape: 'close'}, width: 288, - title: Ox._('Upload File') + title: files.length == 1 + ? Ox._('Upload Document') + : Ox._('Upload {0} Documents', [files.length]) }) .bindEvent({ open: function() { - upload = pandora.chunkupload({ - data: { - filename: filename - }, - file: file, - url: '/api/upload/document/', - }) - .bindEvent({ - done: function(data) { - if (data.progress == 1) { - $uploadDialog.options('buttons')[0].options({title: Ox._('Done')}); - Ox.print('SUCCEEDED'); - } else { - $message.html(Ox._('Upload failed.')) - $uploadDialog.options('buttons')[0].options({title: Ox._('Close')}); - Ox.print('FAILED'); - } - }, - progress: function(data) { - $progress.options({progress: data.progress || 0}); - } - }); + uploadFile(0); } }); - if (!Ox.contains(extensions, extension)) { + if (!Ox.every(extensions, function(extension) { + return Ox.contains(supportedExtensions, extension) + })) { return errorDialog(Ox._('Supported file types are GIF, JPG, PNG and PDF.')); } else { - Ox.oshash(file, function(oshash) { - pandora.api.findDocuments({ - keys: ['id'], - query: { - conditions: [{key: 'oshash', value: oshash, operator: '=='}], - operator: '&' - }, - range: [0, 1], - sort: [{key: 'name', operator: '+'}] - }, function(result) { - if (result.data.items.length) { - errorDialog(filename == result.data.items[0].id - ? Ox._('The file {0} already exists', [filename]) - : Ox._('The file {0} already exists as {1}', [filename, result.data.items[0].id]) - ).open(); - } else { - $uploadDialog.open(); - } - }) + var valid = true; + Ox.parallelForEach(files, function(file, index, array, callback) { + var extension = file.name.split('.').pop().toLowerCase(), + filename = file.name.split('.').slice(0, -1).join('.') + '.' + + (extension == 'jpeg' ? 'jpg' : extension); + valid && Ox.oshash(file, function(oshash) { + pandora.api.findDocuments({ + keys: ['id', 'user', 'name', 'extension'], + query: { + conditions: [{key: 'oshash', value: oshash, operator: '=='}], + operator: '&' + }, + range: [0, 1], + sort: [{key: 'name', operator: '+'}] + }, function(result) { + if (result.data.items.length) { + var id = result.data.items[0].name + '.' + result.data.items[0].extension; + valid && errorDialog(filename == id + ? Ox._('The file {0} already exists', [filename]) + : Ox._('The file {0} already exists as {1}', [filename, id]) + ).open(); + valid = false; + } + callback(); + }) + }); + } ,function() { + valid && $uploadDialog.open(); }); return {open: Ox.noop}; } @@ -125,9 +118,46 @@ pandora.ui.uploadDocumentDialog = function(file, callback) { }) ], content: text, - title: Ox._('Upload File') + title: Ox._('Upload Document') }); } + function uploadFile(part) { + var file = files[part], + extension = file.name.split('.').pop().toLowerCase(), + filename = file.name.split('.').slice(0, -1).join('.') + '.' + + (extension == 'jpeg' ? 'jpg' : extension); + + $text.html(Ox._('Uploading {0}', [file.name])); + upload = pandora.chunkupload({ + data: { + filename: filename + }, + file: file, + url: '/api/upload/document/', + }) + .bindEvent({ + done: function(data) { + if (data.progress == 1) { + part++; + if (part == files.length) { + $progress.options({progress: data.progress}); + $uploadDialog.options('buttons')[0].options({title: Ox._('Done')}); + ids.push(data.id); + } else { + uploadFile(part); + } + } else { + $message.html(Ox._('Upload failed.')) + $uploadDialog.options('buttons')[0].options({title: Ox._('Close')}); + } + }, + progress: function(data) { + var progress = data.progress || 0; + progress = part/files.length + 1/files.length * progress; + $progress.options({progress: progress}); + } + }); + } };