From 091923764d3083dda958ca1109c6c7a806414a4f Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sun, 16 Feb 2020 22:46:18 +0900
Subject: [PATCH] Implement image dialog

---
 CHANGELOG.md                           |  1 +
 locales/ja-JP.yml                      |  1 +
 src/client/components/image-viewer.vue | 54 ++++++++++++++++++++++++++
 src/client/components/media-image.vue  | 12 +++++-
 src/client/components/modal.vue        |  9 ++++-
 src/client/pages/settings/general.vue  |  6 +++
 src/client/store.ts                    |  1 +
 7 files changed, 82 insertions(+), 2 deletions(-)
 create mode 100644 src/client/components/image-viewer.vue

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7207544620..07d836041c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@ unreleased
 ### ✨Improvements
 * 投稿詳細ページで前後の投稿を見れるように
 * 自分のfollowersノートはRenoteできるように
+* 画像ダイアログを実装
 * フォロー申請ページの調整
 * 壁紙設定の強化
 * 画面が狭い状態でMisskeyを起動した場合でも、画面幅が広がったときにウィジェットを表示するように
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 9d88a13601..b628b91ab0 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -402,6 +402,7 @@ existingAcount: "既存のアカウント"
 regenerate: "再生成"
 fontSize: "フォントサイズ"
 noFollowRequests: "フォロー申請はありません"
+openImageInNewTab: "画像を新しいタブで開く"
 
 _ago:
   unknown: "謎"
diff --git a/src/client/components/image-viewer.vue b/src/client/components/image-viewer.vue
new file mode 100644
index 0000000000..3359b600da
--- /dev/null
+++ b/src/client/components/image-viewer.vue
@@ -0,0 +1,54 @@
+<template>
+<x-modal ref="modal" @closed="() => { $emit('closed'); destroyDom(); }">
+	<img class="xubzgfga" ref="img" :src="image.url" :alt="image.name" :title="image.name" @click="close" tabindex="-1"/>
+</x-modal>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import i18n from '../i18n';
+import XModal from './modal.vue';
+
+export default Vue.extend({
+	i18n,
+
+	components: {
+		XModal,
+	},
+
+	props: {
+		image: {
+			type: Object,
+			required: true
+		},
+	},
+
+	mounted() {
+		this.$nextTick(() => {
+			this.$refs.img.focus();
+		});
+	},
+
+	methods: {
+		close() {
+			this.$refs.modal.close();
+		},
+	}
+});
+</script>
+
+<style lang="scss" scoped>
+.xubzgfga {
+	position: fixed;
+	z-index: 2;
+	top: 0;
+	right: 0;
+	bottom: 0;
+	left: 0;
+	max-width: 100%;
+	max-height: 100%;
+	margin: auto;
+	cursor: zoom-out;
+	image-orientation: from-image;
+}
+</style>
diff --git a/src/client/components/media-image.vue b/src/client/components/media-image.vue
index 5ae167d490..3bb1bda5e2 100644
--- a/src/client/components/media-image.vue
+++ b/src/client/components/media-image.vue
@@ -20,6 +20,7 @@ import Vue from 'vue';
 import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
 import i18n from '../i18n';
 import { getStaticImageUrl } from '../scripts/get-static-image-url';
+import ImageViewer from './image-viewer.vue';
 
 export default Vue.extend({
 	i18n,
@@ -60,7 +61,16 @@ export default Vue.extend({
 	},
 	methods: {
 		onClick() {
-			window.open(this.image.url, '_blank');
+			if (this.$store.state.device.imageNewTab) {
+				window.open(this.image.url, '_blank');
+			} else {
+				const viewer = this.$root.new(ImageViewer, {
+					image: this.image
+				});
+				this.$once('hook:beforeDestroy', () => {
+					viewer.close();
+				});
+			}
 		}
 	}
 });
diff --git a/src/client/components/modal.vue b/src/client/components/modal.vue
index a48c7154ee..1a9d98a8cc 100644
--- a/src/client/components/modal.vue
+++ b/src/client/components/modal.vue
@@ -1,5 +1,5 @@
 <template>
-<div class="mk-modal">
+<div class="mk-modal" v-hotkey.global="keymap">
 	<transition :name="$store.state.device.animation ? 'bg-fade' : ''" appear>
 		<div class="bg" ref="bg" v-if="show" @click="close()"></div>
 	</transition>
@@ -20,6 +20,13 @@ export default Vue.extend({
 			show: true,
 		};
 	},
+	computed: {
+		keymap(): any {
+			return {
+				'esc': this.close,
+			};
+		},
+	},
 	methods: {
 		close() {
 			this.show = false;
diff --git a/src/client/pages/settings/general.vue b/src/client/pages/settings/general.vue
index 6b4825c7a9..5a176c0226 100644
--- a/src/client/pages/settings/general.vue
+++ b/src/client/pages/settings/general.vue
@@ -19,6 +19,7 @@
 		<mk-button @click="readAllMessagingMessages">{{ $t('markAsReadAllTalkMessages') }}</mk-button>
 	</div>
 	<div class="_content">
+		<mk-switch v-model="imageNewTab">{{ $t('openImageInNewTab') }}</mk-switch>
 		<mk-switch v-model="disableAnimatedMfm">{{ $t('disableAnimatedMfm') }}</mk-switch>
 		<mk-switch v-model="reduceAnimation">{{ $t('reduceUiAnimation') }}</mk-switch>
 		<mk-switch v-model="useOsNativeEmojis">
@@ -96,6 +97,11 @@ export default Vue.extend({
 			get() { return this.$store.state.device.useOsNativeEmojis; },
 			set(value) { this.$store.commit('device/set', { key: 'useOsNativeEmojis', value }); }
 		},
+
+		imageNewTab: {
+			get() { return this.$store.state.device.imageNewTab; },
+			set(value) { this.$store.commit('device/set', { key: 'imageNewTab', value }); }
+		},
 	},
 
 	watch: {
diff --git a/src/client/store.ts b/src/client/store.ts
index 13722c1bb8..4ebaa9ba55 100644
--- a/src/client/store.ts
+++ b/src/client/store.ts
@@ -38,6 +38,7 @@ const defaultDeviceSettings = {
 	theme: 'light',
 	animation: true,
 	animatedMfm: true,
+	imageNewTab: false,
 	userData: {},
 };