diff --git a/src/pyj/read_book/highlights.pyj b/src/pyj/read_book/highlights.pyj index b9d6ddb0f6..3a2c8af918 100644 --- a/src/pyj/read_book/highlights.pyj +++ b/src/pyj/read_book/highlights.pyj @@ -535,13 +535,13 @@ def get_current_link_prefix(): def link_to_epubcfi(epubcfi, link_prefix, current_query): if runtime.is_standalone_viewer: current_query = {'open_at': epubcfi} - link = link_prefix + encode_query(current_query).replace(/\)/g, '%29') + link = encode_query(current_query) else: if not current_query: current_query = Object.assign({}, get_current_query()) current_query.bookpos = epubcfi - link = link_prefix + encode_query(current_query)[1:].replace(/\)/g, '%29') - return link + link = encode_query(current_query)[1:] + return link_prefix + link.replace(/\)/g, '%29').replace(/\(/g, '%28') def render_highlight_as_text(hl, lines, link_prefix, current_query, as_markdown=False): diff --git a/src/pyj/read_book/iframe.pyj b/src/pyj/read_book/iframe.pyj index fc085d5a00..a4a045a2e4 100644 --- a/src/pyj/read_book/iframe.pyj +++ b/src/pyj/read_book/iframe.pyj @@ -849,6 +849,14 @@ class IframeBoss: anchor_before=anchor_before ) reset_find_caches() + elif dtype is 'cite-current-selection': + sel = window.getSelection() + if not sel.rangeCount: + return + bounds = cfi_for_selection() + anchor_before = find_anchor_before_range(sel.getRangeAt(0), self.book.manifest.toc_anchor_map, self.anchor_funcs) + text = sel.toString() + self.send_message('annotations', type='cite-data', bounds=bounds, highlighted_text=text) else: console.log('Ignoring annotations message to iframe with unknown type: ' + dtype) diff --git a/src/pyj/read_book/selection_bar.pyj b/src/pyj/read_book/selection_bar.pyj index 86a333115a..edd88a42a6 100644 --- a/src/pyj/read_book/selection_bar.pyj +++ b/src/pyj/read_book/selection_bar.pyj @@ -3,20 +3,21 @@ from __python__ import bound_methods, hash_literals from elementmaker import E -from gettext import gettext as _ -from uuid import short_uuid from book_list.globals import get_session_data from book_list.theme import get_color from dom import change_icon_image, clear, svgicon, unique_id -from modals import error_dialog, question_dialog, create_custom_dialog +from gettext import gettext as _ +from modals import create_custom_dialog, error_dialog, question_dialog from read_book.globals import runtime, ui_operations from read_book.highlights import ( - ICON_SIZE, EditNotesAndColors, HighlightStyle, all_styles, render_notes + ICON_SIZE, EditNotesAndColors, HighlightStyle, all_styles, + get_current_link_prefix, link_to_epubcfi, render_notes ) -from widgets import create_button from read_book.shortcuts import shortcut_for_key_event -from read_book.toc import get_toc_nodes_bordering_spine_item, family_for_toc_node +from read_book.toc import family_for_toc_node, get_toc_nodes_bordering_spine_item +from uuid import short_uuid +from widgets import create_button DRAG_SCROLL_ZONE_MIN_HEIGHT = 10 BUTTON_MARGIN = '0.5rem' @@ -193,6 +194,7 @@ def all_actions(): 'remove_highlight': a('trash', _('Remove this highlight'), 'remove_highlight', True), 'clear': a('close', _('Clear selection'), 'clear_selection'), 'speak': a('bullhorn', _('Read aloud'), 'speak_aloud'), + 'cite': a('reference-mode', _('Copy citation to clipboard'), 'cite'), } qh = all_actions.ans.quick_highlight qh.icon_function = quick_highlight_icon.bind(None, qh.icon, qh.text) @@ -961,6 +963,9 @@ class SelectionBar: ui_operations.speak_simple_text(text) self.spoken_aloud_at_least_once = True + def cite(self): + self.send_message('cite-current-selection') + def create_highlight(self): cs = self.view.currently_showing.selection hs = self.current_highlight_style @@ -1042,6 +1047,16 @@ class SelectionBar: self.report_failed_edit_highlight(msg.uuid) elif msg.type is 'double-click': self.last_double_click_at = window.performance.now() + elif msg.type is 'cite-data': + spine_index = self.view.currently_showing.spine_index + spine_index = (1 + spine_index) * 2 + cfi = msg.bounds.start + link_prefix = get_current_link_prefix() + if not link_prefix: + return self.view.show_not_a_library_book_error() + url = link_to_epubcfi(f'epubcfi(/{spine_index}{cfi})', link_prefix) + text = msg.highlighted_text.replace(/\[/g, r'\[').replace(/\]/g, r'\]') + ui_operations.copy_selection(f'[{text}]({url})') else: print('Ignoring annotations message with unknown type:', msg.type) diff --git a/src/pyj/read_book/view.pyj b/src/pyj/read_book/view.pyj index ebdde54455..89534eca3d 100644 --- a/src/pyj/read_book/view.pyj +++ b/src/pyj/read_book/view.pyj @@ -340,11 +340,14 @@ class View: def copy_to_clipboard(self): self.iframe_wrapper.send_message('copy_selection') + def show_not_a_library_book_error(self): + error_dialog(_('Not a calibre library book'), _( + 'This book is not a part of a calibre library, so no calibre:// URL for it exists.')) + def copy_current_location_to_clipboard(self, as_url): link_prefix = get_current_link_prefix() if not link_prefix and as_url: - return error_dialog(_('Not a calibre library book'), _( - 'This book is not a part of a calibre library, so no calibre:// URL for it exists.')) + return self.show_not_a_library_book_error() self.get_current_cfi('copy-location-url', def (req_id, data): if as_url: text = link_to_epubcfi(data.cfi, link_prefix)