bug validaciones, eslint en formato yml

This commit is contained in:
Juan Ferrer Toribio 2017-03-07 12:37:59 +01:00
parent 2cb110feee
commit 3a16f09494
8 changed files with 179 additions and 177 deletions

View File

@ -1,9 +0,0 @@
{
"extends": "google",
"installedESLint": true,
"rules": {
"indent": ["error", 4],
"require-jsdoc": 0,
"max-len": 0
}
}

8
.eslintrc.yml Normal file
View File

@ -0,0 +1,8 @@
extends: google
installedESLint: true
rules:
indent: [error, 4]
no-undef: 0
require-jsdoc: 0
max-len: 0
eqeqeq: 0

View File

@ -5,7 +5,7 @@ class Controller {
this.$state = $state;
}
onNewAddressClick() {
this.$state.go('clientCard.addressCreate', {id: this.client.id});
this.$state.go('clientCard.addressCreate', {id: this.$state.params.id});
}
}
Controller.$inject = ['$state'];

View File

@ -10,12 +10,12 @@ class Controller {
};
}
onSubmit() {
this.$scope.watcher.submit().then (
json => this.$state.go(state, {id: json.data.id})
this.$scope.watcher.submit().then(
json => this.$state.go('clientCard.basicData', {id: json.data.id})
);
}
onCreate() {
this.$scope.watcher.submit().then (
this.$scope.watcher.submit().then(
() => this.$window.history.back()
);
}

View File

@ -46,7 +46,7 @@ export default class Autocomplete extends Component {
loadData(textFilter) {
textFilter = textFilter ? textFilter : '';
if(this.lastSearch === textFilter) {
if (this.lastSearch === textFilter) {
this.popoverDataReady();
return;
}
@ -58,7 +58,7 @@ export default class Autocomplete extends Component {
&& !this.moreData
&& textFilter.substr(0, lastRequest.length) === lastRequest;
if(requestWillSame)
if (requestWillSame)
this.localFilter(textFilter);
else
this.requestData(textFilter, false);
@ -73,9 +73,9 @@ export default class Autocomplete extends Component {
let where = {};
let skip = 0;
if(textFilter)
if (textFilter)
where[this.showField] = {ilike: textFilter};
if(append && this.data)
if (append && this.data)
skip = this.data.length;
let filter = {
@ -89,7 +89,7 @@ export default class Autocomplete extends Component {
this.lastRequest = textFilter ? textFilter : '';
let json = JSON.stringify(filter);
if(this.currentRequest)
if (this.currentRequest)
this.currentRequest.resolve();
this.currentRequest = this.$http.get(`${this.url}?filter=${json}`);
@ -102,7 +102,7 @@ export default class Autocomplete extends Component {
this.currentRequest = null;
this.moreData = data.length >= this.maxRows;
if(!append || !this.data)
if (!append || !this.data)
this.data = data;
else
this.data = this.data.concat(data);
@ -111,7 +111,7 @@ export default class Autocomplete extends Component {
}
localFilter(textFilter) {
let regex = new RegExp(textFilter, 'i');
let data = this.data.filter((item) => {
let data = this.data.filter(item => {
return regex.test(item[this.showField]);
});
this.setPopoverData(data);
@ -121,80 +121,78 @@ export default class Autocomplete extends Component {
this.popoverDataReady();
}
popoverDataReady() {
if(this.hasFocus)
if (this.hasFocus)
this.showPopover();
}
showPopover() {
if(!this.data) return;
if (!this.data) return;
let fragment = this.document.createDocumentFragment();
let data = this.popoverData;
for(let i = 0; i < data.length; i++) {
for (let i = 0; i < data.length; i++) {
let li = this.document.createElement('li');
li.appendChild(this.document.createTextNode(data[i][this.showField]));
fragment.appendChild(li);
}
if(this.moreData) {
if (this.moreData) {
let li = this.document.createElement('li');
li.appendChild(this.document.createTextNode('Load more'));
li.className = 'load-more';
fragment.appendChild(li);
}
if (!this.popover) {
if (this.popover) {
this.popover.innerHTML = '';
this.popover.appendChild(fragment);
} else {
let popover = this.document.createElement('ul');
popover.addEventListener('click',
(e) => this.onPopoverClick(e));
e => this.onPopoverClick(e));
popover.addEventListener('mousedown',
(e) => this.onPopoverMousedown(e));
e => this.onPopoverMousedown(e));
popover.className = 'vn-autocomplete';
popover.appendChild(fragment);
this.vnPopover.show(popover, this.input);
this.popover = popover;
}
else {
this.popover.innerHTML = '';
this.popover.appendChild(fragment);
}
}
hidePopover() {
if(!this.popover) return;
if (!this.popover) return;
this.activeOption = -1;
this.vnPopover.hide();
this.popover = null;
}
selectPopoverOption(index) {
if(!this.popover || index == -1) return;
if(index < this.popoverData.length) {
if (!this.popover || index === -1) return;
if (index < this.popoverData.length) {
this.selectOptionByDataIndex(this.popoverData, index);
this.hidePopover();
}
else
} else
this.requestData(this.lastRequest, true);
}
onPopoverClick(event) {
let childs = this.popover.childNodes;
for(let i = 0; i < childs.length; i++)
if(childs[i] === event.target) {
this.selectPopoverOption(i);
break;
}
for (let i = 0; i < childs.length; i++)
if (childs[i] === event.target) {
this.selectPopoverOption(i);
break;
}
}
onPopoverMousedown(event) {
// Prevents input from loosing focus
event.preventDefault();
}
onClick(event) {
if(!this.popover)
if (!this.popover)
this.showPopover();
}
onFocus() {
this.hasFocus = true;
this.input.select();
if(this.data)
if (this.data)
this.showPopover();
else
this.loadData();
@ -205,29 +203,29 @@ export default class Autocomplete extends Component {
this.hidePopover();
}
onKeydown(event) {
switch(event.keyCode) {
case 13: // Enter
this.selectPopoverOption(this.activeOption);
break;
case 27: // Escape
this.restoreShowValue();
this.input.select();
break;
case 38: // Arrow up
this.activateOption(this.activeOption-1);
break;
case 40: // Arrow down
this.activateOption(this.activeOption+1);
break;
default:
return;
switch (event.keyCode) {
case 13: // Enter
this.selectPopoverOption(this.activeOption);
break;
case 27: // Escape
this.restoreShowValue();
this.input.select();
break;
case 38: // Arrow up
this.activateOption(this.activeOption - 1);
break;
case 40: // Arrow down
this.activateOption(this.activeOption + 1);
break;
default:
return;
}
event.preventDefault();
}
onKeyup(event) {
if(!this.isKeycodePrintable(event.keyCode)) return;
if(this.timeoutId) clearTimeout(this.timeoutId);
if (!this.isKeycodePrintable(event.keyCode)) return;
if (this.timeoutId) clearTimeout(this.timeoutId);
this.timeoutId = setTimeout(() => this.onTimeout(), this.requestDelay);
}
onTimeout() {
@ -235,8 +233,8 @@ export default class Autocomplete extends Component {
this.timeoutId = null;
}
isKeycodePrintable(keyCode) {
return keyCode == 32 // Spacebar
|| keyCode == 8 // Backspace
return keyCode === 32 // Spacebar
|| keyCode === 8 // Backspace
|| (keyCode > 47 && keyCode < 58) // Numbers
|| (keyCode > 64 && keyCode < 91) // Letters
|| (keyCode > 95 && keyCode < 112) // Numpad
@ -247,14 +245,14 @@ export default class Autocomplete extends Component {
this.putItem(this.item);
}
requestItem() {
if(!this.value) return;
if (!this.value) return;
let where = {};
where[this.valueField] = this.value;
let filter = {
fields: this.getRequestFields(),
where: where,
where: where
};
let json = JSON.stringify(filter);
@ -265,25 +263,25 @@ export default class Autocomplete extends Component {
);
}
onItemRequest(data) {
if(data && data.length > 0)
if (data && data.length > 0)
this.showItem(data[0]);
else
this.showItem(null);
}
activateOption(index) {
if(!this.popover)
if (!this.popover)
this.showPopover();
let popover = this.popover;
let childs = popover.childNodes;
let len = this.popoverData.length;
if(this.activeOption >= 0)
if (this.activeOption >= 0)
childs[this.activeOption].className = '';
if(index >= len)
if (index >= len)
index = 0;
else if(index < 0)
else if (index < 0)
index = len - 1;
if (index >= 0) {
@ -291,9 +289,9 @@ export default class Autocomplete extends Component {
let top = popover.scrollTop;
let height = popover.clientHeight;
if(opt.offsetTop + opt.offsetHeight > top + height)
if (opt.offsetTop + opt.offsetHeight > top + height)
top = opt.offsetTop + opt.offsetHeight - height;
else if(opt.offsetTop < top)
else if (opt.offsetTop < top)
top = opt.offsetTop;
opt.className = 'active';
@ -305,26 +303,25 @@ export default class Autocomplete extends Component {
setValue(value) {
this.value = value;
if(value) {
if (value) {
let data = this.data;
if(data)
for(let i = 0; i < data.length; i++)
if(data[i][this.valueField] == value) {
this.putItem(data[i]);
return;
}
if (data)
for (let i = 0; i < data.length; i++)
if (data[i][this.valueField] == value) {
this.putItem(data[i]);
return;
}
this.requestItem();
}
else
} else
this.putItem(null);
}
selectOptionByIndex(index) {
this.selectOptionByDataIndex(this.data, index);
}
selectOptionByDataIndex(data, index) {
if(data && index >= 0 && index < data.length)
if (data && index >= 0 && index < data.length)
this.putItem(data[index]);
else
this.putItem(null);
@ -333,9 +330,9 @@ export default class Autocomplete extends Component {
this.showItem(item);
let value = item ? item[this.valueField] : undefined;
if(!this.locked) {
if (!this.locked) {
this.value = value;
setTimeout (
setTimeout(
() => this.$scope.$apply());
}
}

View File

@ -8,59 +8,64 @@ export function directive(interpolate, compile, $window) {
restrict: 'A',
require: ['ngModel', '^^form'],
link: link
}
};
function link(scope, element, attrs, ctrl) {
let vnValidations = $window.validations;
if(!attrs['vnValidation'] || ! vnValidations)
if (!attrs.vnValidation || !vnValidations)
return;
let split = attrs['vnValidation'].split('.');
let split = attrs.vnValidation.split('.');
if(split.length != 2)
if (split.length !== 2)
throw new Error(`vnValidation: Attribute must have this syntax: [entity].[field]`);
let entityName = firstUpper(split[0]);
let fieldName = split[1];
let entity = vnValidations[entityName];
if(!entity)
if (!entity)
throw new Error(`vnValidation: Entity '${entityName}' doesn't exist`);
let validations = entity.validations[fieldName];
if(!validations || validations.length == 0)
if (!validations || validations.length == 0)
return;
let input = ctrl[0],
form = ctrl[1];
let errorMsg = angular.element('<span class="mdl-textfield__error"></span>');
element.after(errorMsg);
let template = '<span class="mdl-textfield__error" ng-show="{{form}}.$dirty && {{form}}.{{input}}.$invalid"></span>';
let messageNode = interpolate(template)({form: form.$name, input: input.$name});
messageNode = angular.element(messageNode);
let input = ctrl[0];
let form = ctrl[1];
input.$validators['entity'] = function(value) {
return isValid(value, validations, messageNode, element);
}
input.$validators.entity = function(value) {
let parent = element.parent();
element.after(compile(messageNode)(scope));
}
function isValid(value, validations, messageNode, element) {
let parent = element.parent();
try {
validateAll(value, validations);
} catch (e) {
errorMsg.text(e.message);
parent.attr('title', e.message);
return false;
}
try {
validateAll(value, validations)
}
catch(e) {
messageNode.text(e.message);
parent.attr('title', e.message);
parent.addClass('invalid');
return false;
}
return true;
};
parent.removeClass('invalid');
return true;
scope.$watch(function() {
return (form.$submitted || input.$dirty) && input.$invalid;
}, function(value) {
let parent = element.parent();
if (value) {
parent.addClass('invalid');
errorMsg[0].style.display = 'block';
} else {
parent.removeClass('invalid');
errorMsg[0].style.display = 'none';
}
});
}
}
module.directive('vnValidation', directive);

View File

@ -1,36 +1,12 @@
import {validator} from 'vendor';
export function validateAll(value, validations) {
for(let conf of validations)
validate(value, conf);
}
export function validate(value, conf) {
let validator = validators[conf.validation];
try {
checkNull(value, conf);
validator && validator(value, conf);
}
catch(e) {
let message = conf.message ? conf.message : e.message;
throw new Error(message);
}
}
export function checkNull(value, conf) {
if (typeof value === 'undefined') {
if (!conf.allowBlank)
throw new Error(`Value can't be blank`);
} else {
if (value === null && !conf.allowNull)
throw new Error(`Value can't be null`);
}
}
export const validators = {
presence: function(value, conf) {
if(validator.isEmpty(value))
if (validator.isEmpty(value))
throw new Error(`Value can't be empty`);
},
absence: function() {
if(!validator.isEmpty(value))
absence: function(value, conf) {
if (!validator.isEmpty(value))
throw new Error(`Value should be empty`);
},
length: function(value, conf) {
@ -38,34 +14,31 @@ export const validators = {
min: conf.min || conf.is,
max: conf.max || conf.is
};
if(!validator.isLength(value, options)) {
if(conf.is)
if (!validator.isLength(value, options)) {
if (conf.is)
throw new Error(`Value should be ${conf.is} characters long`);
else
throw new Error(`Value should have a length between ${conf.min} and ${conf.max}`);
}
},
numericality: function(value, conf) {
if(conf.int) {
if(!validator.isInt(value))
if (conf.int) {
if (!validator.isInt(value))
throw new Error(`Value should be integer`);
}
else {
if(!validator.isNumeric(vlaue))
throw new Error(`Value should be a number`);
}
} else if (!validator.isNumeric(value))
throw new Error(`Value should be a number`);
},
inclusion: function(value, conf) {
if(!validator.isIn(value, conf.in))
if (!validator.isIn(value, conf.in))
throw new Error(`Invalid value`);
},
exclusion: function(value, conf) {
if(validator.isIn(value, conf.in))
if (validator.isIn(value, conf.in))
throw new Error(`Invalid value`);
},
format: function(value, conf) {
if(!validator.matches(value, conf.with))
if (!validator.matches(value, conf.with))
throw new Error(`Invalid value`);
},
custom: function(value, conf) {
@ -75,12 +48,42 @@ export const validators = {
}
let inst = {attr: value};
conf.customValidator.call(inst, err)
conf.customValidator.call(inst, err);
if(!valid)
if (!valid)
throw new Error(`Invalid value`);
},
uniqueness: function() {
// TODO: Implement me
},
}
};
export function validateAll(value, validations) {
for (let conf of validations)
validate(value, conf);
}
export function validate(value, conf) {
let validator = validators[conf.validation];
try {
checkNull(value, conf);
if (validator) validator(value, conf);
} catch (e) {
let message = conf.message ? conf.message : e.message;
throw new Error(message);
}
}
/**
* Checks if value is null.
*
* @param {value} value The value
* @param {Object} conf The configuration for the field
*/
export function checkNull(value, conf) {
if (typeof value === 'undefined') {
if (!conf.allowBlank)
throw new Error(`Value can't be blank`);
} else if (value === null && !conf.allowNull)
throw new Error(`Value can't be null`);
}

View File

@ -21,16 +21,16 @@ export default class Watcher extends Component {
this.state = null;
this.deregisterCallback = $transitions.onStart({},
(transition) => this.callback(transition));
transition => this.callback(transition));
this.copyData();
}
$onInit() {
if(this.get) {
if (this.get) {
this.fetchData();
}
}
$onChanges(changes) {
if(this.data) {
if (this.data) {
this.copyData();
}
}
@ -47,19 +47,19 @@ export default class Watcher extends Component {
});
}
submit() {
if(this.form && !this.form.$valid) {
return new Promise (
if (this.form && !this.form.$valid) {
return new Promise(
(resolve, reject) => this.invalidForm(reject)
);
}
if (!this.dataChanged()) {
return new Promise (
return new Promise(
(resolve, reject) => this.noChanges(reject)
);
}
let changedData = getModifiedData(this.data, this.orgData);
if(this.save) {
if (this.save) {
this.save.model = changedData;
return new Promise((resolve, reject) => {
this.save.accept().then(
@ -73,7 +73,7 @@ export default class Watcher extends Component {
let id = this.orgData[this.idField];
if(id) {
if (id) {
return new Promise((resolve, reject) => {
this.$http.put(`${this.url}/${id}`, changedData).then(
json => this.writeData(json, resolve),
@ -81,14 +81,13 @@ export default class Watcher extends Component {
);
});
}
else {
return new Promise((resolve, reject) => {
this.$http.post(this.url, this.data).then(
json => this.writeData(json, resolve),
json => reject(json)
);
});
}
return new Promise((resolve, reject) => {
this.$http.post(this.url, this.data).then(
json => this.writeData(json, resolve),
json => reject(json)
);
});
}
writeData(json, resolve) {
copyObject(json.data, this.data);
@ -116,18 +115,17 @@ export default class Watcher extends Component {
this.$scope.confirm.show();
return false;
}
return true;
}
dataChanged() {
return !isEqual(this.data, this.orgData);
}
onConfirmResponse(response) {
if(response == 'ACCEPT') {
if (response === 'ACCEPT') {
copyObject(this.orgData, this.data);
this.$state.go(this.state);
}
else {
} else {
this.state = null;
}
}