SolidScribe/client/src/components/InputNotes.vue
Max G e6c16f3d37 Better formatting and tag stripping for note title display
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
2019-07-20 23:07:22 +00:00

236 lines
5.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>