diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 31d51c25f..70192a55c 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2300,8 +2300,10 @@ room: exit: "戻る" remove: "しまう" save: "保存" + saved: "保存しました" clear: "片付け" clear-confirm: "全ての家具をしまいますか?" + leave-confirm: "未保存の変更があります、移動しますか?" chooseImage: "画像を選択" room-type: "部屋のタイプ" carpet-color: "床の色" diff --git a/src/client/app/common/views/pages/room/room.vue b/src/client/app/common/views/pages/room/room.vue index 2456f8f8e..1e81920c2 100644 --- a/src/client/app/common/views/pages/room/room.vue +++ b/src/client/app/common/views/pages/room/room.vue @@ -42,7 +42,7 @@
- {{ $t('save') }} + {{ $t('save') }} {{ $t('clear') }}
@@ -87,11 +87,14 @@ export default Vue.extend({ isTranslateMode: false, isRotateMode: false, isMyRoom: false, + changed: false, faBoxOpen, faSave, faTrashAlt, faUndo, faArrowsAlt, faBan, faBroom, }; }, async mounted() { + window.addEventListener('beforeunload', this.beforeunload); + const user = await this.$root.api('users/show', { ...parseAcct(this.acct) }); @@ -125,11 +128,37 @@ export default Vue.extend({ }); }, + beforeRouteLeave(to, from, next) { + if (this.changed) { + this.$root.dialog({ + type: 'warning', + text: this.$t('leave-confirm'), + showCancelButton: true + }).then(({ canceled }) => { + if (canceled) { + next(false); + } else { + next(); + } + }); + } else { + next(); + } + }, + beforeDestroy() { room.destroy(); + window.removeEventListener('beforeunload', this.beforeunload); }, methods: { + beforeunload(e: BeforeUnloadEvent) { + if (this.changed) { + e.preventDefault(); + e.returnValue = ''; + } + }, + async add() { const { canceled, result: id } = await this.$root.dialog({ type: null, @@ -143,17 +172,30 @@ export default Vue.extend({ }); if (canceled) return; room.addFurniture(id); + this.changed = true; }, remove() { this.isTranslateMode = false; this.isRotateMode = false; room.removeFurniture(); + this.changed = true; }, save() { this.$root.api('room/update', { room: room.getRoomInfo() + }).then(() => { + this.changed = false; + this.$root.dialog({ + type: 'success', + text: this.$t('saved') + }); + }).catch((e: any) => { + this.$root.dialog({ + type: 'error', + text: e.message + }); }); }, @@ -165,6 +207,7 @@ export default Vue.extend({ }).then(({ canceled }) => { if (canceled) return; room.removeAllFurnitures(); + this.changed = true; }); }, @@ -174,22 +217,26 @@ export default Vue.extend({ }).then(file => { room.updateProp(key, `/proxy/?${urlQuery({ url: file.thumbnailUrl })}`); this.$refs.preview.selected(room.getSelectedObject()); + this.changed = true; }); }, updateColor(key, ev) { room.updateProp(key, ev.target.value); this.$refs.preview.selected(room.getSelectedObject()); + this.changed = true; }, updateCarpetColor(ev) { room.updateCarpetColor(ev.target.value); this.carpetColor = ev.target.value; + this.changed = true; }, updateRoomType(type) { room.changeRoomType(type); this.roomType = type; + this.changed = true; }, translate() { @@ -200,6 +247,7 @@ export default Vue.extend({ this.isTranslateMode = true; room.enterTransformMode('translate'); } + this.changed = true; }, rotate() { @@ -210,12 +258,14 @@ export default Vue.extend({ this.isRotateMode = true; room.enterTransformMode('rotate'); } + this.changed = true; }, exit() { this.isTranslateMode = false; this.isRotateMode = false; room.exitTransformMode(); + this.changed = true; } } });