Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: paukul/chosen-rails
base: master
...
head fork: waymondo/chosen-rails
compare: master
Checking mergeability… Don't worry, you can still create the pull request.
  • 9 commits
  • 6 files changed
  • 0 commit comments
  • 2 contributors
View
2  README.md
@@ -30,7 +30,7 @@ Add to your `app/assets/stylesheets/application.css`
*= require chosen
-## Gem maintainance
+## Gem maintenance
Maintain `chosen-rails` gem with `Rake` commands.
View
2  lib/chosen-rails/source_file.rb
@@ -6,7 +6,7 @@ class SourceFile < Thor
desc "fetch source files", "fetch source files from GitHub"
def fetch
self.destination_root = "vendor/assets"
- remote = "https://github.com/harvesthq/chosen"
+ remote = "https://github.com/koenpunt/chosen"
get "#{remote}/raw/master/chosen/chosen-sprite.png", "images/chosen-sprite.png"
get "#{remote}/raw/master/chosen/chosen.css", "stylesheets/chosen.css"
get "#{remote}/raw/master/coffee/lib/abstract-chosen.coffee", "javascripts/lib/abstract-chosen.coffee"
View
179 vendor/assets/javascripts/chosen.jquery.coffee
@@ -4,13 +4,18 @@ Copyright (c) 2011 by Harvest
###
root = this
$ = jQuery
+isIE6or7 = ->
+ msVersion = navigator.userAgent.match(/MSIE ([0-9]{1,}[\.0-9]{0,})/)
+ msie = !!msVersion
+ msie && parseFloat(msVersion[1]) < 8
$.fn.extend({
chosen: (options) ->
# Do no harm and return as soon as possible for unsupported browsers, namely IE6 and IE7
- return this if $.browser.msie and ($.browser.version is "6.0" or $.browser.version is "7.0")
- $(this).each((input_field) ->
- new Chosen(this, options) unless ($ this).hasClass "chzn-done"
+ return this if isIE6or7()
+ this.each((input_field) ->
+ $this = $ this
+ $this.data('chosen', new Chosen(this, options)) unless $this.hasClass "chzn-done"
)
})
@@ -18,25 +23,24 @@ class Chosen extends AbstractChosen
setup: ->
@form_field_jq = $ @form_field
+ @current_value = @form_field_jq.val()
@is_rtl = @form_field_jq.hasClass "chzn-rtl"
finish_setup: ->
@form_field_jq.addClass "chzn-done"
set_up_html: ->
- @container_id = if @form_field.id.length then @form_field.id.replace(/(:|\.)/g, '_') else this.generate_field_id()
+ @container_id = if @form_field.id.length then @form_field.id.replace(/[^\w]/g, '_') else this.generate_field_id()
@container_id += "_chzn"
-
+
@f_width = @form_field_jq.outerWidth()
-
- @default_text = if @form_field_jq.data 'placeholder' then @form_field_jq.data 'placeholder' else @default_text_default
-
+
container_div = ($ "<div />", {
id: @container_id
class: "chzn-container#{ if @is_rtl then ' chzn-rtl' else '' }"
style: 'width: ' + (@f_width) + 'px;' #use parens around @f_width so coffeescript doesn't think + ' px' is a function parameter
})
-
+
if @is_multiple
container_div.html '<ul class="chzn-choices"><li class="search-field"><input type="text" value="' + @default_text + '" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chzn-drop" style="left:-9000px;"><ul class="chzn-results"></ul></div>'
else
@@ -46,10 +50,10 @@ class Chosen extends AbstractChosen
@container = ($ '#' + @container_id)
@container.addClass( "chzn-container-" + (if @is_multiple then "multi" else "single") )
@dropdown = @container.find('div.chzn-drop').first()
-
+
dd_top = @container.height()
dd_width = (@f_width - get_side_border_padding(@dropdown))
-
+
@dropdown.css({"width": dd_width + "px", "top": dd_top + "px"})
@search_field = @container.find('input').first()
@@ -57,7 +61,7 @@ class Chosen extends AbstractChosen
this.search_field_scale()
@search_no_results = @container.find('li.no-results').first()
-
+
if @is_multiple
@search_choices = @container.find('ul.chzn-choices').first()
@search_container = @container.find('li.search-field').first()
@@ -66,7 +70,7 @@ class Chosen extends AbstractChosen
@selected_item = @container.find('.chzn-single').first()
sf_width = dd_width - get_side_border_padding(@search_container) - get_side_border_padding(@search_field)
@search_field.css( {"width" : sf_width + "px"} )
-
+
this.results_build()
this.set_tab_index()
@form_field_jq.trigger("liszt:ready", {chosen: this})
@@ -76,7 +80,7 @@ class Chosen extends AbstractChosen
@container.mouseup (evt) => this.container_mouseup(evt)
@container.mouseenter (evt) => this.mouse_enter(evt)
@container.mouseleave (evt) => this.mouse_leave(evt)
-
+
@search_results.mouseup (evt) => this.search_results_mouseup(evt)
@search_results.mouseover (evt) => this.search_results_mouseover(evt)
@search_results.mouseout (evt) => this.search_results_mouseout(evt)
@@ -124,18 +128,18 @@ class Chosen extends AbstractChosen
@pending_destroy_click = false
container_mouseup: (evt) ->
- this.results_reset(evt) if evt.target.nodeName is "ABBR"
+ this.results_reset(evt) if evt.target.nodeName is "ABBR" and not @is_disabled
blur_test: (evt) ->
this.close_field() if not @active_field and @container.hasClass "chzn-container-active"
close_field: ->
$(document).unbind "click", @click_test_action
-
+
if not @is_multiple
@selected_item.attr "tabindex", @search_field.attr("tabindex")
@search_field.attr "tabindex", -1
-
+
@active_field = false
this.results_hide()
@@ -163,7 +167,7 @@ class Chosen extends AbstractChosen
@active_field = true
else
this.close_field()
-
+
results_build: ->
@parsing = true
@results_data = root.SelectParser.select_to_array @form_field
@@ -172,7 +176,7 @@ class Chosen extends AbstractChosen
@search_choices.find("li.search-choice").remove()
@choices = 0
else if not @is_multiple
- @selected_item.find("span").text @default_text
+ @selected_item.addClass("chzn-default").find("span").text(@default_text)
if @form_field.options.length <= @disable_search_threshold
@container.addClass "chzn-container-single-nosearch"
else
@@ -193,7 +197,7 @@ class Chosen extends AbstractChosen
this.search_field_disabled()
this.show_search_field_default()
this.search_field_scale()
-
+
@search_results.html content
@parsing = false
@@ -204,7 +208,24 @@ class Chosen extends AbstractChosen
'<li id="' + group.dom_id + '" class="group-result">' + $("<div />").text(group.label).html() + '</li>'
else
""
-
+
+ result_add_option: (option) ->
+ if not option.disabled
+ option.dom_id = @container_id + "_o_" + option.array_index
+
+ classes = if option.selected and @is_multiple then [] else ["active-result"]
+ classes.push "result-selected" if option.selected
+ classes.push "group-option" if option.group_array_index?
+
+ '<li id="' + option.dom_id + '" class="' + classes.join(' ') + '">' + option.html + '</li>'
+ else
+ ""
+
+ results_update_field: ->
+ this.result_clear_highlight()
+ @result_single_selected = null
+ this.results_build()
+
result_do_highlight: (el) ->
if el.length
this.result_clear_highlight()
@@ -215,7 +236,7 @@ class Chosen extends AbstractChosen
maxHeight = parseInt @search_results.css("maxHeight"), 10
visible_top = @search_results.scrollTop()
visible_bottom = maxHeight + visible_top
-
+
high_top = @result_highlight.position().top + @search_results.scrollTop()
high_bottom = high_top + @result_highlight.outerHeight()
@@ -223,7 +244,7 @@ class Chosen extends AbstractChosen
@search_results.scrollTop if (high_bottom - maxHeight) > 0 then (high_bottom - maxHeight) else 0
else if high_top < visible_top
@search_results.scrollTop high_top
-
+
result_clear_highlight: ->
@result_highlight.removeClass "highlighted" if @result_highlight
@result_highlight = null
@@ -233,8 +254,12 @@ class Chosen extends AbstractChosen
@selected_item.addClass "chzn-single-with-drop"
if @result_single_selected
this.result_do_highlight( @result_single_selected )
+ else if @max_selected_options <= @choices
+ @form_field_jq.trigger("liszt:maxselected", {chosen: this})
+ return false
dd_top = if @is_multiple then @container.height() else (@container.height() - 1)
+ @form_field_jq.trigger("liszt:showing_dropdown", {chosen: this})
@dropdown.css {"top": dd_top + "px", "left":0}
@results_showing = true
@@ -246,6 +271,7 @@ class Chosen extends AbstractChosen
results_hide: ->
@selected_item.removeClass "chzn-single-with-drop" unless @is_multiple
this.result_clear_highlight()
+ @form_field_jq.trigger("liszt:hiding_dropdown", {chosen: this})
@dropdown.css {"left":"-9000px"}
@results_showing = false
@@ -282,13 +308,15 @@ class Chosen extends AbstractChosen
search_results_mouseout: (evt) ->
this.result_clear_highlight() if $(evt.target).hasClass "active-result" or $(evt.target).parents('.active-result').first()
-
choices_click: (evt) ->
evt.preventDefault()
if( @active_field and not($(evt.target).hasClass "search-choice" or $(evt.target).parents('.search-choice').first) and not @results_showing )
this.results_show()
choice_build: (item) ->
+ if @is_multiple and @max_selected_options <= @choices
+ @form_field_jq.trigger("liszt:maxselected", {chosen: this})
+ return false # fire event
choice_id = @container_id + "_c_" + item.array_index
@choices += 1
@search_container.before '<li class="search-choice" id="' + choice_id + '"><span>' + item.html + '</span><a href="javascript:void(0)" class="search-choice-close" rel="' + item.array_index + '"></a></li>'
@@ -300,6 +328,8 @@ class Chosen extends AbstractChosen
if not @is_disabled
@pending_destroy_click = true
this.choice_destroy $(evt.target)
+ this.input_blur(evt)
+ @pending_destroy_click = false
else
evt.stopPropagation
@@ -312,20 +342,28 @@ class Chosen extends AbstractChosen
this.result_deselect (link.attr "rel")
link.parents('li').first().remove()
- results_reset: (evt) ->
+ results_reset: ->
@form_field.options[0].selected = true
@selected_item.find("span").text @default_text
@selected_item.addClass("chzn-default") if not @is_multiple
this.show_search_field_default()
- $(evt.target).remove();
+ this.results_reset_cleanup()
@form_field_jq.trigger "change"
this.results_hide() if @active_field
+ results_reset_cleanup: ->
+ @selected_item.find("abbr").remove()
+
result_select: (evt) ->
if @result_highlight
high = @result_highlight
+
+ if high.hasClass 'create-option'
+ this.select_create_option(@search_field.val())
+ return this.results_hide()
+
high_id = high.attr "id"
-
+
this.result_clear_highlight()
if @is_multiple
@@ -334,9 +372,9 @@ class Chosen extends AbstractChosen
@search_results.find(".result-selected").removeClass "result-selected"
@result_single_selected = high
@selected_item.removeClass("chzn-default")
-
+
high.addClass "result-selected"
-
+
position = high_id.substr(high_id.lastIndexOf("_") + 1 )
item = @results_data[position]
item.selected = true
@@ -348,12 +386,13 @@ class Chosen extends AbstractChosen
else
@selected_item.find("span").first().text item.text
this.single_deselect_control_build() if @allow_single_deselect
-
+
this.results_hide() unless evt.metaKey and @is_multiple
@search_field.val ""
- @form_field_jq.trigger "change"
+ @form_field_jq.trigger "change", {'selected': @form_field.options[item.options_index].value} if @is_multiple || @form_field_jq.val() != @current_value
+ @current_value = @form_field_jq.val()
this.search_field_scale()
result_activate: (el) ->
@@ -373,7 +412,7 @@ class Chosen extends AbstractChosen
this.result_clear_highlight()
this.winnow_results()
- @form_field_jq.trigger "change"
+ @form_field_jq.trigger "change", {deselected: @form_field.options[result_data.options_index].value}
this.search_field_scale()
single_deselect_control_build: ->
@@ -381,13 +420,17 @@ class Chosen extends AbstractChosen
winnow_results: ->
this.no_results_clear()
-
+ this.create_option_clear()
+
results = 0
searchText = if @search_field.val() is @default_text then "" else $('<div/>').text($.trim(@search_field.val())).html()
regexAnchor = if @search_contains then "" else "^"
regex = new RegExp(regexAnchor + searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i')
zregex = new RegExp(searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i')
+ eregex = new RegExp('^' + searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + '$', 'i')
+
+ exact_result = false
for option in @results_data
if not option.disabled and not option.empty
@@ -397,10 +440,14 @@ class Chosen extends AbstractChosen
found = false
result_id = option.dom_id
result = $("#" + result_id)
-
+
if regex.test option.html
found = true
results += 1
+ if eregex.test option.html
+ exact_result = true
+
+
else if option.html.indexOf(" ") >= 0 or option.html.indexOf("[") == 0
#TODO: replace this substitution of /\[\]/ with a list of characters to skip.
parts = option.html.replace(/\[|\]/g, "").split(" ")
@@ -417,7 +464,7 @@ class Chosen extends AbstractChosen
text = text.substr(0, startpos) + '<em>' + text.substr(startpos)
else
text = option.html
-
+
result.html(text)
this.result_activate result
@@ -428,7 +475,9 @@ class Chosen extends AbstractChosen
if results < 1 and searchText.length
this.no_results searchText
+ @winnow_results_set_highlight()
else
+ this.show_create_option( searchText ) if @create_option and not exact_result and @persistent_create_option and searchText.length
this.winnow_results_set_highlight()
winnow_results_clear: ->
@@ -443,19 +492,44 @@ class Chosen extends AbstractChosen
this.result_activate li
winnow_results_set_highlight: ->
- if not @result_highlight
+ # if not @result_highlight
+
+ selected_results = if not @is_multiple then @search_results.find(".result-selected.active-result") else []
+ do_high = if selected_results.length then selected_results.first() else @search_results.find(".active-result").first()
- selected_results = if not @is_multiple then @search_results.find(".result-selected.active-result") else []
- do_high = if selected_results.length then selected_results.first() else @search_results.find(".active-result").first()
+ this.result_do_highlight do_high if do_high?
- this.result_do_highlight do_high if do_high?
-
no_results: (terms) ->
no_results_html = $('<li class="no-results">' + @results_none_found + ' "<span></span>"</li>')
no_results_html.find("span").first().html(terms)
- @search_results.append no_results_html
-
+ # @search_results.append no_results_html
+
+ if @create_option #and not selected
+ @show_create_option( terms )
+ else
+ @search_results.append no_results_html
+
+ show_create_option: (terms) ->
+ create_option_html = $('<li class="create-option active-result"><a href="javascript:void(0);">' + @create_option_text + '</a>: "' + terms + '"</li>').bind "click", (evt) => this.select_create_option(terms)
+ @search_results.append create_option_html
+
+ create_option_clear: ->
+ @search_results.find(".create-option").remove()
+
+ select_create_option: (terms) ->
+ if $.isFunction(@create_option)
+ @create_option.call this, terms
+ else
+ this.select_append_option {value: terms, text: terms}
+
+ select_append_option: ( options ) ->
+ option = $('<option />', options ).attr('selected', 'selected')
+ @form_field_jq.append option
+ @form_field_jq.trigger "liszt:updated"
+ #@active_field = false
+ @search_field.trigger('focus')
+
no_results_clear: ->
@search_results.find(".no-results").remove()
@@ -473,7 +547,7 @@ class Chosen extends AbstractChosen
this.results_show()
else if @result_highlight
prev_sibs = @result_highlight.prevAll("li.active-result")
-
+
if prev_sibs.length
this.result_do_highlight prev_sibs.first()
else
@@ -486,7 +560,10 @@ class Chosen extends AbstractChosen
this.clear_backstroke()
else
@pending_backstroke = @search_container.siblings("li.search-choice").last()
- @pending_backstroke.addClass "search-choice-focus"
+ if @single_backstroke_delete
+ @keydown_backstroke()
+ else
+ @pending_backstroke.addClass "search-choice-focus"
clear_backstroke: ->
@pending_backstroke.removeClass "search-choice-focus" if @pending_backstroke
@@ -495,9 +572,9 @@ class Chosen extends AbstractChosen
keydown_checker: (evt) ->
stroke = evt.which ? evt.keyCode
this.search_field_scale()
-
+
this.clear_backstroke() if stroke != 8 and this.pending_backstroke
-
+
switch stroke
when 8
@backstroke_length = this.search_field.val().length
@@ -516,7 +593,7 @@ class Chosen extends AbstractChosen
when 40
this.keydown_arrow()
break
-
+
search_field_scale: ->
if @is_multiple
h = 0
@@ -524,10 +601,10 @@ class Chosen extends AbstractChosen
style_block = "position:absolute; left: -1000px; top: -1000px; display:none;"
styles = ['font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing']
-
+
for style in styles
style_block += style + ":" + @search_field.css(style) + ";"
-
+
div = $('<div />', { 'style' : style_block })
div.text @search_field.val()
$('body').append div
@@ -542,13 +619,13 @@ class Chosen extends AbstractChosen
dd_top = @container.height()
@dropdown.css({"top": dd_top + "px"})
-
+
generate_random_id: ->
string = "sel" + this.generate_random_char() + this.generate_random_char() + this.generate_random_char()
while $("#" + string).length > 0
string += this.generate_random_char()
string
-
+
get_side_border_padding = (elmt) ->
side_border_padding = elmt.outerWidth() - elmt.width()
View
96 vendor/assets/javascripts/chosen.proto.coffee
@@ -7,6 +7,7 @@ root = this
class Chosen extends AbstractChosen
setup: ->
+ @current_value = @form_field.value
@is_rtl = @form_field.hasClassName "chzn-rtl"
finish_setup: ->
@@ -19,10 +20,13 @@ class Chosen extends AbstractChosen
@single_temp = new Template('<a href="javascript:void(0)" class="chzn-single chzn-default"><span>#{default}</span><div><b></b></div></a><div class="chzn-drop" style="left:-9000px;"><div class="chzn-search"><input type="text" autocomplete="off" /></div><ul class="chzn-results"></ul></div>')
@multi_temp = new Template('<ul class="chzn-choices"><li class="search-field"><input type="text" value="#{default}" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chzn-drop" style="left:-9000px;"><ul class="chzn-results"></ul></div>')
@choice_temp = new Template('<li class="search-choice" id="#{id}"><span>#{choice}</span><a href="javascript:void(0)" class="search-choice-close" rel="#{position}"></a></li>')
- @no_results_temp = new Template('<li class="no-results">' + @results_none_found + ' "<span>#{terms}</span>"</li>')
+ @no_results_temp = new Template('<li class="no-results">#{text} "<span>#{terms}</span>"</li>')
+ @new_option_temp = new Template('<option value="#{value}">#{text}</option>')
+ @create_option_temp = new Template('<li class="create-option active-result"><a href="javascript:void(0);">#{text}</a>: #{terms}</li>')
+
set_up_html: ->
- @container_id = @form_field.identify().replace(/(:|\.)/g, '_') + "_chzn"
+ @container_id = @form_field.identify().replace(/[^\w]/g, '_') + "_chzn"
@f_width = if @form_field.getStyle("width") then parseInt @form_field.getStyle("width"), 10 else @form_field.getWidth()
@@ -31,8 +35,6 @@ class Chosen extends AbstractChosen
'class': "chzn-container#{ if @is_rtl then ' chzn-rtl' else '' }"
'style': 'width: ' + (@f_width) + 'px' #use parens around @f_width so coffeescript doesn't think + ' px' is a function parameter
- @default_text = if @form_field.readAttribute 'data-placeholder' then @form_field.readAttribute 'data-placeholder' else @default_text_default
-
base_template = if @is_multiple then new Element('div', container_props).update( @multi_temp.evaluate({ "default": @default_text}) ) else new Element('div', container_props).update( @single_temp.evaluate({ "default":@default_text }) )
@form_field.hide().insert({ after: base_template })
@@ -116,7 +118,7 @@ class Chosen extends AbstractChosen
@pending_destroy_click = false
container_mouseup: (evt) ->
- this.results_reset(evt) if evt.target.nodeName is "ABBR"
+ this.results_reset(evt) if evt.target.nodeName is "ABBR" and not @is_disabled
blur_test: (evt) ->
this.close_field() if not @active_field and @container.hasClassName("chzn-container-active")
@@ -164,7 +166,7 @@ class Chosen extends AbstractChosen
@search_choices.select("li.search-choice").invoke("remove")
@choices = 0
else if not @is_multiple
- @selected_item.down("span").update(@default_text)
+ @selected_item.addClassName("chzn-default").down("span").update(@default_text)
if @form_field.options.length <= @disable_search_threshold
@container.addClassName "chzn-container-single-nosearch"
else
@@ -224,8 +226,12 @@ class Chosen extends AbstractChosen
@selected_item.addClassName('chzn-single-with-drop')
if @result_single_selected
this.result_do_highlight( @result_single_selected )
+ else if @max_selected_options <= @choices
+ @form_field.fire("liszt:maxselected", {chosen: this})
+ return false
dd_top = if @is_multiple then @container.getHeight() else (@container.getHeight() - 1)
+ @form_field.fire("liszt:showing_dropdown", {chosen: this})
@dropdown.setStyle {"top": dd_top + "px", "left":0}
@results_showing = true
@@ -237,6 +243,7 @@ class Chosen extends AbstractChosen
results_hide: ->
@selected_item.removeClassName('chzn-single-with-drop') unless @is_multiple
this.result_clear_highlight()
+ @form_field.fire("liszt:hiding_dropdown", {chosen: this})
@dropdown.setStyle({"left":"-9000px"})
@results_showing = false
@@ -280,6 +287,9 @@ class Chosen extends AbstractChosen
this.results_show()
choice_build: (item) ->
+ if @is_multiple and @max_selected_options <= @choices
+ @form_field.fire("liszt:maxselected", {chosen: this})
+ return false
choice_id = @container_id + "_c_" + item.array_index
@choices += 1
@search_container.insert
@@ -305,18 +315,27 @@ class Chosen extends AbstractChosen
this.result_deselect link.readAttribute("rel")
link.up('li').remove()
- results_reset: (evt) ->
+ results_reset: ->
@form_field.options[0].selected = true
@selected_item.down("span").update(@default_text)
@selected_item.addClassName("chzn-default") if not @is_multiple
this.show_search_field_default()
- evt.target.remove()
+ this.results_reset_cleanup()
@form_field.simulate("change") if typeof Event.simulate is 'function'
this.results_hide() if @active_field
+
+ results_reset_cleanup: ->
+ deselect_trigger = @selected_item.down("abbr")
+ deselect_trigger.remove() if(deselect_trigger)
result_select: (evt) ->
if @result_highlight
high = @result_highlight
+
+ if high.hasClassName 'create-option'
+ this.select_create_option(@search_field.value)
+ return this.results_hide()
+
this.result_clear_highlight()
if @is_multiple
@@ -343,8 +362,10 @@ class Chosen extends AbstractChosen
this.results_hide() unless evt.metaKey and @is_multiple
@search_field.value = ""
-
- @form_field.simulate("change") if typeof Event.simulate is 'function'
+
+ @form_field.simulate("change") if typeof Event.simulate is 'function' && (@is_multiple || @form_field.value != @current_value)
+ @current_value = @form_field.value
+
this.search_field_scale()
result_activate: (el) ->
@@ -372,6 +393,7 @@ class Chosen extends AbstractChosen
winnow_results: ->
this.no_results_clear()
+ this.create_option_clear()
results = 0
@@ -379,6 +401,9 @@ class Chosen extends AbstractChosen
regexAnchor = if @search_contains then "" else "^"
regex = new RegExp(regexAnchor + searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i')
zregex = new RegExp(searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i')
+ eregex = new RegExp('^' + searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + '$', 'i')
+
+ exact_result = false
for option in @results_data
if not option.disabled and not option.empty
@@ -387,10 +412,15 @@ class Chosen extends AbstractChosen
else if not (@is_multiple and option.selected)
found = false
result_id = option.dom_id
+ result = $(result_id)
if regex.test option.html
found = true
results += 1
+ if eregex.test option.html
+ exact_result = true
+
+
else if option.html.indexOf(" ") >= 0 or option.html.indexOf("[") == 0
#TODO: replace this substitution of /\[\]/ with a list of characters to skip.
parts = option.html.replace(/\[|\]/g, "").split(" ")
@@ -408,9 +438,8 @@ class Chosen extends AbstractChosen
else
text = option.html
- $(result_id).update text if $(result_id).innerHTML != text
-
- this.result_activate $(result_id)
+ result.update text if result.innerHTML != text
+ this.result_activate result
$(@results_data[option.group_array_index].dom_id).setStyle({display: 'list-item'}) if option.group_array_index?
else
@@ -418,8 +447,9 @@ class Chosen extends AbstractChosen
this.result_deactivate $(result_id)
if results < 1 and searchText.length
- this.no_results(searchText)
+ this.no_results searchText
else
+ this.show_create_option( searchText ) if @create_option and not exact_result and @persistent_create_option and searchText.length
this.winnow_results_set_highlight()
winnow_results_clear: ->
@@ -442,15 +472,40 @@ class Chosen extends AbstractChosen
do_high = @search_results.down(".active-result")
this.result_do_highlight do_high if do_high?
-
+
no_results: (terms) ->
- @search_results.insert @no_results_temp.evaluate( terms: terms )
-
+ no_results_html = @no_results_temp.evaluate( terms: terms, text: @results_none_found )
+
+ @search_results.insert no_results_html
+
+ if @create_option #and not selected
+ this.show_create_option( terms )
+
+ show_create_option: (terms) ->
+ create_option_html = @create_option_temp.evaluate( terms: terms, text: @create_option_text )
+ @search_results.insert create_option_html
+ @search_results.down(".create-option").observe "click", (evt) => this.select_create_option(terms)
+
+ create_option_clear: ->
+ co = null
+ co.remove() while co = @search_results.down(".create-option")
+
+ select_create_option: ( terms ) ->
+ if Object.isFunction( @create_option )
+ @create_option.call this, terms
+ else
+ this.select_append_option( value: terms, text: terms )
+
+ select_append_option: ( options ) ->
+ option = @new_option_temp.evaluate( options )
+ @form_field.insert option
+ Event.fire @form_field, "liszt:updated"
+ this.result_select()
+
no_results_clear: ->
nr = null
nr.remove() while nr = @search_results.down(".no-results")
-
keydown_arrow: ->
actives = @search_results.select("li.active-result")
if actives.length
@@ -482,7 +537,10 @@ class Chosen extends AbstractChosen
this.clear_backstroke()
else
@pending_backstroke = @search_container.siblings("li.search-choice").last()
- @pending_backstroke.addClassName("search-choice-focus")
+ if @single_backstroke_delete
+ @keydown_backstroke()
+ else
+ @pending_backstroke.addClassName("search-choice-focus")
clear_backstroke: ->
@pending_backstroke.removeClassName("search-choice-focus") if @pending_backstroke
View
32 vendor/assets/javascripts/lib/abstract-chosen.coffee
@@ -10,7 +10,7 @@ class AbstractChosen
this.set_default_values()
@is_multiple = @form_field.multiple
- @default_text_default = if @is_multiple then "Select Some Options" else "Select an Option"
+ this.set_default_text()
this.setup()
@@ -24,14 +24,30 @@ class AbstractChosen
@activate_action = (evt) => this.activate_field(evt)
@active_field = false
@mouse_on_container = false
+ @pending_destroy_click = false
@results_showing = false
@result_highlighted = null
@result_single_selected = null
- @allow_single_deselect = if @options.allow_single_deselect? and @form_field.options[0]? and @form_field.options[0].text is "" then @options.allow_single_deselect else false
+ # @allow_single_deselect = if @options.allow_single_deselect? and @form_field.options[0]? and @form_field.options[0].text is "" then @options.allow_single_deselect else false
+ @allow_single_deselect = if @options.allow_single_deselect? then @options.allow_single_deselect else false
@disable_search_threshold = @options.disable_search_threshold || 0
@search_contains = @options.search_contains || false
@choices = 0
- @results_none_found = @options.no_results_text or "No results match"
+ @single_backstroke_delete = @options.single_backstroke_delete || false
+ @max_selected_options = @options.max_selected_options || Infinity
+ @create_option = @options.create_option || false
+ @persistent_create_option = @options.persistent_create_option || false
+
+ set_default_text: ->
+ if @form_field.getAttribute("data-placeholder")
+ @default_text = @form_field.getAttribute("data-placeholder")
+ else if @is_multiple
+ @default_text = @options.placeholder_text_multiple || @options.placeholder_text || "Select Some Options"
+ else
+ @default_text = @options.placeholder_text_single || @options.placeholder_text || "Select an Option"
+
+ @results_none_found = @form_field.getAttribute("data-no_results_text") || @options.no_results_text || "No results match"
+ @create_option_text = @form_field.getAttribute("data-create_option_text") || @options.create_option_text || "Add option"
mouse_enter: -> @mouse_on_container = true
mouse_leave: -> @mouse_on_container = false
@@ -40,7 +56,7 @@ class AbstractChosen
setTimeout (=> this.container_mousedown()), 50 unless @active_field
input_blur: (evt) ->
- if not @mouse_on_container
+ if not @mouse_on_container or @pending_destroy_click
@active_field = false
setTimeout (=> this.blur_test()), 100
@@ -58,8 +74,12 @@ class AbstractChosen
'<li id="' + option.dom_id + '" class="' + classes.join(' ') + '"'+style+'>' + option.html + '</li>'
else
""
-
+
+ append_option: (option) ->
+ this.select_append_option(option)
+
results_update_field: ->
+ this.results_reset_cleanup() if not @is_multiple
this.result_clear_highlight()
@result_single_selected = null
this.results_build()
@@ -103,7 +123,7 @@ class AbstractChosen
new_id
generate_random_char: ->
- chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ"
+ chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
rand = Math.floor(Math.random() * chars.length)
newchar = chars.substring rand, rand+1
View
29 vendor/assets/stylesheets/chosen.css.sass
@@ -17,7 +17,7 @@
-moz-box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15)
-o-box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15)
box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15)
- z-index: 999
+ z-index: 1010
/* @end
@@ -74,18 +74,20 @@
background: image-url('chosen-sprite.png') right top no-repeat
&:hover
background-position: right -11px
- div
- position: absolute
- right: 0
- top: 0
+ &.chzn-disabled .chzn-single abbr:hover
+ background-position: right top
+ .chzn-single div
+ position: absolute
+ right: 0
+ top: 0
+ display: block
+ height: 100%
+ width: 18px
+ b
+ background: image-url('chosen-sprite.png') no-repeat 0 0
display: block
+ width: 100%
height: 100%
- width: 18px
- b
- background: image-url('chosen-sprite.png') no-repeat 0 0
- display: block
- width: 100%
- height: 100%
.chzn-search
padding: 3px 4px
position: relative
@@ -213,6 +215,7 @@
position: relative
overflow-x: hidden
overflow-y: auto
+ -webkit-overflow-scrolling: touch
.chzn-container-multi .chzn-results
margin: -1px 0 0
@@ -238,6 +241,8 @@
background-image: -ms-linear-gradient(top, #3875d7 20%, #2a62bc 90%)
background-image: linear-gradient(top, #3875d7 20%, #2a62bc 90%)
color: #fff
+ a
+ color: #fff
li em
background: #feffde
font-style: normal
@@ -246,6 +251,8 @@
.no-results
background: #f4f4f4
display: list-item
+ .create-option
+ display: list-item
.group-result
cursor: default
color: #999

No commit comments for this range

Something went wrong with that request. Please try again.