From 4fc76a6919f0f593636ec781c52a56b83c6346c4 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 25 Jan 2018 14:04:15 +0530 Subject: [PATCH] Finish up adding books implementation Still needs to add the new book to the existing book list, so that the book list does not need to be refreshed to see the book. --- src/calibre/srv/cdb.py | 1 + src/pyj/ajax.pyj | 5 +-- src/pyj/book_list/add.pyj | 86 +++++++++++++++++++++++++++++++++++---- src/pyj/utils.pyj | 2 +- 4 files changed, 80 insertions(+), 14 deletions(-) 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):