wip
This commit is contained in:
parent
4f1795b97b
commit
c869883d76
|
@ -13,7 +13,7 @@
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script>
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<form @submit.prevent="onSubmit" autocomplete="off">
|
<form class="form" @submit.prevent="onSubmit" autocomplete="off">
|
||||||
<label class="username">
|
<label class="username">
|
||||||
<p class="caption">%fa:at%%i18n:common.tags.mk-signup.username%</p>
|
<p class="caption">%fa:at%%i18n:common.tags.mk-signup.username%</p>
|
||||||
<input v-model="username" type="text" pattern="^[a-zA-Z0-9-]{3,20}$" placeholder="a~z、A~Z、0~9、-" autocomplete="off" required @keyup="onChangeUsername"/>
|
<input v-model="username" type="text" pattern="^[a-zA-Z0-9-]{3,20}$" placeholder="a~z、A~Z、0~9、-" autocomplete="off" required @keyup="onChangeUsername"/>
|
||||||
<p class="profile-page-url-preview" v-if="refs.username.value != '' && username-state != 'invalidFormat' && username-state != 'minRange' && username-state != 'maxRange'">{ _URL_ + '/' + refs.username.value }</p>
|
<p class="profile-page-url-preview" v-if="username != '' && username-state != 'invalidFormat' && username-state != 'minRange' && username-state != 'maxRange'">{ _URL_ + '/' + refs.username.value }</p>
|
||||||
<p class="info" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw%%i18n:common.tags.mk-signup.checking%</p>
|
<p class="info" v-if="usernameState == 'wait'" style="color:#999">%fa:spinner .pulse .fw%%i18n:common.tags.mk-signup.checking%</p>
|
||||||
<p class="info" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.available%</p>
|
<p class="info" v-if="usernameState == 'ok'" style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.available%</p>
|
||||||
<p class="info" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.unavailable%</p>
|
<p class="info" v-if="usernameState == 'unavailable'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.unavailable%</p>
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
</label>
|
</label>
|
||||||
<label class="recaptcha">
|
<label class="recaptcha">
|
||||||
<p class="caption"><template v-if="recaptchaed">%fa:toggle-on%</template><template v-if="!recaptchaed">%fa:toggle-off%</template>%i18n:common.tags.mk-signup.recaptcha%</p>
|
<p class="caption"><template v-if="recaptchaed">%fa:toggle-on%</template><template v-if="!recaptchaed">%fa:toggle-off%</template>%i18n:common.tags.mk-signup.recaptcha%</p>
|
||||||
<div v-if="recaptcha" class="g-recaptcha" data-callback="onRecaptchaed" data-expired-callback="onRecaptchaExpired" data-sitekey="recaptcha.site_key"></div>
|
<div v-if="recaptcha" class="g-recaptcha" data-callback="onRecaptchaed" data-expired-callback="onRecaptchaExpired" :data-sitekey="recaptchaSitekey"></div>
|
||||||
</label>
|
</label>
|
||||||
<label class="agree-tou">
|
<label class="agree-tou">
|
||||||
<input name="agree-tou" type="checkbox" autocomplete="off" required/>
|
<input name="agree-tou" type="checkbox" autocomplete="off" required/>
|
||||||
|
@ -43,16 +43,98 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
const getPasswordStrength = require('syuilo-password-strength');
|
const getPasswordStrength = require('syuilo-password-strength');
|
||||||
import
|
import { docsUrl, lang, recaptchaSitekey } from '../../../config';
|
||||||
|
|
||||||
const aboutUrl = `${_DOCS_URL_}/${_LANG_}/tou`;
|
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
methods: {
|
props: ['os'],
|
||||||
onSubmit() {
|
data() {
|
||||||
|
return {
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
retypedPassword: '',
|
||||||
|
touUrl: `${docsUrl}/${lang}/tou`,
|
||||||
|
recaptchaSitekey,
|
||||||
|
recaptchaed: false,
|
||||||
|
usernameState: null,
|
||||||
|
passwordStrength: '',
|
||||||
|
passwordRetypeState: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
onChangeUsername() {
|
||||||
|
if (this.username == '') {
|
||||||
|
this.usernameState = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const err =
|
||||||
|
!this.username.match(/^[a-zA-Z0-9\-]+$/) ? 'invalid-format' :
|
||||||
|
this.username.length < 3 ? 'min-range' :
|
||||||
|
this.username.length > 20 ? 'max-range' :
|
||||||
|
null;
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
this.usernameState = err;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.usernameState = 'wait';
|
||||||
|
|
||||||
|
this.os.api('username/available', {
|
||||||
|
username: this.username
|
||||||
|
}).then(result => {
|
||||||
|
this.usernameState = result.available ? 'ok' : 'unavailable';
|
||||||
|
}).catch(err => {
|
||||||
|
this.usernameState = 'error';
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onChangePassword() {
|
||||||
|
if (this.password == '') {
|
||||||
|
this.passwordStrength = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const strength = getPasswordStrength(this.password);
|
||||||
|
this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low';
|
||||||
|
(this.$refs.passwordMetar as any).style.width = `${strength * 100}%`;
|
||||||
|
},
|
||||||
|
onChangePasswordRetype() {
|
||||||
|
if (this.retypedPassword == '') {
|
||||||
|
this.passwordRetypeState = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.passwordRetypeState = this.password == this.retypedPassword ? 'match' : 'not-match';
|
||||||
|
},
|
||||||
|
onSubmit() {
|
||||||
|
this.os.api('signup', {
|
||||||
|
username: this.username,
|
||||||
|
password: this.password,
|
||||||
|
'g-recaptcha-response': (window as any).grecaptcha.getResponse()
|
||||||
|
}).then(() => {
|
||||||
|
this.os.api('signin', {
|
||||||
|
username: this.username,
|
||||||
|
password: this.password
|
||||||
|
}).then(() => {
|
||||||
|
location.href = '/';
|
||||||
|
});
|
||||||
|
}).catch(() => {
|
||||||
|
alert('%i18n:common.tags.mk-signup.some-error%');
|
||||||
|
|
||||||
|
(window as any).grecaptcha.reset();
|
||||||
|
this.recaptchaed = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
(window as any).onRecaptchaed = () => {
|
||||||
|
this.recaptchaed = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
(window as any).onRecaptchaExpired = () => {
|
||||||
|
this.recaptchaed = false;
|
||||||
|
};
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const head = document.getElementsByTagName('head')[0];
|
const head = document.getElementsByTagName('head')[0];
|
||||||
const script = document.createElement('script');
|
const script = document.createElement('script');
|
||||||
|
@ -63,12 +145,8 @@ export default Vue.extend({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
:scope
|
.form
|
||||||
display block
|
|
||||||
min-width 302px
|
min-width 302px
|
||||||
overflow hidden
|
|
||||||
|
|
||||||
> form
|
|
||||||
|
|
||||||
label
|
label
|
||||||
display block
|
display block
|
||||||
|
@ -197,135 +275,3 @@ export default Vue.extend({
|
||||||
background darken($theme-color, 5%)
|
background darken($theme-color, 5%)
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script lang="typescript">
|
|
||||||
this.mixin('api');
|
|
||||||
|
|
||||||
|
|
||||||
this.usernameState = null;
|
|
||||||
this.passwordStrength = '';
|
|
||||||
this.passwordRetypeState = null;
|
|
||||||
this.recaptchaed = false;
|
|
||||||
|
|
||||||
this.aboutUrl = `${_DOCS_URL_}/${_LANG_}/tou`;
|
|
||||||
|
|
||||||
window.onRecaptchaed = () => {
|
|
||||||
this.recaptchaed = true;
|
|
||||||
this.update();
|
|
||||||
};
|
|
||||||
|
|
||||||
window.onRecaptchaExpired = () => {
|
|
||||||
this.recaptchaed = false;
|
|
||||||
this.update();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.on('mount', () => {
|
|
||||||
this.update({
|
|
||||||
recaptcha: {
|
|
||||||
site_key: _RECAPTCHA_SITEKEY_
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const head = document.getElementsByTagName('head')[0];
|
|
||||||
const script = document.createElement('script');
|
|
||||||
script.setAttribute('src', 'https://www.google.com/recaptcha/api.js');
|
|
||||||
head.appendChild(script);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.onChangeUsername = () => {
|
|
||||||
const username = this.$refs.username.value;
|
|
||||||
|
|
||||||
if (username == '') {
|
|
||||||
this.update({
|
|
||||||
usernameState: null
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const err =
|
|
||||||
!username.match(/^[a-zA-Z0-9\-]+$/) ? 'invalid-format' :
|
|
||||||
username.length < 3 ? 'min-range' :
|
|
||||||
username.length > 20 ? 'max-range' :
|
|
||||||
null;
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
this.update({
|
|
||||||
usernameState: err
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.update({
|
|
||||||
usernameState: 'wait'
|
|
||||||
});
|
|
||||||
|
|
||||||
this.api('username/available', {
|
|
||||||
username: username
|
|
||||||
}).then(result => {
|
|
||||||
this.update({
|
|
||||||
usernameState: result.available ? 'ok' : 'unavailable'
|
|
||||||
});
|
|
||||||
}).catch(err => {
|
|
||||||
this.update({
|
|
||||||
usernameState: 'error'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.onChangePassword = () => {
|
|
||||||
const password = this.$refs.password.value;
|
|
||||||
|
|
||||||
if (password == '') {
|
|
||||||
this.passwordStrength = '';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const strength = getPasswordStrength(password);
|
|
||||||
this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low';
|
|
||||||
this.update();
|
|
||||||
this.$refs.passwordMetar.style.width = `${strength * 100}%`;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.onChangePasswordRetype = () => {
|
|
||||||
const password = this.$refs.password.value;
|
|
||||||
const retypedPassword = this.$refs.passwordRetype.value;
|
|
||||||
|
|
||||||
if (retypedPassword == '') {
|
|
||||||
this.passwordRetypeState = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.passwordRetypeState = password == retypedPassword ? 'match' : 'not-match';
|
|
||||||
};
|
|
||||||
|
|
||||||
this.onsubmit = e => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const username = this.$refs.username.value;
|
|
||||||
const password = this.$refs.password.value;
|
|
||||||
|
|
||||||
const locker = document.body.appendChild(document.createElement('mk-locker'));
|
|
||||||
|
|
||||||
this.api('signup', {
|
|
||||||
username: username,
|
|
||||||
password: password,
|
|
||||||
'g-recaptcha-response': grecaptcha.getResponse()
|
|
||||||
}).then(() => {
|
|
||||||
this.api('signin', {
|
|
||||||
username: username,
|
|
||||||
password: password
|
|
||||||
}).then(() => {
|
|
||||||
location.href = '/';
|
|
||||||
});
|
|
||||||
}).catch(() => {
|
|
||||||
alert('%i18n:common.tags.mk-signup.some-error%');
|
|
||||||
|
|
||||||
grecaptcha.reset();
|
|
||||||
this.recaptchaed = false;
|
|
||||||
|
|
||||||
locker.parentNode.removeChild(locker);
|
|
||||||
});
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
11
src/web/app/config.ts
Normal file
11
src/web/app/config.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
declare const _HOST_: string;
|
||||||
|
declare const _URL_: string;
|
||||||
|
declare const _DOCS_URL_: string;
|
||||||
|
declare const _LANG_: string;
|
||||||
|
declare const _RECAPTCHA_SITEKEY_: string;
|
||||||
|
|
||||||
|
export const host = _HOST_;
|
||||||
|
export const url = _URL_;
|
||||||
|
export const docsUrl = _DOCS_URL_;
|
||||||
|
export const lang = _LANG_;
|
||||||
|
export const recaptchaSitekey = _RECAPTCHA_SITEKEY_;
|
|
@ -18,7 +18,7 @@
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
<modal name="signup">
|
<modal name="signup">
|
||||||
<mk-signup/>
|
<mk-signup></mk-signup>
|
||||||
</modal>
|
</modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -70,6 +70,9 @@ export default (callback: (os: MiOS, launch: () => Vue) => void, sw = false) =>
|
||||||
// アプリ基底要素マウント
|
// アプリ基底要素マウント
|
||||||
document.body.innerHTML = '<div id="app"></div>';
|
document.body.innerHTML = '<div id="app"></div>';
|
||||||
|
|
||||||
|
// Register global components
|
||||||
|
require('./common/views/components');
|
||||||
|
|
||||||
const launch = () => {
|
const launch = () => {
|
||||||
return new Vue({
|
return new Vue({
|
||||||
router: new VueRouter({
|
router: new VueRouter({
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { pattern, replacement } from '../../../src/common/build/fa';
|
||||||
|
|
||||||
export default () => ({
|
export default () => ({
|
||||||
enforce: 'pre',
|
enforce: 'pre',
|
||||||
test: /\.(tag|js|ts)$/,
|
test: /\.(vue|js|ts)$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
loader: StringReplacePlugin.replace({
|
loader: StringReplacePlugin.replace({
|
||||||
replacements: [{
|
replacements: [{
|
||||||
|
|
|
@ -10,7 +10,7 @@ export default lang => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
enforce: 'pre',
|
enforce: 'pre',
|
||||||
test: /\.(tag|js|ts)$/,
|
test: /\.(vue|js|ts)$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
loader: StringReplacePlugin.replace({
|
loader: StringReplacePlugin.replace({
|
||||||
replacements: [{
|
replacements: [{
|
||||||
|
|
Loading…
Reference in a new issue