UNPKG

fuelux

Version:

Base Fuel UX styles and controls

293 lines (230 loc) 7.93 kB
/* global jQuery:true */ /* * Fuel UX Selectlist * https://github.com/ExactTarget/fuelux * * Copyright (c) 2014 ExactTarget * Licensed under the BSD New license. */ // -- BEGIN UMD WRAPPER PREFACE -- // For more information on UMD visit: // https://github.com/umdjs/umd/blob/master/jqueryPlugin.js (function umdFactory (factory) { if (typeof define === 'function' && define.amd) { // if AMD loader is available, register as an anonymous module. define(['jquery'], factory); } else if (typeof exports === 'object') { // Node/CommonJS module.exports = factory(require('jquery')); } else { // OR use browser globals if AMD is not present factory(jQuery); } }(function SelectlistWrapper ($) { // -- END UMD WRAPPER PREFACE -- // -- BEGIN MODULE CODE HERE -- var old = $.fn.selectlist; // SELECT CONSTRUCTOR AND PROTOTYPE var Selectlist = function (element, options) { this.$element = $(element); this.options = $.extend({}, $.fn.selectlist.defaults, options); this.$button = this.$element.find('.btn.dropdown-toggle'); this.$hiddenField = this.$element.find('.hidden-field'); this.$label = this.$element.find('.selected-label'); this.$dropdownMenu = this.$element.find('.dropdown-menu'); this.$element.on('click.fu.selectlist', '.dropdown-menu a', $.proxy(this.itemClicked, this)); this.setDefaultSelection(); if (options.resize === 'auto' || this.$element.attr('data-resize') === 'auto') { this.resize(); } // if selectlist is empty or is one item, disable it var items = this.$dropdownMenu.children('li'); if( items.length === 0) { this.disable(); this.doSelect( $(this.options.emptyLabelHTML)); } // support jumping focus to first letter in dropdown when key is pressed this.$element.on('shown.bs.dropdown', function () { var $this = $(this); // attach key listener when dropdown is shown $(document).on('keypress.fu.selectlist', function(e){ // get the key that was pressed var key = String.fromCharCode(e.which); // look the items to find the first item with the first character match and set focus $this.find("li").each(function(idx,item){ if ($(item).text().charAt(0).toLowerCase() === key) { $(item).children('a').focus(); return false; } }); }); }); // unbind key event when dropdown is hidden this.$element.on('hide.bs.dropdown', function () { $(document).off('keypress.fu.selectlist'); }); }; Selectlist.prototype = { constructor: Selectlist, destroy: function () { this.$element.remove(); // any external bindings // [none] // empty elements to return to original markup // [none] // returns string of markup return this.$element[0].outerHTML; }, doSelect: function ($item) { var $selectedItem; this.$selectedItem = $selectedItem = $item; this.$hiddenField.val(this.$selectedItem.attr('data-value')); this.$label.html($(this.$selectedItem.children()[0]).html()); // clear and set selected item to allow declarative init state // unlike other controls, selectlist's value is stored internal, not in an input this.$element.find('li').each(function () { if ($selectedItem.is($(this))) { $(this).attr('data-selected', true); } else { $(this).removeData('selected').removeAttr('data-selected'); } }); }, itemClicked: function (e) { this.$element.trigger('clicked.fu.selectlist', this.$selectedItem); e.preventDefault(); // ignore if a disabled item is clicked if ($(e.currentTarget).parent('li').is('.disabled, :disabled')) { return; } // is clicked element different from currently selected element? if (!($(e.target).parent().is(this.$selectedItem))) { this.itemChanged(e); } // return focus to control after selecting an option this.$element.find('.dropdown-toggle').focus(); }, itemChanged: function (e) { //selectedItem needs to be <li> since the data is stored there, not in <a> this.doSelect($(e.target).closest('li')); // pass object including text and any data-attributes // to onchange event var data = this.selectedItem(); // trigger changed event this.$element.trigger('changed.fu.selectlist', data); }, resize: function () { var width = 0; var newWidth = 0; var sizer = $('<div/>').addClass('selectlist-sizer'); if (Boolean($(document).find('html').hasClass('fuelux'))) { // default behavior for fuel ux setup. means fuelux was a class on the html tag $(document.body).append(sizer); } else { // fuelux is not a class on the html tag. So we'll look for the first one we find so the correct styles get applied to the sizer $('.fuelux:first').append(sizer); } sizer.append(this.$element.clone()); this.$element.find('a').each(function () { sizer.find('.selected-label').text($(this).text()); newWidth = sizer.find('.selectlist').outerWidth(); newWidth = newWidth + sizer.find('.sr-only').outerWidth(); if (newWidth > width) { width = newWidth; } }); if (width <= 1) { return; } this.$button.css('width', width); this.$dropdownMenu.css('width', width); sizer.remove(); }, selectedItem: function () { var txt = this.$selectedItem.text(); return $.extend({ text: txt }, this.$selectedItem.data()); }, selectByText: function (text) { var $item = $([]); this.$element.find('li').each(function () { if ((this.textContent || this.innerText || $(this).text() || '').toLowerCase() === (text || '').toLowerCase()) { $item = $(this); return false; } }); this.doSelect($item); }, selectByValue: function (value) { var selector = 'li[data-value="' + value + '"]'; this.selectBySelector(selector); }, selectByIndex: function (index) { // zero-based index var selector = 'li:eq(' + index + ')'; this.selectBySelector(selector); }, selectBySelector: function (selector) { var $item = this.$element.find(selector); this.doSelect($item); }, setDefaultSelection: function () { var $item = this.$element.find('li[data-selected=true]').eq(0); if ($item.length === 0) { $item = this.$element.find('li').has('a').eq(0); } this.doSelect($item); }, enable: function () { this.$element.removeClass('disabled'); this.$button.removeClass('disabled'); }, disable: function () { this.$element.addClass('disabled'); this.$button.addClass('disabled'); } }; Selectlist.prototype.getValue = Selectlist.prototype.selectedItem; // SELECT PLUGIN DEFINITION $.fn.selectlist = function (option) { var args = Array.prototype.slice.call(arguments, 1); var methodReturn; var $set = this.each(function () { var $this = $(this); var data = $this.data('fu.selectlist'); var options = typeof option === 'object' && option; if (!data) { $this.data('fu.selectlist', (data = new Selectlist(this, options))); } if (typeof option === 'string') { methodReturn = data[option].apply(data, args); } }); return (methodReturn === undefined) ? $set : methodReturn; }; $.fn.selectlist.defaults = { emptyLabelHTML: '<li data-value=""><a href="#">No items</a></li>' }; $.fn.selectlist.Constructor = Selectlist; $.fn.selectlist.noConflict = function () { $.fn.selectlist = old; return this; }; // DATA-API $(document).on('mousedown.fu.selectlist.data-api', '[data-initialize=selectlist]', function (e) { var $control = $(e.target).closest('.selectlist'); if (!$control.data('fu.selectlist')) { $control.selectlist($control.data()); } }); // Must be domReady for AMD compatibility $(function () { $('[data-initialize=selectlist]').each(function () { var $this = $(this); if (!$this.data('fu.selectlist')) { $this.selectlist($this.data()); } }); }); // -- BEGIN UMD WRAPPER AFTERWORD -- })); // -- END UMD WRAPPER AFTERWORD --