I swear, I'm going to start doing regular commits

+ Added a ton of shit
+ About to add socket.io oh god.
This commit is contained in:
Max G
2020-01-03 01:26:55 +00:00
parent 6fe39406b7
commit abb4e20ec3
24 changed files with 3171 additions and 360 deletions

View File

@@ -62,6 +62,12 @@
100%{background-position:0% 50%}
}
/*safari fix - prevents page from being below the menu */
.dont-pad-me {
margin-right: 0 !important;
margin-left: 0 !important;
}
</style>
<template>

View File

@@ -4,15 +4,14 @@
<div class="ui grid" :class="{ 'mush-it-up':showOneColumn() }" ref="content">
<!-- Note filter options -->
<div class="row">
<div class="row" v-if="!$store.getters.getIsUserOnMobile">
<div
:class="{ 'sixteen wide column':showOneColumn(), 'eight wide column':!showOneColumn() }"
>
<div :class="{ 'sixteen wide column':showOneColumn(), 'eight wide column':!showOneColumn() }">
<div class="ui form">
<div class="fields">
<div class="ten wide field">
<input v-model="searchTerm" @keyup="searchKeyUp" @:keyup.enter="search" placeholder="Search Notes" />
<search-input></search-input>
<!-- <input v-model="searchTerm" @keyup="searchKeyUp" @:keyup.enter="search" placeholder="Search Notes" /> -->
</div>
<div class="six wide field">
<span class="ui fluid green button"
@@ -20,16 +19,19 @@
@click="reset">
<i class="undo icon"></i>Reset Filters
</span>
<!-- <fast-filters /> -->
</div>
</div>
</div>
</div>
<div
:class="{ 'sixteen wide column':showOneColumn(), 'eight wide column':!showOneColumn() }"
>
<h2 class="ui right floated">
<fast-filters />
</h2>
</div>
<div v-if="$store.getters.getIsUserOnMobile && showClear" class="row">
<div class="sixteen wide column">
<span class="ui fluid green button"
@click="reset">
<i class="undo icon"></i>Reset Filters
</span>
</div>
</div>
@@ -64,7 +66,8 @@
<!-- pinned notes -->
<div v-if="containsPinnednotes > 0" class="note-card-section">
<h4><i class="green pin icon"></i>Pinned <span v-if="!working">({{containsPinnednotes}})</span></h4>
<!-- ({{containsPinnednotes}}) -->
<h4><i class="green pin icon"></i>Pinned <span v-if="!working"></span></h4>
<div class="note-card-display-area">
<note-title-display-card
v-for="note in notes"
@@ -79,7 +82,8 @@
<!-- normal notes -->
<div v-if="containsNormalNotes > 0" class="note-card-section">
<h4>Notes <span v-if="!working">({{containsNormalNotes}})</span></h4>
<!-- ({{containsNormalNotes}}) -->
<h4><i class="green file icon"></i>Notes <span v-if="!working"></span></h4>
<div class="note-card-display-area">
<note-title-display-card
v-for="note in notes"
@@ -114,12 +118,8 @@
</div>
<input-notes v-if="activeNoteId1 != null" :noteid="activeNoteId1" :position="activeNote1Position" />
<input-notes v-if="activeNoteId2 != null" :noteid="activeNoteId2" :position="activeNote2Position" />
<div v-if="openAttachmentEdit">
<edit-attachment :note-id="editAttchmentId" :key="editAttchmentId" />
</div>
<input-notes v-if="activeNoteId1 != null" :noteid="activeNoteId1" :position="activeNote1Position" ref="note1" />
<input-notes v-if="activeNoteId2 != null" :noteid="activeNoteId2" :position="activeNote2Position" ref="note2" />
</div>
</template>
@@ -134,7 +134,7 @@
'input-notes': require('@/components/NoteInputPanel.vue').default,
'note-title-display-card': require('@/components/NoteTitleDisplayCard.vue').default,
'fast-filters': require('@/components/FastFilters.vue').default,
'edit-attachment': require('@/components/AttachmentEditor.vue').default,
'search-input': require('@/components/SearchInput.vue').default,
},
data () {
return {
@@ -153,6 +153,7 @@
batchOffset: 0, //Tracks the current batch that has been loaded
loadingBatchTimeout: null, //Limit how quickly batches can be loaded
loadingInProgress: false,
fetchTags: false,
//Clear button is not visible
showClear: false,
@@ -162,8 +163,8 @@
containsNormalNotes: 0,
containsPinnednotes: 0,
containsTextResults: 0,
containsTagResults: 0,
containsAttachmentResults: 0,
// containsTagResults: 0,
// containsAttachmentResults: 0,
//Currently open notes in app
activeNoteId1: null,
@@ -173,47 +174,14 @@
activeNote1Position: 0,
activeNote2Position: 0,
//Attchment to edit. Only 1 for now
openAttachmentEdit: false,
editAttchmentId: null,
lastVisibilityState: null,
}
},
beforeMount(){
this.$parent.loginGateway()
this.$bus.$on('open_edit_attachment', noteId => {
this.openAttachmentEdit = true
this.editAttchmentId = noteId
})
this.$bus.$on('close_edit_attachment', noteId => {
this.openAttachmentEdit = false
this.editAttchmentId = null
})
this.$bus.$on('close_active_note', position => {
this.closeNote(position)
})
this.$bus.$on('note_deleted', () => {
this.search()
})
this.$bus.$on('update_fast_filters', newFilter => {
this.fastFilters = newFilter
this.search(true, this.batchSize, false)
})
//New note button pushes open note event
this.$bus.$on('open_note', noteId => {
this.openNote(noteId)
})
//Mount notes on load if note ID is set
if(this.$route.params && this.$route.params.id){
const id = this.$route.params.id
this.openNote(id)
}
window.addEventListener('scroll', this.onScroll)
//Load tinymce into the page only do it once
if(document.querySelectorAll('[data-mceload]').length == 0){
let tinyMceIncluder = document.createElement('script')
@@ -222,21 +190,75 @@
document.head.appendChild(tinyMceIncluder)
}
},
beforeDestroy(){
window.removeEventListener('scroll', this.onScroll)
},
mounted() {
//Load a super fast batch
this.search(true, this.firstLoadBatchSize, 0)
.then( () => {
//Load a larger batch once first batch has loaded
this.search(false, this.batchSize, true).then( () => {
this.$bus.$on('close_active_note', ({position, noteId}) => {
this.closeNote(position)
this.updateSingleNote(noteId)
})
this.$bus.$on('note_deleted', (noteId) => {
//Remove deleted note from set, its deleted
this.notes.forEach( (note, index) => {
if(note.id == noteId){
if(note.pinned == 1){
this.containsPinnednotes--
} else {
this.containsNormalNotes--
}
this.notes.splice(index, 1)
}
})
})
this.$bus.$on('update_fast_filters', newFilter => {
this.fastFilters = newFilter
//Fast filters always return all the results and tags
this.search(true, this.batchSize, false).then( () => {
return this.fetchUserTags()
})
})
//Event to update search from other areas
this.$bus.$on('update_search_term', sentInSearchTerm => {
this.searchTerm = sentInSearchTerm
this.search(true, this.batchSize)
.then( () => {
return this.fetchUserTags()
})
})
//New note button pushes open note event
this.$bus.$on('open_note', noteId => {
this.openNote(noteId)
})
//Reload page content
this.$bus.$on('note_reload', () => {
this.reset()
})
//Mount notes on load if note ID is set
if(this.$route.params && this.$route.params.id){
const id = this.$route.params.id
this.openNote(id)
}
window.addEventListener('scroll', this.onScroll)
//Close notes when back button is pressed
window.addEventListener('hashchange', this.hashChangeAction)
document.addEventListener('visibilitychange', this.visibiltyChangeAction);
},
beforeDestroy(){
console.log('Unbinging all events')
window.removeEventListener('scroll', this.onScroll)
window.removeEventListener('hashchange', this.hashChangeAction)
document.removeEventListener('visibilitychange', this.visibiltyChangeAction)
this.$off() // Remove all event listeners
this.$bus.$off()
},
mounted() {
//Loads initial batch and tags
this.reset()
},
methods: {
showOneColumn(){
@@ -244,7 +266,13 @@
return (this.activeNoteId1 != null || this.activeNoteId2 != null) &&
!this.$store.getters.getIsUserOnMobile
},
openNote(id){
openNote(id, event = null){
//Don't open note if a link is clicked in display card
if(event && event.target && event.target.nodeName){
const nodeClick = event.target.nodeName
if(nodeClick == 'A'){ return }
}
//Do not open same note twice
if(this.activeNoteId1 == id || this.activeNoteId2 == id){
@@ -287,12 +315,17 @@
this.activeNoteId2 = null
}
this.$router.push('/notes')
//IF two notes get opened, update ID of open note
if(this.activeNoteId1 || this.activeNoteId2){
this.$router.push('/notes/open/'+Math.max(this.activeNoteId1,this.activeNoteId2))
} else {
//No notes are open, just show notes page
this.$router.push('/notes')
}
this.activeNote1Position = 0
this.activeNote2Position = 0
this.search(false)
},
toggleTagFilter(tagId){
@@ -302,7 +335,15 @@
this.searchTags.push(tagId)
}
this.search()
//Reset note set and load up notes and tags
if(this.searchTags.length > 0){
this.search(true, this.batchSize)
return
}
//If no tags are selected, reset entire page
this.reset()
},
onScroll(e){
@@ -325,7 +366,7 @@
//If greater than 80 of the way down the page, load the next batch
if(percentageDown >= 80){
console.log('loading batch')
console.log('loading next batch')
this.search(false, this.batchSize, true)
}
@@ -334,14 +375,120 @@
return
},
//Try to close notes on URL hash change /notes/open/123 to /notes - parse 123, close note id 123
hashChangeAction(event){
//Clean up path of hash change
let path = window.location.protocol + '//' + window.location.hostname + window.location.pathname + window.location.hash
let newPath = event.newURL.replace(path,'')
let oldPath = event.oldURL.replace(path,'')
//If we go from open note ID to no note ID, close the note
if(newPath == '' && oldPath.indexOf('/open/') != -1){
//Pull note ID out of URL
const noteIdToClose = oldPath.split('/').pop()
if(this.$refs.note1 && this.$refs.note1.currentNoteId == noteIdToClose){
this.$refs.note1.close()
}
if(this.$refs.note2 && this.$refs.note2.currentNoteId == noteIdToClose){
this.$refs.note2.close()
}
}
},
visibiltyChangeAction(event){
//@TODO - set a timeout on this like 2 minutes or just dont do shit and update it via socket.io
//If user leaves page then returns to page, reload the first batch
if(this.lastVisibilityState == 'hidden' && document.visibilityState == 'visible'){
// console.log('Welcome back. Reloading a batch')
//Load initial batch, then tags, then other batch
this.search(false, this.firstLoadBatchSize)
.then( () => {
return this.fetchUserTags()
})
}
this.lastVisibilityState = document.visibilityState
},
// @TODO Don't even trigger this if the note wasn't changed
updateSingleNote(noteId){
//Lookup one note using passed in ID
const postData = {
searchQuery: this.searchTerm,
searchTags: this.searchTags,
fastFilters:{
noteIdSet:[noteId]
}
}
axios.post('/api/note/search', postData)
.then(results => {
//Pull note data out of note set
let newNote = results.data.notes[0]
let foundNote = false
if(newNote === undefined){
console.log('Note not visible on this page')
return
}
//Go through each note and find the one just updated
this.notes.forEach( (note,index) => {
if(note.id == noteId){
foundNote = true
//Don't move notes that were not changed
if(note.updated == newNote.updated){
return
}
//Compare note tags, if they changed, reload tags
if(newNote.tag_count != note.tag_count){
console.log('Tags changed, update those bitches')
this.fetchUserTags()
}
//go through each prop and update it with new values
Object.keys(newNote).forEach(prop => {
note[prop] = newNote[prop]
})
this.notes.splice(index, 1)
this.notes.unshift(note)
}
})
//This note was not found, update it in list
if(foundNote == false){
if(newNote.pinned == 1){
this.containsPinnednotes++
} else {
this.containsNormalNotes++
}
this.notes.unshift(newNote)
}
})
},
search(showLoading = true, notesInNextLoad = null, mergeExisting = false){
return new Promise((resolve, reject) => {
//Don't double load note batches
if(this.loadingInProgress){
return resolve()
}
//Remove all filter limits
//Reset a lot of stuff if we are not merging batches
if(!mergeExisting){
this.batchOffset = 0 // Reset batch offset if we are not merging note batches
// this.commonTags = [] //Don't reset tags, if search returns tags, they will be set
}
//Remove all filter limits from previous queries
delete this.fastFilters.limitSize
delete this.fastFilters.limitOffset
@@ -375,39 +522,49 @@
axios.post('/api/note/search', postData).
then(response => {
if(!mergeExisting){
this.containsNormalNotes = 0
this.containsPinnednotes = 0
this.containsTextResults = 0
this.batchOffset = 0 // Reset batch offset if we are not merging note batches
this.commonTags = []
this.notes = []
}
//Save the number of notes just loaded
this.batchOffset += response.data.notes.length
//Mush the two new sets of data together
this.commonTags = this.commonTags.concat(response.data.tags)
this.notes = this.notes.concat(response.data.notes)
//Mush the two new sets of data together (set will be empty is reset is on)
if(response.data.tags.length > 0){
this.commonTags = response.data.tags
}
//Either reload all notes with return data or merge return data
if(!mergeExisting){
this.notes = response.data.notes
} else {
this.notes = this.notes.concat(response.data.notes)
}
//Go through each note and see which section to display
let textResultsCount = 0
let pinnedResultsCount = 0
let normalNotesCount = 0
response.data.notes.forEach(note => {
if(note.note_highlights.length > 0){
this.containsTextResults++
textResultsCount++
return
}
if(note.pinned == 1){
this.containsPinnednotes++
pinnedResultsCount++
return
}
this.containsNormalNotes++
normalNotesCount++
})
if(!mergeExisting){
this.containsNormalNotes = normalNotesCount
this.containsPinnednotes = pinnedResultsCount
this.containsTextResults = textResultsCount
} else {
this.containsNormalNotes += normalNotesCount
this.containsPinnednotes += pinnedResultsCount
this.containsTextResults += textResultsCount
}
this.working = false
this.loadingInProgress = false
@@ -420,7 +577,10 @@
let vm = this
clearTimeout(vm.searchDebounce)
vm.searchDebounce = setTimeout(() => {
vm.search()
this.search(true, this.batchSize)
.then( () => {
return this.fetchUserTags()
})
}, 500)
},
ucWords(str){
@@ -435,7 +595,28 @@
this.searchTags = []
this.fastFilters = {}
this.$bus.$emit('reset_fast_filters')
this.search(true, this.firstLoadBatchSize, 0)
//Load initial batch, then tags, then other batch
this.search(true, this.firstLoadBatchSize)
.then( () => {
return this.fetchUserTags()
})
.then( () => {
//Load a larger batch once first batch has loaded
return this.search(false, this.batchSize, true)
})
.then( i => {
//Thats how you promise chain
})
},
fetchUserTags(){
return new Promise((resolve, reject) => {
axios.post('/api/tag/usertags')
.then( ({data}) => {
this.commonTags = data
resolve(data)
})
})
}
}
}