wip
This commit is contained in:
		
							parent
							
								
									4f1795b97b
								
							
						
					
					
						commit
						c869883d76
					
				
					 7 changed files with 217 additions and 257 deletions
				
			
		| 
						 | 
				
			
			@ -13,7 +13,7 @@
 | 
			
		|||
</form>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
<script>
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
<template>
 | 
			
		||||
<form @submit.prevent="onSubmit" autocomplete="off">
 | 
			
		||||
<form class="form" @submit.prevent="onSubmit" autocomplete="off">
 | 
			
		||||
	<label class="username">
 | 
			
		||||
		<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"/>
 | 
			
		||||
		<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 == '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>
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +30,7 @@
 | 
			
		|||
	</label>
 | 
			
		||||
	<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>
 | 
			
		||||
		<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 class="agree-tou">
 | 
			
		||||
		<input name="agree-tou" type="checkbox" autocomplete="off" required/>
 | 
			
		||||
| 
						 | 
				
			
			@ -43,16 +43,98 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
const getPasswordStrength = require('syuilo-password-strength');
 | 
			
		||||
import
 | 
			
		||||
 | 
			
		||||
const aboutUrl = `${_DOCS_URL_}/${_LANG_}/tou`;
 | 
			
		||||
import { docsUrl, lang, recaptchaSitekey } from '../../../config';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	methods: {
 | 
			
		||||
		onSubmit() {
 | 
			
		||||
 | 
			
		||||
	props: ['os'],
 | 
			
		||||
	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() {
 | 
			
		||||
		const head = document.getElementsByTagName('head')[0];
 | 
			
		||||
		const script = document.createElement('script');
 | 
			
		||||
| 
						 | 
				
			
			@ -63,12 +145,8 @@ export default Vue.extend({
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="stylus" scoped>
 | 
			
		||||
	:scope
 | 
			
		||||
		display block
 | 
			
		||||
.form
 | 
			
		||||
	min-width 302px
 | 
			
		||||
		overflow hidden
 | 
			
		||||
 | 
			
		||||
		> form
 | 
			
		||||
 | 
			
		||||
	label
 | 
			
		||||
		display block
 | 
			
		||||
| 
						 | 
				
			
			@ -197,135 +275,3 @@ export default Vue.extend({
 | 
			
		|||
			background darken($theme-color, 5%)
 | 
			
		||||
 | 
			
		||||
</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>
 | 
			
		||||
	</footer>
 | 
			
		||||
	<modal name="signup">
 | 
			
		||||
		<mk-signup/>
 | 
			
		||||
		<mk-signup></mk-signup>
 | 
			
		||||
	</modal>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,6 +70,9 @@ export default (callback: (os: MiOS, launch: () => Vue) => void, sw = false) =>
 | 
			
		|||
		// アプリ基底要素マウント
 | 
			
		||||
		document.body.innerHTML = '<div id="app"></div>';
 | 
			
		||||
 | 
			
		||||
		// Register global components
 | 
			
		||||
		require('./common/views/components');
 | 
			
		||||
 | 
			
		||||
		const launch = () => {
 | 
			
		||||
			return new Vue({
 | 
			
		||||
				router: new VueRouter({
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ import { pattern, replacement } from '../../../src/common/build/fa';
 | 
			
		|||
 | 
			
		||||
export default () => ({
 | 
			
		||||
	enforce: 'pre',
 | 
			
		||||
	test: /\.(tag|js|ts)$/,
 | 
			
		||||
	test: /\.(vue|js|ts)$/,
 | 
			
		||||
	exclude: /node_modules/,
 | 
			
		||||
	loader: StringReplacePlugin.replace({
 | 
			
		||||
		replacements: [{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ export default lang => {
 | 
			
		|||
 | 
			
		||||
	return {
 | 
			
		||||
		enforce: 'pre',
 | 
			
		||||
		test: /\.(tag|js|ts)$/,
 | 
			
		||||
		test: /\.(vue|js|ts)$/,
 | 
			
		||||
		exclude: /node_modules/,
 | 
			
		||||
		loader: StringReplacePlugin.replace({
 | 
			
		||||
			replacements: [{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue