Search within an accordion

后端 未结 2 1998
轮回少年
轮回少年 2021-01-16 23:04

I\'ve got an accordion with section headers and individual items. I\'m going to link to the element ID to scroll to the relevant section but want to use a search box to sear

2条回答
  •  爱一瞬间的悲伤
    2021-01-16 23:24

    I have improved the code which was made by Rick Sibley.

    The previous code had a bug. I added highlight removing in the not correct search after correct search. When you search existing word the text is highlighted in yellow. If you do the following search with a non-existent word hilight will be removed. In previous code this feature doestn work.

    //Hilitor Settings
    var highlightIndex = new Hilitor("highlightIndex");
    highlightIndex.setMatchType("left");
    
    //Globals
    var input = document.getElementById("DefinitionSearch");
    var acc = document.getElementsByClassName("accordion");
    
    //Open Subject Accordion
    [].forEach.call(acc, function(item, index, a) {
      item.addEventListener("click", function() {
        var panel = this.nextElementSibling;
        this.classList.toggle("active");
        if (panel.style.maxHeight) {
          panel.style.maxHeight = null;
        } else {
          panel.style.maxHeight = panel.scrollHeight + "px";
        }
      });
    });
    
    //Search Accordings; Highlight & Open Matching Areas
    input.addEventListener("keyup", function(event) {
      if (event.which === 13 || event.keyCode === 13) {
    
        var input, filter, i, acc, panels, txtValue, searchText, searchTitle;
        input = document.getElementById("DefinitionSearch");
        filter = input.value.toUpperCase();
        acc = document.getElementsByClassName("accordion");
        panels = document.getElementsByClassName("panel");
    
        for (i = 0; i < panels.length; i++) {
          for (i = 0; i < acc.length; i++) {
            searchText = panels[i].textContent || panels[i].innerText;
            searchTitle = acc[i].textContent || acc[i].innerText;
            if (input.value !== "") {
              if (searchText.toUpperCase().indexOf(filter) > -1 || searchTitle.toUpperCase().indexOf(filter) > -1) {
                if (!acc[i].classList.contains("active")) {
                  acc[i].classList.add("active");
                }
                highlightIndex.apply(filter);
                panels[i].style.maxHeight = panels[i].scrollHeight + "px";
                panels[i].scrollIntoView({
                  behavior: 'smooth'
                });
              } else {
                if (acc[i].classList.contains("active")) {
                  acc[i].classList.remove("active");
                  highlightIndex.remove();
                }
                panels[i].style.maxHeight = null;
              }
            } else {
              highlightIndex.remove();
              if (acc[i].classList.contains("active")) {
                acc[i].classList.remove("active");
              }
              panels[i].style.maxHeight = null;
            }
          }
        }
      }
    });
    
    //Clear button
    function clearBtn() {
      var input, i, acc, panels;
      input = document.getElementById("DefinitionSearch");
      acc = document.getElementsByClassName("accordion");
      panels = document.getElementsByClassName("panel");
    
      input.value = "";
      highlightIndex.remove();
      for (i = 0; i < panels.length; i++) {
        for (i = 0; i < acc.length; i++) {
          if (acc[i].classList.contains("active")) {
            acc[i].classList.remove("active");
          }
          panels[i].style.maxHeight = null;
        }
      }
    }
    
    // Highlight Script "hilitor.js" Found at: https://www.the-art-of-web.com/javascript/search-highlight/
    // Original JavaScript code by Chirp Internet: www.chirp.com.au
    // Please acknowledge use of this code by including this header.
    function Hilitor(id, tag) {
    
      // private variables
      var targetNode = document.getElementById(id) || document.body;
      var hiliteTag = tag || "MARK";
      var skipTags = new RegExp("^(?:" + hiliteTag + "|SCRIPT|FORM|SPAN)$");
      //var colors = ["#ff6", "#a0ffff", "#9f9", "#f99", "#f6f"];
      var colors = ["#ff6"];
      var wordColor = [];
      var colorIdx = 0;
      var matchRegExp = "";
      var openLeft = false;
      var openRight = false;
    
      // characters to strip from start and end of the input string
      var endRegExp = new RegExp('^[^\\w]+|[^\\w]+$', "g");
    
      // characters used to break up the input string into words
      var breakRegExp = new RegExp('[^\\w\'-]+', "g");
    
      this.setEndRegExp = function(regex) {
        endRegExp = regex;
        return endRegExp;
      };
    
      this.setBreakRegExp = function(regex) {
        breakRegExp = regex;
        return breakRegExp;
      };
    
      this.setMatchType = function(type) {
        switch (type) {
          case "left":
            this.openLeft = false;
            this.openRight = true;
            break;
    
          case "right":
            this.openLeft = true;
            this.openRight = false;
            break;
    
          case "open":
            this.openLeft = this.openRight = true;
            break;
    
          default:
            this.openLeft = this.openRight = false;
    
        }
      };
    
      this.setRegex = function(input) {
        input = input.replace(endRegExp, "");
    
        //The next two deal with the search, If you want to seach somthing like subject 1 and not see all words with subject highlighted then keep the settings as is. If you want to see them all highlighted then uncomment ...(breakRegExp, "|") and comment out the current setting ...(breakRegExp, " ")
    
        //input = input.replace(breakRegExp, "|");
        input = input.replace(breakRegExp, " ");
    
        input = input.replace(/^\||\|$/g, "");
        if (input) {
          var re = "(" + input + ")";
          if (!this.openLeft) re = "\\b" + re;
          if (!this.openRight) re = re + "\\b";
          matchRegExp = new RegExp(re, "i");
          return matchRegExp;
        }
        return false;
      };
    
      this.getRegex = function() {
        var retval = matchRegExp.toString();
        retval = retval.replace(/(^\/(\\b)?|\(|\)|(\\b)?\/i$)/g, "");
        retval = retval.replace(/\|/g, " ");
        return retval;
      };
    
      // recursively apply word highlighting
      this.hiliteWords = function(node) {
        if (node === undefined || !node) return;
        if (!matchRegExp) return;
        if (skipTags.test(node.nodeName)) return;
    
        if (node.hasChildNodes()) {
          for (var i = 0; i < node.childNodes.length; i++)
            this.hiliteWords(node.childNodes[i]);
        }
        if (node.nodeType == 3) { // NODE_TEXT
          if ((nv = node.nodeValue) && (regs = matchRegExp.exec(nv))) {
            if (!wordColor[regs[0].toLowerCase()]) {
              wordColor[regs[0].toLowerCase()] = colors[colorIdx++ % colors.length];
            }
    
            var match = document.createElement(hiliteTag);
            match.appendChild(document.createTextNode(regs[0]));
            match.style.backgroundColor = wordColor[regs[0].toLowerCase()];
            match.style.color = "#000";
    
            var after = node.splitText(regs.index);
            after.nodeValue = after.nodeValue.substring(regs[0].length);
            node.parentNode.insertBefore(match, after);
          }
        };
      };
    
      // remove highlighting
      this.remove = function() {
        var arr = document.getElementsByTagName(hiliteTag);
        while (arr.length && (el = arr[0])) {
          var parent = el.parentNode;
          parent.replaceChild(el.firstChild, el);
          parent.normalize();
        }
      };
    
      // start highlighting at target node
      this.apply = function(input) {
        this.remove();
        if (input === undefined || !input) return;
        if (this.setRegex(input)) {
          this.hiliteWords(targetNode);
        }
        return matchRegExp;
      };
    
    }
    
    .accordion {
      background-color: #1AD879;
      color: #FFFFFF;
      cursor: pointer;
      padding: 18px;
      width: 100%;
      border: none;
      text-align: left;
      outline: none;
      font-size: 15px;
      transition: 1.6s;
    }
    
    .active,
    .accordion:hover {
      background-color: #45F99F;
    }
    
    .panel {
      padding: 0 18px;
      background-color: #FFFFFF;
      max-height: 0;
      overflow: hidden;
      transition: max-height 0.8s ease-out;
    }
    

    Search the definitions

    Section Header




    hello



    world



    definition.



    definition with more text.



    make the page longer



    to see the scroll effect



    stackoverflow



    many subjects



    this is the end.



提交回复
热议问题