bootstrap-iconpicker.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. /*!========================================================================
  2. * File: bootstrap-iconpicker.js v1.10.0 by @victor-valencia
  3. * https://victor-valencia.github.com/bootstrap-iconpicker
  4. * ========================================================================
  5. * Copyright 2013-2018 Victor Valencia Rico.
  6. * Licensed under MIT license.
  7. * https://github.com/victor-valencia/bootstrap-iconpicker/blob/master/LICENSE
  8. * ========================================================================
  9. */
  10. ;(function($){ "use strict";
  11. // ICONPICKER PUBLIC CLASS DEFINITION
  12. // ==============================
  13. var Iconpicker = function (element, options) {
  14. if (typeof $.fn.popover === 'undefined' || typeof $.fn.popover.Constructor.VERSION === 'undefined') {
  15. throw new TypeError('Bootstrap iconpicker require Bootstrap popover');
  16. }
  17. this.$element = $(element);
  18. this.options = $.extend({}, Iconpicker.DEFAULTS, this.$element.data());
  19. this.options = $.extend({}, this.options, options);
  20. };
  21. // ICONPICKER VERSION
  22. // ==============================
  23. Iconpicker.VERSION = '1.10.0';
  24. // ICONPICKER ICONSET_EMPTY
  25. // ==============================
  26. Iconpicker.ICONSET_EMPTY = {
  27. iconClass: '',
  28. iconClassFix: '',
  29. icons: []
  30. };
  31. // ICONPICKER ICONSET
  32. // ==============================
  33. Iconpicker.ICONSET = {
  34. _custom: null,
  35. elusiveicon: $.iconset_elusiveicon || Iconpicker.ICONSET_EMPTY,
  36. flagicon: $.iconset_flagicon || Iconpicker.ICONSET_EMPTY,
  37. fontawesome4: $.iconset_fontawesome_4 || Iconpicker.ICONSET_EMPTY,
  38. fontawesome5: $.iconset_fontawesome_5 || Iconpicker.ICONSET_EMPTY,
  39. glyphicon: $.iconset_glyphicon || Iconpicker.ICONSET_EMPTY,
  40. ionicon: $.iconset_ionicon || Iconpicker.ICONSET_EMPTY,
  41. mapicon: $.iconset_mapicon || Iconpicker.ICONSET_EMPTY,
  42. materialdesign: $.iconset_materialdesign || Iconpicker.ICONSET_EMPTY,
  43. octicon: $.iconset_octicon || Iconpicker.ICONSET_EMPTY,
  44. typicon: $.iconset_typicon || Iconpicker.ICONSET_EMPTY,
  45. weathericon: $.iconset_weathericon || Iconpicker.ICONSET_EMPTY
  46. };
  47. // ICONPICKER DEFAULTS
  48. // ==============================
  49. Iconpicker.DEFAULTS = {
  50. align: 'center',
  51. arrowClass: 'btn-primary',
  52. arrowNextIconClass: 'fas fa-arrow-right',
  53. arrowPrevIconClass: 'fas fa-arrow-left',
  54. cols: 4,
  55. icon: '',
  56. iconset: 'fontawesome5',
  57. iconsetVersion: 'lastest',
  58. header: true,
  59. labelHeader: '{0} / {1}',
  60. footer: true,
  61. labelFooter: '{0} - {1} of {2}',
  62. placement: 'bottom',
  63. rows: 4,
  64. search: true,
  65. searchText: 'Search icon',
  66. selectedClass: 'btn-warning',
  67. unselectedClass: 'btn-secondary'
  68. };
  69. // ICONPICKER PRIVATE METHODS
  70. // ==============================
  71. Iconpicker.prototype.bindEvents = function () {
  72. var op = this.options;
  73. var el = this;
  74. op.table.find('.btn-previous, .btn-next').off('click').on('click', function(e) {
  75. e.preventDefault();
  76. if(!$(this).hasClass('disabled')){
  77. var inc = parseInt($(this).val(), 10);
  78. el.changeList(op.page + inc);
  79. }
  80. });
  81. op.table.find('.btn-icon').off('click').on('click', function(e) {
  82. e.preventDefault();
  83. el.select($(this).val());
  84. if(op.inline === false){
  85. el.$element.popover(($.fn.bsVersion() === '3.x') ? 'destroy' : 'dispose');
  86. }
  87. else{
  88. op.table.find("i[class$='" + $(this).val() + "']").parent().addClass(op.selectedClass);
  89. }
  90. });
  91. op.table.find('.search-control').off('keyup').on('keyup', function() {
  92. el.changeList(1);
  93. });
  94. };
  95. Iconpicker.prototype.changeList = function (page) {
  96. this.filterIcons();
  97. this.updateLabels(page);
  98. this.updateIcons(page);
  99. this.options.page = page;
  100. this.bindEvents();
  101. };
  102. Iconpicker.prototype.filterIcons = function () {
  103. var op = this.options;
  104. var search = op.table.find('.search-control').val();
  105. var icons = [];
  106. if(op.iconsetVersion != 'lastest' && typeof Iconpicker.ICONSET[op.iconset].allVersions != 'undefined'){
  107. $.each(Iconpicker.ICONSET[op.iconset].allVersions, function(i, v){
  108. if(op.iconsetVersion == v.version){
  109. icons = v.icons;
  110. }
  111. });
  112. }
  113. else
  114. icons = Iconpicker.ICONSET[op.iconset].icons;
  115. if (search === "") {
  116. op.icons = icons;
  117. }
  118. else {
  119. var result = [];
  120. $.each(icons, function(i, v) {
  121. if (v.toLowerCase().indexOf(search) > -1) {
  122. result.push(v);
  123. }
  124. });
  125. op.icons = result;
  126. }
  127. };
  128. Iconpicker.prototype.removeAddClass = function (target, remove, add) {
  129. this.options.table.find(target).removeClass(remove).addClass(add);
  130. return add;
  131. };
  132. Iconpicker.prototype.reset = function () {
  133. this.updatePicker();
  134. this.changeList(1);
  135. };
  136. Iconpicker.prototype.select = function (icon) {
  137. var op = this.options;
  138. var el = this.$element;
  139. op.selected = $.inArray(icon.replace(op.iconClassFix, ''), op.icons);
  140. if (op.selected === -1) {
  141. op.selected = 0;
  142. icon = op.iconClassFix + op.icons[op.selected];
  143. }
  144. if (icon !== '' && op.selected >= 0) {
  145. op.icon = icon;
  146. if(op.inline === false){
  147. el.find('input').val(icon);
  148. el.find('i').attr('class', '').addClass(op.iconClass).addClass(icon);
  149. }
  150. if(icon === op.iconClassFix){
  151. el.trigger({ type: "change", icon: 'empty' });
  152. }
  153. else {
  154. el.trigger({ type: "change", icon: icon });
  155. el.find('input').val(icon);
  156. }
  157. op.table.find('button.' + op.selectedClass).removeClass(op.selectedClass);
  158. }
  159. };
  160. Iconpicker.prototype.switchPage = function (icon) {
  161. var op = this.options;
  162. op.selected = $.inArray(icon.replace(op.iconClassFix, ''), op.icons);
  163. if(op.selected >= 0) {
  164. var page = Math.ceil((op.selected + 1) / this.totalIconsPerPage());
  165. this.changeList(page);
  166. }
  167. if(icon === ''){
  168. //if(op.iconClassFix !== '')
  169. op.table.find('i.' + op.iconClassFix).parent().addClass(op.selectedClass);
  170. //else
  171. }
  172. else{
  173. op.table.find('i.' + icon).parent().addClass(op.selectedClass);
  174. }
  175. };
  176. Iconpicker.prototype.totalPages = function () {
  177. return Math.ceil(this.totalIcons() / this.totalIconsPerPage());
  178. };
  179. Iconpicker.prototype.totalIcons = function () {
  180. return this.options.icons.length;
  181. };
  182. Iconpicker.prototype.totalIconsPerPage = function () {
  183. if(this.options.rows === 0){
  184. return this.options.icons.length;
  185. }
  186. else{
  187. return this.options.cols * this.options.rows;
  188. }
  189. };
  190. Iconpicker.prototype.updateArrows = function (page) {
  191. var op = this.options;
  192. var total_pages = this.totalPages();
  193. if (page === 1) {
  194. op.table.find('.btn-previous').addClass('disabled');
  195. }
  196. else {
  197. op.table.find('.btn-previous').removeClass('disabled');
  198. }
  199. if (page === total_pages || total_pages === 0) {
  200. op.table.find('.btn-next').addClass('disabled');
  201. }
  202. else {
  203. op.table.find('.btn-next').removeClass('disabled');
  204. }
  205. };
  206. Iconpicker.prototype.updateIcons = function (page) {
  207. var op = this.options;
  208. var tbody = op.table.find('tbody').empty();
  209. var offset = (page - 1) * this.totalIconsPerPage();
  210. var length = op.rows;
  211. if(op.rows === 0){
  212. length = op.icons.length;
  213. }
  214. for (var i = 0; i < length; i++) {
  215. var tr = $('<tr></tr>');
  216. for (var j = 0; j < op.cols; j++) {
  217. var pos = offset + (i * op.cols) + j;
  218. var btn = $('<button class="btn ' + op.unselectedClass + ' btn-icon"></button>').hide();
  219. if (pos < op.icons.length) {
  220. var v = op.iconClassFix + op.icons[pos];
  221. btn.val(v).attr('title', v).append('<i class="' + op.iconClass + ' ' + v + '"></i>').show();
  222. if (op.icon === v) {
  223. btn.addClass(op.selectedClass).addClass('btn-icon-selected');
  224. }
  225. }
  226. tr.append($('<td></td>').append(btn));
  227. }
  228. tbody.append(tr);
  229. }
  230. };
  231. Iconpicker.prototype.updateIconsCount = function () {
  232. var op = this.options;
  233. if(op.footer === true){
  234. var icons_count = [
  235. '<tr>',
  236. ' <td colspan="' + op.cols + '" class="text-center">',
  237. ' <span class="icons-count"></span>',
  238. ' </td>',
  239. '</tr>'
  240. ];
  241. op.table.find('tfoot').empty().append(icons_count.join(''));
  242. }
  243. };
  244. Iconpicker.prototype.updateLabels = function (page) {
  245. var op = this.options;
  246. var total_icons = this.totalIcons();
  247. var total_pages = this.totalPages();
  248. op.table.find('.page-count').html(op.labelHeader.replace('{0}', (total_pages === 0 ) ? 0 : page).replace('{1}', total_pages));
  249. var offset = (page - 1) * this.totalIconsPerPage();
  250. var total = page * this.totalIconsPerPage();
  251. op.table.find('.icons-count').html(op.labelFooter.replace('{0}', total_icons ? offset + 1 : 0).replace('{1}', (total < total_icons) ? total: total_icons).replace('{2}', total_icons));
  252. this.updateArrows(page);
  253. };
  254. Iconpicker.prototype.updatePagesCount = function () {
  255. var op = this.options;
  256. if(op.header === true){
  257. var tr = $('<tr></tr>');
  258. for (var i = 0; i < op.cols; i++) {
  259. var td = $('<td class="text-center"></td>');
  260. if (i === 0 || i === op.cols - 1) {
  261. var arrow = [
  262. '<button class="btn btn-arrow ' + ((i === 0) ? 'btn-previous' : 'btn-next') + ' ' + op.arrowClass + '" value="' + ((i === 0) ? -1 : 1) + '">',
  263. '<span class="' + ((i === 0) ? op.arrowPrevIconClass : op.arrowNextIconClass) + '"></span>',
  264. '</button>'
  265. ];
  266. td.append(arrow.join(''));
  267. tr.append(td);
  268. }
  269. else if (tr.find('.page-count').length === 0) {
  270. td.attr('colspan', op.cols - 2).append('<span class="page-count"></span>');
  271. tr.append(td);
  272. }
  273. }
  274. op.table.find('thead').empty().append(tr);
  275. }
  276. };
  277. Iconpicker.prototype.updatePicker = function () {
  278. var op = this.options;
  279. if (op.cols < 4) {
  280. throw 'Iconpicker => The number of columns must be greater than or equal to 4. [option.cols = ' + op.cols + ']';
  281. }
  282. else if (op.rows < 0) {
  283. throw 'Iconpicker => The number of rows must be greater than or equal to 0. [option.rows = ' + op.rows + ']';
  284. }
  285. else {
  286. this.updatePagesCount();
  287. this.updateSearch();
  288. this.updateIconsCount();
  289. }
  290. };
  291. Iconpicker.prototype.updateSearch = function () {
  292. var op = this.options;
  293. var search = [
  294. '<tr>',
  295. ' <td colspan="' + op.cols + '">',
  296. ' <input type="text" class="form-control search-control" style="width: ' + op.cols * (($.fn.bsVersion() === '3.x') ? 39 : 41) + 'px;" placeholder="' + op.searchText + '">',
  297. ' </td>',
  298. '</tr>'
  299. ];
  300. search = $(search.join(''));
  301. if (op.search === true) {
  302. search.show();
  303. }
  304. else {
  305. search.hide();
  306. }
  307. op.table.find('thead').append(search);
  308. };
  309. // ICONPICKER PUBLIC METHODS
  310. // ==============================
  311. Iconpicker.prototype.setAlign = function (value) {
  312. this.$element.removeClass(this.options.align).addClass(value);
  313. this.options.align = value;
  314. };
  315. Iconpicker.prototype.setArrowClass = function (value) {
  316. this.options.arrowClass = this.removeAddClass('.btn-arrow', this.options.arrowClass, value);
  317. };
  318. Iconpicker.prototype.setArrowNextIconClass = function (value) {
  319. this.options.arrowNextIconClass = this.removeAddClass('.btn-next > span', this.options.arrowNextIconClass, value);
  320. };
  321. Iconpicker.prototype.setArrowPrevIconClass = function (value) {
  322. this.options.arrowPrevIconClass = this.removeAddClass('.btn-previous > span', this.options.arrowPrevIconClass, value);
  323. };
  324. Iconpicker.prototype.setCols = function (value) {
  325. this.options.cols = value;
  326. this.reset();
  327. };
  328. Iconpicker.prototype.setFooter = function (value) {
  329. var footer = this.options.table.find('tfoot');
  330. if (value === true) {
  331. footer.show();
  332. }
  333. else {
  334. footer.hide();
  335. }
  336. this.options.footer = value;
  337. };
  338. Iconpicker.prototype.setHeader = function (value) {
  339. var header = this.options.table.find('thead');
  340. if (value === true) {
  341. header.show();
  342. }
  343. else {
  344. header.hide();
  345. }
  346. this.options.header = value;
  347. };
  348. Iconpicker.prototype.setIcon = function (value) {
  349. this.select(value);
  350. };
  351. Iconpicker.prototype.setIconset = function (value) {
  352. var op = this.options;
  353. if ($.isPlainObject(value)) {
  354. Iconpicker.ICONSET._custom = $.extend(Iconpicker.ICONSET_EMPTY, value);
  355. op.iconset = '_custom';
  356. }
  357. else if (!Iconpicker.ICONSET.hasOwnProperty(value)) {
  358. op.iconset = Iconpicker.DEFAULTS.iconset;
  359. }
  360. else {
  361. op.iconset = value;
  362. }
  363. op = $.extend(op, Iconpicker.ICONSET[op.iconset]);
  364. this.reset();
  365. this.select(op.icon);
  366. };
  367. Iconpicker.prototype.setLabelHeader = function (value) {
  368. this.options.labelHeader = value;
  369. this.updateLabels(this.options.page);
  370. };
  371. Iconpicker.prototype.setLabelFooter = function (value) {
  372. this.options.labelFooter = value;
  373. this.updateLabels(this.options.page);
  374. };
  375. Iconpicker.prototype.setPlacement = function (value) {
  376. this.options.placement = value;
  377. };
  378. Iconpicker.prototype.setRows = function (value) {
  379. this.options.rows = value;
  380. this.reset();
  381. };
  382. Iconpicker.prototype.setSearch = function (value) {
  383. var search = this.options.table.find('.search-control');
  384. if (value === true) {
  385. search.show();
  386. }
  387. else {
  388. search.hide();
  389. }
  390. search.val('');
  391. this.changeList(1);
  392. this.options.search = value;
  393. };
  394. Iconpicker.prototype.setSearchText = function (value) {
  395. this.options.table.find('.search-control').attr('placeholder', value);
  396. this.options.searchText = value;
  397. };
  398. Iconpicker.prototype.setSelectedClass = function (value) {
  399. this.options.selectedClass = this.removeAddClass('.btn-icon-selected', this.options.selectedClass, value);
  400. };
  401. Iconpicker.prototype.setUnselectedClass = function (value) {
  402. this.options.unselectedClass = this.removeAddClass('.btn-icon', this.options.unselectedClass, value);
  403. };
  404. // ICONPICKER PLUGIN DEFINITION
  405. // ========================
  406. var old = $.fn.iconpicker;
  407. $.fn.iconpicker = function (option, params) {
  408. return this.each(function () {
  409. var $this = $(this);
  410. var data = $this.data('bs.iconpicker');
  411. var options = typeof option === 'object' && option;
  412. if (!data) {
  413. $this.data('bs.iconpicker', (data = new Iconpicker(this, options)));
  414. }
  415. if (typeof option === 'string') {
  416. if (typeof data[option] === 'undefined') {
  417. throw 'Iconpicker => The "' + option + '" method does not exists.';
  418. }
  419. else {
  420. data[option](params);
  421. }
  422. }
  423. else{
  424. var op = data.options;
  425. op = $.extend(op, {
  426. inline: false,
  427. page: 1,
  428. selected: -1,
  429. table: $('<table class="table-icons"><thead></thead><tbody></tbody><tfoot></tfoot></table>')
  430. });
  431. var name = (typeof $this.attr('name') !== 'undefined') ? 'name="' + $this.attr('name') + '"' : '';
  432. if($this.prop('tagName') === 'BUTTON'){
  433. $this.empty()
  434. .append('<i></i>')
  435. .append('<input type="hidden" ' + name + '></input>')
  436. .append('<span class="caret"></span>')
  437. .addClass('iconpicker ' + (($.fn.bsVersion() === '3.x') ? '' : 'dropdown-toggle'));
  438. data.setIconset(op.iconset);
  439. $this.on('click', function(e) {
  440. e.preventDefault();
  441. $this.popover({
  442. animation: false,
  443. trigger: 'manual',
  444. html: true,
  445. content: op.table,
  446. container: 'body',
  447. placement: op.placement
  448. }).on('inserted.bs.popover', function() {
  449. var el = $this.data('bs.popover');
  450. var tip = ($.fn.bsVersion() === '3.x') ? el.tip() : $(el.getTipElement())
  451. tip.addClass('iconpicker-popover');
  452. }).on('shown.bs.popover', function () {
  453. data.switchPage(op.icon);
  454. data.bindEvents();
  455. });
  456. //console.log($.fn.bsVersion());
  457. $this.popover('show');
  458. });
  459. }
  460. else{
  461. op.inline = true;
  462. data.setIconset(op.iconset);
  463. $this.empty()
  464. .append('<input type="hidden" ' + name + '></input>')
  465. .append(op.table)
  466. .addClass('iconpicker')
  467. .addClass(op.align);
  468. data.switchPage(op.icon);
  469. data.bindEvents();
  470. }
  471. }
  472. });
  473. };
  474. $.fn.iconpicker.Constructor = Iconpicker;
  475. // ICONPICKER NO CONFLICT
  476. // ==================
  477. $.fn.iconpicker.noConflict = function () {
  478. $.fn.iconpicker = old;
  479. return this;
  480. };
  481. $.fn.bsVersion = function() {
  482. return $.fn.popover.Constructor.VERSION.substr(0,2) + 'x';
  483. };
  484. // ICONPICKER DATA-API
  485. // ===============
  486. $(document).on('click', 'body', function (e) {
  487. $('.iconpicker').each(function () {
  488. //the 'is' for buttons that trigger popups
  489. //the 'has' for icons within a button that triggers a popup
  490. if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
  491. $(this).popover(($.fn.bsVersion() === '3.x') ? 'destroy' : 'dispose');
  492. }
  493. });
  494. });
  495. $('button[role="iconpicker"],div[role="iconpicker"]').iconpicker();
  496. })(jQuery);