mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Click to position handles implemented
This commit is contained in:
parent
97da8da4c9
commit
4defd82bed
@ -4,10 +4,10 @@ from __python__ import bound_methods, hash_literals
|
|||||||
|
|
||||||
from dom import svgicon, ensure_id
|
from dom import svgicon, ensure_id
|
||||||
|
|
||||||
WAITING_FOR_CLICK = 0
|
WAITING_FOR_CLICK = 1
|
||||||
WAITING_FOR_DRAG = 1
|
WAITING_FOR_DRAG = 2
|
||||||
DRAGGING_LEFT = 2
|
DRAGGING_LEFT = 3
|
||||||
DRAGGING_RIGHT = 3
|
DRAGGING_RIGHT = 4
|
||||||
|
|
||||||
|
|
||||||
def selection_handle(invert):
|
def selection_handle(invert):
|
||||||
@ -17,6 +17,7 @@ def selection_handle(invert):
|
|||||||
s.transform = 'scaleX(-1)'
|
s.transform = 'scaleX(-1)'
|
||||||
s.position = 'absolute'
|
s.position = 'absolute'
|
||||||
s.boxSizing = 'border-box'
|
s.boxSizing = 'border-box'
|
||||||
|
s.touchAction = 'none'
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
@ -28,6 +29,14 @@ def map_from_iframe_coords(point):
|
|||||||
return point
|
return point
|
||||||
|
|
||||||
|
|
||||||
|
def map_to_iframe_coords(point):
|
||||||
|
l = document.getElementById('book-left-margin')
|
||||||
|
point.x -= l.offsetWidth
|
||||||
|
t = document.getElementById('book-top-margin')
|
||||||
|
point.y -= t.offsetHeight
|
||||||
|
return point
|
||||||
|
|
||||||
|
|
||||||
class CreateAnnotation:
|
class CreateAnnotation:
|
||||||
|
|
||||||
container_id = 'create-annotation-overlay'
|
container_id = 'create-annotation-overlay'
|
||||||
@ -44,6 +53,14 @@ class CreateAnnotation:
|
|||||||
self.right_handle_id = ensure_id(rh, 'handle')
|
self.right_handle_id = ensure_id(rh, 'handle')
|
||||||
container.appendChild(rh)
|
container.appendChild(rh)
|
||||||
|
|
||||||
|
container.addEventListener('click', self.container_clicked)
|
||||||
|
|
||||||
|
def container_clicked(self, ev):
|
||||||
|
ev.stopPropagation(), ev.preventDefault()
|
||||||
|
if self.state is WAITING_FOR_CLICK:
|
||||||
|
pt = map_to_iframe_coords({'x': ev.clientX, 'y': ev.clientY})
|
||||||
|
self.send_message(type='position-handles-at-point', x=pt.x, y=pt.y)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def container(self):
|
def container(self):
|
||||||
return document.getElementById(self.container_id)
|
return document.getElementById(self.container_id)
|
||||||
@ -78,6 +95,9 @@ class CreateAnnotation:
|
|||||||
self.hide_handles()
|
self.hide_handles()
|
||||||
if msg.extents.start.x is not None:
|
if msg.extents.start.x is not None:
|
||||||
self.place_handles(msg.extents)
|
self.place_handles(msg.extents)
|
||||||
|
elif msg.type is 'position-handles':
|
||||||
|
if self.state is WAITING_FOR_CLICK:
|
||||||
|
self.place_handles(msg.extents)
|
||||||
else:
|
else:
|
||||||
print('Ignoring annotations message with unknown type:', msg.type)
|
print('Ignoring annotations message with unknown type:', msg.type)
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ from __python__ import bound_methods, hash_literals
|
|||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
from select import selection_extents, selection_extents_at_point
|
||||||
|
|
||||||
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
|
||||||
@ -50,7 +51,7 @@ from read_book.touch import (
|
|||||||
create_handlers as create_touch_handlers, reset_handlers as reset_touch_handlers
|
create_handlers as create_touch_handlers, reset_handlers as reset_touch_handlers
|
||||||
)
|
)
|
||||||
from read_book.viewport import scroll_viewport
|
from read_book.viewport import scroll_viewport
|
||||||
from utils import debounce, html_escape, is_ios, selection_extents
|
from utils import debounce, html_escape, is_ios
|
||||||
|
|
||||||
FORCE_FLOW_MODE = False
|
FORCE_FLOW_MODE = False
|
||||||
CALIBRE_VERSION = '__CALIBRE_VERSION__'
|
CALIBRE_VERSION = '__CALIBRE_VERSION__'
|
||||||
@ -120,6 +121,7 @@ class IframeBoss:
|
|||||||
'overlay_visibility_changed': self.on_overlay_visibility_changed,
|
'overlay_visibility_changed': self.on_overlay_visibility_changed,
|
||||||
'show_search_result': self.show_search_result,
|
'show_search_result': self.show_search_result,
|
||||||
'handle_navigation_shortcut': self.on_handle_navigation_shortcut,
|
'handle_navigation_shortcut': self.on_handle_navigation_shortcut,
|
||||||
|
'annotations': self.annotations_msg_received,
|
||||||
}
|
}
|
||||||
self.comm = IframeClient(handlers)
|
self.comm = IframeClient(handlers)
|
||||||
self.last_window_ypos = 0
|
self.last_window_ypos = 0
|
||||||
@ -608,6 +610,15 @@ class IframeBoss:
|
|||||||
extents=selection_extents(),
|
extents=selection_extents(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def annotations_msg_received(self, data):
|
||||||
|
if data.type is 'position-handles-at-point':
|
||||||
|
self.send_message(
|
||||||
|
'annotations',
|
||||||
|
type='position-handles',
|
||||||
|
extents=selection_extents_at_point(data.x, data.y))
|
||||||
|
else:
|
||||||
|
console.log('Ignoring annotations message to iframe with unknown type: ' + data.type)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
main.boss = IframeBoss()
|
main.boss = IframeBoss()
|
||||||
|
@ -42,3 +42,51 @@ def word_at_point(x, y):
|
|||||||
r.setStart(r.startContainer, word_info.start)
|
r.setStart(r.startContainer, word_info.start)
|
||||||
r.setEnd(r.startContainer, word_info.end)
|
r.setEnd(r.startContainer, word_info.end)
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def range_extents(start, end):
|
||||||
|
ans = {'start': {'x': None, 'y': None, 'height': None}, 'end': {'x': None, 'y': None, 'height': None}}
|
||||||
|
if not start or not end:
|
||||||
|
return ans
|
||||||
|
start = start.cloneRange()
|
||||||
|
end = end.cloneRange()
|
||||||
|
start.collapse(True)
|
||||||
|
end.collapse(False)
|
||||||
|
|
||||||
|
def for_boundary(r, ans):
|
||||||
|
rects = r.getClientRects()
|
||||||
|
if not rects.length:
|
||||||
|
return
|
||||||
|
rect = rects[0]
|
||||||
|
ans.x = rect.left
|
||||||
|
ans.y = rect.top
|
||||||
|
ans.height = rect.bottom - rect.top
|
||||||
|
|
||||||
|
for_boundary(start, ans.start)
|
||||||
|
for_boundary(end, ans.end)
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def selection_extents():
|
||||||
|
sel = window.getSelection()
|
||||||
|
if not sel or not sel.rangeCount:
|
||||||
|
return range_extents()
|
||||||
|
start = sel.getRangeAt(0)
|
||||||
|
end = sel.getRangeAt(sel.rangeCount - 1)
|
||||||
|
return range_extents(start, end)
|
||||||
|
|
||||||
|
|
||||||
|
def selection_extents_at_point(x, y):
|
||||||
|
r = word_at_point(x, y)
|
||||||
|
if r:
|
||||||
|
sel = window.getSelection()
|
||||||
|
sel.removeAllRanges()
|
||||||
|
sel.addRange(r)
|
||||||
|
return selection_extents(r, r)
|
||||||
|
ans = range_extents()
|
||||||
|
ans.start.y = ans.end.y = y
|
||||||
|
ans.start.height = ans.end.height = parseInt(window.getComputedStyle(document.body).fontSize) + 4
|
||||||
|
ans.start.x = x
|
||||||
|
ans.end.x = x + ans.start.height * 3
|
||||||
|
return ans
|
||||||
|
@ -252,30 +252,6 @@ def sandboxed_html(html, style, sandbox):
|
|||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
def selection_extents():
|
|
||||||
ans = {'start': {'x': None, 'y': None, 'height': None}, 'end': {'x': None, 'y': None, 'height': None}}
|
|
||||||
sel = window.getSelection()
|
|
||||||
if not sel or not sel.rangeCount:
|
|
||||||
return ans
|
|
||||||
start = sel.getRangeAt(0).cloneRange()
|
|
||||||
end = sel.getRangeAt(sel.rangeCount - 1).cloneRange()
|
|
||||||
start.collapse(True)
|
|
||||||
end.collapse(False)
|
|
||||||
|
|
||||||
def for_boundary(r, ans):
|
|
||||||
rects = r.getClientRects()
|
|
||||||
if not rects.length:
|
|
||||||
return
|
|
||||||
rect = rects[0]
|
|
||||||
ans.x = rect.left
|
|
||||||
ans.y = rect.top
|
|
||||||
ans.height = rect.bottom - rect.top
|
|
||||||
|
|
||||||
for_boundary(start, ans.start)
|
|
||||||
for_boundary(end, ans.end)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ is '__main__':
|
if __name__ is '__main__':
|
||||||
from pythonize import strings
|
from pythonize import strings
|
||||||
strings()
|
strings()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user