308 lines
6.3 KiB
Vue
308 lines
6.3 KiB
Vue
<template>
|
|
<AppContent :class="{ loading: loading || isManualSave, 'icon-error': !loading && (!note || note.error), 'sidebar-open': sidebarOpen }">
|
|
<div v-if="!loading && note && !note.error && !note.deleting"
|
|
id="note-container"
|
|
class="note-container"
|
|
:class="{ fullscreen: fullscreen }"
|
|
>
|
|
<div class="note-editor">
|
|
<div v-show="!note.content" class="placeholder">
|
|
{{ preview ? t('notes', 'Empty note') : t('notes', 'Write …') }}
|
|
</div>
|
|
<ThePreview v-if="preview" :value="note.content" />
|
|
<TheEditor v-else :value="note.content" @input="onEdit" />
|
|
</div>
|
|
<span class="action-buttons">
|
|
<Actions :open.sync="actionsOpen" menu-align="right">
|
|
<ActionButton v-show="!sidebarOpen && !fullscreen"
|
|
icon="icon-details"
|
|
@click="onToggleSidebar"
|
|
>
|
|
{{ t('notes', 'Details') }}
|
|
</ActionButton>
|
|
<ActionButton v-if="!preview"
|
|
icon="icon-toggle"
|
|
@click="onTogglePreview"
|
|
>
|
|
{{ t('notes', 'Preview') }}
|
|
</ActionButton>
|
|
<ActionButton v-else
|
|
icon="icon-rename"
|
|
@click="onTogglePreview"
|
|
>
|
|
{{ t('notes', 'Edit') }}
|
|
</ActionButton>
|
|
<ActionButton
|
|
icon="icon-fullscreen"
|
|
:class="{ active: fullscreen }"
|
|
@click="onToggleDistractionFree"
|
|
>
|
|
{{ fullscreen ? t('notes', 'Exit full screen') : t('notes', 'Full screen') }}
|
|
</ActionButton>
|
|
</Actions>
|
|
<button v-show="note.saveError"
|
|
v-tooltip.right="t('notes', 'Save failed. Click to retry.')"
|
|
class="action-error icon-error-color"
|
|
@click="onManualSave"
|
|
/>
|
|
</span>
|
|
</div>
|
|
</AppContent>
|
|
</template>
|
|
<script>
|
|
|
|
import {
|
|
Actions,
|
|
ActionButton,
|
|
AppContent,
|
|
Tooltip,
|
|
} from '@nextcloud/vue'
|
|
|
|
import { fetchNote, saveNote, saveNoteManually } from '../NotesService'
|
|
import { closeNavbar } from '../nextcloud'
|
|
import TheEditor from './EditorEasyMDE'
|
|
import ThePreview from './EditorMarkdownIt'
|
|
import store from '../store'
|
|
|
|
export default {
|
|
name: 'Note',
|
|
|
|
components: {
|
|
Actions,
|
|
ActionButton,
|
|
AppContent,
|
|
TheEditor,
|
|
ThePreview,
|
|
},
|
|
|
|
directives: {
|
|
tooltip: Tooltip,
|
|
},
|
|
|
|
props: {
|
|
noteId: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
},
|
|
|
|
data: function() {
|
|
return {
|
|
loading: false,
|
|
fullscreen: false,
|
|
preview: false,
|
|
actionsOpen: false,
|
|
}
|
|
},
|
|
|
|
computed: {
|
|
note() {
|
|
return store.getters.getNote(parseInt(this.noteId))
|
|
},
|
|
title() {
|
|
return this.note ? this.note.title : ''
|
|
},
|
|
isManualSave() {
|
|
return store.state.isManualSave
|
|
},
|
|
sidebarOpen() {
|
|
return store.state.sidebarOpen
|
|
},
|
|
},
|
|
|
|
watch: {
|
|
// call again the method if the route changes
|
|
'$route': 'fetchData',
|
|
title: 'onUpdateTitle',
|
|
},
|
|
|
|
created() {
|
|
this.fetchData()
|
|
// TODO move the following from jQuery to plain JS
|
|
$(document).bind('webkitfullscreenchange mozfullscreenchange fullscreenchange', this.onDetectFullscreen)
|
|
$(document).bind('keypress.notes.save', this.onKeyPress)
|
|
},
|
|
|
|
destroyed() {
|
|
$(document).unbind('keypress.notes.save')
|
|
store.commit('setSidebarOpen', false)
|
|
this.onUpdateTitle(null)
|
|
},
|
|
|
|
methods: {
|
|
fetchData() {
|
|
store.commit('setSidebarOpen', false)
|
|
|
|
closeNavbar()
|
|
|
|
this.onUpdateTitle(this.title)
|
|
this.loading = true
|
|
this.preview = false
|
|
fetchNote(this.noteId)
|
|
.then((note) => {
|
|
if (note.errorMessage) {
|
|
OC.Notification.showTemporary(note.errorMessage)
|
|
}
|
|
})
|
|
.catch(() => {
|
|
// note not found
|
|
})
|
|
.then(() => {
|
|
this.loading = false
|
|
})
|
|
},
|
|
|
|
onUpdateTitle(title) {
|
|
const defaultTitle = store.state.documentTitle
|
|
if (title) {
|
|
document.title = title + ' - ' + defaultTitle
|
|
} else {
|
|
document.title = defaultTitle
|
|
}
|
|
},
|
|
|
|
onTogglePreview() {
|
|
this.preview = !this.preview
|
|
this.actionsOpen = false
|
|
},
|
|
|
|
onDetectFullscreen() {
|
|
this.fullscreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen
|
|
},
|
|
|
|
onToggleDistractionFree() {
|
|
function launchIntoFullscreen(element) {
|
|
if (element.requestFullscreen) {
|
|
element.requestFullscreen()
|
|
} else if (element.mozRequestFullScreen) {
|
|
element.mozRequestFullScreen()
|
|
} else if (element.webkitRequestFullscreen) {
|
|
element.webkitRequestFullscreen()
|
|
} else if (element.msRequestFullscreen) {
|
|
element.msRequestFullscreen()
|
|
}
|
|
}
|
|
|
|
function exitFullscreen() {
|
|
if (document.exitFullscreen) {
|
|
document.exitFullscreen()
|
|
} else if (document.mozCancelFullScreen) {
|
|
document.mozCancelFullScreen()
|
|
} else if (document.webkitExitFullscreen) {
|
|
document.webkitExitFullscreen()
|
|
}
|
|
}
|
|
|
|
if (this.fullscreen) {
|
|
exitFullscreen()
|
|
} else {
|
|
launchIntoFullscreen(document.getElementById('note-container'))
|
|
}
|
|
this.actionsOpen = false
|
|
},
|
|
|
|
onToggleSidebar() {
|
|
store.commit('setSidebarOpen', !store.state.sidebarOpen)
|
|
this.actionsOpen = false
|
|
},
|
|
|
|
onEdit(newContent) {
|
|
if (this.note.content !== newContent) {
|
|
const note = {
|
|
...this.note,
|
|
content: newContent,
|
|
unsaved: true,
|
|
}
|
|
store.commit('add', note)
|
|
setTimeout(saveNote.bind(this, note.id), 1000)
|
|
}
|
|
},
|
|
|
|
onKeyPress(event) {
|
|
if (event.ctrlKey || event.metaKey) {
|
|
switch (String.fromCharCode(event.which).toLowerCase()) {
|
|
case 's':
|
|
event.preventDefault()
|
|
this.onManualSave()
|
|
break
|
|
}
|
|
}
|
|
},
|
|
|
|
onManualSave() {
|
|
saveNoteManually(this.note.id)
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
<style scoped>
|
|
.note-container {
|
|
min-height: 100%;
|
|
width: 100%;
|
|
background-color: var(--color-main-background);
|
|
}
|
|
|
|
.note-editor {
|
|
max-width: 47em;
|
|
font-size: 16px;
|
|
padding: 1em;
|
|
}
|
|
|
|
/* center editor on large screens */
|
|
@media (min-width: 1600px) {
|
|
.note-editor {
|
|
margin: 0 auto;
|
|
}
|
|
.note-container {
|
|
padding-right: 250px;
|
|
transition-duration: var(--animation-quick);
|
|
transition-property: padding-right;
|
|
}
|
|
.sidebar-open .note-container {
|
|
padding-right: 0px;
|
|
}
|
|
}
|
|
|
|
/* distraction free styles */
|
|
.note-container.fullscreen {
|
|
width: 100vw;
|
|
height: 100vh;
|
|
overflow-y: auto;
|
|
padding: 0;
|
|
}
|
|
|
|
.note-container.fullscreen .note-editor {
|
|
margin: 0 auto;
|
|
}
|
|
|
|
/* placeholder */
|
|
.placeholder {
|
|
position: absolute;
|
|
padding: 1em;
|
|
opacity: 0.5;
|
|
}
|
|
|
|
/* main editor button */
|
|
.action-buttons {
|
|
position: fixed;
|
|
top: 50px;
|
|
right: 20px;
|
|
width: 44px;
|
|
margin-top: 1em;
|
|
z-index: 2000;
|
|
}
|
|
|
|
.action-buttons .action-error {
|
|
width: 44px;
|
|
height: 44px;
|
|
}
|
|
|
|
.note-container.fullscreen .action-buttons {
|
|
top: 0px;
|
|
}
|
|
|
|
.action-buttons button {
|
|
padding: 15px;
|
|
}
|
|
</style>
|