1/* 2Copyright (C) Philippe Meyer 2019-2021 3Distributed under the MIT License 4 5vanillaSelectBox : v0.76 : New changeTree function : to rebuild the original tree with new data + correcting empty() function 6vanillaSelectBox : v0.75 : Remote search ready + local search modification : when a check on optgroup checks children only 7 if they not excluded from search. 8vanillaSelectBox : v0.72 : Remote search (WIP) bugfix [x] Select all duplicated 9vanillaSelectBox : v0.71 : Remote search (WIP) better code 10vanillaSelectBox : v0.70 : Remote search (WIP) for users to test 11vanillaSelectBox : v0.65 : Two levels: bug fix : groups are checked/unchecked when check all/uncheck all is clicked 12vanillaSelectBox : v0.64 : Two levels: groups are now checkable to check/uncheck the children options 13vanillaSelectBox : v0.63 : Two levels: one click on the group selects / unselects children 14vanillaSelectBox : v0.62 : New option: maxOptionWidth set a maximum width for each option for narrow menus 15vanillaSelectBox : v0.61 : New option: maxSelect, set a maximum to the selectable options in a multiple choice menu 16vanillaSelectBox : v0.60 : Two levels: Optgroups are now used to show two level dropdowns 17vanillaSelectBox : v0.59 : Bug fix : search box was overlapping first item in single selects 18vanillaSelectBox : v0.58 : Bug fixes 19vanillaSelectBox : v0.57 : Bug fix (minWidth option not honored) 20vanillaSelectBox : v0.56 : The multiselect checkboxes are a little smaller, maxWidth option is now working + added minWidth option as well 21 The button has now a style attribute to protect its appearance 22vanillaSelectBox : v0.55 : All attributes from the original select options are copied to the selectBox element 23vanillaSelectBox : v0.54 : if all the options of the select are selected by the user then the check all checkbox is checked 24vanillaSelectBox : v0.53 : if all the options of the select are selected then the check all checkbox is checked 25vanillaSelectBox : v0.52 : Better support of select('all') => command is consistent with checkbox and selecting / deselecting while searching select / uncheck only the found items 26vanillaSelectBox : v0.51 : Translations for select all/clear all + minor css corrections + don't select disabled items 27vanillaSelectBox : v0.50 : PR by jaguerra2017 adding a select all/clear all check button + optgroup support ! 28vanillaSelectBox : v0.41 : Bug corrected, the menu content was misplaced if a css transform was applied on a parent 29vanillaSelectBox : v0.40 : A click on one selectBox close the other opened boxes 30vanillaSelectBox : v0.35 : You can enable and disable items 31vanillaSelectBox : v0.30 : The menu stops moving around on window resize and scroll + z-index in order of creation for multiple instances 32vanillaSelectBox : v0.26 : Corrected bug in stayOpen mode with disable() function 33vanillaSelectBox : v0.25 : New option stayOpen, and the dropbox is no longer a dropbox but a nice multi-select 34previous version : v0.24 : corrected bug affecting options with more than one class 35https://github.com/PhilippeMarcMeyer/vanillaSelectBox 36*/ 37 38let VSBoxCounter = function () {
vendor: 46,061 bytes, lines 39-1189
39 let count = 0; 40 let instances = []; 41 return { 42 set: function (instancePtr) { 43 instances.push({ offset: ++count, ptr: instancePtr }); 44 return instances[instances.length - 1].offset; 45 }, 46 remove: function (instanceNr) { 47 let temp = instances.filter(function (x) { 48 return x.offset != instanceNr; 49 }) 50 instances = temp.splice(0); 51 }, 52 closeAllButMe: function (instanceNr) { 53 instances.forEach(function (x) { 54 if (x.offset != instanceNr) { 55 x.ptr.closeOrder(); 56 } 57 }); 58 } 59 }; 60}(); 61 62function vanillaSelectBox(domSelector, options) { 63 let self = this; 64 this.instanceOffset = VSBoxCounter.set(self); 65 this.domSelector = domSelector; 66 this.root = document.querySelector(domSelector); 67 this.rootToken = null; 68 this.main; 69 this.button; 70 this.title; 71 this.isMultiple = this.root.hasAttribute("multiple"); 72 this.multipleSize = this.isMultiple && this.root.hasAttribute("size") ? parseInt(this.root.getAttribute("size")) : -1; 73 this.isOptgroups = false; 74 this.currentOptgroup = 0; 75 this.drop; 76 this.top; 77 this.left; 78 this.options; 79 this.listElements; 80 this.isDisabled = false; 81 this.search = false; 82 this.searchZone = null; 83 this.inputBox = null; 84 this.disabledItems = []; 85 this.ulminWidth = 140; 86 this.ulmaxWidth = 280; 87 this.ulminHeight = 25; 88 this.maxOptionWidth = Infinity; 89 this.maxSelect = Infinity; 90 this.isInitRemote = false; 91 this.isSearchRemote = false; 92 this.onInit = null; 93 this.onSearch = null; // if isRemote is true : a user defined function that loads more options from the back 94 this.onInitSize = null; 95 this.forbidenAttributes = ["class", "selected", "disabled", "data-text", "data-value", "style"]; 96 this.forbidenClasses = ["active", "disabled"]; 97 this.userOptions = { 98 maxWidth: 500, 99 minWidth: -1, 100 maxHeight: 400, 101 translations: { "all": "All", "items": "items", "selectAll": "Select All", "clearAll": "Clear All" }, 102 search: false, 103 placeHolder: "", 104 stayOpen: false, 105 disableSelectAll: false 106 } 107 if (options) { 108 if (options.maxWidth != undefined) { 109 this.userOptions.maxWidth = options.maxWidth; 110 } 111 if (options.minWidth != undefined) { 112 this.userOptions.minWidth = options.minWidth; 113 } 114 if (options.maxHeight != undefined) { 115 this.userOptions.maxHeight = options.maxHeight; 116 } 117 if (options.translations != undefined) { 118 for (var property in options.translations) { 119 if (options.translations.hasOwnProperty(property)) { 120 if (this.userOptions.translations[property]) { 121 this.userOptions.translations[property] = options.translations[property]; 122 } 123 } 124 } 125 } 126 if (options.placeHolder != undefined) { 127 this.userOptions.placeHolder = options.placeHolder; 128 } 129 if (options.search != undefined) { 130 this.search = options.search; 131 } 132 if (options.remote != undefined && options.remote) { 133 134 // user defined onInit function 135 if (options.remote.onInit!= undefined && typeof options.remote.onInit === 'function') { 136 this.onInit = options.remote.onInit; 137 this.isInitRemote = true; 138 } 139 if (options.remote.onInitSize != undefined) { 140 this.onInitSize = options.remote.onInitSize; 141 if (this.onInitSize < 3) this.onInitSize = 3; 142 } 143 // user defined remote search function 144 if (options.remote.onSearch != undefined && typeof options.remote.onSearch === 'function') { 145 this.onSearch = options.remote.onSearch; 146 this.isSearchRemote = true; 147 } 148 } 149 150 if (options.stayOpen != undefined) { 151 this.userOptions.stayOpen = options.stayOpen; 152 } 153 154 if (options.disableSelectAll != undefined) { 155 this.userOptions.disableSelectAll = options.disableSelectAll; 156 } 157 158 if (options.maxSelect != undefined && !isNaN(options.maxSelect) && options.maxSelect >= 1) { 159 this.maxSelect = options.maxSelect; 160 this.userOptions.disableSelectAll = true; 161 } 162 163 if (options.maxOptionWidth != undefined && !isNaN(options.maxOptionWidth) && options.maxOptionWidth >= 20) { 164 this.maxOptionWidth = options.maxOptionWidth; 165 this.ulminWidth = options.maxOptionWidth + 60; 166 this.ulmaxWidth = options.maxOptionWidth + 60; 167 } 168 } 169 170 this.closeOrder = function () { 171 let self = this; 172 if (!self.userOptions.stayOpen) { 173 self.drop.style.visibility = "hidden"; 174 if (self.search) { 175 self.inputBox.value = ""; 176 Array.prototype.slice.call(self.listElements).forEach(function (x) { 177 x.classList.remove("hide"); 178 }); 179 } 180 } 181 } 182 183 this.getCssArray = function (selector) { 184 // Why inline css ? To protect the button display from foreign css files 185 let cssArray = []; 186 if (selector === ".vsb-main button") { 187 cssArray = [ 188 { "key": "min-width", "value": "120px" }, 189 { "key": "border-radius", "value": "0" }, 190 { "key": "width", "value": "100%" }, 191 { "key": "text-align", "value": "left" }, 192 { "key": "z-index", "value": "1" }, 193 { "key": "color", "value": "#333" }, 194 { "key": "background", "value": "white !important" }, 195 { "key": "border", "value": "1px solid #999 !important" }, 196 { "key": "line-height", "value": "20px" }, 197 { "key": "font-size", "value": "14px" }, 198 { "key": "padding", "value": "6px 12px" } 199 ] 200 } 201 202 return cssArrayToString(cssArray); 203 204 function cssArrayToString(cssList) { 205 let list = ""; 206 cssList.forEach(function (x) { 207 list += x.key + ":" + x.value + ";"; 208 }); 209 return list; 210 } 211 } 212 213 this.init = function () { 214 let self = this; 215 if (self.isInitRemote) { 216 self.onInit("",self.onInitSize) 217 .then(function (data) { 218 self.buildSelect(data); 219 self.createTree(); 220 }); 221 } else { 222 self.createTree(); 223 } 224 } 225 226 this.createTree = function () { 227 228 this.rootToken = self.domSelector.replace(/[^A-Za-z0-9]+/, "") 229 this.root.style.display = "none"; 230 let already = document.getElementById("btn-group-" + this.rootToken); 231 if (already) { 232 already.remove(); 233 } 234 this.main = document.createElement("div"); 235 this.root.parentNode.insertBefore(this.main, this.root.nextSibling); 236 this.main.classList.add("vsb-main"); 237 this.main.setAttribute("id", "btn-group-" + this.rootToken); 238 this.main.style.marginLeft = this.main.style.marginLeft; 239 if (self.userOptions.stayOpen) { 240 this.main.style.minHeight = (this.userOptions.maxHeight + 10) + "px"; 241 } 242 243 if (self.userOptions.stayOpen) { 244 this.button = document.createElement("div"); 245 } else { 246 this.button = document.createElement("button"); 247 var cssList = self.getCssArray(".vsb-main button"); 248 this.button.setAttribute("style", cssList); 249 } 250 this.button.style.maxWidth = this.userOptions.maxWidth + "px"; 251 if (this.userOptions.minWidth !== -1) { 252 this.button.style.minWidth = this.userOptions.minWidth + "px"; 253 } 254 255 this.main.appendChild(this.button); 256 this.title = document.createElement("span"); 257 this.button.appendChild(this.title); 258 this.title.classList.add("title"); 259 let caret = document.createElement("span"); 260 this.button.appendChild(caret); 261 262 caret.classList.add("caret"); 263 caret.style.position = "absolute"; 264 caret.style.right = "8px"; 265 caret.style.marginTop = "8px"; 266 267 if (self.userOptions.stayOpen) { 268 caret.style.display = "none"; 269 this.title.style.paddingLeft = "20px"; 270 this.title.style.fontStyle = "italic"; 271 this.title.style.verticalAlign = "20%"; 272 } 273 274 this.drop = document.createElement("div"); 275 this.main.appendChild(this.drop); 276 this.drop.classList.add("vsb-menu"); 277 this.drop.style.zIndex = 2000 - this.instanceOffset; 278 this.ul = document.createElement("ul"); 279 this.drop.appendChild(this.ul); 280 281 this.ul.style.maxHeight = this.userOptions.maxHeight + "px"; 282 this.ul.style.minWidth = this.ulminWidth + "px"; 283 this.ul.style.maxWidth = this.ulmaxWidth + "px"; 284 this.ul.style.minHeight = this.ulminHeight + "px"; 285 if (this.isMultiple) { 286 this.ul.classList.add("multi"); 287 if (!self.userOptions.disableSelectAll) { 288 let selectAll = document.createElement("option"); 289 selectAll.setAttribute("value", 'all'); 290 selectAll.innerText = self.userOptions.translations.selectAll; 291 this.root.insertBefore(selectAll, (this.root.hasChildNodes()) 292 ? this.root.childNodes[0] 293 : null); 294 } 295 } 296 let selectedTexts = "" 297 let sep = ""; 298 let nrActives = 0; 299 300 if (this.search) { 301 this.searchZone = document.createElement("div"); 302 this.ul.appendChild(this.searchZone); 303 this.searchZone.classList.add("vsb-js-search-zone"); 304 this.searchZone.style.zIndex = 2001 - this.instanceOffset; 305 this.inputBox = document.createElement("input"); 306 this.searchZone.appendChild(this.inputBox); 307 this.inputBox.setAttribute("type", "text"); 308 this.inputBox.setAttribute("id", "search_" + this.rootToken); 309 if (this.maxOptionWidth < Infinity) { 310 this.searchZone.style.maxWidth = self.maxOptionWidth + 30 + "px"; 311 this.inputBox.style.maxWidth = self.maxOptionWidth + 30 + "px"; 312 } 313 314 var para = document.createElement("p"); 315 this.ul.appendChild(para); 316 para.style.fontSize = "12px"; 317 para.innerHTML = " "; 318 this.ul.addEventListener("scroll", function (e) { 319 var y = this.scrollTop; 320 self.searchZone.parentNode.style.top = y + "px"; 321 }); 322 } 323 324 this.options = document.querySelectorAll(this.domSelector + " > option"); 325 Array.prototype.slice.call(this.options).forEach(function (x) { 326 let text = x.textContent; 327 let value = x.value; 328 let originalAttrs; 329 if (x.hasAttributes()) { 330 originalAttrs = Array.prototype.slice.call(x.attributes) 331 .filter(function (a) { 332 return self.forbidenAttributes.indexOf(a.name) === -1 333 }); 334 } 335 let classes = x.getAttribute("class"); 336 if (classes) { 337 classes = classes 338 .split(" ") 339 .filter(function (c) { 340 return self.forbidenClasses.indexOf(c) === -1 341 }); 342 } else { 343 classes = []; 344 } 345 let li = document.createElement("li"); 346 let isSelected = x.hasAttribute("selected"); 347 let isDisabled = x.hasAttribute("disabled"); 348 349 self.ul.appendChild(li); 350 li.setAttribute("data-value", value); 351 li.setAttribute("data-text", text); 352 353 if (originalAttrs !== undefined) { 354 originalAttrs.forEach(function (a) { 355 li.setAttribute(a.name, a.value); 356 }); 357 } 358 359 classes.forEach(function (x) { 360 li.classList.add(x); 361 }); 362 363 if (self.maxOptionWidth < Infinity) { 364 li.classList.add("short"); 365 li.style.maxWidth = self.maxOptionWidth + "px"; 366 } 367 368 if (isSelected) { 369 nrActives++; 370 selectedTexts += sep + text; 371 sep = ","; 372 li.classList.add("active"); 373 if (!self.isMultiple) { 374 self.title.textContent = text; 375 if (classes.length != 0) { 376 classes.forEach(function (x) { 377 self.title.classList.add(x); 378 }); 379 } 380 } 381 } 382 if (isDisabled) { 383 li.classList.add("disabled"); 384 } 385 li.appendChild(document.createTextNode(" " + text)); 386 }); 387 388 if (document.querySelector(self.domSelector + ' optgroup') !== null) { 389 self.isOptgroups = true; 390 self.options = document.querySelectorAll(self.domSelector + " option"); 391 let groups = document.querySelectorAll(self.domSelector + ' optgroup'); 392 Array.prototype.slice.call(groups).forEach(function (group) { 393 let groupOptions = group.querySelectorAll('option'); 394 let li = document.createElement("li"); 395 let span = document.createElement("span"); 396 let iCheck = document.createElement("i"); 397 let labelElement = document.createElement("b"); 398 let dataWay = group.getAttribute("data-way"); 399 if (!dataWay) dataWay = "closed"; 400 if (!dataWay || (dataWay !== "closed" && dataWay !== "open")) dataWay = "closed"; 401 li.appendChild(span); 402 li.appendChild(iCheck); 403 self.ul.appendChild(li); 404 li.classList.add('grouped-option'); 405 li.classList.add(dataWay); 406 self.currentOptgroup++; 407 let optId = self.rootToken + "-opt-" + self.currentOptgroup; 408 li.id = optId; 409 li.appendChild(labelElement); 410 labelElement.appendChild(document.createTextNode(group.label)); 411 li.setAttribute("data-text", group.label); 412 self.ul.appendChild(li); 413 414 Array.prototype.slice.call(groupOptions).forEach(function (x) { 415 let text = x.textContent; 416 let value = x.value; 417 let classes = x.getAttribute("class"); 418 if (classes) { 419 classes = classes.split(" "); 420 } 421 else { 422 classes = []; 423 } 424 classes.push(dataWay); 425 let li = document.createElement("li"); 426 let isSelected = x.hasAttribute("selected"); 427 self.ul.appendChild(li); 428 li.setAttribute("data-value", value); 429 li.setAttribute("data-text", text); 430 li.setAttribute("data-parent", optId); 431 if (classes.length != 0) { 432 classes.forEach(function (x) { 433 li.classList.add(x); 434 }); 435 } 436 if (isSelected) { 437 nrActives++; 438 selectedTexts += sep + text; 439 sep = ","; 440 li.classList.add("active"); 441 if (!self.isMultiple) { 442 self.title.textContent = text; 443 if (classes.length != 0) { 444 classes.forEach(function (x) { 445 self.title.classList.add(x); 446 }); 447 } 448 } 449 } 450 li.appendChild(document.createTextNode(text)); 451 }) 452 }) 453 } 454 455 let optionsLength = self.options.length - Number(!self.userOptions.disableSelectAll); 456 457 if (optionsLength == nrActives) { // Bastoune idea to preserve the placeholder 458 let wordForAll = self.userOptions.translations.all || "all"; 459 selectedTexts = wordForAll; 460 } else if (self.multipleSize != -1) { 461 if (nrActives > self.multipleSize) { 462 let wordForItems = self.userOptions.translations.items || "items" 463 selectedTexts = nrActives + " " + wordForItems; 464 } 465 } 466 if (self.isMultiple) { 467 self.title.innerHTML = selectedTexts; 468 } 469 if (self.userOptions.placeHolder != "" && self.title.textContent == "") { 470 self.title.textContent = self.userOptions.placeHolder; 471 } 472 self.listElements = self.drop.querySelectorAll("li:not(.grouped-option)"); 473 if (self.search) { 474 self.inputBox.addEventListener("keyup", function (e) { 475 let searchValue = e.target.value.toUpperCase(); 476 let searchValueLength = searchValue.length; 477 let nrFound = 0; 478 let nrChecked = 0; 479 let selectAll = null; 480 if (self.isSearchRemote) { 481 if (searchValueLength == 0) { 482 self.remoteSearchIntegrate(null); 483 } else if (searchValueLength >= 3) { 484 self.onSearch(searchValue) 485 .then(function (data) { 486 self.remoteSearchIntegrate(data); 487 }); 488 } 489 } else { 490 if (searchValueLength < 3) { 491 Array.prototype.slice.call(self.listElements).forEach(function (x) { 492 if (x.getAttribute('data-value') === 'all') { 493 selectAll = x; 494 } else { 495 x.classList.remove("hidden-search"); 496 nrFound++; 497 nrChecked += x.classList.contains('active'); 498 } 499 }); 500 } else { 501 Array.prototype.slice.call(self.listElements).forEach(function (x) { 502 if (x.getAttribute('data-value') !== 'all') { 503 let text = x.getAttribute("data-text").toUpperCase(); 504 if (text.indexOf(searchValue) === -1 && x.getAttribute('data-value') !== 'all') { 505 x.classList.add("hidden-search"); 506 } else { 507 nrFound++; 508 x.classList.remove("hidden-search"); 509 nrChecked += x.classList.contains('active'); 510 } 511 } else { 512 selectAll = x; 513 } 514 }); 515 } 516 if (selectAll) { 517 if (nrFound === 0) { 518 selectAll.classList.add('disabled'); 519 } else { 520 selectAll.classList.remove('disabled'); 521 } 522 if (nrChecked !== nrFound) { 523 selectAll.classList.remove("active"); 524 selectAll.innerText = self.userOptions.translations.selectAll; 525 selectAll.setAttribute('data-selected', 'false') 526 } else { 527 selectAll.classList.add("active"); 528 selectAll.innerText = self.userOptions.translations.clearAll; 529 selectAll.setAttribute('data-selected', 'true') 530 } 531 } 532 } 533 }); 534 } 535 536 if (self.userOptions.stayOpen) { 537 self.drop.style.visibility = "visible"; 538 self.drop.style.boxShadow = "none"; 539 self.drop.style.minHeight = (this.userOptions.maxHeight + 10) + "px"; 540 self.drop.style.position = "relative"; 541 self.drop.style.left = "0px"; 542 self.drop.style.top = "0px"; 543 self.button.style.border = "none"; 544 } else { 545 this.main.addEventListener("click", function (e) { 546 if (self.isDisabled) return; 547 self.drop.style.left = self.left + "px"; 548 self.drop.style.top = self.top + "px"; 549 self.drop.style.visibility = "visible"; 550 document.addEventListener("click", docListener); 551 e.preventDefault(); 552 e.stopPropagation(); 553 if (!self.userOptions.stayOpen) { 554 VSBoxCounter.closeAllButMe(self.instanceOffset); 555 } 556 }); 557 } 558 559 this.drop.addEventListener("click", function (e) { 560 if (self.isDisabled) return; 561 if (e.target.tagName === 'INPUT') return; 562 let isShowHideCommand = e.target.tagName === 'SPAN'; 563 let isCheckCommand = e.target.tagName === 'I'; 564 let liClicked = e.target.parentElement; 565 if (!liClicked.hasAttribute("data-value")) { 566 if (liClicked.classList.contains("grouped-option")) { 567 if (!isShowHideCommand && !isCheckCommand) return; 568 let oldClass, newClass; 569 if (isCheckCommand) { // check or uncheck children 570 self.checkUncheckFromParent(liClicked); 571 } else { //open or close 572 if (liClicked.classList.contains("open")) { 573 oldClass = "open" 574 newClass = "closed" 575 } else { 576 oldClass = "closed" 577 newClass = "open" 578 } 579 liClicked.classList.remove(oldClass); 580 liClicked.classList.add(newClass); 581 let theChildren = self.drop.querySelectorAll("[data-parent='" + liClicked.id + "']"); 582 theChildren.forEach(function (x) { 583 x.classList.remove(oldClass); 584 x.classList.add(newClass); 585 }) 586 } 587 return; 588 } 589 } 590 let choiceValue = e.target.getAttribute("data-value"); 591 let choiceText = e.target.getAttribute("data-text"); 592 let className = e.target.getAttribute("class"); 593 594 if (className && className.indexOf("disabled") != -1) { 595 return; 596 } 597 598 if (className && className.indexOf("overflow") != -1) { 599 return; 600 } 601 602 if (choiceValue === 'all') { 603 if (e.target.hasAttribute('data-selected') 604 && e.target.getAttribute('data-selected') === 'true') { 605 self.setValue('none') 606 } else { 607 self.setValue('all'); 608 } 609 return; 610 } 611 612 if (!self.isMultiple) { 613 self.root.value = choiceValue; 614 self.title.textContent = choiceText; 615 if (className) { 616 self.title.setAttribute("class", className + " title"); 617 } else { 618 self.title.setAttribute("class", "title"); 619 } 620 Array.prototype.slice.call(self.listElements).forEach(function (x) { 621 x.classList.remove("active"); 622 }); 623 if (choiceText != "") { 624 e.target.classList.add("active"); 625 } 626 self.privateSendChange(); 627 if (!self.userOptions.stayOpen) { 628 docListener(); 629 } 630 } else { 631 let wasActive = false; 632 if (className) { 633 wasActive = className.indexOf("active") != -1; 634 } 635 if (wasActive) { 636 e.target.classList.remove("active"); 637 } else { 638 e.target.classList.add("active"); 639 } 640 if (e.target.hasAttribute("data-parent")) { 641 self.checkUncheckFromChild(e.target); 642 } 643 644 let selectedTexts = "" 645 let sep = ""; 646 let nrActives = 0; 647 let nrAll = 0; 648 for (let i = 0; i < self.options.length; i++) { 649 nrAll++; 650 if (self.options[i].value == choiceValue) { 651 self.options[i].selected = !wasActive; 652 } 653 if (self.options[i].selected) { 654 nrActives++; 655 selectedTexts += sep + self.options[i].textContent; 656 sep = ","; 657 } 658 } 659 if (nrAll == nrActives - Number(!self.userOptions.disableSelectAll)) { 660 let wordForAll = self.userOptions.translations.all || "all"; 661 selectedTexts = wordForAll; 662 } else if (self.multipleSize != -1) { 663 if (nrActives > self.multipleSize) { 664 let wordForItems = self.userOptions.translations.items || "items" 665 selectedTexts = nrActives + " " + wordForItems; 666 } 667 } 668 self.title.textContent = selectedTexts; 669 self.checkSelectMax(nrActives); 670 self.checkUncheckAll(); 671 self.privateSendChange(); 672 } 673 e.preventDefault(); 674 e.stopPropagation(); 675 if (self.userOptions.placeHolder != "" && self.title.textContent == "") { 676 self.title.textContent = self.userOptions.placeHolder; 677 } 678 }); 679 function docListener() { 680 document.removeEventListener("click", docListener); 681 self.drop.style.visibility = "hidden"; 682 if (self.search) { 683 self.inputBox.value = ""; 684 Array.prototype.slice.call(self.listElements).forEach(function (x) { 685 x.classList.remove("hidden-search"); 686 }); 687 } 688 } 689 } 690 this.init(); 691 this.checkUncheckAll(); 692} 693 694vanillaSelectBox.prototype.buildSelect = function (data) { 695 let self = this; 696 if(data == null || data.length < 1) return; 697 if(!self.isOptgroups){ 698 self.isOptgroups = data[0].parent != undefined && data[0].parent != ""; 699 } 700 701 if(self.isOptgroups){ 702 let groups = {}; 703 data = data.filter(function(x){ 704 return x.parent != undefined && x.parent != ""; 705 }); 706 707 data.forEach(function (x) { 708 if(!groups[x.parent]){ 709 groups[x.parent] = true; 710 } 711 }); 712 for (let group in groups) { 713 let anOptgroup = document.createElement("optgroup"); 714 anOptgroup.setAttribute("label", group); 715 716 options = data.filter(function(x){ 717 return x.parent == group; 718 }); 719 options.forEach(function (x) { 720 let anOption = document.createElement("option"); 721 anOption.value = x.value; 722 anOption.text = x.text; 723 if(x.selected){ 724 anOption.setAttribute("selected",true) 725 } 726 anOptgroup.appendChild(anOption); 727 }); 728 self.root.appendChild(anOptgroup); 729 } 730 }else{ 731 data.forEach(function (x) { 732 let anOption = document.createElement("option"); 733 anOption.value = x.value; 734 anOption.text = x.text; 735 if(x.selected){ 736 anOption.setAttribute("selected",true) 737 } 738 self.root.appendChild(anOption); 739 }); 740 } 741} 742 743vanillaSelectBox.prototype.remoteSearchIntegrate = function (data) { 744 let self = this; 745 746 if (data == null || data.length == 0) { 747 let dataChecked = self.optionsCheckedToData(); 748 if(dataChecked) 749 data = dataChecked.slice(0); 750 self.remoteSearchIntegrateIt(data); 751 } else { 752 let dataChecked = self.optionsCheckedToData(); 753 if (dataChecked.length > 0){ 754 for (var i = data.length - 1; i >= 0; i--) { 755 if(dataChecked.indexOf(data[i].id) !=-1){ 756 data.slice(i,1); 757 } 758 } 759 } 760 data = data.concat(dataChecked); 761 762 self.remoteSearchIntegrateIt(data); 763 } 764} 765 766vanillaSelectBox.prototype.optionsCheckedToData = function () { 767 let self = this; 768 let dataChecked = []; 769 let treeOptions = self.ul.querySelectorAll("li.active:not(.grouped-option)"); 770 let keepParents = {}; 771 if (treeOptions) { 772 Array.prototype.slice.call(treeOptions).forEach(function (x) { 773 let oneData = {"value":x.getAttribute("data-value"),"text":x.getAttribute("data-text"),"selected":true}; 774 if(oneData.value !== "all"){ 775 if(self.isOptgroups){ 776 let parentId = x.getAttribute("data-parent"); 777 if(keepParents[parentId]!=undefined){ 778 oneData.parent = keepParents[parentId]; 779 }else{ 780 let parentPtr = self.ul.querySelector("#"+parentId); 781 let parentName = parentPtr.getAttribute("data-text"); 782 keepParents[parentId] = parentName; 783 oneData.parent = parentName; 784 } 785 } 786 dataChecked.push(oneData); 787 } 788 }); 789 } 790 return dataChecked; 791} 792 793vanillaSelectBox.prototype.removeOptionsNotChecked = function (data) { 794 let self = this; 795 let minimumSize = self.onInitSize; 796 let newSearchSize = data == null ? 0 : data.length; 797 let presentSize = self.root.length; 798 if (presentSize + newSearchSize > minimumSize) { 799 let maxToRemove = presentSize + newSearchSize - minimumSize - 1; 800 let removed = 0; 801 for (var i = self.root.length - 1; i >= 0; i--) { 802 if (self.root.options[i].selected == false) { 803 if (removed <= maxToRemove) { 804 removed++; 805 self.root.remove(i); 806 } 807 } 808 } 809 } 810} 811 812vanillaSelectBox.prototype.changeTree = function (data, options) { 813 let self = this; 814 self.empty(); 815 self.remoteSearchIntegrateIt(data); 816 if (options && options.onSearch) { 817 if (typeof options.onSearch === 'function') { 818 self.onSearch = options.onSearch; 819 self.isSearchRemote = true; 820 } 821 } 822 self.listElements = this.drop.querySelectorAll("li:not(.grouped-option)"); 823} 824 825vanillaSelectBox.prototype.remoteSearchIntegrateIt = function (data) { 826 let self = this; 827 if (data == null || data.length == 0) return; 828 while(self.root.firstChild) 829 self.root.removeChild(self.root.firstChild); 830 831 self.buildSelect(data); 832 self.reloadTree(); 833} 834 835vanillaSelectBox.prototype.reloadTree = function () { 836 let self = this; 837 let lis = self.ul.querySelectorAll("li"); 838 if (lis != null) { 839 for (var i = lis.length - 1; i >= 0; i--) { 840 if (lis[i].getAttribute('data-value') !== 'all') { 841 self.ul.removeChild(lis[i]); 842 } 843 } 844 } 845 846 let selectedTexts = "" 847 let sep = ""; 848 let nrActives = 0; 849 let nrAll = 0; 850 851 if (self.isOptgroups) { 852 if (document.querySelector(self.domSelector + ' optgroup') !== null) { 853 self.options = document.querySelectorAll(this.domSelector + " option"); 854 let groups = document.querySelectorAll(this.domSelector + ' optgroup'); 855 Array.prototype.slice.call(groups).forEach(function (group) { 856 let groupOptions = group.querySelectorAll('option'); 857 let li = document.createElement("li"); 858 let span = document.createElement("span"); 859 let iCheck = document.createElement("i"); 860 let labelElement = document.createElement("b"); 861 let dataWay = group.getAttribute("data-way"); 862 if (!dataWay) dataWay = "closed"; 863 if (!dataWay || (dataWay !== "closed" && dataWay !== "open")) dataWay = "closed"; 864 li.appendChild(span); 865 li.appendChild(iCheck); 866 self.ul.appendChild(li); 867 li.classList.add('grouped-option'); 868 li.classList.add(dataWay); 869 self.currentOptgroup++; 870 let optId = self.rootToken + "-opt-" + self.currentOptgroup; 871 li.id = optId; 872 li.appendChild(labelElement); 873 labelElement.appendChild(document.createTextNode(group.label)); 874 li.setAttribute("data-text", group.label); 875 self.ul.appendChild(li); 876 877 Array.prototype.slice.call(groupOptions).forEach(function (x) { 878 let text = x.textContent; 879 let value = x.value; 880 let classes = x.getAttribute("class"); 881 if (classes) { 882 classes = classes.split(" "); 883 } 884 else { 885 classes = []; 886 } 887 classes.push(dataWay); 888 let li = document.createElement("li"); 889 let isSelected = x.hasAttribute("selected"); 890 self.ul.appendChild(li); 891 li.setAttribute("data-value", value); 892 li.setAttribute("data-text", text); 893 li.setAttribute("data-parent", optId); 894 if (classes.length != 0) { 895 classes.forEach(function (x) { 896 li.classList.add(x); 897 }); 898 } 899 if (isSelected) { 900 nrActives++; 901 selectedTexts += sep + text; 902 sep = ","; 903 li.classList.add("active"); 904 if (!self.isMultiple) { 905 self.title.textContent = text; 906 if (classes.length != 0) { 907 classes.forEach(function (x) { 908 self.title.classList.add(x); 909 }); 910 } 911 } 912 } 913 li.appendChild(document.createTextNode(text)); 914 }) 915 }) 916 } 917 self.listElements = this.drop.querySelectorAll("li:not(.grouped-option)"); 918 } else { 919 self.options = self.root.querySelectorAll("option"); 920 Array.prototype.slice.call(self.options).forEach(function (x) { 921 let text = x.textContent; 922 let value = x.value; 923 if (value != "all") { 924 let originalAttrs; 925 if (x.hasAttributes()) { 926 originalAttrs = Array.prototype.slice.call(x.attributes) 927 .filter(function (a) { 928 return self.forbidenAttributes.indexOf(a.name) === -1 929 }); 930 } 931 let classes = x.getAttribute("class"); 932 if (classes) { 933 classes = classes 934 .split(" ") 935 .filter(function (c) { 936 return self.forbidenClasses.indexOf(c) === -1 937 }); 938 } else { 939 classes = []; 940 } 941 let li = document.createElement("li"); 942 let isSelected = x.hasAttribute("selected"); 943 944 let isDisabled = x.disabled; 945 946 self.ul.appendChild(li); 947 li.setAttribute("data-value", value); 948 li.setAttribute("data-text", text); 949 950 if (originalAttrs !== undefined) { 951 originalAttrs.forEach(function (a) { 952 li.setAttribute(a.name, a.value); 953 }); 954 } 955 956 classes.forEach(function (x) { 957 li.classList.add(x); 958 }); 959 960 if (self.maxOptionWidth < Infinity) { 961 li.classList.add("short"); 962 li.style.maxWidth = self.maxOptionWidth + "px"; 963 } 964 965 if (isSelected) { 966 nrActives++; 967 selectedTexts += sep + text; 968 sep = ","; 969 li.classList.add("active"); 970 if (!self.isMultiple) { 971 self.title.textContent = text; 972 if (classes.length != 0) { 973 classes.forEach(function (x) { 974 self.title.classList.add(x); 975 }); 976 } 977 } 978 } 979 if (isDisabled) { 980 li.classList.add("disabled"); 981 } 982 li.appendChild(document.createTextNode(" " + text)); 983 } 984 }); 985 } 986 987} 988 989vanillaSelectBox.prototype.disableItems = function (values) { 990 let self = this; 991 let foundValues = []; 992 if (vanillaSelectBox_type(values) == "string") { 993 values = values.split(","); 994 } 995 996 if (vanillaSelectBox_type(values) == "array") { 997 Array.prototype.slice.call(self.options).forEach(function (x) { 998 if (values.indexOf(x.value) != -1) { 999 foundValues.push(x.value); 1000 x.setAttribute("disabled", ""); 1001 } 1002 }); 1003 } 1004 Array.prototype.slice.call(self.listElements).forEach(function (x) { 1005 let val = x.getAttribute("data-value"); 1006 if (foundValues.indexOf(val) != -1) { 1007 x.classList.add("disabled"); 1008 } 1009 }); 1010} 1011 1012vanillaSelectBox.prototype.enableItems = function (values) { 1013 let self = this; 1014 let foundValues = []; 1015 if (vanillaSelectBox_type(values) == "string") { 1016 values = values.split(","); 1017 } 1018 1019 if (vanillaSelectBox_type(values) == "array") { 1020 Array.prototype.slice.call(self.options).forEach(function (x) { 1021 if (values.indexOf(x.value) != -1) { 1022 foundValues.push(x.value); 1023 x.removeAttribute("disabled"); 1024 } 1025 }); 1026 } 1027 1028 Array.prototype.slice.call(self.listElements).forEach(function (x) { 1029 if (foundValues.indexOf(x.getAttribute("data-value")) != -1) { 1030 x.classList.remove("disabled"); 1031 } 1032 }); 1033} 1034 1035vanillaSelectBox.prototype.checkSelectMax = function (nrActives) { 1036 let self = this; 1037 if (self.maxSelect == Infinity || !self.isMultiple) return; 1038 if (self.maxSelect <= nrActives) { 1039 Array.prototype.slice.call(self.listElements).forEach(function (x) { 1040 if (x.hasAttribute('data-value')) { 1041 if (!x.classList.contains('disabled') && !x.classList.contains('active')) { 1042 x.classList.add("overflow"); 1043 } 1044 } 1045 }); 1046 } else { 1047 Array.prototype.slice.call(self.listElements).forEach(function (x) { 1048 if (x.classList.contains('overflow')) { 1049 x.classList.remove("overflow"); 1050 } 1051 }); 1052 } 1053} 1054 1055vanillaSelectBox.prototype.checkUncheckFromChild = function (liClicked) { 1056 let self = this; 1057 let parentId = liClicked.getAttribute('data-parent'); 1058 let parentLi = document.getElementById(parentId); 1059 if (!self.isMultiple) return; 1060 let listElements = self.drop.querySelectorAll("li"); 1061 let childrenElements = Array.prototype.slice.call(listElements).filter(function (el) { 1062 return el.hasAttribute("data-parent") && el.getAttribute('data-parent') == parentId && !el.classList.contains('hidden-search') ; 1063 }); 1064 let nrChecked = 0; 1065 let nrCheckable = childrenElements.length; 1066 if (nrCheckable == 0) return; 1067 childrenElements.forEach(function (el) { 1068 if (el.classList.contains('active')) nrChecked++; 1069 }); 1070 if (nrChecked === nrCheckable || nrChecked === 0) { 1071 if (nrChecked === 0) { 1072 parentLi.classList.remove("checked"); 1073 } else { 1074 parentLi.classList.add("checked"); 1075 } 1076 } else { 1077 parentLi.classList.remove("checked"); 1078 } 1079} 1080 1081vanillaSelectBox.prototype.checkUncheckFromParent = function (liClicked) { 1082 let self = this; 1083 let parentId = liClicked.id; 1084 if (!self.isMultiple) return; 1085 let listElements = self.drop.querySelectorAll("li"); 1086 let childrenElements = Array.prototype.slice.call(listElements).filter(function (el) { 1087 return el.hasAttribute("data-parent") && el.getAttribute('data-parent') == parentId && !el.classList.contains('hidden-search'); 1088 }); 1089 let nrChecked = 0; 1090 let nrCheckable = childrenElements.length; 1091 if (nrCheckable == 0) return; 1092 childrenElements.forEach(function (el) { 1093 if (el.classList.contains('active')) nrChecked++; 1094 }); 1095 if (nrChecked === nrCheckable || nrChecked === 0) { 1096 //check all or uncheckAll : just do the opposite 1097 childrenElements.forEach(function (el) { 1098 var event = document.createEvent('HTMLEvents'); 1099 event.initEvent('click', true, false); 1100 el.dispatchEvent(event); 1101 }); 1102 if (nrChecked === 0) { 1103 liClicked.classList.add("checked"); 1104 } else { 1105 liClicked.classList.remove("checked"); 1106 } 1107 } else { 1108 //check all 1109 liClicked.classList.remove("checked"); 1110 childrenElements.forEach(function (el) { 1111 if (!el.classList.contains('active')) { 1112 var event = document.createEvent('HTMLEvents'); 1113 event.initEvent('click', true, false); 1114 el.dispatchEvent(event); 1115 } 1116 }); 1117 } 1118} 1119 1120vanillaSelectBox.prototype.checkUncheckAll = function () { 1121 let self = this; 1122 if (!self.isMultiple) return; 1123 let nrChecked = 0; 1124 let nrCheckable = 0; 1125 let checkAllElement = null; 1126 if (self.listElements == null) return; 1127 Array.prototype.slice.call(self.listElements).forEach(function (x) { 1128 if (x.hasAttribute('data-value')) { 1129 if (x.getAttribute('data-value') === 'all') { 1130 checkAllElement = x; 1131 } 1132 if (x.getAttribute('data-value') !== 'all' 1133 && !x.classList.contains('hidden-search') 1134 && !x.classList.contains('disabled')) { 1135 nrCheckable++; 1136 nrChecked += x.classList.contains('active'); 1137 } 1138 } 1139 }); 1140 1141 if (checkAllElement) { 1142 if (nrChecked === nrCheckable) { 1143 // check the checkAll checkbox 1144 self.title.textContent = self.userOptions.translations.all || "all"; 1145 checkAllElement.classList.add("active"); 1146 checkAllElement.innerText = self.userOptions.translations.clearAll; 1147 checkAllElement.setAttribute('data-selected', 'true') 1148 } else if (nrChecked === 0) { 1149 // uncheck the checkAll checkbox 1150 self.title.textContent = self.userOptions.placeHolder; 1151 checkAllElement.classList.remove("active"); 1152 checkAllElement.innerText = self.userOptions.translations.selectAll; 1153 checkAllElement.setAttribute('data-selected', 'false') 1154 } 1155 } 1156} 1157 1158vanillaSelectBox.prototype.setValue = function (values) { 1159 let self = this; 1160 let listElements = self.drop.querySelectorAll("li"); 1161 1162 if (values == null || values == undefined || values == "") { 1163 self.empty(); 1164 } else { 1165 if (self.isMultiple) { 1166 if (vanillaSelectBox_type(values) == "string") { 1167 if (values === "all") { 1168 values = []; 1169 Array.prototype.slice.call(listElements).forEach(function (x) { 1170 if (x.hasAttribute('data-value')) { 1171 let value = x.getAttribute('data-value'); 1172 if (value !== 'all') { 1173 if (!x.classList.contains('hidden-search') && !x.classList.contains('disabled')) { 1174 values.push(x.getAttribute('data-value')); 1175 } 1176 // already checked (but hidden by search) 1177 if (x.classList.contains('active')) { 1178 if (x.classList.contains('hidden-search') || x.classList.contains('disabled')) { 1179 values.push(value); 1180 } 1181 } 1182 }else{ 1183 x.classList.add("active"); 1184 } 1185 } else if (x.classList.contains('grouped-option')) { 1186 x.classList.add("checked"); 1187 } 1188 }); 1189 }
1189 else if (values === "none") { 1190 values = []; 1191 Array.prototype.slice.call(listElements).forEach(function (x) { 1192 if (x.hasAttribute('data-value')) { 1193 let value = x.getAttribute('data-value'); 1194 if (value !== 'all') { 1195 if (x.classList.contains('active')) { 1196 if (x.classList.contains('hidden-search') || x.classList.contains('disabled')) { 1197 values.push(value); 1198 } 1199 } 1200 } 1201 } else if (x.classList.contains('grouped-option')) { 1202 x.classList.remove("checked"); 1203 } 1204 }); 1205 } else { 1206 values = values.split(","); 1207 } 1208 } 1209 let foundValues = []; 1210 if (vanillaSelectBox_type(values) == "array") { 1211 Array.prototype.slice.call(self.options).forEach(function (x) { 1212 if (values.indexOf(x.value) !== -1) { 1213 x.selected = true; 1214 foundValues.push(x.value); 1215 } else { 1216 x.selected = false; 1217 } 1218 }); 1219 let selectedTexts = "" 1220 let sep = ""; 1221 let nrActives = 0; 1222 let nrAll = 0; 1223 Array.prototype.slice.call(listElements).forEach(function (x) { 1224 if (x.value !== 'all') { 1225 nrAll++; 1226 } 1227 if (foundValues.indexOf(x.getAttribute("data-value")) != -1) { 1228 x.classList.add("active"); 1229 nrActives++; 1230 selectedTexts += sep + x.getAttribute("data-text"); 1231 sep = ","; 1232 } else { 1233 x.classList.remove("active"); 1234 } 1235 }); 1236 if (nrAll == nrActives - Number(!self.userOptions.disableSelectAll)) { 1237 let wordForAll = self.userOptions.translations.all || "all"; 1238 selectedTexts = wordForAll; 1239 } else if (self.multipleSize != -1) { 1240 if (nrActives > self.multipleSize) { 1241 let wordForItems = self.userOptions.translations.items || "items" 1242 selectedTexts = nrActives + " " + wordForItems; 1243 } 1244 } 1245 self.title.textContent = selectedTexts; 1246 self.privateSendChange(); 1247 } 1248 self.checkUncheckAll(); 1249 } else { 1250 let found = false; 1251 let text = ""; 1252 let classNames = "" 1253 Array.prototype.slice.call(listElements).forEach(function (x) { 1254 let liVal = x.getAttribute("data-value") == values; 1255 if(liVal !== "all"){ 1256 if (liVal == values) { 1257 x.classList.add("active"); 1258 found = true; 1259 text = x.getAttribute("data-text") 1260 } else { 1261 x.classList.remove("active"); 1262 } 1263 } 1264 }); 1265 Array.prototype.slice.call(self.options).forEach(function (x) { 1266 if (x.value == values) { 1267 x.selected = true; 1268 className = x.getAttribute("class"); 1269 if (!className) className = ""; 1270 } else { 1271 x.selected = false; 1272 } 1273 }); 1274 if (found) { 1275 self.title.textContent = text; 1276 if (self.userOptions.placeHolder != "" && self.title.textContent == "") { 1277 self.title.textContent = self.userOptions.placeHolder; 1278 } 1279 if (className != "") { 1280 self.title.setAttribute("class", className + " title"); 1281 } else { 1282 self.title.setAttribute("class", "title"); 1283 } 1284 } 1285 } 1286 } 1287} 1288 1289vanillaSelectBox.prototype.privateSendChange = function () { 1290 let event = document.createEvent('HTMLEvents'); 1291 event.initEvent('change', true, false); 1292 this.root.dispatchEvent(event); 1293} 1294 1295vanillaSelectBox.prototype.empty = function () {
vendor: 2,103 bytes, lines 1296-1359
1296 Array.prototype.slice.call(this.listElements).forEach(function (x) { 1297 x.classList.remove("active"); 1298 }); 1299 let parentElements = this.drop.querySelectorAll("li.grouped-option"); 1300 if(parentElements){ 1301 Array.prototype.slice.call(parentElements).forEach(function (x) { 1302 x.classList.remove("checked"); 1303 }); 1304 } 1305 Array.prototype.slice.call(this.options).forEach(function (x) { 1306 x.selected = false; 1307 }); 1308 this.title.textContent = ""; 1309 if (this.userOptions.placeHolder != "" && this.title.textContent == "") { 1310 this.title.textContent = this.userOptions.placeHolder; 1311 } 1312 this.checkUncheckAll(); 1313 this.privateSendChange(); 1314} 1315 1316vanillaSelectBox.prototype.destroy = function () { 1317 let already = document.getElementById("btn-group-" + this.rootToken); 1318 if (already) { 1319 VSBoxCounter.remove(this.instanceOffset); 1320 already.remove(); 1321 this.root.style.display = "inline-block"; 1322 } 1323} 1324vanillaSelectBox.prototype.disable = function () { 1325 let already = document.getElementById("btn-group-" + this.rootToken); 1326 if (already) { 1327 button = already.querySelector("button") 1328 if (button) button.classList.add("disabled"); 1329 this.isDisabled = true; 1330 } 1331} 1332vanillaSelectBox.prototype.enable = function () { 1333 let already = document.getElementById("btn-group-" + this.rootToken); 1334 if (already) { 1335 button = already.querySelector("button") 1336 if (button) button.classList.remove("disabled"); 1337 this.isDisabled = false; 1338 } 1339} 1340 1341vanillaSelectBox.prototype.showOptions = function () { 1342 console.log(this.userOptions); 1343} 1344// Polyfills for IE 1345if (!('remove' in Element.prototype)) { 1346 Element.prototype.remove = function () { 1347 if (this.parentNode) { 1348 this.parentNode.removeChild(this); 1349 } 1350 }; 1351} 1352 1353function vanillaSelectBox_type(target) { 1354 const computedType = Object.prototype.toString.call(target); 1355 const stripped = computedType.replace("[object ", "").replace("]", ""); 1356 const lowercased = stripped.toLowerCase(); 1357 return lowercased; 1358} 1359
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.