/**
* Copyright 2016, Yahoo! Inc.
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
import Ember from 'ember';
import Base from 'ember-cp-validations/validators/base';
const {
isEmpty
} = Ember;
/**
* Validates that your attributes have only numeric values.
*
* #### Options
* - `allowBlank` (**Boolean**): If true, skips validation if the value is empty
* - `allowString` (**Boolean**): If true, validator will accept string representation of a number
* - `integer` (**Boolean**): Number must be an integer
* - `positive` (**Boolean**): Number must be greater than 0
* - `odd` (**Boolean**): Number must be odd
* - `even` (**Boolean**): Number must be even
* - `is` (**Number**): Number must be equal to this value
* - `lt` (**Number**): Number must be less than this value
* - `lte` (**Number**): Number must be less than or equal to this value
* - `gt` (**Number**): Number must be greater than this value
* - `gte` (**Number**): Number must be greater than or equal to this value
*
* ```javascript
* // Examples
* validator('number') // Simple check if the value is a number
* validator('number', {
* allowString: true,
* integer: true,
* gt: 5,
* lte: 100
* })
* ```
*
* @class Number
* @module Validators
* @extends Base
*/
export default Base.extend({
validate(value, options) {
const numValue = Number(value);
const optionKeys = Object.keys(options);
if (options.allowBlank && isEmpty(value)) {
return true;
}
if (typeof value === 'string' && (isEmpty(value) || !options.allowString)) {
return this.createErrorMessage('notANumber', value, options);
}
if (!this.isNumber(numValue)) {
return this.createErrorMessage('notANumber', value, options);
}
if (options.integer && !this.isInteger(numValue)) {
return this.createErrorMessage('notAnInteger', value, options);
}
for (let i = 0; i < optionKeys.length; i++) {
const type = optionKeys[i];
const m = this._validateType(type, options, numValue);
if (typeof m === 'string') {
return m;
}
}
return true;
},
_validateType(type, options, value) {
const expected = options[type];
const actual = value;
if (type === 'is' && actual !== expected) {
return this.createErrorMessage('equalTo', value, options);
} else if (type === 'lt' && actual >= expected) {
return this.createErrorMessage('lessThan', value, options);
} else if (type === 'lte' && actual > expected) {
return this.createErrorMessage('lessThanOrEqualTo', value, options);
} else if (type === 'gt' && actual <= expected) {
return this.createErrorMessage('greaterThan', value, options);
} else if (type === 'gte' && actual < expected) {
return this.createErrorMessage('greaterThanOrEqualTo', value, options);
} else if (type === 'positive' && actual < 0) {
return this.createErrorMessage('positive', value, options);
} else if (type === 'odd' && actual % 2 === 0) {
return this.createErrorMessage('odd', value, options);
} else if (type === 'even' && actual % 2 !== 0) {
return this.createErrorMessage('even', value, options);
}
return true;
},
/* Use polyfills instead of Number.isNaN or Number.isInteger to support IE & Safari */
isNumber(value) {
return typeof value === 'number' && !isNaN(value);
},
isInteger(value) {
return typeof value === 'number' && isFinite(value) && Math.floor(value) === value;
}
});