From 6eab44262a16e431ec8dbcb42820babc5d28fc10 Mon Sep 17 00:00:00 2001 From: Jason Woofenden Date: Mon, 1 Feb 2016 22:46:41 -0500 Subject: [PATCH] cursor left/right and alnum typing work --- editor.coffee | 150 ++++++++++++++++++++++++++------------------------------- 1 file changed, 69 insertions(+), 81 deletions(-) diff --git a/editor.coffee b/editor.coffee index e0cae20..5ec9434 100644 --- a/editor.coffee +++ b/editor.coffee @@ -34,7 +34,7 @@ get_el_offset = (el) -> # implementation: insert a span tag where we want the cursor, and ask the # browser where it put that span cursor_to_loc = (n, i) -> - span = domify span: style: "height: 1em" + span = domify span: style: "height: 1em; width: 0", children: [domify text: "|"] parent = n.el.parentNode if i is 0 # cursor at start of text @@ -189,19 +189,46 @@ instantiate_tree = (tree, parent) -> if c.children.length instantiate_tree c.children, c.el -find_next_cursor_position = (n, i) -> - if n.type is TYPE_TEXT - if n.text.length > i - return [n, i + 1] - return null - if n.type is TYPE_TAG - if n.children.length - for c in n.children - ret = find_next_cursor_position c, -1 - return ret if ret? - return null - else - # FIXME create an empty text node if needed depending on tag name +traverse_tree = (tree, state, cb) -> + for c in tree + cb c, state + break if state.done? + if c.children.length + traverse_tree c.children, state, cb + break if state.done? + return state +# find the next element in top (and decendants) that is after n and can contain text +# TODO make it so cursor can go places that don't have text but could +find_next_cursor_position = (top, n, i) -> + if n? and n.type is TYPE_TEXT and n.text.length > i + return [n, i + 1] + found = traverse_tree top, before: n?, (node, state) -> + if node.type is TYPE_TEXT and state.before is false + state.node = node + state.done = true + if node is n + state.before = false + if found.node? + return [found.node, 0] + return null + +# TODO make it so cursor can go places that don't have text but could +find_prev_cursor_position = (top, n, i) -> + if n? and n.type is TYPE_TEXT and i > 0 + return [n, i - 1] + found = traverse_tree top, before: n?, (node, state) -> + if node.type is TYPE_TEXT + unless n? + state.node = node + state.done = true + if node is n + if state.prev? + state.node = state.prev + state.done = true + if node + state.prev = node + if found.node? + return [found.node, found.node.text.length] return null class PeachHTML5Editor @@ -252,83 +279,27 @@ class PeachHTML5Editor #return false if control_key_codes[e.keyCode]? switch e.keyCode when KEY_LEFT - return false - when KEY_UP - return false - when KEY_RIGHT - window.ce = @cursor_el if @cursor? - new_cursor = find_next_cursor_position @cursor... + new_cursor = find_prev_cursor_position @tree, @cursor... if new_cursor? @move_cursor new_cursor - else - after = false - for c in @cursor[0].parent.children - if after - new_cursor = find_next_cursor_position c, -1 - if new_cursor? - @move_cursor new_cursor - break - if c is @cursor[0] - after = true else for c in @tree - new_cursor = find_next_cursor_position c, -1 + new_cursor = find_next_cursor_position @tree, c, -1 if new_cursor? @move_cursor new_cursor break return false - when KEY_DOWN - return false - when KEY_END - return false - when KEY_BACKSPACE - return false - when KEY_DELETE - return false - when KEY_ENTER - return false - when KEY_ESCAPE - return false - when KEY_HOME - return false - when KEY_INSERT - return false - when KEY_PAGE_UP - return false - when KEY_PAGE_DOWN - return false - when KEY_TAB - return false - @idoc.body.onkeypress = (e) => - return if e.ctrlKey - return false if ignore_key_codes[e.keyCode]? - # in firefox, keyCode is only set for non-typing keys - switch e.keyCode - when KEY_LEFT - return false when KEY_UP return false when KEY_RIGHT - console.log "hi" - console.log @cursor if @cursor? - new_cursor = find_next_cursor_position @cursor... + new_cursor = find_next_cursor_position @tree, @cursor... if new_cursor? @move_cursor new_cursor - else - after = false - for c in @cursor[0].parent.children - if after - new_cursor = find_next_cursor_position c, -1 - if new_cursor? - @move_cursor new_cursor - break - if c is @cursor[0] - after = true else for c in @tree - new_cursor = find_next_cursor_position c, -1 + new_cursor = find_prev_cursor_position @tree, c, -1 if new_cursor? @move_cursor new_cursor break @@ -355,9 +326,24 @@ class PeachHTML5Editor return false when KEY_TAB return false + @idoc.body.onkeypress = (e) => + return if e.ctrlKey + return false if ignore_key_codes[e.keyCode]? + return false if control_key_codes[e.keyCode]? # handled in keydown char = e.charCode ? e.keyCode - @in_el.value += String.fromCharCode char - @load_html @in_el.value + if char and @cursor? + char = String.fromCharCode char + if @cursor[1] is 0 + @cursor[0].text = char + @cursor[0].text + else if @cursor[1] is @cursor[0].text.length - 1 + @cursor[0].text += char + else + @cursor[0].text = + @cursor[0].text.substr(0, @cursor[1]) + + char + + @cursor[0].text.substr(@cursor[1]) + @cursor[0].el.nodeValue = @cursor[0].text + @move_cursor [@cursor[0], @cursor[1] + 1] return false if options.stylesheet # TODO test this istyle = @idoc.createElement 'style' @@ -380,12 +366,14 @@ class PeachHTML5Editor @clear_dom() instantiate_tree @tree, @idoc.body move_cursor: (cursor) -> + return if @cursor? and cursor? and @cursor[0] is cursor[0] and @cursor[1] is cursor[1] @cursor = cursor - unless @cursor_el? - @cursor_el = domify div: id: 'peach_html5_editor_cursor' - unless @cursor_visible - @idoc.body.appendChild @cursor_el - @cursor_visible = true + # replace cursor, to reset blink animation + if @cursor_visible + @cursor_el.parentNode.removeChild @cursor_el + @cursor_el = domify div: id: 'peach_html5_editor_cursor' + @idoc.body.appendChild @cursor_el + @cursor_visible = true # TODO figure out top/left coords for cursor loc = cursor_to_loc cursor[0], cursor[1] @cursor_el.style.top = "#{loc.top}px" -- 1.7.10.4