fustrate-rails 0.3.3
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.
- checksums.yaml +7 -0
 - data/lib/fustrate-rails.rb +4 -0
 - data/lib/fustrate/rails/engine.rb +14 -0
 - data/lib/fustrate/rails/version.rb +6 -0
 - data/vendor/assets/javascripts/awesomplete.js +402 -0
 - data/vendor/assets/javascripts/fustrate.coffee +6 -0
 - data/vendor/assets/javascripts/fustrate/_module.coffee +134 -0
 - data/vendor/assets/javascripts/fustrate/components/_module.coffee +3 -0
 - data/vendor/assets/javascripts/fustrate/components/alert_box.coffee +10 -0
 - data/vendor/assets/javascripts/fustrate/components/autocomplete.coffee +161 -0
 - data/vendor/assets/javascripts/fustrate/components/disclosure.coffee +12 -0
 - data/vendor/assets/javascripts/fustrate/components/drop_zone.coffee +9 -0
 - data/vendor/assets/javascripts/fustrate/components/dropdown.coffee +48 -0
 - data/vendor/assets/javascripts/fustrate/components/file_picker.coffee +10 -0
 - data/vendor/assets/javascripts/fustrate/components/flash.coffee +31 -0
 - data/vendor/assets/javascripts/fustrate/components/modal.coffee +213 -0
 - data/vendor/assets/javascripts/fustrate/components/pagination.coffee +84 -0
 - data/vendor/assets/javascripts/fustrate/components/tabs.coffee +28 -0
 - data/vendor/assets/javascripts/fustrate/components/tooltip.coffee +72 -0
 - data/vendor/assets/javascripts/fustrate/generic_form.coffee +31 -0
 - data/vendor/assets/javascripts/fustrate/generic_page.coffee +40 -0
 - data/vendor/assets/javascripts/fustrate/generic_table.coffee +57 -0
 - data/vendor/assets/javascripts/fustrate/listenable.coffee +25 -0
 - data/vendor/assets/javascripts/fustrate/object.coffee +21 -0
 - data/vendor/assets/javascripts/fustrate/record.coffee +23 -0
 - data/vendor/assets/stylesheets/_fustrate.sass +7 -0
 - data/vendor/assets/stylesheets/awesomplete.sass +75 -0
 - data/vendor/assets/stylesheets/fustrate/_colors.sass +9 -0
 - data/vendor/assets/stylesheets/fustrate/_settings.sass +20 -0
 - data/vendor/assets/stylesheets/fustrate/components/_components.sass +36 -0
 - data/vendor/assets/stylesheets/fustrate/components/_functions.sass +40 -0
 - data/vendor/assets/stylesheets/fustrate/components/alerts.sass +78 -0
 - data/vendor/assets/stylesheets/fustrate/components/buttons.sass +103 -0
 - data/vendor/assets/stylesheets/fustrate/components/disclosures.sass +23 -0
 - data/vendor/assets/stylesheets/fustrate/components/dropdowns.sass +31 -0
 - data/vendor/assets/stylesheets/fustrate/components/flash.sass +33 -0
 - data/vendor/assets/stylesheets/fustrate/components/forms.sass +188 -0
 - data/vendor/assets/stylesheets/fustrate/components/grid.sass +204 -0
 - data/vendor/assets/stylesheets/fustrate/components/labels.sass +63 -0
 - data/vendor/assets/stylesheets/fustrate/components/modals.sass +119 -0
 - data/vendor/assets/stylesheets/fustrate/components/pagination.sass +57 -0
 - data/vendor/assets/stylesheets/fustrate/components/panels.sass +49 -0
 - data/vendor/assets/stylesheets/fustrate/components/popovers.sass +15 -0
 - data/vendor/assets/stylesheets/fustrate/components/tables.sass +58 -0
 - data/vendor/assets/stylesheets/fustrate/components/tabs.sass +44 -0
 - data/vendor/assets/stylesheets/fustrate/components/tooltips.sass +28 -0
 - data/vendor/assets/stylesheets/fustrate/components/typography.sass +355 -0
 - metadata +211 -0
 
| 
         @@ -0,0 +1,84 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.Components.Pagination extends Fustrate.Components.Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              constructor: ({@current_page, @total_pages, @total_entries, @per_page}) ->
         
     | 
| 
      
 3 
     | 
    
         
            +
                @base = @constructor._getPreppedPaginationURL()
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              link: (text, page, options = {}) =>
         
     | 
| 
      
 6 
     | 
    
         
            +
                Fustrate.linkTo(text, "#{@base}page=#{page}", options)
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              previousLink: =>
         
     | 
| 
      
 9 
     | 
    
         
            +
                if @current_page > 1
         
     | 
| 
      
 10 
     | 
    
         
            +
                  return "
         
     | 
| 
      
 11 
     | 
    
         
            +
                    <li class=\"previous_page\">
         
     | 
| 
      
 12 
     | 
    
         
            +
                      #{@link('← Previous', @current_page - 1, rel: 'prev')}
         
     | 
| 
      
 13 
     | 
    
         
            +
                    </li>"
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                '<li class="previous_page unavailable"><a href="#">← Previous</a></li>'
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              nextLink: =>
         
     | 
| 
      
 18 
     | 
    
         
            +
                if @current_page < @total_pages
         
     | 
| 
      
 19 
     | 
    
         
            +
                  return "
         
     | 
| 
      
 20 
     | 
    
         
            +
                    <li class=\"next_page\">
         
     | 
| 
      
 21 
     | 
    
         
            +
                      #{@link('Next →', @current_page + 1, rel: 'next')}
         
     | 
| 
      
 22 
     | 
    
         
            +
                    </li>"
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                '<li class="next_page unavailable"><a href="#">Next →</a></li>'
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              generate: =>
         
     | 
| 
      
 27 
     | 
    
         
            +
                pages = []
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                if @total_pages > 1
         
     | 
| 
      
 30 
     | 
    
         
            +
                  pages = for i in @windowedPageNumbers()
         
     | 
| 
      
 31 
     | 
    
         
            +
                    if i == @current_page
         
     | 
| 
      
 32 
     | 
    
         
            +
                      "<li class=\"current\">#{Fustrate.linkTo(i, '#')}</li>"
         
     | 
| 
      
 33 
     | 
    
         
            +
                    else if i == 'gap'
         
     | 
| 
      
 34 
     | 
    
         
            +
                      '<li class="unavailable"><span class="gap">…</span></li>'
         
     | 
| 
      
 35 
     | 
    
         
            +
                    else
         
     | 
| 
      
 36 
     | 
    
         
            +
                      "<li>#{@link i, i}</li>"
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  pages.unshift @previousLink()
         
     | 
| 
      
 39 
     | 
    
         
            +
                  pages.push @nextLink()
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                $('<ul class="pagination">').html pages.join(' ')
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
              windowedPageNumbers: =>
         
     | 
| 
      
 44 
     | 
    
         
            +
                window_from = @current_page - 4
         
     | 
| 
      
 45 
     | 
    
         
            +
                window_to = @current_page + 4
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                if window_to > @total_pages
         
     | 
| 
      
 48 
     | 
    
         
            +
                  window_from -= window_to - @total_pages
         
     | 
| 
      
 49 
     | 
    
         
            +
                  window_to = @total_pages
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                if window_from < 1
         
     | 
| 
      
 52 
     | 
    
         
            +
                  window_to += 1 - window_from
         
     | 
| 
      
 53 
     | 
    
         
            +
                  window_from = 1
         
     | 
| 
      
 54 
     | 
    
         
            +
                  window_to = @total_pages if window_to > @total_pages
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                middle = [window_from..window_to]
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                left = if 4 < middle[0] then [1, 2, 'gap'] else [1...middle[0]]
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                if @total_pages - 3 > middle.last()
         
     | 
| 
      
 61 
     | 
    
         
            +
                  right = [(@total_pages - 1)..@total_pages]
         
     | 
| 
      
 62 
     | 
    
         
            +
                  right.unshift 'gap'
         
     | 
| 
      
 63 
     | 
    
         
            +
                else if middle.last() + 1 <= @total_pages
         
     | 
| 
      
 64 
     | 
    
         
            +
                  right = [(middle.last() + 1)..@total_pages]
         
     | 
| 
      
 65 
     | 
    
         
            +
                else
         
     | 
| 
      
 66 
     | 
    
         
            +
                  right = []
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                left.concat middle, right
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
              @getCurrentPage: ->
         
     | 
| 
      
 71 
     | 
    
         
            +
                window.location.search.match(/[?&]page=(\d+)/)?[1] ? 1
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
              # Just add 'page='
         
     | 
| 
      
 74 
     | 
    
         
            +
              @_getPreppedPaginationURL: ->
         
     | 
| 
      
 75 
     | 
    
         
            +
                search = window.location.search.replace(/[?&]page=\d+/, '')
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                search = if search[0] == '?'
         
     | 
| 
      
 78 
     | 
    
         
            +
                           "#{search}&"
         
     | 
| 
      
 79 
     | 
    
         
            +
                         else if search[0] == '&'
         
     | 
| 
      
 80 
     | 
    
         
            +
                           "?#{search[1...search.length]}&"
         
     | 
| 
      
 81 
     | 
    
         
            +
                         else
         
     | 
| 
      
 82 
     | 
    
         
            +
                           '?'
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                "#{window.location.pathname}#{search}"
         
     | 
| 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.Components.Tabs extends Fustrate.Components.Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              constructor: (@tabs) ->
         
     | 
| 
      
 3 
     | 
    
         
            +
                @tabs.on 'click', 'li > a', (e) =>
         
     | 
| 
      
 4 
     | 
    
         
            +
                  @activateTab $(e.currentTarget)
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  false
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                if window.location.hash
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @activateTab $("li > a[href='#{window.location.hash}']", @tabs).first()
         
     | 
| 
      
 10 
     | 
    
         
            +
                else if $('li > a.active', @tabs).length > 0
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @activateTab $('li > a.active', @tabs).first()
         
     | 
| 
      
 12 
     | 
    
         
            +
                else
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @activateTab $('li > a', @tabs).first()
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              activateTab: (tab) =>
         
     | 
| 
      
 16 
     | 
    
         
            +
                return unless tab
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                $('.active', @tabs).removeClass 'active'
         
     | 
| 
      
 19 
     | 
    
         
            +
                tab.addClass 'active'
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                $("##{tab.attr('href').split('#')[1]}")
         
     | 
| 
      
 22 
     | 
    
         
            +
                  .addClass 'active'
         
     | 
| 
      
 23 
     | 
    
         
            +
                  .siblings()
         
     | 
| 
      
 24 
     | 
    
         
            +
                  .removeClass 'active'
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              @initialize: =>
         
     | 
| 
      
 27 
     | 
    
         
            +
                $('ul.tabs').each (index, elem) =>
         
     | 
| 
      
 28 
     | 
    
         
            +
                  new @($ elem)
         
     | 
| 
         @@ -0,0 +1,72 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.Components.Tooltip extends Fustrate.Components.Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              @fadeSpeed: 100
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
              constructor: (element, title) ->
         
     | 
| 
      
 5 
     | 
    
         
            +
                @element = $ element
         
     | 
| 
      
 6 
     | 
    
         
            +
                @active = false
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                @addEventListeners()
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                @element.attr('title', title) if title
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              addEventListeners: =>
         
     | 
| 
      
 13 
     | 
    
         
            +
                @element
         
     | 
| 
      
 14 
     | 
    
         
            +
                  .off '.tooltip'
         
     | 
| 
      
 15 
     | 
    
         
            +
                  .on 'mouseenter.tooltip', @_show
         
     | 
| 
      
 16 
     | 
    
         
            +
                  .on 'mousemove.tooltip', @_move
         
     | 
| 
      
 17 
     | 
    
         
            +
                  .on 'mouseleave.tooltip', @_hide
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              setTitle: (title) ->
         
     | 
| 
      
 20 
     | 
    
         
            +
                if @active
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @tooltip.text title
         
     | 
| 
      
 22 
     | 
    
         
            +
                else
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @element.prop('title', title)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              _move: (e) =>
         
     | 
| 
      
 26 
     | 
    
         
            +
                @tooltip.css @_tooltipPosition(e) if @active
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                false
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              _show: (e) =>
         
     | 
| 
      
 31 
     | 
    
         
            +
                return false if @active
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                title = @element.prop('title') ? ''
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                return false unless title.length > 0
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                @tooltip ?= $('<span class="tooltip">').hide()
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                @element.attr('title', '').removeAttr('title')
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                @active = true
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                @tooltip
         
     | 
| 
      
 44 
     | 
    
         
            +
                  .text title
         
     | 
| 
      
 45 
     | 
    
         
            +
                  .appendTo $('body')
         
     | 
| 
      
 46 
     | 
    
         
            +
                  .css @_tooltipPosition(e)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  .fadeIn @constructor.fadeSpeed
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                false
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              _hide: (e) =>
         
     | 
| 
      
 52 
     | 
    
         
            +
                # No use hiding something that doesn't exist.
         
     | 
| 
      
 53 
     | 
    
         
            +
                if @tooltip
         
     | 
| 
      
 54 
     | 
    
         
            +
                  @element.attr 'title', @tooltip.text()
         
     | 
| 
      
 55 
     | 
    
         
            +
                  @active = false
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  @tooltip.fadeOut @constructor.fadeSpeed, @tooltip.detach
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                false
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
              _tooltipPosition: (e) ->
         
     | 
| 
      
 62 
     | 
    
         
            +
                top: "#{e.pageY + 15}px"
         
     | 
| 
      
 63 
     | 
    
         
            +
                left: "#{e.pageX - 10}px"
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              @initialize: ->
         
     | 
| 
      
 66 
     | 
    
         
            +
                $('[data-tooltip]').each (index, elem) ->
         
     | 
| 
      
 67 
     | 
    
         
            +
                  new Fustrate.Components.Tooltip elem
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
            $.fn.extend
         
     | 
| 
      
 70 
     | 
    
         
            +
              tooltip: (options) ->
         
     | 
| 
      
 71 
     | 
    
         
            +
                @each (index, element) ->
         
     | 
| 
      
 72 
     | 
    
         
            +
                  new Fustrate.Components.Tooltip element
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #= require './generic_page'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class Fustrate.GenericForm extends Fustrate.GenericPage
         
     | 
| 
      
 4 
     | 
    
         
            +
              addEventListeners: =>
         
     | 
| 
      
 5 
     | 
    
         
            +
                super
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                @root.on 'submit', @onSubmit
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              _reloadUIElements: =>
         
     | 
| 
      
 10 
     | 
    
         
            +
                super
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                for domObject in $('[name][id]', @root)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  element = $ domObject
         
     | 
| 
      
 14 
     | 
    
         
            +
                  name = element.prop 'name'
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  if captures = name.match /\[([a-z_]+)\]$/
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @fields[captures[1]] = element
         
     | 
| 
      
 18 
     | 
    
         
            +
                  else
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @fields[name] = element
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              validate: -> true
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              onSubmit: (e) =>
         
     | 
| 
      
 24 
     | 
    
         
            +
                e.preventDefault()
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                unless @validate()
         
     | 
| 
      
 27 
     | 
    
         
            +
                  setTimeout (=> $.rails.enableFormElements(@root)), 100
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  return false
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                true
         
     | 
| 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.GenericPage
         
     | 
| 
      
 2 
     | 
    
         
            +
              constructor: (@root) ->
         
     | 
| 
      
 3 
     | 
    
         
            +
                @_reloadUIElements()
         
     | 
| 
      
 4 
     | 
    
         
            +
                @addEventListeners()
         
     | 
| 
      
 5 
     | 
    
         
            +
                @initialize()
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              addEventListeners: ->
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              # Once the interface is loaded and the event listeners are active, run any
         
     | 
| 
      
 10 
     | 
    
         
            +
              # other tasks.
         
     | 
| 
      
 11 
     | 
    
         
            +
              initialize: ->
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              _reloadUIElements: =>
         
     | 
| 
      
 14 
     | 
    
         
            +
                @fields = {}
         
     | 
| 
      
 15 
     | 
    
         
            +
                @buttons = {}
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                $('[data-field]', @root).each (index, element) =>
         
     | 
| 
      
 18 
     | 
    
         
            +
                  field = $ element
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @fields[field.data('field')] = field
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                $('[data-button]', @root).each (index, element) =>
         
     | 
| 
      
 22 
     | 
    
         
            +
                  button = $ element
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @buttons[button.data('button')] = button
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              flashSuccess: (message, {icon} = {}) ->
         
     | 
| 
      
 26 
     | 
    
         
            +
                new Fustrate.Components.Flash.Success(message, icon: icon)
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              flashError: (message, {icon} = {}) ->
         
     | 
| 
      
 29 
     | 
    
         
            +
                new Fustrate.Components.Flash.Error(message, icon: icon)
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              flashInfo: (message, {icon} = {}) ->
         
     | 
| 
      
 32 
     | 
    
         
            +
                new Fustrate.Components.Flash.Info(message, icon: icon)
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              setHeader: (text) ->
         
     | 
| 
      
 35 
     | 
    
         
            +
                $('.header > span', @root).text text
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              # Calls all methods matching /refresh.+/
         
     | 
| 
      
 38 
     | 
    
         
            +
              refresh: =>
         
     | 
| 
      
 39 
     | 
    
         
            +
                for own name, func of @
         
     | 
| 
      
 40 
     | 
    
         
            +
                  func() if name.indexOf('refresh') == 0 && name != 'refresh'
         
     | 
| 
         @@ -0,0 +1,57 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.GenericTable extends Fustrate.GenericPage
         
     | 
| 
      
 2 
     | 
    
         
            +
              @blankRow: null
         
     | 
| 
      
 3 
     | 
    
         
            +
              table: null
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              initialize: =>
         
     | 
| 
      
 6 
     | 
    
         
            +
                super
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                @reloadTable()
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              reloadTable: ->
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              sortRows: (rows, sortFunction = ->) ->
         
     | 
| 
      
 13 
     | 
    
         
            +
                sorted = ([sortFunction(row), row] for row in rows)
         
     | 
| 
      
 14 
     | 
    
         
            +
                sorted.sort (x, y) ->
         
     | 
| 
      
 15 
     | 
    
         
            +
                  if x[0] == y[0] then 0 else if x[0] > y[0] then 1 else -1
         
     | 
| 
      
 16 
     | 
    
         
            +
                sorted.map (row) -> row[1]
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              createRow: (item) =>
         
     | 
| 
      
 19 
     | 
    
         
            +
                @updateRow @constructor.blankRow.clone(), item
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              updateRow: (row, item) ->
         
     | 
| 
      
 22 
     | 
    
         
            +
                row
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              reloadRows: (rows, {sort} = { sort: null }) =>
         
     | 
| 
      
 25 
     | 
    
         
            +
                tbody = $ 'tbody', @table
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                $('tr.loading', tbody).hide()
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                if rows
         
     | 
| 
      
 30 
     | 
    
         
            +
                  $('tr:not(.no-records):not(.loading)', tbody).remove()
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  tbody.append if sort then @sortRows(rows, sort) else rows
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                @updated()
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              addRow: (row) =>
         
     | 
| 
      
 37 
     | 
    
         
            +
                $('tbody', @table).append row
         
     | 
| 
      
 38 
     | 
    
         
            +
                @updated()
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              removeRow: (row) =>
         
     | 
| 
      
 41 
     | 
    
         
            +
                row.fadeOut =>
         
     | 
| 
      
 42 
     | 
    
         
            +
                  row.remove()
         
     | 
| 
      
 43 
     | 
    
         
            +
                  @updated()
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              updated: =>
         
     | 
| 
      
 46 
     | 
    
         
            +
                $('tbody tr.no-records', @table)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  .toggle $('tbody tr:not(.no-records):not(.loading)', @table).length < 1
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              getCheckedIds: =>
         
     | 
| 
      
 50 
     | 
    
         
            +
                (item.value for item in $('td:first-child input:checked', @table))
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
              # This should be fed a response from a JSON request for a paginated
         
     | 
| 
      
 53 
     | 
    
         
            +
              # collection.
         
     | 
| 
      
 54 
     | 
    
         
            +
              updatePagination: (response) =>
         
     | 
| 
      
 55 
     | 
    
         
            +
                @pagination = new Fustrate.Components.Pagination response
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                $('.pagination', @root).replaceWith @pagination.generate()
         
     | 
| 
         @@ -0,0 +1,25 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.Listenable
         
     | 
| 
      
 2 
     | 
    
         
            +
              constructor: ->
         
     | 
| 
      
 3 
     | 
    
         
            +
                @listeners = {}
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              on: (eventNames, callback) =>
         
     | 
| 
      
 6 
     | 
    
         
            +
                for eventName in eventNames.split(' ')
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @listeners[eventName] = [] unless @listeners[eventName]
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @listeners[eventName].push callback
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                @
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              off: (eventNames) =>
         
     | 
| 
      
 13 
     | 
    
         
            +
                for eventName in eventNames.split(' ')
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @listeners[eventName] = []
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                @
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              trigger: =>
         
     | 
| 
      
 19 
     | 
    
         
            +
                [name, args...] = arguments
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                return unless name && @listeners[name]
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                event.apply(@, args) for event in @listeners[name]
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                @
         
     | 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.Object extends Fustrate.Listenable
         
     | 
| 
      
 2 
     | 
    
         
            +
              constructor: (data) ->
         
     | 
| 
      
 3 
     | 
    
         
            +
                @extractFromData data
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                super
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              # Simple extractor to assign root keys as properties in the current object.
         
     | 
| 
      
 8 
     | 
    
         
            +
              # Formats a few common attributes as dates with moment.js
         
     | 
| 
      
 9 
     | 
    
         
            +
              extractFromData: (data) =>
         
     | 
| 
      
 10 
     | 
    
         
            +
                @[key] = value for key, value of data
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                @date = moment @date if @date
         
     | 
| 
      
 13 
     | 
    
         
            +
                @created_at = moment @created_at if @created_at
         
     | 
| 
      
 14 
     | 
    
         
            +
                @updated_at = moment @updated_at if @updated_at
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              # Instantiate a new object of type klass for each item in items
         
     | 
| 
      
 17 
     | 
    
         
            +
              _createList: (items, klass, additional_attributes = {}) ->
         
     | 
| 
      
 18 
     | 
    
         
            +
                for item in items
         
     | 
| 
      
 19 
     | 
    
         
            +
                  obj = new klass(item)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  obj[key] = value for key, value of additional_attributes
         
     | 
| 
      
 21 
     | 
    
         
            +
                  obj
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.Record extends Fustrate.Object
         
     | 
| 
      
 2 
     | 
    
         
            +
              # Rails class name
         
     | 
| 
      
 3 
     | 
    
         
            +
              @class: null
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              constructor: (data) ->
         
     | 
| 
      
 6 
     | 
    
         
            +
                super
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                if typeof data is 'number' or typeof data is 'string'
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # If the parameter was a number or string, it's likely the record ID
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @id = parseInt(data, 10)
         
     | 
| 
      
 11 
     | 
    
         
            +
                else
         
     | 
| 
      
 12 
     | 
    
         
            +
                  # Otherwise we were probably given a hash of attributes
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @extractFromData data
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              reload: ->
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              save: ->
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              toObject: -> {}
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              update: (data) =>
         
     | 
| 
      
 22 
     | 
    
         
            +
                @extractFromData data
         
     | 
| 
      
 23 
     | 
    
         
            +
                @save()
         
     | 
| 
         @@ -0,0 +1,75 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /* 1795543d988d0fd9ca6237a5ac176f8e88d63990 */
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            [hidden]
         
     | 
| 
      
 4 
     | 
    
         
            +
              display: none
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            .visually-hidden
         
     | 
| 
      
 7 
     | 
    
         
            +
              position: absolute
         
     | 
| 
      
 8 
     | 
    
         
            +
              clip: rect(0, 0, 0, 0)
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            div.awesomplete
         
     | 
| 
      
 11 
     | 
    
         
            +
              display: block
         
     | 
| 
      
 12 
     | 
    
         
            +
              position: relative
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              > input
         
     | 
| 
      
 15 
     | 
    
         
            +
                display: block
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              > ul
         
     | 
| 
      
 18 
     | 
    
         
            +
                position: absolute
         
     | 
| 
      
 19 
     | 
    
         
            +
                left: 0
         
     | 
| 
      
 20 
     | 
    
         
            +
                z-index: 9
         
     | 
| 
      
 21 
     | 
    
         
            +
                min-width: 100%
         
     | 
| 
      
 22 
     | 
    
         
            +
                box-sizing: border-box
         
     | 
| 
      
 23 
     | 
    
         
            +
                list-style: none
         
     | 
| 
      
 24 
     | 
    
         
            +
                padding: 0
         
     | 
| 
      
 25 
     | 
    
         
            +
                border-radius: .3em
         
     | 
| 
      
 26 
     | 
    
         
            +
                margin: .2em 0 0
         
     | 
| 
      
 27 
     | 
    
         
            +
                background: hsla(0, 0%, 100%, .9)
         
     | 
| 
      
 28 
     | 
    
         
            +
                background: linear-gradient(to bottom right, white, hsla(0, 0%, 100%, .8))
         
     | 
| 
      
 29 
     | 
    
         
            +
                border: 1px solid rgba(0, 0, 0, .3)
         
     | 
| 
      
 30 
     | 
    
         
            +
                box-shadow: .05em .2em .6em rgba(0, 0, 0, .2)
         
     | 
| 
      
 31 
     | 
    
         
            +
                text-shadow: none
         
     | 
| 
      
 32 
     | 
    
         
            +
                max-height: 30vh
         
     | 
| 
      
 33 
     | 
    
         
            +
                overflow-x: scroll
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                &[hidden],
         
     | 
| 
      
 36 
     | 
    
         
            +
                &:empty
         
     | 
| 
      
 37 
     | 
    
         
            +
                  display: none
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                > li
         
     | 
| 
      
 40 
     | 
    
         
            +
                  position: relative
         
     | 
| 
      
 41 
     | 
    
         
            +
                  padding: .2em .5em
         
     | 
| 
      
 42 
     | 
    
         
            +
                  cursor: pointer
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  &:not(:last-child)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    border-bottom: 1px solid rgba(64, 64, 64, .3)
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  &:hover
         
     | 
| 
      
 48 
     | 
    
         
            +
                    background: hsl(200, 40%, 80%)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    color: black
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  &[aria-selected="true"]
         
     | 
| 
      
 52 
     | 
    
         
            +
                    background: hsl(205, 40%, 40%)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    color: white
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
              mark
         
     | 
| 
      
 56 
     | 
    
         
            +
                background: hsl(65, 100%, 50%)
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                li:hover &
         
     | 
| 
      
 59 
     | 
    
         
            +
                  background: hsl(68, 100%, 41%)
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                li[aria-selected="true"] &
         
     | 
| 
      
 62 
     | 
    
         
            +
                  background: hsl(86, 100%, 21%)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  color: inherit
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            @supports (transform: scale(0))
         
     | 
| 
      
 66 
     | 
    
         
            +
              div.awesomplete > ul
         
     | 
| 
      
 67 
     | 
    
         
            +
                transition: .3s cubic-bezier(.4, .2, .5, 1.4)
         
     | 
| 
      
 68 
     | 
    
         
            +
                transform-origin: 1.43em -.43em
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                &[hidden],
         
     | 
| 
      
 71 
     | 
    
         
            +
                &:empty
         
     | 
| 
      
 72 
     | 
    
         
            +
                  opacity: 0
         
     | 
| 
      
 73 
     | 
    
         
            +
                  transform: scale(0)
         
     | 
| 
      
 74 
     | 
    
         
            +
                  display: block
         
     | 
| 
      
 75 
     | 
    
         
            +
                  transition-timing-function: ease
         
     |