/Detergent/jquery.detergent-1.0.js
JavaScript | 238 lines | 188 code | 14 blank | 36 comment | 25 complexity | 1683f744243e1cd39b4e0dfdea671876 MD5 | raw file
- /*
- * Detergent CascadingDropDown : a jQuery plugin, version: 1.0 (2012-02-10)
- * @requires jQuery v1.7.1 or later
-
- * By Ross Dickinson: http://www.rossisdead.com
- * Based off the CascadingDropDown plugin by Raj Kaimal: https://github.com/rajkaimal/CascadingDropDown
- * Licensed under the MIT: http://www.opensource.org/licenses/mit-license.php
- *
- * Detergent is a jQuery plugin that can be attached to a select list to get automatic population.
- * Each time the source element changes value, an ajax request is made to retrieve a list of values for
- * the select list. The respose from the ajax request should be in json with the following format
- *
- * [{
- * "text": "John",
- * "value": "10326"
- * },
- * {
- * "text": "Jane",
- * "value": "10801"
- * }]
- */
-
- // TODO: Finish the destroy method. Needed on both normal and unobtrusive.
- // TODO: Figure out how this is gonna work with being initialized from ajax content.
- // Don't wanna have the same annoyance that the unobtrusive validation library has.
-
- (function($) {
-
- var detergent = function(options) {
- if (typeof options.parentSelector === undefined) {
- throw 'A parent selector is required';
- }
- if (typeof options.actionPath === undefined) {
- throw 'An action path is requried';
- }
- options = $.extend({}, methods.defaults, options);
- return this.each(function() { methods.initialize($(this), options); });
- };
-
- var methods = {
- 'defaults': {
- // Values that must be set
- 'actionPath': null,
- 'parentSelector': null,
-
- // Optional
- 'async': true,
- 'promptText': '-- Select --',
- 'loadingText': 'Loading ..',
- 'errorText': 'Error loading data.',
- 'unselectedText': '-- Select --',
- 'postData': null,
- 'onLoading': null,
- 'onLoaded': null,
- 'httpMethod': 'GET'
- },
-
- 'addOption': function($select, value, text) {
- $select.append(methods.createOption(value, text));
- },
- 'clear': function($select) {
- $select.empty();
- },
- 'createOption': function(value, text) {
- value = value || '';
- return $('<option></option>')
- .attr('value', value)
- .text(text || value);
- },
- 'destroy': function($select) {
- var options = methods.getOptions($select);
- $(options.parentSelector).unbind('.detergent');
- $select.removeData('options', null);
- $select.removeData('data-cascading-initialized');
- },
- 'disable': function($select) {
- methods.clear($select);
- $select.attr('disabled', 'disabled');
- methods.addOption($select, '', methods.getOptions($select).promptText);
- $select.trigger('change');
- },
- 'enable': function($select) {
- $select.removeAttr('disabled');
- $select.trigger('change');
- },
- 'getOptions': function($select) {
- return $select.data('options');
- },
- 'initialize': function($select, options) {
- var initialized = !(!$select.data('data-cascading-initialized'));
- if (!initialized) {
- methods.setOptions($select, options);
- if ($select.children().size() === 0) {
- methods.disable($select);
- }
- $(options.parentSelector).bind('change.detergent', function() {
- if ($(options.parentSelector).val()) {
- methods.post($select);
- }
- else {
- methods.disable($select);
- }
- });
- $select.data('data-cascading-initialized', true);
- }
- else {
- if (options === 'destroy') {
- methods.destroy($select);
- }
- }
- },
- 'onLoaded': function($select) {
- methods.enable($select);
- var onload = methods.getOptions($select).onLoaded;
- $.isFunction(onload) && onload.call($select);
- },
- 'onLoading': function($select) {
- methods.clear($select);
- var opts = methods.getOptions($select);
- methods.addOption($select, '', opts.loadingText);
- $.isFunction(opts.onLoading) && opts.onLoading.call($select);
- },
- 'onAjaxSuccess': function($select, data) {
- var $data = $(data);
- if ($data.length === 0) {
- methods.disable($select);
- }
- else {
- methods.reset($select);
- $data.each(function() {
- methods.addOption($select, this.value || this.Value, this.text || this.Text);
- });
- methods.onLoaded($select);
- }
- },
- 'post': function($select) {
- methods.onLoading($select);
- var opts = methods.getOptions($select);
- $.ajax({
- 'async': opts.async,
- 'data': ((typeof opts.postData == 'function') ? opts.postData() : opts.postData) || $(opts.parentSelector).serialize(),
- 'dataType': 'json',
- 'error': function() {
- methods.showError($select);
- },
- 'success': function(data) {
- return methods.onAjaxSuccess($select, data);
- },
- 'type': opts.httpMethod,
- 'url': opts.actionPath
- });
- },
- 'reset': function($select) {
- methods.clear($select);
- $select.trigger('change');
- },
- 'setOptions': function($select, value) {
- return $select.data('options', value);
- },
- 'showError': function($select) {
- methods.clear($select);
- methods.addOption($select, '', methods.getOptions($select).errorText);
- }
- };
-
- // This makes our methods easily replacable.
- $.extend(detergent, methods);
- // And finally, make it accessible to jQuery
- $.fn.detergent = detergent;
-
- })(jQuery);
-
-
- (function($) {
-
- var unobtrusiveDetergent = function(options) {
- this.each(function() {
- methods.initialize($(this), options);
- });
- };
-
- var methods = {
- 'initialize': function($dropDown, options) {
- // This makes it easier for us to pass in any group of
- // select elements without having to include the data-cascading
- // attribute check outside of this method.
- if ($dropDown.attr('data-cascading') !== 'true') {
- // No attribute = no init.
- return;
- }
- // meaning someone just called $('something').unobtrusiveDetergent();
- if (!options) {
- var data = methods.getSettings($dropDown);
- // Pass in the data object since it'll count as the various text options
- $dropDown.detergent(data);
- }
- else {
- // The only option to pass at the moment is 'destroy'.
- methods.destroy($dropDown);
- }
- },
- 'destroy': function($dropDown) {
- $dropDown.detergent('destroy');
- },
- 'getSettings': function($dropDown) {
- var data = $dropDown.data('cascadingData');
- if (data == null) {
- data = {
- 'actionPath': $dropDown.attr('data-cascading-action'),
- 'parentSelector': $dropDown.attr('data-cascading-dependson'),
- 'errorText': $dropDown.attr('data-cascading-errortext'),
- 'httpMethod': $dropDown.attr('data-cascading-httpmethod'),
- 'loadingText': $dropDown.attr('data-cascading-loadingtext'),
- 'promptText': $dropDown.attr('data-cascading-prompttext'),
- 'async': methods.getAsync($dropDown)
- };
- $dropDown.data('cascadingData', data);
- }
- return data;
- },
- 'getAsync': function($dropDown) {
- var val = $dropDown.attr('data-cascading-async');
- if (val === undefined) {
- // It's a string, and if it's not set, we're defaulting to true.
- return true;
- }
- else {
- return (val === 'true');
- }
- }
- };
-
- $.fn.unobtrusiveDetergent = unobtrusiveDetergent;
- })(jQuery);
-
- $(document).ready(function() {
- $('select').unobtrusiveDetergent();
- });