Refactor rendering

This commit is contained in:
Josh Johnson 2016-05-10 09:02:59 +01:00
parent 7c4ec26479
commit 23ed4d9ecf
2 changed files with 32 additions and 39 deletions

File diff suppressed because one or more lines are too long

View file

@ -283,7 +283,6 @@ export class Choices {
if(nextEl) { if(nextEl) {
// We prevent default to stop the cursor moving // We prevent default to stop the cursor moving
// when pressing the arrow // when pressing the arrow
e.preventDefault();
if(!isScrolledIntoView(nextEl, this.dropdown, directionInt)) { if(!isScrolledIntoView(nextEl, this.dropdown, directionInt)) {
this.scrollToOption(nextEl, directionInt); this.scrollToOption(nextEl, directionInt);
} }
@ -317,6 +316,7 @@ export class Choices {
// We are typing into a text input and have a value, we want to show a dropdown // We are typing into a text input and have a value, we want to show a dropdown
// notice. Otherwise hide the dropdown // notice. Otherwise hide the dropdown
if(this.passedElement.type === 'text') { if(this.passedElement.type === 'text') {
const hasActiveDropdown = this.dropdown.classList.contains(this.options.classNames.activeState);
let dropdownItem; let dropdownItem;
if(this.input.value) { if(this.input.value) {
if (this.options.maxItems && this.options.maxItems <= this.list.children.length) { if (this.options.maxItems && this.options.maxItems <= this.list.children.length) {
@ -333,9 +333,7 @@ export class Choices {
} }
} else { } else {
if(this.dropdown.classList.contains(this.options.classNames.activeState)) { if(hasActiveDropdown) this.hideDropdown();
this.hideDropdown();
}
} }
} }
@ -382,14 +380,15 @@ export class Choices {
* @return * @return
*/ */
onMouseDown(e) { onMouseDown(e) {
const activeItems = this.store.getItemsFilteredByActive();
// If click is affecting a child node of our element // If click is affecting a child node of our element
if(this.containerOuter.contains(e.target)) { if(this.containerOuter.contains(e.target)) {
// Prevent blur event triggering causing dropdown to close // Prevent blur event triggering causing dropdown to close
// in a race condition // in a race condition
e.preventDefault(); e.preventDefault();
const activeItems = this.store.getItemsFilteredByActive();
const hasShiftKey = e.shiftKey ? true : false; const hasShiftKey = e.shiftKey ? true : false;
// If input is not in focus, it ought to be // If input is not in focus, it ought to be
@ -434,11 +433,10 @@ export class Choices {
} else { } else {
// Click is outside of our element so close dropdown and de-select items // Click is outside of our element so close dropdown and de-select items
const hasSelectedItems = activeItems.some((item) => item.selected === true);
const hasActiveDropdown = this.dropdown.classList.contains(this.options.classNames.activeState); const hasActiveDropdown = this.dropdown.classList.contains(this.options.classNames.activeState);
// Deselect items // Deselect items
if(hasSelectedItems) this.deselectAll(); this.deselectAll();
// Remove focus state // Remove focus state
this.containerOuter.classList.remove(this.options.classNames.focusState); this.containerOuter.classList.remove(this.options.classNames.focusState);
@ -518,6 +516,7 @@ export class Choices {
* @return {Boolean} Whether test passed/failed * @return {Boolean} Whether test passed/failed
*/ */
regexFilter(value) { regexFilter(value) {
if(!value) return;
const expression = new RegExp(this.options.regexFilter, 'i'); const expression = new RegExp(this.options.regexFilter, 'i');
return expression.test(value); return expression.test(value);
} }
@ -1048,6 +1047,8 @@ export class Choices {
} }
renderGroups(groups, options, fragment) { renderGroups(groups, options, fragment) {
const groupFragment = fragment || document.createDocumentFragment();
groups.forEach((group, i) => { groups.forEach((group, i) => {
// Grab options that are children of this group // Grab options that are children of this group
const groupOptions = options.filter((option) => { const groupOptions = options.filter((option) => {
@ -1061,32 +1062,30 @@ export class Choices {
if(groupOptions.length >= 1) { if(groupOptions.length >= 1) {
const dropdownGroup = this.getTemplate('optgroup', group); const dropdownGroup = this.getTemplate('optgroup', group);
groupOptions.forEach((option, j) => { groupFragment.appendChild(dropdownGroup);
const dropdownItem = this.getTemplate('option', option);
if(this.passedElement.type === 'select-one') {
dropdownGroup.appendChild(dropdownItem);
} else if(!option.selected) {
dropdownGroup.appendChild(dropdownItem);
}
});
fragment.appendChild(dropdownGroup); this.renderOptions(groupOptions, groupFragment);
} }
}); });
} }
renderOptions(options, fragment) { renderOptions(options, fragment) {
// Create a fragment to store our list items (so we don't have to update the DOM for each item)
const optsFragment = fragment || document.createDocumentFragment();
options.forEach((option, i) => { options.forEach((option, i) => {
const dropdownItem = this.getTemplate('option', option); const dropdownItem = this.getTemplate('option', option);
if(this.passedElement.type === 'select-one') { if(this.passedElement.type === 'select-one') {
fragment.appendChild(dropdownItem); optsFragment.appendChild(dropdownItem);
} else if(!option.selected) { } else if(!option.selected) {
fragment.appendChild(dropdownItem); optsFragment.appendChild(dropdownItem);
} }
}); });
} }
renderItems(items, fragment) { renderItems(items, fragment) {
const itemListFragment = fragment || document.createDocumentFragment();
// Simplify store data to just values // Simplify store data to just values
const itemsFiltered = this.store.getItemsReducedToValues(items); const itemsFiltered = this.store.getItemsReducedToValues(items);
@ -1099,14 +1098,14 @@ export class Choices {
const listItem = this.getTemplate('item', item); const listItem = this.getTemplate('item', item);
// Append it to list // Append it to list
fragment.appendChild(listItem); itemListFragment.appendChild(listItem);
}); });
// Clear list // Clear list
this.list.innerHTML = ''; this.list.innerHTML = '';
// Update list // Update list
this.list.appendChild(fragment); this.list.appendChild(itemListFragment);
} }
/** /**
@ -1124,32 +1123,27 @@ export class Choices {
const activeGroups = this.store.getGroupsFilteredByActive(); const activeGroups = this.store.getGroupsFilteredByActive();
const activeOptions = this.store.getOptionsFilteredByActive(); const activeOptions = this.store.getOptionsFilteredByActive();
// Create a fragment to store our list items (so we don't have to update the DOM for each item) const optListFragment = document.createDocumentFragment();
const optionListFragment = document.createDocumentFragment();
// Clear options // Clear options
this.dropdown.innerHTML = ''; this.dropdown.innerHTML = '';
// If we have grouped options // If we have grouped options
if(activeGroups.length >= 1 && this.isSearching !== true) { if(activeGroups.length >= 1 && this.isSearching !== true) {
this.renderGroups(activeGroups, activeOptions, optionListFragment); this.renderGroups(activeGroups, activeOptions, optListFragment);
} else if(activeOptions.length >= 1) { } else if(activeOptions.length >= 1) {
this.renderOptions(activeOptions, optionListFragment); this.renderOptions(activeOptions, optListFragment);
} }
// If we actually have anything to add to our dropdown if(optListFragment.children.length) {
if(optionListFragment.children.length) { // If we actually have anything to add to our dropdown
this.dropdown.appendChild(optionListFragment); // append it and highlight the first option
this.dropdown.appendChild(optListFragment);
this.highlightOption(); this.highlightOption();
} else { } else {
let dropdownItem; // Otherwise show a notice
if(this.isSearching) { const dropdownItem = this.isSearching ? this.getTemplate('notice', 'No results found') : this.getTemplate('notice', 'No options to select');
// If dropdown is empty, show a no content notice
dropdownItem = this.getTemplate('notice', 'No results found');
} else {
// If dropdown is empty, show a no content notice
dropdownItem = this.getTemplate('notice', 'No options to select');
}
this.dropdown.appendChild(dropdownItem); this.dropdown.appendChild(dropdownItem);
} }
} }
@ -1160,8 +1154,7 @@ export class Choices {
const activeItems = this.store.getItemsFilteredByActive(); const activeItems = this.store.getItemsFilteredByActive();
if(activeItems) { if(activeItems) {
// Create a fragment to store our list items (so we don't have to update the DOM for each item) // Create a fragment to store our list items (so we don't have to update the DOM for each item)
const itemListFragment = document.createDocumentFragment(); this.renderItems(activeItems);
this.renderItems(activeItems, itemListFragment);
} }
} }