From e6c16f3d372f11d6cf720d5267c03d21a08bdbf2 Mon Sep 17 00:00:00 2001 From: Max G Date: Sat, 20 Jul 2019 23:07:22 +0000 Subject: [PATCH] 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 --- client/src/App.vue | 7 +-- client/src/Helpers.js | 62 +++++++++++++++++++ client/src/components/InputNotes.vue | 61 ++++++++++-------- client/src/components/Notes.vue | 13 +--- client/src/components/SearchBar.vue | 92 +++++++++++++++++++++++----- client/src/main.js | 4 ++ server/models/Notes.js | 26 ++++++-- 7 files changed, 204 insertions(+), 61 deletions(-) create mode 100644 client/src/Helpers.js diff --git a/client/src/App.vue b/client/src/App.vue index 35a5944..3891f47 100644 --- a/client/src/App.vue +++ b/client/src/App.vue @@ -14,10 +14,8 @@ \ No newline at end of file diff --git a/client/src/components/SearchBar.vue b/client/src/components/SearchBar.vue index de998b9..874a381 100644 --- a/client/src/components/SearchBar.vue +++ b/client/src/components/SearchBar.vue @@ -5,29 +5,45 @@
-
- - New Note -
- -
Reset
+
+
+ + New Note +
+
+
+
+ +
+
+ + +
Reset
+
{{ucWords(tag.text)}}
{{tag.usages}}
+

Notes ({{notes.length}})

-
+
+

{{note.text}}

+

Edited: {{$helpers.timeAgo(note.updated)}}

+ + + +
@@ -37,23 +53,75 @@ export default { name: 'SearchBar', + components: { + 'input-notes': require('./InputNotes.vue').default, + }, data () { return { initComponent: true, commonTags: [], searchTerm: '', searchTags: [], - notes: null, - searchDebounce: null + notes: [], + searchDebounce: null, + + //Currently open notes in app + activeNoteId1: null, + activeNoteId2: null, + //Position determines how note is Positioned + activeNote1Position: 0, + activeNote2Position: 0 } }, beforeMount(){ - + this.$bus.$on('close_active_note', position => { + this.closeNote(position) + }) }, mounted() { this.search() }, methods: { + openNote(id){ + + //Do not open same note twice + if(this.activeNoteId1 == id || this.activeNoteId2 == id){ + return; + } + + //1 note open + if(this.activeNoteId1 == null && this.activeNoteId2 == null){ + this.activeNoteId1 = id + this.activeNote1Position = 0 //Middel of page + return + } + //2 notes open + if(this.activeNoteId1 != null && this.activeNoteId2 == null){ + this.activeNoteId2 = id + this.activeNote1Position = 1 //Right side of page + this.activeNote2Position = 2 //Left side of page + return + } + }, + closeNote(position){ + //One note open, close that note + if(position == 0){ + this.activeNoteId1 = null + this.activeNoteId2 = null + } + //Right note closed, thats 1 + if(position == 1){ + this.activeNoteId1 = null + } + if(position == 2){ + this.activeNoteId2 = null + } + + this.activeNote1Position = 0 + this.activeNote2Position = 0 + + this.search() + }, toggleTagFilter(tagId){ if(this.searchTags.includes(tagId)){ @@ -99,10 +167,6 @@ } }) }, - openNote(noteId){ - //Emit open note event - this.$bus.$emit('open_note', noteId) - }, ucWords(str){ return (str + '') .replace(/^(.)|\s+(.)/g, function ($1) { diff --git a/client/src/main.js b/client/src/main.js index 21e0da6..40861e6 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -9,6 +9,10 @@ import store from './stores/mainStore'; import App from './App' import router from './router' +//Attach event bus to main vue object, all components will inherit event bus +import EventBus from './EventBus' +import Helpers from './Helpers' + import CKEditor from '@ckeditor/ckeditor5-vue'; Vue.use( CKEditor ) diff --git a/server/models/Notes.js b/server/models/Notes.js index 41df8b0..88818b8 100644 --- a/server/models/Notes.js +++ b/server/models/Notes.js @@ -5,7 +5,7 @@ let Notes = module.exports = {} Notes.create = (userId, noteText) => { return new Promise((resolve, reject) => { - const created = new Date().toISOString().slice(0, 19).replace('T', ' ') + const created = Math.round((+new Date)/1000) db.promise() .query('INSERT INTO notes (user, text, created) VALUES (?,?,?)', [userId, noteText, created]) @@ -18,11 +18,12 @@ Notes.create = (userId, noteText) => { Notes.update = (userId, noteId, noteText) => { return new Promise((resolve, reject) => { - const now = new Date().toISOString().slice(0, 19).replace('T', ' ') + + const now = Math.round((+new Date)/1000) + db.promise() .query('UPDATE notes SET text = ?, updated = ? WHERE id = ? AND user = ? LIMIT 1', [noteText, now, noteId, userId]) .then((rows, fields) => { - console.log(rows) resolve(rows[0]) }) .catch(console.log) @@ -63,7 +64,7 @@ Notes.search = (userId, searchQuery, searchTags) => { //Default note lookup gets all notes let noteSearchQuery = ` - SELECT notes.id, SUBSTRING(text, 1, 100) as text + SELECT notes.id, SUBSTRING(text, 1, 200) as text, updated FROM notes LEFT JOIN notes_tags ON (notes.id = notes_tags.note_id) WHERE user = ?` @@ -81,7 +82,7 @@ Notes.search = (userId, searchQuery, searchTags) => { } //Finish up note query - noteSearchQuery += ' GROUP BY notes.id ORDER BY updated DESC, created DESC' + noteSearchQuery += ' GROUP BY notes.id ORDER BY updated DESC, created DESC, id DESC' //Define return data objects let returnData = { @@ -96,10 +97,23 @@ Notes.search = (userId, searchQuery, searchTags) => { //Push all notes returnData['notes'] = noteRows[0] - //Pull Tags off of selected notes + //pull out all note ids so we can fetch all tags for those notes let noteIds = [] returnData['notes'].forEach(note => { + + //Grab note ID for finding tags noteIds.push(note.id) + + //Attempt to pull string out of first tag in note + let reg = note.text.match(/<([\w]+)[^>]*>(.*?)<\/\1>/) + if(reg != null){ + note.text = reg[2] + } + //Return all notes with HTML tags pulled out + note.text = note.text + .replace(/&[#A-Za-z0-9]+;/g,'') //Rip out all HTML entities + .replace(/<[^>]+>/g, '') //Rip out all HTML tags + }) //If no notes are returned, there are no tags, return empty