Compare commits
3 Commits
master
...
ab45b130b1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab45b130b1 | ||
|
|
3eacb7c438 | ||
|
|
f4dc8a3dd0 |
31
.idea/cake_config_setting_v0_6.xml
generated
Executable file
31
.idea/cake_config_setting_v0_6.xml
generated
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CakeStormCakeSettings">
|
||||||
|
<option name="cakeVersionAbsorption">
|
||||||
|
<map>
|
||||||
|
<entry key="Controller" value="/controllers/" />
|
||||||
|
<entry key="View" value="/views/" />
|
||||||
|
<entry key="Model" value="/models/" />
|
||||||
|
<entry key="Helper" value="/views/helpers/" />
|
||||||
|
<entry key="Component" value="/controllers/components/" />
|
||||||
|
<entry key="Behavior" value="/models/behaviors/" />
|
||||||
|
<entry key="Plugin" value="plugins/" />
|
||||||
|
<entry key="Shell" value="/vendors/shell" />
|
||||||
|
<entry key="Task" value="/vendors/Shell/Task" />
|
||||||
|
<entry key="ControllerTest" value="/tests/cases/controllers/" />
|
||||||
|
<entry key="ModelTest" value="/tests/cases/models/" />
|
||||||
|
<entry key="BehaviorTest" value="/tests/cases/behaviors/" />
|
||||||
|
<entry key="ComponentTest" value="/tests/cases/components/" />
|
||||||
|
<entry key="HelperTest" value="/tests/cases/helpers/" />
|
||||||
|
<entry key="TestFile" value="test" />
|
||||||
|
<entry key="FileSeparator" value="." />
|
||||||
|
<entry key="FileWordSeparator" value="_" />
|
||||||
|
<entry key="Fixture" value="/tests/fixtures/" />
|
||||||
|
<entry key="Element" value="elements/" />
|
||||||
|
<entry key="FixtureFile" value="fixture" />
|
||||||
|
<entry key="Layout" value="layouts/" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
<option name="cakeVersion" value="1" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
2
.idea/modules.xml
generated
2
.idea/modules.xml
generated
@@ -2,7 +2,7 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/x-editable-bs5.iml" filepath="$PROJECT_DIR$/.idea/x-editable-bs5.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/x-editable.iml" filepath="$PROJECT_DIR$/.idea/x-editable.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
2
.idea/vcs.xml
generated
2
.idea/vcs.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
<mapping directory="" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -53,7 +53,7 @@ function getFiles() {
|
|||||||
form: [forms+'editable-form-bootstrap5.js'],
|
form: [forms+'editable-form-bootstrap5.js'],
|
||||||
container: [containers+'editable-popover5.js'],
|
container: [containers+'editable-popover5.js'],
|
||||||
inputs: [
|
inputs: [
|
||||||
inputs+'date/bootstrap-datepicker/js/bootstrap-datepicker.js',
|
// Bootstrap-datepicker now loaded from npm, not bundled
|
||||||
inputs+'date/date.js',
|
inputs+'date/date.js',
|
||||||
inputs+'date/datefield.js',
|
inputs+'date/datefield.js',
|
||||||
inputs+'datetime/datetime.js',
|
inputs+'datetime/datetime.js',
|
||||||
@@ -64,7 +64,7 @@ function getFiles() {
|
|||||||
//inputs+'typeahead.js'
|
//inputs+'typeahead.js'
|
||||||
],
|
],
|
||||||
css: [
|
css: [
|
||||||
inputs+'date/bootstrap-datepicker/css/datepicker.css'
|
// Bootstrap-datepicker CSS now loaded from npm, not bundled
|
||||||
//don't build datetime lib, should be included manually
|
//don't build datetime lib, should be included manually
|
||||||
//inputs+'datetime/bootstrap-datetimepicker/css/datetimepicker.css'
|
//inputs+'datetime/bootstrap-datetimepicker/css/datetimepicker.css'
|
||||||
]
|
]
|
||||||
@@ -268,8 +268,7 @@ module.exports = function(grunt) {
|
|||||||
evil: false,
|
evil: false,
|
||||||
globals: {
|
globals: {
|
||||||
jQuery: true,
|
jQuery: true,
|
||||||
console: true,
|
console: true
|
||||||
bootstrap: true
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
js: [ 'Gruntfile.js',
|
js: [ 'Gruntfile.js',
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
# 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: ...`
|
|
||||||
2
dist/app.js
vendored
2
dist/app.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
|||||||
/*! X-editable-bootstrap5 - v1.5.7
|
/*! X-editable - v1.5.2
|
||||||
* A fork of x-editable for Bootstrap 5 support.
|
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||||
* https://git.24unix.net/tracer/x-editable
|
* https://git.24unix.net/tracer/x-editable
|
||||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||||
.editableform {
|
.editableform {
|
||||||
@@ -156,6 +156,20 @@
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Position datepicker above input for datepicker-above class */
|
||||||
|
.datepicker-above .datepicker-inline {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||||
|
}
|
||||||
|
|
||||||
.editable-container.editable-popup {
|
.editable-container.editable-popup {
|
||||||
max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
|
max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
|
||||||
}
|
}
|
||||||
|
|||||||
425
dist/bootstrap-editable/js/bootstrap-editable.js
vendored
425
dist/bootstrap-editable/js/bootstrap-editable.js
vendored
@@ -1,5 +1,5 @@
|
|||||||
/*! X-editable-bootstrap5 - v1.5.7
|
/*! X-editable - v1.5.2
|
||||||
* A fork of x-editable for Bootstrap 5 support.
|
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||||
* https://git.24unix.net/tracer/x-editable
|
* https://git.24unix.net/tracer/x-editable
|
||||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||||
/**
|
/**
|
||||||
@@ -1505,6 +1505,9 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the editable's type from the input's type
|
||||||
|
this.type = this.input.type;
|
||||||
|
|
||||||
//set value from settings or by element's text
|
//set value from settings or by element's text
|
||||||
if (this.options.value === undefined || this.options.value === null) {
|
if (this.options.value === undefined || this.options.value === null) {
|
||||||
this.value = this.input.html2value(this.$element.html().trim());
|
this.value = this.input.html2value(this.$element.html().trim());
|
||||||
@@ -1540,15 +1543,16 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
//stop propagation to prevent interference with other click handlers
|
//stop propagation not required because in document click handler it checks event target
|
||||||
e.stopPropagation();
|
//e.stopPropagation();
|
||||||
|
|
||||||
if(this.options.toggle === 'mouseenter') {
|
if(this.options.toggle === 'mouseenter') {
|
||||||
//for hover only show container
|
//for hover only show container
|
||||||
this.show();
|
this.show();
|
||||||
} else {
|
} else {
|
||||||
//always close other containers when opening a new one
|
//when toggle='click' we should not close all other containers as they will be closed automatically in document click listener
|
||||||
this.toggle(true);
|
var closeAll = (this.options.toggle !== 'click');
|
||||||
|
this.toggle(closeAll);
|
||||||
}
|
}
|
||||||
}, this));
|
}, this));
|
||||||
} else {
|
} else {
|
||||||
@@ -3600,20 +3604,23 @@ Time
|
|||||||
}(window.jQuery));
|
}(window.jQuery));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/select2/select2.
|
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
|
||||||
Please see [Select2 docs](https://select2.org/) for detailed description and options.
|
Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options.
|
||||||
|
|
||||||
You should manually download and include Select2 v4.x distributive:
|
You should manually download and include select2 distributive:
|
||||||
|
|
||||||
<link href="node_modules/select2/dist/css/select2.css" rel="stylesheet" type="text/css"></link>
|
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link>
|
||||||
<script src="node_modules/select2/dist/js/select2.js"></script>
|
<script src="select2/select2.js"></script>
|
||||||
|
|
||||||
To make it **bootstrap-styled** you can use css from [select2-bootstrap-5-theme](https://github.com/apalfrey/select2-bootstrap-5-theme):
|
To make it **bootstrap-styled** you can use css from [here](https://github.com/t0m/select2-bootstrap-css):
|
||||||
|
|
||||||
<link href="select2-bootstrap-5-theme.css" rel="stylesheet" type="text/css"></link>
|
<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>
|
||||||
|
|
||||||
**Note:** This version requires Select2 v4.x. For remote sources, you may need to provide custom
|
|
||||||
`templateResult` and `templateSelection` functions.
|
|
||||||
|
|
||||||
@class select2
|
@class select2
|
||||||
@extends abstractinput
|
@extends abstractinput
|
||||||
@@ -3642,39 +3649,35 @@ $(function(){
|
|||||||
minimumInputLength: 1
|
minimumInputLength: 1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//remote source (advanced) - Select2 v4.x format
|
//remote source (advanced)
|
||||||
$('#country').editable({
|
$('#country').editable({
|
||||||
select2: {
|
select2: {
|
||||||
placeholder: 'Select Country',
|
placeholder: 'Select Country',
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
minimumInputLength: 3,
|
minimumInputLength: 3,
|
||||||
|
id: function (item) {
|
||||||
|
return item.CountryId;
|
||||||
|
},
|
||||||
ajax: {
|
ajax: {
|
||||||
url: '/getCountries',
|
url: '/getCountries',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
delay: 250,
|
data: function (term, page) {
|
||||||
data: function (params) {
|
return { query: term };
|
||||||
return {
|
|
||||||
query: params.term,
|
|
||||||
page: params.page
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
processResults: function (data, params) {
|
results: function (data, page) {
|
||||||
return {
|
return { results: data };
|
||||||
results: data.map(function(item) {
|
}
|
||||||
return {
|
|
||||||
id: item.CountryId,
|
|
||||||
text: item.CountryName
|
|
||||||
};
|
|
||||||
})
|
|
||||||
};
|
|
||||||
},
|
|
||||||
cache: true
|
|
||||||
},
|
},
|
||||||
templateResult: function (item) {
|
formatResult: function (item) {
|
||||||
return item.text || item.CountryName;
|
return item.CountryName;
|
||||||
},
|
},
|
||||||
templateSelection: function (item) {
|
formatSelection: function (item) {
|
||||||
return item.text || item.CountryName;
|
return item.CountryName;
|
||||||
|
},
|
||||||
|
initSelection: function (element, callback) {
|
||||||
|
return $.get('/getCountryById', { query: element.val() }, function (data) {
|
||||||
|
callback(data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -3706,19 +3709,12 @@ $(function(){
|
|||||||
|
|
||||||
if (typeof source === 'string') {
|
if (typeof source === 'string') {
|
||||||
options.select2.ajax = options.select2.ajax || {};
|
options.select2.ajax = options.select2.ajax || {};
|
||||||
//default ajax params for Select2 v4.x
|
//some default ajax params
|
||||||
if(!options.select2.ajax.data) {
|
if(!options.select2.ajax.data) {
|
||||||
options.select2.ajax.data = function(params) {
|
options.select2.ajax.data = function(term) {return { query:term };};
|
||||||
return {
|
|
||||||
query: params.term,
|
|
||||||
page: params.page
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if(!options.select2.ajax.processResults) {
|
if(!options.select2.ajax.results) {
|
||||||
options.select2.ajax.processResults = function(data) {
|
options.select2.ajax.results = function(data) { return {results:data };};
|
||||||
return {results: data };
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
options.select2.ajax.url = source;
|
options.select2.ajax.url = source;
|
||||||
} else {
|
} else {
|
||||||
@@ -3735,8 +3731,16 @@ $(function(){
|
|||||||
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
||||||
this.isRemote = ('ajax' in this.options.select2);
|
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
|
//store function that renders text in select2
|
||||||
this.formatSelection = this.options.select2.templateSelection;
|
this.formatSelection = this.options.select2.formatSelection;
|
||||||
if (typeof(this.formatSelection) !== "function") {
|
if (typeof(this.formatSelection) !== "function") {
|
||||||
this.formatSelection = function (e) { return e.text; };
|
this.formatSelection = function (e) { return e.text; };
|
||||||
}
|
}
|
||||||
@@ -3748,6 +3752,18 @@ $(function(){
|
|||||||
render: function() {
|
render: function() {
|
||||||
this.setClass();
|
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
|
//trigger resize of editableform to re-position container in multi-valued mode
|
||||||
if(this.isMultiple) {
|
if(this.isMultiple) {
|
||||||
@@ -3757,33 +3773,15 @@ $(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) {
|
value2html: function(value, element) {
|
||||||
var text = '', data,
|
var text = '', data,
|
||||||
that = this;
|
that = this;
|
||||||
|
|
||||||
// Use stored selected data if available (for visual display after selection)
|
if(this.options.select2.tags) { //in tags mode just assign value
|
||||||
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 = value;
|
||||||
|
//data = $.fn.editableutils.itemsByValue(value, this.options.select2.tags, this.idFunc);
|
||||||
} else if(this.sourceData) {
|
} else if(this.sourceData) {
|
||||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, function(e) { return e.id; });
|
data = $.fn.editableutils.itemsByValue(value, this.sourceData, this.idFunc);
|
||||||
} else {
|
} else {
|
||||||
//can not get list of possible values
|
//can not get list of possible values
|
||||||
//(e.g. autotext for select2 with ajax source)
|
//(e.g. autotext for select2 with ajax source)
|
||||||
@@ -3802,6 +3800,7 @@ $(function(){
|
|||||||
|
|
||||||
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
||||||
|
|
||||||
|
//$(element).text(text);
|
||||||
Constructor.superclass.value2html.call(this, text, element);
|
Constructor.superclass.value2html.call(this, text, element);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -3810,97 +3809,46 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
value2input: function(value) {
|
value2input: function(value) {
|
||||||
|
|
||||||
// if value array => join it anyway
|
// if value array => join it anyway
|
||||||
if(Array.isArray(value)) {
|
if(Array.isArray(value)) {
|
||||||
value = value.join(this.getSeparator());
|
value = value.join(this.getSeparator());
|
||||||
}
|
}
|
||||||
|
|
||||||
// For remote sources with existing value, create option element before Select2 init
|
//for remote source just set value, text is updated by initSelection
|
||||||
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')) {
|
if(!this.$input.data('select2')) {
|
||||||
this.$input.val(value);
|
this.$input.val(value);
|
||||||
this.$input.select2(this.options.select2);
|
this.$input.select2(this.options.select2);
|
||||||
|
|
||||||
// Set up minimal event handling AFTER initialization
|
|
||||||
this.$input.on('select2:select', $.proxy(function(e) {
|
|
||||||
|
|
||||||
if (e.params && e.params.data) {
|
|
||||||
var selectedData = e.params.data;
|
|
||||||
this.selectedData = [selectedData];
|
|
||||||
|
|
||||||
// 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 {
|
} else {
|
||||||
//update value on existing select2
|
//second argument needed to separate initial change from user's click (for autosubmit)
|
||||||
this.$input.val(value).trigger('change.select2');
|
this.$input.val(value).trigger('change', true);
|
||||||
|
|
||||||
|
//Uncaught Error: cannot call val() if initSelection() is not defined
|
||||||
|
//this.$input.select2('val', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(!customId && !customText) {
|
||||||
|
var $el = $(this.options.scope);
|
||||||
|
if (!$el.data('editable').isEmpty) {
|
||||||
|
var data = {id: value, text: $el.text()};
|
||||||
|
this.$input.select2('data', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
input2value: function() {
|
input2value: function() {
|
||||||
var val = this.$input.val();
|
return this.$input.select2('val');
|
||||||
|
},
|
||||||
// --- Handle Bootstrap Datepicker ---
|
|
||||||
var dp = this.$input.data('datepicker');
|
|
||||||
if (dp && typeof dp.getFormattedDate === 'function') {
|
|
||||||
val = dp.getFormattedDate(this.options.format || 'yyyy-mm-dd');
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Handle Select2 v4.x ---
|
|
||||||
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) {
|
str2value: function(str, separator) {
|
||||||
if(typeof str !== 'string' || !this.isMultiple) {
|
if(typeof str !== 'string' || !this.isMultiple) {
|
||||||
@@ -3922,10 +3870,16 @@ $(function(){
|
|||||||
return val;
|
return val;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
autosubmit: function() {
|
||||||
|
this.$input.on('change', function(e, isInitial){
|
||||||
|
if(!isInitial) {
|
||||||
|
$(this).closest('form').submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
getSeparator: function() {
|
getSeparator: function() {
|
||||||
// Select2 v4.x uses different separator handling
|
return this.options.select2.separator || $.fn.select2.defaults.separator;
|
||||||
return this.options.select2.separator || ',';
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3961,7 +3915,7 @@ $(function(){
|
|||||||
**/
|
**/
|
||||||
tpl:'<input type="hidden">',
|
tpl:'<input type="hidden">',
|
||||||
/**
|
/**
|
||||||
Configuration of select2. [Full list of options](https://select2.org/configuration).
|
Configuration of select2. [Full list of options](http://ivaynberg.github.com/select2).
|
||||||
|
|
||||||
@property select2
|
@property select2
|
||||||
@type object
|
@type object
|
||||||
@@ -3999,6 +3953,7 @@ $(function(){
|
|||||||
$.fn.editabletypes.select2 = Constructor;
|
$.fn.editabletypes.select2 = Constructor;
|
||||||
|
|
||||||
}(window.jQuery));
|
}(window.jQuery));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combodate - 1.0.5
|
* Combodate - 1.0.5
|
||||||
* Dropdown date and time picker.
|
* Dropdown date and time picker.
|
||||||
@@ -4935,27 +4890,29 @@ $(function(){
|
|||||||
(function ($) {
|
(function ($) {
|
||||||
"use strict";
|
"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) {
|
var Date = function (options) {
|
||||||
this.init('date', options, Date.defaults);
|
this.init('date', options, Date.defaults);
|
||||||
this.initPicker(options, Date.defaults);
|
this.initPicker(options, Date.defaults);
|
||||||
|
|
||||||
|
// Ensure type is set correctly
|
||||||
|
this.type = 'date';
|
||||||
};
|
};
|
||||||
|
|
||||||
$.fn.editableutils.inherit(Date, $.fn.editabletypes.abstractinput);
|
$.fn.editableutils.inherit(Date, $.fn.editabletypes.abstractinput);
|
||||||
|
|
||||||
$.extend(Date.prototype, {
|
$.extend(Date.prototype, {
|
||||||
initPicker: function(options, defaults) {
|
prerender: function() {
|
||||||
// Initialize bootstrap-datepicker reference
|
// Call parent prerender
|
||||||
if (!$.fn.bdatepicker) {
|
Date.superclass.prerender.call(this);
|
||||||
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.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
initPicker: function(options, defaults) {
|
||||||
//'format' is set directly from settings or data-* attributes
|
//'format' is set directly from settings or data-* attributes
|
||||||
|
|
||||||
//by default viewformat equals to format
|
//by default viewformat equals to format
|
||||||
@@ -4975,8 +4932,8 @@ $(function(){
|
|||||||
//language
|
//language
|
||||||
this.options.datepicker.language = this.options.datepicker.language || 'en';
|
this.options.datepicker.language = this.options.datepicker.language || 'en';
|
||||||
|
|
||||||
//store DPglobal
|
//store DPglobal - use datepicker instead of bdatepicker
|
||||||
this.dpg = $.fn.bdatepicker.DPGlobal;
|
this.dpg = $.fn.datepicker.DPGlobal;
|
||||||
|
|
||||||
//store parsed formats
|
//store parsed formats
|
||||||
this.parsedFormat = this.dpg.parseFormat(this.options.format);
|
this.parsedFormat = this.dpg.parseFormat(this.options.format);
|
||||||
@@ -4984,7 +4941,22 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
render: function () {
|
render: function () {
|
||||||
this.$input.bdatepicker(this.options.datepicker);
|
// Ensure we have an input element
|
||||||
|
if (!this.$input || !this.$input.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize datepicker immediately
|
||||||
|
try {
|
||||||
|
this.$input.datepicker(this.options.datepicker);
|
||||||
|
|
||||||
|
// Force set the initial value if we have one
|
||||||
|
if (this.value) {
|
||||||
|
this.$input.datepicker('setDate', this.value);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Silently handle datepicker initialization errors
|
||||||
|
}
|
||||||
|
|
||||||
//"clear" link
|
//"clear" link
|
||||||
if(this.options.clear) {
|
if(this.options.clear) {
|
||||||
@@ -4999,20 +4971,8 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
value2html: function(value, element) {
|
value2html: function(value, element) {
|
||||||
let text = '';
|
var text = value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '';
|
||||||
|
Date.superclass.value2html.call(this, text, element);
|
||||||
if (value) {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
text = value;
|
|
||||||
} else if (value instanceof Date && typeof value.getUTCDate === 'function') {
|
|
||||||
text = this.dpg.formatDate(value, this.parsedFormat, this.options.datepicker.language);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// direct fallback: set text without using editableutils
|
|
||||||
if (element) {
|
|
||||||
element.textContent = text;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
html2value: function(html) {
|
html2value: function(html) {
|
||||||
@@ -5020,17 +4980,7 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
value2str: function(value) {
|
value2str: function(value) {
|
||||||
if (!value) {
|
return value ? this.dpg.formatDate(value, this.parsedFormat, this.options.datepicker.language) : '';
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// If value is already a string (like "2025-11-27"), just return it.
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, assume it's a Date object and format it.
|
|
||||||
return this.dpg.formatDate(value, this.parsedFormat, this.options.datepicker.language);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
str2value: function(str) {
|
str2value: function(str) {
|
||||||
@@ -5042,15 +4992,42 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
value2input: function(value) {
|
value2input: function(value) {
|
||||||
this.$input.bdatepicker('update', value);
|
// Ensure datepicker is initialized before trying to update
|
||||||
|
if (!this.$input.data('datepicker')) {
|
||||||
|
this.$input.datepicker(this.options.datepicker);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$input.datepicker('update', value);
|
||||||
},
|
},
|
||||||
|
|
||||||
input2value: function() {
|
input2value: function() {
|
||||||
const dp = this.$input.data('datepicker');
|
var datepicker = this.$input.data('datepicker');
|
||||||
if (dp && typeof dp.getFormattedDate === 'function') {
|
|
||||||
return dp.getFormattedDate(this.options.format || 'yyyy-mm-dd');
|
if (datepicker) {
|
||||||
|
if (datepicker.date) {
|
||||||
|
return datepicker.date;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try getting date from dates array
|
||||||
|
if (datepicker.dates && datepicker.dates.length > 0) {
|
||||||
|
return datepicker.dates[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try using getDate method
|
||||||
|
if (typeof datepicker.getDate === 'function') {
|
||||||
|
var dateFromMethod = datepicker.getDate();
|
||||||
|
return dateFromMethod;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this.$input.val();
|
|
||||||
|
// Fallback: try to parse the input value directly
|
||||||
|
var inputVal = this.$input.val();
|
||||||
|
if (inputVal) {
|
||||||
|
var parsedDate = this.parseDate(inputVal, this.parsedViewFormat);
|
||||||
|
return parsedDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
activate: function() {
|
activate: function() {
|
||||||
@@ -5185,6 +5162,9 @@ Automatically shown in inline mode.
|
|||||||
var DateField = function (options) {
|
var DateField = function (options) {
|
||||||
this.init('datefield', options, DateField.defaults);
|
this.init('datefield', options, DateField.defaults);
|
||||||
this.initPicker(options, DateField.defaults);
|
this.initPicker(options, DateField.defaults);
|
||||||
|
|
||||||
|
// Ensure type is set correctly
|
||||||
|
this.type = 'datefield';
|
||||||
};
|
};
|
||||||
|
|
||||||
$.fn.editableutils.inherit(DateField, $.fn.editabletypes.date);
|
$.fn.editableutils.inherit(DateField, $.fn.editabletypes.date);
|
||||||
@@ -5195,8 +5175,8 @@ Automatically shown in inline mode.
|
|||||||
this.setClass();
|
this.setClass();
|
||||||
this.setAttr('placeholder');
|
this.setAttr('placeholder');
|
||||||
|
|
||||||
//bootstrap-datepicker is set `bdateicker` to exclude conflict with jQuery UI one. (in date.js)
|
//use datepicker instead of bdatepicker
|
||||||
this.$tpl.bdatepicker(this.options.datepicker);
|
this.$tpl.datepicker(this.options.datepicker);
|
||||||
|
|
||||||
//need to disable original event handlers
|
//need to disable original event handlers
|
||||||
this.$input.off('focus keydown');
|
this.$input.off('focus keydown');
|
||||||
@@ -5204,17 +5184,48 @@ Automatically shown in inline mode.
|
|||||||
//update value of datepicker
|
//update value of datepicker
|
||||||
this.$input.keyup($.proxy(function(){
|
this.$input.keyup($.proxy(function(){
|
||||||
this.$tpl.removeData('date');
|
this.$tpl.removeData('date');
|
||||||
this.$tpl.bdatepicker('update');
|
this.$tpl.datepicker('update');
|
||||||
}, this));
|
}, this));
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
value2input: function(value) {
|
value2input: function(value) {
|
||||||
this.$input.val(value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '');
|
var formattedValue = value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '';
|
||||||
this.$tpl.bdatepicker('update');
|
this.$input.val(formattedValue);
|
||||||
|
this.$tpl.datepicker('update');
|
||||||
},
|
},
|
||||||
|
|
||||||
input2value: function() {
|
input2value: function() {
|
||||||
|
// First try the container datepicker (ideal case)
|
||||||
|
var containerDatepicker = this.$tpl.data('datepicker');
|
||||||
|
|
||||||
|
if (containerDatepicker && containerDatepicker.dates && containerDatepicker.dates.length > 0) {
|
||||||
|
return containerDatepicker.dates[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: try the input datepicker (in case manual init worked)
|
||||||
|
var inputDatepicker = this.$input.data('datepicker');
|
||||||
|
|
||||||
|
if (inputDatepicker && inputDatepicker.dates && inputDatepicker.dates.length > 0) {
|
||||||
|
return inputDatepicker.dates[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try getDate methods
|
||||||
|
if (containerDatepicker && typeof containerDatepicker.getDate === 'function') {
|
||||||
|
var containerDate = containerDatepicker.getDate();
|
||||||
|
if (containerDate) {
|
||||||
|
return containerDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputDatepicker && typeof inputDatepicker.getDate === 'function') {
|
||||||
|
var inputDate = inputDatepicker.getDate();
|
||||||
|
if (inputDate) {
|
||||||
|
return inputDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final fallback to text parsing
|
||||||
return this.html2value(this.$input.val());
|
return this.html2value(this.$input.val());
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -5231,19 +5242,21 @@ Automatically shown in inline mode.
|
|||||||
/**
|
/**
|
||||||
@property tpl
|
@property tpl
|
||||||
**/
|
**/
|
||||||
tpl:'<div class="input-append date"><input type="text"/><span class="add-on"><i class="icon-th"></i></span></div>',
|
tpl:'<div class="input-group input-group-sm date datepicker-above" style="width: 200px; border: 1px solid #dee2e6; border-radius: 0.375rem; position: relative;"><input type="text" class="form-control form-control-sm" style="border: none;"/><span class="input-group-text" style="border: none; background: transparent;"><i class="bi bi-calendar"></i></span></div>',
|
||||||
/**
|
/**
|
||||||
@property inputclass
|
@property inputclass
|
||||||
@default 'input-small'
|
@default 'form-control form-control-sm'
|
||||||
**/
|
**/
|
||||||
inputclass: 'input-small',
|
inputclass: 'form-control form-control-sm',
|
||||||
|
|
||||||
/* datepicker config */
|
/* datepicker config */
|
||||||
datepicker: {
|
datepicker: {
|
||||||
weekStart: 0,
|
weekStart: 0,
|
||||||
startView: 0,
|
startView: 0,
|
||||||
minViewMode: 0,
|
minViewMode: 0,
|
||||||
autoclose: true
|
autoclose: true,
|
||||||
|
orientation: 'top',
|
||||||
|
container: 'body'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
|||||||
/*! X-editable-bootstrap5 - v1.5.7
|
/*! X-editable - v1.5.2
|
||||||
* A fork of x-editable for Bootstrap 5 support.
|
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||||
* https://git.24unix.net/tracer/x-editable
|
* https://git.24unix.net/tracer/x-editable
|
||||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||||
.editableform {
|
.editableform {
|
||||||
@@ -156,6 +156,20 @@
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Position datepicker above input for datepicker-above class */
|
||||||
|
.datepicker-above .datepicker-inline {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||||
|
}
|
||||||
|
|
||||||
.editable-container.editable-popup {
|
.editable-container.editable-popup {
|
||||||
max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
|
max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
|
||||||
}
|
}
|
||||||
|
|||||||
425
dist/bootstrap3-editable/js/bootstrap-editable.js
vendored
425
dist/bootstrap3-editable/js/bootstrap-editable.js
vendored
@@ -1,5 +1,5 @@
|
|||||||
/*! X-editable-bootstrap5 - v1.5.7
|
/*! X-editable - v1.5.2
|
||||||
* A fork of x-editable for Bootstrap 5 support.
|
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||||
* https://git.24unix.net/tracer/x-editable
|
* https://git.24unix.net/tracer/x-editable
|
||||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||||
/**
|
/**
|
||||||
@@ -1505,6 +1505,9 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the editable's type from the input's type
|
||||||
|
this.type = this.input.type;
|
||||||
|
|
||||||
//set value from settings or by element's text
|
//set value from settings or by element's text
|
||||||
if (this.options.value === undefined || this.options.value === null) {
|
if (this.options.value === undefined || this.options.value === null) {
|
||||||
this.value = this.input.html2value(this.$element.html().trim());
|
this.value = this.input.html2value(this.$element.html().trim());
|
||||||
@@ -1540,15 +1543,16 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
//stop propagation to prevent interference with other click handlers
|
//stop propagation not required because in document click handler it checks event target
|
||||||
e.stopPropagation();
|
//e.stopPropagation();
|
||||||
|
|
||||||
if(this.options.toggle === 'mouseenter') {
|
if(this.options.toggle === 'mouseenter') {
|
||||||
//for hover only show container
|
//for hover only show container
|
||||||
this.show();
|
this.show();
|
||||||
} else {
|
} else {
|
||||||
//always close other containers when opening a new one
|
//when toggle='click' we should not close all other containers as they will be closed automatically in document click listener
|
||||||
this.toggle(true);
|
var closeAll = (this.options.toggle !== 'click');
|
||||||
|
this.toggle(closeAll);
|
||||||
}
|
}
|
||||||
}, this));
|
}, this));
|
||||||
} else {
|
} else {
|
||||||
@@ -3600,20 +3604,23 @@ Time
|
|||||||
}(window.jQuery));
|
}(window.jQuery));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/select2/select2.
|
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
|
||||||
Please see [Select2 docs](https://select2.org/) for detailed description and options.
|
Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options.
|
||||||
|
|
||||||
You should manually download and include Select2 v4.x distributive:
|
You should manually download and include select2 distributive:
|
||||||
|
|
||||||
<link href="node_modules/select2/dist/css/select2.css" rel="stylesheet" type="text/css"></link>
|
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link>
|
||||||
<script src="node_modules/select2/dist/js/select2.js"></script>
|
<script src="select2/select2.js"></script>
|
||||||
|
|
||||||
To make it **bootstrap-styled** you can use css from [select2-bootstrap-5-theme](https://github.com/apalfrey/select2-bootstrap-5-theme):
|
To make it **bootstrap-styled** you can use css from [here](https://github.com/t0m/select2-bootstrap-css):
|
||||||
|
|
||||||
<link href="select2-bootstrap-5-theme.css" rel="stylesheet" type="text/css"></link>
|
<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>
|
||||||
|
|
||||||
**Note:** This version requires Select2 v4.x. For remote sources, you may need to provide custom
|
|
||||||
`templateResult` and `templateSelection` functions.
|
|
||||||
|
|
||||||
@class select2
|
@class select2
|
||||||
@extends abstractinput
|
@extends abstractinput
|
||||||
@@ -3642,39 +3649,35 @@ $(function(){
|
|||||||
minimumInputLength: 1
|
minimumInputLength: 1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//remote source (advanced) - Select2 v4.x format
|
//remote source (advanced)
|
||||||
$('#country').editable({
|
$('#country').editable({
|
||||||
select2: {
|
select2: {
|
||||||
placeholder: 'Select Country',
|
placeholder: 'Select Country',
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
minimumInputLength: 3,
|
minimumInputLength: 3,
|
||||||
|
id: function (item) {
|
||||||
|
return item.CountryId;
|
||||||
|
},
|
||||||
ajax: {
|
ajax: {
|
||||||
url: '/getCountries',
|
url: '/getCountries',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
delay: 250,
|
data: function (term, page) {
|
||||||
data: function (params) {
|
return { query: term };
|
||||||
return {
|
|
||||||
query: params.term,
|
|
||||||
page: params.page
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
processResults: function (data, params) {
|
results: function (data, page) {
|
||||||
return {
|
return { results: data };
|
||||||
results: data.map(function(item) {
|
}
|
||||||
return {
|
|
||||||
id: item.CountryId,
|
|
||||||
text: item.CountryName
|
|
||||||
};
|
|
||||||
})
|
|
||||||
};
|
|
||||||
},
|
|
||||||
cache: true
|
|
||||||
},
|
},
|
||||||
templateResult: function (item) {
|
formatResult: function (item) {
|
||||||
return item.text || item.CountryName;
|
return item.CountryName;
|
||||||
},
|
},
|
||||||
templateSelection: function (item) {
|
formatSelection: function (item) {
|
||||||
return item.text || item.CountryName;
|
return item.CountryName;
|
||||||
|
},
|
||||||
|
initSelection: function (element, callback) {
|
||||||
|
return $.get('/getCountryById', { query: element.val() }, function (data) {
|
||||||
|
callback(data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -3706,19 +3709,12 @@ $(function(){
|
|||||||
|
|
||||||
if (typeof source === 'string') {
|
if (typeof source === 'string') {
|
||||||
options.select2.ajax = options.select2.ajax || {};
|
options.select2.ajax = options.select2.ajax || {};
|
||||||
//default ajax params for Select2 v4.x
|
//some default ajax params
|
||||||
if(!options.select2.ajax.data) {
|
if(!options.select2.ajax.data) {
|
||||||
options.select2.ajax.data = function(params) {
|
options.select2.ajax.data = function(term) {return { query:term };};
|
||||||
return {
|
|
||||||
query: params.term,
|
|
||||||
page: params.page
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if(!options.select2.ajax.processResults) {
|
if(!options.select2.ajax.results) {
|
||||||
options.select2.ajax.processResults = function(data) {
|
options.select2.ajax.results = function(data) { return {results:data };};
|
||||||
return {results: data };
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
options.select2.ajax.url = source;
|
options.select2.ajax.url = source;
|
||||||
} else {
|
} else {
|
||||||
@@ -3735,8 +3731,16 @@ $(function(){
|
|||||||
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
||||||
this.isRemote = ('ajax' in this.options.select2);
|
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
|
//store function that renders text in select2
|
||||||
this.formatSelection = this.options.select2.templateSelection;
|
this.formatSelection = this.options.select2.formatSelection;
|
||||||
if (typeof(this.formatSelection) !== "function") {
|
if (typeof(this.formatSelection) !== "function") {
|
||||||
this.formatSelection = function (e) { return e.text; };
|
this.formatSelection = function (e) { return e.text; };
|
||||||
}
|
}
|
||||||
@@ -3748,6 +3752,18 @@ $(function(){
|
|||||||
render: function() {
|
render: function() {
|
||||||
this.setClass();
|
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
|
//trigger resize of editableform to re-position container in multi-valued mode
|
||||||
if(this.isMultiple) {
|
if(this.isMultiple) {
|
||||||
@@ -3757,33 +3773,15 @@ $(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) {
|
value2html: function(value, element) {
|
||||||
var text = '', data,
|
var text = '', data,
|
||||||
that = this;
|
that = this;
|
||||||
|
|
||||||
// Use stored selected data if available (for visual display after selection)
|
if(this.options.select2.tags) { //in tags mode just assign value
|
||||||
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 = value;
|
||||||
|
//data = $.fn.editableutils.itemsByValue(value, this.options.select2.tags, this.idFunc);
|
||||||
} else if(this.sourceData) {
|
} else if(this.sourceData) {
|
||||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, function(e) { return e.id; });
|
data = $.fn.editableutils.itemsByValue(value, this.sourceData, this.idFunc);
|
||||||
} else {
|
} else {
|
||||||
//can not get list of possible values
|
//can not get list of possible values
|
||||||
//(e.g. autotext for select2 with ajax source)
|
//(e.g. autotext for select2 with ajax source)
|
||||||
@@ -3802,6 +3800,7 @@ $(function(){
|
|||||||
|
|
||||||
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
||||||
|
|
||||||
|
//$(element).text(text);
|
||||||
Constructor.superclass.value2html.call(this, text, element);
|
Constructor.superclass.value2html.call(this, text, element);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -3810,97 +3809,46 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
value2input: function(value) {
|
value2input: function(value) {
|
||||||
|
|
||||||
// if value array => join it anyway
|
// if value array => join it anyway
|
||||||
if(Array.isArray(value)) {
|
if(Array.isArray(value)) {
|
||||||
value = value.join(this.getSeparator());
|
value = value.join(this.getSeparator());
|
||||||
}
|
}
|
||||||
|
|
||||||
// For remote sources with existing value, create option element before Select2 init
|
//for remote source just set value, text is updated by initSelection
|
||||||
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')) {
|
if(!this.$input.data('select2')) {
|
||||||
this.$input.val(value);
|
this.$input.val(value);
|
||||||
this.$input.select2(this.options.select2);
|
this.$input.select2(this.options.select2);
|
||||||
|
|
||||||
// Set up minimal event handling AFTER initialization
|
|
||||||
this.$input.on('select2:select', $.proxy(function(e) {
|
|
||||||
|
|
||||||
if (e.params && e.params.data) {
|
|
||||||
var selectedData = e.params.data;
|
|
||||||
this.selectedData = [selectedData];
|
|
||||||
|
|
||||||
// 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 {
|
} else {
|
||||||
//update value on existing select2
|
//second argument needed to separate initial change from user's click (for autosubmit)
|
||||||
this.$input.val(value).trigger('change.select2');
|
this.$input.val(value).trigger('change', true);
|
||||||
|
|
||||||
|
//Uncaught Error: cannot call val() if initSelection() is not defined
|
||||||
|
//this.$input.select2('val', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(!customId && !customText) {
|
||||||
|
var $el = $(this.options.scope);
|
||||||
|
if (!$el.data('editable').isEmpty) {
|
||||||
|
var data = {id: value, text: $el.text()};
|
||||||
|
this.$input.select2('data', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
input2value: function() {
|
input2value: function() {
|
||||||
var val = this.$input.val();
|
return this.$input.select2('val');
|
||||||
|
},
|
||||||
// --- Handle Bootstrap Datepicker ---
|
|
||||||
var dp = this.$input.data('datepicker');
|
|
||||||
if (dp && typeof dp.getFormattedDate === 'function') {
|
|
||||||
val = dp.getFormattedDate(this.options.format || 'yyyy-mm-dd');
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Handle Select2 v4.x ---
|
|
||||||
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) {
|
str2value: function(str, separator) {
|
||||||
if(typeof str !== 'string' || !this.isMultiple) {
|
if(typeof str !== 'string' || !this.isMultiple) {
|
||||||
@@ -3922,10 +3870,16 @@ $(function(){
|
|||||||
return val;
|
return val;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
autosubmit: function() {
|
||||||
|
this.$input.on('change', function(e, isInitial){
|
||||||
|
if(!isInitial) {
|
||||||
|
$(this).closest('form').submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
getSeparator: function() {
|
getSeparator: function() {
|
||||||
// Select2 v4.x uses different separator handling
|
return this.options.select2.separator || $.fn.select2.defaults.separator;
|
||||||
return this.options.select2.separator || ',';
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3961,7 +3915,7 @@ $(function(){
|
|||||||
**/
|
**/
|
||||||
tpl:'<input type="hidden">',
|
tpl:'<input type="hidden">',
|
||||||
/**
|
/**
|
||||||
Configuration of select2. [Full list of options](https://select2.org/configuration).
|
Configuration of select2. [Full list of options](http://ivaynberg.github.com/select2).
|
||||||
|
|
||||||
@property select2
|
@property select2
|
||||||
@type object
|
@type object
|
||||||
@@ -3999,6 +3953,7 @@ $(function(){
|
|||||||
$.fn.editabletypes.select2 = Constructor;
|
$.fn.editabletypes.select2 = Constructor;
|
||||||
|
|
||||||
}(window.jQuery));
|
}(window.jQuery));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combodate - 1.0.5
|
* Combodate - 1.0.5
|
||||||
* Dropdown date and time picker.
|
* Dropdown date and time picker.
|
||||||
@@ -5003,27 +4958,29 @@ $(function(){
|
|||||||
(function ($) {
|
(function ($) {
|
||||||
"use strict";
|
"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) {
|
var Date = function (options) {
|
||||||
this.init('date', options, Date.defaults);
|
this.init('date', options, Date.defaults);
|
||||||
this.initPicker(options, Date.defaults);
|
this.initPicker(options, Date.defaults);
|
||||||
|
|
||||||
|
// Ensure type is set correctly
|
||||||
|
this.type = 'date';
|
||||||
};
|
};
|
||||||
|
|
||||||
$.fn.editableutils.inherit(Date, $.fn.editabletypes.abstractinput);
|
$.fn.editableutils.inherit(Date, $.fn.editabletypes.abstractinput);
|
||||||
|
|
||||||
$.extend(Date.prototype, {
|
$.extend(Date.prototype, {
|
||||||
initPicker: function(options, defaults) {
|
prerender: function() {
|
||||||
// Initialize bootstrap-datepicker reference
|
// Call parent prerender
|
||||||
if (!$.fn.bdatepicker) {
|
Date.superclass.prerender.call(this);
|
||||||
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.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
initPicker: function(options, defaults) {
|
||||||
//'format' is set directly from settings or data-* attributes
|
//'format' is set directly from settings or data-* attributes
|
||||||
|
|
||||||
//by default viewformat equals to format
|
//by default viewformat equals to format
|
||||||
@@ -5043,8 +5000,8 @@ $(function(){
|
|||||||
//language
|
//language
|
||||||
this.options.datepicker.language = this.options.datepicker.language || 'en';
|
this.options.datepicker.language = this.options.datepicker.language || 'en';
|
||||||
|
|
||||||
//store DPglobal
|
//store DPglobal - use datepicker instead of bdatepicker
|
||||||
this.dpg = $.fn.bdatepicker.DPGlobal;
|
this.dpg = $.fn.datepicker.DPGlobal;
|
||||||
|
|
||||||
//store parsed formats
|
//store parsed formats
|
||||||
this.parsedFormat = this.dpg.parseFormat(this.options.format);
|
this.parsedFormat = this.dpg.parseFormat(this.options.format);
|
||||||
@@ -5052,7 +5009,22 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
render: function () {
|
render: function () {
|
||||||
this.$input.bdatepicker(this.options.datepicker);
|
// Ensure we have an input element
|
||||||
|
if (!this.$input || !this.$input.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize datepicker immediately
|
||||||
|
try {
|
||||||
|
this.$input.datepicker(this.options.datepicker);
|
||||||
|
|
||||||
|
// Force set the initial value if we have one
|
||||||
|
if (this.value) {
|
||||||
|
this.$input.datepicker('setDate', this.value);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Silently handle datepicker initialization errors
|
||||||
|
}
|
||||||
|
|
||||||
//"clear" link
|
//"clear" link
|
||||||
if(this.options.clear) {
|
if(this.options.clear) {
|
||||||
@@ -5067,20 +5039,8 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
value2html: function(value, element) {
|
value2html: function(value, element) {
|
||||||
let text = '';
|
var text = value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '';
|
||||||
|
Date.superclass.value2html.call(this, text, element);
|
||||||
if (value) {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
text = value;
|
|
||||||
} else if (value instanceof Date && typeof value.getUTCDate === 'function') {
|
|
||||||
text = this.dpg.formatDate(value, this.parsedFormat, this.options.datepicker.language);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// direct fallback: set text without using editableutils
|
|
||||||
if (element) {
|
|
||||||
element.textContent = text;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
html2value: function(html) {
|
html2value: function(html) {
|
||||||
@@ -5088,17 +5048,7 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
value2str: function(value) {
|
value2str: function(value) {
|
||||||
if (!value) {
|
return value ? this.dpg.formatDate(value, this.parsedFormat, this.options.datepicker.language) : '';
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// If value is already a string (like "2025-11-27"), just return it.
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, assume it's a Date object and format it.
|
|
||||||
return this.dpg.formatDate(value, this.parsedFormat, this.options.datepicker.language);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
str2value: function(str) {
|
str2value: function(str) {
|
||||||
@@ -5110,15 +5060,42 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
value2input: function(value) {
|
value2input: function(value) {
|
||||||
this.$input.bdatepicker('update', value);
|
// Ensure datepicker is initialized before trying to update
|
||||||
|
if (!this.$input.data('datepicker')) {
|
||||||
|
this.$input.datepicker(this.options.datepicker);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$input.datepicker('update', value);
|
||||||
},
|
},
|
||||||
|
|
||||||
input2value: function() {
|
input2value: function() {
|
||||||
const dp = this.$input.data('datepicker');
|
var datepicker = this.$input.data('datepicker');
|
||||||
if (dp && typeof dp.getFormattedDate === 'function') {
|
|
||||||
return dp.getFormattedDate(this.options.format || 'yyyy-mm-dd');
|
if (datepicker) {
|
||||||
|
if (datepicker.date) {
|
||||||
|
return datepicker.date;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try getting date from dates array
|
||||||
|
if (datepicker.dates && datepicker.dates.length > 0) {
|
||||||
|
return datepicker.dates[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try using getDate method
|
||||||
|
if (typeof datepicker.getDate === 'function') {
|
||||||
|
var dateFromMethod = datepicker.getDate();
|
||||||
|
return dateFromMethod;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this.$input.val();
|
|
||||||
|
// Fallback: try to parse the input value directly
|
||||||
|
var inputVal = this.$input.val();
|
||||||
|
if (inputVal) {
|
||||||
|
var parsedDate = this.parseDate(inputVal, this.parsedViewFormat);
|
||||||
|
return parsedDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
activate: function() {
|
activate: function() {
|
||||||
@@ -5253,6 +5230,9 @@ Automatically shown in inline mode.
|
|||||||
var DateField = function (options) {
|
var DateField = function (options) {
|
||||||
this.init('datefield', options, DateField.defaults);
|
this.init('datefield', options, DateField.defaults);
|
||||||
this.initPicker(options, DateField.defaults);
|
this.initPicker(options, DateField.defaults);
|
||||||
|
|
||||||
|
// Ensure type is set correctly
|
||||||
|
this.type = 'datefield';
|
||||||
};
|
};
|
||||||
|
|
||||||
$.fn.editableutils.inherit(DateField, $.fn.editabletypes.date);
|
$.fn.editableutils.inherit(DateField, $.fn.editabletypes.date);
|
||||||
@@ -5263,8 +5243,8 @@ Automatically shown in inline mode.
|
|||||||
this.setClass();
|
this.setClass();
|
||||||
this.setAttr('placeholder');
|
this.setAttr('placeholder');
|
||||||
|
|
||||||
//bootstrap-datepicker is set `bdateicker` to exclude conflict with jQuery UI one. (in date.js)
|
//use datepicker instead of bdatepicker
|
||||||
this.$tpl.bdatepicker(this.options.datepicker);
|
this.$tpl.datepicker(this.options.datepicker);
|
||||||
|
|
||||||
//need to disable original event handlers
|
//need to disable original event handlers
|
||||||
this.$input.off('focus keydown');
|
this.$input.off('focus keydown');
|
||||||
@@ -5272,17 +5252,48 @@ Automatically shown in inline mode.
|
|||||||
//update value of datepicker
|
//update value of datepicker
|
||||||
this.$input.keyup($.proxy(function(){
|
this.$input.keyup($.proxy(function(){
|
||||||
this.$tpl.removeData('date');
|
this.$tpl.removeData('date');
|
||||||
this.$tpl.bdatepicker('update');
|
this.$tpl.datepicker('update');
|
||||||
}, this));
|
}, this));
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
value2input: function(value) {
|
value2input: function(value) {
|
||||||
this.$input.val(value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '');
|
var formattedValue = value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '';
|
||||||
this.$tpl.bdatepicker('update');
|
this.$input.val(formattedValue);
|
||||||
|
this.$tpl.datepicker('update');
|
||||||
},
|
},
|
||||||
|
|
||||||
input2value: function() {
|
input2value: function() {
|
||||||
|
// First try the container datepicker (ideal case)
|
||||||
|
var containerDatepicker = this.$tpl.data('datepicker');
|
||||||
|
|
||||||
|
if (containerDatepicker && containerDatepicker.dates && containerDatepicker.dates.length > 0) {
|
||||||
|
return containerDatepicker.dates[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: try the input datepicker (in case manual init worked)
|
||||||
|
var inputDatepicker = this.$input.data('datepicker');
|
||||||
|
|
||||||
|
if (inputDatepicker && inputDatepicker.dates && inputDatepicker.dates.length > 0) {
|
||||||
|
return inputDatepicker.dates[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try getDate methods
|
||||||
|
if (containerDatepicker && typeof containerDatepicker.getDate === 'function') {
|
||||||
|
var containerDate = containerDatepicker.getDate();
|
||||||
|
if (containerDate) {
|
||||||
|
return containerDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputDatepicker && typeof inputDatepicker.getDate === 'function') {
|
||||||
|
var inputDate = inputDatepicker.getDate();
|
||||||
|
if (inputDate) {
|
||||||
|
return inputDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final fallback to text parsing
|
||||||
return this.html2value(this.$input.val());
|
return this.html2value(this.$input.val());
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -5299,19 +5310,21 @@ Automatically shown in inline mode.
|
|||||||
/**
|
/**
|
||||||
@property tpl
|
@property tpl
|
||||||
**/
|
**/
|
||||||
tpl:'<div class="input-append date"><input type="text"/><span class="add-on"><i class="icon-th"></i></span></div>',
|
tpl:'<div class="input-group input-group-sm date datepicker-above" style="width: 200px; border: 1px solid #dee2e6; border-radius: 0.375rem; position: relative;"><input type="text" class="form-control form-control-sm" style="border: none;"/><span class="input-group-text" style="border: none; background: transparent;"><i class="bi bi-calendar"></i></span></div>',
|
||||||
/**
|
/**
|
||||||
@property inputclass
|
@property inputclass
|
||||||
@default 'input-small'
|
@default 'form-control form-control-sm'
|
||||||
**/
|
**/
|
||||||
inputclass: 'input-small',
|
inputclass: 'form-control form-control-sm',
|
||||||
|
|
||||||
/* datepicker config */
|
/* datepicker config */
|
||||||
datepicker: {
|
datepicker: {
|
||||||
weekStart: 0,
|
weekStart: 0,
|
||||||
startView: 0,
|
startView: 0,
|
||||||
minViewMode: 0,
|
minViewMode: 0,
|
||||||
autoclose: true
|
autoclose: true,
|
||||||
|
orientation: 'top',
|
||||||
|
container: 'body'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
7
dist/bootstrap5-editable/css/bootstrap-datepicker.min.css
vendored
Normal file
7
dist/bootstrap5-editable/css/bootstrap-datepicker.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
|||||||
/*! X-editable-bootstrap5 - v1.5.7
|
/*! X-editable - v1.5.2
|
||||||
* A fork of x-editable for Bootstrap 5 support.
|
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||||
* https://git.24unix.net/tracer/x-editable
|
* https://git.24unix.net/tracer/x-editable
|
||||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||||
.editableform {
|
.editableform {
|
||||||
@@ -156,6 +156,20 @@
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Position datepicker above input for datepicker-above class */
|
||||||
|
.datepicker-above .datepicker-inline {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||||
|
}
|
||||||
|
|
||||||
.editable-container.editable-popup {
|
.editable-container.editable-popup {
|
||||||
max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
|
max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
|
||||||
}
|
}
|
||||||
|
|||||||
14
dist/bootstrap5-editable/css/editable-form.css
vendored
14
dist/bootstrap5-editable/css/editable-form.css
vendored
@@ -151,3 +151,17 @@
|
|||||||
.editable-pre-wrapped {
|
.editable-pre-wrapped {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Position datepicker above input for datepicker-above class */
|
||||||
|
.datepicker-above .datepicker-inline {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||||
|
}
|
||||||
|
|||||||
5509
dist/bootstrap5-editable/js/bootstrap-editable.js
vendored
5509
dist/bootstrap5-editable/js/bootstrap-editable.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,3 +1,15 @@
|
|||||||
|
/*!
|
||||||
|
* Bootstrap v5.3.3 (https://getbootstrap.com/)
|
||||||
|
* Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
|
||||||
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Datepicker for Bootstrap v1.10.0 (https://github.com/uxsolutions/bootstrap-datepicker)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License v2.0 (https://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* jQuery JavaScript Library v3.7.1
|
* jQuery JavaScript Library v3.7.1
|
||||||
* https://jquery.com/
|
* https://jquery.com/
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
18
dist/jquery-editable/css/jquery-editable.css
vendored
18
dist/jquery-editable/css/jquery-editable.css
vendored
@@ -1,5 +1,5 @@
|
|||||||
/*! X-editable-bootstrap5 - v1.5.7
|
/*! X-editable - v1.5.2
|
||||||
* A fork of x-editable for Bootstrap 5 support.
|
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||||
* https://git.24unix.net/tracer/x-editable
|
* https://git.24unix.net/tracer/x-editable
|
||||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||||
.editableform {
|
.editableform {
|
||||||
@@ -156,6 +156,20 @@
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Position datepicker above input for datepicker-above class */
|
||||||
|
.datepicker-above .datepicker-inline {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||||
|
}
|
||||||
|
|
||||||
.editable-container.editable-popup {
|
.editable-container.editable-popup {
|
||||||
max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
|
max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
|
||||||
}
|
}
|
||||||
|
|||||||
259
dist/jquery-editable/js/jquery-editable-poshytip.js
vendored
259
dist/jquery-editable/js/jquery-editable-poshytip.js
vendored
@@ -1,5 +1,5 @@
|
|||||||
/*! X-editable-bootstrap5 - v1.5.7
|
/*! X-editable - v1.5.2
|
||||||
* A fork of x-editable for Bootstrap 5 support.
|
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||||
* https://git.24unix.net/tracer/x-editable
|
* https://git.24unix.net/tracer/x-editable
|
||||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||||
/**
|
/**
|
||||||
@@ -1505,6 +1505,9 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the editable's type from the input's type
|
||||||
|
this.type = this.input.type;
|
||||||
|
|
||||||
//set value from settings or by element's text
|
//set value from settings or by element's text
|
||||||
if (this.options.value === undefined || this.options.value === null) {
|
if (this.options.value === undefined || this.options.value === null) {
|
||||||
this.value = this.input.html2value(this.$element.html().trim());
|
this.value = this.input.html2value(this.$element.html().trim());
|
||||||
@@ -1540,15 +1543,16 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
//stop propagation to prevent interference with other click handlers
|
//stop propagation not required because in document click handler it checks event target
|
||||||
e.stopPropagation();
|
//e.stopPropagation();
|
||||||
|
|
||||||
if(this.options.toggle === 'mouseenter') {
|
if(this.options.toggle === 'mouseenter') {
|
||||||
//for hover only show container
|
//for hover only show container
|
||||||
this.show();
|
this.show();
|
||||||
} else {
|
} else {
|
||||||
//always close other containers when opening a new one
|
//when toggle='click' we should not close all other containers as they will be closed automatically in document click listener
|
||||||
this.toggle(true);
|
var closeAll = (this.options.toggle !== 'click');
|
||||||
|
this.toggle(closeAll);
|
||||||
}
|
}
|
||||||
}, this));
|
}, this));
|
||||||
} else {
|
} else {
|
||||||
@@ -3600,20 +3604,23 @@ Time
|
|||||||
}(window.jQuery));
|
}(window.jQuery));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/select2/select2.
|
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
|
||||||
Please see [Select2 docs](https://select2.org/) for detailed description and options.
|
Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options.
|
||||||
|
|
||||||
You should manually download and include Select2 v4.x distributive:
|
You should manually download and include select2 distributive:
|
||||||
|
|
||||||
<link href="node_modules/select2/dist/css/select2.css" rel="stylesheet" type="text/css"></link>
|
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link>
|
||||||
<script src="node_modules/select2/dist/js/select2.js"></script>
|
<script src="select2/select2.js"></script>
|
||||||
|
|
||||||
To make it **bootstrap-styled** you can use css from [select2-bootstrap-5-theme](https://github.com/apalfrey/select2-bootstrap-5-theme):
|
To make it **bootstrap-styled** you can use css from [here](https://github.com/t0m/select2-bootstrap-css):
|
||||||
|
|
||||||
<link href="select2-bootstrap-5-theme.css" rel="stylesheet" type="text/css"></link>
|
<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>
|
||||||
|
|
||||||
**Note:** This version requires Select2 v4.x. For remote sources, you may need to provide custom
|
|
||||||
`templateResult` and `templateSelection` functions.
|
|
||||||
|
|
||||||
@class select2
|
@class select2
|
||||||
@extends abstractinput
|
@extends abstractinput
|
||||||
@@ -3642,39 +3649,35 @@ $(function(){
|
|||||||
minimumInputLength: 1
|
minimumInputLength: 1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//remote source (advanced) - Select2 v4.x format
|
//remote source (advanced)
|
||||||
$('#country').editable({
|
$('#country').editable({
|
||||||
select2: {
|
select2: {
|
||||||
placeholder: 'Select Country',
|
placeholder: 'Select Country',
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
minimumInputLength: 3,
|
minimumInputLength: 3,
|
||||||
|
id: function (item) {
|
||||||
|
return item.CountryId;
|
||||||
|
},
|
||||||
ajax: {
|
ajax: {
|
||||||
url: '/getCountries',
|
url: '/getCountries',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
delay: 250,
|
data: function (term, page) {
|
||||||
data: function (params) {
|
return { query: term };
|
||||||
return {
|
|
||||||
query: params.term,
|
|
||||||
page: params.page
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
processResults: function (data, params) {
|
results: function (data, page) {
|
||||||
return {
|
return { results: data };
|
||||||
results: data.map(function(item) {
|
}
|
||||||
return {
|
|
||||||
id: item.CountryId,
|
|
||||||
text: item.CountryName
|
|
||||||
};
|
|
||||||
})
|
|
||||||
};
|
|
||||||
},
|
|
||||||
cache: true
|
|
||||||
},
|
},
|
||||||
templateResult: function (item) {
|
formatResult: function (item) {
|
||||||
return item.text || item.CountryName;
|
return item.CountryName;
|
||||||
},
|
},
|
||||||
templateSelection: function (item) {
|
formatSelection: function (item) {
|
||||||
return item.text || item.CountryName;
|
return item.CountryName;
|
||||||
|
},
|
||||||
|
initSelection: function (element, callback) {
|
||||||
|
return $.get('/getCountryById', { query: element.val() }, function (data) {
|
||||||
|
callback(data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -3706,19 +3709,12 @@ $(function(){
|
|||||||
|
|
||||||
if (typeof source === 'string') {
|
if (typeof source === 'string') {
|
||||||
options.select2.ajax = options.select2.ajax || {};
|
options.select2.ajax = options.select2.ajax || {};
|
||||||
//default ajax params for Select2 v4.x
|
//some default ajax params
|
||||||
if(!options.select2.ajax.data) {
|
if(!options.select2.ajax.data) {
|
||||||
options.select2.ajax.data = function(params) {
|
options.select2.ajax.data = function(term) {return { query:term };};
|
||||||
return {
|
|
||||||
query: params.term,
|
|
||||||
page: params.page
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if(!options.select2.ajax.processResults) {
|
if(!options.select2.ajax.results) {
|
||||||
options.select2.ajax.processResults = function(data) {
|
options.select2.ajax.results = function(data) { return {results:data };};
|
||||||
return {results: data };
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
options.select2.ajax.url = source;
|
options.select2.ajax.url = source;
|
||||||
} else {
|
} else {
|
||||||
@@ -3735,8 +3731,16 @@ $(function(){
|
|||||||
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
||||||
this.isRemote = ('ajax' in this.options.select2);
|
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
|
//store function that renders text in select2
|
||||||
this.formatSelection = this.options.select2.templateSelection;
|
this.formatSelection = this.options.select2.formatSelection;
|
||||||
if (typeof(this.formatSelection) !== "function") {
|
if (typeof(this.formatSelection) !== "function") {
|
||||||
this.formatSelection = function (e) { return e.text; };
|
this.formatSelection = function (e) { return e.text; };
|
||||||
}
|
}
|
||||||
@@ -3748,6 +3752,18 @@ $(function(){
|
|||||||
render: function() {
|
render: function() {
|
||||||
this.setClass();
|
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
|
//trigger resize of editableform to re-position container in multi-valued mode
|
||||||
if(this.isMultiple) {
|
if(this.isMultiple) {
|
||||||
@@ -3757,33 +3773,15 @@ $(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) {
|
value2html: function(value, element) {
|
||||||
var text = '', data,
|
var text = '', data,
|
||||||
that = this;
|
that = this;
|
||||||
|
|
||||||
// Use stored selected data if available (for visual display after selection)
|
if(this.options.select2.tags) { //in tags mode just assign value
|
||||||
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 = value;
|
||||||
|
//data = $.fn.editableutils.itemsByValue(value, this.options.select2.tags, this.idFunc);
|
||||||
} else if(this.sourceData) {
|
} else if(this.sourceData) {
|
||||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, function(e) { return e.id; });
|
data = $.fn.editableutils.itemsByValue(value, this.sourceData, this.idFunc);
|
||||||
} else {
|
} else {
|
||||||
//can not get list of possible values
|
//can not get list of possible values
|
||||||
//(e.g. autotext for select2 with ajax source)
|
//(e.g. autotext for select2 with ajax source)
|
||||||
@@ -3802,6 +3800,7 @@ $(function(){
|
|||||||
|
|
||||||
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
||||||
|
|
||||||
|
//$(element).text(text);
|
||||||
Constructor.superclass.value2html.call(this, text, element);
|
Constructor.superclass.value2html.call(this, text, element);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -3810,97 +3809,46 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
value2input: function(value) {
|
value2input: function(value) {
|
||||||
|
|
||||||
// if value array => join it anyway
|
// if value array => join it anyway
|
||||||
if(Array.isArray(value)) {
|
if(Array.isArray(value)) {
|
||||||
value = value.join(this.getSeparator());
|
value = value.join(this.getSeparator());
|
||||||
}
|
}
|
||||||
|
|
||||||
// For remote sources with existing value, create option element before Select2 init
|
//for remote source just set value, text is updated by initSelection
|
||||||
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')) {
|
if(!this.$input.data('select2')) {
|
||||||
this.$input.val(value);
|
this.$input.val(value);
|
||||||
this.$input.select2(this.options.select2);
|
this.$input.select2(this.options.select2);
|
||||||
|
|
||||||
// Set up minimal event handling AFTER initialization
|
|
||||||
this.$input.on('select2:select', $.proxy(function(e) {
|
|
||||||
|
|
||||||
if (e.params && e.params.data) {
|
|
||||||
var selectedData = e.params.data;
|
|
||||||
this.selectedData = [selectedData];
|
|
||||||
|
|
||||||
// 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 {
|
} else {
|
||||||
//update value on existing select2
|
//second argument needed to separate initial change from user's click (for autosubmit)
|
||||||
this.$input.val(value).trigger('change.select2');
|
this.$input.val(value).trigger('change', true);
|
||||||
|
|
||||||
|
//Uncaught Error: cannot call val() if initSelection() is not defined
|
||||||
|
//this.$input.select2('val', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(!customId && !customText) {
|
||||||
|
var $el = $(this.options.scope);
|
||||||
|
if (!$el.data('editable').isEmpty) {
|
||||||
|
var data = {id: value, text: $el.text()};
|
||||||
|
this.$input.select2('data', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
input2value: function() {
|
input2value: function() {
|
||||||
var val = this.$input.val();
|
return this.$input.select2('val');
|
||||||
|
},
|
||||||
// --- Handle Bootstrap Datepicker ---
|
|
||||||
var dp = this.$input.data('datepicker');
|
|
||||||
if (dp && typeof dp.getFormattedDate === 'function') {
|
|
||||||
val = dp.getFormattedDate(this.options.format || 'yyyy-mm-dd');
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Handle Select2 v4.x ---
|
|
||||||
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) {
|
str2value: function(str, separator) {
|
||||||
if(typeof str !== 'string' || !this.isMultiple) {
|
if(typeof str !== 'string' || !this.isMultiple) {
|
||||||
@@ -3922,10 +3870,16 @@ $(function(){
|
|||||||
return val;
|
return val;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
autosubmit: function() {
|
||||||
|
this.$input.on('change', function(e, isInitial){
|
||||||
|
if(!isInitial) {
|
||||||
|
$(this).closest('form').submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
getSeparator: function() {
|
getSeparator: function() {
|
||||||
// Select2 v4.x uses different separator handling
|
return this.options.select2.separator || $.fn.select2.defaults.separator;
|
||||||
return this.options.select2.separator || ',';
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3961,7 +3915,7 @@ $(function(){
|
|||||||
**/
|
**/
|
||||||
tpl:'<input type="hidden">',
|
tpl:'<input type="hidden">',
|
||||||
/**
|
/**
|
||||||
Configuration of select2. [Full list of options](https://select2.org/configuration).
|
Configuration of select2. [Full list of options](http://ivaynberg.github.com/select2).
|
||||||
|
|
||||||
@property select2
|
@property select2
|
||||||
@type object
|
@type object
|
||||||
@@ -3999,6 +3953,7 @@ $(function(){
|
|||||||
$.fn.editabletypes.select2 = Constructor;
|
$.fn.editabletypes.select2 = Constructor;
|
||||||
|
|
||||||
}(window.jQuery));
|
}(window.jQuery));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combodate - 1.0.5
|
* Combodate - 1.0.5
|
||||||
* Dropdown date and time picker.
|
* Dropdown date and time picker.
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
18
dist/jqueryui-editable/css/jqueryui-editable.css
vendored
18
dist/jqueryui-editable/css/jqueryui-editable.css
vendored
@@ -1,5 +1,5 @@
|
|||||||
/*! X-editable-bootstrap5 - v1.5.7
|
/*! X-editable - v1.5.2
|
||||||
* A fork of x-editable for Bootstrap 5 support.
|
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||||
* https://git.24unix.net/tracer/x-editable
|
* https://git.24unix.net/tracer/x-editable
|
||||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||||
.editableform {
|
.editableform {
|
||||||
@@ -156,6 +156,20 @@
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Position datepicker above input for datepicker-above class */
|
||||||
|
.datepicker-above .datepicker-inline {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||||
|
}
|
||||||
|
|
||||||
.editable-container.editable-popup {
|
.editable-container.editable-popup {
|
||||||
max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
|
max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
|
||||||
}
|
}
|
||||||
|
|||||||
259
dist/jqueryui-editable/js/jqueryui-editable.js
vendored
259
dist/jqueryui-editable/js/jqueryui-editable.js
vendored
@@ -1,5 +1,5 @@
|
|||||||
/*! X-editable-bootstrap5 - v1.5.7
|
/*! X-editable - v1.5.2
|
||||||
* A fork of x-editable for Bootstrap 5 support.
|
* A maintained fork of x-editable for Bootstrap 5 support.
|
||||||
* https://git.24unix.net/tracer/x-editable
|
* https://git.24unix.net/tracer/x-editable
|
||||||
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
* Copyright (c) 2025 Micha Espey; Licensed MIT */
|
||||||
/**
|
/**
|
||||||
@@ -1505,6 +1505,9 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the editable's type from the input's type
|
||||||
|
this.type = this.input.type;
|
||||||
|
|
||||||
//set value from settings or by element's text
|
//set value from settings or by element's text
|
||||||
if (this.options.value === undefined || this.options.value === null) {
|
if (this.options.value === undefined || this.options.value === null) {
|
||||||
this.value = this.input.html2value(this.$element.html().trim());
|
this.value = this.input.html2value(this.$element.html().trim());
|
||||||
@@ -1540,15 +1543,16 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
//stop propagation to prevent interference with other click handlers
|
//stop propagation not required because in document click handler it checks event target
|
||||||
e.stopPropagation();
|
//e.stopPropagation();
|
||||||
|
|
||||||
if(this.options.toggle === 'mouseenter') {
|
if(this.options.toggle === 'mouseenter') {
|
||||||
//for hover only show container
|
//for hover only show container
|
||||||
this.show();
|
this.show();
|
||||||
} else {
|
} else {
|
||||||
//always close other containers when opening a new one
|
//when toggle='click' we should not close all other containers as they will be closed automatically in document click listener
|
||||||
this.toggle(true);
|
var closeAll = (this.options.toggle !== 'click');
|
||||||
|
this.toggle(closeAll);
|
||||||
}
|
}
|
||||||
}, this));
|
}, this));
|
||||||
} else {
|
} else {
|
||||||
@@ -3600,20 +3604,23 @@ Time
|
|||||||
}(window.jQuery));
|
}(window.jQuery));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/select2/select2.
|
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
|
||||||
Please see [Select2 docs](https://select2.org/) for detailed description and options.
|
Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options.
|
||||||
|
|
||||||
You should manually download and include Select2 v4.x distributive:
|
You should manually download and include select2 distributive:
|
||||||
|
|
||||||
<link href="node_modules/select2/dist/css/select2.css" rel="stylesheet" type="text/css"></link>
|
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link>
|
||||||
<script src="node_modules/select2/dist/js/select2.js"></script>
|
<script src="select2/select2.js"></script>
|
||||||
|
|
||||||
To make it **bootstrap-styled** you can use css from [select2-bootstrap-5-theme](https://github.com/apalfrey/select2-bootstrap-5-theme):
|
To make it **bootstrap-styled** you can use css from [here](https://github.com/t0m/select2-bootstrap-css):
|
||||||
|
|
||||||
<link href="select2-bootstrap-5-theme.css" rel="stylesheet" type="text/css"></link>
|
<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>
|
||||||
|
|
||||||
**Note:** This version requires Select2 v4.x. For remote sources, you may need to provide custom
|
|
||||||
`templateResult` and `templateSelection` functions.
|
|
||||||
|
|
||||||
@class select2
|
@class select2
|
||||||
@extends abstractinput
|
@extends abstractinput
|
||||||
@@ -3642,39 +3649,35 @@ $(function(){
|
|||||||
minimumInputLength: 1
|
minimumInputLength: 1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//remote source (advanced) - Select2 v4.x format
|
//remote source (advanced)
|
||||||
$('#country').editable({
|
$('#country').editable({
|
||||||
select2: {
|
select2: {
|
||||||
placeholder: 'Select Country',
|
placeholder: 'Select Country',
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
minimumInputLength: 3,
|
minimumInputLength: 3,
|
||||||
|
id: function (item) {
|
||||||
|
return item.CountryId;
|
||||||
|
},
|
||||||
ajax: {
|
ajax: {
|
||||||
url: '/getCountries',
|
url: '/getCountries',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
delay: 250,
|
data: function (term, page) {
|
||||||
data: function (params) {
|
return { query: term };
|
||||||
return {
|
|
||||||
query: params.term,
|
|
||||||
page: params.page
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
processResults: function (data, params) {
|
results: function (data, page) {
|
||||||
return {
|
return { results: data };
|
||||||
results: data.map(function(item) {
|
}
|
||||||
return {
|
|
||||||
id: item.CountryId,
|
|
||||||
text: item.CountryName
|
|
||||||
};
|
|
||||||
})
|
|
||||||
};
|
|
||||||
},
|
|
||||||
cache: true
|
|
||||||
},
|
},
|
||||||
templateResult: function (item) {
|
formatResult: function (item) {
|
||||||
return item.text || item.CountryName;
|
return item.CountryName;
|
||||||
},
|
},
|
||||||
templateSelection: function (item) {
|
formatSelection: function (item) {
|
||||||
return item.text || item.CountryName;
|
return item.CountryName;
|
||||||
|
},
|
||||||
|
initSelection: function (element, callback) {
|
||||||
|
return $.get('/getCountryById', { query: element.val() }, function (data) {
|
||||||
|
callback(data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -3706,19 +3709,12 @@ $(function(){
|
|||||||
|
|
||||||
if (typeof source === 'string') {
|
if (typeof source === 'string') {
|
||||||
options.select2.ajax = options.select2.ajax || {};
|
options.select2.ajax = options.select2.ajax || {};
|
||||||
//default ajax params for Select2 v4.x
|
//some default ajax params
|
||||||
if(!options.select2.ajax.data) {
|
if(!options.select2.ajax.data) {
|
||||||
options.select2.ajax.data = function(params) {
|
options.select2.ajax.data = function(term) {return { query:term };};
|
||||||
return {
|
|
||||||
query: params.term,
|
|
||||||
page: params.page
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if(!options.select2.ajax.processResults) {
|
if(!options.select2.ajax.results) {
|
||||||
options.select2.ajax.processResults = function(data) {
|
options.select2.ajax.results = function(data) { return {results:data };};
|
||||||
return {results: data };
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
options.select2.ajax.url = source;
|
options.select2.ajax.url = source;
|
||||||
} else {
|
} else {
|
||||||
@@ -3735,8 +3731,16 @@ $(function(){
|
|||||||
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
||||||
this.isRemote = ('ajax' in this.options.select2);
|
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
|
//store function that renders text in select2
|
||||||
this.formatSelection = this.options.select2.templateSelection;
|
this.formatSelection = this.options.select2.formatSelection;
|
||||||
if (typeof(this.formatSelection) !== "function") {
|
if (typeof(this.formatSelection) !== "function") {
|
||||||
this.formatSelection = function (e) { return e.text; };
|
this.formatSelection = function (e) { return e.text; };
|
||||||
}
|
}
|
||||||
@@ -3748,6 +3752,18 @@ $(function(){
|
|||||||
render: function() {
|
render: function() {
|
||||||
this.setClass();
|
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
|
//trigger resize of editableform to re-position container in multi-valued mode
|
||||||
if(this.isMultiple) {
|
if(this.isMultiple) {
|
||||||
@@ -3757,33 +3773,15 @@ $(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) {
|
value2html: function(value, element) {
|
||||||
var text = '', data,
|
var text = '', data,
|
||||||
that = this;
|
that = this;
|
||||||
|
|
||||||
// Use stored selected data if available (for visual display after selection)
|
if(this.options.select2.tags) { //in tags mode just assign value
|
||||||
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 = value;
|
||||||
|
//data = $.fn.editableutils.itemsByValue(value, this.options.select2.tags, this.idFunc);
|
||||||
} else if(this.sourceData) {
|
} else if(this.sourceData) {
|
||||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, function(e) { return e.id; });
|
data = $.fn.editableutils.itemsByValue(value, this.sourceData, this.idFunc);
|
||||||
} else {
|
} else {
|
||||||
//can not get list of possible values
|
//can not get list of possible values
|
||||||
//(e.g. autotext for select2 with ajax source)
|
//(e.g. autotext for select2 with ajax source)
|
||||||
@@ -3802,6 +3800,7 @@ $(function(){
|
|||||||
|
|
||||||
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
||||||
|
|
||||||
|
//$(element).text(text);
|
||||||
Constructor.superclass.value2html.call(this, text, element);
|
Constructor.superclass.value2html.call(this, text, element);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -3810,97 +3809,46 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
value2input: function(value) {
|
value2input: function(value) {
|
||||||
|
|
||||||
// if value array => join it anyway
|
// if value array => join it anyway
|
||||||
if(Array.isArray(value)) {
|
if(Array.isArray(value)) {
|
||||||
value = value.join(this.getSeparator());
|
value = value.join(this.getSeparator());
|
||||||
}
|
}
|
||||||
|
|
||||||
// For remote sources with existing value, create option element before Select2 init
|
//for remote source just set value, text is updated by initSelection
|
||||||
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')) {
|
if(!this.$input.data('select2')) {
|
||||||
this.$input.val(value);
|
this.$input.val(value);
|
||||||
this.$input.select2(this.options.select2);
|
this.$input.select2(this.options.select2);
|
||||||
|
|
||||||
// Set up minimal event handling AFTER initialization
|
|
||||||
this.$input.on('select2:select', $.proxy(function(e) {
|
|
||||||
|
|
||||||
if (e.params && e.params.data) {
|
|
||||||
var selectedData = e.params.data;
|
|
||||||
this.selectedData = [selectedData];
|
|
||||||
|
|
||||||
// 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 {
|
} else {
|
||||||
//update value on existing select2
|
//second argument needed to separate initial change from user's click (for autosubmit)
|
||||||
this.$input.val(value).trigger('change.select2');
|
this.$input.val(value).trigger('change', true);
|
||||||
|
|
||||||
|
//Uncaught Error: cannot call val() if initSelection() is not defined
|
||||||
|
//this.$input.select2('val', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(!customId && !customText) {
|
||||||
|
var $el = $(this.options.scope);
|
||||||
|
if (!$el.data('editable').isEmpty) {
|
||||||
|
var data = {id: value, text: $el.text()};
|
||||||
|
this.$input.select2('data', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
input2value: function() {
|
input2value: function() {
|
||||||
var val = this.$input.val();
|
return this.$input.select2('val');
|
||||||
|
},
|
||||||
// --- Handle Bootstrap Datepicker ---
|
|
||||||
var dp = this.$input.data('datepicker');
|
|
||||||
if (dp && typeof dp.getFormattedDate === 'function') {
|
|
||||||
val = dp.getFormattedDate(this.options.format || 'yyyy-mm-dd');
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Handle Select2 v4.x ---
|
|
||||||
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) {
|
str2value: function(str, separator) {
|
||||||
if(typeof str !== 'string' || !this.isMultiple) {
|
if(typeof str !== 'string' || !this.isMultiple) {
|
||||||
@@ -3922,10 +3870,16 @@ $(function(){
|
|||||||
return val;
|
return val;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
autosubmit: function() {
|
||||||
|
this.$input.on('change', function(e, isInitial){
|
||||||
|
if(!isInitial) {
|
||||||
|
$(this).closest('form').submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
getSeparator: function() {
|
getSeparator: function() {
|
||||||
// Select2 v4.x uses different separator handling
|
return this.options.select2.separator || $.fn.select2.defaults.separator;
|
||||||
return this.options.select2.separator || ',';
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3961,7 +3915,7 @@ $(function(){
|
|||||||
**/
|
**/
|
||||||
tpl:'<input type="hidden">',
|
tpl:'<input type="hidden">',
|
||||||
/**
|
/**
|
||||||
Configuration of select2. [Full list of options](https://select2.org/configuration).
|
Configuration of select2. [Full list of options](http://ivaynberg.github.com/select2).
|
||||||
|
|
||||||
@property select2
|
@property select2
|
||||||
@type object
|
@type object
|
||||||
@@ -3999,6 +3953,7 @@ $(function(){
|
|||||||
$.fn.editabletypes.select2 = Constructor;
|
$.fn.editabletypes.select2 = Constructor;
|
||||||
|
|
||||||
}(window.jQuery));
|
}(window.jQuery));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combodate - 1.0.5
|
* Combodate - 1.0.5
|
||||||
* Dropdown date and time picker.
|
* Dropdown date and time picker.
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
272
package-lock.json
generated
272
package-lock.json
generated
@@ -1,13 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "x-editable-bootstrap5",
|
"name": "@24unix/x-editable",
|
||||||
"version": "1.5.3",
|
"version": "1.5.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "x-editable-bootstrap5",
|
"name": "@24unix/x-editable",
|
||||||
"version": "1.5.3",
|
"version": "1.5.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@anthropic-ai/claude-code": "^1.0.61",
|
||||||
"bootstrap": "^5.3.3",
|
"bootstrap": "^5.3.3",
|
||||||
"bootstrap-datepicker": "^1.10.0",
|
"bootstrap-datepicker": "^1.10.0",
|
||||||
"bootstrap-icons": "^1.11.3",
|
"bootstrap-icons": "^1.11.3",
|
||||||
@@ -30,9 +31,26 @@
|
|||||||
"grunt-contrib-uglify": "^5.2.2",
|
"grunt-contrib-uglify": "^5.2.2",
|
||||||
"style-loader": "^4.0.0",
|
"style-loader": "^4.0.0",
|
||||||
"webpack-cli": "^6.0.1"
|
"webpack-cli": "^6.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@anthropic-ai/claude-code": {
|
||||||
|
"version": "1.0.61",
|
||||||
|
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-1.0.61.tgz",
|
||||||
|
"integrity": "sha512-+gjKzY1hsWfHoH52SgKR6E0ujCDPyyRsjyRShtZfS0urKd8VQq3D/DF3hvT3P4JJeW0YuWp5Dep0aSRON+/FFA==",
|
||||||
|
"license": "SEE LICENSE IN README.md",
|
||||||
|
"bin": {
|
||||||
|
"claude": "cli.js"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"engines": {
|
||||||
"select2": ">=4.0.0 || 4.1.0-rc.0"
|
"node": ">=18.0.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-darwin-arm64": "^0.33.5",
|
||||||
|
"@img/sharp-darwin-x64": "^0.33.5",
|
||||||
|
"@img/sharp-linux-arm": "^0.33.5",
|
||||||
|
"@img/sharp-linux-arm64": "^0.33.5",
|
||||||
|
"@img/sharp-linux-x64": "^0.33.5",
|
||||||
|
"@img/sharp-win32-x64": "^0.33.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
@@ -70,6 +88,215 @@
|
|||||||
"node": ">=14.17.0"
|
"node": ">=14.17.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@img/sharp-darwin-arm64": {
|
||||||
|
"version": "0.33.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
|
||||||
|
"integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-darwin-arm64": "1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-darwin-x64": {
|
||||||
|
"version": "0.33.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz",
|
||||||
|
"integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-darwin-x64": "1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-darwin-arm64": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-darwin-x64": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-arm": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-arm64": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-libvips-linux-x64": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-arm": {
|
||||||
|
"version": "0.33.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz",
|
||||||
|
"integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-arm": "1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-arm64": {
|
||||||
|
"version": "0.33.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz",
|
||||||
|
"integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-arm64": "1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-linux-x64": {
|
||||||
|
"version": "0.33.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz",
|
||||||
|
"integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@img/sharp-libvips-linux-x64": "1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@img/sharp-win32-x64": {
|
||||||
|
"version": "0.33.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",
|
||||||
|
"integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "Apache-2.0 AND LGPL-3.0-or-later",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/libvips"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.8",
|
"version": "0.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
|
||||||
@@ -804,9 +1031,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.12",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -3412,9 +3639,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/morgan": {
|
"node_modules/morgan": {
|
||||||
"version": "1.10.0",
|
"version": "1.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz",
|
||||||
"integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==",
|
"integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -3422,7 +3649,7 @@
|
|||||||
"debug": "2.6.9",
|
"debug": "2.6.9",
|
||||||
"depd": "~2.0.0",
|
"depd": "~2.0.0",
|
||||||
"on-finished": "~2.3.0",
|
"on-finished": "~2.3.0",
|
||||||
"on-headers": "~1.0.2"
|
"on-headers": "~1.1.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
@@ -3565,9 +3792,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/on-headers": {
|
"node_modules/on-headers": {
|
||||||
"version": "1.0.2",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
|
||||||
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
|
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -4427,13 +4654,6 @@
|
|||||||
"url": "https://opencollective.com/webpack"
|
"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": {
|
"node_modules/semver": {
|
||||||
"version": "7.7.1",
|
"version": "7.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||||
@@ -4860,9 +5080,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tar-fs": {
|
"node_modules/tar-fs": {
|
||||||
"version": "3.0.8",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.0.tgz",
|
||||||
"integrity": "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==",
|
"integrity": "sha512-5Mty5y/sOF1YWj1J6GiBodjlDc05CUR8PKXrsnFAiSG0xA+GHeWLovaZPYUDXkH/1iKRf2+M5+OrRgzC7O9b7w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
12
package.json
12
package.json
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "x-editable-bootstrap5",
|
"name": "@24unix/x-editable",
|
||||||
"title": "X-editable-bootstrap5",
|
"title": "X-editable",
|
||||||
"description": "A fork of x-editable for Bootstrap 5 support.",
|
"description": "A maintained fork of x-editable for Bootstrap 5 support.",
|
||||||
"version": "1.5.7",
|
"version": "1.5.2",
|
||||||
"homepage": "https://git.24unix.net/tracer/x-editable",
|
"homepage": "https://git.24unix.net/tracer/x-editable",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Micha Espey",
|
"name": "Micha Espey",
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
"module": "dist/bootstrap5-editable/js/bootstrap-editable.esm.js",
|
"module": "dist/bootstrap5-editable/js/bootstrap-editable.esm.js",
|
||||||
"style": "dist/bootstrap5-editable/css/bootstrap-editable.css",
|
"style": "dist/bootstrap5-editable/css/bootstrap-editable.css",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@anthropic-ai/claude-code": "^1.0.61",
|
||||||
"bootstrap": "^5.3.3",
|
"bootstrap": "^5.3.3",
|
||||||
"bootstrap-datepicker": "^1.10.0",
|
"bootstrap-datepicker": "^1.10.0",
|
||||||
"bootstrap-icons": "^1.11.3",
|
"bootstrap-icons": "^1.11.3",
|
||||||
@@ -41,9 +42,6 @@
|
|||||||
"popper.js": "^1.16.1",
|
"popper.js": "^1.16.1",
|
||||||
"webpack": "^5.98.0"
|
"webpack": "^5.98.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
|
||||||
"select2": ">=4.0.0 || 4.1.0-rc.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"css-loader": "^7.1.2",
|
"css-loader": "^7.1.2",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
|
|||||||
32
src/bootstrap5-editable.js
vendored
Normal file
32
src/bootstrap5-editable.js
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
X-Editable Bootstrap 5 - Complete Bundle
|
||||||
|
Uses npm bootstrap-datepicker instead of bundled version
|
||||||
|
Order matches Gruntfile.js for compatibility
|
||||||
|
*/
|
||||||
|
import $ from "jquery";
|
||||||
|
|
||||||
|
// Import bootstrap-datepicker from npm
|
||||||
|
import "bootstrap-datepicker";
|
||||||
|
|
||||||
|
// Core editable functionality - EXACT ORDER from Gruntfile
|
||||||
|
import "./editable-form/editable-form.js";
|
||||||
|
import "./editable-form/editable-form-utils.js";
|
||||||
|
import "./containers/editable-container.js";
|
||||||
|
import "./containers/editable-inline.js";
|
||||||
|
import "./element/editable-element.js";
|
||||||
|
import "./inputs/abstract.js";
|
||||||
|
import "./inputs/list.js";
|
||||||
|
import "./inputs/text.js";
|
||||||
|
import "./inputs/textarea.js";
|
||||||
|
import "./inputs/select.js";
|
||||||
|
|
||||||
|
// Date input (now uses npm bootstrap-datepicker)
|
||||||
|
import "./inputs/date/date.js";
|
||||||
|
import "./inputs/date/datefield.js";
|
||||||
|
|
||||||
|
// Bootstrap 5 specific containers and forms
|
||||||
|
import "./containers/editable-popover5.js";
|
||||||
|
import "./editable-form/editable-form-bootstrap5.js";
|
||||||
|
|
||||||
|
// Export jQuery for compatibility
|
||||||
|
export default $;
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
* ---------------------
|
* ---------------------
|
||||||
* requires bootstrap-popover.js
|
* requires bootstrap-popover.js
|
||||||
*/
|
*/
|
||||||
|
import { Popover } from "bootstrap";
|
||||||
|
|
||||||
(function ($) {
|
(function ($) {
|
||||||
"use strict";
|
"use strict";
|
||||||
@@ -12,7 +13,7 @@
|
|||||||
containerName: 'popover',
|
containerName: 'popover',
|
||||||
containerDataName: 'bs.popover',
|
containerDataName: 'bs.popover',
|
||||||
innerCss: '.popover-body',
|
innerCss: '.popover-body',
|
||||||
defaults: bootstrap.Popover.Default,
|
defaults: Popover.Default,
|
||||||
|
|
||||||
initContainer: function(){
|
initContainer: function(){
|
||||||
$.extend(this.containerOptions, {
|
$.extend(this.containerOptions, {
|
||||||
@@ -39,27 +40,7 @@
|
|||||||
|
|
||||||
/* show */
|
/* show */
|
||||||
innerShow: function () {
|
innerShow: function () {
|
||||||
// Preserve scroll position to prevent page jumping
|
|
||||||
var scrollTop = $(window).scrollTop();
|
|
||||||
var scrollLeft = $(window).scrollLeft();
|
|
||||||
|
|
||||||
this.call('show');
|
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 */
|
/* hide */
|
||||||
@@ -83,7 +64,7 @@
|
|||||||
call: function() {
|
call: function() {
|
||||||
if ( ! $(this.$element).data(this.containerDataName)) {
|
if ( ! $(this.$element).data(this.containerDataName)) {
|
||||||
$(this.$element).data(this.containerDataName,
|
$(this.$element).data(this.containerDataName,
|
||||||
bootstrap.Popover.getOrCreateInstance(this.$element, this.containerOptions)
|
Popover.getOrCreateInstance(this.$element, this.containerOptions)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Editableform based on Twitter Bootstrap 5
|
Editableform based on Twitter Bootstrap 5
|
||||||
*/
|
*/
|
||||||
|
import $ from "jquery";
|
||||||
|
|
||||||
(function ($) {
|
(function ($) {
|
||||||
"use strict";
|
"use strict";
|
||||||
@@ -47,7 +48,7 @@ Editableform based on Twitter Bootstrap 5
|
|||||||
'<button type="submit" class="btn btn-primary btn-sm editable-submit">'+
|
'<button type="submit" class="btn btn-primary btn-sm editable-submit">'+
|
||||||
'<i class="bi bi-check"></i>'+
|
'<i class="bi bi-check"></i>'+
|
||||||
'</button>'+
|
'</button>'+
|
||||||
'<button type="button" class="btn btn-outline-secondary btn-sm editable-cancel">'+
|
'<button type="button" class="btn btn-secondary btn-sm editable-cancel">'+
|
||||||
'<i class="bi bi-x"></i>'+
|
'<i class="bi bi-x"></i>'+
|
||||||
'</button>';
|
'</button>';
|
||||||
|
|
||||||
|
|||||||
@@ -151,3 +151,17 @@
|
|||||||
.editable-pre-wrapped {
|
.editable-pre-wrapped {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Position datepicker above input for datepicker-above class */
|
||||||
|
.datepicker-above .datepicker-inline {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the editable's type from the input's type
|
||||||
|
this.type = this.input.type;
|
||||||
|
|
||||||
//set value from settings or by element's text
|
//set value from settings or by element's text
|
||||||
if (this.options.value === undefined || this.options.value === null) {
|
if (this.options.value === undefined || this.options.value === null) {
|
||||||
this.value = this.input.html2value(this.$element.html().trim());
|
this.value = this.input.html2value(this.$element.html().trim());
|
||||||
@@ -75,15 +78,16 @@ Makes editable any HTML element on the page. Applied as jQuery method.
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
//stop propagation to prevent interference with other click handlers
|
//stop propagation not required because in document click handler it checks event target
|
||||||
e.stopPropagation();
|
//e.stopPropagation();
|
||||||
|
|
||||||
if(this.options.toggle === 'mouseenter') {
|
if(this.options.toggle === 'mouseenter') {
|
||||||
//for hover only show container
|
//for hover only show container
|
||||||
this.show();
|
this.show();
|
||||||
} else {
|
} else {
|
||||||
//always close other containers when opening a new one
|
//when toggle='click' we should not close all other containers as they will be closed automatically in document click listener
|
||||||
this.toggle(true);
|
var closeAll = (this.options.toggle !== 'click');
|
||||||
|
this.toggle(closeAll);
|
||||||
}
|
}
|
||||||
}, this));
|
}, this));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -26,27 +26,29 @@ $(function(){
|
|||||||
(function ($) {
|
(function ($) {
|
||||||
"use strict";
|
"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) {
|
var Date = function (options) {
|
||||||
this.init('date', options, Date.defaults);
|
this.init('date', options, Date.defaults);
|
||||||
this.initPicker(options, Date.defaults);
|
this.initPicker(options, Date.defaults);
|
||||||
|
|
||||||
|
// Ensure type is set correctly
|
||||||
|
this.type = 'date';
|
||||||
};
|
};
|
||||||
|
|
||||||
$.fn.editableutils.inherit(Date, $.fn.editabletypes.abstractinput);
|
$.fn.editableutils.inherit(Date, $.fn.editabletypes.abstractinput);
|
||||||
|
|
||||||
$.extend(Date.prototype, {
|
$.extend(Date.prototype, {
|
||||||
initPicker: function(options, defaults) {
|
prerender: function() {
|
||||||
// Initialize bootstrap-datepicker reference
|
// Call parent prerender
|
||||||
if (!$.fn.bdatepicker) {
|
Date.superclass.prerender.call(this);
|
||||||
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.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
initPicker: function(options, defaults) {
|
||||||
//'format' is set directly from settings or data-* attributes
|
//'format' is set directly from settings or data-* attributes
|
||||||
|
|
||||||
//by default viewformat equals to format
|
//by default viewformat equals to format
|
||||||
@@ -66,8 +68,8 @@ $(function(){
|
|||||||
//language
|
//language
|
||||||
this.options.datepicker.language = this.options.datepicker.language || 'en';
|
this.options.datepicker.language = this.options.datepicker.language || 'en';
|
||||||
|
|
||||||
//store DPglobal
|
//store DPglobal - use datepicker instead of bdatepicker
|
||||||
this.dpg = $.fn.bdatepicker.DPGlobal;
|
this.dpg = $.fn.datepicker.DPGlobal;
|
||||||
|
|
||||||
//store parsed formats
|
//store parsed formats
|
||||||
this.parsedFormat = this.dpg.parseFormat(this.options.format);
|
this.parsedFormat = this.dpg.parseFormat(this.options.format);
|
||||||
@@ -75,7 +77,22 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
render: function () {
|
render: function () {
|
||||||
this.$input.bdatepicker(this.options.datepicker);
|
// Ensure we have an input element
|
||||||
|
if (!this.$input || !this.$input.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize datepicker immediately
|
||||||
|
try {
|
||||||
|
this.$input.datepicker(this.options.datepicker);
|
||||||
|
|
||||||
|
// Force set the initial value if we have one
|
||||||
|
if (this.value) {
|
||||||
|
this.$input.datepicker('setDate', this.value);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Silently handle datepicker initialization errors
|
||||||
|
}
|
||||||
|
|
||||||
//"clear" link
|
//"clear" link
|
||||||
if(this.options.clear) {
|
if(this.options.clear) {
|
||||||
@@ -90,20 +107,8 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
value2html: function(value, element) {
|
value2html: function(value, element) {
|
||||||
let text = '';
|
var text = value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '';
|
||||||
|
Date.superclass.value2html.call(this, text, element);
|
||||||
if (value) {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
text = value;
|
|
||||||
} else if (value instanceof Date && typeof value.getUTCDate === 'function') {
|
|
||||||
text = this.dpg.formatDate(value, this.parsedFormat, this.options.datepicker.language);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// direct fallback: set text without using editableutils
|
|
||||||
if (element) {
|
|
||||||
element.textContent = text;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
html2value: function(html) {
|
html2value: function(html) {
|
||||||
@@ -111,17 +116,7 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
value2str: function(value) {
|
value2str: function(value) {
|
||||||
if (!value) {
|
return value ? this.dpg.formatDate(value, this.parsedFormat, this.options.datepicker.language) : '';
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// If value is already a string (like "2025-11-27"), just return it.
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, assume it's a Date object and format it.
|
|
||||||
return this.dpg.formatDate(value, this.parsedFormat, this.options.datepicker.language);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
str2value: function(str) {
|
str2value: function(str) {
|
||||||
@@ -133,15 +128,42 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
value2input: function(value) {
|
value2input: function(value) {
|
||||||
this.$input.bdatepicker('update', value);
|
// Ensure datepicker is initialized before trying to update
|
||||||
|
if (!this.$input.data('datepicker')) {
|
||||||
|
this.$input.datepicker(this.options.datepicker);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$input.datepicker('update', value);
|
||||||
},
|
},
|
||||||
|
|
||||||
input2value: function() {
|
input2value: function() {
|
||||||
const dp = this.$input.data('datepicker');
|
var datepicker = this.$input.data('datepicker');
|
||||||
if (dp && typeof dp.getFormattedDate === 'function') {
|
|
||||||
return dp.getFormattedDate(this.options.format || 'yyyy-mm-dd');
|
if (datepicker) {
|
||||||
|
if (datepicker.date) {
|
||||||
|
return datepicker.date;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try getting date from dates array
|
||||||
|
if (datepicker.dates && datepicker.dates.length > 0) {
|
||||||
|
return datepicker.dates[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try using getDate method
|
||||||
|
if (typeof datepicker.getDate === 'function') {
|
||||||
|
var dateFromMethod = datepicker.getDate();
|
||||||
|
return dateFromMethod;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return this.$input.val();
|
|
||||||
|
// Fallback: try to parse the input value directly
|
||||||
|
var inputVal = this.$input.val();
|
||||||
|
if (inputVal) {
|
||||||
|
var parsedDate = this.parseDate(inputVal, this.parsedViewFormat);
|
||||||
|
return parsedDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
activate: function() {
|
activate: function() {
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ Automatically shown in inline mode.
|
|||||||
var DateField = function (options) {
|
var DateField = function (options) {
|
||||||
this.init('datefield', options, DateField.defaults);
|
this.init('datefield', options, DateField.defaults);
|
||||||
this.initPicker(options, DateField.defaults);
|
this.initPicker(options, DateField.defaults);
|
||||||
|
|
||||||
|
// Ensure type is set correctly
|
||||||
|
this.type = 'datefield';
|
||||||
};
|
};
|
||||||
|
|
||||||
$.fn.editableutils.inherit(DateField, $.fn.editabletypes.date);
|
$.fn.editableutils.inherit(DateField, $.fn.editabletypes.date);
|
||||||
@@ -24,8 +27,8 @@ Automatically shown in inline mode.
|
|||||||
this.setClass();
|
this.setClass();
|
||||||
this.setAttr('placeholder');
|
this.setAttr('placeholder');
|
||||||
|
|
||||||
//bootstrap-datepicker is set `bdateicker` to exclude conflict with jQuery UI one. (in date.js)
|
//use datepicker instead of bdatepicker
|
||||||
this.$tpl.bdatepicker(this.options.datepicker);
|
this.$tpl.datepicker(this.options.datepicker);
|
||||||
|
|
||||||
//need to disable original event handlers
|
//need to disable original event handlers
|
||||||
this.$input.off('focus keydown');
|
this.$input.off('focus keydown');
|
||||||
@@ -33,17 +36,48 @@ Automatically shown in inline mode.
|
|||||||
//update value of datepicker
|
//update value of datepicker
|
||||||
this.$input.keyup($.proxy(function(){
|
this.$input.keyup($.proxy(function(){
|
||||||
this.$tpl.removeData('date');
|
this.$tpl.removeData('date');
|
||||||
this.$tpl.bdatepicker('update');
|
this.$tpl.datepicker('update');
|
||||||
}, this));
|
}, this));
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
value2input: function(value) {
|
value2input: function(value) {
|
||||||
this.$input.val(value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '');
|
var formattedValue = value ? this.dpg.formatDate(value, this.parsedViewFormat, this.options.datepicker.language) : '';
|
||||||
this.$tpl.bdatepicker('update');
|
this.$input.val(formattedValue);
|
||||||
|
this.$tpl.datepicker('update');
|
||||||
},
|
},
|
||||||
|
|
||||||
input2value: function() {
|
input2value: function() {
|
||||||
|
// First try the container datepicker (ideal case)
|
||||||
|
var containerDatepicker = this.$tpl.data('datepicker');
|
||||||
|
|
||||||
|
if (containerDatepicker && containerDatepicker.dates && containerDatepicker.dates.length > 0) {
|
||||||
|
return containerDatepicker.dates[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: try the input datepicker (in case manual init worked)
|
||||||
|
var inputDatepicker = this.$input.data('datepicker');
|
||||||
|
|
||||||
|
if (inputDatepicker && inputDatepicker.dates && inputDatepicker.dates.length > 0) {
|
||||||
|
return inputDatepicker.dates[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try getDate methods
|
||||||
|
if (containerDatepicker && typeof containerDatepicker.getDate === 'function') {
|
||||||
|
var containerDate = containerDatepicker.getDate();
|
||||||
|
if (containerDate) {
|
||||||
|
return containerDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputDatepicker && typeof inputDatepicker.getDate === 'function') {
|
||||||
|
var inputDate = inputDatepicker.getDate();
|
||||||
|
if (inputDate) {
|
||||||
|
return inputDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final fallback to text parsing
|
||||||
return this.html2value(this.$input.val());
|
return this.html2value(this.$input.val());
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -60,19 +94,21 @@ Automatically shown in inline mode.
|
|||||||
/**
|
/**
|
||||||
@property tpl
|
@property tpl
|
||||||
**/
|
**/
|
||||||
tpl:'<div class="input-append date"><input type="text"/><span class="add-on"><i class="icon-th"></i></span></div>',
|
tpl:'<div class="input-group input-group-sm date datepicker-above" style="width: 200px; border: 1px solid #dee2e6; border-radius: 0.375rem; position: relative;"><input type="text" class="form-control form-control-sm" style="border: none;"/><span class="input-group-text" style="border: none; background: transparent;"><i class="bi bi-calendar"></i></span></div>',
|
||||||
/**
|
/**
|
||||||
@property inputclass
|
@property inputclass
|
||||||
@default 'input-small'
|
@default 'form-control form-control-sm'
|
||||||
**/
|
**/
|
||||||
inputclass: 'input-small',
|
inputclass: 'form-control form-control-sm',
|
||||||
|
|
||||||
/* datepicker config */
|
/* datepicker config */
|
||||||
datepicker: {
|
datepicker: {
|
||||||
weekStart: 0,
|
weekStart: 0,
|
||||||
startView: 0,
|
startView: 0,
|
||||||
minViewMode: 0,
|
minViewMode: 0,
|
||||||
autoclose: true
|
autoclose: true,
|
||||||
|
orientation: 'top',
|
||||||
|
container: 'body'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
87
src/inputs/select2/lib/select2-bootstrap.css
vendored
Normal file
87
src/inputs/select2/lib/select2-bootstrap.css
vendored
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
.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;
|
||||||
|
}
|
||||||
BIN
src/inputs/select2/lib/select2-spinner.gif
Normal file
BIN
src/inputs/select2/lib/select2-spinner.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
615
src/inputs/select2/lib/select2.css
vendored
Normal file
615
src/inputs/select2/lib/select2.css
vendored
Normal file
@@ -0,0 +1,615 @@
|
|||||||
|
/*
|
||||||
|
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
Normal file
3251
src/inputs/select2/lib/select2.js
vendored
Normal file
File diff suppressed because one or more lines are too long
22
src/inputs/select2/lib/select2.min.js
vendored
Normal file
22
src/inputs/select2/lib/select2.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
src/inputs/select2/lib/select2.png
Normal file
BIN
src/inputs/select2/lib/select2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 613 B |
BIN
src/inputs/select2/lib/select2x2.png
Normal file
BIN
src/inputs/select2/lib/select2x2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 845 B |
242
src/inputs/select2/select2.js
vendored
242
src/inputs/select2/select2.js
vendored
@@ -1,18 +1,21 @@
|
|||||||
/**
|
/**
|
||||||
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/select2/select2.
|
Select2 input. Based on amazing work of Igor Vaynberg https://github.com/ivaynberg/select2.
|
||||||
Please see [Select2 docs](https://select2.org/) for detailed description and options.
|
Please see [original select2 docs](http://ivaynberg.github.com/select2) for detailed description and options.
|
||||||
|
|
||||||
You should manually download and include Select2 v4.x distributive:
|
You should manually download and include select2 distributive:
|
||||||
|
|
||||||
<link href="node_modules/select2/dist/css/select2.css" rel="stylesheet" type="text/css"></link>
|
<link href="select2/select2.css" rel="stylesheet" type="text/css"></link>
|
||||||
<script src="node_modules/select2/dist/js/select2.js"></script>
|
<script src="select2/select2.js"></script>
|
||||||
|
|
||||||
To make it **bootstrap-styled** you can use css from [select2-bootstrap-5-theme](https://github.com/apalfrey/select2-bootstrap-5-theme):
|
To make it **bootstrap-styled** you can use css from [here](https://github.com/t0m/select2-bootstrap-css):
|
||||||
|
|
||||||
<link href="select2-bootstrap-5-theme.css" rel="stylesheet" type="text/css"></link>
|
<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>
|
||||||
|
|
||||||
**Note:** This version requires Select2 v4.x. For remote sources, you may need to provide custom
|
|
||||||
`templateResult` and `templateSelection` functions.
|
|
||||||
|
|
||||||
@class select2
|
@class select2
|
||||||
@extends abstractinput
|
@extends abstractinput
|
||||||
@@ -41,39 +44,35 @@ $(function(){
|
|||||||
minimumInputLength: 1
|
minimumInputLength: 1
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//remote source (advanced) - Select2 v4.x format
|
//remote source (advanced)
|
||||||
$('#country').editable({
|
$('#country').editable({
|
||||||
select2: {
|
select2: {
|
||||||
placeholder: 'Select Country',
|
placeholder: 'Select Country',
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
minimumInputLength: 3,
|
minimumInputLength: 3,
|
||||||
|
id: function (item) {
|
||||||
|
return item.CountryId;
|
||||||
|
},
|
||||||
ajax: {
|
ajax: {
|
||||||
url: '/getCountries',
|
url: '/getCountries',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
delay: 250,
|
data: function (term, page) {
|
||||||
data: function (params) {
|
return { query: term };
|
||||||
return {
|
|
||||||
query: params.term,
|
|
||||||
page: params.page
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
processResults: function (data, params) {
|
results: function (data, page) {
|
||||||
return {
|
return { results: data };
|
||||||
results: data.map(function(item) {
|
}
|
||||||
return {
|
|
||||||
id: item.CountryId,
|
|
||||||
text: item.CountryName
|
|
||||||
};
|
|
||||||
})
|
|
||||||
};
|
|
||||||
},
|
|
||||||
cache: true
|
|
||||||
},
|
},
|
||||||
templateResult: function (item) {
|
formatResult: function (item) {
|
||||||
return item.text || item.CountryName;
|
return item.CountryName;
|
||||||
},
|
},
|
||||||
templateSelection: function (item) {
|
formatSelection: function (item) {
|
||||||
return item.text || item.CountryName;
|
return item.CountryName;
|
||||||
|
},
|
||||||
|
initSelection: function (element, callback) {
|
||||||
|
return $.get('/getCountryById', { query: element.val() }, function (data) {
|
||||||
|
callback(data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -105,19 +104,12 @@ $(function(){
|
|||||||
|
|
||||||
if (typeof source === 'string') {
|
if (typeof source === 'string') {
|
||||||
options.select2.ajax = options.select2.ajax || {};
|
options.select2.ajax = options.select2.ajax || {};
|
||||||
//default ajax params for Select2 v4.x
|
//some default ajax params
|
||||||
if(!options.select2.ajax.data) {
|
if(!options.select2.ajax.data) {
|
||||||
options.select2.ajax.data = function(params) {
|
options.select2.ajax.data = function(term) {return { query:term };};
|
||||||
return {
|
|
||||||
query: params.term,
|
|
||||||
page: params.page
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
if(!options.select2.ajax.processResults) {
|
if(!options.select2.ajax.results) {
|
||||||
options.select2.ajax.processResults = function(data) {
|
options.select2.ajax.results = function(data) { return {results:data };};
|
||||||
return {results: data };
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
options.select2.ajax.url = source;
|
options.select2.ajax.url = source;
|
||||||
} else {
|
} else {
|
||||||
@@ -134,8 +126,16 @@ $(function(){
|
|||||||
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
this.isMultiple = this.options.select2.tags || this.options.select2.multiple;
|
||||||
this.isRemote = ('ajax' in this.options.select2);
|
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
|
//store function that renders text in select2
|
||||||
this.formatSelection = this.options.select2.templateSelection;
|
this.formatSelection = this.options.select2.formatSelection;
|
||||||
if (typeof(this.formatSelection) !== "function") {
|
if (typeof(this.formatSelection) !== "function") {
|
||||||
this.formatSelection = function (e) { return e.text; };
|
this.formatSelection = function (e) { return e.text; };
|
||||||
}
|
}
|
||||||
@@ -147,6 +147,18 @@ $(function(){
|
|||||||
render: function() {
|
render: function() {
|
||||||
this.setClass();
|
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
|
//trigger resize of editableform to re-position container in multi-valued mode
|
||||||
if(this.isMultiple) {
|
if(this.isMultiple) {
|
||||||
@@ -156,33 +168,15 @@ $(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) {
|
value2html: function(value, element) {
|
||||||
var text = '', data,
|
var text = '', data,
|
||||||
that = this;
|
that = this;
|
||||||
|
|
||||||
// Use stored selected data if available (for visual display after selection)
|
if(this.options.select2.tags) { //in tags mode just assign value
|
||||||
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 = value;
|
||||||
|
//data = $.fn.editableutils.itemsByValue(value, this.options.select2.tags, this.idFunc);
|
||||||
} else if(this.sourceData) {
|
} else if(this.sourceData) {
|
||||||
data = $.fn.editableutils.itemsByValue(value, this.sourceData, function(e) { return e.id; });
|
data = $.fn.editableutils.itemsByValue(value, this.sourceData, this.idFunc);
|
||||||
} else {
|
} else {
|
||||||
//can not get list of possible values
|
//can not get list of possible values
|
||||||
//(e.g. autotext for select2 with ajax source)
|
//(e.g. autotext for select2 with ajax source)
|
||||||
@@ -201,6 +195,7 @@ $(function(){
|
|||||||
|
|
||||||
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
text = Array.isArray(text) ? text.join(this.options.viewseparator) : text;
|
||||||
|
|
||||||
|
//$(element).text(text);
|
||||||
Constructor.superclass.value2html.call(this, text, element);
|
Constructor.superclass.value2html.call(this, text, element);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -209,97 +204,46 @@ $(function(){
|
|||||||
},
|
},
|
||||||
|
|
||||||
value2input: function(value) {
|
value2input: function(value) {
|
||||||
|
|
||||||
// if value array => join it anyway
|
// if value array => join it anyway
|
||||||
if(Array.isArray(value)) {
|
if(Array.isArray(value)) {
|
||||||
value = value.join(this.getSeparator());
|
value = value.join(this.getSeparator());
|
||||||
}
|
}
|
||||||
|
|
||||||
// For remote sources with existing value, create option element before Select2 init
|
//for remote source just set value, text is updated by initSelection
|
||||||
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')) {
|
if(!this.$input.data('select2')) {
|
||||||
this.$input.val(value);
|
this.$input.val(value);
|
||||||
this.$input.select2(this.options.select2);
|
this.$input.select2(this.options.select2);
|
||||||
|
|
||||||
// Set up minimal event handling AFTER initialization
|
|
||||||
this.$input.on('select2:select', $.proxy(function(e) {
|
|
||||||
|
|
||||||
if (e.params && e.params.data) {
|
|
||||||
var selectedData = e.params.data;
|
|
||||||
this.selectedData = [selectedData];
|
|
||||||
|
|
||||||
// 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 {
|
} else {
|
||||||
//update value on existing select2
|
//second argument needed to separate initial change from user's click (for autosubmit)
|
||||||
this.$input.val(value).trigger('change.select2');
|
this.$input.val(value).trigger('change', true);
|
||||||
|
|
||||||
|
//Uncaught Error: cannot call val() if initSelection() is not defined
|
||||||
|
//this.$input.select2('val', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(!customId && !customText) {
|
||||||
|
var $el = $(this.options.scope);
|
||||||
|
if (!$el.data('editable').isEmpty) {
|
||||||
|
var data = {id: value, text: $el.text()};
|
||||||
|
this.$input.select2('data', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
input2value: function() {
|
input2value: function() {
|
||||||
var val = this.$input.val();
|
return this.$input.select2('val');
|
||||||
|
},
|
||||||
// --- Handle Bootstrap Datepicker ---
|
|
||||||
var dp = this.$input.data('datepicker');
|
|
||||||
if (dp && typeof dp.getFormattedDate === 'function') {
|
|
||||||
val = dp.getFormattedDate(this.options.format || 'yyyy-mm-dd');
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Handle Select2 v4.x ---
|
|
||||||
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) {
|
str2value: function(str, separator) {
|
||||||
if(typeof str !== 'string' || !this.isMultiple) {
|
if(typeof str !== 'string' || !this.isMultiple) {
|
||||||
@@ -321,10 +265,16 @@ $(function(){
|
|||||||
return val;
|
return val;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
autosubmit: function() {
|
||||||
|
this.$input.on('change', function(e, isInitial){
|
||||||
|
if(!isInitial) {
|
||||||
|
$(this).closest('form').submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
getSeparator: function() {
|
getSeparator: function() {
|
||||||
// Select2 v4.x uses different separator handling
|
return this.options.select2.separator || $.fn.select2.defaults.separator;
|
||||||
return this.options.select2.separator || ',';
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -360,7 +310,7 @@ $(function(){
|
|||||||
**/
|
**/
|
||||||
tpl:'<input type="hidden">',
|
tpl:'<input type="hidden">',
|
||||||
/**
|
/**
|
||||||
Configuration of select2. [Full list of options](https://select2.org/configuration).
|
Configuration of select2. [Full list of options](http://ivaynberg.github.com/select2).
|
||||||
|
|
||||||
@property select2
|
@property select2
|
||||||
@type object
|
@type object
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
href="#"
|
href="#"
|
||||||
id="yes-no-switch"
|
id="yes-no-switch"
|
||||||
class="editable editable-click"
|
class="editable editable-click"
|
||||||
|
data-pk="101"
|
||||||
>
|
>
|
||||||
Yes
|
Yes
|
||||||
</a>
|
</a>
|
||||||
@@ -39,7 +40,7 @@
|
|||||||
id="yes-no-switch-json"
|
id="yes-no-switch-json"
|
||||||
class="editable editable-click"
|
class="editable editable-click"
|
||||||
data-type="select"
|
data-type="select"
|
||||||
data-pk="1"
|
data-pk="102"
|
||||||
data-title="Select Yes/No"
|
data-title="Select Yes/No"
|
||||||
>
|
>
|
||||||
Yes
|
Yes
|
||||||
@@ -55,10 +56,10 @@
|
|||||||
id="datepicker"
|
id="datepicker"
|
||||||
class="editable editable-click"
|
class="editable editable-click"
|
||||||
data-type="date"
|
data-type="date"
|
||||||
data-pk="1"
|
data-pk="103"
|
||||||
data-title="Select Date"
|
data-title="Select Date"
|
||||||
>
|
>
|
||||||
Yes
|
Click to select date
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
37
test.js
37
test.js
@@ -1,18 +1,15 @@
|
|||||||
// debugger
|
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
window.$ = window.jQuery = $;
|
window.$ = window.jQuery = $;
|
||||||
//
|
|
||||||
console.log("jQuery version:", $.fn?.jquery);
|
|
||||||
// // import $ from './dist/jquery';
|
|
||||||
import "bootstrap"
|
import "bootstrap"
|
||||||
import "bootstrap/dist/css/bootstrap.min.css"
|
import "bootstrap/dist/css/bootstrap.min.css"
|
||||||
import "bootstrap-icons/font/bootstrap-icons.min.css"
|
import "bootstrap-icons/font/bootstrap-icons.min.css"
|
||||||
|
|
||||||
|
// bootstrap-datepicker loaded separately (not bundled in grunt build)
|
||||||
import "bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js";
|
import "bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js";
|
||||||
import "bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css";
|
import "bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css";
|
||||||
|
|
||||||
const Editable = require("bootstrap5-editable/js/bootstrap-editable");
|
// Import the editable functionality (attaches to jQuery.fn) - using Grunt-built version
|
||||||
console.log("Editable:", Editable);
|
require("./dist/bootstrap5-editable/js/bootstrap-editable");
|
||||||
$.fn.editable.defaults.mode = 'inline';
|
$.fn.editable.defaults.mode = 'inline';
|
||||||
|
|
||||||
$(function() {
|
$(function() {
|
||||||
@@ -23,18 +20,12 @@ $(function() {
|
|||||||
source: 'test.php', // URL to fetch select options
|
source: 'test.php', // URL to fetch select options
|
||||||
value: 1,
|
value: 1,
|
||||||
success: function(response, newValue) {
|
success: function(response, newValue) {
|
||||||
console.log("Saved successfully:", response);
|
// Handle success
|
||||||
},
|
},
|
||||||
error: function(response) {
|
error: function(response) {
|
||||||
console.error("Save error:", response);
|
// Handle error
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log("Internal editable data:", $('#yes-no-switch').data('editable'));
|
|
||||||
const ed = $('#yes-no-switch').data('editable');
|
|
||||||
console.log("Internal editable data:", ed);
|
|
||||||
if (ed) {
|
|
||||||
console.log("TYPE:", ed.type, "OPTIONS:", ed.options);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -48,16 +39,19 @@ $(function() {
|
|||||||
],
|
],
|
||||||
value: 1,
|
value: 1,
|
||||||
success: function(response, newValue) {
|
success: function(response, newValue) {
|
||||||
console.log("Static source saved successfully:", response);
|
// Handle success
|
||||||
},
|
},
|
||||||
error: function(response) {
|
error: function(response) {
|
||||||
console.error("Static source save error:", response);
|
// Handle error
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const initialDateValue = new Date().toISOString().split('T')[0];
|
||||||
|
|
||||||
$('#datepicker').editable({
|
$('#datepicker').editable({
|
||||||
type: 'date',
|
type: 'date',
|
||||||
url: 'test.php', // URL to send the POST request
|
url: 'test.php', // URL to send the POST request
|
||||||
|
value: initialDateValue, // Set to current date (YYYY-MM-DD)
|
||||||
format: 'yyyy-mm-dd', // Date format
|
format: 'yyyy-mm-dd', // Date format
|
||||||
viewformat: 'dd/mm/yyyy', // How the user sees it
|
viewformat: 'dd/mm/yyyy', // How the user sees it
|
||||||
datepicker: {
|
datepicker: {
|
||||||
@@ -66,18 +60,11 @@ $(function() {
|
|||||||
todayHighlight: true
|
todayHighlight: true
|
||||||
},
|
},
|
||||||
success: (response, newValue)=> {
|
success: (response, newValue)=> {
|
||||||
console.log("Date saved successfully:", response);
|
// Handle success
|
||||||
},
|
},
|
||||||
error: (response) => {
|
error: (response) => {
|
||||||
console.error("Date save error:", response);
|
// Handle error
|
||||||
}
|
}
|
||||||
}).on('shown', (e, editable)=> {
|
|
||||||
console.log("Datepicker shown:", editable);
|
|
||||||
$(editable.input.$input).datepicker({
|
|
||||||
weekStart: 1,
|
|
||||||
autoclose: true,
|
|
||||||
todayHighlight: true
|
|
||||||
}).datepicker('show')
|
|
||||||
});
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ module.exports = [
|
|||||||
new CopyWebpackPlugin({
|
new CopyWebpackPlugin({
|
||||||
patterns: [
|
patterns: [
|
||||||
{ from: "src/editable-form/editable-form.css", to: path.resolve(__dirname, "dist/bootstrap5-editable/css") },
|
{ from: "src/editable-form/editable-form.css", to: path.resolve(__dirname, "dist/bootstrap5-editable/css") },
|
||||||
|
{ from: "node_modules/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css", to: path.resolve(__dirname, "dist/bootstrap5-editable/css") },
|
||||||
{ from: "node_modules/bootstrap-icons/font/fonts", to: path.resolve(__dirname, "dist/fonts") }
|
{ from: "node_modules/bootstrap-icons/font/fonts", to: path.resolve(__dirname, "dist/fonts") }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
@@ -54,7 +55,7 @@ module.exports = [
|
|||||||
|
|
||||||
// X-Editable Plugin (Bootstrap 5)
|
// X-Editable Plugin (Bootstrap 5)
|
||||||
{
|
{
|
||||||
entry: "./src/editable-form/editable-form-bootstrap5.js",
|
entry: "./src/bootstrap5-editable.js",
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, "dist/bootstrap5-editable/js"), // X-Editable stays here
|
path: path.resolve(__dirname, "dist/bootstrap5-editable/js"), // X-Editable stays here
|
||||||
filename: "bootstrap-editable.js",
|
filename: "bootstrap-editable.js",
|
||||||
|
|||||||
Reference in New Issue
Block a user