1/* 2 Select customization v 1.70 (09.03.25) <- v 1.60 (05.29.20) 3 Author: Pavlo Tkach 4*/ 5(function($){ 6 7 function handClickLi(event) { 8 var e = event || window.event, 9 $sb = e.data.elm, onSelectChanged = e.data.fun, 10 al = e.data.options.allLabel, label = e.data.label, ip = e.data.ip; 11 if ( !e.target.closest('.selectBox') ) return true; 12 e.stopPropagation(); 13 //e.preventDefault(); 14 15 16 if (e.data.options.selSelect) { 17 var $se = $(e.data.options.selSelect), $w = $sb; 18 } else { 19 var $w = $(this).closest('.wrap-sb'), $se = $w.children('select'); 20 }; 21 var $u = $w.find('.list'),$lb = $w.find('.label'), 22 $inp = $w.find('input'), $val = $lb.find('.value'), 23 $li = $(this).parent().children().not('.group'), 24 ind = $li.index(this); 25 t = $u.attr('data-label')?$u.attr('data-label'):$se.children('option').eq(0).text(); 26 27 if ($se.attr('multiple')) { 28 var lastChecked = $se.data('lastChecked'); 29 30 if ( event.ctrlKey || ( window.navigator.userAgent.indexOf("Mac") !== -1 && event.metaKey ) || e.shiftKey ) { 31 //if ( event.ctrlKey || ( window.navigator.userAgent.indexOf("Mac") && event.metaKey ) || e.shiftKey ) { 32 //$se[0].options[$(this).index()+1].selected = true; 33 if(!lastChecked) lastChecked = this; 34 // with shift 35 if(event.shiftKey) { 36 var start = $li.index(this), 37 end = $li.index(lastChecked); 38 if (start >= 0 && start === end) { 39 if ($li.hasClass('selected')) { 40 $(this).removeClass('selected'); 41 $se[0].options[start].selected = false; 42 $lb.children('[data-value="'+$se[0].options[start].value+'"]').remove(); 43 } else { 44 $(this).addClass('selected'); 45 $se[0].options[start].selected = true; 46 if ($inp.length && ip == 'after') { 47 $('<span class="item" data-value="'+$se[0].options[start].value+'">'+$se[0].options[start].text+'</span>').insertBefore($inp); 48 } else { 49 $('<span class="item" data-value="'+$se[0].options[start].value+'">'+$se[0].options[start].text+'</span>').appendTo($lb); 50 }; 51 } 52 } else { 53 var sel = ($(lastChecked).hasClass('selected') && $(this).hasClass('selected'))?true:false, 54 min = Math.min(start,end), max = Math.max(start,end); 55 for (var i = min; i <= max; i++) { 56 if (sel) { 57 if (i != start) { 58 $li.eq(i).removeClass('selected'); 59 $se[0].options[i+1].selected = false; 60 $lb.children('[data-value="'+$se[0].options[i+1].value+'"]').remove(); 61 } 62 } else { 63 $li.eq(i).addClass('selected'); 64 $se[0].options[i+1].selected = true; 65 if (!$lb.children('[data-value="'+$se[0].options[i+1].value+'"]').length) { 66 if ($inp.length && ip == 'after') { 67 $('<span class="item" data-value="'+$se[0].options[i+1].value+'">'+$se[0].options[i+1].text+'</span>').insertBefore($inp); 68 } else { 69 $('<span class="item" data-value="'+$se[0].options[i+1].value+'">'+$se[0].options[i+1].text+'</span>').appendTo($lb); 70 }; 71 }; 72 }; 73 }; 74 } 75 } else { 76 var i = $li.index(this); 77 if ($(this).hasClass('selected')) { 78 $(this).removeClass('selected'); 79 $se[0].options[i+1].selected = false; 80 $lb.children('[data-value="'+$se[0].options[i+1].value+'"]').remove(); 81 } else { 82 $(this).addClass('selected'); 83 $se[0].options[i+1].selected = true; 84 if ($inp.length && ip == 'after') { 85 $('<span class="item" data-value="'+$se[0].options[i+1].value+'">'+$se[0].options[i+1].text+'</span>').insertBefore($inp); 86 } else { 87 $('<span class="item" data-value="'+$se[0].options[i+1].value+'">'+$se[0].options[i+1].text+'</span>').appendTo($lb); 88 }; 89 } 90 }; 91 $se.data('lastChecked',this); 92 } else { 93 for (var i = 0; i < $se[0].options.length; i++) { 94 $se[0].options[i].selected = false;
95 } 96 $se[0].options[$(this).index()+1].selected = true; 97 $(this).siblings().removeClass('selected'); 98 $lb.children('.item').remove(); 99 $(this).addClass('selected'); 100 if ($inp.length && ip == 'after') { 101 $('<span class="item" data-value="'+$se[0].options[$li.index(this)+1].value+'">'+$se[0].options[$li.index(this)+1].text+'</span>').insertBefore($inp); 102 } else { 103 $('<span class="item" data-value="'+$se[0].options[$li.index(this)+1].value+'">'+$se[0].options[$li.index(this)+1].text+'</span>').appendTo($lb); 104 }; 105 106 //$sb.removeClass('open').find('.ddbox').fadeOut(200); 107 $se.data('lastChecked',this); 108 }; 109 if ($sb.find('.item').length) { 110 $val.css('display','none'); 111 } else { 112 $val.css('display','inline-block'); 113 }; 114 if ($inp.length) $inp.focus(); 115 } else { 116 if ( ind == 0 ) { 117 var str = ''; 118 $lb.addClass('placeholder'); 119 if (typeof al == 'string') { 120 str = al; 121 } else str = label; 122 } else { 123 $lb.removeClass('placeholder'); 124 var $v = $(this).children('.val'); 125 str = $(this).text(); 126 if ($v.length) str = str.slice(0,str.length-$v.text().length); 127 }; 128 $(this).addClass('selected').siblings().removeClass('selected'); 129 $val.html(str); 130 //$se[0].options.selected = false; 131 $se[0].options[ind].selected = true; 132 $se[0].value = $(this).attr('data-value'); 133 $se[0].selectedIndex = ind; 134 $se[0].dispatchEvent(new Event("input", { bubbles: true })); 135 $se[0].dispatchEvent(new Event("change", { bubbles: true })); 136 if ($inp.length) { 137 $inp.css('display','none'); 138 $val.css('display','inline-block'); 139 }; 140 if (typeof $sb == 'object') $sb.removeClass('open').find('.ddbox').fadeOut(200); 141 }; 142 if ($inp.length) $inp.focus();
143 //$se.children().attr("selected",false); 144 //$se.children().eq($(this).index()).attr("selected",true); 145 $se.change(); 146 if ($.isFunction(onSelectChanged)) { 147 onSelectChanged.call(this); 148 }; 149 }; 150 151 var methods = { 152 init : function( options ) { 153 var options = $.extend({ 154 selectBox: '.selectBox', 155 addClasses: '', 156 addValue: false, 157 classCopy: '', 158 addWrapClasses: '', 159 selSelect: '', 160 allLabel: false, //default text: false - selected option or option[0], true - label, otherwise - html code 161 arrangeLabel: false, 162 hideselect: true, 163 filestyle: false, 164 height: 'auto', 165 eventContainer: 'html', 166 multiple: false, 167 search: false, //false,true,'filter' 168 inputPlace: 'after', //'default','before','after' 169 onOpenDDBoxBefore: function() {}, 170 onCloseDDBoxAfter: function() {}, 171 onSelectChanged: function() {}, 172 }, options); 173 174 // restore/save options 175 if ( this.data('select') ) { 176 options = this.data('select'); 177 } else { 178 this.data('select',options); 179 }; 180 181 var selectBox = options.selectBox, ec = options.eventContainer, allLabel = options.allLabel, $u, 182 listc = options.classCopy.split(" "), 183 onOpenDDBoxBefore = options.onOpenDDBoxBefore, 184 onCloseDDBoxAfter = options.onCloseDDBoxAfter, 185 onSelectChanged = options.onSelectChanged, 186 hide = options.hideselect, ov = 'auto', $wo; 187 188 function handClickEC(event) { 189 var ec = event.data.elm, selectBox = event.data.sb, 190 e = event || window.event, $o = $(e.target || e.srcElement); 191 $os = $o.parents(selectBox).length?$o.parents(selectBox):$o; 192 if ( !e.target.closest('.selectBox') ) return true; 193 e.stopPropagation(); 194 //e.preventDefault(); 195 if ($o.closest(ec).length > 0 && !$os.is($(selectBox,ec))) { 196 $(selectBox,ec).each(function() { 197 var $val = $(this).find('.value'), $it = $(this).find('.item'), 198 $inp = $(this).find('input'); 199 if (!$it.length) $val.css('display','inline-block'); 200 if ($inp.length) $inp.css('display','none'); 201 $(this).removeClass('open').find('.ddbox').fadeOut(0); 202 }); 203 } 204 }; 205 function handClickSB(event) { 206 var e = event || window.event, 207 $sb = event.data.elm, op = event.data.se[0].options, $inp, $val; 208 if ( !e.target.closest('.selectBox') ) return true; 209 if ( $sb.hasClass('disabled')) return; 210 e.stopPropagation(); 211 //e.preventDefault(); 212 $(selectBox,options.eventContainer).each(function() { 213 if ($(this).is($sb)) { 214 $inp = $(this).find('input'); 215 $val = $(this).find('.value'); 216 if ($(e.target).hasClass('item')) { 217 var $it = $(e.target), v = $it.attr('data-value'), 218 $li = $sb.find('.ddbox li'), $l = $li.filter('[data-value="'+v+'"]'); 219 if ($l.length) { 220 i = $li.index($l); 221 $l.removeClass('selected'); 222 op[i+1].selected = false; 223 $it.remove(); 224 if ( !$(this).find('.item').length && (!$inp.length || !$(this).hasClass('open')) ) { 225 $val.css('display','inline-block'); 226 }; 227 if ($(this).hasClass('open') && $inp.length) $inp.focus(); 228 }; 229 } else if ( !$(e.target).hasClass('group')) { 230 if ($(this).hasClass('open')) { 231 $(this).removeClass('open').find('.ddbox').fadeOut(200); 232 if (!$sb.find('.item').length) $val.css('display','inline-block'); 233 if ($inp.length) $inp.css('display','none'); 234 if ($.isFunction(onCloseDDBoxAfter)) { 235 onCloseDDBoxAfter.call(this); 236 }; 237 } else { 238 if ($.isFunction(onOpenDDBoxBefore)) { 239 onOpenDDBoxBefore.call(this); 240 }; 241 $(this).addClass('open').find('.ddbox').fadeIn(200);//animate({height:'toggle'},200) 242 if ($inp.length) { 243 $inp.css('display','inline-block'); 244 $val.css('display','none'); 245 } 246 }; 247 }; 248 if ($inp.length) $inp.focus(); 249 } else $(this).removeClass('open').find('.ddbox').fadeOut(0); 250 }); 251 }; 252 function handKeyupINP(event) { 253 var e = event || window.event, 254 $sb = event.data.elm, $li = $sb.find('li'), $db = $sb.find('.ddbox'), 255 filter = this.value,$elm,txt,fl = false,val; 256 for (i = 0; i < $li.length; i++) { 257 $elm = $li.eq(i), txt = $elm.text().replace($elm.children('.val').text(),''); 258 val = options.addValue?($elm.children('.val').length?'<span class="val">'+$elm.children('.val').html()+'</span>':''):''; 259 start = txt.toUpperCase().indexOf(filter.toUpperCase()); 260 if (options.search == 'filter') { 261 if (start > -1) { 262 $elm.html(txt.slice(0,start)+'<em>'+txt.slice(start,start+filter.length)+'</em>'+txt.slice(start+filter.length)+val); 263 $elm.css('display', ""); 264 } else { 265 $elm.remove('em'); 266 $elm.css('display', "none"); 267 } 268 } else { 269 if (start == 0) { 270 if (!fl) $db.scrollTop($elm[0].offsetTop-5); 271 $elm.html(txt.slice(0,start)+'<em>'+txt.slice(start,start+filter.length)+'</em>'+txt.slice(start+filter.length)+val); 272 fl = true; 273 } else { 274 $elm.remove('em'); 275 } 276 } 277 } 278 }; 279 280 // add file list style 281 if (typeof options.filestyle == 'string' && !$('link[href="'+options.filestyle+'"]').length) { 282 var css = $("<link>", { 283 "rel" : "stylesheet", 284 "type" : "text/css", 285 "href" : options.filestyle 286 })[0]; 287 css.onerror = function(event) { 288 console.log('The file "'+this.href+'" not found!'); 289 }; 290 document.getElementsByTagName("head")[0].appendChild(css); 291 } 292 293 // transform select to selectbox 294 function addItem($el,gr,dis) { 295 $el.children('option').each(function(i) { 296 let $li; 297 if (!$el.attr('multiple') || ( $el.attr('multiple') && i != 0 )) { 298 $li = $('<li '+(this.disabled||dis?'class="disabled"':'')+' data-value="'+$
298(this).val()+'"'+ (gr!==false?' data-group="group-'+gr+'"':'') +'>'+$(this).text()+'</li>').appendTo($u); 299 if ( gr!==false ) $li.addClass('group-item'); 300 if ( i!=0 && options.addValue && options.addValue != $(this).val()) $li.append('<span class="val">'+$(this).val()+'</span>'); 301 }; 302 }); 303 }; 304 $(this).each(function(i) { 305 var $se = $(this), $w = $(this).parent(), $inp; 306 if ( $w && !$w.hasClass('wrap-sb') ) { 307 var $lbs = $(this).parent().children('label'),l = ''; 308 if (!$lbs.length) $lbs = $('label[for="'+$(this).attr('id')+'"]'); 309 l = $lbs.length? $lbs.text().trim():''; 310 // arrange label 311 if ($lbs.length && options.arrangeLabel) $lbs.insertBefore($se); 312 // set multiple option 313 if (options.multiple) $(this).attr('multiple',true); 314 // do selectBox base structure 315 $(this).add($lbs).wrapAll('<div class="wrap-sb"></div>'); 316 $w = $(this).parent('.wrap-sb'); 317 var $sb = $('<div class="'+selectBox.replace('.','')+'"><span class="label"></span><div class="ddbox"><ul class="list"></ul></div></div>').insertAfter($(this)), 318 $lb = $sb.children('.label'), $dd = $sb.find('.ddbox'); 319 if ($se.attr('disabled')) $sb.addClass('disabled'); 320 // add classes to .selectBox & wrapper 321 $sb.addClass(options.addClasses); 322 for (var i = 0; i < listc.length; i++) {
323 if ($se.hasClass(listc[i])) $sb.addClass(listc[i]); 324 }; 325 $w.addClass(options.addWrapClasses); 326 327 // do dropdown list 328 $u = $sb.find('ul'), gr = false, dis = false, $ol = $(this).children('option').eq(0); 329 if ( $(this).children('optgroup').length>0 ) { 330 $li = $('<li '+' data-value="'+$ol.val()+'">'+$ol.text()+'</li>').appendTo($u); 331 $(this).children('optgroup').each(function(i) { 332 var dis = this.disabled?true:false, $li; 333 gr = i; 334 $li = $('<li class="group'+(dis?' disabled"':'"')+'>'+$(this).attr('label')+'</li>').appendTo($u); 335 $li.addClass('group-'+gr); 336 addItem($(this),gr,dis); 337 }); 338 } else addItem($(this),gr,dis); 339 340 $li = $u.find('li').not('.group'); 341 342 // set default label value 343 var i = 0, str = ''; 344 if (typeof options.allLabel == 'string') { 345 str = allLabel; 346 } else if (options.allLabel){ 347 str = l; 348 } else { 349 str = this.options[0].text; 350 }; 351 l = str; 352 i = this.selectedIndex; 353 if (!$se.attr('multiple')) { 354 if (i > 0) { 355 $lb.removeClass('placeholder'); 356 $lb.html('<span class="value">'+this.options[i].text+'</span>'); 357 } else { 358 $lb.addClass('placeholder'); 359 $lb.html('<span class="value">'+str+'</span>'); 360 }; 361 $li.eq(i).addClass('selected'); 362 } else { 363 $sb.addClass('multiple'); 364 if (i > 0) { 365 $lb.removeClass('placeholder'); 366 $li.eq(i-1).addClass('selected'); 367 } else { 368 $lb.addClass('placeholder'); 369 } 370 $se.data('lastChecked',$li.eq(i)); 371 $lb.html('<span class="value">'+str+'</span>'); 372 }; 373 374 // search 375 if ( options.search ) { 376 $sb.addClass('search'); 377 if (options.inputPlace == 'after') { 378 $inp = $('<input type="text" autocomplete="off">').appendTo($lb); 379 } else { 380 $inp = $('<input type="text" autocomplete="off">').prependTo($lb); 381 }; 382 }; 383 384 // max dropbox height 385 if(typeof options.height == 'number') $dd.css({'max-height':options.height+'px','overflow':'auto'}); 386 387 // hide select & label 388 $(this).css(hide?{'display':'none'}:{}); 389 $lbs.css((hide === 'all')?{'display':'none'}:{}); 390 391 // add events 392 if ( !$w.is($wo) ){ 393 $sb = $w.find(selectBox); 394 $(ec).off('click.EC'+selectBox+'.select'); 395 $(ec).on('click.EC'+selectBox+'.select',{elm: $(ec),sb: selectBox}, handClickEC); 396 $sb.off('click.SB.select'); 397 $sb.on('click.SB.select',{elm: $sb, se: $se}, handClickSB); 398 if ( options.search ) $inp.on('keyup.INP.select',{elm: $sb, se: $se}, handKeyupINP); 399 $wo = !$wo?$w:$wo.add($w); 400 }; 401 }; 402 403 // relation to select (change select value) 404 $li.not('.disabled').on('click.Li.select', {elm: $sb, options: options, label: l, fun: onSelectChanged, ip: options.inputPlace}, handClickLi); 405 406 }); 407 408 return $(this); 409 }, 410 refresh : function(options) { 411 this.each(function(i){ 412 var options = $(this).data('select'), 413 selectBox = options.selectBox, 414 ec = options.eventContainer, 415 $se = $(this); 416 $w = $(this).closest('.wrap-sb'); 417 if ( $w && $w.hasClass('wrap-sb') ) { 418 var $sb = $w.find(selectBox), 419 $lbs = $w.find('label'), 420 $lb = $sb.find('.label'), $u = $sb.find('ul'), 421 l = $lbs.length? $lbs.text().trim():''; 422 $lb.children().remove(); 423 $u.find('li').remove(); 424 $se.children('option').each(function(i) { 425 this.selected = false; 426 $('<li data-value='+$(this).val()+'>'+$(this).text()+'</li>').appendTo($u); 427 if ( !$se.attr('multiple') && i==0 ) { 428 this.selected = true; 429 this.selectedIndex = 0; 430 $se[0].value = $(this).text(); 431 } else this.selected = false;
432 }); 433 var $li = $u.find('li'); 434 // set default label value 435 var i = 0; 436 if (!$se.attr('multiple')) { 437 if (typeof options.allLabel == 'string') { 438 $lb.html(allLabel); 439 } else if (options.allLabel){ 440 $lb.text(l); 441 } else { 442 l = this.options[0].text; 443 $lb.text(this.options[0].text); 444 } 445 } else { 446 $se.data('lastChecked',$li.eq(-1)); 447 }; 448 }; 449 // relation to select (change select value) 450 if ( $li.length ) $li.on('click.Li.select', {elm: $sb, options: options, label: l}, handClickLi); 451 }); 452 }, 453 remove : function(options) { 454 this.each(function(i){ 455 var options = $(this).data('select'), 456 selectBox = options.selectBox, 457 ec = options.eventContainer, 458 $se = $(this), $w = $(this).closest('.wrap-sb'); 459 if ( $w && $w.hasClass('wrap-sb') ) { 460 var $lbs = $w.find('label'), 461 $sb = $w.find(selectBox),$inp = $sb.find('input'); 462 if ($inp.length) $inp.off('keyup.INP.select'); 463 $sb.off('click.SB.select').remove(); 464 $se.add($lbs).unwrap(); 465 $(ec).off('click.EC'+selectBox+'.select'); 466 467 } 468 }); 469 } 470 }; 471 472 $.fn.select = function( method ) { 473 if ( methods[method] ) { 474 return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 )); 475 } else if ( typeof method === 'object' || ! method ) { 476 return methods.init.apply( this, arguments ); 477 } else { 478 $.error( 'Method with the name ' + method + ' does not exist for jQuery.select.js' ); 479 } 480 }; 481 482})(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.