# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# SETTINGS
+overlay_padding = 6 # TODO generate css from this
+
TYPE_TAG = peach_parser.TYPE_TAG
TYPE_TEXT = peach_parser.TYPE_TEXT
TYPE_COMMENT = peach_parser.TYPE_COMMENT
return '&' if (amp)
return '"' if (quote)
return ' '
+enc_text_regex = new RegExp '(&)|(<)|(\u00A0)', 'g'
+enc_text = (txt) ->
+ return txt.replace enc_text_regex, (match, amp, lt) ->
+ return '&' if (amp)
+ return '<' if (lt)
+ return ' '
void_elements = {
area: true
ret += dom_to_html el.children
ret += "</#{el.name}>"
when TYPE_TEXT
- ret += el.text
+ ret += enc_text el.text
when TYPE_COMMENT
ret += "<!--#{el.text}-->"
when TYPE_DOCTYPE
if n.type is TYPE_TEXT
i = 0
while i < n.text.length # don't foreach, cb might remove chars
- removed = cb n, i
- unless removed
+ advance = cb n, i
+ if advance
i += 1
if n.type is TYPE_TAG
block = is_display_block n.el
next = n
next_i = i
next_px = null
+ advance = true
if cur?
removed = operate()
+ # don't advance (to the next character next time) if we removed a
+ # character from the same text node as ``next``, because doing so
+ # renumbers the indexes in that string
+ if removed and cur is next
+ advance = false
else
removed = false
unless removed
cur = next
cur_i = next_i
cur_px = next_px
- return removed
+ return advance
queue null
iterate tree, queue
queue null
constructor: (in_el, options = {}) ->
@in_el = in_el
@tree = []
- @iframe = domify iframe: class: 'peach_html5_editor'
+ @outer_el = domify div: class: 'peach_html5_editor', children: [
+ @iframe = domify iframe: class: 'peach_html5_editor_iframe'
+ @overlay = domify div: class: 'peach_html5_editor_overlay'
+ ]
@cursor = null
@cursor_el = null
@cursor_visible = false
'34': KEY_PAGE_DOWN
'9': KEY_TAB
- @idoc.body.onclick = (e) =>
- # idoc.body.offset().left/top
- new_cursor = find_loc_cursor_position @tree, x: e.pageX, y: e.pageY
+ @overlay.onclick = (e) =>
+ x = (e.offsetX ? e.layerX) - overlay_padding
+ y = (e.offsetY ? e.layerY) - overlay_padding
+ new_cursor = find_loc_cursor_position @tree, x: x, y: y
if new_cursor?
@move_cursor new_cursor
@idoc.body.onkeyup = (e) =>
@idoc.head.appendChild istyle
icss = @idoc.createElement 'style'
icss.appendChild @idoc.createTextNode css
- @idoc.head.appendChild icss
+ document.head.appendChild icss
@load_html @in_el.value
- @in_el.parentNode.appendChild @iframe
+ @in_el.parentNode.appendChild @outer_el
clear_dom: ->
# FIXME add parent node, so we don't empty body and delete cursor_el
while @idoc.body.childNodes.length
@idoc.body.removeChild @idoc.body.childNodes[0]
+ @kill_cursor()
@cursor_visible = false
return
load_html: (html) ->
@in_el.value = dom_to_html @tree
@in_el.onchange = =>
@load_html @in_el.value
+ kill_cursor: -> # remove it, forget where it was
+ if @cursor_visible
+ @cursor_el.parentNode.removeChild @cursor_el
+ @cursor_visible = false
+ @cursor = null
move_cursor: (cursor) ->
loc = cursor_to_xyh cursor[0], cursor[1]
unless loc?
if @cursor_visible
@cursor_el.parentNode.removeChild @cursor_el
@cursor_el = domify div: id: 'peach_html5_editor_cursor'
- @idoc.body.appendChild @cursor_el
+ @overlay.appendChild @cursor_el
@cursor_visible = true
# TODO figure out x,y coords for cursor
- @cursor_el.style.left = "#{loc.x}px"
- @cursor_el.style.top = "#{loc.y}px"
+ @cursor_el.style.left = "#{loc.x + overlay_padding}px"
+ @cursor_el.style.top = "#{loc.y + overlay_padding}px"
window.peach_html5_editor = (args...) ->
return new PeachHTML5Editor args...