return false
return found # maybe null
+find_up_cursor_position = (tree, cursor, ideal_x) ->
+ new_cursor = cursor
+ # go prev until we're higher on y axis
+ while new_cursor.y >= cursor.y
+ new_cursor = find_prev_cursor_position tree, new_cursor
+ return null unless new_cursor?
+ # done early if we're already left of old cursor position
+ if new_cursor.x <= ideal_x
+ return new_cursor
+ target_y = new_cursor.y
+ # search leftward, until we find the closest position
+ # new_cursor is the prev-most position we've checked
+ # prev_cursor is the older value, so it's not as prev as new_cursor
+ while new_cursor.x > ideal_x and new_cursor.y is target_y
+ prev_cursor = new_cursor
+ new_cursor = find_prev_cursor_position tree, new_cursor
+ break unless new_cursor?
+ # move cursor to prev_cursor or new_cursor
+ if new_cursor?
+ if new_cursor.y is target_y
+ # both valid, and on the same line, use closest
+ if (ideal_x - new_cursor.x) < (prev_cursor.x - ideal_x)
+ return new_cursor
+ else
+ return prev_cursor
+ else
+ # new_cursor on wrong line, use prev_cursor
+ return prev_cursor
+ else
+ # can't go any further prev, use prev_cursor
+ return prev_cursor
+
+find_down_cursor_position = (tree, cursor, ideal_x) ->
+ new_cursor = cursor
+ # go next until we move on the y axis
+ while new_cursor.y <= cursor.y
+ new_cursor = find_next_cursor_position tree, new_cursor
+ return null unless new_cursor?
+ # done early if we're already right of old cursor position
+ if new_cursor.x >= ideal_x
+ # this would be strange, but could happen due to runaround
+ return new_cursor
+ target_y = new_cursor.y
+ # search rightward, until we find the closest position
+ # new_cursor is the next-most position we've checked
+ # prev_cursor is the older value, so it's not as next as new_cursor
+ while new_cursor.x < ideal_x and new_cursor.y is target_y
+ prev_cursor = new_cursor
+ new_cursor = find_next_cursor_position tree, new_cursor
+ break unless new_cursor?
+ # move cursor to prev_cursor or new_cursor
+ if new_cursor?
+ if new_cursor.y is target_y
+ # both valid, and on the same line, use closest
+ if (new_cursor.x - ideal_x) < (ideal_x - prev_cursor.x)
+ return new_cursor
+ else
+ return prev_cursor
+ else
+ # new_cursor on wrong line, use prev_cursor
+ return prev_cursor
+ else
+ # can't go any further prev, use prev_cursor
+ return prev_cursor
+
xy_to_cursor = (tree, xy) ->
for n in tree
if n.type is 'tag' or n.type is 'text'
@cursor = null
@cursor_el = null
@cursor_visible = false
+ @cursor_ideal_x = null
@poll_for_blur_timeout = null
opt_fragment = @options.fragment ? true
@parser_opts = {}
return false
when KEY_UP
if @cursor?
- new_cursor = @cursor
- # go prev until we're higher on y axis
- while new_cursor.y >= @cursor.y
- new_cursor = find_prev_cursor_position @tree, new_cursor
- return false unless new_cursor?
- # done early if we're already left of old cursor position
- if new_cursor.x <= @cursor.x
- @move_cursor new_cursor
- return false
- target_y = new_cursor.y
- # search leftward, until we find the closest position
- # new_cursor is the prev-most position we've checked
- # prev_cursor is the older value, so it's not as prev as new_cursor
- while new_cursor.x > @cursor.x and new_cursor.y is target_y
- prev_cursor = new_cursor
- new_cursor = find_prev_cursor_position @tree, new_cursor
- break unless new_cursor?
- # move cursor to prev_cursor or new_cursor
+ new_cursor = find_up_cursor_position @tree, @cursor, @cursor_ideal_x
if new_cursor?
- if new_cursor.y is target_y
- # both valid, and on the same line, use closest
- if (@cursor.x - new_cursor.x) < (prev_cursor.x - @cursor.x)
- @move_cursor new_cursor
- else
- @move_cursor prev_cursor
- else
- # new_cursor on wrong line, use prev_cursor
- @move_cursor prev_cursor
- else
- # can't go any further prev, use prev_cursor
- @move_cursor prev_cursor
+ saved_ideal_x = @cursor_ideal_x
+ @move_cursor new_cursor
+ @cursor_ideal_x = saved_ideal_x
else
# move cursor to first position in document
new_cursor = first_cursor_position @tree
return false
when KEY_DOWN
if @cursor?
- new_cursor = @cursor
- # go next until we move on the y axis
- while new_cursor.y <= @cursor.y
- new_cursor = find_next_cursor_position @tree, new_cursor
- return false unless new_cursor?
- # done early if we're already right of old cursor position
- if new_cursor.x >= @cursor.x
- # this would be strange, but could happen due to runaround
- @move_cursor new_cursor
- return false
- target_y = new_cursor.y
- # search rightward, until we find the closest position
- # new_cursor is the next-most position we've checked
- # prev_cursor is the older value, so it's not as next as new_cursor
- while new_cursor.x < @cursor.x and new_cursor.y is target_y
- prev_cursor = new_cursor
- new_cursor = find_next_cursor_position @tree, new_cursor
- break unless new_cursor?
- # move cursor to prev_cursor or new_cursor
+ new_cursor = find_down_cursor_position @tree, @cursor, @cursor_ideal_x
if new_cursor?
- if new_cursor.y is target_y
- # both valid, and on the same line, use closest
- if (new_cursor.x - @cursor.x) < (@cursor.x - prev_cursor.x)
- @move_cursor new_cursor
- else
- @move_cursor prev_cursor
- else
- # new_cursor on wrong line, use prev_cursor
- @move_cursor prev_cursor
- else
- # can't go any further prev, use prev_cursor
- @move_cursor prev_cursor
+ saved_ideal_x = @cursor_ideal_x
+ @move_cursor new_cursor
+ @cursor_ideal_x = saved_ideal_x
else
# move cursor to first position in document
new_cursor = last_cursor_position @tree
@cursor = null
@annotate null
move_cursor: (cursor) ->
+ @cursor_ideal_x = cursor.x
@cursor = cursor
unless @cursor_visible
@cursor_el = domify @outer_idoc, div: id: 'cursor'