Nali.extend Collection:
cloning: -> @subscribeTo @Model, "create.#{ @model._name.lower() }", @_onModelCreated @subscribeTo @Model, "update.#{ @model._name.lower() }", @_onModelUpdated @subscribeTo @Model, "destroy.#{ @model._name.lower() }", @_onModelDestroyed @adaptations = apply: [], cancel: [] @_ordering = {} @_adaptCollection() @refilter() @ _toShowViews: [] _visibleViews: [] length: 0 refilter: -> @model.each ( model ) => if isCorrect = model.isCorrect( @filters ) and not ( model in @ ) then @add model else if not isCorrect and model in @ then @remove model @ new: ( model, filters ) -> @clone model: model, filters: filters _onModelCreated: ( model ) -> @add model if not @freezed and model.isCorrect @filters @ _onModelUpdated: ( model ) -> if model.written() if model in @ if @freezed or model.isCorrect @filters @_reorder() @trigger 'update.model', model else @remove model else if not @freezed and model.isCorrect @filters @add model @ _onModelDestroyed: ( model ) -> @remove model if model in @ and not @freezed @ _adaptCollection: -> for name, method of @model when /^__\w+$/.test( name ) and typeof method is 'function' do ( name, method ) => @[ name = name[ 2.. ] ] = ( args... ) => @each ( model ) -> model[ name ] args... @ @ _adaptModel: ( model, type = 'apply' ) -> adaptation.call @, model for adaptation in @adaptations[ type ] @ adaptation: ( apply, cancel ) -> @each ( model ) -> apply.call @, model @adaptations.apply.push apply @adaptations.cancel.unshift cancel if cancel @ add: ( models... ) -> for model in [].concat models... Array::push.call @, model @_adaptModel model @_reorder() @trigger 'update.length.add', model @trigger 'update.length', 'add', model @ remove: ( model ) -> @_adaptModel model, 'cancel' Array::splice.call @, @indexOf( model ), 1 @unsubscribeFrom model @_reorder() @trigger 'update.length.remove', model @trigger 'update.length', 'remove', model @ removeAll: -> @each ( model ) -> @remove model @length = 0 @ each: ( callback ) -> callback.call @, model, index for model, index in @ @ pluck: ( property ) -> model[ property ] for model in @ indexOf: ( model ) -> Array::indexOf.call @, model sort: ( sorter ) -> Array::sort.call @, sorter @ toArray: -> Array::slice.call @, 0 freeze: -> @freezed = true @ unfreeze: -> @freezed = false @refilter() @ where: ( filters ) -> filters[ name ] = value for name, value of @filters @model.where filters order: ( @_ordering ) -> @_reorder() @ _reorder: -> if @_ordering.by? clearTimeout @_ordering.timer if @_ordering.timer? @_ordering.timer = setTimeout => if typeof @_ordering.by is 'function' @sort @_ordering.by else @sort ( one, two ) => one = one[ @_ordering.by ] two = two[ @_ordering.by ] if @_ordering.as is 'number' one = + one two = + two if @_ordering.as is 'string' one = '' + one two = '' + two ( if one > two then 1 else if one < two then -1 else 0 ) * ( if @_ordering.desc then -1 else 1 ) @_orderViews() delete @_ordering.timer , 5 @ _orderViews: -> if @_inside children = Array::slice.call @_inside.children children.sort ( one, two ) => @indexOf( one.view.model ) - @indexOf( two.view.model ) @_inside.appendChild child for child in children @ show: ( viewName, insertTo, isRelation = false ) -> @adaptation ( model ) -> view = model.view viewName if isRelation view.subscribeTo @, 'reset', view.hide else unless @visible @visible = true @_prepareViewToShow view @_hideVisibleViews() else @::_visibleViews.push view view.show insertTo @_inside ?= view.element[0].parentNode , ( model ) -> model.hide viewName @ hide: ( viewName, delay ) -> model.hide viewName, delay for model in @ @ _prepareViewToShow: ( view ) -> unless view in @::_toShowViews @::_toShowViews.push view @_prepareViewToShow layout if ( layout = view.layout() )?.childOf? 'View' @ _hideVisibleViews: -> view.hide() for view in @::_visibleViews when not( view in @::_toShowViews ) @::_visibleViews = @::_toShowViews @::_toShowViews = [] @ first: -> @[0] last: -> @[ @length - 1 ] reset: -> @_inside = null @adaptations.length = 0 @trigger 'reset' @ destroy: -> @trigger 'destroy' @destroyObservation() @removeAll() @reset() @