
/**
 *  jQuery fontIconPicker - 3.1.1
 *
 *  An icon picker built on top of font icons and jQuery
 *
 *  http://codeb.it/fontIconPicker
 *
 *  @author Alessandro Benoit & Swashata Ghosh
 *  @license MIT License
 *
 * {@link https://github.com/micc83/fontIconPicker}
 */
				
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery')) :
  typeof define === 'function' && define.amd ? define(['jquery'], factory) :
  (global.initFontIconPickerNode = factory(global.jQuery));
}(this, (function (jQuery) { 'use strict';

  jQuery = jQuery && jQuery.hasOwnProperty('default') ? jQuery['default'] : jQuery;

  function _typeof(obj) {
    if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
      _typeof = function (obj) {
        return typeof obj;
      };
    } else {
      _typeof = function (obj) {
        return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
      };
    }

    return _typeof(obj);
  }

  function _toConsumableArray(arr) {
    return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
  }

  function _arrayWithoutHoles(arr) {
    if (Array.isArray(arr)) {
      for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];

      return arr2;
    }
  }

  function _iterableToArray(iter) {
    if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
  }

  function _nonIterableSpread() {
    throw new TypeError("Invalid attempt to spread non-iterable instance");
  }

  /**
   * Default configuration options of fontIconPicker
   */

  var options = {
    theme: 'fip-grey',
    // The CSS theme to use with this fontIconPicker. You can set different themes on multiple elements on the same page
    source: false,
    // Icons source (array|false|object)
    emptyIcon: true,
    // Empty icon should be shown?
    emptyIconValue: '',
    // The value of the empty icon, change if you select has something else, say "none"
    autoClose: true,
    // Whether or not to close the FIP automatically when clicked outside
    iconsPerPage: 20,
    // Number of icons per page
    hasSearch: true,
    // Is search enabled?
    searchSource: false,
    // Give a manual search values. If using attributes then for proper search feature we also need to pass icon names under the same order of source
    appendTo: 'self',
    // Where to append the selector popup. You can pass string selectors or jQuery objects
    useAttribute: false,
    // Whether to use attribute selector for printing icons
    attributeName: 'data-icon',
    // HTML Attribute name
    convertToHex: true,
    // Whether or not to convert to hexadecimal for attribute value. If true then please pass decimal integer value to the source (or as value="" attribute of the select field)
    allCategoryText: 'From all categories',
    // The text for the select all category option
    unCategorizedText: 'Uncategorized',
    // The text for the select uncategorized option
    iconGenerator: null,
    // Icon Generator function. Passes, item, flipBoxTitle and index
    windowDebounceDelay: 150,
    // Debounce delay while fixing position on windowResize
    searchPlaceholder: 'Search Icons' // Placeholder for the search input

  };

  /**
  * Implementation of debounce function
  *
  * {@link https://medium.com/a-developers-perspective/throttling-and-debouncing-in-javascript-b01cad5c8edf}
  * @param {Function} func callback function
  * @param {int} delay delay in milliseconds
  */
  var debounce = function debounce(func, delay) {
    var inDebounce;
    return function () {
      var context = this;
      var args = arguments;
      clearTimeout(inDebounce);
      inDebounce = setTimeout(function () {
        return func.apply(context, args);
      }, delay);
    };
  };

  var $ = jQuery; // A guid for implementing namespaced event

  var guid = 0;

  function FontIconPicker(element, options$$1) {
    this.element = $(element);
    this.settings = $.extend({}, options, options$$1);

    if (this.settings.emptyIcon) {
      this.settings.iconsPerPage--;
    }

    this.iconPicker = $('<div/>', {
      class: 'icons-selector',
      style: 'position: relative',
      html: this._getPickerTemplate(),
      attr: {
        'data-fip-origin': this.element.attr('id')
      }
    });
    this.iconContainer = this.iconPicker.find('.fip-icons-container');
    this.searchIcon = this.iconPicker.find('.selector-search i');
    this.selectorPopup = this.iconPicker.find('.selector-popup-wrap');
    this.selectorButton = this.iconPicker.find('.selector-button');
    this.iconsSearched = [];
    this.isSearch = false;
    this.totalPage = 1;
    this.currentPage = 1;
    this.currentIcon = false;
    this.iconsCount = 0;
    this.uniqueiconsCount = 0;
    this.open = false;
    this.guid = guid++;
    this.eventNameSpace = ".fontIconPicker".concat(guid); // Set the default values for the search related variables

    this.searchValues = [];
    this.availableCategoriesSearch = []; // The trigger event for change

    this.triggerEvent = null; // Backups

    this.backupSource = [];
    this.backupSearch = []; // Set the default values of the category related variables

    this.isCategorized = false; // Automatically detects if the icon listing is categorized

    this.selectCategory = this.iconPicker.find('.icon-category-select'); // The category SELECT input field

    this.selectedCategory = false; // false means all categories are selected

    this.availableCategories = []; // Available categories, it is a two dimensional array which holds categorized icons

    this.unCategorizedKey = null; // Key of the uncategorized category
    // Initialize plugin

    this.init();
  }

  FontIconPicker.prototype = {
    /**
     * Init
     */
    init: function init() {
      // Add the theme CSS to the iconPicker
      this.iconPicker.addClass(this.settings.theme); // To properly calculate iconPicker height and width
      // We will first append it to body (with left: -9999px so that it is not visible)

      this.iconPicker.css({
        left: -9999
      }).appendTo('body');
      var iconPickerHeight = this.iconPicker.outerHeight(),
          iconPickerWidth = this.iconPicker.outerWidth(); // Now reset the iconPicker CSS

      this.iconPicker.css({
        left: ''
      }); // Add the icon picker after the select

      this.element.before(this.iconPicker); // Hide source element
      // Instead of doing a display:none, we would rather
      // make the element invisible
      // and adjust the margin

      this.element.css({
        visibility: 'hidden',
        top: 0,
        position: 'relative',
        zIndex: '-1',
        left: '-' + iconPickerWidth + 'px',
        display: 'inline-block',
        height: iconPickerHeight + 'px',
        width: iconPickerWidth + 'px',
        // Reset all margin, border and padding
        padding: '0',
        margin: '0 -' + iconPickerWidth + 'px 0 0',
        // Left margin adjustment to account for dangling space
        border: '0 none',
        verticalAlign: 'top',
        float: 'none' // Fixes positioning with floated elements

      }); // Set the trigger event

      if (!this.element.is('select')) {
        // Drop IE9 support and use the standard input event
        this.triggerEvent = 'input';
      } // If current element is SELECT populate settings.source


      if (!this.settings.source && this.element.is('select')) {
        // Populate data from select
        this._populateSourceFromSelect(); // Normalize the given source

      } else {
        this._initSourceIndex();
      } // load the categories


      this._loadCategories(); // Load icons


      this._loadIcons(); // Initialize dropdown button


      this._initDropDown(); // Category changer


      this._initCategoryChanger(); // Pagination


      this._initPagination(); // Icon Search


      this._initIconSearch(); // Icon Select


      this._initIconSelect();
      /**
       * On click out
       * Add the functionality #9
       * {@link https://github.com/micc83/fontIconPicker/issues/9}
       */


      this._initAutoClose(); // Window resize fix


      this._initFixOnResize();
    },

    /**
     * Set icons after the fip has been initialized
     */
    setIcons: function setIcons(newIcons, iconSearch) {
      this.settings.source = Array.isArray(newIcons) ? _toConsumableArray(newIcons) : $.extend({}, newIcons);
      this.settings.searchSource = Array.isArray(iconSearch) ? _toConsumableArray(iconSearch) : $.extend({}, iconSearch);

      this._initSourceIndex();

      this._loadCategories();

      this._resetSearch();

      this._loadIcons();
    },

    /**
     * Set currently selected icon programmatically
     *
     * @param {string} theIcon current icon value
     */
    setIcon: function setIcon() {
      var theIcon = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';

      this._setSelectedIcon(theIcon);
    },

    /**
     * Destroy picker and all events
     */
    destroy: function destroy() {
      this.iconPicker.off().remove();
      this.element.css({
        visibility: '',
        top: '',
        position: '',
        zIndex: '',
        left: '',
        display: '',
        height: '',
        width: '',
        padding: '',
        margin: '',
        border: '',
        verticalAlign: '',
        float: ''
      }); // Remove the delegated events

      $(window).off('resize' + this.eventNameSpace);
      $('html').off('click' + this.eventNameSpace);
    },

    /**
     * Manually reset position
     */
    resetPosition: function resetPosition() {
      this._fixOnResize();
    },

    /**
     * Manually set page
     * @param {int} pageNum
     */
    setPage: function setPage(pageNum) {
      if ('first' == pageNum) {
        pageNum = 1;
      }

      if ('last' == pageNum) {
        pageNum = this.totalPage;
      }

      pageNum = parseInt(pageNum, 10);

      if (isNaN(pageNum)) {
        pageNum = 1;
      }

      if (pageNum > this.totalPage) {
        pageNum = this.totalPage;
      }

      if (1 > pageNum) {
        pageNum = 1;
      }

      this.currentPage = pageNum;

      this._renderIconContainer();
    },

    /**
     * Initialize Fix on window resize with debouncing
     * This helps reduce function call unnecessary times.
     */
    _initFixOnResize: function _initFixOnResize() {
      var _this = this;

      $(window).on('resize' + this.eventNameSpace, debounce(function () {
        _this._fixOnResize();
      }, this.settings.windowDebounceDelay));
    },

    /**
     * Initiate autoClosing
     *
     * Checks for settings, and if set to yes, then autocloses the dropdown
     */
    _initAutoClose: function _initAutoClose() {
      var _this2 = this;

      if (this.settings.autoClose) {
        $('html').on('click' + this.eventNameSpace, function (event) {
          // Check if event is coming from selector popup or icon picker
          var target = event.target;

          if (_this2.selectorPopup.has(target).length || _this2.selectorPopup.is(target) || _this2.iconPicker.has(target).length || _this2.iconPicker.is(target)) {
            // Return
            return;
          } // Close it


          if (_this2.open) {
            _this2._toggleIconSelector();
          }
        });
      }
    },

    /**
     * Select Icon
     */
    _initIconSelect: function _initIconSelect() {
      var _this3 = this;

      this.selectorPopup.on('click', '.fip-box', function (e) {
        var fipBox = $(e.currentTarget);

        _this3._setSelectedIcon(fipBox.attr('data-fip-value'));

        _this3._toggleIconSelector();
      });
    },

    /**
     * Initiate realtime icon search
     */
    _initIconSearch: function _initIconSearch() {
      var _this4 = this;

      this.selectorPopup.on('input', '.icons-search-input', function (e) {
        // Get the search string
        var searchString = $(e.currentTarget).val(); // If the string is not empty

        if ('' === searchString) {
          _this4._resetSearch();

          return;
        } // Set icon search to X to reset search


        _this4.searchIcon.removeClass('fip-icon-search');

        _this4.searchIcon.addClass('fip-icon-cancel'); // Set this as a search


        _this4.isSearch = true; // Reset current page

        _this4.currentPage = 1; // Actual search
        // This has been modified to search the searchValues instead
        // Then return the value from the source if match is found

        _this4.iconsSearched = [];
        $.grep(_this4.searchValues, function (n, i) {
          if (0 <= n.toLowerCase().search(searchString.toLowerCase())) {
            _this4.iconsSearched[_this4.iconsSearched.length] = _this4.settings.source[i];
            return true;
          }
        }); // Render icon list

        _this4._renderIconContainer();
      });
      /**
      * Quit search
      */
      // Quit search happens only if clicked on the cancel button

      this.selectorPopup.on('click', '.selector-search .fip-icon-cancel', function () {
        _this4.selectorPopup.find('.icons-search-input').focus();

        _this4._resetSearch();
      });
    },

    /**
     * Initiate Pagination
     */
    _initPagination: function _initPagination() {
      var _this5 = this;

      /**
      * Next page
      */
      this.selectorPopup.on('click', '.selector-arrow-right', function (e) {
        if (_this5.currentPage < _this5.totalPage) {
          _this5.currentPage = _this5.currentPage + 1;

          _this5._renderIconContainer();
        }
      });
      /**
      * Prev page
      */

      this.selectorPopup.on('click', '.selector-arrow-left', function (e) {
        if (1 < _this5.currentPage) {
          _this5.currentPage = _this5.currentPage - 1;

          _this5._renderIconContainer();
        }
      });
    },

    /**
     * Initialize category changer dropdown
     */
    _initCategoryChanger: function _initCategoryChanger() {
      var _this6 = this;

      // Since the popup can be appended anywhere
      // We will add the event listener to the popup
      // And will stop the eventPropagation on click
      // @since v2.1.0
      this.selectorPopup.on('change keyup', '.icon-category-select', function (e) {
        // Don't do anything if not categorized
        if (false === _this6.isCategorized) {
          return false;
        }

        var targetSelect = $(e.currentTarget),
            currentCategory = targetSelect.val(); // Check if all categories are selected

        if ('all' === targetSelect.val()) {
          // Restore from the backups
          // @note These backups must be rebuild on source change, otherwise it will lead to error
          _this6.settings.source = _this6.backupSource;
          _this6.searchValues = _this6.backupSearch; // No? So there is a specified category
        } else {
          var key = parseInt(currentCategory, 10);

          if (_this6.availableCategories[key]) {
            _this6.settings.source = _this6.availableCategories[key];
            _this6.searchValues = _this6.availableCategoriesSearch[key];
          }
        }

        _this6._resetSearch();

        _this6._loadIcons();
      });
    },

    /**
     * Initialize Dropdown button
     */
    _initDropDown: function _initDropDown() {
      var _this7 = this;

      this.selectorButton.on('click', function (event) {
        // Open/Close the icon picker
        _this7._toggleIconSelector();
      });
    },

    /**
     * Get icon Picker Template String
     */
    _getPickerTemplate: function _getPickerTemplate() {
      var pickerTemplate = "\n<div class=\"selector\" data-fip-origin=\"".concat(this.element.attr('id'), "\">\n\t<span class=\"selected-icon\">\n\t\t<i class=\"fip-icon-block\"></i>\n\t</span>\n\t<span class=\"selector-button\">\n\t\t<i class=\"fip-icon-down-dir\"></i>\n\t</span>\n</div>\n<div class=\"selector-popup-wrap\" data-fip-origin=\"").concat(this.element.attr('id'), "\">\n\t<div class=\"selector-popup\" style=\"display: none;\"> ").concat(this.settings.hasSearch ? "<div class=\"selector-search\">\n\t\t\t<input type=\"text\" name=\"\" value=\"\" placeholder=\"".concat(this.settings.searchPlaceholder, "\" class=\"icons-search-input\"/>\n\t\t\t<i class=\"fip-icon-search\"></i>\n\t\t</div>") : '', "\n\t\t<div class=\"selector-category\">\n\t\t\t<select name=\"\" class=\"icon-category-select\" style=\"display: none\"></select>\n\t\t</div>\n\t\t<div class=\"fip-icons-container\"></div>\n\t\t<div class=\"selector-footer\" style=\"display:none;\">\n\t\t\t<span class=\"selector-pages\">1/2</span>\n\t\t\t<span class=\"selector-arrows\">\n\t\t\t\t<span class=\"selector-arrow-left\" style=\"display:none;\">\n\t\t\t\t\t<i class=\"fip-icon-left-dir\"></i>\n\t\t\t\t</span>\n\t\t\t\t<span class=\"selector-arrow-right\">\n\t\t\t\t\t<i class=\"fip-icon-right-dir\"></i>\n\t\t\t\t</span>\n\t\t\t</span>\n\t\t</div>\n\t</div>\n</div>");
      return pickerTemplate;
    },

    /**
     * Init the source & search index from the current settings
     * @return {void}
     */
    _initSourceIndex: function _initSourceIndex() {
      // First check for any sorts of errors
      if ('object' !== _typeof(this.settings.source)) {
        return;
      } // We are going to check if the passed source is an array or an object
      // If it is an array, then don't do anything
      // otherwise it has to be an object and therefore is it a categorized icon set


      if (Array.isArray(this.settings.source)) {
        // This is not categorized since it is 1D array
        this.isCategorized = false;
        this.selectCategory.html('').hide(); // We are going to convert the source items to string
        // This is necessary because passed source might not be "strings" for attribute related icons

        this.settings.source = $.map(this.settings.source, function (e, i) {
          if ('function' == typeof e.toString) {
            return e.toString();
          } else {
            return e;
          }
        }); // Now update the search
        // First check if the search is given by user

        if (Array.isArray(this.settings.searchSource)) {
          // Convert everything inside the searchSource to string
          this.searchValues = $.map(this.settings.searchSource, function (e, i) {
            if ('function' == typeof e.toString) {
              return e.toString();
            } else {
              return e;
            }
          }); // Clone the searchSource
          // Not given so use the source instead
        } else {
          this.searchValues = this.settings.source.slice(0); // Clone the source
        } // Categorized icon set

      } else {
        var originalSource = $.extend(true, {}, this.settings.source); // Reset the source

        this.settings.source = []; // Reset other variables

        this.searchValues = [];
        this.availableCategoriesSearch = [];
        this.selectedCategory = false;
        this.availableCategories = [];
        this.unCategorizedKey = null; // Set the categorized to true and reset the HTML

        this.isCategorized = true;
        this.selectCategory.html(''); // Now loop through the source and add to the list

        for (var categoryLabel in originalSource) {
          // Get the key of the new category array
          var thisCategoryKey = this.availableCategories.length,
              // Create the new option for the selectCategory SELECT field
          categoryOption = $('<option />'); // Set the value to this categorykey

          categoryOption.attr('value', thisCategoryKey); // Set the label

          categoryOption.html(categoryLabel); // Append to the DOM

          this.selectCategory.append(categoryOption); // Init the availableCategories array

          this.availableCategories[thisCategoryKey] = [];
          this.availableCategoriesSearch[thisCategoryKey] = []; // Now loop through it's icons and add to the list

          for (var newIconKey in originalSource[categoryLabel]) {
            // Get the new icon value
            var newIconValue = originalSource[categoryLabel][newIconKey]; // Get the label either from the searchSource if set, otherwise from the source itself

            var newIconLabel = this.settings.searchSource && this.settings.searchSource[categoryLabel] && this.settings.searchSource[categoryLabel][newIconKey] ? this.settings.searchSource[categoryLabel][newIconKey] : newIconValue; // Try to convert to the source value string
            // This is to avoid attribute related icon sets
            // Where hexadecimal or decimal numbers might be passed

            if ('function' == typeof newIconValue.toString) {
              newIconValue = newIconValue.toString();
            } // Check if the option element has value and this value does not equal to the empty value


            if (newIconValue && newIconValue !== this.settings.emptyIconValue) {
              // Push to the source, because at first all icons are selected
              this.settings.source.push(newIconValue); // Push to the availableCategories child array

              this.availableCategories[thisCategoryKey].push(newIconValue); // Push to the search values

              this.searchValues.push(newIconLabel);
              this.availableCategoriesSearch[thisCategoryKey].push(newIconLabel);
            }
          }
        }
      } // Clone and backup the original source and search


      this.backupSource = this.settings.source.slice(0);
      this.backupSearch = this.searchValues.slice(0);
    },

    /**
     * Populate source from select element
     * Check if select has optgroup, if so, then we are dealing with categorized
     * data. Otherwise, plain data.
     */
    _populateSourceFromSelect: function _populateSourceFromSelect() {
      var _this8 = this;

      // Reset the source and searchSource
      // These will be populated according to the available options
      this.settings.source = [];
      this.settings.searchSource = []; // Check if optgroup is present within the select
      // If it is present then the source has to be grouped

      if (this.element.find('optgroup').length) {
        // Set the categorized to true
        this.isCategorized = true;
        this.element.find('optgroup').each(function (i, el) {
          // Get the key of the new category array
          var thisCategoryKey = _this8.availableCategories.length,
              // Create the new option for the selectCategory SELECT field
          categoryOption = $('<option />'); // Set the value to this categorykey

          categoryOption.attr('value', thisCategoryKey); // Set the label

          categoryOption.html($(el).attr('label')); // Append to the DOM

          _this8.selectCategory.append(categoryOption); // Init the availableCategories array


          _this8.availableCategories[thisCategoryKey] = [];
          _this8.availableCategoriesSearch[thisCategoryKey] = []; // Now loop through it's option elements and add the icons

          $(el).find('option').each(function (i, cel) {
            var newIconValue = $(cel).val(),
                newIconLabel = $(cel).html(); // Check if the option element has value and this value does not equal to the empty value

            if (newIconValue && newIconValue !== _this8.settings.emptyIconValue) {
              // Push to the source, because at first all icons are selected
              _this8.settings.source.push(newIconValue); // Push to the availableCategories child array


              _this8.availableCategories[thisCategoryKey].push(newIconValue); // Push to the search values


              _this8.searchValues.push(newIconLabel);

              _this8.availableCategoriesSearch[thisCategoryKey].push(newIconLabel);
            }
          });
        }); // Additionally check for any first label option child

        if (this.element.find('> option').length) {
          this.element.find('> option').each(function (i, el) {
            var newIconValue = $(el).val(),
                newIconLabel = $(el).html(); // Don't do anything if the new icon value is empty

            if (!newIconValue || '' === newIconValue || newIconValue == _this8.settings.emptyIconValue) {
              return true;
            } // Set the uncategorized key if not set already


            if (null === _this8.unCategorizedKey) {
              _this8.unCategorizedKey = _this8.availableCategories.length;
              _this8.availableCategories[_this8.unCategorizedKey] = [];
              _this8.availableCategoriesSearch[_this8.unCategorizedKey] = []; // Create an option and append to the category selector

              $('<option />').attr('value', _this8.unCategorizedKey).html(_this8.settings.unCategorizedText).appendTo(_this8.selectCategory);
            } // Push the icon to the category


            _this8.settings.source.push(newIconValue);

            _this8.availableCategories[_this8.unCategorizedKey].push(newIconValue); // Push the icon to the search


            _this8.searchValues.push(newIconLabel);

            _this8.availableCategoriesSearch[_this8.unCategorizedKey].push(newIconLabel);
          });
        } // Not categorized

      } else {
        this.element.find('option').each(function (i, el) {
          var newIconValue = $(el).val(),
              newIconLabel = $(el).html();

          if (newIconValue) {
            _this8.settings.source.push(newIconValue);

            _this8.searchValues.push(newIconLabel);
          }
        });
      } // Clone and backup the original source and search


      this.backupSource = this.settings.source.slice(0);
      this.backupSearch = this.searchValues.slice(0);
    },

    /**
     * Load Categories
     * @return {void}
     */
    _loadCategories: function _loadCategories() {
      // Dont do anything if it is not categorized
      if (false === this.isCategorized) {
        return;
      } // Now append all to the category selector


      $('<option value="all">' + this.settings.allCategoryText + '</option>').prependTo(this.selectCategory); // Show it and set default value to all categories

      this.selectCategory.show().val('all').trigger('change');
    },

    /**
     * Load icons
     */
    _loadIcons: function _loadIcons() {
      // Set the content of the popup as loading
      this.iconContainer.html('<i class="fip-icon-spin3 animate-spin loading"></i>'); // If source is set

      if (Array.isArray(this.settings.source)) {
        // Render icons
        this._renderIconContainer();
      }
    },

    /**
     * Generate icons
     *
     * Supports hookable third-party renderer function.
     */
    _iconGenerator: function _iconGenerator(icon) {
      if ('function' === typeof this.settings.iconGenerator) {
        return this.settings.iconGenerator(icon);
      }

      return '<i ' + (this.settings.useAttribute ? this.settings.attributeName + '="' + (this.settings.convertToHex ? '&#x' + parseInt(icon, 10).toString(16) + ';' : icon) + '"' : 'class="' + icon + '"') + '></i>';
    },

    /**
     * Render icons inside the popup
     */
    _renderIconContainer: function _renderIconContainer() {
      var _this9 = this;

      var offset,
          iconsPaged = [];
   // Set a temporary array for icons

      if (this.isSearch) {
        iconsPaged = [...new Set(this.iconsSearched)]
      } else {
        iconsPaged =  [...new Set(this.settings.source)];
      } // Count elements


      this.iconsCount = iconsPaged.length; // Calculate total page number

      this.totalPage = Math.ceil(this.iconsCount / this.settings.iconsPerPage); // Hide footer if no pagination is needed

      if (1 < this.totalPage) {
        this.selectorPopup.find('.selector-footer').show(); // Reset the pager buttons
        // Fix #8 {@link https://github.com/micc83/fontIconPicker/issues/8}
        // It is better to set/hide the pager button here
        // instead of all other functions that calls back _renderIconContainer

        if (this.currentPage < this.totalPage) {
          // current page is less than total, so show the arrow right
          this.selectorPopup.find('.selector-arrow-right').show();
        } else {
          // else hide it
          this.selectorPopup.find('.selector-arrow-right').hide();
        }

        if (1 < this.currentPage) {
          // current page is greater than one, so show the arrow left
          this.selectorPopup.find('.selector-arrow-left').show();
        } else {
          // else hide it
          this.selectorPopup.find('.selector-arrow-left').hide();
        }
      } else {
        this.selectorPopup.find('.selector-footer').hide();
      } // Set the text for page number index and total icons


      this.selectorPopup.find('.selector-pages').html(this.currentPage + '/' + this.totalPage + ' <em>(' + this.iconsCount + ')</em>'); // Set the offset for slice

      offset = (this.currentPage - 1) * this.settings.iconsPerPage; // Should empty icon be shown?

      if (this.settings.emptyIcon) {
        // Reset icon container HTML and prepend empty icon
        this.iconContainer.html('<span class="fip-box" data-fip-value="fip-icon-block"><i class="fip-icon-block"></i></span>'); // If not show an error when no icons are found
      } else if (1 > iconsPaged.length) {
        this.iconContainer.html('<span class="icons-picker-error" data-fip-value="fip-icon-block"><i class="fip-icon-block"></i></span>');
        return; // else empty the container
      } else {
        this.iconContainer.html('');
      } // Set an array of current page icons


      iconsPaged = iconsPaged.slice(offset, offset + this.settings.iconsPerPage); // List icons

      var _loop = function _loop(i, icon) {
        // eslint-disable-line
        // Set the icon title
        var fipBoxTitle = icon;
        $.grep(_this9.settings.source, $.proxy(function (e, i) {
          if (e === icon) {
            fipBoxTitle = this.searchValues[i];
            return true;
          }

          return false;
        }, _this9)); // Set the icon box

        $('<span/>', {
          html: _this9._iconGenerator(icon),
          attr: {
            'data-fip-value': icon
          },
          class: 'fip-box',
          title: fipBoxTitle
        }).appendTo(_this9.iconContainer);
      };

      for (var i = 0, icon; icon = iconsPaged[i++];) {
        _loop(i, icon);
      } // If no empty icon is allowed and no current value is set or current value is not inside the icon set


      if (!this.settings.emptyIcon && (!this.element.val() || -1 === $.inArray(this.element.val(), this.settings.source))) {
        // Get the first icon
        this._setSelectedIcon(iconsPaged[0]);
      } else if (-1 === $.inArray(this.element.val(), this.settings.source)) {
        // Issue #7
        // Need to pass empty string
        // Set empty
        // Otherwise DOM will be set to null value
        // which would break the initial select value
        this._setSelectedIcon('');
      } else {
        // Fix issue #7
        // The trick is to check the element value
        // Internally fip-icon-block must be used for empty values
        // So if element.val == emptyIconValue then pass fip-icon-block
        var passDefaultIcon = this.element.val();

        if (passDefaultIcon === this.settings.emptyIconValue) {
          passDefaultIcon = 'fip-icon-block';
        } // Set the default selected icon even if not set


        this._setSelectedIcon(passDefaultIcon);
      }
    },

    /**
     * Set Highlighted icon
     */
    _setHighlightedIcon: function _setHighlightedIcon() {
      this.iconContainer.find('.current-icon').removeClass('current-icon');

      if (this.currentIcon) {
        this.iconContainer.find('[data-fip-value="' + this.currentIcon + '"]').addClass('current-icon');
      }
    },

    /**
     * Set selected icon
     *
     * @param {string} theIcon
     */
    _setSelectedIcon: function _setSelectedIcon(theIcon) {
      if ('fip-icon-block' === theIcon) {
        theIcon = '';
      }

      var selectedIcon = this.iconPicker.find('.selected-icon'); // if the icon is empty, then reset to empty

      if ('' === theIcon) {
        selectedIcon.html('<i class="fip-icon-block"></i>');
      } else {
        // Pass it to the render function
        selectedIcon.html(this._iconGenerator(theIcon));
      } // Check if actually changing the DOM element


      var currentValue = this.element.val(); // Set the value of the element

      this.element.val('' === theIcon ? this.settings.emptyIconValue : theIcon); // trigger event if change has actually occured

      if (currentValue !== theIcon) {
        this.element.trigger('change');

        if (null !== this.triggerEvent) {
          this.element.trigger(this.triggerEvent);
        }
      }

      this.currentIcon = theIcon;

      this._setHighlightedIcon();
    },

    /**
     * Recalculate the position of the Popup
     */
    _repositionIconSelector: function _repositionIconSelector() {
      // Calculate the position + width
      var offset = this.iconPicker.offset(),
          offsetTop = offset.top + this.iconPicker.outerHeight(true),
          offsetLeft = offset.left;
      this.selectorPopup.css({
        left: offsetLeft,
        top: offsetTop
      });
    },

    /**
     * Fix window overflow of popup dropdown if needed
     *
     * This can happen if appending to self or someplace else
     */
    _fixWindowOverflow: function _fixWindowOverflow() {
      // Adjust the offsetLeft
      // Resolves issue #10
      // @link https://github.com/micc83/fontIconPicker/issues/10
      var visibilityStatus = this.selectorPopup.find('.selector-popup').is(':visible');

      if (!visibilityStatus) {
        this.selectorPopup.find('.selector-popup').show();
      }

      var popupWidth = this.selectorPopup.outerWidth(),
          windowWidth = $(window).width(),
          popupOffsetLeft = this.selectorPopup.offset().left,
          containerOffset = 'self' == this.settings.appendTo ? this.selectorPopup.parent().offset() : $(this.settings.appendTo).offset();

      if (!visibilityStatus) {
        this.selectorPopup.find('.selector-popup').hide();
      }

      if (popupOffsetLeft + popupWidth > windowWidth - 20
      /* 20px adjustment for better appearance */
      ) {
          // First we try to position with right aligned
          var pickerOffsetRight = this.selectorButton.offset().left + this.selectorButton.outerWidth();
          var preferredLeft = Math.floor(pickerOffsetRight - popupWidth - 1);
          /** 1px adjustment for sub-pixels */
          // If preferredLeft would put the popup out of window from left
          // then don't do it

          if (0 > preferredLeft) {
            this.selectorPopup.css({
              left: windowWidth - 20 - popupWidth - containerOffset.left
            });
          } else {
            // Put it in the preferred position
            this.selectorPopup.css({
              left: preferredLeft
            });
          }
        }
    },

    /**
     * Fix on Window Resize
     */
    _fixOnResize: function _fixOnResize() {
      // If the appendTo is not self, then we need to reposition the dropdown
      if ('self' !== this.settings.appendTo) {
        this._repositionIconSelector();
      } // In any-case, we need to fix for window overflow


      this._fixWindowOverflow();
    },

    /**
     * Open/close popup (toggle)
     */
    _toggleIconSelector: function _toggleIconSelector() {
      this.open = !this.open ? 1 : 0; // Append the popup if needed

      if (this.open) {
        // Check the origin
        if ('self' !== this.settings.appendTo) {
          // Append to the selector and set the CSS + theme
          this.selectorPopup.appendTo(this.settings.appendTo).css({
            zIndex: 1000 // Let's decrease the zIndex to something reasonable

          }).addClass('icons-selector ' + this.settings.theme); // call resize()

          this._repositionIconSelector();
        } // Fix positioning if needed


        this._fixWindowOverflow();
      }

      this.selectorPopup.find('.selector-popup').slideToggle(300, $.proxy(function () {
        this.iconPicker.find('.selector-button i').toggleClass('fip-icon-down-dir');
        this.iconPicker.find('.selector-button i').toggleClass('fip-icon-up-dir');

        if (this.open) {
          this.selectorPopup.find('.icons-search-input').trigger('focus').trigger('select');
        } else {
          // append and revert to the original position and reset theme
          this.selectorPopup.appendTo(this.iconPicker).css({
            left: '',
            top: '',
            zIndex: ''
          }).removeClass('icons-selector ' + this.settings.theme);
        }
      }, this));
    },

    /**
     * Reset search
     */
    _resetSearch: function _resetSearch() {
      // Empty input
      this.selectorPopup.find('.icons-search-input').val(''); // Reset search icon class

      this.searchIcon.removeClass('fip-icon-cancel');
      this.searchIcon.addClass('fip-icon-search'); // Go back to page 1

      this.currentPage = 1;
      this.isSearch = false; // Rerender icons

      this._renderIconContainer();
    }
  }; // ES6 Export it as module

  /**
   * Light weight wrapper to inject fontIconPicker
   * into jQuery.fn
   */

  function fontIconPickerShim($) {
    // Do not init if jQuery doesn't have needed stuff
    if (!$.fn) {
      return false;
    } // save from double init


    if ($.fn && $.fn.fontIconPicker) {
      return true;
    }

    $.fn.fontIconPicker = function (options) {
      var _this = this;

      // Instantiate the plugin
      this.each(function () {
        if (!$.data(this, 'fontIconPicker')) {
          $.data(this, 'fontIconPicker', new FontIconPicker(this, options));
        }
      }); // setIcons method

      this.setIcons = function () {
        var newIcons = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
        var iconSearch = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

        _this.each(function () {
          $.data(this, 'fontIconPicker').setIcons(newIcons, iconSearch);
        });
      }; // setIcon method


      this.setIcon = function () {
        var newIcon = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';

        _this.each(function () {
          $.data(this, 'fontIconPicker').setIcon(newIcon);
        });
      }; // destroy method


      this.destroyPicker = function () {
        _this.each(function () {
          if (!$.data(this, 'fontIconPicker')) {
            return;
          } // Remove the iconPicker


          $.data(this, 'fontIconPicker').destroy(); // destroy data

          $.removeData(this, 'fontIconPicker');
        });
      }; // reInit method


      this.refreshPicker = function (newOptions) {
        if (!newOptions) {
          newOptions = options;
        } // First destroy


        _this.destroyPicker(); // Now reset


        _this.each(function () {
          if (!$.data(this, 'fontIconPicker')) {
            $.data(this, 'fontIconPicker', new FontIconPicker(this, newOptions));
          }
        });
      }; // reposition method


      this.repositionPicker = function () {
        _this.each(function () {
          $.data(this, 'fontIconPicker').resetPosition();
        });
      }; // set page


      this.setPage = function (pageNum) {
        _this.each(function () {
          $.data(this, 'fontIconPicker').setPage(pageNum);
        });
      };

      return this;
    };

    return true;
  }

  function initFontIconPicker(jQuery$$1) {
    return fontIconPickerShim(jQuery$$1);
  }

  /**
   *  jQuery fontIconPicker
   *
   *  An icon picker built on top of font icons and jQuery
   *
   *  http://codeb.it/fontIconPicker
   *
   *  Made by Alessandro Benoit & Swashata
   *  Licensed under MIT License
   *
   * {@link https://github.com/micc83/fontIconPicker}
   */
  // In browser this will work
  // But in node environment it might not.
  // because if jQu

  if (jQuery && jQuery.fn) {
    initFontIconPicker(jQuery);
  } // Export the function anyway, so that it can be initiated
  // from node environment


  var jquery_fonticonpicker = (function (jQuery$$1) {
    return initFontIconPicker(jQuery$$1);
  });

  return jquery_fonticonpicker;

})));
