X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=editor.coffee;h=faa2e3f25462bb44211107f980e8a9b88de31dd9;hb=dc0f845531025a04b5e3a541d1ba8c98fc96b1b4;hp=4de3b8179d8c312fb1e024070b3e9a21c71e0a3a;hpb=a7cff3a244ba086034aed2f284235b6bcb6b7f98;p=peach-html5-editor.git diff --git a/editor.coffee b/editor.coffee index 4de3b81..faa2e3f 100644 --- a/editor.coffee +++ b/editor.coffee @@ -14,3 +14,180 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +# encode text so it can be safely placed inside an html attribute +enc_attr_regex = new RegExp '(&)|(")|(\u00A0)', 'g' +enc_attr = (txt) -> + return txt.replace enc_attr_regex, (match, amp, quote) -> + return '&' if (amp) + return '"' if (quote) + return ' ' + +void_elements = { + area: true + base: true + br: true + col: true + embed: true + hr: true + img: true + input: true + keygen: true + link: true + meta: true + param: true + source: true + track: true + wbr: true +} +dom_to_html = (dom) -> + ret = '' + for el in dom + switch el.type + when peach_parser.TYPE_TAG + ret += '<' + el.name + attr_keys = [] + for k of el.attrs + attr_keys.unshift k + #attr_keys.sort() + for k in attr_keys + ret += " #{k}" + if el.attrs[k].length > 0 + ret += "=\"#{enc_attr el.attrs[k]}\"" + ret += '>' + unless void_elements[el.name] + if el.children.length + ret += dom_to_html el.children + ret += "" + when peach_parser.TYPE_TEXT + ret += el.text + when peach_parser.TYPE_COMMENT + ret += "" + when peach_parser.TYPE_DOCTYPE + ret += " 0 + ret += " \"#{el.public_identifier}\"" + if el.system_identifier? and el.system_identifier.length > 0 + ret += " \"#{el.system_identifier}\"" + ret += ">\n" + return ret + +domify = (h) -> + for tag, attrs of h + if tag is 'text' + return document.createTextNode attrs + el = document.createElement tag + for k, v of attrs + if k is 'children' + for child in v + el.appendChild child + else + el.setAttribute k, v + return el + +css = '' +css += 'div#peach_editor_cursor {' +css += 'display: inline-block;' +css += 'height: 1em;' +css += 'width: 2px;' +css += 'margin-left: -1px;' +css += 'margin-right: -1px;' +css += 'background: #000;' +css += '-webkit-animation: 1s blink step-end infinite;' +css += 'animation: 1s blink step-end infinite;' +css += '}' +css += '@-webkit-keyframes "blink" {' +css += 'from, to { background: #000; }' +css += '50% { background: transparent; }' +css += '}' +css += '@keyframes "blink" {' +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 = {} + if opt_fragment + parser_opts.fragment = 'body' + editor_instance = { + dom: [] + iframe: document.createElement('iframe') + load_html: (html) -> + @dom = peach_parser.parse html, parser_opts + as_html = peach.dom_to_html @dom + as_html = as_html.substr(0, 5) + '' + 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) -> + 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 + if options.stylesheet # TODO test this + istyle = idoc.createElement 'style' + istyle.setAttribute 'src', options.stylesheet + idoc.head.appendChild istyle + icss = idoc.createElement 'style' + icss.appendChild idoc.createTextNode css + idoc.head.appendChild icss + editor_instance.load_html el.value + return editor_instance + +window.peach = { + wysiwyg: wysiwyg + dom_to_html: dom_to_html +} + +# test in browser: peach.wysiwyg(document.getElementsByTagName('textarea')[0])