Compare commits
3 Commits
848c86327a
...
c972430ef4
Author | SHA1 | Date | |
---|---|---|---|
|
c972430ef4 | ||
|
6d0187ee0a | ||
|
00500ecc33 |
@ -12,6 +12,7 @@ echo '-------'
|
|||||||
BACKUPDIR="/home/mab/databaseBackupSolidScribe"
|
BACKUPDIR="/home/mab/databaseBackupSolidScribe"
|
||||||
#DEVDBPASS="Crama!Lama*Jamma###88383!!!!!345345956245i"
|
#DEVDBPASS="Crama!Lama*Jamma###88383!!!!!345345956245i"
|
||||||
DEVDBPASS="RootPass1234!"
|
DEVDBPASS="RootPass1234!"
|
||||||
|
# LazaLinga&33Can't!Do!That34
|
||||||
|
|
||||||
cd $BACKUPDIR
|
cd $BACKUPDIR
|
||||||
|
|
||||||
@ -28,8 +29,12 @@ gunzip -dkv $LASTZIPPEDFILE
|
|||||||
BACKUPFILE=$(ls -At *.sql | head -n1)
|
BACKUPFILE=$(ls -At *.sql | head -n1)
|
||||||
|
|
||||||
#Fix to replace incompatible DB type
|
#Fix to replace incompatible DB type
|
||||||
echo "Updating table name in $BACKUPFILE"
|
echo "Updating table name in -> $BACKUPFILE"
|
||||||
sed -i $BACKUPFILE -e 's/utf8mb4_0900_ai_ci/utf8mb4_unicode_ci/g'
|
#sed -i $BACKUPFILE -e 's/utf8mb4_0900_ai_ci/utf8mb4_unicode_ci/g'
|
||||||
|
|
||||||
|
#Fix encoding for dev DB and exclude system tables
|
||||||
|
sed -i 's/utf8mb4_0900_ai_ci/utf8mb4_general_ci/g' $BACKUPFILE
|
||||||
|
sed -r '/INSERT INTO `(sys|mysql)`/d' $BACKUPFILE > $BACKUPFILE
|
||||||
|
|
||||||
echo "Removing and syncing static files"
|
echo "Removing and syncing static files"
|
||||||
rm -r /home/mab/ss/staticFiles/*
|
rm -r /home/mab/ss/staticFiles/*
|
||||||
@ -38,8 +43,20 @@ rsync -e 'ssh -p 13328' -hazC --update mab@solidscribe.com:/home/mab/pi/staticFi
|
|||||||
echo "Updating Database"
|
echo "Updating Database"
|
||||||
mysql -u root --password="$DEVDBPASS" < $BACKUPFILE
|
mysql -u root --password="$DEVDBPASS" < $BACKUPFILE
|
||||||
|
|
||||||
|
## Optimize Database Tables
|
||||||
|
# mysqlcheck --all-databases
|
||||||
|
mysqlcheck --all-databases -o -u root --password="$DEVDBPASS" --silent
|
||||||
|
# mysqlcheck --all-databases --auto-repair
|
||||||
|
# mysqlcheck --all-databases --analyze
|
||||||
|
|
||||||
|
# Fix an issues with DB after messing around with it
|
||||||
|
mysql_upgrade -u root --password="$DEVDBPASS"
|
||||||
|
|
||||||
|
#clean up extracted and modified SQL dumps
|
||||||
rm *.sql
|
rm *.sql
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
echo '-------'
|
echo '-------'
|
||||||
echo "Applied Prod database to Dev. LastFile: $BACKUPFILE"
|
echo "Applied Prod database to Dev. LastFile: $BACKUPFILE"
|
||||||
echo '-------'
|
echo '-------'
|
@ -200,6 +200,11 @@ export default {
|
|||||||
this.blockUntilNextRequest = true
|
this.blockUntilNextRequest = true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//Track users active sessions
|
||||||
|
this.$io.on('update_active_user_count', countData => {
|
||||||
|
this.$store.commit('setActiveSessions', countData)
|
||||||
|
})
|
||||||
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
loggedIn () {
|
loggedIn () {
|
||||||
|
@ -330,9 +330,14 @@ i.green.icon.icon.icon.icon {
|
|||||||
background-color: rgba(255, 255, 255, 0.2);
|
background-color: rgba(255, 255, 255, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.note-card-text code,
|
||||||
|
.squire-box code,
|
||||||
.note-card-text pre,
|
.note-card-text pre,
|
||||||
.squire-box pre {
|
.squire-box pre {
|
||||||
/*word-wrap: break-word;*/
|
/*word-wrap: break-word;*/
|
||||||
|
display: inline-block;
|
||||||
|
border-left: 2px solid var(--main-accent);
|
||||||
|
padding-left: 15px;
|
||||||
}
|
}
|
||||||
.note-card-text p,
|
.note-card-text p,
|
||||||
.squire-box p {
|
.squire-box p {
|
||||||
@ -880,6 +885,14 @@ i.green.icon.icon.icon.icon {
|
|||||||
-webkit-transform-origin: left center;
|
-webkit-transform-origin: left center;
|
||||||
transform-origin: left center;
|
transform-origin: left center;
|
||||||
}
|
}
|
||||||
|
@media only screen and (max-width: 740px) {
|
||||||
|
/*hide tooltips on mobile*/
|
||||||
|
[data-tooltip]:hover:before,
|
||||||
|
[data-tooltip]:hover:after {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.glint:after {
|
.glint:after {
|
||||||
|
@ -154,16 +154,20 @@
|
|||||||
<style type="text/css" scoped>
|
<style type="text/css" scoped>
|
||||||
.icon-button, .color-button {
|
.icon-button, .color-button {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
width: calc(10% - 7px);
|
width: calc(15% - 1px);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
border: 1px solid grey;
|
border: 1px solid grey;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 5px 0 0;
|
padding: 5px 0px 0 0;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
box-shadow: 0px 1px 3px 0px #3e3e3e;
|
box-shadow: 0px 1px 3px 0px #3e3e3e;
|
||||||
margin: 7px 7px 0 0;
|
margin: 2px 2px 0 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.color-button {
|
||||||
|
width: calc(10% - 4px);
|
||||||
}
|
}
|
||||||
.rounded {
|
.rounded {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<style scoped>
|
<style scoped>
|
||||||
.slotholder {
|
.slotholder {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 155px;
|
width: 180px;
|
||||||
display: block;
|
display: block;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
.global-menu {
|
.global-menu {
|
||||||
width: 155px;
|
width: 180px;
|
||||||
/* background: #221f2b; */
|
/* background: #221f2b; */
|
||||||
background: #221f2b;
|
background: #221f2b;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -21,7 +21,7 @@
|
|||||||
}
|
}
|
||||||
.menu-logo-display {
|
.menu-logo-display {
|
||||||
width: 27px;
|
width: 27px;
|
||||||
margin: 5px 0 0 41px;
|
margin: 5px 0 0 55px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
@ -54,9 +54,6 @@
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.router-link-active i {
|
|
||||||
/*color: #16ab39;*/
|
|
||||||
}
|
|
||||||
.router-link-active {
|
.router-link-active {
|
||||||
background-color: #534c68;
|
background-color: #534c68;
|
||||||
}
|
}
|
||||||
@ -141,6 +138,17 @@
|
|||||||
.mobile-button.active {
|
.mobile-button.active {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
.single-line-text {
|
||||||
|
width: calc(100%);
|
||||||
|
/*margin: 5px 10px;*/
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.faded {
|
||||||
|
color: var(--dark_border_color);
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@ -170,7 +178,6 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- open straight to note -->
|
<!-- open straight to note -->
|
||||||
<router-link
|
<router-link
|
||||||
v-if="loggedIn && $store.getters.totals && $store.getters.totals['quickNote']"
|
v-if="loggedIn && $store.getters.totals && $store.getters.totals['quickNote']"
|
||||||
@ -198,8 +205,8 @@
|
|||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<!-- menu -->
|
<!-- menu -->
|
||||||
<div class="mobile-button">
|
<div class="mobile-button" v-on:click="collapseMenu">
|
||||||
<i class="green link bars icon" v-on:click="collapseMenu"></i>
|
<i class="green link bars icon" ></i>
|
||||||
Menu
|
Menu
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -220,12 +227,12 @@
|
|||||||
|
|
||||||
<div class="menu-section" v-if="loggedIn">
|
<div class="menu-section" v-if="loggedIn">
|
||||||
<div v-if="!disableNewNote" @click="createNote" class="menu-item menu-item menu-button">
|
<div v-if="!disableNewNote" @click="createNote" class="menu-item menu-item menu-button">
|
||||||
<div class="ui green button">
|
<div class="ui green fluid compact button">
|
||||||
<i class="plus icon"></i>New Note
|
<i class="plus icon"></i>New Note
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="disableNewNote" class="menu-item menu-item menu-button">
|
<div v-if="disableNewNote" class="menu-item menu-item menu-button">
|
||||||
<div class="ui basic button">
|
<div class="ui basic fluid compact button">
|
||||||
<i class="plus loading icon"></i>New Note
|
<i class="plus loading icon"></i>New Note
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -238,14 +245,19 @@
|
|||||||
</router-link>
|
</router-link>
|
||||||
<div>
|
<div>
|
||||||
<div class="menu-item menu-button sub" v-on:click="updateFastFilters(3)" v-if="$store.getters.totals && ($store.getters.totals['sharedToNotes'] > 0 || $store.getters.totals['sharedFromNotes'] > 0)">
|
<div class="menu-item menu-button sub" v-on:click="updateFastFilters(3)" v-if="$store.getters.totals && ($store.getters.totals['sharedToNotes'] > 0 || $store.getters.totals['sharedFromNotes'] > 0)">
|
||||||
<i class="grey mail outline icon"></i>Inbox
|
<i class="grey paper plane outline icon"></i>Shared
|
||||||
|
|
||||||
|
<counter v-if="$store.getters.totals && $store.getters.totals['sharedToNotes']" class="float-right" number-id="sharedToNotes" />
|
||||||
</div>
|
</div>
|
||||||
<div class="menu-item menu-button sub" v-on:click="updateFastFilters(2)" v-if="$store.getters.totals && $store.getters.totals['archivedNotes'] > 0">
|
<div class="menu-item menu-button sub" v-on:click="updateFastFilters(2)" v-if="$store.getters.totals && $store.getters.totals['archivedNotes'] > 0">
|
||||||
<i class="grey archive icon"></i>Archived
|
<i class="grey archive icon"></i>Archived
|
||||||
<!-- <span>{{ $store.getters.totals['archivedNotes'] }}</span> -->
|
|
||||||
|
<counter v-if="$store.getters.totals && $store.getters.totals['archivedNotes']" class="float-right" number-id="archivedNotes" />
|
||||||
</div>
|
</div>
|
||||||
<div class="menu-item menu-button sub" v-on:click="updateFastFilters(4)" v-if="$store.getters.totals && $store.getters.totals['trashedNotes'] > 0">
|
<div class="menu-item menu-button sub" v-on:click="updateFastFilters(4)" v-if="$store.getters.totals && $store.getters.totals['trashedNotes'] > 0">
|
||||||
<i class="grey trash alternate outline icon"></i>Trashed
|
<i class="grey trash alternate outline icon"></i>Trashed
|
||||||
|
|
||||||
|
<counter v-if="$store.getters.totals && $store.getters.totals['trashedNotes']" class="float-right" number-id="trashedNotes" />
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="menu-item sub">Show Only <i class="caret down icon"></i></div> -->
|
<!-- <div class="menu-item sub">Show Only <i class="caret down icon"></i></div> -->
|
||||||
<!-- <div v-on:click="updateFastFilters(0)" class="menu-item menu-button sub"><i class="grey linkify icon"></i>Links</div> -->
|
<!-- <div v-on:click="updateFastFilters(0)" class="menu-item menu-button sub"><i class="grey linkify icon"></i>Links</div> -->
|
||||||
@ -320,6 +332,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Tags -->
|
||||||
|
<div class="menu-section" v-if="gotTags()">
|
||||||
|
<div class="menu-item">
|
||||||
|
<i class="green tags icon"></i>
|
||||||
|
Tags
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="gotTags()">
|
||||||
|
<div class="menu-section"
|
||||||
|
v-for="(data, tag) in $store.getters.totals['tags']">
|
||||||
|
<router-link class="menu-item menu-button" :to="`/search/tags/${tag}`">
|
||||||
|
<span class="single-line-text">
|
||||||
|
<!-- <i class="small grey tag icon"></i> -->
|
||||||
|
<span class="float-right">{{ data.uses }}</span>
|
||||||
|
<span class="faded"> #</span> {{ tag }}</span>
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-on:click="reloadPage" class="version-display" v-if="version != 0" >
|
<div v-on:click="reloadPage" class="version-display" v-if="version != 0" >
|
||||||
<i :class="`${getVersionIcon()} icon`"></i> {{ version }}
|
<i :class="`${getVersionIcon()} icon`"></i> {{ version }}
|
||||||
</div>
|
</div>
|
||||||
@ -379,6 +410,16 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
gotTags(){
|
||||||
|
|
||||||
|
if(this.loggedIn && this.$store.getters.totals && this.$store.getters.totals.tags
|
||||||
|
&& Object.keys(this.$store.getters.totals.tags).length
|
||||||
|
){
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
logout() {
|
logout() {
|
||||||
|
|
||||||
this.$router.push('/')
|
this.$router.push('/')
|
||||||
|
@ -39,9 +39,9 @@
|
|||||||
.loading-container {
|
.loading-container {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 100px;
|
/*min-height: 100px;*/
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
padding: 40px;
|
/*padding: 40px;*/
|
||||||
border-radius: 7px;
|
border-radius: 7px;
|
||||||
background-color: var(--small_element_bg_color);
|
background-color: var(--small_element_bg_color);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div v-on:keyup.enter="login()">
|
<div>
|
||||||
|
|
||||||
<!-- thicc form display -->
|
<!-- thicc form display -->
|
||||||
<div v-if="!thin" class="ui large form">
|
<div v-if="!thin" class="ui large form" v-on:keyup.enter="register()">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui input">
|
<div class="ui input">
|
||||||
<input ref="nameForm" v-model="username" type="text" name="email" placeholder="Username or E-mail">
|
<input ref="nameForm" v-model="username" type="text" name="email" placeholder="Username or E-mail">
|
||||||
@ -24,14 +24,14 @@
|
|||||||
<div class="ui fluid buttons">
|
<div class="ui fluid buttons">
|
||||||
|
|
||||||
|
|
||||||
<div v-on:click="register()" class="ui button">
|
<div v-on:click="register()" class="ui green button" :class="{ 'disabled':(username.length == 0 || password.length == 0)}">
|
||||||
<i class="plug icon"></i>
|
<i class="plug icon"></i>
|
||||||
Sign Up
|
Sign Up
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="or"></div>
|
<div class="or"></div>
|
||||||
|
|
||||||
<div :class="{ 'disabled':(username.length == 0 || password.length == 0)}" v-on:click="login()" class="ui green button">
|
<div :class="{ 'disabled':(username.length == 0 || password.length == 0)}" v-on:click="login()" class="ui button">
|
||||||
<i class="power icon"></i>
|
<i class="power icon"></i>
|
||||||
Login
|
Login
|
||||||
</div>
|
</div>
|
||||||
@ -49,7 +49,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Thin form display -->
|
<!-- Thin form display -->
|
||||||
<div v-if="thin" class="ui small form">
|
<div v-if="thin" class="ui small form" v-on:keyup.enter="login()">
|
||||||
|
|
||||||
<div v-if="!require2FA" class="field"><!-- hide this field if someone is logging in with 2FA -->
|
<div v-if="!require2FA" class="field"><!-- hide this field if someone is logging in with 2FA -->
|
||||||
<div class="ui grid">
|
<div class="ui grid">
|
||||||
@ -228,7 +228,6 @@
|
|||||||
<style type="text/css" scoped="true">
|
<style type="text/css" scoped="true">
|
||||||
.small-terms {
|
.small-terms {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-align: right;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
@ -7,38 +7,16 @@
|
|||||||
>
|
>
|
||||||
|
|
||||||
<!-- Giant Edit Note Menu -->
|
<!-- Giant Edit Note Menu -->
|
||||||
<div class="edit-menu glint" :class="{ 'slide-out-top':(sizeDown == true) }">
|
<div class="edit-menu" :class="{ 'slide-out-top':(sizeDown == true) }">
|
||||||
|
|
||||||
<!-- edit spacer is disabled, it is helpful if menu gets bigger. It adds a left margin, starting the icons at the edge of the note -->
|
<!-- edit spacer is disabled, it is helpful if menu gets bigger. It adds a left margin, starting the icons at the edge of the note -->
|
||||||
<div class="edit-spacer"></div>
|
<div class="edit-spacer"></div>
|
||||||
|
|
||||||
<div class="menu-top-half">
|
<div class="menu-top-half">
|
||||||
|
|
||||||
<div class="edit-button" v-on:click=" hash=0; save() " :data-tooltip="`Save\n(CTRL + S)`" data-position="bottom center">
|
|
||||||
<i class="icons">
|
|
||||||
<i class="grey save outline icon"></i>
|
|
||||||
<i v-if="statusText == 'saved'" class="green small bottom left corner check icon"></i>
|
|
||||||
<i v-if="statusText == 'saving'" class="small purple bottom left corner double angle up icon"></i>
|
|
||||||
</i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="edit-divide"></div>
|
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="toggleList('ul')" :data-tooltip="`Task List\n(CTRL + SHIFT + 8)`" data-position="bottom center" :class="{'edit-active':activeToDo}">
|
|
||||||
<i class="tasks icon"></i>
|
|
||||||
</div>
|
|
||||||
<div class="edit-button" v-on:click="toggleList('ol')" :data-tooltip="`Ordered List\n(CTRL + SHIFT + 9)`" data-position="bottom center" :class="{'edit-active':activeList}">
|
|
||||||
<i class="list ol icon"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="edit-divide"></div>
|
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="colorpicker = true" data-tooltip="Text Color" data-position="bottom center">
|
<div class="edit-button" v-on:click="colorpicker = true" data-tooltip="Text Color" data-position="bottom center">
|
||||||
<i class="font icon"></i>
|
<i class="font icon"></i>
|
||||||
</div>
|
<div class="font-color-bar" :style="{'background':lastUsedColor}"></div>
|
||||||
|
|
||||||
<div v-if="lastUsedColor" class="edit-button" v-on:click="applyLastUsedColor()" data-tooltip="Last Color" data-position="bottom center" :style="{'color':lastUsedColor}">
|
|
||||||
<i class="eye dropper icon"></i>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="toggleBold()" :data-tooltip="`Bold\n(CTRL + b)`" data-position="bottom center" :class="{'edit-active':activeBold}">
|
<div class="edit-button" v-on:click="toggleBold()" :data-tooltip="`Bold\n(CTRL + b)`" data-position="bottom center" :class="{'edit-active':activeBold}">
|
||||||
@ -53,10 +31,22 @@
|
|||||||
<i class="underline icon"></i>
|
<i class="underline icon"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="edit-button" v-on:click="modifyCode('1.4em')" data-tooltip="Quote" data-position="bottom center" :class="{'edit-active':activeCode}">
|
||||||
|
<i class="quote right icon"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="edit-button" v-on:click="modifyFont('0.9em')" data-tooltip="Sub Title" data-position="bottom center" :class="{'edit-active':activeSubTitle}">
|
||||||
|
<i class="small text height icon"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="modifyFont('1.4em')" data-tooltip="Title" data-position="bottom center" :class="{'edit-active':activeTitle}">
|
<div class="edit-button" v-on:click="modifyFont('1.4em')" data-tooltip="Title" data-position="bottom center" :class="{'edit-active':activeTitle}">
|
||||||
<i class="text height icon"></i>
|
<i class="text height icon"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="edit-button" v-on:click="removeFormatting()" data-tooltip="Remove Formatting" data-position="bottom center">
|
||||||
|
<i class="remove format icon"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="edit-divide"></div>
|
<div class="edit-divide"></div>
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="editor.increaseQuoteLevel()" :data-tooltip="`Indent\n(TAB)`" data-position="bottom center">
|
<div class="edit-button" v-on:click="editor.increaseQuoteLevel()" :data-tooltip="`Indent\n(TAB)`" data-position="bottom center">
|
||||||
@ -74,18 +64,22 @@
|
|||||||
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/table`)" data-tooltip="Insert Table" data-position="bottom center">
|
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/table`)" data-tooltip="Insert Table" data-position="bottom center">
|
||||||
<i class="border all icon"></i>
|
<i class="border all icon"></i>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
|
||||||
|
<div class="edit-divide"></div>
|
||||||
|
|
||||||
|
<div class="edit-button" v-on:click="toggleList('ul')" :data-tooltip="`Task List\n(CTRL + SHIFT + 8)`" data-position="bottom center" :class="{'edit-active':activeToDo}">
|
||||||
|
<i class="tasks icon"></i>
|
||||||
|
</div>
|
||||||
|
<div class="edit-button" v-on:click="toggleList('ol')" :data-tooltip="`Ordered List\n(CTRL + SHIFT + 9)`" data-position="bottom center" :class="{'edit-active':activeList}">
|
||||||
|
<i class="list ol icon"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="edit-divide"></div>
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="insertDivide()" data-tooltip="Insert Divide" data-position="bottom center">
|
<div class="edit-button" v-on:click="insertDivide()" data-tooltip="Insert Divide" data-position="bottom center">
|
||||||
<i class="grip lines icon"></i>
|
<i class="grip lines icon"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="removeFormatting()" data-tooltip="Remove Formatting" data-position="bottom center">
|
|
||||||
<i class="remove format icon"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="undoCustom()" :data-tooltip="`Undo\n(CTRL + z)`" data-position="bottom center">
|
|
||||||
<i class="undo icon"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="edit-divide"></div>
|
<div class="edit-divide"></div>
|
||||||
|
|
||||||
@ -114,28 +108,19 @@
|
|||||||
|
|
||||||
<div class="edit-divide"></div>
|
<div class="edit-divide"></div>
|
||||||
|
|
||||||
|
<div class="edit-button" v-on:click="undoCustom()" :data-tooltip="`Undo\n(CTRL + z)`" data-position="bottom center">
|
||||||
<div class="edit-button" v-if="usersOnNote > 1" :data-tooltip="`Viewers`" data-position="bottom center">
|
<i class="reply icon"></i>
|
||||||
<i class="green eye icon"></i> {{ usersOnNote }}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--
|
<div class="edit-button done-button" v-on:click="closeButtonAction()" :data-tooltip="`Close\n(ESC)`" data-position="bottom center">
|
||||||
<div class="edit-button" v-on:click="simulateTyping()">
|
<!-- <i class="green close icon"></i> -->
|
||||||
<i class="purple bolt icon"></i>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<div class="edit-button" v-if="diffsApplied > 0" :data-tooltip="`Unsaved Changes`" data-position="bottom center">
|
|
||||||
+{{ diffsApplied }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="edit-button ui" v-on:click="closeButtonAction()" :data-tooltip="`Close\n(ESC)`" data-position="bottom center">
|
|
||||||
<i class="green close icon"></i>
|
|
||||||
<span class="ui green text">Done</span>
|
<span class="ui green text">Done</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- invisible menu item, creates BG for bottom menu -->
|
||||||
<div class="bottom-edit-menu"></div>
|
<div class="bottom-edit-menu"></div>
|
||||||
|
|
||||||
<div class="input-container-wrapper"
|
<div class="input-container-wrapper"
|
||||||
@ -146,7 +131,7 @@
|
|||||||
|
|
||||||
<!-- Loading indicator -->
|
<!-- Loading indicator -->
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<div v-if="loading || forceShowLoading" class="loading-note" :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">
|
<div v-if="loading && forceShowLoading" class="loading-note" :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">
|
||||||
<div class="loading-text">
|
<div class="loading-text">
|
||||||
<loading-icon :message="loadingMessage" />
|
<loading-icon :message="loadingMessage" />
|
||||||
</div>
|
</div>
|
||||||
@ -173,6 +158,12 @@
|
|||||||
<div class="note-mini-tag-area" :class="{ 'size-down':sizeDown }"
|
<div class="note-mini-tag-area" :class="{ 'size-down':sizeDown }"
|
||||||
v-on:click="$router.push(`/notes/open/${noteid}/menu/tags`)"
|
v-on:click="$router.push(`/notes/open/${noteid}/menu/tags`)"
|
||||||
:style="{ 'background-color':styleObject['noteBackground'] }">
|
:style="{ 'background-color':styleObject['noteBackground'] }">
|
||||||
|
|
||||||
|
|
||||||
|
<span>
|
||||||
|
{{ lastVisibilityState }}
|
||||||
|
</span>
|
||||||
|
|
||||||
<span class="add-mini-tag" v-if="allTags.length == 0">
|
<span class="add-mini-tag" v-if="allTags.length == 0">
|
||||||
<i class="tags icon"></i>Add Tags
|
<i class="tags icon"></i>Add Tags
|
||||||
</span>
|
</span>
|
||||||
@ -182,6 +173,28 @@
|
|||||||
<span class="active-mini-tag" v-if="allTags.length > 0">
|
<span class="active-mini-tag" v-if="allTags.length > 0">
|
||||||
+
|
+
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
<span class="status-menu" v-on:click=" hash=0; save()">
|
||||||
|
|
||||||
|
<span v-if="diffsApplied > 0">
|
||||||
|
+{{ diffsApplied }} Unsaved Changes
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-if="usersOnNote > 1" :data-tooltip="`Viewers`" data-position="left center">
|
||||||
|
<i class="green eye icon"></i> {{ usersOnNote }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span v-if="statusText == 'modified'" data-position="left center" data-tooltip="Modified">
|
||||||
|
<i class="grey asterisk icon"></i>
|
||||||
|
</span>
|
||||||
|
<span v-if="statusText == 'saving'" data-position="left center" data-tooltip="Saving">
|
||||||
|
<i class="grey upload icon"></i>
|
||||||
|
</span>
|
||||||
|
<span v-if="statusText == 'saved'" data-position="left center" data-tooltip="Saved">
|
||||||
|
<i class="grey check icon"></i>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -202,6 +215,7 @@
|
|||||||
<!-- color picker -->
|
<!-- color picker -->
|
||||||
<color-tooltip
|
<color-tooltip
|
||||||
v-if="colorpicker"
|
v-if="colorpicker"
|
||||||
|
:last-used-color="lastUsedColor"
|
||||||
v-on:color="color => modifyColor(color)"
|
v-on:color="color => modifyColor(color)"
|
||||||
v-on:close="colorpicker = false"
|
v-on:close="colorpicker = false"
|
||||||
/>
|
/>
|
||||||
@ -234,7 +248,7 @@
|
|||||||
|
|
||||||
<side-slide-menu v-if="options" v-on:close="options = false" name="note-options">
|
<side-slide-menu v-if="options" v-on:close="options = false" name="note-options">
|
||||||
<div class="ui basic padded segment">
|
<div class="ui basic padded segment">
|
||||||
<div class="ui grid">
|
<div class="ui compact stackable grid">
|
||||||
|
|
||||||
<div class="eight wide column">
|
<div class="eight wide column">
|
||||||
<div class="ui dividing header">
|
<div class="ui dividing header">
|
||||||
@ -370,7 +384,7 @@
|
|||||||
data(){
|
data(){
|
||||||
return {
|
return {
|
||||||
loading: true,
|
loading: true,
|
||||||
forceShowLoading: true,
|
forceShowLoading: false,
|
||||||
loadingMessage: 'Loading Note',
|
loadingMessage: 'Loading Note',
|
||||||
currentNoteId: 0,
|
currentNoteId: 0,
|
||||||
modified: false,
|
modified: false,
|
||||||
@ -385,6 +399,7 @@
|
|||||||
lastNoteHash: null,
|
lastNoteHash: null,
|
||||||
saveDebounce: null, //Prevent save from being called numerous times quickly
|
saveDebounce: null, //Prevent save from being called numerous times quickly
|
||||||
updated: 'Never',
|
updated: 'Never',
|
||||||
|
lastInteractionTimestamp:null, //Tracks when note was loaded and last saved/refreshed
|
||||||
editDebounce: null,
|
editDebounce: null,
|
||||||
textChangedDebounce: null,
|
textChangedDebounce: null,
|
||||||
keyPressesCounter: 0, //Determine keys pressed between saves
|
keyPressesCounter: 0, //Determine keys pressed between saves
|
||||||
@ -478,12 +493,12 @@
|
|||||||
},
|
},
|
||||||
mounted: function() {
|
mounted: function() {
|
||||||
|
|
||||||
//Show loading for a minimum time
|
//Show loading if note has not loaded in 500ms
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
this.forceShowLoading = false
|
this.forceShowLoading = true
|
||||||
}, 100)
|
}, 500)
|
||||||
|
|
||||||
// document.addEventListener('visibilitychange', this.checkForUpdatedNote)
|
document.addEventListener('visibilitychange', this.checkForUpdatedNote)
|
||||||
|
|
||||||
//Init squire as early as possible
|
//Init squire as early as possible
|
||||||
if(this.editor && this.editor.destroy){
|
if(this.editor && this.editor.destroy){
|
||||||
@ -561,7 +576,6 @@
|
|||||||
if(!this.$store.getters.getIsUserOnMobile){
|
if(!this.$store.getters.getIsUserOnMobile){
|
||||||
this.editor.focus()
|
this.editor.focus()
|
||||||
this.editor.moveCursorToEnd()
|
this.editor.moveCursorToEnd()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set up websockets after squire is set up
|
//Set up websockets after squire is set up
|
||||||
@ -596,10 +610,6 @@
|
|||||||
|
|
||||||
//If the offset is triggered with a negative offset, it means the before element was clicked
|
//If the offset is triggered with a negative offset, it means the before element was clicked
|
||||||
if(e.offsetX < -5){
|
if(e.offsetX < -5){
|
||||||
//Will hide keyboard if clicked on mobile
|
|
||||||
if(this.$store.getters.getIsUserOnMobile){
|
|
||||||
this.editor.blur()
|
|
||||||
}
|
|
||||||
|
|
||||||
//Area before element was clicked, they clicked the checkbox
|
//Area before element was clicked, they clicked the checkbox
|
||||||
if (el.className === 'active'){
|
if (el.className === 'active'){
|
||||||
@ -607,6 +617,21 @@
|
|||||||
} else {
|
} else {
|
||||||
el.className = 'active';
|
el.className = 'active';
|
||||||
}
|
}
|
||||||
|
//Trigger keyup event to save list changes
|
||||||
|
this.onKeyup(e)
|
||||||
|
|
||||||
|
//Will hide keyboard if clicked on mobile
|
||||||
|
if(this.$store.getters.getIsUserOnMobile){
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
|
||||||
|
document.activeElement.blur()
|
||||||
|
e.preventDefault()
|
||||||
|
return
|
||||||
|
|
||||||
|
}, 25)
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -660,10 +685,10 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
//Show and hide additional toolbars
|
//Show and hide additional toolbars
|
||||||
this.editor.addEventListener('focus', e => {
|
// this.editor.addEventListener('focus', e => {
|
||||||
})
|
// })
|
||||||
this.editor.addEventListener('blur', e => {
|
// this.editor.addEventListener('blur', e => {
|
||||||
})
|
// })
|
||||||
},
|
},
|
||||||
openEditAttachment(){
|
openEditAttachment(){
|
||||||
|
|
||||||
@ -723,35 +748,8 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set up local data
|
//Setup all responsive vue data
|
||||||
this.currentNoteId = this.noteid
|
this.setupLoadedNoteData(response)
|
||||||
this.rawTextId = response.data.rawTextId
|
|
||||||
this.shareUsername = response.data.shareUsername
|
|
||||||
|
|
||||||
this.created = response.data.created
|
|
||||||
this.updated = response.data.updated
|
|
||||||
this.noteTitle = ''
|
|
||||||
if(response.data.title){
|
|
||||||
this.noteTitle = response.data.title
|
|
||||||
}
|
|
||||||
|
|
||||||
this.noteText = response.data.text
|
|
||||||
this.lastNoteHash = this.hashString( response.data.text )
|
|
||||||
// this.diffNoteText = response.data.text
|
|
||||||
|
|
||||||
//Setup note tags
|
|
||||||
this.allTags = response.data.tags ? response.data.tags.split(','):[]
|
|
||||||
|
|
||||||
//Set up note colors
|
|
||||||
if(response.data.color){
|
|
||||||
this.styleObject = JSON.parse(response.data.color)
|
|
||||||
}
|
|
||||||
|
|
||||||
if(response.data.pinned != null){
|
|
||||||
this.pinned = response.data.pinned
|
|
||||||
}
|
|
||||||
this.archived = response.data.archived
|
|
||||||
this.attachmentCount = response.data.attachment_count
|
|
||||||
|
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
|
||||||
@ -768,6 +766,43 @@
|
|||||||
console.log('Could not fetch note')
|
console.log('Could not fetch note')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setupLoadedNoteData(response){
|
||||||
|
//All the data returned by the server, setup locally in vue component
|
||||||
|
|
||||||
|
//Set up local data
|
||||||
|
this.currentNoteId = this.noteid
|
||||||
|
this.rawTextId = response.data.rawTextId
|
||||||
|
this.shareUsername = response.data.shareUsername
|
||||||
|
|
||||||
|
this.created = response.data.created
|
||||||
|
this.updated = response.data.updated
|
||||||
|
this.lastInteractionTimestamp = +new Date
|
||||||
|
this.noteTitle = ''
|
||||||
|
if(response.data.title){
|
||||||
|
this.noteTitle = response.data.title
|
||||||
|
}
|
||||||
|
|
||||||
|
this.noteText = response.data.text
|
||||||
|
this.lastNoteHash = this.hashString( response.data.text )
|
||||||
|
// this.diffNoteText = response.data.text
|
||||||
|
|
||||||
|
//Setup note tags
|
||||||
|
this.allTags = response.data.tags ? response.data.tags.split(','):[]
|
||||||
|
|
||||||
|
//Set up note colors
|
||||||
|
if(response.data.color){
|
||||||
|
this.styleObject = JSON.parse(response.data.color)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(response.data.pinned != null){
|
||||||
|
this.pinned = response.data.pinned
|
||||||
|
}
|
||||||
|
this.archived = response.data.archived
|
||||||
|
this.attachmentCount = response.data.attachment_count
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
},
|
||||||
//Called on squire event for keyup
|
//Called on squire event for keyup
|
||||||
diffText(event){
|
diffText(event){
|
||||||
|
|
||||||
@ -846,10 +881,11 @@
|
|||||||
|
|
||||||
//Save after x keystrokes
|
//Save after x keystrokes
|
||||||
this.keyPressesCounter = (this.keyPressesCounter + 1)
|
this.keyPressesCounter = (this.keyPressesCounter + 1)
|
||||||
if(this.keyPressesCounter > 25){
|
if(this.keyPressesCounter > 60){
|
||||||
this.keyPressesCounter = 0
|
this.keyPressesCounter = 0
|
||||||
this.save()
|
this.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
save(force = false){
|
save(force = false){
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@ -890,6 +926,7 @@
|
|||||||
axios.post('/api/note/update', postData).then( response => {
|
axios.post('/api/note/update', postData).then( response => {
|
||||||
this.statusText = 'saved'
|
this.statusText = 'saved'
|
||||||
this.updated = +new Date
|
this.updated = +new Date
|
||||||
|
this.lastInteractionTimestamp = +new Date
|
||||||
this.modified = true
|
this.modified = true
|
||||||
this.diffsApplied = 0
|
this.diffsApplied = 0
|
||||||
|
|
||||||
@ -902,27 +939,35 @@
|
|||||||
},
|
},
|
||||||
checkForUpdatedNote(){
|
checkForUpdatedNote(){
|
||||||
|
|
||||||
//Ignore visibility changes, handle this with socket IO
|
const now = +new Date
|
||||||
//Just keep it always up to date if user is on note
|
//Only check every 3 seconds
|
||||||
return
|
const checkForUpdateTimeout = now - this.lastInteractionTimestamp > (2 * 1000)
|
||||||
|
|
||||||
//If user leaves page then returns to page, reload the first batch
|
//If user leaves page then returns to page, reload the first batch
|
||||||
if(this.lastVisibilityState == 'hidden' && document.visibilityState == 'visible'){
|
if(this.lastVisibilityState == 'hidden' && document.visibilityState == 'visible' && checkForUpdateTimeout){
|
||||||
// console.log('Checking for note updates after visibility change.')
|
|
||||||
|
//Focus Regained on Note, check for update
|
||||||
|
axios.post('/api/note/get', { 'noteId': this.noteid })
|
||||||
|
.then(response => {
|
||||||
|
|
||||||
const postData = {
|
const serverTextHash = this.hashString( response.data.text )
|
||||||
noteId:this.currentNoteId,
|
|
||||||
text:this.getText(),
|
if(this.lastNoteHash != serverTextHash){
|
||||||
updated: this.updated
|
// console.log('note was changed UPDATE THAT BITCH!!!!')
|
||||||
}
|
this.setupLoadedNoteData(response)
|
||||||
|
|
||||||
|
//Manually set squire text to show
|
||||||
|
this.setText(this.noteText)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
console.log('Focus regained with note open.')
|
|
||||||
console.log('Attempting to fix diff text. fix this. Search spleen')
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Track visibility state
|
//Keep track of visibility change and last interaction time
|
||||||
this.lastVisibilityState = document.visibilityState
|
this.lastVisibilityState = document.visibilityState
|
||||||
|
this.lastInteractionTimestamp = +new Date
|
||||||
|
|
||||||
},
|
},
|
||||||
hashString(inText){
|
hashString(inText){
|
||||||
|
|
||||||
@ -1040,6 +1085,33 @@
|
|||||||
|
|
||||||
<style type="text/css" scoped>
|
<style type="text/css" scoped>
|
||||||
|
|
||||||
|
.status-menu {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
z-index: 1019;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-color-bar {
|
||||||
|
/*width: calc(100% - 8px);*/
|
||||||
|
height: 3px;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 2px;
|
||||||
|
right: 4px;
|
||||||
|
left: 4px;
|
||||||
|
z-index: 0;
|
||||||
|
background: linear-gradient(
|
||||||
|
45deg,
|
||||||
|
rgba(255, 0, 0, 1) 0%,
|
||||||
|
rgba(208, 222, 33, 1) 20%,
|
||||||
|
rgba(63, 218, 216, 1) 40%,
|
||||||
|
rgba(28, 127, 238, 1) 60%,
|
||||||
|
rgba(186, 12, 248, 1) 80%,
|
||||||
|
rgba(255, 0, 0, 1) 100%
|
||||||
|
);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.large-close-button {
|
.large-close-button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
min-height: 55px;
|
min-height: 55px;
|
||||||
@ -1094,6 +1166,7 @@
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
max-width: 1100px;
|
max-width: 1100px;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.add-mini-tag {
|
.add-mini-tag {
|
||||||
color: var(--border_color);
|
color: var(--border_color);
|
||||||
@ -1128,7 +1201,7 @@
|
|||||||
display: block;
|
display: block;
|
||||||
background-color: var(--small_element_bg_color);
|
background-color: var(--small_element_bg_color);
|
||||||
z-index: 1019;
|
z-index: 1019;
|
||||||
padding: 3px 5px;
|
padding: 5px 0;
|
||||||
border: none;
|
border: none;
|
||||||
border-bottom: 1px solid var(--menu-accent);
|
border-bottom: 1px solid var(--menu-accent);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -1140,10 +1213,24 @@
|
|||||||
background-color: var(--small_element_bg_color);
|
background-color: var(--small_element_bg_color);
|
||||||
color: var(--menu-text);
|
color: var(--menu-text);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 1.4em;
|
|
||||||
padding: 4px 1px 5px 4px;
|
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
font-size: 1.4em;
|
||||||
|
box-shadow: 0 0 1px 0 #c4c4c4;
|
||||||
|
margin: 0 3px 0;
|
||||||
|
padding: 6px 0 0 0;
|
||||||
|
text-align: center;
|
||||||
|
min-width: 32px;
|
||||||
|
min-height: 32px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.edit-button > i {
|
||||||
|
font-size: 1em;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.edit-button > span {
|
||||||
|
padding: 0 8px;
|
||||||
}
|
}
|
||||||
.edit-button:hover {
|
.edit-button:hover {
|
||||||
background-color: var(--menu-accent);
|
background-color: var(--menu-accent);
|
||||||
@ -1157,7 +1244,7 @@
|
|||||||
background-color: var(--menu-accent);
|
background-color: var(--menu-accent);
|
||||||
height: 15px;
|
height: 15px;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
margin: 0 1px;
|
margin: 0 8px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
@media only screen and (max-width: 740px) {
|
@media only screen and (max-width: 740px) {
|
||||||
@ -1253,7 +1340,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 35px;
|
top: 35px;
|
||||||
bottom: 40px;
|
bottom: 37px;
|
||||||
background-color: var(--small_element_bg_color);
|
background-color: var(--small_element_bg_color);
|
||||||
}
|
}
|
||||||
.note-wrapper {
|
.note-wrapper {
|
||||||
@ -1263,6 +1350,9 @@
|
|||||||
.shade1, .shade2 {
|
.shade1, .shade2 {
|
||||||
right: 150%;
|
right: 150%;
|
||||||
}
|
}
|
||||||
|
.edit-menu {
|
||||||
|
background-color: var(--dark_border_color);
|
||||||
|
}
|
||||||
/*menu overwrites */
|
/*menu overwrites */
|
||||||
.bottom-edit-menu {
|
.bottom-edit-menu {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@ -1271,14 +1361,19 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
background-color: var(--small_element_bg_color);
|
/*background-color: var(--small_element_bg_color);*/
|
||||||
|
background-color: var(--dark_border_color);
|
||||||
z-index: 1012;
|
z-index: 1012;
|
||||||
border: none;
|
border: none;
|
||||||
border-top: 1px solid var(--menu-accent);
|
border-top: 1px solid var(--menu-accent);
|
||||||
min-height: 40px;
|
min-height: 37px;
|
||||||
}
|
}
|
||||||
.edit-menu {
|
.menu-top-half, .menu-bottom-half {
|
||||||
text-align: center;
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
.edit-divide {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
.menu-bottom-half {
|
.menu-bottom-half {
|
||||||
z-index: 1005;
|
z-index: 1005;
|
||||||
@ -1288,6 +1383,14 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
.edit-button {
|
||||||
|
flex-basis: 100%;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
.done-button {
|
||||||
|
flex-basis: 150%;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="note-title-display-card"
|
<div class="note-title-display-card"
|
||||||
:style="{'background-color':color, 'color':fontColor, 'border-color':color }"
|
:style="{'background-color':color, 'color':fontColor, 'border-color':color }"
|
||||||
:class="{'currently-open':(currentlyOpen || showWorking), 'bgboy':triggerClosedAnimation, 'title-view':titleView }"
|
:class="{
|
||||||
>
|
'currently-open':(currentlyOpen || showWorking),
|
||||||
|
'ring':triggerClosedAnimation,
|
||||||
|
'title-view':titleView
|
||||||
|
}">
|
||||||
|
|
||||||
|
|
||||||
<!-- Show title and snippet below it -->
|
<!-- Show title and snippet below it -->
|
||||||
@ -75,8 +78,15 @@
|
|||||||
<span class="thin-title" v-if="note.title.length > 0">{{ note.title }}</span>
|
<span class="thin-title" v-if="note.title.length > 0">{{ note.title }}</span>
|
||||||
|
|
||||||
<!-- snippet -->
|
<!-- snippet -->
|
||||||
<span class="thin-sub" v-if="note.subtext.length > 0">{{ removeHtml(note.subtext) }}</span>
|
<span class="thick-sub" v-if="note.subtext.length > 0 && note.title.length == 0">
|
||||||
<span v-if="note.title.length == 0 && removeHtml(note.subtext).length == 0">Empty Note</span>
|
{{ removeHtml(note.subtext) }}
|
||||||
|
</span>
|
||||||
|
<span class="thin-sub" v-else-if="note.subtext.length > 0">
|
||||||
|
{{ removeHtml(note.subtext) }}
|
||||||
|
</span>
|
||||||
|
<span v-else-if="note.title.length == 0 && removeHtml(note.subtext).length == 0">
|
||||||
|
Empty Note
|
||||||
|
</span>
|
||||||
|
|
||||||
<!-- tags -->
|
<!-- tags -->
|
||||||
<span v-if="note.tags" class="thin-tags" >
|
<span v-if="note.tags" class="thin-tags" >
|
||||||
@ -280,7 +290,7 @@
|
|||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
//After 3 seconds, hide it
|
//After 3 seconds, hide it
|
||||||
this.triggerClosedAnimation = false
|
this.triggerClosedAnimation = false
|
||||||
}, 3000)
|
}, 1500)
|
||||||
|
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|
||||||
@ -472,7 +482,7 @@
|
|||||||
max-width: none;
|
max-width: none;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
overflow: hidden;
|
/*overflow: hidden;*/
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
border: none;
|
border: none;
|
||||||
/*box-shadow: 0px 0px 1px 1px rgba(210, 211, 211, 0.46);*/
|
/*box-shadow: 0px 0px 1px 1px rgba(210, 211, 211, 0.46);*/
|
||||||
@ -498,8 +508,17 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
-webkit-line-clamp: 2;
|
-webkit-line-clamp: 1;
|
||||||
line-clamp: 2;
|
line-clamp: 1;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
.thin-container .thick-sub {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
line-clamp: 3;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
opacity: 0.85;
|
opacity: 0.85;
|
||||||
}
|
}
|
||||||
@ -700,4 +719,36 @@
|
|||||||
animation: bgin 4s cubic-bezier(0.19, 1, 0.22, 1) 1;
|
animation: bgin 4s cubic-bezier(0.19, 1, 0.22, 1) 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*switch between ring or BG boy to change save animation*/
|
||||||
|
|
||||||
|
.ring {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.ring::after {
|
||||||
|
content: '';
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 100%;
|
||||||
|
border: 6px solid #00FFCB;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 800;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
animation: ring 1.5s 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ring {
|
||||||
|
0% {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
width: 420px;
|
||||||
|
height: 420px;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -2,22 +2,43 @@
|
|||||||
.colors {
|
.colors {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 1023;
|
z-index: 1023;
|
||||||
top: 5px;
|
top: 35px;
|
||||||
/*height: 100px;*/
|
/*height: 100px;*/
|
||||||
width: 400px;
|
width: 400px;
|
||||||
left: 20%;
|
left: 20%;
|
||||||
}
|
}
|
||||||
.colors-container {
|
.colors-container {
|
||||||
max-width: 370px;
|
/*max-width: 360px;*/
|
||||||
|
display: flex;
|
||||||
|
/*flex-direction: column;*/
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: stretch;
|
||||||
|
align-content: stretch;
|
||||||
|
|
||||||
|
height: 250px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
.dot {
|
.dot {
|
||||||
display: inline-block;
|
/*display: inline-block;*/
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
border-radius: 30px;
|
border-radius: 30px;
|
||||||
box-shadow: 0px 1px 3px 0px #3e3e3e;
|
box-shadow: 0px 0px 0px 1px inset #3e3e3e;
|
||||||
margin: 7px 7px 0 0;
|
margin: 0 0 2px 2px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
flex-basis: 9%;
|
||||||
|
height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.dot > i {
|
||||||
|
margin: 9px 0 0 0;
|
||||||
|
color: white;
|
||||||
|
text-shadow:
|
||||||
|
1px 1px 2px #3e3e3e,
|
||||||
|
1px -1px 2px #3e3e3e,
|
||||||
|
-1px 1px 2px #3e3e3e,
|
||||||
|
-1px -1px 2px #3e3e3e
|
||||||
|
;
|
||||||
}
|
}
|
||||||
.shade {
|
.shade {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@ -30,12 +51,16 @@
|
|||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
.big-shadow {
|
||||||
|
box-shadow: 0px 4px 5px 1px #a8a8a8;
|
||||||
|
}
|
||||||
@media only screen and (max-width: 740px) {
|
@media only screen and (max-width: 740px) {
|
||||||
.colors {
|
.colors {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: 5px;
|
||||||
right: 0;
|
right: -5px;
|
||||||
top: 0;
|
top: 5px;
|
||||||
|
width: 95%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -43,13 +68,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="colors">
|
<div class="colors">
|
||||||
<div class="ui raised segment">
|
<div class="ui segment big-shadow">
|
||||||
|
<h3>Select Text Color</h3>
|
||||||
<div class="colors-container">
|
<div class="colors-container">
|
||||||
<span
|
<span
|
||||||
v-for="(color,index) in colors"
|
v-for="(color,index) in colors"
|
||||||
class="dot"
|
class="dot"
|
||||||
v-on:click="onColorClick(index)"
|
v-on:click="onColorClick(index)"
|
||||||
:style="`background-color: ${color};`">
|
:style="`background-color: ${color};`">
|
||||||
|
<i v-if="lastUsedColor == color" class="check icon"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -65,6 +92,7 @@
|
|||||||
components:{
|
components:{
|
||||||
'nm-button':require('@/components/NoteMenuButtonComponent.vue').default
|
'nm-button':require('@/components/NoteMenuButtonComponent.vue').default
|
||||||
},
|
},
|
||||||
|
props: [ 'lastUsedColor' ],
|
||||||
data: function(){
|
data: function(){
|
||||||
return {
|
return {
|
||||||
hover: false,
|
hover: false,
|
||||||
|
@ -9,6 +9,8 @@ const SquireButtonFunctions = {
|
|||||||
activeList: false,
|
activeList: false,
|
||||||
activeToDo: false,
|
activeToDo: false,
|
||||||
activeColor: null,
|
activeColor: null,
|
||||||
|
activeCode: false,
|
||||||
|
activeSubTitle: false,
|
||||||
//
|
//
|
||||||
lastUsedColor: null,
|
lastUsedColor: null,
|
||||||
}
|
}
|
||||||
@ -28,6 +30,8 @@ const SquireButtonFunctions = {
|
|||||||
this.activeToDo = false
|
this.activeToDo = false
|
||||||
this.activeColor = null
|
this.activeColor = null
|
||||||
this.activeUnderline = false
|
this.activeUnderline = false
|
||||||
|
this.activeCode = false
|
||||||
|
this.activeSubTitle = false
|
||||||
|
|
||||||
if(e.path.indexOf('>U>') > -1 || e.path.search(/U$/) > -1){
|
if(e.path.indexOf('>U>') > -1 || e.path.search(/U$/) > -1){
|
||||||
this.activeUnderline = true
|
this.activeUnderline = true
|
||||||
@ -38,15 +42,21 @@ const SquireButtonFunctions = {
|
|||||||
if(e.path.indexOf('>I') > -1){
|
if(e.path.indexOf('>I') > -1){
|
||||||
this.activeItalics = true
|
this.activeItalics = true
|
||||||
}
|
}
|
||||||
if(e.path.indexOf('fontSize') > -1){
|
if(e.path.indexOf('fontSize=1.4em') > -1){
|
||||||
this.activeTitle = true
|
this.activeTitle = true
|
||||||
}
|
}
|
||||||
|
if(e.path.indexOf('fontSize=0.9em') > -1){
|
||||||
|
this.activeSubTitle = true
|
||||||
|
}
|
||||||
if(e.path.indexOf('OL>LI') > -1){
|
if(e.path.indexOf('OL>LI') > -1){
|
||||||
this.activeList = true
|
this.activeList = true
|
||||||
}
|
}
|
||||||
if(e.path.indexOf('UL>LI') > -1){
|
if(e.path.indexOf('UL>LI') > -1){
|
||||||
this.activeToDo = true
|
this.activeToDo = true
|
||||||
}
|
}
|
||||||
|
if(e.path.indexOf('CODE') > -1){
|
||||||
|
this.activeCode= true
|
||||||
|
}
|
||||||
const colorIndex = e.path.indexOf('color=')
|
const colorIndex = e.path.indexOf('color=')
|
||||||
if(colorIndex > -1){
|
if(colorIndex > -1){
|
||||||
//Get all digigs after color index, then limit to 3
|
//Get all digigs after color index, then limit to 3
|
||||||
@ -143,6 +153,12 @@ const SquireButtonFunctions = {
|
|||||||
this.editor.italic()
|
this.editor.italic()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
modifyCode(){
|
||||||
|
|
||||||
|
this.selectLineIfNoSelect()
|
||||||
|
|
||||||
|
this.editor.toggleCode()
|
||||||
|
},
|
||||||
undoCustom(){
|
undoCustom(){
|
||||||
//The same as pressing CTRL + Z
|
//The same as pressing CTRL + Z
|
||||||
// this.editor.focus()
|
// this.editor.focus()
|
||||||
|
@ -26,6 +26,10 @@
|
|||||||
:active-tags="searchTags"
|
:active-tags="searchTags"
|
||||||
v-on:tagClick="tagId => toggleTagFilter(tagId)"
|
v-on:tagClick="tagId => toggleTagFilter(tagId)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
Active Sessions {{ $store.getters.getActiveSessions }}
|
||||||
|
</span>
|
||||||
|
|
||||||
<div class="ui right floated basic shrinking icon button" v-on:click="toggleTitleView()" v-if="$store.getters.totals && $store.getters.totals['totalNotes'] > 0">
|
<div class="ui right floated basic shrinking icon button" v-on:click="toggleTitleView()" v-if="$store.getters.totals && $store.getters.totals['totalNotes'] > 0">
|
||||||
<span v-if="titleView">
|
<span v-if="titleView">
|
||||||
@ -51,7 +55,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sixteen wide column" v-if="searchTerm.length > 0 && !loadingInProgress">
|
<div class="sixteen wide column" v-if="searchTerm.length > 0 && !showLoading">
|
||||||
<h2 class="ui header">
|
<h2 class="ui header">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{{ searchResultsCount.toLocaleString() }} notes with keyword "{{ searchTerm }}"
|
{{ searchResultsCount.toLocaleString() }} notes with keyword "{{ searchTerm }}"
|
||||||
@ -63,11 +67,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="fastFilters['onlyArchived'] == 1" class="sixteen wide column">
|
<div v-if="fastFilters['onlyArchived'] == 1" class="sixteen wide column">
|
||||||
<h2>Archived Notes</h2>
|
<h2>
|
||||||
|
<i class="green archive icon"></i>
|
||||||
|
Archived Notes</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sixteen wide column" v-if="fastFilters['onlyShowTrashed'] == 1">
|
<div class="sixteen wide column" v-if="fastFilters['onlyShowTrashed'] == 1">
|
||||||
<h2>Trash
|
<h2>
|
||||||
|
<i class="green trash alternate outline icon"></i>
|
||||||
|
Trashed Notes
|
||||||
<span>({{ $store.getters.totals['trashedNotes'] }})</span>
|
<span>({{ $store.getters.totals['trashedNotes'] }})</span>
|
||||||
<div class="ui right floated basic button" data-tooltip="This doesn't work yet">
|
<div class="ui right floated basic button" data-tooltip="This doesn't work yet">
|
||||||
<i class="poo storm icon"></i>
|
<i class="poo storm icon"></i>
|
||||||
@ -77,7 +85,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sixteen wide column" v-if="fastFilters['onlyShowSharedNotes'] == 1">
|
<div class="sixteen wide column" v-if="fastFilters['onlyShowSharedNotes'] == 1">
|
||||||
<h2>Shared Notes</h2>
|
<h2><i class="green paper plane outline icon"></i>
|
||||||
|
Shared Notes</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sixteen wide column" v-if="tagSuggestions.length > 0">
|
<div class="sixteen wide column" v-if="tagSuggestions.length > 0">
|
||||||
@ -88,17 +97,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- found attachments -->
|
|
||||||
<div class="sixteen wide column" v-if="foundAttachments.length > 0">
|
|
||||||
<h5 class="ui tiny dividing header"><i class="green folder open outline icon"></i> Files ({{ foundAttachments.length }})</h5>
|
|
||||||
<attachment-display
|
|
||||||
v-for="item in foundAttachments"
|
|
||||||
:item="item"
|
|
||||||
:key="item.id"
|
|
||||||
:search-params="{}"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Note title card display -->
|
<!-- Note title card display -->
|
||||||
<div class="sixteen wide column">
|
<div class="sixteen wide column">
|
||||||
|
|
||||||
@ -130,11 +128,25 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<loading-icon v-if="loadingInProgress" message="Decrypting Notes" />
|
<div class="loading-section" v-if="showLoading">
|
||||||
|
<loading-icon message="Decrypting Notes" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- found attachments -->
|
||||||
|
<div class="sixteen wide column" v-if="foundAttachments.length > 0">
|
||||||
|
<h5 class="ui tiny dividing header"><i class="green folder open outline icon"></i> Files ({{ foundAttachments.length }})</h5>
|
||||||
|
<attachment-display
|
||||||
|
v-for="item in foundAttachments"
|
||||||
|
:item="item"
|
||||||
|
:key="item.id"
|
||||||
|
:search-params="{}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@ -180,10 +192,10 @@
|
|||||||
|
|
||||||
//Load up notes in batches
|
//Load up notes in batches
|
||||||
firstLoadBatchSize: 10, //First set of rapidly loaded notes
|
firstLoadBatchSize: 10, //First set of rapidly loaded notes
|
||||||
batchSize: 25, //Size of batch loaded when user scrolls through current batch
|
batchSize: 20, //Size of batch loaded when user scrolls through current batch
|
||||||
batchOffset: 0, //Tracks the current batch that has been loaded
|
batchOffset: 0, //Tracks the current batch that has been loaded
|
||||||
loadingBatchTimeout: null, //Limit how quickly batches can be loaded
|
loadingBatchTimeout: null, //Limit how quickly batches can be loaded
|
||||||
loadingInProgress: false,
|
showLoading: false,
|
||||||
scrollLoadEnabled: true,
|
scrollLoadEnabled: true,
|
||||||
|
|
||||||
//Clear button is not visible
|
//Clear button is not visible
|
||||||
@ -329,7 +341,7 @@
|
|||||||
|
|
||||||
//Reload page content - don't trigger if load is in progress
|
//Reload page content - don't trigger if load is in progress
|
||||||
this.$bus.$on('note_reload', () => {
|
this.$bus.$on('note_reload', () => {
|
||||||
if(!this.loadingInProgress){
|
if(!this.showLoading){
|
||||||
this.reset()
|
this.reset()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -342,6 +354,8 @@
|
|||||||
//update note on visibility change
|
//update note on visibility change
|
||||||
// document.addEventListener('visibilitychange', this.visibiltyChangeAction);
|
// document.addEventListener('visibilitychange', this.visibiltyChangeAction);
|
||||||
|
|
||||||
|
//Find previously stored notes, cache for 20 hours, load them and compare
|
||||||
|
|
||||||
},
|
},
|
||||||
beforeDestroy(){
|
beforeDestroy(){
|
||||||
window.removeEventListener('scroll', this.onScroll)
|
window.removeEventListener('scroll', this.onScroll)
|
||||||
@ -373,12 +387,29 @@
|
|||||||
'$route.params.id': function(id){
|
'$route.params.id': function(id){
|
||||||
//Open note on ID, null id will close note
|
//Open note on ID, null id will close note
|
||||||
this.activeNoteId1 = id
|
this.activeNoteId1 = id
|
||||||
|
},
|
||||||
|
'$route' (to, from) {
|
||||||
|
|
||||||
|
|
||||||
|
// Reload the notes if returning to this page
|
||||||
|
if(to.fullPath == '/notes' && !from.fullPath.includes('/notes/open/')){
|
||||||
|
|
||||||
|
this.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
//Lookup tags set in URL
|
||||||
|
if(to.params.tag && this.$store.getters.totals && this.$store.getters.totals['tags'][to.params.tag]){
|
||||||
|
|
||||||
|
//Lookup tag in store by string
|
||||||
|
const tagObject = this.$store.getters.totals['tags'][to.params.tag]
|
||||||
|
|
||||||
|
//Pull key out of string and load tags for that key
|
||||||
|
this.toggleTagFilter(tagObject.id)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onScroll(e){
|
|
||||||
console.log('Scroll')
|
|
||||||
},
|
|
||||||
toggleTitleView(){
|
toggleTitleView(){
|
||||||
this.titleView = !this.titleView
|
this.titleView = !this.titleView
|
||||||
},
|
},
|
||||||
@ -418,6 +449,10 @@
|
|||||||
},
|
},
|
||||||
onScroll(e){
|
onScroll(e){
|
||||||
|
|
||||||
|
if(!this.scrollLoadEnabled){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
clearTimeout(this.loadingBatchTimeout)
|
clearTimeout(this.loadingBatchTimeout)
|
||||||
this.loadingBatchTimeout = setTimeout(() => {
|
this.loadingBatchTimeout = setTimeout(() => {
|
||||||
|
|
||||||
@ -427,12 +462,12 @@
|
|||||||
const height = document.getElementById('app').scrollHeight
|
const height = document.getElementById('app').scrollHeight
|
||||||
|
|
||||||
//Load if less than 500px from the bottom
|
//Load if less than 500px from the bottom
|
||||||
if(((height - scrolledDown) < 500) && this.scrollLoadEnabled && !this.loadingInProgress){
|
if(((height - scrolledDown) < 500) && this.scrollLoadEnabled){
|
||||||
|
|
||||||
this.search(false, this.batchSize, true)
|
this.search(true, this.batchSize, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
}, 30)
|
}, 50)
|
||||||
|
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -553,19 +588,14 @@
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
//Don't double load note batches
|
//Don't double load note batches
|
||||||
if(this.loadingInProgress){
|
if(this.showLoading){
|
||||||
console.log('Loading already in progress')
|
console.log('Loading already in progress')
|
||||||
return resolve(false)
|
return resolve(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Reset a lot of stuff if we are not merging batches
|
|
||||||
if(!mergeExisting){
|
if(!mergeExisting){
|
||||||
Object.keys(this.noteSections).forEach( key => {
|
this.batchOffset = 0 // Reset batch offset if we are not merging note batches or new set will be offset from current and overwrite current set with second batch
|
||||||
this.noteSections[key] = []
|
|
||||||
})
|
|
||||||
this.batchOffset = 0 // Reset batch offset if we are not merging note batches
|
|
||||||
}
|
}
|
||||||
this.searchResultsCount = 0
|
|
||||||
|
|
||||||
//Remove all filter limits from previous queries
|
//Remove all filter limits from previous queries
|
||||||
delete this.fastFilters.limitSize
|
delete this.fastFilters.limitSize
|
||||||
@ -593,25 +623,40 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Perform search - or die
|
//Perform search - or die
|
||||||
this.loadingInProgress = true
|
this.showLoading = showLoading
|
||||||
|
this.scrollLoadEnabled = false
|
||||||
axios.post('/api/note/search', postData)
|
axios.post('/api/note/search', postData)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
|
||||||
|
//Reset a lot of stuff if we are not merging batches
|
||||||
|
if(!mergeExisting){
|
||||||
|
Object.keys(this.noteSections).forEach( key => {
|
||||||
|
this.noteSections[key] = []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.searchResultsCount = 0
|
||||||
|
|
||||||
// console.timeEnd('Fetch TitleCard Batch '+notesInNextLoad)
|
// console.timeEnd('Fetch TitleCard Batch '+notesInNextLoad)
|
||||||
|
|
||||||
//Save the number of notes just loaded
|
//Save the number of notes just loaded
|
||||||
this.batchOffset += response.data.notes.length
|
this.batchOffset += response.data.notes.length
|
||||||
|
|
||||||
//Enable or disable scroll loading
|
//Enable scroll loading if endpoint retured notes
|
||||||
this.scrollLoadEnabled = response.data.notes.length > 0
|
this.scrollLoadEnabled = response.data.notes.length > 0
|
||||||
|
|
||||||
if(response.data.total > 0){
|
if(response.data.total > 0){
|
||||||
this.searchResultsCount = response.data.total
|
this.searchResultsCount = response.data.total
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadingInProgress = false
|
this.showLoading = false
|
||||||
this.generateNoteCategories(response.data.notes, mergeExisting)
|
this.generateNoteCategories(response.data.notes, mergeExisting)
|
||||||
|
|
||||||
|
//cache initial notes for faster reloads
|
||||||
|
if(!mergeExisting && this.showClear == false){
|
||||||
|
const cachedNotesJson = JSON.stringify(response.data.notes)
|
||||||
|
localStorage.setItem('snippetCache', cachedNotesJson)
|
||||||
|
}
|
||||||
|
|
||||||
return resolve(true)
|
return resolve(true)
|
||||||
})
|
})
|
||||||
.catch(error => { this.$bus.$emit('notification', 'Failed to Search Notes') })
|
.catch(error => { this.$bus.$emit('notification', 'Failed to Search Notes') })
|
||||||
@ -726,7 +771,7 @@
|
|||||||
//clear out tags
|
//clear out tags
|
||||||
this.searchTags = []
|
this.searchTags = []
|
||||||
this.tagSuggestions = []
|
this.tagSuggestions = []
|
||||||
this.loadingInProgress = false
|
this.showLoading = false
|
||||||
this.searchTerm = ''
|
this.searchTerm = ''
|
||||||
this.$bus.$emit('reset_fast_filters') //Clear out search
|
this.$bus.$emit('reset_fast_filters') //Clear out search
|
||||||
|
|
||||||
@ -743,9 +788,21 @@
|
|||||||
filter[options[index]] = 1
|
filter[options[index]] = 1
|
||||||
|
|
||||||
this.fastFilters = filter
|
this.fastFilters = filter
|
||||||
|
|
||||||
|
//If notes exist in cache, load them up
|
||||||
|
let showLoading = true
|
||||||
|
const cachedNotesJson = localStorage.getItem('snippetCache')
|
||||||
|
const cachedNotes = JSON.parse(cachedNotesJson)
|
||||||
|
if(cachedNotes && cachedNotes.length > 0 && !this.showClear){
|
||||||
|
|
||||||
|
//Load cache. do not merge existing
|
||||||
|
this.generateNoteCategories(cachedNotes, false)
|
||||||
|
showLoading = false
|
||||||
|
}
|
||||||
|
|
||||||
//Fetch First batch of notes with new filter
|
//Fetch First batch of notes with new filter
|
||||||
this.search(true, this.firstLoadBatchSize, false)
|
this.search(showLoading, this.batchSize, false)
|
||||||
.then( r => this.search(false, this.batchSize, true))
|
// .then( r => this.search(false, this.batchSize, true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -769,4 +826,35 @@
|
|||||||
.note-card-section + .note-card-section {
|
.note-card-section + .note-card-section {
|
||||||
padding: 15px 0 0;
|
padding: 15px 0 0;
|
||||||
}
|
}
|
||||||
|
.loading-section {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 40px;
|
||||||
|
padding: 0 10px;
|
||||||
|
right: 5px;
|
||||||
|
box-shadow: 0 1px 3px 0 #656565;
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: var(--small_element_bg_color);
|
||||||
|
opacity: 0.9;
|
||||||
|
font-size: 0.7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*html, body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -43,6 +43,12 @@ export default new Router({
|
|||||||
meta: {title: 'Open Note'},
|
meta: {title: 'Open Note'},
|
||||||
component: NotesPage,
|
component: NotesPage,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/search/tags/:tag',
|
||||||
|
name: 'Search Notes',
|
||||||
|
meta: {title: 'Search Notes'},
|
||||||
|
component: NotesPage,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/notes/open/:id/menu/:openMenu',
|
path: '/notes/open/:id/menu/:openMenu',
|
||||||
name: 'Open Note Menu',
|
name: 'Open Note Menu',
|
||||||
|
@ -10,6 +10,7 @@ export default new Vuex.Store({
|
|||||||
nightMode: false,
|
nightMode: false,
|
||||||
isUserOnMobile: false,
|
isUserOnMobile: false,
|
||||||
userTotals: null,
|
userTotals: null,
|
||||||
|
activeSessions: 0,
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
setUsername(state, username){
|
setUsername(state, username){
|
||||||
@ -24,6 +25,7 @@ export default new Vuex.Store({
|
|||||||
localStorage.removeItem('loginToken')
|
localStorage.removeItem('loginToken')
|
||||||
localStorage.removeItem('username')
|
localStorage.removeItem('username')
|
||||||
localStorage.removeItem('currentVersion')
|
localStorage.removeItem('currentVersion')
|
||||||
|
localStorage.removeItem('snippetCache')
|
||||||
delete axios.defaults.headers.common['authorizationtoken']
|
delete axios.defaults.headers.common['authorizationtoken']
|
||||||
state.username = null
|
state.username = null
|
||||||
state.userTotals = null
|
state.userTotals = null
|
||||||
@ -119,6 +121,10 @@ export default new Vuex.Store({
|
|||||||
// Object.keys(totalsObject).forEach( key => {
|
// Object.keys(totalsObject).forEach( key => {
|
||||||
// console.log(key + ' -- ' + totalsObject[key])
|
// console.log(key + ' -- ' + totalsObject[key])
|
||||||
// })
|
// })
|
||||||
|
},
|
||||||
|
setActiveSessions(state, countData){
|
||||||
|
//Count of the number of active socket.io sessions for this user
|
||||||
|
state.activeSessions = countData
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
@ -144,6 +150,9 @@ export default new Vuex.Store({
|
|||||||
totals: state => {
|
totals: state => {
|
||||||
return state.userTotals
|
return state.userTotals
|
||||||
},
|
},
|
||||||
|
getActiveSessions: state => {
|
||||||
|
return state.activeSessions
|
||||||
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
fetchAndUpdateUserTotals ({ commit }) {
|
fetchAndUpdateUserTotals ({ commit }) {
|
||||||
|
@ -51,12 +51,31 @@ io.on('connection', function(socket){
|
|||||||
Auth.decodeToken(token)
|
Auth.decodeToken(token)
|
||||||
.then(userData => {
|
.then(userData => {
|
||||||
socket.join(userData.userId)
|
socket.join(userData.userId)
|
||||||
|
|
||||||
|
//Track active logged in user accounts
|
||||||
|
const usersInRoom = io.sockets.adapter.rooms[userData.userId]
|
||||||
|
io.to(userData.userId).emit('update_active_user_count', usersInRoom.length)
|
||||||
|
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
//Don't add user to room if they are not logged in
|
//Don't add user to room if they are not logged in
|
||||||
// console.log(error)
|
// console.log(error)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
socket.on('get_active_user_count', token => {
|
||||||
|
Auth.decodeToken(token)
|
||||||
|
.then(userData => {
|
||||||
|
socket.join(userData.userId)
|
||||||
|
|
||||||
|
//Track active logged in user accounts
|
||||||
|
const usersInRoom = io.sockets.adapter.rooms[userData.userId]
|
||||||
|
io.to(userData.userId).emit('update_active_user_count', usersInRoom.length)
|
||||||
|
|
||||||
|
}).catch(error => {
|
||||||
|
// console.log(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
//Renew Session tokens when users request a new one
|
//Renew Session tokens when users request a new one
|
||||||
socket.on('renew_session_token', token => {
|
socket.on('renew_session_token', token => {
|
||||||
|
|
||||||
@ -205,7 +224,7 @@ io.on('connection', function(socket){
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on('disconnect', function(){
|
socket.on('disconnect', function(socket){
|
||||||
// console.log('user disconnected');
|
// console.log('user disconnected');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,7 @@ const speakeasy = require('speakeasy')
|
|||||||
|
|
||||||
let User = module.exports = {}
|
let User = module.exports = {}
|
||||||
|
|
||||||
const version = '3.3.3'
|
const version = '3.4.2'
|
||||||
|
|
||||||
//Login a user, if that user does not exist create them
|
//Login a user, if that user does not exist create them
|
||||||
//Issues login token
|
//Issues login token
|
||||||
@ -196,7 +196,9 @@ User.register = (username, password) => {
|
|||||||
User.getCounts = (userId) => {
|
User.getCounts = (userId) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
let countTotals = {}
|
let countTotals = {
|
||||||
|
tags: {}
|
||||||
|
}
|
||||||
const userHash = cs.hash(String(userId)).toString('base64')
|
const userHash = cs.hash(String(userId)).toString('base64')
|
||||||
|
|
||||||
db.promise().query(
|
db.promise().query(
|
||||||
@ -244,12 +246,37 @@ User.getCounts = (userId) => {
|
|||||||
|
|
||||||
Object.assign(countTotals, rows[0][0]) //combine results
|
Object.assign(countTotals, rows[0][0]) //combine results
|
||||||
|
|
||||||
|
//Count usages of user tags, sort by most popular
|
||||||
|
return db.promise().query(`
|
||||||
|
SELECT
|
||||||
|
tag.text, COUNT(tag_id) AS uses, tag.id
|
||||||
|
FROM note_tag
|
||||||
|
JOIN tag ON (tag.id = note_tag.tag_id)
|
||||||
|
WHERE user_id = ?
|
||||||
|
GROUP BY tag_id
|
||||||
|
ORDER BY uses DESC
|
||||||
|
LIMIT 5
|
||||||
|
`, [userId])
|
||||||
|
|
||||||
|
}).then( (rows, fields) => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Convert everything to an int or 0
|
//Convert everything to an int or 0
|
||||||
Object.keys(countTotals).forEach( key => {
|
Object.keys(countTotals).forEach( key => {
|
||||||
const count = parseInt(countTotals[key])
|
const count = parseInt(countTotals[key])
|
||||||
countTotals[key] = count ? count : 0
|
countTotals[key] = count ? count : 0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//Build out tags object
|
||||||
|
let tagsObject = {}
|
||||||
|
rows[0].forEach(tagRow => {
|
||||||
|
tagsObject[tagRow['text']] = {'id':tagRow.id, 'uses':tagRow.uses}
|
||||||
|
})
|
||||||
|
|
||||||
|
//Assign after counts are updated
|
||||||
|
countTotals['tags'] = tagsObject
|
||||||
|
|
||||||
countTotals['currentVersion'] = version
|
countTotals['currentVersion'] = version
|
||||||
|
|
||||||
resolve(countTotals)
|
resolve(countTotals)
|
||||||
|
Loading…
Reference in New Issue
Block a user