annotate 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
rev   line source
danielebarchiesi@0 1 /**
danielebarchiesi@0 2 * @file
danielebarchiesi@0 3 * Provides dependent visibility for form items in CTools' ajax forms.
danielebarchiesi@0 4 *
danielebarchiesi@0 5 * To your $form item definition add:
danielebarchiesi@0 6 * - '#process' => array('ctools_process_dependency'),
danielebarchiesi@0 7 * - '#dependency' => array('id-of-form-item' => array(list, of, values, that,
danielebarchiesi@0 8 * make, this, item, show),
danielebarchiesi@0 9 *
danielebarchiesi@0 10 * Special considerations:
danielebarchiesi@0 11 * - Radios are harder. Because Drupal doesn't give radio groups individual IDs,
danielebarchiesi@0 12 * use 'radio:name-of-radio'.
danielebarchiesi@0 13 *
danielebarchiesi@0 14 * - Checkboxes don't have their own id, so you need to add one in a div
danielebarchiesi@0 15 * around the checkboxes via #prefix and #suffix. You actually need to add TWO
danielebarchiesi@0 16 * divs because it's the parent that gets hidden. Also be sure to retain the
danielebarchiesi@0 17 * 'expand_checkboxes' in the #process array, because the CTools process will
danielebarchiesi@0 18 * override it.
danielebarchiesi@0 19 */
danielebarchiesi@0 20
danielebarchiesi@0 21 (function ($) {
danielebarchiesi@0 22 Drupal.CTools = Drupal.CTools || {};
danielebarchiesi@0 23 Drupal.CTools.dependent = {};
danielebarchiesi@0 24
danielebarchiesi@0 25 Drupal.CTools.dependent.bindings = {};
danielebarchiesi@0 26 Drupal.CTools.dependent.activeBindings = {};
danielebarchiesi@0 27 Drupal.CTools.dependent.activeTriggers = [];
danielebarchiesi@0 28
danielebarchiesi@0 29 Drupal.CTools.dependent.inArray = function(array, search_term) {
danielebarchiesi@0 30 var i = array.length;
danielebarchiesi@0 31 while (i--) {
danielebarchiesi@0 32 if (array[i] == search_term) {
danielebarchiesi@0 33 return true;
danielebarchiesi@0 34 }
danielebarchiesi@0 35 }
danielebarchiesi@0 36 return false;
danielebarchiesi@0 37 }
danielebarchiesi@0 38
danielebarchiesi@0 39
danielebarchiesi@0 40 Drupal.CTools.dependent.autoAttach = function() {
danielebarchiesi@0 41 // Clear active bindings and triggers.
danielebarchiesi@0 42 for (i in Drupal.CTools.dependent.activeTriggers) {
danielebarchiesi@0 43 $(Drupal.CTools.dependent.activeTriggers[i]).unbind('change');
danielebarchiesi@0 44 }
danielebarchiesi@0 45 Drupal.CTools.dependent.activeTriggers = [];
danielebarchiesi@0 46 Drupal.CTools.dependent.activeBindings = {};
danielebarchiesi@0 47 Drupal.CTools.dependent.bindings = {};
danielebarchiesi@0 48
danielebarchiesi@0 49 if (!Drupal.settings.CTools) {
danielebarchiesi@0 50 return;
danielebarchiesi@0 51 }
danielebarchiesi@0 52
danielebarchiesi@0 53 // Iterate through all relationships
danielebarchiesi@0 54 for (id in Drupal.settings.CTools.dependent) {
danielebarchiesi@0 55 // Test to make sure the id even exists; this helps clean up multiple
danielebarchiesi@0 56 // AJAX calls with multiple forms.
danielebarchiesi@0 57
danielebarchiesi@0 58 // Drupal.CTools.dependent.activeBindings[id] is a boolean,
danielebarchiesi@0 59 // whether the binding is active or not. Defaults to no.
danielebarchiesi@0 60 Drupal.CTools.dependent.activeBindings[id] = 0;
danielebarchiesi@0 61 // Iterate through all possible values
danielebarchiesi@0 62 for(bind_id in Drupal.settings.CTools.dependent[id].values) {
danielebarchiesi@0 63 // This creates a backward relationship. The bind_id is the ID
danielebarchiesi@0 64 // of the element which needs to change in order for the id to hide or become shown.
danielebarchiesi@0 65 // The id is the ID of the item which will be conditionally hidden or shown.
danielebarchiesi@0 66 // Here we're setting the bindings for the bind
danielebarchiesi@0 67 // id to be an empty array if it doesn't already have bindings to it
danielebarchiesi@0 68 if (!Drupal.CTools.dependent.bindings[bind_id]) {
danielebarchiesi@0 69 Drupal.CTools.dependent.bindings[bind_id] = [];
danielebarchiesi@0 70 }
danielebarchiesi@0 71 // Add this ID
danielebarchiesi@0 72 Drupal.CTools.dependent.bindings[bind_id].push(id);
danielebarchiesi@0 73 // Big long if statement.
danielebarchiesi@0 74 // Drupal.settings.CTools.dependent[id].values[bind_id] holds the possible values
danielebarchiesi@0 75
danielebarchiesi@0 76 if (bind_id.substring(0, 6) == 'radio:') {
danielebarchiesi@0 77 var trigger_id = "input[name='" + bind_id.substring(6) + "']";
danielebarchiesi@0 78 }
danielebarchiesi@0 79 else {
danielebarchiesi@0 80 var trigger_id = '#' + bind_id;
danielebarchiesi@0 81 }
danielebarchiesi@0 82
danielebarchiesi@0 83 Drupal.CTools.dependent.activeTriggers.push(trigger_id);
danielebarchiesi@0 84
danielebarchiesi@0 85 if ($(trigger_id).attr('type') == 'checkbox') {
danielebarchiesi@0 86 $(trigger_id).siblings('label').addClass('hidden-options');
danielebarchiesi@0 87 }
danielebarchiesi@0 88
danielebarchiesi@0 89 var getValue = function(item, trigger) {
danielebarchiesi@0 90 if ($(trigger).size() == 0) {
danielebarchiesi@0 91 return null;
danielebarchiesi@0 92 }
danielebarchiesi@0 93
danielebarchiesi@0 94 if (item.substring(0, 6) == 'radio:') {
danielebarchiesi@0 95 var val = $(trigger + ':checked').val();
danielebarchiesi@0 96 }
danielebarchiesi@0 97 else {
danielebarchiesi@0 98 switch ($(trigger).attr('type')) {
danielebarchiesi@0 99 case 'checkbox':
danielebarchiesi@0 100 var val = $(trigger).attr('checked') ? true : false;
danielebarchiesi@0 101
danielebarchiesi@0 102 if (val) {
danielebarchiesi@0 103 $(trigger).siblings('label').removeClass('hidden-options').addClass('expanded-options');
danielebarchiesi@0 104 }
danielebarchiesi@0 105 else {
danielebarchiesi@0 106 $(trigger).siblings('label').removeClass('expanded-options').addClass('hidden-options');
danielebarchiesi@0 107 }
danielebarchiesi@0 108
danielebarchiesi@0 109 break;
danielebarchiesi@0 110 default:
danielebarchiesi@0 111 var val = $(trigger).val();
danielebarchiesi@0 112 }
danielebarchiesi@0 113 }
danielebarchiesi@0 114 return val;
danielebarchiesi@0 115 }
danielebarchiesi@0 116
danielebarchiesi@0 117 var setChangeTrigger = function(trigger_id, bind_id) {
danielebarchiesi@0 118 // Triggered when change() is clicked.
danielebarchiesi@0 119 var changeTrigger = function() {
danielebarchiesi@0 120 var val = getValue(bind_id, trigger_id);
danielebarchiesi@0 121
danielebarchiesi@0 122 if (val == null) {
danielebarchiesi@0 123 return;
danielebarchiesi@0 124 }
danielebarchiesi@0 125
danielebarchiesi@0 126 for (i in Drupal.CTools.dependent.bindings[bind_id]) {
danielebarchiesi@0 127 var id = Drupal.CTools.dependent.bindings[bind_id][i];
danielebarchiesi@0 128 // Fix numerous errors
danielebarchiesi@0 129 if (typeof id != 'string') {
danielebarchiesi@0 130 continue;
danielebarchiesi@0 131 }
danielebarchiesi@0 132
danielebarchiesi@0 133 // This bit had to be rewritten a bit because two properties on the
danielebarchiesi@0 134 // same set caused the counter to go up and up and up.
danielebarchiesi@0 135 if (!Drupal.CTools.dependent.activeBindings[id]) {
danielebarchiesi@0 136 Drupal.CTools.dependent.activeBindings[id] = {};
danielebarchiesi@0 137 }
danielebarchiesi@0 138
danielebarchiesi@0 139 if (val != null && Drupal.CTools.dependent.inArray(Drupal.settings.CTools.dependent[id].values[bind_id], val)) {
danielebarchiesi@0 140 Drupal.CTools.dependent.activeBindings[id][bind_id] = 'bind';
danielebarchiesi@0 141 }
danielebarchiesi@0 142 else {
danielebarchiesi@0 143 delete Drupal.CTools.dependent.activeBindings[id][bind_id];
danielebarchiesi@0 144 }
danielebarchiesi@0 145
danielebarchiesi@0 146 var len = 0;
danielebarchiesi@0 147 for (i in Drupal.CTools.dependent.activeBindings[id]) {
danielebarchiesi@0 148 len++;
danielebarchiesi@0 149 }
danielebarchiesi@0 150
danielebarchiesi@0 151 var object = $('#' + id + '-wrapper');
danielebarchiesi@0 152 if (!object.size()) {
danielebarchiesi@0 153 // Some elements can't use the parent() method or they can
danielebarchiesi@0 154 // damage things. They are guaranteed to have wrappers but
danielebarchiesi@0 155 // only if dependent.inc provided them. This check prevents
danielebarchiesi@0 156 // problems when multiple AJAX calls cause settings to build
danielebarchiesi@0 157 // up.
danielebarchiesi@0 158 var $original = $('#' + id);
danielebarchiesi@0 159 if ($original.is('fieldset') || $original.is('textarea')) {
danielebarchiesi@0 160 continue;
danielebarchiesi@0 161 }
danielebarchiesi@0 162
danielebarchiesi@0 163 object = $('#' + id).parent();
danielebarchiesi@0 164 }
danielebarchiesi@0 165
danielebarchiesi@0 166 if (Drupal.settings.CTools.dependent[id].type == 'disable') {
danielebarchiesi@0 167 if (Drupal.settings.CTools.dependent[id].num <= len) {
danielebarchiesi@0 168 // Show if the element if criteria is matched
danielebarchiesi@0 169 object.attr('disabled', false);
danielebarchiesi@0 170 object.addClass('dependent-options');
danielebarchiesi@0 171 object.children().attr('disabled', false);
danielebarchiesi@0 172 }
danielebarchiesi@0 173 else {
danielebarchiesi@0 174 // Otherwise hide. Use css rather than hide() because hide()
danielebarchiesi@0 175 // does not work if the item is already hidden, for example,
danielebarchiesi@0 176 // in a collapsed fieldset.
danielebarchiesi@0 177 object.attr('disabled', true);
danielebarchiesi@0 178 object.children().attr('disabled', true);
danielebarchiesi@0 179 }
danielebarchiesi@0 180 }
danielebarchiesi@0 181 else {
danielebarchiesi@0 182 if (Drupal.settings.CTools.dependent[id].num <= len) {
danielebarchiesi@0 183 // Show if the element if criteria is matched
danielebarchiesi@0 184 object.show(0);
danielebarchiesi@0 185 object.addClass('dependent-options');
danielebarchiesi@0 186 }
danielebarchiesi@0 187 else {
danielebarchiesi@0 188 // Otherwise hide. Use css rather than hide() because hide()
danielebarchiesi@0 189 // does not work if the item is already hidden, for example,
danielebarchiesi@0 190 // in a collapsed fieldset.
danielebarchiesi@0 191 object.css('display', 'none');
danielebarchiesi@0 192 }
danielebarchiesi@0 193 }
danielebarchiesi@0 194 }
danielebarchiesi@0 195 }
danielebarchiesi@0 196
danielebarchiesi@0 197 $(trigger_id).change(function() {
danielebarchiesi@0 198 // Trigger the internal change function
danielebarchiesi@0 199 // the attr('id') is used because closures are more confusing
danielebarchiesi@0 200 changeTrigger(trigger_id, bind_id);
danielebarchiesi@0 201 });
danielebarchiesi@0 202 // Trigger initial reaction
danielebarchiesi@0 203 changeTrigger(trigger_id, bind_id);
danielebarchiesi@0 204 }
danielebarchiesi@0 205 setChangeTrigger(trigger_id, bind_id);
danielebarchiesi@0 206 }
danielebarchiesi@0 207 }
danielebarchiesi@0 208 }
danielebarchiesi@0 209
danielebarchiesi@0 210 Drupal.behaviors.CToolsDependent = {
danielebarchiesi@0 211 attach: function (context) {
danielebarchiesi@0 212 Drupal.CTools.dependent.autoAttach();
danielebarchiesi@0 213
danielebarchiesi@0 214 // Really large sets of fields are too slow with the above method, so this
danielebarchiesi@0 215 // is a sort of hacked one that's faster but much less flexible.
danielebarchiesi@0 216 $("select.ctools-master-dependent")
danielebarchiesi@0 217 .once('ctools-dependent')
danielebarchiesi@0 218 .change(function() {
danielebarchiesi@0 219 var val = $(this).val();
danielebarchiesi@0 220 if (val == 'all') {
danielebarchiesi@0 221 $('.ctools-dependent-all').show(0);
danielebarchiesi@0 222 }
danielebarchiesi@0 223 else {
danielebarchiesi@0 224 $('.ctools-dependent-all').hide(0);
danielebarchiesi@0 225 $('.ctools-dependent-' + val).show(0);
danielebarchiesi@0 226 }
danielebarchiesi@0 227 })
danielebarchiesi@0 228 .trigger('change');
danielebarchiesi@0 229 }
danielebarchiesi@0 230 }
danielebarchiesi@0 231 })(jQuery);