JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
rename to Peach HTML5 Editor
authorJason Woofenden <jason@jasonwoof.com>
Mon, 1 Feb 2016 19:36:01 +0000 (14:36 -0500)
committerJason Woofenden <jason@jasonwoof.com>
Mon, 1 Feb 2016 19:36:01 +0000 (14:36 -0500)
README.md
editor.coffee
editor_tests.coffee
editor_tests.html [new file with mode: 0644]
editor_tests_coffee.html
parser.coffee
parser_tests.coffee
parser_tests.html
parser_tests_coffee.html

index af50f19..272da2e 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,19 +1,26 @@
-wheic
-=====
+Peach HTML5 Editor
+==================
 
-This project is to build a HTML5 parser, then use that to build a WYSIWYG html
-editor for the browser.
-
-The code is written in CoffeeScript for modern browsers. The HTML5 parser can
-also run under node.js.
+This is a WYSIWYG HTML5 editor for the browser.
 
 
 Status
 ------
 
-HTML5 parser: all (1581) tests pass. Works in the browser and node.js
+Early development stages.
+
+The HTML5 parser component passes the full test suite (1581 tests).
+
+The interface is starting to exist.
+
+
+Technologies
+------------
+
+Programming language: CoffeeScript (compiles to javascript)
+
+Interface: Implemented using the DOM api. No ``contenteditable`` or jquery.
 
-WYSIWYG editor: planning stages
 
 
 Quick Start Guide
@@ -28,7 +35,7 @@ Quick Start Guide
 
 4.     Try running the parser in the console, example:
 
-               window.wheic_parser.parse("<p>foo</p>", {fragment: "body"})
+               window.peach_parser.parse("<p>foo</p>", {fragment: "body"})
 
 For further reading, see "Running Under node.js" below.
 
index 0f68f40..faa2e3f 100644 (file)
@@ -43,7 +43,7 @@ dom_to_html = (dom) ->
        ret = ''
        for el in dom
                switch el.type
-                       when wheic_parser.TYPE_TAG
+                       when peach_parser.TYPE_TAG
                                ret += '<' + el.name
                                attr_keys = []
                                for k of el.attrs
@@ -58,11 +58,11 @@ dom_to_html = (dom) ->
                                        if el.children.length
                                                ret += dom_to_html el.children
                                        ret += "</#{el.name}>"
-                       when wheic_parser.TYPE_TEXT
+                       when peach_parser.TYPE_TEXT
                                ret += el.text
-                       when wheic_parser.TYPE_COMMENT
+                       when peach_parser.TYPE_COMMENT
                                ret += "<!--#{el.text}-->"
-                       when wheic_parser.TYPE_DOCTYPE
+                       when peach_parser.TYPE_DOCTYPE
                                ret += "<!DOCTYPE #{el.name}"
                                if el.public_identifier? and el.public_identifier.length > 0
                                        ret += " \"#{el.public_identifier}\""
@@ -85,7 +85,7 @@ domify = (h) ->
        return el
 
 css = ''
-css += 'span.peach_editor_cursor {'
+css += 'div#peach_editor_cursor {'
 css +=     'display: inline-block;'
 css +=     'height: 1em;'
 css +=     'width: 2px;'
@@ -96,14 +96,30 @@ css +=     '-webkit-animation: 1s blink step-end infinite;'
 css +=     'animation: 1s blink step-end infinite;'
 css += '}'
 css += '@-webkit-keyframes "blink" {'
-css +=     'from, to { background: transparent; }'
-css +=     '50% { background: #000; }'
+css +=     'from, to { background: #000; }'
+css +=     '50% { background: transparent; }'
 css += '}'
 css += '@keyframes "blink" {'
-css +=     'from, to { background: transparent; }'
-css +=     '50% { background: #000; }'
+css +=     'from, to { background: #000; }'
+css +=     '50% { background: transparent; }'
 css += '}'
 
+# key codes:
+KEY_LEFT = 37
+KEY_UP = 38
+KEY_RIGHT = 39
+KEY_DOWN = 40
+KEY_BACKSPACE = 8 # <--
+KEY_DELETE = 46 # -->
+KEY_END = 35
+KEY_ENTER = 13
+KEY_ESCAPE = 27
+KEY_HOME = 36
+KEY_INSERT = 45
+KEY_PAGE_UP = 33
+KEY_PAGE_DOWN = 34
+KEY_TAB = 9
+
 wysiwyg = (el, options = {}) ->
        opt_fragment = options.fragment ? true
        parser_opts = {}
@@ -113,15 +129,49 @@ wysiwyg = (el, options = {}) ->
                dom: []
                iframe: document.createElement('iframe')
                load_html: (html) ->
-                       @dom = wheic_parser.parse html, parser_opts
-                       as_html = wheic.dom_to_html @dom
+                       @dom = peach_parser.parse html, parser_opts
+                       as_html = peach.dom_to_html @dom
                        as_html = as_html.substr(0, 5) + '<span class="peach_editor_cursor"></span>' + as_html.substr(5)
                        @iframe.contentDocument.body.innerHTML = as_html
        }
        el.parentNode.appendChild editor_instance.iframe
        idoc = editor_instance.iframe.contentDocument
+       ignore_key_codes =
+               '18': true # alt
+               '20': true # capslock
+               '17': true # ctrl
+               '144': true # numlock
+               '16': true # shift
+               '91': true # windows "start" key
+       control_key_codes = # we react to these, but they aren't typing
+               '37': KEY_LEFT
+               '38': KEY_UP
+               '39': KEY_RIGHT
+               '40': KEY_DOWN
+               '35': KEY_END
+               '8':  KEY_BACKSPACE
+               '46': KEY_DELETE
+               '13': KEY_ENTER
+               '27': KEY_ESCAPE
+               '36': KEY_HOME
+               '45': KEY_INSERT
+               '33': KEY_PAGE_UP
+               '34': KEY_PAGE_DOWN
+               '9':  KEY_TAB
+
+       idoc.body.onkeyup = (e) ->
+               return false if ignore_key_codes[e.keyCode]?
+               return false if control_key_codes[e.keyCode]?
+       idoc.body.onkeydown = (e) ->
+               return false if ignore_key_codes[e.keyCode]?
+               return false if control_key_codes[e.keyCode]?
        idoc.body.onkeypress = (e) ->
-               char = e.charCode ? e.keyCode ? e.which
+               return if e.ctrlKey
+               return false if ignore_key_codes[e.keyCode]?
+               # in firefox, keyCode is only set for non-typing keys
+               if e.keyCode isnt KEY_BACKSPACE # so this is fine
+                       return false if control_key_codes[e.keyCode]?
+               char = e.charCode ? e.keyCode
                el.value += String.fromCharCode char
                editor_instance.load_html el.value
                return false
@@ -135,9 +185,9 @@ wysiwyg = (el, options = {}) ->
        editor_instance.load_html el.value
        return editor_instance
 
-window.wheic = {
+window.peach = {
        wysiwyg: wysiwyg
        dom_to_html: dom_to_html
 }
 
-# test in browser: wheic(document.getElementsByTagName('textarea')[0])
+# test in browser: peach.wysiwyg(document.getElementsByTagName('textarea')[0])
index 06dfd40..27a891d 100644 (file)
@@ -8,7 +8,7 @@ button.onclick = in_el.onchange = in_el.onkeyup = ->
        else
                # first run
                button.parentNode.removeChild button
-               editor = wheic.wysiwyg in_el
+               editor = peach.wysiwyg in_el
        return false
 button.value="Load"
 button.removeAttribute 'disabled'
diff --git a/editor_tests.html b/editor_tests.html
new file mode 100644 (file)
index 0000000..1a04544
--- /dev/null
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+       <meta charset="UTF-8">
+       <link rel="icon" href="data:;base64,iVBORw0KGgo=">
+       <title>html editor tester</title>
+       <style>
+               textarea {
+                       box-sizing: border-box;
+                       width: 100%;
+               }
+       </style>
+</head>
+<body>
+       <h1>Peach HTML5 Editor test page (partially compiled version)</h1>
+       <p>This version of the editor test page requires that you've compiled parser.js (to speed up page load) but it does compile editor.coffee and editor_tests.coffee in the browser so you don't have to rebuild them every time you make a change.</p>
+       <form action="#" method="get">
+       <p>In:<br><textarea rows="9" cols="22" name="in" id="in">&lt;p&gt;Normal &lt;strong&gt;Bold &lt;em&gt; Italic+Bold&lt;/strong&gt; Italic&lt;/em&gt; Normal&lt;/p&gt;</textarea></p>
+       <p><input id="button" type="submit" value="loading..." disabled></p>
+       </form>
+       <script src="parser.js"></script>
+       <script src="editor.coffee" type="text/coffeescript"></script>
+       <script src="editor_tests.coffee" type="text/coffeescript"></script>
+       <script src="coffee-script.js"></script>
+</body>
+</html>
index a16c0c4..8eb3932 100644 (file)
@@ -12,7 +12,7 @@
        </style>
 </head>
 <body>
-       <h1>WHEIC editor test page (CoffeeScript version)</h1>
+       <h1>Peach HTML5 Editor test page (CoffeeScript version)</h1>
        <p>This version of the test page compiles the CoffeeScript files in the browser. This is slower to load, but saves you having to rebuild as you work (or even install CoffeeScript).</p>
        <form action="#" method="get">
        <p>In:<br><textarea rows="9" cols="22" name="in" id="in">&lt;p&gt;Normal &lt;strong&gt;Bold &lt;em&gt; Italic+Bold&lt;/strong&gt; Italic&lt;/em&gt; Normal&lt;/p&gt;</textarea></p>
index 509e492..aa7233e 100644 (file)
 #
 # Call it like this:
 #
-#     wheic_parser.parse("<p><b>hi</p>")
+#     peach_parser.parse("<p><b>hi</p>")
 #
 # Or, if you don't want <html><head><body>/etc, do this:
 #
-#     wheic_parser.parse("<p><b>hi</p>", {fragment: "body"})
+#     peach_parser.parse("<p><b>hi</p>", {fragment: "body"})
 #
 # return value is an array of Nodes, see "class Node" below.
 
@@ -80,8 +80,8 @@ if (typeof module) isnt 'undefined' and module.exports?
        exports = module.exports
 else
        context = 'browser'
-       window.wheic_parser = {}
-       exports = window.wheic_parser
+       window.peach_parser = {}
+       exports = window.peach_parser
 
 from_code_point = (x) ->
        if String.fromCodePoint?
index 5cc99bf..cc65725 100644 (file)
@@ -7932,19 +7932,19 @@ tests = [
 ]
 
 if typeof module isnt 'undefined' and module.exports?
-       wheic_parser = require './parser.coffee'
+       peach_parser = require './parser.coffee'
 else
-       wheic_parser = window.wheic_parser
+       peach_parser = window.peach_parser
 
 serialize_els = (els, prefix = '| ') ->
        ret = ''
        for el in els
                switch el.type
-                       when wheic_parser.TYPE_TAG
+                       when peach_parser.TYPE_TAG
                                ret += "#{prefix}<"
-                               if el.namespace is wheic_parser.NS_MATHML
+                               if el.namespace is peach_parser.NS_MATHML
                                        ret += "math "
-                               if el.namespace is wheic_parser.NS_SVG
+                               if el.namespace is peach_parser.NS_SVG
                                        ret += "svg "
                                ret += "#{el.name}>\n"
                                attr_keys = []
@@ -7953,16 +7953,16 @@ serialize_els = (els, prefix = '| ') ->
                                attr_keys.sort() # TODO this should be "lexicographically by UTF-16 code unit"
                                for k in attr_keys
                                        ret += "#{prefix}  #{k}=\"#{el.attrs[k]}\"\n"
-                               if el.name is 'template' and el.namespace is wheic_parser.NS_HTML
+                               if el.name is 'template' and el.namespace is peach_parser.NS_HTML
                                        ret += "#{prefix}  content\n"
                                        ret += serialize_els el.children, "#{prefix}    "
                                else
                                        ret += serialize_els el.children, "#{prefix}  "
-                       when wheic_parser.TYPE_TEXT
+                       when peach_parser.TYPE_TEXT
                                ret += "#{prefix}\"#{el.text}\"\n"
-                       when wheic_parser.TYPE_COMMENT
+                       when peach_parser.TYPE_COMMENT
                                ret += "#{prefix}<!-- #{el.text} -->\n"
-                       when wheic_parser.TYPE_DOCTYPE
+                       when peach_parser.TYPE_DOCTYPE
                                ret += "#{prefix}<!DOCTYPE #{el.name}"
                                if (el.public_identifier? and el.public_identifier.length > 0) or (el.system_identifier? and el.system_identifier.length > 0)
                                        ret += " \"#{el.public_identifier ? ''}\""
@@ -7974,17 +7974,17 @@ serialize_els = (els, prefix = '| ') ->
 
 test_results = passed: 0, failed: 0
 test_parser = (args) ->
-       wheic_parser.debug_log_reset()
+       peach_parser.debug_log_reset()
        parse_errors = []
        args.error_cb = (i) ->
                parse_errors.push i
        prev_node_id = 0 # reset counter
-       parsed = wheic_parser.parse args.html, args
+       parsed = peach_parser.parse args.html, args
        serialized = serialize_els parsed
        if serialized isnt args.expected
                test_results.failed += 1
                if test_results.failed is 1
-                       wheic_parser.debug_log_each (str) ->
+                       peach_parser.debug_log_each (str) ->
                                console.log str
                        console.log "FAILED: \"#{args.name}\""
                        console.log "      Input: #{args.html}"
index 5288014..1e59713 100644 (file)
@@ -6,7 +6,7 @@
        <title>html parser tester</title>
 </head>
 <body>
-       <h1>WHEIC html parser test page (javascript version)</h1>
+       <h1>Peach HTML5 Parser test page (javascript version)</h1>
        <p>You'll need to run <code>make</code> to build the javascript files used on this page.</p>
        <p>If you don't have node.js and CoffeeScript installed, you can <a href="parser_tests_coffee.html">use the other test page</a> which compiles the CoffeeScript files on the fly in the browser.</p>
        <p>Check the inspector/console for test results.</p>
index 7d2fc4d..78920ab 100644 (file)
@@ -6,7 +6,7 @@
        <title>html parser tester</title>
 </head>
 <body>
-       <h1>WHEIC html parser test page (CoffeeScript version)</h1>
+       <h1>Peach HTML5 Parser test page (CoffeeScript version)</h1>
        <p>This version of the test page compiles the CoffeeScript files in the browser, so you don't have to install CoffeeScript (or node.js).</p>
        <p>It can take a few seconds for the tests to compile.</p>
        <p>Check the inspector/console for test results.</p>