+# browsers collapse these (html5 spec calls these "space characters")
+is_space_code = (char_code) ->
+ switch char_code
+ when 9, 10, 12, 13, 32
+ return true
+ return false
+is_space = (chr) ->
+ return is_space_code chr.charCodeAt 0
+
+# warning: contains browser-specific hackery
+is_space_significant = (n, i) ->
+ range = document.createRange()
+ range.setStart n.el, i
+ range.setEnd n.el, i + 1
+ rects = range.getClientRects()
+ bounding_rect = range.getBoundingClientRect()
+ if rects.length is 0
+ return false
+ if rects.length > 1
+ # chromium returns two rects in both these cases:
+ # 1. a space that is word-wrapped. one rect on each line. Note that
+ # chromium does _not_ do this for _all_ spaces that are word wrapped.
+ # 2. the last (insignificant) space in a sequence of collapsing spaces
+ # in this case the rects are identical.
+ if rects[1].top > rects[0].top
+ return true
+ width = rects[0].width ? (rects[0].right - rects[0].left)
+ if width > 0
+ return true
+ # firefox reports the space that's word-wrapped as zero width
+ if n.text.length > i + 1
+ range.setStart n.el, i + 1
+ range.setEnd n.el, i + 2
+ next_rects = range.getClientRects()
+ if next_rects.length > 0
+ if next_rects[0].top > rects[0].top
+ # next character is lower on the screen, so this must be a word-wrap space
+ return true
+ else
+ # FIXME detect word-wrap in last character
+ # could be followed by an inline block with no starting space
+ # FIXME chromium gets here for a significant space at the begining of a
+ # text node that word-wraps
+ return false
+
+# pass a node (from parser library, ie it should have .el and .text)
+remove_insignificant_whitespace = (n) ->
+ changed = false
+ if n.type is TYPE_TEXT
+ i = 0
+ while i < n.text.length
+ if is_space_code n.text.charCodeAt i
+ if is_space_significant n, i
+ i += 1
+ else
+ n.el.textContent = n.text = (n.text.substr 0, i) + (n.text.substr i + 1)
+ changed = true
+ else
+ i += 1
+ if n.children.length > 0
+ for c in n.children
+ if remove_insignificant_whitespace c
+ changed = true
+ return changed
+