JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
implement page-up key
[peach-html5-editor.git] / editor.coffee
index 636bf19..a02e278 100644 (file)
@@ -16,6 +16,7 @@
 
 # SETTINGS
 overlay_padding = 10
+breathing_room = 30 # minimum pixels above/below cursor
 
 timeout = (ms, cb) -> return setTimeout cb, ms
 next_frame = (cb) ->
@@ -951,6 +952,7 @@ class PeachHTML5Editor
                        when KEY_INSERT
                                return false
                        when KEY_PAGE_UP
+                               @on_page_up_key e
                                return false
                        when KEY_PAGE_DOWN
                                return false
@@ -1050,13 +1052,21 @@ class PeachHTML5Editor
                                        @kill_cursor
                                return
                else if @cursor.i is 0
-                       console.log 'not implemented yet'
+                       console.log 'unimplemented: backspace at start of non-empty tag'
                        # TODO if block, merge parent into prev
                        # TODO if inline, delete char from prev text node
                        return false
                else
                        # TODO handle case of removing last char
-                       @remove_character @cursor.n, @cursor.i - 1
+                       # CONTINUE
+                       if @is_only_char_in_tag @cursor.n
+                               if is_display_block @cursor.n.parent.el
+                                       @cursor.n.el.textContent = @cursor.n.text = ' '
+                               else
+                                       console.log "unimplemented: delete last char in inline" # FIXME
+                                       return
+                       else
+                               @remove_character @cursor.n, @cursor.i - 1
                        @adjust_whitespace_style @cursor.n
                        @changed()
                        new_cursor = new_cursor_position n: @cursor.n, i: @cursor.i - 1
@@ -1064,6 +1074,50 @@ class PeachHTML5Editor
                                @move_cursor new_cursor
                        else
                                @kill_cursor()
+               return
+       on_page_up_key: (e) ->
+               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
+                       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
                        @idoc.body.removeChild @idoc.body.childNodes[0]
@@ -1155,16 +1209,20 @@ class PeachHTML5Editor
                                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
+       # true if n is text node with only one caracter, and the only child of a tag
+       is_only_char_in_tag: (n, i) ->
+               return false unless n.type is 'text'
+               return false unless n.text.length is 1
+               return false if n.parent is @tree_parent
+               return false unless n.parent.children.length is 1
+               return true
        # true if n is text node with just a space in it, and the only child of a tag
        is_lone_space: (n, i) ->
                return false unless n.type is 'text'
                return false unless n.text is ' '
                return false 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
+               return false unless n.parent.children.length is 1
+               return true
        # 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) ->
@@ -1221,21 +1279,20 @@ class PeachHTML5Editor
                @annotate cursor.n
                @scroll_into_view cursor.y, height
        scroll_into_view: (y, h = 0) ->
-               closest = 30 # setting: smallest pixels from top/bottom of screet that's OK
                y += overlay_padding # convert units from @idoc to @wrap2
                # very top of document
-               if y <= closest
+               if y <= breathing_room
                        @wrap2.scrollTop = 0
                        return
                # very bottom of document
-               if y + h >= @wrap2.scrollHeight - closest
+               if y + h >= @wrap2.scrollHeight - breathing_room
                        @wrap2.scrollTop = @wrap2.scrollHeight - @wrap2_height
                        return
                # The most scrolled up (lowest value for scrollTop) that would be OK
-               upmost = y + h + closest - @wrap2_height
+               upmost = y + h + breathing_room - @wrap2_height
                upmost = Math.max(upmost, 0)
                # the most scrolled down (highest value for scrollTop) that would be OK
-               downmost = y - closest
+               downmost = y - breathing_room
                downmost = Math.min(downmost, @wrap2.scrollHeight - @wrap2_height)
                if upmost > downmost # means h is too big to fit
                        # scroll so top is visible