From 56826f67fc6588297c0b71d5efe1fbed3862b193 Mon Sep 17 00:00:00 2001 From: Ozzieisaacs Date: Sat, 16 Feb 2019 10:05:51 +0100 Subject: [PATCH] progressbar during upload thanks to jim3ma --- cps/static/css/upload.css | 8 ++ cps/static/js/uploadprogress.js | 198 ++++++++++++++++++++++++++++++++ cps/templates/layout.html | 22 ++-- cps/ub.py | 2 + cps/web.py | 18 +-- 5 files changed, 222 insertions(+), 26 deletions(-) create mode 100644 cps/static/css/upload.css create mode 100644 cps/static/js/uploadprogress.js diff --git a/cps/static/css/upload.css b/cps/static/css/upload.css new file mode 100644 index 00000000..8192bd39 --- /dev/null +++ b/cps/static/css/upload.css @@ -0,0 +1,8 @@ +@media (min-device-width: 768px) { + .modal-dialog { + position: absolute; + top: 45%; + left: 50%; + transform: translate(-50%, -50%) !important; + } +} diff --git a/cps/static/js/uploadprogress.js b/cps/static/js/uploadprogress.js new file mode 100644 index 00000000..b28d17f3 --- /dev/null +++ b/cps/static/js/uploadprogress.js @@ -0,0 +1,198 @@ +/* + * bootstrap-uploadprogress + * github: https://github.com/jakobadam/bootstrap-uploadprogress + * + * Copyright (c) 2015 Jakob Aarøe Dam + * Version 1.0.0 + * Licensed under the MIT license. + */ +(function($){ + "use strict"; + + $.support.xhrFileUpload = !!(window.FileReader && window.ProgressEvent); + $.support.xhrFormData = !!window.FormData; + + if(!$.support.xhrFileUpload || !$.support.xhrFormData){ + // skip decorating form + return; + } + + var template = ''; + + var UploadProgress = function(element, options){ + this.options = options; + this.$element = $(element); + }; + + UploadProgress.prototype = { + + constructor: function() { + this.$form = this.$element; + this.$form.on('submit', $.proxy(this.submit, this)); + this.$modal = $(this.options.template); + this.$modal_message = this.$modal.find('.modal-message'); + this.$modal_title = this.$modal.find('.modal-title'); + this.$modal_footer = this.$modal.find('.modal-footer'); + this.$modal_bar = this.$modal.find('.progress-bar'); + + this.$modal.on('hidden.bs.modal', $.proxy(this.reset, this)); + }, + + reset: function(){ + this.$modal_title = this.$modal_title.text('Uploading'); + this.$modal_footer.hide(); + this.$modal_bar.addClass('progress-bar-success'); + this.$modal_bar.removeClass('progress-bar-danger'); + if(this.xhr){ + this.xhr.abort(); + } + }, + + submit: function(e) { + e.preventDefault(); + + this.$modal.modal({ + backdrop: 'static', + keyboard: false + }); + + // We need the native XMLHttpRequest for the progress event + var xhr = new XMLHttpRequest(); + this.xhr = xhr; + + xhr.addEventListener('load', $.proxy(this.success, this, xhr)); + xhr.addEventListener('error', $.proxy(this.error, this, xhr)); + //xhr.addEventListener('abort', function(){}); + + xhr.upload.addEventListener('progress', $.proxy(this.progress, this)); + + var form = this.$form; + + xhr.open(form.attr('method'), form.attr("action")); + xhr.setRequestHeader('X-REQUESTED-WITH', 'XMLHttpRequest'); + + var data = new FormData(form.get(0)); + xhr.send(data); + }, + + success: function(xhr) { + if(xhr.status == 0 || xhr.status >= 400){ + // HTTP 500 ends up here!?! + return this.error(xhr); + } + this.set_progress(100); + var url; + var content_type = xhr.getResponseHeader('Content-Type'); + + // make it possible to return the redirect URL in + // a JSON response + if(content_type.indexOf('application/json') !== -1){ + var response = $.parseJSON(xhr.responseText); + console.log(response); + url = response.location; + } + else{ + url = this.options.redirect_url; + } + window.location.href = url; + }, + + // handle form error + // we replace the form with the returned one + error: function(xhr){ + this.$modal_title.text('Upload failed'); + + this.$modal_bar.removeClass('progress-bar-success'); + this.$modal_bar.addClass('progress-bar-danger'); + this.$modal_footer.show(); + + var content_type = xhr.getResponseHeader('Content-Type'); + + // Replace the contents of the form, with the returned html + if(xhr.status === 422){ + var new_html = $.parseHTML(xhr.responseText); + this.replace_form(new_html); + this.$modal.modal('hide'); + } + // Write the error response to the document. + else{ + var response_text = xhr.responseText; + if(content_type.indexOf('text/plain') !== -1){ + response_text = '
' + response_text + '
'; + } + document.write(xhr.responseText); + } + }, + + set_progress: function(percent){ + var txt = percent + '%'; + if (percent == 100) { + txt = this.options.uploaded_msg; + } + this.$modal_bar.attr('aria-valuenow', percent); + this.$modal_bar.text(txt); + this.$modal_bar.css('width', percent + '%'); + }, + + progress: function(/*ProgressEvent*/e){ + var percent = Math.round((e.loaded / e.total) * 100); + this.set_progress(percent); + }, + + // replace_form replaces the contents of the current form + // with the form in the html argument. + // We use the id of the current form to find the new form in the html + replace_form: function(html){ + var new_form; + var form_id = this.$form.attr('id'); + if(form_id !== undefined){ + new_form = $(html).find('#' + form_id); + } + else{ + new_form = $(html).find('form'); + } + + // add the filestyle again + new_form.find(':file').filestyle({buttonBefore: true}); + this.$form.html(new_form.children()); + } + }; + + $.fn.uploadprogress = function(options, value){ + return this.each(function(){ + var _options = $.extend({}, $.fn.uploadprogress.defaults, options); + var file_progress = new UploadProgress(this, _options); + file_progress.constructor(); + }); + }; + + $.fn.uploadprogress.defaults = { + template: template, + uploaded_msg: "Upload done, processing, please wait..." + //redirect_url: ... + + // need to customize stuff? Add here, and change code accordingly. + }; + +})(window.jQuery); diff --git a/cps/templates/layout.html b/cps/templates/layout.html index 5a340672..94b1e7ee 100644 --- a/cps/templates/layout.html +++ b/cps/templates/layout.html @@ -12,6 +12,7 @@ + {% if g.current_theme == 1 %} {% endif %} @@ -103,14 +104,6 @@ {%endif%} {% endfor %} -
{% if g.user.is_authenticated or g.user.is_anonymous %} @@ -240,6 +233,7 @@ + {% if g.current_theme == 1 %} @@ -247,12 +241,12 @@ {% endif %} {% block js %}{% endblock %} diff --git a/cps/ub.py b/cps/ub.py index 26451564..698a3be8 100644 --- a/cps/ub.py +++ b/cps/ub.py @@ -568,6 +568,8 @@ class Config: # everywhere to curent should work. Migration is done by checking if relevant coloums are existing, and than adding # rows with SQL commands def migrate_Database(): + if not engine.dialect.has_table(engine.connect(), "book_read_link"): + ReadBook.__table__.create(bind=engine) if not engine.dialect.has_table(engine.connect(), "bookmark"): Bookmark.__table__.create(bind=engine) if not engine.dialect.has_table(engine.connect(), "registration"): diff --git a/cps/web.py b/cps/web.py index a643913a..2aeb78ad 100644 --- a/cps/web.py +++ b/cps/web.py @@ -3862,19 +3862,13 @@ def upload(): for author in db_book.authors: author_names.append(author.name) if len(request.files.getlist("btn-upload")) < 2: - cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns. - datatype.notin_(db.cc_exceptions)).all() if current_user.role_edit() or current_user.role_admin(): - return render_title_template('book_edit.html', book=book, authors=author_names, - cc=cc, title=_(u"edit metadata"), page="upload") - book_in_shelfs = [] - kindle_list = helper.check_send_to_kindle(book) - reader_list = helper.check_read_formats(book) - - return render_title_template('detail.html', entry=book, cc=cc, - title=book.title, books_shelfs=book_in_shelfs, kindle_list=kindle_list, - reader_list=reader_list, page="upload") - return redirect(url_for("index")) + resp = {"location": url_for('edit_book', book_id=db_book.id)} + return Response(json.dumps(resp), mimetype='application/json') + else: + resp = {"location": url_for('show_book', book_id=db_book.id)} + return Response(json.dumps(resp), mimetype='application/json') + return Response(json.dumps({"location": url_for("index")}), mimetype='application/json') @app.route("/admin/book/convert/", methods=['POST'])