Implemented PasswordStrength Component

pull/12/head
cagataycivici 2018-12-26 22:02:41 +03:00
parent e128009632
commit d26626a969
8 changed files with 210 additions and 0 deletions

View File

@ -14,6 +14,7 @@
<router-link to="/inputswitch">&#9679; InputSwitch</router-link> <router-link to="/inputswitch">&#9679; InputSwitch</router-link>
<router-link to="/inputtext">&#9679; InputText</router-link> <router-link to="/inputtext">&#9679; InputText</router-link>
<router-link to="/listbox">&#9679; Listbox</router-link> <router-link to="/listbox">&#9679; Listbox</router-link>
<router-link to="/password">&#9679; Password</router-link>
<router-link to="/radiobutton">&#9679; RadioButton</router-link> <router-link to="/radiobutton">&#9679; RadioButton</router-link>
<router-link to="/rating">&#9679; Rating</router-link> <router-link to="/rating">&#9679; Rating</router-link>
<router-link to="/selectbutton">&#9679; SelectButton</router-link> <router-link to="/selectbutton">&#9679; SelectButton</router-link>

View File

@ -9,6 +9,7 @@
@import '../../components/inputswitch/InputSwitch.css'; @import '../../components/inputswitch/InputSwitch.css';
@import '../../components/listbox/Listbox.css'; @import '../../components/listbox/Listbox.css';
@import '../../components/panel/Panel.css'; @import '../../components/panel/Panel.css';
@import '../../components/password/Password.css';
@import '../../components/progressbar/ProgressBar.css'; @import '../../components/progressbar/ProgressBar.css';
@import '../../components/radiobutton/RadioButton.css'; @import '../../components/radiobutton/RadioButton.css';
@import '../../components/rating/Rating.css'; @import '../../components/rating/Rating.css';

View File

@ -0,0 +1,19 @@
.p-password-panel {
padding: .25em .5em;
margin-top: 2px;
}
.p-password-panel .p-password-meter {
height: 10px;
background:transparent url("./images/password-meter.png") no-repeat left top;
padding: 0;
margin: 0;
}
.p-password-info {
margin-top: .25em;
}
.p-password-panel-overlay {
position: absolute;
}

View File

@ -0,0 +1,154 @@
<template>
<input ref="input" type="password" :class="['p-inputtext p-component', {'p-filled': filled}]" v-on="listeners" :value="value" />
</template>
<script>
import DomHandler from '../utils/DomHandler';
export default {
props: {
value: String,
promptLabel: {
type: String,
default: 'Enter a password'
},
weakLabel: {
type: String,
default: 'Weak'
},
mediumLabel: {
type: String,
default: 'Medium'
},
strongLabel: {
type: String,
default: 'Strong'
},
feedback: {
type: Boolean,
default: true
}
},
panel: null,
meter: null,
info: null,
methods: {
testStrength(str) {
let grade = 0;
let val;
val = str.match('[0-9]');
grade += this.normalize(val ? val.length : 1/4, 1) * 25;
val = str.match('[a-zA-Z]');
grade += this.normalize(val ? val.length : 1/2, 3) * 10;
val = str.match('[!@#$%^&*?_~.,;=]');
grade += this.normalize(val ? val.length : 1/6, 1) * 35;
val = str.match('[A-Z]');
grade += this.normalize(val ? val.length : 1/6, 1) * 30;
grade *= str.length / 8;
return grade > 100 ? 100 : grade;
},
normalize(x, y) {
let diff = x - y;
if(diff <= 0)
return x / y;
else
return 1 + 0.5 * (x / (x + y/4));
},
createPanel() {
this.panel = document.createElement('div');
this.panel.className = 'p-password-panel p-component p-hidden p-password-panel-overlay p-input-overlay';
this.meter = document.createElement('div');
this.meter.className = 'p-password-meter';
this.info = document.createElement('div');
this.info.className = 'p-password-info';
this.info.textContent = this.promptLabel;
this.panel.style.minWidth = DomHandler.getOuterWidth(this.$refs.input) + 'px';
this.panel.appendChild(this.meter);
this.panel.appendChild(this.info);
document.body.appendChild(this.panel);
}
},
computed: {
listeners() {
return {
...this.$listeners,
input: event => this.$emit('input', event.target.value),
focus: event => {
if (this.feedback) {
if (!this.panel) {
this.createPanel();
}
this.panel.style.zIndex = String(DomHandler.generateZIndex());
this.panel.style.display = 'block';
setTimeout(() => {
DomHandler.addClass(this.panel, 'p-input-overlay-visible');
DomHandler.removeClass(this.panel, 'p-input-overlay-hidden');
}, 1);
DomHandler.absolutePosition(this.panel, this.$refs.input);
}
this.$emit('focus', event);
},
blur: event => {
if (this.panel) {
DomHandler.addClass(this.panel, 'p-input-overlay-hidden');
DomHandler.removeClass(this.panel, 'p-input-overlay-visible');
setTimeout(() => {
this.panel.style.display = 'none';
DomHandler.removeClass(this.panel, 'p-input-overlay-hidden');
}, 150);
}
this.$emit('blur', event);
},
keyup: event => {
if(this.panel) {
let value = event.target.value;
let label = null;
let meterPos = null;
if (value.length === 0) {
label = this.promptLabel;
meterPos = '0px 0px';
}
else {
let score = this.testStrength(value);
if (score < 30) {
label = this.weakLabel;
meterPos = '0px -10px';
}
else if (score >= 30 && score < 80) {
label = this.mediumLabel;
meterPos = '0px -20px';
}
else if (score >= 80) {
label = this.strongLabel;
meterPos = '0px -30px';
}
}
this.meter.style.backgroundPosition = meterPos;
this.info.textContent = label;
}
this.$emit('keyup', event);
}
};
},
filled() {
return (this.value != null && this.value.toString().length > 0)
}
}
}
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 B

View File

@ -13,6 +13,7 @@ import InputText from './components/inputtext/InputText';
import Fieldset from './components/fieldset/Fieldset'; import Fieldset from './components/fieldset/Fieldset';
import Listbox from './components/listbox/Listbox'; import Listbox from './components/listbox/Listbox';
import Panel from './components/panel/Panel'; import Panel from './components/panel/Panel';
import Password from './components/password/Password';
import ProgressBar from './components/progressbar/ProgressBar'; import ProgressBar from './components/progressbar/ProgressBar';
import Rating from './components/rating/Rating'; import Rating from './components/rating/Rating';
import RadioButton from './components/radiobutton/RadioButton'; import RadioButton from './components/radiobutton/RadioButton';
@ -44,6 +45,7 @@ Vue.component('p-inputtext', InputText);
Vue.component('p-listbox', Listbox); Vue.component('p-listbox', Listbox);
Vue.component('p-fieldset', Fieldset); Vue.component('p-fieldset', Fieldset);
Vue.component('p-panel', Panel); Vue.component('p-panel', Panel);
Vue.component('p-password', Password);
Vue.component('p-progressBar', ProgressBar); Vue.component('p-progressBar', ProgressBar);
Vue.component('p-radioButton', RadioButton); Vue.component('p-radioButton', RadioButton);
Vue.component('p-rating', Rating); Vue.component('p-rating', Rating);

View File

@ -71,6 +71,11 @@ export default new Router({
name: 'panel', name: 'panel',
component: () => import('./views/panel/PanelDemo.vue') component: () => import('./views/panel/PanelDemo.vue')
}, },
{
path: '/password',
name: 'password',
component: () => import('./views/password/PasswordDemo.vue')
},
{ {
path: '/progressbar', path: '/progressbar',
name: 'progressbar', name: 'progressbar',

View File

@ -0,0 +1,28 @@
<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>Password</h1>
<p>Password displays strength indicator for password fields.</p>
</div>
</div>
<div class="content-section implementation">
<p-password v-model="value" />
</div>
</div>
</template>
<script>
export default {
data() {
return {
value: ''
}
}
}
</script>
<style>
</style>