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:
@@ -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>
|
||||
|
@@ -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)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user