From dde84cf239d827cb3a3b412d970e95bd5851216d Mon Sep 17 00:00:00 2001 From: Jason Woofenden Date: Sat, 12 Mar 2016 21:11:51 -0500 Subject: [PATCH] rewrite html pretty-printing --- editor.coffee | 186 +++++++++++++++++++++++++++----------------- editor_tests_compiled.html | 5 +- 2 files changed, 118 insertions(+), 73 deletions(-) diff --git a/editor.coffee b/editor.coffee index 6fa48cb..41d81c3 100644 --- a/editor.coffee +++ b/editor.coffee @@ -58,19 +58,6 @@ is_display_block = (el) -> else return window.getComputedStyle(el, null).getPropertyValue('display') is 'block' -# pass a node (not an element) for a tag -# returns if this is the sort of tag that cares about leading/trailing whitespace -# FIXME this probably doesn't work all the time -is_whitespace_significant = (n) -> - if n.name is 'textarea' - return true - if n.name is 'pre' - return true - if n.el.currentStyle? - return n.el.currentStyle['white-space'].substr(0, 3) is 'pre' - else - return window.getComputedStyle(n.el, null).getPropertyValue('white-space').substr(0, 3) is 'pre' - # Pass return value from dom event handlers to this. # If they return false, this will addinionally stop propagation and default. event_return = (e, bool) -> @@ -161,65 +148,9 @@ no_text_elements = { # these elements never contain text tr: true thead: true tbody: true + ul: true + ol: true } -# FIXME terminology: s/dom/tree/; s/el/n/ -tree_to_html = (tree, indent = '', parent_is_block = false) -> - ret = '' - for n, i in tree - switch n.type - when TYPE_TAG - is_block = is_display_block n.el - if is_block - is_tiny_block = false - if is_whitespace_significant n - is_tiny_block = true - else - if n.children.length is 1 - if n.children[0].type is TYPE_TEXT - if n.children[0].text.length < 35 - is_tiny_block = true - if is_block or (parent_is_block and i is 0) - ret += indent - ret += '<' + n.name - attr_keys = [] - for k of n.attrs - attr_keys.unshift k - #attr_keys.sort() - for k in attr_keys - ret += " #{k}" - if n.attrs[k].length > 0 - ret += "=\"#{enc_attr n.attrs[k]}\"" - ret += '>' - unless void_elements[n.name]? - if is_block - next_indent = indent + ' ' - else - next_indent = indent - if n.children.length - if is_block and not is_tiny_block - ret += "\n" - ret += tree_to_html n.children, next_indent, is_block and not is_tiny_block - if is_block and not is_tiny_block - ret += indent - ret += "" - if is_block or (parent_is_block and i is tree.length - 1) - ret += "\n" - when TYPE_TEXT - if parent_is_block and i is 0 - ret += indent - ret += enc_text n.text - if parent_is_block and i is tree.length - 1 - ret += "\n" - when TYPE_COMMENT - ret += "" - when TYPE_DOCTYPE - ret += " 0 - ret += " \"#{n.public_identifier}\"" - if n.system_identifier? and n.system_identifier.length > 0 - ret += " \"#{n.system_identifier}\"" - ret += ">\n" - return ret domify = (doc, hash) -> for tag, attrs of hash @@ -823,7 +754,7 @@ class PeachHTML5Editor @changed() changed: -> @in_el.onchange = null - @in_el.value = tree_to_html @tree + @in_el.value = @pretty_html @tree @in_el.onchange = => @load_html @in_el.value @iframe.style.height = "0" @@ -873,6 +804,117 @@ class PeachHTML5Editor @matting.push ann n = n.parent alpha *= 1.5 + pretty_html: (tree, indent = '', parent_flags = pre_ish: false, block: true, want_nl: false) -> + ret = '' + want_nl = parent_flags.want_nl + prev_in_flow_is_text = false + prev_in_flow_is_block = false + for n, i in tree + # figure out flags + inner_flags = want_nl: true + is_br = false + switch n.type + when TYPE_TAG + if n.name is 'br' + is_br = true + is_text = false + if n.el.currentStyle? + cs = n.el.currentStyle + whitespace = cs['white-space'] + display = cs['display'] + position = cs['position'] + float = cs['float'] + else + cs = @iframe.contentWindow.getComputedStyle(n.el, null) + whitespace = cs.getPropertyValue 'white-space' + display = cs.getPropertyValue 'display' + position = cs.getPropertyValue 'position' + float = cs.getPropertyValue 'float' + if n.name is 'textarea' + inner_flags.pre_ish = true + else + inner_flags.pre_ish = whitespace.substr(0, 3) is 'pre' + switch float + when 'left', 'right' + in_flow = false + else + switch position + when 'absolute', 'fixed' + in_flow = false + else + if 'display' is 'none' + in_flow = false + else + in_flow = true + switch display + when 'inline', 'none' + inner_flags.block = false + is_block = in_flow_block = false + when 'inline-black' + inner_flags.block = true + is_block = in_flow_block = false + else # block, table, etc + inner_flags.block = true + is_block = true + in_flow_block = in_flow + when TYPE_TEXT + is_text = true + is_block = false + in_flow = true + in_flow_block = false + else # TYPE_COMMENT, TYPE_DOCTYPE + is_text = false + is_block = false + in_flow = false + in_flow_block = false + # print whitespace if we can + unless parent_flags.pre_ish + unless prev_in_flow_is_text and is_br + if (i is 0 and parent_flags.block) or in_flow_block or prev_in_flow_is_block + if want_nl + ret += "\n" + ret += indent + switch n.type + when TYPE_TAG + ret += '<' + n.name + attr_keys = [] + for k of n.attrs + attr_keys.unshift k + #attr_keys.sort() + for k in attr_keys + ret += " #{k}" + if n.attrs[k].length > 0 + ret += "=\"#{enc_attr n.attrs[k]}\"" + ret += '>' + unless void_elements[n.name]? + if inner_flags.block + next_indent = indent + ' ' + else + next_indent = indent + if n.children.length + ret += @pretty_html n.children, next_indent, inner_flags + ret += "" + when TYPE_TEXT + ret += enc_text n.text + when TYPE_COMMENT + ret += "" # TODO encode? + when TYPE_DOCTYPE + ret += " 0 + ret += " \"#{n.public_identifier}\"" + if n.system_identifier? and n.system_identifier.length > 0 + ret += " \"#{n.system_identifier}\"" + ret += ">" + want_nl = true + if in_flow + prev_in_flow_is_text = is_text + prev_in_flow_is_block = is_block or (in_flow and is_br) + if tree.length + # output final newline if allowed + unless parent_flags.pre_ish + if prev_in_flow_is_block or parent_flags.block + ret += "\n#{indent.substr 4}" + return ret window.peach_html5_editor = (args...) -> return new PeachHTML5Editor args... diff --git a/editor_tests_compiled.html b/editor_tests_compiled.html index f91086a..276faa7 100644 --- a/editor_tests_compiled.html +++ b/editor_tests_compiled.html @@ -23,7 +23,7 @@

This version of the editor test page requires that you've compiled all the source files. (Just run make).

HTML view. Changes here propagate when you remove your cursor (press tab or click outside)

-- 1.7.10.4