EPUB CFI basically works. Now for the more comprehensive testing.

This commit is contained in:
Kovid Goyal 2012-01-04 21:50:52 +05:30
parent 6f1824c2eb
commit 5fb8a6d833
5 changed files with 87 additions and 35 deletions

View File

@ -58,16 +58,6 @@ get_current_time = (target) -> # {{{
fstr(ans) 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 class CanonicalFragmentIdentifier
@ -76,13 +66,23 @@ class CanonicalFragmentIdentifier
constructor: () -> 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) -> # {{{ encode: (doc, node, offset, tail) -> # {{{
cfi = tail or "" cfi = tail or ""
# Handle the offset, if any # Handle the offset, if any
switch node.nodeType switch node.nodeType
when 1 # Element node when 1 # Element node
if typeoff(offset) == 'number' if typeof(offset) == 'number'
node = node.childNodes.item(offset) node = node.childNodes.item(offset)
when 3, 4, 5, 6 # Text/entity/CDATA node when 3, 4, 5, 6 # Text/entity/CDATA node
offset or= 0 offset or= 0
@ -136,7 +136,7 @@ class CanonicalFragmentIdentifier
node = doc node = doc
until cfi.length < 1 or error 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]) target = parseInt(r[1])
assertion = r[2] assertion = r[2]
if assertion 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}] try_list = [{start:0, end:0, a:0.5}, {start:0, end:1, a:1}, {start:-1, end:0, a:0}]
else else
try_list = [{start:0, end:0, a:0.5}, {start:-1, end:0, a:0}, {start:0, end:1, a:1}] 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 a = null
rects = null rects = null
node_len = node.nodeValue.length node_len = node.nodeValue.length
until rects or rects.length or k >= try_list.length 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++] t = try_list[k++]
start_offset = r.offset + t.start start_offset = offset + t.start
end_offset = r.offset + t.end end_offset = offset + t.end
a = t.a a = t.a
if start_offset < 0 or end_offset >= node_len if start_offset < 0 or end_offset >= node_len
continue continue
range.setStart(node, start_offset) range.setStart(node, start_offset)
range.setEnd(node, end_offset) range.setEnd(node, end_offset)
rects = range.getClientRects() 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 }") log("Could not find caret position: rects: #{ rects } offset: #{ r.offset }")
return null return null

View File

@ -6,19 +6,59 @@
Released under the GPLv3 License 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) -> viewport_top = (node) ->
$(node).offset().top - window.pageYOffset $(node).offset().top - window.pageYOffset
viewport_left = (node) -> viewport_left = (node) ->
$(node).offset().left - window.pageXOffset $(node).offset().left - window.pageXOffset
window.onload = -> show_cfi = (dont_seek) ->
h1 = document.getElementsByTagName('h1')[0] if window.current_cfi
x = h1.scrollLeft + 150 pos = window.cfi.point(window.current_cfi)
y = viewport_top(h1) + h1.offsetHeight/2 ms = document.getElementById("marker").style
e = document.elementFromPoint x, y if pos
if e.getAttribute('id') != 'first-h1' ms.visibility = "visible"
alert 'Failed to find top h1' ms.top = (pos.y - 30) + window.scrollY + "px"
return ms.left = (pos.x - 1) + window.scrollX + "px"
alert window.cfi.at x, y 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

View File

@ -8,6 +8,8 @@
</head> </head>
<body> <body>
<h1 id="first-h1" style="border: solid 1px red">Testing CFI functionality</h1> <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> </body>
</html> </html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

View File

@ -10,7 +10,8 @@ __docformat__ = 'restructuredtext en'
''' '''
Utilities to help with developing coffeescript based apps 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): class Handler(SimpleHTTPServer.SimpleHTTPRequestHandler):
@ -28,7 +29,7 @@ class Handler(SimpleHTTPServer.SimpleHTTPRequestHandler):
self.send_header("Content-Length", bytes(len(raw))) self.send_header("Content-Length", bytes(len(raw)))
self.send_header("Last-Modified", self.date_time_string(int(mtime))) self.send_header("Last-Modified", self.date_time_string(int(mtime)))
self.end_headers() self.end_headers()
return cStringIO.StringIO(raw) return BytesIO(raw)
return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self) return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self)