app/assets/javascripts/joosy/core/modules/renderer.js.coffee in joosy-0.1.0.RC1 vs app/assets/javascripts/joosy/core/modules/renderer.js.coffee in joosy-0.1.0.RC2
- old
+ new
@@ -2,21 +2,24 @@
#= require metamorph
Joosy.Modules.Renderer =
__renderer: ->
- throw new Error "#{@constructor.name} does not have an attached template"
+ throw new Error "#{Joosy.Module.__className @constructor} does not have an attached template"
__helpers: null
included: ->
- @view = (template) ->
- if Object.isFunction(template)
+ @view = (template, options={}) ->
+ if Object.isFunction template
@::__renderer = template
else
@::__renderer = (locals={}) ->
- @render(template, locals)
+ if options.dynamic
+ @renderDynamic template, locals
+ else
+ @render template, locals
@helpers = (helpers...) ->
@::__helpers ||= []
helpers.map (helper) =>
module = Joosy.Helpers[helper]
@@ -28,89 +31,149 @@
@::__helpers = @::__helpers.unique()
__instantiateHelpers: ->
unless @__helpersInstance
@__helpersInstance = Object.extended Joosy.Helpers.Application
-
- @__helpersInstance.render = =>
- @render(arguments...)
@__helpersInstance.widget = (element, widget) =>
@widgets ||= {}
uuid = Joosy.uuid()
- element = document.createElement(element)
- temp = document.createElement("div")
+ element = document.createElement element
+ temp = document.createElement 'div'
- element.id = uuid
+ element.id = uuid
@widgets['#'+uuid] = widget
- temp.appendChild(element)
+ temp.appendChild element
temp.innerHTML
if @__helpers
for helper in @__helpers
- @__helpersInstance.merge helper
+ Joosy.Module.merge @__helpersInstance, helper
@__helpersInstance
# If we do not have __proto__ available...
__proxifyHelpers: (locals) ->
if locals.hasOwnProperty '__proto__'
locals.__proto__ = @__instantiateHelpers()
-
locals
else
unless @__helpersProxyInstance
@__helpersProxyInstance = (locals) ->
- Object.merge(this, locals)
+ Joosy.Module.merge this, locals
@__helpersProxyInstance.prototype = @__instantiateHelpers()
- new @__helpersProxyInstance(locals)
+ new @__helpersProxyInstance locals
- render: (template, locals={}) ->
- isResource = Joosy.Module.hasAncestor(locals.constructor, Joosy.Resource.Generic)
+ render: (template, locals={}, parentStackPointer=false) ->
+ @__render false, template, locals, parentStackPointer
+ renderDynamic: (template, locals={}, parentStackPointer=false) ->
+ @__render true, template, locals, parentStackPointer
+
+ __render: (dynamic, template, locals={}, parentStackPointer=false) ->
+ stack = @__renderingStackChildFor parentStackPointer
+
+ stack.template = template
+
+ isResource = Joosy.Module.hasAncestor locals.constructor, Joosy.Resource.Generic
+ isCollection = Joosy.Module.hasAncestor locals.constructor, Joosy.Resource.Collection
+
if Object.isString template
if @__renderSection?
template = Joosy.Application.templater.resolveTemplate @__renderSection(), template, this
template = Joosy.Application.templater.buildView template
- else if !Object.isFunction(template)
- throw new Error "#{Joosy.Module.__className__ @}> template (maybe @view) does not look like a string or lambda"
+ else if !Object.isFunction template
+ throw new Error "#{Joosy.Module.__className @}> template (maybe @view) does not look like a string or lambda"
+
+ if !Object.isObject(locals) && !isResource && !isCollection
+ throw new Error "#{Joosy.Module.__className @}> locals (maybe @data?) not in: dumb hash, Resource, Collection"
- if !Object.isObject(locals) && !isResource
- throw new Error "#{Joosy.Module.__className__ @}> locals (maybe @data?) can only be dumb hash or Resource"
-
- # Small code dup due to the fact we sometimes
- # actually CLONE object when proxying helpers
- if !isResource
- locals = @__proxifyHelpers(locals)
- morph = Metamorph template(locals)
- update = => morph.html template(locals)
+ if isResource
+ stack.locals = locals.e
else
- locals.e = @__proxifyHelpers(locals.e)
- morph = Metamorph template(locals.e)
- update = => morph.html template(locals.e)
+ stack.locals = locals
- # This is here to break stack tree and save from
- # repeating DOM handling
- update = update.debounce(0)
+ renderers =
+ render: (template, locals={}) =>
+ @render template, locals, stack
+ renderDynamic: (template, locals={}) =>
+ @renderDynamic template, locals, stack
+
+ context = =>
+ data = {}
+ Joosy.Module.merge data, stack.locals
+ Joosy.Module.merge data, @__instantiateHelpers(), false
+ Joosy.Module.merge data, renderers
+ data
+
+ if dynamic
+ morph = Metamorph template(context())
+ update = =>
+ for child in stack.children
+ @__removeMetamorphs child
+ stack.children = []
+ morph.html template(context())
+ @refreshElements?()
- @__metamorphs ||= []
+ # This is here to break stack tree and save from
+ # repeating DOM handling
+ update = update.debounce 0
- if isResource
- locals.bind 'changed', update
+ if isCollection
+ for resource in locals.data
+ resource.bind 'changed', update
+ stack.metamorphBindings.push [resource, update]
+ if isResource || isCollection
+ locals.bind 'changed', update
+ stack.metamorphBindings.push [locals, update]
+ else
+ for key, object of locals
+ if locals.hasOwnProperty key
+ if object?.bind? && object?.unbind?
+ object.bind 'changed', update
+ stack.metamorphBindings.push [object, update]
+
+ morph.outerHTML()
else
- for key, object of locals
- if locals.hasOwnProperty key
- if object?.bind? && object?.unbind?
- object.bind 'changed', update
- @__metamorphs.push [object, update]
+ template context()
- morph.outerHTML()
+ __renderingStackElement: (parent=null) ->
+ metamorphBindings: []
+ locals: null
+ template: null
+ children: []
+ parent: parent
- __removeMetamorphs: ->
- if @__metamorphs
- for [object, callback] in @__metamorphs
- object.unbind callback
\ No newline at end of file
+ __renderingStackChildFor: (parentPointer) ->
+ if !@__renderingStack
+ @__renderingStack = []
+
+ if !parentPointer
+ element = @__renderingStackElement()
+ @__renderingStack.push element
+ element
+ else
+ element = @__renderingStackElement parentPointer
+ parentPointer.children.push element
+ element
+
+ __removeMetamorphs: (stackPointer=false) ->
+ remove = (stackPointer) =>
+ if stackPointer?.children
+ for child in stackPointer.children
+ @__removeMetamorphs child
+
+ if stackPointer?.metamorphBindings
+ for [object, callback] in stackPointer.metamorphBindings
+ object.unbind callback
+ stackPointer.metamorphBindings = []
+
+ unless stackPointer
+ @__renderingStack?.each (stackPointer) ->
+ remove stackPointer
+ else
+ remove stackPointer