@options = options ? {}
@in_el = in_el
@tree = null
+ @tree_parent = null # top-level nodes in @tree should have this .parent
@matting = []
@init_1_called = false # when iframes have loaded
@outer_iframe # iframe to hold editor
@move_cursor new_cursor
return false
when KEY_END
+ new_cursor = last_cursor_position @tree
+ if new_cursor?
+ @move_cursor new_cursor
return false
when KEY_BACKSPACE
return false unless @cursor?
@kill_cursor()
return false
when KEY_ENTER
+ @on_key_enter e
return false
when KEY_ESCAPE
+ @kill_cursor()
return false
when KEY_HOME
+ new_cursor = first_cursor_position @tree
+ if new_cursor?
+ @move_cursor new_cursor
return false
when KEY_INSERT
return false
console.log "ERROR: couldn't find cursor position after insert"
@kill_cursor()
return false
+ on_key_enter: (e) -> # enter key pressed
+ return unless @cursor_visible
+ cur_block = @cursor.n
+ loop
+ if cur_block.type is 'tag'
+ if is_display_block cur_block.el
+ break
+ return unless cur_block.parent?
+ cur_block = cur_block.parent
+ # find array to insert new element into
+ if cur_block.parent is @tree_parent # top-level
+ parent_el = @idoc.body
+ pc = @tree
+ else
+ parent_el = cur_block.parent.el
+ pc = cur_block.parent.children
+ # find index of current block in its parent
+ for n, i in pc
+ break if n is cur_block
+ i += 1 # we want to be after it
+ if i < pc.length
+ before = pc[i].el
+ else
+ before = null
+ # TODO if content after cursor
+ # TODO new block is empty
+ new_text = new peach_parser.Node 'text', text: ' '
+ new_node = new peach_parser.Node 'tag', name: 'p', parent: cur_block.parent, attrs: {style: 'white-space: pre-wrap'}, children: [new_text]
+ new_text.parent = new_node
+ new_text.el = domify @idoc, text: ' '
+ new_node.el = domify @idoc, p: style: 'white-space: pre-wrap', children: [new_text.el]
+ pc.splice i, 0, new_node
+ parent_el.insertBefore new_node.el, before
+ @changed()
+ new_cursor = new_cursor_position n: new_text, i: 0
+ throw 'bork bork' unless new_cursor?
+ @move_cursor new_cursor
+ # TODO move content past cursor into this new block
clear_dom: -> # remove all the editable content (and cursor, overlays, etc)
while @idoc.body.childNodes.length
@idoc.body.removeChild @idoc.body.childNodes[0]
return
load_html: (html) ->
@tree = peach_parser.parse html, @parser_opts
+ @tree_parent = @tree[0]?.parent
@clear_dom()
instantiate_tree @tree, @idoc.body
tree_dedup_space @tree
if needle is n.attrs.style.substr n.attrs.style.length - needle
n.attrs.style = n.attrs.style.substr 0, n.attrs.style.length - needle
n.el.setAttribute n.attrs.style
+ # detect special case: typing before a space that's the only thing in a block/doc
+ # reason: enter key creates blocks with just a space in them
+ insert_should_replace: (n, i) ->
+ return false unless i is 0
+ return false unless n.text is ' '
+ return true if n.parent is @tree_parent
+ if n.parent.children.length is 1
+ if n.parent.children[0] is n
+ # n is only child
+ return true
+ return false
# after calling this, you MUST call changed() and adjust_whitespace_style()
insert_character: (n, i, char) ->
+ return if @cursor.n.parent is @tree_parent # top-level text not supported atm
parent = @cursor.n.parent
- return unless parent
- return unless parent.el?
# insert the character
- if i is 0
+ if @insert_should_replace n, i
+ n.text = char
+ else if i is 0
n.text = char + n.text
else if i is n.text.length
+ # replace the space
n.text += char
else
n.text =