2019-07-19 20:51:57 +00:00
|
|
|
<template>
|
2019-12-20 05:50:50 +00:00
|
|
|
<div class="ui basic segment no-fluf-segment">
|
2019-07-19 20:51:57 +00:00
|
|
|
|
2019-12-20 05:50:50 +00:00
|
|
|
<div class="ui grid" :class="{ 'mush-it-up':showOneColumn() }" ref="content">
|
2019-07-21 16:28:07 +00:00
|
|
|
|
2020-02-12 05:29:56 +00:00
|
|
|
<div class="sixteen wide column">
|
2020-02-11 21:11:14 +00:00
|
|
|
<!-- :class="{ 'sixteen wide column':showOneColumn(), 'sixteen wide column':!showOneColumn() }" -->
|
2019-12-20 05:50:50 +00:00
|
|
|
|
2020-04-10 03:47:15 +00:00
|
|
|
<div class="ui stackable grid">
|
2020-02-11 21:11:14 +00:00
|
|
|
|
2020-02-12 05:29:56 +00:00
|
|
|
<div class="ten wide column" :class="{ 'sixteen wide column':$store.getters.getIsUserOnMobile }">
|
2020-02-11 21:11:14 +00:00
|
|
|
|
2020-03-26 04:45:23 +00:00
|
|
|
<div class="ui basic button shrinking"
|
2020-02-14 01:08:46 +00:00
|
|
|
v-on:click="updateFastFilters(3)"
|
|
|
|
v-if="$store.getters.totals && ($store.getters.totals['sharedToNotes'] > 0 || $store.getters.totals['sharedFromNotes'] > 0)"
|
|
|
|
style="position: relative;">
|
|
|
|
<i class="green mail icon"></i>Shared Notes
|
2020-02-11 21:11:14 +00:00
|
|
|
<span class="floating ui green label" v-if="$store.getters.totals['unreadNotes'] > 0">
|
|
|
|
{{ $store.getters.totals['unreadNotes'] }}
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
|
2020-03-26 04:45:23 +00:00
|
|
|
<div class="ui basic button shrinking" v-on:click="updateFastFilters(2)" v-if="$store.getters.totals && $store.getters.totals['archivedNotes'] > 0">
|
2020-02-11 21:11:14 +00:00
|
|
|
<i class="green archive icon"></i>Archived
|
|
|
|
<!-- <span>{{ $store.getters.totals['archivedNotes'] }}</span> -->
|
|
|
|
</div>
|
2020-03-13 23:34:32 +00:00
|
|
|
|
2020-03-26 04:45:23 +00:00
|
|
|
<div class="ui basic button shrinking" v-on:click="updateFastFilters(4)" v-if="$store.getters.totals && $store.getters.totals['encryptedNotes'] > 0">
|
2020-03-13 23:34:32 +00:00
|
|
|
<i class="green lock alternate icon"></i>Locked
|
|
|
|
<!-- <span>{{ $store.getters.totals['encryptedNotes'] }}</span> -->
|
|
|
|
</div>
|
2020-02-14 05:31:38 +00:00
|
|
|
|
2020-02-11 21:11:14 +00:00
|
|
|
</div>
|
|
|
|
|
2020-04-10 03:47:15 +00:00
|
|
|
<div class="six wide column" v-if="!$store.getters.getIsUserOnMobile">
|
|
|
|
<search-input
|
|
|
|
v-if="$store.getters.totals && $store.getters.totals['totalNotes']" />
|
|
|
|
</div>
|
|
|
|
|
2020-02-11 21:11:14 +00:00
|
|
|
<div class="eight wide column" v-if="showClear">
|
2020-02-11 06:05:28 +00:00
|
|
|
<!-- <fast-filters /> -->
|
|
|
|
<span class="ui fluid green button"
|
2020-02-11 21:11:14 +00:00
|
|
|
|
2020-02-11 06:05:28 +00:00
|
|
|
@click="reset">
|
|
|
|
<i class="arrow circle left icon"></i>Back to All Notes
|
|
|
|
</span>
|
2019-07-24 18:06:50 +00:00
|
|
|
</div>
|
2020-02-11 21:11:14 +00:00
|
|
|
|
2019-07-21 16:28:07 +00:00
|
|
|
</div>
|
2020-02-11 06:05:28 +00:00
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
</div>
|
|
|
|
|
2020-04-10 03:47:15 +00:00
|
|
|
|
2020-02-26 05:35:43 +00:00
|
|
|
|
2020-02-14 01:08:46 +00:00
|
|
|
<h2 v-if="fastFilters['withLinks'] == 1">Notes with Links</h2>
|
|
|
|
<h2 v-if="fastFilters['withTags'] == 1">Notes with Tags</h2>
|
|
|
|
<h2 v-if="fastFilters['onlyArchived'] == 1">Archived Notes</h2>
|
|
|
|
<h2 v-if="fastFilters['onlyShowSharedNotes'] == 1">Shared Notes</h2>
|
2020-03-14 06:04:03 +00:00
|
|
|
<h2 v-if="fastFilters['onlyShowEncrypted'] == 1">Password Protected Notes</h2>
|
2020-02-14 01:08:46 +00:00
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
<!-- tags section -->
|
2019-12-20 05:50:50 +00:00
|
|
|
<div v-if="commonTags.length > 0" class="sixteen wide column">
|
2020-04-10 03:47:15 +00:00
|
|
|
<h4 class="ui tiny dividing header"><i class="green tags icon"></i>Tags</h4>
|
2019-12-20 05:50:50 +00:00
|
|
|
<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>
|
2019-07-24 18:06:50 +00:00
|
|
|
|
2019-12-20 05:50:50 +00:00
|
|
|
<!-- Note title card display -->
|
|
|
|
<div class="sixteen wide column">
|
2019-07-30 19:10:31 +00:00
|
|
|
|
2020-02-14 01:08:46 +00:00
|
|
|
<h3 v-if="$store.getters.totals && $store.getters.totals['totalNotes'] == 0">
|
2020-04-10 03:47:15 +00:00
|
|
|
No Notes Yet. <br>Thats ok.<br><br> <br>
|
|
|
|
<img loading="lazy" width="25%" src="/api/static/assets/marketing/hamburger.svg" alt="Create a new note"><br>
|
|
|
|
Create one when you feel ready.
|
2020-02-14 01:08:46 +00:00
|
|
|
</h3>
|
2019-09-10 18:10:11 +00:00
|
|
|
|
2019-12-20 05:50:50 +00:00
|
|
|
<!-- Go to one wide column, do not do this on mobile interface -->
|
2020-02-18 22:52:12 +00:00
|
|
|
<div :class="{'one-column':(
|
2019-12-20 05:50:50 +00:00
|
|
|
(activeNoteId1 != null || activeNoteId2 != null) &&
|
|
|
|
!$store.getters.getIsUserOnMobile
|
|
|
|
)}">
|
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
<!-- render each section based on notes in set -->
|
|
|
|
<div v-for="section,index in noteSections" v-if="section.length > 0" class="note-card-section">
|
2020-04-10 03:47:15 +00:00
|
|
|
<h5 class="ui tiny dividing header"><i :class="`green ${sectionData[index][0]} icon`"></i>{{ sectionData[index][1] }}</h5>
|
2019-07-21 16:28:07 +00:00
|
|
|
|
2019-12-20 05:50:50 +00:00
|
|
|
<div class="note-card-display-area">
|
|
|
|
<note-title-display-card
|
2020-02-18 22:52:12 +00:00
|
|
|
v-for="note in section"
|
2020-03-30 05:31:09 +00:00
|
|
|
:ref="'note-'+note.id"
|
2019-12-20 05:50:50 +00:00
|
|
|
:onClick="openNote"
|
|
|
|
:data="note"
|
|
|
|
:currently-open="(activeNoteId1 == note.id || activeNoteId2 == note.id)"
|
2020-02-18 22:52:12 +00:00
|
|
|
:key="note.id + note.color + note.note_highlights.length + note.attachment_highlights.length + ' -' + note.tag_highlights.length + '-' +note.title.length + '-' +note.subtext.length + '-' + note.tag_count + note.updated"
|
2019-12-20 05:50:50 +00:00
|
|
|
/>
|
|
|
|
</div>
|
2019-07-19 20:51:57 +00:00
|
|
|
</div>
|
2019-07-24 18:06:50 +00:00
|
|
|
|
2019-07-19 20:51:57 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2019-12-20 05:50:50 +00:00
|
|
|
|
2020-02-01 22:21:22 +00:00
|
|
|
|
|
|
|
<!-- found attachments -->
|
|
|
|
<div class="sixteen wide column" v-if="foundAttachments.length > 0">
|
2020-02-11 06:05:28 +00:00
|
|
|
<h4><i class="folder open outline icon"></i> Found in Files ({{ foundAttachments.length }})</h4>
|
2020-02-01 22:21:22 +00:00
|
|
|
<attachment-display
|
|
|
|
v-for="item in foundAttachments"
|
|
|
|
:item="item"
|
|
|
|
:key="item.id"
|
|
|
|
:search-params="{}"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
|
2019-07-19 20:51:57 +00:00
|
|
|
</div>
|
|
|
|
|
2019-07-20 23:07:22 +00:00
|
|
|
|
2020-04-10 03:47:15 +00:00
|
|
|
<input-notes
|
|
|
|
v-if="activeNoteId1 != null"
|
|
|
|
:noteid="activeNoteId1"
|
|
|
|
:position="activeNote1Position"
|
|
|
|
:url-data="$route.params"
|
|
|
|
ref="note1" />
|
|
|
|
<input-notes
|
|
|
|
v-if="activeNoteId2 != null"
|
|
|
|
:noteid="activeNoteId2"
|
|
|
|
:position="activeNote2Position"
|
|
|
|
ref="note2" />
|
2019-12-20 05:50:50 +00:00
|
|
|
|
2019-07-19 20:51:57 +00:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
2019-12-20 05:50:50 +00:00
|
|
|
import axios from 'axios'
|
2019-07-19 20:51:57 +00:00
|
|
|
|
|
|
|
export default {
|
|
|
|
name: 'SearchBar',
|
2019-07-20 23:07:22 +00:00
|
|
|
components: {
|
2019-07-30 19:10:31 +00:00
|
|
|
'input-notes': require('@/components/NoteInputPanel.vue').default,
|
|
|
|
'note-title-display-card': require('@/components/NoteTitleDisplayCard.vue').default,
|
2019-09-10 18:10:11 +00:00
|
|
|
'fast-filters': require('@/components/FastFilters.vue').default,
|
2020-01-03 01:26:55 +00:00
|
|
|
'search-input': require('@/components/SearchInput.vue').default,
|
2020-02-01 22:21:22 +00:00
|
|
|
'attachment-display': require('@/components/AttachmentDisplayCard').default,
|
2020-02-14 01:08:46 +00:00
|
|
|
'counter':require('@/components/AnimatedCounterComponent.vue').default
|
2019-07-20 23:07:22 +00:00
|
|
|
},
|
2019-07-19 20:51:57 +00:00
|
|
|
data () {
|
|
|
|
return {
|
|
|
|
initComponent: true,
|
|
|
|
commonTags: [],
|
|
|
|
searchTerm: '',
|
|
|
|
searchTags: [],
|
2019-07-20 23:07:22 +00:00
|
|
|
notes: [],
|
2019-12-20 05:50:50 +00:00
|
|
|
highlights: [],
|
2019-07-20 23:07:22 +00:00
|
|
|
searchDebounce: null,
|
2019-09-10 18:10:11 +00:00
|
|
|
fastFilters: {},
|
|
|
|
working: false,
|
2019-12-20 05:50:50 +00:00
|
|
|
//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,
|
2020-01-03 01:26:55 +00:00
|
|
|
fetchTags: false,
|
2019-12-20 05:50:50 +00:00
|
|
|
|
|
|
|
//Clear button is not visible
|
|
|
|
showClear: false,
|
|
|
|
initialPostData: null,
|
|
|
|
currentPostData: null,
|
|
|
|
|
|
|
|
containsNormalNotes: 0,
|
|
|
|
containsPinnednotes: 0,
|
|
|
|
containsTextResults: 0,
|
2020-01-03 01:26:55 +00:00
|
|
|
// containsTagResults: 0,
|
|
|
|
// containsAttachmentResults: 0,
|
2019-07-20 23:07:22 +00:00
|
|
|
|
|
|
|
//Currently open notes in app
|
|
|
|
activeNoteId1: null,
|
|
|
|
activeNoteId2: null,
|
2019-12-20 05:50:50 +00:00
|
|
|
|
2019-07-20 23:07:22 +00:00
|
|
|
//Position determines how note is Positioned
|
|
|
|
activeNote1Position: 0,
|
2019-07-24 18:06:50 +00:00
|
|
|
activeNote2Position: 0,
|
2019-12-20 05:50:50 +00:00
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
lastVisibilityState: null,
|
|
|
|
|
2020-02-14 01:08:46 +00:00
|
|
|
foundAttachments: [],
|
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
sectionData: {
|
|
|
|
'pinned': ['thumbtack', 'Pinned'],
|
|
|
|
'archived': ['archive', 'Archived'],
|
|
|
|
'shared': ['envelope outline', 'Received Notes'],
|
|
|
|
'sent': ['paper plane outline', 'Shared Notes'],
|
|
|
|
'notes': ['file','Notes'],
|
2020-03-14 06:04:03 +00:00
|
|
|
'highlights': ['paragraph', 'Found In Text'],
|
|
|
|
'locked': ['lock', 'Password Protected']
|
2020-02-18 22:52:12 +00:00
|
|
|
},
|
2020-02-14 01:08:46 +00:00
|
|
|
noteSections: {
|
2020-02-18 22:52:12 +00:00
|
|
|
pinned: [],
|
|
|
|
archived: [],
|
|
|
|
shared:[],
|
|
|
|
sent:[],
|
|
|
|
notes: [],
|
|
|
|
highlights: [],
|
2020-03-14 06:04:03 +00:00
|
|
|
locked: []
|
2020-02-18 22:52:12 +00:00
|
|
|
},
|
2020-02-01 22:21:22 +00:00
|
|
|
|
2019-07-19 20:51:57 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
beforeMount(){
|
2019-07-30 19:10:31 +00:00
|
|
|
|
2019-12-20 05:50:50 +00:00
|
|
|
this.$parent.loginGateway()
|
|
|
|
|
2020-02-11 21:11:14 +00:00
|
|
|
//Update totals for app
|
|
|
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
|
|
|
|
|
|
|
this.$bus.$on('close_active_note', ({position, noteId, modified}) => {
|
2020-04-15 20:44:24 +00:00
|
|
|
|
2019-07-20 23:07:22 +00:00
|
|
|
this.closeNote(position)
|
2020-02-11 21:11:14 +00:00
|
|
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
|
|
|
if(modified){
|
2020-04-15 20:44:24 +00:00
|
|
|
this.updateSingleNote(parseInt(noteId))
|
2020-02-11 21:11:14 +00:00
|
|
|
}
|
2020-03-02 05:33:49 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
this.$bus.$on('update_single_note', (noteId) => {
|
|
|
|
this.updateSingleNote(noteId)
|
2019-07-20 23:07:22 +00:00
|
|
|
})
|
2020-02-18 22:52:12 +00:00
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
this.$bus.$on('note_deleted', (noteId) => {
|
|
|
|
//Remove deleted note from set, its deleted
|
2020-03-09 03:11:05 +00:00
|
|
|
this.fetchUserTags()
|
2020-02-18 22:52:12 +00:00
|
|
|
Object.keys(this.noteSections).forEach( key => {
|
|
|
|
this.noteSections[key].forEach( (note, index) => {
|
|
|
|
if(note.id == noteId){
|
|
|
|
this.noteSections[key].splice(index,1)
|
|
|
|
return
|
2020-01-03 01:26:55 +00:00
|
|
|
}
|
2020-02-18 22:52:12 +00:00
|
|
|
})
|
2020-01-03 01:26:55 +00:00
|
|
|
})
|
2020-02-18 22:52:12 +00:00
|
|
|
|
2019-07-29 07:22:47 +00:00
|
|
|
})
|
2019-09-10 18:10:11 +00:00
|
|
|
this.$bus.$on('update_fast_filters', newFilter => {
|
|
|
|
this.fastFilters = newFilter
|
2020-01-03 01:26:55 +00:00
|
|
|
//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( () => {
|
2020-02-01 22:21:22 +00:00
|
|
|
|
|
|
|
this.searchAttachments()
|
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
return this.fetchUserTags()
|
|
|
|
})
|
2019-12-20 05:50:50 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
//New note button pushes open note event
|
|
|
|
this.$bus.$on('open_note', noteId => {
|
|
|
|
this.openNote(noteId)
|
2019-09-10 18:10:11 +00:00
|
|
|
})
|
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
//Reload page content
|
|
|
|
this.$bus.$on('note_reload', () => {
|
|
|
|
this.reset()
|
|
|
|
})
|
|
|
|
|
2019-09-10 18:10:11 +00:00
|
|
|
//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)
|
|
|
|
}
|
2019-12-20 05:50:50 +00:00
|
|
|
window.addEventListener('scroll', this.onScroll)
|
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
//Close notes when back button is pressed
|
|
|
|
window.addEventListener('hashchange', this.hashChangeAction)
|
|
|
|
|
2020-02-01 22:21:22 +00:00
|
|
|
//update note on visibility change
|
2020-01-03 01:26:55 +00:00
|
|
|
document.addEventListener('visibilitychange', this.visibiltyChangeAction);
|
2019-09-10 18:10:11 +00:00
|
|
|
|
2019-12-20 05:50:50 +00:00
|
|
|
},
|
|
|
|
beforeDestroy(){
|
|
|
|
window.removeEventListener('scroll', this.onScroll)
|
2020-01-03 01:26:55 +00:00
|
|
|
window.removeEventListener('hashchange', this.hashChangeAction)
|
|
|
|
document.removeEventListener('visibilitychange', this.visibiltyChangeAction)
|
2020-01-03 01:54:11 +00:00
|
|
|
|
2020-04-14 05:09:19 +00:00
|
|
|
this.$bus.$off('note_reload')
|
|
|
|
this.$bus.$off('close_active_note')
|
|
|
|
this.$bus.$off('update_single_note')
|
|
|
|
this.$bus.$off('note_deleted')
|
|
|
|
this.$bus.$off('update_fast_filters')
|
|
|
|
this.$bus.$off('update_search_term')
|
|
|
|
this.$bus.$off('open_note')
|
|
|
|
|
2020-01-03 01:54:11 +00:00
|
|
|
//We want to remove event listeners, but something here is messing them up and preventing ALL event listeners from working
|
|
|
|
// this.$off() // Remove all event listeners
|
|
|
|
// this.$bus.$off()
|
2019-07-19 20:51:57 +00:00
|
|
|
},
|
|
|
|
mounted() {
|
2020-02-11 21:11:14 +00:00
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
//Loads initial batch and tags
|
|
|
|
this.reset()
|
2019-07-19 20:51:57 +00:00
|
|
|
},
|
|
|
|
methods: {
|
2019-12-20 05:50:50 +00:00
|
|
|
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
|
|
|
|
},
|
2020-01-03 01:26:55 +00:00
|
|
|
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 }
|
|
|
|
}
|
2019-07-20 23:07:22 +00:00
|
|
|
|
|
|
|
//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
|
2019-09-10 18:10:11 +00:00
|
|
|
this.$router.push('/notes/open/'+this.activeNoteId1)
|
2019-07-20 23:07:22 +00:00
|
|
|
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
|
|
|
|
}
|
2019-09-10 18:10:11 +00:00
|
|
|
//2 notes open
|
|
|
|
if(this.activeNoteId2 != null && this.activeNoteId1 == null){
|
|
|
|
this.activeNoteId1 = id
|
|
|
|
this.activeNote1Position = 2 //Right side of page
|
|
|
|
this.activeNote2Position = 1 //Left side of page
|
|
|
|
return
|
|
|
|
}
|
2019-07-20 23:07:22 +00:00
|
|
|
},
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
//IF two notes get opened, update ID of open note
|
|
|
|
if(this.activeNoteId1 || this.activeNoteId2){
|
2020-04-10 03:47:15 +00:00
|
|
|
this.$router.push('/notes/open/'+Math.max(this.activeNoteId1, this.activeNoteId2))
|
2020-01-03 01:26:55 +00:00
|
|
|
} else {
|
|
|
|
//No notes are open, just show notes page
|
|
|
|
this.$router.push('/notes')
|
|
|
|
}
|
2019-09-10 18:10:11 +00:00
|
|
|
|
2019-07-20 23:07:22 +00:00
|
|
|
this.activeNote1Position = 0
|
|
|
|
this.activeNote2Position = 0
|
|
|
|
|
|
|
|
},
|
2019-07-19 20:51:57 +00:00
|
|
|
toggleTagFilter(tagId){
|
|
|
|
|
|
|
|
if(this.searchTags.includes(tagId)){
|
|
|
|
this.searchTags.splice( this.searchTags.indexOf(tagId) , 1);
|
|
|
|
} else {
|
|
|
|
this.searchTags.push(tagId)
|
|
|
|
}
|
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
//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()
|
|
|
|
|
2019-07-19 20:51:57 +00:00
|
|
|
},
|
2019-12-20 05:50:50 +00:00
|
|
|
onScroll(e){
|
2019-09-10 18:10:11 +00:00
|
|
|
|
2019-12-20 05:50:50 +00:00
|
|
|
clearTimeout(this.loadingBatchTimeout)
|
|
|
|
this.loadingBatchTimeout = setTimeout(() => {
|
2019-09-10 18:10:11 +00:00
|
|
|
|
2019-12-20 05:50:50 +00:00
|
|
|
//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 )
|
|
|
|
|
|
|
|
//If greater than 80 of the way down the page, load the next batch
|
|
|
|
if(percentageDown >= 80){
|
2020-02-10 21:09:09 +00:00
|
|
|
|
2019-12-20 05:50:50 +00:00
|
|
|
this.search(false, this.batchSize, true)
|
|
|
|
}
|
|
|
|
|
|
|
|
}, 50)
|
2019-09-10 18:10:11 +00:00
|
|
|
|
|
|
|
|
2019-12-20 05:50:50 +00:00
|
|
|
return
|
|
|
|
},
|
2020-01-03 01:26:55 +00:00
|
|
|
//Try to close notes on URL hash change /notes/open/123 to /notes - parse 123, close note id 123
|
|
|
|
hashChangeAction(event){
|
2020-02-10 17:44:43 +00:00
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
//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,'')
|
|
|
|
|
2020-04-10 03:47:15 +00:00
|
|
|
// console.log(this.$route.params)
|
|
|
|
// console.log(this.$router)
|
|
|
|
|
|
|
|
//Open note if user goes forward to a note id
|
|
|
|
if(this.$route.params && this.$route.params.id){
|
|
|
|
this.openNote(this.$route.params.id)
|
|
|
|
}
|
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
//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()
|
2020-04-10 03:47:15 +00:00
|
|
|
|
|
|
|
// console.log(noteIdToClose)
|
2020-01-03 01:26:55 +00:00
|
|
|
|
|
|
|
if(this.$refs.note1 && this.$refs.note1.currentNoteId == noteIdToClose){
|
2020-04-10 03:47:15 +00:00
|
|
|
// this.$refs.note1.close()
|
2020-01-03 01:26:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(this.$refs.note2 && this.$refs.note2.currentNoteId == noteIdToClose){
|
2020-04-10 03:47:15 +00:00
|
|
|
//this.$refs.note2.close()
|
2020-01-03 01:26:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
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'){
|
|
|
|
//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]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-30 05:31:09 +00:00
|
|
|
|
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
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){
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
//Find Just updated note and modify all its attributes
|
|
|
|
Object.keys(this.noteSections).forEach(key => {
|
2020-01-03 01:26:55 +00:00
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
this.noteSections[key].forEach( (note,index) => {
|
2020-01-03 01:26:55 +00:00
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
if(note.id == noteId){
|
|
|
|
foundNote = true
|
2020-01-03 01:26:55 +00:00
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
//Don't move notes that were not changed
|
|
|
|
if(note.updated == newNote.updated){
|
2020-03-02 05:33:49 +00:00
|
|
|
// return
|
2020-02-18 22:52:12 +00:00
|
|
|
}
|
2020-01-03 01:26:55 +00:00
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
//Compare note tags, if they changed, reload tags
|
|
|
|
if(newNote.tag_count != note.tag_count){
|
|
|
|
this.fetchUserTags()
|
|
|
|
}
|
2020-01-03 01:26:55 +00:00
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
//go through each prop and update it with new values
|
|
|
|
Object.keys(newNote).forEach(prop => {
|
|
|
|
note[prop] = newNote[prop]
|
|
|
|
})
|
|
|
|
|
|
|
|
//Remove note from location and push to front
|
|
|
|
this.noteSections[key].splice(index, 1)
|
|
|
|
this.noteSections[key].unshift(note)
|
|
|
|
|
2020-03-30 05:31:09 +00:00
|
|
|
this.$nextTick( () => {
|
|
|
|
|
|
|
|
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0]){
|
|
|
|
this.$refs['note-'+noteId][0].justClosed()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
})
|
2020-01-03 01:26:55 +00:00
|
|
|
})
|
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
//New notes don't exist in list, push them to the front
|
|
|
|
if(!foundNote){
|
|
|
|
this.noteSections.notes.unshift(newNote)
|
2020-01-03 01:26:55 +00:00
|
|
|
}
|
2020-02-18 22:52:12 +00:00
|
|
|
//Trigger section rebuild
|
|
|
|
this.rebuildNoteCategorise()
|
2020-01-03 01:26:55 +00:00
|
|
|
})
|
2020-04-14 05:09:19 +00:00
|
|
|
.catch(error => { this.$bus.$emit('notification', 'Failed to Search Notes') })
|
2020-01-03 01:26:55 +00:00
|
|
|
},
|
2020-02-01 22:21:22 +00:00
|
|
|
searchAttachments(){
|
|
|
|
axios.post('/api/attachment/textsearch', {'searchTerm':this.searchTerm})
|
|
|
|
.then(results => {
|
|
|
|
this.foundAttachments = results.data
|
|
|
|
})
|
2020-04-14 05:09:19 +00:00
|
|
|
.catch(error => { this.$bus.$emit('notification', 'Failed to Search Attachments') })
|
2020-02-01 22:21:22 +00:00
|
|
|
},
|
2019-12-20 05:50:50 +00:00
|
|
|
search(showLoading = true, notesInNextLoad = null, mergeExisting = false){
|
|
|
|
return new Promise((resolve, reject) => {
|
2019-09-10 18:10:11 +00:00
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
//Don't double load note batches
|
2019-12-20 05:50:50 +00:00
|
|
|
if(this.loadingInProgress){
|
|
|
|
return resolve()
|
|
|
|
}
|
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
//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
|
2019-12-20 05:50:50 +00:00
|
|
|
delete this.fastFilters.limitSize
|
|
|
|
delete this.fastFilters.limitOffset
|
|
|
|
|
|
|
|
let postData = {
|
|
|
|
searchQuery: this.searchTerm,
|
|
|
|
searchTags: this.searchTags,
|
|
|
|
fastFilters: this.fastFilters,
|
|
|
|
}
|
|
|
|
|
|
|
|
//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
|
2020-02-18 22:52:12 +00:00
|
|
|
axios.post('/api/note/search', postData)
|
|
|
|
.then(response => {
|
2019-12-20 05:50:50 +00:00
|
|
|
|
|
|
|
//Save the number of notes just loaded
|
|
|
|
this.batchOffset += response.data.notes.length
|
|
|
|
|
2020-01-03 01:26:55 +00:00
|
|
|
//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
|
|
|
|
}
|
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
this.loadingInProgress = false
|
|
|
|
this.generateNoteCategories(response.data.notes, mergeExisting)
|
2019-12-20 05:50:50 +00:00
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
return resolve(true)
|
|
|
|
})
|
2020-04-14 05:09:19 +00:00
|
|
|
.catch(error => { this.$bus.$emit('notification', 'Failed to Search Notes') })
|
2020-02-18 22:52:12 +00:00
|
|
|
})
|
|
|
|
},
|
|
|
|
rebuildNoteCategorise(){
|
|
|
|
let currentNotes = []
|
|
|
|
Object.keys(this.noteSections).forEach( key => {
|
|
|
|
this.noteSections[key].forEach( note => {
|
|
|
|
currentNotes.push(note)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
this.generateNoteCategories(currentNotes, false)
|
|
|
|
},
|
|
|
|
generateNoteCategories(notes, mergeExisting){
|
|
|
|
// Place each note in a category based on certain attributes and fast filters
|
2019-12-20 05:50:50 +00:00
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
//Reset all sections if we are not merging existing
|
|
|
|
if(!mergeExisting){
|
|
|
|
Object.keys(this.noteSections).forEach( key => {
|
|
|
|
this.noteSections[key] = []
|
|
|
|
})
|
|
|
|
}
|
2019-12-20 05:50:50 +00:00
|
|
|
|
2020-02-18 22:52:12 +00:00
|
|
|
//Sort notes into defined sections
|
|
|
|
notes.forEach(note => {
|
2020-01-03 01:26:55 +00:00
|
|
|
|
2020-03-30 05:31:09 +00:00
|
|
|
//Show archived notes
|
2020-02-18 22:52:12 +00:00
|
|
|
if(note.archived == 1 && this.fastFilters.onlyArchived == 1){
|
|
|
|
this.noteSections.archived.push(note)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if(note.shareUsername != null){
|
|
|
|
this.noteSections.shared.push(note)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
//Only show sent notes section if shared is selected
|
|
|
|
if(note.shared == 2 && this.fastFilters.onlyShowSharedNotes == 1){
|
|
|
|
this.noteSections.sent.push(note)
|
|
|
|
return
|
|
|
|
}
|
2020-03-14 06:04:03 +00:00
|
|
|
if(note.encrypted == 1 && this.fastFilters.onlyShowEncrypted == 1){
|
|
|
|
this.noteSections.locked.push(note)
|
|
|
|
return
|
|
|
|
}
|
2020-02-18 22:52:12 +00:00
|
|
|
if(note.note_highlights.length > 0){
|
|
|
|
this.noteSections.highlights.push(note)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Pinned notes are always first, they can appear in the archive
|
|
|
|
if(note.pinned == 1){
|
|
|
|
this.noteSections.pinned.push(note)
|
|
|
|
return
|
|
|
|
}
|
2020-03-30 05:31:09 +00:00
|
|
|
//If the note is not archived, push it.
|
|
|
|
if(note.archived != 1 && this.fastFilters.onlyArchived != 1){
|
|
|
|
this.noteSections.notes.push(note)
|
|
|
|
}
|
2019-07-19 20:51:57 +00:00
|
|
|
})
|
2020-02-18 22:52:12 +00:00
|
|
|
|
2019-07-19 20:51:57 +00:00
|
|
|
},
|
|
|
|
ucWords(str){
|
|
|
|
return (str + '')
|
|
|
|
.replace(/^(.)|\s+(.)/g, function ($1) {
|
|
|
|
return $1.toUpperCase()
|
|
|
|
})
|
|
|
|
},
|
|
|
|
reset(){
|
2019-12-20 05:50:50 +00:00
|
|
|
this.showClear = false
|
2019-07-19 20:51:57 +00:00
|
|
|
this.searchTerm = ''
|
|
|
|
this.searchTags = []
|
2019-09-10 18:10:11 +00:00
|
|
|
this.fastFilters = {}
|
2020-02-01 22:21:22 +00:00
|
|
|
this.foundAttachments = [] //Remove all attachments
|
2019-09-10 18:10:11 +00:00
|
|
|
this.$bus.$emit('reset_fast_filters')
|
2020-01-03 01:26:55 +00:00
|
|
|
|
|
|
|
//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) => {
|
2020-02-12 05:29:56 +00:00
|
|
|
|
|
|
|
let postData = {
|
|
|
|
searchQuery: this.searchTerm,
|
|
|
|
searchTags: this.searchTags,
|
|
|
|
fastFilters: this.fastFilters,
|
|
|
|
}
|
|
|
|
|
|
|
|
axios.post('/api/tag/usertags', postData)
|
2020-01-03 01:26:55 +00:00
|
|
|
.then( ({data}) => {
|
|
|
|
this.commonTags = data
|
|
|
|
resolve(data)
|
|
|
|
})
|
2020-04-14 05:09:19 +00:00
|
|
|
.catch(error => { this.$bus.$emit('notification', 'Failed to Fetch Tags') })
|
2020-01-03 01:26:55 +00:00
|
|
|
})
|
2020-02-11 21:11:14 +00:00
|
|
|
},
|
|
|
|
updateFastFilters(index){
|
|
|
|
|
|
|
|
//clear out tags
|
|
|
|
this.searchTags = []
|
|
|
|
|
|
|
|
//A little hacky, brings user to notes page then filters on click
|
2020-04-10 03:47:15 +00:00
|
|
|
if(this.$route.name != 'Note Page'){
|
2020-02-11 21:11:14 +00:00
|
|
|
this.$router.push('/notes')
|
|
|
|
setTimeout( () => {
|
|
|
|
this.updateFastFilters(index)
|
|
|
|
}, 500 )
|
|
|
|
}
|
|
|
|
|
|
|
|
const options = [
|
|
|
|
'withLinks', // 'Only Show Notes with Links'
|
|
|
|
'withTags', // 'Only Show Notes with Tags'
|
|
|
|
'onlyArchived', //'Only Show Archived Notes'
|
|
|
|
'onlyShowSharedNotes', //Only show shared notes
|
2020-03-13 23:34:32 +00:00
|
|
|
'onlyShowEncrypted',
|
2020-02-11 21:11:14 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
let filter = {}
|
|
|
|
filter[options[index]] = 1
|
|
|
|
|
|
|
|
this.$bus.$emit('update_fast_filters', filter)
|
2019-07-19 20:51:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
<style type="text/css" scoped>
|
2019-12-20 05:50:50 +00:00
|
|
|
.mush-it-up {
|
|
|
|
width: calc(50% - 130px);
|
|
|
|
}
|
2019-07-19 20:51:57 +00:00
|
|
|
.detail {
|
|
|
|
float: right;
|
|
|
|
}
|
2019-07-29 07:22:47 +00:00
|
|
|
.note-card-display-area {
|
|
|
|
display: flex;
|
|
|
|
flex-wrap: wrap;
|
|
|
|
}
|
2019-12-20 05:50:50 +00:00
|
|
|
.display-area-title {
|
|
|
|
width: 100%;
|
|
|
|
display: inline-block;
|
|
|
|
}
|
|
|
|
.note-card-section {
|
|
|
|
/*padding-bottom: 15px;*/
|
|
|
|
}
|
|
|
|
.note-card-section + .note-card-section {
|
|
|
|
padding: 15px 0 0;
|
|
|
|
}
|
2019-07-19 20:51:57 +00:00
|
|
|
</style>
|