initial checkin
This commit is contained in:
commit
53e214d32f
16
LICENSE
Normal file
16
LICENSE
Normal file
@ -0,0 +1,16 @@
|
||||
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.
|
100
README.md
Executable file
100
README.md
Executable file
@ -0,0 +1,100 @@
|
||||
Select2
|
||||
=================
|
||||
|
||||
Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results. Look and feel of Select2 is based on the excellent [Chosen](http://harvesthq.github.com/chosen/) library.
|
||||
|
||||
To get started -- checkout http://ivaynberg.github.com/select2!
|
||||
|
||||
|
||||
Versioning
|
||||
----------
|
||||
|
||||
For transparency and insight into our release cycle, and for striving to maintain backward compatibility, Bootstrap will be maintained under the Semantic Versioning guidelines as much as possible.
|
||||
|
||||
Releases will be numbered with the follow format:
|
||||
|
||||
`<major>.<minor>.<patch>`
|
||||
|
||||
And constructed with the following guidelines:
|
||||
|
||||
* Breaking backward compatibility bumps the major
|
||||
* New additions without breaking backward compatibility bumps the minor
|
||||
* Bug fixes and misc changes bump the patch
|
||||
|
||||
For more information on SemVer, please visit http://semver.org/.
|
||||
|
||||
|
||||
Bug tracker
|
||||
-----------
|
||||
|
||||
Have a bug? Please create an issue here on GitHub!
|
||||
|
||||
https://github.com/twitter/bootstrap/issues
|
||||
|
||||
|
||||
Twitter account
|
||||
---------------
|
||||
|
||||
Keep up to date on announcements and more by following Bootstrap on Twitter, <a href="http://twitter.com/TwBootstrap">@TwBootstrap</a>.
|
||||
|
||||
|
||||
Mailing list
|
||||
------------
|
||||
|
||||
Have a question? Ask on our mailing list!
|
||||
|
||||
twitter-bootstrap@googlegroups.com
|
||||
|
||||
http://groups.google.com/group/twitter-bootstrap
|
||||
|
||||
|
||||
IRC
|
||||
---
|
||||
|
||||
Server: irc.freenode.net
|
||||
|
||||
Channel: ##twitter-bootstrap (the double ## is not a typo)
|
||||
|
||||
|
||||
Developers
|
||||
----------
|
||||
|
||||
We have included a makefile with convenience methods for working with the Bootstrap library.
|
||||
|
||||
+ **build** - `make`
|
||||
Runs the LESS compiler to rebuild the `/less` files and compiles the docs pages. Requires lessc and uglify-js. <a href="http://twitter.github.com/bootstrap/less.html#compiling">Read more in our docs »</a>
|
||||
|
||||
+ **watch** - `make watch`
|
||||
This is a convenience method for watching just Less files and automatically building them whenever you save. Requires the Watchr gem.
|
||||
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
||||
**Mark Otto**
|
||||
|
||||
+ http://twitter.com/mdo
|
||||
+ http://github.com/markdotto
|
||||
|
||||
**Jacob Thornton**
|
||||
|
||||
+ http://twitter.com/fat
|
||||
+ http://github.com/fat
|
||||
|
||||
|
||||
Copyright and license
|
||||
---------------------
|
||||
|
||||
Copyright 2012 Twitter, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this work except in compliance with the License.
|
||||
You may obtain a copy of the License in the LICENSE file, or 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.
|
231
select2.css
Executable file
231
select2.css
Executable file
@ -0,0 +1,231 @@
|
||||
.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-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;
|
||||
}
|
||||
|
||||
|
||||
/* active styles */
|
||||
.select2-container-focused .select2-choice {
|
||||
-webkit-box-shadow: 0 0 5px rgba(0,0,0,.3);
|
||||
-moz-box-shadow : 0 0 5px rgba(0,0,0,.3);
|
||||
-o-box-shadow : 0 0 5px rgba(0,0,0,.3);
|
||||
box-shadow : 0 0 5px rgba(0,0,0,.3);
|
||||
border: 1px solid #5897fb;
|
||||
}
|
||||
|
||||
.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-more-results.select2-active {
|
||||
background: #f4f4f4 url('spinner.gif') no-repeat 100%;
|
||||
}
|
||||
|
||||
.select2-more-results {
|
||||
background: #f4f4f4;
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
.select2-container .select2-drop { border: 1px solid red !important;}
|
||||
.select2-container .select2-drop .select2-search { border: 1px solid green !important;}
|
||||
.select2-container .select2-drop .select2-search input { border: 1px solid blue !important;}
|
||||
*/
|
781
select2.js
Executable file
781
select2.js
Executable file
@ -0,0 +1,781 @@
|
||||
/*
|
||||
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, Util, DropDown, ResultList, Selection, Select2, Queries;
|
||||
|
||||
function createClass(def) {
|
||||
var type = function (attrs) {
|
||||
var self = this;
|
||||
if (def.attrs !== undefined) {
|
||||
$.each(def.attrs, function (name, body) {
|
||||
if (attrs[name] !== undefined) {
|
||||
self[name] = attrs[name];
|
||||
} else {
|
||||
if (body.required === true) {
|
||||
throw "Value for required attribute: " + name + " not defined";
|
||||
}
|
||||
if (body.init !== undefined) {
|
||||
self[name] = typeof (body.init) === "function" ? body.init.apply(self) : body.init;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (def.methods !== undefined && def.methods.init !== undefined) {
|
||||
self.init(attrs);
|
||||
}
|
||||
};
|
||||
|
||||
if (def.methods !== undefined) {
|
||||
if (def.methods.bind !== undefined) {
|
||||
throw "Class cannot declare a method called 'bind'";
|
||||
}
|
||||
|
||||
$.each(def.methods, function (name, body) {
|
||||
type.prototype[name] = body;
|
||||
});
|
||||
|
||||
type.prototype.bind = function (func) {
|
||||
var self = this;
|
||||
return function () {
|
||||
func.apply(self, arguments);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
Util = {};
|
||||
|
||||
Util.debounce = function (threshold, fn) {
|
||||
var timeout;
|
||||
return function () {
|
||||
window.clearTimeout(timeout);
|
||||
timeout = window.setTimeout(fn, threshold);
|
||||
};
|
||||
};
|
||||
|
||||
Util.debounceEvent = function (element, threshold, event, debouncedEvent, direct) {
|
||||
debouncedEvent = debouncedEvent || event + "-debounced";
|
||||
direct = direct || true;
|
||||
|
||||
var notify = Util.debounce(threshold, function (e) {
|
||||
element.trigger(debouncedEvent, e);
|
||||
});
|
||||
|
||||
element.on(event, function (e) {
|
||||
if (direct && element.get().indexOf(e.target) < 0) {
|
||||
return;
|
||||
}
|
||||
notify(e);
|
||||
});
|
||||
};
|
||||
|
||||
(function () {
|
||||
|
||||
var lastpos;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
Util.filterMouseEvent = function (element, event, filteredEvent, direct) {
|
||||
filteredEvent = filteredEvent || event + "-filtered";
|
||||
direct = direct || false;
|
||||
|
||||
element.on(event, "*", function (e) {
|
||||
if (direct && element.get().indexOf(e.target) < 0) {
|
||||
return;
|
||||
}
|
||||
if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) {
|
||||
$(e.target).trigger(filteredEvent, e);
|
||||
lastpos = {x: e.pageX, y: e.pageY};
|
||||
}
|
||||
});
|
||||
};
|
||||
}());
|
||||
|
||||
DropDown = createClass({
|
||||
attrs: {
|
||||
container: {required: true},
|
||||
element: {required: true},
|
||||
bus: {required: true}
|
||||
},
|
||||
methods: {
|
||||
open: function () {
|
||||
if (this.isOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.container.addClass("select2-dropdown-open");
|
||||
|
||||
// register click-outside-closes-dropdown listener
|
||||
$(document).on("mousedown.dropdown", this.bind(function (e) {
|
||||
var inside = false,
|
||||
container = this.container.get(0);
|
||||
$(e.target).parents().each(function () {
|
||||
return !(inside = (this === container));
|
||||
});
|
||||
if (!inside) {
|
||||
this.close();
|
||||
}
|
||||
}));
|
||||
|
||||
this.element.show();
|
||||
this.bus.trigger("opened");
|
||||
},
|
||||
|
||||
close: function () {
|
||||
if (!this.isOpen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.container.removeClass("select2-dropdown-open");
|
||||
|
||||
$(document).off("mousedown.dropdown");
|
||||
this.element.hide();
|
||||
this.bus.trigger("closed");
|
||||
},
|
||||
|
||||
isOpen: function () {
|
||||
return this.container.hasClass("select2-dropdown-open");
|
||||
},
|
||||
|
||||
toggle: function () {
|
||||
if (this.isOpen()) {
|
||||
this.close();
|
||||
} else {
|
||||
this.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
ResultList = createClass({
|
||||
attrs: {
|
||||
element: {required: true},
|
||||
bus: {required: true},
|
||||
formatInputTooShort: {required: true},
|
||||
formatNoMatches: {required: true},
|
||||
formatResult: {required: true},
|
||||
minimumInputLength: {required: true},
|
||||
query: {required: true},
|
||||
selection: {required: true}
|
||||
},
|
||||
methods: {
|
||||
init: function () {
|
||||
var self = this;
|
||||
|
||||
this.search = this.element.find("input");
|
||||
this.results = this.element.find("ul");
|
||||
this.scrollPosition = 0;
|
||||
this.vars = {};
|
||||
|
||||
this.search.on("keyup", function (e) {
|
||||
if (e.which >= 48 || e.which === KEY.SPACE || e.which === KEY.BACKSPACE || e.which === KEY.DELETE) {
|
||||
self.update();
|
||||
}
|
||||
});
|
||||
|
||||
this.search.on("keydown", function (e) {
|
||||
switch (e.which) {
|
||||
case KEY.TAB:
|
||||
e.preventDefault();
|
||||
self.select();
|
||||
return;
|
||||
case KEY.ENTER:
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
self.select();
|
||||
return;
|
||||
case KEY.UP:
|
||||
self.moveSelection(-1);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return;
|
||||
case KEY.DOWN:
|
||||
self.moveSelection(1);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return;
|
||||
case KEY.ESC:
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
self.cancel();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// this.results.on("mouseleave", "li.select2-result", this.bind(this.unhighlight));
|
||||
Util.filterMouseEvent(this.results, "mousemove");
|
||||
this.results.on("mousemove-filtered", this.bind(function (e) {
|
||||
var el = $(e.target).closest("li.select2-result");
|
||||
if (el.length < 1) {
|
||||
return;
|
||||
}
|
||||
this.setSelection(el.index());
|
||||
}));
|
||||
this.results.on("click", this.bind(function (e) {
|
||||
var el = $(e.target).closest("li.select2-result");
|
||||
if (el.length < 1) {
|
||||
return;
|
||||
}
|
||||
this.bus.trigger("selected", [el.data("select2-result")]);
|
||||
}));
|
||||
|
||||
Util.debounceEvent(this.results, 100, "scroll");
|
||||
|
||||
this.results.on("scroll-debounced", this.bind(function (e) {
|
||||
this.scrollPosition = this.results.scrollTop();
|
||||
|
||||
var more = this.results.find("li.select2-more-results"), below;
|
||||
|
||||
if (more.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// pixels the element is below the scroll fold, below==0 is when the element is starting to be visible
|
||||
below = more.offset().top - this.results.offset().top - this.results.height();
|
||||
|
||||
if (below <= 0) {
|
||||
more.addClass("select2-active");
|
||||
this.query({term: this.search.val(), vars: this.vars, callback: this.bind(this.append)});
|
||||
}
|
||||
|
||||
}));
|
||||
},
|
||||
open: function (e) {
|
||||
this.search.focus();
|
||||
this.results.scrollTop(this.scrollPosition);
|
||||
if (this.results.children().length === 0) {
|
||||
// first time the dropdown is opened, update the results
|
||||
this.update();
|
||||
}
|
||||
},
|
||||
close: function () {
|
||||
//this.search.val("");
|
||||
//this.clear();
|
||||
},
|
||||
clear: function () {
|
||||
this.results.empty();
|
||||
},
|
||||
showInputTooShort: function () {
|
||||
this.show("<li class='select2-no-results'>" + this.formatInputTooShort(this.search.val(), this.minimumInputLength) + "</li>");
|
||||
},
|
||||
showNoMatches: function () {
|
||||
this.show("<li class='select2-no-results'>" + this.formatNoMatches(this.search.val()) + "</li>");
|
||||
},
|
||||
show: function (html) {
|
||||
this.results.html(html);
|
||||
this.results.scrollTop(0);
|
||||
this.search.removeClass("select2-active");
|
||||
},
|
||||
update: function () {
|
||||
var html = "";
|
||||
|
||||
if (this.search.val().length < this.minimumInputLength) {
|
||||
this.showInputTooShort();
|
||||
return;
|
||||
}
|
||||
|
||||
this.search.addClass("select2-active");
|
||||
this.vars = {};
|
||||
this.query({term: this.search.val(), vars: this.vars, callback: this.bind(this.process)});
|
||||
},
|
||||
process: function (data) {
|
||||
if (data.results.length === 0) {
|
||||
this.showNoMatches();
|
||||
return;
|
||||
}
|
||||
|
||||
var html = this.stringizeResults(data.results), selectedId = this.selection.val(), selectedIndex = 0;
|
||||
|
||||
if (data.more === true) {
|
||||
html += "<li class='select2-more-results'>Loading more results...</li>";
|
||||
}
|
||||
this.vars = data.vars || {};
|
||||
|
||||
this.show(html);
|
||||
|
||||
this.findChoices().each(function (i) {
|
||||
if (selectedId === data.results[i].id) {
|
||||
selectedIndex = i;
|
||||
}
|
||||
$(this).data("select2-result", data.results[i]);
|
||||
});
|
||||
|
||||
this.setSelection(selectedIndex);
|
||||
|
||||
},
|
||||
append: function (data) {
|
||||
|
||||
var more = this.results.find("li.select2-more-results"), html, offset;
|
||||
|
||||
this.vars = data.vars || {};
|
||||
|
||||
if (data.results.length === 0) {
|
||||
more.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
html = this.stringizeResults(data.results);
|
||||
|
||||
offset = this.results.find("li.select2-result").length;
|
||||
|
||||
more.before(html);
|
||||
|
||||
this.results.find("li.select2-result").each(function (i) {
|
||||
if (i >= offset) {
|
||||
$(this).data("select2-result", data.results[i - offset]);
|
||||
}
|
||||
});
|
||||
|
||||
if (data.more !== true) {
|
||||
more.remove();
|
||||
} else {
|
||||
more.removeClass("select2-active");
|
||||
}
|
||||
|
||||
},
|
||||
stringizeResults: function (results, html) {
|
||||
var i, l, classes;
|
||||
html = html || "";
|
||||
for (i = 0, l = results.length; i < l; i += 1) {
|
||||
html += "<li class='select2-result'>";
|
||||
html += this.formatResult(results[i]);
|
||||
html += "</li>";
|
||||
}
|
||||
return html;
|
||||
},
|
||||
|
||||
findChoices: function () {
|
||||
return this.results.children("li.select2-result");
|
||||
},
|
||||
|
||||
removeSelection: function () {
|
||||
this.findChoices().each(function () {
|
||||
$(this).removeClass("select2-highlighted");
|
||||
});
|
||||
},
|
||||
|
||||
setSelection: function (index) {
|
||||
this.removeSelection();
|
||||
|
||||
var children = this.findChoices(),
|
||||
child = $(children[index]),
|
||||
hb,
|
||||
rb,
|
||||
y,
|
||||
more;
|
||||
|
||||
child.addClass("select2-highlighted");
|
||||
|
||||
this.search.focus();
|
||||
|
||||
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 = this.results.find("li.select2-more-results");
|
||||
if (more.length > 0) {
|
||||
hb = more.offset().top + more.outerHeight();
|
||||
}
|
||||
}
|
||||
|
||||
rb = this.results.offset().top + this.results.outerHeight();
|
||||
if (hb > rb) {
|
||||
this.results.scrollTop(this.results.scrollTop() + (hb - rb));
|
||||
}
|
||||
y = child.offset().top - this.results.offset().top;
|
||||
|
||||
// make sure the top of the element is visible
|
||||
if (y < 0) {
|
||||
this.results.scrollTop(this.results.scrollTop() + y); // y is negative
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getSelectionIndex: function () {
|
||||
var children = this.findChoices(), i = 0, l = children.length;
|
||||
for (; i < l; i += 1) {
|
||||
if ($(children[i]).hasClass("select2-highlighted")) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
|
||||
moveSelection: function (delta) {
|
||||
var current = this.getSelectionIndex(),
|
||||
children = this.findChoices(),
|
||||
next = current + delta;
|
||||
|
||||
if (current >= 0 && next >= 0 && next < children.length) {
|
||||
this.setSelection(next);
|
||||
}
|
||||
},
|
||||
|
||||
select: function () {
|
||||
var selected = this.results.find("li.select2-highlighted");
|
||||
if (selected.length > 0) {
|
||||
this.bus.trigger("selected", [selected.data("select2-result")]);
|
||||
}
|
||||
},
|
||||
|
||||
cancel: function () {
|
||||
this.bus.trigger("cancelled");
|
||||
},
|
||||
|
||||
val: function (data) {
|
||||
var choices = this.findChoices(), index;
|
||||
|
||||
choices.each(function (i) {
|
||||
if ($(this).data("select2-result").id === data) {
|
||||
index = i;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (index === undefined && data.id !== undefined) {
|
||||
choices.each(function (i) {
|
||||
if ($(this).data("select2-result").id === data.id) {
|
||||
index = i;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (index !== undefined) {
|
||||
this.setSelection(index);
|
||||
this.select();
|
||||
return;
|
||||
}
|
||||
|
||||
this.bus.trigger("selected", data);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
Selection = createClass({
|
||||
attrs: {
|
||||
bus: {required: true},
|
||||
element: {required: true},
|
||||
display: {init: function () {
|
||||
return this.element.find("span");
|
||||
}},
|
||||
hidden: {required: true},
|
||||
formatSelection: {required: true},
|
||||
placeholder: {},
|
||||
dropdown: {required: true}
|
||||
},
|
||||
methods: {
|
||||
init: function () {
|
||||
if (this.placeholder) {
|
||||
this.select(this.placeholder);
|
||||
}
|
||||
this.element.click(this.dropdown.bind(this.dropdown.toggle));
|
||||
|
||||
var self = this;
|
||||
this.element.on("keydown", function (e) {
|
||||
switch (e.which) {
|
||||
case KEY.TAB:
|
||||
case KEY.SHIFT:
|
||||
case KEY.CTRL:
|
||||
case KEY.ALT:
|
||||
case KEY.LEFT:
|
||||
case KEY.RIGHT:
|
||||
return;
|
||||
}
|
||||
self.dropdown.open();
|
||||
});
|
||||
},
|
||||
select: function (data) {
|
||||
this.display.html(this.formatSelection(data));
|
||||
this.hidden.val(data.id);
|
||||
},
|
||||
focus: function () {
|
||||
this.element.focus();
|
||||
},
|
||||
val: function () {
|
||||
return this.hidden.val();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Queries = {};
|
||||
Queries.select = function (select2, element) {
|
||||
var options = [];
|
||||
element.find("option").each(function () {
|
||||
var e = $(this);
|
||||
options.push({id: e.attr("value"), text: e.text()});
|
||||
});
|
||||
return function (query) {
|
||||
var data = {results: [], more: false},
|
||||
text = query.term.toUpperCase();
|
||||
$.each(options, function (i) {
|
||||
if (this.text.toUpperCase().indexOf(text) >= 0) {
|
||||
data.results.push(this);
|
||||
}
|
||||
});
|
||||
query.callback(data);
|
||||
};
|
||||
};
|
||||
Queries.ajax = function (select2, el) {
|
||||
var timeout, // current scheduled but not yet executed request
|
||||
requestSequence = 0, // sequence used to drop out-of-order responses
|
||||
quietMillis = select2.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 = select2.ajax, // ajax parameters
|
||||
data = options.data; // ajax data function
|
||||
|
||||
data = data.call(this, query.term, query.vars);
|
||||
|
||||
$.ajax({
|
||||
url: options.url,
|
||||
dataType: options.dataType,
|
||||
data: data
|
||||
}).success(
|
||||
function (data) {
|
||||
if (requestNumber < requestSequence) {
|
||||
return;
|
||||
}
|
||||
query.callback(options.results(data, query.vars));
|
||||
}
|
||||
);
|
||||
}, quietMillis);
|
||||
};
|
||||
};
|
||||
|
||||
Select2 = createClass({
|
||||
attrs: {
|
||||
el: {required: true},
|
||||
formatResult: {init: function () {
|
||||
return function (data) {
|
||||
return data.text;
|
||||
};
|
||||
}},
|
||||
formatSelection: {init: function () {
|
||||
return function (data) {
|
||||
return data.text;
|
||||
};
|
||||
}},
|
||||
formatNoMatches: {init: function () {
|
||||
return function () {
|
||||
return "No matches found";
|
||||
};
|
||||
}},
|
||||
formatInputTooShort: {init: function () {
|
||||
return function (input, min) {
|
||||
return "Please enter " + (min - input.length) + " more characters to start search";
|
||||
};
|
||||
}},
|
||||
minimumInputLength: {init: 0},
|
||||
placeholder: {init: undefined},
|
||||
ajax: {init: undefined},
|
||||
query: {init: undefined}
|
||||
},
|
||||
methods: {
|
||||
init: function () {
|
||||
var self = this, width, dropdown, results, selected, select;
|
||||
|
||||
this.el = $(this.el);
|
||||
|
||||
width = this.el.outerWidth();
|
||||
|
||||
this.container = $("<div></div>", {
|
||||
"class": "select2-container",
|
||||
style: "width: " + width + "px"
|
||||
});
|
||||
this.container.html(
|
||||
" <a href='javascript:void(0)' class='select2-choice'>" +
|
||||
" <span></span>" +
|
||||
" <div><b></b></div>" +
|
||||
"</a>" +
|
||||
"<div class='select2-drop' style='display:none;'>" +
|
||||
" <div class='select2-search'>" +
|
||||
" <input type='text' autocomplete='off'/>" +
|
||||
" </div>" +
|
||||
" <ul class='select2-results'>" +
|
||||
" </ul>" +
|
||||
"</div>" +
|
||||
"<input type='hidden'/>"
|
||||
);
|
||||
|
||||
this.el.data("select2", this);
|
||||
this.el.hide();
|
||||
this.el.after(self.container);
|
||||
if (this.el.attr("class") !== undefined) {
|
||||
this.container.addClass(this.el.attr("class"));
|
||||
}
|
||||
this.container.data("select2", this);
|
||||
this.container.find("input[type=hidden]").attr("name", this.el.attr("name"));
|
||||
|
||||
if (this.query === undefined && this.el.get(0).tagName.toUpperCase() === "SELECT") {
|
||||
this.query = "select";
|
||||
select = true;
|
||||
}
|
||||
if (Queries[this.query] !== undefined) {
|
||||
this.query = Queries[this.query](this, this.el);
|
||||
}
|
||||
|
||||
(function () {
|
||||
|
||||
var dropdown, searchContainer, search, width;
|
||||
|
||||
function getSideBorderPadding(e) {
|
||||
return e.outerWidth() - e.width();
|
||||
}
|
||||
|
||||
// position and size dropdown
|
||||
dropdown = self.container.find("div.select2-drop");
|
||||
width = self.container.outerWidth() - getSideBorderPadding(dropdown);
|
||||
dropdown.css({top: self.container.height(), width: width});
|
||||
|
||||
// size search field
|
||||
searchContainer = self.container.find(".select2-search");
|
||||
search = searchContainer.find("input");
|
||||
width = dropdown.width();
|
||||
width -= getSideBorderPadding(searchContainer);
|
||||
width -= getSideBorderPadding(search);
|
||||
search.css({width: width});
|
||||
}());
|
||||
|
||||
dropdown = new DropDown({
|
||||
element: this.container.find("div.select2-drop"),
|
||||
container: this.container,
|
||||
bus: this.el
|
||||
});
|
||||
|
||||
this.selection = new Selection({
|
||||
bus: this.el,
|
||||
element: this.container.find(".select2-choice"),
|
||||
hidden: this.container.find("input[type=hidden]"),
|
||||
formatSelection: this.formatSelection,
|
||||
placeholder: this.placeholder,
|
||||
dropdown: dropdown
|
||||
});
|
||||
|
||||
this.results = new ResultList({
|
||||
element: this.container.find("div.select2-drop"),
|
||||
bus: this.el,
|
||||
formatInputTooShort: this.formatInputTooShort,
|
||||
formatNoMatches: this.formatNoMatches,
|
||||
formatResult: this.formatResult,
|
||||
minimumInputLength: this.minimumInputLength,
|
||||
query: this.query,
|
||||
selection: this.selection
|
||||
});
|
||||
|
||||
this.el.on("selected", function (e, result) {
|
||||
dropdown.close();
|
||||
self.selection.select(result);
|
||||
});
|
||||
|
||||
this.el.on("cancelled", function () {
|
||||
dropdown.close();
|
||||
});
|
||||
|
||||
this.el.on("opened", this.bind(function () {
|
||||
this.results.open();
|
||||
}));
|
||||
|
||||
this.el.on("closed", this.bind(function () {
|
||||
this.container.removeClass("select2-dropdown-open");
|
||||
this.results.close();
|
||||
this.selection.focus();
|
||||
}));
|
||||
|
||||
// if attached to a select do some default initialization
|
||||
if (select) {
|
||||
this.results.update(); // build the results
|
||||
selected = this.el.find("option[selected]");
|
||||
if (selected.length < 1 && this.placeholder === undefined) {
|
||||
selected = $(this.el.find("option")[0]);
|
||||
}
|
||||
if (selected.length > 0) {
|
||||
this.val({id: selected.attr("value"), text: selected.text()});
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
val: function () {
|
||||
var data;
|
||||
if (arguments.length === 0) {
|
||||
return this.selection.val();
|
||||
} else {
|
||||
data = arguments[0];
|
||||
this.results.val(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.fn.select2 = function () {
|
||||
var args = Array.prototype.slice.call(arguments, 0), value, tmp;
|
||||
this.each(function () {
|
||||
if (args.length === 0) {
|
||||
tmp = new Select2({el: this});
|
||||
} else if (typeof (args[0]) === "object") {
|
||||
args[0].el = this;
|
||||
tmp = new Select2(args[0]);
|
||||
} else if (typeof (args[0]) === "string") {
|
||||
var select2 = $(this).data("select2");
|
||||
value = select2[args[0]].apply(select2, args.slice(1));
|
||||
return false;
|
||||
} else {
|
||||
throw "Invalid arguments to select2 plugin: " + args;
|
||||
}
|
||||
});
|
||||
return (value === undefined) ? this : value;
|
||||
};
|
||||
|
||||
}(jQuery));
|
BIN
select2.png
Executable file
BIN
select2.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 396 B |
BIN
spinner.gif
Executable file
BIN
spinner.gif
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
Loading…
Reference in New Issue
Block a user