Modernize Select2 integration and fix popover page jumping
- Upgraded Select2 from bundled v3.4.4 (2013) to v4.x peer dependency - Removed legacy Select2 v3.x bundled files from lib directory - Updated Select2 input to use v4.x API (events, AJAX, templates) - Fixed Bootstrap 5 popover page jumping issue with multi-timeout scroll restoration - Added comprehensive migration documentation in README-select2-upgrade.md - Rebuilt all distribution files with updated source code Breaking Changes: - Select2 now requires separate installation as peer dependency - AJAX configuration updated for v4.x format - Event names changed (select2:select vs select2-loaded) - Template functions renamed (templateResult vs formatResult)
This commit is contained in:
8
.idea/.gitignore
generated
vendored
Executable file
8
.idea/.gitignore
generated
vendored
Executable file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
8
.idea/modules.xml
generated
Executable file
8
.idea/modules.xml
generated
Executable file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/x-editable-bs5.iml" filepath="$PROJECT_DIR$/.idea/x-editable-bs5.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
19
.idea/php.xml
generated
Executable file
19
.idea/php.xml
generated
Executable file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MessDetectorOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCSFixerOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCodeSnifferOptionsConfiguration">
|
||||
<option name="highlightLevel" value="WARNING" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PsalmOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
generated
Executable file
6
.idea/vcs.xml
generated
Executable file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
8
.idea/x-editable-bs5.iml
generated
Executable file
8
.idea/x-editable-bs5.iml
generated
Executable file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
@@ -268,7 +268,8 @@ module.exports = function(grunt) {
|
||||
evil: false,
|
||||
globals: {
|
||||
jQuery: true,
|
||||
console: true
|
||||
console: true,
|
||||
bootstrap: true
|
||||
},
|
||||
},
|
||||
js: [ 'Gruntfile.js',
|
||||
|
92
README-select2-upgrade.md
Normal file
92
README-select2-upgrade.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Select2 Modernization
|
||||
|
||||
This fork has been updated to work with **Select2 v4.x** instead of the bundled v3.4.4 from 2013.
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
### Select2 Dependency
|
||||
Select2 is now a **peer dependency** and must be installed separately:
|
||||
|
||||
```bash
|
||||
npm install select2@^4.0.0
|
||||
```
|
||||
|
||||
### Include Select2 in Your HTML
|
||||
You must now include Select2 yourself:
|
||||
|
||||
```html
|
||||
<link href="node_modules/select2/dist/css/select2.css" rel="stylesheet" type="text/css">
|
||||
<script src="node_modules/select2/dist/js/select2.js"></script>
|
||||
```
|
||||
|
||||
For Bootstrap 5 styling, also include:
|
||||
```html
|
||||
<link href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css" rel="stylesheet">
|
||||
```
|
||||
|
||||
## API Changes
|
||||
|
||||
### Event Handling
|
||||
Select2 v4.x uses different event names:
|
||||
- `select2:select` instead of `select2-loaded`
|
||||
- `select2:unselect` for deselection
|
||||
|
||||
### AJAX Configuration
|
||||
For remote data sources, use the new v4.x format:
|
||||
|
||||
```javascript
|
||||
$('#element').editable({
|
||||
select2: {
|
||||
ajax: {
|
||||
url: '/api/data',
|
||||
dataType: 'json',
|
||||
delay: 250,
|
||||
data: function (params) {
|
||||
return {
|
||||
query: params.term,
|
||||
page: params.page
|
||||
};
|
||||
},
|
||||
processResults: function (data) {
|
||||
return {
|
||||
results: data.map(function(item) {
|
||||
return {
|
||||
id: item.id,
|
||||
text: item.name
|
||||
};
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Template Functions
|
||||
Use `templateResult` and `templateSelection` instead of `formatResult` and `formatSelection`:
|
||||
|
||||
```javascript
|
||||
select2: {
|
||||
templateResult: function(item) {
|
||||
return item.text;
|
||||
},
|
||||
templateSelection: function(item) {
|
||||
return item.text;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Migration Guide
|
||||
|
||||
1. **Install Select2 v4.x** as a peer dependency
|
||||
2. **Include Select2 CSS/JS** in your HTML before x-editable
|
||||
3. **Update AJAX configurations** to use v4.x format
|
||||
4. **Update template functions** to use new naming
|
||||
5. **Test thoroughly** - Select2 v4.x has different behavior
|
||||
|
||||
## Debug Mode
|
||||
|
||||
The updated code includes console logging for debugging. Check browser console for:
|
||||
- `[Select2 Debug] value2input called with: ...`
|
||||
- `[Select2 Debug] Item selected: ...`
|
||||
- `[Select2 Debug] Change event triggered: ...`
|
@@ -1,4 +1,4 @@
|
||||
/*! X-editable - v1.5.2
|
||||
/*! X-editable-bs5 - v1.5.2
|
||||
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||
* https://git.24unix.net/tracer/x-editable
|
||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||
|
256
dist/bootstrap-editable/js/bootstrap-editable.js
vendored
256
dist/bootstrap-editable/js/bootstrap-editable.js
vendored
@@ -1,4 +1,4 @@
|
||||
/*! X-editable - v1.5.2
|
||||
/*! X-editable-bs5 - v1.5.2
|
||||
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||
* https://git.24unix.net/tracer/x-editable
|
||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||
@@ -1540,16 +1540,15 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
//stop propagation not required because in document click handler it checks event target
|
||||
//e.stopPropagation();
|
||||
//stop propagation to prevent interference with other click handlers
|
||||
e.stopPropagation();
|
||||
|
||||
if(this.options.toggle === 'mouseenter') {
|
||||
//for hover only show container
|
||||
this.show();
|
||||
} else {
|
||||
//when toggle='click' we should not close all other containers as they will be closed automatically in document click listener
|
||||
var closeAll = (this.options.toggle !== 'click');
|
||||
this.toggle(closeAll);
|
||||
//always close other containers when opening a new one
|
||||
this.toggle(true);
|
||||
}
|
||||
}, this));
|
||||
} else {
|
||||
@@ -3601,23 +3600,20 @@ Time
|
||||
}(window.jQuery));
|
||||
|
||||
/**
|
||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
|
||||
Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options.
|
||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/select2/select2.
|
||||
Please see [Select2 docs](https://select2.org/) for detailed description and options.
|
||||
|
||||
You should manually download and include select2 distributive:
|
||||
You should manually download and include Select2 v4.x distributive:
|
||||
|
||||
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link>
|
||||
<script src="select2/select2.js"></script>
|
||||
<link href="node_modules/select2/dist/css/select2.css" rel="stylesheet" type="text/css"></link>
|
||||
<script src="node_modules/select2/dist/js/select2.js"></script>
|
||||
|
||||
To make it **bootstrap-styled** you can use css from [here](https://github.com/t0m/select2-bootstrap-css):
|
||||
To make it **bootstrap-styled** you can use css from [select2-bootstrap-5-theme](https://github.com/apalfrey/select2-bootstrap-5-theme):
|
||||
|
||||
<link href="select2-bootstrap.css" rel="stylesheet" type="text/css"></link>
|
||||
|
||||
**Note:** currently `autotext` feature does not work for select2 with `ajax` remote source.
|
||||
You need initially put both `data-value` and element's text youself:
|
||||
|
||||
<a href="#" data-type="select2" data-value="1">Text1</a>
|
||||
<link href="select2-bootstrap-5-theme.css" rel="stylesheet" type="text/css"></link>
|
||||
|
||||
**Note:** This version requires Select2 v4.x. For remote sources, you may need to provide custom
|
||||
`templateResult` and `templateSelection` functions.
|
||||
|
||||
@class select2
|
||||
@extends abstractinput
|
||||
@@ -3646,35 +3642,39 @@ $(function(){
|
||||
minimumInputLength: 1
|
||||
}
|
||||
});
|
||||
//remote source (advanced)
|
||||
//remote source (advanced) - Select2 v4.x format
|
||||
$('#country').editable({
|
||||
select2: {
|
||||
placeholder: 'Select Country',
|
||||
allowClear: true,
|
||||
minimumInputLength: 3,
|
||||
id: function (item) {
|
||||
return item.CountryId;
|
||||
},
|
||||
ajax: {
|
||||
url: '/getCountries',
|
||||
dataType: 'json',
|
||||
data: function (term, page) {
|
||||
return { query: term };
|
||||
delay: 250,
|
||||
data: function (params) {
|
||||
return {
|
||||
query: params.term,
|
||||
page: params.page
|
||||
};
|
||||
},
|
||||
results: function (data, page) {
|
||||
return { results: data };
|
||||
}
|
||||
processResults: function (data, params) {
|
||||
return {
|
||||
results: data.map(function(item) {
|
||||
return {
|
||||
id: item.CountryId,
|
||||
text: item.CountryName
|
||||
};
|
||||
})
|
||||
};
|
||||
},
|
||||
cache: true
|
||||
},
|
||||
formatResult: function (item) {
|
||||
return item.CountryName;
|
||||
templateResult: function (item) {
|
||||
return item.text || item.CountryName;
|
||||
},
|
||||
formatSelection: function (item) {
|
||||
return item.CountryName;
|
||||
},
|
||||
initSelection: function (element, callback) {
|
||||
return $.get('/getCountryById', { query: element.val() }, function (data) {
|
||||
callback(data);
|
||||
});
|
||||
templateSelection: function (item) {
|
||||
return item.text || item.CountryName;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -3706,12 +3706,19 @@ $(function(){
|
||||
|
||||
if (typeof source === 'string') {
|
||||
options.select2.ajax = options.select2.ajax || {};
|
||||
//some default ajax params
|
||||
//default ajax params for Select2 v4.x
|
||||
if(!options.select2.ajax.data) {
|
||||
options.select2.ajax.data = function(term) {return { query:term };};
|
||||
options.select2.ajax.data = function(params) {
|
||||
return {
|
||||
query: params.term,
|
||||
page: params.page
|
||||
};
|
||||
};
|
||||
}
|
||||
if(!options.select2.ajax.results) {
|
||||
options.select2.ajax.results = function(data) { return {results:data };};
|
||||
if(!options.select2.ajax.processResults) {
|
||||
options.select2.ajax.processResults = function(data) {
|
||||
return {results: data };
|
||||
};
|
||||
}
|
||||
options.select2.ajax.url = source;
|
||||
} else {
|
||||
@@ -3728,16 +3735,8 @@ $(function(){
|
||||
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
||||
this.isRemote = ('ajax' in this.options.select2);
|
||||
|
||||
//store function returning ID of item
|
||||
//should be here as used inautotext for local source
|
||||
this.idFunc = this.options.select2.id;
|
||||
if (typeof(this.idFunc) !== "function") {
|
||||
var idKey = this.idFunc || 'id';
|
||||
this.idFunc = function (e) { return e[idKey]; };
|
||||
}
|
||||
|
||||
//store function that renders text in select2
|
||||
this.formatSelection = this.options.select2.formatSelection;
|
||||
this.formatSelection = this.options.select2.templateSelection;
|
||||
if (typeof(this.formatSelection) !== "function") {
|
||||
this.formatSelection = function (e) { return e.text; };
|
||||
}
|
||||
@@ -3749,18 +3748,6 @@ $(function(){
|
||||
render: function() {
|
||||
this.setClass();
|
||||
|
||||
//can not apply select2 here as it calls initSelection
|
||||
//over input that does not have correct value yet.
|
||||
//apply select2 only in value2input
|
||||
//this.$input.select2(this.options.select2);
|
||||
|
||||
//when data is loaded via ajax, we need to know when it's done to populate listData
|
||||
if(this.isRemote) {
|
||||
//listen to loaded event to populate data
|
||||
this.$input.on('select2-loaded', $.proxy(function(e) {
|
||||
this.sourceData = e.items.results;
|
||||
}, this));
|
||||
}
|
||||
|
||||
//trigger resize of editableform to re-position container in multi-valued mode
|
||||
if(this.isMultiple) {
|
||||
@@ -3770,15 +3757,33 @@ $(function(){
|
||||
}
|
||||
},
|
||||
|
||||
autosubmit: function() {
|
||||
var self = this;
|
||||
var submitting = false;
|
||||
|
||||
// Use Select2 v4.x events for autosubmit - avoid double submissions
|
||||
this.$input.on('select2:select select2:unselect', $.proxy(function(e){
|
||||
if (!submitting) {
|
||||
submitting = true;
|
||||
setTimeout(function() {
|
||||
$(self.$input).closest('form').submit();
|
||||
submitting = false;
|
||||
}, 100);
|
||||
}
|
||||
}, this));
|
||||
},
|
||||
|
||||
value2html: function(value, element) {
|
||||
var text = '', data,
|
||||
that = this;
|
||||
|
||||
if(this.options.select2.tags) { //in tags mode just assign value
|
||||
// Use stored selected data if available (for visual display after selection)
|
||||
if(this.selectedData && this.selectedData.length > 0) {
|
||||
data = this.selectedData;
|
||||
} else if(this.options.select2.tags) { //in tags mode just assign value
|
||||
data = value;
|
||||
//data = $.fn.editableutils.itemsByValue(value, this.options.select2.tags, this.idFunc);
|
||||
} else if(this.sourceData) {
|
||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, this.idFunc);
|
||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, function(e) { return e.id; });
|
||||
} else {
|
||||
//can not get list of possible values
|
||||
//(e.g. autotext for select2 with ajax source)
|
||||
@@ -3797,7 +3802,6 @@ $(function(){
|
||||
|
||||
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
||||
|
||||
//$(element).text(text);
|
||||
Constructor.superclass.value2html.call(this, text, element);
|
||||
},
|
||||
|
||||
@@ -3806,45 +3810,90 @@ $(function(){
|
||||
},
|
||||
|
||||
value2input: function(value) {
|
||||
|
||||
// if value array => join it anyway
|
||||
if(Array.isArray(value)) {
|
||||
value = value.join(this.getSeparator());
|
||||
}
|
||||
|
||||
//for remote source just set value, text is updated by initSelection
|
||||
// For remote sources with existing value, create option element before Select2 init
|
||||
if(this.isRemote && !this.isMultiple && value) {
|
||||
var $el = $(this.options.scope);
|
||||
if (!$el.data('editable').isEmpty) {
|
||||
var text = $el.text();
|
||||
var $option = new Option(text, value, true, true);
|
||||
this.$input.append($option);
|
||||
}
|
||||
}
|
||||
|
||||
//initialize select2 if not already done
|
||||
if(!this.$input.data('select2')) {
|
||||
this.$input.val(value);
|
||||
this.$input.select2(this.options.select2);
|
||||
} else {
|
||||
//second argument needed to separate initial change from user's click (for autosubmit)
|
||||
this.$input.val(value).trigger('change', true);
|
||||
|
||||
//Uncaught Error: cannot call val() if initSelection() is not defined
|
||||
//this.$input.select2('val', value);
|
||||
}
|
||||
// Set up minimal event handling AFTER initialization
|
||||
this.$input.on('select2:select', $.proxy(function(e) {
|
||||
|
||||
// if defined remote source AND no multiple mode AND no user's initSelection provided -->
|
||||
// we should somehow get text for provided id.
|
||||
// The solution is to use element's text as text for that id (exclude empty)
|
||||
if(this.isRemote && !this.isMultiple && !this.options.select2.initSelection) {
|
||||
// customId and customText are methods to extract `id` and `text` from data object
|
||||
// we can use this workaround only if user did not define these methods
|
||||
// otherwise we cant construct data object
|
||||
var customId = this.options.select2.id,
|
||||
customText = this.options.select2.formatSelection;
|
||||
if (e.params && e.params.data) {
|
||||
var selectedData = e.params.data;
|
||||
this.selectedData = [selectedData];
|
||||
|
||||
if(!customId && !customText) {
|
||||
var $el = $(this.options.scope);
|
||||
if (!$el.data('editable').isEmpty) {
|
||||
var data = {id: value, text: $el.text()};
|
||||
this.$input.select2('data', data);
|
||||
// Fix Select2's visual display by ensuring the option exists and is selected
|
||||
var $existingOption = this.$input.find('option[value="' + selectedData.id + '"]');
|
||||
if ($existingOption.length === 0) {
|
||||
// Create the option if it doesn't exist
|
||||
var $option = $('<option></option>')
|
||||
.attr('value', selectedData.id)
|
||||
.text(selectedData.text)
|
||||
.prop('selected', true);
|
||||
this.$input.append($option);
|
||||
} else {
|
||||
// Make sure existing option is selected
|
||||
$existingOption.prop('selected', true);
|
||||
}
|
||||
|
||||
// Force Select2 to update its display
|
||||
this.$input.trigger('change.select2');
|
||||
|
||||
// Mark that a selection was just made (for blur handling)
|
||||
this._justSelected = true;
|
||||
}
|
||||
}
|
||||
}, this));
|
||||
|
||||
this.$input.on('select2:unselect', $.proxy(function(e) {
|
||||
this.selectedData = [];
|
||||
}, this));
|
||||
|
||||
// Ensure Select2 doesn't interfere with x-editable's document click handling
|
||||
// by making sure clicks on Select2 elements don't stop propagation
|
||||
this.$input.on('select2:open', $.proxy(function(e) {
|
||||
// Find the Select2 dropdown container and ensure it allows document clicks to propagate
|
||||
setTimeout(function() {
|
||||
$('.select2-container--open .select2-dropdown').off('click.editable-prevent-close');
|
||||
$('.select2-container--open .select2-results').off('click.editable-prevent-close');
|
||||
}, 10);
|
||||
}, this));
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
//update value on existing select2
|
||||
this.$input.val(value).trigger('change.select2');
|
||||
}
|
||||
},
|
||||
|
||||
input2value: function() {
|
||||
return this.$input.select2('val');
|
||||
var val = this.$input.val();
|
||||
|
||||
// For Select2 v4.x, ensure we get the actual selected value
|
||||
if (this.$input.data('select2')) {
|
||||
var selectedData = this.$input.select2('data');
|
||||
if (selectedData && selectedData.length > 0) {
|
||||
val = this.isMultiple ? selectedData.map(function(item) { return item.id; }) : selectedData[0].id;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
},
|
||||
|
||||
str2value: function(str, separator) {
|
||||
@@ -3867,16 +3916,10 @@ $(function(){
|
||||
return val;
|
||||
},
|
||||
|
||||
autosubmit: function() {
|
||||
this.$input.on('change', function(e, isInitial){
|
||||
if(!isInitial) {
|
||||
$(this).closest('form').submit();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getSeparator: function() {
|
||||
return this.options.select2.separator || $.fn.select2.defaults.separator;
|
||||
// Select2 v4.x uses different separator handling
|
||||
return this.options.select2.separator || ',';
|
||||
},
|
||||
|
||||
/*
|
||||
@@ -3912,7 +3955,7 @@ $(function(){
|
||||
**/
|
||||
tpl:'<input type="hidden">',
|
||||
/**
|
||||
Configuration of select2. [Full list of options](http://ivaynberg.github.com/select2).
|
||||
Configuration of select2. [Full list of options](https://select2.org/configuration).
|
||||
|
||||
@property select2
|
||||
@type object
|
||||
@@ -3950,7 +3993,6 @@ $(function(){
|
||||
$.fn.editabletypes.select2 = Constructor;
|
||||
|
||||
}(window.jQuery));
|
||||
|
||||
/**
|
||||
* Combodate - 1.0.5
|
||||
* Dropdown date and time picker.
|
||||
@@ -4887,12 +4929,6 @@ $(function(){
|
||||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
//store bootstrap-datepicker as bdateicker to exclude conflict with jQuery UI one
|
||||
$.fn.bdatepicker = $.fn.datepicker.noConflict();
|
||||
if(!$.fn.datepicker) { //if there were no other datepickers, keep also original name
|
||||
$.fn.datepicker = $.fn.bdatepicker;
|
||||
}
|
||||
|
||||
var Date = function (options) {
|
||||
this.init('date', options, Date.defaults);
|
||||
this.initPicker(options, Date.defaults);
|
||||
@@ -4902,6 +4938,18 @@ $(function(){
|
||||
|
||||
$.extend(Date.prototype, {
|
||||
initPicker: function(options, defaults) {
|
||||
// Initialize bootstrap-datepicker reference
|
||||
if (!$.fn.bdatepicker) {
|
||||
if ($.fn.datepicker) {
|
||||
$.fn.bdatepicker = $.fn.datepicker.noConflict();
|
||||
if(!$.fn.datepicker) { //if there were no other datepickers, keep also original name
|
||||
$.fn.datepicker = $.fn.bdatepicker;
|
||||
}
|
||||
} else {
|
||||
throw new Error('bootstrap-datepicker not found. Please include bootstrap-datepicker before x-editable.');
|
||||
}
|
||||
}
|
||||
|
||||
//'format' is set directly from settings or data-* attributes
|
||||
|
||||
//by default viewformat equals to format
|
||||
|
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
/*! X-editable - v1.5.2
|
||||
/*! X-editable-bs5 - v1.5.2
|
||||
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||
* https://git.24unix.net/tracer/x-editable
|
||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||
|
256
dist/bootstrap3-editable/js/bootstrap-editable.js
vendored
256
dist/bootstrap3-editable/js/bootstrap-editable.js
vendored
@@ -1,4 +1,4 @@
|
||||
/*! X-editable - v1.5.2
|
||||
/*! X-editable-bs5 - v1.5.2
|
||||
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||
* https://git.24unix.net/tracer/x-editable
|
||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||
@@ -1540,16 +1540,15 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
//stop propagation not required because in document click handler it checks event target
|
||||
//e.stopPropagation();
|
||||
//stop propagation to prevent interference with other click handlers
|
||||
e.stopPropagation();
|
||||
|
||||
if(this.options.toggle === 'mouseenter') {
|
||||
//for hover only show container
|
||||
this.show();
|
||||
} else {
|
||||
//when toggle='click' we should not close all other containers as they will be closed automatically in document click listener
|
||||
var closeAll = (this.options.toggle !== 'click');
|
||||
this.toggle(closeAll);
|
||||
//always close other containers when opening a new one
|
||||
this.toggle(true);
|
||||
}
|
||||
}, this));
|
||||
} else {
|
||||
@@ -3601,23 +3600,20 @@ Time
|
||||
}(window.jQuery));
|
||||
|
||||
/**
|
||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
|
||||
Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options.
|
||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/select2/select2.
|
||||
Please see [Select2 docs](https://select2.org/) for detailed description and options.
|
||||
|
||||
You should manually download and include select2 distributive:
|
||||
You should manually download and include Select2 v4.x distributive:
|
||||
|
||||
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link>
|
||||
<script src="select2/select2.js"></script>
|
||||
<link href="node_modules/select2/dist/css/select2.css" rel="stylesheet" type="text/css"></link>
|
||||
<script src="node_modules/select2/dist/js/select2.js"></script>
|
||||
|
||||
To make it **bootstrap-styled** you can use css from [here](https://github.com/t0m/select2-bootstrap-css):
|
||||
To make it **bootstrap-styled** you can use css from [select2-bootstrap-5-theme](https://github.com/apalfrey/select2-bootstrap-5-theme):
|
||||
|
||||
<link href="select2-bootstrap.css" rel="stylesheet" type="text/css"></link>
|
||||
|
||||
**Note:** currently `autotext` feature does not work for select2 with `ajax` remote source.
|
||||
You need initially put both `data-value` and element's text youself:
|
||||
|
||||
<a href="#" data-type="select2" data-value="1">Text1</a>
|
||||
<link href="select2-bootstrap-5-theme.css" rel="stylesheet" type="text/css"></link>
|
||||
|
||||
**Note:** This version requires Select2 v4.x. For remote sources, you may need to provide custom
|
||||
`templateResult` and `templateSelection` functions.
|
||||
|
||||
@class select2
|
||||
@extends abstractinput
|
||||
@@ -3646,35 +3642,39 @@ $(function(){
|
||||
minimumInputLength: 1
|
||||
}
|
||||
});
|
||||
//remote source (advanced)
|
||||
//remote source (advanced) - Select2 v4.x format
|
||||
$('#country').editable({
|
||||
select2: {
|
||||
placeholder: 'Select Country',
|
||||
allowClear: true,
|
||||
minimumInputLength: 3,
|
||||
id: function (item) {
|
||||
return item.CountryId;
|
||||
},
|
||||
ajax: {
|
||||
url: '/getCountries',
|
||||
dataType: 'json',
|
||||
data: function (term, page) {
|
||||
return { query: term };
|
||||
delay: 250,
|
||||
data: function (params) {
|
||||
return {
|
||||
query: params.term,
|
||||
page: params.page
|
||||
};
|
||||
},
|
||||
results: function (data, page) {
|
||||
return { results: data };
|
||||
}
|
||||
processResults: function (data, params) {
|
||||
return {
|
||||
results: data.map(function(item) {
|
||||
return {
|
||||
id: item.CountryId,
|
||||
text: item.CountryName
|
||||
};
|
||||
})
|
||||
};
|
||||
},
|
||||
cache: true
|
||||
},
|
||||
formatResult: function (item) {
|
||||
return item.CountryName;
|
||||
templateResult: function (item) {
|
||||
return item.text || item.CountryName;
|
||||
},
|
||||
formatSelection: function (item) {
|
||||
return item.CountryName;
|
||||
},
|
||||
initSelection: function (element, callback) {
|
||||
return $.get('/getCountryById', { query: element.val() }, function (data) {
|
||||
callback(data);
|
||||
});
|
||||
templateSelection: function (item) {
|
||||
return item.text || item.CountryName;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -3706,12 +3706,19 @@ $(function(){
|
||||
|
||||
if (typeof source === 'string') {
|
||||
options.select2.ajax = options.select2.ajax || {};
|
||||
//some default ajax params
|
||||
//default ajax params for Select2 v4.x
|
||||
if(!options.select2.ajax.data) {
|
||||
options.select2.ajax.data = function(term) {return { query:term };};
|
||||
options.select2.ajax.data = function(params) {
|
||||
return {
|
||||
query: params.term,
|
||||
page: params.page
|
||||
};
|
||||
};
|
||||
}
|
||||
if(!options.select2.ajax.results) {
|
||||
options.select2.ajax.results = function(data) { return {results:data };};
|
||||
if(!options.select2.ajax.processResults) {
|
||||
options.select2.ajax.processResults = function(data) {
|
||||
return {results: data };
|
||||
};
|
||||
}
|
||||
options.select2.ajax.url = source;
|
||||
} else {
|
||||
@@ -3728,16 +3735,8 @@ $(function(){
|
||||
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
||||
this.isRemote = ('ajax' in this.options.select2);
|
||||
|
||||
//store function returning ID of item
|
||||
//should be here as used inautotext for local source
|
||||
this.idFunc = this.options.select2.id;
|
||||
if (typeof(this.idFunc) !== "function") {
|
||||
var idKey = this.idFunc || 'id';
|
||||
this.idFunc = function (e) { return e[idKey]; };
|
||||
}
|
||||
|
||||
//store function that renders text in select2
|
||||
this.formatSelection = this.options.select2.formatSelection;
|
||||
this.formatSelection = this.options.select2.templateSelection;
|
||||
if (typeof(this.formatSelection) !== "function") {
|
||||
this.formatSelection = function (e) { return e.text; };
|
||||
}
|
||||
@@ -3749,18 +3748,6 @@ $(function(){
|
||||
render: function() {
|
||||
this.setClass();
|
||||
|
||||
//can not apply select2 here as it calls initSelection
|
||||
//over input that does not have correct value yet.
|
||||
//apply select2 only in value2input
|
||||
//this.$input.select2(this.options.select2);
|
||||
|
||||
//when data is loaded via ajax, we need to know when it's done to populate listData
|
||||
if(this.isRemote) {
|
||||
//listen to loaded event to populate data
|
||||
this.$input.on('select2-loaded', $.proxy(function(e) {
|
||||
this.sourceData = e.items.results;
|
||||
}, this));
|
||||
}
|
||||
|
||||
//trigger resize of editableform to re-position container in multi-valued mode
|
||||
if(this.isMultiple) {
|
||||
@@ -3770,15 +3757,33 @@ $(function(){
|
||||
}
|
||||
},
|
||||
|
||||
autosubmit: function() {
|
||||
var self = this;
|
||||
var submitting = false;
|
||||
|
||||
// Use Select2 v4.x events for autosubmit - avoid double submissions
|
||||
this.$input.on('select2:select select2:unselect', $.proxy(function(e){
|
||||
if (!submitting) {
|
||||
submitting = true;
|
||||
setTimeout(function() {
|
||||
$(self.$input).closest('form').submit();
|
||||
submitting = false;
|
||||
}, 100);
|
||||
}
|
||||
}, this));
|
||||
},
|
||||
|
||||
value2html: function(value, element) {
|
||||
var text = '', data,
|
||||
that = this;
|
||||
|
||||
if(this.options.select2.tags) { //in tags mode just assign value
|
||||
// Use stored selected data if available (for visual display after selection)
|
||||
if(this.selectedData && this.selectedData.length > 0) {
|
||||
data = this.selectedData;
|
||||
} else if(this.options.select2.tags) { //in tags mode just assign value
|
||||
data = value;
|
||||
//data = $.fn.editableutils.itemsByValue(value, this.options.select2.tags, this.idFunc);
|
||||
} else if(this.sourceData) {
|
||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, this.idFunc);
|
||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, function(e) { return e.id; });
|
||||
} else {
|
||||
//can not get list of possible values
|
||||
//(e.g. autotext for select2 with ajax source)
|
||||
@@ -3797,7 +3802,6 @@ $(function(){
|
||||
|
||||
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
||||
|
||||
//$(element).text(text);
|
||||
Constructor.superclass.value2html.call(this, text, element);
|
||||
},
|
||||
|
||||
@@ -3806,45 +3810,90 @@ $(function(){
|
||||
},
|
||||
|
||||
value2input: function(value) {
|
||||
|
||||
// if value array => join it anyway
|
||||
if(Array.isArray(value)) {
|
||||
value = value.join(this.getSeparator());
|
||||
}
|
||||
|
||||
//for remote source just set value, text is updated by initSelection
|
||||
// For remote sources with existing value, create option element before Select2 init
|
||||
if(this.isRemote && !this.isMultiple && value) {
|
||||
var $el = $(this.options.scope);
|
||||
if (!$el.data('editable').isEmpty) {
|
||||
var text = $el.text();
|
||||
var $option = new Option(text, value, true, true);
|
||||
this.$input.append($option);
|
||||
}
|
||||
}
|
||||
|
||||
//initialize select2 if not already done
|
||||
if(!this.$input.data('select2')) {
|
||||
this.$input.val(value);
|
||||
this.$input.select2(this.options.select2);
|
||||
} else {
|
||||
//second argument needed to separate initial change from user's click (for autosubmit)
|
||||
this.$input.val(value).trigger('change', true);
|
||||
|
||||
//Uncaught Error: cannot call val() if initSelection() is not defined
|
||||
//this.$input.select2('val', value);
|
||||
}
|
||||
// Set up minimal event handling AFTER initialization
|
||||
this.$input.on('select2:select', $.proxy(function(e) {
|
||||
|
||||
// if defined remote source AND no multiple mode AND no user's initSelection provided -->
|
||||
// we should somehow get text for provided id.
|
||||
// The solution is to use element's text as text for that id (exclude empty)
|
||||
if(this.isRemote && !this.isMultiple && !this.options.select2.initSelection) {
|
||||
// customId and customText are methods to extract `id` and `text` from data object
|
||||
// we can use this workaround only if user did not define these methods
|
||||
// otherwise we cant construct data object
|
||||
var customId = this.options.select2.id,
|
||||
customText = this.options.select2.formatSelection;
|
||||
if (e.params && e.params.data) {
|
||||
var selectedData = e.params.data;
|
||||
this.selectedData = [selectedData];
|
||||
|
||||
if(!customId && !customText) {
|
||||
var $el = $(this.options.scope);
|
||||
if (!$el.data('editable').isEmpty) {
|
||||
var data = {id: value, text: $el.text()};
|
||||
this.$input.select2('data', data);
|
||||
// Fix Select2's visual display by ensuring the option exists and is selected
|
||||
var $existingOption = this.$input.find('option[value="' + selectedData.id + '"]');
|
||||
if ($existingOption.length === 0) {
|
||||
// Create the option if it doesn't exist
|
||||
var $option = $('<option></option>')
|
||||
.attr('value', selectedData.id)
|
||||
.text(selectedData.text)
|
||||
.prop('selected', true);
|
||||
this.$input.append($option);
|
||||
} else {
|
||||
// Make sure existing option is selected
|
||||
$existingOption.prop('selected', true);
|
||||
}
|
||||
|
||||
// Force Select2 to update its display
|
||||
this.$input.trigger('change.select2');
|
||||
|
||||
// Mark that a selection was just made (for blur handling)
|
||||
this._justSelected = true;
|
||||
}
|
||||
}
|
||||
}, this));
|
||||
|
||||
this.$input.on('select2:unselect', $.proxy(function(e) {
|
||||
this.selectedData = [];
|
||||
}, this));
|
||||
|
||||
// Ensure Select2 doesn't interfere with x-editable's document click handling
|
||||
// by making sure clicks on Select2 elements don't stop propagation
|
||||
this.$input.on('select2:open', $.proxy(function(e) {
|
||||
// Find the Select2 dropdown container and ensure it allows document clicks to propagate
|
||||
setTimeout(function() {
|
||||
$('.select2-container--open .select2-dropdown').off('click.editable-prevent-close');
|
||||
$('.select2-container--open .select2-results').off('click.editable-prevent-close');
|
||||
}, 10);
|
||||
}, this));
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
//update value on existing select2
|
||||
this.$input.val(value).trigger('change.select2');
|
||||
}
|
||||
},
|
||||
|
||||
input2value: function() {
|
||||
return this.$input.select2('val');
|
||||
var val = this.$input.val();
|
||||
|
||||
// For Select2 v4.x, ensure we get the actual selected value
|
||||
if (this.$input.data('select2')) {
|
||||
var selectedData = this.$input.select2('data');
|
||||
if (selectedData && selectedData.length > 0) {
|
||||
val = this.isMultiple ? selectedData.map(function(item) { return item.id; }) : selectedData[0].id;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
},
|
||||
|
||||
str2value: function(str, separator) {
|
||||
@@ -3867,16 +3916,10 @@ $(function(){
|
||||
return val;
|
||||
},
|
||||
|
||||
autosubmit: function() {
|
||||
this.$input.on('change', function(e, isInitial){
|
||||
if(!isInitial) {
|
||||
$(this).closest('form').submit();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getSeparator: function() {
|
||||
return this.options.select2.separator || $.fn.select2.defaults.separator;
|
||||
// Select2 v4.x uses different separator handling
|
||||
return this.options.select2.separator || ',';
|
||||
},
|
||||
|
||||
/*
|
||||
@@ -3912,7 +3955,7 @@ $(function(){
|
||||
**/
|
||||
tpl:'<input type="hidden">',
|
||||
/**
|
||||
Configuration of select2. [Full list of options](http://ivaynberg.github.com/select2).
|
||||
Configuration of select2. [Full list of options](https://select2.org/configuration).
|
||||
|
||||
@property select2
|
||||
@type object
|
||||
@@ -3950,7 +3993,6 @@ $(function(){
|
||||
$.fn.editabletypes.select2 = Constructor;
|
||||
|
||||
}(window.jQuery));
|
||||
|
||||
/**
|
||||
* Combodate - 1.0.5
|
||||
* Dropdown date and time picker.
|
||||
@@ -4955,12 +4997,6 @@ $(function(){
|
||||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
//store bootstrap-datepicker as bdateicker to exclude conflict with jQuery UI one
|
||||
$.fn.bdatepicker = $.fn.datepicker.noConflict();
|
||||
if(!$.fn.datepicker) { //if there were no other datepickers, keep also original name
|
||||
$.fn.datepicker = $.fn.bdatepicker;
|
||||
}
|
||||
|
||||
var Date = function (options) {
|
||||
this.init('date', options, Date.defaults);
|
||||
this.initPicker(options, Date.defaults);
|
||||
@@ -4970,6 +5006,18 @@ $(function(){
|
||||
|
||||
$.extend(Date.prototype, {
|
||||
initPicker: function(options, defaults) {
|
||||
// Initialize bootstrap-datepicker reference
|
||||
if (!$.fn.bdatepicker) {
|
||||
if ($.fn.datepicker) {
|
||||
$.fn.bdatepicker = $.fn.datepicker.noConflict();
|
||||
if(!$.fn.datepicker) { //if there were no other datepickers, keep also original name
|
||||
$.fn.datepicker = $.fn.bdatepicker;
|
||||
}
|
||||
} else {
|
||||
throw new Error('bootstrap-datepicker not found. Please include bootstrap-datepicker before x-editable.');
|
||||
}
|
||||
}
|
||||
|
||||
//'format' is set directly from settings or data-* attributes
|
||||
|
||||
//by default viewformat equals to format
|
||||
|
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
/*! X-editable - v1.5.2
|
||||
/*! X-editable-bs5 - v1.5.2
|
||||
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||
* https://git.24unix.net/tracer/x-editable
|
||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||
|
5477
dist/bootstrap5-editable/js/bootstrap-editable.js
vendored
5477
dist/bootstrap5-editable/js/bootstrap-editable.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
dist/jquery-editable/css/jquery-editable.css
vendored
2
dist/jquery-editable/css/jquery-editable.css
vendored
@@ -1,4 +1,4 @@
|
||||
/*! X-editable - v1.5.2
|
||||
/*! X-editable-bs5 - v1.5.2
|
||||
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||
* https://git.24unix.net/tracer/x-editable
|
||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||
|
238
dist/jquery-editable/js/jquery-editable-poshytip.js
vendored
238
dist/jquery-editable/js/jquery-editable-poshytip.js
vendored
@@ -1,4 +1,4 @@
|
||||
/*! X-editable - v1.5.2
|
||||
/*! X-editable-bs5 - v1.5.2
|
||||
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||
* https://git.24unix.net/tracer/x-editable
|
||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||
@@ -1540,16 +1540,15 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
//stop propagation not required because in document click handler it checks event target
|
||||
//e.stopPropagation();
|
||||
//stop propagation to prevent interference with other click handlers
|
||||
e.stopPropagation();
|
||||
|
||||
if(this.options.toggle === 'mouseenter') {
|
||||
//for hover only show container
|
||||
this.show();
|
||||
} else {
|
||||
//when toggle='click' we should not close all other containers as they will be closed automatically in document click listener
|
||||
var closeAll = (this.options.toggle !== 'click');
|
||||
this.toggle(closeAll);
|
||||
//always close other containers when opening a new one
|
||||
this.toggle(true);
|
||||
}
|
||||
}, this));
|
||||
} else {
|
||||
@@ -3601,23 +3600,20 @@ Time
|
||||
}(window.jQuery));
|
||||
|
||||
/**
|
||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
|
||||
Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options.
|
||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/select2/select2.
|
||||
Please see [Select2 docs](https://select2.org/) for detailed description and options.
|
||||
|
||||
You should manually download and include select2 distributive:
|
||||
You should manually download and include Select2 v4.x distributive:
|
||||
|
||||
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link>
|
||||
<script src="select2/select2.js"></script>
|
||||
<link href="node_modules/select2/dist/css/select2.css" rel="stylesheet" type="text/css"></link>
|
||||
<script src="node_modules/select2/dist/js/select2.js"></script>
|
||||
|
||||
To make it **bootstrap-styled** you can use css from [here](https://github.com/t0m/select2-bootstrap-css):
|
||||
To make it **bootstrap-styled** you can use css from [select2-bootstrap-5-theme](https://github.com/apalfrey/select2-bootstrap-5-theme):
|
||||
|
||||
<link href="select2-bootstrap.css" rel="stylesheet" type="text/css"></link>
|
||||
|
||||
**Note:** currently `autotext` feature does not work for select2 with `ajax` remote source.
|
||||
You need initially put both `data-value` and element's text youself:
|
||||
|
||||
<a href="#" data-type="select2" data-value="1">Text1</a>
|
||||
<link href="select2-bootstrap-5-theme.css" rel="stylesheet" type="text/css"></link>
|
||||
|
||||
**Note:** This version requires Select2 v4.x. For remote sources, you may need to provide custom
|
||||
`templateResult` and `templateSelection` functions.
|
||||
|
||||
@class select2
|
||||
@extends abstractinput
|
||||
@@ -3646,35 +3642,39 @@ $(function(){
|
||||
minimumInputLength: 1
|
||||
}
|
||||
});
|
||||
//remote source (advanced)
|
||||
//remote source (advanced) - Select2 v4.x format
|
||||
$('#country').editable({
|
||||
select2: {
|
||||
placeholder: 'Select Country',
|
||||
allowClear: true,
|
||||
minimumInputLength: 3,
|
||||
id: function (item) {
|
||||
return item.CountryId;
|
||||
},
|
||||
ajax: {
|
||||
url: '/getCountries',
|
||||
dataType: 'json',
|
||||
data: function (term, page) {
|
||||
return { query: term };
|
||||
delay: 250,
|
||||
data: function (params) {
|
||||
return {
|
||||
query: params.term,
|
||||
page: params.page
|
||||
};
|
||||
},
|
||||
results: function (data, page) {
|
||||
return { results: data };
|
||||
}
|
||||
processResults: function (data, params) {
|
||||
return {
|
||||
results: data.map(function(item) {
|
||||
return {
|
||||
id: item.CountryId,
|
||||
text: item.CountryName
|
||||
};
|
||||
})
|
||||
};
|
||||
},
|
||||
cache: true
|
||||
},
|
||||
formatResult: function (item) {
|
||||
return item.CountryName;
|
||||
templateResult: function (item) {
|
||||
return item.text || item.CountryName;
|
||||
},
|
||||
formatSelection: function (item) {
|
||||
return item.CountryName;
|
||||
},
|
||||
initSelection: function (element, callback) {
|
||||
return $.get('/getCountryById', { query: element.val() }, function (data) {
|
||||
callback(data);
|
||||
});
|
||||
templateSelection: function (item) {
|
||||
return item.text || item.CountryName;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -3706,12 +3706,19 @@ $(function(){
|
||||
|
||||
if (typeof source === 'string') {
|
||||
options.select2.ajax = options.select2.ajax || {};
|
||||
//some default ajax params
|
||||
//default ajax params for Select2 v4.x
|
||||
if(!options.select2.ajax.data) {
|
||||
options.select2.ajax.data = function(term) {return { query:term };};
|
||||
options.select2.ajax.data = function(params) {
|
||||
return {
|
||||
query: params.term,
|
||||
page: params.page
|
||||
};
|
||||
};
|
||||
}
|
||||
if(!options.select2.ajax.results) {
|
||||
options.select2.ajax.results = function(data) { return {results:data };};
|
||||
if(!options.select2.ajax.processResults) {
|
||||
options.select2.ajax.processResults = function(data) {
|
||||
return {results: data };
|
||||
};
|
||||
}
|
||||
options.select2.ajax.url = source;
|
||||
} else {
|
||||
@@ -3728,16 +3735,8 @@ $(function(){
|
||||
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
||||
this.isRemote = ('ajax' in this.options.select2);
|
||||
|
||||
//store function returning ID of item
|
||||
//should be here as used inautotext for local source
|
||||
this.idFunc = this.options.select2.id;
|
||||
if (typeof(this.idFunc) !== "function") {
|
||||
var idKey = this.idFunc || 'id';
|
||||
this.idFunc = function (e) { return e[idKey]; };
|
||||
}
|
||||
|
||||
//store function that renders text in select2
|
||||
this.formatSelection = this.options.select2.formatSelection;
|
||||
this.formatSelection = this.options.select2.templateSelection;
|
||||
if (typeof(this.formatSelection) !== "function") {
|
||||
this.formatSelection = function (e) { return e.text; };
|
||||
}
|
||||
@@ -3749,18 +3748,6 @@ $(function(){
|
||||
render: function() {
|
||||
this.setClass();
|
||||
|
||||
//can not apply select2 here as it calls initSelection
|
||||
//over input that does not have correct value yet.
|
||||
//apply select2 only in value2input
|
||||
//this.$input.select2(this.options.select2);
|
||||
|
||||
//when data is loaded via ajax, we need to know when it's done to populate listData
|
||||
if(this.isRemote) {
|
||||
//listen to loaded event to populate data
|
||||
this.$input.on('select2-loaded', $.proxy(function(e) {
|
||||
this.sourceData = e.items.results;
|
||||
}, this));
|
||||
}
|
||||
|
||||
//trigger resize of editableform to re-position container in multi-valued mode
|
||||
if(this.isMultiple) {
|
||||
@@ -3770,15 +3757,33 @@ $(function(){
|
||||
}
|
||||
},
|
||||
|
||||
autosubmit: function() {
|
||||
var self = this;
|
||||
var submitting = false;
|
||||
|
||||
// Use Select2 v4.x events for autosubmit - avoid double submissions
|
||||
this.$input.on('select2:select select2:unselect', $.proxy(function(e){
|
||||
if (!submitting) {
|
||||
submitting = true;
|
||||
setTimeout(function() {
|
||||
$(self.$input).closest('form').submit();
|
||||
submitting = false;
|
||||
}, 100);
|
||||
}
|
||||
}, this));
|
||||
},
|
||||
|
||||
value2html: function(value, element) {
|
||||
var text = '', data,
|
||||
that = this;
|
||||
|
||||
if(this.options.select2.tags) { //in tags mode just assign value
|
||||
// Use stored selected data if available (for visual display after selection)
|
||||
if(this.selectedData && this.selectedData.length > 0) {
|
||||
data = this.selectedData;
|
||||
} else if(this.options.select2.tags) { //in tags mode just assign value
|
||||
data = value;
|
||||
//data = $.fn.editableutils.itemsByValue(value, this.options.select2.tags, this.idFunc);
|
||||
} else if(this.sourceData) {
|
||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, this.idFunc);
|
||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, function(e) { return e.id; });
|
||||
} else {
|
||||
//can not get list of possible values
|
||||
//(e.g. autotext for select2 with ajax source)
|
||||
@@ -3797,7 +3802,6 @@ $(function(){
|
||||
|
||||
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
||||
|
||||
//$(element).text(text);
|
||||
Constructor.superclass.value2html.call(this, text, element);
|
||||
},
|
||||
|
||||
@@ -3806,45 +3810,90 @@ $(function(){
|
||||
},
|
||||
|
||||
value2input: function(value) {
|
||||
|
||||
// if value array => join it anyway
|
||||
if(Array.isArray(value)) {
|
||||
value = value.join(this.getSeparator());
|
||||
}
|
||||
|
||||
//for remote source just set value, text is updated by initSelection
|
||||
// For remote sources with existing value, create option element before Select2 init
|
||||
if(this.isRemote && !this.isMultiple && value) {
|
||||
var $el = $(this.options.scope);
|
||||
if (!$el.data('editable').isEmpty) {
|
||||
var text = $el.text();
|
||||
var $option = new Option(text, value, true, true);
|
||||
this.$input.append($option);
|
||||
}
|
||||
}
|
||||
|
||||
//initialize select2 if not already done
|
||||
if(!this.$input.data('select2')) {
|
||||
this.$input.val(value);
|
||||
this.$input.select2(this.options.select2);
|
||||
} else {
|
||||
//second argument needed to separate initial change from user's click (for autosubmit)
|
||||
this.$input.val(value).trigger('change', true);
|
||||
|
||||
//Uncaught Error: cannot call val() if initSelection() is not defined
|
||||
//this.$input.select2('val', value);
|
||||
}
|
||||
// Set up minimal event handling AFTER initialization
|
||||
this.$input.on('select2:select', $.proxy(function(e) {
|
||||
|
||||
// if defined remote source AND no multiple mode AND no user's initSelection provided -->
|
||||
// we should somehow get text for provided id.
|
||||
// The solution is to use element's text as text for that id (exclude empty)
|
||||
if(this.isRemote && !this.isMultiple && !this.options.select2.initSelection) {
|
||||
// customId and customText are methods to extract `id` and `text` from data object
|
||||
// we can use this workaround only if user did not define these methods
|
||||
// otherwise we cant construct data object
|
||||
var customId = this.options.select2.id,
|
||||
customText = this.options.select2.formatSelection;
|
||||
if (e.params && e.params.data) {
|
||||
var selectedData = e.params.data;
|
||||
this.selectedData = [selectedData];
|
||||
|
||||
if(!customId && !customText) {
|
||||
var $el = $(this.options.scope);
|
||||
if (!$el.data('editable').isEmpty) {
|
||||
var data = {id: value, text: $el.text()};
|
||||
this.$input.select2('data', data);
|
||||
// Fix Select2's visual display by ensuring the option exists and is selected
|
||||
var $existingOption = this.$input.find('option[value="' + selectedData.id + '"]');
|
||||
if ($existingOption.length === 0) {
|
||||
// Create the option if it doesn't exist
|
||||
var $option = $('<option></option>')
|
||||
.attr('value', selectedData.id)
|
||||
.text(selectedData.text)
|
||||
.prop('selected', true);
|
||||
this.$input.append($option);
|
||||
} else {
|
||||
// Make sure existing option is selected
|
||||
$existingOption.prop('selected', true);
|
||||
}
|
||||
|
||||
// Force Select2 to update its display
|
||||
this.$input.trigger('change.select2');
|
||||
|
||||
// Mark that a selection was just made (for blur handling)
|
||||
this._justSelected = true;
|
||||
}
|
||||
}
|
||||
}, this));
|
||||
|
||||
this.$input.on('select2:unselect', $.proxy(function(e) {
|
||||
this.selectedData = [];
|
||||
}, this));
|
||||
|
||||
// Ensure Select2 doesn't interfere with x-editable's document click handling
|
||||
// by making sure clicks on Select2 elements don't stop propagation
|
||||
this.$input.on('select2:open', $.proxy(function(e) {
|
||||
// Find the Select2 dropdown container and ensure it allows document clicks to propagate
|
||||
setTimeout(function() {
|
||||
$('.select2-container--open .select2-dropdown').off('click.editable-prevent-close');
|
||||
$('.select2-container--open .select2-results').off('click.editable-prevent-close');
|
||||
}, 10);
|
||||
}, this));
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
//update value on existing select2
|
||||
this.$input.val(value).trigger('change.select2');
|
||||
}
|
||||
},
|
||||
|
||||
input2value: function() {
|
||||
return this.$input.select2('val');
|
||||
var val = this.$input.val();
|
||||
|
||||
// For Select2 v4.x, ensure we get the actual selected value
|
||||
if (this.$input.data('select2')) {
|
||||
var selectedData = this.$input.select2('data');
|
||||
if (selectedData && selectedData.length > 0) {
|
||||
val = this.isMultiple ? selectedData.map(function(item) { return item.id; }) : selectedData[0].id;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
},
|
||||
|
||||
str2value: function(str, separator) {
|
||||
@@ -3867,16 +3916,10 @@ $(function(){
|
||||
return val;
|
||||
},
|
||||
|
||||
autosubmit: function() {
|
||||
this.$input.on('change', function(e, isInitial){
|
||||
if(!isInitial) {
|
||||
$(this).closest('form').submit();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getSeparator: function() {
|
||||
return this.options.select2.separator || $.fn.select2.defaults.separator;
|
||||
// Select2 v4.x uses different separator handling
|
||||
return this.options.select2.separator || ',';
|
||||
},
|
||||
|
||||
/*
|
||||
@@ -3912,7 +3955,7 @@ $(function(){
|
||||
**/
|
||||
tpl:'<input type="hidden">',
|
||||
/**
|
||||
Configuration of select2. [Full list of options](http://ivaynberg.github.com/select2).
|
||||
Configuration of select2. [Full list of options](https://select2.org/configuration).
|
||||
|
||||
@property select2
|
||||
@type object
|
||||
@@ -3950,7 +3993,6 @@ $(function(){
|
||||
$.fn.editabletypes.select2 = Constructor;
|
||||
|
||||
}(window.jQuery));
|
||||
|
||||
/**
|
||||
* Combodate - 1.0.5
|
||||
* Dropdown date and time picker.
|
||||
|
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
/*! X-editable - v1.5.2
|
||||
/*! X-editable-bs5 - v1.5.2
|
||||
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||
* https://git.24unix.net/tracer/x-editable
|
||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||
|
238
dist/jqueryui-editable/js/jqueryui-editable.js
vendored
238
dist/jqueryui-editable/js/jqueryui-editable.js
vendored
@@ -1,4 +1,4 @@
|
||||
/*! X-editable - v1.5.2
|
||||
/*! X-editable-bs5 - v1.5.2
|
||||
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||
* https://git.24unix.net/tracer/x-editable
|
||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||
@@ -1540,16 +1540,15 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
//stop propagation not required because in document click handler it checks event target
|
||||
//e.stopPropagation();
|
||||
//stop propagation to prevent interference with other click handlers
|
||||
e.stopPropagation();
|
||||
|
||||
if(this.options.toggle === 'mouseenter') {
|
||||
//for hover only show container
|
||||
this.show();
|
||||
} else {
|
||||
//when toggle='click' we should not close all other containers as they will be closed automatically in document click listener
|
||||
var closeAll = (this.options.toggle !== 'click');
|
||||
this.toggle(closeAll);
|
||||
//always close other containers when opening a new one
|
||||
this.toggle(true);
|
||||
}
|
||||
}, this));
|
||||
} else {
|
||||
@@ -3601,23 +3600,20 @@ Time
|
||||
}(window.jQuery));
|
||||
|
||||
/**
|
||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
|
||||
Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options.
|
||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/select2/select2.
|
||||
Please see [Select2 docs](https://select2.org/) for detailed description and options.
|
||||
|
||||
You should manually download and include select2 distributive:
|
||||
You should manually download and include Select2 v4.x distributive:
|
||||
|
||||
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link>
|
||||
<script src="select2/select2.js"></script>
|
||||
<link href="node_modules/select2/dist/css/select2.css" rel="stylesheet" type="text/css"></link>
|
||||
<script src="node_modules/select2/dist/js/select2.js"></script>
|
||||
|
||||
To make it **bootstrap-styled** you can use css from [here](https://github.com/t0m/select2-bootstrap-css):
|
||||
To make it **bootstrap-styled** you can use css from [select2-bootstrap-5-theme](https://github.com/apalfrey/select2-bootstrap-5-theme):
|
||||
|
||||
<link href="select2-bootstrap.css" rel="stylesheet" type="text/css"></link>
|
||||
|
||||
**Note:** currently `autotext` feature does not work for select2 with `ajax` remote source.
|
||||
You need initially put both `data-value` and element's text youself:
|
||||
|
||||
<a href="#" data-type="select2" data-value="1">Text1</a>
|
||||
<link href="select2-bootstrap-5-theme.css" rel="stylesheet" type="text/css"></link>
|
||||
|
||||
**Note:** This version requires Select2 v4.x. For remote sources, you may need to provide custom
|
||||
`templateResult` and `templateSelection` functions.
|
||||
|
||||
@class select2
|
||||
@extends abstractinput
|
||||
@@ -3646,35 +3642,39 @@ $(function(){
|
||||
minimumInputLength: 1
|
||||
}
|
||||
});
|
||||
//remote source (advanced)
|
||||
//remote source (advanced) - Select2 v4.x format
|
||||
$('#country').editable({
|
||||
select2: {
|
||||
placeholder: 'Select Country',
|
||||
allowClear: true,
|
||||
minimumInputLength: 3,
|
||||
id: function (item) {
|
||||
return item.CountryId;
|
||||
},
|
||||
ajax: {
|
||||
url: '/getCountries',
|
||||
dataType: 'json',
|
||||
data: function (term, page) {
|
||||
return { query: term };
|
||||
delay: 250,
|
||||
data: function (params) {
|
||||
return {
|
||||
query: params.term,
|
||||
page: params.page
|
||||
};
|
||||
},
|
||||
results: function (data, page) {
|
||||
return { results: data };
|
||||
}
|
||||
processResults: function (data, params) {
|
||||
return {
|
||||
results: data.map(function(item) {
|
||||
return {
|
||||
id: item.CountryId,
|
||||
text: item.CountryName
|
||||
};
|
||||
})
|
||||
};
|
||||
},
|
||||
cache: true
|
||||
},
|
||||
formatResult: function (item) {
|
||||
return item.CountryName;
|
||||
templateResult: function (item) {
|
||||
return item.text || item.CountryName;
|
||||
},
|
||||
formatSelection: function (item) {
|
||||
return item.CountryName;
|
||||
},
|
||||
initSelection: function (element, callback) {
|
||||
return $.get('/getCountryById', { query: element.val() }, function (data) {
|
||||
callback(data);
|
||||
});
|
||||
templateSelection: function (item) {
|
||||
return item.text || item.CountryName;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -3706,12 +3706,19 @@ $(function(){
|
||||
|
||||
if (typeof source === 'string') {
|
||||
options.select2.ajax = options.select2.ajax || {};
|
||||
//some default ajax params
|
||||
//default ajax params for Select2 v4.x
|
||||
if(!options.select2.ajax.data) {
|
||||
options.select2.ajax.data = function(term) {return { query:term };};
|
||||
options.select2.ajax.data = function(params) {
|
||||
return {
|
||||
query: params.term,
|
||||
page: params.page
|
||||
};
|
||||
};
|
||||
}
|
||||
if(!options.select2.ajax.results) {
|
||||
options.select2.ajax.results = function(data) { return {results:data };};
|
||||
if(!options.select2.ajax.processResults) {
|
||||
options.select2.ajax.processResults = function(data) {
|
||||
return {results: data };
|
||||
};
|
||||
}
|
||||
options.select2.ajax.url = source;
|
||||
} else {
|
||||
@@ -3728,16 +3735,8 @@ $(function(){
|
||||
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
||||
this.isRemote = ('ajax' in this.options.select2);
|
||||
|
||||
//store function returning ID of item
|
||||
//should be here as used inautotext for local source
|
||||
this.idFunc = this.options.select2.id;
|
||||
if (typeof(this.idFunc) !== "function") {
|
||||
var idKey = this.idFunc || 'id';
|
||||
this.idFunc = function (e) { return e[idKey]; };
|
||||
}
|
||||
|
||||
//store function that renders text in select2
|
||||
this.formatSelection = this.options.select2.formatSelection;
|
||||
this.formatSelection = this.options.select2.templateSelection;
|
||||
if (typeof(this.formatSelection) !== "function") {
|
||||
this.formatSelection = function (e) { return e.text; };
|
||||
}
|
||||
@@ -3749,18 +3748,6 @@ $(function(){
|
||||
render: function() {
|
||||
this.setClass();
|
||||
|
||||
//can not apply select2 here as it calls initSelection
|
||||
//over input that does not have correct value yet.
|
||||
//apply select2 only in value2input
|
||||
//this.$input.select2(this.options.select2);
|
||||
|
||||
//when data is loaded via ajax, we need to know when it's done to populate listData
|
||||
if(this.isRemote) {
|
||||
//listen to loaded event to populate data
|
||||
this.$input.on('select2-loaded', $.proxy(function(e) {
|
||||
this.sourceData = e.items.results;
|
||||
}, this));
|
||||
}
|
||||
|
||||
//trigger resize of editableform to re-position container in multi-valued mode
|
||||
if(this.isMultiple) {
|
||||
@@ -3770,15 +3757,33 @@ $(function(){
|
||||
}
|
||||
},
|
||||
|
||||
autosubmit: function() {
|
||||
var self = this;
|
||||
var submitting = false;
|
||||
|
||||
// Use Select2 v4.x events for autosubmit - avoid double submissions
|
||||
this.$input.on('select2:select select2:unselect', $.proxy(function(e){
|
||||
if (!submitting) {
|
||||
submitting = true;
|
||||
setTimeout(function() {
|
||||
$(self.$input).closest('form').submit();
|
||||
submitting = false;
|
||||
}, 100);
|
||||
}
|
||||
}, this));
|
||||
},
|
||||
|
||||
value2html: function(value, element) {
|
||||
var text = '', data,
|
||||
that = this;
|
||||
|
||||
if(this.options.select2.tags) { //in tags mode just assign value
|
||||
// Use stored selected data if available (for visual display after selection)
|
||||
if(this.selectedData && this.selectedData.length > 0) {
|
||||
data = this.selectedData;
|
||||
} else if(this.options.select2.tags) { //in tags mode just assign value
|
||||
data = value;
|
||||
//data = $.fn.editableutils.itemsByValue(value, this.options.select2.tags, this.idFunc);
|
||||
} else if(this.sourceData) {
|
||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, this.idFunc);
|
||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, function(e) { return e.id; });
|
||||
} else {
|
||||
//can not get list of possible values
|
||||
//(e.g. autotext for select2 with ajax source)
|
||||
@@ -3797,7 +3802,6 @@ $(function(){
|
||||
|
||||
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
||||
|
||||
//$(element).text(text);
|
||||
Constructor.superclass.value2html.call(this, text, element);
|
||||
},
|
||||
|
||||
@@ -3806,45 +3810,90 @@ $(function(){
|
||||
},
|
||||
|
||||
value2input: function(value) {
|
||||
|
||||
// if value array => join it anyway
|
||||
if(Array.isArray(value)) {
|
||||
value = value.join(this.getSeparator());
|
||||
}
|
||||
|
||||
//for remote source just set value, text is updated by initSelection
|
||||
// For remote sources with existing value, create option element before Select2 init
|
||||
if(this.isRemote && !this.isMultiple && value) {
|
||||
var $el = $(this.options.scope);
|
||||
if (!$el.data('editable').isEmpty) {
|
||||
var text = $el.text();
|
||||
var $option = new Option(text, value, true, true);
|
||||
this.$input.append($option);
|
||||
}
|
||||
}
|
||||
|
||||
//initialize select2 if not already done
|
||||
if(!this.$input.data('select2')) {
|
||||
this.$input.val(value);
|
||||
this.$input.select2(this.options.select2);
|
||||
} else {
|
||||
//second argument needed to separate initial change from user's click (for autosubmit)
|
||||
this.$input.val(value).trigger('change', true);
|
||||
|
||||
//Uncaught Error: cannot call val() if initSelection() is not defined
|
||||
//this.$input.select2('val', value);
|
||||
}
|
||||
// Set up minimal event handling AFTER initialization
|
||||
this.$input.on('select2:select', $.proxy(function(e) {
|
||||
|
||||
// if defined remote source AND no multiple mode AND no user's initSelection provided -->
|
||||
// we should somehow get text for provided id.
|
||||
// The solution is to use element's text as text for that id (exclude empty)
|
||||
if(this.isRemote && !this.isMultiple && !this.options.select2.initSelection) {
|
||||
// customId and customText are methods to extract `id` and `text` from data object
|
||||
// we can use this workaround only if user did not define these methods
|
||||
// otherwise we cant construct data object
|
||||
var customId = this.options.select2.id,
|
||||
customText = this.options.select2.formatSelection;
|
||||
if (e.params && e.params.data) {
|
||||
var selectedData = e.params.data;
|
||||
this.selectedData = [selectedData];
|
||||
|
||||
if(!customId && !customText) {
|
||||
var $el = $(this.options.scope);
|
||||
if (!$el.data('editable').isEmpty) {
|
||||
var data = {id: value, text: $el.text()};
|
||||
this.$input.select2('data', data);
|
||||
// Fix Select2's visual display by ensuring the option exists and is selected
|
||||
var $existingOption = this.$input.find('option[value="' + selectedData.id + '"]');
|
||||
if ($existingOption.length === 0) {
|
||||
// Create the option if it doesn't exist
|
||||
var $option = $('<option></option>')
|
||||
.attr('value', selectedData.id)
|
||||
.text(selectedData.text)
|
||||
.prop('selected', true);
|
||||
this.$input.append($option);
|
||||
} else {
|
||||
// Make sure existing option is selected
|
||||
$existingOption.prop('selected', true);
|
||||
}
|
||||
|
||||
// Force Select2 to update its display
|
||||
this.$input.trigger('change.select2');
|
||||
|
||||
// Mark that a selection was just made (for blur handling)
|
||||
this._justSelected = true;
|
||||
}
|
||||
}
|
||||
}, this));
|
||||
|
||||
this.$input.on('select2:unselect', $.proxy(function(e) {
|
||||
this.selectedData = [];
|
||||
}, this));
|
||||
|
||||
// Ensure Select2 doesn't interfere with x-editable's document click handling
|
||||
// by making sure clicks on Select2 elements don't stop propagation
|
||||
this.$input.on('select2:open', $.proxy(function(e) {
|
||||
// Find the Select2 dropdown container and ensure it allows document clicks to propagate
|
||||
setTimeout(function() {
|
||||
$('.select2-container--open .select2-dropdown').off('click.editable-prevent-close');
|
||||
$('.select2-container--open .select2-results').off('click.editable-prevent-close');
|
||||
}, 10);
|
||||
}, this));
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
//update value on existing select2
|
||||
this.$input.val(value).trigger('change.select2');
|
||||
}
|
||||
},
|
||||
|
||||
input2value: function() {
|
||||
return this.$input.select2('val');
|
||||
var val = this.$input.val();
|
||||
|
||||
// For Select2 v4.x, ensure we get the actual selected value
|
||||
if (this.$input.data('select2')) {
|
||||
var selectedData = this.$input.select2('data');
|
||||
if (selectedData && selectedData.length > 0) {
|
||||
val = this.isMultiple ? selectedData.map(function(item) { return item.id; }) : selectedData[0].id;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
},
|
||||
|
||||
str2value: function(str, separator) {
|
||||
@@ -3867,16 +3916,10 @@ $(function(){
|
||||
return val;
|
||||
},
|
||||
|
||||
autosubmit: function() {
|
||||
this.$input.on('change', function(e, isInitial){
|
||||
if(!isInitial) {
|
||||
$(this).closest('form').submit();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getSeparator: function() {
|
||||
return this.options.select2.separator || $.fn.select2.defaults.separator;
|
||||
// Select2 v4.x uses different separator handling
|
||||
return this.options.select2.separator || ',';
|
||||
},
|
||||
|
||||
/*
|
||||
@@ -3912,7 +3955,7 @@ $(function(){
|
||||
**/
|
||||
tpl:'<input type="hidden">',
|
||||
/**
|
||||
Configuration of select2. [Full list of options](http://ivaynberg.github.com/select2).
|
||||
Configuration of select2. [Full list of options](https://select2.org/configuration).
|
||||
|
||||
@property select2
|
||||
@type object
|
||||
@@ -3950,7 +3993,6 @@ $(function(){
|
||||
$.fn.editabletypes.select2 = Constructor;
|
||||
|
||||
}(window.jQuery));
|
||||
|
||||
/**
|
||||
* Combodate - 1.0.5
|
||||
* Dropdown date and time picker.
|
||||
|
File diff suppressed because one or more lines are too long
14
package-lock.json
generated
14
package-lock.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "@24unix/x-editable",
|
||||
"name": "x-editable-bs5",
|
||||
"version": "1.5.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@24unix/x-editable",
|
||||
"name": "x-editable-bs5",
|
||||
"version": "1.5.2",
|
||||
"dependencies": {
|
||||
"bootstrap": "^5.3.3",
|
||||
@@ -30,6 +30,9 @@
|
||||
"grunt-contrib-uglify": "^5.2.2",
|
||||
"style-loader": "^4.0.0",
|
||||
"webpack-cli": "^6.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"select2": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
@@ -4424,6 +4427,13 @@
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/select2": {
|
||||
"version": "4.0.13",
|
||||
"resolved": "https://registry.npmjs.org/select2/-/select2-4.0.13.tgz",
|
||||
"integrity": "sha512-1JeB87s6oN/TDxQQYCvS5EFoQyvV6eYMZZ0AeA4tdFDYWN3BAGZ8npr17UBFddU0lgAt3H0yjX3X6/ekOj1yjw==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@24unix/x-editable",
|
||||
"title": "X-editable",
|
||||
"name": "x-editable-bs5",
|
||||
"title": "X-editable-bs5",
|
||||
"description": "A maintained fork of x-editable for Bootstrap 5 support.",
|
||||
"version": "1.5.2",
|
||||
"homepage": "https://git.24unix.net/tracer/x-editable",
|
||||
@@ -41,6 +41,9 @@
|
||||
"popper.js": "^1.16.1",
|
||||
"webpack": "^5.98.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"select2": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"css-loader": "^7.1.2",
|
||||
"file-loader": "^6.2.0",
|
||||
|
@@ -3,7 +3,6 @@
|
||||
* ---------------------
|
||||
* requires bootstrap-popover.js
|
||||
*/
|
||||
import { Popover } from "bootstrap";
|
||||
|
||||
(function ($) {
|
||||
"use strict";
|
||||
@@ -13,7 +12,7 @@ import { Popover } from "bootstrap";
|
||||
containerName: 'popover',
|
||||
containerDataName: 'bs.popover',
|
||||
innerCss: '.popover-body',
|
||||
defaults: Popover.Default,
|
||||
defaults: bootstrap.Popover.Default,
|
||||
|
||||
initContainer: function(){
|
||||
$.extend(this.containerOptions, {
|
||||
@@ -40,7 +39,27 @@ import { Popover } from "bootstrap";
|
||||
|
||||
/* show */
|
||||
innerShow: function () {
|
||||
// Preserve scroll position to prevent page jumping
|
||||
var scrollTop = $(window).scrollTop();
|
||||
var scrollLeft = $(window).scrollLeft();
|
||||
|
||||
this.call('show');
|
||||
|
||||
// Multiple restoration attempts to handle async positioning
|
||||
setTimeout(function() {
|
||||
$(window).scrollTop(scrollTop);
|
||||
$(window).scrollLeft(scrollLeft);
|
||||
}, 0);
|
||||
|
||||
setTimeout(function() {
|
||||
$(window).scrollTop(scrollTop);
|
||||
$(window).scrollLeft(scrollLeft);
|
||||
}, 10);
|
||||
|
||||
setTimeout(function() {
|
||||
$(window).scrollTop(scrollTop);
|
||||
$(window).scrollLeft(scrollLeft);
|
||||
}, 50);
|
||||
},
|
||||
|
||||
/* hide */
|
||||
@@ -64,7 +83,7 @@ import { Popover } from "bootstrap";
|
||||
call: function() {
|
||||
if ( ! $(this.$element).data(this.containerDataName)) {
|
||||
$(this.$element).data(this.containerDataName,
|
||||
Popover.getOrCreateInstance(this.$element, this.containerOptions)
|
||||
bootstrap.Popover.getOrCreateInstance(this.$element, this.containerOptions)
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
/*
|
||||
Editableform based on Twitter Bootstrap 5
|
||||
*/
|
||||
import $ from "jquery";
|
||||
|
||||
(function ($) {
|
||||
"use strict";
|
||||
@@ -48,7 +47,7 @@ import $ from "jquery";
|
||||
'<button type="submit" class="btn btn-primary btn-sm editable-submit">'+
|
||||
'<i class="bi bi-check"></i>'+
|
||||
'</button>'+
|
||||
'<button type="button" class="btn btn-secondary btn-sm editable-cancel">'+
|
||||
'<button type="button" class="btn btn-outline-secondary btn-sm editable-cancel">'+
|
||||
'<i class="bi bi-x"></i>'+
|
||||
'</button>';
|
||||
|
||||
|
@@ -75,16 +75,15 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
//stop propagation not required because in document click handler it checks event target
|
||||
//e.stopPropagation();
|
||||
//stop propagation to prevent interference with other click handlers
|
||||
e.stopPropagation();
|
||||
|
||||
if(this.options.toggle === 'mouseenter') {
|
||||
//for hover only show container
|
||||
this.show();
|
||||
} else {
|
||||
//when toggle='click' we should not close all other containers as they will be closed automatically in document click listener
|
||||
var closeAll = (this.options.toggle !== 'click');
|
||||
this.toggle(closeAll);
|
||||
//always close other containers when opening a new one
|
||||
this.toggle(true);
|
||||
}
|
||||
}, this));
|
||||
} else {
|
||||
|
@@ -26,12 +26,6 @@ $(function(){
|
||||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
//store bootstrap-datepicker as bdateicker to exclude conflict with jQuery UI one
|
||||
$.fn.bdatepicker = $.fn.datepicker.noConflict();
|
||||
if(!$.fn.datepicker) { //if there were no other datepickers, keep also original name
|
||||
$.fn.datepicker = $.fn.bdatepicker;
|
||||
}
|
||||
|
||||
var Date = function (options) {
|
||||
this.init('date', options, Date.defaults);
|
||||
this.initPicker(options, Date.defaults);
|
||||
@@ -41,6 +35,18 @@ $(function(){
|
||||
|
||||
$.extend(Date.prototype, {
|
||||
initPicker: function(options, defaults) {
|
||||
// Initialize bootstrap-datepicker reference
|
||||
if (!$.fn.bdatepicker) {
|
||||
if ($.fn.datepicker) {
|
||||
$.fn.bdatepicker = $.fn.datepicker.noConflict();
|
||||
if(!$.fn.datepicker) { //if there were no other datepickers, keep also original name
|
||||
$.fn.datepicker = $.fn.bdatepicker;
|
||||
}
|
||||
} else {
|
||||
throw new Error('bootstrap-datepicker not found. Please include bootstrap-datepicker before x-editable.');
|
||||
}
|
||||
}
|
||||
|
||||
//'format' is set directly from settings or data-* attributes
|
||||
|
||||
//by default viewformat equals to format
|
||||
|
87
src/inputs/select2/lib/select2-bootstrap.css
vendored
87
src/inputs/select2/lib/select2-bootstrap.css
vendored
@@ -1,87 +0,0 @@
|
||||
.form-control .select2-choice {
|
||||
border: 0;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.form-control .select2-choice .select2-arrow {
|
||||
border-radius: 0 2px 2px 0;
|
||||
}
|
||||
|
||||
.form-control.select2-container {
|
||||
height: auto !important;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.form-control.select2-container.select2-dropdown-open {
|
||||
border-color: #5897FB;
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
.form-control .select2-container.select2-dropdown-open .select2-choices {
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
.form-control.select2-container .select2-choices {
|
||||
border: 0 !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.control-group.warning .select2-container .select2-choice,
|
||||
.control-group.warning .select2-container .select2-choices,
|
||||
.control-group.warning .select2-container-active .select2-choice,
|
||||
.control-group.warning .select2-container-active .select2-choices,
|
||||
.control-group.warning .select2-dropdown-open.select2-drop-above .select2-choice,
|
||||
.control-group.warning .select2-dropdown-open.select2-drop-above .select2-choices,
|
||||
.control-group.warning .select2-container-multi.select2-container-active .select2-choices {
|
||||
border: 1px solid #C09853 !important;
|
||||
}
|
||||
|
||||
.control-group.warning .select2-container .select2-choice div {
|
||||
border-left: 1px solid #C09853 !important;
|
||||
background: #FCF8E3 !important;
|
||||
}
|
||||
|
||||
.control-group.error .select2-container .select2-choice,
|
||||
.control-group.error .select2-container .select2-choices,
|
||||
.control-group.error .select2-container-active .select2-choice,
|
||||
.control-group.error .select2-container-active .select2-choices,
|
||||
.control-group.error .select2-dropdown-open.select2-drop-above .select2-choice,
|
||||
.control-group.error .select2-dropdown-open.select2-drop-above .select2-choices,
|
||||
.control-group.error .select2-container-multi.select2-container-active .select2-choices {
|
||||
border: 1px solid #B94A48 !important;
|
||||
}
|
||||
|
||||
.control-group.error .select2-container .select2-choice div {
|
||||
border-left: 1px solid #B94A48 !important;
|
||||
background: #F2DEDE !important;
|
||||
}
|
||||
|
||||
.control-group.info .select2-container .select2-choice,
|
||||
.control-group.info .select2-container .select2-choices,
|
||||
.control-group.info .select2-container-active .select2-choice,
|
||||
.control-group.info .select2-container-active .select2-choices,
|
||||
.control-group.info .select2-dropdown-open.select2-drop-above .select2-choice,
|
||||
.control-group.info .select2-dropdown-open.select2-drop-above .select2-choices,
|
||||
.control-group.info .select2-container-multi.select2-container-active .select2-choices {
|
||||
border: 1px solid #3A87AD !important;
|
||||
}
|
||||
|
||||
.control-group.info .select2-container .select2-choice div {
|
||||
border-left: 1px solid #3A87AD !important;
|
||||
background: #D9EDF7 !important;
|
||||
}
|
||||
|
||||
.control-group.success .select2-container .select2-choice,
|
||||
.control-group.success .select2-container .select2-choices,
|
||||
.control-group.success .select2-container-active .select2-choice,
|
||||
.control-group.success .select2-container-active .select2-choices,
|
||||
.control-group.success .select2-dropdown-open.select2-drop-above .select2-choice,
|
||||
.control-group.success .select2-dropdown-open.select2-drop-above .select2-choices,
|
||||
.control-group.success .select2-container-multi.select2-container-active .select2-choices {
|
||||
border: 1px solid #468847 !important;
|
||||
}
|
||||
|
||||
.control-group.success .select2-container .select2-choice div {
|
||||
border-left: 1px solid #468847 !important;
|
||||
background: #DFF0D8 !important;
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 1.8 KiB |
615
src/inputs/select2/lib/select2.css
vendored
615
src/inputs/select2/lib/select2.css
vendored
@@ -1,615 +0,0 @@
|
||||
/*
|
||||
Version: 3.4.4 Timestamp: Thu Oct 24 13:23:11 PDT 2013
|
||||
*/
|
||||
.select2-container {
|
||||
margin: 0;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
/* inline-block for ie7 */
|
||||
zoom: 1;
|
||||
*display: inline;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.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
|
||||
*/
|
||||
-webkit-box-sizing: border-box; /* webkit */
|
||||
-moz-box-sizing: border-box; /* firefox */
|
||||
box-sizing: border-box; /* css3 */
|
||||
}
|
||||
|
||||
.select2-container .select2-choice {
|
||||
display: block;
|
||||
height: 26px;
|
||||
padding: 0 0 0 8px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
border: 1px solid #aaa;
|
||||
white-space: nowrap;
|
||||
line-height: 26px;
|
||||
color: #444;
|
||||
text-decoration: none;
|
||||
|
||||
border-radius: 4px;
|
||||
|
||||
background-clip: padding-box;
|
||||
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
background-color: #fff;
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff));
|
||||
background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%);
|
||||
background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0);
|
||||
background-image: linear-gradient(top, #fff 0%, #eee 50%);
|
||||
}
|
||||
|
||||
.select2-container.select2-drop-above .select2-choice {
|
||||
border-bottom-color: #aaa;
|
||||
|
||||
border-radius: 0 0 4px 4px;
|
||||
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff));
|
||||
background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%);
|
||||
background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 90%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0);
|
||||
background-image: linear-gradient(top, #eee 0%, #fff 90%);
|
||||
}
|
||||
|
||||
.select2-container.select2-allowclear .select2-choice .select2-chosen {
|
||||
margin-right: 42px;
|
||||
}
|
||||
|
||||
.select2-container .select2-choice > .select2-chosen {
|
||||
margin-right: 26px;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
|
||||
white-space: nowrap;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.select2-container .select2-choice abbr {
|
||||
display: none;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
position: absolute;
|
||||
right: 24px;
|
||||
top: 8px;
|
||||
|
||||
font-size: 1px;
|
||||
text-decoration: none;
|
||||
|
||||
border: 0;
|
||||
background: url('select2.png') right top no-repeat;
|
||||
cursor: pointer;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.select2-container.select2-allowclear .select2-choice abbr {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.select2-container .select2-choice abbr:hover {
|
||||
background-position: right -11px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.select2-drop-mask {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
height: auto;
|
||||
width: auto;
|
||||
opacity: 0;
|
||||
z-index: 9998;
|
||||
/* styles required for IE to work */
|
||||
background-color: #fff;
|
||||
filter: alpha(opacity=0);
|
||||
}
|
||||
|
||||
.select2-drop {
|
||||
width: 100%;
|
||||
margin-top: -1px;
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
top: 100%;
|
||||
|
||||
background: #fff;
|
||||
color: #000;
|
||||
border: 1px solid #aaa;
|
||||
border-top: 0;
|
||||
|
||||
border-radius: 0 0 4px 4px;
|
||||
|
||||
-webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
|
||||
box-shadow: 0 4px 5px rgba(0, 0, 0, .15);
|
||||
}
|
||||
|
||||
.select2-drop-auto-width {
|
||||
border-top: 1px solid #aaa;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.select2-drop-auto-width .select2-search {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.select2-drop.select2-drop-above {
|
||||
margin-top: 1px;
|
||||
border-top: 1px solid #aaa;
|
||||
border-bottom: 0;
|
||||
|
||||
border-radius: 4px 4px 0 0;
|
||||
|
||||
-webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
|
||||
box-shadow: 0 -4px 5px rgba(0, 0, 0, .15);
|
||||
}
|
||||
|
||||
.select2-drop-active {
|
||||
border: 1px solid #5897fb;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.select2-drop.select2-drop-above.select2-drop-active {
|
||||
border-top: 1px solid #5897fb;
|
||||
}
|
||||
|
||||
.select2-container .select2-choice .select2-arrow {
|
||||
display: inline-block;
|
||||
width: 18px;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
|
||||
border-left: 1px solid #aaa;
|
||||
border-radius: 0 4px 4px 0;
|
||||
|
||||
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%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0);
|
||||
background-image: linear-gradient(top, #ccc 0%, #eee 60%);
|
||||
}
|
||||
|
||||
.select2-container .select2-choice .select2-arrow b {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url('select2.png') no-repeat 0 1px;
|
||||
}
|
||||
|
||||
.select2-search {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
min-height: 26px;
|
||||
margin: 0;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
|
||||
position: relative;
|
||||
z-index: 10000;
|
||||
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.select2-search input {
|
||||
width: 100%;
|
||||
height: auto !important;
|
||||
min-height: 26px;
|
||||
padding: 4px 20px 4px 5px;
|
||||
margin: 0;
|
||||
|
||||
outline: 0;
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 0;
|
||||
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
|
||||
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, #fff), color-stop(0.99, #eee));
|
||||
background: url('select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
|
||||
background: url('select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
|
||||
background: url('select2.png') no-repeat 100% -22px, linear-gradient(top, #fff 85%, #eee 99%);
|
||||
}
|
||||
|
||||
.select2-drop.select2-drop-above .select2-search input {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.select2-search input.select2-active {
|
||||
background: #fff url('select2-spinner.gif') no-repeat 100%;
|
||||
background: url('select2-spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee));
|
||||
background: url('select2-spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%);
|
||||
background: url('select2-spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%);
|
||||
background: url('select2-spinner.gif') no-repeat 100%, linear-gradient(top, #fff 85%, #eee 99%);
|
||||
}
|
||||
|
||||
.select2-container-active .select2-choice,
|
||||
.select2-container-active .select2-choices {
|
||||
border: 1px solid #5897fb;
|
||||
outline: none;
|
||||
|
||||
-webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, .3);
|
||||
}
|
||||
|
||||
.select2-dropdown-open .select2-choice {
|
||||
border-bottom-color: transparent;
|
||||
-webkit-box-shadow: 0 1px 0 #fff inset;
|
||||
box-shadow: 0 1px 0 #fff inset;
|
||||
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
|
||||
background-color: #eee;
|
||||
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(0.5, #eee));
|
||||
background-image: -webkit-linear-gradient(center bottom, #fff 0%, #eee 50%);
|
||||
background-image: -moz-linear-gradient(center bottom, #fff 0%, #eee 50%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
|
||||
background-image: linear-gradient(top, #fff 0%, #eee 50%);
|
||||
}
|
||||
|
||||
.select2-dropdown-open.select2-drop-above .select2-choice,
|
||||
.select2-dropdown-open.select2-drop-above .select2-choices {
|
||||
border: 1px solid #5897fb;
|
||||
border-top-color: transparent;
|
||||
|
||||
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(0.5, #eee));
|
||||
background-image: -webkit-linear-gradient(center top, #fff 0%, #eee 50%);
|
||||
background-image: -moz-linear-gradient(center top, #fff 0%, #eee 50%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0);
|
||||
background-image: linear-gradient(bottom, #fff 0%, #eee 50%);
|
||||
}
|
||||
|
||||
.select2-dropdown-open .select2-choice .select2-arrow {
|
||||
background: transparent;
|
||||
border-left: none;
|
||||
filter: none;
|
||||
}
|
||||
.select2-dropdown-open .select2-choice .select2-arrow b {
|
||||
background-position: -18px 1px;
|
||||
}
|
||||
|
||||
/* results */
|
||||
.select2-results {
|
||||
max-height: 200px;
|
||||
padding: 0 0 0 4px;
|
||||
margin: 4px 4px 4px 0;
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.select2-results ul.select2-result-sub {
|
||||
margin: 0;
|
||||
padding-left: 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;
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.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;
|
||||
|
||||
min-height: 1em;
|
||||
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.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-highlighted ul {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
|
||||
.select2-results .select2-no-results,
|
||||
.select2-results .select2-searching,
|
||||
.select2-results .select2-selection-limit {
|
||||
background: #f4f4f4;
|
||||
display: list-item;
|
||||
}
|
||||
|
||||
/*
|
||||
disabled look for disabled 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-selected {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.select2-more-results.select2-active {
|
||||
background: #f4f4f4 url('select2-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 .select2-arrow {
|
||||
background-color: #f4f4f4;
|
||||
background-image: none;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.select2-container.select2-container-disabled .select2-choice abbr {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/* multiselect */
|
||||
|
||||
.select2-container-multi .select2-choices {
|
||||
height: auto !important;
|
||||
height: 1%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
|
||||
border: 1px solid #aaa;
|
||||
cursor: text;
|
||||
overflow: hidden;
|
||||
|
||||
background-color: #fff;
|
||||
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eee), color-stop(15%, #fff));
|
||||
background-image: -webkit-linear-gradient(top, #eee 1%, #fff 15%);
|
||||
background-image: -moz-linear-gradient(top, #eee 1%, #fff 15%);
|
||||
background-image: linear-gradient(top, #eee 1%, #fff 15%);
|
||||
}
|
||||
|
||||
.select2-locked {
|
||||
padding: 3px 5px 3px 5px !important;
|
||||
}
|
||||
|
||||
.select2-container-multi .select2-choices {
|
||||
min-height: 26px;
|
||||
}
|
||||
|
||||
.select2-container-multi.select2-container-active .select2-choices {
|
||||
border: 1px solid #5897fb;
|
||||
outline: none;
|
||||
|
||||
-webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3);
|
||||
box-shadow: 0 0 5px rgba(0, 0, 0, .3);
|
||||
}
|
||||
.select2-container-multi .select2-choices li {
|
||||
float: left;
|
||||
list-style: none;
|
||||
}
|
||||
.select2-container-multi .select2-choices .select2-search-field {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.select2-container-multi .select2-choices .select2-search-field input {
|
||||
padding: 5px;
|
||||
margin: 1px 0;
|
||||
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
color: #666;
|
||||
outline: 0;
|
||||
border: 0;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.select2-container-multi .select2-choices .select2-search-field input.select2-active {
|
||||
background: #fff url('select2-spinner.gif') no-repeat 100% !important;
|
||||
}
|
||||
|
||||
.select2-default {
|
||||
color: #999 !important;
|
||||
}
|
||||
|
||||
.select2-container-multi .select2-choices .select2-search-choice {
|
||||
padding: 3px 5px 3px 18px;
|
||||
margin: 3px 0 3px 5px;
|
||||
position: relative;
|
||||
|
||||
line-height: 13px;
|
||||
color: #333;
|
||||
cursor: default;
|
||||
border: 1px solid #aaaaaa;
|
||||
|
||||
border-radius: 3px;
|
||||
|
||||
-webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
|
||||
box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
|
||||
|
||||
background-clip: padding-box;
|
||||
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
background-color: #e4e4e4;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#f4f4f4', 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%, #eee));
|
||||
background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
|
||||
background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
|
||||
background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
|
||||
}
|
||||
.select2-container-multi .select2-choices .select2-search-choice .select2-chosen {
|
||||
cursor: default;
|
||||
}
|
||||
.select2-container-multi .select2-choices .select2-search-choice-focus {
|
||||
background: #d4d4d4;
|
||||
}
|
||||
|
||||
.select2-search-choice-close {
|
||||
display: block;
|
||||
width: 12px;
|
||||
height: 13px;
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: 4px;
|
||||
|
||||
font-size: 1px;
|
||||
outline: none;
|
||||
background: url('select2.png') right top no-repeat;
|
||||
}
|
||||
|
||||
.select2-container-multi .select2-search-choice-close {
|
||||
left: 3px;
|
||||
}
|
||||
|
||||
.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover {
|
||||
background-position: right -11px;
|
||||
}
|
||||
.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close {
|
||||
background-position: right -11px;
|
||||
}
|
||||
|
||||
/* 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 {
|
||||
padding: 3px 5px 3px 5px;
|
||||
border: 1px solid #ddd;
|
||||
background-image: none;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none;
|
||||
background: none;
|
||||
}
|
||||
/* end multiselect */
|
||||
|
||||
|
||||
.select2-result-selectable .select2-match,
|
||||
.select2-result-unselectable .select2-match {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.select2-offscreen, .select2-offscreen:focus {
|
||||
clip: rect(0 0 0 0) !important;
|
||||
width: 1px !important;
|
||||
height: 1px !important;
|
||||
border: 0 !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
overflow: hidden !important;
|
||||
position: absolute !important;
|
||||
outline: 0 !important;
|
||||
left: 0px !important;
|
||||
top: 0px !important;
|
||||
}
|
||||
|
||||
.select2-display-none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.select2-measure-scrollbar {
|
||||
position: absolute;
|
||||
top: -10000px;
|
||||
left: -10000px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
overflow: scroll;
|
||||
}
|
||||
/* Retina-ize icons */
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi) {
|
||||
.select2-search input, .select2-search-choice-close, .select2-container .select2-choice abbr, .select2-container .select2-choice .select2-arrow 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;
|
||||
}
|
||||
}
|
3251
src/inputs/select2/lib/select2.js
vendored
3251
src/inputs/select2/lib/select2.js
vendored
File diff suppressed because one or more lines are too long
22
src/inputs/select2/lib/select2.min.js
vendored
22
src/inputs/select2/lib/select2.min.js
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 613 B |
Binary file not shown.
Before Width: | Height: | Size: 845 B |
226
src/inputs/select2/select2.js
vendored
226
src/inputs/select2/select2.js
vendored
@@ -1,21 +1,18 @@
|
||||
/**
|
||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
|
||||
Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options.
|
||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/select2/select2.
|
||||
Please see [Select2 docs](https://select2.org/) for detailed description and options.
|
||||
|
||||
You should manually download and include select2 distributive:
|
||||
You should manually download and include Select2 v4.x distributive:
|
||||
|
||||
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link>
|
||||
<script src="select2/select2.js"></script>
|
||||
<link href="node_modules/select2/dist/css/select2.css" rel="stylesheet" type="text/css"></link>
|
||||
<script src="node_modules/select2/dist/js/select2.js"></script>
|
||||
|
||||
To make it **bootstrap-styled** you can use css from [here](https://github.com/t0m/select2-bootstrap-css):
|
||||
To make it **bootstrap-styled** you can use css from [select2-bootstrap-5-theme](https://github.com/apalfrey/select2-bootstrap-5-theme):
|
||||
|
||||
<link href="select2-bootstrap.css" rel="stylesheet" type="text/css"></link>
|
||||
|
||||
**Note:** currently `autotext` feature does not work for select2 with `ajax` remote source.
|
||||
You need initially put both `data-value` and element's text youself:
|
||||
|
||||
<a href="#" data-type="select2" data-value="1">Text1</a>
|
||||
<link href="select2-bootstrap-5-theme.css" rel="stylesheet" type="text/css"></link>
|
||||
|
||||
**Note:** This version requires Select2 v4.x. For remote sources, you may need to provide custom
|
||||
`templateResult` and `templateSelection` functions.
|
||||
|
||||
@class select2
|
||||
@extends abstractinput
|
||||
@@ -44,35 +41,39 @@ $(function(){
|
||||
minimumInputLength: 1
|
||||
}
|
||||
});
|
||||
//remote source (advanced)
|
||||
//remote source (advanced) - Select2 v4.x format
|
||||
$('#country').editable({
|
||||
select2: {
|
||||
placeholder: 'Select Country',
|
||||
allowClear: true,
|
||||
minimumInputLength: 3,
|
||||
id: function (item) {
|
||||
return item.CountryId;
|
||||
},
|
||||
ajax: {
|
||||
url: '/getCountries',
|
||||
dataType: 'json',
|
||||
data: function (term, page) {
|
||||
return { query: term };
|
||||
delay: 250,
|
||||
data: function (params) {
|
||||
return {
|
||||
query: params.term,
|
||||
page: params.page
|
||||
};
|
||||
},
|
||||
results: function (data, page) {
|
||||
return { results: data };
|
||||
}
|
||||
processResults: function (data, params) {
|
||||
return {
|
||||
results: data.map(function(item) {
|
||||
return {
|
||||
id: item.CountryId,
|
||||
text: item.CountryName
|
||||
};
|
||||
})
|
||||
};
|
||||
},
|
||||
cache: true
|
||||
},
|
||||
formatResult: function (item) {
|
||||
return item.CountryName;
|
||||
templateResult: function (item) {
|
||||
return item.text || item.CountryName;
|
||||
},
|
||||
formatSelection: function (item) {
|
||||
return item.CountryName;
|
||||
},
|
||||
initSelection: function (element, callback) {
|
||||
return $.get('/getCountryById', { query: element.val() }, function (data) {
|
||||
callback(data);
|
||||
});
|
||||
templateSelection: function (item) {
|
||||
return item.text || item.CountryName;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -104,12 +105,19 @@ $(function(){
|
||||
|
||||
if (typeof source === 'string') {
|
||||
options.select2.ajax = options.select2.ajax || {};
|
||||
//some default ajax params
|
||||
//default ajax params for Select2 v4.x
|
||||
if(!options.select2.ajax.data) {
|
||||
options.select2.ajax.data = function(term) {return { query:term };};
|
||||
options.select2.ajax.data = function(params) {
|
||||
return {
|
||||
query: params.term,
|
||||
page: params.page
|
||||
};
|
||||
};
|
||||
}
|
||||
if(!options.select2.ajax.results) {
|
||||
options.select2.ajax.results = function(data) { return {results:data };};
|
||||
if(!options.select2.ajax.processResults) {
|
||||
options.select2.ajax.processResults = function(data) {
|
||||
return {results: data };
|
||||
};
|
||||
}
|
||||
options.select2.ajax.url = source;
|
||||
} else {
|
||||
@@ -126,16 +134,8 @@ $(function(){
|
||||
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
||||
this.isRemote = ('ajax' in this.options.select2);
|
||||
|
||||
//store function returning ID of item
|
||||
//should be here as used inautotext for local source
|
||||
this.idFunc = this.options.select2.id;
|
||||
if (typeof(this.idFunc) !== "function") {
|
||||
var idKey = this.idFunc || 'id';
|
||||
this.idFunc = function (e) { return e[idKey]; };
|
||||
}
|
||||
|
||||
//store function that renders text in select2
|
||||
this.formatSelection = this.options.select2.formatSelection;
|
||||
this.formatSelection = this.options.select2.templateSelection;
|
||||
if (typeof(this.formatSelection) !== "function") {
|
||||
this.formatSelection = function (e) { return e.text; };
|
||||
}
|
||||
@@ -147,18 +147,6 @@ $(function(){
|
||||
render: function() {
|
||||
this.setClass();
|
||||
|
||||
//can not apply select2 here as it calls initSelection
|
||||
//over input that does not have correct value yet.
|
||||
//apply select2 only in value2input
|
||||
//this.$input.select2(this.options.select2);
|
||||
|
||||
//when data is loaded via ajax, we need to know when it's done to populate listData
|
||||
if(this.isRemote) {
|
||||
//listen to loaded event to populate data
|
||||
this.$input.on('select2-loaded', $.proxy(function(e) {
|
||||
this.sourceData = e.items.results;
|
||||
}, this));
|
||||
}
|
||||
|
||||
//trigger resize of editableform to re-position container in multi-valued mode
|
||||
if(this.isMultiple) {
|
||||
@@ -168,15 +156,33 @@ $(function(){
|
||||
}
|
||||
},
|
||||
|
||||
autosubmit: function() {
|
||||
var self = this;
|
||||
var submitting = false;
|
||||
|
||||
// Use Select2 v4.x events for autosubmit - avoid double submissions
|
||||
this.$input.on('select2:select select2:unselect', $.proxy(function(e){
|
||||
if (!submitting) {
|
||||
submitting = true;
|
||||
setTimeout(function() {
|
||||
$(self.$input).closest('form').submit();
|
||||
submitting = false;
|
||||
}, 100);
|
||||
}
|
||||
}, this));
|
||||
},
|
||||
|
||||
value2html: function(value, element) {
|
||||
var text = '', data,
|
||||
that = this;
|
||||
|
||||
if(this.options.select2.tags) { //in tags mode just assign value
|
||||
// Use stored selected data if available (for visual display after selection)
|
||||
if(this.selectedData && this.selectedData.length > 0) {
|
||||
data = this.selectedData;
|
||||
} else if(this.options.select2.tags) { //in tags mode just assign value
|
||||
data = value;
|
||||
//data = $.fn.editableutils.itemsByValue(value, this.options.select2.tags, this.idFunc);
|
||||
} else if(this.sourceData) {
|
||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, this.idFunc);
|
||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, function(e) { return e.id; });
|
||||
} else {
|
||||
//can not get list of possible values
|
||||
//(e.g. autotext for select2 with ajax source)
|
||||
@@ -195,7 +201,6 @@ $(function(){
|
||||
|
||||
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
||||
|
||||
//$(element).text(text);
|
||||
Constructor.superclass.value2html.call(this, text, element);
|
||||
},
|
||||
|
||||
@@ -204,45 +209,90 @@ $(function(){
|
||||
},
|
||||
|
||||
value2input: function(value) {
|
||||
|
||||
// if value array => join it anyway
|
||||
if(Array.isArray(value)) {
|
||||
value = value.join(this.getSeparator());
|
||||
}
|
||||
|
||||
//for remote source just set value, text is updated by initSelection
|
||||
// For remote sources with existing value, create option element before Select2 init
|
||||
if(this.isRemote && !this.isMultiple && value) {
|
||||
var $el = $(this.options.scope);
|
||||
if (!$el.data('editable').isEmpty) {
|
||||
var text = $el.text();
|
||||
var $option = new Option(text, value, true, true);
|
||||
this.$input.append($option);
|
||||
}
|
||||
}
|
||||
|
||||
//initialize select2 if not already done
|
||||
if(!this.$input.data('select2')) {
|
||||
this.$input.val(value);
|
||||
this.$input.select2(this.options.select2);
|
||||
} else {
|
||||
//second argument needed to separate initial change from user's click (for autosubmit)
|
||||
this.$input.val(value).trigger('change', true);
|
||||
|
||||
//Uncaught Error: cannot call val() if initSelection() is not defined
|
||||
//this.$input.select2('val', value);
|
||||
}
|
||||
// Set up minimal event handling AFTER initialization
|
||||
this.$input.on('select2:select', $.proxy(function(e) {
|
||||
|
||||
// if defined remote source AND no multiple mode AND no user's initSelection provided -->
|
||||
// we should somehow get text for provided id.
|
||||
// The solution is to use element's text as text for that id (exclude empty)
|
||||
if(this.isRemote && !this.isMultiple && !this.options.select2.initSelection) {
|
||||
// customId and customText are methods to extract `id` and `text` from data object
|
||||
// we can use this workaround only if user did not define these methods
|
||||
// otherwise we cant construct data object
|
||||
var customId = this.options.select2.id,
|
||||
customText = this.options.select2.formatSelection;
|
||||
if (e.params && e.params.data) {
|
||||
var selectedData = e.params.data;
|
||||
this.selectedData = [selectedData];
|
||||
|
||||
if(!customId && !customText) {
|
||||
var $el = $(this.options.scope);
|
||||
if (!$el.data('editable').isEmpty) {
|
||||
var data = {id: value, text: $el.text()};
|
||||
this.$input.select2('data', data);
|
||||
// Fix Select2's visual display by ensuring the option exists and is selected
|
||||
var $existingOption = this.$input.find('option[value="' + selectedData.id + '"]');
|
||||
if ($existingOption.length === 0) {
|
||||
// Create the option if it doesn't exist
|
||||
var $option = $('<option></option>')
|
||||
.attr('value', selectedData.id)
|
||||
.text(selectedData.text)
|
||||
.prop('selected', true);
|
||||
this.$input.append($option);
|
||||
} else {
|
||||
// Make sure existing option is selected
|
||||
$existingOption.prop('selected', true);
|
||||
}
|
||||
|
||||
// Force Select2 to update its display
|
||||
this.$input.trigger('change.select2');
|
||||
|
||||
// Mark that a selection was just made (for blur handling)
|
||||
this._justSelected = true;
|
||||
}
|
||||
}
|
||||
}, this));
|
||||
|
||||
this.$input.on('select2:unselect', $.proxy(function(e) {
|
||||
this.selectedData = [];
|
||||
}, this));
|
||||
|
||||
// Ensure Select2 doesn't interfere with x-editable's document click handling
|
||||
// by making sure clicks on Select2 elements don't stop propagation
|
||||
this.$input.on('select2:open', $.proxy(function(e) {
|
||||
// Find the Select2 dropdown container and ensure it allows document clicks to propagate
|
||||
setTimeout(function() {
|
||||
$('.select2-container--open .select2-dropdown').off('click.editable-prevent-close');
|
||||
$('.select2-container--open .select2-results').off('click.editable-prevent-close');
|
||||
}, 10);
|
||||
}, this));
|
||||
|
||||
|
||||
|
||||
} else {
|
||||
//update value on existing select2
|
||||
this.$input.val(value).trigger('change.select2');
|
||||
}
|
||||
},
|
||||
|
||||
input2value: function() {
|
||||
return this.$input.select2('val');
|
||||
var val = this.$input.val();
|
||||
|
||||
// For Select2 v4.x, ensure we get the actual selected value
|
||||
if (this.$input.data('select2')) {
|
||||
var selectedData = this.$input.select2('data');
|
||||
if (selectedData && selectedData.length > 0) {
|
||||
val = this.isMultiple ? selectedData.map(function(item) { return item.id; }) : selectedData[0].id;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
},
|
||||
|
||||
str2value: function(str, separator) {
|
||||
@@ -265,16 +315,10 @@ $(function(){
|
||||
return val;
|
||||
},
|
||||
|
||||
autosubmit: function() {
|
||||
this.$input.on('change', function(e, isInitial){
|
||||
if(!isInitial) {
|
||||
$(this).closest('form').submit();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getSeparator: function() {
|
||||
return this.options.select2.separator || $.fn.select2.defaults.separator;
|
||||
// Select2 v4.x uses different separator handling
|
||||
return this.options.select2.separator || ',';
|
||||
},
|
||||
|
||||
/*
|
||||
@@ -310,7 +354,7 @@ $(function(){
|
||||
**/
|
||||
tpl:'<input type="hidden">',
|
||||
/**
|
||||
Configuration of select2. [Full list of options](http://ivaynberg.github.com/select2).
|
||||
Configuration of select2. [Full list of options](https://select2.org/configuration).
|
||||
|
||||
@property select2
|
||||
@type object
|
||||
|
Reference in New Issue
Block a user