mirror of
https://github.com/Choices-js/Choices.git
synced 2024-06-19 14:15:08 +02:00
Placeholder work
This commit is contained in:
parent
bc9adcf4ff
commit
94e3c97b4e
|
@ -1,4 +1,4 @@
|
|||
export const addItem = (value, label, id, choiceId, groupId, customProperties, keyCode) => {
|
||||
export const addItem = (value, label, id, choiceId, groupId, customProperties, placeholder, keyCode) => {
|
||||
return {
|
||||
type: 'ADD_ITEM',
|
||||
value,
|
||||
|
@ -7,7 +7,8 @@ export const addItem = (value, label, id, choiceId, groupId, customProperties, k
|
|||
choiceId,
|
||||
groupId,
|
||||
customProperties,
|
||||
keyCode
|
||||
placeholder,
|
||||
keyCode,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -27,7 +28,7 @@ export const highlightItem = (id, highlighted) => {
|
|||
};
|
||||
};
|
||||
|
||||
export const addChoice = (value, label, id, groupId, disabled, elementId, customProperties, keyCode) => {
|
||||
export const addChoice = (value, label, id, groupId, disabled, elementId, customProperties, placeholder, keyCode) => {
|
||||
return {
|
||||
type: 'ADD_CHOICE',
|
||||
value,
|
||||
|
@ -37,6 +38,7 @@ export const addChoice = (value, label, id, groupId, disabled, elementId, custom
|
|||
disabled,
|
||||
elementId,
|
||||
customProperties,
|
||||
placeholder,
|
||||
keyCode
|
||||
};
|
||||
};
|
||||
|
|
|
@ -75,6 +75,7 @@ class Choices {
|
|||
sortFilter: sortByAlpha,
|
||||
placeholder: true,
|
||||
placeholderValue: null,
|
||||
searchPlaceholderValue: null,
|
||||
prependValue: null,
|
||||
appendValue: null,
|
||||
renderSelectedChoices: 'auto',
|
||||
|
@ -174,6 +175,11 @@ class Choices {
|
|||
this.highlightPosition = 0;
|
||||
this.canSearch = this.config.searchEnabled;
|
||||
|
||||
this.placeholder = false;
|
||||
if (!this.isSelectOneElement) {
|
||||
this.placeholder = (this.config.placeholderValue || this.passedElement.getAttribute('placeholder')) || false;
|
||||
}
|
||||
|
||||
// Assign preset choices from passed object
|
||||
this.presetChoices = this.config.choices;
|
||||
|
||||
|
@ -376,22 +382,35 @@ class Choices {
|
|||
rendererableChoices = choices.filter(choice => !choice.selected);
|
||||
}
|
||||
|
||||
// Split array into placeholders and "normal" choices
|
||||
const { placeholderChoices, normalChoices } = rendererableChoices.reduce((acc, choice) => {
|
||||
if (choice.placeholder) {
|
||||
acc.placeholderChoices.push(choice);
|
||||
} else {
|
||||
acc.normalChoices.push(choice);
|
||||
}
|
||||
return acc;
|
||||
}, { placeholderChoices: [], normalChoices: [] });
|
||||
|
||||
// If sorting is enabled or the user is searching, filter choices
|
||||
if (this.config.shouldSort || this.isSearching) {
|
||||
rendererableChoices.sort(filter);
|
||||
normalChoices.sort(filter);
|
||||
}
|
||||
|
||||
let choiceLimit = rendererableChoices.length;
|
||||
|
||||
// Prepend placeholeder
|
||||
const sortedChoices = [...placeholderChoices, ...normalChoices];
|
||||
|
||||
if (this.isSearching) {
|
||||
choiceLimit = Math.min(searchResultLimit, rendererableChoices.length - 1);
|
||||
choiceLimit = Math.min(searchResultLimit, sortedChoices.length - 1);
|
||||
} else if (renderChoiceLimit > 0 && !withinGroup) {
|
||||
choiceLimit = Math.min(renderChoiceLimit, rendererableChoices.length - 1);
|
||||
choiceLimit = Math.min(renderChoiceLimit, sortedChoices.length - 1);
|
||||
}
|
||||
|
||||
// Add each choice to dropdown within range
|
||||
for (let i = 0; i < choiceLimit; i++) {
|
||||
appendChoice(rendererableChoices[i]);
|
||||
appendChoice(sortedChoices[i]);
|
||||
};
|
||||
|
||||
return choicesFragment;
|
||||
|
@ -525,15 +544,17 @@ class Choices {
|
|||
|
||||
// Items
|
||||
if (this.currentState.items !== this.prevState.items) {
|
||||
// Get active items (items that can be selected)
|
||||
const activeItems = this.store.getItemsFilteredByActive();
|
||||
if (activeItems) {
|
||||
|
||||
// Clear list
|
||||
this.itemList.innerHTML = '';
|
||||
|
||||
if (activeItems && activeItems) {
|
||||
// Create a fragment to store our list items
|
||||
// (so we don't have to update the DOM for each item)
|
||||
const itemListFragment = this.renderItems(activeItems);
|
||||
|
||||
// Clear list
|
||||
this.itemList.innerHTML = '';
|
||||
|
||||
// If we have items to add
|
||||
if (itemListFragment.childNodes) {
|
||||
// Update list
|
||||
|
@ -858,7 +879,7 @@ class Choices {
|
|||
false,
|
||||
-1,
|
||||
item.customProperties,
|
||||
null
|
||||
item.placeholder
|
||||
);
|
||||
} else {
|
||||
this._addItem(
|
||||
|
@ -867,7 +888,7 @@ class Choices {
|
|||
item.id,
|
||||
undefined,
|
||||
item.customProperties,
|
||||
null
|
||||
item.placeholder
|
||||
);
|
||||
}
|
||||
} else if (itemType === 'String') {
|
||||
|
@ -924,6 +945,7 @@ class Choices {
|
|||
foundChoice.id,
|
||||
foundChoice.groupId,
|
||||
foundChoice.customProperties,
|
||||
foundChoice.placeholder,
|
||||
foundChoice.keyCode
|
||||
);
|
||||
} else if (!this.config.silent) {
|
||||
|
@ -974,8 +996,8 @@ class Choices {
|
|||
result.selected,
|
||||
result.disabled,
|
||||
undefined,
|
||||
result['customProperties'],
|
||||
null
|
||||
result.customProperties,
|
||||
result.placeholder
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -1124,7 +1146,8 @@ class Choices {
|
|||
this._triggerChange(itemToRemove.value);
|
||||
|
||||
if (this.isSelectOneElement) {
|
||||
const placeholder = this.config.placeholder ? this.config.placeholderValue || this.passedElement.getAttribute('placeholder') :
|
||||
const placeholder = this.config.placeholder ?
|
||||
(this.config.placeholderValue || this.passedElement.getAttribute('placeholder')) :
|
||||
false;
|
||||
if (placeholder) {
|
||||
const placeholderItem = this._getTemplate('placeholder', placeholder);
|
||||
|
@ -1206,6 +1229,7 @@ class Choices {
|
|||
choice.id,
|
||||
choice.groupId,
|
||||
choice.customProperties,
|
||||
choice.placeholder,
|
||||
choice.keyCode
|
||||
);
|
||||
this._triggerChange(choice.value);
|
||||
|
@ -1379,10 +1403,26 @@ class Choices {
|
|||
result.selected,
|
||||
result.disabled,
|
||||
undefined,
|
||||
result['customProperties'],
|
||||
null
|
||||
result.customProperties,
|
||||
result.placeholder
|
||||
);
|
||||
}
|
||||
|
||||
if (this.passedElement.type === 'select-one') {
|
||||
const placeholderChoice = this.store.getPlaceholderChoice();
|
||||
|
||||
if (placeholderChoice) {
|
||||
this._addItem(
|
||||
placeholderChoice.value,
|
||||
placeholderChoice.label,
|
||||
placeholderChoice.id,
|
||||
placeholderChoice.groupId,
|
||||
null,
|
||||
placeholderChoice.placeholder
|
||||
);
|
||||
this._triggerChange(placeholderChoice.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// No results, remove loading state
|
||||
|
@ -1405,7 +1445,7 @@ class Choices {
|
|||
|
||||
// If new value matches the desired length and is not the same as the current value with a space
|
||||
if (newValue.length >= 1 && newValue !== `${currentValue} `) {
|
||||
const haystack = this.store.getChoicesFilteredBySelectable();
|
||||
const haystack = this.store.getSearchableChoices();
|
||||
const needle = newValue;
|
||||
const keys = isType('Array', this.config.searchFields) ? this.config.searchFields : [this.config.searchFields];
|
||||
const options = Object.assign(this.config.fuseOptions, { keys });
|
||||
|
@ -2200,7 +2240,7 @@ class Choices {
|
|||
* @return {Object} Class instance
|
||||
* @public
|
||||
*/
|
||||
_addItem(value, label = null, choiceId = -1, groupId = -1, customProperties = null, keyCode = null) {
|
||||
_addItem(value, label = null, choiceId = -1, groupId = -1, customProperties = null, placeholder = false, keyCode = null) {
|
||||
let passedValue = isType('String', value) ? value.trim() : value;
|
||||
let passedKeyCode = keyCode;
|
||||
const items = this.store.getItems();
|
||||
|
@ -2231,6 +2271,7 @@ class Choices {
|
|||
passedOptionId,
|
||||
groupId,
|
||||
customProperties,
|
||||
placeholder,
|
||||
passedKeyCode
|
||||
)
|
||||
);
|
||||
|
@ -2311,7 +2352,7 @@ class Choices {
|
|||
* @return
|
||||
* @private
|
||||
*/
|
||||
_addChoice(value, label = null, isSelected = false, isDisabled = false, groupId = -1, customProperties = null, keyCode = null) {
|
||||
_addChoice(value, label = null, isSelected = false, isDisabled = false, groupId = -1, customProperties = null, placeholder = false, keyCode = null) {
|
||||
if (typeof value === 'undefined' || value === null) {
|
||||
return;
|
||||
}
|
||||
|
@ -2331,6 +2372,7 @@ class Choices {
|
|||
isDisabled,
|
||||
choiceElementId,
|
||||
customProperties,
|
||||
placeholder,
|
||||
keyCode
|
||||
)
|
||||
);
|
||||
|
@ -2342,6 +2384,7 @@ class Choices {
|
|||
choiceId,
|
||||
undefined,
|
||||
customProperties,
|
||||
placeholder,
|
||||
keyCode
|
||||
);
|
||||
}
|
||||
|
@ -2395,7 +2438,8 @@ class Choices {
|
|||
option.selected,
|
||||
isOptDisabled,
|
||||
groupId,
|
||||
option.customProperties
|
||||
option.customProperties,
|
||||
option.placeholder
|
||||
);
|
||||
});
|
||||
} else {
|
||||
|
@ -2484,7 +2528,8 @@ class Choices {
|
|||
globalClasses.item,
|
||||
{
|
||||
[globalClasses.highlightedState]: data.highlighted,
|
||||
[globalClasses.itemSelectable]: !data.highlighted
|
||||
[globalClasses.itemSelectable]: !data.highlighted,
|
||||
[globalClasses.placeholder]: data.placeholder
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -2493,7 +2538,8 @@ class Choices {
|
|||
globalClasses.item,
|
||||
{
|
||||
[globalClasses.highlightedState]: data.highlighted,
|
||||
[globalClasses.itemSelectable]: !data.disabled
|
||||
[globalClasses.itemSelectable]: !data.disabled,
|
||||
[globalClasses.placeholder]: data.placeholder
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -2589,7 +2635,8 @@ class Choices {
|
|||
globalClasses.itemChoice,
|
||||
{
|
||||
[globalClasses.itemDisabled]: data.disabled,
|
||||
[globalClasses.itemSelectable]: !data.disabled
|
||||
[globalClasses.itemSelectable]: !data.disabled,
|
||||
[globalClasses.placeholder]: data.placeholder
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -2731,6 +2778,14 @@ class Choices {
|
|||
input.placeholder = placeholder;
|
||||
if (!this.isSelectOneElement) {
|
||||
input.style.width = getWidthOfInput(input);
|
||||
} else {
|
||||
// If select one element with a search placeholder value
|
||||
if (this.config.searchPlaceholderValue) {
|
||||
input.placeholder = this.config.searchPlaceholderValue;
|
||||
} else {
|
||||
const placeholderItem = this._getTemplate('placeholder', this.placeholder);
|
||||
this.itemList.appendChild(placeholderItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2774,6 +2829,7 @@ class Choices {
|
|||
label: o.innerHTML,
|
||||
selected: o.selected,
|
||||
disabled: o.disabled || o.parentNode.disabled,
|
||||
placeholder: o.hasAttribute('placeholder')
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -2798,7 +2854,8 @@ class Choices {
|
|||
choice.selected,
|
||||
choice.disabled,
|
||||
undefined,
|
||||
choice.customProperties
|
||||
choice.customProperties,
|
||||
choice.placeholder
|
||||
);
|
||||
} else {
|
||||
// Otherwise pre-select the first choice in the array
|
||||
|
@ -2808,7 +2865,8 @@ class Choices {
|
|||
true,
|
||||
false,
|
||||
undefined,
|
||||
choice.customProperties
|
||||
choice.customProperties,
|
||||
choice.placeholder
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
@ -2818,7 +2876,8 @@ class Choices {
|
|||
choice.selected,
|
||||
choice.disabled,
|
||||
undefined,
|
||||
choice.customProperties
|
||||
choice.customProperties,
|
||||
choice.placeholder
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -2836,7 +2895,8 @@ class Choices {
|
|||
item.label,
|
||||
item.id,
|
||||
undefined,
|
||||
item.customProperties
|
||||
item.customProperties,
|
||||
item.placeholder
|
||||
);
|
||||
} else if (itemType === 'String') {
|
||||
this._addItem(item);
|
||||
|
|
|
@ -132,13 +132,13 @@ export const extend = function() {
|
|||
*/
|
||||
export const whichTransitionEvent = function() {
|
||||
var t,
|
||||
el = document.createElement("fakeelement");
|
||||
el = document.createElement('fakeelement');
|
||||
|
||||
var transitions = {
|
||||
"transition": "transitionend",
|
||||
"OTransition": "oTransitionEnd",
|
||||
"MozTransition": "transitionend",
|
||||
"WebkitTransition": "webkitTransitionEnd"
|
||||
'transition': 'transitionend',
|
||||
'OTransition': 'oTransitionEnd',
|
||||
'MozTransition': 'transitionend',
|
||||
'WebkitTransition': 'webkitTransitionEnd'
|
||||
}
|
||||
|
||||
for (t in transitions) {
|
||||
|
@ -509,6 +509,20 @@ export const getWidthOfInput = (input) => {
|
|||
testEl.style.width = 'auto';
|
||||
testEl.style.whiteSpace = 'pre';
|
||||
|
||||
if (document.body.contains(input) && window.getComputedStyle) {
|
||||
const inputStyle = window.getComputedStyle(input);
|
||||
|
||||
if (inputStyle) {
|
||||
testEl.style.fontSize = inputStyle.fontSize;
|
||||
testEl.style.fontFamily = inputStyle.fontFamily;
|
||||
testEl.style.fontWeight = inputStyle.fontWeight;
|
||||
testEl.style.fontStyle = inputStyle.fontStyle;
|
||||
testEl.style.letterSpacing = inputStyle.letterSpacing;
|
||||
testEl.style.textTransform = inputStyle.textTransform;
|
||||
testEl.style.padding = inputStyle.padding;
|
||||
}
|
||||
}
|
||||
|
||||
document.body.appendChild(testEl);
|
||||
|
||||
if (value && testEl.offsetWidth !== input.offsetWidth) {
|
||||
|
|
|
@ -17,6 +17,7 @@ const choices = (state = [], action) => {
|
|||
active: true,
|
||||
score: 9999,
|
||||
customProperties: action.customProperties,
|
||||
placeholder: (action.placeholder || false),
|
||||
keyCode: null
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ const items = (state = [], action) => {
|
|||
active: true,
|
||||
highlighted: false,
|
||||
customProperties: action.customProperties,
|
||||
placeholder: (action.placeholder || false),
|
||||
keyCode: null
|
||||
}];
|
||||
|
||||
|
|
|
@ -85,9 +85,7 @@ export default class Store {
|
|||
*/
|
||||
getChoicesFilteredByActive() {
|
||||
const choices = this.getChoices();
|
||||
const values = choices.filter((choice) => {
|
||||
return choice.active === true;
|
||||
}, []);
|
||||
const values = choices.filter(choice => choice.active === true);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
@ -98,13 +96,20 @@ export default class Store {
|
|||
*/
|
||||
getChoicesFilteredBySelectable() {
|
||||
const choices = this.getChoices();
|
||||
const values = choices.filter((choice) => {
|
||||
return choice.disabled !== true;
|
||||
}, []);
|
||||
const values = choices.filter(choice => choice.disabled !== true);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get choices that can be searched (excluding placeholders)
|
||||
* @return {Array} Option objects
|
||||
*/
|
||||
getSearchableChoices() {
|
||||
const filtered = this.getChoicesFilteredBySelectable();
|
||||
return filtered.filter(choice => choice.placeholder !== true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get single choice by it's ID
|
||||
* @return {Object} Found choice
|
||||
|
@ -159,6 +164,19 @@ export default class Store {
|
|||
|
||||
return foundGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get placeholder choice from store
|
||||
* @return {Object} Found placeholder
|
||||
*/
|
||||
getPlaceholderChoice() {
|
||||
const choices = this.getChoices();
|
||||
const values = choices.filter((choice) => {
|
||||
return choice.placeholder === true;
|
||||
}, []);
|
||||
|
||||
return values[0];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Store;
|
||||
|
|
|
@ -69,6 +69,7 @@ describe('Choices', () => {
|
|||
expect(this.choices.config.shouldSortItems).toEqual(jasmine.any(Boolean));
|
||||
expect(this.choices.config.placeholder).toEqual(jasmine.any(Boolean));
|
||||
expect(this.choices.config.placeholderValue).toEqual(null);
|
||||
expect(this.choices.config.searchPlaceholderValue).toEqual(null);
|
||||
expect(this.choices.config.prependValue).toEqual(null);
|
||||
expect(this.choices.config.appendValue).toEqual(null);
|
||||
expect(this.choices.config.renderSelectedChoices).toEqual(jasmine.any(String));
|
||||
|
@ -1045,6 +1046,7 @@ describe('Choices', () => {
|
|||
customProperties: {
|
||||
foo: 'bar'
|
||||
},
|
||||
placeholder: false,
|
||||
keyCode: null
|
||||
};
|
||||
|
||||
|
@ -1057,6 +1059,7 @@ describe('Choices', () => {
|
|||
active: true,
|
||||
highlighted: false,
|
||||
customProperties: randomItem.customProperties,
|
||||
placeholder: false,
|
||||
keyCode: randomItem.keyCode
|
||||
}];
|
||||
|
||||
|
@ -1084,6 +1087,7 @@ describe('Choices', () => {
|
|||
customProperties: {
|
||||
foo: 'bar'
|
||||
},
|
||||
placeholder: false,
|
||||
keyCode: null
|
||||
};
|
||||
|
||||
|
@ -1098,6 +1102,7 @@ describe('Choices', () => {
|
|||
active: true,
|
||||
score: 9999,
|
||||
customProperties: randomChoice.customProperties,
|
||||
placeholder: randomChoice.placeholder,
|
||||
keyCode: randomChoice.keyCode
|
||||
}];
|
||||
|
||||
|
|
Loading…
Reference in a new issue