HEX
Server: Apache
System: Linux webm010.cluster127.gra.hosting.ovh.net 6.18.42-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Wed Aug 5 15:59:48 CEST 2026 x86_64
User: alloesb (202139)
PHP: 8.3.31
Disabled: _dyuweyrj4,_dyuweyrj4r,dl
Upload Files
File: /home/a/l/l/alloesb/www/wp-content/plugins/customify/js/customizer/search.js
/**
 * The logic for the Customizer controls search.
 *
 * Based on the logic from this WordPress plugin: https://wordpress.org/plugins/customizer-search/
 */

/** @namespace customify */
window.customify = window.customify || parent.customify || {};

(function ($, customify, wp) {

  /**
   * Expose the API publicly on window.customify.search
   *
   * @namespace customify.search
   */
  if (typeof customify.search === 'undefined') {
    customify.search = {}
  }

  _.extend(customify.search, function () {
    const api = wp.customize

    const searchWrapperSelector = '#accordion-section-customify-customizer-search'
    const searchInputSelector = '#customify-customizer-search-input'

    let customizePanelsParent = null

    let fuse = null

    const init = function () {

      const searchableControls = _.map(api.settings.controls, function (control, controlId) {
        if ( typeof controlId !== 'string') {
          controlId = String(controlId)
        }
        // Determine if the control should be excluded from search results.
        const excluded = _.find( customify.search.excludedControls, function (partial) {
          return controlId.indexOf(partial) !== -1;
        })
        if (excluded !== undefined) {
          return
        }

        const searchableControl = {
          "label": (typeof control.label !== 'undefined' && !_.isEmpty(control.label)) ? control.label : '',
          "description": (typeof control.description !== 'undefined' && !_.isEmpty(control.description)) ? control.description : '',
          "panelName": '',
          "sectionName": '',
          "panel": null,
          "section": control.section, // This is to know what section to expand when clicking on this result.
        }

        _.map(api.settings.sections, function (section, index) {
          if (control.section === section.id) {
            _.map(_wpCustomizeSettings.panels, function (panel, index) {
              if ('' === section.panel) {
                searchableControl.panelName = section.title
              }

              if (section.panel === panel.id) {
                searchableControl.sectionName = section.title
                searchableControl.panel = section.panel
                searchableControl.panelName = panel.title
              }
            })
          }
        })

        return searchableControl
      }).filter(function(item){ // Make sure that we remove excluded controls entries.
        return item !== undefined;
      })

      // Initialize the FuseJS search
      const fuseOptions = {
        includeScore: true,
        includeMatches: true,
        shouldSort: true,
        minMatchCharLength: 2,
        threshold: 0.3, // The fussy search threshold. Lower for closer matches (less fuzzy).
        keys: [
          {
            name: 'label',
            weight: 1
          },
          {
            name: 'description',
            weight: 0.8
          },
          {
            name: 'panelName',
            weight: 0.4
          },
          {
            name: 'sectionName',
            weight: 0.4
          }
        ]
      }

      // Create a new instance of Fuse
      fuse = new Fuse(searchableControls, fuseOptions)

      const $customizeInfo = $('#customize-info')

      customizePanelsParent = $('#customize-theme-controls')
      customizePanelsParent.after('<div id="customify-search-results"></div>')

      $customizeInfo.on('keyup', searchInputSelector, function (event) {
        event.preventDefault()

        const searchString = $(searchInputSelector).val()

        // At least 3 characters required for search.
        if (searchString.length > 2) {
          displayResults(searchString)
        } else if (searchString.length === 0) {
          clearSearch()
        }
      })

      $customizeInfo.on('click', '.clear-search', function (event) {
        clearSearch()
      })

      $customizeInfo.on('click', '.close-search', function (event) {
        toggleDisplaySearchForm()
      })

      $customizeInfo.on('click', '.customize-search-toggle', function (event) {
        toggleDisplaySearchForm()
      })

      api.previewer.targetWindow.bind(showSearchButtonToggle)

      // Handle showing the current search results when returning to the top pane.
      api.state( 'expandedSection' ).bind(showSearchResultsWhenTopPaneVisible)
      api.state( 'expandedPanel' ).bind(showSearchResultsWhenTopPaneVisible)
    }

    const showSearchResultsWhenTopPaneVisible = function() {
      if (!api.state( 'expandedSection' ).get() && !api.state( 'expandedPanel' ).get()) {
        const searchString = $(searchInputSelector).val()
        if (searchString.length > 2) {
          setTimeout( function() {
            displayResults(searchString)
          }, 400)
        }
      }
    }

    const displayResults = function (stringToSearch) {
      const resultsArray = fuse.search(stringToSearch)

      // Bail if no results.
      if (0 === resultsArray.length) {
        customizePanelsParent.removeClass('search-found')
        return
      }

      const html = resultsArray.map(function (result, index) {

        // Bail if no matches or empty label.
        if (_.isEmpty(result.matches) || '' === result.item.label) {
          return
        }

        // Make a copy for highlight.
        const highlightedResult =$.extend(true, {}, result);

        // Highlight everything there is to highlight.
        _.each(result.matches, function(match) {
          if (typeof match.indices === 'undefined' || _.isEmpty(match.indices)) {
            // No highlighting to do.
            return
          }

          // The key is like `label` or `sectionName`.
          highlightedResult.item[match.key] = generateHighlightedText(match.value, match.indices)
        })

        // Construct the control trail with panel > section.
        let controlTrail = highlightedResult.item.panelName
        if ('' !== highlightedResult.item.sectionName) {
          controlTrail = `${controlTrail} ▸ ${highlightedResult.item.sectionName}`
        }

        return `
                <li id="accordion-section-${result.item.section}" class="accordion-section control-section control-section-default customizer-search-results" aria-owns="sub-accordion-section-${result.item.section}" data-section="${result.item.section}">
                    <h3 class="accordion-section-title" tabindex="0">
                        ${highlightedResult.item.label}
                        <span class="screen-reader-text">${customify.l10n.search.resultsSectionScreenReaderText}</span>
                    </h3>
                    <span class="search-setting-path">${controlTrail}</i></span>
                </li>
                `
      }).join('')

      customizePanelsParent.addClass('search-found')
      document.getElementById('customify-search-results').innerHTML = `<ul>${html}</ul>`

      const searchSettings = document.querySelectorAll('#customify-search-results .accordion-section')
      searchSettings.forEach(setting => setting.addEventListener('click', expandSection))
    }

    // Does not account for overlapping highlighted regions, if that exists at all O_o..
    const generateHighlightedText = function (text, regions) {
      if(!regions) {
        return text;
      }

      const highlightedText = []
      let pair = regions.shift()
      // Build the formatted string
      for (let i = 0; i < text.length; i++) {
        const char = text.charAt(i)
        if (pair && i == pair[0]) {
          highlightedText.push('<span class="hl">')
        }
        highlightedText.push(char)
        if (pair && i == pair[1]) {
          highlightedText.push('</span>')
          pair = regions.shift()
        }
      }

      return highlightedText.join('')
    }

    /**
     * Shows the message that is shown for when a header
     * or footer is already set for this page.
     */
    const showSearchButtonToggle = function () {
      let template = wp.template('customify-search-button')
      if ($('#customize-info .accordion-section-title .customize-search-toggle').length === 0) {
        $('#customize-info .accordion-section-title').append(template())
      }

      template = wp.template('customify-search-form')
      if ($('#customize-info '+searchWrapperSelector).length === 0) {
        $('#customize-info .customize-panel-description').after(template())
      }
    }

    const toggleDisplaySearchForm = function () {
      const $wrapper = $(searchWrapperSelector)

      if ($wrapper.hasClass('open')) {
        // Close it
        $wrapper.removeClass('open')
        $wrapper.slideUp('fast')

        // Also clear the search.
        clearSearch()
      } else {
        // Open it
        $('.customize-panel-description').removeClass('open')
        $('.customize-panel-description').slideUp('fast')

        $wrapper.addClass('open')
        $wrapper.slideDown('fast')

        $(searchInputSelector).focus()
      }
    }

    const expandSection = function (event) {
      const sectionName = this.getAttribute('data-section')
      const section = api.section(sectionName)

      customizePanelsParent.removeClass('search-found')
      document.getElementById('customify-search-results').innerHTML = ''
      $(searchInputSelector).focus()

      section.expand()
    }

    /**
     * Clear Search input and display all the options.
     */
    const clearSearch = function () {
      customizePanelsParent.removeClass('search-found')
      document.getElementById('customify-search-results').innerHTML = ''
      document.getElementById('customify-customizer-search-input').value = ''

      $(searchInputSelector).focus()
    }

    // When the customizer is ready prepare the search logic.
    api.bind('ready', init)

    return {
      init: init,
    }
  }())

})(jQuery, customify, wp)