JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
preserve <script> tags and whitespace in plaintext elements
[peach-html5-editor.git] / editor.js
index 104bbae..f3c6204 100644 (file)
--- a/editor.js
+++ b/editor.js
@@ -121,11 +121,10 @@ get_el_bounds = window.bounds = function(el) {
 }
 
 function is_display_block (el) {
-       if (el.currentStyle != null) {
-               return el.currentStyle.display === 'block'
-       } else {
+       if (el.nodeType === 1) {
                return window.getComputedStyle(el, null).getPropertyValue('display') === 'block'
        }
+       return false
 }
 
 // Pass return value from dom event handlers to this.
@@ -428,12 +427,19 @@ function instantiate_tree (tree, parent) {
                        break
                        case 'tag':
                                if (c.name === 'script' || c.name === 'object' || c.name === 'iframe' || c.name === 'link') {
-                                       // TODO put placeholders instead
-                                       remove.unshift(i)
+                                       // TODO make some placeholders visible
+                                       // problematic to have different type than c: c.el = parent.ownerDocument.createComment(c.name + ' tag here')
+                                       c.el = parent.ownerDocument.createElement(c.name)
+                                       // correct type, but empty and no attributes
                                        continue
                                }
-                               // TODO create in correct namespace
-                               c.el = parent.ownerDocument.createElement(c.name)
+                               if (c.namespace === 'svg') {
+                                       c.el = parent.ownerDocument.createElementNS('http://www.w3.org/2000/svg', c.name)
+                               } else if (c.namespace === 'mathml') {
+                                       c.el = parent.ownerDocument.createElementNS('http://www.w3.org/1998/Math/MathML', c.name)
+                               } else {
+                                       c.el = parent.ownerDocument.createElement(c.name)
+                               }
                                ref1 = c.attrs
                                for (k in ref1) {
                                        v = ref1[k]
@@ -450,13 +456,6 @@ function instantiate_tree (tree, parent) {
                                }
                }
        }
-       results = []
-       for (i = 0; i < remove.length; i++) {
-               // FIXME this deletes the wrong node when siblings are removed
-               index = remove[i]
-               results.push(tree.splice(index, 1))
-       }
-       return results
 }
 
 function traverse_tree (tree, cb) {
@@ -805,6 +804,7 @@ function PeachHTML5Editor (in_el, options) {
        this.init_1_called = false // when iframes have loaded
        this.outer_iframe // iframe to hold editor
        this.outer_idoc // "document" object for this.outer_iframe
+       this.input_el = null
        this.wrap2 = null // scrollbar is on this
        this.wrap2_offset = null
        this.wrap2_height = null // including padding
@@ -814,7 +814,6 @@ function PeachHTML5Editor (in_el, options) {
        this.cursor_el = null
        this.cursor_visible = false
        this.cursor_ideal_x = null
-       this.poll_for_blur_timeout = null
        opt_fragment = this.options.fragment != null ? this.options.fragment : true
        this.parser_opts = {}
        if (opt_fragment) {
@@ -832,6 +831,9 @@ function PeachHTML5Editor (in_el, options) {
                        domify(_this.outer_idoc, {text: css})
                ]}})
                _this.outer_idoc.head.appendChild(icss)
+               _this.input_el = domify(_this.outer_idoc, {textarea: {style: "position: relative; left: 100px"}}) // {style: "display: block; position: absolute; top: -1000px; left: 0; height: 500px; width 50em"}})
+               _this.input_el.onblur = _this.onblur.bind(_this)
+               _this.outer_idoc.body.appendChild(_this.input_el)
                _this.iframe = domify(_this.outer_idoc, {iframe: {sandbox: 'allow-same-origin allow-scripts'}})
                _this.iframe.onload = function() {
                        return _this.init_1()
@@ -894,36 +896,18 @@ PeachHTML5Editor.prototype.init_1 = function() { // this.iframe has loaded (but
        }
 }
 PeachHTML5Editor.prototype.init_2 = function() { // this.iframe and it's css file(s) are ready
-       this.overlay.onclick = (function(_this) {
-               return function(e) {
-                       _this.have_focus()
-                       return event_return(e, _this.onclick(e))
-               }
-       })(this)
-       this.overlay.ondoubleclick = (function(_this) {
-               return function(e) {
-                       _this.have_focus()
-                       return event_return(e, _this.ondoubleclick(e))
-               }
-       })(this)
-       this.outer_idoc.body.onkeyup = (function(_this) {
-               return function(e) {
-                       _this.have_focus()
-                       return event_return(e, _this.onkeyup(e))
-               }
-       })(this)
-       this.outer_idoc.body.onkeydown = (function(_this) {
-               return function(e) {
+       var _this = this
+       var this_event_bind = function (cb) {
+               return function (e) {
                        _this.have_focus()
-                       return event_return(e, _this.onkeydown(e))
+                       event_return(e, _this[cb](e))
                }
-       })(this)
-       this.outer_idoc.body.onkeypress = (function(_this) {
-               return function(e) {
-                       _this.have_focus()
-                       return event_return(e, _this.onkeypress(e))
-               }
-       })(this)
+       }
+       this.overlay.onmousedown = this_event_bind('onclick')
+       this.overlay.ondoubleclick = this_event_bind('ondoubleclick')
+       this.outer_idoc.body.onkeyup = this_event_bind('onkeyup')
+       this.outer_idoc.body.onkeydown = this_event_bind('onkeydown')
+       this.outer_idoc.body.onkeypress = this_event_bind('onkeypress')
        this.load_html(this.in_el.value)
        if (this.options.on_init != null) {
                return this.options.on_init()
@@ -1689,9 +1673,9 @@ PeachHTML5Editor.prototype.clear_dom = function() {
        this.kill_cursor()
 }
 PeachHTML5Editor.prototype.load_html = function(html) {
-       this.tree = peach_parser(html, this.parser_opts)
+       this.tree = peach_parser.parse(html, this.parser_opts)
        if (this.tree[0] == null ? true : this.tree[0].parent == null) {
-               this.tree = peach_parser('<p style="white-space: pre-wrap"> </p>', this.parser_opts)
+               this.tree = peach_parser.parse('<p style="white-space: pre-wrap"> </p>', this.parser_opts)
        }
        this.tree_parent = this.tree[0].parent
        this.tree_parent.el = this.idoc.body
@@ -1878,7 +1862,7 @@ PeachHTML5Editor.prototype.collapse_whitespace = function(tree) {
                                if (block) {
                                        cb(null)
                                }
-                               if (n.children.length > 0) {
+                               if (n.children.length > 0 && plaintext_elements[n.name] == null) {
                                        iterate(n.children, cb)
                                }
                                if (block) {
@@ -2383,21 +2367,12 @@ PeachHTML5Editor.prototype.pretty_html = function(tree, indent, parent_flags) {
                                        is_br = true
                                }
                                is_text = false
-                               if (n.el.currentStyle != null) {
-                                       cs = n.el.currentStyle
-                                       whitespace = cs['white-space']
-                                       display = cs['display']
-                                       position = cs['position']
-                                       float = cs['float']
-                                       visibility = cs['visibility']
-                               } else {
-                                       cs = this.iframe.contentWindow.getComputedStyle(n.el, null)
-                                       whitespace = cs.getPropertyValue('white-space')
-                                       display = cs.getPropertyValue('display')
-                                       position = cs.getPropertyValue('position')
-                                       float = cs.getPropertyValue('float')
-                                       visibility = cs.getPropertyValue('visibility')
-                               }
+                               cs = this.iframe.contentWindow.getComputedStyle(n.el, null)
+                               whitespace = cs.getPropertyValue('white-space')
+                               display = cs.getPropertyValue('display')
+                               position = cs.getPropertyValue('position')
+                               float = cs.getPropertyValue('float')
+                               visibility = cs.getPropertyValue('visibility')
                                if (n.name === 'textarea') {
                                        inner_flags.pre_ish = true
                                } else {
@@ -2535,27 +2510,14 @@ PeachHTML5Editor.prototype.pretty_html = function(tree, indent, parent_flags) {
        return ret
 }
 PeachHTML5Editor.prototype.onblur = function() {
+       this.editor_is_focused = false
        this.kill_cursor()
 }
 PeachHTML5Editor.prototype.have_focus = function() {
-       this.editor_is_focused = true
-       this.poll_for_blur()
-}
-PeachHTML5Editor.prototype.poll_for_blur = function() {
-       if (this.poll_for_blur_timeout != null) {
-               return
+       if (!this.editor_is_focused) {
+               this.input_el.focus()
+               this.editor_is_focused = true
        }
-       this.poll_for_blur_timeout = timeout(150, (function(_this) { return function() {
-               next_frame(function() { // pause polling when browser knows we're not active/visible/etc.
-                       _this.poll_for_blur_timeout = null
-                       if (document.activeElement === _this.outer_iframe) {
-                               _this.poll_for_blur()
-                       } else {
-                               _this.editor_is_focused = false
-                               _this.onblur()
-                       }
-               })
-       }})(this))
 }
 
 window.peach_html5_editor = function() {