mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Show highlight notes in the select bar
This commit is contained in:
parent
6436d36f2e
commit
2078309b52
@ -150,3 +150,29 @@ def set_selection_to_highlight():
|
|||||||
if crw:
|
if crw:
|
||||||
select_crw(crw)
|
select_crw(crw)
|
||||||
return crw or None
|
return crw or None
|
||||||
|
|
||||||
|
|
||||||
|
def highlight_associated_with_selection(sel, annot_id_uuid_map):
|
||||||
|
# Return the annotation id for a highlight that contains the focus or
|
||||||
|
# anchor of the selection
|
||||||
|
|
||||||
|
def get_annot_id_for(node, offset):
|
||||||
|
if not node:
|
||||||
|
return
|
||||||
|
if node.nodeType is Node.ELEMENT_NODE:
|
||||||
|
if node.dataset.calibreRangeWrapper:
|
||||||
|
return annot_id_uuid_map[node.dataset.calibreRangeWrapper]
|
||||||
|
if offset is 0:
|
||||||
|
if node.firstChild?.nodeType is Node.ELEMENT_NODE and node.firstChild.dataset.calibreRangeWrapper:
|
||||||
|
return annot_id_uuid_map[node.firstChild.dataset.calibreRangeWrapper]
|
||||||
|
elif offset < node.childNodes.length:
|
||||||
|
node = node.childNodes[offset]
|
||||||
|
return get_annot_id_for(node, 0)
|
||||||
|
elif node.nodeType is Node.TEXT_NODE:
|
||||||
|
if node.parentNode?.nodeType is Node.ELEMENT_NODE and node.parentNode.dataset.calibreRangeWrapper:
|
||||||
|
return annot_id_uuid_map[node.parentNode.dataset.calibreRangeWrapper]
|
||||||
|
|
||||||
|
annot_id = get_annot_id_for(sel.focusNode, sel.focusOffset)
|
||||||
|
if not annot_id:
|
||||||
|
annot_id = get_annot_id_for(sel.anchorNode, sel.anchorOffset)
|
||||||
|
return annot_id
|
||||||
|
@ -15,9 +15,13 @@ from read_book.globals import ui_operations
|
|||||||
from read_book.shortcuts import shortcut_for_key_event
|
from read_book.shortcuts import shortcut_for_key_event
|
||||||
from widgets import create_button
|
from widgets import create_button
|
||||||
|
|
||||||
|
|
||||||
# TODO:
|
# TODO:
|
||||||
# Get rid of view annotations and show notes in selection bar if available
|
# Custom colors for highlights
|
||||||
# Allow adding/removing custom highlight colors
|
# Google lookup for selections
|
||||||
|
# Export all annots as plain text/JSON
|
||||||
|
# Remove lookup and create highlight buttons from chrome
|
||||||
|
# position bar at mouse x during drag
|
||||||
|
|
||||||
|
|
||||||
class AnnotationsManager:
|
class AnnotationsManager:
|
||||||
@ -61,7 +65,7 @@ class AnnotationsManager:
|
|||||||
ui_operations.highlights_changed(Object.values(self.highlights))
|
ui_operations.highlights_changed(Object.values(self.highlights))
|
||||||
|
|
||||||
def notes_for_highlight(self, uuid):
|
def notes_for_highlight(self, uuid):
|
||||||
h = self.highlights[uuid]
|
h = self.highlights[uuid] if uuid else None
|
||||||
if h:
|
if h:
|
||||||
return h.notes
|
return h.notes
|
||||||
|
|
||||||
@ -726,8 +730,6 @@ class CreateAnnotation:
|
|||||||
_('Failed to apply highlighting, try adjusting extent of highlight')
|
_('Failed to apply highlighting, try adjusting extent of highlight')
|
||||||
)
|
)
|
||||||
self.annotations_manager.add_highlight(msg, self.current_highlight_style, self.current_notes)
|
self.annotations_manager.add_highlight(msg, self.current_highlight_style, self.current_notes)
|
||||||
elif msg.type is 'annotation-activated':
|
|
||||||
self.view.view_annotation.show(msg.uuid)
|
|
||||||
else:
|
else:
|
||||||
print('Ignoring annotations message with unknown type:', msg.type)
|
print('Ignoring annotations message with unknown type:', msg.type)
|
||||||
|
|
||||||
@ -770,93 +772,3 @@ class CreateAnnotation:
|
|||||||
else:
|
else:
|
||||||
self.place_single_handle(self.left_handle, extents.start)
|
self.place_single_handle(self.left_handle, extents.start)
|
||||||
self.place_single_handle(self.right_handle, extents.end)
|
self.place_single_handle(self.right_handle, extents.end)
|
||||||
|
|
||||||
|
|
||||||
class ViewAnnotation: # {{{
|
|
||||||
|
|
||||||
container_id = 'view-annotation-overlay'
|
|
||||||
|
|
||||||
def __init__(self, view):
|
|
||||||
self.view = view
|
|
||||||
self.annotations_manager = view.annotations_manager
|
|
||||||
c = self.container
|
|
||||||
self.showing_uuid = None
|
|
||||||
c.style.flexDirection = 'column'
|
|
||||||
c.style.justifyContent = 'flex-end'
|
|
||||||
c.appendChild(E.div(
|
|
||||||
style='pointer-events: auto; padding: 1ex 1rem; box-sizing: border-box; border-top: solid 2px currentColor; overflow: hidden',
|
|
||||||
onclick=def(ev):
|
|
||||||
ev.preventDefault(), ev.stopPropagation()
|
|
||||||
,
|
|
||||||
E.div(
|
|
||||||
style='display: flex; justify-content: space-between; align-items: flex-start',
|
|
||||||
E.a(
|
|
||||||
svgicon('close', f'{BAR_SIZE}px', f'{BAR_SIZE}px'),
|
|
||||||
class_='simple-link', href='javascript: void', title=_('Close'),
|
|
||||||
onclick=def(ev):
|
|
||||||
self.hide()
|
|
||||||
),
|
|
||||||
E.div(
|
|
||||||
style='margin-left: 2rem; margin-right: 2rem; max-height: 20vh; overflow-y: auto; overflow-x: hidden; box-sizing: border-box; padding-top: 1ex',
|
|
||||||
class_='highlight-notes-viewer'
|
|
||||||
),
|
|
||||||
E.a(
|
|
||||||
svgicon('pencil', f'{BAR_SIZE}px', f'{BAR_SIZE}px'),
|
|
||||||
class_='simple-link', href='javascript: void', title=_('Edit this highlight'),
|
|
||||||
onclick=def(ev):
|
|
||||||
self.edit_current()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def container(self):
|
|
||||||
return document.getElementById(self.container_id)
|
|
||||||
|
|
||||||
def show(self, uuid):
|
|
||||||
c = self.container
|
|
||||||
c.style.display = 'flex'
|
|
||||||
self.showing_uuid = uuid
|
|
||||||
s = self.annotations_manager.style_for_highlight(uuid) or default_highlight_style()
|
|
||||||
c = c.firstChild
|
|
||||||
c.style.color = s.color
|
|
||||||
c.style.backgroundColor = s['background-color']
|
|
||||||
text = self.annotations_manager.notes_for_highlight(uuid) or ''
|
|
||||||
self.display_text(text)
|
|
||||||
|
|
||||||
def display_text(self, text):
|
|
||||||
text = text or _('This highlight has no added notes')
|
|
||||||
text = text.strip()
|
|
||||||
div = self.container.querySelector('.highlight-notes-viewer')
|
|
||||||
clear(div)
|
|
||||||
current_block = ''
|
|
||||||
|
|
||||||
def add_para():
|
|
||||||
nonlocal current_block
|
|
||||||
div.appendChild(E.p(current_block))
|
|
||||||
if div.childNodes.length > 1:
|
|
||||||
div.lastChild.style.marginTop = '2ex'
|
|
||||||
current_block = ''
|
|
||||||
|
|
||||||
for line in text.splitlines():
|
|
||||||
if not line or not line.strip():
|
|
||||||
if current_block:
|
|
||||||
add_para()
|
|
||||||
continue
|
|
||||||
current_block += line + '\n'
|
|
||||||
if current_block:
|
|
||||||
add_para()
|
|
||||||
|
|
||||||
def hide(self):
|
|
||||||
self.container.style.display = 'none'
|
|
||||||
self.showing_uuid = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_visible(self):
|
|
||||||
return self.container.style.display is not 'none'
|
|
||||||
|
|
||||||
def edit_current(self):
|
|
||||||
if self.showing_uuid:
|
|
||||||
self.view.create_annotation.edit_highlight(self.showing_uuid)
|
|
||||||
self.hide()
|
|
||||||
# }}}
|
|
||||||
|
@ -8,14 +8,15 @@ from read_book.globals import annot_id_uuid_map
|
|||||||
|
|
||||||
def get_elements(x, y):
|
def get_elements(x, y):
|
||||||
nonlocal img_id_counter
|
nonlocal img_id_counter
|
||||||
ans = {'link': None, 'img': None, 'highlight': None}
|
ans = {'link': None, 'img': None, 'highlight': None, 'crw': None}
|
||||||
for elem in document.elementsFromPoint(x, y):
|
for elem in document.elementsFromPoint(x, y):
|
||||||
if elem.tagName.toLowerCase() is 'a' and elem.getAttribute('href') and not ans.link:
|
if elem.tagName.toLowerCase() is 'a' and elem.getAttribute('href') and not ans.link:
|
||||||
ans.link = elem.getAttribute('href')
|
ans.link = elem.getAttribute('href')
|
||||||
elif elem.tagName.toLowerCase() is 'img' and elem.getAttribute('data-calibre-src') and not ans.img:
|
elif elem.tagName.toLowerCase() is 'img' and elem.getAttribute('data-calibre-src') and not ans.img:
|
||||||
ans.img = elem.getAttribute('data-calibre-src')
|
ans.img = elem.getAttribute('data-calibre-src')
|
||||||
elif elem.dataset?.calibreRangeWrapper:
|
elif elem.dataset?.calibreRangeWrapper:
|
||||||
annot_id = annot_id_uuid_map[elem.dataset.calibreRangeWrapper]
|
ans.crw = elem.dataset.calibreRangeWrapper
|
||||||
|
annot_id = annot_id_uuid_map[ans.crw]
|
||||||
if annot_id:
|
if annot_id:
|
||||||
ans.highlight = annot_id
|
ans.highlight = annot_id
|
||||||
return ans
|
return ans
|
||||||
|
@ -12,8 +12,8 @@ from select import (
|
|||||||
from fs_images import fix_fullscreen_svg_images
|
from fs_images import fix_fullscreen_svg_images
|
||||||
from iframe_comm import IframeClient
|
from iframe_comm import IframeClient
|
||||||
from range_utils import (
|
from range_utils import (
|
||||||
reset_highlight_counter, select_crw, set_selection_to_highlight, unwrap_all_crw,
|
highlight_associated_with_selection, reset_highlight_counter, select_crw,
|
||||||
unwrap_crw, wrap_text_in_range
|
set_selection_to_highlight, unwrap_all_crw, unwrap_crw, wrap_text_in_range
|
||||||
)
|
)
|
||||||
from read_book.cfi import (
|
from read_book.cfi import (
|
||||||
cfi_for_selection, range_from_cfi, scroll_to as scroll_to_cfi
|
cfi_for_selection, range_from_cfi, scroll_to as scroll_to_cfi
|
||||||
@ -292,14 +292,13 @@ class IframeBoss:
|
|||||||
self.send_message('view_image', calibre_src=elements.img)
|
self.send_message('view_image', calibre_src=elements.img)
|
||||||
return
|
return
|
||||||
if elements.highlight:
|
if elements.highlight:
|
||||||
self.activate_annotation(elements.highlight)
|
select_crw(elements.crw)
|
||||||
return
|
return
|
||||||
r = word_at_point(gesture.viewport_x, gesture.viewport_y)
|
r = word_at_point(gesture.viewport_x, gesture.viewport_y)
|
||||||
if r:
|
if r:
|
||||||
s = document.getSelection()
|
s = document.getSelection()
|
||||||
s.removeAllRanges()
|
s.removeAllRanges()
|
||||||
s.addRange(r)
|
s.addRange(r)
|
||||||
self.send_message('lookup_word', word=str(r))
|
|
||||||
|
|
||||||
def gesture_from_margin(self, data):
|
def gesture_from_margin(self, data):
|
||||||
self.handle_gesture(data.gesture)
|
self.handle_gesture(data.gesture)
|
||||||
@ -523,11 +522,13 @@ class IframeBoss:
|
|||||||
return
|
return
|
||||||
sel = window.getSelection()
|
sel = window.getSelection()
|
||||||
text = ''
|
text = ''
|
||||||
|
annot_id = None
|
||||||
collapsed = not sel or sel.isCollapsed
|
collapsed = not sel or sel.isCollapsed
|
||||||
if not collapsed:
|
if not collapsed:
|
||||||
text = sel.toString()
|
text = sel.toString()
|
||||||
|
annot_id = highlight_associated_with_selection(sel, annot_id_uuid_map)
|
||||||
self.send_message(
|
self.send_message(
|
||||||
'selectionchange', text=text, empty=v'!!collapsed',
|
'selectionchange', text=text, empty=v'!!collapsed', annot_id=annot_id,
|
||||||
selection_extents=selection_extents(current_layout_mode() is 'flow', True))
|
selection_extents=selection_extents(current_layout_mode() is 'flow', True))
|
||||||
|
|
||||||
def onresize_stage2(self):
|
def onresize_stage2(self):
|
||||||
@ -825,15 +826,11 @@ class IframeBoss:
|
|||||||
def add_highlight_listeners(self, wrapper):
|
def add_highlight_listeners(self, wrapper):
|
||||||
wrapper.addEventListener('dblclick', self.highlight_wrapper_dblclicked)
|
wrapper.addEventListener('dblclick', self.highlight_wrapper_dblclicked)
|
||||||
|
|
||||||
def activate_annotation(self, uuid):
|
|
||||||
if uuid:
|
|
||||||
self.send_message('annotations', type='annotation-activated', uuid=uuid)
|
|
||||||
window.getSelection().removeAllRanges()
|
|
||||||
|
|
||||||
def highlight_wrapper_dblclicked(self, ev):
|
def highlight_wrapper_dblclicked(self, ev):
|
||||||
crw = ev.currentTarget.dataset.calibreRangeWrapper
|
crw = ev.currentTarget.dataset.calibreRangeWrapper
|
||||||
ev.preventDefault(), ev.stopPropagation()
|
if crw:
|
||||||
self.activate_annotation(annot_id_uuid_map[crw])
|
ev.preventDefault(), ev.stopPropagation()
|
||||||
|
select_crw(crw)
|
||||||
|
|
||||||
def copy_selection(self):
|
def copy_selection(self):
|
||||||
text = window.getSelection().toString()
|
text = window.getSelection().toString()
|
||||||
|
@ -5,7 +5,6 @@ from __python__ import hash_literals
|
|||||||
import traceback
|
import traceback
|
||||||
from elementmaker import E
|
from elementmaker import E
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from select import word_at_point
|
|
||||||
|
|
||||||
from dom import set_css
|
from dom import set_css
|
||||||
from read_book.cfi import (
|
from read_book.cfi import (
|
||||||
@ -667,13 +666,6 @@ def handle_gesture(gesture):
|
|||||||
scroll_by_page(True, opts.paged_taps_scroll_by_screen)
|
scroll_by_page(True, opts.paged_taps_scroll_by_screen)
|
||||||
elif gesture.type is 'next-page':
|
elif gesture.type is 'next-page':
|
||||||
scroll_by_page(False, opts.paged_taps_scroll_by_screen)
|
scroll_by_page(False, opts.paged_taps_scroll_by_screen)
|
||||||
elif gesture.type is 'long-tap':
|
|
||||||
r = word_at_point(gesture.viewport_x, gesture.viewport_y)
|
|
||||||
if r:
|
|
||||||
s = document.getSelection()
|
|
||||||
s.removeAllRanges()
|
|
||||||
s.addRange(r)
|
|
||||||
get_boss().send_message('lookup_word', word=str(r))
|
|
||||||
|
|
||||||
|
|
||||||
anchor_funcs = {
|
anchor_funcs = {
|
||||||
|
@ -6,21 +6,34 @@ from elementmaker import E
|
|||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
from book_list.theme import get_color
|
from book_list.theme import get_color
|
||||||
from dom import svgicon
|
from dom import clear, svgicon
|
||||||
from read_book.globals import ui_operations
|
from read_book.globals import runtime, ui_operations
|
||||||
|
|
||||||
|
|
||||||
class SelectionBar:
|
class SelectionBar:
|
||||||
|
|
||||||
def __init__(self, view):
|
def __init__(self, view):
|
||||||
self.view = view
|
self.view = view
|
||||||
|
|
||||||
|
def build_bar(self, notes):
|
||||||
c = self.container
|
c = self.container
|
||||||
bar = E.div(
|
max_width = 'min(50rem, 90vw)' if self.supports_css_min_max else '50rem'
|
||||||
style='position: absolute; height: 4ex; border: solid 1px currentColor; border-radius: 5px; overflow: hidden;'
|
bar_container = E.div(
|
||||||
'display: flex; align-items: center; pointer-events: auto; padding: 5px; left: 0; top: 0;'
|
style='position: absolute; border: solid 1px currentColor; border-radius: 5px;'
|
||||||
'background-color: {}'.format(get_color("window-background"))
|
'left: 0; top: 0; pointer-events: auto; display: flex; flex-direction: column;'
|
||||||
|
'background-color: {}; max-width: {}'.format(get_color("window-background"), max_width),
|
||||||
|
|
||||||
|
E.div(style='height: 4ex; display: flex; align-items: center; padding: 5px; justify-content: center'),
|
||||||
|
|
||||||
|
E.hr(style='border-top: solid 1px; margin: 0; padding: 0'),
|
||||||
|
|
||||||
|
E.div(
|
||||||
|
style='display: none; padding: 5px;',
|
||||||
|
E.div(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
c.appendChild(bar)
|
bar = bar_container.firstChild
|
||||||
|
c.appendChild(bar_container)
|
||||||
|
|
||||||
def cb(icon, tooltip, callback):
|
def cb(icon, tooltip, callback):
|
||||||
ans = svgicon(icon, '3ex', '3ex', tooltip)
|
ans = svgicon(icon, '3ex', '3ex', tooltip)
|
||||||
@ -35,6 +48,12 @@ class SelectionBar:
|
|||||||
bar.appendChild(cb('library', _('Lookup/search selected word'), self.lookup))
|
bar.appendChild(cb('library', _('Lookup/search selected word'), self.lookup))
|
||||||
bar.appendChild(cb('highlight', _('Highlight selection'), self.create_highlight))
|
bar.appendChild(cb('highlight', _('Highlight selection'), self.create_highlight))
|
||||||
bar.appendChild(cb('close', _('Clear the selection'), self.clear_selection))
|
bar.appendChild(cb('close', _('Clear the selection'), self.clear_selection))
|
||||||
|
self.show_notes(bar_container, notes)
|
||||||
|
return bar_container
|
||||||
|
|
||||||
|
@property
|
||||||
|
def supports_css_min_max(self):
|
||||||
|
return not runtime.is_standalone_viewer or runtime.QT_VERSION >= 0x050f00
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def container(self):
|
def container(self):
|
||||||
@ -48,9 +67,8 @@ class SelectionBar:
|
|||||||
self.container.style.display = 'none'
|
self.container.style.display = 'none'
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
if self.view.create_annotation.is_visible:
|
if not self.view.create_annotation.is_visible:
|
||||||
return
|
self.container.style.display = 'block'
|
||||||
self.container.style.display = 'block'
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_visible(self):
|
def is_visible(self):
|
||||||
@ -69,11 +87,46 @@ class SelectionBar:
|
|||||||
def create_highlight(self):
|
def create_highlight(self):
|
||||||
self.view.initiate_create_annotation(True)
|
self.view.initiate_create_annotation(True)
|
||||||
|
|
||||||
|
def show_notes(self, bar, notes):
|
||||||
|
notes = (notes or "").strip()
|
||||||
|
if not notes:
|
||||||
|
return
|
||||||
|
notes_container = bar.lastChild
|
||||||
|
c = notes_container.lastChild
|
||||||
|
notes_container.style.display = notes_container.previousSibling.style.display = 'block'
|
||||||
|
c.style.overflow = 'auto'
|
||||||
|
if self.supports_css_min_max:
|
||||||
|
c.style.maxHeight = 'min(20ex, 40vh)'
|
||||||
|
else:
|
||||||
|
c.style.maxHeight = '20ex'
|
||||||
|
current_block = ''
|
||||||
|
|
||||||
|
def add_para():
|
||||||
|
nonlocal current_block
|
||||||
|
c.appendChild(E.p(current_block))
|
||||||
|
if c.childNodes.length > 1:
|
||||||
|
c.lastChild.style.marginTop = '2ex'
|
||||||
|
current_block = ''
|
||||||
|
|
||||||
|
for line in notes.splitlines():
|
||||||
|
if not line or not line.strip():
|
||||||
|
if current_block:
|
||||||
|
add_para()
|
||||||
|
continue
|
||||||
|
current_block += line + '\n'
|
||||||
|
if current_block:
|
||||||
|
add_para()
|
||||||
|
|
||||||
def update_position(self):
|
def update_position(self):
|
||||||
|
container = self.container
|
||||||
|
clear(container)
|
||||||
cs = self.view.currently_showing
|
cs = self.view.currently_showing
|
||||||
if not cs.has_selection:
|
if not cs.has_selection:
|
||||||
return self.hide()
|
return self.hide()
|
||||||
|
|
||||||
|
if not cs.selection_start.onscreen and not cs.selection_end.onscreen:
|
||||||
|
return self.hide()
|
||||||
|
|
||||||
margins = {
|
margins = {
|
||||||
'top': document.getElementById('book-top-margin').offsetHeight,
|
'top': document.getElementById('book-top-margin').offsetHeight,
|
||||||
'bottom': document.getElementById('book-bottom-margin').offsetHeight,
|
'bottom': document.getElementById('book-bottom-margin').offsetHeight,
|
||||||
@ -84,15 +137,11 @@ class SelectionBar:
|
|||||||
def map_boundary(x):
|
def map_boundary(x):
|
||||||
return {'x': (x.x or 0) + margins.left, 'y': (x.y or 0) + margins.top, 'height': x.height or 0, 'onscreen': x.onscreen}
|
return {'x': (x.x or 0) + margins.left, 'y': (x.y or 0) + margins.top, 'height': x.height or 0, 'onscreen': x.onscreen}
|
||||||
|
|
||||||
if not cs.selection_start.onscreen and not cs.selection_end.onscreen:
|
bar = self.build_bar(self.view.annotations_manager.notes_for_highlight(cs.selection_annot_id))
|
||||||
return self.hide()
|
|
||||||
start = map_boundary(cs.selection_start)
|
start = map_boundary(cs.selection_start)
|
||||||
end = map_boundary(cs.selection_end)
|
end = map_boundary(cs.selection_end)
|
||||||
|
|
||||||
self.show()
|
self.show()
|
||||||
end_after_start = start.y < end.y or (start.y is end.y and start.x < end.x)
|
end_after_start = start.y < end.y or (start.y is end.y and start.x < end.x)
|
||||||
container = self.container
|
|
||||||
bar = self.bar
|
|
||||||
|
|
||||||
# vertical position
|
# vertical position
|
||||||
bar_height = bar.offsetHeight
|
bar_height = bar.offsetHeight
|
||||||
@ -106,9 +155,11 @@ class SelectionBar:
|
|||||||
top = (end.y + end.height + buffer) if put_below else (end.y - bar_height - buffer)
|
top = (end.y + end.height + buffer) if put_below else (end.y - bar_height - buffer)
|
||||||
top = max(buffer, min(top, container.offsetHeight - bar_height - buffer))
|
top = max(buffer, min(top, container.offsetHeight - bar_height - buffer))
|
||||||
bar.style.top = top + 'px'
|
bar.style.top = top + 'px'
|
||||||
|
bar.style.flexDirection = 'column' if put_below else 'column-reverse'
|
||||||
|
|
||||||
# horizontal position
|
# horizontal position
|
||||||
bar_width = bar.offsetWidth
|
bar_width = bar.offsetWidth
|
||||||
left = end.x - bar_width // 2
|
left = end.x - bar_width // 2
|
||||||
left = max(buffer, min(left, container.offsetWidth - bar_width - buffer))
|
# - 10 ensures we dont cover scroll bar
|
||||||
|
left = max(buffer, min(left, container.offsetWidth - bar_width - buffer - 10))
|
||||||
bar.style.left = left + 'px'
|
bar.style.left = left + 'px'
|
||||||
|
@ -13,9 +13,7 @@ from dom import add_extra_css, build_rule, clear, set_css, svgicon, unique_id
|
|||||||
from iframe_comm import IframeWrapper
|
from iframe_comm import IframeWrapper
|
||||||
from modals import error_dialog, warning_dialog
|
from modals import error_dialog, warning_dialog
|
||||||
from read_book.content_popup import ContentPopupOverlay
|
from read_book.content_popup import ContentPopupOverlay
|
||||||
from read_book.create_annotation import (
|
from read_book.create_annotation import AnnotationsManager, CreateAnnotation
|
||||||
AnnotationsManager, CreateAnnotation, ViewAnnotation
|
|
||||||
)
|
|
||||||
from read_book.globals import (
|
from read_book.globals import (
|
||||||
current_book, runtime, set_current_spine_item, ui_operations
|
current_book, runtime, set_current_spine_item, ui_operations
|
||||||
)
|
)
|
||||||
@ -229,7 +227,6 @@ class View:
|
|||||||
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; overflow: auto; display:none', id='book-overlay'), # main overlay
|
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; overflow: auto; display:none', id='book-overlay'), # main overlay
|
||||||
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; display:none', id='controls-help-overlay'), # controls help overlay
|
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; display:none', id='controls-help-overlay'), # controls help overlay
|
||||||
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; display:none; overflow: hidden', id=CreateAnnotation.container_id, tabindex='0'), # create annotation overlay
|
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; display:none; overflow: hidden', id=CreateAnnotation.container_id, tabindex='0'), # create annotation overlay
|
||||||
E.div(style='position: absolute; top:0; left:0; width: 100%; height: 100%; pointer-events:none; display:none; z-index: 4000', id=ViewAnnotation.container_id), # view annotation overlay
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
E.div(
|
E.div(
|
||||||
@ -301,7 +298,6 @@ class View:
|
|||||||
self.book_scrollbar.apply_visibility()
|
self.book_scrollbar.apply_visibility()
|
||||||
self.annotations_manager = AnnotationsManager(self)
|
self.annotations_manager = AnnotationsManager(self)
|
||||||
self.create_annotation = CreateAnnotation(self)
|
self.create_annotation = CreateAnnotation(self)
|
||||||
self.view_annotation = ViewAnnotation(self)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def iframe(self):
|
def iframe(self):
|
||||||
@ -526,6 +522,7 @@ class View:
|
|||||||
self.currently_showing.has_selection = not data.empty
|
self.currently_showing.has_selection = not data.empty
|
||||||
self.currently_showing.selection_start = data.selection_extents.start
|
self.currently_showing.selection_start = data.selection_extents.start
|
||||||
self.currently_showing.selection_end = data.selection_extents.end
|
self.currently_showing.selection_end = data.selection_extents.end
|
||||||
|
self.currently_showing.selection_annot_id = data.annot_id
|
||||||
if ui_operations.selection_changed:
|
if ui_operations.selection_changed:
|
||||||
ui_operations.selection_changed(self.currently_showing.selected_text)
|
ui_operations.selection_changed(self.currently_showing.selected_text)
|
||||||
self.selection_bar.update_position()
|
self.selection_bar.update_position()
|
||||||
@ -610,7 +607,6 @@ class View:
|
|||||||
self.content_popup_overlay.hide()
|
self.content_popup_overlay.hide()
|
||||||
self.reference_mode_overlay.style.display = 'none'
|
self.reference_mode_overlay.style.display = 'none'
|
||||||
self.create_annotation.hide()
|
self.create_annotation.hide()
|
||||||
self.view_annotation.hide()
|
|
||||||
self.focus_iframe()
|
self.focus_iframe()
|
||||||
|
|
||||||
def focus_iframe(self):
|
def focus_iframe(self):
|
||||||
@ -1020,8 +1016,7 @@ class View:
|
|||||||
|
|
||||||
def set_notes_for_highlight(self, uuid, notes):
|
def set_notes_for_highlight(self, uuid, notes):
|
||||||
if self.annotations_manager.set_notes_for_highlight(uuid, notes):
|
if self.annotations_manager.set_notes_for_highlight(uuid, notes):
|
||||||
if self.view_annotation.is_visible and self.view_annotation.showing_uuid is uuid:
|
self.selection_bar.update_position()
|
||||||
self.view_annotation.show(uuid)
|
|
||||||
|
|
||||||
def on_next_spine_item(self, data):
|
def on_next_spine_item(self, data):
|
||||||
spine = self.book.manifest.spine
|
spine = self.book.manifest.spine
|
||||||
|
Loading…
x
Reference in New Issue
Block a user