e6c16f3d37
cleaned up interface a bunch allow for opening of two notes at once Escape closes note Added global helper class and time ago function Time ago function displays on main page and in note Removed tab button creating tabbed spaces in document Simplified save text
236 lines
5.9 KiB
Vue
236 lines
5.9 KiB
Vue
<template>
|
||
<div id="InputNotes" class="master-note-edit" :class="[ 'position-'+position ]" @keyup.esc="close">
|
||
|
||
<ckeditor ref="main-edit"
|
||
:editor="editor" @ready="onReady" v-model="noteText" :config="editorConfig" v-on:blur="save"></ckeditor>
|
||
|
||
<div class="ui buttons">
|
||
<div class="ui green button">{{statusText}}</div>
|
||
<div class="ui button">Delete</div>
|
||
<div v-on:click="close" class="ui button">Close (ESC)</div>
|
||
</div>
|
||
<p>
|
||
Last Updated: {{$helpers.timeAgo(updated)}}
|
||
</p>
|
||
|
||
<div class="ui segment">
|
||
<note-tag-edit :noteId="noteid" :key="'tags-for-note-'+noteid"/>
|
||
</div>
|
||
|
||
<div class="ui segment" v-if="false">
|
||
Block formatting
|
||
|
||
The following block formatting options are available:
|
||
|
||
<p> Bulleted list – Start a line with * or - followed by a space.</p>
|
||
<p> Numbered list – Start a line with 1. or 1) followed by a space.</p>
|
||
<p> Headings – Start a line with # or ## or ### followed by a space to create a heading 1, heading 2 or heading 3 (up to heading 6 if options defines more headings).</p>
|
||
<p> Block quote – Start a line with > followed by a space.</p>
|
||
|
||
Inline formatting
|
||
|
||
The following inline formatting options are available:
|
||
|
||
Bold – Type **text** or __text__,
|
||
Italic – Type *text* or _text_,
|
||
Code – Type `text`.
|
||
</div>
|
||
|
||
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
|
||
import axios from 'axios'
|
||
import DecoupledEditor from '@ckeditor/ckeditor5-build-decoupled-document';
|
||
|
||
|
||
export default {
|
||
name: 'InputNotes',
|
||
props: [ 'noteid', 'position' ],
|
||
components:{
|
||
'note-tag-edit': require('./NoteTagEdit.vue').default
|
||
},
|
||
data(){
|
||
return {
|
||
currentNoteId: 0,
|
||
noteText: '',
|
||
statusText: 'Save',
|
||
lastNoteHash: null,
|
||
lastSaved: 0,
|
||
updated: 'Never',
|
||
editDebounce: null,
|
||
keyPressesCounter: 0,
|
||
|
||
editor: DecoupledEditor,
|
||
editorConfig: {
|
||
startupFocus: 'end',
|
||
toolbar: ["alignment", "fontSize", "removeHighlight", "highlight", "bold", "italic", "strikethrough", "underline", "blockQuote", "heading", "link", "numberedList", "bulletedList", "insertTable", "|", "undo", "redo"]
|
||
}
|
||
}
|
||
},
|
||
watch: {
|
||
noteid:function(newVal, oldVal){
|
||
|
||
if(newVal == this.currentNoteId){
|
||
return
|
||
}
|
||
|
||
if(newVal == oldVal){
|
||
return
|
||
}
|
||
|
||
this.currentNoteId = newVal
|
||
this.loadNote(this.currentNoteId)
|
||
|
||
}
|
||
},
|
||
beforeMount(){
|
||
|
||
},
|
||
beforeDestroy(){
|
||
|
||
},
|
||
mounted: function() {
|
||
|
||
this.loadNote(this.noteid)
|
||
},
|
||
methods: {
|
||
loadNote(noteId){
|
||
let vm = this
|
||
//Component is activated with NoteId in place, lookup text with associated ID
|
||
if(this.$store.getters.getLoggedIn){
|
||
axios.post('/api/notes/get', {'noteId': noteId})
|
||
.then(response => {
|
||
//Set up local data
|
||
vm.currentNoteId = noteId
|
||
vm.noteText = response.data.text
|
||
vm.updated = response.data.updated
|
||
vm.lastNoteHash = vm.hashString(response.data.text)
|
||
|
||
//Put focus on note, at the end of the note text
|
||
vm.$nextTick(() => {
|
||
// vm.$refs['custom-input'].focus()
|
||
})
|
||
|
||
})
|
||
} else {
|
||
console.log('Could not fetch note')
|
||
}
|
||
},
|
||
onReady(editor){
|
||
|
||
let vm = this
|
||
|
||
// Insert the toolbar before the editable area.
|
||
editor.ui.getEditableElement().parentElement.insertBefore(
|
||
editor.ui.view.toolbar.element,
|
||
editor.ui.getEditableElement()
|
||
);
|
||
|
||
editor.editing.view.focus()
|
||
|
||
// const editor = this.editor;
|
||
const view = editor.editing.view;
|
||
const viewDocument = view.document;
|
||
|
||
//Insert 5 spaces when tab is pressed
|
||
viewDocument.on( 'keyup', ( evt, data ) => {
|
||
|
||
//Each note, save after 5 seconds, focus lost or 30 characters typed.
|
||
clearTimeout(vm.editDebounce)
|
||
vm.editDebounce = setTimeout(() => {
|
||
vm.save()
|
||
}, 5000)
|
||
//Save after 20 keystrokes
|
||
vm.keyPressesCounter = (vm.keyPressesCounter + 1)
|
||
if(vm.keyPressesCounter > 30){
|
||
vm.keyPressesCounter = 0
|
||
vm.save()
|
||
}
|
||
|
||
//Optional data bindings for tab key
|
||
if( (data.keyCode == 9) && viewDocument.isFocused ){
|
||
|
||
//Insert 5 spaces to simulate tab
|
||
//editor.execute( 'input', { text: " " } );
|
||
|
||
evt.stop(); // Prevent executing the default handler.
|
||
data.preventDefault();
|
||
view.scrollToTheSelection();
|
||
}
|
||
|
||
} );
|
||
},
|
||
save(){
|
||
|
||
clearTimeout(this.editDebounce)
|
||
|
||
//Don't save note if its hash doesn't change
|
||
if(this.lastNoteHash == this.hashString(this.noteText)){
|
||
return
|
||
}
|
||
|
||
|
||
const postData = {
|
||
'noteId':this.currentNoteId,
|
||
'text': this.noteText
|
||
}
|
||
|
||
let vm = this
|
||
|
||
//Only notify user if saving - may help with debugging in the future
|
||
vm.statusText = 'Saving'
|
||
axios.post('/api/notes/update', postData).then( response => {
|
||
vm.statusText = 'Save'
|
||
vm.updated = Math.round((+new Date)/1000)
|
||
|
||
//Update last saved note hash
|
||
vm.lastNoteHash = vm.hashString(vm.noteText)
|
||
})
|
||
},
|
||
hashString(text){
|
||
var hash = 0;
|
||
if (text.length == 0) {
|
||
return hash;
|
||
}
|
||
for (let i = 0; i < text.length; i++) {
|
||
let char = text.charCodeAt(i);
|
||
hash = ((hash<<5)-hash)+char;
|
||
hash = hash & hash; // Convert to 32bit integer
|
||
}
|
||
return hash;
|
||
},
|
||
close(){
|
||
this.$bus.$emit('close_active_note', this.position)
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style type="text/css" scoped>
|
||
|
||
.master-note-edit {
|
||
position: fixed;
|
||
bottom: 0;
|
||
background: white;
|
||
height: 99vh;
|
||
box-shadow: 0px 0px 5px 2px rgba(140,140,140,1);
|
||
}
|
||
/* One note open, in the middle of the screen */
|
||
.master-note-edit.position-0 {
|
||
left: 30%;
|
||
right: 1%;
|
||
}
|
||
/* Two Notes Open, each takes up 50% of the space */
|
||
.master-note-edit.position-1 {
|
||
left: 50%;
|
||
right: 0%;
|
||
}
|
||
.master-note-edit.position-2 {
|
||
left: 0%;
|
||
right: 50%;
|
||
}
|
||
|
||
</style> |