Proper CFI calculation for paged mode

This commit is contained in:
Kovid Goyal 2012-06-20 10:14:55 +05:30
parent ce3fba7161
commit 89724d321d
3 changed files with 83 additions and 42 deletions

View File

@ -572,6 +572,44 @@ class CanonicalFragmentIdentifier
null null
# }}} # }}}
at_point: (ox, oy) ->
# The CFI at the specified point. Different to at() in that this method
# returns null if there is an error, and also calculates a point from
# the CFI and returns null if the calculated point is far from the
# original point.
dist = (p1, p2) ->
Math.sqrt(Math.pow(p1[0]-p2[0], 2), Math.pow(p1[1]-p2[1], 2))
try
cfi = window.cfi.at(ox, oy)
point = window.cfi.point(cfi)
catch err
cfi = null
if cfi
if point.range != null
r = point.range
rect = r.getClientRects()[0]
x = (point.a*rect.left + (1-point.a)*rect.right)
y = (rect.top + rect.bottom)/2
[x, y] = viewport_to_document(x, y, r.startContainer.ownerDocument)
else
node = point.node
r = node.getBoundingClientRect()
[x, y] = viewport_to_document(r.left, r.top, node.ownerDocument)
if typeof(point.x) == 'number' and node.offsetWidth
x += (point.x*node.offsetWidth)/100
if typeof(point.y) == 'number' and node.offsetHeight
y += (point.y*node.offsetHeight)/100
if dist(viewport_to_document(ox, oy), [x, y]) > 50
cfi = null
return cfi
at_current: () -> # {{{ at_current: () -> # {{{
[winx, winy] = window_scroll_pos() [winx, winy] = window_scroll_pos()
[winw, winh] = [window.innerWidth, window.innerHeight] [winw, winh] = [window.innerWidth, window.innerHeight]
@ -585,44 +623,12 @@ class CanonicalFragmentIdentifier
minx = max(-winx, -winw) minx = max(-winx, -winw)
maxx = winw maxx = winw
dist = (p1, p2) -> x_loop = (cury) =>
Math.sqrt(Math.pow(p1[0]-p2[0], 2), Math.pow(p1[1]-p2[1], 2))
get_cfi = (ox, oy) ->
try
cfi = window.cfi.at(ox, oy)
point = window.cfi.point(cfi)
catch err
cfi = null
if cfi
if point.range != null
r = point.range
rect = r.getClientRects()[0]
x = (point.a*rect.left + (1-point.a)*rect.right)
y = (rect.top + rect.bottom)/2
[x, y] = viewport_to_document(x, y, r.startContainer.ownerDocument)
else
node = point.node
r = node.getBoundingClientRect()
[x, y] = viewport_to_document(r.left, r.top, node.ownerDocument)
if typeof(point.x) == 'number' and node.offsetWidth
x += (point.x*node.offsetWidth)/100
if typeof(point.y) == 'number' and node.offsetHeight
y += (point.y*node.offsetHeight)/100
if dist(viewport_to_document(ox, oy), [x, y]) > 50
cfi = null
return cfi
x_loop = (cury) ->
for direction in [-1, 1] for direction in [-1, 1]
delta = deltax * direction delta = deltax * direction
curx = 0 curx = 0
until (direction < 0 and curx < minx) or (direction > 0 and curx > maxx) until (direction < 0 and curx < minx) or (direction > 0 and curx > maxx)
cfi = get_cfi(curx, cury) cfi = this.at_point(curx, cury)
if cfi if cfi
return cfi return cfi
curx += delta curx += delta

View File

@ -67,6 +67,8 @@ class PagedDisplay
### ###
constructor: () -> constructor: () ->
if not this instanceof arguments.callee
throw new Error('PagedDisplay constructor called as function')
this.set_geometry() this.set_geometry()
this.page_width = 0 this.page_width = 0
this.screen_width = 0 this.screen_width = 0
@ -213,11 +215,11 @@ class PagedDisplay
# most column in the viewport is the column containing the start of the # most column in the viewport is the column containing the start of the
# element and that the scroll position is at the start of the column. # element and that the scroll position is at the start of the column.
elem = document.getElementById(name) elem = document.getElementById(name)
if !elem if not elem
elems = document.getElementsByName(name) elems = document.getElementsByName(name)
if elems if elems
elem = elems[0] elem = elems[0]
if !elem if not elem
return return
elem.scrollIntoView() elem.scrollIntoView()
if this.in_paged_mode if this.in_paged_mode
@ -249,12 +251,48 @@ class PagedDisplay
window.scrollTo(0, y) window.scrollTo(0, y)
) )
current_cfi: () ->
# The Conformal Fragment Identifier at the current position, returns
# null if it could not be calculated. Requires the cfi.coffee library.
ans = null
if not window.cfi?
return ans
if this.in_paged_mode
c = this.current_column_location()
for x in [c, c-this.page_width, c+this.page_width]
# Try the current column, the previous column and the next
# column. Each column is tried from top to bottom.
[left, right] = [x, x + this.page_width]
if left < 0 or right > document.body.scrollWidth
continue
deltax = Math.floor(this.page_width/25)
deltay = Math.floor(window.innerHeight/25)
cury = this.margin_top
until cury >= (window.innerHeight - this.margin_bottom)
curx = left + this.current_margin_side
until curx >= (right - this.current_margin_side)
cfi = window.cfi.at_point(curx-window.pageXOffset, cury-window.pageYOffset)
if cfi
log('Viewport cfi:', cfi)
return cfi
curx += deltax
cury += deltay
else
try
ans = window.cfi.at_current()
if not ans
ans = null
catch err
log(err)
if ans
log('Viewport cfi:', ans)
return ans
if window? if window?
window.paged_display = new PagedDisplay() window.paged_display = new PagedDisplay()
# TODO: # TODO:
# css pagebreak rules # css pagebreak rules
# CFI and bookmarks
# Go to reference positions # Go to reference positions
# Indexing # Indexing
# Resizing of images # Resizing of images

View File

@ -19,13 +19,10 @@ class PagePosition(object):
ans = None ans = None
res = self.document.mainFrame().evaluateJavaScript(''' res = self.document.mainFrame().evaluateJavaScript('''
ans = 'undefined'; ans = 'undefined';
try { if (window.paged_display) {
ans = window.cfi.at_current(); ans = window.paged_display.current_cfi();
if (!ans) ans = 'undefined'; if (!ans) ans = 'undefined';
} catch (err) {
window.console.log(err);
} }
window.console.log("Viewport cfi: " + ans);
ans; ans;
''') ''')
if res.isValid() and not res.isNull() and res.type() == res.String: if res.isValid() and not res.isNull() and res.type() == res.String: