231 lines
4.8 KiB
Vue
231 lines
4.8 KiB
Vue
<template>
|
|
<AppSidebar v-if="sidebarOpen"
|
|
:title="note.title"
|
|
:subtitle="subtitle"
|
|
:star-loading="loading.favorite"
|
|
:starred="note.favorite"
|
|
@update:starred="onSetFavorite"
|
|
@close="onCloseSidebar"
|
|
>
|
|
<div class="sidebar-content-wrapper">
|
|
<div class="note-category" :title="t('notes', 'Set category')">
|
|
<h4>{{ t('notes', 'Category') }} <span v-tooltip="categoriesInfo" class="icon-info svg" /></h4>
|
|
<form class="category" @submit.prevent.stop="">
|
|
<Multiselect id="category"
|
|
:value="category"
|
|
:options="categories"
|
|
:placeholder="t('notes', 'Uncategorized')"
|
|
:disabled="loading.category"
|
|
:class="['category-select', {'icon-loading-small': loading.category}]"
|
|
:show-no-results="false"
|
|
:taggable="true"
|
|
:preserve-search="true"
|
|
@input="onSaveCategory"
|
|
@close="onFinishEditCategory"
|
|
@search-change="onEditCategory"
|
|
>
|
|
<template #option="{ option }">
|
|
<span :class="{ gray: option==='' }">{{ option | categoryOptionLabel }}</span>
|
|
</template>
|
|
</Multiselect>
|
|
<input
|
|
type="text"
|
|
style="display: none"
|
|
><input
|
|
type="submit"
|
|
value=""
|
|
class="icon-confirm loading"
|
|
:disabled="loading.category"
|
|
>
|
|
</form>
|
|
</div>
|
|
<div class="modified"
|
|
:title="t('notes', 'Click here to save manually')"
|
|
@click="onManualSave"
|
|
>
|
|
<div v-show="note.error" class="note-error">
|
|
{{ t('notes', 'Saving failed!') }}
|
|
</div>
|
|
{{ t('notes', 'Last modified: {date}', { date: formattedDate }) }}
|
|
<span v-show="note.unsaved" :title="t('notes', 'Note has unsaved changes')"> * </span>
|
|
</div>
|
|
</div>
|
|
</AppSidebar>
|
|
</template>
|
|
<script>
|
|
|
|
import {
|
|
AppSidebar,
|
|
Multiselect,
|
|
Tooltip,
|
|
} from '@nextcloud/vue'
|
|
|
|
import { categoryLabel, getCategories, setFavorite, setCategory, saveNoteManually } from '../NotesService'
|
|
import store from '../store'
|
|
|
|
export default {
|
|
name: 'Sidebar',
|
|
|
|
components: {
|
|
AppSidebar,
|
|
Multiselect,
|
|
},
|
|
|
|
directives: {
|
|
tooltip: Tooltip,
|
|
},
|
|
|
|
filters: {
|
|
categoryOptionLabel: function(obj) {
|
|
const category = obj.isTag ? obj.label : obj
|
|
return categoryLabel(category)
|
|
},
|
|
},
|
|
|
|
props: {
|
|
noteId: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
},
|
|
|
|
data: function() {
|
|
return {
|
|
loading: {
|
|
category: false,
|
|
favorite: false,
|
|
},
|
|
categoryInput: null,
|
|
}
|
|
},
|
|
|
|
computed: {
|
|
note() {
|
|
return store.getters.getNote(parseInt(this.noteId))
|
|
},
|
|
category() {
|
|
return this.note ? this.note.category : ''
|
|
},
|
|
formattedDate() {
|
|
return OC.Util.formatDate(this.note.modified * 1000)
|
|
},
|
|
wordCount() {
|
|
const value = this.note.content
|
|
if (value && (typeof value === 'string')) {
|
|
const wordCount = value.split(/\s+/).filter(
|
|
// only count words containing
|
|
// at least one alphanumeric character
|
|
value => value.search(/[A-Za-z0-9]/) !== -1
|
|
).length
|
|
return n('notes', '%n word', '%n words', wordCount)
|
|
} else {
|
|
return ''
|
|
}
|
|
},
|
|
subtitle() {
|
|
return this.wordCount
|
|
},
|
|
categoriesInfo() {
|
|
return t('notes', 'You can create subcategories by using “/” as delimiter between parent category and subcategory, e.g. “{parent}/{sub}”.', { parent: t('notes', 'Category'), sub: t('notes', 'Subcategory') })
|
|
},
|
|
categories() {
|
|
return [ '', ...getCategories(0, false) ]
|
|
},
|
|
sidebarOpen() {
|
|
return store.state.sidebarOpen
|
|
},
|
|
},
|
|
|
|
methods: {
|
|
onCloseSidebar() {
|
|
store.commit('setSidebarOpen', false)
|
|
},
|
|
|
|
onEditCategory(text) {
|
|
this.categoryInput = text
|
|
},
|
|
|
|
onFinishEditCategory(str) {
|
|
if (this.categoryInput) {
|
|
this.onSaveCategory(this.categoryInput)
|
|
}
|
|
},
|
|
|
|
onSetFavorite(favorite) {
|
|
this.loading.favorite = true
|
|
setFavorite(this.note.id, favorite)
|
|
.catch(() => {
|
|
})
|
|
.then(() => {
|
|
this.loading.favorite = false
|
|
})
|
|
},
|
|
|
|
onSaveCategory(category) {
|
|
this.categoryInput = null
|
|
if (category !== null && this.note.category !== category) {
|
|
this.loading.category = true
|
|
this.note.category = category
|
|
setCategory(this.note.id, category)
|
|
.catch(() => {
|
|
})
|
|
.then(() => {
|
|
this.loading.category = false
|
|
})
|
|
}
|
|
},
|
|
|
|
onManualSave() {
|
|
saveNoteManually(this.note.id)
|
|
},
|
|
|
|
},
|
|
}
|
|
</script>
|
|
<style scoped>
|
|
.sidebar-content-wrapper {
|
|
padding: 0 10px;
|
|
}
|
|
|
|
.note-error {
|
|
background-color: var(--color-error);
|
|
color: var(--color-primary-text);
|
|
border-radius: 0.5ex;
|
|
padding: 0.5ex 1ex;
|
|
}
|
|
|
|
.note-category {
|
|
margin-top: 1ex;
|
|
}
|
|
|
|
form.category > .multiselect,
|
|
form.category > .icon-confirm {
|
|
vertical-align: middle;
|
|
}
|
|
|
|
form.category {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.note-category .icon-info {
|
|
padding: 11px 20px;
|
|
vertical-align: super;
|
|
}
|
|
|
|
.category-select {
|
|
flex-grow: 1;
|
|
}
|
|
|
|
.gray {
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.modified {
|
|
position: absolute;
|
|
bottom: 0;
|
|
padding: 1ex 0;
|
|
opacity: 0.5;
|
|
}
|
|
</style>
|