X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=editor.coffee;h=870c61bb6b91fb21b111b805509e99085fb3724d;hb=dac5189783f7b082e0baf790c859aae9f28c5412;hp=8bc72ef32b75d814d17a41351150e9d2063e5d77;hpb=a1a9a189a821bc17cd1f07d7d145d5fe0e1d80a8;p=peach-html5-editor.git diff --git a/editor.coffee b/editor.coffee index 8bc72ef..870c61b 100644 --- a/editor.coffee +++ b/editor.coffee @@ -18,6 +18,24 @@ overlay_padding = 10 timeout = (ms, cb) -> return setTimeout cb, ms +next_frame = (cb) -> + if (window.requestAnimationFrame?) + window.requestAnimationFrame cb + else + timeout 16, cb + +this_url_sans_path = -> + ret = "#{window.location.href}" + clip = ret.lastIndexOf '#' + if clip > -1 + ret = ret.substr 0, clip + clip = ret.lastIndexOf '?' + if clip > -1 + ret = ret.substr 0, clip + clip = ret.lastIndexOf '/' + if clip > -1 + ret = ret.substr 0, clip + 1 + return ret # xml 1.0 spec, chromium and firefox accept these, plus lots of unicode chars valid_attr_regex = new RegExp '^[a-zA-Z_:][-a-zA-Z0-9_:.]*$' @@ -227,14 +245,20 @@ outer_css = (args) -> ret += 'height: 1em;' # FIXME adjust for hight of text ret += 'width: 2px;' ret += 'background: #444;' - ret += '-webkit-animation: blink 1s steps(2, start) infinite;' - ret += 'animation: blink 1s steps(2, start) infinite;' + ret += '-webkit-animation: blink 1s linear infinite;' + ret += 'animation: blink 1s linear infinite;' ret += '}' ret += '@-webkit-keyframes blink {' - ret += 'to { visibility: hidden; }' + ret += '0% { background-color: rgba(0,0,0,0.7); }' + ret += '50% { background-color: rgba(0,0,0,0.7); }' + ret += '50.001% { background-color: rgba(255,255,255,0.7); }' + ret += '100% { background-color: rgba(255,255,255,0.7); }' ret += '}' ret += '@keyframes blink {' - ret += 'to { visibility: hidden; }' + ret += '0% { background-color: rgba(0,0,0,0.7); }' + ret += '50% { background-color: rgba(0,0,0,0.7); }' + ret += '50.001% { background-color: rgba(255,255,255,0.7); }' + ret += '100% { background-color: rgba(255,255,255,0.7); }' ret += '}' ret += '.ann_box {' ret += 'z-index: 5;' @@ -248,6 +272,10 @@ outer_css = (args) -> ret += 'font-size: 8px;' ret += 'white-space: pre;' ret += 'background: rgba(255,255,255,0.4);' + ret += '-ms-user-select: none;' + ret += '-webkit-user-select: none;' + ret += '-moz-user-select: none;' + ret += 'user-select: none;' ret += '}' return ret @@ -578,6 +606,7 @@ tree_dedup_space = (tree) -> class PeachHTML5Editor # Options: (all optional) # editor_id: "id" attribute for outer-most element created by/for editor + # css_file: filename of a css file to style editable content # on_init: callback for when the editable content is in place constructor: (in_el, options) -> @options = options ? {} @@ -593,6 +622,7 @@ class PeachHTML5Editor @cursor = null @cursor_el = null @cursor_visible = false + @poll_for_blur_timeout = null @iframe_offset = null opt_fragment = @options.fragment ? true @parser_opts = {} @@ -609,7 +639,7 @@ class PeachHTML5Editor domify @outer_idoc, text: css ] @outer_idoc.head.appendChild icss - @iframe = domify @outer_idoc, iframe: {} + @iframe = domify @outer_idoc, iframe: sandbox: 'allow-same-origin allow-scripts' @iframe.onload = => @init() setTimeout (=> @init() unless @inited), 200 # firefox never fires this onload @@ -637,18 +667,26 @@ class PeachHTML5Editor init: -> # called by @iframe's onload (or timeout on firefox) @idoc = @iframe.contentDocument @overlay.onclick = (e) => + @have_focus() return event_return e, @onclick e @overlay.ondoubleclick = (e) => + @have_focus() return event_return e, @ondoubleclick e @outer_idoc.body.onkeyup = (e) => + @have_focus() return event_return e, @onkeyup e @outer_idoc.body.onkeydown = (e) => + @have_focus() return event_return e, @onkeydown e @outer_idoc.body.onkeypress = (e) => + @have_focus() return event_return e, @onkeypress e - if @options.stylesheet + # chromium doesn't resolve relative urls as though they were at the same domain + # so add a tag + @idoc.head.appendChild domify @idoc, base: href: this_url_sans_path() + if @options.css_file # TODO test this - @idoc.head.appendChild domify @idoc, style: src: @options.stylesheet + @idoc.head.appendChild domify @idoc, link: rel: 'stylesheet', type: 'text/css', href: @options.css_file @load_html @in_el.value @inited = true if @options.on_init? @@ -847,12 +885,14 @@ class PeachHTML5Editor display = cs['display'] position = cs['position'] float = cs['float'] + visibility = cs['visibility'] 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' + visibility = cs.getPropertyValue 'visibility' if n.name is 'textarea' inner_flags.pre_ish = true else @@ -868,7 +908,11 @@ class PeachHTML5Editor if 'display' is 'none' in_flow = false else - in_flow = true + switch visibility + when 'hidden', 'collapse' + in_flow = false + else # visible + in_flow = true switch display when 'inline', 'none' inner_flags.block = false @@ -938,6 +982,21 @@ class PeachHTML5Editor if prev_in_flow_is_block or parent_flags.block ret += "\n#{indent.substr 4}" return ret + onblur: -> + @kill_cursor() + have_focus: -> + @editor_is_focused = true + @poll_for_blur() + poll_for_blur: -> + return if @poll_for_blur_timeout? # already polling + @poll_for_blur_timeout = timeout 150, => + next_frame => # pause polling when browser knows we're not active/visible/etc. + @poll_for_blur_timeout = null + if document.activeElement is @outer_iframe + @poll_for_blur() + else + @editor_is_focused = false + @onblur() window.peach_html5_editor = (args...) -> return new PeachHTML5Editor args...