PageSourceSearch

https://www.fhf.fr/themes/custom/fhf_theme/js/source/jquery.sumoselect.js?v=1.2

js fhf.fr collected 2026-09-24 09:25:52 UTC 33,052 bytes, 940 lines download raw bytes

1/*global jQuery, define, module, require*/
2/*!
3 * jquery.sumoselect
4 * http://hemantnegi.github.io/jquery.sumoselect
5 * 2016-12-12
6 *
7 * Copyright 2015 Hemant Negi
8 * Email : [email protected]
9 * Compressor http://refresh-sf.com/
10 */
11
12(function (factory) {
13  'use strict';
14  if (typeof define === 'function' && define.amd) {
15    define(['jquery'], factory);
16  } else if (typeof exports !== 'undefined') {
17    module.exports = factory(require('jquery'));
18  } else {
19    factory(jQuery);
20  }
21
22})(($) => {
23
24  'namespace sumo';
25  $.fn.SumoSelect = function (options) {
26    // Extra check for IE compatibility
27    const dispatchEvent = (target, eventName) => {
28      let event = null;
29      if (typeof (Event) === 'function') {
30        event = new Event(eventName, {
31          bubbles: true
32        });
33      } else {
34        event = document.createEvent('Event');
35        event.initEvent(eventName, true, true);
36      }
37
38      target.dispatchEvent(event);
39    };
40
41    // missing forEach on NodeList for IE11
42    if (window.NodeList && !NodeList.prototype.forEach) {
43      NodeList.prototype.forEach = Array.prototype.forEach;
44    }
45
46    // This is the easiest way to have default options.
47    const defaultOptions = {
48      placeholder: 'Select Here',   // Dont change it here.
49      csvDispCount: 3,              // display no. of items in multiselect. 0 to display all.
50      captionFormat: '{0} Selected', // format of caption text. you can set your locale.
51      captionFormatAllSelected: '{0} all selected!', // format of caption text when all elements are selected. set null to use captionFormat. It will not work if there are disabled elements in select.
52      floatWidth: 400,              // Screen width of device at which the list is rendered in floating popup fashion.
53      forceCustomRendering: false,  // force the custom modal on all devices below floatWidth resolution.
54      nativeOnDevice: ['Android', 'BlackBerry', 'iPhone', 'iPad', 'iPod', 'Opera Mini', 'IEMobile', 'Silk'], //
55      outputAsCSV: false,           // true to POST data as csv ( false for Html control array ie. default select )
56      csvSepChar: ',',              // separation char in csv mode
57      okCancelInMulti: false,       // display ok cancel buttons in desktop mode multiselect also.
58      isClickAwayOk: false,         // for okCancelInMulti=true. sets whether click outside will trigger Ok or Cancel (default is cancel).
59      triggerChangeCombined: true,  // im multi select mode whether to trigger change event on individual selection or combined selection.
60      selectAll: false,             // to display select all button in multiselect mode.|| also select all will not be available on mobile devices.
61      selectAllPartialCheck: true,  // Display a disabled checkbox in multiselect mode when all the items are not selected.
62      search: false,                // to display input for filtering content. selectAlltext will be input text placeholder
63      searchText: 'Search...',      // placeholder for search input
64      searchFn(haystack, needle) { // search function
65        return haystack.toLowerCase().indexOf(needle.toLowerCase()) < 0;
66      },
67      noMatch: 'No matches for "{0}"',
68      prefix: '',                   // some prefix usually the field name. eg. '<b>Hello</b>'
69      locale: ['OK', 'Cancel', 'Select All'],  // all text that is used. don't change the index.
70      up: false,                    // set true to open upside.
71      showTitle: true,              // set to false to prevent title (tooltip) from appearing
72      max: null,                    // Maximum number of options selected (when multiple)
73      // eslint-disable-next-line no-unused-vars
74      renderLi: (li, _originalOption) => li          // Custom <li> item renderer
75    };
76
77    const ret = this.each(function () {
78      const selObj = this; // the original select object.
79      if (this.sumo || !$(this).is('select')) return; //already initialized
80
81      const settings = $.extend({}, defaultOptions, options, $(this).data());
82
83      this.sumo = {
84        E: $(selObj),   //the jquery object of original select element.
85        is_multi: $(selObj).attr('multiple'),  //if its a multiple select
86        select: '',
87        caption: '',
88        placeholder: '',
89        optDiv: '',
90        CaptionCont: '',
91        ul: '',
92        is_floating: false,
93        is_opened: false,
94        //backdrop: '',
95        mob: false, // if to open device default select
96        Pstate: [],
97        lastUnselected: null,
98        selectedCount: 0,
99
100        createElems() {
101          const O = this;
102          const selectedOptions = O.E.find('option:checked');
103          O.E.wrap('<div class="SumoSelect" tabindex="0" role="button" aria-expanded="false">');
104          selectedOptions.each((_, selectedOption) => { // Fix for IE resetting index to 0 when -1
105            selectedOption.selected = true;
106          });
107          O.select = O.E.parent();
108          O.caption = $('<span>');
109          O.CaptionCont = $(`<p class="CaptionCont SelectBox ${O.E.attr('class')}" ><label><i></i></label></p>`)
110            .attr('style', O.E.attr('style'))
111            .prepend(O.caption);
112          O.select.append(O.CaptionCont);
113
114          // default turn off if no multiselect
115          if (!O.is_multi) settings.okCancelInMulti = false;
116
117          if (O.E.attr('disabled'))
118            O.select.addClass('disabled').removeAttr('tabindex');
119
120          //if output as csv and is a multiselect.
121          if (settings.outputAsCSV && O.is_multi && O.E.attr('name')) {
122            //create a hidden field to store csv value.
123            O.select.append($('<input class="HEMANT123" type="hidden" />').attr('name', O.E.attr('name')).val(O.getSelStr()));
124
125            // so it can not post the original select.
126            O.E.removeAttr('name');
127          }
128
129          //break for mobile rendring.. if forceCustomRendering is false
130          if (O.isMobile() && !settings.forceCustomRendering) {
131            O.setNativeMobile();
132            return;
133          }
134
135          // if there is a name attr in select add a class to container div
136          if (O.E.attr('name')) O.select.addClass(`sumo_${O.E.attr('name').replace(/\[\]/, '')}`);
137
138          //hide original select
139          O.E.addClass('SumoUnder').attr('tabindex', '-1');
140
141          //## Creating the list...
142          O.optDiv = $(`<div class="optWrapper ${settings.up ? 'up' : ''}">`);
143
144          //branch for floating list in low res devices.
145          O.floatingList();
146
147          //Creating the markup for the available options
148          O.ul = $('<ul class="options">');
149          O.optDiv.append(O.ul);
150
151          // Select all functionality
152          if (settings.selectAll && O.is_multi && !settings.max) O.SelAll();
153
154          // search functionality
155          if (settings.search) O.Search();
156
157          O.ul.append(O.prepItems(O.E.children()));
158
159          //if multiple then add the class multiple and add OK / CANCEL button
160          if (O.is_multi) O.multiSelelect();
161
162          O.select.append(O.optDiv);
163          O._handleMax();
164          O.basicEvents();
165          O.selAllState();
166        },
167
168        prepItems(opts, d) {
169          const lis = [], O = this;
170          $(opts).each((i, opt) => {       // parsing options to li
171            const $opt = $(opt);
172            lis.push($opt.is('optgroup') ?
173              $(`<li class="group ${opt.disabled ? 'disabled' : ''}"><label></label><ul></ul></li>`)
174                .find('label')
175                .text($opt.attr('label'))
176                .end()
177                .find('ul')
178                .append(O.prepItems($opt.children(), opt.disabled))
179                .end()
180              :
181              O.createLi($opt, d)
182            );
183          });
184          return lis;
185        },
186
187        //## Creates a LI element from a given option and binds events to it
188        //## returns the jquery instance of li (not inserted in dom)
189        createLi(opt, d) {
190          const O = this;
191
192          if (!opt.attr('value')) opt.attr('value', opt.val());
193          const li = $(`<li class="opt"><label>${opt.html()}</label></li>`);
194
195          li.data('opt', opt);    // store a direct reference to option.
196          opt.data('li', li);    // store a direct reference to list item.
197          if (O.is_multi) li.prepend('<span><i></i></span>');
198
199          if (opt[0].disabled || d)
200            li.addClass('disabled');
201
202          O.onOptClick(li);
203
204          if (opt[0].selected) {
205            li.addClass('selected');
206            O.selectedCount++;
207          }
208
209          if (opt.attr('class'))
210            li.addClass(opt.attr('class'));
211
212          if (opt.attr('title'))
213            li.attr('title', opt.attr('title'));
214
215          return settings.renderLi(li, opt);
216        },
217
218        //## Returns the selected items as string in a Multiselect.
219        getSelStr() {
220          // get the pre selected items.
221          const sopt = [];
222          this.E.find('option:checked').each(function () { sopt.push($(this).val()); });
223          return sopt.join(settings.csvSepChar);
224        },
225
226        //## THOSE OK/CANCEL BUTTONS ON MULTIPLE SELECT.
227        multiSelelect() {
228          const O = this;
229          O.optDiv.addClass('multiple');
230          O.okbtn = $('<p tabindex="0" class="btnOk"></p>').click(() => {
231            //if combined change event is set.
232            O._okbtn();
233            O.hideOpts();
234          });
235          [O.okbtn[0].innerText] = settings.locale;
236
237          O.cancelBtn = $('<p tabindex="0" class="btnCancel"></p>').click(() => {
238            O._cnbtn();
239            O.hideOpts();
240          });
241          [, O.cancelBtn[0].innerText] = settings.locale;
242
243          const btns = O.okbtn.add(O.cancelBtn);
244          O.optDiv.append($('<div class="MultiControls">').append(btns));
245
246          // handling keyboard navigation on ok cancel buttons.
247          btns.on('keydown.sumo', function (e) {
248            const el = $(this);
249            switch (e.which) {
250              case 32: // space
251              case 13: // enter
252                el.trigger('click');
253                break;
254
255              case 9:  //tab
256                if (el.hasClass('btnOk')) return;
257                break;
258              case 27: // esc
259                O._cnbtn();
260                O.hideOpts();
261                return;
262              default:
263                break;
264            }
265            e.stopPropagation();
266            e.preventDefault();
267          });
268        },
269
270        _okbtn() {
271          const O = this;
272          let cg = 0;
273          //if combined change event is set.
274          if (settings.triggerChangeCombined) {
275            //check for a change in the selection.
276            if (O.E.find('option:checked').length !== O.Pstate.length) {
277              cg = 1;
278            }
279            else {
280              O.E.find('option').each((i, e) => {
281                if (e.selected && O.Pstate.indexOf(i) < 0) cg = 1;
282              });
283            }
284
285            if (cg) {
286              O.callChange();
287              O.setText();
288            }
289          }
290        },
291        _cnbtn() {
292          const O = this;
293          //remove all selections
294          O.E.find('option:checked').each(function () { this.selected = false; });
295          O.optDiv.find('li.selected').removeClass('selected');
296
297          //restore selections from saved state.
298          for (let i = 0; i < O.Pstate.length; i++) {
299            O.E.find('option')[O.Pstate[i]].selected = true;
300            O.ul.find('li.opt').eq(O.Pstate[i]).addClass('selected');
301          }
302          O.selAllState();
303        },
304
305        _handleMax() {
306          // Disable options if max reached
307          if (settings.max) {
308            if (this.selectedCount >= +settings.max) {
309              this.optDiv.find('li.opt').not('.hidden').each((ix, e) => {
310                if (!$(e).hasClass('selected')) {
311                  $(e).addClass('temporary-disabled disabled');
312                }
313              });
314            } else {
315              // Enable options back
316              this.optDiv.find('li.opt').not('.hidden').each((ix, e) => {
317                if ($(e).hasClass('temporary-disabled')) {
318                  $(e).removeClass('temporary-disabled disabled');
319                }
320              });
321            }
322          }
323        },
324
325        SelAll() {
326          const O = this;
327          if (!O.is_multi) return;
328          O.selAll = $('<p class="select-all"><span><i></i></span><label></label></p>');
329          [, , O.selAll.find('label')[0].innerText] = settings.locale;
330          O.optDiv.addClass('selall');
331          O.selAll.on('click', () => {
332            O.selAll.toggleClass('selected');
333            O.toggSelAll(O.selAll.hasClass('selected'), 1);
334            O.selAllState();
335          });
336
337          O.optDiv.prepend(O.selAll);
338        },
339
340        // search module (can be removed if not required.)
341        Search() {
342          const O = this,
343            cc = O.CaptionCont.addClass('search'),
344            P = $('<p class="no-match">'),
345            fn = (options.searchFn && typeof options.searchFn === 'function') ? options.searchFn : settings.searchFn;
346
347          O.ftxt = $('<input type="text" class="search-txt" value="" autocomplete="off">')
348            .on('click', (e) => {
349              e.stopPropagation();
350            });
351          O.ftxt[0].placeholder = settings.searchText;
352          cc.append(O.ftxt);
353          O.optDiv.children('ul').after(P);
354
355          O.ftxt.on('keyup.sumo', () => {
356            const hid = O.optDiv.find('ul.options li.opt').each((ix, e) => {
357              const el = $(e),
358                { 0: opt } = el.data('opt');
359              opt.hidden = fn(el.text(), O.ftxt.val(), el);
360              el.toggleClass('hidden', opt.hidden);
361            }).not('.hidden');
362
363            // Hide opt-groups with no options matched
364            O.optDiv[0].querySelectorAll('li.group').forEach(optGroup => {
365              if (optGroup.querySelector('li:not(.hidden)')) {
366                optGroup.classList.remove('hidden');
367              } else {
368                optGroup.classList.add('hidden');
369              }
370            });
371
372            P.html(settings.noMatch.replace(/\{0\}/g, '<em></em>')).toggle(!hid.length);
373            P.find('em').text(O.ftxt.val());
374            O.selAllState();
375          });
376        },
377
378        selAllState() {
379          const O = this;
380          if (settings.selectAll && O.is_multi) {
381            let sc = 0, vc = 0;
382            O.optDiv.find('li.opt:not(.disabled):not(.hidden)').each((ix, e) => {
383              if ($(e).hasClass('selected')) sc++;
384              vc++;
385            });
386            //select all checkbox state change.
387            if (sc === vc)  O.selAll.removeClass('partial').addClass('selected');
388            else if (sc === 0) O.selAll.removeClass('selected partial');
389            else {
390              if(settings.selectAllPartialCheck) {
391                O.selAll.addClass('partial')
392              }
393              O.selAll.removeClass('selected');
394            }
395          }
396        },
397
398        showOpts() {
399          const O = this;
400          if (O.E.attr('disabled')) return; // if select is disabled then retrun
401          O.E.trigger('sumo:opening', O);
402          O.is_opened = true;
403          O.select.addClass('open').attr('aria-expanded', 'true');
404          O.E.trigger('sumo:opened', O);
405
406          if (O.ftxt) O.ftxt.focus();
407          else O.select.focus();
408
409          // hide options on click outside.
410          $(document).on('click.sumo', (e) => {
411            if (!O.select.is(e.target)                  // if the target of the click isn't the container...
412              && O.select.has(e.target).length === 0) { // ... nor a descendant of the container
413              if (!O.is_opened) return;
414              O.hideOpts();
415              if (settings.okCancelInMulti) {
416                if (settings.isClickAwayOk)
417                  O._okbtn();
418                else
419                  O._cnbtn();
420              }
421            }
422          });
423
424          if (O.is_floating) {
425            let H = O.optDiv.children('ul').outerHeight() + 2;  // +2 is clear fix
426            if (O.is_multi) H = H + +O.optDiv.css('padding-bottom');
427            O.optDiv.css('height', H);
428            $('body').addClass('sumoStopScroll');
429          }
430
431          O.setPstate();
432        },
433
434        //maintain state when ok/cancel buttons are available storing the indexes.
435        setPstate() {
436          const O = this;
437          if (O.is_multi && (O.is_floating || settings.okCancelInMulti)) {
438            O.Pstate = [];
439            // assuming that find returns elements in tree order
440            O.E.find('option').each((i, e) => { if (e.selected) O.Pstate.push(i); });
441          }
442        },
443
444        callChange() {
445          this.E.get().forEach(e => {
446            dispatchEvent(e, 'change');
447            dispatchEvent(e, 'click');
448          });
449        },
450
451        hideOpts() {
452          const O = this;
453          if (O.is_opened) {
454            O.E.trigger('sumo:closing', O);
455            O.is_opened = false;
456            O.select.removeClass('open').attr('aria-expanded', 'false').find('ul li.sel').removeClass('sel');
457            O.E.trigger('sumo:closed', O);
458            $(document).off('click.sumo');
459            $('body').removeClass('sumoStopScroll');
460
461            // clear the search
462            if (settings.search) {
463              O.ftxt.val('');
464              O.ftxt.trigger('keyup.sumo');
465            }
466          }
467        },
468        setOnOpen() {
469          const O = this;
470          let li = O.optDiv.find('li.opt:not(.hidden)').eq(settings.search ? 0 : O.E[0].selectedIndex);
471          if (li.hasClass('disabled')) {
472            li = li.next(':not(disabled)');
473            if (!li.length) return;
474          }
475          O.optDiv.find('li.sel').removeClass('sel');
476          li.addClass('sel');
477          O.showOpts();
478        },
479        nav(up) {
480          const O = this;
481          let c = null, sel = O.ul.find('li.opt.sel:not(.hidden)');
482          const
483            s = O.ul.find('li.opt:not(.disabled):not(.hidden)'),
484            idx = s.index(sel);
485          if (O.is_opened && sel.length) {
486            if (up && idx > 0)
487              c = s.eq(idx - 1);
488            else if (!up && idx < s.length - 1 && idx > -1)
489              c = s.eq(idx + 1);
490            else return; // if no items before or after
491
492            sel.removeClass('sel');
493            sel = c.addClass('sel');
494
495            // setting sel item to visible view.
496            const { ul } = O,
497              st = ul.scrollTop(),
498              t = sel.position().top + st;
499            if (t >= st + ul.height() - sel.outerHeight())
500              ul.scrollTop(t - ul.height() + sel.outerHeight());
501            if (t < st)
502              ul.scrollTop(t);
503
504          }
505          else
506            O.setOnOpen();
507        },
508
509        basicEvents() {
510          const O = this;
511          O.CaptionCont.click((evt) => {
512            O.E.trigger('click');
513            if (O.is_opened) O.hideOpts(); else O.showOpts();
514            evt.stopPropagation();
515          });
516
517          O.select.on('keydown.sumo', (e) => {
518            switch (e.which) {
519              case 38: // up
520                O.nav(true);
521                break;
522
523              case 40: // down
524                O.nav(false);
525                break;
526
527              case 65: // shortcut ctrl + a to select all and ctrl + shift + a to unselect all.
528                if (O.is_multi && !settings.max && e.ctrlKey) {
529                  O.toggSelAll(!e.shiftKey, 1);
530                  break;
531                }
532                else
533                  return;
534
535              case 32: // space
536                if (settings.search && O.ftxt.is(e.target)) return;
537                break;
538              case 13: // enter
539                if (O.is_opened)
540                  O.optDiv.find('ul li.sel').trigger('click');
541                else
542                  O.setOnOpen();
543                break;
544              case 9:	 //tab
545                if (!settings.okCancelInMulti)
546                  O.hideOpts();
547                return;
548              case 27: // esc
549                if (settings.okCancelInMulti) O._cnbtn();
550                O.hideOpts();
551                return;
552
553              default:
554                return; // exit this handler for other keys
555            }
556            e.preventDefault(); // prevent the default action (scroll / move caret)
557          });
558
559          $(window).on('resize.sumo', () => {
560            O.floatingList();
561          });
562        },
563
564        onOptClick(li) {
565          const O = this;
566          li.click(function () {
567            const $li = $(this);
568            if ($li.hasClass('disabled')) return;
569            if (O.is_multi) {
570              $li.toggleClass('selected');
571              $li.data('opt')[0].selected = $li.hasClass('selected');
572              if ($li.data('opt')[0].selected === false) {
573                O.lastUnselected = $li.data('opt')[0].textContent;
574                O.selectedCount--;
575              } else {
576                O.selectedCount++;
577              }
578
579              if (settings.max) {
580                O._handleMax();
581              }
582
583              O.selAllState();
584            }
585            else {
586              $li.parent().find('li.selected').removeClass('selected'); //if not multiselect then remove all selections from this list
587              $li.toggleClass('selected');
588              $li.data('opt')[0].selected = true;
589              O.selectedCount = 1;
590            }
591
592            //branch for combined change event.
593            if (!(O.is_multi && settings.triggerChangeCombined && (O.is_floating || settings.okCancelInMulti))) {
594              O.setText();
595              O.callChange();
596            }
597
598            if (!O.is_multi) O.hideOpts(); //if its not a multiselect then hide on single select.
599          });
600        },
601
602        // fixed some variables that were not explicitly typed (michc)
603        setText() {
604          const O = this;
605          O.placeholder = "";
606          if (O.is_multi) {
607            const sels = O.E.find(':checked').not(':disabled'); //selected options.
608
609            if (settings.csvDispCount && sels.length > settings.csvDispCount) {
610              if (sels.length === O.E.find('option').length && settings.captionFormatAllSelected) {
611                O.placeholder = settings.captionFormatAllSelected.replace(/\{0\}/g, sels.length);
612              }
613              else {
614                O.placeholder = settings.captionFormat.replace(/\{0\}/g, sels.length);
615              }
616            }
617            else {
618              O.placeholder = sels.toArray().map(selected => selected.innerText).join(', ');
619            }
620          }
621          else {
622            O.placeholder = O.E.find(':checked').not(':disabled').text();
623          }
624
625          let is_placeholder = false;
626
627          if (!O.placeholder) {
628
629            is_placeholder = true;
630
631            O.placeholder = O.E.attr('placeholder');
632            if (!O.placeholder)                  //if placeholder is there then set it
633              O.placeholder = O.E.find('option:disabled:checked').text();
634          }
635
636          O.placeholder = O.placeholder ? (`${settings.prefix} ${O.placeholder}`) : settings.placeholder;
637
638          //set display text
639          O.caption.text(O.placeholder);
640          if (settings.showTitle) O.CaptionCont.attr('title', O.placeholder);
641
642          //set the hidden field if post as csv is true.
643          const csvField = O.select.find('input.HEMANT123');
644          if (csvField.length) csvField.val(O.getSelStr());
645
646          //add class placeholder if its a placeholder text.
647          if (is_placeholder) O.caption.addClass('placeholder'); else O.caption.removeClass('placeholder');
648          return O.placeholder;
649        },
650
651        isMobile() {
652
653          // Adapted from http://www.detectmobilebrowsers.com
654          const ua = navigator.userAgent || navigator.vendor || window.opera;
655
656          // Checks for iOs, Android, Blackberry, Opera Mini, and Windows mobile devices
657          for (let i = 0; i < settings.nativeOnDevice.length; i++) if (ua.toString().toLowerCase().indexOf(settings.nativeOnDevice[i].toLowerCase()) > 0) return settings.nativeOnDevice[i];
658          return false;
659        },
660
661        setNativeMobile() {
662          const O = this;
663          O.E.addClass('SelectClass');//.css('height', O.select.outerHeight());
664          O.mob = true;
665          O.E.change(() => {
666            O.setText();
667          });
668        },
669
670        floatingList() {
671          const O = this;
672          //called on init and also on resize.
673          //O.is_floating = true if window width is < specified float width
674          O.is_floating = $(window).width() <= settings.floatWidth;
675
676          //set class isFloating
677          O.optDiv.toggleClass('isFloating', O.is_floating);
678
679          //remove height if not floating
680          if (!O.is_floating) O.optDiv.css('height', '');
681
682          //toggle class according to okCancelInMulti flag only when it is not floating
683          O.optDiv.toggleClass('okCancelInMulti', settings.okCancelInMulti && !O.is_floating);
684        },
685
686        //HELPERS FOR OUTSIDERS
687        // validates range of given item operations
688        vRange(i) {
689          const O = this;
690          const opts = O.E.find('option');
691          if (opts.length <= i || i < 0) throw new Error("index out of bounds");
692          return O;
693        },
694
695        //toggles selection on c as boolean.
696        toggSel(c, i) {
697          const O = this;
698          let opt = null;
699          if (typeof (i) === "number") {
700            O.vRange(i);
701            opt = O.E.find('option')[i];
702          }
703          else {
704            opt = O.E.find(`option[value="${i}"]`)[0] || 0;
705          }
706          if (!opt || opt.disabled)
707            return;
708
709          if (opt.selected !== c) {
710            if ((settings.max && !opt.selected && O.selectedCount < settings.max) || opt.selected || (!settings.max && !opt.selected)) {
711              opt.selected = c;
712              if (!O.mob) $(opt).data('li').toggleClass('selected', c);
713
714              O.callChange();
715              O.setPstate();
716              O.setText();
717              O.selAllState();
718            }
719          }
720        },
721
722        //toggles disabled on c as boolean.
723        toggDis(c, i) {
724          const O = this.vRange(i);
725          O.E.find('option')[i].disabled = c;
726          if (c) O.E.find('option')[i].selected = false;
727          if (!O.mob) O.optDiv.find('ul.options li.opt').eq(i).toggleClass('disabled', c).removeClass('selected');
728          O.setText();
729        },
730
731        // toggle disable/enable on complete select control
732        toggSumo(val) {
733          const O = this;
734          O.enabled = val;
735          O.select.toggleClass('disabled', val);
736
737          if (val) {
738            O.E.attr('disabled', 'disabled');
739            O.select.removeAttr('tabindex');
740          }
741          else {
742            O.E.removeAttr('disabled');
743            O.select.attr('tabindex', '0');
744          }
745
746          return O;
747        },
748
749        // toggles all option on c as boolean.
750        // set direct=false/0 bypasses okCancelInMulti behaviour.
751        toggSelAll(c, direct) {
752          const O = this;
753          const cloneOriginalEvents = $.extend(true, {}, $._data(O.E.get(0), "events")); // clone original select elements events
754          O.E.off(); // unbind original select elements events because we do not want the following clicks to trigger change on it
755
756          if (O.is_multi) {
757            // Select all
758            if (c) {
759              O.E.find('option:not(:checked):not(:disabled):not(:hidden)').toArray().forEach(option => {
760                if (!$(option).data('li').hasClass('hidden')) {
761                  option.selected = true;
762                  $(option).data('li').toggleClass('selected', true);
763                }
764              });
765            } else {
766              // Unselect all
767              O.E.find('option:checked:not(:disabled):not(:hidden)').toArray().forEach(option => {
768                if (!$(option).data('li').hasClass('hidden')) {
769                  option.selected = false;
770                  $(option).data('li').toggleClass('selected', false);
771                }
772              });
773            }
774          } else {
775            if (!c) O.E[0].selectedIndex = -1;
776            else console.warn('You called `SelectAll` on a non-multiple select');
777          }
778
779          // rebind original select elements events
780          $.each(cloneOriginalEvents, (_, e) => {
781            $.each(e, (__, ev) => {
782              O.E.on(ev.type, ev.handler);
783            });
784          });
785
786          if ((O.is_multi && !settings.okCancelInMulti) || !O.is_multi) {
787            O.callChange(); // call change on original select element
788            O.setText();
789          }
790
791          if (!direct) {
792            if (!O.mob && O.selAll) O.selAll.removeClass('partial').toggleClass('selected', !!c);
793            O.setText();
794            O.setPstate();
795          }
796        },
797
798        /* outside accessibility options
799          which can be accessed from the element instance.
800         */
801        reload() {
802          const elm = this.unload();
803          return $(elm).SumoSelect(settings);
804        },
805
806        unload() {
807          const O = this;
808          O.select.before(O.E);
809          O.E.show();
810          O.E[0].classList.remove('SumoUnder', 'SelectClass');
811
812          if (settings.outputAsCSV && O.is_multi && O.select.find('input.HEMANT123').length) {
813            O.E.attr('name', O.select.find('input.HEMANT123').attr('name')); // restore the name;
814          }
815          O.select.remove();
816          delete selObj.sumo;
817          O.E.trigger('sumo:unloaded', O);
818          return selObj;
819        },
820
821        //## add a new option to select at a given index.
822        add(val, txt, i, attr) {
823          if (typeof val === "undefined") throw new Error("No value to add");
824
825          const O = this;
826          const opts = O.E.find('option');
827          const value = val;
828          let
829            text = txt,
830            index = i;
831          if (typeof txt === "number") { // .add('xxx', 2) shorthand
832            index = txt;
833            text = val;
834          } else if (typeof txt === "undefined") { // .add('xxx') shorthand
835            text = val;
836          }
837
838          const opt = $("<option></option>").val(value).html(text);
839
840          if (attr && typeof attr === "object") {
841            $.each(attr, (j, v) => {
842              opt.attr(j, v);
843            });
844          }
845
846          if (opts.length < index) throw new Error("index out of bounds");
847
848          if (typeof index === "undefined" || opts.length === index) { // add it to the last if given index is last no or no index provides.
849            O.E.append(opt);
850            if (!O.mob) O.ul.append(O.createLi(opt));
851          }
852          else {
853            opts.eq(index).before(opt);
854            if (!O.mob) O.ul.find('li.opt').eq(index).before(O.createLi(opt));
855          }
856
857          return selObj;
858        },
859
860        //## removes an item at a given index.
861        remove(i) {
862          const O = this.vRange(i);
863          O.E.find('option').eq(i).remove();
864          if (!O.mob) O.optDiv.find('ul.options li.opt').eq(i).remove();
865          O.setText();
866        },
867
868        // removes all but the selected one
869        removeAll() {
870          const O = this;
871          const optionList = O.E.find('option');
872
873          for (let x = (optionList.length - 1); x >= 0; x--) {
874            if (optionList[x].selected !== true) {
875              O.remove(x);
876            }
877          }
878
879        },
880
881
882        find(val) {
883          const O = this;
884          const optionList = O.E.find('option');
885          for (const x in optionList) {
886            if (optionList[x].value === val) {
887              return +x;
888            }
889          }
890
891          return -1;
892
893        },
894
895        //## Select an item at a given index.
896        selectItem(i) { this.toggSel(true, i); },
897
898        //## UnSelect an iten at a given index.
899        unSelectItem(i) { this.toggSel(false, i); },
900
901        //## Select all items  of the select.
902        selectAll() { this.toggSelAll(true); },
903
904        //## UnSelect all items of the select.
905        unSelectAll() { this.toggSelAll(false); },
906
907        //## Disable an iten at a given index.
908        disableItem(i) { this.toggDis(true, i); },
909
910        //## Removes disabled an iten at a given index.
911        enableItem(i) { this.toggDis(false, i); },
912
913        //## New simple methods as getter and setter are not working fine in ie8-
914        //## variable to check state of control if enabled or disabled.
915        enabled: true,
916        //## Enables the control
917        enable() { return this.toggSumo(false); },
918
919        //## Disables the control
920        disable() { return this.toggSumo(true); },
921
922
923        init() {
924          const O = this;
925          O.createElems();
926          O.setText();
927          O.E.trigger('sumo:initialized', O);
928          return O;
929        }
930
931      };
932
933      selObj.sumo.init();
934    });
935
936    return ret.length === 1 ? ret[0] : ret;
937  };
938
939
940});

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.