File: /home/circuix/www/wp-content/plugins/wp-file-manager-pro/js/jquery.multiselect.js
/*
* Project: Multiselect
* Description: An alternative and responsive multiselect widget
* URL:
* Author: Danier Rivas
* License: MIT
*/
;
(function ($, window, document, undefined) {
// undefined is used here as the undefined global variable in ECMAScript 3 is
// mutable (ie. it can be changed by someone else). undefined isn't really being
// passed in so we can ensure the value of it is truly undefined. In ES5, undefined
// can no longer be modified.
// window and document are passed through as local variable rather than global
// as this (slightly) quickens the resolution process and can be more efficiently
// minified (especially when both are regularly referenced in your plugin).
// Create the defaults once
var pluginName = "multiselect",
defaults = {
addScrollBar: true,
addSearchBox: true,
addActionBox: true,
animateSearch: false, // Can be 'normal', 'slow', 'fast', or int number
searchBoxText: 'Type here to search list...',
checkAllText: 'Check all',
uncheckAllText: 'Uncheck all',
invertSelectText: 'Invert select',
showCheckboxes: true,
showSelectedItems: false,
overwriteName: false, // Use false when you need to use original name attribute, or use
// true if you want to overwrite original name attribute with id; Very
// important for Ruby on Rails support to use original name attribute!
submitDataAsArray: true, // This one allows compatibility with languages that use arrays
// to process the form data, such as PHP. Set to false if using
// ColdFusion or anything else with a list-based approach.
preferIdOverName: true, // When this is true (default) the ID of the select box is
// submitted to the server as the variable containing the checked
// items. Set to false to use the "name" attribute instead (this makes
// it compatible with Drupal's Views module and Ruby on Rails.)
maxNumOfSelections: -1, // If you want to limit the number of items a user can select in a
// checklist, set this to a positive integer.
// This function gets executed whenever you go over the max number of allowable selections.
onMaxNumExceeded: function () {
alert('You cannot select more than ' + this.maxNumOfSelections + ' items in this list.');
},
initSelection: $.noop(),
// In case of name conflicts, you can change the class names to whatever you want to use.
cssContainer: 'checklistContainer',
cssChecklist: 'checklist',
cssChecklistHighlighted: 'checklistHighlighted',
cssLeaveRoomForCheckbox: 'leaveRoomForCheckbox', // For label elements
cssEven: 'even',
cssOdd: 'odd',
cssChecked: 'checked',
cssDisabled: 'disabled',
cssShowSelectedItems: 'showSelectedItems',
cssFocused: 'focused', // This cssFocused is for the li's in the checklist
cssFindInList: 'findInList',
cssBlurred: 'blurred', // This cssBlurred is for the findInList divs.
cssContainsPlaceholder: 'contains-placeholder', // This cssBlurred is for the findInList divs.
cssOptgroup: 'optgroup',
listWidth: 0, // force the list width, if 0 the original SELECT width is used
itemWidth: 0 // 0 : each item will be large as the list (single column)
// > 0 : each item will have a fixed size, so we could split
// list into more than one column
// WARNING: vertical scroll bar width must be taken into account
// listWidth=200, itemWidth=50 DOES NOT GIVE a 4 columns list
// if list scroll bar is visible
};
// The actual plugin constructor
function Plugin(element, options) {
this.element = element;
// jQuery has an extend method which merges the contents of two or
// more objects, storing the result in the first object. The first object
// is generally empty as we don't want to alter the default options for
// future instances of the plugin
this.settings = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.init();
}
// Avoid Plugin.prototype conflicts
$.extend(Plugin.prototype, {
init: function () {
// Place initialization logic here
// You already have access to the DOM element and
// the options via the instance, e.g. this.element
// and this.settings
// you can add more functions like the one below and
// call them like so: this.updateChecklist(this.element, this.settings).
var self = this,
o = this.settings,
el = $(this.element);
var overflowProperty = ( o.addScrollBar ) ? 'overflow-y: auto; overflow-x: hidden;' : '',
leaveRoomForCheckbox = ( o.showCheckboxes ) ? 'padding-left: 25px' : 'padding-left: 3px';
// Here, THIS refers to the jQuery stack object that contains all the target elements that
// are going to be converted to checklists. Let's loop over them and do the conversion.
$.each(el, function () {
var numOfCheckedBoxesSoFar = 0;
// Hang on to the important information about this <select> element.
var jSelectElem = $(this);
var jSelectElemId = jSelectElem.attr('id');
var jSelectElemName = jSelectElem.attr('name');
if (jSelectElemId == '' || !o.preferIdOverName) {
// Regardless of whether this is a PHP environment, we need an id
// for the element, and it shouldn't have brackets [] in it.
jSelectElemId = jSelectElemName.replace(/\[|\]/g, '');
if (jSelectElemId == '') {
self.error('Can\'t convert element to checklist.\nYour SELECT element must'
+ ' have a "name" attribute and/or an "id" attribute specified.');
return $;
}
}
var h = jSelectElem.outerHeight();
/* : '100%'; */
var w = o.listWidth ? o.listWidth : jSelectElem.outerWidth();
// We have to account for the extra thick left border.
w -= 2;
// Make sure it's a SELECT element, and that it's a multiple one.
if (this.type != 'select-multiple' && this.type != 'select-one') {
self.error("Can't convert element to checklist.\n"
+ "Expecting SELECT element with \"multiple\" attribute.");
return $;
} else if (this.type == 'select-one') {
return $;
}
var convertListItemsToCheckboxes = function () {
var checkboxValue = $(this).val();
// The option tag may not have had a "value" attribute set. In this case,
// Firefox automatically uses the innerHTML instead, but we need to set it
// manually for IE.
if (checkboxValue == '') {
checkboxValue = $(this).html();
}
checkboxValue = checkboxValue.replace(/ /g, '_');
var checkboxId = jSelectElemId + '_' + checkboxValue;
// escape bad values for checkboxId
checkboxId = checkboxId.replace(/[^A-Z0-9]+/ig, "_"); //.replace(/(\.|\/|\,|\%|\<|\>|\=)/g, '\\$1');
var labelText = $(this).html();
var selected = '';
if ($(this).attr('disabled')) {
var disabled = ' disabled="disabled"';
var disabledClass = ' class="disabled"';
} else {
var disabled = '';
var disabledClass = '';
var selected = '';
if ($(this).attr('selected')) {
if (o.maxNumOfSelections != -1 && numOfCheckedBoxesSoFar <= o.maxNumOfSelections) {
selected += 'checked="checked"';
numOfCheckedBoxesSoFar++;
} else if (o.maxNumOfSelections == -1) {
selected += 'checked="checked"';
}
}
}
var arrayBrackets = (o.submitDataAsArray) ? '[]' : '';
var checkboxName = (o.preferIdOverName) ? jSelectElemId + arrayBrackets : jSelectElemName + arrayBrackets;
// avoid trailing double [][]
checkboxName = checkboxName.replace(/\[\]\[\]$/, '[]');
$(this).replaceWith('<li tabindex="0"><input type="checkbox" value="' + checkboxValue
+ '" name="' + checkboxName + '" id="' + checkboxId + '" ' + selected + disabled
+ ' /><label for="' + checkboxId + '"' + disabledClass + '>' + labelText + '</label></li>');
// Hide the checkboxes.
if (o.showCheckboxes === false) {
// We could use display:none here, but IE can't handle it. Better
// to hide the checkboxes off screen to the left.
$('#' + checkboxId).css('position', 'absolute').css('left', '-50000px');
} else {
$('label[for=' + checkboxId + ']').addClass(o.cssLeaveRoomForCheckbox);
}
};
// Loop through optgroup elements (if any) and turn them into headings
$('optgroup', jSelectElem).each(function (i) {
$('option', this).each(convertListItemsToCheckboxes);
$(this).replaceWith(
'<li class="' + o.cssOptgroup + '">'
+ '<input type="checkbox" class="' + o.cssOptgroup + '" id="' + jSelectElemId + '_' + o.cssOptgroup + '_' + i + '">'
+ '<label for="' + jSelectElemId + '_' + o.cssOptgroup + '_' + i + '" class="leaveRoomForCheckbox">' + $(this).attr('label') + '</label>'
+ '</li>' + $(this).html()
);
});
// Loop through all remaining options (not in optgroups) and convert them to li's
// with checkboxes and labels.
$('option', jSelectElem).each(convertListItemsToCheckboxes);
// If the first list item in the checklist is an optgroup label, we want
// to remove the top border so it doesn't look ugly.
$('li:first', jSelectElem).each(function () {
if ($(this).hasClass(o.cssOptgroup)) {
$(this).css('border-top', 'none');
}
});
var checklistId = jSelectElemId + '_' + 'checklist';
// Convert the outer SELECT elem to a <div>
// Also, enclose it inside another div that has the original id, so developers
// can access it as before. Also, this allows the search box to be inside
// the div as well.
jSelectElem.replaceWith('<div id="' + jSelectElemId + '" class="' + o.cssContainer + '"><div id="' + checklistId + '">'
+ '<ul>' + jSelectElem.html() + '</ul></div></div>');
var checklistDivId = '#' + checklistId;
// We're going to create a custom HTML attribute in the main div box (the one
// that contains the checklist) to store our value for the showSelectedItems
// setting. This is necessary because we may need to change this value dynamically
// after the initial conversion in order to make it faster to check/uncheck every
// item in the list.
$('#' + jSelectElemId).attr('showSelectedItems', o.showSelectedItems.toString());
$('#' + jSelectElemId).css('width', w + 2);
// We MUST set the checklist div's position to either 'relative' or 'absolute'
// (default is 'static'), or else Firefox will think the offsetParent of the inner
// elements is BODY instead of DIV.
$(checklistDivId).css('position', 'relative');
// Add the findInList div, if settings call for it.
var findInListDivHeight = 0;
if (o.addSearchBox) {
self.addSearchBox(jSelectElem, checklistDivId, w, o);
}
if (o.addActionBox) {
self.addActionBox(jSelectElem, checklistDivId, w, o);
}
// Bind optgroup inputs
$('li.' + o.cssOptgroup, checklistDivId).on('click', 'input', function (e) {
var index = parseInt(this.id.replace(jSelectElemId + '_' + o.cssOptgroup + '_', '')),
nextElement = $('li.' + o.cssOptgroup + ':eq(' + (index + 1) + ')', checklistDivId),
selector = $('li.' + o.cssOptgroup + ':eq(' + index + ')', checklistDivId).nextUntil(nextElement);
self.updateChecklist((this.checked ? 'checkAllGroup' : 'clearAllGroup'), checklistDivId, selector);
});
// Add styles
var items = $('li', checklistDivId);
$(checklistDivId).addClass(o.cssChecklist);
if (o.addScrollBar) {
$(checklistDivId).height(h - findInListDivHeight).width(w);
} else {
$(checklistDivId).height('100%').width(w);
}
$('ul', checklistDivId).addClass(o.cssChecklist);
// Stripe the li's
$('li:even', checklistDivId).addClass(o.cssEven);
$('li:odd', checklistDivId).addClass(o.cssOdd);
// Emulate the :hover effect for keyboard navigation.
items.focus(function () {
$(this).addClass(o.cssFocused);
}).blur(function (event) {
$(this).removeClass(o.cssFocused);
});
// Multicolumn items
// make items float:left if itemWidth option is set
if (o.itemWidth > 0) {
var colW = o.itemWidth + 'px';
items.each(function () {
$(this).css({
'float': 'left',
'width': colW
});
});
}
// Highlight preselected ones.
items.each(function () {
if ($('input', this).attr('checked')) {
$(this).addClass(o.cssChecked);
}
});
// EVENT HANDLERS
var toggleDivGlow = function () {
// Make sure the div is glowing if something is checked in it.
if (items.hasClass(o.cssChecked)) {
$(checklistDivId).addClass(o.cssChecklistHighlighted);
} else {
$(checklistDivId).removeClass(o.cssChecklistHighlighted);
}
};
var moveToNextLi = function () {
// Make sure that the next LI has a checkbox (some LIs don't, because
// they came from <optgroup> tags.
if ($(this).prop('tagName').toLowerCase() != 'li') {
return;
}
if ($(this).is('li:has(input)')) {
$(this).focus();
}
else {
$(this).next().each(moveToNextLi);
}
};
// Check/uncheck boxes
var check = function (event) {
// This needs to be keyboard accessible too. Only check the box if the user
// presses space (enter typically submits a form, so is not safe).
if (event.type == 'keydown') {
// Pressing spacebar in IE and Opera triggers a Page Down. We don't want that
// to happen in this case. Opera doesn't respond to this, unfortunately...
// We also want to prevent form submission with enter key.
if (event.keyCode == 32 || event.keyCode == 13) {
event.preventDefault();
}
// Tab keys need to move to the next item in IE, Opera, Safari, Chrome, etc.
if (event.keyCode == 9 && !event.shiftKey) {
event.preventDefault();
// Move to the next LI
$(this).off('keydown.tabBack').blur().next().each(moveToNextLi);
} else if (event.keyCode == 9 && event.shiftKey) {
// Move to the previous LI
//$(this).prev(':has(input)').focus();
}
if (event.keyCode != 32) {
return;
}
}
// If we go over the maxNumOfSelections limit, trigger our custom
// event onMaxNumExceeded.
var numOfItemsChecked = $('input:checked', checklistDivId).length;
if (o.maxNumOfSelections != -1 && numOfItemsChecked > o.maxNumOfSelections
&& !$('input', this).attr('checked')) {
o.onMaxNumExceeded();
event.preventDefault();
return;
}
// Not sure if unbind() here removes default action, but that's what I want.
$('label', this).off();
// Make sure that the event handler isn't triggered twice (thus preventing the user
// from actually checking the box) if clicking directly on checkbox or label.
// Note: the && is not a mistake here. It should not be ||
if (event.target.tagName.toLowerCase() != 'input' && event.target.tagName.toLowerCase() != 'label') {
$('input', this).trigger('click');
}
// Change the styling of the row to be checked or unchecked.
var checkbox = $('input', this).get(0);
updateLIStyleToMatchCheckedStatus(checkbox);
// The showSelectedItems setting can change after the initial conversion to
// a checklist, so rather than checking o.showSelectedItems, we check the
// value of the custom HTML attribute on the main containing div.
if ($('#' + jSelectElemId).attr('showSelectedItems') === 'true') {
showSelectedItems();
}
};
var updateLIStyleToMatchCheckedStatus = function (checkbox) {
if (checkbox.checked) {
$(checkbox).parent().addClass(o.cssChecked);
} else {
$(checkbox).parent().removeClass(o.cssChecked);
}
toggleDivGlow();
};
// Accessibility, primarily for IE
var handFocusToLI = function () {
// Make sure that labels and checkboxes that receive
// focus divert the focus to the LI itself.
$(this).parent().focus();
};
$('li:has(input)', checklistDivId).click(check).keydown(check);
$('label', checklistDivId).focus(handFocusToLI);
$('input', checklistDivId).focus(handFocusToLI);
toggleDivGlow();
// Make sure that resetting the form doesn't leave highlighted divs where
// they shouldn't be and vice versa.
var fixFormElems = function (event) {
$('input', this).each(function () {
this.checked = this.defaultChecked;
updateLIStyleToMatchCheckedStatus(this);
if (o.showSelectedItems) {
showSelectedItems();
}
}).parent();
};
$('form:has(div.' + o.cssChecklist + ')').on('reset.fixFormElems', fixFormElems);
// List the selected items in a UL
var selectedItemsListId = '#' + jSelectElemId + '_selectedItems';
if (o.showSelectedItems) {
$(selectedItemsListId).addClass(o.cssShowSelectedItems);
}
var showSelectedItems = function () {
// Clear the innerHTML of the list and then add every item to it
// that is highlighted in the checklist.
$(selectedItemsListId).html('');
$('label', checklistDivId).each(function () {
var vcontext = $(this).parent();
if ($(this).parent().hasClass(o.cssChecked)) {
var labelText = jQuery.trim($(this).html());
$('<li class="">' + labelText + '</li>')
.on('click.remove', function () {
vcontext.trigger('click');
}).appendTo(selectedItemsListId);
}
});
};
// We have to run showSelectedItems() once here too, upon initial conversion.
if (o.showSelectedItems) {
showSelectedItems();
}
});
},
// Since o can be a string instead of an object, we need a function that
// will handle the action requested when o is a string (e.g. 'clearAll')
updateChecklist: function (action, checklistElem, selector) {
// Before we operate on all checkboxes, we need to make sure that
// showSelectedItems is disabled, at least temporarily. Otherwise,
// this process will be REALLY slow because it tries to update the
// DOM a thousand times unnecessarily.
// (We will only do this if the list is greater than 3 items.)
var showSelectedItemsSetting;
var disableDynamicList = function (checklistLength) {
if (checklistLength > 3) {
showSelectedItemsSetting = $(checklistElem).attr('showSelectedItems');
$(checklistElem).attr('showSelectedItems', 'false');
}
};
var enableDynamicList = function () {
$(checklistElem).attr('showSelectedItems', showSelectedItemsSetting);
};
switch (action) {
case 'clearAll' :
var selector = 'li:has(input:checked:not(:hidden))';
break;
case 'checkAll' :
var selector = 'li:has(input:not(:checked,:disabled,:hidden))';
break;
case 'invert' :
var selector = 'li:has(input:not(:hidden))';
break;
case 'checkAllGroup' :
var selector = selector.find(':input:not(:checked,:disabled,:hidden)');
break;
case 'clearAllGroup' :
var selector = selector.find(':input:checked:not(:hidden)');
break;
default :
alert("multiselect Plugin says:\n\nWarning - Invalid action requested on checklist.\nThe action requested was: " + action);
break;
}
var checklistLength = $(selector, checklistElem).length;
disableDynamicList(checklistLength);
// If it's checked, force the click event handler to run.
$(selector, checklistElem).each(function (i) {
// Before we check/uncheck the penultimate item in the list, we need to restore
// the showSelectedItems setting to its original setting, so that we update the
// list of selected items appropriately on the last item we check/uncheck.
if (i == checklistLength - 2 && checklistLength > 3) {
enableDynamicList();
}
if (!$(this).hasClass('optgroup')) {
$(this).trigger('click');
} else {
var input = $(this).find(':input');
input.prop('checked', !input[0].checked);
}
});
},
error: function (msg) {
alert("jQuery Plugin Error (Plugin: multiselect)\n\n" + msg);
},
addSearchBox: function (jSelectElem, checklistDivId, w, o) {
// Poorly named function... It's really onFocusSearchBox.
var focusSearchBox = function () {
// Remove placeholder text when focusing search box if it contains placeholder.
if ($(this).hasClass(o.cssContainsPlaceholder)) {
$(this).val('');
}
$(this).removeClass(o.cssBlurred);
};
var showAllSelectOptions = function () {
$('label', checklistDivId).each(function () {
if (o.animateSearch !== false)
$(this).parent('li').slideDown(o.animateSearch);
else
$(this).parent('li').show();
});
};
var blurSearchBox = function () {
// Restore default text on blur.
if ($(this).val() === '') {
$(this).val(o.searchBoxText);
$(this).addClass(o.cssContainsPlaceholder);
var t = setTimeout(showAllSelectOptions, 250);
}
$(this).addClass(o.cssBlurred);
};
var initSearchBox = function () {
$(checklistDivId).before('<div class="findInList" id="' + jSelectElem.attr('id') + '_findInListDiv">'
+ '<input type="text" placeholder="' + o.searchBoxText + '" value="" id="'
+ jSelectElem.attr('id') + '_findInList" class="' + o.cssBlurred + ' ' + o.cssContainsPlaceholder + '" /></div>');
// Set width of searchbox input to same as original SELECT element.
w -= 4;
$('#' + jSelectElem.attr('id') + '_findInList').css('width', w);
var searchBoxId = '#' + jSelectElem.attr('id') + '_findInList';
// We want to be able to simply press tab to move the focus from the
// search text box to the item in the list that we found with it.
$(searchBoxId)
.on('keydown.tabToFocus', function (event) {
if (event.keyCode == 9) {
// event.preventDefault(); // No double tabs, please...
$('label:first:visible', checklistDivId).parent().on('keydown.tabBack', function (event) {
// This function lets you shift-tab to get back to the search box easily.
if (event.keyCode == 9 && event.shiftKey) {
event.preventDefault(); // No double tabs, please...
$(searchBoxId)
//.off('focus.focusSearchBox')
//.removeClass(o.cssBlurred)
//.on('focus.focusSearchBox',focusSearchBox)
// .on('blur.blurSearchBox',blurSearchBox)
.focus();
$(this).off('keydown.tabBack');
}
}).focus(); // Focuses the actual list item found by the search box
// $(this).off('keydown.tabToFocus');
} else {
//$(this).off('blur.blurSearchBox');
}
})
.on('focus.focusSearchBox', focusSearchBox) // Set up keydown and keyup event handlers, etc. on searchbox
.on('blur.blurSearchBox', blurSearchBox)
.on('keyup', function (event) {
// Search for the actual text.
var textbox = this; // holder
if ($(this).val() === '') {
showAllSelectOptions();
//$(this).off('keydown.tabToFocus');
return false;
}
else {
// Remove placeholder on user input.
$(this).removeClass(o.cssContainsPlaceholder);
}
$('label', checklistDivId).each(function () {
var $curLabel = $(this);
if (!$curLabel.is(':disabled')) {
var curItem = $curLabel.text().toLowerCase();
var typedText = textbox.value.toLowerCase();
if (curItem.indexOf(typedText) == -1) {
if (o.animateSearch !== false)
$curLabel.parent('li').slideUp(o.animateSearch);
else
$curLabel.parent('li').hide();
} else {
if (o.animateSearch !== false)
$curLabel.parent('li').slideDown(o.animateSearch);
else
$curLabel.parent('li').show();
}
}
});
return;
});
// Compensate for the extra space the search box takes up by shortening the
// height of the checklist div. Also account for margin below the search box.
findInListDivHeight = $('#' + jSelectElem.attr('id') + '_findInListDiv').height() + 3;
};
initSearchBox();
},
addActionBox: function (jSelectElem, checklistDivId, w, o) {
var self = this;
var initActionBox = function () {
$(checklistDivId).after('<div class="actionButtons" id="' + jSelectElem.attr('id') + '_actionButtons">'
+ '<span data-action="checkAll" >' + o.checkAllText + '</span> | '
+ '<span data-action="clearAll" >' + o.uncheckAllText + '</span> | '
+ '<span data-action="invert" >' + o.invertSelectText + '</span></div>'
);
var actionBoxId = '#' + jSelectElem.attr('id') + '_actionButtons';
$(actionBoxId).on('click', 'span', function () {
var action = $(this).data("action");
self.updateChecklist(action, checklistDivId);
});
};
initActionBox();
}
});
// A really lightweight plugin wrapper around the constructor,
// preventing against multiple instantiations
$.fn[pluginName] = function (options) {
this.each(function () {
if (!$.data(this, "plugin_" + pluginName)) {
$.data(this, "plugin_" + pluginName, new Plugin(this, options));
}
});
// chain jQuery functions
return this;
};
})(jQuery, window, document);