I need to get back into using git. The hell is wrong with me!?
This commit is contained in:
@@ -1,120 +1,132 @@
|
||||
<template>
|
||||
<div class="ui basic segment">
|
||||
<div class="ui basic segment no-fluf-segment">
|
||||
|
||||
<div class="ui equal width grid">
|
||||
<div class="ui grid" :class="{ 'mush-it-up':showOneColumn() }" ref="content">
|
||||
|
||||
<!-- <div class="ui row">{{ $store.getters.getIsUserOnMobile ? 'Mobile Device':'Normal Browser' }}</div> -->
|
||||
|
||||
<!-- mobile search menu -->
|
||||
<div class="ui mobile only row">
|
||||
<!-- Small screen new note button -->
|
||||
<div class="ui four wide column">
|
||||
<div @click="createNote" class="ui fluid green icon button">
|
||||
<i class="plus icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui twelve wide column">
|
||||
<div class="ui form">
|
||||
<input v-model="searchTerm" @keyup="searchKeyUp" @:keyup.enter="search" placeholder="Search Notes" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- search menu -->
|
||||
<div class="ui large screen only row">
|
||||
|
||||
<div class="ui two wide column">
|
||||
<div @click="createNote" class="ui fluid green button">
|
||||
<i class="plus icon"></i>
|
||||
New Note
|
||||
</div>
|
||||
</div>
|
||||
<!-- Note filter options -->
|
||||
<div class="row">
|
||||
|
||||
<div class="ui five wide column">
|
||||
<div
|
||||
:class="{ 'sixteen wide column':showOneColumn(), 'eight wide column':!showOneColumn() }"
|
||||
>
|
||||
<div class="ui form">
|
||||
<input v-model="searchTerm" @keyup="searchKeyUp" @:keyup.enter="search" placeholder="Search Notes" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui nine wide column">
|
||||
|
||||
<router-link class="ui basic button" to="/help">Help</router-link>
|
||||
|
||||
<div v-on:click="toggleNightMode" class="ui basic icon button">
|
||||
<i class="eye icon"></i> Dark Theme:
|
||||
<span v-if="$store.getters.getIsNightMode">On</span>
|
||||
<span v-else>Off</span>
|
||||
</div>
|
||||
|
||||
<div v-on:click="toggleArchivedVisible" class="ui basic icon button">
|
||||
<i class="archive icon"></i> Archived:
|
||||
<span v-if="showArchived == 1">Visible</span>
|
||||
<span v-else>Hidden</span>
|
||||
</div>
|
||||
|
||||
<div class="ui right floated basic button"
|
||||
data-tooltip="Log Out" data-position="left center"
|
||||
v-on:click="destroyLoginToken"><i class="user icon"></i> {{username}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui row">
|
||||
|
||||
<!-- tags display -->
|
||||
<div class="ui two wide large screen only column" v-if="activeNoteId1 == null && activeNoteId2 == null">
|
||||
<div class="ui small basic fluid button" @click="reset">
|
||||
<i class="undo icon"></i>Reset Filters
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
<div class="ui section list">
|
||||
<div class="item" v-for="tag in commonTags" @click="toggleTagFilter(tag.id)">
|
||||
<div class="ui clickable basic fluid large label" :class="{ 'green':(searchTags.includes(tag.id)) }">
|
||||
{{ucWords(tag.text)}} <div class="detail">{{tag.usages}}</div>
|
||||
<div class="fields">
|
||||
<div class="ten wide field">
|
||||
<input v-model="searchTerm" @keyup="searchKeyUp" @:keyup.enter="search" placeholder="Search Notes" />
|
||||
</div>
|
||||
<div class="six wide field">
|
||||
<span class="ui fluid green button"
|
||||
v-if="showClear"
|
||||
@click="reset">
|
||||
<i class="undo icon"></i>Reset Filters
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Note title cards -->
|
||||
<div class="ui fourteen wide computer sixteen wide mobile column">
|
||||
<h2>
|
||||
({{notes.length}}) <fast-filters />
|
||||
<div
|
||||
:class="{ 'sixteen wide column':showOneColumn(), 'eight wide column':!showOneColumn() }"
|
||||
>
|
||||
<h2 class="ui right floated">
|
||||
<fast-filters />
|
||||
</h2>
|
||||
|
||||
<h3 v-if="searchTerm.length > 0 && notes.length == 0">No notes found. Check your spelling, try completing the word or using a different phrase.</h3>
|
||||
|
||||
<h3 v-if="searchTerm.length == 0 && notes.length == 0">Create your first note. Click the "New Note" button.</h3>
|
||||
|
||||
<div v-if="working"><div class="ui active inline loader"></div> Working...</div>
|
||||
|
||||
<div v-if="notes !== null && !working"
|
||||
class="note-card-display-area"
|
||||
:class="{'one-column':(activeNoteId1 != null || activeNoteId2 != null )}
|
||||
">
|
||||
<note-title-display-card
|
||||
v-for="note in notes"
|
||||
:onClick="openNote"
|
||||
:data="note"
|
||||
:currently-open="(activeNoteId1 == note.id || activeNoteId2 == note.id)"
|
||||
:key="note.id + note.color + note.note_highlights.length + note.attachment_highlights.length + ' -' + note.tag_highlights.length + '-' +note.title.length + '-' +note.subtext.length"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="commonTags.length > 0" class="sixteen wide column">
|
||||
<span v-for="tag in commonTags" @click="toggleTagFilter(tag.id)">
|
||||
<span class="ui clickable basic label" :class="{ 'green':(searchTags.includes(tag.id)) }">
|
||||
{{ucWords(tag.text)}} <span class="detail">{{tag.usages}}</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h2 v-if="fastFilters['withLinks'] == 1">Only showing notes containing Links</h2>
|
||||
<h2 v-if="fastFilters['withTags'] == 1">Only showing notse with Tags</h2>
|
||||
<h2 v-if="fastFilters['onlyArchived'] == 1">Only showing Archived notes.</h2>
|
||||
|
||||
<!-- Note title card display -->
|
||||
<div class="sixteen wide column">
|
||||
<h3 v-if="searchTerm.length > 0 && notes.length == 0">No notes found. Check your spelling, try completing the word or using a different phrase.</h3>
|
||||
|
||||
<h3 v-if="searchTerm.length == 0 && notes.length == 0">Create your first note. Click the "New Note" button.</h3>
|
||||
|
||||
<div v-if="working">
|
||||
<div class="ui active inline loader"></div> Working...
|
||||
</div>
|
||||
|
||||
<!-- Go to one wide column, do not do this on mobile interface -->
|
||||
<div v-if="notes !== null && notes.length > 0"
|
||||
:class="{'one-column':(
|
||||
(activeNoteId1 != null || activeNoteId2 != null) &&
|
||||
!$store.getters.getIsUserOnMobile
|
||||
)}">
|
||||
|
||||
<!-- 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>
|
||||
<div class="note-card-display-area">
|
||||
<note-title-display-card
|
||||
v-for="note in notes"
|
||||
v-if="note.pinned"
|
||||
:onClick="openNote"
|
||||
:data="note"
|
||||
:currently-open="(activeNoteId1 == note.id || activeNoteId2 == note.id)"
|
||||
:key="note.id + note.color + note.note_highlights.length + note.attachment_highlights.length + ' -' + note.tag_highlights.length + '-' +note.title.length + '-' +note.subtext.length"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- normal notes -->
|
||||
<div v-if="containsNormalNotes > 0" class="note-card-section">
|
||||
<h4>Notes <span v-if="!working">({{containsNormalNotes}})</span></h4>
|
||||
<div class="note-card-display-area">
|
||||
<note-title-display-card
|
||||
v-for="note in notes"
|
||||
v-if="note.note_highlights && !note.pinned"
|
||||
:onClick="openNote"
|
||||
:data="note"
|
||||
:currently-open="(activeNoteId1 == note.id || activeNoteId2 == note.id)"
|
||||
:key="note.id + note.color + note.note_highlights.length + note.attachment_highlights.length + ' -' + note.tag_highlights.length + '-' +note.title.length + '-' +note.subtext.length"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- found in text -->
|
||||
<div v-if="containsTextResults" class="note-card-section">
|
||||
<h4><i class="green paragraph icon"></i> Found in Text ({{containsTextResults}})</h4>
|
||||
<div class="note-card-display-area">
|
||||
<note-title-display-card
|
||||
v-for="note in notes"
|
||||
v-if="note.note_highlights && note.note_highlights.length"
|
||||
:textResults="true"
|
||||
:onClick="openNote"
|
||||
:data="note"
|
||||
:currently-open="(activeNoteId1 == note.id || activeNoteId2 == note.id)"
|
||||
:key="note.id + note.color + note.note_highlights.length + note.attachment_highlights.length + ' -' + note.tag_highlights.length + '-' +note.title.length + '-' +note.subtext.length"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</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>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import axios from 'axios';
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'SearchBar',
|
||||
@@ -122,32 +134,62 @@
|
||||
'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,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
username:'',
|
||||
initComponent: true,
|
||||
commonTags: [],
|
||||
searchTerm: '',
|
||||
searchTags: [],
|
||||
notes: [],
|
||||
highlights: [],
|
||||
searchDebounce: null,
|
||||
fastFilters: {},
|
||||
showArchived: 0,
|
||||
working: false,
|
||||
//Load up notes in batches
|
||||
firstLoadBatchSize: 30, //First set of rapidly loaded notes
|
||||
batchSize: 100, //Size of batch loaded when user scrolls through current batch
|
||||
batchOffset: 0, //Tracks the current batch that has been loaded
|
||||
loadingBatchTimeout: null, //Limit how quickly batches can be loaded
|
||||
loadingInProgress: false,
|
||||
|
||||
//Clear button is not visible
|
||||
showClear: false,
|
||||
initialPostData: null,
|
||||
currentPostData: null,
|
||||
|
||||
containsNormalNotes: 0,
|
||||
containsPinnednotes: 0,
|
||||
containsTextResults: 0,
|
||||
containsTagResults: 0,
|
||||
containsAttachmentResults: 0,
|
||||
|
||||
//Currently open notes in app
|
||||
activeNoteId1: null,
|
||||
activeNoteId2: null,
|
||||
|
||||
//Position determines how note is Positioned
|
||||
activeNote1Position: 0,
|
||||
activeNote2Position: 0,
|
||||
|
||||
//Attchment to edit. Only 1 for now
|
||||
openAttachmentEdit: false,
|
||||
editAttchmentId: null,
|
||||
}
|
||||
},
|
||||
beforeMount(){
|
||||
|
||||
let username = this.$store.getters.getUsername
|
||||
this.username = this.ucWords(username)
|
||||
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)
|
||||
@@ -157,24 +199,51 @@
|
||||
})
|
||||
this.$bus.$on('update_fast_filters', newFilter => {
|
||||
this.fastFilters = newFilter
|
||||
this.search()
|
||||
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
|
||||
console.log('About to load note ', 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')
|
||||
tinyMceIncluder.setAttribute('src', '/api/static/assets/tinymce/tinymce.min.js')
|
||||
tinyMceIncluder.setAttribute('data-mceload','loaded')
|
||||
document.head.appendChild(tinyMceIncluder)
|
||||
}
|
||||
|
||||
},
|
||||
beforeDestroy(){
|
||||
window.removeEventListener('scroll', this.onScroll)
|
||||
},
|
||||
mounted() {
|
||||
|
||||
this.search()
|
||||
//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( () => {
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
},
|
||||
methods: {
|
||||
showOneColumn(){
|
||||
//If note 1 or 2 is open, show one column. Or if the user is on mobile
|
||||
return (this.activeNoteId1 != null || this.activeNoteId2 != null) &&
|
||||
!this.$store.getters.getIsUserOnMobile
|
||||
},
|
||||
openNote(id){
|
||||
|
||||
//Do not open same note twice
|
||||
@@ -196,7 +265,6 @@
|
||||
this.activeNote2Position = 2 //Left side of page
|
||||
return
|
||||
}
|
||||
|
||||
//2 notes open
|
||||
if(this.activeNoteId2 != null && this.activeNoteId1 == null){
|
||||
this.activeNoteId1 = id
|
||||
@@ -236,33 +304,116 @@
|
||||
|
||||
this.search()
|
||||
},
|
||||
search(showLoading = true){
|
||||
onScroll(e){
|
||||
|
||||
//Add archived to fast filters
|
||||
this.fastFilters['archived'] = 0
|
||||
if(this.showArchived == 1){
|
||||
this.fastFilters['archived'] = 1
|
||||
}
|
||||
clearTimeout(this.loadingBatchTimeout)
|
||||
this.loadingBatchTimeout = setTimeout(() => {
|
||||
|
||||
let postData = {
|
||||
searchQuery: this.searchTerm,
|
||||
searchTags: this.searchTags,
|
||||
fastFilters: this.fastFilters,
|
||||
}
|
||||
//Distance to bottom of page
|
||||
const bottomOfWindow =
|
||||
Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop)
|
||||
+ window.innerHeight
|
||||
|
||||
//height of page
|
||||
const offsetHeight = this.$refs.content.clientHeight
|
||||
|
||||
//Determine percentage down the page
|
||||
const percentageDown = Math.round( (bottomOfWindow/offsetHeight)*100 )
|
||||
|
||||
// console.log( percentageDown + '%' )
|
||||
|
||||
//If greater than 80 of the way down the page, load the next batch
|
||||
if(percentageDown >= 80){
|
||||
|
||||
console.log('loading batch')
|
||||
this.search(false, this.batchSize, true)
|
||||
}
|
||||
|
||||
}, 50)
|
||||
|
||||
if(showLoading){
|
||||
this.working = true
|
||||
}
|
||||
|
||||
return
|
||||
},
|
||||
search(showLoading = true, notesInNextLoad = null, mergeExisting = false){
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
//Perform search
|
||||
let vm = this
|
||||
axios.post('/api/note/search', postData).
|
||||
then(response => {
|
||||
vm.commonTags = response.data.tags
|
||||
vm.notes = response.data.notes
|
||||
vm.highlights = response.data.highlights
|
||||
this.working = false
|
||||
if(this.loadingInProgress){
|
||||
return resolve()
|
||||
}
|
||||
|
||||
//Remove all filter limits
|
||||
delete this.fastFilters.limitSize
|
||||
delete this.fastFilters.limitOffset
|
||||
|
||||
let postData = {
|
||||
searchQuery: this.searchTerm,
|
||||
searchTags: this.searchTags,
|
||||
fastFilters: this.fastFilters,
|
||||
}
|
||||
|
||||
if(showLoading){
|
||||
this.working = true
|
||||
}
|
||||
|
||||
//Save initial post data on first load
|
||||
if(this.initialPostData == null){
|
||||
this.initialPostData = JSON.stringify(postData)
|
||||
}
|
||||
//If post data is not the same as initial, show clear button
|
||||
if(JSON.stringify(postData) != this.initialPostData){
|
||||
this.showClear = true
|
||||
}
|
||||
|
||||
if(notesInNextLoad && notesInNextLoad > 0){
|
||||
//Create limit based off of the number of notes already loaded
|
||||
postData.fastFilters.limitSize = notesInNextLoad
|
||||
postData.fastFilters.limitOffset = this.batchOffset
|
||||
}
|
||||
|
||||
//Perform search - or die
|
||||
this.loadingInProgress = true
|
||||
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)
|
||||
|
||||
|
||||
//Go through each note and see which section to display
|
||||
response.data.notes.forEach(note => {
|
||||
|
||||
if(note.note_highlights.length > 0){
|
||||
this.containsTextResults++
|
||||
return
|
||||
}
|
||||
|
||||
if(note.pinned == 1){
|
||||
this.containsPinnednotes++
|
||||
return
|
||||
}
|
||||
|
||||
this.containsNormalNotes++
|
||||
})
|
||||
|
||||
this.working = false
|
||||
this.loadingInProgress = false
|
||||
|
||||
return resolve(true)
|
||||
})
|
||||
})
|
||||
},
|
||||
searchKeyUp(){
|
||||
@@ -270,19 +421,7 @@
|
||||
clearTimeout(vm.searchDebounce)
|
||||
vm.searchDebounce = setTimeout(() => {
|
||||
vm.search()
|
||||
}, 300)
|
||||
},
|
||||
createNote(event){
|
||||
const title = ''
|
||||
let vm = this
|
||||
|
||||
axios.post('/api/note/create', {title})
|
||||
.then(response => {
|
||||
|
||||
if(response.data && response.data.id){
|
||||
vm.openNote(response.data.id)
|
||||
}
|
||||
})
|
||||
}, 500)
|
||||
},
|
||||
ucWords(str){
|
||||
return (str + '')
|
||||
@@ -291,31 +430,20 @@
|
||||
})
|
||||
},
|
||||
reset(){
|
||||
this.showClear = false
|
||||
this.searchTerm = ''
|
||||
this.searchTags = []
|
||||
this.fastFilters = {}
|
||||
this.$bus.$emit('reset_fast_filters')
|
||||
this.search()
|
||||
},
|
||||
destroyLoginToken() {
|
||||
this.$store.commit('destroyLoginToken')
|
||||
this.$router.push('/')
|
||||
},
|
||||
toggleNightMode(){
|
||||
this.$store.commit('toggleNightMode')
|
||||
},
|
||||
toggleArchivedVisible(){
|
||||
if(this.showArchived == 0){
|
||||
this.showArchived = 1
|
||||
} else {
|
||||
this.showArchived = 0
|
||||
}
|
||||
this.search()
|
||||
this.search(true, this.firstLoadBatchSize, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style type="text/css" scoped>
|
||||
.mush-it-up {
|
||||
width: calc(50% - 130px);
|
||||
}
|
||||
.detail {
|
||||
float: right;
|
||||
}
|
||||
@@ -323,4 +451,14 @@
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.display-area-title {
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
}
|
||||
.note-card-section {
|
||||
/*padding-bottom: 15px;*/
|
||||
}
|
||||
.note-card-section + .note-card-section {
|
||||
padding: 15px 0 0;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user