@fonticonpicker/fonticonpicker
Version:
jQuery Plugin which allows you to include a simple icon picker with search and pagination inside your administration forms.
1,214 lines (944 loc) • 40.7 kB
JavaScript
/**
* 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.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 = this.iconsSearched;
} else {
iconsPaged = 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;
})));
//# sourceMappingURL=jquery.fonticonpicker.js.map