From 58b51f48f90d7eb02acf9e3dd8131f6f2da0aab5 Mon Sep 17 00:00:00 2001 From: TyrionGraphiste Date: Sun, 17 Jan 2016 13:26:12 +0100 Subject: [PATCH 1/6] Select component passed to Vanilla JS. Normally fix all known issues. --- forms.html | 31 +- js/forms.js | 851 +++++++++++++++++++++++---------- sass/components/_dropdown.scss | 2 +- sass/components/_form.scss | 50 +- 4 files changed, 669 insertions(+), 265 deletions(-) diff --git a/forms.html b/forms.html index d8daf7a534..db52ca9217 100644 --- a/forms.html +++ b/forms.html @@ -413,7 +413,20 @@

Select

- + + +
+ +

@@ -474,6 +487,20 @@

Select

<label>Materialize Multiple Select</label> </div> + <div class="input-field col s12"> + <select> + <optgroup label="team 1"> + <option value="1">Option 1</option> + <option value="2">Option 2</option> + </optgroup> + <optgroup label="team 2"> + <option value="3">Option 3</option> + <option value="4">Option 4</option> + </optgroup> + </select> + <label>Materialize Select with Optgroups</label> + </div> + <div class="input-field col s12"> <select multiple> <optgroup label="team 1"> @@ -485,7 +512,7 @@

Select

<option value="4">Option 4</option> </optgroup> </select> - <label>Optgroups</label> + <label>Materialize Multiple Select with Optgroups</label> </div> <div class="input-field col s12 m6"> diff --git a/js/forms.js b/js/forms.js index 0a073baa74..0783e04f11 100644 --- a/js/forms.js +++ b/js/forms.js @@ -276,320 +276,685 @@ /******************* * Select Plugin * ******************/ - $.fn.material_select = function (callback) { - $(this).each(function(){ - var $select = $(this); + $.fn.material_select = function(callback) { + // Return true if the element passed as parameter matches to the tag name + function isTagName(tagName, element) { + return tagName === element.tagName; + } + + // Fill the input with all values from selected options + function fillContentInput(selectedOptions, _this) { + var value = []; - if ($select.hasClass('browser-default')) { - return; // Continue to next (return false breaks out of entire loop) + // Push all the text values in value + for (var i = 0, countOptions = selectedOptions.length; i < countOptions; i++) { + value.push(selectedOptions[i].textContent); } - var multiple = $select.attr('multiple') ? true : false, - lastID = $select.data('select-id'); // Tear down structure if Select needs to be rebuilt + // If no selected, get the text from the first disabled + if (!value.length) { + // Prevent error if there is no disabled option + var disabledElement = _this.elements.dropdown.querySelector('li.disabled'); + + if (disabledElement) { + value.push(disabledElement.textContent); + } + } + + _this.elements.input.value = value.join(', '); + } + + // Get all elements from a specific optgroup + function getOptgroupElements(optgroupLabel, _this) { + var elements = _this.elements.select.querySelectorAll('optgroup[label="' + optgroupLabel + '"] option'); + + return elements; + } + + // Destroy a select + function destroySelect(select) { + var defaultSelectParent = select.parentNode.parentNode, + selectParent = select.parentNode; + + // Reset the select + select.dataset.id = null; + select.classList.remove('initialized'); + // Reorder the select in the DOM before material_select changes + defaultSelectParent.appendChild(select); + defaultSelectParent.removeChild(selectParent); + defaultSelectParent.insertBefore(select, defaultSelectParent.querySelector('label')); + } + + // Update the select with new values + function updateSelect(_this) { + // Reset the select + resetSelect(_this); - if (lastID) { - $select.parent().find('span.caret').remove(); - $select.parent().find('input').remove(); + // Fill the dropdown with new values + if (_this.prop.isSelectedOption) { + var selected = _this.prop.selected(); - $select.unwrap(); - $('ul#select-options-'+lastID).remove(); + Array.prototype.forEach.call(selected, function(option) { + // True is specify for performing on load + toggleSelectElement(option, _this, true); + }); } + } - // If destroying the select, remove the selelct-id and reset it to it's uninitialized state. - if(callback === 'destroy') { - $select.data('select-id', null).removeClass('initialized'); - return; + // Reset the select with no selected status + function resetSelect(_this) { + if (_this.prop.multiple) { + Array.prototype.forEach.call(_this.elements.checkboxes, function(element) { + element.checked = false; + }); + } else { + Array.prototype.forEach.call(_this.elements.radio, function(element) { + element.checked = false; + }); } - var uniqueID = Materialize.guid(); - $select.data('select-id', uniqueID); - var wrapper = $('
'); - wrapper.addClass($select.attr('class')); - var options = $(''), - selectChildren = $select.children('option, optgroup'), - valuesSelected = [], - optionsHover = false; - - var label = $select.find('option:selected').html() || $select.find('option:first').html() || ""; - - // Function that renders and appends the option taking into - // account type and possible image icon. - var appendOptionWithIcon = function(select, option, type) { - // Add disabled attr if disabled - var disabledClass = (option.is(':disabled')) ? 'disabled ' : ''; - - // add icons - var icon_url = option.data('icon'); - var classes = option.attr('class'); - if (!!icon_url) { - var classString = ''; - if (!!classes) classString = ' class="' + classes + '"'; - - // Check for multiple type. - if (type === 'multiple') { - options.append($('
  • ' + option.html() + '
  • ')); - } else { - options.append($('
  • ' + option.html() + '
  • ')); - } - return true; - } + Array.prototype.forEach.call(_this.elements.li, function(element) { + element.classList.remove('active'); + }); + } - // Check for multiple type. - if (type === 'multiple') { - options.append($('
  • ' + option.html() + '
  • ')); - } else { - options.append($('
  • ' + option.html() + '
  • ')); + // Make option as active or selected and scroll to its position + function activateOption(collection, newOption) { + if (newOption) { + // Remove selected class from previous selected element + var selected = collection.querySelector('li.selected'); + + if (selected) { + selected.classList.remove('selected'); } - }; - /* Create dropdown structure. */ - if (selectChildren.length) { - selectChildren.each(function() { - if ($(this).is('option')) { - // Direct descendant option. - if (multiple) { - appendOptionWithIcon($select, $(this), 'multiple'); + newOption.classList.add('selected'); + $(collection).scrollTo(newOption); + } + } - } else { - appendOptionWithIcon($select, $(this)); + /* Create a new select with his own data + * + * Select Constructor + * + */ + function CreateSelect(select) { + var _this = {}; + + // Reference for class and optgroup and multiple attributes + _this.prop = (function() { + var self = {}; + self.id = Materialize.guid(); + self.className = select.className; + self.optgroup = select.querySelector('optgroup') ? true : false; + self.multiple = select.getAttribute('multiple') !== null ? true : false; + self.hover = false; + self.elements = select.querySelectorAll('*'), + self.isSelectedOption = function() { + var selectedOption = select.options[_this.elements.select.selectedIndex] ? true : false; + + return selectedOption; + }, + self.selected = function() { + var list = [], + option; + + for (var i = 0, countOptions = _this.elements.select.options.length; i < countOptions; i++) { + option = _this.elements.select.options[i]; + + if (option.selected) { + list.push(option); + } } - } else if ($(this).is('optgroup')) { - // Optgroup. - var selectOptions = $(this).children('option'); - options.append($('
  • ' + $(this).attr('label') + '
  • ')); - - selectOptions.each(function() { - appendOptionWithIcon($select, $(this)); - }); + + return list; + }; + + return self; + })(); + _this.elements = {}; + + // Refer the select + _this.elements.select = select; + _this.elements.select.dataset.id = _this.prop.id; + // Add trigger for change event + $(_this.elements.select).on('update', function() { + updateSelect(_this); + }); + + // Create the caret + _this.elements.caret = document.createElement('span'); + _this.elements.caret.className = 'caret'; + _this.elements.caret.innerHTML = '▼'; + + // Create the dropdown + _this.elements.dropdown = document.createElement('ul'); + _this.elements.dropdown.id = 'select-options-' + _this.prop.id; + // Refer the select id as data-id + if (_this.elements.select.id) { + _this.elements.dropdown.dataset.id = _this.elements.select.id; + } + _this.elements.dropdown.className = 'dropdown-content select-dropdown'; + // Add event + $(_this.elements.dropdown).hover(function() { + _this.prop.hover = true; + }, function() { + _this.prop.hover = false; + }); + + // Create the wrapper + _this.elements.wrapper = document.createElement('div'); + _this.elements.wrapper.className = _this.prop.className; + _this.elements.wrapper.classList.add('select-wrapper'); + + // Create the input + _this.elements.input = document.createElement('input'); + _this.elements.input.type = 'text'; + _this.elements.input.className = 'select-dropdown'; + _this.elements.input.setAttribute('readonly', true); + _this.elements.input.dataset.activates = 'select-options-' + _this.prop.id; + if (_this.elements.select.dataset.maxlength) { + _this.elements.input.dataset.maxlength = _this.elements.select.dataset.maxlength; + } + // Add events + $(_this.elements.input).on({ + 'focus': function() { + if ($('ul.select-dropdown').not(_this.elements.dropdown).is(':visible')) { + $('input.select-dropdown').trigger('close'); } - }); + + if (!$(_this.elements.dropdown).is(':visible')) { + $(_this.elements.input).trigger('open', ['focus']); + } + }, + 'click': function(e) { + e.stopPropagation(); + }, + 'blur': function() { + if (!_this.prop.multiple) { + $(_this.elements.input).trigger('close'); + } + } + }); + + $(window).on({ + 'click': function() { + _this.prop.multiple && (_this.prop.hover || $(_this.elements.input).trigger('close')); + } + }); + + // Copy tabindex + if (_this.elements.select.getAttribute('tabindex')) { + _this.elements.input.setAttribute('tabindex', _this.elements.select.getAttribute('tabindex')); } - options.find('li:not(.optgroup)').each(function (i) { - $(this).click(function (e) { - // Check if option element is disabled - if (!$(this).hasClass('disabled') && !$(this).hasClass('optgroup')) { - var selected = true; + // Set the onkeydown function + _this.filterQuery = []; - if (multiple) { - $('input[type="checkbox"]', this).prop('checked', function(i, v) { return !v; }); - selected = toggleEntryFromArray(valuesSelected, $(this).index(), $select); - $newSelect.trigger('focus'); - } else { - options.find('li').removeClass('active'); - $(this).toggleClass('active'); - $newSelect.val($(this).text()); + function onKeyDown(e) { + var code = e.keyCode || e.which; + + // TAB - switch to another input + if (code === 9) { + $(_this.elements.input).trigger('close'); + + return; + } + + // ARROW DOWN WHEN SELECT IS CLOSED - open select dropdown + if (code === 40 && _this.elements.dropdown.offsetParent === null) { + $(_this.elements.input).trigger('open'); + + return; + } + + // ENTER WHEN SELECT IS CLOSED - submit form + if (code === 13 && _this.elements.dropdown.offsetParent === null) { + return; + } + + e.preventDefault(); + + // CASE WHEN USER TYPE LETTERS + var letter = String.fromCharCode(code).toLowerCase(), + nonLetters = [9, 13, 27, 38, 40], + selectedOption; + + if (letter && (nonLetters.indexOf(code) === -1)) { + _this.filterQuery.push(letter); + + var array = [], + options = _this.elements.dropdown.querySelectorAll('li'); + + Array.prototype.forEach.call(options, function(option) { + array.push(option); + }); + + var string = _this.filterQuery.join(''), + newOption = array.filter(function(option) { + return option.textContent.toLowerCase().indexOf(string) === 0; + })[0]; + + if (newOption) { + activateOption(_this.elements.dropdown, newOption); + } + } + + // ENTER - select option and close when select dropdown are opened + if (code === 13) { + var activeOption = _this.elements.dropdown.querySelector('li.selected:not(.disabled)'); + + if (activeOption) { + $(activeOption).trigger('click'); + + if (!_this.prop.multiple) { + $(_this.elements.input).trigger('close'); } + } + } - activateOption(options, $(this)); - $select.find('option').eq(i).prop('selected', selected); - // Trigger onchange() event - $select.trigger('change'); - if (typeof callback !== 'undefined') callback(); + if (code === 40) { + selectedOption = _this.elements.dropdown.querySelector('li.selected'); + + if (selectedOption) { + newOption = _this.elements.dropdown.querySelector('li.selected').nextSibling; + } else { + newOption = _this.elements.dropdown.querySelector('li:not(.disabled)'); } - e.stopPropagation(); - }); - }); + activateOption(_this.elements.dropdown, newOption); + } - // Wrap Elements - $select.wrap(wrapper); - // Add Select Display Element - var dropdownIcon = $(''); - if ($select.is(':disabled')) - dropdownIcon.addClass('disabled'); + // ESC - close dropdown + if (code === 27) { + $(_this.elements.input).trigger('close'); + } - // escape double quotes - var sanitizedLabelHtml = label.replace(/"/g, '"'); + // ARROW UP - move to previous not disabled option + if (code === 38) { + selectedOption = _this.elements.dropdown.querySelector('li.selected'); - var $newSelect = $(''); - $select.before($newSelect); - $newSelect.before(dropdownIcon); + if (selectedOption) { + newOption = selectedOption.previousSibling; + activateOption(_this.elements.dropdown, newOption); + } + } - $newSelect.after(options); - // Check if section element is disabled - if (!$select.is(':disabled')) { - $newSelect.dropdown({'hover': false, 'closeOnClick': false}); + // Automatically clean filter query so user can search again by starting letters + setTimeout(function() { + _this.filterQuery.length = 0; + }, 1000); } - // Copy tabindex - if ($select.attr('tabindex')) { - $($newSelect[0]).attr('tabindex', $select.attr('tabindex')); + // Add event + $(_this.elements.input).on('keydown', onKeyDown); + + // Fill the dropdown + Array.prototype.forEach.call(_this.prop.elements, function(element) { + prepareElement(element, _this); + }); + + // Refer all the checkboxes and list option previously created + if (_this.prop.multiple) { + _this.elements.checkboxes = _this.elements.dropdown.querySelectorAll('input[type="checkbox"]'); + } else { + _this.elements.radio = _this.elements.dropdown.querySelectorAll('input[type="radio"]'); } + _this.elements.li = _this.elements.dropdown.querySelectorAll('li'); + + _this.elements.wrapper.appendChild(_this.elements.caret); + _this.elements.wrapper.appendChild(_this.elements.input); + _this.elements.wrapper.appendChild(_this.elements.dropdown); + // Append the wrapper into the select parent + _this.elements.select.parentNode.insertBefore(_this.elements.wrapper, _this.elements.select.parentNode.firstChild); + // Move the parent into the wrapper + _this.elements.wrapper.appendChild(select); + // Initialized the select + _this.elements.select.classList.add('initialized'); + + // Check if preselected option are existing + if (_this.prop.isSelectedOption()) { + var selected = _this.prop.selected(); + + // Select all the selected option + Array.prototype.forEach.call(selected, function(option) { + // Select / deselect option + toggleSelectElement(option, _this, true); + }); + } else { + var disabledOption = _this.elements.select.querySelector('option:disabled'); - $select.addClass('initialized'); + // If no options are preselected, select the first disabled + if (disabledOption) { + var equivalent = equivalentItem(disabledOption, _this), + input = equivalent.querySelector('input[type="radio"]'); - $newSelect.on({ - 'focus': function (){ - if ($('ul.select-dropdown').not(options[0]).is(':visible')) { - $('input.select-dropdown').trigger('close'); - } - if (!options.is(':visible')) { - $(this).trigger('open', ['focus']); - var label = $(this).val(); - var selectedOption = options.find('li').filter(function() { - return $(this).text().toLowerCase() === label.toLowerCase(); - })[0]; - activateOption(options, selectedOption); + // We don't want checkbox because a disabled option isn't selected + if (input) { + input.checked = true; } - }, - 'click': function (e){ - e.stopPropagation(); + + // Fill the content input + fillContentInput([disabledOption], _this); } + } + + // Initialize the dropdown + $(_this.elements.input).dropdown({ + 'hover': false }); - $newSelect.on('blur', function() { - if (!multiple) { - $(this).trigger('close'); + return _this; + } + + // If all elements from parent are active so select it too + function selectParent(child, parent, _this) { + var siblings = (function() { + var self = {}; + self.all = getOptgroupElements(child.dataset.optgroup, _this); + self.selected = []; + + return self; + })(), + option = { + equivalent: parent, + input: parent.querySelector('input[type="checkbox"]'), + }; + + // For each siblings we check if they're active + for (var i = 0, countSiblings = siblings.all.length; i < countSiblings; i++) { + siblings.all[i].selected ? siblings.selected.push(true) : siblings.selected.push(false); + } + + // If all siblings are selected select parent + if (siblings.selected.indexOf(false) === -1) { + selectElement(option); + } else { + deselectElement(option); + } + } + + // Returns the equivalent item to the element passed as parameter (li, option, optgroup) + function equivalentItem(element, _this) { + var tagName = element.tagName, + item; + + switch (tagName) { + case 'LI': + item = _this.elements.select.querySelector('option[value="' + element.dataset.value + '"]'); + + break; + case 'OPTION': + item = _this.elements.dropdown.querySelector('li[data-value="' + element.value + '"]'); + + break; + case 'OPTGROUP': + item = _this.elements.dropdown.querySelector('li[data-value="' + element.label + '"]'); + + break; + default: + console.log('Error. Please open an issue at Materialize.'); + + break; + } + + return item; + } + + // Select an option and element + function selectElement(option) { + if (option.element) { + option.element.selected = true; + } + + option.equivalent.classList.add('active'); + option.input.checked = true; + } + + // Deselect an option and element + function deselectElement(option) { + if (option.element) { + option.element.selected = false; + } + + option.equivalent.classList.remove('active'); + option.input.checked = false; + } + + // Select an element + function toggleSelectElement(element, _this, onload) { + var option = {}; + + // If element is LI reverse the attributions + if (isTagName('LI', element)) { + option.element = equivalentItem(element, _this); + + if (!option.element) { + return; } - options.find('li.selected').removeClass('selected'); - }); - options.hover(function() { - optionsHover = true; - }, function () { - optionsHover = false; - }); + option.equivalent = element; + option.parent = option.element.parentNode; + } - $(window).on({ - 'click': function () { - multiple && (optionsHover || $newSelect.trigger('close')); + // Fill the object which contains all its data + option = (function() { + option.element = option.element || element; + option.equivalent = option.equivalent || equivalentItem(element, _this); + option.input = option.equivalent.querySelector('input'); + option.selected = option.element.selected; + option.parent = option.parent || option.element.parentNode; + + return option; + })(); + + // Return if there is no findable li or if the option is already selected for single select + if (!option.equivalent || (!_this.prop.multiple && option.equivalent.classList.contains('active'))) { + return; + } + + // If select is single + if (!_this.prop.multiple && !onload) { + var oldSelectedOption = _this.prop.selected()[0], + oldSelectedElement = equivalentItem(oldSelectedOption, _this); + + // Fill an object relative to the old selected option + var oldOption = (function() { + var self = {}; + self.element = oldSelectedOption, + self.equivalent = oldSelectedElement, + self.input = self.equivalent.querySelector('input'); + + return self; + })(); + + deselectElement(oldOption); + } + + // Deselect options here + if (option.selected && !onload) { + deselectElement(option); + // Select options here + } else { + selectElement(option); + } + + // Select parent if all its children are selected + if (_this.prop.optgroup && _this.prop.multiple && isTagName('OPTGROUP', option.parent)) { + var parent = equivalentItem(option.parent, _this); + + // Verification of existing parent + if (parent) { + selectParent(option.equivalent, parent, _this); } - }); + } - // Add initial multiple selections. - if (multiple) { - $select.find("option:selected:not(:disabled)").each(function () { - var index = $(this).index(); + // Fill the input value with new values + fillContentInput(_this.prop.selected(), _this); + } - toggleEntryFromArray(valuesSelected, index, $select); - options.find("li").eq(index).find(":checkbox").prop("checked", true); + // Toggle select all li relative to an optgroup li + function toggleSelectAllElements(optgroup, _this) { + var status = optgroup.classList.contains('active'), + allChildren = getOptgroupElements(optgroup.dataset.value, _this), + matches; + + if (status) { + // Filter for every optgroup's option is active and isn't disabled + matches = Array.prototype.slice.call(allChildren).filter(function(element) { + return element.selected && !element.disabled; + }); + } else { + // Filter for every optgroup's option isn't active and isn't disabled + matches = Array.prototype.slice.call(allChildren).filter(function(element) { + return !element.selected && !element.disabled; }); } - // Make option as selected and scroll to selected position - var activateOption = function(collection, newOption) { - if (newOption) { - collection.find('li.selected').removeClass('selected'); - var option = $(newOption); - option.addClass('selected'); - options.scrollTo(option); - } + // Toggle all options stored + Array.prototype.forEach.call(matches, function(li) { + toggleSelectElement(li, _this); + }); + } + + // Prepare element by passing relative values to it + function prepareElement(element, _this) { + // Check if element is optgroup + isTagName('OPTGROUP', element) ? CreateElement(element, _this, true) : CreateElement(element, _this, false); + } + + /* Create a new option with the correct params + * + * Li Constructor + * + */ + function CreateElement(element, _this, optgroup) { + var options = { + iconUrl: element.dataset.icon, + imageClasses: element.className, + text: element.getAttribute('label') || element.textContent, + dataValue: element.getAttribute('label') || element.value, + disabled: element.disabled || element.parentNode.disabled }; - // Allow user to search by typing - // this array is cleared after 1 second - var filterQuery = [], - onKeyDown = function(e){ - // TAB - switch to another input - if(e.which == 9){ - $newSelect.trigger('close'); - return; - } + _this.elements.dropdown.appendChild(createLiElement()); - // ARROW DOWN WHEN SELECT IS CLOSED - open select options - if(e.which == 40 && !options.is(':visible')){ - $newSelect.trigger('open'); - return; - } + function createLiElement() { + var liElement = document.createElement('li'), + spanElement = document.createElement('span'); - // ENTER WHEN SELECT IS CLOSED - submit form - if(e.which == 13 && !options.is(':visible')){ - return; - } + // Add icon url if exists + if (options.iconUrl) { + var image = document.createElement('img'); + image.src = options.iconUrl; + image.className = options.imageClasses; - e.preventDefault(); + liElement.appendChild(image); + } - // CASE WHEN USER TYPE LETTERS - var letter = String.fromCharCode(e.which).toLowerCase(), - nonLetters = [9,13,27,38,40]; - if (letter && (nonLetters.indexOf(e.which) === -1)) { - filterQuery.push(letter); + var label = document.createElement('label'), + input; - var string = filterQuery.join(''), - newOption = options.find('li').filter(function() { - return $(this).text().toLowerCase().indexOf(string) === 0; - })[0]; + // Refer the optgroup parent for each option that isn't an optgroup + if (_this.prop.optgroup && !optgroup) { + var parent = element.parentNode; - if (newOption) { - activateOption(options, newOption); - } - } + // Refer the label as data-label if the optgroup has a label + if (isTagName('OPTGROUP', parent) && parent.label) { + liElement.dataset.optgroup = parent.label; + } + } - // ENTER - select option and close when select options are opened - if (e.which == 13) { - var activeOption = options.find('li.selected:not(.disabled)')[0]; - if(activeOption){ - $(activeOption).trigger('click'); - if (!multiple) { - $newSelect.trigger('close'); - } - } - } + // Create input and label + if (_this.prop.multiple) { + input = document.createElement('input'); + input.type = 'checkbox'; + + spanElement.appendChild(input); + spanElement.appendChild(label); + } else { + input = document.createElement('input'); + input.type = 'radio'; + + spanElement.appendChild(input); + spanElement.appendChild(label); + } + + // Set span content + spanElement.innerHTML += options.text.replace(/"/g, '"').trim(); + + // Verify the current element isn't disabled before applying class + // Set datavalue for the current element + element.id ? liElement.dataset.id = element.id : ''; + liElement.className += optgroup ? 'optgroup' : ''; + options.disabled ? liElement.classList.add('disabled') : ''; + liElement.dataset.value = options.dataValue; + + // Add event handler + $(liElement).on('click', function() { + // Return if element is disabled + if (liElement.classList.contains('disabled')) { + return; + } - // ARROW DOWN - move to next not disabled option - if (e.which == 40) { - if (options.find('li.selected').length) { - newOption = options.find('li.selected').next('li:not(.disabled)')[0]; - } else { - newOption = options.find('li:not(.disabled)')[0]; + if (_this.prop.multiple) { + if (optgroup) { + // Avoid multiple selection by clicking on a optgroup which have disabled option + var disabledElements = getOptgroupElements(liElement.dataset.value, _this); + disabledElements = Array.prototype.slice.call(disabledElements).filter(function(element) { + return element.classList.contains('disabled'); + }); + + // Avoid clicking if the element is disabled + if (liElement.classList.contains('disabled') || disabledElements.length) { + return; } - activateOption(options, newOption); - } - // ESC - close options - if (e.which == 27) { - $newSelect.trigger('close'); + // Select all children relative to the optgroup clicked + toggleSelectAllElements(liElement, _this); + } else { + toggleSelectElement(liElement, _this); } - - // ARROW UP - move to previous not disabled option - if (e.which == 38) { - newOption = options.find('li.selected').prev('li:not(.disabled)')[0]; - if(newOption) - activateOption(options, newOption); + } else { + // Return if element is optgroup for single select + if (liElement.classList.contains('optgroup')) { + return; } - // Automaticaly clean filter query so user can search again by starting letters - setTimeout(function(){ filterQuery = []; }, 1000); - }; + toggleSelectElement(liElement, _this); + } - $newSelect.on('keydown', onKeyDown); - }); + // Scroll to the option + $(_this.elements.dropdown).scrollTo(liElement); + }); - function toggleEntryFromArray(entriesArray, entryIndex, select) { - var index = entriesArray.indexOf(entryIndex), - notAdded = index === -1; + liElement.appendChild(spanElement); - if (notAdded) { - entriesArray.push(entryIndex); - } else { - entriesArray.splice(index, 1); + return liElement; } - - select.siblings('ul.dropdown-content').find('li').eq(entryIndex).toggleClass('active'); - - // use notAdded instead of true (to detect if the option is selected or not) - select.find('option').eq(entryIndex).prop('selected', notAdded); - setValueToInput(entriesArray, select); - - return notAdded; } - function setValueToInput(entriesArray, select) { - var value = ''; + Array.prototype.forEach.call(this, function(selectElement) { + var initialized = selectElement.classList.contains('initialized'); - for (var i = 0, count = entriesArray.length; i < count; i++) { - var text = select.find('option').eq(entriesArray[i]).text(); + // Destroy callback + if ('destroy' === callback && initialized) { + destroySelect(selectElement); - i === 0 ? value += text : value += ', ' + text; + return; } - if (value === '') { - value = select.find('option:disabled').eq(0).text(); + // Return if user choose to apply a native select or select is disabled or initialized or if select isn't filled + if (selectElement.classList.contains('browser-default') || initialized || selectElement.disabled || !selectElement.options.length) { + return; // Continue to the next select } - select.siblings('input.select-dropdown').val(value); - } + // Initialize the select + var Select = CreateSelect(selectElement); + }); + + // For not breaking jQuery chaining return a jQuery element + return $(this); }; }( jQuery )); diff --git a/sass/components/_dropdown.scss b/sass/components/_dropdown.scss index 71ab9f5528..e89f0c6f5a 100644 --- a/sass/components/_dropdown.scss +++ b/sass/components/_dropdown.scss @@ -42,7 +42,7 @@ padding: (($dropdown-item-height - 22) / 2) 16px; } - & > span > label { + & > span > label, & > span > input[type="radio"] + label, & > span > input[type="checkbox"] + label { top: 1px; left: 3px; height: 18px; diff --git a/sass/components/_form.scss b/sass/components/_form.scss index 1b1da0fa35..9aea491c94 100644 --- a/sass/components/_form.scss +++ b/sass/components/_form.scss @@ -688,14 +688,6 @@ input[type=checkbox]:not(:disabled) ~ .lever:active:after { } } -select { display: none; } -select.browser-default { display: block; } - -// Disabled styles -select:disabled { - color: rgba(0,0,0,.3); -} - .select-wrapper input.select-dropdown:disabled { color: rgba(0,0,0,.3); cursor: default; @@ -709,11 +701,24 @@ select:disabled { color: rgba(0,0,0,.3); } -.select-dropdown li.disabled, -.select-dropdown li.disabled > span, -.select-dropdown li.optgroup { - color: rgba(0,0,0,.3); - background-color: transparent; +.select-dropdown li { + &.disabled, &.disabled > span, &.optgroup { + color: rgba(0,0,0,.3); + background-color: transparent; + } + + &.disabled { + cursor: not-allowed; + + &.selected { + background-color: rgba(0, 0, 0, 0.05); + } + + [type="checkbox"]:checked + label:before, [type="checkbox"]:checked:not(.filled-in) + label:after { + border-right: 2px solid rgba(0, 0, 0, 0.3); + border-bottom: 2px solid rgba(0, 0, 0, 0.3); + } + } } // Icons @@ -728,19 +733,16 @@ select:disabled { // Optgroup styles .select-dropdown li.optgroup { + background-color: rgba(0, 0, 0, 0.02); border-top: 1px solid $dropdown-hover-bg-color; - &.selected > span { - color: rgba(0, 0, 0, .7); + &.selected, .active { + background-color: rgba(0, 0, 0, 0.1); } & > span { color: rgba(0, 0, 0, .4); } - - & ~ li:not(.optgroup) { - padding-left: 1rem; - } } /********************* @@ -952,4 +954,14 @@ select { border: 1px solid #f2f2f2; border-radius: 2px; height: 3rem; + display: none; + + &.browser-default { + display: block; + } + + // Disabled styles + &:disabled { + color: rgba(0,0,0,.3); + } } From afea5f9df5f8a0f48948a39e824497dd7622b346 Mon Sep 17 00:00:00 2001 From: TyrionGraphiste Date: Sun, 17 Jan 2016 13:52:16 +0100 Subject: [PATCH 2/6] CSS oversights. --- sass/components/_form.scss | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sass/components/_form.scss b/sass/components/_form.scss index 9aea491c94..f6a9194fcf 100644 --- a/sass/components/_form.scss +++ b/sass/components/_form.scss @@ -715,14 +715,18 @@ input[type=checkbox]:not(:disabled) ~ .lever:active:after { } [type="checkbox"]:checked + label:before, [type="checkbox"]:checked:not(.filled-in) + label:after { - border-right: 2px solid rgba(0, 0, 0, 0.3); - border-bottom: 2px solid rgba(0, 0, 0, 0.3); + border-right: 2px solid rgba(0, 0, 0, .3); + border-bottom: 2px solid rgba(0, 0, 0, .3); } } } // Icons .select-dropdown li { + &[data-optgroup] { + padding-left: 1rem; + } + img { height: $dropdown-item-height - 10; width: $dropdown-item-height - 10; @@ -733,15 +737,15 @@ input[type=checkbox]:not(:disabled) ~ .lever:active:after { // Optgroup styles .select-dropdown li.optgroup { - background-color: rgba(0, 0, 0, 0.02); + background-color: rgba(0, 0, 0, .02); border-top: 1px solid $dropdown-hover-bg-color; &.selected, .active { - background-color: rgba(0, 0, 0, 0.1); + background-color: rgba(0, 0, 0, .1); } & > span { - color: rgba(0, 0, 0, .4); + color: rgba(0, 0, 0, .7); } } From f9b040cd1f4ae5e210e5de074fa1f823e6e8b075 Mon Sep 17 00:00:00 2001 From: TyrionGraphiste Date: Mon, 18 Jan 2016 17:51:38 +0100 Subject: [PATCH 3/6] Add options for select. --- js/dropdown.js | 394 ++++++++++++++++++++++++++----------------------- js/forms.js | 36 +++-- 2 files changed, 238 insertions(+), 192 deletions(-) diff --git a/js/dropdown.js b/js/dropdown.js index a5fc1e9be4..ab14a16590 100644 --- a/js/dropdown.js +++ b/js/dropdown.js @@ -7,7 +7,7 @@ return this; }; - $.fn.dropdown = function (option) { + $.fn.dropdown = function(option) { var defaults = { inDuration: 300, outDuration: 225, @@ -15,219 +15,249 @@ hover: false, gutter: 0, // Spacing from edge belowOrigin: false, - alignment: 'left' + alignment: 'left', + maxWidth: null, + maxHeight: null, + arrangement: 'bottom' }; - this.each(function(){ - var origin = $(this); - var options = $.extend({}, defaults, option); - var isFocused = false; - - // Dropdown menu - var activates = $("#"+ origin.attr('data-activates')); - - function updateOptions() { - if (origin.data('induration') !== undefined) - options.inDuration = origin.data('inDuration'); - if (origin.data('outduration') !== undefined) - options.outDuration = origin.data('outDuration'); - if (origin.data('constrainwidth') !== undefined) - options.constrain_width = origin.data('constrainwidth'); - if (origin.data('hover') !== undefined) - options.hover = origin.data('hover'); - if (origin.data('gutter') !== undefined) - options.gutter = origin.data('gutter'); - if (origin.data('beloworigin') !== undefined) - options.belowOrigin = origin.data('beloworigin'); - if (origin.data('alignment') !== undefined) - options.alignment = origin.data('alignment'); - } - - updateOptions(); - - // Attach dropdown to its activator - origin.after(activates); - - /* - Helper function to position and resize dropdown. - Used in hover and click handler. - */ - function placeDropdown(eventType) { - // Check for simultaneous focus and click events. - if (eventType === 'focus') { - isFocused = true; + this.each(function() { + var origin = $(this); + var options = $.extend({}, defaults, option); + var isFocused = false; + + // Dropdown menu + var activates = $("#" + origin.attr('data-activates')); + + function updateOptions() { + if (origin.data('induration') !== undefined) + options.inDuration = origin.data('inDuration'); + if (origin.data('outduration') !== undefined) + options.outDuration = origin.data('outDuration'); + if (origin.data('constrainwidth') !== undefined) + options.constrain_width = origin.data('constrainwidth'); + if (origin.data('hover') !== undefined) + options.hover = origin.data('hover'); + if (origin.data('gutter') !== undefined) + options.gutter = origin.data('gutter'); + if (origin.data('beloworigin') !== undefined) + options.belowOrigin = origin.data('beloworigin'); + if (origin.data('alignment') !== undefined) + options.alignment = origin.data('alignment'); + if (origin.data('maxWidth') !== undefined) + options.maxWidth = origin.data('maxWidth'); + if (origin.data('maxHeight') !== undefined) + options.maxHeight = origin.data('maxHeight'); + if (origin.data('arrangement') !== undefined) + options.arrangement = origin.data('arrangement'); } - // Check html data attributes updateOptions(); - // Set Dropdown state - activates.addClass('active'); - origin.addClass('active'); + // Attach dropdown to its activator + origin.after(activates); - // Constrain width - if (options.constrain_width === true) { - activates.css('width', origin.outerWidth()); + /* + Helper function to position and resize dropdown. + Used in hover and click handler. + */ + function placeDropdown(eventType) { + // Check for simultaneous focus and click events. + if (eventType === 'focus') { + isFocused = true; + } - } else { - activates.css('white-space', 'nowrap'); - } + // Check html data attributes + updateOptions(); - // Offscreen detection - var windowHeight = window.innerHeight; - var originHeight = origin.innerHeight(); - var offsetLeft = origin.offset().left; - var offsetTop = origin.offset().top - $(window).scrollTop(); - var currAlignment = options.alignment; - var activatesLeft, gutterSpacing; - - // Below Origin - var verticalOffset = 0; - if (options.belowOrigin === true) { - verticalOffset = originHeight; - } + // Set Dropdown state + activates.addClass('active'); + origin.addClass('active'); - // Check for scrolling positioned container. - var scrollOffset = 0; - var wrapper = origin.parent(); - if (!wrapper.is('body') && wrapper[0].scrollHeight > wrapper[0].clientHeight) { - scrollOffset = wrapper[0].scrollTop; - } + // Constrain width + if (options.constrain_width) { + activates.css('width', origin.outerWidth()); + } else { + activates.css('white-space', 'nowrap'); + } - if (offsetLeft + activates.innerWidth() > $(window).width()) { - // Dropdown goes past screen on right, force right alignment - currAlignment = 'right'; + if (options.maxWidth) { + activates.css('max-width', options.maxWidth); + } - } else if (offsetLeft - activates.innerWidth() + origin.innerWidth() < 0) { - // Dropdown goes past screen on left, force left alignment - currAlignment = 'left'; - } - // Vertical bottom offscreen detection - if (offsetTop + activates.innerHeight() > windowHeight) { - // If going upwards still goes offscreen, just crop height of dropdown. - if (offsetTop + originHeight - activates.innerHeight() < 0) { - var adjustedHeight = windowHeight - offsetTop - verticalOffset; - activates.css('max-height', adjustedHeight); - } else { - // Flow upwards. - if (!verticalOffset) { - verticalOffset += originHeight; - } - verticalOffset -= activates.innerHeight(); + if (options.maxHeight) { + activates.css('max-height', options.maxHeight); } - } - // Handle edge alignment - if (currAlignment === 'left') { - gutterSpacing = options.gutter; - leftPosition = origin.position().left + gutterSpacing; - } - else if (currAlignment === 'right') { - var offsetRight = origin.position().left + origin.outerWidth() - activates.outerWidth(); - gutterSpacing = -options.gutter; - leftPosition = offsetRight + gutterSpacing; - } + // Offscreen detection + var windowHeight = window.innerHeight; + var originHeight = origin.innerHeight(); + var offsetLeft = origin.offset().left; + var offsetTop = origin.offset().top - $(window).scrollTop(); + var currAlignment = options.alignment; + var gutterSpacing; - // Position dropdown - activates.css({ - position: 'absolute', - top: origin.position().top + verticalOffset + scrollOffset, - left: leftPosition - }); + // Below Origin + var verticalOffset = 0; + if (options.belowOrigin) { + verticalOffset = originHeight; + } + if (offsetLeft + activates.innerWidth() > $(window).width()) { + // Dropdown goes past screen on right, force right alignment + currAlignment = 'right'; - // Show dropdown - activates.stop(true, true).css('opacity', 0) - .slideDown({ - queue: false, - duration: options.inDuration, - easing: 'easeOutCubic', - complete: function() { - $(this).css('height', ''); + } else if (offsetLeft - activates.innerWidth() + origin.innerWidth() < 0) { + // Dropdown goes past screen on left, force left alignment + currAlignment = 'left'; } - }) - .animate( {opacity: 1}, {queue: false, duration: options.inDuration, easing: 'easeOutSine'}); - } - - function hideDropdown() { - // Check for simultaneous focus and click events. - isFocused = false; - activates.fadeOut(options.outDuration); - activates.removeClass('active'); - origin.removeClass('active'); - setTimeout(function() { activates.css('max-height', ''); }, options.outDuration); - } - - // Hover - if (options.hover) { - var open = false; - origin.unbind('click.' + origin.attr('id')); - // Hover handler to show dropdown - origin.on('mouseenter', function(e){ // Mouse over - if (open === false) { - placeDropdown(); - open = true; + + // Vertical bottom offscreen detection + if (offsetTop + activates.innerHeight() > windowHeight) { + // If going upwards still goes offscreen, just crop height of dropdown. + if (offsetTop + originHeight - activates.innerHeight() < 0) { + var adjustedHeight = windowHeight - offsetTop - verticalOffset; + activates.css('max-height', adjustedHeight); + } else { + // Flow upwards. + if (!verticalOffset) { + verticalOffset += originHeight; + } + verticalOffset -= activates.innerHeight(); + } } - }); - origin.on('mouseleave', function(e){ - // If hover on origin then to something other than dropdown content, then close - var toEl = e.toElement || e.relatedTarget; // added browser compatibility for target element - if(!$(toEl).closest('.dropdown-content').is(activates)) { - activates.stop(true, true); - hideDropdown(); - open = false; + + if (options.arrangement === 'top') { + if (options.maxHeight) { + if (activates.height() < options.maxHeight) { + verticalOffset = -activates.height() + originHeight; + } else { + verticalOffset = -options.maxHeight + originHeight; + } + } else { + verticalOffset = -activates.height() + originHeight; + } } - }); - activates.on('mouseleave', function(e){ // Mouse out - var toEl = e.toElement || e.relatedTarget; - if(!$(toEl).closest('.dropdown-button').is(origin)) { - activates.stop(true, true); - hideDropdown(); - open = false; + // Handle edge alignment + if (currAlignment === 'left') { + gutterSpacing = options.gutter; + leftPosition = origin.position().left + gutterSpacing; + } else if (currAlignment === 'right') { + var offsetRight = origin.position().left + origin.outerWidth() - activates.outerWidth(); + gutterSpacing = -options.gutter; + leftPosition = offsetRight + gutterSpacing; } - }); - // Click - } else { - // Click handler to show dropdown - origin.unbind('click.' + origin.attr('id')); - origin.bind('click.'+origin.attr('id'), function(e){ - if (!isFocused) { - if ( origin[0] == e.currentTarget && - !origin.hasClass('active') && - ($(e.target).closest('.dropdown-content').length === 0)) { - e.preventDefault(); // Prevents button click from moving window - placeDropdown('click'); + // Position dropdown + activates.css({ + position: 'absolute', + top: origin.position().top + verticalOffset, + left: leftPosition + }); + + // Show dropdown + activates.stop(true, true).css('opacity', 0) + .slideDown({ + queue: false, + duration: options.inDuration, + easing: 'easeOutCubic', + complete: function() { + $(this).css('height', ''); + } + }) + .animate({ + opacity: 1 + }, { + queue: false, + duration: options.inDuration, + easing: 'easeOutSine' + }); + } + + function hideDropdown() { + // Check for simultaneous focus and click events. + isFocused = false; + activates.fadeOut(options.outDuration); + activates.removeClass('active'); + origin.removeClass('active'); + + if (!options.maxHeight) { + setTimeout(function() { + activates.css('max-height', ''); + }, options.outDuration); + } + } + + // Hover + if (options.hover) { + var open = false; + origin.unbind('click.' + origin.attr('id')); + // Hover handler to show dropdown + origin.on('mouseenter', function(e) { // Mouse over + if (open === false) { + placeDropdown(); + open = true; } - // If origin is clicked and menu is open, close menu - else if (origin.hasClass('active')) { + }); + origin.on('mouseleave', function(e) { + // If hover on origin then to something other than dropdown content, then close + var toEl = e.toElement || e.relatedTarget; // added browser compatibility for target element + if (!$(toEl).closest('.dropdown-content').is(activates)) { + activates.stop(true, true); hideDropdown(); - $(document).unbind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id')); + open = false; } - // If menu open, add click close handler to document - if (activates.hasClass('active')) { - $(document).bind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id'), function (e) { - if (!activates.is(e.target) && !origin.is(e.target) && (!origin.find(e.target).length) ) { - hideDropdown(); - $(document).unbind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id')); - } - }); + }); + + activates.on('mouseleave', function(e) { // Mouse out + var toEl = e.toElement || e.relatedTarget; + if (!$(toEl).closest('.dropdown-button').is(origin)) { + activates.stop(true, true); + hideDropdown(); + open = false; } - } - }); + }); - } // End else + // Click + } else { + // Click handler to show dropdown + origin.unbind('click.' + origin.attr('id')); + origin.bind('click.' + origin.attr('id'), function(e) { + if (!isFocused) { + if (origin[0] == e.currentTarget && + !origin.hasClass('active') && + ($(e.target).closest('.dropdown-content').length === 0)) { + e.preventDefault(); // Prevents button click from moving window + placeDropdown('click'); + } + // If origin is clicked and menu is open, close menu + else if (origin.hasClass('active')) { + hideDropdown(); + $(document).unbind('click.' + activates.attr('id') + ' touchstart.' + activates.attr('id')); + } + // If menu open, add click close handler to document + if (activates.hasClass('active')) { + $(document).bind('click.' + activates.attr('id') + ' touchstart.' + activates.attr('id'), function(e) { + if (!activates.is(e.target) && !origin.is(e.target) && (!origin.find(e.target).length)) { + hideDropdown(); + $(document).unbind('click.' + activates.attr('id') + ' touchstart.' + activates.attr('id')); + } + }); + } + } + }); - // Listen to open and close event - useful for select component - origin.on('open', function(e, eventType) { - placeDropdown(eventType); - }); - origin.on('close', hideDropdown); + } // End else + // Listen to open and close event - useful for select component + origin.on('open', function(e, eventType) { + placeDropdown(eventType); + }); + origin.on('close', hideDropdown); + }); - }); }; // End dropdown plugin $(document).ready(function(){ diff --git a/js/forms.js b/js/forms.js index 0783e04f11..9a279f8d32 100644 --- a/js/forms.js +++ b/js/forms.js @@ -378,7 +378,7 @@ * Select Constructor * */ - function CreateSelect(select) { + function CreateSelect(select, options) { var _this = {}; // Reference for class and optgroup and multiple attributes @@ -389,12 +389,12 @@ self.optgroup = select.querySelector('optgroup') ? true : false; self.multiple = select.getAttribute('multiple') !== null ? true : false; self.hover = false; - self.elements = select.querySelectorAll('*'), - self.isSelectedOption = function() { - var selectedOption = select.options[_this.elements.select.selectedIndex] ? true : false; + self.elements = select.querySelectorAll('*'); + self.isSelectedOption = function() { + var selectedOption = select.options[_this.elements.select.selectedIndex] ? true : false; - return selectedOption; - }, + return selectedOption; + }, self.selected = function() { var list = [], option; @@ -409,6 +409,7 @@ return list; }; + self.options = {}; return self; })(); @@ -639,10 +640,25 @@ } } + // Initialize options + if (options.hover !== undefined) { + _this.prop.options.hover = options.hover; + } + if (options.belowOrigin !== undefined) { + _this.prop.options.belowOrigin = options.belowOrigin; + } + if (options.maxHeight !== undefined) { + _this.prop.options.maxHeight = options.maxHeight; + } + if (options.maxWidth !== undefined) { + _this.prop.options.maxWidth = options.maxWidth; + } + if (options.arrangement !== undefined) { + _this.prop.options.arrangement = options.arrangement; + } + // Initialize the dropdown - $(_this.elements.input).dropdown({ - 'hover': false - }); + $(_this.elements.input).dropdown(_this.prop.options); return _this; } @@ -950,7 +966,7 @@ } // Initialize the select - var Select = CreateSelect(selectElement); + var Select = CreateSelect(selectElement, callback); }); // For not breaking jQuery chaining return a jQuery element From 488c1e08386abeae93fcdcb700ef892e2d6e95f1 Mon Sep 17 00:00:00 2001 From: TyrionGraphiste Date: Mon, 18 Jan 2016 18:28:36 +0100 Subject: [PATCH 4/6] Update the documentation. --- forms.html | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/forms.html b/forms.html index db52ca9217..c1f2b7f123 100644 --- a/forms.html +++ b/forms.html @@ -597,8 +597,16 @@

    Initialization

    -

    Updating/Destroying Select

    -

    If you want to update the items inside the select, just rerun the initialization code from above after editing the original select. Or you can destroy the material select with this function below, and create a new select altogether

    +

    Updating Select

    +

    You can update the material select by passing new values with this function below, in this case you don't need to use the destroying select function.

    +
    
    +  $('select').val([value1, value2]).trigger('update'); // for multiple select
    +  $('select').val(value).trigger('update'); // for single select
    +            
    +
    +
    +

    Destroying Select

    +

    Or you can destroy the material select with this function below, and create a new select altogether

    
       $('select').material_select('destroy');
                 
    @@ -606,6 +614,39 @@

    Updating/Destroying Select

    +
    +

    Options

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Option nameDescription
    hoverIf true, the dropdown will open on hover. Default: false
    beloworiginIf true, the dropdown will show below the activator. Default: false
    maxHeightDefines the max-height CSS property of the dropdown Default: null
    maxWidthDefines the max-width CSS property of the dropdown. Default: null
    arrangementDefines the direction of the opening menu (dropdown). Default: 'bottom'
    +

    Radio Buttons

    From 4b42ffa000f739876e241c2ebf4b676bcf22a636 Mon Sep 17 00:00:00 2001 From: TyrionGraphiste Date: Mon, 18 Jan 2016 18:31:44 +0100 Subject: [PATCH 5/6] Specify some details options. --- forms.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/forms.html b/forms.html index c1f2b7f123..5e305e93c2 100644 --- a/forms.html +++ b/forms.html @@ -626,23 +626,23 @@

    Options

    hover - If true, the dropdown will open on hover. Default: false + If true, the dropdown will open on hover. Default: false. Available: true. Typeof: boolean - beloworigin - If true, the dropdown will show below the activator. Default: false + belowOrigin + If true, the dropdown will show below the activator. Default: false. Available: true. Typeof: boolean maxHeight - Defines the max-height CSS property of the dropdown Default: null + Defines the max-height CSS property of the dropdown Default: null. Typeof: number (100) maxWidth - Defines the max-width CSS property of the dropdown. Default: null + Defines the max-width CSS property of the dropdown. Default: null. Typeof: number (100) arrangement - Defines the direction of the opening menu (dropdown). Default: 'bottom' + Defines the direction of the opening menu (dropdown). Default: 'bottom'. Available: 'bottom'. Typeof: string From 88c9706b186ea05f8126f8366ee8908cc0d0dd55 Mon Sep 17 00:00:00 2001 From: TyrionGraphiste Date: Mon, 18 Jan 2016 18:34:38 +0100 Subject: [PATCH 6/6] Update documentation with example. --- forms.html | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/forms.html b/forms.html index 5e305e93c2..52ab1caeec 100644 --- a/forms.html +++ b/forms.html @@ -593,6 +593,21 @@

    Initialization

    
       $(document).ready(function() {
         $('select').material_select();
    +  });
    +            
    +
    +
    +

    Initialization with options

    +

    You can initialize the select element with some options.

    +
    
    +  $(document).ready(function() {
    +    $('select').material_select({
    +      'hover': false,
    +      'belowOrigin': true,
    +      'maxWidth': 500, // width 500px
    +      'maxHeight': 200, // height 200px
    +      'arrangement': 'top' // Open the dropdown to top
    +    });
       });