Mercurial > hg > rr-repo
diff sites/all/modules/ctools/js/dependent.js @ 0:ff03f76ab3fe
initial version
author | danieleb <danielebarchiesi@me.com> |
---|---|
date | Wed, 21 Aug 2013 18:51:11 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sites/all/modules/ctools/js/dependent.js Wed Aug 21 18:51:11 2013 +0100 @@ -0,0 +1,231 @@ +/** + * @file + * Provides dependent visibility for form items in CTools' ajax forms. + * + * To your $form item definition add: + * - '#process' => array('ctools_process_dependency'), + * - '#dependency' => array('id-of-form-item' => array(list, of, values, that, + * make, this, item, show), + * + * Special considerations: + * - Radios are harder. Because Drupal doesn't give radio groups individual IDs, + * use 'radio:name-of-radio'. + * + * - Checkboxes don't have their own id, so you need to add one in a div + * around the checkboxes via #prefix and #suffix. You actually need to add TWO + * divs because it's the parent that gets hidden. Also be sure to retain the + * 'expand_checkboxes' in the #process array, because the CTools process will + * override it. + */ + +(function ($) { + Drupal.CTools = Drupal.CTools || {}; + Drupal.CTools.dependent = {}; + + Drupal.CTools.dependent.bindings = {}; + Drupal.CTools.dependent.activeBindings = {}; + Drupal.CTools.dependent.activeTriggers = []; + + Drupal.CTools.dependent.inArray = function(array, search_term) { + var i = array.length; + while (i--) { + if (array[i] == search_term) { + return true; + } + } + return false; + } + + + Drupal.CTools.dependent.autoAttach = function() { + // Clear active bindings and triggers. + for (i in Drupal.CTools.dependent.activeTriggers) { + $(Drupal.CTools.dependent.activeTriggers[i]).unbind('change'); + } + Drupal.CTools.dependent.activeTriggers = []; + Drupal.CTools.dependent.activeBindings = {}; + Drupal.CTools.dependent.bindings = {}; + + if (!Drupal.settings.CTools) { + return; + } + + // Iterate through all relationships + for (id in Drupal.settings.CTools.dependent) { + // Test to make sure the id even exists; this helps clean up multiple + // AJAX calls with multiple forms. + + // Drupal.CTools.dependent.activeBindings[id] is a boolean, + // whether the binding is active or not. Defaults to no. + Drupal.CTools.dependent.activeBindings[id] = 0; + // Iterate through all possible values + for(bind_id in Drupal.settings.CTools.dependent[id].values) { + // This creates a backward relationship. The bind_id is the ID + // of the element which needs to change in order for the id to hide or become shown. + // The id is the ID of the item which will be conditionally hidden or shown. + // Here we're setting the bindings for the bind + // id to be an empty array if it doesn't already have bindings to it + if (!Drupal.CTools.dependent.bindings[bind_id]) { + Drupal.CTools.dependent.bindings[bind_id] = []; + } + // Add this ID + Drupal.CTools.dependent.bindings[bind_id].push(id); + // Big long if statement. + // Drupal.settings.CTools.dependent[id].values[bind_id] holds the possible values + + if (bind_id.substring(0, 6) == 'radio:') { + var trigger_id = "input[name='" + bind_id.substring(6) + "']"; + } + else { + var trigger_id = '#' + bind_id; + } + + Drupal.CTools.dependent.activeTriggers.push(trigger_id); + + if ($(trigger_id).attr('type') == 'checkbox') { + $(trigger_id).siblings('label').addClass('hidden-options'); + } + + var getValue = function(item, trigger) { + if ($(trigger).size() == 0) { + return null; + } + + if (item.substring(0, 6) == 'radio:') { + var val = $(trigger + ':checked').val(); + } + else { + switch ($(trigger).attr('type')) { + case 'checkbox': + var val = $(trigger).attr('checked') ? true : false; + + if (val) { + $(trigger).siblings('label').removeClass('hidden-options').addClass('expanded-options'); + } + else { + $(trigger).siblings('label').removeClass('expanded-options').addClass('hidden-options'); + } + + break; + default: + var val = $(trigger).val(); + } + } + return val; + } + + var setChangeTrigger = function(trigger_id, bind_id) { + // Triggered when change() is clicked. + var changeTrigger = function() { + var val = getValue(bind_id, trigger_id); + + if (val == null) { + return; + } + + for (i in Drupal.CTools.dependent.bindings[bind_id]) { + var id = Drupal.CTools.dependent.bindings[bind_id][i]; + // Fix numerous errors + if (typeof id != 'string') { + continue; + } + + // This bit had to be rewritten a bit because two properties on the + // same set caused the counter to go up and up and up. + if (!Drupal.CTools.dependent.activeBindings[id]) { + Drupal.CTools.dependent.activeBindings[id] = {}; + } + + if (val != null && Drupal.CTools.dependent.inArray(Drupal.settings.CTools.dependent[id].values[bind_id], val)) { + Drupal.CTools.dependent.activeBindings[id][bind_id] = 'bind'; + } + else { + delete Drupal.CTools.dependent.activeBindings[id][bind_id]; + } + + var len = 0; + for (i in Drupal.CTools.dependent.activeBindings[id]) { + len++; + } + + var object = $('#' + id + '-wrapper'); + if (!object.size()) { + // Some elements can't use the parent() method or they can + // damage things. They are guaranteed to have wrappers but + // only if dependent.inc provided them. This check prevents + // problems when multiple AJAX calls cause settings to build + // up. + var $original = $('#' + id); + if ($original.is('fieldset') || $original.is('textarea')) { + continue; + } + + object = $('#' + id).parent(); + } + + if (Drupal.settings.CTools.dependent[id].type == 'disable') { + if (Drupal.settings.CTools.dependent[id].num <= len) { + // Show if the element if criteria is matched + object.attr('disabled', false); + object.addClass('dependent-options'); + object.children().attr('disabled', false); + } + else { + // Otherwise hide. Use css rather than hide() because hide() + // does not work if the item is already hidden, for example, + // in a collapsed fieldset. + object.attr('disabled', true); + object.children().attr('disabled', true); + } + } + else { + if (Drupal.settings.CTools.dependent[id].num <= len) { + // Show if the element if criteria is matched + object.show(0); + object.addClass('dependent-options'); + } + else { + // Otherwise hide. Use css rather than hide() because hide() + // does not work if the item is already hidden, for example, + // in a collapsed fieldset. + object.css('display', 'none'); + } + } + } + } + + $(trigger_id).change(function() { + // Trigger the internal change function + // the attr('id') is used because closures are more confusing + changeTrigger(trigger_id, bind_id); + }); + // Trigger initial reaction + changeTrigger(trigger_id, bind_id); + } + setChangeTrigger(trigger_id, bind_id); + } + } + } + + Drupal.behaviors.CToolsDependent = { + attach: function (context) { + Drupal.CTools.dependent.autoAttach(); + + // Really large sets of fields are too slow with the above method, so this + // is a sort of hacked one that's faster but much less flexible. + $("select.ctools-master-dependent") + .once('ctools-dependent') + .change(function() { + var val = $(this).val(); + if (val == 'all') { + $('.ctools-dependent-all').show(0); + } + else { + $('.ctools-dependent-all').hide(0); + $('.ctools-dependent-' + val).show(0); + } + }) + .trigger('change'); + } + } +})(jQuery);