diff --git a/src/calibre/srv/cdb.py b/src/calibre/srv/cdb.py index 49176f43b0..473421f8ff 100644 --- a/src/calibre/srv/cdb.py +++ b/src/calibre/srv/cdb.py @@ -82,6 +82,7 @@ def cdb_add_book(ctx, rd, job_id, add_duplicates, filename, library_id): add_duplicates = add_duplicates in ('y', '1') path = os.path.join(rd.tdir, sfilename) rd.request_body_file.name = path + rd.request_body_file.seek(0) mi = get_metadata(rd.request_body_file, stream_type=fmt, use_libprs_metadata=True) rd.request_body_file.seek(0) ids, duplicates = db.add_books([(mi, {fmt: rd.request_body_file})], add_duplicates=add_duplicates) diff --git a/src/pyj/ajax.pyj b/src/pyj/ajax.pyj index c4dbea43a2..341ce5c95b 100644 --- a/src/pyj/ajax.pyj +++ b/src/pyj/ajax.pyj @@ -126,10 +126,7 @@ def ajax_send_file(path, file, on_complete, on_progress, timeout=None, ok_code=2 xhr = ajax(path, on_complete, on_progress, False, 'POST', timeout, ok_code) if file.type: xhr.overrideMimeType(file.type) - r = FileReader() - r.onload = def(evt): - xhr.send(evt.target.result) - r.readAsBinaryString(file) + xhr.send(file) return xhr diff --git a/src/pyj/book_list/add.pyj b/src/pyj/book_list/add.pyj index e819304c53..529a5ae153 100644 --- a/src/pyj/book_list/add.pyj +++ b/src/pyj/book_list/add.pyj @@ -2,25 +2,41 @@ # License: GPL v3 Copyright: 2018, Kovid Goyal from __python__ import bound_methods, hash_literals +from elementmaker import E from gettext import gettext as _ from ajax import ajax_send_file from book_list.library_data import loaded_books_query from book_list.router import back from book_list.top_bar import create_top_bar -from dom import ensure_id +from book_list.ui import query_as_href, show_panel +from dom import clear, ensure_id from file_uploads import ( update_status_widget, upload_files_widget, upload_status_widget ) +from session import get_interface_data +from utils import safe_set_inner_html +from widgets import create_button state = { 'in_progress': False, 'container_id': None, 'counter': 0, + 'number': 0, 'fake_send': False, + 'transfers': v'[]', } + +def cancel_in_progress(): + for xhr in state.transfers: + xhr.abort() + state.transfers = v'[]' + state.in_progress = False + + def on_close(): + cancel_in_progress() back() @@ -31,16 +47,66 @@ def get_job_container(container_id, job_id): return container.querySelector(f'[data-job="{job_id}"]') -def on_progress(container_id, job_id): +def on_progress(container_id, job_id, loaded, total, xhr): container = get_job_container(container_id, job_id) if container is None: return + if total: + update_status_widget(container, loaded, total) -def on_complete(container_id, job_id): +def list_added_book(container, data): + container.appendChild(E.h3(E.b(data.title), E.span(' ' + _('by') + ' '), E.i(' & '.join(data.authors)))) + container.appendChild(E.span(_('Added successfully') + ' ')) + q = {'book_id': data.book_id + ''} + a = create_button(_('Open'), action=query_as_href(q, 'book_details')) + if state.number > 1: + a.setAttribute('target', '_blank') + else: + a.addEventListener('click', def(e): + e.preventDefault() + show_panel('book_details', {'book_id': data.book_id + ''}, True) + ) + container.appendChild(a) + + +def list_duplicate_book(container, container_id, job_id, data, file): + container.appendChild(E.div(style="padding: 1rem 1ex", _('A book with the title "{0}" already exists in the library.').format(data.title))) + b = create_button(_('Add anyway'), action=def(): + c = get_job_container(container_id, job_id) + clear(c) + w = upload_status_widget(file.name, job_id) + c.appendChild(w) + send_file(file, container_id, job_id, True) + ) + container.appendChild(b) + + +def on_complete(container_id, job_id, end_type, xhr, ev): + idx = state.transfers.indexOf(xhr) + if idx > -1: + state.transfers.splice(idx, 1) container = get_job_container(container_id, job_id) if container is None: return + clear(container) + if end_type is 'load': + data = JSON.parse(xhr.responseText) + if data.book_id: + list_added_book(container, data) + else: + list_duplicate_book(container, container_id, job_id, data, this) + elif end_type is 'abort': + return + else: + html = _('Failed to upload the file: {}').format(this.name) + '
' + if xhr.status is 403: + un = get_interface_data().username + if un: + html += _('You are not allowed to make changes to the library') + '
' + else: + html += _('You must be logged in to make changes to the library') + '
' + safe_set_inner_html(container, html + '
' + xhr.error_html) def fake_send(container_id, job_id): @@ -55,17 +121,21 @@ def fake_send(container_id, job_id): def send_file(file, container_id, job_id, add_duplicates): lid = loaded_books_query().library_id ad = 'y' if add_duplicates else 'n' - return ajax_send_file( + xhr = ajax_send_file( f'/cdb/add-book/{job_id}/{ad}/{encodeURIComponent(file.name)}/{lid}', - file, on_complete.bind(None, container_id, job_id), on_progress.bind(None, container_id, job_id)) + file, on_complete.bind(file, container_id, job_id), on_progress.bind(None, container_id, job_id)) + state.transfers.push(xhr) + return xhr def files_chosen(container_id, files): container = document.getElementById(container_id) if not container: return + state.number = 0 for file in files: state.counter += 1 + state.number += 1 job_id = state.counter w = upload_status_widget(file.name, job_id) container.appendChild(w) @@ -79,6 +149,7 @@ def files_chosen(container_id, files): def add_books_panel(container_id): container = document.getElementById(container_id) create_top_bar(container, title=_('Add books'), action=on_close, icon='close') + cancel_in_progress() state.in_progress = True state.container_id = container_id state.fake_send = False @@ -86,7 +157,4 @@ def add_books_panel(container_id): def develop(container): - c = add_books_panel(ensure_id(container)) - state.fake_send = True - container.removeChild(c) - files_chosen(container.id, [{'name': 'test1.epub', 'type': 'application/epub+zip'}, {'name': 'xxxx.yyy'}]) + add_books_panel(ensure_id(container)) diff --git a/src/pyj/utils.pyj b/src/pyj/utils.pyj index 28ae5433d3..dd1da80328 100644 --- a/src/pyj/utils.pyj +++ b/src/pyj/utils.pyj @@ -219,7 +219,7 @@ def simple_markup(html): div.textContent = html html = div.innerHTML return html.replace(/\uffff(\/?[a-z1-6]+)\uffff/g, '<$1>') -simple_markup.allowed_tags = v"'a|b|i|br|h1|h2|h3|h4|h5|h6|div|em|strong|span'.split('|')" +simple_markup.allowed_tags = v"'a|b|i|br|hr|h1|h2|h3|h4|h5|h6|div|em|strong|span'.split('|')" def safe_set_inner_html(elem, html):