From b30b4555056968ae115f16a8fc349cae1dfb1964 Mon Sep 17 00:00:00 2001 From: Igor Vaynberg Date: Thu, 29 Mar 2012 11:08:14 -0700 Subject: [PATCH] Fix CRLF --- select2.css | 736 ++++++++-------- select2.js | 2312 +++++++++++++++++++++++++-------------------------- 2 files changed, 1524 insertions(+), 1524 deletions(-) diff --git a/select2.css b/select2.css index b35796f4..34034b1f 100755 --- a/select2.css +++ b/select2.css @@ -1,368 +1,368 @@ -.select2-container { - position: relative; - display: inline-block; - /* inline-block for ie7 */ - zoom: 1; - *display: inline; - -} - -.select2-container .select2-choice { - background-color: #fff; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(0.5, white)); - background-image: -webkit-linear-gradient(center bottom, #eeeeee 0%, white 50%); - background-image: -moz-linear-gradient(center bottom, #eeeeee 0%, white 50%); - background-image: -o-linear-gradient(top, #eeeeee 0%, #ffffff 50%); - background-image: -ms-linear-gradient(top, #eeeeee 0%, #ffffff 50%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#ffffff', GradientType = 0); - background-image: linear-gradient(top, #eeeeee 0%, #ffffff 50%); - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -moz-background-clip: padding; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #aaa; - display: block; - overflow: hidden; - white-space: nowrap; - position: relative; - height: 26px; - line-height: 26px; - padding: 0 0 0 8px; - color: #444; - text-decoration: none; -} - -.select2-container .select2-choice span { - margin-right: 26px; - display: block; - overflow: hidden; - white-space: nowrap; - -o-text-overflow: ellipsis; - -ms-text-overflow: ellipsis; - text-overflow: ellipsis; -} - -.select2-container .select2-choice abbr { - display: block; - position: absolute; - right: 26px; - top: 8px; - width: 12px; - height: 12px; - font-size: 1px; - background: url(select2.png) right top no-repeat; - cursor: pointer; - text-decoration: none; - border:0; - outline: 0; -} -.select2-container .select2-choice abbr:hover { - background-position: right -11px; - cursor: pointer; -} - -.select2-container .select2-drop { - background: #fff; - border: 1px solid #aaa; - border-top: 0; - position: absolute; - top: 29px; - left: 0; - -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); - -moz-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); - -o-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); - box-shadow: 0 4px 5px rgba(0, 0, 0, .15); - z-index: 999; - - -webkit-border-radius: 0 0 4px 4px; - -moz-border-radius: 0 0 4px 4px; - border-radius: 0 0 4px 4px; - -moz-background-clip: padding; - -webkit-background-clip: padding-box; - background-clip: padding-box; -} - -.select2-container .select2-choice div { - -webkit-border-radius: 0 4px 4px 0; - -moz-border-radius: 0 4px 4px 0; - border-radius: 0 4px 4px 0; - -moz-background-clip: padding; - -webkit-background-clip: padding-box; - background-clip: padding-box; - background: #ccc; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee)); - background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%); - background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%); - background-image: -o-linear-gradient(bottom, #ccc 0%, #eee 60%); - background-image: -ms-linear-gradient(top, #cccccc 0%, #eeeeee 60%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#cccccc', endColorstr = '#eeeeee', GradientType = 0); - background-image: linear-gradient(top, #cccccc 0%, #eeeeee 60%); - border-left: 1px solid #aaa; - position: absolute; - right: 0; - top: 0; - display: block; - height: 100%; - width: 18px; -} - -.select2-container .select2-choice div b { - background: url('select2.png') no-repeat 0 1px; - display: block; - width: 100%; - height: 100%; -} - -.select2-container .select2-search { - padding: 3px 4px; - position: relative; - margin: 0; - white-space: nowrap; - z-index: 1010; -} - -.select2-container .select2-search input { - background: #fff url('select2.png') no-repeat 100% -22px; - background: url('select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); - background: url('select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('select2.png') no-repeat 100% -22px, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); - background: url('select2.png') no-repeat 100% -22px, -ms-linear-gradient(top, #ffffff 85%, #eeeeee 99%); - background: url('select2.png') no-repeat 100% -22px, linear-gradient(top, #ffffff 85%, #eeeeee 99%); - margin: 1px 0; - padding: 4px 20px 4px 5px; - outline: 0; - border: 1px solid #aaa; - font-family: sans-serif; - font-size: 1em; -} - -.select2-container .select2-search input.select2-active { - background: #fff url('spinner.gif') no-repeat 100%; - background: url('spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); - background: url('spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('spinner.gif') no-repeat 100%, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); - background: url('spinner.gif') no-repeat 100%, -ms-linear-gradient(top, #ffffff 85%, #eeeeee 99%); - background: url('spinner.gif') no-repeat 100%, linear-gradient(top, #ffffff 85%, #eeeeee 99%); - margin: 1px 0; - padding: 4px 20px 4px 5px; - outline: 0; - border: 1px solid #aaa; - font-family: sans-serif; - font-size: 1em; -} - - -.select2-container-active .select2-choice, -.select2-container-active .select2-choices { - -webkit-box-shadow: none; - -moz-box-shadow: none; - box-shadow: none; - outline: thin dotted #333; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; - -} - -.select2-dropdown-open .select2-choice { - border: 1px solid #aaa; - -webkit-box-shadow: 0 1px 0 #fff inset; - -moz-box-shadow : 0 1px 0 #fff inset; - -o-box-shadow : 0 1px 0 #fff inset; - box-shadow : 0 1px 0 #fff inset; - background-color: #eee; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, white), color-stop(0.5, #eeeeee)); - background-image: -webkit-linear-gradient(center bottom, white 0%, #eeeeee 50%); - background-image: -moz-linear-gradient(center bottom, white 0%, #eeeeee 50%); - background-image: -o-linear-gradient(bottom, white 0%, #eeeeee 50%); - background-image: -ms-linear-gradient(top, #ffffff 0%,#eeeeee 50%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee',GradientType=0 ); - background-image: linear-gradient(top, #ffffff 0%,#eeeeee 50%); - -webkit-border-bottom-left-radius : 0; - -webkit-border-bottom-right-radius: 0; - -moz-border-radius-bottomleft : 0; - -moz-border-radius-bottomright: 0; - border-bottom-left-radius : 0; - border-bottom-right-radius: 0; -} - -.select2-dropdown-open .select2-choice div { - background: transparent; - border-left: none; -} -.select2-dropdown-open .select2-choice div b { - background-position: -18px 1px; -} - -/* results */ -.select2-container .select2-results { - margin: 0 4px 4px 0; - padding: 0 0 0 4px; - position: relative; - overflow-x: hidden; - overflow-y: auto; - max-height: 200px; -} -.select2-container .select2-results li { - line-height: 80%; - padding: 7px 7px 8px; - margin: 0; - list-style: none; - cursor: pointer; - display: list-item; -} - -.select2-container .select2-results .select2-highlighted { - background: #3875d7; - color: #fff; -} -.select2-container .select2-results li em { - background: #feffde; - font-style: normal; -} -.select2-container .select2-results .select2-highlighted em { - background: transparent; -} -.select2-container .select2-results .select2-no-results { - background: #f4f4f4; - display: list-item; -} - -.select2-container .select2-results .select2-disabled.select2-highlighted { - color: #666; - background: #f4f4f4; - display: list-item; - cursor: default; -} -.select2-container .select2-results .select2-disabled { - background: #f4f4f4; - display: list-item; - cursor: default; -} - - -.select2-more-results.select2-active { - background: #f4f4f4 url('spinner.gif') no-repeat 100%; -} - -.select2-more-results { - background: #f4f4f4; - display: list-item; -} - -/* multiselect */ - -.select2-container-multi .select2-choices { - background-color: #fff; - background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); - background-image: -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%); - background-image: -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%); - background-image: -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%); - background-image: -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%); - background-image: linear-gradient(top, #eeeeee 1%, #ffffff 15%); - border: 1px solid #aaa; - margin: 0; - padding: 0; - cursor: text; - overflow: hidden; - height: auto !important; - height: 1%; - position: relative; -} -.select2-container-multi .select2-choices li { - float: left; - list-style: none; -} -.select2-container-multi .select2-choices .select2-search-field { - white-space: nowrap; - margin: 0; - padding: 0; -} - -.select2-container-multi .select2-choices .select2-search-field input { - color: #666; - background: transparent !important; - font-family: sans-serif; - font-size: 100%; - height: 15px; - padding: 5px; - margin: 1px 0; - outline: 0; - border: 0; - -webkit-box-shadow: none; - -moz-box-shadow : none; - -o-box-shadow : none; - box-shadow : none; -} - - -.select2-default { - color: #999 !important; -} - -.select2-container-multi .select2-choices .select2-search-choice { - -webkit-border-radius: 3px; - -moz-border-radius : 3px; - border-radius : 3px; - -moz-background-clip : padding; - -webkit-background-clip: padding-box; - background-clip : padding-box; - background-color: #e4e4e4; - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f4f4f4', endColorstr='#eeeeee', GradientType=0 ); - background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee)); - background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); - background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); - background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); - background-image: -ms-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); - background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); - -webkit-box-shadow: 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); - -moz-box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); - box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); - color: #333; - border: 1px solid #aaaaaa; - line-height: 13px; - padding: 3px 5px 3px 18px; - margin: 3px 0 3px 5px; - position: relative; - cursor: default; -} -.select2-container-multi .select2-choices .select2-search-choice span { - cursor: default; -} -.select2-container-multi .select2-choices .select2-search-choice-focus { - background: #d4d4d4; -} - -.select2-search-choice-close { - display: block; - position: absolute; - right: 3px; - top: 4px; - width: 12px; - height: 13px; - font-size: 1px; - background: url(select2.png) right top no-repeat; -} - -.select2-container-multi .select2-search-choice-close { - left: 3px; -} - - -.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover { - background-position: right -11px; -} -.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close { - background-position: right -11px; -} - - -.select2-container-multi .select2-results { - margin: -1px 0 0; - padding: 0; -} - -/* end multiselect */ +.select2-container { + position: relative; + display: inline-block; + /* inline-block for ie7 */ + zoom: 1; + *display: inline; + +} + +.select2-container .select2-choice { + background-color: #fff; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(0.5, white)); + background-image: -webkit-linear-gradient(center bottom, #eeeeee 0%, white 50%); + background-image: -moz-linear-gradient(center bottom, #eeeeee 0%, white 50%); + background-image: -o-linear-gradient(top, #eeeeee 0%, #ffffff 50%); + background-image: -ms-linear-gradient(top, #eeeeee 0%, #ffffff 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#ffffff', GradientType = 0); + background-image: linear-gradient(top, #eeeeee 0%, #ffffff 50%); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + border: 1px solid #aaa; + display: block; + overflow: hidden; + white-space: nowrap; + position: relative; + height: 26px; + line-height: 26px; + padding: 0 0 0 8px; + color: #444; + text-decoration: none; +} + +.select2-container .select2-choice span { + margin-right: 26px; + display: block; + overflow: hidden; + white-space: nowrap; + -o-text-overflow: ellipsis; + -ms-text-overflow: ellipsis; + text-overflow: ellipsis; +} + +.select2-container .select2-choice abbr { + display: block; + position: absolute; + right: 26px; + top: 8px; + width: 12px; + height: 12px; + font-size: 1px; + background: url(select2.png) right top no-repeat; + cursor: pointer; + text-decoration: none; + border:0; + outline: 0; +} +.select2-container .select2-choice abbr:hover { + background-position: right -11px; + cursor: pointer; +} + +.select2-container .select2-drop { + background: #fff; + border: 1px solid #aaa; + border-top: 0; + position: absolute; + top: 29px; + left: 0; + -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); + -moz-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); + -o-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 4px 5px rgba(0, 0, 0, .15); + z-index: 999; + + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} + +.select2-container .select2-choice div { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; + background: #ccc; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee)); + background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%); + background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%); + background-image: -o-linear-gradient(bottom, #ccc 0%, #eee 60%); + background-image: -ms-linear-gradient(top, #cccccc 0%, #eeeeee 60%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#cccccc', endColorstr = '#eeeeee', GradientType = 0); + background-image: linear-gradient(top, #cccccc 0%, #eeeeee 60%); + border-left: 1px solid #aaa; + position: absolute; + right: 0; + top: 0; + display: block; + height: 100%; + width: 18px; +} + +.select2-container .select2-choice div b { + background: url('select2.png') no-repeat 0 1px; + display: block; + width: 100%; + height: 100%; +} + +.select2-container .select2-search { + padding: 3px 4px; + position: relative; + margin: 0; + white-space: nowrap; + z-index: 1010; +} + +.select2-container .select2-search input { + background: #fff url('select2.png') no-repeat 100% -22px; + background: url('select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); + background: url('select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); + background: url('select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); + background: url('select2.png') no-repeat 100% -22px, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); + background: url('select2.png') no-repeat 100% -22px, -ms-linear-gradient(top, #ffffff 85%, #eeeeee 99%); + background: url('select2.png') no-repeat 100% -22px, linear-gradient(top, #ffffff 85%, #eeeeee 99%); + margin: 1px 0; + padding: 4px 20px 4px 5px; + outline: 0; + border: 1px solid #aaa; + font-family: sans-serif; + font-size: 1em; +} + +.select2-container .select2-search input.select2-active { + background: #fff url('spinner.gif') no-repeat 100%; + background: url('spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); + background: url('spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); + background: url('spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); + background: url('spinner.gif') no-repeat 100%, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); + background: url('spinner.gif') no-repeat 100%, -ms-linear-gradient(top, #ffffff 85%, #eeeeee 99%); + background: url('spinner.gif') no-repeat 100%, linear-gradient(top, #ffffff 85%, #eeeeee 99%); + margin: 1px 0; + padding: 4px 20px 4px 5px; + outline: 0; + border: 1px solid #aaa; + font-family: sans-serif; + font-size: 1em; +} + + +.select2-container-active .select2-choice, +.select2-container-active .select2-choices { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; + +} + +.select2-dropdown-open .select2-choice { + border: 1px solid #aaa; + -webkit-box-shadow: 0 1px 0 #fff inset; + -moz-box-shadow : 0 1px 0 #fff inset; + -o-box-shadow : 0 1px 0 #fff inset; + box-shadow : 0 1px 0 #fff inset; + background-color: #eee; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, white), color-stop(0.5, #eeeeee)); + background-image: -webkit-linear-gradient(center bottom, white 0%, #eeeeee 50%); + background-image: -moz-linear-gradient(center bottom, white 0%, #eeeeee 50%); + background-image: -o-linear-gradient(bottom, white 0%, #eeeeee 50%); + background-image: -ms-linear-gradient(top, #ffffff 0%,#eeeeee 50%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee',GradientType=0 ); + background-image: linear-gradient(top, #ffffff 0%,#eeeeee 50%); + -webkit-border-bottom-left-radius : 0; + -webkit-border-bottom-right-radius: 0; + -moz-border-radius-bottomleft : 0; + -moz-border-radius-bottomright: 0; + border-bottom-left-radius : 0; + border-bottom-right-radius: 0; +} + +.select2-dropdown-open .select2-choice div { + background: transparent; + border-left: none; +} +.select2-dropdown-open .select2-choice div b { + background-position: -18px 1px; +} + +/* results */ +.select2-container .select2-results { + margin: 0 4px 4px 0; + padding: 0 0 0 4px; + position: relative; + overflow-x: hidden; + overflow-y: auto; + max-height: 200px; +} +.select2-container .select2-results li { + line-height: 80%; + padding: 7px 7px 8px; + margin: 0; + list-style: none; + cursor: pointer; + display: list-item; +} + +.select2-container .select2-results .select2-highlighted { + background: #3875d7; + color: #fff; +} +.select2-container .select2-results li em { + background: #feffde; + font-style: normal; +} +.select2-container .select2-results .select2-highlighted em { + background: transparent; +} +.select2-container .select2-results .select2-no-results { + background: #f4f4f4; + display: list-item; +} + +.select2-container .select2-results .select2-disabled.select2-highlighted { + color: #666; + background: #f4f4f4; + display: list-item; + cursor: default; +} +.select2-container .select2-results .select2-disabled { + background: #f4f4f4; + display: list-item; + cursor: default; +} + + +.select2-more-results.select2-active { + background: #f4f4f4 url('spinner.gif') no-repeat 100%; +} + +.select2-more-results { + background: #f4f4f4; + display: list-item; +} + +/* multiselect */ + +.select2-container-multi .select2-choices { + background-color: #fff; + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); + background-image: -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background-image: -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background-image: -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background-image: -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background-image: linear-gradient(top, #eeeeee 1%, #ffffff 15%); + border: 1px solid #aaa; + margin: 0; + padding: 0; + cursor: text; + overflow: hidden; + height: auto !important; + height: 1%; + position: relative; +} +.select2-container-multi .select2-choices li { + float: left; + list-style: none; +} +.select2-container-multi .select2-choices .select2-search-field { + white-space: nowrap; + margin: 0; + padding: 0; +} + +.select2-container-multi .select2-choices .select2-search-field input { + color: #666; + background: transparent !important; + font-family: sans-serif; + font-size: 100%; + height: 15px; + padding: 5px; + margin: 1px 0; + outline: 0; + border: 0; + -webkit-box-shadow: none; + -moz-box-shadow : none; + -o-box-shadow : none; + box-shadow : none; +} + + +.select2-default { + color: #999 !important; +} + +.select2-container-multi .select2-choices .select2-search-choice { + -webkit-border-radius: 3px; + -moz-border-radius : 3px; + border-radius : 3px; + -moz-background-clip : padding; + -webkit-background-clip: padding-box; + background-clip : padding-box; + background-color: #e4e4e4; + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f4f4f4', endColorstr='#eeeeee', GradientType=0 ); + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee)); + background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: -ms-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + -webkit-box-shadow: 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); + -moz-box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); + box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); + color: #333; + border: 1px solid #aaaaaa; + line-height: 13px; + padding: 3px 5px 3px 18px; + margin: 3px 0 3px 5px; + position: relative; + cursor: default; +} +.select2-container-multi .select2-choices .select2-search-choice span { + cursor: default; +} +.select2-container-multi .select2-choices .select2-search-choice-focus { + background: #d4d4d4; +} + +.select2-search-choice-close { + display: block; + position: absolute; + right: 3px; + top: 4px; + width: 12px; + height: 13px; + font-size: 1px; + background: url(select2.png) right top no-repeat; +} + +.select2-container-multi .select2-search-choice-close { + left: 3px; +} + + +.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover { + background-position: right -11px; +} +.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close { + background-position: right -11px; +} + + +.select2-container-multi .select2-results { + margin: -1px 0 0; + padding: 0; +} + +/* end multiselect */ diff --git a/select2.js b/select2.js index 761cd150..abb5b979 100755 --- a/select2.js +++ b/select2.js @@ -1,1156 +1,1156 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ -(function ($) { - "use strict"; - /*global document, window, jQuery, console */ - - var KEY = { - TAB: 9, - ENTER: 13, - ESC: 27, - SPACE: 32, - LEFT: 37, - UP: 38, - RIGHT: 39, - DOWN: 40, - SHIFT: 16, - CTRL: 17, - ALT: 18, - PAGE_UP: 33, - PAGE_DOWN: 34, - HOME: 36, - END: 35, - BACKSPACE: 8, - DELETE: 46, - isArrow: function (k) { - k = k.which ? k.which : k; - switch (k) { - case KEY.LEFT: - case KEY.RIGHT: - case KEY.UP: - case KEY.DOWN: - return true; - } - return false; - }, - isControl: function (k) { - k = k.which ? k.which : k; - switch (k) { - case KEY.SHIFT: - case KEY.CTRL: - case KEY.ALT: - return true; - } - return false; - }, - isFunctionKey: function (k) { - k = k.which ? k.which : k; - return k >= 112 && k <= 123; - } - }; - - function indexOf(value, array) { - var i = 0, l = array.length, v; - - if (value.constructor === String) { - for (; i < l; i++) if (value.localeCompare(array[i]) === 0) return i; - } else { - for (; i < l; i++) { - v = array[i]; - if (v.constructor === String) { - if (v.localeCompare(value) === 0) return i; - } else { - if (v === value) return i; - } - } - } - return -1; - } - - function getSideBorderPadding(element) { - return element.outerWidth() - element.width(); - } - - function installKeyUpChangeEvent(element) { - element.on("keydown", function () { - element.data("keyup-change-value", element.val()); - }); - element.on("keyup", function () { - if (element.val() !== element.data("keyup-change-value")) { - element.trigger("keyup-change"); - } - }); - } - - /** - * filters mouse events so an event is fired only if the mouse moved. - * - * filters out mouse events that occur when mouse is stationary but - * the elements under the pointer are scrolled. - */ - $(document).on("mousemove", function (e) { - $(this).data("select2-lastpos", {x: e.pageX, y: e.pageY}); - }); - function installFilteredMouseMove(element) { - var doc = $(document); - element.on("mousemove", function (e) { - var lastpos = doc.data("select2-lastpos"); - - if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) { - $(e.target).trigger("mousemove-filtered", e); - } - }); - } - - function debounce(threshold, fn) { - var timeout; - return function () { - window.clearTimeout(timeout); - timeout = window.setTimeout(fn, threshold); - }; - } - - function installDebouncedScroll(threshold, element) { - var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);}); - element.on("scroll", function (e) { - if (indexOf(e.target, element.get()) >= 0) notify(e); - }); - } - - function killEvent(event) { - event.preventDefault(); - event.stopPropagation(); - } - - function measureTextWidth(e) { - var sizer, width; - sizer = $("
").css({ - position: "absolute", - left: "-1000px", - top: "-1000px", - display: "none", - fontSize: e.css("fontSize"), - fontFamily: e.css("fontFamily"), - fontStyle: e.css("fontStyle"), - fontWeight: e.css("fontWeight"), - letterSpacing: e.css("letterSpacing"), - textTransform: e.css("textTransform"), - whiteSpace: "nowrap" - }); - sizer.text(e.val()); - $("body").append(sizer); - width = sizer.width(); - sizer.remove(); - return width; - } - - /** - * blurs any Select2 container that has focus when an element outside them was clicked or received focus - */ - $(document).ready(function () { - $(document).on("mousedown focusin", function (e) { - var target = $(e.target).closest("div.select2-container").get(0); - $(document).find("div.select2-container-active").each(function () { - if (this !== target) $(this).data("select2").blur(); - }); - }); - }); - - /** - * - * @param opts - */ - function AbstractSelect2() { - } - - AbstractSelect2.prototype.bind = function (func) { - var self = this; - return function () { - func.apply(self, arguments); - }; - }; - - AbstractSelect2.prototype.init = function (opts) { - var results, search; - - // prepare options - this.opts = this.prepareOpts(opts); - - this.container = this.createContainer(); - - if (opts.element.attr("class") !== undefined) { - this.container.addClass(opts.element.attr("class")); - } - - // swap container for the element - - this.opts.element.data("select2", this) - .hide() - .after(this.container); - this.container.data("select2", this); - - this.dropdown = this.container.find(".select2-drop"); - this.results = results = this.container.find(".select2-results"); - this.search = search = this.container.find("input[type=text]"); - // initialize the container - - this.resultsPage = 0; - - this.initContainer(); - - installFilteredMouseMove(this.results); - results.on("mousemove-filtered", this.bind(this.highlightUnderEvent)); - - installDebouncedScroll(80, this.results); - results.on("scroll-debounced", this.bind(this.loadMoreIfNeeded)); - - // if jquery.mousewheel plugin is installed we can prevent out-of-bounds scrolling of results via mousewheel - if ($.fn.mousewheel) { - results.mousewheel(function (e, delta, deltaX, deltaY) { - var top = results.scrollTop(), height; - if (deltaY > 0 && top - deltaY <= 0) { - results.scrollTop(0); - killEvent(e); - } else if (deltaY < 0 && results.get(0).scrollHeight - results.scrollTop() + deltaY <= results.height()) { - results.scrollTop(results.get(0).scrollHeight - results.height()); - killEvent(e); - } - }); - } - - installKeyUpChangeEvent(search); - search.on("keyup-change", this.bind(this.updateResults)); - - results.on("click", this.bind(function (e) { - if ($(e.target).closest(".select2-result:not(.select2-disabled)").length > 0) { - this.highlightUnderEvent(e); - this.selectHighlighted(e); - } else { - killEvent(e); - this.focusSearch(); - } - })); - }; - - AbstractSelect2.prototype.prepareOpts = function (opts) { - var element, select; - - opts = $.extend({}, { - formatResult: function (data) { return data.text; }, - formatSelection: function (data) { return data.text; }, - formatNoMatches: function () { return "No matches found"; }, - formatInputTooShort: function (input, min) { return "Please enter " + (min - input.length) + " more characters"; }, - minimumResultsForSearch: 0 - }, opts); - - element = opts.element; - - if (element.get(0).tagName.toLowerCase() === "select") { - this.select = select = opts.element; - } - - // TODO add missing validation logic - if (select) { - /*$.each(["multiple", "ajax", "query", "minimumInputLength"], function () { - if (this in opts) { - throw "Option '" + this + "' is not allowed for Select2 when attached to a select element"; - } - });*/ - this.opts = opts = $.extend({}, { - miniumInputLength: 0 - }, opts); - } else { - this.opts = opts = $.extend({}, { - miniumInputLength: 0 - }, opts); - } - - if (select) { - opts.query = this.bind(function (query) { - var data = {results: [], more: false}, - term = query.term.toUpperCase(), - placeholder = this.getPlaceholder(); - element.find("option").each(function (i) { - var e = $(this), - text = e.text(); - - if (i === 0 && placeholder !== undefined && text === "") return true; - - if (text.toUpperCase().indexOf(term) >= 0) { - data.results.push({id: e.attr("value"), text: text}); - } - }); - query.callback(data); - }); - } else { - if (!("query" in opts)) { - if ("ajax" in opts) { - opts.query = (function () { - var timeout, // current scheduled but not yet executed request - requestSequence = 0, // sequence used to drop out-of-order responses - quietMillis = opts.ajax.quietMillis || 100; - - return function (query) { - window.clearTimeout(timeout); - timeout = window.setTimeout(function () { - requestSequence += 1; // increment the sequence - var requestNumber = requestSequence, // this request's sequence number - options = opts.ajax, // ajax parameters - data = options.data; // ajax data function - - data = data.call(this, query.term, query.page); - - $.ajax({ - url: options.url, - dataType: options.dataType, - data: data - }).success( - function (data) { - if (requestNumber < requestSequence) { - return; - } - query.callback(options.results(data, query.page)); - } - ); - }, quietMillis); - }; - }()); - } else if ("data" in opts) { - opts.query = (function () { - var data = opts.data, // data elements - text = function (item) { return item.text; }; // function used to retrieve the text portion of a data item that is matched against the search - - if (!$.isArray(data)) { - text = data.text; - // if text is not a function we assume it to be a key name - if (!$.isFunction(text)) text = function (item) { return item[data.text]; }; - data = data.results; - } - - return function (query) { - var t = query.term.toUpperCase(), filtered = {}; - if (t === "") { - query.callback({results: data}); - return; - } - filtered.result = $(data) - .filter(function () {return text(this).toUpperCase().indexOf(t) >= 0;}) - .get(); - query.callback(filtered); - }; - }()); - } - } - } - if (typeof(opts.query) !== "function") { - throw "query function not defined for Select2 " + opts.element.attr("id"); - } - - return opts; - }; - - AbstractSelect2.prototype.opened = function () { - return this.container.hasClass("select2-dropdown-open"); - }; - - AbstractSelect2.prototype.alignDropdown = function () { - this.dropdown.css({ - top: this.container.height(), - width: this.container.outerWidth() - getSideBorderPadding(this.dropdown) - }); - }; - - AbstractSelect2.prototype.open = function () { - var width; - - if (this.opened()) return; - - this.container.addClass("select2-dropdown-open").addClass("select2-container-active"); - - this.updateResults(true); - this.alignDropdown(); - this.dropdown.show(); - this.focusSearch(); - }; - - AbstractSelect2.prototype.close = function () { - if (!this.opened()) return; - - this.dropdown.hide(); - this.container.removeClass("select2-dropdown-open"); - this.results.empty(); - this.clearSearch(); - }; - - AbstractSelect2.prototype.clearSearch = function () { - - }; - - AbstractSelect2.prototype.ensureHighlightVisible = function () { - var results = this.results, children, index, child, hb, rb, y, more; - - children = results.children(".select2-result"); - index = this.highlight(); - - if (index < 0) return; - - child = $(children[index]); - - hb = child.offset().top + child.outerHeight(); - - // if this is the last child lets also make sure select2-more-results is visible - if (index === children.length - 1) { - more = results.find("li.select2-more-results"); - if (more.length > 0) { - hb = more.offset().top + more.outerHeight(); - } - } - - rb = results.offset().top + results.outerHeight(); - if (hb > rb) { - results.scrollTop(results.scrollTop() + (hb - rb)); - } - y = child.offset().top - results.offset().top; - - // make sure the top of the element is visible - if (y < 0) { - results.scrollTop(results.scrollTop() + y); // y is negative - } - }; - - AbstractSelect2.prototype.moveHighlight = function (delta) { - var choices = this.results.children(".select2-result"), - index = this.highlight(); - - while (index > -1 && index < choices.length) { - index += delta; - if (!$(choices[index]).hasClass("select2-disabled")) { - this.highlight(index); - break; - } - } - }; - - AbstractSelect2.prototype.highlight = function (index) { - var choices = this.results.children(".select2-result"); - - if (arguments.length === 0) { - return indexOf(choices.filter(".select2-highlighted")[0], choices.get()); - } - - choices.removeClass("select2-highlighted"); - - if (index >= choices.length) index = choices.length - 1; - if (index < 0) index = 0; - - $(choices[index]).addClass("select2-highlighted"); - this.ensureHighlightVisible(); - - if (this.opened()) this.focusSearch(); - }; - - AbstractSelect2.prototype.highlightUnderEvent = function (event) { - var el = $(event.target).closest(".select2-result"); - if (el.length > 0) { - this.highlight(el.index()); - } - }; - - AbstractSelect2.prototype.loadMoreIfNeeded = function () { - var results = this.results, - more = results.find("li.select2-more-results"), - below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible - offset = -1, // index of first element without data - page = this.resultsPage + 1; - - if (more.length === 0) return; - - below = more.offset().top - results.offset().top - results.height(); - - if (below <= 0) { - more.addClass("select2-active"); - this.opts.query({term: this.search.val(), page: page, callback: this.bind(function (data) { - var parts = [], self = this; - $(data.results).each(function () { - parts.push("
  • "); - parts.push(self.opts.formatResult(this)); - parts.push("
  • "); - }); - more.before(parts.join("")); - results.find(".select2-result").each(function (i) { - var e = $(this); - if (e.data("select2-data") !== undefined) { - offset = i; - } else { - e.data("select2-data", data.results[i - offset - 1]); - } - }); - if (data.more) { - more.removeClass("select2-active"); - } else { - more.remove(); - } - this.resultsPage = page; - })}); - } - }; - - /** - * @param initial whether or not this is the call to this method right after the dropdown has been opened - */ - AbstractSelect2.prototype.updateResults = function (initial) { - var search = this.search, results = this.results, opts = this.opts; - - search.addClass("select2-active"); - - function render(html) { - results.html(html); - results.scrollTop(0); - search.removeClass("select2-active"); - } - - if (search.val().length < opts.minimumInputLength) { - render("
  • " + opts.formatInputTooShort(search.val(), opts.minimumInputLength) + "
  • "); - return; - } - - this.resultsPage = 1; - opts.query({term: search.val(), page: this.resultsPage, callback: this.bind(function (data) { - var parts = []; // html parts - - if (data.results.length === 0) { - render("
  • " + opts.formatNoMatches(search.val()) + "
  • "); - return; - } - - $(data.results).each(function () { - parts.push("
  • "); - parts.push(opts.formatResult(this)); - parts.push("
  • "); - }); - - if (data.more === true) { - parts.push("
  • Loading more results...
  • "); - } - - render(parts.join("")); - results.children(".select2-result").each(function (i) { - var d = data.results[i]; - $(this).data("select2-data", d); - }); - this.postprocessResults(data, initial); - })}); - }; - - AbstractSelect2.prototype.cancel = function () { - this.close(); - }; - - AbstractSelect2.prototype.blur = function () { - /* we do this in a timeout so that current event processing can complete before this code is executed. - this allows tab index to be preserved even if this code blurs the textfield */ - window.setTimeout(this.bind(function () { - this.close(); - this.container.removeClass("select2-container-active"); - this.clearSearch(); - this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); - this.search.blur(); - }), 10); - }; - - AbstractSelect2.prototype.focusSearch = function () { - /* we do this in a timeout so that current event processing can complete before this code is executed. - this makes sure the search field is focussed even if the current event would blur it */ - window.setTimeout(this.bind(function () { - this.search.focus(); - }), 10); - }; - - AbstractSelect2.prototype.selectHighlighted = function () { - var data = this.results.find(".select2-highlighted:not(.select2-disabled)").data("select2-data"); - if (data) { - this.onSelect(data); - } - }; - - AbstractSelect2.prototype.getPlaceholder = function () { - var placeholder = this.opts.element.data("placeholder"); - if (placeholder !== undefined) return placeholder; - return this.opts.placeholder; - }; - - function SingleSelect2() { - } - - SingleSelect2.prototype = new AbstractSelect2(); - SingleSelect2.prototype.constructor = SingleSelect2; - SingleSelect2.prototype.parent = AbstractSelect2.prototype; - - SingleSelect2.prototype.createContainer = function () { - return $("
    ", { - "class": "select2-container", - "style": "width: " + this.opts.element.outerWidth() + "px" - }).html([ - " ", - " ", - "
    " , - "
    ", - " "].join("")); - }; - - SingleSelect2.prototype.open = function () { - - var width; - - if (this.opened()) return; - - this.parent.open.apply(this, arguments); - - // size the search field - - width = this.dropdown.width(); - width -= getSideBorderPadding(this.container.find(".select2-search")); - width -= getSideBorderPadding(this.search); - this.search.css({width: width}); - }; - - SingleSelect2.prototype.close = function () { - if (!this.opened()) return; - this.parent.close.apply(this, arguments); - }; - - SingleSelect2.prototype.cancel = function () { - this.parent.cancel.apply(this, arguments); - this.selection.focus(); - }; - - SingleSelect2.prototype.initContainer = function () { - - var selection, container = this.container, clickingInside = false, - selected; - - this.selection = selection = container.find(".select2-choice"); - - this.search.on("keydown", this.bind(function (e) { - switch (e.which) { - case KEY.UP: - case KEY.DOWN: - this.moveHighlight((e.which === KEY.UP) ? -1 : 1); - killEvent(e); - return; - case KEY.TAB: - case KEY.ENTER: - this.selectHighlighted(); - killEvent(e); - return; - case KEY.ESC: - this.cancel(e); - e.preventDefault(); - return; - } - })); - - selection.on("click", this.bind(function (e) { - clickingInside = true; - - if (this.opened()) { - this.close(); - selection.focus(); - } else { - this.open(); - } - e.preventDefault(); - - clickingInside = false; - })); - selection.on("keydown", this.bind(function (e) { - if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) { - return; - } - this.open(); - if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN || e.which === KEY.SPACE) { - // prevent the page from scrolling - killEvent(e); - } - if (e.which === KEY.ENTER) { - // do not propagate the event otherwise we open, and propagate enter which closes - killEvent(e); - } - })); - selection.on("focus", function () { container.addClass("select2-container-active"); }); - selection.on("blur", this.bind(function () { - if (clickingInside) return; - if (!this.opened()) this.blur(); - })); - - selection.find("abbr") - .on("click", this.bind(function (e) { - this.val(""); - killEvent(e); - this.close(); - } - )); - - if (this.select) { - selected = this.select.find(":selected"); - this.updateSelection({id: selected.attr("value"), text: selected.text()}); - } - - this.setPlaceholder(); - }; - - SingleSelect2.prototype.setPlaceholder = function () { - var placeholder = this.getPlaceholder(); - - if (this.opts.element.val() === "" && placeholder !== undefined) { - - // check for a first blank option if attached to a select - if (this.select && this.select.find("option:first").text() !== "") return; - - if (typeof(placeholder) === "object") { - this.updateSelection(placeholder); - } else { - this.selection.find("span").html(placeholder); - } - this.selection.addClass("select2-default"); - - this.selection.find("abbr").hide(); - } - }; - - SingleSelect2.prototype.postprocessResults = function (data, initial) { - var selected = 0, self = this; - - // find the selected element in the result list - - this.results.find(".select2-result").each(function (i) { - if ($(this).data("select2-data").id === self.opts.element.val()) { - selected = i; - return false; - } - }); - - // and highlight it - - this.highlight(selected); - - // hide the search box if this is the first we got the results and there are a few of them - - if (initial === true) { - this.search.toggle(data.results.length >= this.opts.minimumResultsForSearch); - } - - }; - - SingleSelect2.prototype.onSelect = function (data) { - this.opts.element.val(data.id); - this.updateSelection(data); - this.close(); - this.selection.focus(); - }; - - SingleSelect2.prototype.updateSelection = function (data) { - this.selection.find("span").html(this.opts.formatSelection(data)); - this.selection.removeClass("select2-default"); - if (this.opts.allowClear && this.getPlaceholder() !== undefined) { - this.selection.find("abbr").show(); - } - }; - - SingleSelect2.prototype.val = function () { - var val, data = null; - - if (arguments.length === 0) { - return this.opts.element.val(); - } - - val = arguments[0]; - - if (this.select) { - // val is an id - this.select.val(val); - this.select.find(":selected").each(function () { - data = {id: $(this).attr("value"), text: $(this).text()}; - return false; - }); - this.updateSelection(data); - } else { - // val is an object - this.opts.element.val((val === null) ? "" : val.id); - this.updateSelection(val); - } - this.setPlaceholder(); - - }; - - SingleSelect2.prototype.clearSearch = function () { - this.search.val(""); - }; - - function MultiSelect2(opts) { - - } - - MultiSelect2.prototype = new AbstractSelect2(); - MultiSelect2.prototype.constructor = AbstractSelect2; - MultiSelect2.prototype.parent = AbstractSelect2.prototype; - - MultiSelect2.prototype.createContainer = function () { - return $("
    ", { - "class": "select2-container select2-container-multi", - "style": "width: " + this.opts.element.outerWidth() + "px" - }).html([ - " " , - ""].join("")); - }; - - MultiSelect2.prototype.initContainer = function () { - - var selection, data; - - this.searchContainer = this.container.find(".select2-search-field"); - this.selection = selection = this.container.find(".select2-choices"); - - this.search.on("keydown", this.bind(function (e) { - if (e.which === KEY.BACKSPACE && this.search.val() === "") { - this.close(); - - var choices, - selected = this.selection.find(".select2-search-choice-focus"); - if (selected.length > 0) { - this.unselect(selected.first()); - this.search.width(10); - killEvent(e); - return; - } - - choices = this.selection.find(".select2-search-choice"); - if (choices.length > 0) { - choices.last().addClass("select2-search-choice-focus"); - } - } else { - this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); - } - - if (this.opened()) { - switch (e.which) { - case KEY.UP: - case KEY.DOWN: - this.moveHighlight((e.which === KEY.UP) ? -1 : 1); - killEvent(e); - return; - case KEY.ENTER: - this.selectHighlighted(); - killEvent(e); - return; - case KEY.ESC: - this.cancel(e); - e.preventDefault(); - return; - } - } - - if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.BACKSPACE || e.which === KEY.ESC) { - return; - } - - this.open(); - - if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { - // prevent the page from scrolling - killEvent(e); - } - })); - - this.search.on("keyup", this.bind(this.resizeSearch)); - - this.selection.on("click", this.bind(function (e) { - if (this.select) { - this.open(); - } - this.focusSearch(); - e.preventDefault(); - })); - - this.search.on("focus", this.bind(function () { - this.container.addClass("select2-container-active"); - this.clearPlaceholder(); - })); - - if (this.select) { - data = []; - this.select.find(":selected").each(function () { - data.push({id: $(this).attr("value"), text: $(this).text()}); - }); - - this.updateSelection(data); - } - - // set the placeholder if necessary - this.clearSearch(); - }; - - MultiSelect2.prototype.clearSearch = function () { - var placeholder = this.getPlaceholder(); - - this.search.val("").width(10); - - if (placeholder !== undefined && this.getVal().length === 0) { - this.search.val(placeholder).addClass("select2-default"); - this.resizeSearch(); - } - }; - - MultiSelect2.prototype.clearPlaceholder = function () { - if (this.search.hasClass("select2-default")) { - this.search.val("").removeClass("select2-default"); - } - }; - - MultiSelect2.prototype.open = function () { - if (this.opened()) return; - this.parent.open.apply(this, arguments); - this.resizeSearch(); - this.focusSearch(); - }; - - MultiSelect2.prototype.close = function () { - if (!this.opened()) return; - this.parent.close.apply(this, arguments); - }; - - MultiSelect2.prototype.updateSelection = function (data) { - var self = this; - this.selection.find(".select2-search-choice").remove(); - $(data).each(function () { - self.addSelectedChoice(this); - }); - self.postprocessResults(); - this.alignDropdown(); - }; - - MultiSelect2.prototype.onSelect = function (data) { - this.addSelectedChoice(data); - if (this.select) { this.postprocessResults(); } - this.close(); - this.search.width(10); - this.focusSearch(); - }; - - MultiSelect2.prototype.cancel = function () { - this.close(); - this.focusSearch(); - }; - - MultiSelect2.prototype.addSelectedChoice = function (data) { - var choice, - id = data.id, - parts, - val = this.getVal(); - - parts = ["
  • ", - this.opts.formatSelection(data), - "", - "
  • " - ]; - - choice = $(parts.join("")); - choice.find("a") - .on("click dblclick", this.bind(function (e) { - this.unselect($(e.target)); - this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); - killEvent(e); - this.close(); - this.focusSearch(); - })).on("focus", this.bind(function () { - this.container.addClass("select2-container-active"); - })); - - choice.data("select2-data", data); - choice.insertBefore(this.searchContainer); - - val.push(id); - this.setVal(val); - }; - - MultiSelect2.prototype.unselect = function (selected) { - var val = this.getVal(), - index; - - selected = selected.closest(".select2-search-choice"); - - if (selected.length === 0) { - throw "Invalid argument: " + selected + ". Must be .select2-search-choice"; - } - - index = indexOf(selected.data("select2-data").id, val); - - if (index >= 0) { - val.splice(index, 1); - this.setVal(val); - if (this.select) this.postprocessResults(); - } - selected.remove(); - window.setTimeout(this.bind(this.alignDropdown), 20); - }; - - MultiSelect2.prototype.postprocessResults = function () { - var val = this.getVal(), - choices = this.results.find(".select2-result"), - self = this; - - choices.each(function () { - var choice = $(this), id = choice.data("select2-data").id; - if (val.indexOf(id) >= 0) { - choice.addClass("select2-disabled"); - } else { - choice.removeClass("select2-disabled"); - } - }); - - choices.each(function (i) { - if (!$(this).hasClass("select2-disabled")) { - self.highlight(i); - return false; - } - }); - - }; - - MultiSelect2.prototype.resizeSearch = function () { - - var minimumWidth, left, maxWidth, containerLeft, searchWidth; - - minimumWidth = measureTextWidth(this.search) + 10; - - left = this.search.offset().left; - - maxWidth = this.selection.width(); - containerLeft = this.selection.offset().left; - - searchWidth = maxWidth - (left - containerLeft) - getSideBorderPadding(this.search); - - if (searchWidth < minimumWidth) { - searchWidth = maxWidth - getSideBorderPadding(this.search); - } - - if (searchWidth < 40) { - searchWidth = maxWidth - getSideBorderPadding(this.search); - } - this.search.width(searchWidth); - }; - - MultiSelect2.prototype.getVal = function () { - var val; - if (this.select) { - val = this.select.val(); - return val === null ? [] : val; - } else { - val = this.opts.element.val(); - return (val === null || val === "") ? [] : val.split(","); - } - }; - - MultiSelect2.prototype.setVal = function (val) { - if (this.select) { - this.select.val(val); - } else { - this.opts.element.val(val.length === 0 ? "" : val.join(",")); - } - }; - - MultiSelect2.prototype.val = function () { - var val, data = []; - - if (arguments.length === 0) { - return this.getVal(); - } - - val = arguments[0]; - - if (this.select) { - // val is a list of ids - this.setVal(val); - this.select.find(":selected").each(function () { - data.push({id: $(this).attr("value"), text: $(this).text()}); - }); - this.updateSelection(data); - } else { - val = (val === null) ? [] : val; - this.setVal(val); - // val is a list of objects - - $(val).each(function () { data.push(this.id); }); - this.setVal(data); - this.updateSelection(val); - } - }; - - $.fn.select2 = function () { - - var args = Array.prototype.slice.call(arguments, 0), - opts, - select2, - value, multiple, allowedMethods = ["val"]; - - this.each(function () { - if (args.length === 0 || typeof(args[0]) === "object") { - opts = args.length === 0 ? {} : args[0]; - opts.element = $(this); - - if (opts.element.get(0).tagName.toLowerCase() === "select") { - multiple = opts.element.prop("multiple"); - } else { - multiple = opts.multiple || false; - } - - select2 = multiple ? new MultiSelect2() : new SingleSelect2(); - select2.init(opts); - } else if (typeof(args[0]) === "string") { - - if (indexOf(args[0], allowedMethods) < 0) { - throw "Unknown method: " + args[0]; - } - - value = undefined; - select2 = $(this).data("select2"); - value = select2[args[0]].apply(select2, args.slice(1)); - if (value !== undefined) {return false;} - } else { - throw "Invalid arguments to select2 plugin: " + args; - } - }); - return (value === undefined) ? this : value; - }; - -}(jQuery)); +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ +(function ($) { + "use strict"; + /*global document, window, jQuery, console */ + + var KEY = { + TAB: 9, + ENTER: 13, + ESC: 27, + SPACE: 32, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + SHIFT: 16, + CTRL: 17, + ALT: 18, + PAGE_UP: 33, + PAGE_DOWN: 34, + HOME: 36, + END: 35, + BACKSPACE: 8, + DELETE: 46, + isArrow: function (k) { + k = k.which ? k.which : k; + switch (k) { + case KEY.LEFT: + case KEY.RIGHT: + case KEY.UP: + case KEY.DOWN: + return true; + } + return false; + }, + isControl: function (k) { + k = k.which ? k.which : k; + switch (k) { + case KEY.SHIFT: + case KEY.CTRL: + case KEY.ALT: + return true; + } + return false; + }, + isFunctionKey: function (k) { + k = k.which ? k.which : k; + return k >= 112 && k <= 123; + } + }; + + function indexOf(value, array) { + var i = 0, l = array.length, v; + + if (value.constructor === String) { + for (; i < l; i++) if (value.localeCompare(array[i]) === 0) return i; + } else { + for (; i < l; i++) { + v = array[i]; + if (v.constructor === String) { + if (v.localeCompare(value) === 0) return i; + } else { + if (v === value) return i; + } + } + } + return -1; + } + + function getSideBorderPadding(element) { + return element.outerWidth() - element.width(); + } + + function installKeyUpChangeEvent(element) { + element.on("keydown", function () { + element.data("keyup-change-value", element.val()); + }); + element.on("keyup", function () { + if (element.val() !== element.data("keyup-change-value")) { + element.trigger("keyup-change"); + } + }); + } + + /** + * filters mouse events so an event is fired only if the mouse moved. + * + * filters out mouse events that occur when mouse is stationary but + * the elements under the pointer are scrolled. + */ + $(document).on("mousemove", function (e) { + $(this).data("select2-lastpos", {x: e.pageX, y: e.pageY}); + }); + function installFilteredMouseMove(element) { + var doc = $(document); + element.on("mousemove", function (e) { + var lastpos = doc.data("select2-lastpos"); + + if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) { + $(e.target).trigger("mousemove-filtered", e); + } + }); + } + + function debounce(threshold, fn) { + var timeout; + return function () { + window.clearTimeout(timeout); + timeout = window.setTimeout(fn, threshold); + }; + } + + function installDebouncedScroll(threshold, element) { + var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);}); + element.on("scroll", function (e) { + if (indexOf(e.target, element.get()) >= 0) notify(e); + }); + } + + function killEvent(event) { + event.preventDefault(); + event.stopPropagation(); + } + + function measureTextWidth(e) { + var sizer, width; + sizer = $("
    ").css({ + position: "absolute", + left: "-1000px", + top: "-1000px", + display: "none", + fontSize: e.css("fontSize"), + fontFamily: e.css("fontFamily"), + fontStyle: e.css("fontStyle"), + fontWeight: e.css("fontWeight"), + letterSpacing: e.css("letterSpacing"), + textTransform: e.css("textTransform"), + whiteSpace: "nowrap" + }); + sizer.text(e.val()); + $("body").append(sizer); + width = sizer.width(); + sizer.remove(); + return width; + } + + /** + * blurs any Select2 container that has focus when an element outside them was clicked or received focus + */ + $(document).ready(function () { + $(document).on("mousedown focusin", function (e) { + var target = $(e.target).closest("div.select2-container").get(0); + $(document).find("div.select2-container-active").each(function () { + if (this !== target) $(this).data("select2").blur(); + }); + }); + }); + + /** + * + * @param opts + */ + function AbstractSelect2() { + } + + AbstractSelect2.prototype.bind = function (func) { + var self = this; + return function () { + func.apply(self, arguments); + }; + }; + + AbstractSelect2.prototype.init = function (opts) { + var results, search; + + // prepare options + this.opts = this.prepareOpts(opts); + + this.container = this.createContainer(); + + if (opts.element.attr("class") !== undefined) { + this.container.addClass(opts.element.attr("class")); + } + + // swap container for the element + + this.opts.element.data("select2", this) + .hide() + .after(this.container); + this.container.data("select2", this); + + this.dropdown = this.container.find(".select2-drop"); + this.results = results = this.container.find(".select2-results"); + this.search = search = this.container.find("input[type=text]"); + // initialize the container + + this.resultsPage = 0; + + this.initContainer(); + + installFilteredMouseMove(this.results); + results.on("mousemove-filtered", this.bind(this.highlightUnderEvent)); + + installDebouncedScroll(80, this.results); + results.on("scroll-debounced", this.bind(this.loadMoreIfNeeded)); + + // if jquery.mousewheel plugin is installed we can prevent out-of-bounds scrolling of results via mousewheel + if ($.fn.mousewheel) { + results.mousewheel(function (e, delta, deltaX, deltaY) { + var top = results.scrollTop(), height; + if (deltaY > 0 && top - deltaY <= 0) { + results.scrollTop(0); + killEvent(e); + } else if (deltaY < 0 && results.get(0).scrollHeight - results.scrollTop() + deltaY <= results.height()) { + results.scrollTop(results.get(0).scrollHeight - results.height()); + killEvent(e); + } + }); + } + + installKeyUpChangeEvent(search); + search.on("keyup-change", this.bind(this.updateResults)); + + results.on("click", this.bind(function (e) { + if ($(e.target).closest(".select2-result:not(.select2-disabled)").length > 0) { + this.highlightUnderEvent(e); + this.selectHighlighted(e); + } else { + killEvent(e); + this.focusSearch(); + } + })); + }; + + AbstractSelect2.prototype.prepareOpts = function (opts) { + var element, select; + + opts = $.extend({}, { + formatResult: function (data) { return data.text; }, + formatSelection: function (data) { return data.text; }, + formatNoMatches: function () { return "No matches found"; }, + formatInputTooShort: function (input, min) { return "Please enter " + (min - input.length) + " more characters"; }, + minimumResultsForSearch: 0 + }, opts); + + element = opts.element; + + if (element.get(0).tagName.toLowerCase() === "select") { + this.select = select = opts.element; + } + + // TODO add missing validation logic + if (select) { + /*$.each(["multiple", "ajax", "query", "minimumInputLength"], function () { + if (this in opts) { + throw "Option '" + this + "' is not allowed for Select2 when attached to a select element"; + } + });*/ + this.opts = opts = $.extend({}, { + miniumInputLength: 0 + }, opts); + } else { + this.opts = opts = $.extend({}, { + miniumInputLength: 0 + }, opts); + } + + if (select) { + opts.query = this.bind(function (query) { + var data = {results: [], more: false}, + term = query.term.toUpperCase(), + placeholder = this.getPlaceholder(); + element.find("option").each(function (i) { + var e = $(this), + text = e.text(); + + if (i === 0 && placeholder !== undefined && text === "") return true; + + if (text.toUpperCase().indexOf(term) >= 0) { + data.results.push({id: e.attr("value"), text: text}); + } + }); + query.callback(data); + }); + } else { + if (!("query" in opts)) { + if ("ajax" in opts) { + opts.query = (function () { + var timeout, // current scheduled but not yet executed request + requestSequence = 0, // sequence used to drop out-of-order responses + quietMillis = opts.ajax.quietMillis || 100; + + return function (query) { + window.clearTimeout(timeout); + timeout = window.setTimeout(function () { + requestSequence += 1; // increment the sequence + var requestNumber = requestSequence, // this request's sequence number + options = opts.ajax, // ajax parameters + data = options.data; // ajax data function + + data = data.call(this, query.term, query.page); + + $.ajax({ + url: options.url, + dataType: options.dataType, + data: data + }).success( + function (data) { + if (requestNumber < requestSequence) { + return; + } + query.callback(options.results(data, query.page)); + } + ); + }, quietMillis); + }; + }()); + } else if ("data" in opts) { + opts.query = (function () { + var data = opts.data, // data elements + text = function (item) { return item.text; }; // function used to retrieve the text portion of a data item that is matched against the search + + if (!$.isArray(data)) { + text = data.text; + // if text is not a function we assume it to be a key name + if (!$.isFunction(text)) text = function (item) { return item[data.text]; }; + data = data.results; + } + + return function (query) { + var t = query.term.toUpperCase(), filtered = {}; + if (t === "") { + query.callback({results: data}); + return; + } + filtered.result = $(data) + .filter(function () {return text(this).toUpperCase().indexOf(t) >= 0;}) + .get(); + query.callback(filtered); + }; + }()); + } + } + } + if (typeof(opts.query) !== "function") { + throw "query function not defined for Select2 " + opts.element.attr("id"); + } + + return opts; + }; + + AbstractSelect2.prototype.opened = function () { + return this.container.hasClass("select2-dropdown-open"); + }; + + AbstractSelect2.prototype.alignDropdown = function () { + this.dropdown.css({ + top: this.container.height(), + width: this.container.outerWidth() - getSideBorderPadding(this.dropdown) + }); + }; + + AbstractSelect2.prototype.open = function () { + var width; + + if (this.opened()) return; + + this.container.addClass("select2-dropdown-open").addClass("select2-container-active"); + + this.updateResults(true); + this.alignDropdown(); + this.dropdown.show(); + this.focusSearch(); + }; + + AbstractSelect2.prototype.close = function () { + if (!this.opened()) return; + + this.dropdown.hide(); + this.container.removeClass("select2-dropdown-open"); + this.results.empty(); + this.clearSearch(); + }; + + AbstractSelect2.prototype.clearSearch = function () { + + }; + + AbstractSelect2.prototype.ensureHighlightVisible = function () { + var results = this.results, children, index, child, hb, rb, y, more; + + children = results.children(".select2-result"); + index = this.highlight(); + + if (index < 0) return; + + child = $(children[index]); + + hb = child.offset().top + child.outerHeight(); + + // if this is the last child lets also make sure select2-more-results is visible + if (index === children.length - 1) { + more = results.find("li.select2-more-results"); + if (more.length > 0) { + hb = more.offset().top + more.outerHeight(); + } + } + + rb = results.offset().top + results.outerHeight(); + if (hb > rb) { + results.scrollTop(results.scrollTop() + (hb - rb)); + } + y = child.offset().top - results.offset().top; + + // make sure the top of the element is visible + if (y < 0) { + results.scrollTop(results.scrollTop() + y); // y is negative + } + }; + + AbstractSelect2.prototype.moveHighlight = function (delta) { + var choices = this.results.children(".select2-result"), + index = this.highlight(); + + while (index > -1 && index < choices.length) { + index += delta; + if (!$(choices[index]).hasClass("select2-disabled")) { + this.highlight(index); + break; + } + } + }; + + AbstractSelect2.prototype.highlight = function (index) { + var choices = this.results.children(".select2-result"); + + if (arguments.length === 0) { + return indexOf(choices.filter(".select2-highlighted")[0], choices.get()); + } + + choices.removeClass("select2-highlighted"); + + if (index >= choices.length) index = choices.length - 1; + if (index < 0) index = 0; + + $(choices[index]).addClass("select2-highlighted"); + this.ensureHighlightVisible(); + + if (this.opened()) this.focusSearch(); + }; + + AbstractSelect2.prototype.highlightUnderEvent = function (event) { + var el = $(event.target).closest(".select2-result"); + if (el.length > 0) { + this.highlight(el.index()); + } + }; + + AbstractSelect2.prototype.loadMoreIfNeeded = function () { + var results = this.results, + more = results.find("li.select2-more-results"), + below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible + offset = -1, // index of first element without data + page = this.resultsPage + 1; + + if (more.length === 0) return; + + below = more.offset().top - results.offset().top - results.height(); + + if (below <= 0) { + more.addClass("select2-active"); + this.opts.query({term: this.search.val(), page: page, callback: this.bind(function (data) { + var parts = [], self = this; + $(data.results).each(function () { + parts.push("
  • "); + parts.push(self.opts.formatResult(this)); + parts.push("
  • "); + }); + more.before(parts.join("")); + results.find(".select2-result").each(function (i) { + var e = $(this); + if (e.data("select2-data") !== undefined) { + offset = i; + } else { + e.data("select2-data", data.results[i - offset - 1]); + } + }); + if (data.more) { + more.removeClass("select2-active"); + } else { + more.remove(); + } + this.resultsPage = page; + })}); + } + }; + + /** + * @param initial whether or not this is the call to this method right after the dropdown has been opened + */ + AbstractSelect2.prototype.updateResults = function (initial) { + var search = this.search, results = this.results, opts = this.opts; + + search.addClass("select2-active"); + + function render(html) { + results.html(html); + results.scrollTop(0); + search.removeClass("select2-active"); + } + + if (search.val().length < opts.minimumInputLength) { + render("
  • " + opts.formatInputTooShort(search.val(), opts.minimumInputLength) + "
  • "); + return; + } + + this.resultsPage = 1; + opts.query({term: search.val(), page: this.resultsPage, callback: this.bind(function (data) { + var parts = []; // html parts + + if (data.results.length === 0) { + render("
  • " + opts.formatNoMatches(search.val()) + "
  • "); + return; + } + + $(data.results).each(function () { + parts.push("
  • "); + parts.push(opts.formatResult(this)); + parts.push("
  • "); + }); + + if (data.more === true) { + parts.push("
  • Loading more results...
  • "); + } + + render(parts.join("")); + results.children(".select2-result").each(function (i) { + var d = data.results[i]; + $(this).data("select2-data", d); + }); + this.postprocessResults(data, initial); + })}); + }; + + AbstractSelect2.prototype.cancel = function () { + this.close(); + }; + + AbstractSelect2.prototype.blur = function () { + /* we do this in a timeout so that current event processing can complete before this code is executed. + this allows tab index to be preserved even if this code blurs the textfield */ + window.setTimeout(this.bind(function () { + this.close(); + this.container.removeClass("select2-container-active"); + this.clearSearch(); + this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); + this.search.blur(); + }), 10); + }; + + AbstractSelect2.prototype.focusSearch = function () { + /* we do this in a timeout so that current event processing can complete before this code is executed. + this makes sure the search field is focussed even if the current event would blur it */ + window.setTimeout(this.bind(function () { + this.search.focus(); + }), 10); + }; + + AbstractSelect2.prototype.selectHighlighted = function () { + var data = this.results.find(".select2-highlighted:not(.select2-disabled)").data("select2-data"); + if (data) { + this.onSelect(data); + } + }; + + AbstractSelect2.prototype.getPlaceholder = function () { + var placeholder = this.opts.element.data("placeholder"); + if (placeholder !== undefined) return placeholder; + return this.opts.placeholder; + }; + + function SingleSelect2() { + } + + SingleSelect2.prototype = new AbstractSelect2(); + SingleSelect2.prototype.constructor = SingleSelect2; + SingleSelect2.prototype.parent = AbstractSelect2.prototype; + + SingleSelect2.prototype.createContainer = function () { + return $("
    ", { + "class": "select2-container", + "style": "width: " + this.opts.element.outerWidth() + "px" + }).html([ + " ", + " ", + "
    " , + "
    ", + " "].join("")); + }; + + SingleSelect2.prototype.open = function () { + + var width; + + if (this.opened()) return; + + this.parent.open.apply(this, arguments); + + // size the search field + + width = this.dropdown.width(); + width -= getSideBorderPadding(this.container.find(".select2-search")); + width -= getSideBorderPadding(this.search); + this.search.css({width: width}); + }; + + SingleSelect2.prototype.close = function () { + if (!this.opened()) return; + this.parent.close.apply(this, arguments); + }; + + SingleSelect2.prototype.cancel = function () { + this.parent.cancel.apply(this, arguments); + this.selection.focus(); + }; + + SingleSelect2.prototype.initContainer = function () { + + var selection, container = this.container, clickingInside = false, + selected; + + this.selection = selection = container.find(".select2-choice"); + + this.search.on("keydown", this.bind(function (e) { + switch (e.which) { + case KEY.UP: + case KEY.DOWN: + this.moveHighlight((e.which === KEY.UP) ? -1 : 1); + killEvent(e); + return; + case KEY.TAB: + case KEY.ENTER: + this.selectHighlighted(); + killEvent(e); + return; + case KEY.ESC: + this.cancel(e); + e.preventDefault(); + return; + } + })); + + selection.on("click", this.bind(function (e) { + clickingInside = true; + + if (this.opened()) { + this.close(); + selection.focus(); + } else { + this.open(); + } + e.preventDefault(); + + clickingInside = false; + })); + selection.on("keydown", this.bind(function (e) { + if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) { + return; + } + this.open(); + if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN || e.which === KEY.SPACE) { + // prevent the page from scrolling + killEvent(e); + } + if (e.which === KEY.ENTER) { + // do not propagate the event otherwise we open, and propagate enter which closes + killEvent(e); + } + })); + selection.on("focus", function () { container.addClass("select2-container-active"); }); + selection.on("blur", this.bind(function () { + if (clickingInside) return; + if (!this.opened()) this.blur(); + })); + + selection.find("abbr") + .on("click", this.bind(function (e) { + this.val(""); + killEvent(e); + this.close(); + } + )); + + if (this.select) { + selected = this.select.find(":selected"); + this.updateSelection({id: selected.attr("value"), text: selected.text()}); + } + + this.setPlaceholder(); + }; + + SingleSelect2.prototype.setPlaceholder = function () { + var placeholder = this.getPlaceholder(); + + if (this.opts.element.val() === "" && placeholder !== undefined) { + + // check for a first blank option if attached to a select + if (this.select && this.select.find("option:first").text() !== "") return; + + if (typeof(placeholder) === "object") { + this.updateSelection(placeholder); + } else { + this.selection.find("span").html(placeholder); + } + this.selection.addClass("select2-default"); + + this.selection.find("abbr").hide(); + } + }; + + SingleSelect2.prototype.postprocessResults = function (data, initial) { + var selected = 0, self = this; + + // find the selected element in the result list + + this.results.find(".select2-result").each(function (i) { + if ($(this).data("select2-data").id === self.opts.element.val()) { + selected = i; + return false; + } + }); + + // and highlight it + + this.highlight(selected); + + // hide the search box if this is the first we got the results and there are a few of them + + if (initial === true) { + this.search.toggle(data.results.length >= this.opts.minimumResultsForSearch); + } + + }; + + SingleSelect2.prototype.onSelect = function (data) { + this.opts.element.val(data.id); + this.updateSelection(data); + this.close(); + this.selection.focus(); + }; + + SingleSelect2.prototype.updateSelection = function (data) { + this.selection.find("span").html(this.opts.formatSelection(data)); + this.selection.removeClass("select2-default"); + if (this.opts.allowClear && this.getPlaceholder() !== undefined) { + this.selection.find("abbr").show(); + } + }; + + SingleSelect2.prototype.val = function () { + var val, data = null; + + if (arguments.length === 0) { + return this.opts.element.val(); + } + + val = arguments[0]; + + if (this.select) { + // val is an id + this.select.val(val); + this.select.find(":selected").each(function () { + data = {id: $(this).attr("value"), text: $(this).text()}; + return false; + }); + this.updateSelection(data); + } else { + // val is an object + this.opts.element.val((val === null) ? "" : val.id); + this.updateSelection(val); + } + this.setPlaceholder(); + + }; + + SingleSelect2.prototype.clearSearch = function () { + this.search.val(""); + }; + + function MultiSelect2(opts) { + + } + + MultiSelect2.prototype = new AbstractSelect2(); + MultiSelect2.prototype.constructor = AbstractSelect2; + MultiSelect2.prototype.parent = AbstractSelect2.prototype; + + MultiSelect2.prototype.createContainer = function () { + return $("
    ", { + "class": "select2-container select2-container-multi", + "style": "width: " + this.opts.element.outerWidth() + "px" + }).html([ + " " , + ""].join("")); + }; + + MultiSelect2.prototype.initContainer = function () { + + var selection, data; + + this.searchContainer = this.container.find(".select2-search-field"); + this.selection = selection = this.container.find(".select2-choices"); + + this.search.on("keydown", this.bind(function (e) { + if (e.which === KEY.BACKSPACE && this.search.val() === "") { + this.close(); + + var choices, + selected = this.selection.find(".select2-search-choice-focus"); + if (selected.length > 0) { + this.unselect(selected.first()); + this.search.width(10); + killEvent(e); + return; + } + + choices = this.selection.find(".select2-search-choice"); + if (choices.length > 0) { + choices.last().addClass("select2-search-choice-focus"); + } + } else { + this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); + } + + if (this.opened()) { + switch (e.which) { + case KEY.UP: + case KEY.DOWN: + this.moveHighlight((e.which === KEY.UP) ? -1 : 1); + killEvent(e); + return; + case KEY.ENTER: + this.selectHighlighted(); + killEvent(e); + return; + case KEY.ESC: + this.cancel(e); + e.preventDefault(); + return; + } + } + + if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.BACKSPACE || e.which === KEY.ESC) { + return; + } + + this.open(); + + if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { + // prevent the page from scrolling + killEvent(e); + } + })); + + this.search.on("keyup", this.bind(this.resizeSearch)); + + this.selection.on("click", this.bind(function (e) { + if (this.select) { + this.open(); + } + this.focusSearch(); + e.preventDefault(); + })); + + this.search.on("focus", this.bind(function () { + this.container.addClass("select2-container-active"); + this.clearPlaceholder(); + })); + + if (this.select) { + data = []; + this.select.find(":selected").each(function () { + data.push({id: $(this).attr("value"), text: $(this).text()}); + }); + + this.updateSelection(data); + } + + // set the placeholder if necessary + this.clearSearch(); + }; + + MultiSelect2.prototype.clearSearch = function () { + var placeholder = this.getPlaceholder(); + + this.search.val("").width(10); + + if (placeholder !== undefined && this.getVal().length === 0) { + this.search.val(placeholder).addClass("select2-default"); + this.resizeSearch(); + } + }; + + MultiSelect2.prototype.clearPlaceholder = function () { + if (this.search.hasClass("select2-default")) { + this.search.val("").removeClass("select2-default"); + } + }; + + MultiSelect2.prototype.open = function () { + if (this.opened()) return; + this.parent.open.apply(this, arguments); + this.resizeSearch(); + this.focusSearch(); + }; + + MultiSelect2.prototype.close = function () { + if (!this.opened()) return; + this.parent.close.apply(this, arguments); + }; + + MultiSelect2.prototype.updateSelection = function (data) { + var self = this; + this.selection.find(".select2-search-choice").remove(); + $(data).each(function () { + self.addSelectedChoice(this); + }); + self.postprocessResults(); + this.alignDropdown(); + }; + + MultiSelect2.prototype.onSelect = function (data) { + this.addSelectedChoice(data); + if (this.select) { this.postprocessResults(); } + this.close(); + this.search.width(10); + this.focusSearch(); + }; + + MultiSelect2.prototype.cancel = function () { + this.close(); + this.focusSearch(); + }; + + MultiSelect2.prototype.addSelectedChoice = function (data) { + var choice, + id = data.id, + parts, + val = this.getVal(); + + parts = ["
  • ", + this.opts.formatSelection(data), + "", + "
  • " + ]; + + choice = $(parts.join("")); + choice.find("a") + .on("click dblclick", this.bind(function (e) { + this.unselect($(e.target)); + this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); + killEvent(e); + this.close(); + this.focusSearch(); + })).on("focus", this.bind(function () { + this.container.addClass("select2-container-active"); + })); + + choice.data("select2-data", data); + choice.insertBefore(this.searchContainer); + + val.push(id); + this.setVal(val); + }; + + MultiSelect2.prototype.unselect = function (selected) { + var val = this.getVal(), + index; + + selected = selected.closest(".select2-search-choice"); + + if (selected.length === 0) { + throw "Invalid argument: " + selected + ". Must be .select2-search-choice"; + } + + index = indexOf(selected.data("select2-data").id, val); + + if (index >= 0) { + val.splice(index, 1); + this.setVal(val); + if (this.select) this.postprocessResults(); + } + selected.remove(); + window.setTimeout(this.bind(this.alignDropdown), 20); + }; + + MultiSelect2.prototype.postprocessResults = function () { + var val = this.getVal(), + choices = this.results.find(".select2-result"), + self = this; + + choices.each(function () { + var choice = $(this), id = choice.data("select2-data").id; + if (val.indexOf(id) >= 0) { + choice.addClass("select2-disabled"); + } else { + choice.removeClass("select2-disabled"); + } + }); + + choices.each(function (i) { + if (!$(this).hasClass("select2-disabled")) { + self.highlight(i); + return false; + } + }); + + }; + + MultiSelect2.prototype.resizeSearch = function () { + + var minimumWidth, left, maxWidth, containerLeft, searchWidth; + + minimumWidth = measureTextWidth(this.search) + 10; + + left = this.search.offset().left; + + maxWidth = this.selection.width(); + containerLeft = this.selection.offset().left; + + searchWidth = maxWidth - (left - containerLeft) - getSideBorderPadding(this.search); + + if (searchWidth < minimumWidth) { + searchWidth = maxWidth - getSideBorderPadding(this.search); + } + + if (searchWidth < 40) { + searchWidth = maxWidth - getSideBorderPadding(this.search); + } + this.search.width(searchWidth); + }; + + MultiSelect2.prototype.getVal = function () { + var val; + if (this.select) { + val = this.select.val(); + return val === null ? [] : val; + } else { + val = this.opts.element.val(); + return (val === null || val === "") ? [] : val.split(","); + } + }; + + MultiSelect2.prototype.setVal = function (val) { + if (this.select) { + this.select.val(val); + } else { + this.opts.element.val(val.length === 0 ? "" : val.join(",")); + } + }; + + MultiSelect2.prototype.val = function () { + var val, data = []; + + if (arguments.length === 0) { + return this.getVal(); + } + + val = arguments[0]; + + if (this.select) { + // val is a list of ids + this.setVal(val); + this.select.find(":selected").each(function () { + data.push({id: $(this).attr("value"), text: $(this).text()}); + }); + this.updateSelection(data); + } else { + val = (val === null) ? [] : val; + this.setVal(val); + // val is a list of objects + + $(val).each(function () { data.push(this.id); }); + this.setVal(data); + this.updateSelection(val); + } + }; + + $.fn.select2 = function () { + + var args = Array.prototype.slice.call(arguments, 0), + opts, + select2, + value, multiple, allowedMethods = ["val"]; + + this.each(function () { + if (args.length === 0 || typeof(args[0]) === "object") { + opts = args.length === 0 ? {} : args[0]; + opts.element = $(this); + + if (opts.element.get(0).tagName.toLowerCase() === "select") { + multiple = opts.element.prop("multiple"); + } else { + multiple = opts.multiple || false; + } + + select2 = multiple ? new MultiSelect2() : new SingleSelect2(); + select2.init(opts); + } else if (typeof(args[0]) === "string") { + + if (indexOf(args[0], allowedMethods) < 0) { + throw "Unknown method: " + args[0]; + } + + value = undefined; + select2 = $(this).data("select2"); + value = select2[args[0]].apply(select2, args.slice(1)); + if (value !== undefined) {return false;} + } else { + throw "Invalid arguments to select2 plugin: " + args; + } + }); + return (value === undefined) ? this : value; + }; + +}(jQuery));