mirror of
https://github.com/ExactTarget/fuelux.git
synced 2026-01-10 23:18:07 -05:00
293 lines
7.7 KiB
JavaScript
293 lines
7.7 KiB
JavaScript
/* 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 --
|