# vim:fileencoding=utf-8 # License: GPL v3 Copyright: 2016, Kovid Goyal from __python__ import bound_methods, hash_literals import traceback from elementmaker import E from gettext import gettext as _ from ajax import encode_query_component from book_list.item_list import build_list, create_item from dom import ensure_id, set_css from modals import error_dialog from read_book.globals import current_book, runtime, ui_operations from read_book.prefs.head_foot import format_pos from read_book.toc import get_border_nodes, get_toc_maps from widgets import create_button def create_goto_list(onclick, current_position_data): ans = E.div() items = v'[]' location_text = format_pos(current_position_data.progress_frac, current_position_data.book_length) + ' :: ' if current_position_data.cfi: location_text += current_position_data.cfi landmarks = current_book().manifest.landmarks toc = current_book().manifest.toc id_map = get_toc_maps(toc)[1] before, after = get_border_nodes(toc, id_map) if after: items.push(create_item(_('Next section'), icon='caret-right', subtitle=after.title, action=onclick.bind(None, after.dest, after.frag))) if before: items.push(create_item(_('Previous section'), icon='caret-left', subtitle=before.title, action=onclick.bind(None, before.dest, before.frag))) items.push(create_item(_('Book start'), action=onclick.bind(None, def(view): view.goto_doc_boundary(True);))) items.push(create_item(_('Book end'), action=onclick.bind(None, def(view): view.goto_doc_boundary(False);))) items.push(create_item(_('Metadata'), subtitle=_('Details about this book'), action=onclick.bind(None, def(view): view.overlay.show_metadata() ))) if not runtime.is_standalone_viewer: items.push(create_item(_('Book page in library'), subtitle=_('The page for this book in the calibre library'), action=onclick.bind(None, def(view): view.open_book_page() ))) items.push(create_item(_('Location'), subtitle=location_text, action=onclick.bind(None, def(view): view.overlay.show_ask_for_location();))) for l in landmarks: items.push(create_item(l.title, action=onclick.bind(None, l.dest, l.frag))) build_list(ans, items) return ans def get_next_section(forward): toc = current_book().manifest.toc id_map = get_toc_maps(toc)[1] before, after = get_border_nodes(toc, id_map) return after if forward else before def create_goto_panel(current_position_data, book, container, onclick): panel = create_goto_list(onclick, current_position_data) set_css(container, display='flex', flex_direction='column') set_css(panel, flex_grow='10') container.appendChild(panel) def create_location_overlay(current_position_data, book, overlay, container): container_id = ensure_id(container) container.appendChild(E.div(style='margin: 0 1rem')) container = container.lastChild current_cfi = current_position_data.cfi calibre_book_url = book?.calibre_book_url def copy_button(text_to_copy): return create_button(_('Copy'), action=def(): src = document.querySelector(f'#{container_id} input') orig = src.value src.value = text_to_copy src.focus() src.select() try: document.execCommand('copy') finally: src.value = orig ) def display_and_copy(label, text): container.appendChild(E.div( style='margin: 1rem; margin-bottom: calc(1rem - 1ex); display: flex; align-items: baseline; flex-wrap: wrap', E.div(style='flex-grow: 10; text-overflow: ellipsis; margin-bottom: 1ex', label, ' ', E.span(text, style='font-size: smaller; font-family: monospace')), copy_button(text) )) if current_cfi: display_and_copy(_('Current location:'), current_cfi) def goto_cfi(cfi): if ui_operations.goto_cfi(cfi): overlay.hide() else: error_dialog(_('No such location'), _( 'No location {} found').format(cfi)) def goto_ref(ref): ref = ref.replace(/,/g, '.') if ui_operations.goto_reference(ref): overlay.hide() else: error_dialog(_('No such reference'), _( 'No reference {} found').format(ref)) if current_position_data.book_length > 0: container.appendChild( E.div(style='margin: 1rem', _('Current position: {}').format( format_pos(current_position_data.progress_frac, current_position_data.book_length)))) container.appendChild( E.div(style='margin: 1rem', _( 'Type the position, location or reference below. For a reference type ref: followed by the reference:'))) def goto_pos(): src = document.querySelector(f'#{container_id} [name=newpos]').value if not src: return if src.indexOf('epubcfi(') is 0: return goto_cfi(src) if src.indexOf('ref:') is 0: return goto_ref(src[len('ref:'):]) try: ui_operations.goto_book_position(float(src)) except: error_dialog(_('Not a valid book position'), _( '{} is not a valid book position').format(src), traceback.format_exc()) else: overlay.hide() container.appendChild(E.div( style='margin: 1rem;', E.div( style='display: flex; align-items: baseline; flex-wrap: wrap', E.label(_('Go to:'), style='margin-right: 1rem'), E.input(name='newpos', type='text', min='0', max=str(current_position_data.book_length), step='0.1', style='flex-grow: 10; margin-right: 1rem', onkeydown=def(ev): if ev.key is 'Enter': goto_pos() ), E.span(' '), create_button(_('Go'), action=goto_pos) ) )) if calibre_book_url: if current_cfi: calibre_book_url += '?open_at=' + encode_query_component(current_cfi) display_and_copy(_('URL for this position:'), calibre_book_url) elif not runtime.is_standalone_viewer: display_and_copy(_('URL for this position:'), window.top.location.toString()) window.setTimeout(def(): container = document.getElementById(container_id) if container: container.querySelector('[name=newpos]').focus() , 10)