@on_page_up_key e
return false
when KEY_PAGE_DOWN
+ @on_page_down_key e
return false
when KEY_TAB
return false
@kill_cursor()
return
on_page_up_key: (e) ->
+ if @cursor?
+ screen_y = @cursor.y - @wrap2.scrollTop
scroll_amount = @wrap2_height - breathing_room
- # scroll up a page
@wrap2.scrollTop = Math.max 0, @wrap2.scrollTop - scroll_amount
- # note: if cursor innacuracy causes it no not be within new scroll,
- # @move_cursor will adjust the scroll a bit.
if @cursor?
- # move cursor up approximately scroll_amount
- was = @cursor
- y_target = @cursor.y - scroll_amount
- y_min = Math.min y_target, @wrap2.scrollTop
- y_max = Math.min y_target, @wrap2.scrollTop - scroll_amount
- y_target = Math.min y_target, y_max
- y_target = Math.max y_target, y_min
- loop
- cur = find_up_cursor_position @tree, was, @cursor_ideal_x
- break unless cur?
- break if cur.y <= y_target
- was = cur
- if was is @cursor
- if cur?
- new_cursor = cur
- else
- # should this move the cursor to the beginning of the line?
- new_cursor = null
- else
- if cur?
- # both valid, pick best
- if cur.y < y_min
- new_cursor = was
- else if was.y > y_max
- new_cursor = cur
- else if cur.y - y_target < y_target - was.y
- new_cursor = cur
- else
- new_cursor = was
- else
- new_cursor = was
+ @move_cursor_into_view screen_y + @wrap2.scrollTop
+ on_page_down_key: (e) ->
+ if @cursor?
+ screen_y = @cursor.y - @wrap2.scrollTop
+ scroll_amount = @wrap2_height - breathing_room
+ lowest_scrollpos = @wrap2.scrollHeight - @wrap2_height
+ if @wrap2.scrollTop is lowest_scrollpos # already at bottom
+ return unless @cursor?
+ # move cursor to bottom
+ new_cursor = last_cursor_position @tree
if new_cursor?
- saved_ideal_x = @cursor_ideal_x
- @move_cursor new_cursor
- @cursor_ideal_x = saved_ideal_x
+ if new_cursor.n isnt @cursor.n or new_cursor.i isnt @cursor.i
+ @move_cursor new_cursor
+ return
+ @wrap2.scrollTop = Math.min lowest_scrollpos, @wrap2.scrollTop + scroll_amount
+ if @cursor?
+ @move_cursor_into_view screen_y + @wrap2.scrollTop
+ return
+ move_cursor_into_view: (y_target) ->
+ return if y_target is @cursor.y
+ was = @cursor
+ y_min = @wrap2.scrollTop
+ unless @wrap2.scrollTop is 0
+ y_min += breathing_room
+ y_max = @wrap2.scrollTop + @wrap2_height
+ unless @wrap2.scrollTop is @wrap2.scrollHeight - @wrap2_height # downmost
+ y_max -= breathing_room
+ y_target = Math.min y_target, y_max
+ y_target = Math.max y_target, y_min
+ if y_target < @cursor.y
+ finder = find_up_cursor_position
+ far_enough = (cur, target_y) ->
+ return cur.y + cur.h <= target_y
+ else
+ finder = find_down_cursor_position
+ far_enough = (cur, y_target) ->
+ return cur.y >= y_target
+ loop
+ cur = finder @tree, was, @cursor_ideal_x
+ break unless cur?
+ break if far_enough cur, y_target
+ was = cur
+ if was is @cursor
+ was = null
+ if was?
+ if was.y + was.h > y_max
+ was = null
+ else if was.y < y_min
+ was = null
+ if cur?
+ if cur.y + cur.h > y_max
+ cur = null
+ else if cur.y < y_min
+ cur = null
+ if cur? and was?
+ # both valid, pick best
+ if cur.y < y_min
+ new_cursor = was
+ else if was.y + was.h > y_max
+ new_cursor = cur
+ else if cur.y - y_target < y_target - was.y
+ new_cursor = cur
+ else
+ new_cursor = was
+ else
+ new_cursor = was ? cur
+ if new_cursor?
+ saved_ideal_x = @cursor_ideal_x
+ @move_cursor new_cursor
+ @cursor_ideal_x = saved_ideal_x
return
clear_dom: -> # remove all the editable content (and cursor, overlays, etc)
while @idoc.body.childNodes.length