mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Implement adding notes when creating annotations
This commit is contained in:
parent
0f4f21d4a2
commit
a00cde1120
@ -120,7 +120,7 @@ def reset_highlight_counter():
|
|||||||
|
|
||||||
def set_selection_to_highlight():
|
def set_selection_to_highlight():
|
||||||
sel = window.getSelection()
|
sel = window.getSelection()
|
||||||
if not sel or not sel.getRangeAt(0):
|
if not sel or not sel.rangeCount:
|
||||||
return
|
return
|
||||||
r = sel.getRangeAt(0)
|
r = sel.getRangeAt(0)
|
||||||
crw = None
|
crw = None
|
||||||
|
@ -37,6 +37,11 @@ class AnnotationsManager:
|
|||||||
v'delete h.spine_name'
|
v'delete h.spine_name'
|
||||||
v'delete h.spine_index'
|
v'delete h.spine_index'
|
||||||
|
|
||||||
|
def notes_for_highlight(self, uuid):
|
||||||
|
h = self.highlights[uuid]
|
||||||
|
if h:
|
||||||
|
return h.notes
|
||||||
|
|
||||||
def add_highlight(self, msg, style, notes):
|
def add_highlight(self, msg, style, notes):
|
||||||
now = Date().toISOString()
|
now = Date().toISOString()
|
||||||
for uuid in msg.removed_highlights:
|
for uuid in msg.removed_highlights:
|
||||||
@ -138,6 +143,7 @@ class CreateAnnotation:
|
|||||||
def __init__(self, view):
|
def __init__(self, view):
|
||||||
self.view = view
|
self.view = view
|
||||||
self.editing_annot_uuid = None
|
self.editing_annot_uuid = None
|
||||||
|
self.current_notes = ''
|
||||||
self.annotations_manager = self.view.annotations_manager
|
self.annotations_manager = self.view.annotations_manager
|
||||||
self.state = WAITING_FOR_CLICK
|
self.state = WAITING_FOR_CLICK
|
||||||
self.left_line_height = self.right_line_height = 8
|
self.left_line_height = self.right_line_height = 8
|
||||||
@ -171,10 +177,10 @@ class CreateAnnotation:
|
|||||||
tb.appendChild(E.span(style=f'height: {tb.style.height}'))
|
tb.appendChild(E.span(style=f'height: {tb.style.height}'))
|
||||||
if ui_operations.copy_selection:
|
if ui_operations.copy_selection:
|
||||||
button(tb.lastChild, 'copy', _('Copy to clipboard'), self.copy_to_clipboard)
|
button(tb.lastChild, 'copy', _('Copy to clipboard'), self.copy_to_clipboard)
|
||||||
tb.lastChild.appendChild(E.span('\xa0'))
|
tb.lastChild.appendChild(E.span('\xa0\xa0\xa0'))
|
||||||
button(tb.lastChild, 'check', _('Finish creation of highlight'), self.accept)
|
button(tb.lastChild, 'check', _('Finish creation of highlight'), self.accept)
|
||||||
|
|
||||||
middle = E.div(id=unique_id('middle'), style='display: none')
|
middle = E.div(id=unique_id('middle'), style='display: none; text-align: center; z-index: 90000')
|
||||||
self.middle_id = middle.id
|
self.middle_id = middle.id
|
||||||
container.appendChild(middle)
|
container.appendChild(middle)
|
||||||
|
|
||||||
@ -182,7 +188,7 @@ class CreateAnnotation:
|
|||||||
container.appendChild(bb)
|
container.appendChild(bb)
|
||||||
button(bb, 'fg', _('Change highlight color'), self.choose_color)
|
button(bb, 'fg', _('Change highlight color'), self.choose_color)
|
||||||
button(bb, 'chevron-down', _('Scroll down'), self.scroll_down)
|
button(bb, 'chevron-down', _('Scroll down'), self.scroll_down)
|
||||||
button(bb, 'pencil', _('Add a note'), self.add_text)
|
button(bb, 'pencil', _('Add a note'), self.add_notes)
|
||||||
|
|
||||||
sd = get_session_data()
|
sd = get_session_data()
|
||||||
style = sd.get('highlight_style') or {
|
style = sd.get('highlight_style') or {
|
||||||
@ -218,10 +224,67 @@ class CreateAnnotation:
|
|||||||
def middle(self):
|
def middle(self):
|
||||||
return document.getElementById(self.middle_id)
|
return document.getElementById(self.middle_id)
|
||||||
|
|
||||||
def choose_color(self):
|
def add_notes(self):
|
||||||
|
self.show_middle(self.apply_notes)
|
||||||
|
container = self.middle
|
||||||
|
clear(container)
|
||||||
|
c = E.div(
|
||||||
|
style=f'background: {get_color("window-background")}; margin: auto; padding: 1rem',
|
||||||
|
onclick=def(ev):
|
||||||
|
ev.stopPropagation(), ev.preventDefault()
|
||||||
|
self.hide_middle()
|
||||||
|
,
|
||||||
|
|
||||||
|
E.h3(_('Add notes for this highlight')),
|
||||||
|
E.textarea(
|
||||||
|
self.current_notes or '',
|
||||||
|
rows='10', spellcheck='true', style='resize: none; width: 80vw; max-width: 80em; margin: 1ex',
|
||||||
|
onkeydown=def(ev):
|
||||||
|
ev.stopPropagation()
|
||||||
|
if ev.key is 'Escape':
|
||||||
|
self.hide_middle()
|
||||||
|
,
|
||||||
|
onclick=def(ev):
|
||||||
|
ev.stopPropagation()
|
||||||
|
),
|
||||||
|
E.div(
|
||||||
|
style='display: flex; justify-content: space-between; margin-top: 1ex; align-items: center',
|
||||||
|
E.a(
|
||||||
|
svgicon('eraser', f'{BAR_SIZE}px', f'{BAR_SIZE}px'),
|
||||||
|
href='javascript:void',
|
||||||
|
class_='simple-link',
|
||||||
|
title=_('Clear'),
|
||||||
|
onclick=def(ev):
|
||||||
|
ev.preventDefault(), ev.stopPropagation()
|
||||||
|
ta = self.middle.querySelector('textarea')
|
||||||
|
ta.value = ''
|
||||||
|
ta.focus()
|
||||||
|
),
|
||||||
|
E.div(
|
||||||
|
_('To view the notes for a highlight, tap or click on it.'),
|
||||||
|
style='font-size-smaller; margin-left: 1rem; margin-right: 1rem'
|
||||||
|
),
|
||||||
|
E.a(
|
||||||
|
svgicon('check', f'{BAR_SIZE}px', f'{BAR_SIZE}px'),
|
||||||
|
href='javascript:void',
|
||||||
|
class_='simple-link',
|
||||||
|
title=_('Done adding notes'),
|
||||||
|
onclick=def(ev):
|
||||||
|
ev.preventDefault(), ev.stopPropagation()
|
||||||
|
self.hide_middle()
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
container.appendChild(c)
|
||||||
|
c.querySelector('textarea').focus()
|
||||||
|
|
||||||
|
def apply_notes(self):
|
||||||
|
self.current_notes = self.middle.querySelector('textarea').value or ''
|
||||||
|
return True
|
||||||
|
|
||||||
|
def choose_color(self):
|
||||||
|
self.show_middle()
|
||||||
container = self.middle
|
container = self.middle
|
||||||
container.style.display = 'block'
|
|
||||||
container.style.textAlign = 'center'
|
|
||||||
clear(container)
|
clear(container)
|
||||||
c = E.div(
|
c = E.div(
|
||||||
E.h3(_('Choose highlight color')),
|
E.h3(_('Choose highlight color')),
|
||||||
@ -289,15 +352,20 @@ class CreateAnnotation:
|
|||||||
use.style.stroke = stroke
|
use.style.stroke = stroke
|
||||||
use.style.fill = fill
|
use.style.fill = fill
|
||||||
|
|
||||||
def show_middle(self):
|
def show_middle(self, pre_close_callback):
|
||||||
|
self.pre_middle_close_callback = pre_close_callback
|
||||||
self.save_handle_state()
|
self.save_handle_state()
|
||||||
self.middle.style.display = 'block'
|
self.middle.style.display = 'block'
|
||||||
|
|
||||||
def hide_middle(self):
|
def hide_middle(self):
|
||||||
m = self.middle
|
m = self.middle
|
||||||
if m.style.display is not 'none':
|
if m.style.display is not 'none':
|
||||||
|
if self.pre_middle_close_callback:
|
||||||
|
if not self.pre_middle_close_callback():
|
||||||
|
return
|
||||||
self.restore_handle_state()
|
self.restore_handle_state()
|
||||||
m.style.display = 'none'
|
m.style.display = 'none'
|
||||||
|
self.container.focus()
|
||||||
|
|
||||||
def save_handle_state(self):
|
def save_handle_state(self):
|
||||||
for h in (self.left_handle, self.right_handle):
|
for h in (self.left_handle, self.right_handle):
|
||||||
@ -414,6 +482,7 @@ class CreateAnnotation:
|
|||||||
b.dataset.style = JSON.stringify(val)
|
b.dataset.style = JSON.stringify(val)
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
|
self.middle.style.display = 'none'
|
||||||
c = self.container
|
c = self.container
|
||||||
c.style.display = 'flex'
|
c.style.display = 'flex'
|
||||||
c.focus()
|
c.focus()
|
||||||
@ -430,6 +499,7 @@ class CreateAnnotation:
|
|||||||
def handle_message(self, msg):
|
def handle_message(self, msg):
|
||||||
if msg.type is 'create-annotation':
|
if msg.type is 'create-annotation':
|
||||||
self.editing_annot_uuid = None
|
self.editing_annot_uuid = None
|
||||||
|
self.current_notes = ''
|
||||||
if not self.is_visible:
|
if not self.is_visible:
|
||||||
self.view.hide_overlays()
|
self.view.hide_overlays()
|
||||||
self.state = WAITING_FOR_CLICK
|
self.state = WAITING_FOR_CLICK
|
||||||
@ -443,6 +513,8 @@ class CreateAnnotation:
|
|||||||
if self.state is WAITING_FOR_CLICK:
|
if self.state is WAITING_FOR_CLICK:
|
||||||
self.place_handles(msg.extents)
|
self.place_handles(msg.extents)
|
||||||
self.editing_annot_uuid = msg.existing or None
|
self.editing_annot_uuid = msg.existing or None
|
||||||
|
if self.editing_annot_uuid:
|
||||||
|
self.current_notes = self.annotations_manager.notes_for_highlight(self.editing_annot_uuid) or ''
|
||||||
elif msg.type is 'update-handles':
|
elif msg.type is 'update-handles':
|
||||||
self.place_handles(msg.extents)
|
self.place_handles(msg.extents)
|
||||||
if msg.from_scroll and not msg.selection_extended:
|
if msg.from_scroll and not msg.selection_extended:
|
||||||
@ -460,7 +532,7 @@ class CreateAnnotation:
|
|||||||
_('Highlighting failed'),
|
_('Highlighting failed'),
|
||||||
_('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.annotations_manager.add_highlight(msg, self.current_highlight_style, self.current_notes)
|
||||||
else:
|
else:
|
||||||
print('Ignoring annotations message with unknown type:', msg.type)
|
print('Ignoring annotations message with unknown type:', msg.type)
|
||||||
|
|
||||||
|
@ -659,26 +659,30 @@ class IframeBoss:
|
|||||||
set_selection_style(data.style)
|
set_selection_style(data.style)
|
||||||
elif data.type is 'apply-highlight':
|
elif data.type is 'apply-highlight':
|
||||||
sel = window.getSelection()
|
sel = window.getSelection()
|
||||||
text = ''
|
|
||||||
if sel:
|
|
||||||
text = sel.toString()
|
text = sel.toString()
|
||||||
|
if not sel.rangeCount:
|
||||||
|
return
|
||||||
bounds = cfi_for_selection()
|
bounds = cfi_for_selection()
|
||||||
annot_id, intersecting_wrappers = wrap_text_in_range(data.style)
|
annot_id, intersecting_wrappers = wrap_text_in_range(data.style)
|
||||||
removed_highlights = {}
|
removed_highlights = v'[]'
|
||||||
if annot_id is not None:
|
if annot_id is not None:
|
||||||
sel.removeAllRanges()
|
intersecting_uuids = [self.annot_id_uuid_map[x] for x in intersecting_wrappers]
|
||||||
self.annot_id_uuid_map[annot_id] = data.uuid
|
if data.existing and intersecting_uuids.indexOf(data.existing) > -1:
|
||||||
|
idx = intersecting_uuids.indexOf(data.existing)
|
||||||
|
intersecting_wrappers.splice(idx, 1)
|
||||||
|
data.uuid = data.existing
|
||||||
|
elif intersecting_wrappers.length is 1 and self.annot_id_uuid_map[intersecting_wrappers[0]]:
|
||||||
|
data.uuid = self.annot_id_uuid_map[intersecting_wrappers[0]]
|
||||||
|
intersecting_wrappers = v'[]'
|
||||||
|
removed_highlights = {}
|
||||||
for crw in intersecting_wrappers:
|
for crw in intersecting_wrappers:
|
||||||
unwrap_crw(crw)
|
unwrap_crw(crw)
|
||||||
|
if self.annot_id_uuid_map[crw]:
|
||||||
removed_highlights[self.annot_id_uuid_map[crw]] = True
|
removed_highlights[self.annot_id_uuid_map[crw]] = True
|
||||||
v'delete self.annot_id_uuid_map[crw]'
|
v'delete self.annot_id_uuid_map[crw]'
|
||||||
if data.existing and removed_highlights[data.existing]:
|
|
||||||
data.uuid = data.existing
|
|
||||||
v'delete removed_highlights[data.existing]'
|
|
||||||
removed_highlights = Object.keys(removed_highlights)
|
removed_highlights = Object.keys(removed_highlights)
|
||||||
if removed_highlights.length is 1:
|
sel.removeAllRanges()
|
||||||
data.uuid = removed_highlights[0]
|
self.annot_id_uuid_map[annot_id] = data.uuid
|
||||||
removed_highlights = v'[]'
|
|
||||||
self.send_message(
|
self.send_message(
|
||||||
'annotations',
|
'annotations',
|
||||||
type='highlight-applied',
|
type='highlight-applied',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user