diff --git a/._screen16.png b/._screen16.png new file mode 100755 index 0000000..2d14e28 Binary files /dev/null and b/._screen16.png differ diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..354f725 --- /dev/null +++ b/.npmignore @@ -0,0 +1,25 @@ +# Development files +demo/ +test/ +src/ +webpack.config.js +Gruntfile.js + +# IDE files +.idea/ +.claude/ + +# Temporary files +node_modules/ +*.log + +# Webpack dev files +dist/app.js +dist/app.js.* +dist/jquery.js +dist/jquery.js.* + +# Legacy files +Package.nuspec +bower.json +composer.json \ No newline at end of file diff --git a/README.md b/README.md index 4eb3fe8..e854f49 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,11 @@ The demo showcases: ## Installation +### Via npm +```bash +npm install x-editable-bootstrap5 +``` + ### Dependencies This library requires: diff --git a/dist/README.md b/dist/README.md index f8d632b..e854f49 100644 --- a/dist/README.md +++ b/dist/README.md @@ -1,17 +1,123 @@ # X-Editable (Bootstrap 5 Fork) -This project is a fork of [vitalets/x-editable](https://github.com/vitalets/x-editable), adapted to work with **Bootstrap 5** while maintaining compatibility with jQuery. +A drop-in replacement for legacy Bootstrap 3 x-editable projects, modernized for **Bootstrap 5** with jQuery support. ## Why This Fork? -The original **x-editable** library was designed for Bootstrap 3 and has not been actively maintained. This fork modernizes the codebase and updates it to support: -- **Bootstrap 5** -- **Bootstrap Icons** (replacing Glyphicons) +This project was created when we needed a **drop-in replacement** for x-editable in a legacy Bootstrap 3 project. The original [vitalets/x-editable](https://github.com/vitalets/x-editable) library has not been actively maintained and doesn't support Bootstrap 5. -NOTE: This repo has not yet been completely tested and is not available via NPM right now! +**Key Features:** +- **Bootstrap 5** compatibility +- **jQuery** support maintained +- **Select dropdowns** - fully functional +- **Date pickers** - using bootstrap-datepicker +- **Drop-in replacement** - minimal code changes needed +- **Streamlined codebase** - Bootstrap 5 only, legacy code removed -Later: -### Using npm: -```sh +## Demo + +The `/demo` folder contains working examples of the library in action. + +**To run the demo:** +```bash +# In the project root directory +php -S 0.0.0.0:8000 + +# Then visit: http://localhost:8000/demo/ +``` + +The demo showcases: +- Select inputs with AJAX and static data sources +- Date picker functionality +- Basic in-place editing + +## Installation + +### Via npm +```bash npm install x-editable-bootstrap5 ``` + +### Dependencies + +This library requires: +- **Bootstrap 5** (CSS and JS) +- **jQuery 3.x** +- **bootstrap-datepicker** (for date inputs) + +### Quick Start + +1. **Include the CSS and JS files:** +```html + + + + + + + + + + + + + + +``` + +2. **Initialize editable elements:** +```javascript +$('#my-editable').editable({ + type: 'select', + source: [ + {value: 1, text: 'Option 1'}, + {value: 2, text: 'Option 2'} + ], + url: '/update-endpoint' +}); +``` + +## Migration from Bootstrap 3 + +If you're migrating from the original x-editable: + +1. **Update Bootstrap** to version 5 +2. **Add bootstrap-datepicker** dependency (no longer bundled) +3. **Replace x-editable files** with this Bootstrap 5 version +4. **Update CSS classes** if using custom styling (Bootstrap 3 → 5 changes) + +The JavaScript API remains largely the same, making it a true drop-in replacement. + +## Build + +To build the library from source: + +```bash +# Install dependencies +npm install + +# Build with Grunt +grunt build + +# Or build with webpack for demo +npx webpack --mode=development +``` + +## Repository + +**Main Repository:** [git.24unix.net/tracer/x-editable-bs5](https://git.24unix.net/tracer/x-editable-bs5) + +**Mirrors:** +- GitHub: [github.com/24unix/x-editable-bs5](https://github.com/24unix/x-editable-bs5) +- GitLab: [gitlab.com/24unix/x-editable-bs5](https://gitlab.com/24unix/x-editable-bs5) + +Development happens on the main repository at git.24unix.net, with mirrors automatically synced to GitHub and GitLab. + +## License + +This project maintains the same MIT license as the original x-editable project. + +## Credits + +- Original [x-editable](https://github.com/vitalets/x-editable) by [Vitaliy Potapov](https://github.com/vitalets) +- Bootstrap 5 modernization and maintenance by this fork diff --git a/dist/bootstrap5-editable/css/bootstrap-editable.css b/dist/bootstrap5-editable/css/bootstrap-editable.css index 51ab5c7..e5a3dda 100644 --- a/dist/bootstrap5-editable/css/bootstrap-editable.css +++ b/dist/bootstrap5-editable/css/bootstrap-editable.css @@ -1,4 +1,4 @@ -/*! X-editable - v1.5.2 +/*! X-editable Bootstrap 5 - v25.0.1 * A maintained fork of x-editable for Bootstrap 5 support. * https://git.24unix.net/tracer/x-editable * Copyright (c) 2025 Micha Espey; Licensed MIT */ @@ -170,6 +170,45 @@ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); } +/* Bootstrap 5 inline editing fixes */ +.editable-inline .editableform { + display: inline-flex; + align-items: center; + gap: 0.5rem; + flex-wrap: nowrap; +} + +.editable-inline .editable-input { + flex-shrink: 1; + min-width: 0; + max-width: 200px; /* Prevent overly wide selects */ +} + +.editable-inline .editable-input select { + max-width: 100%; + min-width: 120px; +} + +.editable-inline .editable-buttons { + flex-shrink: 0; + margin-left: 0; + display: flex; + align-items: center; + gap: 0.25rem; +} + +/* Improve button styling for Bootstrap 5 */ +.editable-buttons .btn { + padding: 0.25rem 0.5rem; + line-height: 1.2; + border-radius: 0.25rem; +} + +.editable-buttons .btn-sm { + padding: 0.125rem 0.25rem; + font-size: 0.875rem; +} + .editable-container.editable-popup { max-width: none !important; /* without this rule poshytip/tooltip does not stretch */ } diff --git a/dist/bootstrap5-editable/js/bootstrap-editable.js b/dist/bootstrap5-editable/js/bootstrap-editable.js index d12b27d..a0e520a 100644 --- a/dist/bootstrap5-editable/js/bootstrap-editable.js +++ b/dist/bootstrap5-editable/js/bootstrap-editable.js @@ -1,2 +1,4145 @@ -/*! For license information please see bootstrap-editable.js.LICENSE.txt */ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.EditableForm=e():t.EditableForm=e()}(self,(()=>(()=>{var t={12:()=>{!function(t){"use strict";t.fn.editabletypes={};var e=function(){};e.prototype={init:function(e,i,n){this.type=e,this.options=t.extend({},n,i)},prerender:function(){this.$tpl=t(this.options.tpl),this.$input=this.$tpl,this.$clear=null,this.error=null},render:function(){},value2html:function(e,i){t(i)[this.options.escape?"text":"html"](e.trim())},html2value:function(e){return t("
").html(e).text()},value2str:function(t){return t},str2value:function(t){return t},value2submit:function(t){return t},value2input:function(t){this.$input.val(t)},input2value:function(){return this.$input.val()},activate:function(){this.$input.is(":visible")&&this.$input.focus()},clear:function(){this.$input.val(null)},escape:function(e){return t("
").text(e).html()},autosubmit:function(){},destroy:function(){},setClass:function(){this.options.inputclass&&this.$input.addClass(this.options.inputclass)},setAttr:function(t){void 0!==this.options[t]&&null!==this.options[t]&&this.$input.attr(t,this.options[t])},option:function(t,e){this.options[t]=e}},e.defaults={tpl:"",inputclass:null,escape:!0,scope:null,showbuttons:!0},t.extend(t.fn.editabletypes,{abstractinput:e})}(window.jQuery)},45:()=>{!function(t){"use strict";var e=function(t){this.init("text",t,e.defaults)};t.fn.editableutils.inherit(e,t.fn.editabletypes.abstractinput),t.extend(e.prototype,{render:function(){this.renderClear(),this.setClass(),this.setAttr("placeholder")},activate:function(){this.$input.is(":visible")&&(this.$input.focus(),t.fn.editableutils.setCursorPosition(this.$input.get(0),this.$input.val().length),this.toggleClear&&this.toggleClear())},renderClear:function(){this.options.clear&&(this.$clear=t(''),this.$input.after(this.$clear).css("padding-right",24).keyup(t.proxy((function(e){if(!~t.inArray(e.keyCode,[40,38,9,13,27])){clearTimeout(this.t);var i=this;this.t=setTimeout((function(){i.toggleClear(e)}),100)}}),this)).parent().css("position","relative"),this.$clear.click(t.proxy(this.clear,this)))},postrender:function(){},toggleClear:function(t){if(this.$clear){var e=this.$input.val().length,i=this.$clear.is(":visible");e&&!i&&this.$clear.show(),!e&&i&&this.$clear.hide()}},clear:function(){this.$clear.hide(),this.$input.val("").focus()}}),e.defaults=t.extend({},t.fn.editabletypes.abstractinput.defaults,{tpl:'',placeholder:null,clear:!0}),t.fn.editabletypes.text=e}(window.jQuery)},52:()=>{!function(t){"use strict";var e=function(t){this.init("textarea",t,e.defaults)};t.fn.editableutils.inherit(e,t.fn.editabletypes.abstractinput),t.extend(e.prototype,{render:function(){this.setClass(),this.setAttr("placeholder"),this.setAttr("rows"),this.$input.keydown((function(e){e.ctrlKey&&13===e.which&&t(this).closest("form").submit()}))},activate:function(){t.fn.editabletypes.text.prototype.activate.call(this)}}),e.defaults=t.extend({},t.fn.editabletypes.abstractinput.defaults,{tpl:"",inputclass:"input-large",placeholder:null,rows:7}),t.fn.editabletypes.textarea=e}(window.jQuery)},53:()=>{!function(t){"use strict";t.fn.bdatepicker=t.fn.datepicker.noConflict(),t.fn.datepicker||(t.fn.datepicker=t.fn.bdatepicker);var e=function(t){this.init("date",t,e.defaults),this.initPicker(t,e.defaults),this.type="date"};t.fn.editableutils.inherit(e,t.fn.editabletypes.abstractinput),t.extend(e.prototype,{prerender:function(){e.superclass.prerender.call(this)},initPicker:function(e,i){this.options.viewformat||(this.options.viewformat=this.options.format),e.datepicker=t.fn.editableutils.tryParseJson(e.datepicker,!0),this.options.datepicker=t.extend({},i.datepicker,e.datepicker,{format:this.options.viewformat}),this.options.datepicker.language=this.options.datepicker.language||"en",this.dpg=t.fn.datepicker.DPGlobal,this.parsedFormat=this.dpg.parseFormat(this.options.format),this.parsedViewFormat=this.dpg.parseFormat(this.options.viewformat)},render:function(){if(this.$input&&this.$input.length){try{this.$input.datepicker(this.options.datepicker),this.value&&this.$input.datepicker("setDate",this.value)}catch(t){}this.options.clear&&(this.$clear=t('').html(this.options.clear).click(t.proxy((function(t){t.preventDefault(),t.stopPropagation(),this.clear()}),this)),this.$tpl.parent().append(t('
').append(this.$clear)))}},value2html:function(t,i){var n=t?this.dpg.formatDate(t,this.parsedViewFormat,this.options.datepicker.language):"";e.superclass.value2html.call(this,n,i)},html2value:function(t){return this.parseDate(t,this.parsedViewFormat)},value2str:function(t){return t?this.dpg.formatDate(t,this.parsedFormat,this.options.datepicker.language):""},str2value:function(t){return this.parseDate(t,this.parsedFormat)},value2submit:function(t){return this.value2str(t)},value2input:function(t){this.$input.data("datepicker")||this.$input.datepicker(this.options.datepicker),this.$input.datepicker("update",t)},input2value:function(){var t=this.$input.data("datepicker");if(t){if(t.date)return t.date;if(t.dates&&t.dates.length>0)return t.dates[0];if("function"==typeof t.getDate)return t.getDate()}var e=this.$input.val();return e?this.parseDate(e,this.parsedViewFormat):null},activate:function(){},clear:function(){this.$input.data("datepicker").date=null,this.$input.find(".active").removeClass("active"),this.options.showbuttons||this.$input.closest("form").submit()},autosubmit:function(){this.$input.on("mouseup",".day",(function(e){if(!t(e.currentTarget).is(".old")&&!t(e.currentTarget).is(".new")){var i=t(this).closest("form");setTimeout((function(){i.submit()}),200)}}))},parseDate:function(t,e){var i=null;return t&&(i=this.dpg.parseDate(t,e,this.options.datepicker.language),"string"==typeof t&&t!==this.dpg.formatDate(i,e,this.options.datepicker.language)&&(i=null)),i}}),e.defaults=t.extend({},t.fn.editabletypes.abstractinput.defaults,{tpl:'
',inputclass:null,format:"yyyy-mm-dd",viewformat:null,datepicker:{weekStart:0,startView:0,minViewMode:0,autoclose:!1},clear:"× clear"}),t.fn.editabletypes.date=e}(window.jQuery)},243:()=>{!function(t){"use strict";t.fn.editableutils={inherit:function(t,e){var i=function(){};i.prototype=e.prototype,t.prototype=new i,t.prototype.constructor=t,t.superclass=e.prototype},setCursorPosition:function(t,e){if(t.setSelectionRange)t.setSelectionRange(e,e);else if(t.createTextRange){var i=t.createTextRange();i.collapse(!0),i.moveEnd("character",e),i.moveStart("character",e),i.select()}},tryParseJson:function(t,e){if("string"==typeof t&&t.length&&t.match(/^[\{\[].*[\}\]]$/))if(e)try{t=new Function("return "+t)()}catch(t){}finally{return t}else t=new Function("return "+t)();return t},sliceObj:function(t,e,i){var n,s,o={};if(!Array.isArray(e)||!e.length)return o;for(var r=0;r").text(e).html()},itemsByValue:function(e,i,n){if(!i||null===e)return[];if("function"!=typeof n){var s=n||"value";n=function(t){return t[s]}}var o=Array.isArray(e),r=[],a=this;return t.each(i,(function(i,s){if(s.children)r=r.concat(a.itemsByValue(e,s.children,n));else if(o)t.grep(e,(function(t){return t==(s&&"object"==typeof s?n(s):s)})).length&&r.push(s);else{var l=s&&"object"==typeof s?n(s):s;e==l&&r.push(s)}})),r},createInput:function(e){var i,n=e.type;return"date"===n&&("inline"===e.mode?t.fn.editabletypes.datefield?n="datefield":t.fn.editabletypes.dateuifield&&(n="dateuifield"):t.fn.editabletypes.date?n="date":t.fn.editabletypes.dateui&&(n="dateui"),"date"!==n||t.fn.editabletypes.date||(n="combodate")),"datetime"===n&&"inline"===e.mode&&(n="datetimefield"),"wysihtml5"!==n||t.fn.editabletypes[n]||(n="textarea"),"function"==typeof t.fn.editabletypes[n]?new(i=t.fn.editabletypes[n])(this.sliceObj(e,this.objectKeys(i.defaults))):(t.error("Unknown type: "+n),!1)},supportsTransitions:function(){var t=(document.body||document.documentElement).style,e="transition",i=["Moz","Webkit","Khtml","O","ms"];if("string"==typeof t[e])return!0;e=e.charAt(0).toUpperCase()+e.substr(1);for(var n=0;n{!function(t){"use strict";t.extend(t.fn.editableContainer.Inline.prototype,t.fn.editableContainer.Popup.prototype,{containerName:"editableform",innerCss:".editable-inline",containerClass:"editable-container editable-inline",initContainer:function(){this.$tip=t(""),this.options.anim||(this.options.anim=0)},splitOptions:function(){this.containerOptions={},this.formOptions=this.options},tip:function(){return this.$tip},innerShow:function(){this.$element.hide(),this.tip().insertAfter(this.$element).show()},innerHide:function(){this.$tip.hide(this.options.anim,t.proxy((function(){this.$element.show(),this.innerDestroy()}),this))},innerDestroy:function(){this.tip()&&this.tip().empty().remove()}})}(window.jQuery)},418:()=>{!function(t){"use strict";var e=function(t){this.init("select",t,e.defaults)};t.fn.editableutils.inherit(e,t.fn.editabletypes.list),t.extend(e.prototype,{renderList:function(){this.$input.empty();var e=function(i,n){var s;if(Array.isArray(n))for(var o=0;o",s),n[o].children))):(s.value=n[o].value,n[o].disabled&&(s.disabled=!0),i.append(t("