Skip to content
Snippets Groups Projects
Commit a90e469b authored by Chris Gross's avatar Chris Gross
Browse files

daily build

parent 29dfcfbe
No related branches found
No related tags found
No related merge requests found
Showing
with 2029 additions and 6 deletions
WCM Base 7.x-1.x, 2016-02-04
----------------------------
- OCIO Media: Patches to allow per-extension file size limits and fix bugs.
WCM Base 7.x-1.x, 2016-02-03
-----------------------------
----------------------------
- OCIO Media: Added support for .dwg and .zip files.
- WCM User Config: Return to destination URL after Shibboleth login redirect.
- WCM Base:
......@@ -7,24 +11,24 @@ WCM Base 7.x-1.x, 2016-02-03
- Added Chosen module, allowing read-only jQuery multiselect field formats.
WCM Base 7.x-1.x, 2016-02-01
-----------------------------
----------------------------
- WCM Base: Added Private module patch that prevents non-privileged
users with the Private Content Viewer role from editing private nodes.
- WCM Workbench: Added Workbench Moderation patch that fixes nodes not appearing
on the "Needs Review" page for non-administrators.
WCM Base 7.x-1.x, 2016-01-29
-----------------------------
----------------------------
- OCIO SimpleSAMLphp Auth: Added patch to the simplesamlphp_auth contrib module to
allow shib-authenticated users to create other users.
- OCIO Landing Page: Allow reusable panel panes to be added to panel pages.
WCM Base 7.x-1.x, 2016-01-21
-----------------------------
----------------------------
- WCM Base: Renamed namespace-agnostic configuration features.
WCM Base 7.x-1.x, 2016-01-15
-----------------------------
----------------------------
- WCM Base: Add Zurb Responsive Tables module.
- OCIO Media, OCIO Omega Base: Added small center video style.
- OCIO Search: Updated search views page parsing parameters.
......@@ -34,7 +38,7 @@ WCM Base 7.x-1.x, 2016-01-15
types except for news articles.
WCM Base 7.x-1.x, 2016-01-12
-----------------------------
----------------------------
- WCM Base:
- Updated Panopoly to 1.30.
- Updated contrib modules: defaultconfig, features, features extra, ctools,
......
.DS_Store
node_modules
.project
public/*.js
public/*.css
public/bower.json
chosen.zip
.sass-cache
.ruby-version
.rbenv-gemsets
.grunt
_SpecRunner.html
spec/public
language: node_js
node_js:
- "0.10"
before_install:
- npm install -g grunt-cli
- gem install bundler
- bundle install
before_script: grunt build
after_success: ./bower-publish.sh
env:
global:
secure: FHc3fAbJDydJywQ3HcFrTxqyAmmKbiAwP5Bi3qIzvXXCKNYbZb45iSjrMPFq7sHQR/evxDKl3zzBd8k6lvx0Sr77GDkmbN7HjI22fb3wu1Pi3WhmIM90/70ATs6hSZunsNEHCtQa4fDFM3NYeOeiwHFX8HQ9tVlqtjeAZngONL8=
source "https://rubygems.org"
gem 'compass'
GEM
remote: https://rubygems.org/
specs:
chunky_png (1.2.8)
compass (0.12.2)
chunky_png (~> 1.2)
fssm (>= 0.2.7)
sass (~> 3.1)
fssm (0.2.10)
sass (3.2.9)
PLATFORMS
ruby
DEPENDENCIES
compass
module.exports = (grunt) ->
require('load-grunt-tasks')(grunt);
version = ->
grunt.file.readJSON("package.json").version
version_tag = ->
"v#{version()}"
grunt.initConfig
pkg: grunt.file.readJSON("package.json")
comments: """
/*!
Chosen, a Select Box Enhancer for jQuery and Prototype
by Patrick Filler for Harvest, http://getharvest.com
Version <%= pkg.version %>
Full source at https://github.com/harvesthq/chosen
Copyright (c) 2011-<%= grunt.template.today('yyyy') %> Harvest http://getharvest.com
MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
This file is generated by `grunt build`, do not edit it by hand.
*/
\n
"""
minified_comments: "/* Chosen #{version_tag()} | (c) 2011-<%= grunt.template.today('yyyy') %> by Harvest | MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md */\n"
concat:
options:
banner: "<%= comments %>"
jquery:
src: ["public/chosen.jquery.js"]
dest: "public/chosen.jquery.js"
proto:
src: ["public/chosen.proto.js"]
dest: "public/chosen.proto.js"
css:
src: ["public/chosen.css"]
dest: "public/chosen.css"
coffee:
options:
join: true
compile:
files:
'public/chosen.jquery.js': ['coffee/lib/select-parser.coffee', 'coffee/lib/abstract-chosen.coffee', 'coffee/chosen.jquery.coffee']
'public/chosen.proto.js': ['coffee/lib/select-parser.coffee', 'coffee/lib/abstract-chosen.coffee', 'coffee/chosen.proto.coffee']
'spec/public/jquery_specs.js': 'spec/jquery/*.spec.coffee'
'spec/public/proto_specs.js': 'spec/proto/*.spec.coffee'
uglify:
options:
mangle:
except: ['jQuery', 'AbstractChosen', 'Chosen', 'SelectParser']
banner: "<%= minified_comments %>"
minified_chosen_js:
files:
'public/chosen.jquery.min.js': ['public/chosen.jquery.js']
'public/chosen.proto.min.js': ['public/chosen.proto.js']
compass:
chosen_css:
options:
bundleExec: true
specify: ['sass/chosen.scss']
cssmin:
minified_chosen_css:
options:
banner: "<%= minified_comments %>"
keepSpecialComments: 0
src: 'public/chosen.css'
dest: 'public/chosen.min.css'
watch:
scripts:
files: ['coffee/**/*.coffee', 'sass/*.scss']
tasks: ['build']
dom_munger:
latest_version:
src: ['public/index.html', 'public/index.proto.html', 'public/options.html']
options:
callback: ($) ->
$("#latest-version").text(version_tag())
zip:
chosen:
cwd: 'public/'
src: ['public/**/*']
dest: "chosen_#{version_tag()}.zip"
'gh-pages':
options:
base: 'public',
message: "Updated to new Chosen version #{version()}"
src: ['**']
jasmine:
jquery:
src: [ 'public/chosen.jquery.js' ]
options:
vendor: [ 'http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js' ]
specs: 'spec/public/jquery_specs.js'
proto:
src: [ 'public/chosen.proto.js' ]
options:
vendor: [
'https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js',
'public/docsupport/event.simulate.js'
]
specs: 'spec/public/proto_specs.js'
grunt.registerTask 'default', ['build']
grunt.registerTask 'build', ['coffee', 'compass', 'concat', 'uglify', 'cssmin', 'package-bower']
grunt.registerTask 'prep-release', ['build', 'dom_munger:latest_version', 'zip:chosen','package-jquery']
grunt.registerTask 'test', ['coffee', 'jasmine']
grunt.registerTask 'publish-release', ['gh-pages']
grunt.registerTask 'package-jquery', 'Generate a jquery.json manifest file from package.json', () ->
src = "package.json"
dest = "chosen.jquery.json"
pkg = grunt.file.readJSON(src)
json1 =
"name": pkg.name
"description": pkg.description
"version": version()
"licenses": pkg.licenses
json2 = pkg.jqueryJSON
json1[key] = json2[key] for key of json2
json1.author.name = pkg.author
grunt.file.write('chosen.jquery.json', JSON.stringify(json1, null, 2) + "\n")
grunt.registerTask 'package-bower', 'Generate a bower.json manifest file from package.json', () ->
pkg = grunt.file.readJSON("package.json")
bowerjson = pkg.bowerJSON
jqueryjson = pkg.jqueryJSON
bower =
"name": pkg.name
"description": pkg.description
"version": version()
"main": bowerjson.main
"license": pkg.licenses
"ignore": []
"keywords": jqueryjson.keywords
"authors": jqueryjson.maintainers
"homepage": jqueryjson.homepage
"repository": pkg.repository
"dependencies": jqueryjson.dependencies
"devDependencies": []
grunt.file.write("public/bower.json", JSON.stringify(bower, null, 2) + "\n")
grunt.registerTask 'cleanup-bower', 'Delete generated bower.json file', () ->
grunt.file.delete("public/bower.json")
#### Chosen
- by Patrick Filler for [Harvest](http://getharvest.com)
- Copyright (c) 2011-2015 by Harvest
Available for use under the [MIT License](http://en.wikipedia.org/wiki/MIT_License)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# Chosen
Chosen is a library for making long, unwieldy select boxes more user friendly.
- jQuery support: 1.4+
- Prototype support: 1.7+
For **documentation**, usage, and examples, see:
http://harvesthq.github.io/chosen/
For **downloads**, see:
https://github.com/harvesthq/chosen/releases/
### Bower Installation
Chosen is available for Bower installation:
`bower install chosen`
The compiled files for the Bower package are automatically generated and stored in a [2nd Chosen repository](https://github.com/harvesthq/bower-chosen). No pull requests will be accepted to that repository.
### Contributing to this project
We welcome all to participate in making Chosen the best software it can be. The repository is maintained by only a few people, but has accepted contributions from over 50 authors after reviewing hundreds of pull requests related to thousands of issues. You can help reduce the maintainers' workload (and increase your chance of having an accepted contribution to Chosen) by following the
[guidelines for contributing](contributing.md).
* [Bug reports](contributing.md#bugs)
* [Feature requests](contributing.md#features)
* [Pull requests](contributing.md#pull-requests)
### Chosen Credits
- Concept and development by [Patrick Filler](http://patrickfiller.com) for [Harvest](http://getharvest.com/).
- Design and CSS by [Matthew Lettini](http://matthewlettini.com/)
- Repository maintained by [@pfiller](http://github.com/pfiller), [@kenearley](http://github.com/kenearley), [@stof](http://github.com/stof), [@koenpunt](http://github.com/koenpunt), and [@tjschuck](http://github.com/tjschuck).
- Chosen includes [contributions by many fine folks](https://github.com/harvesthq/chosen/contributors).
#!/bin/sh
CURRENT_BRANCH=`git name-rev --name-only HEAD`
if [ $CURRENT_BRANCH != 'master' ] ; then
echo "Build not on master. Skipped bower-chosen release"
exit 0
fi
git config --global user.email "notmyemail@bower-chosen.lol"
git config --global user.name "bower-chosen"
git clone https://pfiller:${GH_TOKEN}@github.com/harvesthq/bower-chosen.git
rm -rf bower-chosen/*
cp public/bower.json public/*.png public/chosen.jquery.js public/chosen.css bower-chosen/
cd bower-chosen
LATEST_VERSION=$(git diff bower.json | grep version | cut -d':' -f2 | cut -d'"' -f2 | tail -1)
if [ -z $LATEST_VERSION ] ; then
echo "No Chosen version change. Skipped tagging"
else
echo "Chosen version changed. Tagging version ${LATEST_VERSION}\n"
git tag -a "v${LATEST_VERSION}" -m "Version ${LATEST_VERSION}"
fi
git remote set-url origin https://pfiller:${GH_TOKEN}@github.com/harvesthq/bower-chosen.git
git add -A
git commit -m "Chosen build to bower-chosen"
git push origin master
git push origin --tags
echo "Chosen published to harvesthq/bower-chosen"
{
"name": "chosen",
"description": "Chosen is a JavaScript plugin that makes long, unwieldy select boxes much more user-friendly. It is currently available in both jQuery and Prototype flavors.",
"version": "1.4.2",
"licenses": [
{
"type": "MIT",
"url": "https://github.com/harvesthq/chosen/blob/master/LICENSE.md"
}
],
"title": "Chosen",
"keywords": [
"select",
"multiselect",
"dropdown",
"form",
"input",
"ui"
],
"author": {
"url": "http://getharvest.com",
"name": "harvest"
},
"maintainers": [
{
"name": "Patrick Filler",
"url": "https://github.com/pfiller"
},
{
"name": "Christophe Coevoet",
"url": "https://github.com/stof"
},
{
"name": "Ken Earley",
"url": "https://github.com/kenearley"
},
{
"name": "Koen Punt",
"url": "https://github.com/koenpunt"
}
],
"download": "https://github.com/harvesthq/chosen/releases",
"homepage": "http://harvesthq.github.io/chosen/",
"docs": "http://harvesthq.github.io/chosen/",
"bugs": "https://github.com/harvesthq/chosen/issues",
"dependencies": {
"jquery": ">=1.4.4"
}
}
$ = jQuery
$.fn.extend({
chosen: (options) ->
# Do no harm and return as soon as possible for unsupported browsers, namely IE6 and IE7
# Continue on if running IE document type but in compatibility mode
return this unless AbstractChosen.browser_is_supported()
this.each (input_field) ->
$this = $ this
chosen = $this.data('chosen')
if options is 'destroy'
if chosen instanceof Chosen
chosen.destroy()
return
unless chosen instanceof Chosen
$this.data('chosen', new Chosen(this, options))
return
})
class Chosen extends AbstractChosen
setup: ->
@form_field_jq = $ @form_field
@current_selectedIndex = @form_field.selectedIndex
@is_rtl = @form_field_jq.hasClass "chosen-rtl"
set_up_html: ->
container_classes = ["chosen-container"]
container_classes.push "chosen-container-" + (if @is_multiple then "multi" else "single")
container_classes.push @form_field.className if @inherit_select_classes && @form_field.className
container_classes.push "chosen-rtl" if @is_rtl
container_props =
'class': container_classes.join ' '
'style': "width: #{this.container_width()};"
'title': @form_field.title
container_props.id = @form_field.id.replace(/[^\w]/g, '_') + "_chosen" if @form_field.id.length
@container = ($ "<div />", container_props)
if @is_multiple
@container.html '<ul class="chosen-choices"><li class="search-field"><input type="text" value="' + @default_text + '" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chosen-drop"><ul class="chosen-results"></ul></div>'
else
@container.html '<a class="chosen-single chosen-default"><span>' + @default_text + '</span><div><b></b></div></a><div class="chosen-drop"><div class="chosen-search"><input type="text" autocomplete="off" /></div><ul class="chosen-results"></ul></div>'
@form_field_jq.hide().after @container
@dropdown = @container.find('div.chosen-drop').first()
@search_field = @container.find('input').first()
@search_results = @container.find('ul.chosen-results').first()
this.search_field_scale()
@search_no_results = @container.find('li.no-results').first()
if @is_multiple
@search_choices = @container.find('ul.chosen-choices').first()
@search_container = @container.find('li.search-field').first()
else
@search_container = @container.find('div.chosen-search').first()
@selected_item = @container.find('.chosen-single').first()
this.results_build()
this.set_tab_index()
this.set_label_behavior()
on_ready: ->
@form_field_jq.trigger("chosen:ready", {chosen: this})
register_observers: ->
@container.bind 'touchstart.chosen', (evt) => this.container_mousedown(evt); evt.preventDefault()
@container.bind 'touchend.chosen', (evt) => this.container_mouseup(evt); evt.preventDefault()
@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.input_blur(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
if @is_multiple
@search_choices.bind 'click.chosen', (evt) => this.choices_click(evt); return
else
@container.bind 'click.chosen', (evt) -> evt.preventDefault(); return # gobble click of anchor
destroy: ->
$(@container[0].ownerDocument).unbind "click.chosen", @click_test_action
if @search_field[0].tabIndex
@form_field_jq[0].tabIndex = @search_field[0].tabIndex
@container.remove()
@form_field_jq.removeData('chosen')
@form_field_jq.show()
search_field_disabled: ->
@is_disabled = @form_field_jq[0].disabled
if(@is_disabled)
@container.addClass 'chosen-disabled'
@search_field[0].disabled = true
@selected_item.unbind "focus.chosen", @activate_action if !@is_multiple
this.close_field()
else
@container.removeClass 'chosen-disabled'
@search_field[0].disabled = false
@selected_item.bind "focus.chosen", @activate_action if !@is_multiple
container_mousedown: (evt) ->
if !@is_disabled
if evt and evt.type is "mousedown" and not @results_showing
evt.preventDefault()
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
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()
this.results_toggle()
this.activate_field()
container_mouseup: (evt) ->
this.results_reset(evt) if evt.target.nodeName is "ABBR" and not @is_disabled
search_results_mousewheel: (evt) ->
delta = evt.originalEvent.deltaY or -evt.originalEvent.wheelDelta or evt.originalEvent.detail if evt.originalEvent
if delta?
evt.preventDefault()
delta = delta * 40 if evt.type is 'DOMMouseScroll'
@search_results.scrollTop(delta + @search_results.scrollTop())
blur_test: (evt) ->
this.close_field() if not @active_field and @container.hasClass "chosen-container-active"
close_field: ->
$(@container[0].ownerDocument).unbind "click.chosen", @click_test_action
@active_field = false
this.results_hide()
@container.removeClass "chosen-container-active"
this.clear_backstroke()
this.show_search_field_default()
this.search_field_scale()
activate_field: ->
@container.addClass "chosen-container-active"
@active_field = true
@search_field.val(@search_field.val())
@search_field.focus()
test_active_click: (evt) ->
active_container = $(evt.target).closest('.chosen-container')
if active_container.length and @container[0] == active_container[0]
@active_field = true
else
this.close_field()
results_build: ->
@parsing = true
@selected_option_count = null
@results_data = SelectParser.select_to_array @form_field
if @is_multiple
@search_choices.find("li.search-choice").remove()
else if not @is_multiple
this.single_set_selected_text()
if @disable_search or @form_field.options.length <= @disable_search_threshold
@search_field[0].readOnly = true
@container.addClass "chosen-container-single-nosearch"
else
@search_field[0].readOnly = false
@container.removeClass "chosen-container-single-nosearch"
this.update_results_content this.results_option_build({first:true})
this.search_field_disabled()
this.show_search_field_default()
this.search_field_scale()
@parsing = false
result_do_highlight: (el) ->
if el.length
this.result_clear_highlight()
@result_highlight = el
@result_highlight.addClass "highlighted"
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()
if high_bottom >= visible_bottom
@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
results_show: ->
if @is_multiple and @max_selected_options <= this.choices_count()
@form_field_jq.trigger("chosen:maxselected", {chosen: this})
return false
@container.addClass "chosen-with-drop"
@results_showing = true
@search_field.focus()
@search_field.val @search_field.val()
this.winnow_results()
@form_field_jq.trigger("chosen:showing_dropdown", {chosen: this})
update_results_content: (content) ->
@search_results.html content
results_hide: ->
if @results_showing
this.result_clear_highlight()
@container.removeClass "chosen-with-drop"
@form_field_jq.trigger("chosen:hiding_dropdown", {chosen: this})
@results_showing = false
set_tab_index: (el) ->
if @form_field.tabIndex
ti = @form_field.tabIndex
@form_field.tabIndex = -1
@search_field[0].tabIndex = ti
set_label_behavior: ->
@form_field_label = @form_field_jq.parents("label") # first check for a parent label
if not @form_field_label.length and @form_field.id.length
@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', (evt) => if @is_multiple then this.container_mousedown(evt) else this.activate_field()
show_search_field_default: ->
if @is_multiple and this.choices_count() < 1 and not @active_field
@search_field.val(@default_text)
@search_field.addClass "default"
else
@search_field.val("")
@search_field.removeClass "default"
search_results_mouseup: (evt) ->
target = if $(evt.target).hasClass "active-result" then $(evt.target) else $(evt.target).parents(".active-result").first()
if target.length
@result_highlight = target
this.result_select(evt)
@search_field.focus()
search_results_mouseover: (evt) ->
target = if $(evt.target).hasClass "active-result" then $(evt.target) else $(evt.target).parents(".active-result").first()
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()
choice_build: (item) ->
choice = $('<li />', { class: "search-choice" }).html("<span>#{this.choice_label(item)}</span>")
if item.disabled
choice.addClass 'search-choice-disabled'
else
close_link = $('<a />', { class: 'search-choice-close', 'data-option-array-index': item.array_index })
close_link.bind 'click.chosen', (evt) => this.choice_destroy_link_click(evt)
choice.append close_link
@search_container.before choice
choice_destroy_link_click: (evt) ->
evt.preventDefault()
evt.stopPropagation()
this.choice_destroy $(evt.target) unless @is_disabled
choice_destroy: (link) ->
if this.result_deselect( link[0].getAttribute("data-option-array-index") )
this.show_search_field_default()
this.results_hide() if @is_multiple and this.choices_count() > 0 and @search_field.val().length < 1
link.parents('li').first().remove()
this.search_field_scale()
results_reset: ->
this.reset_single_select_options()
@form_field.options[0].selected = true
this.single_set_selected_text()
this.show_search_field_default()
this.results_reset_cleanup()
@form_field_jq.trigger "change"
this.results_hide() if @active_field
results_reset_cleanup: ->
@current_selectedIndex = @form_field.selectedIndex
@selected_item.find("abbr").remove()
result_select: (evt) ->
if @result_highlight
high = @result_highlight
this.result_clear_highlight()
if @is_multiple and @max_selected_options <= this.choices_count()
@form_field_jq.trigger("chosen:maxselected", {chosen: this})
return false
if @is_multiple
high.removeClass("active-result")
else
this.reset_single_select_options()
high.addClass("result-selected")
item = @results_data[ high[0].getAttribute("data-option-array-index") ]
item.selected = true
@form_field.options[item.options_index].selected = true
@selected_option_count = null
if @is_multiple
this.choice_build item
else
this.single_set_selected_text(this.choice_label(item))
this.results_hide() unless (evt.metaKey or evt.ctrlKey) and @is_multiple
this.show_search_field_default()
@form_field_jq.trigger "change", {'selected': @form_field.options[item.options_index].value} if @is_multiple || @form_field.selectedIndex != @current_selectedIndex
@current_selectedIndex = @form_field.selectedIndex
evt.preventDefault()
this.search_field_scale()
single_set_selected_text: (text=@default_text) ->
if text is @default_text
@selected_item.addClass("chosen-default")
else
this.single_deselect_control_build()
@selected_item.removeClass("chosen-default")
@selected_item.find("span").html(text)
result_deselect: (pos) ->
result_data = @results_data[pos]
if not @form_field.options[result_data.options_index].disabled
result_data.selected = false
@form_field.options[result_data.options_index].selected = false
@selected_option_count = null
this.result_clear_highlight()
this.winnow_results() if @results_showing
@form_field_jq.trigger "change", {deselected: @form_field.options[result_data.options_index].value}
this.search_field_scale()
return true
else
return false
single_deselect_control_build: ->
return unless @allow_single_deselect
@selected_item.find("span").first().after "<abbr class=\"search-choice-close\"></abbr>" unless @selected_item.find("abbr").length
@selected_item.addClass("chosen-single-with-deselect")
get_search_text: ->
$('<div/>').text($.trim(@search_field.val())).html()
winnow_results_set_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()
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
@form_field_jq.trigger("chosen:no_results", {chosen:this})
no_results_clear: ->
@search_results.find(".no-results").remove()
keydown_arrow: ->
if @results_showing and @result_highlight
next_sib = @result_highlight.nextAll("li.active-result").first()
this.result_do_highlight next_sib if next_sib
else
this.results_show()
keyup_arrow: ->
if not @results_showing and not @is_multiple
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
this.results_hide() if this.choices_count() > 0
this.result_clear_highlight()
keydown_backstroke: ->
if @pending_backstroke
this.choice_destroy @pending_backstroke.find("a").first()
this.clear_backstroke()
else
next_available_destroy = @search_container.siblings("li.search-choice").last()
if next_available_destroy.length and not next_available_destroy.hasClass("search-choice-disabled")
@pending_backstroke = next_available_destroy
if @single_backstroke_delete
@keydown_backstroke()
else
@pending_backstroke.addClass "search-choice-focus"
clear_backstroke: ->
@pending_backstroke.removeClass "search-choice-focus" if @pending_backstroke
@pending_backstroke = null
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
break
when 9
this.result_select(evt) if this.results_showing and not @is_multiple
@mouse_on_container = false
break
when 13
evt.preventDefault() if this.results_showing
break
when 32
evt.preventDefault() if @disable_search
break
when 38
evt.preventDefault()
this.keyup_arrow()
break
when 40
evt.preventDefault()
this.keydown_arrow()
break
search_field_scale: ->
if @is_multiple
h = 0
w = 0
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
w = div.width() + 25
div.remove()
f_width = @container.outerWidth()
if( w > f_width - 10 )
w = f_width - 10
@search_field.css({'width': w + 'px'})
class @Chosen extends AbstractChosen
setup: ->
@current_selectedIndex = @form_field.selectedIndex
@is_rtl = @form_field.hasClassName "chosen-rtl"
set_default_values: ->
super()
# HTML Templates
@single_temp = new Template('<a class="chosen-single chosen-default"><span>#{default}</span><div><b></b></div></a><div class="chosen-drop"><div class="chosen-search"><input type="text" autocomplete="off" /></div><ul class="chosen-results"></ul></div>')
@multi_temp = new Template('<ul class="chosen-choices"><li class="search-field"><input type="text" value="#{default}" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chosen-drop"><ul class="chosen-results"></ul></div>')
@no_results_temp = new Template('<li class="no-results">' + @results_none_found + ' "<span>#{terms}</span>"</li>')
set_up_html: ->
container_classes = ["chosen-container"]
container_classes.push "chosen-container-" + (if @is_multiple then "multi" else "single")
container_classes.push @form_field.className if @inherit_select_classes && @form_field.className
container_classes.push "chosen-rtl" if @is_rtl
container_props =
'class': container_classes.join ' '
'style': "width: #{this.container_width()};"
'title': @form_field.title
container_props.id = @form_field.id.replace(/[^\w]/g, '_') + "_chosen" if @form_field.id.length
@container = 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: @container })
@dropdown = @container.down('div.chosen-drop')
@search_field = @container.down('input')
@search_results = @container.down('ul.chosen-results')
this.search_field_scale()
@search_no_results = @container.down('li.no-results')
if @is_multiple
@search_choices = @container.down('ul.chosen-choices')
@search_container = @container.down('li.search-field')
else
@search_container = @container.down('div.chosen-search')
@selected_item = @container.down('.chosen-single')
this.results_build()
this.set_tab_index()
this.set_label_behavior()
on_ready: ->
@form_field.fire("chosen:ready", {chosen: this})
register_observers: ->
@container.observe "touchstart", (evt) => this.container_mousedown(evt); evt.preventDefault()
@container.observe "touchend", (evt) => this.container_mouseup(evt); evt.preventDefault()
@container.observe "mousedown", (evt) => this.container_mousedown(evt)
@container.observe "mouseup", (evt) => this.container_mouseup(evt)
@container.observe "mouseenter", (evt) => this.mouse_enter(evt)
@container.observe "mouseleave", (evt) => this.mouse_leave(evt)
@search_results.observe "mouseup", (evt) => this.search_results_mouseup(evt)
@search_results.observe "mouseover", (evt) => this.search_results_mouseover(evt)
@search_results.observe "mouseout", (evt) => this.search_results_mouseout(evt)
@search_results.observe "mousewheel", (evt) => this.search_results_mousewheel(evt)
@search_results.observe "DOMMouseScroll", (evt) => this.search_results_mousewheel(evt)
@search_results.observe "touchstart", (evt) => this.search_results_touchstart(evt)
@search_results.observe "touchmove", (evt) => this.search_results_touchmove(evt)
@search_results.observe "touchend", (evt) => this.search_results_touchend(evt)
@form_field.observe "chosen:updated", (evt) => this.results_update_field(evt)
@form_field.observe "chosen:activate", (evt) => this.activate_field(evt)
@form_field.observe "chosen:open", (evt) => this.container_mousedown(evt)
@form_field.observe "chosen:close", (evt) => this.input_blur(evt)
@search_field.observe "blur", (evt) => this.input_blur(evt)
@search_field.observe "keyup", (evt) => this.keyup_checker(evt)
@search_field.observe "keydown", (evt) => this.keydown_checker(evt)
@search_field.observe "focus", (evt) => this.input_focus(evt)
@search_field.observe "cut", (evt) => this.clipboard_event_checker(evt)
@search_field.observe "paste", (evt) => this.clipboard_event_checker(evt)
if @is_multiple
@search_choices.observe "click", (evt) => this.choices_click(evt)
else
@container.observe "click", (evt) => evt.preventDefault() # gobble click of anchor
destroy: ->
@container.ownerDocument.stopObserving "click", @click_test_action
@form_field.stopObserving()
@container.stopObserving()
@search_results.stopObserving()
@search_field.stopObserving()
@form_field_label.stopObserving() if @form_field_label?
if @is_multiple
@search_choices.stopObserving()
@container.select(".search-choice-close").each (choice) ->
choice.stopObserving()
else
@selected_item.stopObserving()
if @search_field.tabIndex
@form_field.tabIndex = @search_field.tabIndex
@container.remove()
@form_field.show()
search_field_disabled: ->
@is_disabled = @form_field.disabled
if(@is_disabled)
@container.addClassName 'chosen-disabled'
@search_field.disabled = true
@selected_item.stopObserving "focus", @activate_action if !@is_multiple
this.close_field()
else
@container.removeClassName 'chosen-disabled'
@search_field.disabled = false
@selected_item.observe "focus", @activate_action if !@is_multiple
container_mousedown: (evt) ->
if !@is_disabled
if evt and evt.type is "mousedown" and not @results_showing
evt.stop()
if not (evt? and evt.target.hasClassName "search-choice-close")
if not @active_field
@search_field.clear() if @is_multiple
@container.ownerDocument.observe "click", @click_test_action
this.results_show()
else if not @is_multiple and evt and (evt.target is @selected_item || evt.target.up("a.chosen-single"))
this.results_toggle()
this.activate_field()
container_mouseup: (evt) ->
this.results_reset(evt) if evt.target.nodeName is "ABBR" and not @is_disabled
search_results_mousewheel: (evt) ->
delta = evt.deltaY or -evt.wheelDelta or evt.detail
if delta?
evt.preventDefault()
delta = delta * 40 if evt.type is 'DOMMouseScroll'
@search_results.scrollTop = delta + @search_results.scrollTop
blur_test: (evt) ->
this.close_field() if not @active_field and @container.hasClassName("chosen-container-active")
close_field: ->
@container.ownerDocument.stopObserving "click", @click_test_action
@active_field = false
this.results_hide()
@container.removeClassName "chosen-container-active"
this.clear_backstroke()
this.show_search_field_default()
this.search_field_scale()
activate_field: ->
@container.addClassName "chosen-container-active"
@active_field = true
@search_field.value = @search_field.value
@search_field.focus()
test_active_click: (evt) ->
if evt.target.up('.chosen-container') is @container
@active_field = true
else
this.close_field()
results_build: ->
@parsing = true
@selected_option_count = null
@results_data = SelectParser.select_to_array @form_field
if @is_multiple
@search_choices.select("li.search-choice").invoke("remove")
else if not @is_multiple
this.single_set_selected_text()
if @disable_search or @form_field.options.length <= @disable_search_threshold
@search_field.readOnly = true
@container.addClassName "chosen-container-single-nosearch"
else
@search_field.readOnly = false
@container.removeClassName "chosen-container-single-nosearch"
this.update_results_content this.results_option_build({first:true})
this.search_field_disabled()
this.show_search_field_default()
this.search_field_scale()
@parsing = false
result_do_highlight: (el) ->
this.result_clear_highlight()
@result_highlight = el
@result_highlight.addClassName "highlighted"
maxHeight = parseInt @search_results.getStyle('maxHeight'), 10
visible_top = @search_results.scrollTop
visible_bottom = maxHeight + visible_top
high_top = @result_highlight.positionedOffset().top
high_bottom = high_top + @result_highlight.getHeight()
if high_bottom >= visible_bottom
@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.removeClassName('highlighted') if @result_highlight
@result_highlight = null
results_show: ->
if @is_multiple and @max_selected_options <= this.choices_count()
@form_field.fire("chosen:maxselected", {chosen: this})
return false
@container.addClassName "chosen-with-drop"
@results_showing = true
@search_field.focus()
@search_field.value = @search_field.value
this.winnow_results()
@form_field.fire("chosen:showing_dropdown", {chosen: this})
update_results_content: (content) ->
@search_results.update content
results_hide: ->
if @results_showing
this.result_clear_highlight()
@container.removeClassName "chosen-with-drop"
@form_field.fire("chosen:hiding_dropdown", {chosen: this})
@results_showing = false
set_tab_index: (el) ->
if @form_field.tabIndex
ti = @form_field.tabIndex
@form_field.tabIndex = -1
@search_field.tabIndex = ti
set_label_behavior: ->
@form_field_label = @form_field.up("label") # first check for a parent label
if not @form_field_label?
@form_field_label = $$("label[for='#{@form_field.id}']").first() #next check for a for=#{id}
if @form_field_label?
@form_field_label.observe "click", (evt) => if @is_multiple then this.container_mousedown(evt) else this.activate_field()
show_search_field_default: ->
if @is_multiple and this.choices_count() < 1 and not @active_field
@search_field.value = @default_text
@search_field.addClassName "default"
else
@search_field.value = ""
@search_field.removeClassName "default"
search_results_mouseup: (evt) ->
target = if evt.target.hasClassName("active-result") then evt.target else evt.target.up(".active-result")
if target
@result_highlight = target
this.result_select(evt)
@search_field.focus()
search_results_mouseover: (evt) ->
target = if evt.target.hasClassName("active-result") then evt.target else evt.target.up(".active-result")
this.result_do_highlight( target ) if target
search_results_mouseout: (evt) ->
this.result_clear_highlight() if evt.target.hasClassName('active-result') or evt.target.up('.active-result')
choice_build: (item) ->
choice = new Element('li', { class: "search-choice" }).update("<span>#{this.choice_label(item)}</span>")
if item.disabled
choice.addClassName 'search-choice-disabled'
else
close_link = new Element('a', { href: '#', class: 'search-choice-close', rel: item.array_index })
close_link.observe "click", (evt) => this.choice_destroy_link_click(evt)
choice.insert close_link
@search_container.insert { before: choice }
choice_destroy_link_click: (evt) ->
evt.preventDefault()
evt.stopPropagation()
this.choice_destroy evt.target unless @is_disabled
choice_destroy: (link) ->
if this.result_deselect link.readAttribute("rel")
this.show_search_field_default()
this.results_hide() if @is_multiple and this.choices_count() > 0 and @search_field.value.length < 1
link.up('li').remove()
this.search_field_scale()
results_reset: ->
this.reset_single_select_options()
@form_field.options[0].selected = true
this.single_set_selected_text()
this.show_search_field_default()
this.results_reset_cleanup()
@form_field.simulate("change") if typeof Event.simulate is 'function'
this.results_hide() if @active_field
results_reset_cleanup: ->
@current_selectedIndex = @form_field.selectedIndex
deselect_trigger = @selected_item.down("abbr")
deselect_trigger.remove() if(deselect_trigger)
result_select: (evt) ->
if @result_highlight
high = @result_highlight
this.result_clear_highlight()
if @is_multiple and @max_selected_options <= this.choices_count()
@form_field.fire("chosen:maxselected", {chosen: this})
return false
if @is_multiple
high.removeClassName("active-result")
else
this.reset_single_select_options()
high.addClassName("result-selected")
item = @results_data[ high.getAttribute("data-option-array-index") ]
item.selected = true
@form_field.options[item.options_index].selected = true
@selected_option_count = null
if @is_multiple
this.choice_build item
else
this.single_set_selected_text(this.choice_label(item))
this.results_hide() unless (evt.metaKey or evt.ctrlKey) and @is_multiple
this.show_search_field_default()
@form_field.simulate("change") if typeof Event.simulate is 'function' && (@is_multiple || @form_field.selectedIndex != @current_selectedIndex)
@current_selectedIndex = @form_field.selectedIndex
evt.preventDefault()
this.search_field_scale()
single_set_selected_text: (text=@default_text) ->
if text is @default_text
@selected_item.addClassName("chosen-default")
else
this.single_deselect_control_build()
@selected_item.removeClassName("chosen-default")
@selected_item.down("span").update(text)
result_deselect: (pos) ->
result_data = @results_data[pos]
if not @form_field.options[result_data.options_index].disabled
result_data.selected = false
@form_field.options[result_data.options_index].selected = false
@selected_option_count = null
this.result_clear_highlight()
this.winnow_results() if @results_showing
@form_field.simulate("change") if typeof Event.simulate is 'function'
this.search_field_scale()
return true
else
return false
single_deselect_control_build: ->
return unless @allow_single_deselect
@selected_item.down("span").insert { after: "<abbr class=\"search-choice-close\"></abbr>" } unless @selected_item.down("abbr")
@selected_item.addClassName("chosen-single-with-deselect")
get_search_text: ->
@search_field.value.strip().escapeHTML()
winnow_results_set_highlight: ->
if not @is_multiple
do_high = @search_results.down(".result-selected.active-result")
if not do_high?
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 )
@form_field.fire("chosen:no_results", {chosen: this})
no_results_clear: ->
nr = null
nr.remove() while nr = @search_results.down(".no-results")
keydown_arrow: ->
if @results_showing and @result_highlight
next_sib = @result_highlight.next('.active-result')
this.result_do_highlight next_sib if next_sib
else
this.results_show()
keyup_arrow: ->
if not @results_showing and not @is_multiple
this.results_show()
else if @result_highlight
sibs = @result_highlight.previousSiblings()
actives = @search_results.select("li.active-result")
prevs = sibs.intersect(actives)
if prevs.length
this.result_do_highlight prevs.first()
else
this.results_hide() if this.choices_count() > 0
this.result_clear_highlight()
keydown_backstroke: ->
if @pending_backstroke
this.choice_destroy @pending_backstroke.down("a")
this.clear_backstroke()
else
next_available_destroy = @search_container.siblings().last()
if next_available_destroy and next_available_destroy.hasClassName("search-choice") and not next_available_destroy.hasClassName("search-choice-disabled")
@pending_backstroke = next_available_destroy
@pending_backstroke.addClassName("search-choice-focus") if @pending_backstroke
if @single_backstroke_delete
@keydown_backstroke()
else
@pending_backstroke.addClassName("search-choice-focus")
clear_backstroke: ->
@pending_backstroke.removeClassName("search-choice-focus") if @pending_backstroke
@pending_backstroke = null
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.value.length
break
when 9
this.result_select(evt) if this.results_showing and not @is_multiple
@mouse_on_container = false
break
when 13
evt.preventDefault() if this.results_showing
break
when 32
evt.preventDefault() if @disable_search
break
when 38
evt.preventDefault()
this.keyup_arrow()
break
when 40
evt.preventDefault()
this.keydown_arrow()
break
search_field_scale: ->
if @is_multiple
h = 0
w = 0
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.getStyle(style) + ";"
div = new Element('div', { 'style' : style_block }).update(@search_field.value.escapeHTML())
document.body.appendChild(div)
w = Element.measure(div, 'width') + 25
div.remove()
f_width = @container.getWidth()
if( w > f_width-10 )
w = f_width - 10
@search_field.setStyle({'width': w + 'px'})
class AbstractChosen
constructor: (@form_field, @options={}) ->
return unless AbstractChosen.browser_is_supported()
@is_multiple = @form_field.multiple
this.set_default_text()
this.set_default_values()
this.setup()
this.set_up_html()
this.register_observers()
# instantiation done, fire ready
this.on_ready()
set_default_values: ->
@click_test_action = (evt) => this.test_active_click(evt)
@activate_action = (evt) => this.activate_field(evt)
@active_field = false
@mouse_on_container = false
@results_showing = false
@result_highlighted = 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
@disable_search_threshold = @options.disable_search_threshold || 0
@disable_search = @options.disable_search || false
@enable_split_word_search = if @options.enable_split_word_search? then @options.enable_split_word_search else true
@group_search = if @options.group_search? then @options.group_search else true
@search_contains = @options.search_contains || false
@single_backstroke_delete = if @options.single_backstroke_delete? then @options.single_backstroke_delete else true
@max_selected_options = @options.max_selected_options || Infinity
@inherit_select_classes = @options.inherit_select_classes || false
@display_selected_options = if @options.display_selected_options? then @options.display_selected_options else true
@display_disabled_options = if @options.display_disabled_options? then @options.display_disabled_options else true
@include_group_label_in_selected = @options.include_group_label_in_selected || false
@max_shown_results = @options.max_shown_results || Number.POSITIVE_INFINITY
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 || AbstractChosen.default_multiple_text
else
@default_text = @options.placeholder_text_single || @options.placeholder_text || AbstractChosen.default_single_text
@results_none_found = @form_field.getAttribute("data-no_results_text") || @options.no_results_text || AbstractChosen.default_no_result_text
choice_label: (item) ->
if @include_group_label_in_selected and item.group_label?
"<b class='group-name'>#{item.group_label}</b>#{item.html}"
else
item.html
mouse_enter: -> @mouse_on_container = true
mouse_leave: -> @mouse_on_container = false
input_focus: (evt) ->
if @is_multiple
setTimeout (=> this.container_mousedown()), 50 unless @active_field
else
@activate_field() unless @active_field
input_blur: (evt) ->
if not @mouse_on_container
@active_field = false
setTimeout (=> this.blur_test()), 100
results_option_build: (options) ->
content = ''
shown_results = 0
for data in @results_data
data_content = ''
if data.group
data_content = this.result_add_group data
else
data_content = this.result_add_option data
if data_content != ''
shown_results++
content += data_content
# this select logic pins on an awkward flag
# we can make it better
if options?.first
if data.selected and @is_multiple
this.choice_build data
else if data.selected and not @is_multiple
this.single_set_selected_text(this.choice_label(data))
if shown_results >= @max_shown_results
break
content
result_add_option: (option) ->
return '' unless option.search_match
return '' unless this.include_option_in_results(option)
classes = []
classes.push "active-result" if !option.disabled and !(option.selected and @is_multiple)
classes.push "disabled-result" if option.disabled and !(option.selected and @is_multiple)
classes.push "result-selected" if option.selected
classes.push "group-option" if option.group_array_index?
classes.push option.classes if option.classes != ""
option_el = document.createElement("li")
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.title = option.title if option.title
this.outerHTML(option_el)
result_add_group: (group) ->
return '' unless group.search_match || group.group_match
return '' unless group.active_options > 0
classes = []
classes.push "group-result"
classes.push group.classes if group.classes
group_el = document.createElement("li")
group_el.className = classes.join(" ")
group_el.innerHTML = group.search_text
group_el.title = group.title if group.title
this.outerHTML(group_el)
results_update_field: ->
this.set_default_text()
this.results_reset_cleanup() if not @is_multiple
this.result_clear_highlight()
this.results_build()
this.winnow_results() if @results_showing
reset_single_select_options: () ->
for result in @results_data
result.selected = false if result.selected
results_toggle: ->
if @results_showing
this.results_hide()
else
this.results_show()
results_search: (evt) ->
if @results_showing
this.winnow_results()
else
this.results_show()
winnow_results: ->
this.no_results_clear()
results = 0
searchText = this.get_search_text()
escapedSearchText = searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")
zregex = new RegExp(escapedSearchText, 'i')
regex = this.get_search_regex(escapedSearchText)
for option in @results_data
option.search_match = false
results_group = null
if this.include_option_in_results(option)
if option.group
option.group_match = false
option.active_options = 0
if option.group_array_index? and @results_data[option.group_array_index]
results_group = @results_data[option.group_array_index]
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
unless option.group and not @group_search
option.search_match = this.search_string_match(option.search_text, regex)
results += 1 if option.search_match and not option.group
if option.search_match
if searchText.length
startpos = option.search_text.search zregex
text = option.search_text.substr(0, startpos + searchText.length) + '</em>' + option.search_text.substr(startpos + searchText.length)
option.search_text = text.substr(0, startpos) + '<em>' + text.substr(startpos)
results_group.group_match = true if results_group?
else if option.group_array_index? and @results_data[option.group_array_index].search_match
option.search_match = true
this.result_clear_highlight()
if results < 1 and searchText.length
this.update_results_content ""
this.no_results searchText
else
this.update_results_content this.results_option_build()
this.winnow_results_set_highlight()
get_search_regex: (escaped_search_string) ->
regex_anchor = if @search_contains then "" else "^"
new RegExp(regex_anchor + escaped_search_string, 'i')
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
choices_count: ->
return @selected_option_count if @selected_option_count?
@selected_option_count = 0
for option in @form_field.options
@selected_option_count += 1 if option.selected
return @selected_option_count
choices_click: (evt) ->
evt.preventDefault()
this.results_show() unless @results_showing or @is_disabled
keyup_checker: (evt) ->
stroke = evt.which ? evt.keyCode
this.search_field_scale()
switch stroke
when 8
if @is_multiple and @backstroke_length < 1 and this.choices_count() > 0
this.keydown_backstroke()
else if not @pending_backstroke
this.result_clear_highlight()
this.results_search()
when 13
evt.preventDefault()
this.result_select(evt) if this.results_showing
when 27
this.results_hide() if @results_showing
return true
when 9, 38, 40, 16, 91, 17, 18
# don't do anything on these keys
else this.results_search()
clipboard_event_checker: (evt) ->
setTimeout (=> this.results_search()), 50
container_width: ->
return if @options.width? then @options.width else "#{@form_field.offsetWidth}px"
include_option_in_results: (option) ->
return false if @is_multiple and (not @display_selected_options and option.selected)
return false if not @display_disabled_options and option.disabled
return false if option.empty
return true
search_results_touchstart: (evt) ->
@touch_started = true
this.search_results_mouseover(evt)
search_results_touchmove: (evt) ->
@touch_started = false
this.search_results_mouseout(evt)
search_results_touchend: (evt) ->
this.search_results_mouseup(evt) if @touch_started
outerHTML: (element) ->
return element.outerHTML if element.outerHTML
tmp = document.createElement("div")
tmp.appendChild(element)
tmp.innerHTML
# class methods and variables ============================================================
@browser_is_supported: ->
if /iP(od|hone)/i.test(window.navigator.userAgent)
return false
if /Android/i.test(window.navigator.userAgent)
return false if /Mobile/i.test(window.navigator.userAgent)
if /IEMobile/i.test(window.navigator.userAgent)
return false
if /Windows Phone/i.test(window.navigator.userAgent)
return false
if /BlackBerry/i.test(window.navigator.userAgent)
return false
if /BB10/i.test(window.navigator.userAgent)
return false
if window.navigator.appName is "Microsoft Internet Explorer"
return document.documentMode >= 8
return true
@default_multiple_text: "Select Some Options"
@default_single_text: "Select an Option"
@default_no_result_text: "No results match"
class SelectParser
constructor: ->
@options_index = 0
@parsed = []
add_node: (child) ->
if child.nodeName.toUpperCase() is "OPTGROUP"
this.add_group child
else
this.add_option child
add_group: (group) ->
group_position = @parsed.length
@parsed.push
array_index: group_position
group: true
label: this.escapeExpression(group.label)
title: group.title if group.title
children: 0
disabled: group.disabled,
classes: group.className
this.add_option( option, group_position, group.disabled ) for option in group.childNodes
add_option: (option, group_position, group_disabled) ->
if option.nodeName.toUpperCase() is "OPTION"
if option.text != ""
if group_position?
@parsed[group_position].children += 1
@parsed.push
array_index: @parsed.length
options_index: @options_index
value: option.value
text: option.text
html: option.innerHTML
title: option.title if option.title
selected: option.selected
disabled: if group_disabled is true then group_disabled else option.disabled
group_array_index: group_position
group_label: if group_position? then @parsed[group_position].label else null
classes: option.className
style: option.style.cssText
else
@parsed.push
array_index: @parsed.length
options_index: @options_index
empty: true
@options_index += 1
escapeExpression: (text) ->
if not text? or text is false
return ""
unless /[\&\<\>\"\'\`]/.test(text)
return text
map =
"<": "&lt;"
">": "&gt;"
'"': "&quot;"
"'": "&#x27;"
"`": "&#x60;"
unsafe_chars = /&(?!\w+;)|[\<\>\"\'\`]/g
text.replace unsafe_chars, (chr) ->
map[chr] || "&amp;"
SelectParser.select_to_array = (select) ->
parser = new SelectParser()
parser.add_node( child ) for child in select.childNodes
parser.parsed
http_path = "/"
css_dir = "public"
sass_dir = "sass"
images_dir = "public"
relative_assets = true
line_comments = false
asset_cache_buster :none
\ No newline at end of file
# Contributing to this project
Please take a moment to review this document in order to make the contribution
process easy and effective for everyone involved.
Following these guidelines will help us get back to you more quickly, and will
show that you care about making Chosen better just like we do. In return, we'll
do our best to respond to your issue or pull request as soon as possible with
the same respect.
_**Please Note:** These guidelines are adapted from [@necolas](https://github.com/necolas)'s
[issue-guidelines](https://github.com/necolas/issue-guidelines) and serve as
an excellent starting point for contributing to any open source project._
## Using the issue tracker
The [issue tracker](https://github.com/harvesthq/chosen/issues) is the
preferred channel for [bug reports](#bugs), [features requests](#features)
and [submitting pull requests](#pull-requests), but please respect the
following restrictions:
* Support issues or usage question that are not bugs should be posted on
[Stack Overflow, using the `chosen.js`](http://stackoverflow.com/questions/tagged/chosen.js) tag
(related tags: [`jquery-chosen`](http://stackoverflow.com/questions/tagged/jquery-chosen),
[`prototype-chosen`](http://stackoverflow.com/questions/tagged/prototype-chosen)).
* Please **do not** derail or troll issues. Keep the discussion on topic and
respect the opinions of others.
<a name="bugs"></a>
## Bug reports
A bug is a _demonstrable problem_ that is caused by the code in the repository.
Good bug reports are extremely helpful &mdash; thank you!
Guidelines for bug reports:
1. **Use the [GitHub issue search](https://github.com/harvesthq/chosen/search?type=Issues)** &mdash; check if the issue has already been
reported.
2. **Check if the bug has already been fixed** &mdash; try to reproduce it using the
repository's latest `master` changes.
3. **Isolate the problem** &mdash; ideally create a [reduced test
case](http://css-tricks.com/6263-reduced-test-cases/) and a live example
(perhaps a [fiddle](http://jsfiddle.net)).
A good bug report shouldn't leave others needing to contact you for more
information. Please try to be as detailed as possible in your report. What is
your environment? What steps will reproduce the issue? What browser(s) and OS
experience the problem? What outcome did you expect, and how did it differ from
what you actually saw? All these details will help people to fix any potential
bugs.
Example:
> Short and descriptive example bug report title
>
> A summary of the issue and the browser/OS environment in which it occurs. If
> suitable, include the steps required to reproduce the bug.
>
> 1. This is the first step
> 2. This is the second step
> 3. Further steps, etc.
>
> `<url>` - a link to the reduced test case
>
> Any other information you want to share that is relevant to the issue being
> reported. This might include the lines of code that you have identified as
> causing the bug, and potential solutions (and your opinions on their
> merits).
**Note:** In an effort to keep open issues to a manageable number, we will close any issues
that do not provide enough information for us to be able to work on a solution.
You will be encouraged to provide the necessary details, after which we will reopen the issue.
<a name="features"></a>
## Feature requests
Feature requests are welcome. But take a moment to find out whether your idea
fits with the scope and aims of the project. It's up to *you* to make a strong
case to convince the project's developers of the merits of this feature. Please
provide as much detail and context as possible.
Building something great means choosing features carefully especially because it
is much, much easier to add features than it is to take them away. Additions
to Chosen will be evaluated on a combination of scope (how well it fits into the
project), maintenance burden and general usefulness.
Creating something great often means saying no to seemingly good ideas. Don't
dispair if your feature request isn't accepted, take action! Fork the
repository, build your idea and share it with others. We released Chosen under
the MIT License for this purpose precisely. Open source works best when smart
and dedicated people riff off of each others' ideas to make even greater things.
<a name="pull-requests"></a>
## Pull requests
Good pull requests &mdash; patches, improvements, new features &mdash; are a fantastic help.
They should remain focused in scope and avoid containing unrelated commits.
**Please ask first** before embarking on any significant pull request (e.g.
implementing features, refactoring code, porting to a different language),
otherwise you risk spending a lot of time working on something that the
project's developers might not want to merge into the project. You can solicit
feedback and opinions in an open feature request thread or create a new one.
Please use the [git flow for pull requests](#git-flow) and follow Chosen's
[code conventions](#code-conventions) before submitting your work. Adhering to
these guidelines is the best way to get your work included in Chosen.
<a name="git-flow"></a>
#### Git Flow for pull requests
1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork,
and configure the remotes:
```bash
# Clone your fork of the repo into the current directory
git clone git@github.com:<YOUR_USERNAME>/chosen.git
# Navigate to the newly cloned directory
cd chosen
# Assign the original repo to a remote called "upstream"
git remote add upstream https://github.com/harvesthq/chosen
```
2. If you cloned a while ago, get the latest changes from upstream:
```bash
git checkout master
git pull upstream master
```
3. Create a new topic branch (off the main project development branch) to
contain your feature, change, or fix:
```bash
git checkout -b <topic-branch-name>
```
4. Commit your changes in logical chunks. Please adhere to these [git commit
message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
or your code is unlikely be merged into the main project. Use Git's
[interactive rebase](https://help.github.com/articles/interactive-rebase)
feature to tidy up your commits before making them public.
5. Locally merge (or rebase) the upstream development branch into your topic branch:
```bash
git pull [--rebase] upstream master
```
6. Push your topic branch up to your fork:
```bash
git push origin <topic-branch-name>
```
7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
with a clear title and description.
**IMPORTANT**: By submitting a patch, you agree to allow the project owner to
license your work under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
<a name="code-conventions"></a>
#### Chosen Code Conventions
1. Make all changes in CoffeeScript files, **not** JavaScript files.
2. Use [Grunt](#grunt) to build the JavaScript files.
3. For feature changes, update both jQuery *and* Prototype versions
4. Don't manually update the version number in `package.json`. This is done using a Grunt task on deployment.
<a name="grunt"></a>
#### Using CoffeeScript and Grunt
To install all development dependencies, in the project's root directory, run
npm install && gem install bundler && bundle install
Once you're configured, building the JavaScript from the command line is easy:
grunt build # build Chosen from source
grunt watch # watch coffee/ for changes and build Chosen
If you're interested, you can find the task in [Gruntfile.coffee](https://github.com/harvesthq/chosen/blob/master/Gruntfile.coffee).
{
"author": "harvest",
"name": "chosen",
"version": "1.4.2",
"description": "Chosen is a JavaScript plugin that makes select boxes user-friendly. It is currently available in both jQuery and Prototype flavors.",
"repository": {
"type": "git",
"url": "https://github.com/harvesthq/chosen"
},
"engines": {
"node": ">=0.4.0"
},
"scripts": {
"test": "grunt test"
},
"dependencies": {},
"devDependencies": {
"coffee-script": ">= 1.6",
"grunt": "~0.4.1",
"grunt-contrib-coffee": "~0.6.4",
"grunt-contrib-compass": "~0.5.0",
"grunt-contrib-concat": "~0.1.3",
"grunt-contrib-cssmin": "~0.6.1",
"grunt-contrib-jasmine": "~0.5.1",
"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-zip": "~0.9.2",
"load-grunt-tasks": "^3.0.0"
},
"licenses": [
{
"type": "MIT",
"url": "https://github.com/harvesthq/chosen/blob/master/LICENSE.md"
}
],
"bowerJSON":{
"main": [
"chosen.jquery.js",
"chosen.css",
"chosen-sprite@2x.png",
"chosen-sprite.png"
]
},
"jqueryJSON": {
"title": "Chosen",
"keywords": [
"select",
"multiselect",
"dropdown",
"form",
"input",
"ui"
],
"author": {
"url": "http://getharvest.com"
},
"maintainers": [
{
"name": "Patrick Filler",
"url": "https://github.com/pfiller"
},
{
"name": "Christophe Coevoet",
"url": "https://github.com/stof"
},
{
"name": "Ken Earley",
"url": "https://github.com/kenearley"
},
{
"name": "Koen Punt",
"url": "https://github.com/koenpunt"
}
],
"download": "https://github.com/harvesthq/chosen/releases",
"homepage": "http://harvesthq.github.io/chosen/",
"docs": "http://harvesthq.github.io/chosen/",
"bugs": "https://github.com/harvesthq/chosen/issues",
"dependencies": {
"jquery": ">=1.4.4"
}
}
}
profiles/wcm_base/libraries/chosen/public/chosen-sprite.png

538 B

profiles/wcm_base/libraries/chosen/public/chosen-sprite@2x.png

738 B

profiles/wcm_base/libraries/chosen/public/docsupport/chosen.png

1.47 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment