585 lines
21 KiB
JavaScript
585 lines
21 KiB
JavaScript
|
|
(function (window, $) {
|
|
|
|
function FastVue() {
|
|
|
|
}
|
|
|
|
FastVue.noop = function (a, b, c) { };
|
|
|
|
//解析数字,返回值:NAN或正常数字或''(输入参数为空)
|
|
FastVue.parseNumber = function (val,percent) {
|
|
|
|
switch (typeof val) {
|
|
case 'number': return val;
|
|
case 'string':
|
|
{
|
|
val = val.trim();
|
|
|
|
if (val === '') return '';
|
|
|
|
let isPercent = val.endsWith('%') || percent==true;
|
|
|
|
if (isPercent) {
|
|
val = val.replace(/%+$/, '');
|
|
if (val === '') return '';
|
|
}
|
|
if (val.endsWith('‱')) {
|
|
val = val.replace(/‱+$/, '');
|
|
if (val === '') return '';
|
|
}
|
|
let number = new Number(val);
|
|
|
|
return isPercent ? number / 100 : number;
|
|
}
|
|
default: return Number.NaN;
|
|
}
|
|
};
|
|
|
|
FastVue.extend = $.extend;
|
|
|
|
FastVue.setWidth = function (el, width) {
|
|
width && (el.style.width = typeof width === 'number' ? width + 'px' : width);
|
|
};
|
|
|
|
FastVue.getDomElement = function (el) {
|
|
if (!el) return null;
|
|
if (typeof el === 'string') {
|
|
return document.getElementById(el.startsWith('#') ? el.substring(1) : el);
|
|
}
|
|
el instanceof jQuery && (el = el[0]);
|
|
return el;
|
|
};
|
|
|
|
function Form(options) {
|
|
|
|
if (!(this instanceof Form)) {
|
|
throw 'FastVue.Form is a constructor and should be called with the `new` keyword';
|
|
}
|
|
|
|
this.data = {};
|
|
|
|
this.layout = {
|
|
display: 'inline',
|
|
title: {
|
|
width: 100
|
|
},
|
|
input: {
|
|
width: '165px'
|
|
}
|
|
};
|
|
|
|
this.submit = {
|
|
url: '',
|
|
before() { },
|
|
after() { }
|
|
};
|
|
|
|
this.fields = {};
|
|
|
|
this.view = {};
|
|
|
|
this.init(options);
|
|
}
|
|
|
|
FastVue.Form = Form;
|
|
|
|
window.FastVue = FastVue;
|
|
|
|
}(window, jQuery));
|
|
|
|
//autocomplete
|
|
(function (window, $) {
|
|
|
|
function __resetLookup(options, context) {
|
|
|
|
if (options.lookupFn) {
|
|
let lookupFn = options.lookupFn;
|
|
return options.lookup = function (query, callback) {
|
|
let queryLowerCase = (query || '').toLowerCase();
|
|
let suggestions = lookupFn.call(context) || [];
|
|
if (queryLowerCase) {
|
|
if (options.searchField) {
|
|
suggestions = suggestions.filter(data => {
|
|
return options.searchField.some(x => (data[x] || '').toLowerCase().indexOf(queryLowerCase) !== -1);
|
|
});
|
|
} else {
|
|
suggestions = suggestions.filter(data => {
|
|
return (data[options.valueField] || '').toLowerCase().indexOf(queryLowerCase) !== -1;
|
|
});
|
|
}
|
|
}
|
|
|
|
if (typeof suggestions[0] !== 'object') {
|
|
suggestions = suggestions.map(x => new Object({ value: x, data: x }));
|
|
} else {
|
|
suggestions = suggestions ? suggestions.map(x => {
|
|
return { value: x[options.nameField], data: x };
|
|
}) : [];
|
|
}
|
|
|
|
callback({ suggestions: suggestions });
|
|
};
|
|
}
|
|
|
|
if (!options.lookup) return;
|
|
|
|
if (typeof options.lookup === 'function') {
|
|
let lookupFn = options.lookup;
|
|
return options.lookup = function (query, callback) {
|
|
let queryLowerCase = (query || '').toLowerCase();
|
|
let suggestions = lookupFn.call(context, queryLowerCase) || [];
|
|
if (typeof suggestions[0] !== 'object') {
|
|
suggestions = suggestions.map(x => new Object({ value: x, data: x }));
|
|
} else {
|
|
suggestions = suggestions.map(x => {
|
|
return { value: x[options.nameField], data: x };
|
|
});
|
|
}
|
|
callback({ suggestions: suggestions });
|
|
};
|
|
}
|
|
|
|
if (Array.isArray(options.lookup)) {
|
|
|
|
let lookup = options.lookup;
|
|
|
|
if (typeof lookup[0] !== 'object') {
|
|
return options.lookup = lookup.map(x => new Object({ value: x, data: x }));
|
|
}
|
|
|
|
options.lookup = lookup.map(x => {
|
|
return { value: x[options.nameField], data: x };
|
|
});
|
|
|
|
if (options.searchField) {
|
|
options.lookupFilter = function (suggestion, originalQuery, queryLowerCase) {
|
|
return options.searchField.some(x => (suggestion.data[x] || '').toLowerCase().indexOf(queryLowerCase) !== -1);
|
|
};
|
|
} else {
|
|
options.lookupFilter = function (suggestion, originalQuery, queryLowerCase) {
|
|
return (suggestion.value || '').toLowerCase().indexOf(queryLowerCase) !== -1;
|
|
};
|
|
}
|
|
|
|
} else {
|
|
throw '[autocomplete.lookup]必须为数组或函数';
|
|
}
|
|
}
|
|
|
|
FastVue.autocomplete = function (el, options, context) {
|
|
|
|
!context && (context = this);
|
|
|
|
el = FastVue.getDomElement(el)
|
|
|
|
if (!el) throw '[FastVue.autocomplete]el is null or undefined:' + (options ? options.debugInfo : '');
|
|
|
|
let _el = el;//_el对应nameField
|
|
|
|
options = Object.assign({ minChars: 0, autoSelectFirst: true }, options);
|
|
|
|
!options.valueField && (options.valueField = options.nameField || 'value');
|
|
!options.nameField && (options.nameField = options.valueField);
|
|
|
|
if (options.nameField !== options.valueField) {
|
|
_el = el.cloneNode(true);
|
|
_el.setAttribute('name', '');
|
|
_el.setAttribute('value', '');
|
|
_el.id && _el.setAttribute('id', _el.id + '_auto');
|
|
el.setAttribute('type', 'hidden');
|
|
if (!el.parentNode) {
|
|
document.createElement("div").append(el);
|
|
}
|
|
el.parentNode.insertBefore(_el, el);
|
|
el.dataset.autocompleteClone = _el;
|
|
}
|
|
|
|
__resetLookup(options, context);
|
|
|
|
const onSelectFn = options.onSelect;
|
|
options.onSelect = function (suggestion) {
|
|
_el.dataset.select = '1';
|
|
if (options.nameField !== options.valueField) {
|
|
el.value = suggestion.data[options.valueField];
|
|
}
|
|
onSelectFn && onSelectFn(suggestion.data);
|
|
};
|
|
|
|
$(_el).autocomplete('dispose');
|
|
|
|
$(_el).on('focus', function () {
|
|
this.setAttribute("placeholder", this.value);
|
|
this.value = '';
|
|
this.dataset.select = '';
|
|
}).on('blur', function () {
|
|
!this.dataset.select && (this.value = this.getAttribute("placeholder"));
|
|
this.setAttribute("placeholder", '');
|
|
}).on('keydown', function (event) {
|
|
if ((event.which || event.keyCode) === 13) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
$(this).blur();
|
|
}
|
|
}).autocomplete(options);
|
|
|
|
return {
|
|
setData(data) {
|
|
if (options.nameField === options.valueField) {
|
|
_el.value = (typeof data === 'object' ? data[options.nameField] : data) || '';
|
|
} else if (data) {
|
|
el.value = data[options.valueField] || '';
|
|
_el.value = data[options.nameField] || '';
|
|
} else {
|
|
_el.value = el.value = '';
|
|
}
|
|
},
|
|
dispose() {
|
|
$(_el).autocomplete('dispose');
|
|
$(_el).remove();
|
|
},
|
|
toggleDisabled(disabled) {
|
|
_el.disabled = typeof disabled === 'undefined' ? !_el.disabled : !!disabled;
|
|
},
|
|
clearCache() {
|
|
$(_el).autocomplete('clearCache');
|
|
},
|
|
setOptions(newOptions) {
|
|
$(_el).autocomplete('setOptions', Object.assign({}, options, newOptions));
|
|
}
|
|
};
|
|
};
|
|
|
|
//静态dispose方法
|
|
FastVue.autocomplete.dispose = function (el) {
|
|
(el instanceof jQuery) && (el = el.get(0));
|
|
if (!el) return;
|
|
$(el).autocomplete('dispose');
|
|
el.dataset && $(el.dataset.autocompleteClone).autocomplete('dispose');
|
|
};
|
|
|
|
}(FastVue, jQuery));
|
|
|
|
//numberInput
|
|
(function (window, $) {
|
|
|
|
FastVue.numberInput = function (el, options) {
|
|
|
|
let _el = typeof el === 'string' ? document.getElementById(el.replace(/^#/, '')) : el instanceof jQuery ? el[0] : el;
|
|
|
|
if (!_el) {
|
|
throw "[FastVue.numberInput]not found el:" + el;
|
|
}
|
|
|
|
let _ctrlV = false, _chnInput = -1;
|
|
|
|
let _options = { append: '', precision: 2, negative: false, grouping: false };
|
|
|
|
function getValue() {
|
|
let val = _el.value;
|
|
if (val && val !== _options.append) {
|
|
_options.append && _options.append !== '%' && _options.append !== '‱' && (val = val.replace(new RegExp(_options.append + "$"), ''));
|
|
return FastVue.parseNumber(val, _options.percent);
|
|
}
|
|
return '';
|
|
}
|
|
|
|
function setOptions(options) {
|
|
options = Object.assign(_options, options);
|
|
!options.append && (options.append = '');
|
|
let precision = parseInt(options.precision) || 0;
|
|
options.precision = precision < 0 ? 0 : precision;
|
|
options.negative = !!options.negative;
|
|
_options = options;
|
|
setValue(getValue());
|
|
}
|
|
|
|
function setValue(value) {
|
|
if (value || value === 0) {
|
|
let oval = parseFloat(value) || 0;
|
|
if (_options.append === '%' || _options.percent == true) {
|
|
oval *= 100;
|
|
}
|
|
else if (_options.append ==="‱") {
|
|
oval *= 10000;
|
|
}
|
|
if (_options.precision > 0) {
|
|
let str = main.formatNumber(oval, _options.precision, { grouping: _options.grouping });
|
|
if (typeof value === 'number' && str.endsWith("0") && str.includes('.')) {
|
|
str = str.replace(/\.?0+$/, '');
|
|
}
|
|
_el.value = str + _options.append;
|
|
} else {
|
|
let str = main.formatNumber(Math.floor(oval), 0, { grouping: _options.grouping });
|
|
_el.value = str + _options.append;
|
|
}
|
|
} else {
|
|
_el.value = '';
|
|
}
|
|
}
|
|
|
|
function checkDotInput() {
|
|
if (this.selectionStart >= this.value.length) {
|
|
return _options.append && this.value.endsWith(_options.append) ? false : this.value.indexOf('.') < 0;
|
|
}
|
|
if (this.value.length - _options.append.length - this.selectionEnd > _options.precision) {
|
|
return false;
|
|
}
|
|
return this.value.substring(0, this.selectionStart).indexOf('.') < 0 && this.value.substring(this.selectionEnd, this.value.length).indexOf('.') < 0;
|
|
}
|
|
|
|
function __keyHandle(event) {
|
|
if (!event) return false;
|
|
|
|
_chnInput = -1;
|
|
|
|
let charCode = event.which || event.keyCode;
|
|
|
|
switch (charCode) {
|
|
case 8: //break space
|
|
return !_options.append || !this.value.endsWith(_options.append) || this.selectionStart < this.value.length - _options.append.length + 1;
|
|
case 9: //tab
|
|
case 35: //end
|
|
case 36: //home
|
|
case 37: //left arrow
|
|
case 39: //right arrow
|
|
case 42: //print
|
|
case 116: //F5
|
|
return true;
|
|
case 46: //del
|
|
return !_options.append || !this.value.endsWith(_options.append) || this.selectionStart < this.value.length - _options.append.length;
|
|
case 229:
|
|
return _chnInput = this.selectionStart;
|
|
}
|
|
|
|
if (event.shiftKey) return false;
|
|
|
|
switch (charCode) {
|
|
case 109: //negative sign(-)
|
|
return _options.negative && this.selectionStart < 1 && this.value.charAt(0) !== '-';
|
|
case 189: //negative sign(-_)
|
|
return _options.negative && !event.shiftKey && this.selectionStart < 1 && this.value.charAt(0) !== '-';
|
|
case 110: //dot(.)
|
|
return _options.precision > 0 && checkDotInput.call(this);
|
|
case 190: //dot(.>)
|
|
return _options.precision > 0 && !event.shiftKey && checkDotInput.call(this);
|
|
case 13: //enter
|
|
case 108: //enter
|
|
$(this).blur();
|
|
return true;
|
|
case 67: //ctrl+c
|
|
return event.ctrlKey;
|
|
case 86: //ctrl+v
|
|
return event.ctrlKey && (_ctrlV = true);
|
|
default:
|
|
if (charCode < 48 || charCode > 57 && (charCode < 96 || charCode > 105)) {
|
|
return false;
|
|
}
|
|
if (this.selectionStart === 0) {
|
|
return !this.value || this.value.charAt(this.selectionEnd) !== '-';
|
|
}
|
|
if (_options.precision < 1) {
|
|
return true;
|
|
}
|
|
if (this.selectionStart >= this.value.length && _options.append && this.value.endsWith(_options.append)) {
|
|
return false;
|
|
}
|
|
if (this.selectionEnd > this.selectionStart) {
|
|
return /\d/.test(this.value.substring(this.selectionStart, this.selectionEnd));
|
|
} else {
|
|
let dotIndex = this.value.lastIndexOf('.', this.selectionStart - 1);
|
|
return dotIndex < 0 || !/\d/.test(this.value[dotIndex + _options.precision]);
|
|
}
|
|
}
|
|
}
|
|
|
|
//处理中文字符输入
|
|
function __onChineseInput(chnPos) {
|
|
if (this.value.length < chnPos) {
|
|
chnPos = this.value.length - 1;
|
|
}
|
|
let ch = this.value.charCodeAt(chnPos);
|
|
if (ch > 47 && ch < 58) {
|
|
chnPos += 1;
|
|
}
|
|
else if (ch === 46 || ch === 12290) {
|
|
if (_options.precision > 0 && !/\d/.test(this.value[this.selectionStart + _options.precision])
|
|
&& this.value.lastIndexOf('.', chnPos - 1) < 0 && this.value.indexOf('.', this.selectionStart) < 0) {
|
|
if (ch === 12290) {
|
|
this.value = this.value.substring(0, chnPos) + '.' + this.value.substring(this.selectionStart);
|
|
this.setSelectionRange(chnPos + 1, chnPos + 1);
|
|
return;
|
|
}
|
|
chnPos += 1;
|
|
}
|
|
}
|
|
else if (chnPos === 0 && ch === 45 && _options.negative && this.value[this.selectionStart] !== '-') { //负号
|
|
return;
|
|
} else {
|
|
for (; chnPos >= 0; chnPos--) {
|
|
ch = this.value.charCodeAt(chnPos);
|
|
if (ch === 46 || ch > 47 && ch < 58 || chnPos === 0 && ch === 45 && _options.negative) {
|
|
chnPos += 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
this.value = this.value.substring(0, chnPos) + this.value.substring(this.selectionStart);
|
|
this.setSelectionRange(chnPos, chnPos);
|
|
}
|
|
|
|
//处理字符输入
|
|
function __onInput() {
|
|
if (_ctrlV) {
|
|
_ctrlV = false;
|
|
return setValue(this.value);
|
|
}
|
|
if (_chnInput >= 0) {
|
|
__onChineseInput.call(this, _chnInput);
|
|
}
|
|
if (!_options.append || !this.value) return;
|
|
let appended = true;
|
|
if (this.value !== _options.append) {
|
|
appended = this.value.endsWith(_options.append);
|
|
}
|
|
if (!appended) {
|
|
let caretPos = this.selectionStart;
|
|
this.value += _options.append;
|
|
this.setSelectionRange(caretPos, caretPos);
|
|
} else if (_options.negative && this.selectionStart === 2 && this.value[1] === '-') {
|
|
this.value = this.value.substring(1);
|
|
this.setSelectionRange(1, 1);
|
|
}
|
|
}
|
|
|
|
//输入完成处理
|
|
function __change() {
|
|
let f = '';
|
|
if (this.value && this.value !== _options.append) {
|
|
f = parseFloat(this.value.replaceAll(",", "")) || 0;
|
|
if (_options.append === '%' || _options.percent == true) f /= 100;
|
|
else if (_options.append === '‱') f /= 10000;
|
|
|
|
}
|
|
_options.onchange && _options.onchange(f, this.value);
|
|
}
|
|
|
|
//功能禁用
|
|
function __disable() {
|
|
return false;
|
|
}
|
|
|
|
setOptions(options);
|
|
|
|
$(_el).on('keydown', __keyHandle).on('dragenter', __disable).on('input', __onInput).on('change', __change);
|
|
|
|
return {
|
|
isEmpty() {
|
|
return !_el.value || _el.value === _options.append;
|
|
},
|
|
getValue: getValue,
|
|
setValue: setValue,
|
|
setOptions: setOptions,
|
|
getOptions() {
|
|
return Object.assign({}, _options);
|
|
},
|
|
dispose() {
|
|
$(_el).off();
|
|
}
|
|
};
|
|
};
|
|
|
|
//静态dispose方法
|
|
FastVue.numberInput.dispose = function (el) {
|
|
(el instanceof jQuery ? el : $(el)).off();
|
|
};
|
|
|
|
}(FastVue, jQuery));
|
|
|
|
//FastVue.vueNumberInput
|
|
//数字输入组件(借助FastVue.numberInput)
|
|
(function (global) {
|
|
|
|
global.vueNumberInput = function () {
|
|
return {
|
|
props: {
|
|
value: {
|
|
type: Number,
|
|
default: ''
|
|
},
|
|
format: {
|
|
type: Object,
|
|
default: {
|
|
append: '',
|
|
precision: 2,
|
|
negative: false,
|
|
grouping: false,
|
|
percent: false
|
|
}
|
|
},
|
|
disabled: {
|
|
type: Boolean
|
|
},
|
|
ret_type: {
|
|
type: Number,
|
|
default: 0
|
|
}
|
|
},
|
|
data() {
|
|
return { inputctrl: null,init:true};
|
|
},
|
|
mounted() {
|
|
let self = this;
|
|
let options = FastVue.extend({ onchange: this.onchange }, this.format);
|
|
this.inputctrl = FastVue.numberInput(this.$el, options);
|
|
this.inputctrl.setValue(this.value)
|
|
},
|
|
methods: {
|
|
onchange(value, text) {
|
|
this.init = false;
|
|
this.$emit('input', this.ret_type === 1 ? text : value);
|
|
}
|
|
},
|
|
watch: {
|
|
value(val, old) {
|
|
let val1 = '';
|
|
switch (typeof val) {
|
|
case 'number':
|
|
val1 = val || 0; break;
|
|
case 'string':
|
|
if (val) {
|
|
val1 = parseFloat(val) || 0;
|
|
if (val1 && (val.trimEnd().endsWith('%') || (this.format.percent && !this.init))) {
|
|
val1 /= 100;
|
|
} else if (val1 && (val.trimEnd().endsWith('‱'))){
|
|
val1 /= 10000;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (!this.inputctrl.isEmpty()) {
|
|
let val2 = this.inputctrl.getValue();
|
|
if (Math.abs(val1 - val2) < 1e-10) return;
|
|
}
|
|
this.$nextTick(function () {
|
|
this.inputctrl.setValue(val1);
|
|
});
|
|
},
|
|
format: {
|
|
deep: true,
|
|
handler(val) {
|
|
this.inputctrl.setOptions(val);
|
|
this.$nextTick(function () {
|
|
this.inputctrl.setValue(this.value);
|
|
});
|
|
}
|
|
}
|
|
},
|
|
destroyed() {
|
|
FastVue.numberInput.dispose(this.$el);
|
|
},
|
|
template: '<input type="text" v-bind:disabled="disabled">'
|
|
};
|
|
};
|
|
|
|
}(window.FastVue)); |