Content server viewer: Allow editing metadata from the view metadata panel

Fixes #1890755
This commit is contained in:
Kovid Goyal 2020-08-10 21:28:09 +05:30
parent e304300fc6
commit 1867cadd5c
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 103 additions and 7 deletions

View File

@ -15,6 +15,7 @@ from book_list.comments_editor import (
create_comments_editor, focus_comments_editor, get_comments_html,
set_comments_html
)
from book_list.globals import get_current_query
from book_list.library_data import (
book_metadata, cover_url, current_library_id, field_names_for, library_data,
load_status, loaded_book_ids, set_book_metadata
@ -937,8 +938,15 @@ def changes_submitted(container_id, book_id, end_type, xhr, ev):
error_dialog(_('Could not update metadata for book'), _('Server returned an invalid response'), err.toString())
return
for bid in dirtied:
set_book_metadata(bid, dirtied[book_id])
cq = get_current_query()
if cq.from_read_book and window.opener:
window.opener.postMessage(
{'type': 'update_cached_book_metadata', 'library_id': cq.library_id, 'book_id': cq.book_id, 'metadata': dirtied[book_id], 'from_read_book': cq.from_read_book},
document.location.protocol + '//' + document.location.host
)
else:
for bid in dirtied:
set_book_metadata(bid, dirtied[bid])
on_close(container_id)
@ -994,7 +1002,10 @@ def on_close(container_id):
q = parse_url_params()
show_book(container_id, int(q.book_id))
return
back()
if get_current_query().from_read_book:
window.close()
else:
back()
def proceed_after_succesful_fetch_metadata(container_id, book_id):
@ -1054,6 +1065,18 @@ def init(container_id):
container.lastChild.focus()
container.lastChild.appendChild(E.div(_('Loading books from the calibre library, please wait...'), style='margin: 1ex 1em'))
conditional_timeout(container_id, 5, check_for_books_loaded)
cq = get_current_query()
if cq.from_read_book:
window.opener.postMessage(
{'type': 'edit_metadata_opened', 'library_id': cq.library_id, 'book_id': cq.book_id, 'from_read_book': cq.from_read_book},
document.location.protocol + '//' + document.location.host
)
window.addEventListener('unload', def (ev):
window.opener.postMessage(
{'type': 'edit_metadata_closed', 'from_read_book': cq.from_read_book},
document.location.protocol + '//' + document.location.host
)
)
set_panel_handler('edit_metadata', init)

View File

@ -297,6 +297,12 @@ class DB:
book.last_read[unkey] = book.recent_date = now
self.do_op(['books'], book, _('Failed to write to the books database'), op='put')
def update_metadata(self, book, new_metadata):
if book.metadata:
for key in Object.keys(new_metadata):
book.metadata[key] = new_metadata[key]
self.do_op(['books'], book, _('Failed to write to the books database'), op='put')
def update_annotations_data_from_key(self, library_id, book_id, fmt, new_data):
unkey = username_key(get_interface_data().username)
self.get_book(library_id, book_id, fmt, None, def(book):

View File

@ -4,12 +4,16 @@ from __python__ import bound_methods, hash_literals
from elementmaker import E
from gettext import gettext as _
from uuid import short_uuid
from book_list.book_details import CLASS_NAME as BD_CLASS_NAME, render_metadata
from book_list.globals import get_session_data
from book_list.library_data import sync_library_books
from book_list.library_data import (
current_library_id, set_book_metadata, sync_library_books
)
from book_list.router import home
from book_list.theme import get_color
from book_list.ui import query_as_href
from dom import add_extra_css, build_rule, clear, set_css, svgicon, unique_id
from modals import error_dialog
from read_book.globals import runtime, ui_operations
@ -665,10 +669,44 @@ class Overlay:
def show_metadata(self):
self.hide_current_panel()
from_read_book = short_uuid()
def show_metadata_overlay(mi, pathtoebook, overlay, container):
container.appendChild(E.div(class_=BD_CLASS_NAME, style='padding: 1ex 1em'))
def show_metadata_overlay(mi, pathtoebook, lname, book_id, overlay, container):
container.appendChild(E.div(class_=BD_CLASS_NAME, style='padding: 1ex 1em', id=from_read_book))
table = E.table(class_='metadata')
def handle_message(msg):
data = msg.data
if data.from_read_book is not from_read_book:
return
if data.type is 'edit_metadata_opened':
if document.getElementById(from_read_book) and self.panels.length and self.panels[-1].from_read_book is from_read_book:
self.hide_current_panel()
return
if data.type is 'edit_metadata_closed':
ui_operations.stop_waiting_for_messages_from(this)
return
if data.type is 'update_cached_book_metadata' and data.metadata:
if current_library_id() is data.library_id:
mi = data.metadata
book_id = int(data.book_id)
set_book_metadata(book_id, mi)
book = self.view.book
if book and book.key[0] is data.library_id and book.key[1] is book_id:
ui_operations.update_metadata(book, mi)
if not runtime.is_standalone_viewer and lname:
container.lastChild.appendChild(E.div(
style='text-align: right',
E.a(_('Edit metadata of book in library'), class_='blue-link', onclick=def():
w = window.open(query_as_href({
'from_read_book': from_read_book, 'library_id': lname, 'book_id': book_id + ''}, 'edit_metadata')
, '_blank'
)
ui_operations.wait_for_messages_from(w, handle_message.bind(w))
)
))
container.lastChild.appendChild(table)
render_metadata(mi, table, None, f'html {{ font-size: {document.documentElement.style.fontSize} }}')
for a in table.querySelectorAll('a[href]'):
@ -680,7 +718,13 @@ class Overlay:
style='margin-top: 1ex; padding-top: 1ex; border-top: solid 1px',
_('Path: {}').format(pathtoebook)))
self.panels.push(SimpleOverlay(self, show_metadata_overlay.bind(None, self.view.book.metadata, self.view.book.manifest.pathtoebook), self.view.book.metadata.title))
book = self.view.book
key = book.key or v'[null, 0]'
lname, book_id = key
book_id = int(book_id or 0)
panel = SimpleOverlay(self, show_metadata_overlay.bind(None, book.metadata, book.manifest.pathtoebook, lname, book_id), self.view.book.metadata.title)
panel.from_read_book = from_read_book
self.panels.push(panel)
self.show_current_panel()
def show_ask_for_location(self):

View File

@ -53,7 +53,9 @@ class ReadUI:
id=self.display_id, style='display:none',
))
self.view = View(container.lastChild)
self.windows_to_listen_for_messages_from = []
window.addEventListener('resize', debounce(self.on_resize.bind(self), 250))
window.addEventListener('message', self.message_from_other_window.bind(self))
self.db = get_db(self.db_initialized.bind(self), self.show_error.bind(self))
ui_operations.get_file = self.db.get_file
ui_operations.get_mathjax_files = self.db.get_mathjax_files
@ -75,6 +77,9 @@ class ReadUI:
ui_operations.toggle_full_screen = self.toggle_full_screen.bind(self)
ui_operations.highlights_changed = self.highlights_changed.bind(self)
ui_operations.annotations_synced = self.annotations_synced.bind(self)
ui_operations.wait_for_messages_from = self.wait_for_messages_from.bind(self)
ui_operations.stop_waiting_for_messages_from = self.stop_waiting_for_messages_from.bind(self)
ui_operations.update_metadata = self.update_metadata.bind(self)
ui_operations.open_url = def(url):
window.open(url, '_blank')
ui_operations.copy_selection = def(text):
@ -534,3 +539,21 @@ class ReadUI:
def update_url_state(self, replace):
push_state(self.url_data, replace=replace, mode=read_book_mode)
def update_metadata(self, book, metadata):
self.db.update_metadata(book, metadata)
def wait_for_messages_from(self, w, callback):
self.windows_to_listen_for_messages_from.push(v'[w, callback]')
def stop_waiting_for_messages_from(self, w):
self.windows_to_listen_for_messages_from = [x for x in self.windows_to_listen_for_messages_from if x[0] is not w]
def message_from_other_window(self, msg):
if not self.windows_to_listen_for_messages_from.length:
return
old = self.windows_to_listen_for_messages_from
for x in old:
w, callback = x
if w is msg.source:
callback(msg)