page_editor.js.coffee |
|
---|---|
class @Mercury.PageEditor |
|
options saveStyle: ‘form’, or ‘json’ (defaults to json) saveDataType: ‘xml’, ‘json’, ‘jsonp’, ‘script’, ‘text’, ‘html’ (defaults to json) saveMethod: ‘POST’, or ‘PUT’, create or update actions on save (defaults to POST) visible: boolean, if the interface should start visible or not (defaults to true) |
constructor: (@saveUrl = null, @options = {}) ->
throw Mercury.I18n('Mercury.PageEditor is unsupported in this client. Supported browsers are chrome 10+, firefix 4+, and safari 5+.') unless Mercury.supported
throw Mercury.I18n('Mercury.PageEditor can only be instantiated once.') if window.mercuryInstance
@options.visible = true unless @options.visible == false
@visible = @options.visible
window.mercuryInstance = @
@regions = []
@initializeInterface()
Mercury.csrfToken = token if token = jQuery(Mercury.config.csrfSelector).attr('content')
initializeInterface: ->
@focusableElement = jQuery('<input>', {class: 'mercury-focusable', type: 'text'}).appendTo(@options.appendTo ? 'body')
@iframe = jQuery('<iframe>', {id: 'mercury_iframe', class: 'mercury-iframe', seamless: 'true', frameborder: '0', src: 'about:blank'})
@iframe.appendTo(jQuery(@options.appendTo).get(0) ? 'body')
@toolbar = new Mercury.Toolbar(@options)
@statusbar = new Mercury.Statusbar(@options)
@resize()
@iframe.on 'load', => @initializeFrame()
@iframe.get(0).contentWindow.document.location.href = @iframeSrc()
initializeFrame: ->
try
return if @iframe.data('loaded')
@iframe.data('loaded', true)
Mercury.notify("Opera isn't a fully supported browser, your results may not be optimal.") if jQuery.browser.opera
@document = jQuery(@iframe.get(0).contentWindow.document)
stylesToInject = Mercury.config.injectedStyles.replace(/{{regionClass}}/g, Mercury.config.regionClass)
jQuery("<style mercury-styles=\"true\">").html(stylesToInject).appendTo(@document.find('head')) |
jquery: make jQuery evaluate scripts within the context of the iframe window
todo: look into |
iframeWindow = @iframe.get(0).contentWindow
jQuery.globalEval = (data) -> (iframeWindow.execScript || (data) -> iframeWindow["eval"].call(iframeWindow, data))(data) if (data && /\S/.test(data))
iframeWindow.Mercury = Mercury
iframeWindow.History = History if window.History && History.Adapter
@bindEvents()
@resize()
@initializeRegions()
@finalizeInterface()
Mercury.trigger('ready')
jQuery(iframeWindow).trigger('mercury:ready')
iframeWindow.Event.fire(iframeWindow, 'mercury:ready') if iframeWindow.Event && iframeWindow.Event.fire
iframeWindow.onMercuryReady() if iframeWindow.onMercuryReady
@iframe.css({visibility: 'visible'})
catch error
Mercury.notify('Mercury.PageEditor failed to load: %s\n\nPlease try refreshing.', error)
initializeRegions: ->
@regions = []
@buildRegion(jQuery(region)) for region in jQuery(".#{Mercury.config.regionClass}", @document)
return unless @options.visible
for region in @regions
if region.focus
region.focus()
break
buildRegion: (region) ->
try
if region.data('region')
region = region.data('region')
else
type = region.data('type').titleize()
region = new Mercury.Regions[type](region, @iframe.get(0).contentWindow)
region.togglePreview() if @previewing
@regions.push(region)
catch error
Mercury.notify(error) if Mercury.debug
Mercury.notify('Region type is malformed, no data-type provided, or "%s" is unknown for the "%s" region.', type, region.attr('id') || 'unknown')
finalizeInterface: ->
@santizerElement = jQuery('<div>', {id: 'mercury_sanitizer', contenteditable: 'true', style: 'position:fixed;width:100px;height:100px;top:0;left:-100px;opacity:0;overflow:hidden'})
@santizerElement.appendTo(@options.appendTo ? @document.find('body'))
@snippetToolbar = new Mercury.SnippetToolbar(@document)
@hijackLinksAndForms()
Mercury.trigger('mode', {mode: 'preview'}) unless @options.visible
bindEvents: ->
Mercury.on 'initialize:frame', => setTimeout(100, @initializeFrame)
Mercury.on 'focus:frame', => @iframe.focus()
Mercury.on 'focus:window', => setTimeout(10, => @focusableElement.focus())
Mercury.on 'toggle:interface', => @toggleInterface()
Mercury.on 'reinitialize', => @initializeRegions()
Mercury.on 'mode', (event, options) => @previewing = !@previewing if options.mode == 'preview'
Mercury.on 'action', (event, options) => @save() if options.action == 'save'
@document.on 'mousedown', (event) ->
Mercury.trigger('hide:dialogs')
if Mercury.region
Mercury.trigger('unfocus:regions') unless jQuery(event.target).closest(".#{Mercury.config.regionClass}").get(0) == Mercury.region.element.get(0)
jQuery(window).on 'resize', =>
@resize()
window.onbeforeunload = @beforeUnload
toggleInterface: ->
if @visible
Mercury.trigger('mode', {mode: 'preview'}) if @previewing
@visible = false
@toolbar.hide()
@statusbar.hide()
else
@visible = true
@toolbar.show()
@statusbar.show()
Mercury.trigger('mode', {mode: 'preview'})
@resize()
resize: ->
width = jQuery(window).width()
height = @statusbar.top()
toolbarHeight = @toolbar.height()
Mercury.displayRect = {top: toolbarHeight, left: 0, width: width, height: height - toolbarHeight, fullHeight: height}
@iframe.css {
top: toolbarHeight
left: 0
height: height - toolbarHeight
}
Mercury.trigger('resize')
iframeSrc: (url = null) ->
(url ? window.location.href).replace(/([http|https]:\/\/.[^\/]*)\/editor\/?(.*)/i, "$1/$2")
hijackLinksAndForms: ->
for element in jQuery('a, form', @document)
ignored = false
for classname in Mercury.config.nonHijackableClasses || []
if jQuery(element).hasClass(classname)
ignored = true
continue
if !ignored && (element.target == '' || element.target == '_self') && !jQuery(element).closest(".#{Mercury.config.regionClass}").length
jQuery(element).attr('target', '_top')
beforeUnload: ->
if Mercury.changes && !Mercury.silent
return Mercury.I18n('You have unsaved changes. Are you sure you want to leave without saving them first?')
return null
getRegionByName: (id) ->
for region in @regions
return region if region.name == id
return null
save: (callback) ->
url = @saveUrl ? Mercury.saveURL ? @iframeSrc()
data = @serialize()
Mercury.log('saving', data)
data = jQuery.toJSON(data) unless @options.saveStyle == 'form'
method = 'PUT' if @options.saveMethod == 'PUT'
jQuery.ajax url, {
headers: Mercury.ajaxHeaders()
type: method || 'POST'
dataType: @options.saveDataType || 'json'
data: {content: data, _method: method}
success: =>
callback() if callback
Mercury.changes = false
Mercury.trigger('saved')
error: =>
Mercury.notify('Mercury was unable to save to the url: %s', url)
}
serialize: ->
serialized = {}
serialized[region.name] = region.serialize() for region in @regions
return serialized |