Use getters and setters appropriately

This commit is contained in:
Josh Johnson 2018-04-24 12:54:45 +01:00
parent 275295adc5
commit 152b740670
19 changed files with 134 additions and 186 deletions

View file

@ -119,9 +119,9 @@ class Choices {
this.presetItems = this.config.items;
// Then add any values passed from attribute
if (this.passedElement.getValue()) {
if (this.passedElement.value) {
this.presetItems = this.presetItems.concat(
this.passedElement.getValue().split(this.config.delimiter),
this.passedElement.value.split(this.config.delimiter),
);
}
@ -220,7 +220,7 @@ class Choices {
this.containerOuter.unwrap(this.passedElement.element);
if (this.isSelectElement) {
this.passedElement.setOptions(this.presetChoices);
this.passedElement.options = this.presetChoices;
}
// Clear data store
@ -391,10 +391,10 @@ class Choices {
if (this.isTextElement) {
// Update the value of the hidden input
this.passedElement.setValue(items);
this.passedElement.value = items;
} else {
// Update the options of the hidden input
this.passedElement.setOptions(items);
this.passedElement.options = items;
}
const addItemToFragment = (item) => {
@ -416,7 +416,7 @@ class Choices {
* @private
*/
render() {
this.currentState = this.store.getState();
this.currentState = this.store.state;
const stateChanged = (
this.currentState.choices !== this.prevState.choices ||
this.currentState.groups !== this.prevState.groups ||
@ -465,7 +465,7 @@ class Choices {
// If we have choices to show
if (choiceListFragment.childNodes && choiceListFragment.childNodes.length > 0) {
const activeItems = this.store.getItemsFilteredByActive();
const canAddItem = this._canAddItem(activeItems, this.input.getValue());
const canAddItem = this._canAddItem(activeItems, this.input.value);
// ...and we can select them
if (canAddItem.response) {
@ -581,7 +581,7 @@ class Choices {
* @public
*/
highlightAll() {
const items = this.store.getItems();
const items = this.store.items;
items.forEach(item => this.highlightItem(item));
return this;
}
@ -592,7 +592,7 @@ class Choices {
* @public
*/
unhighlightAll() {
const items = this.store.getItems();
const items = this.store.items;
items.forEach(item => this.unhighlightItem(item));
return this;
}
@ -670,7 +670,7 @@ class Choices {
}
this.dropdown.show();
this.containerOuter.open(this.dropdown.getVerticalPos());
this.containerOuter.open(this.dropdown.distanceFromTopWindow());
if (focusInput && this.canSearch) {
this.input.focus();
@ -1046,7 +1046,7 @@ class Choices {
// If editing the last item is allowed and there are not other selected items,
// we can edit the item value. Otherwise if we can remove items, remove all selected items
if (this.config.editItems && !hasHighlightedItems && lastItem) {
this.input.setValue(lastItem.value);
this.input.value = lastItem.value;
this.input.setWidth();
this._removeItem(lastItem);
this._triggerChange(lastItem.value);
@ -1077,7 +1077,7 @@ class Choices {
placeholderItem.innerHTML = this.config.loadingText;
}
} else {
this.input.setPlaceholder(this.config.loadingText);
this.input.placeholder = this.config.loadingText;
}
} else {
this.containerOuter.removeLoadingState();
@ -1085,7 +1085,7 @@ class Choices {
if (this.isSelectOneElement) {
placeholderItem.innerHTML = (this.placeholder || '');
} else {
this.input.setPlaceholder(this.placeholder || '');
this.input.placeholder = (this.placeholder || '');
}
}
}
@ -1351,7 +1351,7 @@ class Choices {
this.canSearch = false;
if (
this.config.removeItems &&
!this.input.getValue() &&
!this.input.value &&
this.input.element === document.activeElement
) {
// Highlight items
@ -1363,7 +1363,7 @@ class Choices {
const onEnterKey = () => {
// If enter key is pressed and the input has a value
if (this.isTextElement && target.value) {
const value = this.input.getValue();
const value = this.input.value;
const canAddItem = this._canAddItem(activeItems, value);
// All is good, add
@ -1490,7 +1490,7 @@ class Choices {
return;
}
const value = this.input.getValue();
const value = this.input.value;
const activeItems = this.store.getItemsFilteredByActive();
const canAddItem = this._canAddItem(activeItems, value);
@ -1523,7 +1523,7 @@ class Choices {
this.store.dispatch(activateChoices(true));
}
} else if (this.canSearch && canAddItem.response) {
this._handleSearch(this.input.getValue());
this._handleSearch(this.input.value);
}
}
// Re-establish canSearch value from changes in _onKeyDown
@ -1901,7 +1901,7 @@ class Choices {
let passedValue = isType('String', value) ? value.trim() : value;
const passedKeyCode = keyCode;
const passedCustomProperties = customProperties;
const items = this.store.getItems();
const items = this.store.items;
const passedLabel = label || passedValue;
const passedOptionId = parseInt(choiceId, 10) || -1;
@ -2183,9 +2183,9 @@ class Choices {
this.containerOuter.wrap(this.containerInner.element);
if (this.isSelectOneElement) {
this.input.setPlaceholder(this.config.searchPlaceholderValue || '');
this.input.placeholder = (this.config.searchPlaceholderValue || '');
} else if (this.placeholder) {
this.input.setPlaceholder(this.placeholder);
this.input.placeholder = this.placeholder;
this.input.setWidth(true);
}
@ -2215,14 +2215,14 @@ class Choices {
}
_addPredefinedChoices() {
const passedGroups = this.passedElement.getOptionGroups();
const passedGroups = this.passedElement.optionGroups;
this.highlightPosition = 0;
this.isSearching = false;
if (passedGroups && passedGroups.length) {
// If we have a placeholder option
const placeholderChoice = this.passedElement.getPlaceholderOption();
const placeholderChoice = this.passedElement.placeholderOption;
if (placeholderChoice && placeholderChoice.parentNode.tagName === 'SELECT') {
this._addChoice(
placeholderChoice.value,
@ -2239,7 +2239,7 @@ class Choices {
this._addGroup(group, (group.id || null));
});
} else {
const passedOptions = this.passedElement.getOptions();
const passedOptions = this.passedElement.options;
const filter = this.config.sortFn;
const allChoices = this.presetChoices;

View file

@ -767,18 +767,17 @@ describe('choices', () => {
];
beforeEach(() => {
storeGetItemsStub = stub().returns(items);
storeGetItemsStub = stub(instance.store, 'items').get(() => items);
highlightItemStub = stub();
instance.highlightItem = highlightItemStub;
instance.store.getItems = storeGetItemsStub;
output = instance.highlightAll();
});
afterEach(() => {
highlightItemStub.reset();
instance.store.getItems.reset();
storeGetItemsStub.reset();
});
returnsInstance(output);
@ -806,18 +805,17 @@ describe('choices', () => {
];
beforeEach(() => {
storeGetItemsStub = stub().returns(items);
storeGetItemsStub = stub(instance.store, 'items').get(() => items);
unhighlightItemStub = stub();
instance.unhighlightItem = unhighlightItemStub;
instance.store.getItems = storeGetItemsStub;
output = instance.unhighlightAll();
});
afterEach(() => {
instance.unhighlightItem.reset();
instance.store.getItems.reset();
storeGetItemsStub.reset();
});
returnsInstance(output);

View file

@ -15,10 +15,6 @@ export default class Container {
this.onBlur = this.onBlur.bind(this);
}
getElement() {
return this.element;
}
/**
* Add event listeners
*/

View file

@ -40,12 +40,6 @@ describe('components/container', () => {
});
});
describe('getElement', () => {
it('returns DOM reference of element', () => {
expect(instance.getElement()).to.eql(element);
});
});
describe('addEventListeners', () => {
let addEventListenerStub;

View file

@ -8,16 +8,12 @@ export default class Dropdown {
this.isActive = false;
}
getElement() {
return this.element;
}
/**
* Determine how far the top of our element is from
* the top of the window
* @return {Number} Vertical position
*/
getVerticalPos() {
distanceFromTopWindow() {
this.dimensions = this.element.getBoundingClientRect();
this.position = Math.ceil(this.dimensions.top + window.pageYOffset + this.element.offsetHeight);
return this.position;

View file

@ -39,13 +39,7 @@ describe('components/dropdown', () => {
});
});
describe('getElement', () => {
it('returns DOM reference of element', () => {
expect(instance.getElement()).to.eql(choicesElement);
});
});
describe('getVerticalPos', () => {
describe('distanceFromTopWindow', () => {
let top;
let offset;
let dimensions;
@ -74,18 +68,18 @@ describe('components/dropdown', () => {
it('determines how far the top of our element is from the top of the window', () => {
const expectedResponse = top + offset;
const actualResponse = instance.getVerticalPos();
const actualResponse = instance.distanceFromTopWindow();
expect(actualResponse).to.equal(expectedResponse);
});
it('assigns dimensions to instance', () => {
instance.getVerticalPos();
instance.distanceFromTopWindow();
const expectedResponse = dimensions;
expect(instance.dimensions).to.equal(expectedResponse);
});
it('assigns posisiton to instance', () => {
instance.getVerticalPos();
instance.distanceFromTopWindow();
const expectedResponse = top + offset;
expect(instance.position).to.equal(expectedResponse);
});

View file

@ -1,4 +1,4 @@
import { getWidthOfInput } from '../lib/utils';
import { calcWidthOfInput } from '../lib/utils';
export default class Input {
constructor(instance, element, classNames) {
@ -15,8 +15,16 @@ export default class Input {
this.onBlur = this.onBlur.bind(this);
}
getElement() {
return this.element;
set placeholder(placeholder) {
this.element.placeholder = placeholder;
}
set value(value) {
this.element.value = value;
}
get value() {
return this.element.value;
}
addEventListeners() {
@ -124,28 +132,16 @@ export default class Input {
this.element.value.length >= (this.parentInstance.placeholder.length / 1.25)) ||
enforceWidth
) {
this.element.style.width = this.getWidth();
this.element.style.width = this.calcWidth();
}
} else {
// If there is no placeholder, resize input to contents
this.element.style.width = this.getWidth();
this.element.style.width = this.calcWidth();
}
}
getWidth() {
return getWidthOfInput(this.element);
}
setPlaceholder(placeholder) {
this.element.placeholder = placeholder;
}
setValue(value) {
this.element.value = value;
}
getValue() {
return this.element.value;
calcWidth() {
return calcWidthOfInput(this.element);
}
setActiveDescendant(activeDescendantID) {

View file

@ -37,12 +37,6 @@ describe('components/input', () => {
});
});
describe('getElement', () => {
it('returns DOM reference of element', () => {
expect(instance.getElement()).to.eql(choicesElement);
});
});
describe('addEventListeners', () => {
let addEventListenerStub;
@ -278,15 +272,15 @@ describe('components/input', () => {
});
describe('setWidth', () => {
let getWidthStub;
let calcWidthStub;
const inputWidth = '200px';
beforeEach(() => {
getWidthStub = stub(instance, 'getWidth').returns(inputWidth);
calcWidthStub = stub(instance, 'calcWidth').returns(inputWidth);
});
afterEach(() => {
getWidthStub.restore();
calcWidthStub.restore();
});
describe('with a placeholder', () => {
@ -296,7 +290,7 @@ describe('components/input', () => {
instance.element.value = 'This is a test';
expect(instance.element.style.width).to.not.equal(inputWidth);
instance.setWidth();
expect(getWidthStub.callCount).to.equal(1);
expect(calcWidthStub.callCount).to.equal(1);
expect(instance.element.style.width).to.equal(inputWidth);
});
});
@ -307,7 +301,7 @@ describe('components/input', () => {
instance.element.value = '';
expect(instance.element.style.width).to.not.equal(inputWidth);
instance.setWidth(true);
expect(getWidthStub.callCount).to.equal(1);
expect(calcWidthStub.callCount).to.equal(1);
expect(instance.element.style.width).to.equal(inputWidth);
});
});
@ -317,7 +311,7 @@ describe('components/input', () => {
instance.parentInstance.placeholder = 'This is a test';
instance.element.value = 'Test';
instance.setWidth();
expect(getWidthStub.callCount).to.equal(0);
expect(calcWidthStub.callCount).to.equal(0);
});
});
});
@ -327,35 +321,35 @@ describe('components/input', () => {
instance.placeholder = null;
expect(instance.element.style.width).to.not.equal(inputWidth);
instance.setWidth();
expect(getWidthStub.callCount).to.equal(1);
expect(calcWidthStub.callCount).to.equal(1);
expect(instance.element.style.width).to.equal(inputWidth);
});
});
});
describe('setPlaceholder', () => {
describe('placeholder setter', () => {
it('sets value of element to passed placeholder', () => {
const placeholder = 'test';
expect(instance.element.placeholder).to.equal('');
instance.setPlaceholder(placeholder);
instance.placeholder = placeholder;
expect(instance.element.placeholder).to.equal(placeholder);
});
});
describe('setValue', () => {
describe('value setter', () => {
it('sets value of element to passed value', () => {
const value = 'test';
expect(instance.element.value).to.equal('');
instance.setValue(value);
instance.value = value;
expect(instance.element.value).to.equal(value);
});
});
describe('getValue', () => {
describe('value getter', () => {
it('sets value of element to passed value', () => {
const value = 'test';
instance.element.value = value;
const actualResponse = instance.getValue();
const actualResponse = instance.value;
expect(actualResponse).to.equal(value);
});
});

View file

@ -8,10 +8,6 @@ export default class List {
this.hasChildren = !!this.element.children;
}
getElement() {
return this.element;
}
/**
* Clear List contents
*/

View file

@ -36,12 +36,6 @@ describe('components/list', () => {
});
});
describe('getElement', () => {
it('returns DOM reference of element', () => {
expect(instance.getElement()).to.eql(choicesElement);
});
});
describe('clear', () => {
it('clears element\'s inner HTML', () => {
const innerHTML = 'test';

View file

@ -8,11 +8,7 @@ export default class WrappedElement {
this.isDisabled = false;
}
getElement() {
return this.element;
}
getValue() {
get value() {
return this.element.value;
}

View file

@ -41,9 +41,9 @@ describe('components/wrappedElement', () => {
});
});
describe('getElement', () => {
it('returns DOM reference of element', () => {
expect(instance.getElement()).to.eql(element);
describe('value getter', () => {
it('returns element value', () => {
expect(instance.value).to.eql(element.value);
});
});

View file

@ -9,8 +9,16 @@ export default class WrappedInput extends WrappedElement {
this.classNames = classNames;
}
getElement() {
super.getElement();
set value(items) {
const itemsFiltered = reduceToValues(items);
const itemsFilteredString = itemsFiltered.join(this.parentInstance.config.delimiter);
this.element.setAttribute('value', itemsFilteredString);
this.element.value = itemsFilteredString;
}
get value() {
return super.value;
}
conceal() {
@ -28,12 +36,4 @@ export default class WrappedInput extends WrappedElement {
disable() {
super.disable();
}
setValue(items) {
const itemsFiltered = reduceToValues(items);
const itemsFilteredString = itemsFiltered.join(this.parentInstance.config.delimiter);
this.element.setAttribute('value', itemsFilteredString);
this.element.value = itemsFilteredString;
}
}

View file

@ -39,7 +39,7 @@ describe('components/wrappedInput', () => {
});
describe('inherited methods', () => {
['getElement', 'conceal', 'reveal', 'enable', 'disable'].forEach((method) => {
['conceal', 'reveal', 'enable', 'disable'].forEach((method) => {
describe(method, () => {
beforeEach(() => {
stub(WrappedElement.prototype, method);
@ -58,7 +58,7 @@ describe('components/wrappedInput', () => {
});
});
describe('setValue', () => {
describe('value setter', () => {
const data = [
{
id: 'ID 1',
@ -76,8 +76,8 @@ describe('components/wrappedInput', () => {
it('sets delimited value of element based on passed data', () => {
expect(instance.element.value).to.equal('');
instance.setValue(data);
expect(instance.element.value).to.equal('Value 1,Value 2,Value 3');
instance.value = data;
expect(instance.value).to.equal('Value 1,Value 2,Value 3');
});
});
});

View file

@ -9,8 +9,31 @@ export default class WrappedSelect extends WrappedElement {
this.classNames = classNames;
}
getElement() {
super.getElement();
get placeholderOption() {
return this.element.querySelector('option[placeholder]');
}
get optionGroups() {
return Array.from(this.element.getElementsByTagName('OPTGROUP'));
}
get options() {
return Array.from(this.element.options);
}
set options(options) {
const fragment = document.createDocumentFragment();
const addOptionToFragment = (data) => {
// Create a standard select option
const template = templates.option(data);
// Append it to fragment
fragment.appendChild(template);
};
// Add each list item to list
options.forEach(optionData => addOptionToFragment(optionData));
this.appendDocFragment(fragment);
}
conceal() {
@ -29,33 +52,6 @@ export default class WrappedSelect extends WrappedElement {
super.disable();
}
getPlaceholderOption() {
return this.element.querySelector('option[placeholder]');
}
getOptions() {
return Array.from(this.element.options);
}
getOptionGroups() {
return Array.from(this.element.getElementsByTagName('OPTGROUP'));
}
setOptions(options) {
const fragment = document.createDocumentFragment();
const addOptionToFragment = (data) => {
// Create a standard select option
const template = templates.option(data);
// Append it to fragment
fragment.appendChild(template);
};
// Add each list item to list
options.forEach(optionData => addOptionToFragment(optionData));
this.appendDocFragment(fragment);
}
appendDocFragment(fragment) {
this.element.innerHTML = '';
this.element.appendChild(fragment);

View file

@ -55,7 +55,7 @@ describe('components/wrappedSelect', () => {
});
describe('inherited methods', () => {
['getElement', 'conceal', 'reveal', 'enable', 'disable'].forEach((method) => {
['conceal', 'reveal', 'enable', 'disable'].forEach((method) => {
beforeEach(() => {
stub(WrappedElement.prototype, method);
});
@ -74,39 +74,38 @@ describe('components/wrappedSelect', () => {
});
});
describe('getPlaceholderOption', () => {
describe('placeholderOption getter', () => {
it('returns option element with placeholder attribute', () => {
const output = instance.getPlaceholderOption();
expect(output).to.be.instanceOf(HTMLOptionElement);
expect(instance.placeholderOption).to.be.instanceOf(HTMLOptionElement);
});
});
describe('getOptions', () => {
describe('options getter', () => {
it('returns all option elements', () => {
const output = instance.getOptions();
expect(output).to.be.an('array');
output.forEach((option) => {
const { options } = instance;
expect(options).to.be.an('array');
options.forEach((option) => {
expect(option).to.be.instanceOf(HTMLOptionElement);
});
});
});
describe('getOptionGroups', () => {
describe('optionGroups getter', () => {
it('returns an array of all option groups', () => {
for (let i = 1; i <= 3; i++) {
const group = document.createElement('optgroup');
instance.element.appendChild(group);
}
const output = instance.getOptionGroups();
expect(output.length).to.equal(3);
output.forEach((option) => {
const { optionGroups } = instance;
expect(optionGroups.length).to.equal(3);
optionGroups.forEach((option) => {
expect(option).to.be.instanceOf(HTMLOptGroupElement);
});
});
});
describe('setOptions', () => {
describe('options setter', () => {
let appendDocFragmentStub;
const options = [
{
@ -134,7 +133,7 @@ describe('components/wrappedSelect', () => {
it('creates an option element for each passed object, adds it to a fragment and calls appendDocFragment with created fragment', () => {
expect(appendDocFragmentStub.called).to.equal(false);
instance.setOptions(options);
instance.options = options;
expect(appendDocFragmentStub.called).to.equal(true);
const fragment = appendDocFragmentStub.firstCall.args[0];

View file

@ -485,7 +485,7 @@ export const strToEl = (function() {
* Sets the width of a passed input based on its value
* @return {Number} Width of input
*/
export const getWidthOfInput = (input) => {
export const calcWidthOfInput = (input) => {
const value = input.value || input.placeholder;
let width = input.offsetWidth;

View file

@ -33,7 +33,7 @@ export default class Store {
* Get store object (wrapping Redux method)
* @return {Object} State
*/
getState() {
get state() {
return this.store.getState();
}
@ -41,9 +41,8 @@ export default class Store {
* Get items from store
* @return {Array} Item objects
*/
getItems() {
const state = this.store.getState();
return state.items;
get items() {
return this.state.items;
}
/**
@ -51,7 +50,7 @@ export default class Store {
* @return {Array} Item objects
*/
getItemsFilteredByActive() {
const items = this.getItems();
const items = this.items;
const values = items.filter(item => item.active === true);
return values;
@ -62,7 +61,7 @@ export default class Store {
* @return {Array} Item objects
*/
getItemsFilteredByHighlighted() {
const items = this.getItems();
const items = this.items;
const values = items.filter(item => item.active && item.highlighted);
return values;
@ -73,8 +72,7 @@ export default class Store {
* @return {Array} Option objects
*/
getChoices() {
const state = this.store.getState();
return state.choices;
return this.state.choices;
}
/**
@ -139,8 +137,7 @@ export default class Store {
* @return {Array} Group objects
*/
getGroups() {
const state = this.store.getState();
return state.groups;
return this.state.groups;
}
/**

View file

@ -53,11 +53,14 @@ describe('reducers/store', () => {
});
});
describe('getState', () => {
it('wraps redux getState method', () => {
expect(getStateStub.callCount).to.equal(0);
instance.getState();
expect(getStateStub.callCount).to.equal(1);
describe('state getter', () => {
it('returns state', () => {
const state = {
items: [],
};
getStateStub.returns(state);
expect(instance.state).to.equal(state);
});
});
@ -153,11 +156,10 @@ describe('reducers/store', () => {
getStateStub.returns(state);
});
describe('getItems', () => {
describe('items getter', () => {
it('returns items', () => {
const expectedResponse = state.items;
const actualResponse = instance.getItems();
expect(actualResponse).to.eql(expectedResponse);
expect(instance.items).to.eql(expectedResponse);
});
});