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,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.Components.AlertBox extends Fustrate.Components.Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              @fadeSpeed: 300
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
              @initialize: ->
         
     | 
| 
      
 5 
     | 
    
         
            +
                $('.alert-box').on 'click', '.close', (e) ->
         
     | 
| 
      
 6 
     | 
    
         
            +
                  alert_box = $(e.currentTarget).closest('.alert-box')
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  alert_box.fadeOut @constructor.fadeSpeed, alert_box.remove
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  false
         
     | 
| 
         @@ -0,0 +1,161 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.Components.Autocomplete extends Fustrate.Components.Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              @types:
         
     | 
| 
      
 3 
     | 
    
         
            +
                plain:
         
     | 
| 
      
 4 
     | 
    
         
            +
                  displayKey: 'value'
         
     | 
| 
      
 5 
     | 
    
         
            +
                  item: (object, userInput) -> "<li>#{@highlight object.value}</li>"
         
     | 
| 
      
 6 
     | 
    
         
            +
                  filter: (object, userInput) -> object.value.indexOf(userInput) >= 0
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              @initialize: ->
         
     | 
| 
      
 9 
     | 
    
         
            +
                # Override the default sort
         
     | 
| 
      
 10 
     | 
    
         
            +
                Awesomplete.SORT_BYLENGTH = ->
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              constructor: (@input, types) ->
         
     | 
| 
      
 13 
     | 
    
         
            +
                if $.isArray types
         
     | 
| 
      
 14 
     | 
    
         
            +
                  types = {
         
     | 
| 
      
 15 
     | 
    
         
            +
                    plain:
         
     | 
| 
      
 16 
     | 
    
         
            +
                      list: types.map (value) -> { value: value }
         
     | 
| 
      
 17 
     | 
    
         
            +
                  }
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                @sources = for own type, options of types
         
     | 
| 
      
 20 
     | 
    
         
            +
                  $.extend({}, @constructor.types[type], options)
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                @sources = [@sources] if $.isPlainObject @sources
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                existing = @input.data('awesomplete')
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                if existing
         
     | 
| 
      
 27 
     | 
    
         
            +
                  existing.sources = @sources
         
     | 
| 
      
 28 
     | 
    
         
            +
                  return
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                @awesomplete = new Awesomplete(
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @input[0]
         
     | 
| 
      
 32 
     | 
    
         
            +
                  minChars: 0
         
     | 
| 
      
 33 
     | 
    
         
            +
                  maxItems: 25
         
     | 
| 
      
 34 
     | 
    
         
            +
                  filter: -> true
         
     | 
| 
      
 35 
     | 
    
         
            +
                  item: (option, userInput) -> option # Items are pre-rendered
         
     | 
| 
      
 36 
     | 
    
         
            +
                )
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                @input
         
     | 
| 
      
 39 
     | 
    
         
            +
                  .data 'awesomplete', @
         
     | 
| 
      
 40 
     | 
    
         
            +
                  .on 'awesomplete-highlight', @onHighlight
         
     | 
| 
      
 41 
     | 
    
         
            +
                  .on 'awesomplete-select', @onSelect
         
     | 
| 
      
 42 
     | 
    
         
            +
                  .on 'keyup', @constructor.debounce(@onKeyup)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  .on 'focus', @onFocus
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              blanked: =>
         
     | 
| 
      
 46 
     | 
    
         
            +
                return unless @input.val().trim() == ''
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                @awesomplete.close()
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                $("~ input:hidden##{@input.attr('id')}_id", @awesomplete.container)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  .val null
         
     | 
| 
      
 52 
     | 
    
         
            +
                $("~ input:hidden##{@input.attr('id')}_type", @awesomplete.container)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  .val null
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                @input.trigger 'blanked.autocomplete'
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              onFocus: =>
         
     | 
| 
      
 58 
     | 
    
         
            +
                @items = []
         
     | 
| 
      
 59 
     | 
    
         
            +
                @value = @input.val().trim() ? ''
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                for source in @sources when source.list?.length
         
     | 
| 
      
 62 
     | 
    
         
            +
                  for datum in source.list when source.filter(datum, @value)
         
     | 
| 
      
 63 
     | 
    
         
            +
                    @items.push @createListItem(datum, source)
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                @awesomplete.list = @items
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              onHighlight: =>
         
     | 
| 
      
 68 
     | 
    
         
            +
                item = $('+ ul li[aria-selected="true"]', @input)
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                return unless item[0]
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                item[0].scrollIntoView false
         
     | 
| 
      
 73 
     | 
    
         
            +
                @replace item.data('datum')._displayValue
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
              onSelect: (e) =>
         
     | 
| 
      
 76 
     | 
    
         
            +
                # aria-selected isn't set on click
         
     | 
| 
      
 77 
     | 
    
         
            +
                item = $(e.originalEvent.origin).closest('li')
         
     | 
| 
      
 78 
     | 
    
         
            +
                datum = item.data('datum')
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                @replace datum._displayValue
         
     | 
| 
      
 81 
     | 
    
         
            +
                @awesomplete.close()
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                $("~ input:hidden##{@input.attr('id')}_id", @awesomplete.container)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  .val datum.id
         
     | 
| 
      
 85 
     | 
    
         
            +
                $("~ input:hidden##{@input.attr('id')}_type", @awesomplete.container)
         
     | 
| 
      
 86 
     | 
    
         
            +
                  .val datum._type
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                @input.data(datum: datum).trigger('finished.autocomplete')
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                false
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
              onKeyup: (e) =>
         
     | 
| 
      
 93 
     | 
    
         
            +
                keyCode = e.which || e.keyCode
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                value = @input.val().trim()
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                return @blanked() if value == ''
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                # Ignore: Tab, Enter, Esc, Left, Up, Right, Down
         
     | 
| 
      
 100 
     | 
    
         
            +
                return if keyCode in [9, 13, 27, 37, 38, 39, 40]
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                # Don't perform the same search twice in a row
         
     | 
| 
      
 103 
     | 
    
         
            +
                return unless value != @value && value.length >= 2
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                @value = value
         
     | 
| 
      
 106 
     | 
    
         
            +
                @items = []
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                for source in @sources
         
     | 
| 
      
 109 
     | 
    
         
            +
                  if source.url?
         
     | 
| 
      
 110 
     | 
    
         
            +
                    @performSearch(source)
         
     | 
| 
      
 111 
     | 
    
         
            +
                  else if source.list?
         
     | 
| 
      
 112 
     | 
    
         
            +
                    for datum in source.list when source.filter(datum, @value)
         
     | 
| 
      
 113 
     | 
    
         
            +
                      @items.push @createListItem(datum, source)
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                    @awesomplete.list = @items
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
              performSearch: (source) =>
         
     | 
| 
      
 118 
     | 
    
         
            +
                $.get source.url(search: @value, commit: 1, format: 'json')
         
     | 
| 
      
 119 
     | 
    
         
            +
                .done (response) =>
         
     | 
| 
      
 120 
     | 
    
         
            +
                  for datum in response
         
     | 
| 
      
 121 
     | 
    
         
            +
                    @items.push @createListItem(datum, source)
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                  @awesomplete.list = @items
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
              createListItem: (datum, source) ->
         
     | 
| 
      
 126 
     | 
    
         
            +
                datum._displayValue = datum[source.displayKey]
         
     | 
| 
      
 127 
     | 
    
         
            +
                datum._type = source.type
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                $ source.item.call(@, datum, @value)
         
     | 
| 
      
 130 
     | 
    
         
            +
                  .data datum: datum
         
     | 
| 
      
 131 
     | 
    
         
            +
                  .get(0)
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
              highlight: (text) =>
         
     | 
| 
      
 134 
     | 
    
         
            +
                return '' unless text
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                text.replace RegExp("(#{@value.split(/\s+/).join('|')})", 'gi'),
         
     | 
| 
      
 137 
     | 
    
         
            +
                             '<mark>$&</mark>'
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
              replace: (text) =>
         
     | 
| 
      
 140 
     | 
    
         
            +
                @awesomplete.replace(text)
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
              @debounce: (func, milliseconds = 300, immediate = false) ->
         
     | 
| 
      
 143 
     | 
    
         
            +
                timeout = null
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                (args...) ->
         
     | 
| 
      
 146 
     | 
    
         
            +
                  delayed = =>
         
     | 
| 
      
 147 
     | 
    
         
            +
                    func.apply(@, args) unless immediate
         
     | 
| 
      
 148 
     | 
    
         
            +
                    timeout = null
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                  if timeout
         
     | 
| 
      
 151 
     | 
    
         
            +
                    clearTimeout(timeout)
         
     | 
| 
      
 152 
     | 
    
         
            +
                  else if immediate
         
     | 
| 
      
 153 
     | 
    
         
            +
                    func.apply(@, args)
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                  timeout = setTimeout delayed, milliseconds
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
              @addType: (name, func) =>
         
     | 
| 
      
 158 
     | 
    
         
            +
                @types[name] = func
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
              @addTypes: (types) ->
         
     | 
| 
      
 161 
     | 
    
         
            +
                @addType(name, func) for own name, func of types
         
     | 
| 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.Components.Disclosure extends Fustrate.Components.Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              @initialize: ->
         
     | 
| 
      
 3 
     | 
    
         
            +
                $('body').on 'click', '.disclosure-title', (event) ->
         
     | 
| 
      
 4 
     | 
    
         
            +
                  disclosure = $(event.currentTarget).closest('.disclosure')
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  isOpen = disclosure.hasClass 'open'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  disclosure
         
     | 
| 
      
 9 
     | 
    
         
            +
                    .toggleClass 'open'
         
     | 
| 
      
 10 
     | 
    
         
            +
                    .trigger "#{if isOpen then 'closed' else 'opened'}.disclosure"
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  false
         
     | 
| 
         @@ -0,0 +1,9 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.Components.DropZone extends Fustrate.Components.Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              constructor: (target, callback) ->
         
     | 
| 
      
 3 
     | 
    
         
            +
                $(target)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  .off '.drop_zone'
         
     | 
| 
      
 5 
     | 
    
         
            +
                  .on 'dragover.drop_zone dragenter.drop_zone', false
         
     | 
| 
      
 6 
     | 
    
         
            +
                  .on 'drop.drop_zone', (event) ->
         
     | 
| 
      
 7 
     | 
    
         
            +
                    callback event.originalEvent.dataTransfer.files
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                    false
         
     | 
| 
         @@ -0,0 +1,48 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.Components.Dropdown extends Fustrate.Components.Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              @locked: false
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
              @initialize: ->
         
     | 
| 
      
 5 
     | 
    
         
            +
                @body = $ 'body'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                @body.on 'click.dropdowns', '.has-dropdown', @open
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              @open: (event) =>
         
     | 
| 
      
 10 
     | 
    
         
            +
                @hide()
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                button = $ event.currentTarget
         
     | 
| 
      
 13 
     | 
    
         
            +
                dropdown = $ '+ .dropdown', button
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                @locked = true
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                if button.position().top > (@body.height() / 2)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  top = button.position().top - dropdown.outerHeight() - 2
         
     | 
| 
      
 19 
     | 
    
         
            +
                else
         
     | 
| 
      
 20 
     | 
    
         
            +
                  top = button.position().top + button.outerHeight() + 2
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                if button.position().left > (@body.width() / 2)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  left = 'inherit'
         
     | 
| 
      
 24 
     | 
    
         
            +
                  right = @body.width() - button.position().left - button.outerWidth()
         
     | 
| 
      
 25 
     | 
    
         
            +
                else
         
     | 
| 
      
 26 
     | 
    
         
            +
                  right = 'inherit'
         
     | 
| 
      
 27 
     | 
    
         
            +
                  left = button.position().left
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                @showDropdown dropdown, left: left, top: top, right: right
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                false
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              @showDropdown: (dropdown, css) ->
         
     | 
| 
      
 34 
     | 
    
         
            +
                dropdown
         
     | 
| 
      
 35 
     | 
    
         
            +
                  .addClass 'visible'
         
     | 
| 
      
 36 
     | 
    
         
            +
                  .hide()
         
     | 
| 
      
 37 
     | 
    
         
            +
                  .css css
         
     | 
| 
      
 38 
     | 
    
         
            +
                  .fadeIn 200, =>
         
     | 
| 
      
 39 
     | 
    
         
            +
                    @locked = false
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    @body.one 'click', @hide
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
              @hide: =>
         
     | 
| 
      
 44 
     | 
    
         
            +
                return if @locked
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                $('.dropdown.visible')
         
     | 
| 
      
 47 
     | 
    
         
            +
                  .removeClass 'visible'
         
     | 
| 
      
 48 
     | 
    
         
            +
                  .fadeOut 200
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.Components.Flash extends Fustrate.Components.Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              @fadeInSpeed: 500
         
     | 
| 
      
 3 
     | 
    
         
            +
              @fadeOutSpeed: 2000
         
     | 
| 
      
 4 
     | 
    
         
            +
              @displayTime: 4000
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              constructor: (message, {type, icon} = {}) ->
         
     | 
| 
      
 7 
     | 
    
         
            +
                message = "#{Fustrate.icon(icon)} #{message}" if icon
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                bar = $ "<div class=\"flash #{type ? 'info'}\"></div>"
         
     | 
| 
      
 10 
     | 
    
         
            +
                  .html message
         
     | 
| 
      
 11 
     | 
    
         
            +
                  .hide()
         
     | 
| 
      
 12 
     | 
    
         
            +
                  .prependTo $('#flashes')
         
     | 
| 
      
 13 
     | 
    
         
            +
                  .fadeIn @constructor.fadeInSpeed
         
     | 
| 
      
 14 
     | 
    
         
            +
                  .delay @constructor.displayTime
         
     | 
| 
      
 15 
     | 
    
         
            +
                  .fadeOut @constructor.fadeOutSpeed, ->
         
     | 
| 
      
 16 
     | 
    
         
            +
                    bar.remove()
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              @initialize: ->
         
     | 
| 
      
 19 
     | 
    
         
            +
                $('body').append '<div id="flashes">'
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              class @Error
         
     | 
| 
      
 22 
     | 
    
         
            +
                constructor: (message, {icon} = {}) ->
         
     | 
| 
      
 23 
     | 
    
         
            +
                  new Fustrate.Components.Flash message, type: 'error', icon: icon
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              class @Info
         
     | 
| 
      
 26 
     | 
    
         
            +
                constructor: (message, {icon} = {}) ->
         
     | 
| 
      
 27 
     | 
    
         
            +
                  new Fustrate.Components.Flash message, type: 'info', icon: icon
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              class @Success
         
     | 
| 
      
 30 
     | 
    
         
            +
                constructor: (message, {icon} = {}) ->
         
     | 
| 
      
 31 
     | 
    
         
            +
                  new Fustrate.Components.Flash message, type: 'success', icon: icon
         
     | 
| 
         @@ -0,0 +1,213 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Fustrate.Components.Modal extends Fustrate.Components.Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              @fadeSpeed: 250
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
              @settings:
         
     | 
| 
      
 5 
     | 
    
         
            +
                closeOnBackgroundClick: true
         
     | 
| 
      
 6 
     | 
    
         
            +
                distanceFromTop: 25
         
     | 
| 
      
 7 
     | 
    
         
            +
                appendTo: 'body'
         
     | 
| 
      
 8 
     | 
    
         
            +
                css:
         
     | 
| 
      
 9 
     | 
    
         
            +
                  open:
         
     | 
| 
      
 10 
     | 
    
         
            +
                    opacity: 0
         
     | 
| 
      
 11 
     | 
    
         
            +
                    visibility: 'visible'
         
     | 
| 
      
 12 
     | 
    
         
            +
                    display: 'block'
         
     | 
| 
      
 13 
     | 
    
         
            +
                  close:
         
     | 
| 
      
 14 
     | 
    
         
            +
                    opacity: 1
         
     | 
| 
      
 15 
     | 
    
         
            +
                    visibility: 'hidden'
         
     | 
| 
      
 16 
     | 
    
         
            +
                    display: 'none'
         
     | 
| 
      
 17 
     | 
    
         
            +
                _cachedHeight: undefined
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              constructor: ({title, content, size, settings}) ->
         
     | 
| 
      
 20 
     | 
    
         
            +
                @modal = @constructor.createModal size: size
         
     | 
| 
      
 21 
     | 
    
         
            +
                @settings = $.extend true, @constructor.settings, (settings ? {})
         
     | 
| 
      
 22 
     | 
    
         
            +
                @settings.previousModal = $()
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                @setTitle title
         
     | 
| 
      
 25 
     | 
    
         
            +
                @setContent content
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                @_reloadUIElements()
         
     | 
| 
      
 28 
     | 
    
         
            +
                @addEventListeners()
         
     | 
| 
      
 29 
     | 
    
         
            +
                @initialize()
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                super
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              initialize: ->
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              _reloadUIElements: =>
         
     | 
| 
      
 36 
     | 
    
         
            +
                @fields = {}
         
     | 
| 
      
 37 
     | 
    
         
            +
                @buttons = {}
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                $('[data-field]', @modal).each (index, element) =>
         
     | 
| 
      
 40 
     | 
    
         
            +
                  field = $ element
         
     | 
| 
      
 41 
     | 
    
         
            +
                  @fields[field.data('field')] = field
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                $('[data-button]', @modal).each (index, element) =>
         
     | 
| 
      
 44 
     | 
    
         
            +
                  button = $ element
         
     | 
| 
      
 45 
     | 
    
         
            +
                  @buttons[button.data('button')] = button
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
              setTitle: (title) =>
         
     | 
| 
      
 48 
     | 
    
         
            +
                $('.modal-title span', @modal).html title
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              setContent: (content) =>
         
     | 
| 
      
 51 
     | 
    
         
            +
                $('.modal-content', @modal).html content
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                @settings._cachedHeight = undefined
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                @_reloadUIElements()
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              addEventListeners: =>
         
     | 
| 
      
 58 
     | 
    
         
            +
                @modal
         
     | 
| 
      
 59 
     | 
    
         
            +
                  .off '.modal'
         
     | 
| 
      
 60 
     | 
    
         
            +
                  .on 'close.modal', @close
         
     | 
| 
      
 61 
     | 
    
         
            +
                  .on 'open.modal', @open
         
     | 
| 
      
 62 
     | 
    
         
            +
                  .on 'hide.modal', @hide
         
     | 
| 
      
 63 
     | 
    
         
            +
                  .on 'opened.modal', @focusFirstInput
         
     | 
| 
      
 64 
     | 
    
         
            +
                  .on 'click.modal', '.modal-close', @constructor.closeButtonClicked
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                # TODO: Re-enable when modals are fully converted
         
     | 
| 
      
 67 
     | 
    
         
            +
                #   .off '.modal'
         
     | 
| 
      
 68 
     | 
    
         
            +
                $(document).on 'click.modal touchstart.modal',
         
     | 
| 
      
 69 
     | 
    
         
            +
                               '.modal-overlay',
         
     | 
| 
      
 70 
     | 
    
         
            +
                               @constructor.backgroundClicked
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
              focusFirstInput: =>
         
     | 
| 
      
 73 
     | 
    
         
            +
                # Focus requires a slight physical scroll on iOS 8.4
         
     | 
| 
      
 74 
     | 
    
         
            +
                return true if /iPad|iPhone|iPod/g.test navigator.userAgent
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                $('input, select', @modal)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  .filter(':visible:not(:disabled):not([readonly])')
         
     | 
| 
      
 78 
     | 
    
         
            +
                  .first()
         
     | 
| 
      
 79 
     | 
    
         
            +
                  .focus()
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
              open: =>
         
     | 
| 
      
 82 
     | 
    
         
            +
                return if @modal.hasClass('locked') || @modal.hasClass('open')
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                @modal.addClass('locked')
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                # If there is currently a modal being shown, store it and re-open it when
         
     | 
| 
      
 87 
     | 
    
         
            +
                # this modal closes.
         
     | 
| 
      
 88 
     | 
    
         
            +
                @settings.previousModal = $('.modal.open')
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                # These events only matter when the modal is visible
         
     | 
| 
      
 91 
     | 
    
         
            +
                $('body')
         
     | 
| 
      
 92 
     | 
    
         
            +
                  .off 'keyup.modal'
         
     | 
| 
      
 93 
     | 
    
         
            +
                  .on 'keyup.modal', (e) =>
         
     | 
| 
      
 94 
     | 
    
         
            +
                    return if @modal.hasClass('locked') || e.which != 27
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                    @close()
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                @modal.trigger 'opening.modal'
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                @_cacheHeight() if typeof @settings._cachedHeight == 'undefined'
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                if @settings.previousModal.length
         
     | 
| 
      
 103 
     | 
    
         
            +
                  @settings.previousModal.trigger('hide.modal')
         
     | 
| 
      
 104 
     | 
    
         
            +
                else
         
     | 
| 
      
 105 
     | 
    
         
            +
                  # There are no open modals - show the background overlay
         
     | 
| 
      
 106 
     | 
    
         
            +
                  @constructor.toggleBackground true
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                css = @settings.css.open
         
     | 
| 
      
 109 
     | 
    
         
            +
                # css.top = parseInt @modal.css('top'), 10
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                css.top = $(window).scrollTop() - @settings._cachedHeight + 'px'
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                end_css =
         
     | 
| 
      
 114 
     | 
    
         
            +
                  top: $(window).scrollTop() + @settings.distanceFromTop + 'px',
         
     | 
| 
      
 115 
     | 
    
         
            +
                  opacity: 1
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                setTimeout (=>
         
     | 
| 
      
 118 
     | 
    
         
            +
                  @modal
         
     | 
| 
      
 119 
     | 
    
         
            +
                    .css css
         
     | 
| 
      
 120 
     | 
    
         
            +
                    .addClass('open')
         
     | 
| 
      
 121 
     | 
    
         
            +
                    .animate end_css, 250, 'linear', =>
         
     | 
| 
      
 122 
     | 
    
         
            +
                      @modal.removeClass('locked').trigger('opened.modal')
         
     | 
| 
      
 123 
     | 
    
         
            +
                ), 125
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
              close: (openPrevious = true) =>
         
     | 
| 
      
 126 
     | 
    
         
            +
                return if @modal.hasClass('locked') || !@modal.hasClass('open')
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                @modal.addClass 'locked'
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                $('body').off 'keyup.modal'
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                unless @settings.previousModal.length && openPrevious
         
     | 
| 
      
 133 
     | 
    
         
            +
                  @constructor.toggleBackground(false)
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                end_css =
         
     | 
| 
      
 136 
     | 
    
         
            +
                  top: - $(window).scrollTop() - @settings._cachedHeight + 'px',
         
     | 
| 
      
 137 
     | 
    
         
            +
                  opacity: 0
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                setTimeout (=>
         
     | 
| 
      
 140 
     | 
    
         
            +
                  @modal
         
     | 
| 
      
 141 
     | 
    
         
            +
                    .animate end_css, 250, 'linear', =>
         
     | 
| 
      
 142 
     | 
    
         
            +
                      @modal
         
     | 
| 
      
 143 
     | 
    
         
            +
                        .css @settings.css.close
         
     | 
| 
      
 144 
     | 
    
         
            +
                        .removeClass 'locked'
         
     | 
| 
      
 145 
     | 
    
         
            +
                        .trigger 'closed.modal'
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                      if openPrevious
         
     | 
| 
      
 148 
     | 
    
         
            +
                        @openPreviousModal()
         
     | 
| 
      
 149 
     | 
    
         
            +
                      else
         
     | 
| 
      
 150 
     | 
    
         
            +
                        @settings.previousModal = $()
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                    .removeClass('open')
         
     | 
| 
      
 153 
     | 
    
         
            +
                ), 125
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
              # Just hide the modal immediately and don't bother with an overlay
         
     | 
| 
      
 156 
     | 
    
         
            +
              hide: =>
         
     | 
| 
      
 157 
     | 
    
         
            +
                @modal.removeClass('open locked').css @settings.css.close
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
              openPreviousModal: =>
         
     | 
| 
      
 160 
     | 
    
         
            +
                @settings.previousModal.trigger 'open.modal'
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                @settings.previousModal = $()
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
              _cacheHeight: =>
         
     | 
| 
      
 165 
     | 
    
         
            +
                @settings._cachedHeight = @modal.show().height()
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                @modal.hide()
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
              @createModal: ({size}) ->
         
     | 
| 
      
 170 
     | 
    
         
            +
                $("""
         
     | 
| 
      
 171 
     | 
    
         
            +
                  <div class="modal #{size ? 'tiny'}">
         
     | 
| 
      
 172 
     | 
    
         
            +
                    <div class="modal-title">
         
     | 
| 
      
 173 
     | 
    
         
            +
                      <span></span>
         
     | 
| 
      
 174 
     | 
    
         
            +
                      <a href="#" class="modal-close">×</a>
         
     | 
| 
      
 175 
     | 
    
         
            +
                    </div>
         
     | 
| 
      
 176 
     | 
    
         
            +
                    <div class="modal-content"></div>
         
     | 
| 
      
 177 
     | 
    
         
            +
                  </div>""").appendTo(@settings.appendTo)
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
              @toggleBackground: (visible = true) =>
         
     | 
| 
      
 180 
     | 
    
         
            +
                @overlay = $ '<div class="modal-overlay">' unless @overlay
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
                if visible
         
     | 
| 
      
 183 
     | 
    
         
            +
                  return if @overlay.is(':visible')
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                  @overlay
         
     | 
| 
      
 186 
     | 
    
         
            +
                    .hide()
         
     | 
| 
      
 187 
     | 
    
         
            +
                    .appendTo('body')
         
     | 
| 
      
 188 
     | 
    
         
            +
                    .fadeIn @fadeSpeed
         
     | 
| 
      
 189 
     | 
    
         
            +
                else
         
     | 
| 
      
 190 
     | 
    
         
            +
                  @overlay
         
     | 
| 
      
 191 
     | 
    
         
            +
                    .fadeOut @fadeSpeed, ->
         
     | 
| 
      
 192 
     | 
    
         
            +
                      $(@).detach()
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
              @backgroundClicked: ->
         
     | 
| 
      
 195 
     | 
    
         
            +
                modal = $ '.modal.open'
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                return if !modal || modal.hasClass('locked')
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
      
 199 
     | 
    
         
            +
                # Don't continue to close if we're not supposed to
         
     | 
| 
      
 200 
     | 
    
         
            +
                return unless Fustrate.Components.Modal.settings.closeOnBackgroundClick
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                modal.trigger 'close.modal'
         
     | 
| 
      
 203 
     | 
    
         
            +
             
     | 
| 
      
 204 
     | 
    
         
            +
                false
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
              @closeButtonClicked: ->
         
     | 
| 
      
 207 
     | 
    
         
            +
                modal = $ '.modal.open'
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
                return if !modal || modal.hasClass('locked')
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
                modal.trigger 'close.modal'
         
     | 
| 
      
 212 
     | 
    
         
            +
             
     | 
| 
      
 213 
     | 
    
         
            +
                false
         
     |