View.coffeesrc/ | |
---|---|
Provides a simple view class. Implements | define ['./Template', './Events'], (Template, Events) -> \
new Class
Implements: [Options, Events, Template]
Binds: ['destroy'] |
Dust.js template name to be used for rendering this view | template: null |
Define events for delegation here, of the type below. See
| events: {} |
Reference to the rendered view element | el: null |
Model can be passed in to provide the template with data. If so we'll
listen to the | model: null |
Use this object to store for the template, which can be used as well as a model | data: {} |
Define parser funcions to create dynamic template fields or alter existing mode/data attributes for template display only | parsers: {} |
If | options:
injectTo: null
autoDestroyModel: false |
On class initialisation any dust templates present will be loaded, the view will be rendered and injected into the passed in container if specified. Rendering also causes events to be delegated.
| initialize: (options={}) ->
@loadAllTemplates()
for key in ['model', 'el']
if options[key]?
@[key] = options[key]
delete options[key]
@setOptions options
if @model? and @options.autoDestroyModel
@model.addEvent 'destroy', @destroy
@render options.data, silent: true
if @options.injectTo?
@inject @options.injectTo
@ |
Renders the view, if already rendered then replaces the current element
whilst keeping the
| render: (data={}, options={}) ->
el = @_render data
el.store 'view', @
if not @el?
@el = el
else
@_replaceCurrentEl el
@refs = @getRefs el
@delegateEvents @el, @events
container = Array.from(el)[0].getParent()
@_checkDomUpdate container
@fireEvent 'render' unless options.silent
el |
When rendering a model this is called to get a representation suitable
for passing into the template. By default this calls | parseForDisplay: (model) ->
@model.toJSON() |
Use to rerender a template partially, can be used to preserve visual state within the template. Doesn't alter events as assumed to be run on a child node.
| rerender: (refs, data={}, options={}) ->
el = @_render data
Array.from(refs).each (ref) =>
replaceThis = @refs[ref]
if not replaceThis
throw "Cannot find ref #{ref} in template #{@template}"
newEl = @getRefs(el)[ref]
Object.merge @refs, @getRefs(newEl)
@refs[ref].replaces replaceThis
@_checkDomUpdate newEl.getParent()
@fireEvent 'rerender' unless options.silent |
We have an inject method here so that we can fire | inject: (container, el=@el) ->
el.inject container
@_checkDomUpdate container
getElement: -> @el.getElement.apply @el, arguments
getElements: -> @el.getElements.apply @el, arguments
getViews: (el) ->
els = el.getChildren()
els.retrieve('view')
reorderViews: (collection, rootEl) ->
views = @getViews rootEl
for view in views
dummy = new Element 'div'
current = $(view)
desiredIndex = collection.indexOf view.model
swap = rootEl.getChildren()[desiredIndex]
dummy.inject current, 'before'
current.inject swap, 'before'
swap.inject dummy, 'before'
dummy.destroy() |
Very handy method for emptying an element and killing all the views
inside it by calling their | destroyViews: (el) ->
views = @getViews(el)
return if views is null
views.invoke 'destroy'
destroy: ->
if @model? and @options.autoDestroyModel
@model.removeEvent 'destroy', @destroy
@el.eliminate 'view'
@el.destroy()
toElement: -> @el |
Private methods | |
Replaces the elements in | _replaceCurrentEl: (el) ->
if not instanceOf el, Array
@el = el.replaces @el
else
@el.each (currentEl, idx) =>
@el[idx] = el[idx].replaces currentEl
_render: (data={}) ->
data = @_getTemplateData data
el = @renderTemplate @template, data
_getTemplateData: (data={}) ->
data = Object.merge @data, data
if @model?
data = Object.merge {}, @parseForDisplay(@model), data
for fieldName, parser of @parsers
data[fieldName] = parser.call this, data
data |
Recurse back through an elements parents to determine whether it is
within the DOM or not, if so fire | _checkDomUpdate: (container) ->
inDom = false
parent = container
if parent == document.body
inDom = true
while parent = $(parent).getParent()
inDom = true if parent == document.body
if inDom
document.fireEvent 'domupdated', [container]
|