Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

export validators from addon namespace #152

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions addon/validators/belongs-to.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/**
* 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 './base';

const {
get,
canInvoke
} = Ember;


/**
* Identifies a `belongs-to` relationship in an Ember Data Model or Ember.Object.
* This is used to create a link to the validations object of the child model.
*
* _**Note:** Validations must exist on **both** models/objects_
*
* ### Ember Model
*
* ```javascript
* // model/users.js
*
* const Validations = buildValidations({
* details: validator('belongs-to')
* });
*
* export default DS.Model.extend(Validations, {
* 'details': DS.belongsTo('user-detail')
* });
* ```
*
* ```javascript
* // model/user-details.js
*
* const Validations = buildValidations({
* firstName: validator('presence', true),
* lastName: validator('presence', true)
* });
*
* export default DS.Model.extend(Validations, {
* "firstName": attr('string'),
* "lastName": attr('string'),
* });
* ```
*
* ### Ember Object
*
* ```javascript
* // model/users.js
*
* import UserDetails from '../user-details';
*
* const Validations = buildValidations({
* details: validator('belongs-to')
* });
*
* export default Ember.Object.extend(Validations, {
* details: null,
*
* init() {
* this._super(...arguments);
* let owner = Ember.getOwner(this);
* this.set('details', UserDetails.create(owner.ownerInjection()));
* }
* });
* ```
*
* From our `user` model, we can now check any validation propery on the `user-details` model.
*
* ```javascript
* get(model, 'validations.attrs.details.isValid')
* get(model, 'validations.attrs.details.messages')
* ```
*
* @class Belongs To
* @module Validators
* @extends Base
*/
export default Base.extend({
validate(value) {
if (value) {
if (canInvoke(value, 'then')) {
return value.then(model => get(model, 'validations'));
}
return get(value, 'validations');
}

return true;
}
});
71 changes: 71 additions & 0 deletions addon/validators/collection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* 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 './base';

const {
isArray
} = Ember;

/**
* If `true` validates that the given value is a valid collection and will add `<ATTRIUTE>.[]` as a dependent key to the CP.
* If `false`, validates that the given value is singular. Use this validator if you want validation to occur when the content of your collection changes.
*
* ```javascript
* // Examples
* validator('collection', true)
* validator('collection', false)
* validator('collection', {
* collection: true,
* message: 'must be a collection'
* })
* ```
*
* @class Collection
* @module Validators
* @extends Base
*/
export default Base.extend({

/**
* Normalized options passed in.
* ```js
* validator('collection', true)
* // Becomes
* validator('collection', {
* collection: true
* })
* ```
*
* @method buildOptions
* @param {Object} options
* @param {Object} defaultOptions
* @param {Object} globalOptions
* @return {Object}
*/
buildOptions(options = {}, defaultOptions = {}, globalOptions = {}) {
let opts = options;

if (typeof options === 'boolean') {
opts = {
collection: options
};
}
return this._super(opts, defaultOptions, globalOptions);
},

validate(value, options) {
if (options.collection === true && !isArray(value)) {
return this.createErrorMessage('collection', value, options);
}

if (options.collection === false && isArray(value)) {
return this.createErrorMessage('singular', value, options);
}

return true;
}
});
44 changes: 44 additions & 0 deletions addon/validators/confirmation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* 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 './base';

const {
get,
isEqual,
isNone
} = Ember;

/**
* You should use this validator when you have two text fields that should receive exactly the same content.
* For example, you may want to confirm an email address or a password. This validator doesnt have to be created on an attribute defined in your model.
* This means that when you save your model, in this case, `verfiedEmail` will not be part of the payload.
*
* ```javascript
* // Example
* email: validator('format', {
* type: 'email'
* })
* verifiedEmail: validator('confirmation', {
* on: 'email',
* message: 'do not match',
* description: 'Email addresses'
* })
* ```
*
* @class Confirmation
* @module Validators
* @extends Base
*/
export default Base.extend({
validate(value, options, model) {
if (!isNone(options.on) && !isEqual(value, get(model, options.on))) {
return this.createErrorMessage('confirmation', value, options);
}

return true;
}
});
92 changes: 92 additions & 0 deletions addon/validators/date.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* 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 './base';
const moment = (self.requirejs.entries.moment || self.requirejs.entries['moment/index']) && self.require('moment').default;

if (typeof moment === 'undefined') {
throw new Error('MomentJS is required to use the Date validator. The easiest way to install moment.js is to install ember-moment.\n' +
'Installation instructions and documentation can be found at https://github.com/stefanpenner/ember-moment');
}

const {
isEmpty
} = Ember;

/**
* Validate over a date range. Uses [MomentJS](http://momentjs.com/) for date mathematics and calculations.
*
* -*Note**: MomentJS must be installed to be able to use this validator. The easiest way to do this is to install [ember-moment](https://github.com/stefanpenner/ember-moment)
*
* #### Options
* - `allowBlank` (**Boolean**): If true, skips validation if the value is empty
* - `before` (**String**): The specified date must be before this date
* - `after` (**String**): The specified date must be after this date
* - `format` (**String**): Input value date format
* - `errorFormat` (**String**): Error output date format. Defaults to `MMM Do, YYYY`
*
* ```javascript
* // Example
* validator('date', {
* after: 'now',
* before: '1/1/2020',
* format: 'M/D/YYY',
* errorFormat: 'M/D/YYY'
* })
* // If before or after is set to 'now', the value given to the validator will be tested against the current date and time.
* ```
*
* @class Date
* @module Validators
* @extends Base
*/
export default Base.extend({

_parseDate(dateStr, format) {
if (dateStr === 'now' || isEmpty(dateStr)) {
return moment();
}
return format ? moment(dateStr, format) : moment(new Date(dateStr));
},

validate(value, options) {
const errorFormat = options.errorFormat || 'MMM Do, YYYY';
const format = options.format;
let { before, after } = options;

if (options.allowBlank && isEmpty(value)) {
return true;
}

const date = this._parseDate(value, format);

if (!date.isValid()) {
return this.createErrorMessage('date', value, options);
}

if (format && !moment(value, format, true).isValid()) {
return this.createErrorMessage('wrongDateFormat', value, options);
}

if (before) {
before = this._parseDate(before, format);
if (before < date) {
options.before = before.format(errorFormat);
return this.createErrorMessage('before', value, options);
}
}

if (after) {
after = this._parseDate(after, format);
if (after > date) {
options.after = after.format(errorFormat);
return this.createErrorMessage('after', value, options);
}
}

return true;
}
});
55 changes: 55 additions & 0 deletions addon/validators/dependent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* 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 './base';

const {
get,
isNone,
isEmpty
} = Ember;

/**
* Defines an attribute as valid only if its dependents are valid.
*
* #### Options
* - `on` (**Array**): Attributes this field is dependent on
*
* ```javascript
* // Example
* // Full name will only be valid if firstName and lastName are filled in
* validator('dependent', {
* on: ['firstName', 'lastName'],
* })
* ```
*
* @class Dependent
* @module Validators
* @extends Base
*/
export default Base.extend({
validate(value, options, model) {
if (isNone(options) || isNone(model) || isEmpty(Object.keys(options))) {
return true;
}

if (options.allowBlank && isEmpty(value)) {
return true;
}

if (isEmpty(options.on)) {
return true;
}

const dependentValidations = options.on.map(dependent => get(model, `validations.attrs.${dependent}`));

if (!isEmpty(dependentValidations.filter(v => !get(v, 'isTruelyValid')))) {
return this.createErrorMessage('invalid', value, options);
}

return true;
}
});
Loading