Merge branch 'release-1.4.1'
This commit is contained in:
commit
64b1dedd09
@ -2,6 +2,17 @@ X-editable changelog
|
||||
=============================
|
||||
|
||||
|
||||
Version 1.4.1 Jan 18, 2013
|
||||
----------------------------
|
||||
[enh #62] new option `selector` to work with delegated targets (vitalets)
|
||||
[enh] new option `unsavedclass` to set css class when value was not sent to server (vitalets)
|
||||
[enh] new option `emptyclass` to set css class when element is empty (vitalets)
|
||||
[enh #59] select2 input (vitalets)
|
||||
[enh #17] typeahead input (vitalets)
|
||||
[enh] select: support of OPTGROUP via `children` key in source (vitalets)
|
||||
[enh] checklist: set checked via prop instead of attr (vitalets)
|
||||
|
||||
|
||||
Version 1.4.0 Jan 11, 2013
|
||||
----------------------------
|
||||
[enh] added new input type: combodate (vitalets)
|
||||
|
6
grunt.js
6
grunt.js
@ -14,7 +14,9 @@ function getFiles() {
|
||||
inputs: [
|
||||
inputs+'date/date.js',
|
||||
inputs+'date/datefield.js',
|
||||
inputs+'date/bootstrap-datepicker/js/bootstrap-datepicker.js'],
|
||||
inputs+'date/bootstrap-datepicker/js/bootstrap-datepicker.js',
|
||||
inputs+'typeahead.js'
|
||||
],
|
||||
css: [inputs+'date/bootstrap-datepicker/css/datepicker.css']
|
||||
},
|
||||
jqueryui: {
|
||||
@ -52,6 +54,7 @@ function getFiles() {
|
||||
inputs+'select.js',
|
||||
inputs+'checklist.js',
|
||||
inputs+'html5types.js',
|
||||
inputs+'select2/select2.js',
|
||||
inputs+'combodate/lib/combodate.js',
|
||||
inputs+'combodate/combodate.js'
|
||||
];
|
||||
@ -162,6 +165,7 @@ module.exports = function(grunt) {
|
||||
'src/inputs/date/*.js',
|
||||
'src/inputs/dateui/*.js',
|
||||
'src/inputs/combodate/*.js',
|
||||
'src/inputs/select2/*.js',
|
||||
|
||||
'src/inputs-ext/address/*.js',
|
||||
'src/inputs-ext/wysihtml5/*.js'
|
||||
|
@ -2,7 +2,7 @@
|
||||
"name": "X-editable",
|
||||
"title": "X-editable",
|
||||
"description": "In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.1",
|
||||
"homepage": "http://github.com/vitalets/x-editable",
|
||||
"author": {
|
||||
"name": "Vitaliy Potapov",
|
||||
|
@ -23,8 +23,8 @@ Applied as jQuery method.
|
||||
innerCss: null, //tbd in child class
|
||||
init: function(element, options) {
|
||||
this.$element = $(element);
|
||||
//todo: what is in priority: data or js?
|
||||
this.options = $.extend({}, $.fn.editableContainer.defaults, $.fn.editableutils.getConfigData(this.$element), options);
|
||||
//since 1.4.1 container do not use data-* directly as they already merged into options.
|
||||
this.options = $.extend({}, $.fn.editableContainer.defaults, options);
|
||||
this.splitOptions();
|
||||
|
||||
//set scope of form callbacks to element
|
||||
@ -116,6 +116,7 @@ Applied as jQuery method.
|
||||
cancel: $.proxy(function(){ this.hide('cancel'); }, this), //click on calcel button
|
||||
show: $.proxy(this.setPosition, this), //re-position container every time form is shown (occurs each time after loading state)
|
||||
rendering: $.proxy(this.setPosition, this), //this allows to place container correctly when loading shown
|
||||
resize: $.proxy(this.setPosition, this), //this allows to re-position container when form size is changed
|
||||
rendered: $.proxy(function(){
|
||||
/**
|
||||
Fired when container is shown and form is rendered (for select will wait for loading dropdown options)
|
||||
@ -242,7 +243,6 @@ Applied as jQuery method.
|
||||
},
|
||||
|
||||
save: function(e, params) {
|
||||
this.hide('save');
|
||||
/**
|
||||
Fired when new value was submitted. You can use <code>$(this).data('editableContainer')</code> inside handler to access to editableContainer instance
|
||||
|
||||
@ -263,6 +263,9 @@ Applied as jQuery method.
|
||||
});
|
||||
**/
|
||||
this.$element.triggerHandler('save', params);
|
||||
|
||||
//hide must be after trigger, as saving value may require methods od plugin, applied to input
|
||||
this.hide('save');
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -38,12 +38,14 @@
|
||||
innerHide: function () {
|
||||
this.$tip.hide(this.options.anim, $.proxy(function() {
|
||||
this.$element.show();
|
||||
this.tip().empty().remove();
|
||||
this.innerDestroy();
|
||||
}, this));
|
||||
},
|
||||
|
||||
innerDestroy: function() {
|
||||
this.tip().remove();
|
||||
if(this.tip()) {
|
||||
this.tip().empty().remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -132,21 +132,34 @@
|
||||
/*
|
||||
returns array items from sourceData having value property equal or inArray of 'value'
|
||||
*/
|
||||
itemsByValue: function(value, sourceData) {
|
||||
itemsByValue: function(value, sourceData, valueProp) {
|
||||
if(!sourceData || value === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
//convert to array
|
||||
if(!$.isArray(value)) {
|
||||
value = [value];
|
||||
}
|
||||
valueProp = valueProp || 'value';
|
||||
|
||||
/*jslint eqeq: true*/
|
||||
var result = $.grep(sourceData, function(o){
|
||||
return $.grep(value, function(v){ return v == o.value; }).length;
|
||||
var isValArray = $.isArray(value),
|
||||
result = [],
|
||||
that = this;
|
||||
|
||||
$.each(sourceData, function(i, o) {
|
||||
if(o.children) {
|
||||
result = result.concat(that.itemsByValue(value, o.children));
|
||||
} else {
|
||||
/*jslint eqeq: true*/
|
||||
if(isValArray) {
|
||||
if($.grep(value, function(v){ return v == (o && typeof o === 'object' ? o[valueProp] : o); }).length) {
|
||||
result.push(o);
|
||||
}
|
||||
} else {
|
||||
if(value == (o && typeof o === 'object' ? o[valueProp] : o)) {
|
||||
result.push(o);
|
||||
}
|
||||
}
|
||||
/*jslint eqeq: false*/
|
||||
}
|
||||
});
|
||||
/*jslint eqeq: false*/
|
||||
|
||||
return result;
|
||||
},
|
||||
|
@ -110,18 +110,4 @@
|
||||
|
||||
.editable-clear-x:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/*
|
||||
.editable-clear-x1 {
|
||||
background: url('../img/clear.png') center center no-repeat;
|
||||
display: inline-block;
|
||||
zoom: 1;
|
||||
*display: inline;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
margin-left: -20px;
|
||||
}
|
||||
*/
|
||||
}
|
@ -11,7 +11,7 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
||||
|
||||
var EditableForm = function (div, options) {
|
||||
this.options = $.extend({}, $.fn.editableform.defaults, options);
|
||||
this.$div = $(div); //div, containing form. Not form tag! Not editable-element.
|
||||
this.$div = $(div); //div, containing form. Not form tag. Not editable-element.
|
||||
if(!this.options.scope) {
|
||||
this.options.scope = this;
|
||||
}
|
||||
@ -25,6 +25,7 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
||||
this.input = this.options.input;
|
||||
|
||||
//set initial value
|
||||
//todo: may be add check: typeof str === 'string' ?
|
||||
this.value = this.input.str2value(this.options.value);
|
||||
},
|
||||
initTemplate: function() {
|
||||
@ -227,6 +228,7 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
||||
}
|
||||
|
||||
//if success callback returns object like {newValue: <something>} --> use that value instead of submitted
|
||||
//it is usefull if you want to chnage value in url-function
|
||||
if(res && typeof res === 'object' && res.hasOwnProperty('newValue')) {
|
||||
newValue = res.newValue;
|
||||
}
|
||||
@ -382,18 +384,25 @@ Editableform is linked with one of input types, e.g. 'text', 'select' etc.
|
||||
type: 'text',
|
||||
/**
|
||||
Url for submit, e.g. <code>'/post'</code>
|
||||
If function - it will be called instead of ajax. Function can return deferred object to run fail/done callbacks.
|
||||
If function - it will be called instead of ajax. Function should return deferred object to run fail/done callbacks.
|
||||
|
||||
@property url
|
||||
@type string|function
|
||||
@default null
|
||||
@example
|
||||
url: function(params) {
|
||||
var d = new $.Deferred;
|
||||
if(params.value === 'abc') {
|
||||
var d = new $.Deferred;
|
||||
return d.reject('error message'); //returning error via deferred object
|
||||
} else {
|
||||
someModel.set(params.name, params.value); //save data in some js model
|
||||
//async saving data in js model
|
||||
someModel.asyncSaveMethod({
|
||||
...,
|
||||
success: function(){
|
||||
d.resolve();
|
||||
}
|
||||
});
|
||||
return d.promise();
|
||||
}
|
||||
}
|
||||
**/
|
||||
|
@ -8,8 +8,13 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
|
||||
var Editable = function (element, options) {
|
||||
this.$element = $(element);
|
||||
this.options = $.extend({}, $.fn.editable.defaults, $.fn.editableutils.getConfigData(this.$element), options);
|
||||
this.init();
|
||||
//data-* has more priority over js options: because dynamically created elements may change data-*
|
||||
this.options = $.extend({}, $.fn.editable.defaults, options, $.fn.editableutils.getConfigData(this.$element));
|
||||
if(this.options.selector) {
|
||||
this.initLive();
|
||||
} else {
|
||||
this.init();
|
||||
}
|
||||
};
|
||||
|
||||
Editable.prototype = {
|
||||
@ -52,8 +57,10 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
if(this.options.toggle !== 'manual') {
|
||||
this.$element.addClass('editable-click');
|
||||
this.$element.on(this.options.toggle + '.editable', $.proxy(function(e){
|
||||
//prevent following link
|
||||
e.preventDefault();
|
||||
//stop propagation not required anymore because in document click handler it checks event target
|
||||
|
||||
//stop propagation not required because in document click handler it checks event target
|
||||
//e.stopPropagation();
|
||||
|
||||
if(this.options.toggle === 'mouseenter') {
|
||||
@ -95,6 +102,24 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
}, this));
|
||||
},
|
||||
|
||||
/*
|
||||
Initializes parent element for live editables
|
||||
*/
|
||||
initLive: function() {
|
||||
//store selector
|
||||
var selector = this.options.selector;
|
||||
//modify options for child elements
|
||||
this.options.selector = false;
|
||||
this.options.autotext = 'never';
|
||||
//listen toggle events
|
||||
this.$element.on(this.options.toggle + '.editable', selector, $.proxy(function(e){
|
||||
var $target = $(e.target);
|
||||
if(!$target.data('editable')) {
|
||||
$target.editable(this.options).trigger(e);
|
||||
}
|
||||
}, this));
|
||||
},
|
||||
|
||||
/*
|
||||
Renders value into element's text.
|
||||
Can call custom display method from options.
|
||||
@ -108,8 +133,8 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
return;
|
||||
}
|
||||
|
||||
//if it is input with source, we pass callback in third param to be called when source is loaded
|
||||
if(this.input.options.hasOwnProperty('source')) {
|
||||
//if input has `value2htmlFinal` method, we pass callback in third param to be called when source is loaded
|
||||
if(this.input.value2htmlFinal) {
|
||||
return this.input.value2html(this.value, this.$element[0], this.options.display, response);
|
||||
//if display method defined --> use it
|
||||
} else if(typeof this.options.display === 'function') {
|
||||
@ -127,7 +152,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
enable: function() {
|
||||
this.options.disabled = false;
|
||||
this.$element.removeClass('editable-disabled');
|
||||
this.handleEmpty();
|
||||
this.handleEmpty(this.isEmpty);
|
||||
if(this.options.toggle !== 'manual') {
|
||||
if(this.$element.attr('tabindex') === '-1') {
|
||||
this.$element.removeAttr('tabindex');
|
||||
@ -143,7 +168,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
this.options.disabled = true;
|
||||
this.hide();
|
||||
this.$element.addClass('editable-disabled');
|
||||
this.handleEmpty();
|
||||
this.handleEmpty(this.isEmpty);
|
||||
//do not stop focus on this element
|
||||
this.$element.attr('tabindex', -1);
|
||||
},
|
||||
@ -204,27 +229,33 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
},
|
||||
|
||||
/*
|
||||
* set emptytext if element is empty (reverse: remove emptytext if needed)
|
||||
* set emptytext if element is empty
|
||||
*/
|
||||
handleEmpty: function () {
|
||||
handleEmpty: function (isEmpty) {
|
||||
//do not handle empty if we do not display anything
|
||||
if(this.options.display === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var emptyClass = 'editable-empty';
|
||||
this.isEmpty = isEmpty !== undefined ? isEmpty : $.trim(this.$element.text()) === '';
|
||||
|
||||
//emptytext shown only for enabled
|
||||
if(!this.options.disabled) {
|
||||
if ($.trim(this.$element.text()) === '') {
|
||||
this.$element.addClass(emptyClass).text(this.options.emptytext);
|
||||
} else {
|
||||
this.$element.removeClass(emptyClass);
|
||||
if (this.isEmpty) {
|
||||
this.$element.text(this.options.emptytext);
|
||||
if(this.options.emptyclass) {
|
||||
this.$element.addClass(this.options.emptyclass);
|
||||
}
|
||||
} else if(this.options.emptyclass) {
|
||||
this.$element.removeClass(this.options.emptyclass);
|
||||
}
|
||||
} else {
|
||||
//below required if element disable property was changed
|
||||
if(this.$element.hasClass(emptyClass)) {
|
||||
if(this.isEmpty) {
|
||||
this.$element.empty();
|
||||
this.$element.removeClass(emptyClass);
|
||||
if(this.options.emptyclass) {
|
||||
this.$element.removeClass(this.options.emptyclass);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -246,6 +277,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
input: this.input //pass input to form (as it is already created)
|
||||
});
|
||||
this.$element.editableContainer(containerOptions);
|
||||
//listen `save` event
|
||||
this.$element.on("save.internal", $.proxy(this.save, this));
|
||||
this.container = this.$element.data('editableContainer');
|
||||
} else if(this.container.tip().is(':visible')) {
|
||||
@ -283,13 +315,29 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
* called when form was submitted
|
||||
*/
|
||||
save: function(e, params) {
|
||||
//if url is not user's function and value was not sent to server and value changed --> mark element with unsaved css.
|
||||
if(typeof this.options.url !== 'function' && this.options.display !== false && params.response === undefined && this.input.value2str(this.value) !== this.input.value2str(params.newValue)) {
|
||||
this.$element.addClass('editable-unsaved');
|
||||
} else {
|
||||
this.$element.removeClass('editable-unsaved');
|
||||
//mark element with unsaved class if needed
|
||||
if(this.options.unsavedclass) {
|
||||
/*
|
||||
Add unsaved css to element if:
|
||||
- url is not user's function
|
||||
- value was not sent to server
|
||||
- params.response === undefined, that means data was not sent
|
||||
- value changed
|
||||
*/
|
||||
var sent = false;
|
||||
sent = sent || typeof this.options.url === 'function';
|
||||
sent = sent || this.options.display === false;
|
||||
sent = sent || params.response !== undefined;
|
||||
sent = sent || (this.options.savenochange && this.input.value2str(this.value) !== this.input.value2str(params.newValue));
|
||||
|
||||
if(sent) {
|
||||
this.$element.removeClass(this.options.unsavedclass);
|
||||
} else {
|
||||
this.$element.addClass(this.options.unsavedclass);
|
||||
}
|
||||
}
|
||||
|
||||
//set new value
|
||||
this.setValue(params.newValue, false, params.response);
|
||||
|
||||
/**
|
||||
@ -381,7 +429,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
url: '/post',
|
||||
pk: 1
|
||||
});
|
||||
**/
|
||||
**/
|
||||
$.fn.editable = function (option) {
|
||||
//special API methods returning non-jquery object
|
||||
var result = {}, args = arguments, datakey = 'editable';
|
||||
@ -398,7 +446,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
username: "username is required",
|
||||
fullname: "fullname should be minimum 3 letters length"
|
||||
}
|
||||
**/
|
||||
**/
|
||||
case 'validate':
|
||||
this.each(function () {
|
||||
var $this = $(this), data = $this.data(datakey), error;
|
||||
@ -419,7 +467,7 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
username: "superuser",
|
||||
fullname: "John"
|
||||
}
|
||||
**/
|
||||
**/
|
||||
case 'getValue':
|
||||
this.each(function () {
|
||||
var $this = $(this), data = $this.data(datakey);
|
||||
@ -438,11 +486,11 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
@param {object} options
|
||||
@param {object} options.url url to submit data
|
||||
@param {object} options.data additional data to submit
|
||||
@param {object} options.ajaxOptions additional ajax options
|
||||
@param {object} options.ajaxOptions additional ajax options
|
||||
@param {function} options.error(obj) error handler
|
||||
@param {function} options.success(obj,config) success handler
|
||||
@returns {Object} jQuery object
|
||||
**/
|
||||
**/
|
||||
case 'submit': //collects value, validate and submit to server for creating new record
|
||||
var config = arguments[1] || {},
|
||||
$elems = this,
|
||||
@ -593,7 +641,51 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
}
|
||||
}
|
||||
**/
|
||||
display: null
|
||||
display: null,
|
||||
/**
|
||||
Css class applied when editable text is empty.
|
||||
|
||||
@property emptyclass
|
||||
@type string
|
||||
@since 1.4.1
|
||||
@default editable-empty
|
||||
**/
|
||||
emptyclass: 'editable-empty',
|
||||
/**
|
||||
Css class applied when value was stored but not sent to server (`pk` is empty or `send = 'never'`).
|
||||
You may set it to `null` if you work with editables locally and submit them together.
|
||||
|
||||
@property unsavedclass
|
||||
@type string
|
||||
@since 1.4.1
|
||||
@default editable-unsaved
|
||||
**/
|
||||
unsavedclass: 'editable-unsaved',
|
||||
/**
|
||||
If a css selector is provided, editable will be delegated to the specified targets.
|
||||
Usefull for dynamically generated DOM elements.
|
||||
**Please note**, that delegated targets can't use `emptytext` and `autotext` options,
|
||||
as they are initialized after first click.
|
||||
|
||||
@property selector
|
||||
@type string
|
||||
@since 1.4.1
|
||||
@default null
|
||||
@example
|
||||
<div id="user">
|
||||
<a href="#" data-name="username" data-type="text" title="Username">awesome</a>
|
||||
<a href="#" data-name="group" data-type="select" data-source="/groups" data-value="1" title="Group">Operator</a>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('#user').editable({
|
||||
selector: 'a',
|
||||
url: '/post',
|
||||
pk: 1
|
||||
});
|
||||
</script>
|
||||
**/
|
||||
selector: null
|
||||
};
|
||||
|
||||
}(window.jQuery));
|
||||
|
@ -186,15 +186,7 @@ To create your own input you can inherit from this class.
|
||||
@type string
|
||||
@default input-medium
|
||||
**/
|
||||
inputclass: 'input-medium',
|
||||
/**
|
||||
Name attribute of input
|
||||
|
||||
@property name
|
||||
@type string
|
||||
@default null
|
||||
**/
|
||||
name: null
|
||||
inputclass: 'input-medium'
|
||||
};
|
||||
|
||||
$.extend($.fn.editabletypes, {abstractinput: AbstractInput});
|
||||
|
@ -42,8 +42,7 @@ $(function(){
|
||||
for(var i=0; i<this.sourceData.length; i++) {
|
||||
$label = $('<label>').append($('<input>', {
|
||||
type: 'checkbox',
|
||||
value: this.sourceData[i].value,
|
||||
name: this.options.name
|
||||
value: this.sourceData[i].value
|
||||
}))
|
||||
.append($('<span>').text(' '+this.sourceData[i].text));
|
||||
|
||||
@ -72,7 +71,7 @@ $(function(){
|
||||
|
||||
//set checked on required checkboxes
|
||||
value2input: function(value) {
|
||||
this.$input.removeAttr('checked');
|
||||
this.$input.prop('checked', false);
|
||||
if($.isArray(value) && value.length) {
|
||||
this.$input.each(function(i, el) {
|
||||
var $el = $(el);
|
||||
@ -81,7 +80,7 @@ $(function(){
|
||||
/*jslint eqeq: true*/
|
||||
if($el.val() == val) {
|
||||
/*jslint eqeq: false*/
|
||||
$el.attr('checked', 'checked');
|
||||
$el.prop('checked', true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -144,7 +144,7 @@ List - abstract class for inputs that have source option loaded from js array or
|
||||
}, this)
|
||||
});
|
||||
} else { //options as json/array/function
|
||||
if (typeof this.options.source === 'function') {
|
||||
if ($.isFunction(this.options.source)) {
|
||||
this.sourceData = this.makeArray(this.options.source());
|
||||
} else {
|
||||
this.sourceData = this.makeArray(this.options.source);
|
||||
@ -200,35 +200,45 @@ List - abstract class for inputs that have source option loaded from js array or
|
||||
* convert data to array suitable for sourceData, e.g. [{value: 1, text: 'abc'}, {...}]
|
||||
*/
|
||||
makeArray: function(data) {
|
||||
var count, obj, result = [], iterateEl;
|
||||
var count, obj, result = [], item, iterateItem;
|
||||
if(!data || typeof data === 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if($.isArray(data)) { //array
|
||||
iterateEl = function (k, v) {
|
||||
/*
|
||||
function to iterate inside item of array if item is object.
|
||||
Caclulates count of keys in item and store in obj.
|
||||
*/
|
||||
iterateItem = function (k, v) {
|
||||
obj = {value: k, text: v};
|
||||
if(count++ >= 2) {
|
||||
return false;// exit each if object has more than one value
|
||||
return false;// exit from `each` if item has more than one key.
|
||||
}
|
||||
};
|
||||
|
||||
for(var i = 0; i < data.length; i++) {
|
||||
if(typeof data[i] === 'object') {
|
||||
count = 0;
|
||||
$.each(data[i], iterateEl);
|
||||
if(count === 1) {
|
||||
item = data[i];
|
||||
if(typeof item === 'object') {
|
||||
count = 0; //count of keys inside item
|
||||
$.each(item, iterateItem);
|
||||
//case: [{val1: 'text1'}, {val2: 'text2} ...]
|
||||
if(count === 1) {
|
||||
result.push(obj);
|
||||
} else if(count > 1 && data[i].hasOwnProperty('value') && data[i].hasOwnProperty('text')) {
|
||||
result.push(data[i]);
|
||||
} else {
|
||||
//data contains incorrect objects
|
||||
//case: [{value: 1, text: 'text1'}, {value: 2, text: 'text2'}, ...]
|
||||
} else if(count > 1) {
|
||||
//removed check of existance: item.hasOwnProperty('value') && item.hasOwnProperty('text')
|
||||
if(item.children) {
|
||||
item.children = this.makeArray(item.children);
|
||||
}
|
||||
result.push(item);
|
||||
}
|
||||
} else {
|
||||
result.push({value: data[i], text: data[i]});
|
||||
//case: ['text1', 'text2' ...]
|
||||
result.push({value: item, text: item});
|
||||
}
|
||||
}
|
||||
} else { //object
|
||||
} else { //case: {val1: 'text1', val2: 'text2, ...}
|
||||
$.each(data, function (k, v) {
|
||||
result.push({value: k, text: v});
|
||||
});
|
||||
@ -251,12 +261,16 @@ List - abstract class for inputs that have source option loaded from js array or
|
||||
List.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
||||
/**
|
||||
Source data for list.
|
||||
If **array** - it should be in format: `[{value: 1, text: "text1"}, {...}]`
|
||||
If **array** - it should be in format: `[{value: 1, text: "text1"}, {value: 2, text: "text2"}, ...]`
|
||||
For compability, object format is also supported: `{"1": "text1", "2": "text2" ...}` but it does not guarantee elements order.
|
||||
|
||||
If **string** - considered ajax url to load items. In that case results will be cached for fields with the same source and name. See also `sourceCache` option.
|
||||
|
||||
If **function**, it should return data in format above (since 1.4.0).
|
||||
|
||||
Since 1.4.1 key `children` supported to render OPTGROUP (for **select** input only).
|
||||
`[{text: "group1", children: [{value: 1, text: "text1"}, {value: 2, text: "text2"}]}, ...]`
|
||||
|
||||
|
||||
@property source
|
||||
@type string | array | object | function
|
||||
@ -280,8 +294,8 @@ List - abstract class for inputs that have source option loaded from js array or
|
||||
**/
|
||||
sourceError: 'Error when loading list',
|
||||
/**
|
||||
if <code>true</code> and source is **string url** - results will be cached for fields with the same source and name.
|
||||
Usefull for editable grids.
|
||||
if <code>true</code> and source is **string url** - results will be cached for fields with the same source.
|
||||
Usefull for editable column in grid to prevent extra requests.
|
||||
|
||||
@property sourceCache
|
||||
@type boolean
|
||||
|
@ -31,14 +31,21 @@ $(function(){
|
||||
$.extend(Select.prototype, {
|
||||
renderList: function() {
|
||||
this.$input.empty();
|
||||
|
||||
if(!$.isArray(this.sourceData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(var i=0; i<this.sourceData.length; i++) {
|
||||
this.$input.append($('<option>', {value: this.sourceData[i].value}).text(this.sourceData[i].text));
|
||||
}
|
||||
var fillItems = function($el, data) {
|
||||
if($.isArray(data)) {
|
||||
for(var i=0; i<data.length; i++) {
|
||||
if(data[i].children) {
|
||||
$el.append(fillItems($('<optgroup>', {label: data[i].text}), data[i].children));
|
||||
} else {
|
||||
$el.append($('<option>', {value: data[i].value}).text(data[i].text));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $el;
|
||||
};
|
||||
|
||||
fillItems(this.$input, this.sourceData);
|
||||
|
||||
this.setClass();
|
||||
|
||||
|
12
src/inputs/select2/lib/LICENSE
Normal file
12
src/inputs/select2/lib/LICENSE
Normal file
@ -0,0 +1,12 @@
|
||||
Copyright 2012 Igor Vaynberg
|
||||
|
||||
Version: @@ver@@ Timestamp: @@timestamp@@
|
||||
|
||||
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.
|
68
src/inputs/select2/lib/README.md
Normal file
68
src/inputs/select2/lib/README.md
Normal file
@ -0,0 +1,68 @@
|
||||
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!
|
||||
|
||||
What Does Select2 Support That Chosen Does Not?
|
||||
-------------------------------------------------
|
||||
|
||||
* Working with large datasets: Chosen requires the entire dataset to be loaded as `option` tags in the DOM, which limits
|
||||
it to working with small-ish datasets. Select2 uses a function to find results on-the-fly, which allows it to partially
|
||||
load results.
|
||||
* Paging of results: Since Select2 works with large datasets and only loads a small amount of matching results at a time
|
||||
it has to support paging. Select2 will call the search function when the user scrolls to the bottom of currently loaded
|
||||
result set allowing for the 'infinite scrolling' of results.
|
||||
* Custom markup for results: Chosen only supports rendering text results because that is the only markup supported by
|
||||
`option` tags. Select2 provides an extension point which can be used to produce any kind of markup to represent results.
|
||||
* Ability to add results on the fly: Select2 provides the ability to add results from the search term entered by the user, which allows it to be used for
|
||||
tagging.
|
||||
|
||||
Browser Compatibility
|
||||
--------------------
|
||||
* IE 8+ (7 mostly works except for [issue with z-index](https://github.com/ivaynberg/select2/issues/37))
|
||||
* Chrome 8+
|
||||
* Firefox 3.5+
|
||||
* Safari 3+
|
||||
* Opera 10.6+
|
||||
|
||||
Integrations
|
||||
------------
|
||||
|
||||
* [Wicket-Select2](https://github.com/ivaynberg/wicket-select2) (Java / Apache Wicket)
|
||||
* [select2-rails](https://github.com/argerim/select2-rails) (Ruby on Rails)
|
||||
* [AngularUI](http://angular-ui.github.com/#directives-select2) ([AngularJS](angularjs.org))
|
||||
* [Django](https://github.com/applegrew/django-select2)
|
||||
|
||||
Bug tracker
|
||||
-----------
|
||||
|
||||
Have a bug? Please create an issue here on GitHub!
|
||||
|
||||
https://github.com/ivaynberg/select2/issues
|
||||
|
||||
|
||||
Mailing list
|
||||
------------
|
||||
|
||||
Have a question? Ask on our mailing list!
|
||||
|
||||
select2@googlegroups.com
|
||||
|
||||
https://groups.google.com/d/forum/select2
|
||||
|
||||
|
||||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright 2012 Igor Vaynberg
|
||||
|
||||
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.
|
63
src/inputs/select2/lib/release.sh
Normal file
63
src/inputs/select2/lib/release.sh
Normal file
@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo -n "Enter the version for this release: "
|
||||
|
||||
read ver
|
||||
|
||||
if [ ! $ver ]; then
|
||||
echo "Invalid version."
|
||||
exit
|
||||
fi
|
||||
|
||||
name="select2"
|
||||
js="$name.js"
|
||||
mini="$name.min.js"
|
||||
css="$name.css"
|
||||
release="$name-$ver"
|
||||
tag="release-$ver"
|
||||
branch="build-$ver"
|
||||
curbranch=`git branch | grep "*" | sed "s/* //"`
|
||||
timestamp=$(date)
|
||||
tokens="s/@@ver@@/$ver/g;s/\@@timestamp@@/$timestamp/g"
|
||||
remote="github"
|
||||
|
||||
git branch "$branch"
|
||||
git checkout "$branch"
|
||||
|
||||
echo "Tokenizing..."
|
||||
|
||||
find . -name "$js" | xargs -I{} sed -e "$tokens" -i "" {}
|
||||
find . -name "$css" | xargs -I{} sed -e "$tokens" -i "" {}
|
||||
|
||||
git add "$js"
|
||||
git add "$css"
|
||||
|
||||
echo "Minifying..."
|
||||
|
||||
echo "/*" > "$mini"
|
||||
cat LICENSE | sed "$tokens" >> "$mini"
|
||||
echo "*/" >> "$mini"
|
||||
|
||||
curl -s \
|
||||
-d compilation_level=SIMPLE_OPTIMIZATIONS \
|
||||
-d output_format=text \
|
||||
-d output_info=compiled_code \
|
||||
--data-urlencode "js_code@$js" \
|
||||
http://closure-compiler.appspot.com/compile \
|
||||
>> "$mini"
|
||||
|
||||
git add "$mini"
|
||||
|
||||
git commit -m "release $ver"
|
||||
|
||||
echo "Tagging..."
|
||||
git tag -a "$tag" -m "tagged version $ver"
|
||||
git push "$remote" --tags
|
||||
|
||||
echo "Cleaning Up..."
|
||||
|
||||
git checkout "$curbranch"
|
||||
git branch -D "$branch"
|
||||
|
||||
echo "Done"
|
524
src/inputs/select2/lib/select2.css
vendored
Normal file
524
src/inputs/select2/lib/select2.css
vendored
Normal file
@ -0,0 +1,524 @@
|
||||
/*
|
||||
Version: 3.2 Timestamp: Mon Sep 10 10:38:04 PDT 2012
|
||||
*/
|
||||
.select2-container {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
/* inline-block for ie7 */
|
||||
zoom: 1;
|
||||
*display: inline;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.select2-container,
|
||||
.select2-drop,
|
||||
.select2-search,
|
||||
.select2-search input{
|
||||
/*
|
||||
Force border-box so that % widths fit the parent
|
||||
container without overlap because of margin/padding.
|
||||
|
||||
More Info : http://www.quirksmode.org/css/box.html
|
||||
*/
|
||||
-moz-box-sizing: border-box; /* firefox */
|
||||
-ms-box-sizing: border-box; /* ie */
|
||||
-webkit-box-sizing: border-box; /* webkit */
|
||||
-khtml-box-sizing: border-box; /* konqueror */
|
||||
box-sizing: border-box; /* css3 */
|
||||
}
|
||||
|
||||
.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(bottom, #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-drop-above .select2-choice
|
||||
{
|
||||
border-bottom-color: #aaa;
|
||||
-webkit-border-radius:0px 0px 4px 4px;
|
||||
-moz-border-radius:0px 0px 4px 4px;
|
||||
border-radius:0px 0px 4px 4px;
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(0.9, white));
|
||||
background-image: -webkit-linear-gradient(center bottom, #eeeeee 0%, white 90%);
|
||||
background-image: -moz-linear-gradient(center bottom, #eeeeee 0%, white 90%);
|
||||
background-image: -o-linear-gradient(bottom, #eeeeee 0%, white 90%);
|
||||
background-image: -ms-linear-gradient(top, #eeeeee 0%,#ffffff 90%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff',GradientType=0 );
|
||||
background-image: linear-gradient(top, #eeeeee 0%,#ffffff 90%);
|
||||
}
|
||||
|
||||
.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-drop {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
border: 1px solid #aaa;
|
||||
border-top: 0;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
-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: 9999;
|
||||
width:100%;
|
||||
margin-top:-1px;
|
||||
|
||||
-webkit-border-radius: 0 0 4px 4px;
|
||||
-moz-border-radius: 0 0 4px 4px;
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
|
||||
.select2-drop.select2-drop-above {
|
||||
-webkit-border-radius: 4px 4px 0px 0px;
|
||||
-moz-border-radius: 4px 4px 0px 0px;
|
||||
border-radius: 4px 4px 0px 0px;
|
||||
margin-top:1px;
|
||||
border-top: 1px solid #aaa;
|
||||
border-bottom: 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);
|
||||
}
|
||||
|
||||
.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-search {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
z-index: 10000;
|
||||
min-height: 26px;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.select2-search-hidden {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -10000px;
|
||||
}
|
||||
|
||||
.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%);
|
||||
padding: 4px 20px 4px 5px;
|
||||
outline: 0;
|
||||
border: 1px solid #aaa;
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
width:100%;
|
||||
margin:0;
|
||||
height:auto !important;
|
||||
min-height: 26px;
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
-moz-border-radius: 0;
|
||||
-webkit-border-radius: 0;
|
||||
}
|
||||
|
||||
.select2-drop.select2-drop-above .select2-search input
|
||||
{
|
||||
margin-top:4px;
|
||||
}
|
||||
|
||||
.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%);
|
||||
}
|
||||
|
||||
|
||||
.select2-container-active .select2-choice,
|
||||
.select2-container-active .select2-choices {
|
||||
-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;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.select2-dropdown-open .select2-choice {
|
||||
border: 1px solid #aaa;
|
||||
border-bottom-color: transparent;
|
||||
-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-results {
|
||||
margin: 4px 4px 4px 0;
|
||||
padding: 0 0 0 4px;
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.select2-results ul.select2-result-sub {
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
|
||||
.select2-results ul.select2-result-sub > li .select2-result-label { padding-left: 20px }
|
||||
.select2-results ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 40px }
|
||||
.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 60px }
|
||||
.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 80px }
|
||||
.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 100px }
|
||||
.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 110px }
|
||||
.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 120px }
|
||||
|
||||
.select2-results li {
|
||||
list-style: none;
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
.select2-results li.select2-result-with-children > .select2-result-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.select2-results .select2-result-label {
|
||||
padding: 3px 7px 4px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.select2-results .select2-highlighted {
|
||||
background: #3875d7;
|
||||
color: #fff;
|
||||
}
|
||||
.select2-results li em {
|
||||
background: #feffde;
|
||||
font-style: normal;
|
||||
}
|
||||
.select2-results .select2-highlighted em {
|
||||
background: transparent;
|
||||
}
|
||||
.select2-results .select2-no-results,
|
||||
.select2-results .select2-searching,
|
||||
.select2-results .select2-selection-limit {
|
||||
background: #f4f4f4;
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/*
|
||||
disabled look for already selected choices in the results dropdown
|
||||
.select2-results .select2-disabled.select2-highlighted {
|
||||
color: #666;
|
||||
background: #f4f4f4;
|
||||
display: list-item;
|
||||
cursor: default;
|
||||
}
|
||||
.select2-results .select2-disabled {
|
||||
background: #f4f4f4;
|
||||
display: list-item;
|
||||
cursor: default;
|
||||
}
|
||||
*/
|
||||
.select2-results .select2-disabled {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.select2-more-results.select2-active {
|
||||
background: #f4f4f4 url('spinner.gif') no-repeat 100%;
|
||||
}
|
||||
|
||||
.select2-more-results {
|
||||
background: #f4f4f4;
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/* disabled styles */
|
||||
|
||||
.select2-container.select2-container-disabled .select2-choice {
|
||||
background-color: #f4f4f4;
|
||||
background-image: none;
|
||||
border: 1px solid #ddd;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.select2-container.select2-container-disabled .select2-choice div {
|
||||
background-color: #f4f4f4;
|
||||
background-image: none;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
|
||||
/* 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 {
|
||||
min-height: 26px;
|
||||
}
|
||||
|
||||
.select2-container-multi.select2-container-active .select2-choices {
|
||||
-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;
|
||||
outline: none;
|
||||
}
|
||||
.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-container-multi .select2-choices .select2-search-field input.select2-active {
|
||||
background: #fff url('spinner.gif') no-repeat 100% !important;
|
||||
}
|
||||
|
||||
.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;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
/* disabled styles */
|
||||
|
||||
.select2-container-multi.select2-container-disabled .select2-choices{
|
||||
background-color: #f4f4f4;
|
||||
background-image: none;
|
||||
border: 1px solid #ddd;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice {
|
||||
background-image: none;
|
||||
background-color: #f4f4f4;
|
||||
border: 1px solid #ddd;
|
||||
padding: 3px 5px 3px 5px;
|
||||
}
|
||||
|
||||
.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close {
|
||||
display: none;
|
||||
}
|
||||
/* end multiselect */
|
||||
|
||||
.select2-result-selectable .select2-match,
|
||||
.select2-result-unselectable .select2-result-selectable .select2-match { text-decoration: underline; }
|
||||
.select2-result-unselectable .select2-match { text-decoration: none; }
|
||||
|
||||
.select2-offscreen { position: absolute; left: -10000px; }
|
||||
|
||||
/* Retina-ize icons */
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 1.5) {
|
||||
.select2-search input, .select2-search-choice-close, .select2-container .select2-choice abbr, .select2-container .select2-choice div b {
|
||||
background-image: url(select2x2.png) !important;
|
||||
background-repeat: no-repeat !important;
|
||||
background-size: 60px 40px !important;
|
||||
}
|
||||
.select2-search input {
|
||||
background-position: 100% -21px !important;
|
||||
}
|
||||
}
|
2407
src/inputs/select2/lib/select2.js
vendored
Normal file
2407
src/inputs/select2/lib/select2.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
82
src/inputs/select2/lib/select2.min.js
vendored
Normal file
82
src/inputs/select2/lib/select2.min.js
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright 2012 Igor Vaynberg
|
||||
|
||||
Version: 3.2 Timestamp: Mon Sep 10 10:38:04 PDT 2012
|
||||
|
||||
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.
|
||||
*/
|
||||
(function(e){"undefined"==typeof e.fn.each2&&e.fn.extend({each2:function(g){for(var i=e([0]),m=-1,s=this.length;++m<s&&(i.context=i[0]=this[m])&&!1!==g.call(i[0],m,i););return this}})})(jQuery);
|
||||
(function(e,g){function i(a,b){var c=0,d=b.length,j;if("undefined"===typeof a)return-1;if(a.constructor===String)for(;c<d;c+=1){if(0===a.localeCompare(b[c]))return c}else for(;c<d;c+=1)if(j=b[c],j.constructor===String){if(0===j.localeCompare(a))return c}else if(j===a)return c;return-1}function m(a,b){return a===b?!0:a===g||b===g||null===a||null===b?!1:a.constructor===String?0===a.localeCompare(b):b.constructor===String?0===b.localeCompare(a):!1}function s(a,b){var c,d,j;if(null===a||1>a.length)return[];
|
||||
c=a.split(b);d=0;for(j=c.length;d<j;d+=1)c[d]=e.trim(c[d]);return c}function A(a,b,c){var c=c||g,d;return function(){var j=arguments;window.clearTimeout(d);d=window.setTimeout(function(){b.apply(c,j)},a)}}function l(a){a.preventDefault();a.stopPropagation()}function B(a,b,c){var d=a.toUpperCase().indexOf(b.toUpperCase()),b=b.length;0>d?c.push(a):(c.push(a.substring(0,d)),c.push("<span class='select2-match'>"),c.push(a.substring(d,d+b)),c.push("</span>"),c.push(a.substring(d+b,a.length)))}function C(a){var b,
|
||||
c=0,d=null,j=a.quietMillis||100;return function(h){window.clearTimeout(b);b=window.setTimeout(function(){var b=c+=1,j=a.data,n=a.transport||e.ajax,f=a.traditional||!1,g=a.type||"GET",j=j.call(this,h.term,h.page,h.context);null!==d&&d.abort();d=n.call(null,{url:a.url,dataType:a.dataType,data:j,type:g,traditional:f,success:function(d){b<c||(d=a.results(d,h.page),h.callback(d))}})},j)}}function D(a){var b=a,c,d=function(a){return""+a.text};e.isArray(b)||(d=b.text,e.isFunction(d)||(c=b.text,d=function(a){return a[c]}),
|
||||
b=b.results);return function(a){var c=a.term,f={results:[]},k;if(c==="")a.callback({results:b});else{k=function(b,f){var g,t,b=b[0];if(b.children){g={};for(t in b)b.hasOwnProperty(t)&&(g[t]=b[t]);g.children=[];e(b.children).each2(function(a,b){k(b,g.children)});g.children.length&&f.push(g)}else a.matcher(c,d(b))&&f.push(b)};e(b).each2(function(a,b){k(b,f.results)});a.callback(f)}}}function E(a){return e.isFunction(a)?a:function(b){var c=b.term,d={results:[]};e(a).each(function(){var a=this.text!==
|
||||
g,e=a?this.text:this;if(""===c||b.matcher(c,e))d.results.push(a?this:{id:this,text:this})});b.callback(d)}}function u(a){if(e.isFunction(a))return!0;if(!a)return!1;throw Error("formatterName must be a function or a falsy value");}function v(a){return e.isFunction(a)?a():a}function F(a){var b=0;e.each(a,function(a,d){d.children?b+=F(d.children):b++});return b}function H(a,b,c,d){var e=a,h=!1,f,k,n,o;if(!d.createSearchChoice||!d.tokenSeparators||1>d.tokenSeparators.length)return g;for(;;){h=-1;k=0;
|
||||
for(n=d.tokenSeparators.length;k<n&&!(o=d.tokenSeparators[k],h=a.indexOf(o),0<=h);k++);if(0>h)break;f=a.substring(0,h);a=a.substring(h+o.length);if(0<f.length&&(f=d.createSearchChoice(f,b),f!==g&&null!==f&&d.id(f)!==g&&null!==d.id(f))){h=!1;k=0;for(n=b.length;k<n;k++)if(m(d.id(f),d.id(b[k]))){h=!0;break}h||c(f)}}if(0!=e.localeCompare(a))return a}function x(a,b){var c=function(){};c.prototype=new a;c.prototype.constructor=c;c.prototype.parent=a.prototype;c.prototype=e.extend(c.prototype,b);return c}
|
||||
if(window.Select2===g){var f,w,y,z,G,q;f={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(a){a=a.which?a.which:a;switch(a){case f.LEFT:case f.RIGHT:case f.UP:case f.DOWN:return!0}return!1},isControl:function(a){switch(a.which){case f.SHIFT:case f.CTRL:case f.ALT:return!0}return a.metaKey?!0:!1},isFunctionKey:function(a){a=a.which?a.which:a;return 112<=a&&123>=a}};var I=1;G=function(){return I++};
|
||||
e(document).delegate("body","mousemove",function(a){e.data(document,"select2-lastpos",{x:a.pageX,y:a.pageY})});e(document).ready(function(){e(document).delegate("body","mousedown touchend",function(a){var b=e(a.target).closest("div.select2-container").get(0),c;b?e(document).find("div.select2-container-active").each(function(){this!==b&&e(this).data("select2").blur()}):(b=e(a.target).closest("div.select2-drop").get(0),e(document).find("div.select2-drop-active").each(function(){this!==b&&e(this).data("select2").blur()}));
|
||||
b=e(a.target);c=b.attr("for");"LABEL"===a.target.tagName&&(c&&0<c.length)&&(b=e("#"+c),b=b.data("select2"),b!==g&&(b.focus(),a.preventDefault()))})});w=x(Object,{bind:function(a){var b=this;return function(){a.apply(b,arguments)}},init:function(a){var b,c;this.opts=a=this.prepareOpts(a);this.id=a.id;a.element.data("select2")!==g&&null!==a.element.data("select2")&&this.destroy();this.enabled=!0;this.container=this.createContainer();this.containerId="s2id_"+(a.element.attr("id")||"autogen"+G());this.containerSelector=
|
||||
"#"+this.containerId.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g,"\\$1");this.container.attr("id",this.containerId);var d=!1,j;this.body=function(){!1===d&&(j=a.element.closest("body"),d=!0);return j};a.element.attr("class")!==g&&this.container.addClass(a.element.attr("class").replace(/validate\[[\S ]+] ?/,""));this.container.css(v(a.containerCss));this.container.addClass(v(a.containerCssClass));this.opts.element.data("select2",this).hide().before(this.container);this.container.data("select2",
|
||||
this);this.dropdown=this.container.find(".select2-drop");this.dropdown.addClass(v(a.dropdownCssClass));this.dropdown.data("select2",this);this.results=b=this.container.find(".select2-results");this.search=c=this.container.find("input.select2-input");c.attr("tabIndex",this.opts.element.attr("tabIndex"));this.resultsPage=0;this.context=null;this.initContainer();this.initContainerWidth();this.results.bind("mousemove",function(a){var b=e.data(document,"select2-lastpos");(b===g||b.x!==a.pageX||b.y!==a.pageY)&&
|
||||
e(a.target).trigger("mousemove-filtered",a)});this.dropdown.delegate(".select2-results","mousemove-filtered",this.bind(this.highlightUnderEvent));var h=this.results,f=A(80,function(a){h.trigger("scroll-debounced",a)});h.bind("scroll",function(a){0<=i(a.target,h.get())&&f(a)});this.dropdown.delegate(".select2-results","scroll-debounced",this.bind(this.loadMoreIfNeeded));e.fn.mousewheel&&b.mousewheel(function(a,c,d,e){c=b.scrollTop();0<e&&0>=c-e?(b.scrollTop(0),l(a)):0>e&&b.get(0).scrollHeight-b.scrollTop()+
|
||||
e<=b.height()&&(b.scrollTop(b.get(0).scrollHeight-b.height()),l(a))});c.bind("keydown",function(){e.data(c,"keyup-change-value")===g&&e.data(c,"keyup-change-value",c.val())});c.bind("keyup",function(){var a=e.data(c,"keyup-change-value");a!==g&&c.val()!==a&&(e.removeData(c,"keyup-change-value"),c.trigger("keyup-change"))});c.bind("keyup-change",this.bind(this.updateResults));c.bind("focus",function(){c.addClass("select2-focused");" "===c.val()&&c.val("")});c.bind("blur",function(){c.removeClass("select2-focused")});
|
||||
this.dropdown.delegate(".select2-results","mouseup",this.bind(function(a){0<e(a.target).closest(".select2-result-selectable:not(.select2-disabled)").length?(this.highlightUnderEvent(a),this.selectHighlighted(a)):this.focusSearch();l(a)}));this.dropdown.bind("click mouseup mousedown",function(a){a.stopPropagation()});e.isFunction(this.opts.initSelection)&&(this.initSelection(),this.monitorSource());(a.element.is(":disabled")||a.element.is("[readonly='readonly']"))&&this.disable()},destroy:function(){var a=
|
||||
this.opts.element.data("select2");a!==g&&(a.container.remove(),a.dropdown.remove(),a.opts.element.removeData("select2").unbind(".select2").show())},prepareOpts:function(a){var b,c,d;b=a.element;"select"===b.get(0).tagName.toLowerCase()&&(this.select=c=a.element);c&&e.each("id multiple ajax query createSearchChoice initSelection data tags".split(" "),function(){if(this in a)throw Error("Option '"+this+"' is not allowed for Select2 when attached to a <select> element.");});a=e.extend({},{populateResults:function(b,
|
||||
c,d){var f,n=this.opts.id,o=this;f=function(b,c,j){var h,l,i,m,r,p,q;h=0;for(l=b.length;h<l;h=h+1){i=b[h];m=n(i)!==g;r=i.children&&i.children.length>0;p=e("<li></li>");p.addClass("select2-results-dept-"+j);p.addClass("select2-result");p.addClass(m?"select2-result-selectable":"select2-result-unselectable");r&&p.addClass("select2-result-with-children");p.addClass(o.opts.formatResultCssClass(i));m=e("<div></div>");m.addClass("select2-result-label");q=a.formatResult(i,m,d);q!==g&&m.html(o.opts.escapeMarkup(q));
|
||||
p.append(m);if(r){r=e("<ul></ul>");r.addClass("select2-result-sub");f(i.children,r,j+1);p.append(r)}p.data("select2-data",i);c.append(p)}};f(c,b,0)}},e.fn.select2.defaults,a);"function"!==typeof a.id&&(d=a.id,a.id=function(a){return a[d]});if(c)a.query=this.bind(function(a){var c={results:[],more:false},d=a.term,f,n,o;o=function(b,c){var e;if(b.is("option"))a.matcher(d,b.text(),b)&&c.push({id:b.attr("value"),text:b.text(),element:b.get(),css:b.attr("class")});else if(b.is("optgroup")){e={text:b.attr("label"),
|
||||
children:[],element:b.get(),css:b.attr("class")};b.children().each2(function(a,b){o(b,e.children)});e.children.length>0&&c.push(e)}};f=b.children();if(this.getPlaceholder()!==g&&f.length>0){n=f[0];e(n).text()===""&&(f=f.not(n))}f.each2(function(a,b){o(b,c.results)});a.callback(c)}),a.id=function(a){return a.id},a.formatResultCssClass=function(a){return a.css};else if(!("query"in a))if("ajax"in a){if((c=a.element.data("ajax-url"))&&0<c.length)a.ajax.url=c;a.query=C(a.ajax)}else"data"in a?a.query=D(a.data):
|
||||
"tags"in a&&(a.query=E(a.tags),a.createSearchChoice=function(a){return{id:a,text:a}},a.initSelection=function(b,c){var d=[];e(s(b.val(),a.separator)).each(function(){var b=this,c=this,j=a.tags;e.isFunction(j)&&(j=j());e(j).each(function(){if(m(this.id,b)){c=this.text;return false}});d.push({id:b,text:c})});c(d)});if("function"!==typeof a.query)throw"query function not defined for Select2 "+a.element.attr("id");return a},monitorSource:function(){this.opts.element.bind("change.select2",this.bind(function(){!0!==
|
||||
this.opts.element.data("select2-change-triggered")&&this.initSelection()}))},triggerChange:function(a){a=a||{};a=e.extend({},a,{type:"change",val:this.val()});this.opts.element.data("select2-change-triggered",!0);this.opts.element.trigger(a);this.opts.element.data("select2-change-triggered",!1);this.opts.element.click();this.opts.blurOnChange&&this.opts.element.blur()},enable:function(){this.enabled||(this.enabled=!0,this.container.removeClass("select2-container-disabled"))},disable:function(){this.enabled&&
|
||||
(this.close(),this.enabled=!1,this.container.addClass("select2-container-disabled"))},opened:function(){return this.container.hasClass("select2-dropdown-open")},positionDropdown:function(){var a=this.container.offset(),b=this.container.outerHeight(),c=this.container.outerWidth(),d=this.dropdown.outerHeight(),j=e(window).scrollTop()+document.documentElement.clientHeight,b=a.top+b,f=a.left,j=b+d<=j,g=a.top-d>=this.body().scrollTop(),k=this.dropdown.hasClass("select2-drop-above"),n;"static"!==this.body().css("position")&&
|
||||
(n=this.body().offset(),b-=n.top,f-=n.left);k?(k=!0,!g&&j&&(k=!1)):(k=!1,!j&&g&&(k=!0));k?(b=a.top-d,this.container.addClass("select2-drop-above"),this.dropdown.addClass("select2-drop-above")):(this.container.removeClass("select2-drop-above"),this.dropdown.removeClass("select2-drop-above"));a=e.extend({top:b,left:f,width:c},v(this.opts.dropdownCss));this.dropdown.css(a)},shouldOpen:function(){var a;if(this.opened())return!1;a=e.Event("open");this.opts.element.trigger(a);return!a.isDefaultPrevented()},
|
||||
clearDropdownAlignmentPreference:function(){this.container.removeClass("select2-drop-above");this.dropdown.removeClass("select2-drop-above")},open:function(){if(!this.shouldOpen())return!1;window.setTimeout(this.bind(this.opening),1);return!0},opening:function(){var a=this.containerId,b=this.containerSelector,c="scroll."+a,d="resize."+a;this.container.parents().each(function(){e(this).bind(c,function(){var a=e(b);0==a.length&&e(this).unbind(c);a.select2("close")})});e(window).bind(d,function(){var a=
|
||||
e(b);0==a.length&&e(window).unbind(d);a.select2("close")});this.clearDropdownAlignmentPreference();" "===this.search.val()&&this.search.val("");this.container.addClass("select2-dropdown-open").addClass("select2-container-active");this.updateResults(!0);this.dropdown[0]!==this.body().children().last()[0]&&this.dropdown.detach().appendTo(this.body());this.dropdown.show();this.positionDropdown();this.dropdown.addClass("select2-drop-active");this.ensureHighlightVisible();this.focusSearch()},close:function(){if(this.opened()){var a=
|
||||
this;this.container.parents().each(function(){e(this).unbind("scroll."+a.containerId)});e(window).unbind("resize."+this.containerId);this.clearDropdownAlignmentPreference();this.dropdown.hide();this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active");this.results.empty();this.clearSearch();this.opts.element.trigger(e.Event("close"))}},clearSearch:function(){},ensureHighlightVisible:function(){var a=this.results,b,c,d,f;c=this.highlight();0>c||(0==c?a.scrollTop(0):
|
||||
(b=a.find(".select2-result-selectable"),d=e(b[c]),f=d.offset().top+d.outerHeight(),c===b.length-1&&(b=a.find("li.select2-more-results"),0<b.length&&(f=b.offset().top+b.outerHeight())),b=a.offset().top+a.outerHeight(),f>b&&a.scrollTop(a.scrollTop()+(f-b)),d=d.offset().top-a.offset().top,0>d&&a.scrollTop(a.scrollTop()+d)))},moveHighlight:function(a){for(var b=this.results.find(".select2-result-selectable"),c=this.highlight();-1<c&&c<b.length;){var c=c+a,d=e(b[c]);if(d.hasClass("select2-result-selectable")&&
|
||||
!d.hasClass("select2-disabled")){this.highlight(c);break}}},highlight:function(a){var b=this.results.find(".select2-result-selectable").not(".select2-disabled");if(0===arguments.length)return i(b.filter(".select2-highlighted")[0],b.get());a>=b.length&&(a=b.length-1);0>a&&(a=0);b.removeClass("select2-highlighted");e(b[a]).addClass("select2-highlighted");this.ensureHighlightVisible()},countSelectableResults:function(){return this.results.find(".select2-result-selectable").not(".select2-disabled").length},
|
||||
highlightUnderEvent:function(a){a=e(a.target).closest(".select2-result-selectable");if(0<a.length&&!a.is(".select2-highlighted")){var b=this.results.find(".select2-result-selectable");this.highlight(b.index(a))}else 0==a.length&&this.results.find(".select2-highlighted").removeClass("select2-highlighted")},loadMoreIfNeeded:function(){var a=this.results,b=a.find("li.select2-more-results"),c,d=this.resultsPage+1,e=this,f=this.search.val(),g=this.context;0!==b.length&&(c=b.offset().top-a.offset().top-
|
||||
a.height(),0>=c&&(b.addClass("select2-active"),this.opts.query({term:f,page:d,context:g,matcher:this.opts.matcher,callback:this.bind(function(c){e.opened()&&(e.opts.populateResults.call(this,a,c.results,{term:f,page:d,context:g}),!0===c.more?(b.detach().appendTo(a).text(e.opts.formatLoadMore(d+1)),window.setTimeout(function(){e.loadMoreIfNeeded()},10)):b.remove(),e.positionDropdown(),e.resultsPage=d)})})))},tokenize:function(){},updateResults:function(a){function b(){f.scrollTop(0);d.removeClass("select2-active");
|
||||
k.positionDropdown()}function c(a){f.html(k.opts.escapeMarkup(a));b()}var d=this.search,f=this.results,h=this.opts,i,k=this;if(!(!0!==a&&(!1===this.showSearchInput||!this.opened()))){d.addClass("select2-active");if(1<=h.maximumSelectionSize&&(i=this.data(),e.isArray(i)&&i.length>=h.maximumSelectionSize&&u(h.formatSelectionTooBig,"formatSelectionTooBig"))){c("<li class='select2-selection-limit'>"+h.formatSelectionTooBig(h.maximumSelectionSize)+"</li>");return}d.val().length<h.minimumInputLength&&u(h.formatInputTooShort,
|
||||
"formatInputTooShort")?c("<li class='select2-no-results'>"+h.formatInputTooShort(d.val(),h.minimumInputLength)+"</li>"):(c("<li class='select2-searching'>"+h.formatSearching()+"</li>"),i=this.tokenize(),i!=g&&null!=i&&d.val(i),this.resultsPage=1,h.query({term:d.val(),page:this.resultsPage,context:null,matcher:h.matcher,callback:this.bind(function(i){var l;this.opened()&&((this.context=i.context===g?null:i.context,this.opts.createSearchChoice&&""!==d.val()&&(l=this.opts.createSearchChoice.call(null,
|
||||
d.val(),i.results),l!==g&&null!==l&&k.id(l)!==g&&null!==k.id(l)&&0===e(i.results).filter(function(){return m(k.id(this),k.id(l))}).length&&i.results.unshift(l)),0===i.results.length&&u(h.formatNoMatches,"formatNoMatches"))?c("<li class='select2-no-results'>"+h.formatNoMatches(d.val())+"</li>"):(f.empty(),k.opts.populateResults.call(this,f,i.results,{term:d.val(),page:this.resultsPage,context:null}),!0===i.more&&u(h.formatLoadMore,"formatLoadMore")&&(f.append("<li class='select2-more-results'>"+k.opts.escapeMarkup(h.formatLoadMore(this.resultsPage))+
|
||||
"</li>"),window.setTimeout(function(){k.loadMoreIfNeeded()},10)),this.postprocessResults(i,a),b()))})}))}},cancel:function(){this.close()},blur:function(){this.close();this.container.removeClass("select2-container-active");this.dropdown.removeClass("select2-drop-active");this.search[0]===document.activeElement&&this.search.blur();this.clearSearch();this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus")},focusSearch:function(){this.search.show();this.search.focus();
|
||||
window.setTimeout(this.bind(function(){this.search.show();this.search.focus();this.search.val(this.search.val())}),10)},selectHighlighted:function(){var a=this.highlight(),b=this.results.find(".select2-highlighted").not(".select2-disabled"),c=b.closest(".select2-result-selectable").data("select2-data");c&&(b.addClass("select2-disabled"),this.highlight(a),this.onSelect(c))},getPlaceholder:function(){return this.opts.element.attr("placeholder")||this.opts.element.attr("data-placeholder")||this.opts.element.data("placeholder")||
|
||||
this.opts.placeholder},initContainerWidth:function(){var a=function(){var a,c,d,f;if("off"===this.opts.width)return null;if("element"===this.opts.width)return 0===this.opts.element.outerWidth()?"auto":this.opts.element.outerWidth()+"px";if("copy"===this.opts.width||"resolve"===this.opts.width){a=this.opts.element.attr("style");if(a!==g){a=a.split(";");d=0;for(f=a.length;d<f;d+=1)if(c=a[d].replace(/\s/g,"").match(/width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/),null!==c&&1<=c.length)return c[1]}return"resolve"===
|
||||
this.opts.width?(a=this.opts.element.css("width"),0<a.indexOf("%")?a:0===this.opts.element.outerWidth()?"auto":this.opts.element.outerWidth()+"px"):null}return e.isFunction(this.opts.width)?this.opts.width():this.opts.width}.call(this);null!==a&&this.container.attr("style","width: "+a)}});y=x(w,{createContainer:function(){return e("<div></div>",{"class":"select2-container"}).html(" <a href='#' onclick='return false;' class='select2-choice'> <span></span><abbr class='select2-search-choice-close' style='display:none;'></abbr> <div><b></b></div></a> <div class='select2-drop select2-offscreen'> <div class='select2-search'> <input type='text' autocomplete='off' class='select2-input'/> </div> <ul class='select2-results'> </ul></div>")},
|
||||
opening:function(){this.search.show();this.parent.opening.apply(this,arguments);this.dropdown.removeClass("select2-offscreen")},close:function(){this.opened()&&(this.parent.close.apply(this,arguments),this.dropdown.removeAttr("style").addClass("select2-offscreen").insertAfter(this.selection).show())},focus:function(){this.close();this.selection.focus()},isFocused:function(){return this.selection[0]===document.activeElement},cancel:function(){this.parent.cancel.apply(this,arguments);this.selection.focus()},
|
||||
initContainer:function(){var a,b=this.dropdown;this.selection=a=this.container.find(".select2-choice");this.search.bind("keydown",this.bind(function(a){if(this.enabled)if(a.which===f.PAGE_UP||a.which===f.PAGE_DOWN)l(a);else if(this.opened())switch(a.which){case f.UP:case f.DOWN:this.moveHighlight(a.which===f.UP?-1:1);l(a);break;case f.TAB:case f.ENTER:this.selectHighlighted();l(a);break;case f.ESC:this.cancel(a),l(a)}else a.which===f.TAB||f.isControl(a)||f.isFunctionKey(a)||a.which===f.ESC||!1===
|
||||
this.opts.openOnEnter&&a.which===f.ENTER||this.open()}));this.search.bind("focus",this.bind(function(){this.selection.attr("tabIndex","-1")}));this.search.bind("blur",this.bind(function(){this.opened()||this.container.removeClass("select2-container-active");window.setTimeout(this.bind(function(){this.selection.attr("tabIndex",this.opts.element.attr("tabIndex"))}),10)}));a.bind("mousedown",this.bind(function(){this.opened()?(this.close(),this.selection.focus()):this.enabled&&this.open()}));b.bind("mousedown",
|
||||
this.bind(function(){this.search.focus()}));a.bind("focus",this.bind(function(){this.container.addClass("select2-container-active");this.search.attr("tabIndex","-1")}));a.bind("blur",this.bind(function(){this.opened()||this.container.removeClass("select2-container-active");window.setTimeout(this.bind(function(){this.search.attr("tabIndex",this.opts.element.attr("tabIndex"))}),10)}));a.bind("keydown",this.bind(function(a){if(this.enabled)if(a.which===f.PAGE_UP||a.which===f.PAGE_DOWN)l(a);else if(!(a.which===
|
||||
f.TAB||f.isControl(a)||f.isFunctionKey(a)||a.which===f.ESC)&&!(!1===this.opts.openOnEnter&&a.which===f.ENTER))if(a.which==f.DELETE)this.opts.allowClear&&this.clear();else{this.open();if(a.which!==f.ENTER&&!(48>a.which)){var b=String.fromCharCode(a.which).toLowerCase();a.shiftKey&&(b=b.toUpperCase());this.search.focus();this.search.val(b)}l(a)}}));a.delegate("abbr","mousedown",this.bind(function(a){this.enabled&&(this.clear(),l(a),this.close(),this.triggerChange(),this.selection.focus())}));this.setPlaceholder();
|
||||
this.search.bind("focus",this.bind(function(){this.container.addClass("select2-container-active")}))},clear:function(){this.opts.element.val("");this.selection.find("span").empty();this.selection.removeData("select2-data");this.setPlaceholder()},initSelection:function(){if(""===this.opts.element.val())this.close(),this.setPlaceholder();else{var a=this;this.opts.initSelection.call(null,this.opts.element,function(b){b!==g&&null!==b&&(a.updateSelection(b),a.close(),a.setPlaceholder())})}},prepareOpts:function(){var a=
|
||||
this.parent.prepareOpts.apply(this,arguments);"select"===a.element.get(0).tagName.toLowerCase()&&(a.initSelection=function(a,c){var d=a.find(":selected");e.isFunction(c)&&c({id:d.attr("value"),text:d.text()})});return a},setPlaceholder:function(){var a=this.getPlaceholder();""===this.opts.element.val()&&a!==g&&!(this.select&&""!==this.select.find("option:first").text())&&(this.selection.find("span").html(this.opts.escapeMarkup(a)),this.selection.addClass("select2-default"),this.selection.find("abbr").hide())},
|
||||
postprocessResults:function(a,b){var c=0,d=this,f=!0;this.results.find(".select2-result-selectable").each2(function(a,b){if(m(d.id(b.data("select2-data")),d.opts.element.val()))return c=a,!1});this.highlight(c);!0===b&&(f=this.showSearchInput=F(a.results)>=this.opts.minimumResultsForSearch,this.dropdown.find(".select2-search")[f?"removeClass":"addClass"]("select2-search-hidden"),e(this.dropdown,this.container)[f?"addClass":"removeClass"]("select2-with-searchbox"))},onSelect:function(a){var b=this.opts.element.val();
|
||||
this.opts.element.val(this.id(a));this.updateSelection(a);this.close();this.selection.focus();m(b,this.id(a))||this.triggerChange()},updateSelection:function(a){var b=this.selection.find("span");this.selection.data("select2-data",a);b.empty();a=this.opts.formatSelection(a,b);a!==g&&b.append(this.opts.escapeMarkup(a));this.selection.removeClass("select2-default");this.opts.allowClear&&this.getPlaceholder()!==g&&this.selection.find("abbr").show()},val:function(){var a,b=null,c=this;if(0===arguments.length)return this.opts.element.val();
|
||||
a=arguments[0];if(this.select)this.select.val(a).find(":selected").each2(function(a,c){b={id:c.attr("value"),text:c.text()};return!1}),this.updateSelection(b),this.setPlaceholder();else{if(this.opts.initSelection===g)throw Error("cannot call val() if initSelection() is not defined");a?(this.opts.element.val(a),this.opts.initSelection(this.opts.element,function(a){c.opts.element.val(!a?"":c.id(a));c.updateSelection(a);c.setPlaceholder()})):this.clear()}},clearSearch:function(){this.search.val("")},
|
||||
data:function(a){var b;if(0===arguments.length)return b=this.selection.data("select2-data"),b==g&&(b=null),b;!a||""===a?this.clear():(this.opts.element.val(!a?"":this.id(a)),this.updateSelection(a))}});z=x(w,{createContainer:function(){return e("<div></div>",{"class":"select2-container select2-container-multi"}).html(" <ul class='select2-choices'> <li class='select2-search-field'> <input type='text' autocomplete='off' class='select2-input'> </li></ul><div class='select2-drop select2-drop-multi' style='display:none;'> <ul class='select2-results'> </ul></div>")},
|
||||
prepareOpts:function(){var a=this.parent.prepareOpts.apply(this,arguments);"select"===a.element.get(0).tagName.toLowerCase()&&(a.initSelection=function(a,c){var d=[];a.find(":selected").each2(function(a,b){d.push({id:b.attr("value"),text:b.text()})});e.isFunction(c)&&c(d)});return a},initContainer:function(){var a;this.searchContainer=this.container.find(".select2-search-field");this.selection=a=this.container.find(".select2-choices");this.search.bind("keydown",this.bind(function(b){if(this.enabled){if(b.which===
|
||||
f.BACKSPACE&&""===this.search.val()){this.close();var c;c=a.find(".select2-search-choice-focus");if(0<c.length){this.unselect(c.first());this.search.width(10);l(b);return}c=a.find(".select2-search-choice");0<c.length&&c.last().addClass("select2-search-choice-focus")}else a.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");if(this.opened())switch(b.which){case f.UP:case f.DOWN:this.moveHighlight(b.which===f.UP?-1:1);l(b);return;case f.ENTER:case f.TAB:this.selectHighlighted();
|
||||
l(b);return;case f.ESC:this.cancel(b);l(b);return}if(!(b.which===f.TAB||f.isControl(b)||f.isFunctionKey(b)||b.which===f.BACKSPACE||b.which===f.ESC)&&!(!1===this.opts.openOnEnter&&b.which===f.ENTER))this.open(),(b.which===f.PAGE_UP||b.which===f.PAGE_DOWN)&&l(b)}}));this.search.bind("keyup",this.bind(this.resizeSearch));this.search.bind("blur",this.bind(function(a){this.container.removeClass("select2-container-active");this.search.removeClass("select2-focused");this.clearSearch();a.stopImmediatePropagation()}));
|
||||
this.container.delegate(".select2-choices","mousedown",this.bind(function(a){this.enabled&&!(0<e(a.target).closest(".select2-search-choice").length)&&(this.clearPlaceholder(),this.open(),this.focusSearch(),a.preventDefault())}));this.container.delegate(".select2-choices","focus",this.bind(function(){this.enabled&&(this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"),this.clearPlaceholder())}));this.clearSearch()},enable:function(){this.enabled||(this.parent.enable.apply(this,
|
||||
arguments),this.search.removeAttr("disabled"))},disable:function(){this.enabled&&(this.parent.disable.apply(this,arguments),this.search.attr("disabled",!0))},initSelection:function(){""===this.opts.element.val()&&(this.updateSelection([]),this.close(),this.clearSearch());if(this.select||""!==this.opts.element.val()){var a=this;this.opts.initSelection.call(null,this.opts.element,function(b){if(b!==g&&b!==null){a.updateSelection(b);a.close();a.clearSearch()}})}},clearSearch:function(){var a=this.getPlaceholder();
|
||||
a!==g&&0===this.getVal().length&&!1===this.search.hasClass("select2-focused")?(this.search.val(a).addClass("select2-default"),this.resizeSearch()):this.search.val(" ").width(10)},clearPlaceholder:function(){this.search.hasClass("select2-default")?this.search.val("").removeClass("select2-default"):" "===this.search.val()&&this.search.val("")},opening:function(){this.parent.opening.apply(this,arguments);this.clearPlaceholder();this.resizeSearch();this.focusSearch()},close:function(){this.opened()&&
|
||||
this.parent.close.apply(this,arguments)},focus:function(){this.close();this.search.focus()},isFocused:function(){return this.search.hasClass("select2-focused")},updateSelection:function(a){var b=[],c=[],d=this;e(a).each(function(){0>i(d.id(this),b)&&(b.push(d.id(this)),c.push(this))});a=c;this.selection.find(".select2-search-choice").remove();e(a).each(function(){d.addSelectedChoice(this)});d.postprocessResults()},tokenize:function(){var a=this.search.val(),a=this.opts.tokenizer(a,this.data(),this.bind(this.onSelect),
|
||||
this.opts);null!=a&&a!=g&&(this.search.val(a),0<a.length&&this.open())},onSelect:function(a){this.addSelectedChoice(a);this.select&&this.postprocessResults();this.opts.closeOnSelect?(this.close(),this.search.width(10)):0<this.countSelectableResults()?(this.search.width(10),this.resizeSearch(),this.positionDropdown()):this.close();this.triggerChange({added:a});this.focusSearch()},cancel:function(){this.close();this.focusSearch()},addSelectedChoice:function(a){var b=e("<li class='select2-search-choice'> <div></div> <a href='#' onclick='return false;' class='select2-search-choice-close' tabindex='-1'></a></li>"),
|
||||
c=this.id(a),d=this.getVal(),f;f=this.opts.formatSelection(a,b);b.find("div").replaceWith("<div>"+this.opts.escapeMarkup(f)+"</div>");b.find(".select2-search-choice-close").bind("mousedown",l).bind("click dblclick",this.bind(function(a){this.enabled&&(e(a.target).closest(".select2-search-choice").fadeOut("fast",this.bind(function(){this.unselect(e(a.target));this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");this.close();this.focusSearch()})).dequeue(),
|
||||
l(a))})).bind("focus",this.bind(function(){this.enabled&&(this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"))}));b.data("select2-data",a);b.insertBefore(this.searchContainer);d.push(c);this.setVal(d)},unselect:function(a){var b=this.getVal(),c,d,a=a.closest(".select2-search-choice");if(0===a.length)throw"Invalid argument: "+a+". Must be .select2-search-choice";c=a.data("select2-data");d=i(this.id(c),b);0<=d&&(b.splice(d,1),this.setVal(b),this.select&&
|
||||
this.postprocessResults());a.remove();this.triggerChange({removed:c})},postprocessResults:function(){var a=this.getVal(),b=this.results.find(".select2-result-selectable"),c=this.results.find(".select2-result-with-children"),d=this;b.each2(function(b,c){var e=d.id(c.data("select2-data"));0<=i(e,a)?c.addClass("select2-disabled").removeClass("select2-result-selectable"):c.removeClass("select2-disabled").addClass("select2-result-selectable")});c.each2(function(a,b){0==b.find(".select2-result-selectable").length?
|
||||
b.addClass("select2-disabled"):b.removeClass("select2-disabled")});b.each2(function(a,b){if(!b.hasClass("select2-disabled")&&b.hasClass("select2-result-selectable"))return d.highlight(0),!1})},resizeSearch:function(){var a,b,c,d,f=this.search.outerWidth()-this.search.width();a=this.search;q||(c=a[0].currentStyle||window.getComputedStyle(a[0],null),q=e("<div></div>").css({position:"absolute",left:"-10000px",top:"-10000px",display:"none",fontSize:c.fontSize,fontFamily:c.fontFamily,fontStyle:c.fontStyle,
|
||||
fontWeight:c.fontWeight,letterSpacing:c.letterSpacing,textTransform:c.textTransform,whiteSpace:"nowrap"}),e("body").append(q));q.text(a.val());a=q.width()+10;b=this.search.offset().left;c=this.selection.width();d=this.selection.offset().left;b=c-(b-d)-f;b<a&&(b=c-f);40>b&&(b=c-f);this.search.width(b)},getVal:function(){var a;if(this.select)return a=this.select.val(),null===a?[]:a;a=this.opts.element.val();return s(a,this.opts.separator)},setVal:function(a){var b;this.select?this.select.val(a):(b=
|
||||
[],e(a).each(function(){0>i(this,b)&&b.push(this)}),this.opts.element.val(0===b.length?"":b.join(this.opts.separator)))},val:function(){var a,b=[],c=this;if(0===arguments.length)return this.getVal();if(a=arguments[0])if(this.setVal(a),this.select)this.select.find(":selected").each(function(){b.push({id:e(this).attr("value"),text:e(this).text()})}),this.updateSelection(b);else{if(this.opts.initSelection===g)throw Error("val() cannot be called if initSelection() is not defined");this.opts.initSelection(this.opts.element,
|
||||
function(a){var b=e(a).map(c.id);c.setVal(b);c.updateSelection(a);c.clearSearch()})}else this.opts.element.val(""),this.updateSelection([]);this.clearSearch()},onSortStart:function(){if(this.select)throw Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead.");this.search.width(0);this.searchContainer.hide()},onSortEnd:function(){var a=[],b=this;this.searchContainer.show();this.searchContainer.appendTo(this.searchContainer.parent());this.resizeSearch();
|
||||
this.selection.find(".select2-search-choice").each(function(){a.push(b.opts.id(e(this).data("select2-data")))});this.setVal(a);this.triggerChange()},data:function(a){var b=this,c;if(0===arguments.length)return this.selection.find(".select2-search-choice").map(function(){return e(this).data("select2-data")}).get();a||(a=[]);c=e.map(a,function(a){return b.opts.id(a)});this.setVal(c);this.updateSelection(a);this.clearSearch()}});e.fn.select2=function(){var a=Array.prototype.slice.call(arguments,0),b,
|
||||
c,d,f,h="val destroy opened open close focus isFocused container onSortStart onSortEnd enable disable positionDropdown data".split(" ");this.each(function(){if(0===a.length||"object"===typeof a[0])b=0===a.length?{}:e.extend({},a[0]),b.element=e(this),"select"===b.element.get(0).tagName.toLowerCase()?f=b.element.attr("multiple"):(f=b.multiple||!1,"tags"in b&&(b.multiple=f=!0)),c=f?new z:new y,c.init(b);else if("string"===typeof a[0]){if(0>i(a[0],h))throw"Unknown method: "+a[0];d=g;c=e(this).data("select2");
|
||||
if(c!==g&&(d="container"===a[0]?c.container:c[a[0]].apply(c,a.slice(1)),d!==g))return!1}else throw"Invalid arguments to select2 plugin: "+a;});return d===g?this:d};e.fn.select2.defaults={width:"copy",closeOnSelect:!0,openOnEnter:!0,containerCss:{},dropdownCss:{},containerCssClass:"",dropdownCssClass:"",formatResult:function(a,b,c){b=[];B(a.text,c.term,b);return b.join("")},formatSelection:function(a){return a?a.text:g},formatResultCssClass:function(){return g},formatNoMatches:function(){return"No matches found"},
|
||||
formatInputTooShort:function(a,b){return"Please enter "+(b-a.length)+" more characters"},formatSelectionTooBig:function(a){return"You can only select "+a+" item"+(1==a?"":"s")},formatLoadMore:function(){return"Loading more results..."},formatSearching:function(){return"Searching..."},minimumResultsForSearch:0,minimumInputLength:0,maximumSelectionSize:0,id:function(a){return a.id},matcher:function(a,b){return 0<=b.toUpperCase().indexOf(a.toUpperCase())},separator:",",tokenSeparators:[],tokenizer:H,
|
||||
escapeMarkup:function(a){return a&&"string"===typeof a?a.replace(/&/g,"&"):a},blurOnChange:!1};window.Select2={query:{ajax:C,local:D,tags:E},util:{debounce:A,markMatch:B},"class":{"abstract":w,single:y,multi:z}}}})(jQuery);
|
BIN
src/inputs/select2/lib/select2.png
Normal file
BIN
src/inputs/select2/lib/select2.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 613 B |
BIN
src/inputs/select2/lib/select2x2.png
Normal file
BIN
src/inputs/select2/lib/select2x2.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 845 B |
BIN
src/inputs/select2/lib/spinner.gif
Normal file
BIN
src/inputs/select2/lib/spinner.gif
Normal file
Binary file not shown.
After ![]() (image error) Size: 1.8 KiB |
193
src/inputs/select2/select2.js
vendored
Normal file
193
src/inputs/select2/select2.js
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
/**
|
||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
|
||||
Please see [original docs](http://ivaynberg.github.com/select2) for detailed description and options.
|
||||
You should manually include select2 distributive:
|
||||
|
||||
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link>
|
||||
<script src="select2/select2.js"></script>
|
||||
|
||||
@class select2
|
||||
@extends abstractinput
|
||||
@since 1.4.1
|
||||
@final
|
||||
@example
|
||||
<a href="#" id="country" data-type="select2" data-pk="1" data-value="ru" data-url="/post" data-original-title="Select country"></a>
|
||||
<script>
|
||||
$(function(){
|
||||
$('#country').editable({
|
||||
source: [
|
||||
{id: 'gb', text: 'Great Britain'},
|
||||
{id: 'us', text: 'United States'},
|
||||
{id: 'ru', text: 'Russia'}
|
||||
],
|
||||
select2: {
|
||||
multiple: true
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
**/
|
||||
(function ($) {
|
||||
|
||||
var Constructor = function (options) {
|
||||
this.init('select2', options, Constructor.defaults);
|
||||
|
||||
options.select2 = options.select2 || {};
|
||||
|
||||
var that = this,
|
||||
mixin = {
|
||||
placeholder: options.placeholder
|
||||
};
|
||||
|
||||
//detect whether it is multi-valued
|
||||
this.isMultiple = options.select2.tags || options.select2.multiple;
|
||||
|
||||
//if not `tags` mode, we need define init set data from source
|
||||
if(!options.select2.tags) {
|
||||
if(options.source) {
|
||||
mixin.data = options.source;
|
||||
}
|
||||
|
||||
//this function can be defaulted in seletc2. See https://github.com/ivaynberg/select2/issues/710
|
||||
mixin.initSelection = function (element, callback) {
|
||||
var val = that.str2value(element.val()),
|
||||
data = $.fn.editableutils.itemsByValue(val, mixin.data, 'id');
|
||||
|
||||
//for single-valued mode should not use array. Take first element instead.
|
||||
if($.isArray(data) && data.length && !that.isMultiple) {
|
||||
data = data[0];
|
||||
}
|
||||
|
||||
callback(data);
|
||||
};
|
||||
}
|
||||
|
||||
//overriding objects in config (as by default jQuery extend() is not recursive)
|
||||
this.options.select2 = $.extend({}, Constructor.defaults.select2, mixin, options.select2);
|
||||
};
|
||||
|
||||
$.fn.editableutils.inherit(Constructor, $.fn.editabletypes.abstractinput);
|
||||
|
||||
$.extend(Constructor.prototype, {
|
||||
render: function() {
|
||||
this.setClass();
|
||||
//apply select2
|
||||
this.$input.select2(this.options.select2);
|
||||
|
||||
//trigger resize of editableform to re-position container in multi-valued mode
|
||||
if(this.isMultiple) {
|
||||
this.$input.on('change', function() {
|
||||
$(this).closest('form').parent().triggerHandler('resize');
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
value2html: function(value, element) {
|
||||
var text = '', data;
|
||||
if(this.$input) { //when submitting form
|
||||
data = this.$input.select2('data');
|
||||
} else { //on init (autotext)
|
||||
//here select2 instance not created yet and data may be even not loaded.
|
||||
//we can check data/tags property of select config and if exist lookup text
|
||||
if(this.options.select2.tags) {
|
||||
data = value;
|
||||
} else if(this.options.select2.data) {
|
||||
data = $.fn.editableutils.itemsByValue(value, this.options.select2.data, 'id');
|
||||
}
|
||||
}
|
||||
|
||||
if($.isArray(data)) {
|
||||
//collect selected data and show with separator
|
||||
text = [];
|
||||
$.each(data, function(k, v){
|
||||
text.push(v && typeof v === 'object' ? v.text : v);
|
||||
});
|
||||
} else if(data) {
|
||||
text = data.text;
|
||||
}
|
||||
|
||||
text = $.isArray(text) ? text.join(this.options.viewseparator) : text;
|
||||
|
||||
$(element).text(text);
|
||||
},
|
||||
|
||||
html2value: function(html) {
|
||||
return this.options.select2.tags ? this.str2value(html, this.options.viewseparator) : null;
|
||||
},
|
||||
|
||||
value2input: function(value) {
|
||||
this.$input.val(value).trigger('change');
|
||||
},
|
||||
|
||||
input2value: function() {
|
||||
return this.$input.select2('val');
|
||||
},
|
||||
|
||||
str2value: function(str, separator) {
|
||||
if(typeof str !== 'string' || !this.isMultiple) {
|
||||
return str;
|
||||
}
|
||||
|
||||
separator = separator || this.options.select2.separator || $.fn.select2.defaults.separator;
|
||||
|
||||
var val, i, l;
|
||||
|
||||
if (str === null || str.length < 1) {
|
||||
return null;
|
||||
}
|
||||
val = str.split(separator);
|
||||
for (i = 0, l = val.length; i < l; i = i + 1) {
|
||||
val[i] = $.trim(val[i]);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Constructor.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
||||
/**
|
||||
@property tpl
|
||||
@default <input type="hidden">
|
||||
**/
|
||||
tpl:'<input type="hidden">',
|
||||
/**
|
||||
Configuration of select2. [Full list of options](http://ivaynberg.github.com/select2).
|
||||
|
||||
@property select2
|
||||
@type object
|
||||
@default null
|
||||
**/
|
||||
select2: null,
|
||||
/**
|
||||
Placeholder attribute of select
|
||||
|
||||
@property placeholder
|
||||
@type string
|
||||
@default null
|
||||
**/
|
||||
placeholder: null,
|
||||
/**
|
||||
Source data for select. It will be assigned to select2 `data` property and kept here just for convenience.
|
||||
Please note, that format is different from simple `select` input: use 'id' instead of 'value'.
|
||||
E.g. `[{id: 1, text: "text1"}, {id: 2, text: "text2"}, ...]`.
|
||||
|
||||
@property source
|
||||
@type array
|
||||
@default null
|
||||
**/
|
||||
source: null,
|
||||
/**
|
||||
Separator used to display tags.
|
||||
|
||||
@property viewseparator
|
||||
@type string
|
||||
@default ', '
|
||||
**/
|
||||
viewseparator: ', '
|
||||
});
|
||||
|
||||
$.fn.editabletypes.select2 = Constructor;
|
||||
|
||||
}(window.jQuery));
|
@ -48,10 +48,7 @@ $(function(){
|
||||
.keyup($.proxy(this.toggleClear, this))
|
||||
.parent().css('position', 'relative');
|
||||
|
||||
this.$clear.click($.proxy(function(){
|
||||
this.$clear.hide();
|
||||
this.$input.val('').focus();
|
||||
}, this));
|
||||
this.$clear.click($.proxy(this.clear, this));
|
||||
}
|
||||
},
|
||||
|
||||
@ -76,12 +73,17 @@ $(function(){
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.$input.val()) {
|
||||
if(this.$input.val().length) {
|
||||
this.$clear.show();
|
||||
} else {
|
||||
this.$clear.hide();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
this.$clear.hide();
|
||||
this.$input.val('').focus();
|
||||
}
|
||||
});
|
||||
|
||||
Text.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
||||
|
221
src/inputs/typeahead.js
Normal file
221
src/inputs/typeahead.js
Normal file
@ -0,0 +1,221 @@
|
||||
/**
|
||||
Typeahead input (bootstrap only). Based on Twitter Bootstrap [typeahead](http://twitter.github.com/bootstrap/javascript.html#typeahead).
|
||||
Depending on `source` format typeahead operates in two modes:
|
||||
|
||||
* **strings**:
|
||||
When `source` defined as array of strings, e.g. `['text1', 'text2', 'text3' ...]`.
|
||||
User can submit one of these strings or any text entered in input (even if it is not matching source).
|
||||
|
||||
* **objects**:
|
||||
When `source` defined as array of objects, e.g. `[{value: 1, text: "text1"}, {value: 2, text: "text2"}, ...]`.
|
||||
User can submit only values that are in source (otherwise `null` is submitted). This is more like *dropdown* behavior.
|
||||
|
||||
@class typeahead
|
||||
@extends list
|
||||
@since 1.4.1
|
||||
@final
|
||||
@example
|
||||
<a href="#" id="country" data-type="typeahead" data-pk="1" data-url="/post" data-original-title="Input country"></a>
|
||||
<script>
|
||||
$(function(){
|
||||
$('#country').editable({
|
||||
value: 'ru',
|
||||
source: [
|
||||
{value: 'gb', text: 'Great Britain'},
|
||||
{value: 'us', text: 'United States'},
|
||||
{value: 'ru', text: 'Russia'}
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
**/
|
||||
(function ($) {
|
||||
|
||||
var Constructor = function (options) {
|
||||
this.init('typeahead', options, Constructor.defaults);
|
||||
|
||||
//overriding objects in config (as by default jQuery extend() is not recursive)
|
||||
this.options.typeahead = $.extend({}, Constructor.defaults.typeahead, {
|
||||
//set default methods for typeahead to work with objects
|
||||
matcher: this.matcher,
|
||||
sorter: this.sorter,
|
||||
highlighter: this.highlighter,
|
||||
updater: this.updater
|
||||
}, options.typeahead);
|
||||
};
|
||||
|
||||
$.fn.editableutils.inherit(Constructor, $.fn.editabletypes.list);
|
||||
|
||||
$.extend(Constructor.prototype, {
|
||||
renderList: function() {
|
||||
this.$input = this.$tpl.is('input') ? this.$tpl : this.$tpl.find('input[type="text"]');
|
||||
|
||||
//set source of typeahead
|
||||
this.options.typeahead.source = this.sourceData;
|
||||
|
||||
//apply typeahead
|
||||
this.$input.typeahead(this.options.typeahead);
|
||||
|
||||
//attach own render method
|
||||
this.$input.data('typeahead').render = $.proxy(this.typeaheadRender, this.$input.data('typeahead'));
|
||||
|
||||
this.renderClear();
|
||||
this.setClass();
|
||||
this.setAttr('placeholder');
|
||||
},
|
||||
|
||||
value2htmlFinal: function(value, element) {
|
||||
if(this.getIsObjects()) {
|
||||
var items = $.fn.editableutils.itemsByValue(value, this.sourceData);
|
||||
$(element).text(items.length ? items[0].text : '');
|
||||
} else {
|
||||
$(element).text(value);
|
||||
}
|
||||
},
|
||||
|
||||
html2value: function (html) {
|
||||
return html ? html : null;
|
||||
},
|
||||
|
||||
value2input: function(value) {
|
||||
if(this.getIsObjects()) {
|
||||
var items = $.fn.editableutils.itemsByValue(value, this.sourceData);
|
||||
this.$input.data('value', value).val(items.length ? items[0].text : '');
|
||||
} else {
|
||||
this.$input.val(value);
|
||||
}
|
||||
},
|
||||
|
||||
input2value: function() {
|
||||
if(this.getIsObjects()) {
|
||||
var value = this.$input.data('value'),
|
||||
items = $.fn.editableutils.itemsByValue(value, this.sourceData);
|
||||
|
||||
if(items.length && items[0].text.toLowerCase() === this.$input.val().toLowerCase()) {
|
||||
return value;
|
||||
} else {
|
||||
return null; //entered string not found in source
|
||||
}
|
||||
} else {
|
||||
return this.$input.val();
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
if in sourceData values <> texts, typeahead in "objects" mode:
|
||||
user must pick some value from list, otherwise `null` returned.
|
||||
if all values == texts put typeahead in "strings" mode:
|
||||
anything what entered is submited.
|
||||
*/
|
||||
getIsObjects: function() {
|
||||
if(this.isObjects === undefined) {
|
||||
this.isObjects = false;
|
||||
for(var i=0; i<this.sourceData.length; i++) {
|
||||
if(this.sourceData[i].value !== this.sourceData[i].text) {
|
||||
this.isObjects = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.isObjects;
|
||||
},
|
||||
|
||||
/*
|
||||
Methods borrowed from text input
|
||||
*/
|
||||
activate: $.fn.editabletypes.text.prototype.activate,
|
||||
renderClear: $.fn.editabletypes.text.prototype.renderClear,
|
||||
postrender: $.fn.editabletypes.text.prototype.postrender,
|
||||
toggleClear: $.fn.editabletypes.text.prototype.toggleClear,
|
||||
clear: function() {
|
||||
$.fn.editabletypes.text.prototype.clear.call(this);
|
||||
this.$input.data('value', '');
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
Typeahead option methods used as defaults
|
||||
*/
|
||||
/*jshint eqeqeq:false, curly: false, laxcomma: true*/
|
||||
matcher: function (item) {
|
||||
return $.fn.typeahead.Constructor.prototype.matcher.call(this, item.text);
|
||||
},
|
||||
sorter: function (items) {
|
||||
var beginswith = []
|
||||
, caseSensitive = []
|
||||
, caseInsensitive = []
|
||||
, item
|
||||
, text;
|
||||
|
||||
while (item = items.shift()) {
|
||||
text = item.text;
|
||||
if (!text.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item);
|
||||
else if (~text.indexOf(this.query)) caseSensitive.push(item);
|
||||
else caseInsensitive.push(item);
|
||||
}
|
||||
|
||||
return beginswith.concat(caseSensitive, caseInsensitive);
|
||||
},
|
||||
highlighter: function (item) {
|
||||
return $.fn.typeahead.Constructor.prototype.highlighter.call(this, item.text);
|
||||
},
|
||||
updater: function (item) {
|
||||
item = this.$menu.find('.active').data('item');
|
||||
this.$element.data('value', item.value);
|
||||
return item.text;
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
Overwrite typeahead's render method to store objects.
|
||||
There are a lot of disscussion in bootstrap repo on this point and still no result.
|
||||
See https://github.com/twitter/bootstrap/issues/5967
|
||||
|
||||
This function just store item in via jQuery data() method instead of attr('data-value')
|
||||
*/
|
||||
typeaheadRender: function (items) {
|
||||
var that = this;
|
||||
|
||||
items = $(items).map(function (i, item) {
|
||||
// i = $(that.options.item).attr('data-value', item)
|
||||
i = $(that.options.item).data('item', item);
|
||||
i.find('a').html(that.highlighter(item));
|
||||
return i[0];
|
||||
});
|
||||
|
||||
items.first().addClass('active');
|
||||
this.$menu.html(items);
|
||||
return this;
|
||||
}
|
||||
/*jshint eqeqeq: true, curly: true, laxcomma: false*/
|
||||
|
||||
});
|
||||
|
||||
Constructor.defaults = $.extend({}, $.fn.editabletypes.list.defaults, {
|
||||
/**
|
||||
@property tpl
|
||||
@default <input type="text">
|
||||
**/
|
||||
tpl:'<input type="text">',
|
||||
/**
|
||||
Configuration of typeahead. [Full list of options](http://twitter.github.com/bootstrap/javascript.html#typeahead).
|
||||
|
||||
@property typeahead
|
||||
@type object
|
||||
@default null
|
||||
**/
|
||||
typeahead: null,
|
||||
/**
|
||||
Whether to show `clear` button
|
||||
|
||||
@property clear
|
||||
@type boolean
|
||||
@default true
|
||||
**/
|
||||
clear: true
|
||||
});
|
||||
|
||||
$.fn.editabletypes.typeahead = Constructor;
|
||||
|
||||
}(window.jQuery));
|
@ -21,7 +21,7 @@
|
||||
<div>
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture"></div>
|
||||
<div id="async-fixture"></div>
|
||||
<div id="async-fixture" style="padding-left:300px"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -40,7 +40,8 @@ define(function () {
|
||||
'inputs/checklist',
|
||||
'inputs/html5types',
|
||||
'inputs/combodate/combodate',
|
||||
'inputs-ext/address/address'],
|
||||
'inputs-ext/address/address',
|
||||
'inputs/select2/select2'],
|
||||
init: function(require) {
|
||||
loadCss(require.toUrl("./editable-form.css"));
|
||||
}
|
||||
@ -52,7 +53,8 @@ define(function () {
|
||||
'inputs/textarea': ['inputs/abstract'],
|
||||
'inputs/abstract': ['editable-form/editable-form-utils'],
|
||||
'inputs/html5types': ['inputs/text'],
|
||||
'inputs/combodate/combodate': ['inputs/abstract', 'inputs/combodate/lib/combodate', 'inputs/combodate/lib/moment.min'],
|
||||
'inputs/combodate/combodate': ['inputs/abstract', 'inputs/combodate/lib/combodate', 'inputs/combodate/lib/moment.min'],
|
||||
'inputs/typeahead': ['inputs/list'],
|
||||
|
||||
/*
|
||||
bootstrap
|
||||
@ -94,6 +96,17 @@ define(function () {
|
||||
}
|
||||
},
|
||||
|
||||
//select2
|
||||
'inputs/select2/select2': {
|
||||
deps: ['require',
|
||||
'inputs/select2/lib/select2',
|
||||
'inputs/abstract'],
|
||||
init: function(require) {
|
||||
loadCss(require.toUrl("./lib/select2.css"));
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
//datefield
|
||||
'inputs/date/datefield': ['inputs/date/date'],
|
||||
|
||||
@ -155,6 +168,7 @@ define(function () {
|
||||
//bootstrap
|
||||
shim['editable-form/editable-form'].deps.push('inputs/date/datefield');
|
||||
shim['editable-form/editable-form'].deps.push('inputs-ext/wysihtml5/wysihtml5');
|
||||
shim['editable-form/editable-form'].deps.push('inputs/typeahead');
|
||||
shim['element/editable-element'].deps.push('editable-form/editable-form-bootstrap');
|
||||
shim['element/editable-element'].deps.push('containers/editable-popover');
|
||||
} else if(f === 'jqueryui') {
|
||||
|
@ -31,7 +31,11 @@ require(["loader", jqurl], function(loader) {
|
||||
|
||||
switch(params.f) {
|
||||
case 'bootstrap':
|
||||
custom = ['test/unit/datefield', 'test/unit/date', 'test/unit/wysihtml5'];
|
||||
custom = ['test/unit/datefield',
|
||||
'test/unit/date',
|
||||
'test/unit/wysihtml5',
|
||||
'test/unit/typeahead'
|
||||
];
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -45,7 +49,8 @@ require(["loader", jqurl], function(loader) {
|
||||
'test/unit/textarea',
|
||||
'test/unit/select',
|
||||
'test/unit/checklist',
|
||||
'test/unit/combodate'
|
||||
'test/unit/combodate',
|
||||
'test/unit/select2'
|
||||
];
|
||||
tests = tests.concat(custom);
|
||||
tests.push('test/unit/api');
|
||||
|
@ -155,13 +155,13 @@
|
||||
ok(!p.is(':visible'), 'popover1 closed');
|
||||
ok(!p2.is(':visible'), 'popover2 closed');
|
||||
});
|
||||
|
||||
|
||||
test("onblur: submit", function () {
|
||||
var oldValue = 'abc',
|
||||
newValue = 'cde',
|
||||
e = $('<a href="#" data-type="text" data-pk="1" data-url="post.php" id="a">'+oldValue+'</a>').appendTo('#qunit-fixture').editable({
|
||||
e = $('<a href="#" data-type="text" data-pk="1" id="a">'+oldValue+'</a>').appendTo('#qunit-fixture').editable({
|
||||
onblur: 'submit',
|
||||
url: function() {}
|
||||
send: 'never'
|
||||
}),
|
||||
e2 = $('<a href="#" data-type="text" data-pk="1" data-url="post.php" id="b">abcd</a>').appendTo('#qunit-fixture').editable();
|
||||
|
||||
@ -179,7 +179,7 @@
|
||||
$('#qunit-fixture').click();
|
||||
ok(!p.is(':visible'), 'popover1 closed');
|
||||
equal(e.data('editable').value, newValue, 'new value saved');
|
||||
|
||||
|
||||
//click on another editable
|
||||
e.click();
|
||||
p = tip(e);
|
||||
@ -545,5 +545,156 @@
|
||||
ok(p.is(':visible'), 'inline visible visible');
|
||||
ok(p.hasClass('editable-inline'), 'has inline class');
|
||||
});
|
||||
|
||||
test("option 'inputclass'", function () {
|
||||
var e = $('<a href="#" id="a" data-inputclass="span4"> </a>').appendTo('#qunit-fixture').editable();
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
ok(p.find('input[type=text]').hasClass('span4'), 'class set correctly');
|
||||
p.find('.editable-cancel').click();
|
||||
ok(!p.is(':visible'), 'popover was removed');
|
||||
});
|
||||
|
||||
test("emptytext, emptyclass", function () {
|
||||
var emptytext = 'empty!',
|
||||
emptyclass = 'abc',
|
||||
e = $('<a href="#" id="a"> </a>').appendTo('#qunit-fixture').editable({
|
||||
emptytext: emptytext,
|
||||
emptyclass: emptyclass,
|
||||
send: 'never'
|
||||
});
|
||||
|
||||
equal(e.text(), emptytext, 'emptytext shown on init');
|
||||
ok(e.hasClass(emptyclass), 'emptyclass added');
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
equal(p.find('input[type="text"]').val(), '', 'input val is empty string');
|
||||
// p.find('.editable-cancel').click();
|
||||
//set non-empty value
|
||||
p.find('input[type="text"]').val('abc');
|
||||
p.find('form').submit();
|
||||
|
||||
ok(!p.is(':visible'), 'popover was removed');
|
||||
ok(e.text() != emptytext, 'emptytext not shown');
|
||||
ok(!e.hasClass(emptyclass), 'emptyclass removed');
|
||||
|
||||
e.click();
|
||||
p = tip(e);
|
||||
p.find('input[type="text"]').val('');
|
||||
p.find('form').submit();
|
||||
|
||||
ok(!p.is(':visible'), 'popover was removed');
|
||||
equal(e.text(), emptytext, 'emptytext shown');
|
||||
ok(e.hasClass(emptyclass), 'emptyclass added');
|
||||
|
||||
e.editable('disable');
|
||||
equal(e.text(), '', 'emptytext removed');
|
||||
ok(!e.hasClass(emptyclass), 'emptyclass removed');
|
||||
|
||||
e.editable('enable');
|
||||
e.editable('enable');
|
||||
|
||||
equal(e.text(), emptytext, 'emptytext shown');
|
||||
ok(e.hasClass(emptyclass), 'emptyclass added');
|
||||
});
|
||||
|
||||
asyncTest("submit to url defined as function", function () {
|
||||
expect(10);
|
||||
var newText = 'qwe',
|
||||
pass = false;
|
||||
//should be called even without pk!
|
||||
e = $('<a href="#" data-pk1="1" id="a"></a>').appendTo(fx).editable({
|
||||
url: function(params) {
|
||||
ok(this === e[0], 'scope is ok');
|
||||
ok(params.value, newText, 'new text passed in users function');
|
||||
if(!pass) {
|
||||
var d = new $.Deferred;
|
||||
return d.reject('my error');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
|
||||
ok(p.find('input[type=text]').length, 'input exists')
|
||||
p.find('input').val(newText);
|
||||
p.find('form').submit();
|
||||
|
||||
setTimeout(function() {
|
||||
ok(p.is(':visible'), 'popover visible');
|
||||
equal(p.find('.editable-error-block').text(), 'my error', 'error shown correctly');
|
||||
|
||||
pass = true;
|
||||
newText = 'dfgd';
|
||||
p.find('input').val(newText);
|
||||
p.find('form').submit();
|
||||
|
||||
setTimeout(function() {
|
||||
ok(!p.is(':visible'), 'popover closed');
|
||||
equal(e.text(), newText, 'element text ok');
|
||||
ok(!e.hasClass($.fn.editable.defaults.unsavedclass), 'no unsaved class');
|
||||
|
||||
e.remove();
|
||||
start();
|
||||
}, timeout);
|
||||
}, timeout);
|
||||
|
||||
});
|
||||
|
||||
test("`selector` option", function () {
|
||||
var parent = $('<div><a href="#" id="a" data-type="text">123</a></div>').appendTo('#qunit-fixture').editable({
|
||||
selector: 'a',
|
||||
url: 'post.php',
|
||||
source: groups
|
||||
}),
|
||||
b = $('<a href="#" id="b" data-type="select" data-value="1"></a>'),
|
||||
e = $('#a'),
|
||||
selected = 2;
|
||||
|
||||
ok(!e.hasClass('editable'), 'no editable class applied');
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
|
||||
ok(e.hasClass('editable'), 'editable class applied');
|
||||
ok(e.data('editable'), 'data(editable) ok');
|
||||
ok(!e.data('editable').selector, 'selector cleared');
|
||||
equal(e.data('editable').options.url, 'post.php', 'url ok');
|
||||
equal(e.data('editable').options.type, 'text', 'type text ok');
|
||||
|
||||
ok(p.is(':visible'), 'popover visible');
|
||||
ok(p.find('input[type=text]').length, 'input exists');
|
||||
equal(p.find('input[type=text]').val(), '123', 'input contain correct value');
|
||||
|
||||
//dynamically add second element
|
||||
b.appendTo(parent);
|
||||
e = b;
|
||||
|
||||
e.click();
|
||||
ok(!p.is(':visible'), 'first popover closed');
|
||||
|
||||
ok(e.data('editable'), 'data(editable) ok');
|
||||
ok(!e.data('editable').selector, 'selector cleared');
|
||||
equal(e.data('editable').options.url, 'post.php', 'url ok');
|
||||
equal(e.data('editable').options.type, 'select', 'type select ok');
|
||||
|
||||
p = tip(e);
|
||||
ok(p.is(':visible'), 'second popover visible');
|
||||
|
||||
ok(p.find('select').length, 'select exists');
|
||||
equal(p.find('select').find('option').length, size, 'options loaded');
|
||||
equal(p.find('select').val(), e.data('editable').value, 'selected value correct');
|
||||
|
||||
p.find('select').val(selected);
|
||||
p.find('form').submit();
|
||||
|
||||
ok(!p.is(':visible'), 'popover closed');
|
||||
equal(e.data('editable').value, selected, 'new value saved');
|
||||
equal(e.text(), groups[selected], 'new text shown');
|
||||
});
|
||||
|
||||
|
||||
}(jQuery));
|
@ -689,6 +689,43 @@ $(function () {
|
||||
}, timeout);
|
||||
|
||||
}, timeout);
|
||||
});
|
||||
});
|
||||
|
||||
asyncTest("optgroup", function () {
|
||||
var
|
||||
selected = 2,
|
||||
e = $('<a href="#" data-type="select" data-value="'+selected+'" data-url="post.php"></a>').appendTo(fx).editable({
|
||||
pk: 1,
|
||||
source: [
|
||||
{text: 'groups', children: groups},
|
||||
{value: 'v1', text: 't1', children: ['a', 'b', 'c']},
|
||||
{value: 'v2', text: 't2'}
|
||||
]
|
||||
});
|
||||
|
||||
equal(e.text(), groups[selected], 'text shown');
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
ok(p.is(':visible'), 'container visible');
|
||||
ok(p.find('select').length, 'select exists');
|
||||
equal(p.find('select').find('option').length, size + 3 + 1, 'options loaded');
|
||||
equal(p.find('select').val(), e.data('editable').value, 'selected value correct');
|
||||
|
||||
equal(p.find('select').find('optgroup').length, 2, 'optgroup loaded');
|
||||
equal(p.find('select').find('optgroup').eq(0).children().length, size, 'optgroup items ok');
|
||||
|
||||
selected = 'a';
|
||||
p.find('select').val(selected);
|
||||
p.find('form').submit();
|
||||
|
||||
setTimeout(function() {
|
||||
ok(!p.is(':visible'), 'popover closed')
|
||||
equal(e.data('editable').value, selected, 'new value saved')
|
||||
equal(e.text(), 'a', 'new text shown')
|
||||
e.remove();
|
||||
start();
|
||||
}, timeout);
|
||||
});
|
||||
|
||||
});
|
||||
|
146
test/unit/select2.js
Normal file
146
test/unit/select2.js
Normal file
@ -0,0 +1,146 @@
|
||||
$(function () {
|
||||
|
||||
module("select2", {
|
||||
setup: function(){
|
||||
sfx = $('#qunit-fixture'),
|
||||
fx = $('#async-fixture');
|
||||
$.support.transition = false;
|
||||
}
|
||||
});
|
||||
|
||||
asyncTest("data (single)", function () {
|
||||
var s = 2, text = 'text2',
|
||||
e = $('<a href="#" data-type="select2" data-name="select2" data-value="'+s+'"></a>').appendTo(fx).editable({
|
||||
source: [{id: 1, text: 'text1'}, {id: s, text: text}, {id: 3, text: 'text3'}],
|
||||
select2: {}
|
||||
});
|
||||
|
||||
//autotext
|
||||
equal(e.data('editable').value, s, 'initial value ok');
|
||||
equal(e.text(), text, 'intial text ok');
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
|
||||
ok(p.is(':visible'), 'popover visible');
|
||||
var $input = p.find('input[type="hidden"]');
|
||||
ok($input.length, 'input exists');
|
||||
ok($input.select2, 'select2 applied');
|
||||
equal($input.val(), e.data('editable').value, 'selected value correct');
|
||||
equal(p.find('.select2-choice span').text(), text, 'selected text correct');
|
||||
|
||||
//select new value
|
||||
s = 1;
|
||||
text = 'text1';
|
||||
$input.select2('val', s);
|
||||
|
||||
equal($input.val(), s, 'new value ok');
|
||||
equal(p.find('.select2-choice span').text(), text, 'new text ok');
|
||||
|
||||
p.find('form').submit();
|
||||
|
||||
setTimeout(function() {
|
||||
ok(!p.is(':visible'), 'popover closed');
|
||||
equal(e.data('editable').value, s, 'new value ok');
|
||||
equal(e.text(), text, 'new text ok');
|
||||
|
||||
e.remove();
|
||||
start();
|
||||
}, timeout);
|
||||
});
|
||||
|
||||
asyncTest("data (multiple)", function () {
|
||||
var s = '2,3', text = 'text2, text3',
|
||||
e = $('<a href="#" data-type="select2" data-name="select2" data-value="'+s+'"></a>').appendTo(fx).editable({
|
||||
source: [{id: 1, text: 'text1'}, {id: 2, text: 'text2'}, {id: 3, text: 'text3'}],
|
||||
viewseparator: ', ',
|
||||
select2: {
|
||||
multiple: true
|
||||
}
|
||||
});
|
||||
|
||||
//autotext
|
||||
equal(e.data('editable').value.join(','), s, 'initial value ok');
|
||||
equal(e.text(), text, 'intial text ok');
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
|
||||
ok(p.is(':visible'), 'popover visible');
|
||||
var $input = p.find('input[type="hidden"]');
|
||||
ok($input.length, 'input exists');
|
||||
ok($input.select2, 'select2 applied');
|
||||
equal($input.val(), s, 'selected value ok');
|
||||
equal(p.find('.select2-search-choice > div').length, 2, 'selected text ok');
|
||||
equal(p.find('.select2-search-choice > div').eq(0).text(), 'text2', 'text2 ok');
|
||||
equal(p.find('.select2-search-choice > div').eq(1).text(), 'text3', 'text3 ok');
|
||||
|
||||
//select new value
|
||||
s = '1,2';
|
||||
text = 'text1, text2';
|
||||
$input.select2('val', [1, 2]);
|
||||
|
||||
equal($input.val(), s, 'new value ok');
|
||||
equal(p.find('.select2-search-choice > div').length, 2, 'new text ok');
|
||||
equal(p.find('.select2-search-choice > div').eq(0).text(), 'text1', 'text1 ok');
|
||||
equal(p.find('.select2-search-choice > div').eq(1).text(), 'text2', 'text2 ok');
|
||||
|
||||
p.find('form').submit();
|
||||
|
||||
setTimeout(function() {
|
||||
ok(!p.is(':visible'), 'popover closed');
|
||||
equal(e.data('editable').value, s, 'new value ok');
|
||||
equal(e.text(), text, 'new text ok');
|
||||
|
||||
e.remove();
|
||||
start();
|
||||
}, timeout);
|
||||
});
|
||||
|
||||
asyncTest("tags", function () {
|
||||
var s = 'text2,abc', text = 'text2, abc',
|
||||
e = $('<a href="#" data-type="select2" data-name="select2">'+text+'</a>').appendTo(fx).editable({
|
||||
viewseparator: ', ',
|
||||
select2: {
|
||||
tags: ['text1', 'text2']
|
||||
}
|
||||
});
|
||||
|
||||
equal(e.data('editable').value.join(','), s, 'initial value ok');
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
|
||||
ok(p.is(':visible'), 'popover visible');
|
||||
var $input = p.find('input[type="hidden"]');
|
||||
ok($input.length, 'input exists');
|
||||
ok($input.select2, 'select2 applied');
|
||||
equal($input.val(), s, 'selected value ok');
|
||||
equal(p.find('.select2-search-choice > div').length, 2, 'selected text ok');
|
||||
equal(p.find('.select2-search-choice > div').eq(0).text(), 'text2', 'text2 ok');
|
||||
equal(p.find('.select2-search-choice > div').eq(1).text(), 'abc', 'abc ok');
|
||||
|
||||
//select new value
|
||||
s = 'text1,cde';
|
||||
text = 'text1, cde';
|
||||
$input.select2('val', ['text1', 'cde']);
|
||||
|
||||
equal($input.val(), s, 'new value ok');
|
||||
equal(p.find('.select2-search-choice > div').length, 2, 'new text ok');
|
||||
equal(p.find('.select2-search-choice > div').eq(0).text(), 'text1', 'text1 ok');
|
||||
equal(p.find('.select2-search-choice > div').eq(1).text(), 'cde', 'cde ok');
|
||||
|
||||
p.find('form').submit();
|
||||
|
||||
setTimeout(function() {
|
||||
ok(!p.is(':visible'), 'popover closed');
|
||||
equal(e.data('editable').value, s, 'new value ok');
|
||||
equal(e.text(), text, 'new text ok');
|
||||
|
||||
e.remove();
|
||||
start();
|
||||
}, timeout);
|
||||
});
|
||||
|
||||
|
||||
});
|
@ -7,19 +7,6 @@ $(function () {
|
||||
}
|
||||
});
|
||||
|
||||
test("if element originally empty: emptytext should be shown and input should contain ''", function () {
|
||||
var emptytext = 'empty!',
|
||||
e = $('<a href="#" id="a"> </a>').appendTo('#qunit-fixture').editable({emptytext: emptytext});
|
||||
|
||||
equal(e.text(), emptytext, 'emptytext shown on init');
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
equal(p.find('input[type="text"]').val(), '', 'input val is empty string')
|
||||
p.find('.editable-cancel').click();
|
||||
ok(!p.is(':visible'), 'popover was removed')
|
||||
})
|
||||
|
||||
test("option 'placeholder'", function () {
|
||||
var e = $('<a href="#" id="a" data-placeholder="abc"> </a>').appendTo('#qunit-fixture').editable();
|
||||
|
||||
@ -29,16 +16,6 @@ $(function () {
|
||||
p.find('.editable-cancel').click();
|
||||
ok(!p.is(':visible'), 'popover was removed');
|
||||
});
|
||||
|
||||
test("option 'inputclass'", function () {
|
||||
var e = $('<a href="#" id="a" data-inputclass="span4"> </a>').appendTo('#qunit-fixture').editable();
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
ok(p.find('input[type=text]').hasClass('span4'), 'class set correctly');
|
||||
p.find('.editable-cancel').click();
|
||||
ok(!p.is(':visible'), 'popover was removed');
|
||||
});
|
||||
|
||||
asyncTest("should load correct value and save new entered text (and value)", function () {
|
||||
var v = 'ab<b>"',
|
||||
@ -242,35 +219,6 @@ $(function () {
|
||||
}, timeout);
|
||||
|
||||
});
|
||||
|
||||
|
||||
asyncTest("submit to url defined as function", function () {
|
||||
expect(4);
|
||||
var newText = 'qwe',
|
||||
//should be called even without pk!
|
||||
e = $('<a href="#" data-pk1="1" id="a"></a>').appendTo(fx).editable({
|
||||
url: function(params) {
|
||||
ok(this === e[0], 'scope is ok');
|
||||
ok(params.value, newText, 'new text passed in users function');
|
||||
var d = new $.Deferred;
|
||||
return d.reject('my error');
|
||||
}
|
||||
});
|
||||
|
||||
e.click();
|
||||
var p = tip(e);
|
||||
|
||||
ok(p.find('input[type=text]').length, 'input exists')
|
||||
p.find('input').val(newText);
|
||||
p.find('form').submit();
|
||||
|
||||
setTimeout(function() {
|
||||
equal(p.find('.editable-error-block').text(), 'my error', 'error shown correctly');
|
||||
e.remove();
|
||||
start();
|
||||
}, timeout);
|
||||
|
||||
});
|
||||
|
||||
asyncTest("should show emptytext if entered text is empty", function () {
|
||||
var emptytext = 'blabla',
|
||||
@ -364,13 +312,14 @@ $(function () {
|
||||
ok(!p.is(':visible'), 'popover was removed');
|
||||
equal(e.data('editable').value, newText, 'new text saved to value');
|
||||
equal(e.text(), newText, 'new text shown');
|
||||
ok(e.hasClass('editable-unsaved'), 'has class editable-unsaved');
|
||||
ok(e.hasClass($.fn.editable.defaults.unsavedclass), 'has class editable-unsaved');
|
||||
});
|
||||
|
||||
test("send = 'never'. if pk defined --> should save new entered text and value, but no ajax", function () {
|
||||
var e = $('<a href="#" data-name="text1">abc</a>').appendTo('#qunit-fixture').editable({
|
||||
pk: 123,
|
||||
send: 'never'
|
||||
send: 'never',
|
||||
unsavedclass: 'qq'
|
||||
}),
|
||||
newText = 'cde';
|
||||
|
||||
@ -383,7 +332,7 @@ $(function () {
|
||||
ok(!p.is(':visible'), 'popover was removed');
|
||||
equal(e.data('editable').value, newText, 'new text saved to value');
|
||||
equal(e.text(), newText, 'new text shown');
|
||||
ok(e.hasClass('editable-unsaved'), 'has class editable-unsaved');
|
||||
ok(e.hasClass('qq'), 'has class editable-unsaved');
|
||||
});
|
||||
|
||||
test("if name not defined --> should be taken from id", function () {
|
||||
@ -436,6 +385,7 @@ $(function () {
|
||||
ok(!p.is(':visible'), 'popover was removed');
|
||||
ok(!e.text().length, 'element still empty, new value was not displayed');
|
||||
equal(e.data('editable').value, newText, 'new text saved to value');
|
||||
ok(!e.hasClass($.fn.editable.defaults.unsavedclass), 'no unsaved css');
|
||||
e.remove();
|
||||
start();
|
||||
}, timeout);
|
||||
|
122
test/unit/typeahead.js
Normal file
122
test/unit/typeahead.js
Normal file
@ -0,0 +1,122 @@
|
||||
$(function () {
|
||||
|
||||
module("typeahead", {
|
||||
setup: function(){
|
||||
sfx = $('#qunit-fixture'),
|
||||
fx = $('#async-fixture');
|
||||
$.support.transition = false;
|
||||
}
|
||||
});
|
||||
|
||||
asyncTest("should load correct value and save new entered text (source as objects)", function () {
|
||||
var v = 2,
|
||||
e = $('<a href="#" data-pk="1" data-name="text1" data-type="typeahead" data-value="'+v+'" data-url="post.php"></a>').appendTo(fx).editable({
|
||||
source: groups,
|
||||
typeahead: {
|
||||
items: 5
|
||||
}
|
||||
}),
|
||||
newText = 'adm';
|
||||
|
||||
|
||||
equal(e.text(), groups[v], 'autotext ok');
|
||||
equal(e.data().editable.value, v, 'initial value ok');
|
||||
|
||||
e.click();
|
||||
var p = tip(e),
|
||||
$input = p.find('input[type=text]');
|
||||
|
||||
ok(p.is(':visible'), 'popup visible');
|
||||
ok($input.length, 'input exists');
|
||||
equal($input.val(), groups[v], 'input contain correct text');
|
||||
equal($input.data('value'), v, 'input contain correct data-value');
|
||||
ok($input.typeahead, 'typeahead applied to input');
|
||||
|
||||
$input.val(newText).keyup();
|
||||
ok(p.find('.typeahead.dropdown-menu').is(':visible'), 'dropdown visible');
|
||||
|
||||
//select `Admin`
|
||||
v = 5;
|
||||
p.find('.typeahead.dropdown-menu').find('.active').click();
|
||||
|
||||
equal($input.val(), groups[v], 'input contain correct text');
|
||||
p.find('form').submit();
|
||||
|
||||
setTimeout(function() {
|
||||
ok(!p.is(':visible'), 'popup closed');
|
||||
equal(e.data('editable').value, v, 'new text saved to value');
|
||||
equal(e.text(), groups[v], 'new text shown');
|
||||
|
||||
e.click();
|
||||
p = tip(e),
|
||||
$input = p.find('input[type=text]');
|
||||
|
||||
$input.val('not_matched_text').keyup();
|
||||
ok(!p.find('.typeahead.dropdown-menu').is(':visible'), 'dropdown not visible');
|
||||
|
||||
p.find('form').submit();
|
||||
setTimeout(function() {
|
||||
equal(e.data('editable').value, null, 'null saved to value');
|
||||
equal(e.text(), e.data().editable.options.emptytext, 'emptytext shown');
|
||||
|
||||
e.remove();
|
||||
start();
|
||||
}, timeout);
|
||||
}, timeout);
|
||||
});
|
||||
|
||||
|
||||
asyncTest("should load correct value and save new entered text (source as strings)", function () {
|
||||
var v = 'a',
|
||||
e = $('<a href="#" data-pk="1" data-name="text1" data-type="typeahead" data-value="'+v+'" data-url="post.php"></a>').appendTo(fx).editable({
|
||||
source: ['a', 'ab', 'c']
|
||||
});
|
||||
|
||||
|
||||
equal(e.text(), v, 'autotext ok');
|
||||
equal(e.data().editable.value, v, 'initial value ok');
|
||||
|
||||
e.click();
|
||||
var p = tip(e),
|
||||
$input = p.find('input[type=text]');
|
||||
|
||||
ok(p.is(':visible'), 'popup visible');
|
||||
ok($input.length, 'input exists');
|
||||
equal($input.val(), v, 'input contain correct text');
|
||||
equal($input.data('value'), undefined, 'input not contain data-value');
|
||||
ok($input.typeahead, 'typeahead applied to input');
|
||||
|
||||
$input.val('b').keyup();
|
||||
ok(p.find('.typeahead.dropdown-menu').is(':visible'), 'dropdown visible');
|
||||
|
||||
//select `ab`
|
||||
v = 'ab';
|
||||
p.find('.typeahead.dropdown-menu').find('.active').click();
|
||||
|
||||
equal($input.val(), v, 'input contain correct text');
|
||||
p.find('form').submit();
|
||||
|
||||
setTimeout(function() {
|
||||
ok(!p.is(':visible'), 'popup closed');
|
||||
equal(e.data('editable').value, v, 'new text saved to value');
|
||||
equal(e.text(), v, 'new text shown');
|
||||
|
||||
e.click();
|
||||
p = tip(e),
|
||||
$input = p.find('input[type=text]');
|
||||
|
||||
v = 'not_matched_text';
|
||||
$input.val(v).keyup();
|
||||
ok(!p.find('.typeahead.dropdown-menu').is(':visible'), 'dropdown not visible');
|
||||
|
||||
p.find('form').submit();
|
||||
setTimeout(function() {
|
||||
equal(e.data('editable').value, v, 'new text saved to value');
|
||||
equal(e.text(), v, 'new text shown');
|
||||
e.remove();
|
||||
start();
|
||||
}, timeout);
|
||||
}, timeout);
|
||||
});
|
||||
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user