All files / app/assets/javascripts/deprecated_jquery_dropdown gl_dropdown_filter.js

44.26% Statements 27/61
47.5% Branches 19/40
36.36% Functions 4/11
44.06% Lines 26/59

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139          15x   15x         40x 40x   40x 40x 40x 40x                     40x   40x               16x 7x 9x 3x     16x     16x                         16x 15x   16x 16x 16x 16x           13x 13x                                                       16x                                                     10x                  
import fuzzaldrinPlus from 'fuzzaldrin-plus';
import $ from 'jquery';
import { debounce } from 'lodash';
import { isObject } from '~/lib/utils/type_utility';
 
const BLUR_KEYCODES = [27, 40];
 
const HAS_VALUE_CLASS = 'has-value';
 
export class GitLabDropdownFilter {
  constructor(input, options) {
    let ref;
    this.input = input;
    this.options = options;
    // eslint-disable-next-line no-cond-assign
    this.filterInputBlur = (ref = this.options.filterInputBlur) != null ? ref : true;
    const $inputContainer = this.input.parent();
    const $clearButton = $inputContainer.find('.js-dropdown-input-clear');
    const filterRemoteDebounced = debounce(() => {
      options.instance.dropdown.trigger('filtering.gl.dropdown');
      $inputContainer.parent().addClass('is-loading');
 
      return this.options.query(this.input.val(), (data) => {
        options.instance.dropdown.trigger('done.filtering.gl.dropdown');
        $inputContainer.parent().removeClass('is-loading');
        return this.options.callback(data);
      });
    }, 500);
 
    $clearButton.on('click', this.clear);
    // Key events
    this.input
      .on('keydown', (e) => {
        const keyCode = e.which;
        if (keyCode === 13 && !options.elIsInput) {
          e.preventDefault();
        }
      })
      .on('input', () => {
        if (this.input.val() !== '' && !$inputContainer.hasClass(HAS_VALUE_CLASS)) {
          $inputContainer.addClass(HAS_VALUE_CLASS);
        } else if (this.input.val() === '' && $inputContainer.hasClass(HAS_VALUE_CLASS)) {
          $inputContainer.removeClass(HAS_VALUE_CLASS);
        }
        // Only filter asynchronously only if option remote is set
        Iif (this.options.remote) {
          return filterRemoteDebounced();
        }
        return this.filter(this.input.val());
      });
  }
 
  static shouldBlur(keyCode) {
    return BLUR_KEYCODES.indexOf(keyCode) !== -1;
  }
 
  // eslint-disable-next-line consistent-return
  filter(searchText) {
    let group;
    let results;
    let tmp;
    if (this.options.onFilter) {
      this.options.onFilter(searchText);
    }
    const data = this.options.data();
    Eif (data != null && !this.options.filterByText) {
      results = data;
      if (searchText !== '') {
        // When data is an array of objects therefore [object Array] e.g.
        // [
        //   { prop: 'foo' },
        //   { prop: 'baz' }
        // ]
        if (Array.isArray(data)) {
          results = fuzzaldrinPlus.filter(data, searchText, {
            key: this.options.keys,
          });
        }
        // If data is grouped therefore an [object Object]. e.g.
        // {
        //   groupName1: [
        //     { prop: 'foo' },
        //     { prop: 'baz' }
        //   ],
        //   groupName2: [
        //     { prop: 'abc' },
        //     { prop: 'def' }
        //   ]
        // }
        else Eif (isObject(data)) {
          results = {};
          Object.keys(data).forEach((key) => {
            group = data[key];
            tmp = fuzzaldrinPlus.filter(group, searchText, {
              key: this.options.keys,
            });
            if (tmp.length) {
              results[key] = tmp.map((item) => item);
            }
          });
        }
      }
      return this.options.callback(results);
    }
    const elements = this.options.elements();
    if (searchText) {
      // eslint-disable-next-line func-names
      elements.each(function () {
        const $el = $(this);
        const matches = fuzzaldrinPlus.match($el.text().trim(), searchText);
        if (!$el.is('.dropdown-header')) {
          if (matches.length) {
            $el.show().removeClass('option-hidden');
          } else {
            $el.hide().addClass('option-hidden');
          }
        }
      });
    } else {
      elements.show().removeClass('option-hidden');
    }
 
    elements
      .parent()
      .find('.dropdown-menu-empty-item')
      .toggleClass('hidden', elements.is(':visible'));
  }
 
  clear(e) {
    Eif (this.input.val() === '') return;
    if (e) {
      // Clear click
      e.preventDefault();
      e.stopPropagation();
    }
    this.input.val('').trigger('input').focus();
  }
}