mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
E-book viewer: Allow adding a button to the selection bar that copies the currently selected text along with a calibre:// URL to show the text in the book. See #1912070 ([Enhancement] Additional access to copying Go To URL location link)
This commit is contained in:
parent
9032d92954
commit
15e8980cb2
@ -535,13 +535,13 @@ def get_current_link_prefix():
|
|||||||
def link_to_epubcfi(epubcfi, link_prefix, current_query):
|
def link_to_epubcfi(epubcfi, link_prefix, current_query):
|
||||||
if runtime.is_standalone_viewer:
|
if runtime.is_standalone_viewer:
|
||||||
current_query = {'open_at': epubcfi}
|
current_query = {'open_at': epubcfi}
|
||||||
link = link_prefix + encode_query(current_query).replace(/\)/g, '%29')
|
link = encode_query(current_query)
|
||||||
else:
|
else:
|
||||||
if not current_query:
|
if not current_query:
|
||||||
current_query = Object.assign({}, get_current_query())
|
current_query = Object.assign({}, get_current_query())
|
||||||
current_query.bookpos = epubcfi
|
current_query.bookpos = epubcfi
|
||||||
link = link_prefix + encode_query(current_query)[1:].replace(/\)/g, '%29')
|
link = encode_query(current_query)[1:]
|
||||||
return link
|
return link_prefix + link.replace(/\)/g, '%29').replace(/\(/g, '%28')
|
||||||
|
|
||||||
|
|
||||||
def render_highlight_as_text(hl, lines, link_prefix, current_query, as_markdown=False):
|
def render_highlight_as_text(hl, lines, link_prefix, current_query, as_markdown=False):
|
||||||
|
@ -849,6 +849,14 @@ class IframeBoss:
|
|||||||
anchor_before=anchor_before
|
anchor_before=anchor_before
|
||||||
)
|
)
|
||||||
reset_find_caches()
|
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:
|
else:
|
||||||
console.log('Ignoring annotations message to iframe with unknown type: ' + dtype)
|
console.log('Ignoring annotations message to iframe with unknown type: ' + dtype)
|
||||||
|
|
||||||
|
@ -3,20 +3,21 @@
|
|||||||
from __python__ import bound_methods, hash_literals
|
from __python__ import bound_methods, hash_literals
|
||||||
|
|
||||||
from elementmaker import E
|
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.globals import get_session_data
|
||||||
from book_list.theme import get_color
|
from book_list.theme import get_color
|
||||||
from dom import change_icon_image, clear, svgicon, unique_id
|
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.globals import runtime, ui_operations
|
||||||
from read_book.highlights import (
|
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.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
|
DRAG_SCROLL_ZONE_MIN_HEIGHT = 10
|
||||||
BUTTON_MARGIN = '0.5rem'
|
BUTTON_MARGIN = '0.5rem'
|
||||||
@ -193,6 +194,7 @@ def all_actions():
|
|||||||
'remove_highlight': a('trash', _('Remove this highlight'), 'remove_highlight', True),
|
'remove_highlight': a('trash', _('Remove this highlight'), 'remove_highlight', True),
|
||||||
'clear': a('close', _('Clear selection'), 'clear_selection'),
|
'clear': a('close', _('Clear selection'), 'clear_selection'),
|
||||||
'speak': a('bullhorn', _('Read aloud'), 'speak_aloud'),
|
'speak': a('bullhorn', _('Read aloud'), 'speak_aloud'),
|
||||||
|
'cite': a('reference-mode', _('Copy citation to clipboard'), 'cite'),
|
||||||
}
|
}
|
||||||
qh = all_actions.ans.quick_highlight
|
qh = all_actions.ans.quick_highlight
|
||||||
qh.icon_function = quick_highlight_icon.bind(None, qh.icon, qh.text)
|
qh.icon_function = quick_highlight_icon.bind(None, qh.icon, qh.text)
|
||||||
@ -961,6 +963,9 @@ class SelectionBar:
|
|||||||
ui_operations.speak_simple_text(text)
|
ui_operations.speak_simple_text(text)
|
||||||
self.spoken_aloud_at_least_once = True
|
self.spoken_aloud_at_least_once = True
|
||||||
|
|
||||||
|
def cite(self):
|
||||||
|
self.send_message('cite-current-selection')
|
||||||
|
|
||||||
def create_highlight(self):
|
def create_highlight(self):
|
||||||
cs = self.view.currently_showing.selection
|
cs = self.view.currently_showing.selection
|
||||||
hs = self.current_highlight_style
|
hs = self.current_highlight_style
|
||||||
@ -1042,6 +1047,16 @@ class SelectionBar:
|
|||||||
self.report_failed_edit_highlight(msg.uuid)
|
self.report_failed_edit_highlight(msg.uuid)
|
||||||
elif msg.type is 'double-click':
|
elif msg.type is 'double-click':
|
||||||
self.last_double_click_at = window.performance.now()
|
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:
|
else:
|
||||||
print('Ignoring annotations message with unknown type:', msg.type)
|
print('Ignoring annotations message with unknown type:', msg.type)
|
||||||
|
|
||||||
|
@ -340,11 +340,14 @@ class View:
|
|||||||
def copy_to_clipboard(self):
|
def copy_to_clipboard(self):
|
||||||
self.iframe_wrapper.send_message('copy_selection')
|
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):
|
def copy_current_location_to_clipboard(self, as_url):
|
||||||
link_prefix = get_current_link_prefix()
|
link_prefix = get_current_link_prefix()
|
||||||
if not link_prefix and as_url:
|
if not link_prefix and as_url:
|
||||||
return error_dialog(_('Not a calibre library book'), _(
|
return self.show_not_a_library_book_error()
|
||||||
'This book is not a part of a calibre library, so no calibre:// URL for it exists.'))
|
|
||||||
self.get_current_cfi('copy-location-url', def (req_id, data):
|
self.get_current_cfi('copy-location-url', def (req_id, data):
|
||||||
if as_url:
|
if as_url:
|
||||||
text = link_to_epubcfi(data.cfi, link_prefix)
|
text = link_to_epubcfi(data.cfi, link_prefix)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user