mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -04:00
EPUB CFI basically works. Now for the more comprehensive testing.
This commit is contained in:
parent
6f1824c2eb
commit
5fb8a6d833
@ -58,16 +58,6 @@ get_current_time = (target) -> # {{{
|
||||
fstr(ans)
|
||||
# }}}
|
||||
|
||||
set_current_time = (target, val) -> # {{{
|
||||
if target.currentTime == undefined
|
||||
return
|
||||
if target.readyState == 4 or target.readyState == "complete"
|
||||
target.currentTime = val
|
||||
else
|
||||
fn = -> target.currentTime = val
|
||||
target.addEventListener("canplay", fn, false)
|
||||
|
||||
#}}}
|
||||
|
||||
class CanonicalFragmentIdentifier
|
||||
|
||||
@ -76,13 +66,23 @@ class CanonicalFragmentIdentifier
|
||||
|
||||
constructor: () ->
|
||||
|
||||
set_current_time: (target, val) -> # {{{
|
||||
if target.currentTime == undefined
|
||||
return
|
||||
if target.readyState == 4 or target.readyState == "complete"
|
||||
target.currentTime = val
|
||||
else
|
||||
fn = -> target.currentTime = val
|
||||
target.addEventListener("canplay", fn, false)
|
||||
#}}}
|
||||
|
||||
encode: (doc, node, offset, tail) -> # {{{
|
||||
cfi = tail or ""
|
||||
|
||||
# Handle the offset, if any
|
||||
switch node.nodeType
|
||||
when 1 # Element node
|
||||
if typeoff(offset) == 'number'
|
||||
if typeof(offset) == 'number'
|
||||
node = node.childNodes.item(offset)
|
||||
when 3, 4, 5, 6 # Text/entity/CDATA node
|
||||
offset or= 0
|
||||
@ -136,7 +136,7 @@ class CanonicalFragmentIdentifier
|
||||
node = doc
|
||||
|
||||
until cfi.length < 1 or error
|
||||
if ( (r = cfi.match(simple_node_regex)) is not null ) # Path step
|
||||
if (r = cfi.match(simple_node_regex)) # Path step
|
||||
target = parseInt(r[1])
|
||||
assertion = r[2]
|
||||
if assertion
|
||||
@ -318,22 +318,31 @@ class CanonicalFragmentIdentifier
|
||||
try_list = [{start:0, end:0, a:0.5}, {start:0, end:1, a:1}, {start:-1, end:0, a:0}]
|
||||
else
|
||||
try_list = [{start:0, end:0, a:0.5}, {start:-1, end:0, a:0}, {start:0, end:1, a:1}]
|
||||
k = 0
|
||||
a = null
|
||||
rects = null
|
||||
node_len = node.nodeValue.length
|
||||
until rects or rects.length or k >= try_list.length
|
||||
t = try_list[k++]
|
||||
start_offset = r.offset + t.start
|
||||
end_offset = r.offset + t.end
|
||||
a = t.a
|
||||
if start_offset < 0 or end_offset >= node_len
|
||||
continue
|
||||
range.setStart(node, start_offset)
|
||||
range.setEnd(node, end_offset)
|
||||
rects = range.getClientRects()
|
||||
offset = r.offset
|
||||
for i in [0, 1]
|
||||
# Try reducing the offset by 1 if we get no match as if it refers to the position after the
|
||||
# last character we wont get a match with getClientRects
|
||||
offset = r.offset - i
|
||||
if offset < 0
|
||||
offset = 0
|
||||
k = 0
|
||||
until rects?.length or k >= try_list.length
|
||||
t = try_list[k++]
|
||||
start_offset = offset + t.start
|
||||
end_offset = offset + t.end
|
||||
a = t.a
|
||||
if start_offset < 0 or end_offset >= node_len
|
||||
continue
|
||||
range.setStart(node, start_offset)
|
||||
range.setEnd(node, end_offset)
|
||||
rects = range.getClientRects()
|
||||
if rects?.length
|
||||
break
|
||||
|
||||
if not rects or not rects.length
|
||||
if not rects?.length
|
||||
log("Could not find caret position: rects: #{ rects } offset: #{ r.offset }")
|
||||
return null
|
||||
|
||||
|
@ -6,19 +6,59 @@
|
||||
Released under the GPLv3 License
|
||||
###
|
||||
|
||||
log = (error) ->
|
||||
if error
|
||||
if window?.console?.log
|
||||
window.console.log(error)
|
||||
else if process?.stdout?.write
|
||||
process.stdout.write(error + '\n')
|
||||
|
||||
viewport_top = (node) ->
|
||||
$(node).offset().top - window.pageYOffset
|
||||
|
||||
viewport_left = (node) ->
|
||||
$(node).offset().left - window.pageXOffset
|
||||
|
||||
window.onload = ->
|
||||
h1 = document.getElementsByTagName('h1')[0]
|
||||
x = h1.scrollLeft + 150
|
||||
y = viewport_top(h1) + h1.offsetHeight/2
|
||||
e = document.elementFromPoint x, y
|
||||
if e.getAttribute('id') != 'first-h1'
|
||||
alert 'Failed to find top h1'
|
||||
return
|
||||
alert window.cfi.at x, y
|
||||
show_cfi = (dont_seek) ->
|
||||
if window.current_cfi
|
||||
pos = window.cfi.point(window.current_cfi)
|
||||
ms = document.getElementById("marker").style
|
||||
if pos
|
||||
ms.visibility = "visible"
|
||||
ms.top = (pos.y - 30) + window.scrollY + "px"
|
||||
ms.left = (pos.x - 1) + window.scrollX + "px"
|
||||
if not dont_seek
|
||||
if typeof pos.time == "number"
|
||||
window.cfi.set_current_time(pos.node, pos.time)
|
||||
scrollTo(0, pos.y - 30)
|
||||
null
|
||||
|
||||
RELOAD = true
|
||||
|
||||
mark_and_reload = (evt) ->
|
||||
window.current_cfi = window.cfi.at(evt.clientX, evt.clientY)
|
||||
if not RELOAD
|
||||
show_cfi(true)
|
||||
if window.current_cfi
|
||||
fn = () ->
|
||||
newloc = window.location.href.replace(/#.*$/, '') + "#epubcfi(#{ window.current_cfi })"
|
||||
window.location.replace(newloc)
|
||||
if RELOAD
|
||||
window.location.reload()
|
||||
|
||||
setTimeout(fn, 1)
|
||||
null
|
||||
|
||||
window.onload = ->
|
||||
window.onscroll = show_cfi
|
||||
window.onresize = show_cfi
|
||||
document.onclick = mark_and_reload
|
||||
for iframe in document.getElementsByTagName("iframe")
|
||||
iframe.contentWindow.onscroll = show_cfi
|
||||
r = location.hash.match(/#epubcfi\((.+)\)$/)
|
||||
if r
|
||||
window.current_cfi = r[1]
|
||||
setTimeout(show_cfi, 1)
|
||||
null
|
||||
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="first-h1" style="border: solid 1px red">Testing CFI functionality</h1>
|
||||
<img id="marker" style="position: absolute; visibility: hidden;" src="marker.png" alt="Marker" />
|
||||
<p>0123</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
BIN
src/calibre/ebooks/oeb/display/test/marker.png
Normal file
BIN
src/calibre/ebooks/oeb/display/test/marker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 751 B |
@ -10,7 +10,8 @@ __docformat__ = 'restructuredtext en'
|
||||
'''
|
||||
Utilities to help with developing coffeescript based apps
|
||||
'''
|
||||
import time, SimpleHTTPServer, SocketServer, os, subprocess, cStringIO
|
||||
import time, SimpleHTTPServer, SocketServer, os, subprocess
|
||||
from io import BytesIO
|
||||
|
||||
class Handler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
|
||||
@ -28,7 +29,7 @@ class Handler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
||||
self.send_header("Content-Length", bytes(len(raw)))
|
||||
self.send_header("Last-Modified", self.date_time_string(int(mtime)))
|
||||
self.end_headers()
|
||||
return cStringIO.StringIO(raw)
|
||||
return BytesIO(raw)
|
||||
|
||||
return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user