diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index db03f7a49..000000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "extends": "google",
- "installedESLint": true,
- "rules": {
- "indent": ["error", 4],
- "require-jsdoc": 0,
- "max-len": 0
- }
-}
diff --git a/.eslintrc.yml b/.eslintrc.yml
new file mode 100644
index 000000000..d92eef6f2
--- /dev/null
+++ b/.eslintrc.yml
@@ -0,0 +1,8 @@
+extends: google
+installedESLint: true
+rules:
+ indent: [error, 4]
+ no-undef: 0
+ require-jsdoc: 0
+ max-len: 0
+ eqeqeq: 0
diff --git a/client/client/src/addresses/index.js b/client/client/src/addresses/index.js
index f66295d37..8afad6631 100644
--- a/client/client/src/addresses/index.js
+++ b/client/client/src/addresses/index.js
@@ -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'];
diff --git a/client/client/src/create/index.js b/client/client/src/create/index.js
index a554df979..6cd940bd9 100644
--- a/client/client/src/create/index.js
+++ b/client/client/src/create/index.js
@@ -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()
);
}
diff --git a/client/core/src/autocomplete/index.js b/client/core/src/autocomplete/index.js
index 80d6b5468..09c9c3535 100644
--- a/client/core/src/autocomplete/index.js
+++ b/client/core/src/autocomplete/index.js
@@ -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());
}
}
diff --git a/client/core/src/directives/validation.js b/client/core/src/directives/validation.js
index b03b27b5d..24fe52efb 100644
--- a/client/core/src/directives/validation.js
+++ b/client/core/src/directives/validation.js
@@ -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('');
+ element.after(errorMsg);
- let template = '';
- 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);
diff --git a/client/core/src/lib/validator.js b/client/core/src/lib/validator.js
index 11c582f47..fa32bf38a 100644
--- a/client/core/src/lib/validator.js
+++ b/client/core/src/lib/validator.js
@@ -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`);
+}
diff --git a/client/core/src/watcher/index.js b/client/core/src/watcher/index.js
index 0d161b6da..9a629a6c4 100644
--- a/client/core/src/watcher/index.js
+++ b/client/core/src/watcher/index.js
@@ -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;
}
}