window.CMI or= {} window.CMI.FormComponents or= {}
class CMI.FormComponents.Select
@get: (domElement) -> domElement = $(domElement) unless domElement instanceof jQuery unless domElement.data('cmi-select') instanceof CMI.FormComponents.Select domElement.data 'cmi-select', new @(domElement) domElement.data 'cmi-select' @reset: (domElement) -> domElement = $(domElement) unless domElement instanceof jQuery @get(domElement) @open: (domElement, selectCallback = null) -> domElement = $(domElement) unless domElement instanceof jQuery @get(domElement).open(selectCallback) @close: (domElement) -> domElement = $(domElement) unless domElement instanceof jQuery @get(domElement).close() @select: (domElement, value) -> domElement = $(domElement) unless domElement instanceof jQuery @get(domElement).select(value) @destroy: (domElement) -> domElement = $(domElement) unless domElement instanceof jQuery @get(domElement).destroy() domElement.data 'cmi-select', null # --------------------------------------------- constructor: (@domElement) -> @reset() reset: -> @_prepare() destroy: -> @_unbindListeners() @_clear() open: -> return if @domElement.hasClass 'cmi-select-open' @_open = true @domElement.addClass 'cmi-select-open' @getDropdownList().addClass 'cmi-select-open' $('body').addClass 'cmi-select-list-open' $(window).on 'resize.cmiSelectOpen', $.proxy(@updateDropdownListPosition, @) @updateDropdownListPosition() close: -> return unless @domElement.hasClass 'cmi-select-open' $(window).off 'resize.cmiSelectOpen' @_open = false @domElement.removeClass 'cmi-select-open' @getDropdownList().removeClass 'cmi-select-open' $('body').removeClass 'cmi-select-list-open' CMI.FormComponents.TextField.reset(@getInput()) select: (value) -> getInput: -> @domElement.data('cmi-select-input') || $('<div></div>') getDropdownList: -> @domElement.data('cmi-select-dropdown-list') || $('<div></div>') getSelect: -> $('select', @domElement) getName: -> @getSelect().attr 'name' getDocumentHeight: -> html = document.documentElement body = document.body Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight ) getViewportHeight: -> Math.max(document.documentElement.clientHeight, window.innerHeight || 0) getViewportScrollY: -> window.pageYOffset updateDropdownListPosition: -> offset = @getInput().offset() width = @getInput().width() # reset @getDropdownList().removeClass 'cmi-select-list-scroll' @getDropdownList().css height: 'auto' top: 0 bottom: 'auto' width: "#{width}px" left: "#{offset.left}px" # set the position dropdownHeight = @getDropdownList().outerHeight(true) dropdownMarginTop = parseInt(@getDropdownList().css('margin-top')) pos = { bottom: null, top: offset.top - dropdownMarginTop } # adjust position for selected element selected = $('.cmi-select-selected', @getDropdownList()).first() selectedOffset = selected.offset().top - selected.offsetParent().offset().top pos.top = pos.top - selectedOffset # fix if top is outside viewport if pos.top < @getViewportScrollY() pos.top = @getViewportScrollY() # fix if bottom is outside viewport if pos.top + dropdownHeight > @getViewportScrollY() + @getViewportHeight() pos.bottom = @getViewportScrollY() * -1 pos.top = null if pos.top > @getViewportScrollY() # fix if top is outside viewport if pos.top == null && dropdownHeight > @getViewportHeight() pos.top = @getViewportScrollY() @getDropdownList().addClass 'cmi-select-list-scroll' # set position pos.top = if pos.top == null then 'auto' else "#{pos.top}px" pos.bottom = if pos.bottom == null then 'auto' else "#{pos.bottom}px" @getDropdownList().css pos onInputClick: -> @open() onInputFocus: -> @open() onInputBlur: (event) -> @close() setTimeout => CMI.FormComponents.TextField.reset(@getInput()) , 50 onListClick: (event) -> event.preventDefault() return unless @_open == true selected = $('option:selected', @getSelect()) selected[0].removeAttribute('selected') if selected.length > 0 target = $("option[value='#{$(event.target).data('cmi-value')}']", @getSelect()) target.attr('selected', true) @_setValues() @getSelect().trigger 'change' @close() @getInput().stop().delay(250).blur() # --------------------------------------------- # private methods # @nodoc _prepare: -> return unless @domElement instanceof jQuery return unless @domElement.length > 0 @_initializeInput() @_initializeDropdownList() @_hideSelect() @_setValues() @_bindListeners() CMI.FormComponents.TextField.reset(@getInput()) # @nodoc _clear: -> return unless @domElement instanceof jQuery return unless @domElement.length > 0 @_clearInput() @_clearDropdownList() @_showSelect() # @nodoc _initializeInput: -> input = $("<input class='cmi-input' readonly='true' />") @domElement.data 'cmi-select-input', input @domElement.prepend input # @nodoc _clearInput: -> return unless @domElement.data('cmi-select-input') instanceof jQuery @domElement.data('cmi-select-input').remove() @domElement.data 'cmi-select-input', null # @nodoc _initializeDropdownList: -> options = [] for option in $('option', @getSelect()) content = $(option).text() content = ' ' if content.length <= 0 options.push "<li data-cmi-value='#{$(option).val()}'>#{content}</li>" dropdownList = $("<div class='cmi-select-list'><ul>#{options.join('')}</ul></div>") @domElement.data 'cmi-select-dropdown-list', dropdownList $('body').append dropdownList # @nodoc _clearDropdownList: -> return unless @domElement.data('cmi-select-dropdown-list') instanceof jQuery @domElement.data('cmi-select-dropdown-list').remove() @domElement.data 'cmi-select-dropdown-list', null # @nodoc _hideSelect: -> @getSelect().addClass 'cmi-select-select-hidden' # @nodoc _showSelect: -> @getSelect().removeClass 'cmi-select-select-hidden' # @nodoc _setValues: -> selected = $('option:selected', @getSelect()) return if selected.length <= 0 content = selected.text() value = selected.val() if selected.data('cmi-input-content') && selected.data('cmi-input-content').length > 0 content = selected.data('cmi-input-content') @getInput().val content $("li", @getDropdownList()).removeClass 'cmi-select-selected' $("li[data-cmi-value='#{value}']", @getDropdownList()).addClass 'cmi-select-selected' # @nodoc _bindListeners: -> @getDropdownList().on "mousedown.cmiInput#{@getName()}", 'li', $.proxy(@onListClick, @) @getInput().on "focus.cmiInput#{@getName()}", $.proxy(@onInputFocus, @) @getInput().on "click.cmiInput#{@getName()}", $.proxy(@onInputClick, @) @getInput().on "blur.cmiInput#{@getName()}", $.proxy(@onInputBlur, @) # @nodoc _unbindListeners: -> @getDropdownList().off "mousedown.cmiInput#{@getName()}", 'li' @getInput().off "focus.cmiInput#{@getName()}" @getInput().off "blur.cmiInput#{@getName()}"