neat-rails 0.2.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/neat/rails/version.rb +1 -1
- data/vendor/assets/javascripts/neat/collection_editor.coffee +32 -124
- data/vendor/assets/javascripts/neat/lib/jquery_extensions.coffee +10 -2
- data/vendor/assets/javascripts/neat/lib/scroll_handler.coffee +33 -0
- data/vendor/assets/javascripts/neat/model_editor.coffee +37 -20
- data/vendor/assets/javascripts/neat/renderer/basic.coffee +102 -0
- data/vendor/assets/javascripts/neat/renderer/infinite_reveal.coffee +37 -0
- data/vendor/assets/javascripts/neat/renderer/paginated.coffee +41 -0
- data/vendor/assets/javascripts/neat.js +5 -1
- metadata +8 -5
- data/vendor/assets/javascripts/neat/lib/delayed_action.js +0 -49
    
        data/lib/neat/rails/version.rb
    CHANGED
    
    
| @@ -15,13 +15,12 @@ KEYS = { | |
| 15 15 | 
             
            #   viewPath - by default this is set to resource
         | 
| 16 16 | 
             
            #
         | 
| 17 17 | 
             
            class window.Neat.CollectionEditor extends Backbone.View
         | 
| 18 | 
            -
              sortOrder: 'asc'
         | 
| 19 | 
            -
              sortAliases: {}
         | 
| 20 18 | 
             
              templateOptions: {}
         | 
| 21 | 
            -
              pageSize: 30
         | 
| 22 19 | 
             
              useKeyboardToChangeRows: true
         | 
| 23 20 | 
             
              cancelOnEsc: true
         | 
| 24 21 | 
             
              saveOnEnter: true
         | 
| 22 | 
            +
              renderer: "Basic"
         | 
| 23 | 
            +
              rendererOptions: {}
         | 
| 25 24 |  | 
| 26 25 | 
             
              initialize: ->
         | 
| 27 26 | 
             
                @keyDownHandlers = {}
         | 
| @@ -36,41 +35,15 @@ class window.Neat.CollectionEditor extends Backbone.View | |
| 36 35 | 
             
                @debug "looking for template at #{"#{@viewPath}/index"}"
         | 
| 37 36 | 
             
                @template = @template ? Neat.template["#{@viewPath}/index"]
         | 
| 38 37 |  | 
| 39 | 
            -
                 | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
                 | 
| 43 | 
            -
             | 
| 44 | 
            -
                @ | 
| 45 | 
            -
             | 
| 46 | 
            -
                @ | 
| 47 | 
            -
             | 
| 48 | 
            -
                # We need to rerender the page if a model's attributes
         | 
| 49 | 
            -
                # have changed just in case this would affect how the
         | 
| 50 | 
            -
                # models are sorted.
         | 
| 51 | 
            -
                #
         | 
| 52 | 
            -
                # !todo: perhaps we can be smarter here and only listen
         | 
| 53 | 
            -
                # for changes to the attribute the view is sorted on.
         | 
| 54 | 
            -
                #
         | 
| 55 | 
            -
                # We don't want to redraw the page every time a model
         | 
| 56 | 
            -
                # has changed. If an old transaction is deleted, a very
         | 
| 57 | 
            -
                # large number of more recent transactions' running
         | 
| 58 | 
            -
                # balances could be updated very rapidly. Redrawing the
         | 
| 59 | 
            -
                # page will slow things down dramatically.
         | 
| 60 | 
            -
                #
         | 
| 61 | 
            -
                # Instead, redraw the page 500ms after a model has changed.
         | 
| 62 | 
            -
                #
         | 
| 63 | 
            -
                # This allows us to wait for activity to die down
         | 
| 64 | 
            -
                # and to redraw the page when it's more likely the system
         | 
| 65 | 
            -
                # has settled into new state.
         | 
| 66 | 
            -
                #
         | 
| 67 | 
            -
                @delayedRerender = new Lail.DelayedAction(_.bind(@rerenderPage, @), delay: 500)
         | 
| 68 | 
            -
                @collection.bind 'change', =>
         | 
| 69 | 
            -
                  @delayedRerender.trigger() if @sortedBy
         | 
| 70 | 
            -
             | 
| 71 | 
            -
                # If the view's headers are 'a' tags, this view will try
         | 
| 72 | 
            -
                # to sort the collection using the header tags.
         | 
| 73 | 
            -
                $(@el).delegate '.header a', 'click', _.bind(@sort, @)
         | 
| 38 | 
            +
                # For backwards-compatibility
         | 
| 39 | 
            +
                @rendererOptions.pageSize = @pageSize if @pageSize?
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                rendererKlass = @renderer
         | 
| 42 | 
            +
                rendererKlass = Neat.Renderer[rendererKlass] if _.isString(rendererKlass)
         | 
| 43 | 
            +
                @_renderer = new rendererKlass(@, @collection, @rendererOptions)
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                @_renderer.afterRender _.bind(@afterRender, @)
         | 
| 46 | 
            +
             | 
| 74 47 | 
             
                $(@el).delegate '.editor', 'keydown', _.bind(@onKeyDown, @)
         | 
| 75 48 |  | 
| 76 49 | 
             
                if @cancelOnEsc
         | 
| @@ -83,37 +56,19 @@ class window.Neat.CollectionEditor extends Backbone.View | |
| 83 56 | 
             
                  @keyDownHandlers['UP']     = -> @edit @prevView()
         | 
| 84 57 | 
             
                  @keyDownHandlers['DOWN']   = -> @edit @nextView()
         | 
| 85 58 |  | 
| 86 | 
            -
                @views = []
         | 
| 87 59 | 
             
                @viewInEdit = null
         | 
| 88 60 | 
             
                @templateOptions = {}
         | 
| 89 61 |  | 
| 90 | 
            -
              repaginate: ->
         | 
| 91 | 
            -
                @rerenderPage(1)
         | 
| 92 62 |  | 
| 93 | 
            -
              rerenderPage: (page)->
         | 
| 94 | 
            -
                page = @paginator.getCurrentPage() unless _.isNumber(page)
         | 
| 95 | 
            -
                if @sortedBy
         | 
| 96 | 
            -
                  sortField = @sortField(@sortedBy)
         | 
| 97 | 
            -
                  items = @collection.sortBy (model)->
         | 
| 98 | 
            -
                    val = model.get(sortField) || ''
         | 
| 99 | 
            -
                    if _.isString(val) then val.toLowerCase() else val
         | 
| 100 | 
            -
                  items.reverse() if @sortOrder == 'desc'
         | 
| 101 | 
            -
                else
         | 
| 102 | 
            -
                  items = @collection.toArray()
         | 
| 103 | 
            -
                @paginator.init items, page
         | 
| 104 63 |  | 
| 105 64 |  | 
| 106 65 | 
             
              render: ->
         | 
| 107 66 | 
             
                $el = $(@el)
         | 
| 108 67 | 
             
                $el.html @template(@context())
         | 
| 109 68 | 
             
                $el.cssHover '.neat-row.neat-interactive'
         | 
| 69 | 
            +
                @$ul = $(@el).find("##{@resource}")
         | 
| 110 70 |  | 
| 111 | 
            -
                @ | 
| 112 | 
            -
             | 
| 113 | 
            -
                @updateSortStyle() if @sortedBy
         | 
| 114 | 
            -
             | 
| 115 | 
            -
                @paginator.renderPaginationIn($el.find('.pagination'))
         | 
| 116 | 
            -
                @repaginate()
         | 
| 71 | 
            +
                @_renderer.renderTo @$ul
         | 
| 117 72 | 
             
                @
         | 
| 118 73 |  | 
| 119 74 | 
             
              context: ->
         | 
| @@ -122,32 +77,21 @@ class window.Neat.CollectionEditor extends Backbone.View | |
| 122 77 | 
             
              afterRender: ->
         | 
| 123 78 | 
             
                @
         | 
| 124 79 |  | 
| 125 | 
            -
               | 
| 126 | 
            -
                alt = false
         | 
| 127 | 
            -
                $ul = $(@el).find("##{@resource}").empty() # e.g. $('#calendars')
         | 
| 128 | 
            -
                @views = []
         | 
| 80 | 
            +
              buildViewFor: (model) ->
         | 
| 129 81 | 
             
                self = @
         | 
| 130 | 
            -
             | 
| 131 | 
            -
             | 
| 132 | 
            -
             | 
| 133 | 
            -
             | 
| 134 | 
            -
                   | 
| 135 | 
            -
             | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 138 | 
            -
                    templateOptions: @templateOptions
         | 
| 139 | 
            -
                  view.bind 'edit:begin', -> self.beforeEdit.call(self, @)
         | 
| 140 | 
            -
                  view.bind 'edit:end', -> self.afterEdit.call(self, @)
         | 
| 141 | 
            -
             | 
| 142 | 
            -
                  @views.push(view)
         | 
| 143 | 
            -
             | 
| 144 | 
            -
                  $el = $(view.render().el)
         | 
| 145 | 
            -
                  $el.toggleClass 'alt', !(alt = !alt)
         | 
| 146 | 
            -
                  $ul.append $el
         | 
| 147 | 
            -
                @
         | 
| 82 | 
            +
                view = @constructModelView
         | 
| 83 | 
            +
                  resource: @resource
         | 
| 84 | 
            +
                  viewPath: @viewPath
         | 
| 85 | 
            +
                  model: model
         | 
| 86 | 
            +
                  templateOptions: @templateOptions
         | 
| 87 | 
            +
                view.bind 'edit:begin', -> self.beforeEdit.call(self, @)
         | 
| 88 | 
            +
                view.bind 'edit:end', -> self.afterEdit.call(self, @)
         | 
| 89 | 
            +
                view
         | 
| 148 90 |  | 
| 149 91 | 
             
              constructModelView: (options) ->
         | 
| 150 | 
            -
                 | 
| 92 | 
            +
                viewClass = @modelView
         | 
| 93 | 
            +
                viewClass = viewClass(options.model) if _.isFunction(viewClass) and !(viewClass.prototype instanceof Neat.ModelEditor)
         | 
| 94 | 
            +
                new viewClass(options)
         | 
| 151 95 |  | 
| 152 96 |  | 
| 153 97 | 
             
              beforeEdit: (view)->
         | 
| @@ -162,33 +106,6 @@ class window.Neat.CollectionEditor extends Backbone.View | |
| 162 106 |  | 
| 163 107 |  | 
| 164 108 |  | 
| 165 | 
            -
              sort: (e)->
         | 
| 166 | 
            -
                e.preventDefault()
         | 
| 167 | 
            -
                e.stopImmediatePropagation()
         | 
| 168 | 
            -
                sortBy = $(e.target).closest('a').attr('class').substring(@singular.length + 1)
         | 
| 169 | 
            -
                @log "sort by #{sortBy} [#{@sortField(sortBy)}]"
         | 
| 170 | 
            -
                if @sortedBy == sortBy
         | 
| 171 | 
            -
                  @sortOrder = if @sortOrder == 'asc' then 'desc' else 'asc'
         | 
| 172 | 
            -
                else
         | 
| 173 | 
            -
                  @removeSortStyle @sortedBy
         | 
| 174 | 
            -
                  @sortedBy = sortBy
         | 
| 175 | 
            -
                @repaginate()
         | 
| 176 | 
            -
                @updateSortStyle()
         | 
| 177 | 
            -
                false
         | 
| 178 | 
            -
             | 
| 179 | 
            -
              removeSortStyle: (field)->
         | 
| 180 | 
            -
             | 
| 181 | 
            -
              updateSortStyle: ()->
         | 
| 182 | 
            -
                @removeSortStyle @sortedBy
         | 
| 183 | 
            -
             | 
| 184 | 
            -
              getHeader: (field)->
         | 
| 185 | 
            -
                $(@el).find(".header > .#{@singular}-#{field}")
         | 
| 186 | 
            -
             | 
| 187 | 
            -
              sortField: (field)->
         | 
| 188 | 
            -
                @sortAliases[field] ? field
         | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 191 | 
            -
             | 
| 192 109 | 
             
              onKeyDown: (e)->
         | 
| 193 110 | 
             
                keyName = @identifyKey(e.keyCode)
         | 
| 194 111 | 
             
                handler = @keyDownHandlers[keyName]
         | 
| @@ -203,18 +120,21 @@ class window.Neat.CollectionEditor extends Backbone.View | |
| 203 120 | 
             
                # i.e. return true if target is in a dropdown control like Chosen
         | 
| 204 121 | 
             
                false
         | 
| 205 122 |  | 
| 206 | 
            -
             | 
| 123 | 
            +
              views: ->
         | 
| 124 | 
            +
                @_renderer.views
         | 
| 207 125 |  | 
| 208 126 | 
             
              nextView: ->
         | 
| 209 | 
            -
                @views[@indexOfViewInEdit() + 1]
         | 
| 127 | 
            +
                @views()[@indexOfViewInEdit() + 1]
         | 
| 210 128 |  | 
| 211 129 | 
             
              prevView: ->
         | 
| 212 | 
            -
                @views[@indexOfViewInEdit() - 1]
         | 
| 130 | 
            +
                @views()[@indexOfViewInEdit() - 1]
         | 
| 213 131 |  | 
| 214 132 | 
             
              indexOfViewInEdit: ->
         | 
| 215 | 
            -
                _.indexOf @views, @viewInEdit
         | 
| 133 | 
            +
                _.indexOf @views(), @viewInEdit
         | 
| 216 134 |  | 
| 217 135 | 
             
              edit: (view)->
         | 
| 136 | 
            +
                if view instanceof Backbone.Model
         | 
| 137 | 
            +
                  view = @_renderer.findViewForModel(view)
         | 
| 218 138 | 
             
                if view
         | 
| 219 139 | 
             
                  @viewInEdit?.save()
         | 
| 220 140 | 
             
                  view.edit()
         | 
| @@ -224,18 +144,6 @@ class window.Neat.CollectionEditor extends Backbone.View | |
| 224 144 | 
             
                @viewInEdit?.cancelEdit()
         | 
| 225 145 |  | 
| 226 146 |  | 
| 227 | 
            -
             | 
| 228 | 
            -
              __reset: ->
         | 
| 229 | 
            -
                @render()
         | 
| 230 | 
            -
             | 
| 231 | 
            -
              __add: ->
         | 
| 232 | 
            -
                @rerenderPage()
         | 
| 233 | 
            -
             | 
| 234 | 
            -
              __remove: ->
         | 
| 235 | 
            -
                @rerenderPage()
         | 
| 236 | 
            -
             | 
| 237 | 
            -
             | 
| 238 | 
            -
             | 
| 239 147 | 
             
              debug: (o...)->
         | 
| 240 148 | 
             
                @log(o...) if Neat.debug
         | 
| 241 149 |  | 
| @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            $.fn.extend
         | 
| 2 | 
            -
              cssHover: (selector)->
         | 
| 2 | 
            +
              cssHover: (selector) ->
         | 
| 3 3 | 
             
                if arguments.length == 0
         | 
| 4 4 | 
             
                  @hover(
         | 
| 5 5 | 
             
                    -> $(@).addClass('hovered'),
         | 
| @@ -11,5 +11,13 @@ $.fn.extend | |
| 11 11 | 
             
                    else
         | 
| 12 12 | 
             
                      $(@).removeClass('hovered')
         | 
| 13 13 |  | 
| 14 | 
            -
              isIn: (selector)->
         | 
| 14 | 
            +
              isIn: (selector) ->
         | 
| 15 15 | 
             
                @is(selector) or (@parents(selector).length > 0)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              insertBeforeChildOrAppendTo: (parent, selector) ->
         | 
| 18 | 
            +
                $parent = $ parent
         | 
| 19 | 
            +
                $insertionPoint = $parent.children(selector)
         | 
| 20 | 
            +
                if $insertionPoint.length > 0
         | 
| 21 | 
            +
                  $insertionPoint.before @
         | 
| 22 | 
            +
                else
         | 
| 23 | 
            +
                  $parent.append @
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            class @Neat.ScrollHandler
         | 
| 2 | 
            +
              _.extend @prototype, Backbone.Events
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              constructor: (options={})->
         | 
| 5 | 
            +
                @$viewPort = $(options.viewPort ? window)
         | 
| 6 | 
            +
                @$document = $(document)
         | 
| 7 | 
            +
                @$viewPort.scroll _.bind(@_windowWasScrolled, @)
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              _viewportHeight: ->
         | 
| 10 | 
            +
                @$viewPort.height()
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              _documentHeight: ->
         | 
| 13 | 
            +
                if $.isWindow @$viewPort[0]
         | 
| 14 | 
            +
                  @$document.height()
         | 
| 15 | 
            +
                else
         | 
| 16 | 
            +
                  @$viewPort[0].scrollHeight
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              _windowWasScrolled: ->
         | 
| 19 | 
            +
                viewportHeight = @_viewportHeight()
         | 
| 20 | 
            +
                documentHeight = @_documentHeight()
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                scrollTop = @$viewPort.scrollTop()
         | 
| 23 | 
            +
                scrollMax = documentHeight - viewportHeight
         | 
| 24 | 
            +
                progress = scrollTop / scrollMax
         | 
| 25 | 
            +
                distanceFromBottom = scrollTop - scrollMax
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                return if scrollMax <= 0
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                @trigger "scroll",
         | 
| 30 | 
            +
                  scrollTop: scrollTop
         | 
| 31 | 
            +
                  scrollMax: scrollMax
         | 
| 32 | 
            +
                  progress: progress
         | 
| 33 | 
            +
                  distanceFromBottom: distanceFromBottom
         | 
| @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            class window.Neat.ModelEditor extends Backbone.View
         | 
| 2 2 | 
             
              tagName: 'li'
         | 
| 3 3 | 
             
              className: 'neat-row neat-interactive neat-editable'
         | 
| 4 | 
            +
              waitOnSave: true
         | 
| 4 5 |  | 
| 5 6 | 
             
              initialize: (options)->
         | 
| 6 7 | 
             
                options = options ? {}
         | 
| @@ -82,7 +83,7 @@ class window.Neat.ModelEditor extends Backbone.View | |
| 82 83 | 
             
                  previousAttributes = @model.toJSON()
         | 
| 83 84 |  | 
| 84 85 | 
             
                  @model.save attributes,
         | 
| 85 | 
            -
                    wait:  | 
| 86 | 
            +
                    wait: @waitOnSave
         | 
| 86 87 | 
             
                    success: =>
         | 
| 87 88 | 
             
                      for attribute, newValue of attributes
         | 
| 88 89 | 
             
                        @debug "  . #{attribute} changed from ", previousAttributes[attribute], " to ", @model.get(attribute)
         | 
| @@ -94,26 +95,42 @@ class window.Neat.ModelEditor extends Backbone.View | |
| 94 95 | 
             
              okToSave: (attributes)->
         | 
| 95 96 | 
             
                true
         | 
| 96 97 |  | 
| 97 | 
            -
              attributesFromForm: ($el)->
         | 
| 98 | 
            +
              attributesFromForm: ($el) ->
         | 
| 98 99 | 
             
                attrs = {}
         | 
| 99 100 | 
             
                $el.find('input, select, textarea').each ->
         | 
| 100 | 
            -
                  elem = $( | 
| 101 | 
            +
                  elem = $(@)
         | 
| 101 102 | 
             
                  name = elem.attr('name')
         | 
| 102 | 
            -
                   | 
| 103 | 
            -
             | 
| 104 | 
            -
             | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 115 | 
            -
                     | 
| 116 | 
            -
             | 
| 103 | 
            +
                  elemType = elem.attr('type')
         | 
| 104 | 
            +
                  value = elem.val()
         | 
| 105 | 
            +
                  return true unless name
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  # Parse out nested objects as represented in names
         | 
| 108 | 
            +
                  # person[address][zip]=63303 should be serialized to:
         | 
| 109 | 
            +
                  # person:
         | 
| 110 | 
            +
                  #   address:
         | 
| 111 | 
            +
                  #     zip: 63303
         | 
| 112 | 
            +
                  parts = _.without(name.split(/\[([^\]]+)\]/), '')
         | 
| 113 | 
            +
                  name = parts.pop()
         | 
| 114 | 
            +
                  isArray = false
         | 
| 115 | 
            +
                  while name is '[]'
         | 
| 116 | 
            +
                    isArray = true
         | 
| 117 | 
            +
                    name = parts.pop()
         | 
| 118 | 
            +
                  context = attrs
         | 
| 119 | 
            +
                  for part in parts
         | 
| 120 | 
            +
                    context = context[part] or (context[part] = {})
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                  if (elemType == 'checkbox' || elemType == 'radio') && !elem.prop('checked')
         | 
| 123 | 
            +
                    return true
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                  if isArray
         | 
| 126 | 
            +
                    # select with multiple=true will return
         | 
| 127 | 
            +
                    # an array of selected values, so we don't
         | 
| 128 | 
            +
                    # need to nest that array in another array
         | 
| 129 | 
            +
                    value = [value] unless _.isArray(value)
         | 
| 130 | 
            +
                    value = (context[name] || []).concat(value)
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                  context[name] = value
         | 
| 133 | 
            +
                  true # Don't break out of the loop
         | 
| 117 134 | 
             
                attrs
         | 
| 118 135 |  | 
| 119 136 | 
             
              destroy: (e)->
         | 
| @@ -123,8 +140,8 @@ class window.Neat.ModelEditor extends Backbone.View | |
| 123 140 |  | 
| 124 141 | 
             
                  @model.destroy
         | 
| 125 142 | 
             
                    wait: true
         | 
| 126 | 
            -
                    success:  | 
| 127 | 
            -
                    error: _.bind(@ | 
| 143 | 
            +
                    success: _.bind(@onDestroySuccess, @)
         | 
| 144 | 
            +
                    error: _.bind(@onDestroyError, @)
         | 
| 128 145 | 
             
                  @endEdit()
         | 
| 129 146 |  | 
| 130 147 | 
             
              confirmDestroy: (resource, callback)->
         | 
| @@ -0,0 +1,102 @@ | |
| 1 | 
            +
            class window.Neat.Renderer.Basic
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              constructor: (@view, @collection, @options) ->
         | 
| 4 | 
            +
                @collection.bind 'reset',   @_collectionHasBeenReset, @
         | 
| 5 | 
            +
                @collection.bind 'sort',    @_collectionHasBeenSorted, @
         | 
| 6 | 
            +
                @collection.bind 'add',     @_modelHasBeenAddedToCollection, @
         | 
| 7 | 
            +
                @collection.bind 'remove',  @_modelHasBeenRemovedFromCollection, @
         | 
| 8 | 
            +
                @collection.bind 'change',  @_modelHasBeenChanged, @
         | 
| 9 | 
            +
                @views = []
         | 
| 10 | 
            +
                @observer = new Observer()
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              renderTo: (@$ul) ->
         | 
| 13 | 
            +
                @views = []
         | 
| 14 | 
            +
                @_render()
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              findViewForModel: (model)->
         | 
| 17 | 
            +
                @views[@_indexOfViewForModel(model)]
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              afterRender: (callback) ->
         | 
| 20 | 
            +
                @observer.observe "after_render", callback
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              _render: ->
         | 
| 23 | 
            +
                # Doesn't need to render anything else like pagination controls on the view
         | 
| 24 | 
            +
                # Just needs the @$ul that it should render views to
         | 
| 25 | 
            +
                @_renderVisibleModels()
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              _renderVisibleModels: ->
         | 
| 28 | 
            +
                visibleModels = @_visibleModels()
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                # Remove views that no longer correspond to visible models.
         | 
| 31 | 
            +
                viewIndex = 0
         | 
| 32 | 
            +
                while viewIndex < @views.length
         | 
| 33 | 
            +
                  if _.contains(visibleModels, @views[viewIndex].model)
         | 
| 34 | 
            +
                    viewIndex += 1
         | 
| 35 | 
            +
                  else
         | 
| 36 | 
            +
                    @_removeView(viewIndex)
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                # Add views for newly-visible models; and coerce views
         | 
| 39 | 
            +
                # (and their corresponding DOM elements) to show up in
         | 
| 40 | 
            +
                # the same order as the visible models.
         | 
| 41 | 
            +
                for model, index in visibleModels
         | 
| 42 | 
            +
                  viewIndex = @_indexOfViewForModel(model)
         | 
| 43 | 
            +
                  if viewIndex >= 0
         | 
| 44 | 
            +
                    @_moveView(viewIndex, index) unless viewIndex is index
         | 
| 45 | 
            +
                  else
         | 
| 46 | 
            +
                    @_insertView @view.buildViewFor(model), index
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                @observer.fire "after_render"
         | 
| 49 | 
            +
                @
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              _insertView: (view, newIndex) ->
         | 
| 52 | 
            +
                view.render()
         | 
| 53 | 
            +
                $(view.el).insertBeforeChildOrAppendTo @$ul, ".neat-row:eq(#{newIndex})"
         | 
| 54 | 
            +
                @views.splice(newIndex, 0, view)
         | 
| 55 | 
            +
                @_viewAddedAt(view, newIndex)
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              _moveView: (oldIndex, newIndex) ->
         | 
| 58 | 
            +
                $el = $ @views[oldIndex].el
         | 
| 59 | 
            +
                $el.detach().insertBeforeChildOrAppendTo @$ul, ".neat-row:eq(#{newIndex})"
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                view = @views.splice(oldIndex, 1)[0]
         | 
| 62 | 
            +
                @views.splice(newIndex, 0, view)
         | 
| 63 | 
            +
                @_viewRemovedAt(view, oldIndex)
         | 
| 64 | 
            +
                @_viewAddedAt(view, newIndex)
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              _removeView: (oldIndex) ->
         | 
| 67 | 
            +
                @views[oldIndex].remove()
         | 
| 68 | 
            +
                view = @views.splice(oldIndex, 1)[0]
         | 
| 69 | 
            +
                @_viewRemovedAt(view, oldIndex)
         | 
| 70 | 
            +
             | 
| 71 | 
            +
             | 
| 72 | 
            +
             | 
| 73 | 
            +
              _viewAddedAt: (view, index) ->
         | 
| 74 | 
            +
                # do nothing
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              _viewRemovedAt: (view, index) ->
         | 
| 77 | 
            +
                # do nothing
         | 
| 78 | 
            +
             | 
| 79 | 
            +
             | 
| 80 | 
            +
             | 
| 81 | 
            +
              _visibleModels: ->
         | 
| 82 | 
            +
                @collection.toArray()
         | 
| 83 | 
            +
             | 
| 84 | 
            +
              _indexOfViewForModel: (model)->
         | 
| 85 | 
            +
                _.findIndex @views, (view)-> view.model.cid is model.cid
         | 
| 86 | 
            +
             | 
| 87 | 
            +
             | 
| 88 | 
            +
             | 
| 89 | 
            +
              _collectionHasBeenReset: ->
         | 
| 90 | 
            +
                @_render()
         | 
| 91 | 
            +
             | 
| 92 | 
            +
              _collectionHasBeenSorted: ->
         | 
| 93 | 
            +
                @_render()
         | 
| 94 | 
            +
             | 
| 95 | 
            +
              _modelHasBeenAddedToCollection: ->
         | 
| 96 | 
            +
                @_render()
         | 
| 97 | 
            +
             | 
| 98 | 
            +
              _modelHasBeenRemovedFromCollection: ->
         | 
| 99 | 
            +
                @_render()
         | 
| 100 | 
            +
             | 
| 101 | 
            +
              _modelHasBeenChanged: (model) ->
         | 
| 102 | 
            +
                # do nothing
         | 
| @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            class window.Neat.Renderer.InfiniteReveal extends window.Neat.Renderer.Basic
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              constructor: (@view, @collection, @options) ->
         | 
| 4 | 
            +
                super
         | 
| 5 | 
            +
                @scrollHandler = new Neat.ScrollHandler()
         | 
| 6 | 
            +
                @scrollHandler.on "scroll", _.bind(@_windowHasBeenScrolled, @)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                @sensitivity = @options.sensitivity ? 5
         | 
| 9 | 
            +
                @pageSize = @options.pageSize ? 50
         | 
| 10 | 
            +
             | 
| 11 | 
            +
             | 
| 12 | 
            +
             | 
| 13 | 
            +
              _render: ->
         | 
| 14 | 
            +
                @_setMaxItems @pageSize
         | 
| 15 | 
            +
                super
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              _visibleModels: ->
         | 
| 18 | 
            +
                @collection.models[0...@maxItems]
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              _loadMore: ->
         | 
| 21 | 
            +
                Neat.logger.log "[Neat.Renderer.InfiniteReveal] loading..."
         | 
| 22 | 
            +
                @_setMaxItems @maxItems + @pageSize
         | 
| 23 | 
            +
                @_renderVisibleModels()
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              _thereIsMore: ->
         | 
| 26 | 
            +
                @collection.length > @maxItems
         | 
| 27 | 
            +
             | 
| 28 | 
            +
             | 
| 29 | 
            +
             | 
| 30 | 
            +
              _setMaxItems: (value) ->
         | 
| 31 | 
            +
                @maxItems = Math.min value, @collection.length
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              _windowHasBeenScrolled: (e) ->
         | 
| 34 | 
            +
                return unless @_thereIsMore()
         | 
| 35 | 
            +
                return unless Math.abs(e.distanceFromBottom) <= @sensitivity
         | 
| 36 | 
            +
                return unless @view.$el.is(':visible')
         | 
| 37 | 
            +
                @_loadMore()
         | 
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            class window.Neat.Renderer.Paginated extends window.Neat.Renderer.Basic
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              constructor: (@view, @collection, @options) ->
         | 
| 4 | 
            +
                super
         | 
| 5 | 
            +
                @paginator = new window.Lail.PaginatedList [],
         | 
| 6 | 
            +
                  page_size: if window.Neat.forPrint then Infinity else @options.pageSize
         | 
| 7 | 
            +
                  always_show: false
         | 
| 8 | 
            +
                @paginator.onPageChange _.bind(@_renderPage, @)
         | 
| 9 | 
            +
             | 
| 10 | 
            +
             | 
| 11 | 
            +
             | 
| 12 | 
            +
              _render: ->
         | 
| 13 | 
            +
                @paginator.renderPaginationIn(@view.$el.find('.pagination'))
         | 
| 14 | 
            +
                @_repaginate()
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              _repaginate: ->
         | 
| 17 | 
            +
                @_rerenderPage(1)
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              _rerenderPage: (page)->
         | 
| 20 | 
            +
                page = @paginator.getCurrentPage() unless _.isNumber(page)
         | 
| 21 | 
            +
                items = @collection.toArray()
         | 
| 22 | 
            +
                @paginator.init items, page
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              _renderPage: ->
         | 
| 25 | 
            +
                @view.$el.find('.extended-pagination').html(@paginator.renderExtendedPagination())
         | 
| 26 | 
            +
                @_renderVisibleModels()
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              _visibleModels: ->
         | 
| 29 | 
            +
                @paginator.getCurrentSet()
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              _collectionHasBeenSorted: ->
         | 
| 32 | 
            +
                @_repaginate()
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              _modelHasBeenAddedToCollection: ->
         | 
| 35 | 
            +
                @_rerenderPage()
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              _modelHasBeenRemovedFromCollection: ->
         | 
| 38 | 
            +
                @_rerenderPage()
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              _modelHasBeenChanged: ->
         | 
| 41 | 
            +
                @_rerenderPage()
         | 
| @@ -8,12 +8,16 @@ | |
| 8 8 | 
             
            //= require ./neat/lib/inflect
         | 
| 9 9 | 
             
            //= require ./neat/lib/observer
         | 
| 10 10 | 
             
            //= require ./neat/lib/paginated_list
         | 
| 11 | 
            -
            //= require ./neat/lib/delayed_action
         | 
| 12 11 | 
             
            //= require ./neat/lib/jquery_extensions
         | 
| 12 | 
            +
            //= require ./neat/lib/scroll_handler
         | 
| 13 | 
            +
            //= require ./neat/renderer/basic
         | 
| 14 | 
            +
            //= require ./neat/renderer/paginated
         | 
| 15 | 
            +
            //= require ./neat/renderer/infinite_reveal
         | 
| 13 16 | 
             
            //= require ./neat/collection_editor
         | 
| 14 17 | 
             
            //= require ./neat/model_editor
         | 
| 15 18 |  | 
| 16 19 | 
             
            window.Neat = window.Neat || {}
         | 
| 20 | 
            +
            window.Neat.Renderer = window.Neat.Renderer || {}
         | 
| 17 21 | 
             
            window.Neat.debug = true;
         | 
| 18 22 | 
             
            window.Neat.logger = {
         | 
| 19 23 | 
             
              log: function() {
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: neat-rails
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.5.0
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 6 | 
             
            platform: ruby
         | 
| 7 7 | 
             
            authors:
         | 
| @@ -10,7 +10,7 @@ authors: | |
| 10 10 | 
             
            autorequire: 
         | 
| 11 11 | 
             
            bindir: bin
         | 
| 12 12 | 
             
            cert_chain: []
         | 
| 13 | 
            -
            date: 2016- | 
| 13 | 
            +
            date: 2016-04-05 00:00:00.000000000 Z
         | 
| 14 14 | 
             
            dependencies:
         | 
| 15 15 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 16 16 | 
             
              name: rake
         | 
| @@ -47,12 +47,15 @@ files: | |
| 47 47 | 
             
            - neat-rails.gemspec
         | 
| 48 48 | 
             
            - vendor/assets/javascripts/neat.js
         | 
| 49 49 | 
             
            - vendor/assets/javascripts/neat/collection_editor.coffee
         | 
| 50 | 
            -
            - vendor/assets/javascripts/neat/lib/delayed_action.js
         | 
| 51 50 | 
             
            - vendor/assets/javascripts/neat/lib/inflect.js
         | 
| 52 51 | 
             
            - vendor/assets/javascripts/neat/lib/jquery_extensions.coffee
         | 
| 53 52 | 
             
            - vendor/assets/javascripts/neat/lib/observer.js
         | 
| 54 53 | 
             
            - vendor/assets/javascripts/neat/lib/paginated_list.js
         | 
| 54 | 
            +
            - vendor/assets/javascripts/neat/lib/scroll_handler.coffee
         | 
| 55 55 | 
             
            - vendor/assets/javascripts/neat/model_editor.coffee
         | 
| 56 | 
            +
            - vendor/assets/javascripts/neat/renderer/basic.coffee
         | 
| 57 | 
            +
            - vendor/assets/javascripts/neat/renderer/infinite_reveal.coffee
         | 
| 58 | 
            +
            - vendor/assets/javascripts/neat/renderer/paginated.coffee
         | 
| 56 59 | 
             
            homepage: ''
         | 
| 57 60 | 
             
            licenses: []
         | 
| 58 61 | 
             
            post_install_message: 
         | 
| @@ -67,7 +70,7 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 67 70 | 
             
                  version: '0'
         | 
| 68 71 | 
             
                  segments:
         | 
| 69 72 | 
             
                  - 0
         | 
| 70 | 
            -
                  hash:  | 
| 73 | 
            +
                  hash: -2190152860109017268
         | 
| 71 74 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 72 75 | 
             
              none: false
         | 
| 73 76 | 
             
              requirements:
         | 
| @@ -76,7 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 76 79 | 
             
                  version: '0'
         | 
| 77 80 | 
             
                  segments:
         | 
| 78 81 | 
             
                  - 0
         | 
| 79 | 
            -
                  hash:  | 
| 82 | 
            +
                  hash: -2190152860109017268
         | 
| 80 83 | 
             
            requirements: []
         | 
| 81 84 | 
             
            rubyforge_project: 
         | 
| 82 85 | 
             
            rubygems_version: 1.8.23.2
         | 
| @@ -1,49 +0,0 @@ | |
| 1 | 
            -
            var Lail; if(!Lail) Lail={};
         | 
| 2 | 
            -
            Lail.DelayedAction = function(callback, options) {
         | 
| 3 | 
            -
              // !todo: paste John Resig's code
         | 
| 4 | 
            -
             | 
| 5 | 
            -
              options = options || {};
         | 
| 6 | 
            -
              var self           = this,
         | 
| 7 | 
            -
                  delay          = options.delay || 1000,
         | 
| 8 | 
            -
                  steps          = options.steps || 10,
         | 
| 9 | 
            -
                  intervalPeriod = delay / steps,
         | 
| 10 | 
            -
                  counter        = 0,
         | 
| 11 | 
            -
                  _params,
         | 
| 12 | 
            -
                  _interval;
         | 
| 13 | 
            -
             | 
| 14 | 
            -
              this.trigger = function(params) {
         | 
| 15 | 
            -
                _params = params;
         | 
| 16 | 
            -
                restartCountdown();
         | 
| 17 | 
            -
              }
         | 
| 18 | 
            -
             | 
| 19 | 
            -
              function restartCountdown() {
         | 
| 20 | 
            -
                counter = steps;
         | 
| 21 | 
            -
                if(!_interval) {
         | 
| 22 | 
            -
                  _interval = setInterval(countdown, intervalPeriod);
         | 
| 23 | 
            -
                }
         | 
| 24 | 
            -
              }
         | 
| 25 | 
            -
             | 
| 26 | 
            -
              function countdown() {
         | 
| 27 | 
            -
                if(counter > 0) {
         | 
| 28 | 
            -
                  counter = counter - 1;
         | 
| 29 | 
            -
                } else {
         | 
| 30 | 
            -
                  stopCountdown()
         | 
| 31 | 
            -
                  fireCallback();
         | 
| 32 | 
            -
                }
         | 
| 33 | 
            -
              }
         | 
| 34 | 
            -
             | 
| 35 | 
            -
              function stopCountdown() {
         | 
| 36 | 
            -
                if(_interval) {
         | 
| 37 | 
            -
                  clearInterval(_interval);
         | 
| 38 | 
            -
                  _interval = null;
         | 
| 39 | 
            -
                }
         | 
| 40 | 
            -
              }
         | 
| 41 | 
            -
             | 
| 42 | 
            -
              function fireCallback() {
         | 
| 43 | 
            -
                try {
         | 
| 44 | 
            -
                  callback(_params);
         | 
| 45 | 
            -
                } catch(e) {
         | 
| 46 | 
            -
                  App.debug(e);
         | 
| 47 | 
            -
                }
         | 
| 48 | 
            -
              }
         | 
| 49 | 
            -
            }
         |