Commit a3510307 authored by NikulinR's avatar NikulinR

Initial commit

parent d8f458c1
{
"presets": [
["es2015", { "modules": false }]
]
}
.DS_Store
node_modules/
dist/
npm-debug.log
# vue-masked-input # Vue Masked Input
\ No newline at end of file Dead simple masked input component for Vue.js 2.X. Based on [inputmask-core](https://github.com/insin/inputmask-core).
### [Live Demo](http://127.0.0.1)
## Install
### npm
```
npm install vue-masked-input --save
```
## Usage
Use it with `v-model` just like a native html input with the `mask` attribute:
```vue
<masked-input v-model="date" mask="11/11/1111" placeholder="dd/mm/yyyy" />
```
The following format characters define editable parts of the mask (see [inputmask-core](https://github.com/insin/inputmask-core)):
* `1` - number
* `a` - letter
* `A` - letter, forced to upper case when entered
* `*` - alphanumeric
* `#` - alphanumeric, forced to upper case when entered
If you need to include one of these characters as a static part of the mask, you can escape them with a preceding backslash:
```vue
<masked-input v-model="date" mask="+\\1 (111) 111-1111" placeholder="Phone number" type="tel" />
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>vue-masked-input</title>
</head>
<body>
<div id="app"></div>
<script src="/dist/build.js"></script>
</body>
</html>
{
"name": "vue-masked-input",
"description": "Masked input component for Vue.js 2.X",
"version": "0.1.0",
"author": "niksmr",
"private": true,
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --open --inline --hot",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
},
"dependencies": {
"inputmask-core": "^2.2.0",
"vue": "^2.1.0"
},
"devDependencies": {
"babel-core": "^6.0.0",
"babel-loader": "^6.0.0",
"babel-preset-es2015": "^6.0.0",
"cross-env": "^3.0.0",
"css-loader": "^0.25.0",
"file-loader": "^0.9.0",
"vue-loader": "^10.0.0",
"vue-template-compiler": "^2.1.0",
"webpack": "^2.1.0-beta.25",
"webpack-dev-server": "^2.1.0-beta.9"
}
}
<template>
<div id="app">
<h1>Vue Masked Input</h1>
<h3>Dead simple masked input component for Vue.js 2.X</h3>
<hr />
<h4>Date: </h4>
<masked-input v-model="date" mask="11 / 11 / 1111" placeholder="Date" /><span v-if="">{{ date }}</span>
<p class="code">
&lt;masked-input v-model="date" mask="11 / 11 / 1111" placeholder="Date" /&gt;
</p>
<h4>Phone: </h4>
<masked-input v-model="phone" mask="+\1 (111) 1111-11" placeholder="Phone" /><span>{{ phone }}</span>
<p class="code">
&lt;masked-input v-model="phone" mask="+\1 (111) 1111-11" placeholder="Phone" /&gt;
</p>
<h4>Your own mask (hot re-mask available): </h4>
<input v-model="userMask" placeholder="Mask" />
<masked-input v-model="userField" :mask="userMask" placeholder="Text" /><span>{{ userField }}</span>
<br />
<h4>Check <a href="#">GitHub</a> for more</h4>
</div>
</template>
<script>
import MaskedInput from './MaskedInput.vue';
export default {
name: 'app',
data: () => ({
date: '',
phone: '',
userMask: 'aa-aa-AAAA',
userField: '',
}),
components: {
MaskedInput
}
}
</script>
<style>
@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900');
@import url('https://fonts.googleapis.com/css?family=Overpass+Mono:400,700');
body {
background-color: #FAFAFA;
}
#app {
max-width: 780px;
margin: auto;
font-family: 'Roboto', sans-serif;
color: #2c3e50;
}
input {
font-family: inherit;
font-size: inherit;
padding: 8px 16px;
border: none;
border-bottom: 1px solid #4fc08d;
outline: none;
margin-right: 24px;
}
hr {
border: none;
border-bottom: 1px solid #DDD;
}
h1 {
font-size: 48px;
margin: 48px 0 8px 0;
font-weight: 900;
}
h3 {
margin: 0 0 24px;
font-weight: 300;
}
h4 {
margin: 36px 0 12px;
}
span {
opacity: 0.5;
margin-left: 32px;
}
.code {
padding: 24px;
font-family: 'Overpass Mono', monospace;
background-color: #EEE;
font-size: 0.95em;
font-weight: 500;
line-height: 1.5em;
}
</style>
<template>
<input ref="input" :value="value" @keypress.prevent="keyPress(arguments[0])" @keydown="keyDown(arguments[0])" @mouseup="mouseUp(arguments[0])" @focus.prevent="focusin(arguments[0])" @focusout="focusout(arguments[0])" @cut="cut(arguments[0])" @copy="copy(arguments[0])"
@paste="paste(arguments[0])" />
</template>
<script>
import InputMask from 'inputmask-core';
import ffpoly from './ff-polyfill.js'; //Firefox Polyfill for focus events
ffpoly();
export default {
name: 'MaskedInput',
data: () => ({
firstFocus: true,
marginLeft: 0,
mask_core: null
}),
props: {
value: {
type: String
},
default: {
type: String,
default: ''
},
mask: {
type: String,
required: true
}
},
watch: {
// whenever question changes, this function will run
mask: function(newMask) {
try {
this.mask_core = new InputMask({
pattern: newMask,
value: this.default
})
} catch (e) {
this.mask_core = new InputMask({
pattern: 'B\\ad1M\\ask',
value: this.default
})
}
this.update();
}
},
mounted() {
this.mask_core = new InputMask({
pattern: this.mask,
value: this.default
})
this.$refs.input.value = this.default
},
methods: {
getValue() {
return this.$refs.input.value
},
keyPress(e) {
this.mask_core.input(e.key)
this.update()
},
keyDown(e) {
this.setNativeSelection()
switch (e.keyCode) {
//backspace
case 8:
e.preventDefault()
if (
this.mask_core.selection.start > this.marginLeft ||
this.mask_core.selection.start != this.mask_core.selection.end
) {
this.mask_core.backspace();
}
break;
//left arrow
case 37:
e.preventDefault()
if (this.$refs.input.selectionStart === this.$refs.input.selectionEnd)
this.$refs.input.selectionStart--
this.mask_core.selection = {
start: this.$refs.input.selectionStart,
end: this.$refs.input.selectionStart
}
break;
//right arrow
case 39:
e.preventDefault()
if (this.$refs.input.selectionStart === this.$refs.input.selectionEnd)
this.$refs.input.selectionEnd++;
this.mask_core.selection = {
start: this.$refs.input.selectionEnd,
end: this.$refs.input.selectionEnd
}
break;
//end
case 35:
e.preventDefault()
this.$refs.input.selectionStart = this.$refs.input.selectionEnd = this.$refs.input.value.length
this.mask_core.selection = {
start: this.$refs.input.selectionEnd,
end: this.$refs.input.selectionEnd
}
break;
//home
case 36:
e.preventDefault()
this.$refs.input.selectionStart = this.$refs.input.selectionEnd = 0
this.mask_core.selection = {
start: this.$refs.input.selectionStart,
end: this.$refs.input.selectionStart
}
break;
//delete
case 46:
e.preventDefault()
if (this.$refs.input.selectionStart === this.$refs.input.selectionEnd) {
if (this.$refs.input.selectionEnd !== this.mask_core.length) {
this.mask_core.setSelection({
start: 0,
end: this.mask_core.getValue().length
})
this.mask_core.backspace()
this.mask_core.setSelection({
start: 0,
end: 0
})
this.$refs.input.selectionStart = this.mask_core.selection.start;
this.$refs.input.selectionEnd = this.mask_core.selection.start;
}
} else {
this.mask_core.backspace()
}
break;
}
this.update()
},
cut(e) {
e.preventDefault();
if (this.$refs.input.selectionStart !== this.$refs.input.selectionEnd) {
let text = this.$refs.input.value.slice(
this.$refs.input.selectionStart,
this.$refs.input.selectionEnd
)
try {
document.execCommand('copy')
} catch (err) {}
this.mask_core.backspace()
this.update()
}
},
copy(e) {},
paste(e) {
e.preventDefault();
this.mask_core.paste(e.clipboardData.getData('text'))
this.update()
},
update() {
this.$refs.input.value = this.mask_core.getValue()
this.$refs.input.selectionStart = this.mask_core.selection.start;
this.$refs.input.selectionEnd = this.mask_core.selection.end;
this.$emit('input', this.$refs.input.value)
},
focusin(e) {
this.mask_core.setValue(this.value)
this.update()
},
isEmpty() {
return this.mask_core.emptyValue === this.$refs.input.value
},
focusout(e) {
if (this.isEmpty()) {
this.$refs.input.value = this.default
this.mask_core.setSelection({
start: 0,
end: 0
})
this.$emit('input', '')
}
},
setNativeSelection() {
this.mask_core.selection = {
start: this.$refs.input.selectionStart,
end: this.$refs.input.selectionEnd
}
},
mouseUp(e) {
if (this.$refs.input.value === this.mask_core.emptyValue &&
this.$refs.input.selectionStart === this.$refs.input.selectionEnd) {
this.mask_core.setSelection({
start: 0,
end: 0
})
this.$refs.input.selectionStart = this.mask_core.selection.start;
this.$refs.input.selectionEnd = this.mask_core.selection.start;
this.marginLeft = this.mask_core.selection.start;
} else {
this.setNativeSelection();
}
}
}
}
</script>
//https://gist.github.com/nuxodin/9250e56a3ce6c0446efa
export default function () {
var w = window,
d = w.document;
if (w.onfocusin === undefined) {
d.addEventListener('focus', addPolyfill, true);
d.addEventListener('blur', addPolyfill, true);
d.addEventListener('focusin', removePolyfill, true);
d.addEventListener('focusout', removePolyfill, true);
}
function addPolyfill(e) {
var type = e.type === 'focus' ? 'focusin' : 'focusout';
var event = new CustomEvent(type, {
bubbles: true,
cancelable: false
});
event.c1Generated = true;
e.target.dispatchEvent(event);
}
function removePolyfill(e) {
if (!e.c1Generated) { // focus after focusin, so chrome will the first time trigger tow times focusin
d.removeEventListener('focus', addPolyfill, true);
d.removeEventListener('blur', addPolyfill, true);
d.removeEventListener('focusin', removePolyfill, true);
d.removeEventListener('focusout', removePolyfill, true);
}
setTimeout(function () {
d.removeEventListener('focusin', removePolyfill, true);
d.removeEventListener('focusout', removePolyfill, true);
});
}
};
import Vue from 'vue'
import App from './App.vue'
new Vue({
el: '#app',
render: h => h(App)
})
var path = require('path')
var webpack = require('webpack')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
// Since sass-loader (weirdly) has SCSS as its default parse mode, we map
// the "scss" and "sass" values for the lang attribute to the right configs here.
// other preprocessors should work out of the box, no loader config like this nessessary.
'scss': 'vue-style-loader!css-loader!sass-loader',
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.common.js'
}
},
devServer: {
historyApiFallback: true,
noInfo: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
}
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment