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