//= require pikaday
//= require autonumeric
/*
DOCUMENTATION
==============
Examples
-------------
Plain Text Inputs
Email Inputs
Date Inputs
Number Inputs
Required positive number with upper unrestricted bounds
Options
-------------
type -> alias (plain text - no type)
calendar -> calendar, date
percent -> percent
number -> number, numeric
money -> money, currency
email -> email
precision (null)
Used on any number type (percent, number, money) to set the amount
of decimals used. The defaults are 2 for numbers, 0 for percent, and 3 for money
min (null)
Sets the minimum value on number types (percent, number, money).
restrictMin (true)
Used to show a message rather than restrict actual input
max (null)
Sets the maximum value on number types (percent, number, money).
restrictMax (true)
Used to show a message rather than restrict actual input
placeholder (null)
Used to set the placeholder
required (false)
Used to show a message if the field is empty
validate (true)
Validates the format of the input if available. Currently this
only supports the following types (email, date, unrestricted min and max)
toString (false)
Return the string version of the input rather than either a number or a date
noIcon (false)
Used to remove the icon if the field has one. Only effects Date types right now.
*/
(function() {
"use strict";
App.register('component').enter(function() {
var template = '
'
var inputTypeMap = {
'money':'money',
'currency':'money',
'number':'number',
'numeric':'number',
'date':'date',
'calendar':'date',
'percent':'percent',
'bool':'bool',
'check':'bool',
'boolean':'bool',
'toggle': 'toggle',
'text':'text',
'email':'text',
'phone':'text',
'option': 'radio',
'radio': 'radio',
'select':'select',
'list':'select'
}
var dataTypeMap = {
'money':'number',
'currency':'number',
'number':'number',
'integer':'number',
'float':'number',
'numeric':'number',
'date':'date',
'calendar':'date',
'percent':'number',
'bool':'bool',
'check':'bool',
'boolean':'bool',
'toggle':'toggle',
'text':'string',
'radio':'radio',
'select':'select'
}
var numericDefaults = {
'money': {aSign: '$', mDec: '2', wEmpty: 'empty'},
'percent': {aSign: '%', pSign: 's', mDec: '0', wEmpty: 'empty'},
'number': {wEmpty: 'empty'},
'integer': {mDec: '0', wEmpty: 'empty'}
}
Vue.component('vue-input', {
mixins: [App.vue.interfaces.formValidation, App.vue.interfaces.contentValidators, App.vue.interfaces.helpers],
template: template,
props: {
'type': {
default: 'plain'
},
'precision': {
default: null
},
'min': {
default: null
},
'max': {
default: null
},
'numberLabel': {
default: null
},
'numberPostLabel': {
default: null
},
'numberPreLabel': {
default: null
},
'restrictMax': {
default: true
},
'restrictMin': {
default: true
},
'placeholder': {
default: null
},
'required': {
default: false
},
'validate': {
default: true
},
'toString': {
default: false
},
'noIcon': {
default: false
},
'value': {
twoWay: true
},
'keyCodes': {
default: true
},
'id': {
default: null
},
'name': {
default: null
},
'optionsForSelect': {
default: function() {return [];}
},
'disabled': {
default: false
}
},
data: function() {
return {
inputValue: null,
message: null,
inputFormat: null,
validating: false,
formatting: true,
renderHTML: false,
obj: null,
showInput: false,
initialValue: this.value,
}
},
ready: function() {
if (this._valueIsEmpty(this.id)) {
this.id = this._randomId();
}
// set the initial value
if (this.isDate) {
if (this._valueIsEmpty(this.value)) {
this.inputValue = this.value;
}else{
this.inputValue = moment(this.value).format(this._formatForDate());
}
}else{
this.inputValue = this.value;
}
this.renderHTML = true;
var self = this;
this.$nextTick(function(){
self.setupNumber();
self.setupDate();
self.validating = true;
$(self.$els.input).on('focus', self.validateContent);
});
},
beforeDestroy: function() {
try {
$(self.$els.input).off('focus');
$(this.$els.input).autoNumeric('destroy');
this.obj.destroy();
}catch(err){}
},
watch: {
disabled: function(newValue) {
if (newValue) {
this.validateContent();
}
},
inputValue: function(newValue) {
if (this.toString) {
this.value = String(newValue);
}else if (this.isDate) {
if (this._valueIsEmpty(newValue)) {
this.value = null;
}else{
this.value = new Date(newValue);
}
}else if (this.isNumber){
try{
this.value = $(this.$els.input).autoNumeric('get');
}catch(e){
this.value = newValue;
}
}else{
this.value = newValue;
}
this.formatContent();
this.validateContent();
}
},
methods: {
setupDate: function() {
if (this.isDate) {
var options = {
field: this.$els.input,
format: this._formatForDate()
};
if (this.hasRestrictedMax) {
options['maxDate'] = new Date(this.max);
}
if (this.hasRestrictedMin) {
options['minDate'] = new Date(this.min);
}
this.obj = new Pikaday(options);
}
},
setupNumber: function() {
if (this.isNumber) {
var baseOptions = numericDefaults[this.type] || numericDefaults[this.dataType] || {};
if (this.precision) {
baseOptions['mDec'] = this.precision;
}
if (this.hasRestrictedMax) {
baseOptions['vMax'] = this.max;
}
if (this.hasRestrictedMin) {
baseOptions['vMin'] = this.min;
}
if (this.numberPostLabel || this.numberLabel) {
baseOptions['aSign'] = this.numberPostLabel || this.numberLabel;
baseOptions['pSign'] = 's';
}else if (this.numberPreLabel) {
baseOptions['aSign'] = this.numberPreLabel;
baseOptions['pSign'] = 'p';
}
var self = this;
$(this.$els.input).autoNumeric('init', baseOptions).on('keyup', function() {
self.value = $(self.$els.input).autoNumeric('get');
});
$(this.$els.input).autoNumeric('set', this.inputValue);
}
},
showInputFor: function(type) {
if (!this.renderHTML) {
return false;
}
return this.dataType === type;
},
incrementValue: function() {
if (this.keyCodes) {
if (this.isDate) {
this.obj.nextMonth();
}
if (this.isNumber) {
if (this.inputValue < this.max) {
this.inputValue++;
}
}
}
},
decrementValue: function() {
if (this.keyCodes) {
if (this.isDate) {
this.obj.prevMonth();
}
if (this.isNumber) {
if (this.inputValue > this.min) {
this.inputValue--;
}
}
}
},
activeObject: function() {
if (this.isDate) {
this.obj.show();
}
},
formatContent: function() {
if (this.formatting) {
if (this.type === 'phone' && this._valueIsPhone(this.inputValue)) {
this.inputValue = App.vue.interfaces.formatters.methods._formatToPhoneNumber(this.inputValue);
}
}
},
validateContent: function() {
this.message = null;
this.inputFormat = null;
if (this.validating && !this.disabled) {
if (this._valueIsEmpty(this.inputValue)) {
if (this.required) {
this.message = "This can't be empty";
this.inputFormat = this._formatForEmpty();
return false;
}else{
// Empty but not required
return true;
}
}
if (this.validate) {
if (this.type === 'email') {
var res = this._valueIsEmail(this.inputValue);
if (!res) {
this.message = "Not a valid email address.";
this.inputFormat = this._formatForEmail();
}
return res;
}else if (this.type === 'phone') {
var res = this._valueIsPhone(this.inputValue);
if (!res) {
this.message = "Not a valid phone number.";
this.inputFormat = this._formatForPhone();
}
return res;
}else if (this.isDate) {
var res = this._valueIsDate(this.inputValue);
if (!res) {
this.message = "Not a valid date.";
this.inputFormat = this._formatForDate();
}
return res;
}else if (this.isNumber) {
if (this.hasUnrestrictedMax && numeral(this.inputValue).value() > this.max) {
this.message = "Number out of range.";
this.inputFormat = "less than or equal to " + this.max;
}else if (this.hasUnrestrictedMin && numeral(this.inputValue).value() < this.min) {
this.message = "Number out of range.";
this.inputFormat = "greater than or equal to " + this.min;
}
}else{
return true;
}
}
}
return true;
},
optionValue: function(option) {
return option.value || option;
},
optionLabel: function(option) {
return option.label || option;
}
},
computed: {
inputType: function() {
return inputTypeMap[this.type] || 'text';
},
dataType: function() {
return dataTypeMap[this.inputType] || 'string';
},
isNumber: function() {
if (this.dataType === 'number') {
return true;
}else{
return false;
}
},
isDate: function() {
if (this.dataType === 'date') {
return true;
}else{
return false;
}
},
isBool: function() {
if (this.dataType === 'bool') {
return true;
}else{
return false;
}
},
isString: function() {
if (this.dataType === 'string') {
return true;
}else{
return false;
}
},
hasRestrictedMax: function() {
if (this.max !== null && this.restrictMax) {
return true;
}else{
return false;
}
},
hasRestrictedMin: function() {
if (this.min !== null && this.restrictMin) {
return true;
}else{
return false;
}
},
hasUnrestrictedMax: function() {
if (this.max !== null && !this.restrictMax) {
return true;
}else{
return false;
}
},
hasUnrestrictedMin: function() {
if (this.min !== null && !this.restrictMin) {
return true;
}else{
return false;
}
},
inputIcon: function() {
if (this.isDate && !this.init) {
return 'fa-calendar';
}
}
}
});
});
})();