Added a night mode and no way to toggle it!

Tweaked a lot of styles and added some cool animations
Added a little to the help text
Quickly adding a note, saving and closing no longer causes half formed or empty notes to appear
Close Editor animation
Display cards text show at the bottom of card
Added a delete function, and it works
Added browser title attributes
More debugging and error checking on scraped links
Updated not search to display title and text below the title
This commit is contained in:
Max G 2019-07-29 07:22:47 +00:00
parent b0a8071b41
commit fcee24a61d
13 changed files with 387 additions and 105 deletions

View File

@ -1,18 +1,110 @@
/*body, h3, h2, h1, p {
color: #3d3d3d; :root {
}*/ --primary_color: #1C84DA;
--secondary_color: #1EAEDB;
--element_background_color: #FFF;
--background_color: #fff;
--text_color: #3d3d3d;
--outline_color: rgba(34,36,38,.15);
}
/* Night mode colors */
:root {
--background_color: #000;
--text_color: #a98457;
--outline_color: #a98457;
}
/* OVERWRITE DEFAULT SEMANTIC STYLES FOR CUSTOM/NIGHT MODES*/
body{
color: var(--text_color);
background-color: var(--background_color);
}
.ui.form input:not([type]),
.ui.form input:not([type]):focus {
color: var(--text_color);
background-color: var(--background_color);
border-color: var(--border_color);
}
.ui.basic.label {
color: var(--text_color);
background-color: var(--background_color);
border-color: var(--border_color);
}
div.ui.basic.green.label {
background-color: var(--background_color) !important;
}
.ui.basic.button, .ui.basic.buttons .button {
background-color: var(--background_color) !important;
color: var(--text_color) !important;
border: 1px solid;
border-color: var(--border_color) !important;
box-shadow: none;
}
.ui.basic.button:focus, .ui.basic.button:hover {
background-color: var(--background_color) !important;
color: var(--text_color) !important;
box-shadow: none;
}
.ui.tabular.menu .item {
background-color: var(--background_color) !important;
color: var(--text_color) !important;
}
.ui.tabular.menu .item.active {
background-color: var(--background_color) !important;
color: var(--text_color) !important;
border-color: var(--border_color) !important;
}
/* OVERWRITE DEFAULT SEMANTIC STYLES FOR CUSTOM/NIGHT MODES*/
.clickable { .clickable {
cursor: pointer; cursor: pointer;
} }
.textarea-height {
height: calc(100% - 105px);
}
.ck-content { .ck-content {
font-family: 'Open Sans' !important; font-family: 'Open Sans' !important;
font-size: 1.3rem !important; font-size: 1.3rem !important;
background-color: rgba(255, 255, 255, 0); background-color: rgba(255, 255, 255, 0);
height: 100%; height: calc(100% - 40px);
overflow: hidden; overflow: hidden;
} }
.ck .ck-editor__nested-editable:focus {
background-color: var(--background_color) !important;
}
.ui.white.button { .ui.white.button {
background: #FFF; background: #FFF;
}
.fade-in-fwd {
animation: fade-in-fwd 0.8s both;
}
/* ----------------------------------------------
* Generated by Animista on 2019-7-25 17:12:5
* w: http://animista.net, t: @cssanimista
* ---------------------------------------------- */
/**
* ----------------------------------------
* animation fade-in-fwd
* ----------------------------------------
*/
@keyframes fade-in-fwd {
0% {
transform: translateZ(-80px);
opacity: 0;
}
100% {
transform: translateZ(0);
opacity: 1;
}
} }

View File

@ -0,0 +1,40 @@
<template>
<span>
<span class="clickable" @click="confirmDelete()" v-if="click == 0">
<i class="grey trash alternate icon"></i>
</span>
<span class="clickable" @click="actuallyDelete()" @mouseleave="reset" v-if="click == 1" data-tooltip="Click again to delete." data-position="left center">
<i class="red trash alternate icon"></i>
</span>
</span>
</template>
<script>
import axios from 'axios'
export default {
name: 'NoteTitleDisplayCard',
props: [ 'noteId', 'displayText' ],
data () {
return {
click: 0,
}
},
methods:{
confirmDelete(){
this.click++
},
actuallyDelete(){
axios.post('/api/notes/delete', {'noteId':this.noteId}).then(response => {
if(response.data == true){
this.$bus.$emit('note_deleted')
}
})
},
reset(){
this.click = 0
}
}
}
</script>

View File

@ -2,6 +2,9 @@
<div class="ui basic segment"> <div class="ui basic segment">
<div class="ui container"> <div class="ui container">
CTRL + SHIFT + V - paste without formatting
CTRL + Z - Undo in note, <b>Undo youtube video player embed.</b>
<h2>Block formatting</h2> <h2>Block formatting</h2>
<p>The following block formatting options are available:</p> <p>The following block formatting options are available:</p>

View File

@ -1,49 +1,54 @@
<template> <template>
<div id="InputNotes" class="master-note-edit" :class="[ 'position-'+position ]" @keyup.esc="close" :style="{'background-color':color, 'color':fontColor}"> <div
id="InputNotes" class="master-note-edit"
@keyup.esc="close"
:class="[{'size-down':(sizeDown == true)}, 'position-'+position ]"
:style="{'background-color':color, 'color':fontColor}"
>
<div v-if="fancyInput == 1" class="textarea-height no-flow">
<ckeditor ref="main-edit"
:editor="editor" @ready="onReady" v-model="noteText" :config="editorConfig" v-on:blur="save" />
</div>
<div v-if="fancyInput == 1" class="textarea-height no-flow"> <textarea
<ckeditor ref="main-edit" class="textarea-height raw-edit"
:editor="editor" @ready="onReady" v-model="noteText" :config="editorConfig" v-on:blur="save" /> v-if="fancyInput == 0"
</div> v-model="noteText"
v-on:blur="save"
v-on:keyup="onKeyup"
/>
<textarea <div class="ui buttons">
class="textarea-height raw-edit" <div @click="close" class="ui button">Close + Save (ESC)</div>
v-if="fancyInput == 0" <div class="ui button">Delete</div>
v-model="noteText"
v-on:blur="save" <div @click="onToggleFancyInput" class="ui button">
v-on:keyup="onKeyup" Fancy ({{fancyInput?'On':'Off'}})
/> </div>
</div>
<div class="ui buttons"> <div class="ui buttons">
<div class="ui right floated green button">{{statusText}}</div> <button @click="onChangeColor" class="ui icon white button"></button>
<div class="ui button">Delete</div> <button @click="onChangeColor" class="ui icon red button"></button>
<div @click="close" class="ui button">Close (ESC)</div> <button @click="onChangeColor" class="ui icon orange button"></button>
<div @click="onToggleFancyInput" class="ui button"> <button @click="onChangeColor" class="ui icon yellow button"></button>
Fancy ({{fancyInput?'On':'Off'}}) <button @click="onChangeColor" class="ui icon olive button"></button>
</div> <button @click="onChangeColor" class="ui icon green button"></button>
</div> <button @click="onChangeColor" class="ui icon teal button"></button>
<div class="ui buttons"> <button @click="onChangeColor" class="ui icon blue button"></button>
<button @click="onChangeColor" class="ui icon white button"></button> <button @click="onChangeColor" class="ui icon violet button"></button>
<button @click="onChangeColor" class="ui icon red button"></button> <button @click="onChangeColor" class="ui icon purple button"></button>
<button @click="onChangeColor" class="ui icon orange button"></button> <button @click="onChangeColor" class="ui icon pink button"></button>
<button @click="onChangeColor" class="ui icon yellow button"></button> <button @click="onChangeColor" class="ui icon brown button"></button>
<button @click="onChangeColor" class="ui icon olive button"></button> <button @click="onChangeColor" class="ui icon grey button"></button>
<button @click="onChangeColor" class="ui icon green button"></button> <button @click="onChangeColor" class="ui icon black button"></button>
<button @click="onChangeColor" class="ui icon teal button"></button> </div>
<button @click="onChangeColor" class="ui icon blue button"></button> <div class="ui right floated green button">{{statusText}}</div>
<button @click="onChangeColor" class="ui icon violet button"></button>
<button @click="onChangeColor" class="ui icon purple button"></button>
<button @click="onChangeColor" class="ui icon pink button"></button>
<button @click="onChangeColor" class="ui icon brown button"></button>
<button @click="onChangeColor" class="ui icon grey button"></button>
<button @click="onChangeColor" class="ui icon black button"></button>
</div>
<!-- <p> <!-- <p>
Last Updated: {{$helpers.timeAgo(updated)}} Last Updated: {{$helpers.timeAgo(updated)}}
</p> --> </p> -->
<note-tag-edit :noteId="noteid" :key="'tags-for-note-'+noteid"/> <note-tag-edit :noteId="noteid" :key="'tags-for-note-'+noteid"/>
</div> </div>
</template> </template>
@ -64,7 +69,7 @@
return { return {
currentNoteId: 0, currentNoteId: 0,
noteText: '', noteText: '',
statusText: 'Save', statusText: 'Saved',
lastNoteHash: null, lastNoteHash: null,
saveDebounce: null, //Prevent save from being called numerous times quickly saveDebounce: null, //Prevent save from being called numerous times quickly
lastSaved: 0, lastSaved: 0,
@ -74,6 +79,7 @@
fancyInput: 0, //Default to basic text edit. Upgrade if set to 1 fancyInput: 0, //Default to basic text edit. Upgrade if set to 1
color: '#FFF', color: '#FFF',
fontColor: '#000', fontColor: '#000',
sizeDown: false,
editor: DecoupledEditor, editor: DecoupledEditor,
editorConfig: { editorConfig: {
@ -127,7 +133,7 @@
if(this.color == "rgb(255, 255, 255)" || this.color == '#FFF'){ if(this.color == "rgb(255, 255, 255)" || this.color == '#FFF'){
this.color = null this.color = null
this.fontColor = '#000' this.fontColor = null
} }
this.lastNoteHash = 0 //Update hash to force note update on next save this.lastNoteHash = 0 //Update hash to force note update on next save
@ -150,7 +156,7 @@
this.fontColor = '#FFF' this.fontColor = '#FFF'
if(this.color == "rgb(255, 255, 255)" || this.color == '#FFF' || this.color == null){ if(this.color == "rgb(255, 255, 255)" || this.color == '#FFF' || this.color == null){
this.color = null this.color = null
this.fontColor = '#000' this.fontColor = null
} }
if(response.data.raw_input == 1){ if(response.data.raw_input == 1){
@ -201,14 +207,16 @@
} ); } );
}, },
//Used by simple editor
onKeyup(){ onKeyup(){
let vm = this let vm = this
vm.statusText = 'Modified'
//Each note, save after 5 seconds, focus lost or 30 characters typed. //Each note, save after 5 seconds, focus lost or 30 characters typed.
clearTimeout(vm.editDebounce) clearTimeout(vm.editDebounce)
vm.editDebounce = setTimeout(() => { vm.editDebounce = setTimeout(() => {
vm.save() vm.save()
}, 5000) }, 5000)
//Save after 20 keystrokes //Save after 30 keystrokes
vm.keyPressesCounter = (vm.keyPressesCounter + 1) vm.keyPressesCounter = (vm.keyPressesCounter + 1)
if(vm.keyPressesCounter > 30){ if(vm.keyPressesCounter > 30){
vm.keyPressesCounter = 0 vm.keyPressesCounter = 0
@ -216,36 +224,40 @@
} }
}, },
save(){ save(){
return new Promise((resolve, reject) => {
clearTimeout(this.editDebounce) clearTimeout(this.editDebounce)
//Don't save note if its hash doesn't change //Don't save note if its hash doesn't change
if( this.lastNoteHash == this.hashString(this.noteText) ){ if( this.lastNoteHash == this.hashString(this.noteText) ){
return setTimeout(() => {
} resolve(true)
return
const postData = { }, 500)
'noteId':this.currentNoteId, }
'text': this.noteText,
'fancyInput': this.fancyInput, const postData = {
'color': this.color 'noteId':this.currentNoteId,
} 'text': this.noteText,
'fancyInput': this.fancyInput,
'color': this.color
}
let vm = this let vm = this
//Only save every 1 second //Only save every 1 second
clearTimeout(this.saveDebounce) clearTimeout(this.saveDebounce)
this.saveDebounce = setTimeout(() => { this.saveDebounce = setTimeout(() => {
//Only notify user if saving - may help with debugging in the future //Only notify user if saving - may help with debugging in the future
vm.statusText = 'Saving' vm.statusText = 'Saving'
axios.post('/api/notes/update', postData).then( response => { axios.post('/api/notes/update', postData).then( response => {
vm.statusText = 'Save' vm.statusText = 'Saved'
vm.updated = Math.round((+new Date)/1000) vm.updated = Math.round((+new Date)/1000)
//Update last saved note hash
vm.lastNoteHash = vm.hashString(vm.noteText)
})
}, 500)
//Update last saved note hash
vm.lastNoteHash = vm.hashString(vm.noteText)
resolve(true)
})
}, 500)
})
}, },
hashString(text){ hashString(text){
@ -261,8 +273,11 @@
return hash; return hash;
}, },
close(){ close(){
this.save() this.sizeDown = true
this.$bus.$emit('close_active_note', this.position) this.save().then( () => {
this.$bus.$emit('close_active_note', this.position)
})
} }
} }
} }
@ -270,9 +285,7 @@
<style type="text/css" scoped> <style type="text/css" scoped>
.textarea-height {
height: calc(100% - 177px);
}
.no-flow { .no-flow {
overflow: hidden; overflow: hidden;
} }
@ -280,7 +293,7 @@
.raw-edit { .raw-edit {
font-family: 'Open Sans' !important; font-family: 'Open Sans' !important;
font-size: 1.3rem !important; font-size: 1.3rem !important;
background: white; background: rgba(0,0,0,0);
width: 100%; width: 100%;
resize: none; resize: none;
padding: 15px; padding: 15px;
@ -292,7 +305,8 @@
.master-note-edit { .master-note-edit {
position: fixed; position: fixed;
bottom: 0; bottom: 0;
background: white; background: var(--background_color);
/*color: var(--text_color);*/
height: 100vh; height: 100vh;
box-shadow: 0px 0px 5px 2px rgba(140,140,140,1); box-shadow: 0px 0px 5px 2px rgba(140,140,140,1);
} }
@ -320,4 +334,19 @@
right: 50%; right: 50%;
} }
.size-down {
animation: size-down 0.5s linear both;
}
@keyframes size-down {
0% {
opacity: 1;
top: 0;
}
100% {
opacity: 0;
top: 405vh;
}
}
</style> </style>

View File

@ -1,7 +1,35 @@
<template> <template>
<div class="ui clickable segment" @click="onClick(note.id)" :style="{'background-color':color, 'color':fontColor}"> <div class="note-title-display-card fade-in-fwd" :style="{'background-color':color, 'color':fontColor}">
<h3>{{note.text}}</h3>
<p>Edited: {{$helpers.timeAgo(note.updated)}}</p> <div class="ui grid max-height">
<div class="top aligned row">
<div class="sixteen wide column overflow-hidden">
<h3 @click="onClick(note.id)" class="clickable">{{note.title}}</h3>
</div>
<div class="sixteen wide column overflow-hidden">
<p @click="onClick(note.id)" class="clickable">{{note.subtext}}</p>
</div>
</div>
<div class="bottom aligned row">
<div class="ten wide column clickable" @click="onClick(note.id)">Edited: {{$helpers.timeAgo(note.updated)}}</div>
<div class="six wide right aligned column">
<span v-if="note.attachment_count > 0" class>
<i class="grey linkify icon"></i> {{note.attachment_count}}
</span>
<span v-if="note.tag_count == 1" data-tooltip="Note has 1 tag">
<i class="grey tags icon"></i> {{note.tag_count}}
</span>
<span v-if="note.tag_count > 1" :data-tooltip="`Note has ${note.tag_count} tags`">
<i class="grey tags icon"></i> {{note.tag_count}}
</span>
<delete-button :note-id="note.id" />
</div>
</div>
</div>
<!-- Display highlights from solr results --> <!-- Display highlights from solr results -->
<div v-if="note.note_highlights.length > 0" class="term-usage"> <div v-if="note.note_highlights.length > 0" class="term-usage">
@ -9,13 +37,14 @@
<div class="usage-row" v-for="highlight in note.note_highlights" v-html="highlight"></div> <div class="usage-row" v-for="highlight in note.note_highlights" v-html="highlight"></div>
</div> </div>
<div v-if="note.attachment_highlights.length > 0" class="term-usage"> <div v-if="note.attachment_highlights.length > 0" class="term-usage">
<p>Note URL Text</p> <p><i class="linkify icon"></i> Note URL Text</p>
<div class="usage-row" v-for="highlight in note.attachment_highlights" v-html="highlight"></div> <div class="usage-row" v-for="highlight in note.attachment_highlights" v-html="highlight"></div>
</div> </div>
<div v-if="note.tag_highlights.length > 0" class="term-usage"> <div v-if="note.tag_highlights.length > 0" class="term-usage">
Tag <i class="tags icon"></i> Tag
<div class="ui icon large label" v-for="highlight in note.tag_highlights" v-html="highlight"></div> <div class="ui icon large label" v-for="highlight in note.tag_highlights" v-html="highlight"></div>
</div> </div>
</div> </div>
</template> </template>
@ -24,11 +53,14 @@
export default { export default {
name: 'NoteTitleDisplayCard', name: 'NoteTitleDisplayCard',
props: [ 'onClick', 'data' ], props: [ 'onClick', 'data' ],
components: {
'delete-button': require('./DeleteButtonComponent.vue').default,
},
data () { data () {
return { return {
note: null, note: null,
color: '#FFF', color: null, //'#FFF',
fontColor: '#000' fontColor: null, //'#000'
} }
}, },
beforeMount(){ beforeMount(){
@ -43,6 +75,7 @@
} }
</script> </script>
<style type="text/css"> <style type="text/css">
.term-usage { .term-usage {
border: 1px solid #DDD; border: 1px solid #DDD;
padding: 10px; padding: 10px;
@ -57,4 +90,34 @@
border-top: 1px solid #DDD; border-top: 1px solid #DDD;
margin: 8px 0 0; margin: 8px 0 0;
} }
.note-title-display-card {
position: relative;
box-shadow: 0 1px 2px 0 rgba(34,36,38,.15);
margin: 0 15px 15px 0;
padding: 1em;
border-radius: .28571429rem;
border: 1px solid;
border-color: var(--border_color);
width: 31.5%;
/*transition: width 0.2s;*/
}
.one-column .note-title-display-card {
margin-right: 65%;
width: 18%;
}
.overflow-hidden {
overflow: hidden;
word-break: break-all;
}
.max-height {
height: calc(100% + 30px);
}
@media only screen and (max-width: 740px) {
.note-title-display-card {
width: 100%;
margin: 15px 0 0 0;
}
}
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<div id="NotesPage"> <div id="NotesPage">
<div class="ui segment"> <div class="ui basic segment">
<search-bar /> <search-bar />
</div> </div>

View File

@ -50,7 +50,7 @@
<!-- tags display --> <!-- tags display -->
<div class="ui two wide large screen only column"> <div class="ui two wide large screen only column">
<div class="ui basic fluid button" @click="reset">Reset</div> <div class="ui basic fluid button" @click="reset"><i class="undo icon"></i>All Notes</div>
<div class="ui divider"></div> <div class="ui divider"></div>
<div class="ui clickable basic fluid large label" v-for="tag in commonTags" @click="toggleTagFilter(tag.id)" <div class="ui clickable basic fluid large label" v-for="tag in commonTags" @click="toggleTagFilter(tag.id)"
:class="{ 'green':(searchTags.includes(tag.id)) }"> :class="{ 'green':(searchTags.includes(tag.id)) }">
@ -61,7 +61,7 @@
<!-- Note title cards --> <!-- Note title cards -->
<div class="ui fourteen wide computer sixteen wide mobile column"> <div class="ui fourteen wide computer sixteen wide mobile column">
<h2>Notes ({{notes.length}})</h2> <h2>Notes ({{notes.length}})</h2>
<div v-if="notes !== null"> <div v-if="notes !== null" class="note-card-display-area" :class="{'one-column':(activeNoteId1 != null || activeNoteId2 != null )}">
<note-title-display-card <note-title-display-card
v-for="note in notes" v-for="note in notes"
:onClick="openNote" :onClick="openNote"
@ -113,7 +113,9 @@
this.$bus.$on('close_active_note', position => { this.$bus.$on('close_active_note', position => {
this.closeNote(position) this.closeNote(position)
}) })
this.$bus.$on('note_deleted', () => {
this.search()
})
}, },
mounted() { mounted() {
@ -223,6 +225,7 @@
}, },
destroyLoginToken() { destroyLoginToken() {
this.$store.commit('destroyLoginToken') this.$store.commit('destroyLoginToken')
this.$router.push('/')
} }
} }
} }
@ -231,4 +234,8 @@
.detail { .detail {
float: right; float: right;
} }
.note-card-display-area {
display: flex;
flex-wrap: wrap;
}
</style> </style>

View File

@ -9,6 +9,14 @@ import store from './stores/mainStore';
import App from './App' import App from './App'
import router from './router' import router from './router'
// This callback runs before every route change, including on page load.
// Sets the title of the page using vue router
router.beforeEach((to, from, next) => {
document.title = to.meta.title;
next();
});
//Attach event bus to main vue object, all components will inherit event bus //Attach event bus to main vue object, all components will inherit event bus
import EventBus from './EventBus' import EventBus from './EventBus'
import Helpers from './Helpers' import Helpers from './Helpers'

View File

@ -13,21 +13,25 @@ export default new Router({
{ {
path: '/', path: '/',
name: 'HelloWorld', name: 'HelloWorld',
meta: {title:'Home'},
component: HelloWorld component: HelloWorld
}, },
{ {
path: '/login', path: '/login',
name: 'Login', name: 'Login',
meta: {title:'Login'},
component: Login component: Login
}, },
{ {
path: '/notes', path: '/notes',
name: 'Notes', name: 'Notes',
meta: {title:'Notes'},
component: Notes component: Notes
}, },
{ {
path: '/help', path: '/help',
name: 'Help', name: 'Help',
meta: {title:'Help'},
component: HelpPage component: HelpPage
}, },
] ]

View File

@ -16,8 +16,6 @@ export default new Vuex.Store({
state.count++ state.count++
}, },
setLoginToken(state, userData){ setLoginToken(state, userData){
console.log(userData)
const username = userData.username const username = userData.username
const token = userData.token const token = userData.token

View File

@ -38,7 +38,10 @@ Attachment.scanTextForWebsites = (userId, noteId, noteText) => {
//Find all URLs in text //Find all URLs in text
const urlPattern = /(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[A-Z0-9+&@#/%=~_|$])/igm const urlPattern = /(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#/%=~_|$?!:,.]*\)|[A-Z0-9+&@#/%=~_|$])/igm
let foundUrls = noteText.match(urlPattern) let allUrls = noteText.match(urlPattern)
//Remove all duplicates
let foundUrls = [...new Set(allUrls)]
//Go through each attachment, check for existing URLs //Go through each attachment, check for existing URLs
attachments.forEach(attachment => { attachments.forEach(attachment => {
@ -54,7 +57,7 @@ Attachment.scanTextForWebsites = (userId, noteId, noteText) => {
}) })
//No newly scraped URLs, resolve with looked up attachment text //No newly scraped URLs, resolve with looked up attachment text
if(foundUrls.length == 0){ if(foundUrls == null || foundUrls.length == 0){
resolve(solrAttachmentText) resolve(solrAttachmentText)
} }
@ -166,12 +169,14 @@ Attachment.processUrl = (userId, noteId, url) => {
let finalWords = [] let finalWords = []
for(let i=0; i<15; i++){ for(let i=0; i<15; i++){
if(sortable[i][0]){ if(sortable[i] && sortable[i][0]){
finalWords.push(sortable[i][0]) finalWords.push(sortable[i][0])
} }
} }
desiredSearchText += finalWords.join(', ') desiredSearchText += finalWords.join(', ')
console.log('TexT Scraped')
console.log(desiredSearchText)
const created = Math.round((+new Date)/1000) const created = Math.round((+new Date)/1000)

View File

@ -75,7 +75,20 @@ Notes.update = (userId, noteId, noteText, fancyInput, color) => {
Notes.delete = (userId, noteId) => { Notes.delete = (userId, noteId) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
//Create new note, return created or finger your butt // DELETE FROM notes WHERE notes.id = 290 AND notes.user = 61;
// DELETE FROM attachment WHERE attachment.note_id = 290 AND attachment.user_id = 61;
// DELETE FROM notes_tags WHERE notes_tags.note_id = 290 AND notes_tags.user_id = 61;
db.promise().query('DELETE FROM notes WHERE notes.id = ? AND notes.user = ?', [noteId,userId])
.then((rows, fields) => {
db.promise().query('DELETE FROM attachment WHERE attachment.note_id = ? AND attachment.user_id = ?', [noteId,userId])
.then((rows, fields)=> {
db.promise().query('DELETE FROM notes_tags WHERE notes_tags.note_id = ? AND notes_tags.user_id = ?', [noteId,userId])
.then((rows, fields)=> {
console.log('All Deleted')
resolve(true)
})
})
})
}) })
} }
@ -153,9 +166,10 @@ Notes.search = (userId, searchQuery, searchTags) => {
//Default note lookup gets all notes //Default note lookup gets all notes
let noteSearchQuery = ` let noteSearchQuery = `
SELECT notes.id, SUBSTRING(text, 1, 200) as text, updated, color SELECT notes.id, SUBSTRING(notes.text, 1, 400) as text, updated, color, count(distinct notes_tags.id) as tag_count, count(distinct attachment.id) as attachment_count
FROM notes FROM notes
LEFT JOIN notes_tags ON (notes.id = notes_tags.note_id) LEFT JOIN notes_tags ON (notes.id = notes_tags.note_id)
LEFT JOIN attachment ON (notes.id = attachment.note_id AND attachment.attachment_type = 1)
WHERE user = ?` WHERE user = ?`
let searchParams = [userId] let searchParams = [userId]
@ -193,16 +207,30 @@ Notes.search = (userId, searchQuery, searchTags) => {
noteIds.push(note.id) noteIds.push(note.id)
//Attempt to pull string out of first tag in note //Attempt to pull string out of first tag in note
let reg = note.text.match(/<([\w]+)[^>]*>(.*?)<\/\1>/) let reg = note.text.match(/<([\w]+)[^>]*>(.*?)<\/\1>/g)
if(reg != null){
note.text = reg[2] //Pull out first html tag contents, that is the title
if(reg != null && reg[0]){
note.title = reg[0] //First line from HTML
} else {
note.title = note.text //Entire note
} }
//Return all notes with HTML tags pulled out //Clean up html title
note.text = note.text note.title = note.title
.replace(/&[#A-Za-z0-9]+;/g,'') //Rip out all HTML entities .replace(/&[#A-Za-z0-9]+;/g,'') //Rip out all HTML entities
.replace(/<[^>]+>/g, '') //Rip out all HTML tags .replace(/<[^>]+>/g, '') //Rip out all HTML tags
//Generate Subtext
if(note.text != '' && note.title != ''){
note.subtext = note.text
.replace(/&[#A-Za-z0-9]+;/g,' ') //Rip out all HTML entities
.replace(/<[^>]+>/g, ' ') //Rip out all HTML tags
.replace(/\s+/g, ' ') //Remove all whitespace
.substring(note.title.length + 2)
}
note.note_highlights = [] note.note_highlights = []
note.attachment_highlights = [] note.attachment_highlights = []
note.tag_highlights = [] note.tag_highlights = []

View File

@ -24,6 +24,11 @@ router.post('/get', function (req, res) {
.then( data => res.send(data) ) .then( data => res.send(data) )
}) })
router.post('/delete', function (req, res) {
Notes.delete(userId, req.body.noteId)
.then( data => res.send(data) )
})
router.post('/create', function (req, res) { router.post('/create', function (req, res) {
Notes.create(userId, req.body.title) Notes.create(userId, req.body.title)
.then( id => res.send({id}) ) .then( id => res.send({id}) )