jquery.sumoselect.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. /*!
  2. * jquery.sumoselect - v3.0.3
  3. * http://hemantnegi.github.io/jquery.sumoselect
  4. * 2016-12-12
  5. *
  6. * Copyright 2015 Hemant Negi
  7. * Email : hemant.frnz@gmail.com
  8. * Compressor http://refresh-sf.com/
  9. */
  10. (function (factory) {
  11. 'use strict';
  12. if (typeof define === 'function' && define.amd) {
  13. define(['jquery'], factory);
  14. } else if (typeof exports !== 'undefined') {
  15. module.exports = factory(require('jquery'));
  16. } else {
  17. factory(jQuery);
  18. }
  19. })(function ($) {
  20. 'namespace sumo';
  21. $.fn.SumoSelect = function (options) {
  22. // This is the easiest way to have default options.
  23. var settings = $.extend({
  24. placeholder: 'Select Here', // Dont change it here.
  25. csvDispCount: 3, // display no. of items in multiselect. 0 to display all.
  26. captionFormat: '{0} Selected', // format of caption text. you can set your locale.
  27. captionFormatAllSelected: '{0} all selected!', // format of caption text when all elements are selected. set null to use captionFormat. It will not work if there are disabled elements in select.
  28. floatWidth: 400, // Screen width of device at which the list is rendered in floating popup fashion.
  29. forceCustomRendering: false, // force the custom modal on all devices below floatWidth resolution.
  30. nativeOnDevice: ['Android', 'BlackBerry', 'iPhone', 'iPad', 'iPod', 'Opera Mini', 'IEMobile', 'Silk'], //
  31. outputAsCSV: false, // true to POST data as csv ( false for Html control array ie. default select )
  32. csvSepChar: ',', // separation char in csv mode
  33. okCancelInMulti: false, // display ok cancel buttons in desktop mode multiselect also.
  34. isClickAwayOk: false, // for okCancelInMulti=true. sets whether click outside will trigger Ok or Cancel (default is cancel).
  35. triggerChangeCombined: true, // im multi select mode whether to trigger change event on individual selection or combined selection.
  36. selectAll: false, // to display select all button in multiselect mode.|| also select all will not be available on mobile devices.
  37. search: false, // to display input for filtering content. selectAlltext will be input text placeholder
  38. searchText: 'Search...', // placeholder for search input
  39. searchFn: function(haystack, needle) { // search function
  40. return haystack.toLowerCase().indexOf(needle.toLowerCase()) < 0;
  41. },
  42. noMatch: 'No matches for "{0}"',
  43. prefix: '', // some prefix usually the field name. eg. '<b>Hello</b>'
  44. locale: ['OK', 'Cancel', 'Select All'], // all text that is used. don't change the index.
  45. up: false, // set true to open upside.
  46. showTitle: true // set to false to prevent title (tooltip) from appearing
  47. }, options);
  48. var ret = this.each(function () {
  49. var selObj = this; // the original select object.
  50. if (this.sumo || !$(this).is('select')) return; //already initialized
  51. this.sumo = {
  52. E: $(selObj), //the jquery object of original select element.
  53. is_multi: $(selObj).attr('multiple'), //if its a multiple select
  54. select: '',
  55. caption: '',
  56. placeholder: '',
  57. optDiv: '',
  58. CaptionCont: '',
  59. ul: '',
  60. is_floating: false,
  61. is_opened: false,
  62. //backdrop: '',
  63. mob: false, // if to open device default select
  64. Pstate: [],
  65. lastUnselected: null,
  66. createElems: function () {
  67. var O = this;
  68. O.E.wrap('<div class="SumoSelect" tabindex="0" role="button" aria-expanded="false">');
  69. O.select = O.E.parent();
  70. O.caption = $('<span>');
  71. O.CaptionCont = $('<p class="CaptionCont SelectBox" ><label><i></i></label></p>')
  72. .attr('style', O.E.attr('style'))
  73. .prepend(O.caption);
  74. O.select.append(O.CaptionCont);
  75. // default turn off if no multiselect
  76. if (!O.is_multi) settings.okCancelInMulti = false
  77. if (O.E.attr('disabled'))
  78. O.select.addClass('disabled').removeAttr('tabindex');
  79. //if output as csv and is a multiselect.
  80. if (settings.outputAsCSV && O.is_multi && O.E.attr('name')) {
  81. //create a hidden field to store csv value.
  82. O.select.append($('<input class="HEMANT123" type="hidden" />').attr('name', O.E.attr('name')).val(O.getSelStr()));
  83. // so it can not post the original select.
  84. O.E.removeAttr('name');
  85. }
  86. //break for mobile rendring.. if forceCustomRendering is false
  87. if (O.isMobile() && !settings.forceCustomRendering) {
  88. O.setNativeMobile();
  89. return;
  90. }
  91. // if there is a name attr in select add a class to container div
  92. if (O.E.attr('name')) O.select.addClass('sumo_' + O.E.attr('name').replace(/\[\]/, ''))
  93. //hide original select
  94. O.E.addClass('SumoUnder').attr('tabindex', '-1');
  95. //## Creating the list...
  96. O.optDiv = $('<div class="optWrapper ' + (settings.up ? 'up' : '') + '">');
  97. //branch for floating list in low res devices.
  98. O.floatingList();
  99. //Creating the markup for the available options
  100. O.ul = $('<ul class="options">');
  101. O.optDiv.append(O.ul);
  102. // Select all functionality
  103. if (settings.selectAll && O.is_multi) O.SelAll();
  104. // search functionality
  105. if (settings.search) O.Search();
  106. O.ul.append(O.prepItems(O.E.children()));
  107. //if multiple then add the class multiple and add OK / CANCEL button
  108. if (O.is_multi) O.multiSelelect();
  109. O.select.append(O.optDiv);
  110. O.basicEvents();
  111. O.selAllState();
  112. },
  113. prepItems: function (opts, d) {
  114. var lis = [], O = this;
  115. $(opts).each(function (i, opt) { // parsing options to li
  116. opt = $(opt);
  117. lis.push(opt.is('optgroup') ?
  118. $('<li class="group ' + (opt[0].disabled ? 'disabled' : '') + '"><label>' + opt.attr('label') + '</label><ul></ul></li>')
  119. .find('ul')
  120. .append(O.prepItems(opt.children(), opt[0].disabled))
  121. .end()
  122. :
  123. O.createLi(opt, d)
  124. );
  125. });
  126. return lis;
  127. },
  128. //## Creates a LI element from a given option and binds events to it
  129. //## returns the jquery instance of li (not inserted in dom)
  130. createLi: function (opt, d) {
  131. var O = this;
  132. if (!opt.attr('value')) opt.attr('value', opt.val());
  133. var li = $('<li class="opt"><label>' + opt.text() + '</label></li>');
  134. li.data('opt', opt); // store a direct reference to option.
  135. opt.data('li', li); // store a direct reference to list item.
  136. if (O.is_multi) li.prepend('<span><i></i></span>');
  137. if (opt[0].disabled || d)
  138. li = li.addClass('disabled');
  139. O.onOptClick(li);
  140. if (opt[0].selected)
  141. li.addClass('selected');
  142. if (opt.attr('class'))
  143. li.addClass(opt.attr('class'));
  144. if (opt.attr('title'))
  145. li.attr('title', opt.attr('title'));
  146. return li;
  147. },
  148. //## Returns the selected items as string in a Multiselect.
  149. getSelStr: function () {
  150. // get the pre selected items.
  151. var sopt = [];
  152. this.E.find('option:selected').each(function () { sopt.push($(this).val()); });
  153. return sopt.join(settings.csvSepChar);
  154. },
  155. //## THOSE OK/CANCEL BUTTONS ON MULTIPLE SELECT.
  156. multiSelelect: function () {
  157. var O = this;
  158. O.optDiv.addClass('multiple');
  159. O.okbtn = $('<p tabindex="0" class="btnOk">' + settings.locale[0] + '</p>').click(function () {
  160. //if combined change event is set.
  161. O._okbtn();
  162. O.hideOpts();
  163. });
  164. O.cancelBtn = $('<p tabindex="0" class="btnCancel">' + settings.locale[1] + '</p>').click(function () {
  165. O._cnbtn();
  166. O.hideOpts();
  167. });
  168. var btns = O.okbtn.add(O.cancelBtn);
  169. O.optDiv.append($('<div class="MultiControls">').append(btns));
  170. // handling keyboard navigation on ok cancel buttons.
  171. btns.on('keydown.sumo', function (e) {
  172. var el = $(this);
  173. switch (e.which) {
  174. case 32: // space
  175. case 13: // enter
  176. el.trigger('click');
  177. break;
  178. case 9: //tab
  179. if (el.hasClass('btnOk')) return;
  180. case 27: // esc
  181. O._cnbtn();
  182. O.hideOpts();
  183. return;
  184. }
  185. e.stopPropagation();
  186. e.preventDefault();
  187. });
  188. },
  189. _okbtn: function () {
  190. var O = this, cg = 0;
  191. //if combined change event is set.
  192. if (settings.triggerChangeCombined) {
  193. //check for a change in the selection.
  194. if (O.E.find('option:selected').length !== O.Pstate.length) {
  195. cg = 1;
  196. }
  197. else {
  198. O.E.find('option').each(function (i, e) {
  199. if (e.selected && O.Pstate.indexOf(i) < 0) cg = 1;
  200. });
  201. }
  202. if (cg) {
  203. O.callChange();
  204. O.setText();
  205. }
  206. }
  207. },
  208. _cnbtn: function () {
  209. var O = this;
  210. //remove all selections
  211. O.E.find('option:selected').each(function () { this.selected = false; });
  212. O.optDiv.find('li.selected').removeClass('selected')
  213. //restore selections from saved state.
  214. for (var i = 0; i < O.Pstate.length; i++) {
  215. O.E.find('option')[O.Pstate[i]].selected = true;
  216. O.ul.find('li.opt').eq(O.Pstate[i]).addClass('selected');
  217. }
  218. O.selAllState();
  219. },
  220. SelAll: function () {
  221. var O = this;
  222. if (!O.is_multi) return;
  223. O.selAll = $('<p class="select-all"><span><i></i></span><label>' + settings.locale[2] + '</label></p>');
  224. O.optDiv.addClass('selall');
  225. O.selAll.on('click', function () {
  226. O.selAll.toggleClass('selected');
  227. O.toggSelAll(O.selAll.hasClass('selected'), 1);
  228. //O.selAllState();
  229. });
  230. O.optDiv.prepend(O.selAll);
  231. },
  232. // search module (can be removed if not required.)
  233. Search: function () {
  234. var O = this,
  235. cc = O.CaptionCont.addClass('search'),
  236. P = $('<p class="no-match">'),
  237. fn = (options.searchFn && typeof options.searchFn == 'function') ? options.searchFn : settings.searchFn;
  238. O.ftxt = $('<input type="text" class="search-txt" value="" placeholder="' + settings.searchText + '">')
  239. .on('click', function (e) {
  240. e.stopPropagation();
  241. });
  242. cc.append(O.ftxt);
  243. O.optDiv.children('ul').after(P);
  244. O.ftxt.on('keyup.sumo', function () {
  245. var hid = O.optDiv.find('ul.options li.opt').each(function (ix, e) {
  246. var e = $(e),
  247. opt = e.data('opt')[0];
  248. opt.hidden = fn(e.text(), O.ftxt.val());
  249. e.toggleClass('hidden', opt.hidden);
  250. }).not('.hidden');
  251. P.html(settings.noMatch.replace(/\{0\}/g, '<em></em>')).toggle(!hid.length);
  252. P.find('em').text(O.ftxt.val());
  253. O.selAllState();
  254. });
  255. },
  256. selAllState: function () {
  257. var O = this;
  258. if (settings.selectAll && O.is_multi) {
  259. var sc = 0, vc = 0;
  260. O.optDiv.find('li.opt').not('.hidden').each(function (ix, e) {
  261. if ($(e).hasClass('selected')) sc++;
  262. if (!$(e).hasClass('disabled')) vc++;
  263. });
  264. //select all checkbox state change.
  265. if (sc === vc) O.selAll.removeClass('partial').addClass('selected');
  266. else if (sc === 0) O.selAll.removeClass('selected partial');
  267. else O.selAll.addClass('partial')//.removeClass('selected');
  268. }
  269. },
  270. showOpts: function () {
  271. var O = this;
  272. if (O.E.attr('disabled')) return; // if select is disabled then retrun
  273. O.E.trigger('sumo:opening', O);
  274. O.is_opened = true;
  275. O.select.addClass('open').attr('aria-expanded', 'true');
  276. O.E.trigger('sumo:opened', O);
  277. if (O.ftxt) O.ftxt.focus();
  278. else O.select.focus();
  279. // hide options on click outside.
  280. $(document).on('click.sumo', function (e) {
  281. if (!O.select.is(e.target) // if the target of the click isn't the container...
  282. && O.select.has(e.target).length === 0) { // ... nor a descendant of the container
  283. if (!O.is_opened) return;
  284. O.hideOpts();
  285. if (settings.okCancelInMulti) {
  286. if (settings.isClickAwayOk)
  287. O._okbtn();
  288. else
  289. O._cnbtn();
  290. }
  291. }
  292. });
  293. if (O.is_floating) {
  294. var H = O.optDiv.children('ul').outerHeight() + 2; // +2 is clear fix
  295. if (O.is_multi) H = H + parseInt(O.optDiv.css('padding-bottom'));
  296. O.optDiv.css('height', H);
  297. $('body').addClass('sumoStopScroll');
  298. }
  299. O.setPstate();
  300. },
  301. //maintain state when ok/cancel buttons are available storing the indexes.
  302. setPstate: function () {
  303. var O = this;
  304. if (O.is_multi && (O.is_floating || settings.okCancelInMulti)) {
  305. O.Pstate = [];
  306. // assuming that find returns elements in tree order
  307. O.E.find('option').each(function (i, e) { if (e.selected) O.Pstate.push(i); });
  308. }
  309. },
  310. callChange: function () {
  311. this.E.trigger('change').trigger('click');
  312. },
  313. hideOpts: function () {
  314. var O = this;
  315. if (O.is_opened) {
  316. O.E.trigger('sumo:closing', O);
  317. O.is_opened = false;
  318. O.select.removeClass('open').attr('aria-expanded', 'true').find('ul li.sel').removeClass('sel');
  319. O.E.trigger('sumo:closed', O);
  320. $(document).off('click.sumo');
  321. O.select.focus();
  322. $('body').removeClass('sumoStopScroll');
  323. // clear the search
  324. if (settings.search) {
  325. O.ftxt.val('');
  326. O.ftxt.trigger('keyup.sumo');
  327. }
  328. }
  329. },
  330. setOnOpen: function () {
  331. var O = this,
  332. li = O.optDiv.find('li.opt:not(.hidden)').eq(settings.search ? 0 : O.E[0].selectedIndex);
  333. if (li.hasClass('disabled')) {
  334. li = li.next(':not(disabled)')
  335. if (!li.length) return;
  336. }
  337. O.optDiv.find('li.sel').removeClass('sel');
  338. li.addClass('sel');
  339. O.showOpts();
  340. },
  341. nav: function (up) {
  342. var O = this, c,
  343. s = O.ul.find('li.opt:not(.disabled, .hidden)'),
  344. sel = O.ul.find('li.opt.sel:not(.hidden)'),
  345. idx = s.index(sel);
  346. if (O.is_opened && sel.length) {
  347. if (up && idx > 0)
  348. c = s.eq(idx - 1);
  349. else if (!up && idx < s.length - 1 && idx > -1)
  350. c = s.eq(idx + 1);
  351. else return; // if no items before or after
  352. sel.removeClass('sel');
  353. sel = c.addClass('sel');
  354. // setting sel item to visible view.
  355. var ul = O.ul,
  356. st = ul.scrollTop(),
  357. t = sel.position().top + st;
  358. if (t >= st + ul.height() - sel.outerHeight())
  359. ul.scrollTop(t - ul.height() + sel.outerHeight());
  360. if (t < st)
  361. ul.scrollTop(t);
  362. }
  363. else
  364. O.setOnOpen();
  365. },
  366. basicEvents: function () {
  367. var O = this;
  368. O.CaptionCont.click(function (evt) {
  369. O.E.trigger('click');
  370. if (O.is_opened) O.hideOpts(); else O.showOpts();
  371. evt.stopPropagation();
  372. });
  373. O.select.on('keydown.sumo', function (e) {
  374. switch (e.which) {
  375. case 38: // up
  376. O.nav(true);
  377. break;
  378. case 40: // down
  379. O.nav(false);
  380. break;
  381. case 65: // shortcut ctrl + a to select all and ctrl + shift + a to unselect all.
  382. if (O.is_multi && e.ctrlKey) {
  383. O.toggSelAll(!e.shiftKey, 1);
  384. break;
  385. }
  386. else
  387. return;
  388. case 32: // space
  389. if (settings.search && O.ftxt.is(e.target)) return;
  390. case 13: // enter
  391. if (O.is_opened)
  392. O.optDiv.find('ul li.sel').trigger('click');
  393. else
  394. O.setOnOpen();
  395. break;
  396. case 9: //tab
  397. if (!settings.okCancelInMulti)
  398. O.hideOpts();
  399. return;
  400. case 27: // esc
  401. if (settings.okCancelInMulti) O._cnbtn();
  402. O.hideOpts();
  403. return;
  404. default:
  405. return; // exit this handler for other keys
  406. }
  407. e.preventDefault(); // prevent the default action (scroll / move caret)
  408. });
  409. $(window).on('resize.sumo', function () {
  410. O.floatingList();
  411. });
  412. },
  413. onOptClick: function (li) {
  414. var O = this;
  415. li.click(function () {
  416. var li = $(this);
  417. if (li.hasClass('disabled')) return;
  418. var txt = "";
  419. if (O.is_multi) {
  420. li.toggleClass('selected');
  421. li.data('opt')[0].selected = li.hasClass('selected');
  422. if (li.data('opt')[0].selected === false) {
  423. O.lastUnselected = li.data('opt')[0].textContent;
  424. }
  425. O.selAllState();
  426. }
  427. else {
  428. li.parent().find('li.selected').removeClass('selected'); //if not multiselect then remove all selections from this list
  429. li.toggleClass('selected');
  430. li.data('opt')[0].selected = true;
  431. }
  432. //branch for combined change event.
  433. if (!(O.is_multi && settings.triggerChangeCombined && (O.is_floating || settings.okCancelInMulti))) {
  434. O.setText();
  435. O.callChange();
  436. }
  437. if (!O.is_multi) O.hideOpts(); //if its not a multiselect then hide on single select.
  438. });
  439. },
  440. // fixed some variables that were not explicitly typed (michc)
  441. setText: function () {
  442. var O = this;
  443. O.placeholder = "";
  444. if (O.is_multi) {
  445. var sels = O.E.find(':selected').not(':disabled'); //selected options.
  446. for (var i = 0; i < sels.length; i++) {
  447. if (i + 1 >= settings.csvDispCount && settings.csvDispCount) {
  448. if (sels.length === O.E.find('option').length && settings.captionFormatAllSelected) {
  449. O.placeholder = settings.captionFormatAllSelected.replace(/\{0\}/g, sels.length) + ',';
  450. } else {
  451. O.placeholder = settings.captionFormat.replace(/\{0\}/g, sels.length) + ',';
  452. }
  453. break;
  454. }
  455. else O.placeholder += $(sels[i]).text() + ", ";
  456. }
  457. O.placeholder = O.placeholder.replace(/,([^,]*)$/, '$1'); //remove unexpected "," from last.
  458. }
  459. else {
  460. O.placeholder = O.E.find(':selected').not(':disabled').text();
  461. }
  462. var is_placeholder = false;
  463. if (!O.placeholder) {
  464. is_placeholder = true;
  465. O.placeholder = O.E.attr('placeholder');
  466. if (!O.placeholder) //if placeholder is there then set it
  467. O.placeholder = O.E.find('option:disabled:selected').text();
  468. }
  469. O.placeholder = O.placeholder ? (settings.prefix + ' ' + O.placeholder) : settings.placeholder
  470. //set display text
  471. O.caption.html(O.placeholder);
  472. if (settings.showTitle) O.CaptionCont.attr('title', O.placeholder);
  473. //set the hidden field if post as csv is true.
  474. var csvField = O.select.find('input.HEMANT123');
  475. if (csvField.length) csvField.val(O.getSelStr());
  476. //add class placeholder if its a placeholder text.
  477. if (is_placeholder) O.caption.addClass('placeholder'); else O.caption.removeClass('placeholder');
  478. return O.placeholder;
  479. },
  480. isMobile: function () {
  481. // Adapted from http://www.detectmobilebrowsers.com
  482. var ua = navigator.userAgent || navigator.vendor || window.opera;
  483. // Checks for iOs, Android, Blackberry, Opera Mini, and Windows mobile devices
  484. for (var i = 0; i < settings.nativeOnDevice.length; i++) if (ua.toString().toLowerCase().indexOf(settings.nativeOnDevice[i].toLowerCase()) > 0) return settings.nativeOnDevice[i];
  485. return false;
  486. },
  487. setNativeMobile: function () {
  488. var O = this;
  489. O.E.addClass('SelectClass')//.css('height', O.select.outerHeight());
  490. O.mob = true;
  491. O.E.change(function () {
  492. O.setText();
  493. });
  494. },
  495. floatingList: function () {
  496. var O = this;
  497. //called on init and also on resize.
  498. //O.is_floating = true if window width is < specified float width
  499. O.is_floating = $(window).width() <= settings.floatWidth;
  500. //set class isFloating
  501. O.optDiv.toggleClass('isFloating', O.is_floating);
  502. //remove height if not floating
  503. if (!O.is_floating) O.optDiv.css('height', '');
  504. //toggle class according to okCancelInMulti flag only when it is not floating
  505. O.optDiv.toggleClass('okCancelInMulti', settings.okCancelInMulti && !O.is_floating);
  506. },
  507. //HELPERS FOR OUTSIDERS
  508. // validates range of given item operations
  509. vRange: function (i) {
  510. var O = this;
  511. var opts = O.E.find('option');
  512. if (opts.length <= i || i < 0) throw "index out of bounds"
  513. return O;
  514. },
  515. //toggles selection on c as boolean.
  516. toggSel: function (c, i) {
  517. var O = this;
  518. var opt;
  519. if (typeof (i) === "number") {
  520. O.vRange(i);
  521. opt = O.E.find('option')[i];
  522. }
  523. else {
  524. opt = O.E.find('option[value="' + i + '"]')[0] || 0;
  525. }
  526. if (!opt || opt.disabled)
  527. return;
  528. if (opt.selected !== c) {
  529. opt.selected = c;
  530. if (!O.mob) $(opt).data('li').toggleClass('selected', c);
  531. O.callChange();
  532. O.setPstate();
  533. O.setText();
  534. O.selAllState();
  535. }
  536. },
  537. //toggles disabled on c as boolean.
  538. toggDis: function (c, i) {
  539. var O = this.vRange(i);
  540. O.E.find('option')[i].disabled = c;
  541. if (c) O.E.find('option')[i].selected = false;
  542. if (!O.mob) O.optDiv.find('ul.options li').eq(i).toggleClass('disabled', c).removeClass('selected');
  543. O.setText();
  544. },
  545. // toggle disable/enable on complete select control
  546. toggSumo: function (val) {
  547. var O = this;
  548. O.enabled = val;
  549. O.select.toggleClass('disabled', val);
  550. if (val) {
  551. O.E.attr('disabled', 'disabled');
  552. O.select.removeAttr('tabindex');
  553. }
  554. else {
  555. O.E.removeAttr('disabled');
  556. O.select.attr('tabindex', '0');
  557. }
  558. return O;
  559. },
  560. // toggles all option on c as boolean.
  561. // set direct=false/0 bypasses okCancelInMulti behaviour.
  562. toggSelAll: function (c, direct) {
  563. var O = this;
  564. O.E.find('option:not(:disabled,:hidden)')
  565. .each(function (ix, e) {
  566. var is_selected = e.selected,
  567. e = $(e).data('li');
  568. if (e.hasClass('hidden')) return;
  569. if (!!c) {
  570. if (!is_selected) e.trigger('click');
  571. }
  572. else {
  573. if (is_selected) e.trigger('click');
  574. }
  575. });
  576. if (!direct) {
  577. if (!O.mob && O.selAll) O.selAll.removeClass('partial').toggleClass('selected', !!c);
  578. O.callChange();
  579. O.setText();
  580. O.setPstate();
  581. }
  582. },
  583. /* outside accessibility options
  584. which can be accessed from the element instance.
  585. */
  586. reload: function () {
  587. var elm = this.unload();
  588. return $(elm).SumoSelect(settings);
  589. },
  590. unload: function () {
  591. var O = this;
  592. O.select.before(O.E);
  593. O.E.show();
  594. if (settings.outputAsCSV && O.is_multi && O.select.find('input.HEMANT123').length) {
  595. O.E.attr('name', O.select.find('input.HEMANT123').attr('name')); // restore the name;
  596. }
  597. O.select.remove();
  598. delete selObj.sumo;
  599. return selObj;
  600. },
  601. //## add a new option to select at a given index.
  602. add: function (val, txt, i) {
  603. if (typeof val === "undefined") throw "No value to add"
  604. var O = this;
  605. var opts = O.E.find('option')
  606. if (typeof txt === "number") { i = txt; txt = val; }
  607. if (typeof txt === "undefined") { txt = val; }
  608. var opt = $("<option></option>").val(val).html(txt);
  609. if (opts.length < i) throw "index out of bounds"
  610. if (typeof i === "undefined" || opts.length === i) { // add it to the last if given index is last no or no index provides.
  611. O.E.append(opt);
  612. if (!O.mob) O.ul.append(O.createLi(opt));
  613. }
  614. else {
  615. opts.eq(i).before(opt);
  616. if (!O.mob) O.ul.find('li.opt').eq(i).before(O.createLi(opt));
  617. }
  618. return selObj;
  619. },
  620. //## removes an item at a given index.
  621. remove: function (i) {
  622. var O = this.vRange(i);
  623. O.E.find('option').eq(i).remove();
  624. if (!O.mob) O.optDiv.find('ul.options li').eq(i).remove();
  625. O.setText();
  626. },
  627. // removes all but the selected one
  628. removeAll: function () {
  629. var O = this;
  630. var options = O.E.find('option');
  631. for (var x = (options.length - 1); x >= 0; x--) {
  632. if (options[x].selected !== true) {
  633. O.remove(x);
  634. }
  635. }
  636. },
  637. find: function (val) {
  638. var O = this;
  639. var options = O.E.find('option');
  640. for (var x in options) {
  641. if (options[x].value === val) {
  642. return parseInt(x);
  643. }
  644. }
  645. return -1;
  646. },
  647. //## Select an item at a given index.
  648. selectItem: function (i) { this.toggSel(true, i); },
  649. //## UnSelect an iten at a given index.
  650. unSelectItem: function (i) { this.toggSel(false, i); },
  651. //## Select all items of the select.
  652. selectAll: function () { this.toggSelAll(true); },
  653. //## UnSelect all items of the select.
  654. unSelectAll: function () { this.toggSelAll(false); },
  655. //## Disable an iten at a given index.
  656. disableItem: function (i) { this.toggDis(true, i) },
  657. //## Removes disabled an iten at a given index.
  658. enableItem: function (i) { this.toggDis(false, i) },
  659. //## New simple methods as getter and setter are not working fine in ie8-
  660. //## variable to check state of control if enabled or disabled.
  661. enabled: true,
  662. //## Enables the control
  663. enable: function () { return this.toggSumo(false) },
  664. //## Disables the control
  665. disable: function () { return this.toggSumo(true) },
  666. init: function () {
  667. var O = this;
  668. O.createElems();
  669. O.setText();
  670. return O
  671. }
  672. };
  673. selObj.sumo.init();
  674. });
  675. return ret.length === 1 ? ret[0] : ret;
  676. };
  677. });