/** * jQuery fontIconPicker - v2.0.0 * * An icon picker built on top of font icons and jQuery * * http://micc83.github.io/fontIconPicker/ * * Made by Alessandro Benoit & Swashata * Under MIT License * * {@link https://github.com/micc83/fontIconPicker} */ ;(function ($) { 'use strict'; // Create the defaults once var defaults = { 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" 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 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 }; // The actual plugin constructor function Plugin(element, options) { this.element = $(element); this.settings = $.extend({}, defaults, options); if (this.settings.emptyIcon) { this.settings.iconsPerPage--; } this.iconPicker = $('
', { 'class': 'icons-selector', style: 'position: relative', html: '
' + '' + '' + '' + '' + '' + '' + '
' + '' }); this.iconContainer = this.iconPicker.find('.fip-icons-container'); this.searchIcon = this.iconPicker.find('.selector-search i'); this.iconsSearched = []; this.isSearch = false; this.totalPage = 1; this.currentPage = 1; this.currentIcon = false; this.iconsCount = 0; this.open = false; // 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(); } Plugin.prototype = { /** * Init */ init: function () { // 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' }); // Set the trigger event if ( ! this.element.is('select') ) { // Determine the event that is fired when user change the field value // Most modern browsers supports input event except IE 7, 8. // IE 9 supports input event but the event is still not fired if I press the backspace key. // Get IE version // https://gist.github.com/padolsey/527683/#comment-7595 var ieVersion = (function() { var v = 3, div = document.createElement('div'), a = div.all || []; while (div.innerHTML = '', a[0]); return v > 4 ? v : !v; }()); var el = document.createElement('div'); this.triggerEvent = (ieVersion === 9 || !('oninput' in el)) ? ['keyup'] : ['input', 'keyup']; // Let's keep the keyup event for scripts that listens to it } // If current element is SELECT populate settings.source if (!this.settings.source && this.element.is('select')) { // 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($.proxy(function(i, el) { // Get the key of the new category array var thisCategoryKey = this.availableCategories.length, // Create the new option for the selectCategory SELECT field categoryOption = $('').prependTo(this.selectCategory); // Show it and set default value to all categories this.selectCategory.show().val('all').trigger('change'); }, /** * Load icons */ loadIcons: function () { // Set the content of the popup as loading this.iconContainer.html(''); // If source is set if (this.settings.source instanceof Array) { // Render icons this.renderIconContainer(); } }, /** * Render icons inside the popup */ renderIconContainer: function () { 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 (this.totalPage > 1) { this.iconPicker.find('.selector-footer').show(); } else { this.iconPicker.find('.selector-footer').hide(); } // Set the text for page number index and total icons this.iconPicker.find('.selector-pages').html(this.currentPage + '/' + this.totalPage + ' (' + this.iconsCount + ')'); // 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(''); // If not show an error when no icons are found } else if (iconsPaged.length < 1) { this.iconContainer.html(''); 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 for (var i = 0, item; item = iconsPaged[i++];) { // Set the icon title var flipBoxTitle = item; $.grep(this.settings.source, $.proxy(function(e, i) { if ( e === item ) { flipBoxTitle = this.searchValues[i]; return true; } return false; }, this)); // Set the icon box $('', { html: '', 'class': 'fip-box', title: flipBoxTitle }).appendTo(this.iconContainer); } // 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() || $.inArray(this.element.val(), this.settings.source) === -1)) { // Get the first icon this.setSelectedIcon(iconsPaged[0]); } else if ($.inArray(this.element.val(), this.settings.source) === -1) { // Set empty this.setSelectedIcon(); } else { // Set the default selected icon even if not set this.setSelectedIcon(this.element.val()); } }, /** * Set Highlighted icon */ setHighlightedIcon: function () { this.iconContainer.find('.current-icon').removeClass('current-icon'); if (this.currentIcon) { this.iconContainer.find('[data-fip-value="' + this.currentIcon + '"]').parent('span').addClass('current-icon'); } }, /** * Set selected icon * * @param {string} theIcon */ setSelectedIcon: function (theIcon) { if (theIcon === 'fip-icon-block') { theIcon = ''; } // Check if attribute is to be used if ( this.settings.useAttribute ) { if ( theIcon ) { this.iconPicker.find('.selected-icon').html('' ); } else { this.iconPicker.find('.selected-icon').html(''); } // Use class } else { this.iconPicker.find('.selected-icon').html(''); } // Set the value of the element and trigger change event this.element.val((theIcon === '' ? this.settings.emptyIconValue : theIcon )).trigger('change'); if ( this.triggerEvent !== null ) { // Trigger other events for ( var eventKey in this.triggerEvent ) { this.element.trigger(this.triggerEvent[eventKey]); } } this.currentIcon = theIcon; this.setHighlightedIcon(); }, /** * Open/close popup (toggle) */ toggleIconSelector: function () { this.open = (!this.open) ? 1 : 0; this.iconPicker.find('.selector-popup').slideToggle(300); 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.iconPicker.find('.icons-search-input').focus().select(); } }, /** * Reset search */ resetSearch: function () { // Empty input this.iconPicker.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 and remove back arrow this.iconPicker.find('.selector-arrow-left').hide(); this.currentPage = 1; this.isSearch = false; // Rerender icons this.renderIconContainer(); // Restore pagination if needed if (this.totalPage > 1) { this.iconPicker.find('.selector-arrow-right').show(); } } }; // Lightweight plugin wrapper $.fn.fontIconPicker = function (options) { // Instantiate the plugin this.each(function () { if (!$.data(this, "fontIconPicker")) { $.data(this, "fontIconPicker", new Plugin(this, options)); } }); // setIcons method this.setIcons = $.proxy(function (newIcons, iconSearch) { if ( undefined === newIcons ) { newIcons = false; } if ( undefined === iconSearch ) { iconSearch = false; } this.each(function () { $.data(this, "fontIconPicker").settings.source = newIcons; $.data(this, "fontIconPicker").settings.searchSource = iconSearch; $.data(this, "fontIconPicker").initSourceIndex(); $.data(this, "fontIconPicker").resetSearch(); $.data(this, "fontIconPicker").loadIcons(); }); }, this); // destroy method this.destroyPicker = $.proxy(function() { this.each(function() { if (!$.data(this, "fontIconPicker")) { return; } // Remove the iconPicker $.data(this, "fontIconPicker").iconPicker.remove(); // Reset the CSS $.data(this, "fontIconPicker").element.css({ visibility: '', top: '', position: '', zIndex: '', left: '', display: '', height: '', width: '', padding: '', margin: '', border: '', verticalAlign: '' }); // destroy data $.removeData(this, "fontIconPicker"); }); }, this); // reInit method this.refreshPicker = $.proxy(function(newOptions) { if ( ! newOptions ) { newOptions = options; } // First destroy this.destroyPicker(); // Now reset this.each(function() { if (!$.data(this, "fontIconPicker")) { $.data(this, "fontIconPicker", new Plugin(this, newOptions)); } }); }, this); return this; }; })(jQuery);