PageSourceSearch

https://up.lawgro.com/sites/all/modules/contrib-custom/better_exposed_filters/better_exposed_filters.js?r62e24

js lawgro.com collected 2026-10-04 17:12:14 UTC 18,277 bytes, 448 lines download raw bytes

1/**
2 * @file better_exposed_filters.js
3 *
4 * Provides some client-side functionality for the Better Exposed Filters module
5 */
6(function ($) {
7  Drupal.behaviors.betterExposedFilters = {
8    attach: function(context) {
9      // Add highlight class to checked checkboxes for better theming
10      $('.bef-tree input[type=checkbox], .bef-checkboxes input[type=checkbox]')
11        // Highlight newly selected checkboxes
12        .change(function() {
13          _bef_highlight(this, context);
14        })
15        .filter(':checked').closest('.form-item', context).addClass('highlight')
16      ;
17    }
18  };
19
20  Drupal.behaviors.betterExposedFiltersSelectAllNone = {
21    attach: function(context) {
22
23      /*
24       * Add Select all/none links to specified checkboxes
25       */
26      var selected = $('.form-checkboxes.bef-select-all-none:not(.bef-processed)');
27      if (selected.length) {
28        var selAll = Drupal.t('Select All');
29        var selNone = Drupal.t('Select None');
30
31        // Set up a prototype link and event handlers
32        var link = $('<a class="bef-toggle" href="#">'+ selAll +'</a>')
33        link.click(function(event) {
34          // Don't actually follow the link...
35          event.preventDefault();
36          event.stopPropagation();
37
38          if (selAll == $(this).text()) {
39            // Select all the checkboxes
40            $(this)
41              .html(selNone)
42              .siblings('.bef-checkboxes, .bef-tree')
43                .find('.form-item input:checkbox').each(function() {
44                  $(this).attr('checked', true);
45                  _bef_highlight(this, context);
46                })
47              .end()
48
49              // attr() doesn't trigger a change event, so we do it ourselves. But just on
50              // one checkbox otherwise we have many spinning cursors
51              .find('input[type=checkbox]:first').change()
52            ;
53          }
54          else {
55            // Unselect all the checkboxes
56            $(this)
57              .html(selAll)
58              .siblings('.bef-checkboxes, .bef-tree')
59                .find('.form-item input:checkbox').each(function() {
60                  $(this).attr('checked', false);
61                  _bef_highlight(this, context);
62                })
63              .end()
64
65              // attr() doesn't trigger a change event, so we do it ourselves. But just on
66              // one checkbox otherwise we have many spinning cursors
67              .find('input[type=checkbox]:first').change()
68            ;
69          }
70        });
71
72        // Add link to the page for each set of checkboxes.
73        selected
74          .addClass('bef-processed')
75          .each(function(index) {
76            // Clone the link prototype and insert into the DOM
77            var newLink = link.clone(true);
78
79            newLink.insertBefore($('.bef-checkboxes, .bef-tree', this));
80
81            // If all checkboxes are already checked by default then switch to Select None
82            if ($('input:checkbox:checked', this).length == $('input:checkbox', this).length) {
83              newLink.click();
84            }
85          })
86        ;
87      }
88
89      // Check for and initialize datepickers
90      var befSettings = Drupal.settings.better_exposed_filters;
91      if (befSettings && befSettings.datepicker && befSettings.datepicker_options && $.fn.datepicker) {
92        var opt = [];
93        $.each(befSettings.datepicker_options, function(key, val) {
94          if (key && val) {
95            opt[key] = JSON.parse(val);
96          }
97        });
98        $('.bef-datepicker').datepicker(opt);
99      }
100
101    }                   // attach: function() {
102  };                    // Drupal.behaviors.better_exposed_filters = {
103
104  Drupal.behaviors.betterExposedFiltersAllNoneNested = {
105    attach:function (context, settings) {
106      $('.form-checkboxes.bef-select-all-none-nested li').has('ul').once('bef-all-none-nested', function () {
107        $(this)
108          // To respect term depth, check/uncheck child term checkboxes.
109          .find('input.form-checkboxes:first')
110          .click(function() {
111            var checkedParent = $(this).attr('checked');
112            if (!checkedParent) {
113              // Uncheck all children if parent is unchecked.
114              $(this).parents('li:first').find('ul input.form-checkboxes').removeAttr('checked');
115            }
116            else {
117              // Check all children if parent is checked.
118              $(this).parents('li:first').find('ul input.form-checkboxes').attr('checked', $(this).attr('checked'));
119            }
120          })
121          .end()
122          // When a child term is checked or unchecked, set the parent term's
123          // status.
124          .find('ul input.form-checkboxes')
125          .click(function() {
126            var checked = $(this).attr('checked');
127
128            // Determine the number of unchecked sibling checkboxes.
129            var ct = $(this).parents('ul:first').find('input.form-checkboxes:not(:checked)').size();
130
131            // If the child term is unchecked, uncheck the parent.
132            if (!checked) {
133              // Uncheck parent if any of the childres is unchecked.
134              $(this).parents('li:first').parents('li:first').find('input.form-checkboxes:first').removeAttr('checked');
135            }
136
137            // If all sibling terms are checked, check the parent.
138            if (!ct) {
139              // Check the parent if all the children are checked.
140              $(this).parents('li:first').parents('li:first').find('input.form-checkboxes:first').attr('checked', checked);
141            }
142          });
143      });
144    }
145  };
146
147  Drupal.behaviors.better_exposed_filters_slider = {
148    attach: function(context, settings) {
149      var befSettings = settings.better_exposed_filters;
150      if (befSettings && befSettings.slider && befSettings.slider_options) {
151        $.each(befSettings.slider_options, function(i, sliderOptions) {
152          var containing_parent = "#" + sliderOptions.viewId + " #edit-" + sliderOptions.id + "-wrapper .views-widget";
153          var $filter = $(containing_parent);
154
155          // If the filter is placed in a secondary fieldset, we may not have
156          // the usual wrapper element.
157          if (!$filter.length) {
158            containing_parent = "#" + sliderOptions.viewId + " .bef-slider-wrapper";
159            $filter = $(containing_parent);
160          }
161
162          // Only make one slider per filter.
163          $filter.once('slider-filter', function() {
164            var $input = $(this).find('input[type=text]');
165
166            // This is a "between" or "not between" filter with two values.
167            if ($input.length == 2) {
168              var $min = $input.parent().find('input#edit-' + sliderOptions.id + '-min'),
169                  $max = $input.parent().find('input#edit-' + sliderOptions.id + '-max'),
170                  default_min,
171                  default_max;
172
173              if (!$min.length || !$max.length) {
174                return;
175              }
176
177              // Get the default values.
178              // We use slider min & max if there are no defaults.
179              default_min = parseFloat(($min.val() == '') ? sliderOptions.min : $min.val(), 10);
180              default_max = parseFloat(($max.val() == '') ? sliderOptions.max : $max.val(), 10);
181              // Set the element value in case we are using the slider min & max.
182              $min.val(default_min);
183              $max.val(default_max);
184
185              $min.parents(containing_parent).after(
186                $('<div class="bef-slider"></div>').slider({
187                  range: true,
188                  min: parseFloat(sliderOptions.min, 10),
189                  max: parseFloat(sliderOptions.max, 10),
190                  step: parseFloat(sliderOptions.step, 10),
191                  animate: sliderOptions.animate ? sliderOptions.animate : false,
192                  orientation: sliderOptions.orientation,
193                  values: [default_min, default_max],
194                  // Update the textfields as the sliders are moved
195                  slide: function (event, ui) {
196                    $min.val(ui.values[0]);
197                    $max.val(ui.values[1]);
198                  },
199                  // This fires when the value is set programmatically or the
200                  // stop event fires.
201                  // This takes care of the case that a user enters a value
202                  // into the text field that is not a valid step of the slider.
203                  // In that case the slider will go to the nearest step and
204                  // this change event will update the text area.
205                  change: function (event, ui) {
206                    $min.val(ui.values[0]);
207                    $max.val(ui.values[1]);
208                  },
209                  // Attach stop listeners.
210                  stop: function(event, ui) {
211                    // Click the auto submit button.
212                    $(this).parents('form').find('.ctools-auto-submit-click').click();
213                  }
214                })
215              );
216
217              // Update the slider when the fields are updated.
218              $min.blur(function() {
219                befUpdateSlider($(this), 0, sliderOptions);
220              });
221              $max.blur(function() {
222                befUpdateSlider($(this), 1, sliderOptions);
223              });
224            }
225            // This is single value filter.
226            else if ($input.length == 1) {
227              if ($input.attr('id') != 'edit-' + sliderOptions.id) {
228                return;
229              }
230
231              // Get the default value. We use slider min if there is no default.
232              var default_value = parseFloat(($input.val() == '') ? sliderOptions.min : $input.val(), 10);
233              // Set the element value in case we are using the slider min.
234              $input.val(default_value);
235
236              $input.parents(containing_parent).after(
237                $('<div class="bef-slider"></div>').slider({
238                  min: parseFloat(sliderOptions.min, 10),
239                  max: parseFloat(sliderOptions.max, 10),
240                  step: parseFloat(sliderOptions.step, 10),
241                  animate: sliderOptions.animate ? sliderOptions.animate : false,
242                  orientation: sliderOptions.orientation,
243                  value: default_value,
244                  // Update the textfields as the sliders are moved.
245                  slide: function (event, ui) {
246                    $input.val(ui.value);
247                  },
248                  // This fires when the value is set programmatically or the
249                  // stop event fires.
250                  // This takes care of the case that a user enters a value
251                  // into the text field that is not a valid step of the slider.
252                  // In that case the slider will go to the nearest step and
253                  // this change event will update the text area.
254                  change: function (event, ui) {
255                    $input.val(ui.value);
256                  },
257                  // Attach stop listeners.
258                  stop: function(event, ui) {
259                    // Click the auto submit button.
260                    $(this).parents('form').find('.ctools-auto-submit-click').click();
261                  }
262                })
263              );
264
265              // Update the slider when the field is updated.
266              $input.blur(function() {
267                befUpdateSlider($(this), null, sliderOptions);
268              });
269            }
270            else {
271              return;
272            }
273          })
274        });
275      }
276    }
277  };
278
279  // This is only needed to provide ajax functionality
280  Drupal.behaviors.better_exposed_filters_select_as_links = {
281    attach: function(context, settings) {
282
283      $('.bef-select-as-links', context).once(function() {
284        var $element = $(this);
285
286        // Check if ajax submission is enabled. If it's not enabled then we
287        // don't need to attach our custom submission handling, because the
288        // links are already properly built.
289
290        // First check if any ajax views are contained in the current page.
291        if (typeof settings.views == 'undefined' || typeof settings.views.ajaxViews == 'undefined') {
292          return;
293        }
294
295        // Now check that the view for which the current filter block is used,
296        // is part of the configured ajax views.
297        var $uses_ajax = false;
298        $.each(settings.views.ajaxViews, function(i, item) {
299          var $view_name = item.view_name.replace(/_/g, '-');
300          var $view_display_id = item.view_display_id.replace(/_/g, '-');
301          var $id = 'views-exposed-form-' + $view_name + '-' + $view_display_id;
302          var $form_id = $element.parents('form').attr('id');
303          if ($form_id == $id) {
304            $uses_ajax = true;
305            return;
306          }
307        });
308
309        // If no ajax is used for form submission, we quit here.
310        if (!$uses_ajax) {
311          return;
312        }
313
314        // Attach selection toggle and form submit on click to each link.
315        $(this).find('a').click(function(event) {
316          var $wrapper = $(this).parents('.bef-select-as-links');
317          var $options = $wrapper.find('select option');
318          // We have to prevent the page load triggered by the links.
319          event.preventDefault();
320          event.stopPropagation();
321          // Un select old select value.
322          $wrapper.find('select option').removeAttr('selected');
323
324          // Set the corresponding option inside the select element as selected.
325          var link_text = $(this).text();
326          $selected = $options.filter(function() {
327            return $(this).text() == link_text;
328          });
329          $selected.attr('selected', 'selected');
330          $wrapper.find('.bef-new-value').val($selected.val());
331          $wrapper.find('a').removeClass('active');
332          $(this).addClass('active');
333          // Submit the form.
334          $wrapper.parents('form').find('.views-submit-button *[type=submit]').click();
335        });
336      });
337    }
338  };
339
340  Drupal.behaviors.betterExposedFiltersRequiredFilter = {
341    attach: function(context, settings) {
342      // Required checkboxes should re-check all inputs if a user un-checks
343      // them all.
344      $('.bef-select-as-checkboxes', context).once('bef-required-filter').ajaxComplete(function (e, xhr, s) {
345        var $element = $(this);
346
347        if (typeof settings.views == 'undefined' || typeof settings.views.ajaxViews == 'undefined') {
348          return;
349        }
350
351        // Now check that the view for which the current filter block is used,
352        // is part of the configured ajax views.
353        var $view_name;
354        var $view_display_id;
355        var $uses_ajax = false;
356        $.each(settings.views.ajaxViews, function(i, item) {
357          $view_name = item.view_name;
358          $view_display_id = item.view_display_id;
359          var $id = 'views-exposed-form-' + $view_name.replace(/_/g, '-') + '-' + $view_display_id.replace(/_/g, '-');
360          var $form_id = $element.parents('form').attr('id');
361          if ($form_id == $id) {
362            $uses_ajax = true;
363            return false;
364          }
365        });
366
367        //Check if we have any filters at all because of Views Selective Filter
368        if($('input', this).length > 0) {
369          var $filter_name = $('input', this).attr('name').slice(0, -2);
370          if (Drupal.settings.better_exposed_filters.views[$view_name].displays[$view_display_id].filters[$filter_name].required && $('input:checked', this).length == 0) {
371            $('input', this).prop('checked', true);
372          }
373        }
374      });
375    }
376  }
377
378  /*
379   * Helper functions
380   */
381
382  /**
383   * Adds/Removes the highlight class from the form-item div as appropriate
384   */
385  function _bef_highlight(elem, context) {
386    $elem = $(elem, context);
387    $elem.attr('checked')
388      ? $elem.closest('.form-item', context).addClass('highlight')
389      : $elem.closest('.form-item', context).removeClass('highlight');
390  }
391
392  /**
393   * Update a slider when a related input element is changed.
394   *
395   * We don't need to check whether the new value is valid based on slider min,
396   * max, and step because the slider will do that automatically and then we
397   * update the textfield on the slider's change event.
398   *
399   * We still have to make sure that the min & max values of a range slider
400   * don't pass each other though, however once this jQuery UI bug is fixed we
401   * won't have to. - http://bugs.jqueryui.com/ticket/3762
402   *
403   * @param $el
404   *   A jQuery object of the updated element.
405   * @param valIndex
406   *   The index of the value for a range slider or null for a non-range slider.
407   * @param sliderOptions
408   *   The options for the current slider.
409   */
410  function befUpdateSlider($el, valIndex, sliderOptions) {
411    var val = parseFloat($el.val(), 10),
412        currentMin = $el.parents('div.views-widget').next('.bef-slider').slider('values', 0),
413        currentMax = $el.parents('div.views-widget').next('.bef-slider').slider('values', 1);
414    // If we have a range slider.
415    if (valIndex != null) {
416      // Make sure the min is not more than the current max value.
417      if (valIndex == 0 && val > currentMax) {
418        val = currentMax;
419      }
420      // Make sure the max is not more than the current max value.
421      if (valIndex == 1 && val < currentMin) {
422        val = currentMin;
423      }
424      // If the number is invalid, go back to the last value.
425      if (isNaN(val)) {
426        val = $el.parents('div.views-widget').next('.bef-slider').slider('values', valIndex);
427      }
428    }
429    else {
430      // If the number is invalid, go back to the last value.
431      if (isNaN(val)) {
432        val = $el.parents('div.views-widget').next('.bef-slider').slider('value');
433      }
434    }
435    // Make sure we are a number again.
436    val = parseFloat(val, 10);
437    // Set the slider to the new value.
438    // The slider's change event will then update the textfield again so that
439    // they both have the same value.
440    if (valIndex != null) {
441      $el.parents('div.views-widget').next('.bef-slider').slider('values', valIndex, val);
442    }
443    else {
444      $el.parents('div.views-widget').next('.bef-slider').slider('value', val);
445    }
446  }
447
448}) (jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.