Skip to content
Snippets Groups Projects
post-form.vue 8.42 KiB
Newer Older
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
<template>
<div class="mk-post-form">
	<header>
		<button class="cancel" @click="cancel">%fa:times%</button>
		<div>
syuilo's avatar
syuilo committed
			<span class="text-count" :class="{ over: text.length > 1000 }">{{ 1000 - text.length }}</span>
syuilo's avatar
syuilo committed
			<span class="geo" v-if="geo">%fa:map-marker-alt%</span>
syuilo's avatar
syuilo committed
			<button class="submit" :disabled="posting" @click="post">
				<template v-if="reply">%i18n:@reply%</template>
				<template v-else-if="renote">%i18n:@renote%</template>
				<template v-else>%i18n:@submit%</template>
			</button>
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
		</div>
	</header>
	<div class="form">
syuilo's avatar
syuilo committed
		<mk-note-preview v-if="reply" :note="reply"/>
syuilo's avatar
syuilo committed
		<mk-note-preview v-if="renote" :note="renote"/>
syuilo's avatar
syuilo committed
		<div v-if="visibility == 'specified'" class="visibleUsers">
			<span v-for="u in visibleUsers">{{ u | userName }}<a @click="removeVisibleUser(u)">[x]</a></span>
			<a @click="addVisibleUser">+ユーザーを追加</a>
		</div>
syuilo's avatar
CW  
syuilo committed
		<input v-show="useCw" v-model="cw" placeholder="内容への注釈 (オプション)">
syuilo's avatar
syuilo committed
		<textarea v-model="text" ref="text" :disabled="posting" :placeholder="reply ? '%i18n:!@reply-placeholder%' : renote ? '%i18n:!@renote-placeholder%' : '%i18n:!@note-placeholder%'"></textarea>
syuilo's avatar
syuilo committed
		<div class="attaches" v-show="files.length != 0">
syuilo's avatar
syuilo committed
			<x-draggable class="files" :list="files" :options="{ animation: 150 }">
				<div class="file" v-for="file in files" :key="file.id">
					<div class="img" :style="`background-image: url(${file.url}?thumbnail&size=128)`" @click="detachMedia(file)"></div>
				</div>
			</x-draggable>
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
		</div>
syuilo's avatar
syuilo committed
		<mk-poll-editor v-if="poll" ref="poll" @destroyed="poll = false"/>
syuilo's avatar
syuilo committed
		<mk-uploader ref="uploader" @uploaded="attachMedia" @change="onChangeUploadings"/>
syuilo's avatar
syuilo committed
		<footer>
			<button class="upload" @click="chooseFile">%fa:upload%</button>
			<button class="drive" @click="chooseFileFromDrive">%fa:cloud%</button>
			<button class="kao" @click="kao">%fa:R smile%</button>
			<button class="poll" @click="poll = true">%fa:chart-pie%</button>
			<button class="poll" @click="useCw = !useCw">%fa:eye-slash%</button>
			<button class="geo" @click="geo ? removeGeo() : setGeo()">%fa:map-marker-alt%</button>
			<button class="visibility" @click="setVisibility" ref="visibilityButton">%fa:lock%</button>
		</footer>
syuilo's avatar
syuilo committed
		<input ref="file" class="file" type="file" accept="image/*" multiple="multiple" @change="onChangeFile"/>
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
	</div>
syuilo's avatar
syuilo committed
</div>
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
</template>

<script lang="ts">
import Vue from 'vue';
syuilo's avatar
syuilo committed
import * as XDraggable from 'vuedraggable';
syuilo's avatar
syuilo committed
import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue';
syuilo's avatar
syuilo committed
import getKao from '../../../common/scripts/get-kao';
こぴなたみぽ's avatar
wip
こぴなたみぽ committed

export default Vue.extend({
syuilo's avatar
syuilo committed
	components: {
syuilo's avatar
syuilo committed
		XDraggable,
		MkVisibilityChooser
syuilo's avatar
syuilo committed
	},
syuilo's avatar
CW  
syuilo committed

syuilo's avatar
syuilo committed
	props: ['reply', 'renote'],
syuilo's avatar
CW  
syuilo committed

こぴなたみぽ's avatar
wip
こぴなたみぽ committed
	data() {
		return {
			posting: false,
			text: '',
			uploadings: [],
			files: [],
syuilo's avatar
syuilo committed
			poll: false,
syuilo's avatar
CW  
syuilo committed
			geo: null,
syuilo's avatar
syuilo committed
			visibility: 'public',
			visibleUsers: [],
syuilo's avatar
CW  
syuilo committed
			useCw: false,
			cw: null
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
		};
	},
syuilo's avatar
CW  
syuilo committed

こぴなたみぽ's avatar
wip
こぴなたみぽ committed
	mounted() {
		if (this.reply && this.reply.user.host != null) {
			this.text = `@${this.reply.user.username}@${this.reply.user.host} `;
		}

syuilo's avatar
syuilo committed
		this.$nextTick(() => {
syuilo's avatar
syuilo committed
			this.focus();
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
		});
	},
syuilo's avatar
CW  
syuilo committed

こぴなたみぽ's avatar
wip
こぴなたみぽ committed
	methods: {
syuilo's avatar
syuilo committed
		focus() {
			(this.$refs.text as any).focus();
		},
syuilo's avatar
CW  
syuilo committed

syuilo's avatar
syuilo committed
		chooseFile() {
			(this.$refs.file as any).click();
		},
syuilo's avatar
CW  
syuilo committed

syuilo's avatar
syuilo committed
		chooseFileFromDrive() {
			(this as any).apis.chooseDriveFile({
				multiple: true
			}).then(files => {
				files.forEach(this.attachMedia);
			});
		},
syuilo's avatar
CW  
syuilo committed

こぴなたみぽ's avatar
wip
こぴなたみぽ committed
		attachMedia(driveFile) {
			this.files.push(driveFile);
			this.$emit('change-attached-media', this.files);
		},
syuilo's avatar
CW  
syuilo committed

syuilo's avatar
syuilo committed
		detachMedia(file) {
			this.files = this.files.filter(x => x.id != file.id);
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
			this.$emit('change-attached-media', this.files);
		},
syuilo's avatar
CW  
syuilo committed

こぴなたみぽ's avatar
wip
こぴなたみぽ committed
		onChangeFile() {
			Array.from((this.$refs.file as any).files).forEach(this.upload);
		},
syuilo's avatar
CW  
syuilo committed

こぴなたみぽ's avatar
wip
こぴなたみぽ committed
		upload(file) {
			(this.$refs.uploader as any).upload(file);
		},
syuilo's avatar
CW  
syuilo committed

こぴなたみぽ's avatar
wip
こぴなたみぽ committed
		onChangeUploadings(uploads) {
			this.$emit('change-uploadings', uploads);
		},
syuilo's avatar
CW  
syuilo committed

syuilo's avatar
syuilo committed
		setGeo() {
			if (navigator.geolocation == null) {
				alert('お使いの端末は位置情報に対応していません');
				return;
			}

			navigator.geolocation.getCurrentPosition(pos => {
				this.geo = pos.coords;
			}, err => {
				alert('エラー: ' + err.message);
			}, {
				enableHighAccuracy: true
			});
		},
syuilo's avatar
CW  
syuilo committed

syuilo's avatar
syuilo committed
		removeGeo() {
			this.geo = null;
		},
syuilo's avatar
CW  
syuilo committed

syuilo's avatar
syuilo committed
		setVisibility() {
			const w = (this as any).os.new(MkVisibilityChooser, {
				source: this.$refs.visibilityButton,
				compact: true,
				v: this.visibility
			});
			w.$once('chosen', v => {
				this.visibility = v;
			});
		},

		addVisibleUser() {
			(this as any).apis.input({
				title: 'ユーザー名を入力してください'
			}).then(username => {
				(this as any).api('users/show', {
					username
				}).then(user => {
					this.visibleUsers.push(user);
				});
			});
		},

		removeVisibleUser(user) {
			this.visibleUsers = this.visibleUsers.filter(u => u != user);
		},

こぴなたみぽ's avatar
wip
こぴなたみぽ committed
		clear() {
			this.text = '';
			this.files = [];
			this.poll = false;
			this.$emit('change-attached-media');
		},
syuilo's avatar
CW  
syuilo committed

syuilo's avatar
syuilo committed
		post() {
			this.posting = true;
syuilo's avatar
syuilo committed
			const viaMobile = (this as any).clientSettings.disableViaMobile !== true;
syuilo's avatar
syuilo committed
			(this as any).api('notes/create', {
syuilo's avatar
syuilo committed
				text: this.text == '' ? undefined : this.text,
syuilo's avatar
syuilo committed
				mediaIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
				replyId: this.reply ? this.reply.id : undefined,
syuilo's avatar
syuilo committed
				renoteId: this.renote ? this.renote.id : undefined,
syuilo's avatar
syuilo committed
				poll: this.poll ? (this.$refs.poll as any).get() : undefined,
syuilo's avatar
CW  
syuilo committed
				cw: this.useCw ? this.cw || '' : undefined,
syuilo's avatar
syuilo committed
				geo: this.geo ? {
syuilo's avatar
syuilo committed
					coordinates: [this.geo.longitude, this.geo.latitude],
syuilo's avatar
syuilo committed
					altitude: this.geo.altitude,
					accuracy: this.geo.accuracy,
					altitudeAccuracy: this.geo.altitudeAccuracy,
					heading: isNaN(this.geo.heading) ? null : this.geo.heading,
					speed: this.geo.speed,
				} : null,
syuilo's avatar
syuilo committed
				visibility: this.visibility,
				visibleUserIds: this.visibility == 'specified' ? this.visibleUsers.map(u => u.id) : undefined,
syuilo's avatar
syuilo committed
				viaMobile: viaMobile
syuilo's avatar
syuilo committed
			}).then(data => {
syuilo's avatar
syuilo committed
				this.$emit('note');
syuilo's avatar
syuilo committed
				this.$destroy();
			}).catch(err => {
				this.posting = false;
			});
		},
syuilo's avatar
CW  
syuilo committed

こぴなたみぽ's avatar
wip
こぴなたみぽ committed
		cancel() {
			this.$emit('cancel');
			this.$destroy();
syuilo's avatar
syuilo committed
		},
syuilo's avatar
CW  
syuilo committed

syuilo's avatar
syuilo committed
		kao() {
			this.text += getKao();
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
		}
	}
});
</script>

<style lang="stylus" scoped>
syuilo's avatar
syuilo committed
@import '~const.styl'

syuilo's avatar
syuilo committed
root(isDark)
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
	max-width 500px
	width calc(100% - 16px)
	margin 8px auto
syuilo's avatar
syuilo committed
	background isDark ? #282C37 : #fff
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
	border-radius 8px
syuilo's avatar
syuilo committed
	box-shadow 0 0 2px rgba(#000, 0.1)
こぴなたみぽ's avatar
wip
こぴなたみぽ committed

	@media (min-width 500px)
		margin 16px auto
		width calc(100% - 32px)
syuilo's avatar
syuilo committed
		box-shadow 0 8px 32px rgba(#000, 0.1)
syuilo's avatar
syuilo committed

	@media (min-width 600px)
		margin 32px auto
こぴなたみぽ's avatar
wip
こぴなたみぽ committed

	> header
syuilo's avatar
syuilo committed
		z-index 1000
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
		height 50px
syuilo's avatar
syuilo committed
		box-shadow 0 1px 0 0 isDark ? rgba(#000, 0.2) : rgba(#000, 0.1)
こぴなたみぽ's avatar
wip
こぴなたみぽ committed

		> .cancel
syuilo's avatar
syuilo committed
			padding 0
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
			width 50px
			line-height 50px
			font-size 24px
syuilo's avatar
syuilo committed
			color isDark ? #9baec8 : #555
こぴなたみぽ's avatar
wip
こぴなたみぽ committed

		> div
			position absolute
			top 0
			right 0
syuilo's avatar
syuilo committed
			color #657786
こぴなたみぽ's avatar
wip
こぴなたみぽ committed

			> .text-count
				line-height 50px
syuilo's avatar
syuilo committed

			> .geo
				margin 0 8px
				line-height 50px
こぴなたみぽ's avatar
wip
こぴなたみぽ committed

			> .submit
				margin 8px
				padding 0 16px
				line-height 34px
syuilo's avatar
syuilo committed
				vertical-align bottom
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
				color $theme-color-foreground
				background $theme-color
				border-radius 4px

				&:disabled
					opacity 0.7

	> .form
		max-width 500px
		margin 0 auto

syuilo's avatar
syuilo committed
		> .mk-note-preview
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
			padding 16px

syuilo's avatar
syuilo committed
		> .visibleUsers
			margin-bottom 8px
			font-size 14px

			> span
				margin-right 16px
				color isDark ? #fff : #666

		> input
			z-index 1

		> input
		> textarea
			display block
			padding 12px
			margin 0
			width 100%
			font-size 16px
			color isDark ? #fff : #333
			background isDark ? #191d23 : #fff
			border none
			border-radius 0
			box-shadow 0 1px 0 0 isDark ? rgba(#000, 0.2) : rgba(#000, 0.1)

			&:disabled
				opacity 0.5

		> textarea
			max-width 100%
			min-width 100%
			min-height 80px

こぴなたみぽ's avatar
wip
こぴなたみぽ committed
		> .attaches

			> .files
				display block
				margin 0
				padding 4px
				list-style none

				&:after
					content ""
					display block
					clear both

				> .file
					display block
					float left
					margin 0
					padding 0
					border solid 4px transparent

					> .img
						width 64px
						height 64px
						background-size cover
						background-position center center

syuilo's avatar
syuilo committed
		> .mk-uploader
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
			margin 8px 0 0 0
			padding 8px

syuilo's avatar
syuilo committed
		> .file
こぴなたみぽ's avatar
wip
こぴなたみぽ committed
			display none

syuilo's avatar
syuilo committed
		> footer
			white-space nowrap
			overflow auto
			-webkit-overflow-scrolling touch
			overflow-scrolling touch

			> *
				display inline-block
				padding 0
				margin 0
				width 48px
				height 48px
				font-size 20px
				color #657786
				background transparent
				outline none
				border none
				border-radius 0
				box-shadow none
こぴなたみぽ's avatar
wip
こぴなたみぽ committed

syuilo's avatar
syuilo committed
.mk-post-form[data-darkmode]
	root(true)

.mk-post-form:not([data-darkmode])
	root(false)
こぴなたみぽ's avatar
wip
こぴなたみぽ committed

syuilo's avatar
syuilo committed
</style>