diff --git a/CHANGE.md b/CHANGE.md index ac45b77..27a7eca 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -1,9 +1,13 @@ -version 1.3.1 +version 1.4.0 ============= -**Date:** 28-Nov-2014 +**Date:** 01-Feb-2015 1. Updated trigger of afterChange event 2. Set composer minimum stability to stable. +3. (enh #10): Enhance ability to use checkbox or radio as the first dependent parent. +4. (enh #14): Code cleanup and restructure for various JS lint changes (using JSHint Code cleanup library). +5. (enh #15): Implement reusable constructor for extending plugin if needed. +6. (enh #16): Enhance Select2 dropdowns to show loading indicator. version 1.3.0 ============= diff --git a/README.md b/README.md index 6da49ad..d6e7d2d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A multi level dependent dropdown JQuery plugin that allows nested dependencies. select inputs, whose options are derived based on value selected in another input/or a group of inputs. It works both with normal select options and select with optgroups as well. -> NOTE: The latest version of the plugin v1.3.1 has been released. Refer the [CHANGE LOG](https://github.com/kartik-v/dependent-dropdown/blob/master/CHANGE.md) for details. +> NOTE: The latest version of the plugin v1.4.0 has been released. Refer the [CHANGE LOG](https://github.com/kartik-v/dependent-dropdown/blob/master/CHANGE.md) for details. ## Features diff --git a/bower.json b/bower.json index 73237b2..d1802b7 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "dependent-dropdown", - "version": "1.3.1", + "version": "1.4.0", "homepage": "https://github.com/kartik-v/dependent-dropdown", "authors": [ "Kartik Visweswaran " diff --git a/composer.json b/composer.json index 23b369b..852dbf9 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "homepage": "http://www.krajee.com/" } ], - "minimum-stability": "stable", + "minimum-stability": "stable", "autoload": { "psr-4": { "kartik\\plugins\\depdrop\\": "" diff --git a/css/dependent-dropdown.css b/css/dependent-dropdown.css index 283b124..b1e1dd0 100644 --- a/css/dependent-dropdown.css +++ b/css/dependent-dropdown.css @@ -1,18 +1,21 @@ /*! * @copyright Copyright © Kartik Visweswaran, Krajee.com, 2014 - * @version 1.3.1 + * @version 1.4.0 * * Styling for the dependent-dropdown JQuery plugin. * * For more JQuery plugins visit http://plugins.krajee.com * For more Yii related demos visit http://demos.krajee.com */ - -.kv-loading { +.kv-loading, .select2-container.kv-loading .select2-chosen { background-image: url('../img/loading.gif'); background-position: right 30px center; background-repeat: no-repeat; - z-index: 15000; cursor: wait; opacity: 0.6; +} + +.select2-container.kv-loading .select2-chosen { + background-position: right center; + margin-right: 15px!important; } \ No newline at end of file diff --git a/css/dependent-dropdown.min.css b/css/dependent-dropdown.min.css index 2a82939..0aea23a 100644 --- a/css/dependent-dropdown.min.css +++ b/css/dependent-dropdown.min.css @@ -1,9 +1,9 @@ /*! * @copyright Copyright © Kartik Visweswaran, Krajee.com, 2014 - * @version 1.3.1 - * - * Styling for the dependent-dropdown JQuery plugin. + * @version 1.4.0 * + * Styling for the dependent-dropdown JQuery plugin. + * * For more JQuery plugins visit http://plugins.krajee.com * For more Yii related demos visit http://demos.krajee.com - */ .kv-loading{background-image:url('../img/loading.gif');background-position:right 30px center;background-repeat:no-repeat;z-index:15000;cursor:wait;opacity:.6} \ No newline at end of file + */.kv-loading,.select2-container.kv-loading .select2-chosen{background-image:url(../img/loading.gif);background-position:right 30px center;background-repeat:no-repeat;cursor:wait;opacity:.6}.select2-container.kv-loading .select2-chosen{background-position:right center;margin-right:15px!important} \ No newline at end of file diff --git a/js/dependent-dropdown.js b/js/dependent-dropdown.js index bcaf68d..d067e18 100644 --- a/js/dependent-dropdown.js +++ b/js/dependent-dropdown.js @@ -1,6 +1,6 @@ /*! * @copyright © Kartik Visweswaran, Krajee.com, 2014 - * @version 1.3.1 + * @version 1.4.0 * * A multi level dependent dropdown JQuery plugin. The plugin * allows nested and combined dependencies. @@ -9,132 +9,127 @@ * For more Yii related demos visit http://demos.krajee.com */ (function ($) { + "use strict"; var isEmpty = function (value, trim) { - return typeof value === 'undefined' || value === null || value === undefined || value == [] - || value === '' || trim && $.trim(value) === ''; - }; - var addOption = function ($el, id, name, sel) { - var settings = (id == sel && sel !== null) ? {value: id, text: name, selected: "selected"} : {value: id, text: name}; - $("', {label: i}); + $.each(groups, function (j, option) { + addOption($group, option.id, option.name, defVal); + }); + $group.appendTo($select); + } + }); + return $select.html(); + }, + processDep = function ($el, vUrl, vId, vVal, vDef, vLoad, vLoadCss, vLoadMsg, vNullMsg, vInit, vFunc, vPar) { + var selected, optCount = 0, ajaxData = {depdrop_parents: vVal}, params = {}, settings; + if (!isEmpty(vPar)) { + for (var i = 0; i < vPar.length; i++) { + params[i] = $('#' + vPar[i]).val(); + } + ajaxData = {depdrop_parents: vVal, depdrop_params: params}; + } + settings = { + url: vUrl, + type: 'post', + data: ajaxData, + dataType: 'json', + success: function (data) { + selected = (vInit === false) ? (isEmpty(data.selected) ? null : data.selected) : vInit; + if (isEmpty(data)) { + addOption($el, '', vNullMsg, ''); } - if (data.output.length !== 0) { - $el.val(selected); - $el.removeAttr('disabled'); + else { + $el.html(getSelect(data.output, vDef, selected)); + if ($el.find('optgroup').length > 0) { + $el.find('option[value=""]').attr('disabled', 'disabled'); + } + if (data.output.length !== 0) { + $el.val(selected); + $el.removeAttr('disabled'); + } } + optCount = $el.find('option').length; + if ($el.find('option[value=""]').length > 0) { + optCount -= 1; + } + $el.trigger('depdrop.change', [vId, $("#" + vId).val(), optCount, vInit]); } - optCount = $el.find('option').length; - if ($el.find('option[value=""]').length > 0) { - optCount--; + }; + settings.beforeSend = function () { + $el.trigger('depdrop.beforeChange', [vId, $("#" + vId).val(), vInit]); + $el.attr('disabled', 'disabled'); + $el.html(''); + if (vLoad) { + $el.addClass(vLoadCss); + $el.html(''); } - $el.trigger('depdrop.change', [id, $("#" + id).val(), optCount, initVal]); - } - }; - settings['beforeSend'] = function () { - $el.trigger('depdrop.beforeChange', [id, $("#" + id).val(), initVal]); - $el.attr('disabled', 'disabled'); - $el.html(''); - if (vLoading) { - $el.addClass(vLoadingClass); - $el.html(''); + }; + settings.error = function () { + $el.trigger('depdrop.error', [vId, $("#" + vId).val(), vInit]); + }; + settings.complete = function () { + vFunc(); + if (vLoad) { + $el.removeClass(vLoadCss); + } + $el.trigger('depdrop.afterChange', [vId, $("#" + vId).val(), vInit]); + }; + $.ajax(settings); + }, + initDep = function (j, depends, preset) { + var value = {}, $id, i, initVal = preset[j + 1], + $el = $('#' + depends[j + 1]), len = depends.length; + for (i = 0; i <= j; i++) { + $id = $('#' + depends[i]); + value[i] = $id.val(); } - }; - settings['error'] = function () { - $el.trigger('depdrop.error', [id, $("#" + id).val(), initVal]); - }; - settings['complete'] = function () { - callBack(); - if (vLoading) { - $el.removeClass(vLoadingClass); + if (j < len - 1) { + processDep( + $el, + $el.data('url'), + $el.attr('id'), + value, + $el.data('placeholder'), + $el.data('loading'), + $el.data('loadingClass'), + $el.data('loadingText'), + $el.data('emptyMsg'), + initVal, + function () { + initDep(j + 1, depends, preset); + }, + $el.data('params') + ); } - $el.trigger('depdrop.afterChange', [id, $("#" + id).val(), initVal]); + }, + DepDrop = function (element, options) { + var self = this; + self.$element = $(element); + $.each(options, function (key, value) { + self[key] = value; + }); + self.initData(); + self.init(); }; - return settings; - }; - var initDependency = function (j, depends, preset) { - var $el = $('#' + depends[j]), value = {}, $id, - $elNew = $('#' + depends[j + 1]), len = depends.length; - for (i = 0; i <= j; i++) { - $id = $('#' + depends[i]); - value[i] = $id.val(); - } - var initVal = preset[j + 1]; - if (j < len - 1) { - $.ajax(getSettings($elNew, - $elNew.data('url'), - $elNew.attr('id'), - value, - $elNew.data('placeholder'), - $elNew.data('loading'), - $elNew.data('loadingClass'), - $elNew.data('loadingText'), - $elNew.data('emptyMsg'), - initVal, - function () { - initDependency(j + 1, depends, preset); - }, - $elNew.data('params') - )); - } - }; - // DepDrop public class definition - var DepDrop = function (element, options) { - this.$element = $(element); - this.url = options.url; - this.depends = options.depends; - this.loading = options.loading; - this.loadingClass = options.loadingClass; - this.loadingText = options.loadingText; - this.placeholder = options.placeholder; - this.emptyMsg = options.emptyMsg; - this.initialize = options.initialize; - this.params = options.params; - this.initData(); - this.init(); - }; DepDrop.prototype = { constructor: DepDrop, @@ -151,16 +146,19 @@ self.$element.data('params', self.params); }, init: function () { - var self = this, depends = self.depends, $id, $el, $elNew = null, len = depends.length, val = self.$element.val(), pValue = {}, - chkOptions = self.$element.find('option').length; - if (chkOptions == 0 || self.$element.find('option[value=""]').length == chkOptions) { - self.$element.attr('disabled', 'disabled'); + var self = this, depends = self.depends, $id, $el = self.$element, len = depends.length, + pValue = {}, chkOptions = $el.find('option').length, + handler = function ($elem) { + return function () { + self.setDep($elem, depends, len, false); + }; + }; + if (chkOptions === 0 || $el.find('option[value=""]').length === chkOptions) { + $el.attr('disabled', 'disabled'); } for (var i = 0; i < len; i++) { $id = $('#' + depends[i]); - $id.on('change', function () { - self.setDependency($id, depends, len, false); - }); + $id.on('change', handler($id)); } if (self.initialize === true) { for (var j = 0; j < len; j++) { @@ -168,30 +166,42 @@ pValue[j] = $('#' + depends[j]).val(); } } - depends[len] = self.$element.attr('id'); - pValue[len] = self.$element.val(); - var a = depends.join(), b = ''; + depends[len] = $el.attr('id'); + pValue[len] = $el.val(); $(document).ready(function () { - initDependency(0, depends, pValue); + initDep(0, depends, pValue); }); } - self.$element.trigger('depdrop.init'); + $el.trigger('depdrop.init'); }, - setDependency: function ($id, depends, len, vInitVal) { - var self = this, value = {}, initVal = vInitVal, callBack = function () { - self.$element.trigger('change'); - }; + setDep: function ($elem, depends, len, vInit) { + var self = this, $el, typ, value = {}, initVal = vInit, + callBack = function () { + self.$element.trigger('change'); + }; for (var j = 0; j < len; j++) { - var $el = $('#' + depends[j]); - value[j] = $el.val(); + $el = $('#' + depends[j]); + typ = $el.attr('type'); + value[j] = (typ === "checkbox" || typ === "radio") ? $el.prop('checked') : $el.val(); } - $.ajax(getSettings(self.$element, self.url, $id.attr('id'), value, - self.placeholder, self.loading, self.loadingClass, self.loadingText, self.emptyMsg, initVal, callBack, self.params)); + processDep( + self.$element, + self.url, + $elem.attr('id'), + value, + self.placeholder, + self.loading, + self.loadingClass, + self.loadingText, + self.emptyMsg, + initVal, + callBack, + self.params + ); } }; - //Dependent dropdown plugin definition $.fn.depdrop = function (option) { var args = Array.apply(null, arguments); args.shift(); @@ -201,7 +211,8 @@ options = typeof option === 'object' && option; if (!data) { - $this.data('depdrop', (data = new DepDrop(this, $.extend({}, $.fn.depdrop.defaults, options, $(this).data())))); + $this.data('depdrop', + (data = new DepDrop(this, $.extend({}, $.fn.depdrop.defaults, options, $(this).data())))); } if (typeof option === 'string') { @@ -221,6 +232,8 @@ params: {} }; + $.fn.depdrop.Constructor = DepDrop; + /** * Convert automatically select with class 'depdrop' * into dependent dropdowns. @@ -228,4 +241,4 @@ $(function () { $('select.depdrop').depdrop(); }); -}(jQuery)); +}(window.jQuery)); diff --git a/js/dependent-dropdown.min.js b/js/dependent-dropdown.min.js index 0ba2802..4f5b06f 100644 --- a/js/dependent-dropdown.min.js +++ b/js/dependent-dropdown.min.js @@ -1,10 +1,10 @@ /*! * @copyright © Kartik Visweswaran, Krajee.com, 2014 - * @version 1.3.1 + * @version 1.4.0 * * A multi level dependent dropdown JQuery plugin. The plugin * allows nested and combined dependencies. * * For more JQuery plugins visit http://plugins.krajee.com * For more Yii related demos visit http://demos.krajee.com - */ !function(e){var t=function(t,a){return"undefined"==typeof t||null===t||void 0===t||t==[]||""===t||a&&""===e.trim(t)},a=function(t,a,n,i){var l=a==i&&null!==i?{value:a,text:n,selected:"selected"}:{value:a,text:n};e("",{label:t});e.each(n,function(e,t){a(o,t.id,t.name,d)}),o.appendTo(i)}}),i.html()},d=function(d,i,o,l,r,p,s,u,c,g,f,h){var m,v,y=0,$={depdrop_parents:l},b={};if(!t(h)){for(var x=0;x0&&d.find('option[value=""]').attr("disabled","disabled"),0!==i.output.length&&(d.val(m),d.removeAttr("disabled"))),y=d.find("option").length,d.find('option[value=""]').length>0&&(y-=1),d.trigger("depdrop.change",[o,e("#"+o).val(),y,g])}},v.beforeSend=function(){d.trigger("depdrop.beforeChange",[o,e("#"+o).val(),g]),d.attr("disabled","disabled"),d.html(""),p&&(d.addClass(s),d.html('"))},v.error=function(){d.trigger("depdrop.error",[o,e("#"+o).val(),g])},v.complete=function(){f(),p&&d.removeClass(s),d.trigger("depdrop.afterChange",[o,e("#"+o).val(),g])},e.ajax(v)},i=function(t,a,n){var o,l,r={},p=n[t+1],s=e("#"+a[t+1]),u=a.length;for(l=0;t>=l;l++)o=e("#"+a[l]),r[l]=o.val();u-1>t&&d(s,s.data("url"),s.attr("id"),r,s.data("placeholder"),s.data("loading"),s.data("loadingClass"),s.data("loadingText"),s.data("emptyMsg"),p,function(){i(t+1,a,n)},s.data("params"))},o=function(t,a){var n=this;n.$element=e(t),e.each(a,function(e,t){n[e]=t}),n.initData(),n.init()};o.prototype={constructor:o,initData:function(){var e=this;e.$element.data("url",e.url),e.$element.data("depends",e.depends),e.$element.data("placeholder",e.placeholder),e.$element.data("loading",e.loading),e.$element.data("loadingClass",e.loadingClass),e.$element.data("loadingText",e.loadingText),e.$element.data("emptyMsg",e.emptyMsg),e.$element.data("initialize",e.initialize),e.$element.data("params",e.params)},init:function(){var t,a=this,n=a.depends,d=a.$element,o=n.length,l={},r=d.find("option").length,p=function(e){return function(){a.setDep(e,n,o,!1)}};(0===r||d.find('option[value=""]').length===r)&&d.attr("disabled","disabled");for(var s=0;o>s;s++)t=e("#"+n[s]),t.on("change",p(t));if(a.initialize===!0){for(var u=0;o>u;u++)u>0&&(l[u]=e("#"+n[u]).val());n[o]=d.attr("id"),l[o]=d.val(),e(document).ready(function(){i(0,n,l)})}d.trigger("depdrop.init")},setDep:function(t,a,n,i){for(var o,l,r=this,p={},s=i,u=function(){r.$element.trigger("change")},c=0;n>c;c++)o=e("#"+a[c]),l=o.attr("type"),p[c]="checkbox"===l||"radio"===l?o.prop("checked"):o.val();d(r.$element,r.url,t.attr("id"),p,r.placeholder,r.loading,r.loadingClass,r.loadingText,r.emptyMsg,s,u,r.params)}},e.fn.depdrop=function(t){var a=Array.apply(null,arguments);return a.shift(),this.each(function(){var n=e(this),d=n.data("depdrop"),i="object"==typeof t&&t;d||n.data("depdrop",d=new o(this,e.extend({},e.fn.depdrop.defaults,i,e(this).data()))),"string"==typeof t&&d[t].apply(d,a)})},e.fn.depdrop.defaults={url:"",loading:!0,loadingClass:"kv-loading",loadingText:"Loading ...",placeholder:"Select ...",emptyMsg:"No data found",initialize:!1,params:{}},e.fn.depdrop.Constructor=o,e(function(){e("select.depdrop").depdrop()})}(window.jQuery); \ No newline at end of file