diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index a69315a2d35..8d8371fd267 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -18,7 +18,7 @@ Tell us how to reproduce this issue. 3. Further steps, etc. -Additionally, please link to a working demo that shows the issue so we can attempt to reproduce. You can use [this template](https://jsfiddle.net/5v3v353z/) as a base. Alternatively, confirm that the [Chosen demo page](http://harvesthq.github.io/chosen/) shows the issue. +Additionally, please link to a working demo that shows the issue so we can attempt to reproduce. You can use [this template](https://jsfiddle.net/j7k727cp/) as a base. Alternatively, confirm that the [Chosen demo page](http://harvesthq.github.io/chosen/) shows the issue. ### Expected behavior diff --git a/.travis.yml b/.travis.yml index a1f3e2132cb..67da37df4ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,8 @@ sudo: false language: node_js node_js: - - "node" + - 6 + - node addons: apt: @@ -12,6 +13,11 @@ addons: packages: - git +matrix: + fast_finish: true + allow_failures: + - node_js: node + before_install: npm install -g grunt-cli before_script: grunt build package-npm package-bower @@ -19,4 +25,4 @@ after_success: ./publish-package.sh env: global: - secure: FHc3fAbJDydJywQ3HcFrTxqyAmmKbiAwP5Bi3qIzvXXCKNYbZb45iSjrMPFq7sHQR/evxDKl3zzBd8k6lvx0Sr77GDkmbN7HjI22fb3wu1Pi3WhmIM90/70ATs6hSZunsNEHCtQa4fDFM3NYeOeiwHFX8HQ9tVlqtjeAZngONL8= + secure: "SOYNh0YO4eLAM38FQxrg7iqytXgdjJHRkmj/1lFzGrGeuuXP6Owe/2TaMyTJXWb9nHAAtRRwQyhAUE07eKhxI6b3YNyozeRulMK4B0K8P3P1B2MslpROyvQYtZupno3dWc0tyvsQ3ucnZE25mtetH6KYcwiI+vHv6hT8HnzBnp0=" diff --git a/Gruntfile.coffee b/Gruntfile.coffee index 85c5feaf883..d33778b87a7 100644 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -1,5 +1,6 @@ module.exports = (grunt) -> require('load-grunt-tasks')(grunt) + grunt.loadNpmTasks('grunt1.0-dom-munger') # the naming convention of the package does not allow auto-discovery. grunt.initConfig pkg: grunt.file.readJSON('package.json') @@ -52,8 +53,9 @@ This file is generated by `grunt build`, do not edit it by hand. banner: '<%= minified_comments %>' jquery: options: + ie8: true mangle: - except: ['jQuery'] + reserved: ['jQuery'] files: 'public/chosen.jquery.min.js': ['public/chosen.jquery.js'] proto: @@ -95,14 +97,21 @@ This file is generated by `grunt build`, do not edit it by hand. jquery: options: vendor: [ - 'https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js' + 'public/docsupport/jquery-3.2.1.min.js' + ] + specs: 'spec/public/jquery_specs.js' + src: [ 'public/chosen.jquery.js' ] + jquery_old: + options: + vendor: [ + 'public/docsupport/jquery-1.12.4.min.js' ] specs: 'spec/public/jquery_specs.js' src: [ 'public/chosen.jquery.js' ] proto: options: vendor: [ - 'https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js' + 'public/docsupport/prototype-1.7.0.0.js' 'node_modules/simulant/dist/simulant.umd.js' ] specs: 'spec/public/proto_specs.js' @@ -111,9 +120,9 @@ This file is generated by `grunt build`, do not edit it by hand. grunt.loadTasks 'tasks' grunt.registerTask 'default', ['build'] - grunt.registerTask 'build', ['coffee:jquery', 'coffee:proto', 'sass', 'concat', 'uglify', 'postcss', 'cssmin', 'package-bower'] + grunt.registerTask 'build', ['coffee:jquery', 'coffee:proto', 'sass', 'concat', 'uglify', 'postcss', 'cssmin'] grunt.registerTask 'test', ['coffee', 'jasmine'] - grunt.registerTask 'test:jquery', ['coffee:test', 'coffee:jquery', 'jasmine:jquery'] + grunt.registerTask 'test:jquery', ['coffee:test', 'coffee:jquery', 'jasmine:jquery', 'jasmine:jquery_old'] grunt.registerTask 'test:proto', ['coffee:test', 'coffee:proto', 'jasmine:proto'] diff --git a/README.md b/README.md index 53164e7eef7..a3aa89e217b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Chosen is a library for making long, unwieldy select boxes more user friendly. -- jQuery support: 1.4+ +- jQuery support: 1.7+ - Prototype support: 1.7+ For **documentation**, usage, and examples, see: diff --git a/coffee/chosen.jquery.coffee b/coffee/chosen.jquery.coffee index da24de6a0f5..e7077679502 100644 --- a/coffee/chosen.jquery.coffee +++ b/coffee/chosen.jquery.coffee @@ -71,43 +71,43 @@ class Chosen extends AbstractChosen @form_field_jq.trigger("chosen:ready", {chosen: this}) register_observers: -> - @container.bind 'touchstart.chosen', (evt) => this.container_mousedown(evt); return - @container.bind 'touchend.chosen', (evt) => this.container_mouseup(evt); return - - @container.bind 'mousedown.chosen', (evt) => this.container_mousedown(evt); return - @container.bind 'mouseup.chosen', (evt) => this.container_mouseup(evt); return - @container.bind 'mouseenter.chosen', (evt) => this.mouse_enter(evt); return - @container.bind 'mouseleave.chosen', (evt) => this.mouse_leave(evt); return - - @search_results.bind 'mouseup.chosen', (evt) => this.search_results_mouseup(evt); return - @search_results.bind 'mouseover.chosen', (evt) => this.search_results_mouseover(evt); return - @search_results.bind 'mouseout.chosen', (evt) => this.search_results_mouseout(evt); return - @search_results.bind 'mousewheel.chosen DOMMouseScroll.chosen', (evt) => this.search_results_mousewheel(evt); return - - @search_results.bind 'touchstart.chosen', (evt) => this.search_results_touchstart(evt); return - @search_results.bind 'touchmove.chosen', (evt) => this.search_results_touchmove(evt); return - @search_results.bind 'touchend.chosen', (evt) => this.search_results_touchend(evt); return - - @form_field_jq.bind "chosen:updated.chosen", (evt) => this.results_update_field(evt); return - @form_field_jq.bind "chosen:activate.chosen", (evt) => this.activate_field(evt); return - @form_field_jq.bind "chosen:open.chosen", (evt) => this.container_mousedown(evt); return - @form_field_jq.bind "chosen:close.chosen", (evt) => this.close_field(evt); return - - @search_field.bind 'blur.chosen', (evt) => this.input_blur(evt); return - @search_field.bind 'keyup.chosen', (evt) => this.keyup_checker(evt); return - @search_field.bind 'keydown.chosen', (evt) => this.keydown_checker(evt); return - @search_field.bind 'focus.chosen', (evt) => this.input_focus(evt); return - @search_field.bind 'cut.chosen', (evt) => this.clipboard_event_checker(evt); return - @search_field.bind 'paste.chosen', (evt) => this.clipboard_event_checker(evt); return + @container.on 'touchstart.chosen', (evt) => this.container_mousedown(evt); return + @container.on 'touchend.chosen', (evt) => this.container_mouseup(evt); return + + @container.on 'mousedown.chosen', (evt) => this.container_mousedown(evt); return + @container.on 'mouseup.chosen', (evt) => this.container_mouseup(evt); return + @container.on 'mouseenter.chosen', (evt) => this.mouse_enter(evt); return + @container.on 'mouseleave.chosen', (evt) => this.mouse_leave(evt); return + + @search_results.on 'mouseup.chosen', (evt) => this.search_results_mouseup(evt); return + @search_results.on 'mouseover.chosen', (evt) => this.search_results_mouseover(evt); return + @search_results.on 'mouseout.chosen', (evt) => this.search_results_mouseout(evt); return + @search_results.on 'mousewheel.chosen DOMMouseScroll.chosen', (evt) => this.search_results_mousewheel(evt); return + + @search_results.on 'touchstart.chosen', (evt) => this.search_results_touchstart(evt); return + @search_results.on 'touchmove.chosen', (evt) => this.search_results_touchmove(evt); return + @search_results.on 'touchend.chosen', (evt) => this.search_results_touchend(evt); return + + @form_field_jq.on "chosen:updated.chosen", (evt) => this.results_update_field(evt); return + @form_field_jq.on "chosen:activate.chosen", (evt) => this.activate_field(evt); return + @form_field_jq.on "chosen:open.chosen", (evt) => this.container_mousedown(evt); return + @form_field_jq.on "chosen:close.chosen", (evt) => this.close_field(evt); return + + @search_field.on 'blur.chosen', (evt) => this.input_blur(evt); return + @search_field.on 'keyup.chosen', (evt) => this.keyup_checker(evt); return + @search_field.on 'keydown.chosen', (evt) => this.keydown_checker(evt); return + @search_field.on 'focus.chosen', (evt) => this.input_focus(evt); return + @search_field.on 'cut.chosen', (evt) => this.clipboard_event_checker(evt); return + @search_field.on 'paste.chosen', (evt) => this.clipboard_event_checker(evt); return if @is_multiple - @search_choices.bind 'click.chosen', (evt) => this.choices_click(evt); return + @search_choices.on 'click.chosen', (evt) => this.choices_click(evt); return else - @container.bind 'click.chosen', (evt) -> evt.preventDefault(); return # gobble click of anchor + @container.on 'click.chosen', (evt) -> evt.preventDefault(); return # gobble click of anchor destroy: -> - $(@container[0].ownerDocument).unbind 'click.chosen', @click_test_action - @form_field_label.unbind 'click.chosen' if @form_field_label.length > 0 + $(@container[0].ownerDocument).off 'click.chosen', @click_test_action + @form_field_label.off 'click.chosen' if @form_field_label.length > 0 if @search_field[0].tabIndex @form_field_jq[0].tabIndex = @search_field[0].tabIndex @@ -123,12 +123,12 @@ class Chosen extends AbstractChosen @search_field[0].disabled = @is_disabled unless @is_multiple - @selected_item.unbind 'focus.chosen', this.activate_field + @selected_item.off 'focus.chosen', this.activate_field if @is_disabled this.close_field() else unless @is_multiple - @selected_item.bind 'focus.chosen', this.activate_field + @selected_item.on 'focus.chosen', this.activate_field container_mousedown: (evt) -> return if @is_disabled @@ -139,7 +139,7 @@ class Chosen extends AbstractChosen if not (evt? and ($ evt.target).hasClass "search-choice-close") if not @active_field @search_field.val "" if @is_multiple - $(@container[0].ownerDocument).bind 'click.chosen', @click_test_action + $(@container[0].ownerDocument).on 'click.chosen', @click_test_action this.results_show() else if not @is_multiple and evt and (($(evt.target)[0] == @selected_item[0]) || $(evt.target).parents("a.chosen-single").length) evt.preventDefault() @@ -161,7 +161,7 @@ class Chosen extends AbstractChosen this.close_field() if not @active_field and @container.hasClass "chosen-container-active" close_field: -> - $(@container[0].ownerDocument).unbind "click.chosen", @click_test_action + $(@container[0].ownerDocument).off "click.chosen", @click_test_action @active_field = false this.results_hide() @@ -198,7 +198,7 @@ class Chosen extends AbstractChosen if @is_multiple @search_choices.find("li.search-choice").remove() - else if not @is_multiple + else this.single_set_selected_text() if @disable_search or @form_field.options.length <= @disable_search_threshold and not @create_option @search_field[0].readOnly = true @@ -243,6 +243,9 @@ class Chosen extends AbstractChosen @form_field_jq.trigger("chosen:maxselected", {chosen: this}) return false + unless @is_multiple + @search_container.append @search_field + @container.addClass "chosen-with-drop" @results_showing = true @@ -259,6 +262,10 @@ class Chosen extends AbstractChosen if @results_showing this.result_clear_highlight() + unless @is_multiple + @selected_item.prepend @search_field + @search_field.focus() + @container.removeClass "chosen-with-drop" @form_field_jq.trigger("chosen:hiding_dropdown", {chosen: this}) @@ -277,7 +284,7 @@ class Chosen extends AbstractChosen @form_field_label = $("label[for='#{@form_field.id}']") #next check for a for=#{id} if @form_field_label.length > 0 - @form_field_label.bind 'click.chosen', this.label_click_handler + @form_field_label.on 'click.chosen', this.label_click_handler show_search_field_default: -> if @is_multiple and this.choices_count() < 1 and not @active_field @@ -299,7 +306,7 @@ class Chosen extends AbstractChosen this.result_do_highlight( target ) if target search_results_mouseout: (evt) -> - this.result_clear_highlight() if $(evt.target).hasClass "active-result" or $(evt.target).parents('.active-result').first() + this.result_clear_highlight() if $(evt.target).hasClass("active-result") or $(evt.target).parents('.active-result').first() choice_build: (item) -> choice = $('
  • ', { class: "search-choice" }).html("#{this.choice_label(item)}") @@ -308,7 +315,7 @@ class Chosen extends AbstractChosen choice.addClass 'search-choice-disabled' else close_link = $('', { class: 'search-choice-close', 'data-option-array-index': item.array_index }) - close_link.bind 'click.chosen', (evt) => this.choice_destroy_link_click(evt) + close_link.on 'click.chosen', (evt) => this.choice_destroy_link_click(evt) choice.append close_link @search_container.before choice @@ -370,13 +377,16 @@ class Chosen extends AbstractChosen @form_field.options[item.options_index].selected = true @selected_option_count = null + @search_field.val("") if @is_multiple this.choice_build item else this.single_set_selected_text(this.choice_label(item)) - unless @is_multiple && (!@hide_results_on_select || (evt.metaKey or evt.ctrlKey)) + if @is_multiple && (!@hide_results_on_select || (evt.metaKey or evt.ctrlKey)) + this.winnow_results() + else this.results_hide() this.show_search_field_default() @@ -424,7 +434,7 @@ class Chosen extends AbstractChosen @search_field.val() get_search_text: -> - this.escape_html $.trim(this.get_search_field_value()) + $.trim this.get_search_field_value() escape_html: (text) -> $('
    ').text(text).html() @@ -524,9 +534,8 @@ class Chosen extends AbstractChosen width = div.width() + 25 div.remove() - container_width = @container.outerWidth() - - width = Math.min(container_width - 10, width) + if @container.is(':visible') + width = Math.min(@container.outerWidth() - 10, width) @search_field.width(width) diff --git a/coffee/chosen.proto.coffee b/coffee/chosen.proto.coffee index da94cca4b4b..60a816d5a68 100644 --- a/coffee/chosen.proto.coffee +++ b/coffee/chosen.proto.coffee @@ -7,7 +7,6 @@ class @Chosen extends AbstractChosen super() # HTML Templates - @no_results_temp = new Template(this.get_no_results_html('#{terms}')) @new_option_temp = new Template('') @create_option_temp = new Template('
  • #{text}: "#{terms}"
  • ') @@ -199,7 +198,7 @@ class @Chosen extends AbstractChosen if @is_multiple @search_choices.select("li.search-choice").invoke("remove") - else if not @is_multiple + else this.single_set_selected_text() if @disable_search or @form_field.options.length <= @disable_search_threshold and not @create_option @search_field.readOnly = true @@ -243,6 +242,9 @@ class @Chosen extends AbstractChosen @form_field.fire("chosen:maxselected", {chosen: this}) return false + unless @is_multiple + @search_container.insert @search_field + @container.addClassName "chosen-with-drop" @results_showing = true @@ -259,6 +261,10 @@ class @Chosen extends AbstractChosen if @results_showing this.result_clear_highlight() + unless @is_multiple + @selected_item.insert top: @search_field + @search_field.focus() + @container.removeClassName "chosen-with-drop" @form_field.fire("chosen:hiding_dropdown", {chosen: this}) @@ -371,13 +377,16 @@ class @Chosen extends AbstractChosen @form_field.options[item.options_index].selected = true @selected_option_count = null + @search_field.value = "" if @is_multiple this.choice_build item else this.single_set_selected_text(this.choice_label(item)) - unless @is_multiple && (!@hide_results_on_select || (evt.metaKey or evt.ctrlKey)) + if @is_multiple && (!@hide_results_on_select || (evt.metaKey or evt.ctrlKey)) + this.winnow_results() + else this.results_hide() this.show_search_field_default() @@ -424,7 +433,7 @@ class @Chosen extends AbstractChosen @search_field.value get_search_text: -> - this.escape_html this.get_search_field_value().strip() + this.get_search_field_value().strip() escape_html: (text) -> text.escapeHTML() @@ -439,7 +448,7 @@ class @Chosen extends AbstractChosen this.result_do_highlight do_high if do_high? no_results: (terms) -> - @search_results.insert @no_results_temp.evaluate( terms: terms ) + @search_results.insert this.get_no_results_html(terms) @form_field.fire("chosen:no_results", {chosen: this}) show_create_option: (terms) -> @@ -533,9 +542,8 @@ class @Chosen extends AbstractChosen width = div.measure('width') + 25 div.remove() - container_width = @container.getWidth() - - width = Math.min(container_width - 10, width) + if container_width = @container.getWidth() + width = Math.min(container_width - 10, width) @search_field.setStyle(width: width + 'px') diff --git a/coffee/lib/abstract-chosen.coffee b/coffee/lib/abstract-chosen.coffee index d39398fe383..6033eef71e0 100644 --- a/coffee/lib/abstract-chosen.coffee +++ b/coffee/lib/abstract-chosen.coffee @@ -120,7 +120,7 @@ class AbstractChosen option_el.className = classes.join(" ") option_el.style.cssText = option.style option_el.setAttribute("data-option-array-index", option.array_index) - option_el.innerHTML = option.search_text + option_el.innerHTML = option.highlighted_html or option.html option_el.title = option.title if option.title this.outerHTML(option_el) @@ -135,7 +135,7 @@ class AbstractChosen group_el = document.createElement("li") group_el.className = classes.join(" ") - group_el.innerHTML = group.search_text + group_el.innerHTML = group.highlighted_html or this.escape_html(group.label) group_el.title = group.title if group.title this.outerHTML(group_el) @@ -172,16 +172,17 @@ class AbstractChosen results = 0 exact_result = false - searchText = this.get_search_text() - escapedSearchText = searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") - regex = this.get_search_regex(escapedSearchText) - exactRegex = new RegExp("^#{escapedSearchText}$") - highlightRegex = this.get_highlight_regex(escapedSearchText) + query = this.get_search_text() + escapedQuery = query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + regex = this.get_search_regex(escapedQuery) + exactRegex = new RegExp("^#{escapedQuery}$") for option in @results_data option.search_match = false results_group = null + search_match = null + option.highlighted_html = '' if this.include_option_in_results(option) @@ -194,19 +195,23 @@ class AbstractChosen results += 1 if results_group.active_options is 0 and results_group.search_match results_group.active_options += 1 - option.search_text = if option.group then option.label else option.html + text = if option.group then option.label else option.text unless option.group and not @group_search - option.search_match = this.search_string_match(option.search_text, regex) + search_match = this.search_string_match(text, regex) + option.search_match = search_match? + results += 1 if option.search_match and not option.group exact_result = exact_result || exactRegex.test option.html if option.search_match - if searchText.length - startpos = option.search_text.search highlightRegex - text = option.search_text.substr(0, startpos + searchText.length) + '' + option.search_text.substr(startpos + searchText.length) - option.search_text = text.substr(0, startpos) + '' + text.substr(startpos) + if query.length + startpos = search_match.index + prefix = text.slice(0, startpos) + fix = text.slice(startpos, startpos + query.length) + suffix = text.slice(startpos + query.length) + option.highlighted_html = "#{this.escape_html(prefix)}#{this.escape_html(fix)}#{this.escape_html(suffix)}" results_group.group_match = true if results_group? @@ -215,36 +220,26 @@ class AbstractChosen this.result_clear_highlight() - if results < 1 and searchText.length + if results < 1 and query.length this.update_results_content "" - this.no_results searchText unless @create_option and @skip_no_results + this.no_results query unless @create_option and @skip_no_results else this.update_results_content this.results_option_build() this.winnow_results_set_highlight() - if @create_option and (results < 1 or (!exact_result and @persistent_create_option)) and searchText.length - this.show_create_option( searchText ) + if @create_option and (results < 1 or (!exact_result and @persistent_create_option)) and query.length + this.show_create_option( query ) get_search_regex: (escaped_search_string) -> - regex_anchor = if @search_contains then "" else "^" - regex_flag = if @case_sensitive_search then "" else "i" - new RegExp(regex_anchor + escaped_search_string, regex_flag) - - get_highlight_regex: (escaped_search_string) -> - regex_anchor = if @search_contains then "" else "\\b" + regex_string = if @search_contains then escaped_search_string else "(^|\\s|\\b)#{escaped_search_string}[^\\s]*" + regex_string = "^#{regex_string}" unless @enable_split_word_search or @search_contains regex_flag = if @case_sensitive_search then "" else "i" - new RegExp(regex_anchor + escaped_search_string, regex_flag) + new RegExp(regex_string, regex_flag) search_string_match: (search_string, regex) -> - if regex.test search_string - return true - else if @enable_split_word_search and (search_string.indexOf(" ") >= 0 or search_string.indexOf("[") == 0) - #TODO: replace this substitution of /\[\]/ with a list of characters to skip. - parts = search_string.replace(/\[|\]/g, "").split(" ") - if parts.length - for part in parts - if regex.test part - return true + match = regex.exec(search_string) + match.index += 1 if !@search_contains && match?[1] # make up for lack of lookbehind operator in regex + match choices_count: -> return @selected_option_count if @selected_option_count? @@ -351,12 +346,12 @@ class AbstractChosen get_single_html: -> """ + #{@default_text}
    @@ -377,7 +372,7 @@ class AbstractChosen get_no_results_html: (terms) -> """
  • - #{@results_none_found} #{terms} + #{@results_none_found} #{this.escape_html(terms)}
  • """ diff --git a/coffee/lib/select-parser.coffee b/coffee/lib/select-parser.coffee index 3cd0637b2d0..86258e3b77a 100644 --- a/coffee/lib/select-parser.coffee +++ b/coffee/lib/select-parser.coffee @@ -15,7 +15,7 @@ class SelectParser @parsed.push array_index: group_position group: true - label: this.escapeExpression(group.label) + label: group.label title: group.title if group.title children: 0 disabled: group.disabled, @@ -47,21 +47,6 @@ class SelectParser empty: true @options_index += 1 - escapeExpression: (text) -> - if not text? or text is false - return "" - unless /[\&\<\>\"\'\`]/.test(text) - return text - map = - "<": "<" - ">": ">" - '"': """ - "'": "'" - "`": "`" - unsafe_chars = /&(?!\w+;)|[\<\>\"\'\`]/g - text.replace unsafe_chars, (chr) -> - map[chr] || "&" - SelectParser.select_to_array = (select) -> parser = new SelectParser() parser.add_node( child ) for child in select.childNodes diff --git a/package.json b/package.json index 30ca5606338..b27b9e2397f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "author": "harvest", "name": "chosen", - "version": "1.7.0", + "version": "1.8.3", "description": "Chosen is a JavaScript plugin that makes select boxes user-friendly. It is currently available in both jQuery and Prototype flavors.", "keywords": [ "select", @@ -16,28 +16,28 @@ "url": "https://github.com/harvesthq/chosen.git" }, "engines": { - "node": ">=0.4.0" + "node": ">=4" }, "scripts": { "test": "grunt test" }, "dependencies": {}, "devDependencies": { - "autoprefixer": "^6.1.2", + "autoprefixer": "^7.1.2", "coffee-script": ">= 1.6", - "grunt": "~0.4.1", - "grunt-contrib-coffee": "~0.6.4", - "grunt-contrib-concat": "~0.1.3", - "grunt-contrib-cssmin": "~0.6.1", - "grunt-contrib-jasmine": "~1.0.3", - "grunt-contrib-uglify": "~0.2.0", - "grunt-contrib-watch": "~0.3.1", - "grunt-dom-munger": "~2.0.1", - "grunt-gh-pages": "~0.10.0", - "grunt-postcss": "^0.7.1", - "grunt-sass": "^1.1.0", - "grunt-zip": "~0.9.2", - "load-grunt-tasks": "^3.0.0", + "grunt": "~1.0", + "grunt-contrib-coffee": "~1.0", + "grunt-contrib-concat": "~1.0", + "grunt-contrib-cssmin": "~2.2", + "grunt-contrib-jasmine": "~1.1", + "grunt-contrib-uglify": "~3.0", + "grunt-contrib-watch": "~1.0", + "grunt-gh-pages": "~2.0", + "grunt-postcss": "^0.8.0", + "grunt-sass": "^2.0", + "grunt-zip": "~0.17.1", + "grunt1.0-dom-munger": "~3.4", + "load-grunt-tasks": "^3.5.2", "simulant": "^0.2.2" }, "contributors": [ @@ -71,9 +71,17 @@ "download": "https://github.com/harvesthq/chosen/releases", "docs": "https://harvesthq.github.io/chosen/" }, + "main": [ + "chosen.jquery.js", + "chosen.css" + ], "files": [ "chosen.jquery.js", + "chosen.jquery.min.js", + "chosen.proto.js", + "chosen.proto.min.js", "chosen.css", + "chosen.min.css", "chosen-sprite@2x.png", "chosen-sprite.png" ] diff --git a/public/create-example.jquery.html b/public/create-example.jquery.html index a176a2ae906..2737d3d59d6 100644 --- a/public/create-example.jquery.html +++ b/public/create-example.jquery.html @@ -1,19 +1,21 @@ - - + + + + Chosen: A jQuery Plugin by Harvest to Tame Unwieldy Select Boxes + - + + +
    -

    Chosen

    +

    Chosen (v1.8.3)

    Chosen is a jQuery plugin that makes long, unwieldy select boxes much more user-friendly.

    @@ -22,1048 +24,1048 @@

    Chosen

    Project Source Contribute

    - -

    Standard Select

    + +

    Standard Select

    Turns This - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    - Into This - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    - -

    Multiple Select

    + +

    Multiple Select

    Turns This - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    - Into This - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    - -

    <optgroup> Support

    + +

    <optgroup> Support

    Single Select with Groups - @@ -1117,7 +1119,7 @@

    <optgroup> Support

    Multiple Select with Groups - @@ -1171,12 +1173,12 @@

    <optgroup> Support

    -

    Selected and Disabled Support

    +

    Selected and Disabled Support

    Chosen automatically highlights selected options and removes disabled options.

    Single Select - @@ -1190,7 +1192,7 @@

    Selected and Disabled Support

    Multiple Select - @@ -1204,15 +1206,13 @@

    Selected and Disabled Support

    -

    Hide Search on Single Select

    +

    Hide Search on Single Select

    -

    The disable_search_threshold option can be specified to hide the search input on single selects if there are fewer than (n) options.

    - - $(".chosen-select").chosen({disable_search_threshold: 10}); - +

    The disable_search_threshold option can be specified to hide the search input on single selects if there are n or fewer options.

    +
    $(".chosen-select").chosen({disable_search_threshold: 10});

    - @@ -1227,23 +1227,21 @@

    Hide Search on Single Select

    -

    Default Text Support

    +

    Default Text Support

    Chosen automatically sets the default field text ("Choose a country...") by reading the select element's data-placeholder value. If no data-placeholder value is present, it will default to "Select an Option" or "Select Some Options" depending on whether the select is single or multiple. You can change these elements in the plugin js file as you see fit.

    - <select data-placeholder="Choose a country..." style="width:350px;" multiple class="chosen-select"> +
    <select data-placeholder="Choose a country..." multiple class="chosen-select">

    Note: on single selects, the first element is assumed to be selected by the browser. To take advantage of the default text support, you will need to include a blank option as the first element of your select list.

    - -

    No Results Text Support

    + +

    No Results Text Support

    Setting the "No results" search text is as easy as passing an option when you create Chosen:

    - - $(".chosen-select").chosen({no_results_text: "Oops, nothing found!"}); - +
     $(".chosen-select").chosen({no_results_text: "Oops, nothing found!"}); 

    Single Select - @@ -1257,7 +1255,7 @@

    No Results Text Support

    Multiple Select - @@ -1268,26 +1266,22 @@

    No Results Text Support

    -
    +
    -

    Limit Selected Options in Multiselect

    +

    Limit Selected Options in Multiselect

    -

    You can easily limit how many options can user select:

    - - $(".chosen-select").chosen({max_selected_options: 5}); - -

    If you try to select another option with limit reached chosen:maxselected event is triggered:

    - - $(".chosen-select").bind("chosen:maxselected", function () { ... }); - +

    You can easily limit how many options the user can select:

    +
    $(".chosen-select").chosen({max_selected_options: 5});
    +

    If you try to select another option with limit reached chosen:maxselected event is triggered:

    +
     $(".chosen-select").bind("chosen:maxselected", function () { ... }); 
    - -

    Allow Deselect on Single Selects

    + +

    Allow Deselect on Single Selects

    -

    When a single select box isn't a required field, you can set allow_single_deselect: true and Chosen will add a UI element for option deselection. This will only work if the first option has blank text.

    +

    When a single select box isn't a required field, you can set allow_single_deselect: true and Chosen will add a UI element for option deselection. This will only work if the first option has blank text.

    - @@ -1301,13 +1295,14 @@

    Allow Deselect on Single Selects

    -

    Right to Left Support

    +

    Right-to-Left Support

    -

    Chosen supports right to left select boxes too. just add "chosen-rtl" in addition to "chosen-select" to your select tags and you are good to go.

    -

    <select class="chosen-select chosen-rtl">

    +

    You can set right-to-left text by setting rtl: true

    +
     $(".chosen-select").chosen({rtl: true}); 
    +
    - Single right to left select - @@ -1318,8 +1313,8 @@

    Right to Left Support

    - Multiple right to left select - @@ -1331,29 +1326,31 @@

    Right to Left Support

    -

    Change / Update Events

    +

    Observing, Updating, and Destroying Chosen

    • -

      Form Field Change

      -

      When working with form fields, you often want to perform some behavior after a value has been selected or deselected. Whenever a user selects a field in Chosen, it triggers a "change" event* on the original form field. That let's you do something like this:

      -

      $("#form_field").chosen().change( … );

      +

      Observing Form Field Changes

      +

      When working with form fields, you often want to perform some behavior after a value has been selected or deselected. Whenever a user selects a field in Chosen, it triggers a "change" event on the original form field. That lets you do something like this:

      +
      $("#form_field").chosen().change( … );
    • Updating Chosen Dynamically

      If you need to update the options in your select field and want Chosen to pick up the changes, you'll need to trigger the "chosen:updated" event on the field. Chosen will re-build itself based on the updated content.

      -

      $("#form_field").trigger("chosen:updated");

      +
      $("#form_field").trigger("chosen:updated");
      +
    • +
    • +

      Destroying Chosen

      +

      To destroy Chosen and revert back to the native select:

      +
      $("#form_field").chosen("destroy");
    -

    Custom Width Support

    +

    Custom Width Support

    Using a custom width with Chosen is as easy as passing an option when you create Chosen:

    - - $(".chosen-select").chosen({width: "95%"}); - -

    +
     $(".chosen-select").chosen({width: "95%"}); 
    Single Select + +
    - -

    Setup

    + +

    Setup

    Using Chosen is easy as can be.

    1. Download the plugin and copy the chosen files to your app.
    2. -
    3. Activate the plugin on the select boxes of your choice: $(".chosen-select").chosen()
    4. -
    5. Disco.
    6. +
    7. Activate the plugin on the select boxes of your choice: $(".chosen-select").chosen()
    8. +
    9. Disco.
    -

    FAQs

    +

    FAQs

    • -

      Something doesn't work. Can you fix it?

      -

      Yes! Please report all issues using the GitHub issue tracking tool. Please include the plugin version (jQuery or Prototype), browser and OS. The more information provided, the easier it is to fix a problem.

      +

      Do you have all the available options documented somewhere?

      +

      Yes! You can find them on the options page.

      +
    • +
    • +

      Something doesn't work. Can you fix it?

      +

      Yes! Please report all issues using the GitHub issue tracking tool. Please include the plugin version (jQuery or Prototype), browser and OS. The more information provided, the easier it is to fix a problem.

    • -

      What browsers are supported?

      -

      All modern browsers are supported (Firefox, Chrome, Safari and IE9). Legacy support for IE8 is also enabled.

      +

      What browsers are supported?

      +

      All modern desktop browsers are supported (Firefox, Chrome, Safari and IE9). Legacy support for IE8 is also enabled. Chosen is disabled on iPhone, iPod Touch, and Android mobile devices (more information).

    • Didn't there used to be a Prototype version of Chosen?

      There still is!

    - -

    Credits

    + +

    Credits

    -
    + - + - + +