Adding everything to get started on cycle tracking and maybe avid habit clone
This commit is contained in:
parent
77cd95fdcb
commit
b51e5ac0d0
28
client/certs/192.168.1.164+4-key.pem
Normal file
28
client/certs/192.168.1.164+4-key.pem
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC9vBYgeFm2nDnj
|
||||||
|
HJ+Cq4H96adNLrynoFPs0lSxk3YMXG/mP2sXUpqT3P8S7E6QK55IyU0jtiOoYiV1
|
||||||
|
bjcTuDrQyZXrtt+Nz0A7vQxtRu8CatXSEG8Vc3y8QrcDT0HfTezHdNkuJXE8cnYv
|
||||||
|
XSgrZH+cHF996ytOA0lLJWBCHCJH5WIHj5Jziw5dHaLc4mjxSg51xjjqfzLFWQgZ
|
||||||
|
rOPF6lviAWBFux8RIXXg7nClNvEeyikdraZvVuWFgt89KhN/ePU1Xik/o6++evhT
|
||||||
|
HxBZqMQHnTp/4h5T25lPGcs0CPPX0afwNSUdPc8yspuSYNcLsWix3oROLMX6cHBa
|
||||||
|
CTBrtlLzAgMBAAECggEAIBhG7est0dQPfrmCygnVDWyO3mF/jCN0zuStavR0zZZ9
|
||||||
|
X0dvCBzzBPwnMb5Dc+PM/KcAo3/V/E/N4lVof690U4kmER94JXbfeLt79KhBGfmU
|
||||||
|
fdpF0C0e9oGaj7bCf9GgsgS0EDhJNV5vW4e4mc6AP5oVFSnIw4OOzGVgKQ61Rc/e
|
||||||
|
vaalAEz7xGbsYYh2Y43tFnNA6g/qOzs+H8e2Uv+G9mxx7EID1MG3txJJCBpeUeN5
|
||||||
|
JbHQe254IBy4Ko3+i5Tq3ziYL3WyyElCwK5PiRtAP7WNL5AqFT6Fn4L2fULwkTKL
|
||||||
|
sjPSgGxt7QHomeW+12n9bst1mOEmsz0hTGrAtIf1UQKBgQDu1u7BLdTt9H+zaOFl
|
||||||
|
XfhOR3GDZnrIs+F6VuEjdjwNEQLKvOYzGhbgDNRArSETK6f03Jvl7ZC9XYwNC836
|
||||||
|
J29fHsXVcsMJm8fq69PBSdmMXmOpRfjgALu6DYxK1vBqNQ2ToulCwiWoskKEuPUN
|
||||||
|
GwVCc/0HcvwZElWZ1UhsB5Xf9wKBgQDLXfMCtsVpfI15w8qEqRCdrCzprHSitcHJ
|
||||||
|
dCXO72+i9ygMuFtcxo7kgivT0oFUCYmt7Ex+krOlq/xbVLu4sJXWd1FDZ1IeTsIh
|
||||||
|
cuh4IhSOGJR70S4Q/DzbGUQ08Hu+4hrudaw1Y8Fod0wTERCyOIQiWBfKn3Tab3mk
|
||||||
|
X29RdGod5QKBgBig5UHaXgijm79+Yy+2vvIjf9sS6DpmAixBZTno6UxXorgRPpOq
|
||||||
|
bw1vhTueHrkBWXJwhUrycmh0iwqVWwoeoudmHvRhvybwf28EHnPiD6Lf4NsFsiI3
|
||||||
|
MSSAXSUigOwSyHGe7PrLVmLM7vsMr4hIbwRpPYBVJRXYxCb2zV8GcTgFAoGBALiV
|
||||||
|
gWhJNE1We6K1jy9xtF8oU2uU2BiHGGkdPuPgd1dXNca13lcK8c9+RwFv42q/bXOr
|
||||||
|
MpL/3IbW36qV8fzkalvK2LtxIBvaKGHrxgykAjwnGz520nUgPKww9rOGQwsydndR
|
||||||
|
3whmjrme7jGwH5NjsKrrgkyrBojs/V+wL32jSF3xAoGAPLmI5gamjEo9K25ojNxO
|
||||||
|
XjA0fIOxUz/rTPS/qYrxcluXibz8eGXDLq8/D3Q4uWDh18ZQYzWVGoN/x2Qv0srz
|
||||||
|
SHU4AyJo6+asZAe+viOhAtI81B7uM5V4oyEkPaEASPg6+do/to7SFmdcw/XM/p2v
|
||||||
|
KYVXalAeFhW0wJ4I4z6DkuU=
|
||||||
|
-----END PRIVATE KEY-----
|
26
client/certs/192.168.1.164+4.pem
Normal file
26
client/certs/192.168.1.164+4.pem
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEWTCCAsGgAwIBAgIRAPWg+zwqGDC6qPGon1qGS0cwDQYJKoZIhvcNAQELBQAw
|
||||||
|
czEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSQwIgYDVQQLDBttYWJA
|
||||||
|
bWFydmluIChNYXggR2lhbGFuZWxsYSkxKzApBgNVBAMMIm1rY2VydCBtYWJAbWFy
|
||||||
|
dmluIChNYXggR2lhbGFuZWxsYSkwHhcNMjIwNjI2MTgxMDE5WhcNMjQwOTI2MTgx
|
||||||
|
MDE5WjBPMScwJQYDVQQKEx5ta2NlcnQgZGV2ZWxvcG1lbnQgY2VydGlmaWNhdGUx
|
||||||
|
JDAiBgNVBAsMG21hYkBtYXJ2aW4gKE1heCBHaWFsYW5lbGxhKTCCASIwDQYJKoZI
|
||||||
|
hvcNAQEBBQADggEPADCCAQoCggEBAL28FiB4WbacOeMcn4Krgf3pp00uvKegU+zS
|
||||||
|
VLGTdgxcb+Y/axdSmpPc/xLsTpArnkjJTSO2I6hiJXVuNxO4OtDJleu2343PQDu9
|
||||||
|
DG1G7wJq1dIQbxVzfLxCtwNPQd9N7Md02S4lcTxydi9dKCtkf5wcX33rK04DSUsl
|
||||||
|
YEIcIkflYgePknOLDl0dotziaPFKDnXGOOp/MsVZCBms48XqW+IBYEW7HxEhdeDu
|
||||||
|
cKU28R7KKR2tpm9W5YWC3z0qE3949TVeKT+jr756+FMfEFmoxAedOn/iHlPbmU8Z
|
||||||
|
yzQI89fRp/A1JR09zzKym5Jg1wuxaLHehE4sxfpwcFoJMGu2UvMCAwEAAaOBizCB
|
||||||
|
iDAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHwYDVR0jBBgw
|
||||||
|
FoAUzspSlchxoKIVJLKOhPGrcTFjRyowQAYDVR0RBDkwN4IMbWFydmluLmxvY2Fs
|
||||||
|
gglsb2NhbGhvc3SHBMCoAaSHBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZI
|
||||||
|
hvcNAQELBQADggGBAAaTOkCKiVwsapOAuiEt8kG7HS/r4HG+drLzhb2dUFYfqxpz
|
||||||
|
mfRlRfFA88JN8nyFtOPcpoeOEaTPMi0hxq0rOw9zHPga5kz6LRAUJeADPgA4pw2S
|
||||||
|
fYT1CEbPMknmHQyhVODKNZN05l3vWC2CL2SDs9lirGVrzmfg7kZ0im8hc81GQgo+
|
||||||
|
MsfnC3AT1r1rzMqGLWiBHM8BjeGGwgqjjFZmxoHuGw+0CuV2TZfkZlNoJRtlRtyV
|
||||||
|
xlkUuRkVDYbLmHLMz7n9+ItOy8epKLToFpIXyhGR+ehAzYyyJeh2SCaboJ71lU+h
|
||||||
|
+90GQPl20ajWzLtwTsZHEAehHu4l/JLWleNaQh3nVdllHyzvU3IR/C7hhVv6im+q
|
||||||
|
/KiwDR3W8LqIOGJsemca5iu73EXd1d5UU49alIPm1Ko+Z22X/WMPj74+9CNW65DV
|
||||||
|
7ebM17NNQgr4tEJdXF3IYwaZ0Epv1/Y7v6bAXT8V2mdjtXfRBwu3HyySl22a9Y4R
|
||||||
|
h7svqj31cb0ubXEfrA==
|
||||||
|
-----END CERTIFICATE-----
|
@ -290,7 +290,7 @@ i.green.icon.icon.icon.icon {
|
|||||||
border: none;
|
border: none;
|
||||||
/*height: calc(100% - 69px);*/
|
/*height: calc(100% - 69px);*/
|
||||||
|
|
||||||
min-height: 500px;
|
min-height: 300px;
|
||||||
background-color: var(--small_element_bg_color);
|
background-color: var(--small_element_bg_color);
|
||||||
/*margin-bottom: 15px;*/
|
/*margin-bottom: 15px;*/
|
||||||
|
|
||||||
@ -309,6 +309,9 @@ i.green.icon.icon.icon.icon {
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
max-width: 1100px;
|
max-width: 1100px;
|
||||||
|
|
||||||
|
box-shadow: 0 8px 24px rgba(0,0,0,0.1);
|
||||||
|
|
||||||
}
|
}
|
||||||
.squire-box::selection,
|
.squire-box::selection,
|
||||||
.squire-box::-moz-selection {
|
.squire-box::-moz-selection {
|
||||||
@ -372,8 +375,37 @@ i.green.icon.icon.icon.icon {
|
|||||||
.squire-box ol,
|
.squire-box ol,
|
||||||
.note-card-text ul,
|
.note-card-text ul,
|
||||||
.squire-box ul {
|
.squire-box ul {
|
||||||
margin: 8px 0 0 0;
|
margin: 3px 0;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
/* Add border 1 indent level */
|
||||||
|
.note-card-text > ol > ol,
|
||||||
|
.squire-box > ol > ol,
|
||||||
|
.note-card-text > ul > ul,
|
||||||
|
.squire-box > ul > ul
|
||||||
|
{
|
||||||
|
border-left: 1px solid var(--border_color);
|
||||||
|
}
|
||||||
|
.note-card-text ol > ol,
|
||||||
|
.squire-box ol > ol,
|
||||||
|
.note-card-text ul > ul,
|
||||||
|
.squire-box ul > ul {
|
||||||
|
list-style-type: upper-alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ol {
|
||||||
|
counter-reset: item;
|
||||||
|
}
|
||||||
|
ol li {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
ol li:before {
|
||||||
|
content: counters(item, ".") ".";
|
||||||
|
counter-increment: item;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.note-card-text ul > li,
|
.note-card-text ul > li,
|
||||||
.squire-box ul > li {
|
.squire-box ul > li {
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -500,10 +532,6 @@ i.green.icon.icon.icon.icon {
|
|||||||
/* adjust checkboxes for mobile. Make them a little bigger, easier to click */
|
/* adjust checkboxes for mobile. Make them a little bigger, easier to click */
|
||||||
@media only screen and (max-width: 740px) {
|
@media only screen and (max-width: 740px) {
|
||||||
|
|
||||||
.squire-box {
|
|
||||||
min-height: calc(100vh - 122px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ui.button.shrinking {
|
.ui.button.shrinking {
|
||||||
font-size: 0.85714286rem;
|
font-size: 0.85714286rem;
|
||||||
margin: 0 3px;
|
margin: 0 3px;
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
padding: 1em 5px;
|
padding: 1em 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.popup-row > span {
|
.popup-row > p {
|
||||||
/*width: calc(100% - 50px);*/
|
/*width: calc(100% - 50px);*/
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
@ -85,6 +85,18 @@
|
|||||||
animation: progressBar 3s linear;
|
animation: progressBar 3s linear;
|
||||||
animation-fill-mode: both;
|
animation-fill-mode: both;
|
||||||
}
|
}
|
||||||
|
.time-display {
|
||||||
|
display: inline-block;
|
||||||
|
width: calc(100% - 25px);
|
||||||
|
/*text-align: right;*/
|
||||||
|
color: white;
|
||||||
|
font-size: 0.7em;
|
||||||
|
margin: 0 0 0 25px;
|
||||||
|
}
|
||||||
|
.text-display {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes progressBar {
|
@keyframes progressBar {
|
||||||
0% { width: 0; }
|
0% { width: 0; }
|
||||||
@ -101,7 +113,11 @@
|
|||||||
<div class="meter">
|
<div class="meter">
|
||||||
<span><span class="progress"></span></span>
|
<span><span class="progress"></span></span>
|
||||||
</div>
|
</div>
|
||||||
<span><i class="small info circle icon"></i>{{ item }}</span>
|
<p class="text-display">
|
||||||
|
<i class="small info circle icon"></i>
|
||||||
|
{{ item.text }}
|
||||||
|
<span class="time-display">{{ item.time }}</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -119,8 +135,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeMount(){
|
beforeMount(){
|
||||||
this.$bus.$on('notification', info => {
|
this.$bus.$on('notification', notificationText => {
|
||||||
this.displayNotification(info)
|
this.displayNotification(notificationText)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
mounted(){
|
mounted(){
|
||||||
@ -131,8 +147,17 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
displayNotification(newNotification){
|
displayNotification(notificationText){
|
||||||
this.notifications.push(newNotification)
|
|
||||||
|
const date = new Date()
|
||||||
|
const time = date.toLocaleTimeString()
|
||||||
|
|
||||||
|
const notification = {
|
||||||
|
text: notificationText,
|
||||||
|
time: time
|
||||||
|
}
|
||||||
|
|
||||||
|
this.notifications.unshift(notification)
|
||||||
clearTimeout(this.totalTimeout)
|
clearTimeout(this.totalTimeout)
|
||||||
this.totalTimeout = setTimeout(() => {
|
this.totalTimeout = setTimeout(() => {
|
||||||
this.dismiss()
|
this.dismiss()
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
width: 180px;
|
width: 180px;
|
||||||
display: block;
|
display: block;
|
||||||
float: left;
|
float: left;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.global-menu {
|
.global-menu {
|
||||||
width: 180px;
|
width: 180px;
|
||||||
@ -106,6 +107,7 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
color: #8c80ae;
|
color: #8c80ae;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
background-color: var(--menu-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-button {
|
.mobile-button {
|
||||||
|
@ -1,133 +1,134 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- change class to .master-note-edit to have it popup on the screen.
|
<!-- change class to .master-note-edit to have it popup on the screen.
|
||||||
@keyup.esc="closeButtonAction()" -->
|
@keyup.esc="closeButtonAction()" -->
|
||||||
<div
|
<div class="master-note-edit">
|
||||||
id="InputNotes"
|
|
||||||
class="master-note-edit"
|
|
||||||
>
|
|
||||||
|
|
||||||
<!-- Giant Edit Note Menu -->
|
<!-- Edit Menus -->
|
||||||
<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 -->
|
<div class="menu-top-half" :class="{ 'hide-text':(openNotes > 1) }">
|
||||||
<div class="edit-spacer"></div>
|
|
||||||
|
|
||||||
<div class="menu-top-half">
|
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="colorpicker = true" data-tooltip="Text Color" data-position="bottom center">
|
|
||||||
<i class="font icon"></i>
|
|
||||||
<div class="font-color-bar" :style="{'background':lastUsedColor}"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="toggleBold()" :data-tooltip="`Bold\n(CTRL + b)`" data-position="bottom center" :class="{'edit-active':activeBold}">
|
|
||||||
<i class="bold icon"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="toggleItalic()" :data-tooltip="`Italic\n(CRTL + i)`" data-position="bottom center" :class="{'edit-active':activeItalics}">
|
|
||||||
<i class="italic icon"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="toggleUnderline()" :data-tooltip="`Underline\n(CRTL + u)`" data-position="bottom center" :class="{'edit-active':activeUnderline}">
|
|
||||||
<i class="underline icon"></i>
|
|
||||||
</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}">
|
|
||||||
<i class="text height icon"></i>
|
|
||||||
</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-button" v-on:click="editor.increaseQuoteLevel()" :data-tooltip="`Indent\n(TAB)`" data-position="bottom center">
|
|
||||||
<i class="indent icon"></i>
|
|
||||||
</div>
|
|
||||||
<div class="edit-button" v-on:click="editor.decreaseQuoteLevel()" :data-tooltip="`Un-Indent\n(SHIFT + TAB)`" data-position="bottom center">
|
|
||||||
<i class="outdent icon"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div class="edit-button" v-on:click="colorpicker = true" data-tooltip="Text Color" data-position="bottom center">
|
||||||
|
<i class="font icon"></i>
|
||||||
|
<div class="font-color-bar" :style="{'background':lastUsedColor}"></div>
|
||||||
|
<span>Color</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="menu-bottom-half">
|
<div class="edit-button" v-on:click="toggleBold()" :data-tooltip="`Bold\n(CTRL + b)`" data-position="bottom center" :class="{'edit-active':activeBold}">
|
||||||
|
<i class="bold icon"></i>
|
||||||
<!--
|
<span>Bold</span>
|
||||||
<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>
|
|
||||||
</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">
|
|
||||||
<i class="grip lines icon"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="edit-divide"></div>
|
|
||||||
|
|
||||||
<!-- <div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/colors`)" data-tooltip="Note Color" data-position="bottom center" :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">
|
|
||||||
<i class="paint brush icon"></i>
|
|
||||||
</div> -->
|
|
||||||
<!-- <div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/tags`)" data-tooltip="Tags" data-position="bottom center">
|
|
||||||
<i class="tags icon"></i>
|
|
||||||
</div> -->
|
|
||||||
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/images`)" data-tooltip="Images" data-position="bottom center">
|
|
||||||
<i class="image icon"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<file-upload-button
|
|
||||||
data-tooltip="Upload File" data-position="bottom center"
|
|
||||||
class="edit-button"
|
|
||||||
:noteId="noteid" />
|
|
||||||
|
|
||||||
<div class="edit-divide"></div>
|
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/options`)" data-tooltip="More Options" data-position="bottom center">
|
|
||||||
|
|
||||||
<i class="ellipsis horizontal icon"></i>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="edit-divide"></div>
|
|
||||||
|
|
||||||
<div class="edit-button" v-on:click="undoCustom()" :data-tooltip="`Undo\n(CTRL + z)`" data-position="bottom center">
|
|
||||||
<i class="reply icon"></i>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="edit-button done-button" 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>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="edit-button" v-on:click="toggleItalic()" :data-tooltip="`Italic\n(CRTL + i)`" data-position="bottom center" :class="{'edit-active':activeItalics}">
|
||||||
|
<i class="italic icon"></i>
|
||||||
|
<span>Italic</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="edit-button" v-on:click="toggleUnderline()" :data-tooltip="`Underline\n(CRTL + u)`" data-position="bottom center" :class="{'edit-active':activeUnderline}">
|
||||||
|
<i class="underline icon"></i>
|
||||||
|
<span>Underline</span>
|
||||||
|
</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>
|
||||||
|
<span>Quote</span>
|
||||||
|
</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>
|
||||||
|
<span>Small Text</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<span>Title</span>
|
||||||
|
</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-button" v-on:click="indentText" :data-tooltip="`Indent\n(TAB)`" data-position="bottom center">
|
||||||
|
<i class="indent icon"></i>
|
||||||
|
<span>Indent</span>
|
||||||
|
</div>
|
||||||
|
<div class="edit-button" v-on:click="outdentText" :data-tooltip="`Un-Indent\n(SHIFT + TAB)`" data-position="bottom center">
|
||||||
|
<i class="outdent icon"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- invisible menu item, creates BG for bottom menu -->
|
<div class="menu-bottom-half" :class="{ 'hide-text':(openNotes > 1) }">
|
||||||
<div class="bottom-edit-menu"></div>
|
|
||||||
|
<!--
|
||||||
|
<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>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
|
||||||
|
<div class="edit-button" v-on:click="toggleList('ul')" :data-tooltip="`Task List\n(CTRL + SHIFT + 8)`" data-position="top center" :class="{'edit-active':activeToDo}">
|
||||||
|
<i class="tasks icon"></i>
|
||||||
|
<span>To-Do</span>
|
||||||
|
</div>
|
||||||
|
<div class="edit-button" v-on:click="toggleList('ol')" :data-tooltip="`Ordered List\n(CTRL + SHIFT + 9)`" data-position="top center" :class="{'edit-active':activeList}">
|
||||||
|
<i class="list ol icon"></i>
|
||||||
|
<span>List</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="edit-divide"></div>
|
||||||
|
|
||||||
|
<div class="edit-button" v-on:click="insertDivide()" data-tooltip="Insert Divide" data-position="top center">
|
||||||
|
<i class="grip lines icon"></i>
|
||||||
|
<span>Divide</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="edit-divide"></div>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/colors`)" data-tooltip="Note Color" data-position="top center" :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">
|
||||||
|
<i class="paint brush icon"></i>
|
||||||
|
</div> -->
|
||||||
|
<!-- <div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/tags`)" data-tooltip="Tags" data-position="top center">
|
||||||
|
<i class="tags icon"></i>
|
||||||
|
</div> -->
|
||||||
|
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/images`)" data-tooltip="Images" data-position="top center">
|
||||||
|
<i class="image icon"></i>
|
||||||
|
<span>Images</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<file-upload-button
|
||||||
|
data-tooltip="Upload File" data-position="top center"
|
||||||
|
class="edit-button"
|
||||||
|
:noteId="noteid" />
|
||||||
|
|
||||||
|
<div class="edit-divide"></div>
|
||||||
|
|
||||||
|
<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/options`)" data-tooltip="More Options" data-position="top center">
|
||||||
|
|
||||||
|
<i class="ellipsis horizontal icon"></i>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="edit-divide"></div>
|
||||||
|
|
||||||
|
<div class="edit-button" v-on:click="undoCustom()" :data-tooltip="`Undo\n(CTRL + z)`" data-position="top center">
|
||||||
|
<i class="reply icon"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="edit-button done-button" v-on:click="closeButtonAction()" :data-tooltip="`Close\n(ESC)`" data-position="top center">
|
||||||
|
<!-- <i class="green close icon"></i> -->
|
||||||
|
<span class="ui green text">Done</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="input-container-wrapper"
|
<div class="input-container-wrapper"
|
||||||
:class="{ 'side-menu-open':sideMenuOpen, 'size-down':(sizeDown == true),}">
|
:class="{ 'side-menu-open':sideMenuOpen }">
|
||||||
|
|
||||||
<!-- Squire box grows -->
|
<!-- Squire box grows -->
|
||||||
<div id="text-box-container" class="note-wrapper" :style="{ 'background-color':styleObject['noteBackground']}">
|
<div class="note-wrapper">
|
||||||
|
|
||||||
<!-- Loading indicator -->
|
<!-- Loading indicator -->
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
@ -155,9 +156,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- tags on the side, only show on desktop -->
|
<!-- tags on the side, only show on desktop -->
|
||||||
<div class="note-mini-tag-area" :class="{ 'size-down':sizeDown }"
|
<div class="note-mini-tag-area"
|
||||||
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'], 'color':styleObject['noteText'] }">
|
||||||
|
|
||||||
<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
|
||||||
@ -341,9 +342,9 @@
|
|||||||
</side-slide-menu>
|
</side-slide-menu>
|
||||||
|
|
||||||
<!-- Show side shades if user is on desktop only -->
|
<!-- Show side shades if user is on desktop only -->
|
||||||
<div class="full-focus-shade shade1"
|
<!-- <div class="full-focus-shade shade1"
|
||||||
:class="{ 'fade-me-out':sizeDown }"
|
:class="{ 'fade-me-out':sizeDown }"
|
||||||
v-on:click="closeButtonAction()"></div>
|
v-on:click="closeButtonAction()"></div> -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -360,8 +361,8 @@
|
|||||||
import SquireButtonFunctions from '@/mixins/SquireButtonFunctions.js'
|
import SquireButtonFunctions from '@/mixins/SquireButtonFunctions.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'InputNotes',
|
name: 'NoteInputPanel',
|
||||||
props: [ 'noteid', 'position', 'openMenu', 'urlData' ],
|
props: [ 'noteid', 'position', 'openMenu', 'urlData', 'openNotes'],
|
||||||
components:{
|
components:{
|
||||||
'note-tag-edit': () => import('@/components/NoteTagEdit.vue'),
|
'note-tag-edit': () => import('@/components/NoteTagEdit.vue'),
|
||||||
'color-picker': () => import('@/components/ColorPicker.vue'),
|
'color-picker': () => import('@/components/ColorPicker.vue'),
|
||||||
@ -436,12 +437,10 @@
|
|||||||
watch: {
|
watch: {
|
||||||
urlData(newVal, oldVal){
|
urlData(newVal, oldVal){
|
||||||
|
|
||||||
// return
|
|
||||||
|
|
||||||
//Handle changes in URL to
|
//Handle changes in URL to
|
||||||
|
|
||||||
if(newVal.id == undefined || newVal.id != this.noteid){
|
if(newVal.id == undefined || newVal.id != this.noteid){
|
||||||
this.closeButtonAction()
|
// this.closeButtonAction()
|
||||||
}
|
}
|
||||||
|
|
||||||
//Reset all note menus on URL change
|
//Reset all note menus on URL change
|
||||||
@ -453,7 +452,7 @@
|
|||||||
this.table = false
|
this.table = false
|
||||||
|
|
||||||
//If a menu value is set, open it
|
//If a menu value is set, open it
|
||||||
if(newVal.openMenu){
|
if(newVal.openMenu && newVal.id == this.noteid){
|
||||||
//Only modify menu boolean if its defined
|
//Only modify menu boolean if its defined
|
||||||
if(typeof this[newVal.openMenu] == 'boolean'){
|
if(typeof this[newVal.openMenu] == 'boolean'){
|
||||||
this.sideMenuOpen = true
|
this.sideMenuOpen = true
|
||||||
@ -471,6 +470,12 @@
|
|||||||
this.save()
|
this.save()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.$bus.$on('close_note_by_id', (noteId) => {
|
||||||
|
if(noteId == this.noteid){
|
||||||
|
this.closeButtonAction()
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
beforeDestroy(){
|
beforeDestroy(){
|
||||||
|
|
||||||
@ -485,6 +490,7 @@
|
|||||||
//Obliterate squire instance
|
//Obliterate squire instance
|
||||||
this.editor.destroy()
|
this.editor.destroy()
|
||||||
|
|
||||||
|
// trigger save actions and reindex
|
||||||
this.close()
|
this.close()
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -643,9 +649,9 @@
|
|||||||
if(keyCode == 'Tab'){
|
if(keyCode == 'Tab'){
|
||||||
|
|
||||||
if(event.shiftKey){
|
if(event.shiftKey){
|
||||||
this.editor.decreaseQuoteLevel()
|
this.outdentText()
|
||||||
} else {
|
} else {
|
||||||
this.editor.increaseQuoteLevel()
|
this.indentText()
|
||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
@ -989,12 +995,14 @@
|
|||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
},
|
},
|
||||||
closeButtonAction(){
|
closeButtonAction(playAnimation = false){
|
||||||
this.sizeDown = true
|
this.sizeDown = playAnimation
|
||||||
|
const animationTimeout = (playAnimation ? 300 : 0)
|
||||||
//This timeout allows animation to play before closing
|
//This timeout allows animation to play before closing
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.$router.push('/notes')
|
// this.$router.push('/notes')
|
||||||
}, 300)
|
this.close()
|
||||||
|
}, animationTimeout)
|
||||||
},
|
},
|
||||||
close(){
|
close(){
|
||||||
|
|
||||||
@ -1022,9 +1030,9 @@
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
destroyWebSockets(){
|
destroyWebSockets(){
|
||||||
this.$io.removeListener('past_diffs')
|
// this.$io.removeListener('past_diffs')
|
||||||
this.$io.removeListener('update_user_count')
|
// this.$io.removeListener('update_user_count')
|
||||||
this.$io.removeListener('incoming_diff')
|
// this.$io.removeListener('incoming_diff')
|
||||||
},
|
},
|
||||||
setupWebSockets(){
|
setupWebSockets(){
|
||||||
|
|
||||||
@ -1134,42 +1142,41 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background-color: var(--menu-accent);
|
background-color: var(--small_element_bg_color);
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
opacity: 0.9;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* squire styles */
|
/* squire styles */
|
||||||
.input-container-wrapper {
|
.input-container-wrapper {
|
||||||
position: fixed;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 15%;
|
left: 0;
|
||||||
right: 15%;
|
right: 0;
|
||||||
z-index: 1005;
|
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
scrollbar-color: transparent transparent;
|
scrollbar-color: transparent transparent;
|
||||||
overscroll-behavior: contain;
|
overscroll-behavior: contain;
|
||||||
|
|
||||||
|
background-color: var(--border_color);
|
||||||
}
|
}
|
||||||
.note-wrapper {
|
.note-wrapper {
|
||||||
background-color: var(--small_element_bg_color);
|
background-color: var(--border_color);
|
||||||
border: 1px solid var(--menu-accent);
|
|
||||||
margin: 45px 0 45px 0;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
margin: 50px auto;
|
||||||
|
|
||||||
|
max-width: 1100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-mini-tag-area {
|
.note-mini-tag-area {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 5px 15px 0 15px;
|
padding: 5px 15px 0 15px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
max-width: 1100px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
background: var(--small_element_bg_color);
|
||||||
}
|
}
|
||||||
.add-mini-tag {
|
.add-mini-tag {
|
||||||
color: var(--border_color);
|
color: var(--border_color);
|
||||||
@ -1195,22 +1202,29 @@
|
|||||||
Edit Menu Styles START
|
Edit Menu Styles START
|
||||||
|
|
||||||
*/
|
*/
|
||||||
.edit-menu {
|
.menu-top-half, .menu-bottom-half {
|
||||||
position: fixed;
|
display: flex;
|
||||||
top: 0;
|
justify-content: center;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1001;
|
||||||
|
background-color: green;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 5px 5px;
|
||||||
|
background-color: var(--menu-background);
|
||||||
|
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
background-color: var(--small_element_bg_color);
|
|
||||||
z-index: 1019;
|
|
||||||
padding: 5px 0;
|
|
||||||
border: none;
|
|
||||||
border-bottom: 1px solid var(--menu-accent);
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
.menu-top-half, .menu-bottom-half {
|
.menu-top-half{
|
||||||
display: inline-block;
|
top: 0;
|
||||||
|
}
|
||||||
|
.menu-bottom-half {
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.menu-top-half.hide-text .edit-button > span:not(.ui),
|
||||||
|
.menu-bottom-half.hide-text .edit-button > span:not(.ui)
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
.edit-button {
|
.edit-button {
|
||||||
background-color: var(--small_element_bg_color);
|
background-color: var(--small_element_bg_color);
|
||||||
@ -1218,14 +1232,15 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 1.4em;
|
font-size: 1em;
|
||||||
box-shadow: 0 0 1px 0 #c4c4c4;
|
box-shadow: 0 0 1px 0 #c4c4c4;
|
||||||
margin: 0 3px 0;
|
margin: 0 3px 0;
|
||||||
padding: 6px 0 0 0;
|
padding: 6px 12px 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
min-width: 32px;
|
min-width: 25px;
|
||||||
min-height: 32px;
|
min-height: 30px;
|
||||||
|
/*flex-basis: 100%;*/
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.edit-button > i {
|
.edit-button > i {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
@ -1244,19 +1259,29 @@
|
|||||||
}
|
}
|
||||||
.edit-divide {
|
.edit-divide {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background-color: var(--menu-accent);
|
|
||||||
height: 15px;
|
height: 15px;
|
||||||
width: 1px;
|
width: 7px;
|
||||||
margin: 0 8px;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
@media only screen and (max-width: 740px) {
|
@media only screen and (max-width: 740px) {
|
||||||
.edit-spacer {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.edit-button {
|
.edit-button {
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
|
.menu-top-half, .menu-bottom-half {
|
||||||
|
padding: 3px 2px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
transform: none;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
.menu-bottom-half {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 100000;
|
||||||
|
}
|
||||||
|
.note-wrapper {
|
||||||
|
margin-bottom: 100px;
|
||||||
|
margin-top: 38px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
||||||
@ -1331,68 +1356,22 @@
|
|||||||
left: calc(50% + 10px) !important;
|
left: calc(50% + 10px) !important;
|
||||||
right: calc(0% + 10px) !important;
|
right: calc(0% + 10px) !important;
|
||||||
}
|
}
|
||||||
@media only screen and (max-width: 740px) {
|
/*weird inbetween size for tables*/
|
||||||
|
@media only screen and (max-width: 875px) {
|
||||||
|
|
||||||
.master-note-edit {
|
}
|
||||||
left: 0;
|
@media only screen and (max-width: 830px) {
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.input-container-wrapper {
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
top: 35px;
|
|
||||||
bottom: 37px;
|
|
||||||
background-color: var(--small_element_bg_color);
|
|
||||||
}
|
|
||||||
.note-wrapper {
|
|
||||||
margin: 0;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
.shade1, .shade2 {
|
.shade1, .shade2 {
|
||||||
right: 150%;
|
right: 150%;
|
||||||
}
|
}
|
||||||
.edit-menu {
|
|
||||||
background-color: var(--dark_border_color);
|
|
||||||
}
|
|
||||||
/*menu overwrites */
|
|
||||||
.bottom-edit-menu {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
/*background-color: var(--small_element_bg_color);*/
|
|
||||||
background-color: var(--dark_border_color);
|
|
||||||
z-index: 1012;
|
|
||||||
border: none;
|
|
||||||
border-top: 1px solid var(--menu-accent);
|
|
||||||
min-height: 37px;
|
|
||||||
}
|
|
||||||
.menu-top-half, .menu-bottom-half {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-around;
|
|
||||||
}
|
|
||||||
.edit-divide {
|
.edit-divide {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.menu-bottom-half {
|
|
||||||
z-index: 1005;
|
|
||||||
position: fixed;
|
|
||||||
bottom: 4px;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
.edit-button {
|
.edit-button {
|
||||||
flex-basis: 100%;
|
padding: 6px 0px 0;
|
||||||
margin: 0 2px;
|
|
||||||
}
|
}
|
||||||
.done-button {
|
.edit-button > span:not(.ui) {
|
||||||
flex-basis: 150%;
|
display: none;
|
||||||
font-size: 13px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<!-- Show title and snippet below it -->
|
<!-- Show title and snippet below it -->
|
||||||
<div class="overflow-hidden note-card-text" @click="cardClicked" v-if="!titleView">
|
<div class="overflow-hidden note-card-text" @click.stop="cardClicked" v-if="!titleView">
|
||||||
|
|
||||||
<span v-if="note.title == '' && note.subtext == ''">
|
<span v-if="note.title == '' && note.subtext == ''">
|
||||||
Empty Note
|
Empty Note
|
||||||
@ -24,7 +24,7 @@
|
|||||||
class="big-text"><p>{{ note.title }}</p></span>
|
class="big-text"><p>{{ note.title }}</p></span>
|
||||||
|
|
||||||
<span class="tags" v-if="note.tags">
|
<span class="tags" v-if="note.tags">
|
||||||
<span v-for="tag in (note.tags.split(','))" class="little-tag" v-on:click="$emit('tagClick', tag.split(':')[1] )">#{{ tag.split(':')[0] }}</span>
|
<span v-for="tag in (note.tags.split(','))" class="little-tag" v-on:click.stop="$emit('tagClick', tag.split(':')[1] )">#{{ tag.split(':')[0] }}</span>
|
||||||
<br>
|
<br>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@ -444,10 +444,10 @@
|
|||||||
.note-title-display-card {
|
.note-title-display-card {
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: var(--small_element_bg_color);
|
background-color: var(--small_element_bg_color);
|
||||||
|
|
||||||
/*The subtle shadow*/
|
/*The subtle shadow*/
|
||||||
/*box-shadow: 0px 1px 2px 1px rgba(210, 211, 211, 0.46);*/
|
|
||||||
box-shadow: 2px 2px 6px 0 rgba(0,0,0,.15);
|
box-shadow: 2px 2px 6px 0 rgba(0,0,0,.15);
|
||||||
transition: box-shadow ease 0.5s, transform linear 0.1s;
|
transition: box-shadow, border-color ease 0.5s, transform linear 0.5s;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
/*padding: 0.7em 1em;*/
|
/*padding: 0.7em 1em;*/
|
||||||
border-radius: .28571429rem;
|
border-radius: .28571429rem;
|
||||||
@ -472,9 +472,8 @@
|
|||||||
max-height: 450px;
|
max-height: 450px;
|
||||||
}
|
}
|
||||||
.note-title-display-card:hover {
|
.note-title-display-card:hover {
|
||||||
/*box-shadow: 0px 2px 2px 1px rgba(210, 211, 211, 0.8);*/
|
box-shadow: 0 8px 15px rgba(0,0,0,0.3);
|
||||||
/*transform: translateY(-2px);*/
|
border-color: var(--main-accent);
|
||||||
box-shadow: 0 8px 24px rgba(0,0,0,0.1);
|
|
||||||
}
|
}
|
||||||
.note-title-display-card.title-view {
|
.note-title-display-card.title-view {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
116
client/src/components/PasteButton.vue
Normal file
116
client/src/components/PasteButton.vue
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div class="ui right floated basic shrinking icon button" v-on:click="showPasteInputArea">
|
||||||
|
<i class="paste icon"></i>
|
||||||
|
Paste
|
||||||
|
</div>
|
||||||
|
<div class="shade" v-if="showPasteArea" @click.prevent="close">
|
||||||
|
<div class="ui stackable grid full-height" @click.prevent="close">
|
||||||
|
<div class="four wide column"></div>
|
||||||
|
<div class="eight wide middle aligned center aligned column">
|
||||||
|
<div class="ui raised segment">
|
||||||
|
<div class="ui dividing header">
|
||||||
|
<i class="green paste icon"></i>
|
||||||
|
Paste & automatically Save
|
||||||
|
</div>
|
||||||
|
<div class="ui fluid action input">
|
||||||
|
<input
|
||||||
|
id="pastetextarea"
|
||||||
|
type="text"
|
||||||
|
ref="pastearea"
|
||||||
|
@paste.prevent="onPaste"
|
||||||
|
@keyup.enter.prevent="onEnter"
|
||||||
|
placeholder="Paste Here">
|
||||||
|
<button class="ui green labeled icon button" @click.prevent="onEnter">
|
||||||
|
<i class="save icon"></i>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="four wide column"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'PasteButton',
|
||||||
|
props: {},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
showPasteArea: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
close(){
|
||||||
|
this.showPasteArea = false
|
||||||
|
},
|
||||||
|
onEnter(e){
|
||||||
|
|
||||||
|
const text = this.$refs.pastearea.value
|
||||||
|
this.saveText(text)
|
||||||
|
|
||||||
|
},
|
||||||
|
onPaste(e){
|
||||||
|
|
||||||
|
// Get pasted data via clipboard API
|
||||||
|
const clipboardData = e.clipboardData || window.clipboardData
|
||||||
|
const pastedData = String(clipboardData.getData('Text')).trim()
|
||||||
|
|
||||||
|
this.saveText(pastedData)
|
||||||
|
|
||||||
|
},
|
||||||
|
saveText(text){
|
||||||
|
|
||||||
|
this.showPasteArea = false
|
||||||
|
if(!text){
|
||||||
|
this.$bus.$emit('notification', 'Nothing to save.')
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
axios.post('/api/quick-note/update', { 'pushText':text } )
|
||||||
|
.then( response => {
|
||||||
|
|
||||||
|
this.$bus.$emit('notification', 'Saved To Scratch Pad')
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$bus.$emit('notification', 'Failed to Save')
|
||||||
|
})
|
||||||
|
|
||||||
|
},
|
||||||
|
showPasteInputArea(){
|
||||||
|
|
||||||
|
// Show text area and focus its contents
|
||||||
|
this.showPasteArea = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const aux = document.getElementById('pastetextarea')
|
||||||
|
aux.focus();
|
||||||
|
})
|
||||||
|
|
||||||
|
// auto hide after 1 Minute
|
||||||
|
setTimeout(() => {
|
||||||
|
this.showPasteArea = false
|
||||||
|
}, 60*1000)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="css">
|
||||||
|
.paste-text-container {
|
||||||
|
background-color: green;
|
||||||
|
position: absolute;
|
||||||
|
width: 50vw;
|
||||||
|
height: 80vh;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.full-height {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,9 +1,9 @@
|
|||||||
<style type="text/css" scoped>
|
<style type="text/css" scoped>
|
||||||
.slide-container {
|
.slide-container {
|
||||||
position: fixed;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 50%;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
z-index: 1020;
|
z-index: 1020;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -98,11 +98,9 @@
|
|||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="slide-shadow" :class="{'full-shadow':fullShadow}" v-on:click="close"></div>
|
<!-- <div class="slide-shadow" :class="{'full-shadow':fullShadow}" v-on:click="close"></div> -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- </transition> -->
|
<!-- </transition> -->
|
||||||
|
44
client/src/components/SvgDisplayer.vue
Normal file
44
client/src/components/SvgDisplayer.vue
Normal file
File diff suppressed because one or more lines are too long
@ -404,6 +404,26 @@ const SquireButtonFunctions = {
|
|||||||
|
|
||||||
this.$router.go(-1)
|
this.$router.go(-1)
|
||||||
},
|
},
|
||||||
|
indentText(){
|
||||||
|
|
||||||
|
// Lists use increase list level, increase quote breaks numbering
|
||||||
|
if(this.activeList || this.activeToDo){
|
||||||
|
|
||||||
|
this.editor.increaseListLevel()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.editor.increaseQuoteLevel()
|
||||||
|
},
|
||||||
|
outdentText(){
|
||||||
|
|
||||||
|
// Lists use increase list level, increase quote breaks numbering
|
||||||
|
if(this.activeList || this.activeToDo){
|
||||||
|
|
||||||
|
this.editor.decreaseListLevel()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.editor.decreaseQuoteLevel()
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,15 @@
|
|||||||
Other Files
|
Other Files
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
|
<router-link
|
||||||
|
v-if="$store.getters.totals && $store.getters.totals['sharedToNotes']"
|
||||||
|
exact-active-class="green"
|
||||||
|
class="ui basic button shrinking"
|
||||||
|
to="/attachments/type/shared">
|
||||||
|
<i class="send icon"></i>
|
||||||
|
Show Shared
|
||||||
|
</router-link>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sixteen wide column" v-if="searchParams.noteId">
|
<div class="sixteen wide column" v-if="searchParams.noteId">
|
||||||
@ -165,6 +174,12 @@
|
|||||||
this.searchParams.attachmentType = this.$route.params.type
|
this.searchParams.attachmentType = this.$route.params.type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// include files from shared notes or selected notes
|
||||||
|
this.searchParams.includeShared = false
|
||||||
|
if(this.$route.params.type == 'shared'){
|
||||||
|
this.searchParams.includeShared = true
|
||||||
|
}
|
||||||
|
|
||||||
//Set noteId in if in URL
|
//Set noteId in if in URL
|
||||||
if(this.$route.params.id){
|
if(this.$route.params.id){
|
||||||
this.searchParams.noteId = this.$route.params.id
|
this.searchParams.noteId = this.$route.params.id
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page-container" v-on:scroll="onScroll">
|
<div class="page-container">
|
||||||
|
|
||||||
<div class="ui grid" ref="content">
|
<div class="ui grid" ref="content">
|
||||||
|
|
||||||
<div class="sixteen wide column">
|
<div class="sixteen wide column">
|
||||||
<!-- :class="{ 'sixteen wide column':showOneColumn(), 'sixteen wide column':!showOneColumn() }" -->
|
<!-- :class="{ 'sixteen wide column':showOneColumn 'sixteen wide column':!showOneColumn}" -->
|
||||||
|
|
||||||
<div class="ui stackable grid">
|
<div class="ui stackable grid">
|
||||||
|
|
||||||
@ -33,15 +33,6 @@
|
|||||||
Active Sessions {{ $store.getters.getActiveSessions }}
|
Active Sessions {{ $store.getters.getActiveSessions }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<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">
|
|
||||||
<i class="th icon"></i> Tiles
|
|
||||||
</span>
|
|
||||||
<span v-if="!titleView">
|
|
||||||
<i class="list icon"></i> List
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="eight wide column" v-if="showClear">
|
<div class="eight wide column" v-if="showClear">
|
||||||
@ -107,7 +98,19 @@
|
|||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<!-- Go to one wide column, do not do this on mobile interface -->
|
<!-- Go to one wide column, do not do this on mobile interface -->
|
||||||
<div :class="{'one-column':( showOneColumn() )}">
|
<div :class="{'one-column':( showOneColumn), 'floating-list':( isFloatingList ), 'hidden-floating-list':(collapseFloatingList)}" v-on:scroll="onScroll">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="ui basic fitted right aligned segment" v-if="isFloatingList">
|
||||||
|
<div class="ui small basic green left floated button" v-on:click="closeAllNotes()" v-if="openNotes.length > 1">
|
||||||
|
<i class="times circle outline icon"></i>
|
||||||
|
Close All
|
||||||
|
</div>
|
||||||
|
<div class="ui small green button" v-on:click="collapseFloatingList = true">
|
||||||
|
<i class="caret square left outline icon"></i>
|
||||||
|
Hide Menu
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- render each section based on notes in set -->
|
<!-- render each section based on notes in set -->
|
||||||
<div v-for="section,index in noteSections" v-if="section.length > 0" class="note-card-section">
|
<div v-for="section,index in noteSections" v-if="section.length > 0" class="note-card-section">
|
||||||
@ -120,8 +123,8 @@
|
|||||||
:ref="'note-'+note.id"
|
:ref="'note-'+note.id"
|
||||||
:onClick="openNote"
|
:onClick="openNote"
|
||||||
:data="note"
|
:data="note"
|
||||||
:title-view="titleView"
|
:title-view="titleView || isFloatingList"
|
||||||
:currently-open="activeNoteId1 == note.id"
|
:currently-open="openNotes.includes(note.id)"
|
||||||
:key="note.id + note.color + '-' +note.title.length + '-' +note.subtext.length + '-' + note.tag_count + note.updated"
|
:key="note.id + note.color + '-' +note.title.length + '-' +note.subtext.length + '-' + note.tag_count + note.updated"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -149,13 +152,21 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="show-hidden-note-list-button" v-if="collapseFloatingList" v-on:click="collapseFloatingList = false">
|
||||||
|
<i class="caret square right outline icon"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
<note-input-panel
|
<!-- flexbox note container evenly spaces open notes -->
|
||||||
v-if="activeNoteId1 != null"
|
<div class="note-panel-container" :class="{ 'note-panel-fullwidth':collapseFloatingList}" v-if="openNotes.length">
|
||||||
:key="activeNoteId1"
|
<note-input-panel
|
||||||
:noteid="activeNoteId1"
|
v-for="noteId in openNotes"
|
||||||
:url-data="$route.params"
|
v-if="noteId != null"
|
||||||
/>
|
:key="noteId"
|
||||||
|
:noteid="noteId"
|
||||||
|
:url-data="$route.params"
|
||||||
|
:open-notes="openNotes.length"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -165,7 +176,7 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SearchBar',
|
name: 'NotesPage',
|
||||||
components: {
|
components: {
|
||||||
|
|
||||||
'note-input-panel': () => import(/* webpackChunkName: "NoteInputPanel" */ '@/components/NoteInputPanel.vue'),
|
'note-input-panel': () => import(/* webpackChunkName: "NoteInputPanel" */ '@/components/NoteInputPanel.vue'),
|
||||||
@ -186,6 +197,8 @@
|
|||||||
searchResultsCount: 0,
|
searchResultsCount: 0,
|
||||||
searchTags: [],
|
searchTags: [],
|
||||||
notes: [],
|
notes: [],
|
||||||
|
openNotes: [],
|
||||||
|
collapseFloatingList: false,
|
||||||
highlights: [],
|
highlights: [],
|
||||||
searchDebounce: null,
|
searchDebounce: null,
|
||||||
fastFilters: {},
|
fastFilters: {},
|
||||||
@ -247,35 +260,34 @@
|
|||||||
|
|
||||||
this.$io.on('new_note_created', noteId => {
|
this.$io.on('new_note_created', noteId => {
|
||||||
|
|
||||||
//Do not update note if its open
|
// Push new note to top of list and animate
|
||||||
if(this.activeNoteId1 != noteId){
|
this.updateSingleNote(noteId)
|
||||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||||
this.updateSingleNote(noteId, false)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
this.$io.on('note_attribute_modified', noteId => {
|
this.$io.on('note_attribute_modified', noteId => {
|
||||||
|
|
||||||
|
const drawFocus = !this.openNotes.includes(parseInt(noteId))
|
||||||
|
this.updateSingleNote(noteId, drawFocus)
|
||||||
|
|
||||||
//Do not update note if its open
|
//Do not update note if its open
|
||||||
if(this.activeNoteId1 != noteId){
|
if(this.openNotes.includes(parseInt(noteId))){
|
||||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||||
this.updateSingleNote(noteId, false)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
//Update title cards when new note text is saved
|
//Update title cards when new note text is saved
|
||||||
this.$io.on('new_note_text_saved', ({noteId, hash}) => {
|
this.$io.on('new_note_text_saved', ({noteId, hash}) => {
|
||||||
|
|
||||||
//Do not update note if its open
|
const drawFocus = !this.openNotes.includes(parseInt(noteId))
|
||||||
if(this.activeNoteId1 != noteId){
|
this.updateSingleNote(noteId, drawFocus)
|
||||||
this.updateSingleNote(noteId, true)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
this.$bus.$on('update_single_note', (noteId) => {
|
this.$bus.$on('update_single_note', (noteId) => {
|
||||||
//Do not update note if its open
|
|
||||||
if(this.activeNoteId1 != noteId){
|
const drawFocus = !this.openNotes.includes(parseInt(noteId))
|
||||||
this.updateSingleNote(noteId)
|
this.updateSingleNote(noteId, drawFocus)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
//Update totals for app
|
//Update totals for app
|
||||||
@ -283,19 +295,7 @@
|
|||||||
|
|
||||||
//Close note event
|
//Close note event
|
||||||
this.$bus.$on('close_active_note', ({noteId, modified}) => {
|
this.$bus.$on('close_active_note', ({noteId, modified}) => {
|
||||||
|
this.closeNote(noteId, modified)
|
||||||
if(modified){
|
|
||||||
console.log('Just closed Note -> ' + noteId + ', modified -> ', modified)
|
|
||||||
}
|
|
||||||
|
|
||||||
//A note has been closed
|
|
||||||
if(this.$route.fullPath != '/notes'){
|
|
||||||
this.$router.push('/notes')
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$store.dispatch('fetchAndUpdateUserTotals')
|
|
||||||
//Focus and animate if modified
|
|
||||||
this.updateSingleNote(noteId, modified)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
this.$bus.$on('note_deleted', (noteId) => {
|
this.$bus.$on('note_deleted', (noteId) => {
|
||||||
@ -347,6 +347,8 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Window scroll needed when scrolling full page.
|
||||||
|
// second scroll event added on note-list for floating view scroll detection
|
||||||
window.addEventListener('scroll', this.onScroll)
|
window.addEventListener('scroll', this.onScroll)
|
||||||
|
|
||||||
//Close notes when back button is pressed
|
//Close notes when back button is pressed
|
||||||
@ -355,8 +357,6 @@
|
|||||||
//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)
|
||||||
@ -375,9 +375,9 @@
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
||||||
//Open note on load if ID is set
|
//Open note on PAGE LOAD if ID is set
|
||||||
if(this.$route.params.id > 1){
|
if(this.$route.params.id > 1){
|
||||||
this.activeNoteId1 = this.$route.params.id
|
this.openNote(this.$route.params.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Loads initial batch and tags
|
//Loads initial batch and tags
|
||||||
@ -386,18 +386,21 @@
|
|||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
'$route.params.id': function(id){
|
'$route.params.id': function(id){
|
||||||
//Open note on ID, null id will close note
|
this.openNote(id)
|
||||||
this.activeNoteId1 = id
|
|
||||||
},
|
},
|
||||||
'$route' (to, from) {
|
'$route' (to, from) {
|
||||||
|
|
||||||
|
|
||||||
// Reload the notes if returning to this page
|
// Reload the notes if returning to this page
|
||||||
if(to.fullPath == '/notes' && !from.fullPath.includes('/notes/open/')){
|
if(to.fullPath == '/notes' && !from.fullPath.includes('/notes/open/')){
|
||||||
|
|
||||||
this.reset()
|
this.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close all notes if returning to /notes page
|
||||||
|
if(to.fullPath == '/notes' && from.fullPath.includes('/notes/open/')){
|
||||||
|
this.closeAllNotes()
|
||||||
|
}
|
||||||
|
|
||||||
//Lookup tags set in URL
|
//Lookup tags set in URL
|
||||||
if(to.params.tag && this.$store.getters.totals && this.$store.getters.totals['tags'][to.params.tag]){
|
if(to.params.tag && this.$store.getters.totals && this.$store.getters.totals['tags'][to.params.tag]){
|
||||||
|
|
||||||
@ -410,30 +413,96 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
computed: {
|
||||||
toggleTitleView(){
|
isFloatingList(){
|
||||||
this.titleView = !this.titleView
|
|
||||||
|
//If note 1 or 2 is open, show floating column
|
||||||
|
return (this.openNotes.length > 0)
|
||||||
|
|
||||||
},
|
},
|
||||||
showOneColumn(){
|
showOneColumn(){
|
||||||
|
|
||||||
return this.$store.getters.getIsUserOnMobile
|
return this.$store.getters.getIsUserOnMobile
|
||||||
|
|
||||||
//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
|
methods: {
|
||||||
},
|
|
||||||
openNote(id, event = null){
|
openNote(id, event = null){
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
const intId = parseInt(id)
|
||||||
|
if(this.openNotes.includes(intId)){
|
||||||
|
|
||||||
|
console.log('Open already open note?')
|
||||||
|
|
||||||
|
// const openIndex = this.openNotes.indexOf(intId)
|
||||||
|
// if(openIndex != -1){
|
||||||
|
// console.log('Open note and remove it ', intId + ' on index ' + openIndex)
|
||||||
|
// this.openNotes.splice(openIndex, 1)
|
||||||
|
// }
|
||||||
|
// this.$bus.$emit('close_note_by_id', intId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
//Don't open note if a link is clicked in display card
|
//Don't open note if a link is clicked in display card
|
||||||
if(event && event.target && event.target.nodeName){
|
if(event && event.target && event.target.nodeName){
|
||||||
const nodeClick = event.target.nodeName
|
const nodeClick = event.target.nodeName
|
||||||
if(nodeClick == 'A'){ return }
|
if(nodeClick == 'A'){ return }
|
||||||
}
|
}
|
||||||
|
|
||||||
//Open note if a link was not clicked
|
// Push note to stack if not open
|
||||||
this.$router.push('/notes/open/'+id)
|
if(Number.isInteger(intId) && !this.openNotes.includes(intId)){
|
||||||
|
this.openNotes.push(intId)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$nextTick(() => {
|
||||||
|
// change route if open ID is not the same as current ID
|
||||||
|
if(this.$route.params.id != id){
|
||||||
|
console.log('Open note, change route -> route id ' + this.$route.params.id + ' note id ->' + id + ', ' +(this.$route.params.id == id))
|
||||||
|
this.$router.push('/notes/open/'+id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
|
closeNote(noteId, modified){
|
||||||
|
|
||||||
|
console.log('close note', this.$route.fullPath)
|
||||||
|
|
||||||
|
const openIndex = this.openNotes.indexOf(noteId)
|
||||||
|
if(openIndex != -1){
|
||||||
|
console.log('Removing note id ', noteId + ' on index ' + openIndex)
|
||||||
|
this.openNotes.splice(openIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// //A note has been closed
|
||||||
|
// if(this.$route.fullPath != '/notes'){
|
||||||
|
// this.$router.push('/notes')
|
||||||
|
// }
|
||||||
|
if(this.openNotes.length == 0 && this.$route.fullPath != '/notes'){
|
||||||
|
this.$router.push('/notes')
|
||||||
|
}
|
||||||
|
|
||||||
|
if(modified){
|
||||||
|
console.log('Just closed Note -> ' + noteId + ', modified -> ', modified)
|
||||||
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||||
|
//Focus and animate if modified
|
||||||
|
this.updateSingleNote(noteId, modified)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('closeNote(): Open notes length ', this.openNotes.length)
|
||||||
|
},
|
||||||
|
closeAllNotes(){
|
||||||
|
console.log('Close all notes ------------')
|
||||||
|
for (let i = this.openNotes.length - 1; i >= 0; i--) {
|
||||||
|
console.log('Close all notes -> ' + this.openNotes[i])
|
||||||
|
this.closeNote(this.openNotes[i])
|
||||||
|
}
|
||||||
|
console.log('----------------')
|
||||||
|
},
|
||||||
toggleTagFilter(tagId){
|
toggleTagFilter(tagId){
|
||||||
|
|
||||||
this.searchTags = [tagId]
|
this.searchTags = [tagId]
|
||||||
@ -489,7 +558,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.lastVisibilityState = document.visibilityState
|
this.lastVisibilityState = document.visibilityState
|
||||||
|
|
||||||
},
|
},
|
||||||
// @TODO Don't even trigger this if the note wasn't changed
|
// @TODO Don't even trigger this if the note wasn't changed
|
||||||
updateSingleNote(noteId, focuseAndAnimate = true){
|
updateSingleNote(noteId, focuseAndAnimate = true){
|
||||||
@ -525,6 +593,7 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if old note data and new note data exists
|
||||||
if(note && newNote){
|
if(note && newNote){
|
||||||
|
|
||||||
//go through each prop and update it with new values
|
//go through each prop and update it with new values
|
||||||
@ -533,7 +602,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
//Push new note to front if its modified or we want it to
|
//Push new note to front if its modified or we want it to
|
||||||
if( focuseAndAnimate || note.updated != newNote.updated ){
|
if( note.updated != newNote.updated ){
|
||||||
|
|
||||||
// Find note, in section, move to front
|
// Find note, in section, move to front
|
||||||
Object.keys(this.noteSections).forEach( key => {
|
Object.keys(this.noteSections).forEach( key => {
|
||||||
@ -547,6 +616,9 @@
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if( focuseAndAnimate ){
|
||||||
this.$nextTick( () => {
|
this.$nextTick( () => {
|
||||||
//Trigger close animation on note
|
//Trigger close animation on note
|
||||||
this.$refs['note-'+noteId][0].justClosed()
|
this.$refs['note-'+noteId][0].justClosed()
|
||||||
@ -833,15 +905,130 @@
|
|||||||
padding: 15px 0 0;
|
padding: 15px 0 0;
|
||||||
}
|
}
|
||||||
.loading-section {
|
.loading-section {
|
||||||
position: fixed;
|
color: var(--main-accent);
|
||||||
bottom: 40px;
|
box-shadow: 0 1px 3px 0 var(--main-accent);
|
||||||
padding: 0 10px;
|
|
||||||
right: 5px;
|
|
||||||
box-shadow: 0 1px 3px 0 #656565;
|
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background-color: var(--small_element_bg_color);
|
background-color: var(--small_element_bg_color);
|
||||||
opacity: 0.9;
|
display: inline-block;
|
||||||
font-size: 0.7em;
|
width: 100%;
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
.floating-list {
|
||||||
|
z-index: 1000;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 25%;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: var(--small_element_bg_color);
|
||||||
|
padding: 15px 5px 0px 10px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
overflow-x: hidden;
|
||||||
|
-ms-overflow-style: none; /* Internet Explorer 10+ */
|
||||||
|
scrollbar-width: none; /* Firefox */
|
||||||
|
background-color: var(--border_color);
|
||||||
|
}
|
||||||
|
.floating-list::-webkit-scrollbar {
|
||||||
|
display: none; /* Safari and Chrome */
|
||||||
|
}
|
||||||
|
.note-panel-container {
|
||||||
|
position: fixed;
|
||||||
|
width: 75%;
|
||||||
|
height: 100vh;
|
||||||
|
background: gray;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: stretch;
|
||||||
|
align-content: stretch;
|
||||||
|
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
.note-panel-fullwidth {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-panel-container > div {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.hidden-floating-list {
|
||||||
|
left: -1000px !important;
|
||||||
|
}
|
||||||
|
.show-hidden-note-list-button {
|
||||||
|
position: fixed;
|
||||||
|
top: 25px;
|
||||||
|
left: 0;
|
||||||
|
min-width: 45px;
|
||||||
|
background-color: var(--main-accent);
|
||||||
|
color: var(--text_color);
|
||||||
|
display: block;
|
||||||
|
z-index: 1100;
|
||||||
|
cursor: pointer;
|
||||||
|
border-bottom-right-radius: 5px;
|
||||||
|
border-top-right-radius: 5px;
|
||||||
|
padding: 8px 0px 8px 13px;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 1.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width:320px) { /* smartphones, iPhone, portrait 480x320 phones */
|
||||||
|
.floating-list {
|
||||||
|
left: -1000px;
|
||||||
|
}
|
||||||
|
.note-panel-container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width:481px) { /* portrait e-readers (Nook/Kindle), smaller tablets @ 600 or @ 640 wide. */
|
||||||
|
.floating-list {
|
||||||
|
left: 0px;
|
||||||
|
}
|
||||||
|
.note-panel-container {
|
||||||
|
width: 75%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (min-width:641px) { /* portrait tablets, portrait iPad, landscape e-readers, landscape 800x480 or 854x480 phones */
|
||||||
|
|
||||||
|
}
|
||||||
|
@media (min-width:961px) { /* tablet, landscape iPad, lo-res laptops ands desktops */
|
||||||
|
|
||||||
|
}
|
||||||
|
@media (min-width:1025px) { /* big landscape tablets, laptops, and desktops */
|
||||||
|
|
||||||
|
}
|
||||||
|
@media (min-width:1281px) { /* hi-res laptops and desktops */
|
||||||
|
|
||||||
|
}
|
||||||
|
@media (min-width:2000px) { /* BIG hi-res laptops and desktops */
|
||||||
|
.floating-list {
|
||||||
|
left: 180px;
|
||||||
|
width: calc(30% - 180px);
|
||||||
|
}
|
||||||
|
.note-panel-container {
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.master-note-edit {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
background: var(--small_element_bg_color);
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.master-note-edit + .master-note-edit {
|
||||||
|
border-left: 2px solid var(--main-accent);
|
||||||
|
border-left: 5px solid var(--border_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
761
client/src/pages/OverviewPage.vue
Normal file
761
client/src/pages/OverviewPage.vue
Normal file
@ -0,0 +1,761 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page-container">
|
||||||
|
|
||||||
|
<div class="ui grid" ref="content">
|
||||||
|
|
||||||
|
<div class="sixteen wide column">
|
||||||
|
<!-- :class="{ 'sixteen wide column':showOneColumn(), 'sixteen wide column':!showOneColumn() }" -->
|
||||||
|
|
||||||
|
<div class="ui stackable grid">
|
||||||
|
|
||||||
|
<div class="six wide column" v-if="$store.getters.totals && $store.getters.totals['totalNotes']">
|
||||||
|
<search-input />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ten wide column" :class="{ 'sixteen wide column':$store.getters.getIsUserOnMobile }">
|
||||||
|
|
||||||
|
<div class="ui basic button shrinking"
|
||||||
|
v-on:click="updateFastFilters(3)"
|
||||||
|
v-if="$store.getters.totals && ($store.getters.totals['youGotMailCount'] > 0)"
|
||||||
|
style="position: relative;">
|
||||||
|
<i class="green mail icon"></i>Inbox
|
||||||
|
<span class="tiny circular floating ui green label">+{{ $store.getters.totals['youGotMailCount'] }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<tag-display
|
||||||
|
:active-tags="searchTags"
|
||||||
|
v-on:tagClick="tagId => toggleTagFilter(tagId)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="ui basic shrinking icon button" v-on:click="toggleTitleView()" v-if="$store.getters.totals && $store.getters.totals['totalNotes'] > 0">
|
||||||
|
<i v-if="titleView" class="th icon"></i>
|
||||||
|
<i v-if="!titleView" class="bars icon"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="eight wide column" v-if="showClear">
|
||||||
|
<!-- <fast-filters /> -->
|
||||||
|
<span class="ui fluid green button" @click="reset">
|
||||||
|
<i class="arrow circle left icon"></i>Show All Notes
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sixteen wide column" v-if="searchTerm.length > 0 && !loadingInProgress">
|
||||||
|
<h2 class="ui header">
|
||||||
|
<div class="content">
|
||||||
|
{{ searchResultsCount.toLocaleString() }} notes with keyword "{{ searchTerm }}"
|
||||||
|
<div v-if="searchResultsCount == 0" class="sub header">
|
||||||
|
Search can only find key words. Try a single word search.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="fastFilters['onlyArchived'] == 1" class="sixteen wide column">
|
||||||
|
<h2>Archived Notes</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sixteen wide column" v-if="fastFilters['onlyShowTrashed'] == 1">
|
||||||
|
<h2>Trash
|
||||||
|
<span>({{ $store.getters.totals['trashedNotes'] }})</span>
|
||||||
|
<div class="ui right floated basic button" data-tooltip="This doesn't work yet">
|
||||||
|
<i class="poo storm icon"></i>
|
||||||
|
Empty Trash
|
||||||
|
</div>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sixteen wide column" v-if="fastFilters['onlyShowSharedNotes'] == 1">
|
||||||
|
<h2>Shared Notes</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sixteen wide column" v-if="tagSuggestions.length > 0">
|
||||||
|
<h5 class="ui tiny dividing header"><i class="green tags icon"></i> Tags ({{ tagSuggestions.length }})</h5>
|
||||||
|
<div class="ui clickable green label" v-for="tag in tagSuggestions" v-on:click="tagId => toggleTagFilter(tag.id)">
|
||||||
|
<i class="tag icon"></i>
|
||||||
|
{{ tag.text }}
|
||||||
|
</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 -->
|
||||||
|
<div class="sixteen wide column">
|
||||||
|
|
||||||
|
<h3 v-if="$store.getters.totals && $store.getters.totals['totalNotes'] == 0 && fastFilters['notesHome'] == 1">
|
||||||
|
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.
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<!-- Go to one wide column, do not do this on mobile interface -->
|
||||||
|
<div :class="{'one-column':( showOneColumn() )}">
|
||||||
|
|
||||||
|
<!-- render each section based on notes in set -->
|
||||||
|
<div v-for="section,index in noteSections" v-if="section.length > 0" class="note-card-section">
|
||||||
|
<h5 class="ui tiny dividing header"><i :class="`green ${sectionData[index][0]} icon`"></i>{{ sectionData[index][1] }}</h5>
|
||||||
|
|
||||||
|
<div class="note-card-display-area">
|
||||||
|
<note-title-display-card
|
||||||
|
v-on:tagClick="tagId => toggleTagFilter(tagId)"
|
||||||
|
v-for="note in section"
|
||||||
|
:ref="'note-'+note.id"
|
||||||
|
:onClick="openNote"
|
||||||
|
:data="note"
|
||||||
|
:title-view="titleView"
|
||||||
|
:currently-open="activeNoteId1 == note.id"
|
||||||
|
:key="note.id + note.color + '-' +note.title.length + '-' +note.subtext.length + '-' + note.tag_count + note.updated"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<loading-icon v-if="loadingInProgress" message="Decrypting Notes" />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<note-input-panel
|
||||||
|
v-if="activeNoteId1 != null"
|
||||||
|
:key="activeNoteId1"
|
||||||
|
:noteid="activeNoteId1"
|
||||||
|
:url-data="$route.params"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SearchBar',
|
||||||
|
components: {
|
||||||
|
|
||||||
|
'note-input-panel': () => import(/* webpackChunkName: "NoteInputPanel" */ '@/components/NoteInputPanel.vue'),
|
||||||
|
|
||||||
|
'note-title-display-card': require('@/components/NoteTitleDisplayCard.vue').default,
|
||||||
|
// 'fast-filters': require('@/components/FastFilters.vue').default,
|
||||||
|
'search-input': require('@/components/SearchInput.vue').default,
|
||||||
|
'attachment-display': require('@/components/AttachmentDisplayCard').default,
|
||||||
|
'counter':require('@/components/AnimatedCounterComponent.vue').default,
|
||||||
|
'tag-display':require('@/components/TagDisplayComponent.vue').default,
|
||||||
|
'loading-icon':require('@/components/LoadingIconComponent.vue').default,
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
initComponent: true,
|
||||||
|
tagSuggestions:[],
|
||||||
|
searchTerm: '',
|
||||||
|
searchResultsCount: 0,
|
||||||
|
searchTags: [],
|
||||||
|
notes: [],
|
||||||
|
highlights: [],
|
||||||
|
searchDebounce: null,
|
||||||
|
fastFilters: {},
|
||||||
|
titleView: false,
|
||||||
|
|
||||||
|
//Load up notes in batches
|
||||||
|
firstLoadBatchSize: 10, //First set of rapidly loaded notes
|
||||||
|
batchSize: 25, //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,
|
||||||
|
scrollLoadEnabled: true,
|
||||||
|
|
||||||
|
//Clear button is not visible
|
||||||
|
showClear: false,
|
||||||
|
initialPostData: null,
|
||||||
|
|
||||||
|
//Currently open notes in app
|
||||||
|
activeNoteId1: null,
|
||||||
|
activeNoteId2: null,
|
||||||
|
|
||||||
|
//Position determines how note is Positioned
|
||||||
|
activeNote1Position: 0,
|
||||||
|
activeNote2Position: 0,
|
||||||
|
|
||||||
|
lastVisibilityState: null,
|
||||||
|
|
||||||
|
foundAttachments: [],
|
||||||
|
|
||||||
|
sectionData: {
|
||||||
|
'pinned': ['thumbtack', 'Pinned'],
|
||||||
|
'archived': ['archive', 'Archived'],
|
||||||
|
'shared': ['envelope outline', 'Inbox'],
|
||||||
|
'sent': ['paper plane outline', 'Sent Notes'],
|
||||||
|
'notes': ['file','Notes'],
|
||||||
|
'highlights': ['paragraph', 'Found In Text'],
|
||||||
|
'trashed': ['poop', 'Trashed Notes'],
|
||||||
|
'tagged': ['tag', 'Tagged'],
|
||||||
|
},
|
||||||
|
noteSections: {
|
||||||
|
pinned: [],
|
||||||
|
archived: [],
|
||||||
|
shared:[],
|
||||||
|
sent:[],
|
||||||
|
notes: [],
|
||||||
|
highlights: [],
|
||||||
|
trashed: [],
|
||||||
|
tagged:[],
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeMount(){
|
||||||
|
|
||||||
|
this.$parent.loginGateway()
|
||||||
|
|
||||||
|
this.$io.on('new_note_created', noteId => {
|
||||||
|
|
||||||
|
//Do not update note if its open
|
||||||
|
if(this.activeNoteId1 != noteId){
|
||||||
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||||
|
this.updateSingleNote(noteId, false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$io.on('note_attribute_modified', noteId => {
|
||||||
|
//Do not update note if its open
|
||||||
|
if(this.activeNoteId1 != noteId){
|
||||||
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||||
|
this.updateSingleNote(noteId, false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//Update title cards when new note text is saved
|
||||||
|
this.$io.on('new_note_text_saved', ({noteId, hash}) => {
|
||||||
|
|
||||||
|
//Do not update note if its open
|
||||||
|
if(this.activeNoteId1 != noteId){
|
||||||
|
this.updateSingleNote(noteId, true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$bus.$on('update_single_note', (noteId) => {
|
||||||
|
//Do not update note if its open
|
||||||
|
if(this.activeNoteId1 != noteId){
|
||||||
|
this.updateSingleNote(noteId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
//Update totals for app
|
||||||
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||||
|
|
||||||
|
//Close note event
|
||||||
|
this.$bus.$on('close_active_note', ({noteId, modified}) => {
|
||||||
|
|
||||||
|
if(modified){
|
||||||
|
console.log('Just closed Note -> ' + noteId + ', modified -> ', modified)
|
||||||
|
}
|
||||||
|
|
||||||
|
//A note has been closed
|
||||||
|
if(this.$route.fullPath != '/notes'){
|
||||||
|
this.$router.push('/notes')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||||
|
//Focus and animate if modified
|
||||||
|
this.updateSingleNote(noteId, modified)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$bus.$on('note_deleted', (noteId) => {
|
||||||
|
//Remove deleted note from set, its deleted
|
||||||
|
|
||||||
|
Object.keys(this.noteSections).forEach( key => {
|
||||||
|
this.noteSections[key].forEach( (note, index) => {
|
||||||
|
if(note.id == noteId){
|
||||||
|
this.noteSections[key].splice(index,1)
|
||||||
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$bus.$on('update_fast_filters', filterIndex => {
|
||||||
|
|
||||||
|
this.updateFastFilters(filterIndex)
|
||||||
|
})
|
||||||
|
|
||||||
|
//Event to update search from other areas
|
||||||
|
this.$bus.$on('update_search_term', sentInSearchTerm => {
|
||||||
|
this.searchTerm = sentInSearchTerm
|
||||||
|
this.search(true, this.batchSize)
|
||||||
|
.then( () => {
|
||||||
|
|
||||||
|
this.searchAttachments()
|
||||||
|
|
||||||
|
const postData = {
|
||||||
|
'tagText':this.searchTerm.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tagSuggestions = []
|
||||||
|
axios.post('/api/tag/suggest', postData)
|
||||||
|
.then( response => {
|
||||||
|
|
||||||
|
this.tagSuggestions = response.data
|
||||||
|
})
|
||||||
|
|
||||||
|
// return
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
//Reload page content - don't trigger if load is in progress
|
||||||
|
this.$bus.$on('note_reload', () => {
|
||||||
|
if(!this.loadingInProgress){
|
||||||
|
this.reset()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
window.addEventListener('scroll', this.onScroll)
|
||||||
|
|
||||||
|
//Close notes when back button is pressed
|
||||||
|
// window.addEventListener('hashchange', this.hashChangeAction)
|
||||||
|
|
||||||
|
//update note on visibility change
|
||||||
|
// document.addEventListener('visibilitychange', this.visibiltyChangeAction);
|
||||||
|
|
||||||
|
},
|
||||||
|
beforeDestroy(){
|
||||||
|
window.removeEventListener('scroll', this.onScroll)
|
||||||
|
// document.removeEventListener('visibilitychange', this.visibiltyChangeAction)
|
||||||
|
|
||||||
|
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')
|
||||||
|
|
||||||
|
//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()
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
|
||||||
|
//Open note on load if ID is set
|
||||||
|
if(this.$route.params.id > 1){
|
||||||
|
this.activeNoteId1 = this.$route.params.id
|
||||||
|
}
|
||||||
|
|
||||||
|
//Loads initial batch and tags
|
||||||
|
this.reset()
|
||||||
|
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'$route.params.id': function(id){
|
||||||
|
//Open note on ID, null id will close note
|
||||||
|
this.activeNoteId1 = id
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleTitleView(){
|
||||||
|
this.titleView = !this.titleView
|
||||||
|
},
|
||||||
|
showOneColumn(){
|
||||||
|
|
||||||
|
return this.$store.getters.getIsUserOnMobile
|
||||||
|
|
||||||
|
//If note 1 or 2 is open, show one column. Or if the user is on mobile
|
||||||
|
return (this.activeNoteId1 != null || this.activeNoteId2 != null) &&
|
||||||
|
!this.$store.getters.getIsUserOnMobile
|
||||||
|
},
|
||||||
|
openNote(id, 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 }
|
||||||
|
}
|
||||||
|
|
||||||
|
//Open note if a link was not clicked
|
||||||
|
this.$router.push('/notes/open/'+id)
|
||||||
|
return
|
||||||
|
},
|
||||||
|
toggleTagFilter(tagId){
|
||||||
|
|
||||||
|
this.searchTags = [tagId]
|
||||||
|
|
||||||
|
//Reset note set and load up notes and tags
|
||||||
|
if(this.searchTags.length > 0){
|
||||||
|
this.search(true, this.batchSize)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//If no tags are selected, reset entire page
|
||||||
|
this.reset()
|
||||||
|
|
||||||
|
},
|
||||||
|
onScroll(e){
|
||||||
|
|
||||||
|
clearTimeout(this.loadingBatchTimeout)
|
||||||
|
this.loadingBatchTimeout = setTimeout(() => {
|
||||||
|
|
||||||
|
//Detect distance scrolled down the page
|
||||||
|
const scrolledDown = window.pageYOffset + window.innerHeight
|
||||||
|
//Get height of div to properly detect scroll distance down
|
||||||
|
const height = document.getElementById('app').scrollHeight
|
||||||
|
|
||||||
|
//Load if less than 500px from the bottom
|
||||||
|
if(((height - scrolledDown) < 500) && this.scrollLoadEnabled && !this.loadingInProgress){
|
||||||
|
|
||||||
|
this.search(false, this.batchSize, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 30)
|
||||||
|
|
||||||
|
|
||||||
|
return
|
||||||
|
},
|
||||||
|
visibiltyChangeAction(event){
|
||||||
|
|
||||||
|
//Fuck this shit, just use web sockets
|
||||||
|
return
|
||||||
|
|
||||||
|
//@TODO - phase this out, 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.lastVisibilityState = document.visibilityState
|
||||||
|
|
||||||
|
},
|
||||||
|
// @TODO Don't even trigger this if the note wasn't changed
|
||||||
|
updateSingleNote(noteId, focuseAndAnimate = true){
|
||||||
|
|
||||||
|
noteId = parseInt(noteId)
|
||||||
|
|
||||||
|
//Find local note, if it exists; continue
|
||||||
|
let note = null
|
||||||
|
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0] && this.$refs['note-'+noteId][0].note){
|
||||||
|
note = this.$refs['note-'+noteId][0].note
|
||||||
|
//Show that note is working on updating
|
||||||
|
this.$refs['note-'+noteId][0].showWorking = true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Lookup one note using passed in ID
|
||||||
|
const postData = {
|
||||||
|
searchQuery: this.searchTerm,
|
||||||
|
searchTags: this.searchTags,
|
||||||
|
fastFilters:{
|
||||||
|
noteIdSet:[noteId]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Note data must be fetched, then sorted into existing note data
|
||||||
|
axios.post('/api/note/search', postData)
|
||||||
|
.then(results => {
|
||||||
|
|
||||||
|
//Pull note data out of note set
|
||||||
|
let newNote = results.data.notes[0]
|
||||||
|
|
||||||
|
if(newNote === undefined){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if(note && newNote){
|
||||||
|
|
||||||
|
//go through each prop and update it with new values
|
||||||
|
Object.keys(newNote).forEach(prop => {
|
||||||
|
note[prop] = newNote[prop]
|
||||||
|
})
|
||||||
|
|
||||||
|
//Push new note to front if its modified or we want it to
|
||||||
|
if( focuseAndAnimate || note.updated != newNote.updated ){
|
||||||
|
|
||||||
|
// Find note, in section, move to front
|
||||||
|
Object.keys(this.noteSections).forEach( key => {
|
||||||
|
this.noteSections[key].forEach( (searchNote, index) => {
|
||||||
|
if(searchNote.id == noteId){
|
||||||
|
//Remove note from location and push to front
|
||||||
|
this.noteSections[key].splice(index, 1)
|
||||||
|
this.noteSections[key].unshift(note)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.$nextTick( () => {
|
||||||
|
//Trigger close animation on note
|
||||||
|
this.$refs['note-'+noteId][0].justClosed()
|
||||||
|
this.$refs['note-'+noteId][0].showWorking = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//New notes don't exist in list, push them to the front
|
||||||
|
if(note == null){
|
||||||
|
this.noteSections.notes.unshift(newNote)
|
||||||
|
//Trigger close animation on note
|
||||||
|
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0]){
|
||||||
|
this.$refs['note-'+noteId][0].justClosed()
|
||||||
|
this.$refs['note-'+noteId][0].showWorking = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.$refs['note-'+noteId] && this.$refs['note-'+noteId][0]){
|
||||||
|
this.$refs['note-'+noteId][0].showWorking = false
|
||||||
|
}
|
||||||
|
|
||||||
|
//Trigger section rebuild
|
||||||
|
this.rebuildNoteCategorise()
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error)
|
||||||
|
this.$bus.$emit('notification', 'Failed to Update Note')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
searchAttachments(){
|
||||||
|
axios.post('/api/attachment/textsearch', {'searchTerm':this.searchTerm})
|
||||||
|
.then(results => {
|
||||||
|
this.foundAttachments = results.data
|
||||||
|
})
|
||||||
|
.catch(error => { this.$bus.$emit('notification', 'Failed to Search Attachments') })
|
||||||
|
},
|
||||||
|
search(showLoading = true, notesInNextLoad = 10, mergeExisting = false){
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
//Don't double load note batches
|
||||||
|
if(this.loadingInProgress){
|
||||||
|
console.log('Loading already in progress')
|
||||||
|
return resolve(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
//Reset a lot of stuff if we are not merging batches
|
||||||
|
if(!mergeExisting){
|
||||||
|
Object.keys(this.noteSections).forEach( key => {
|
||||||
|
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
|
||||||
|
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
|
||||||
|
axios.post('/api/note/search', postData)
|
||||||
|
.then(response => {
|
||||||
|
|
||||||
|
// console.timeEnd('Fetch TitleCard Batch '+notesInNextLoad)
|
||||||
|
|
||||||
|
//Save the number of notes just loaded
|
||||||
|
this.batchOffset += response.data.notes.length
|
||||||
|
|
||||||
|
//Enable or disable scroll loading
|
||||||
|
this.scrollLoadEnabled = response.data.notes.length > 0
|
||||||
|
|
||||||
|
if(response.data.total > 0){
|
||||||
|
this.searchResultsCount = response.data.total
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadingInProgress = false
|
||||||
|
this.generateNoteCategories(response.data.notes, mergeExisting)
|
||||||
|
|
||||||
|
return resolve(true)
|
||||||
|
})
|
||||||
|
.catch(error => { this.$bus.$emit('notification', 'Failed to Search Notes') })
|
||||||
|
})
|
||||||
|
},
|
||||||
|
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
|
||||||
|
|
||||||
|
//Reset all sections if we are not merging existing
|
||||||
|
if(!mergeExisting){
|
||||||
|
Object.keys(this.noteSections).forEach( key => {
|
||||||
|
this.noteSections[key] = []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sort notes into defined sections
|
||||||
|
notes.forEach(note => {
|
||||||
|
|
||||||
|
if(this.searchTerm.length > 0){
|
||||||
|
if(note.pinned == 1){
|
||||||
|
this.noteSections.pinned.push(note)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Push to default note section
|
||||||
|
this.noteSections.notes.push(note)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Display all tags in tag section
|
||||||
|
if(this.searchTags.length >= 1){
|
||||||
|
this.noteSections.tagged.push(note)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Only show trashed notes when trashed
|
||||||
|
if(this.fastFilters.onlyShowTrashed == 1){
|
||||||
|
|
||||||
|
if(note.trashed == 1){
|
||||||
|
this.noteSections.trashed.push(note)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(note.trashed == 1){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Show archived notes
|
||||||
|
if(this.fastFilters.onlyArchived == 1){
|
||||||
|
|
||||||
|
if(note.pinned == 1 && note.archived == 1){
|
||||||
|
this.noteSections.pinned.push(note)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(note.archived == 1){
|
||||||
|
this.noteSections.archived.push(note)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(note.archived == 1){ return }
|
||||||
|
|
||||||
|
//Only show sent notes section if shared is selected
|
||||||
|
if(this.fastFilters.onlyShowSharedNotes == 1){
|
||||||
|
|
||||||
|
if(note.shared == 2){
|
||||||
|
this.noteSections.sent.push(note)
|
||||||
|
}
|
||||||
|
if(note.shareUsername != null){
|
||||||
|
this.noteSections.shared.push(note)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//Show shared notes on main list but not notes shared with you
|
||||||
|
if(note.shareUsername != null){ return }
|
||||||
|
|
||||||
|
// Pinned notes are always first, they can appear in the archive
|
||||||
|
if(note.pinned == 1){
|
||||||
|
this.noteSections.pinned.push(note)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Push to default note section
|
||||||
|
this.noteSections.notes.push(note)
|
||||||
|
|
||||||
|
return
|
||||||
|
})
|
||||||
|
|
||||||
|
},
|
||||||
|
reset(){
|
||||||
|
this.showClear = false
|
||||||
|
this.scrollLoadEnabled = true
|
||||||
|
this.searchTerm = ''
|
||||||
|
this.searchTags = []
|
||||||
|
this.tagSuggestions = []
|
||||||
|
this.fastFilters = {}
|
||||||
|
this.foundAttachments = [] //Remove all attachments
|
||||||
|
|
||||||
|
this.updateFastFilters(5) //This loads notes
|
||||||
|
|
||||||
|
},
|
||||||
|
updateFastFilters(index){
|
||||||
|
|
||||||
|
//clear out tags
|
||||||
|
this.searchTags = []
|
||||||
|
this.tagSuggestions = []
|
||||||
|
this.loadingInProgress = false
|
||||||
|
this.searchTerm = ''
|
||||||
|
this.$bus.$emit('reset_fast_filters') //Clear out search
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
'withLinks', // 'Only Show Notes with Links'
|
||||||
|
'withTags', // 'Only Show Notes with Tags'
|
||||||
|
'onlyArchived', //'Only Show Archived Notes'
|
||||||
|
'onlyShowSharedNotes', //Only show shared notes
|
||||||
|
'onlyShowTrashed',
|
||||||
|
'notesHome',
|
||||||
|
]
|
||||||
|
|
||||||
|
let filter = {}
|
||||||
|
filter[options[index]] = 1
|
||||||
|
|
||||||
|
this.fastFilters = filter
|
||||||
|
//Fetch First batch of notes with new filter
|
||||||
|
this.search(true, this.firstLoadBatchSize, false)
|
||||||
|
.then( r => this.search(false, this.batchSize, true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style type="text/css" scoped>
|
||||||
|
|
||||||
|
.detail {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.note-card-display-area {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.display-area-title {
|
||||||
|
width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.note-card-section {
|
||||||
|
/*padding-bottom: 15px;*/
|
||||||
|
}
|
||||||
|
.note-card-section + .note-card-section {
|
||||||
|
padding: 15px 0 0;
|
||||||
|
}
|
||||||
|
</style>
|
@ -48,7 +48,7 @@ export default new Vuex.Store({
|
|||||||
'small_element_bg_color': '#000',
|
'small_element_bg_color': '#000',
|
||||||
'text_color': '#FFF',
|
'text_color': '#FFF',
|
||||||
'dark_border_color': '#555',//'#ACACAC', //Lighter color to accent elemnts user can interact with
|
'dark_border_color': '#555',//'#ACACAC', //Lighter color to accent elemnts user can interact with
|
||||||
'border_color': '#555',
|
'border_color': '#0b0110',
|
||||||
'menu-accent': '#626262',
|
'menu-accent': '#626262',
|
||||||
'menu-text': '#d9d9d9',
|
'menu-text': '#d9d9d9',
|
||||||
},
|
},
|
||||||
|
158
configs/dev nginx sites available default.cfg
Normal file
158
configs/dev nginx sites available default.cfg
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
#
|
||||||
|
# Working dev server config
|
||||||
|
#
|
||||||
|
|
||||||
|
server {
|
||||||
|
|
||||||
|
listen 443 ssl;
|
||||||
|
|
||||||
|
ssl_certificate /home/mab/ss/client/certs/192.168.1.164+4.pem;
|
||||||
|
ssl_certificate_key /home/mab/ss/client/certs/192.168.1.164+4-key.pem;
|
||||||
|
ssl_session_cache shared:SSL:1m;
|
||||||
|
ssl_session_timeout 5m;
|
||||||
|
ssl_protocols TLSV1.1 TLSV1.2 TLSV1.3;
|
||||||
|
|
||||||
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
|
||||||
|
access_log /var/log/nginx/httpslocalhost.access.log;
|
||||||
|
error_log /var/log/nginx/httpslocalhost.error.log;
|
||||||
|
|
||||||
|
client_max_body_size 20M;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass https://127.0.0.1:8081;
|
||||||
|
proxy_set_header Host localhost;
|
||||||
|
proxy_set_header X-Forwarded-Host localhost;
|
||||||
|
proxy_set_header X-Forwarded-Server localhost;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_connect_timeout 90s;
|
||||||
|
proxy_read_timeout 90s;
|
||||||
|
proxy_send_timeout 90s;
|
||||||
|
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /sockjs-node {
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-NginX-Proxy true;
|
||||||
|
|
||||||
|
proxy_pass https://127.0.0.1:8081;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api {
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-NginX-Proxy true;
|
||||||
|
|
||||||
|
proxy_pass http://127.0.0.1:3000;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /socket {
|
||||||
|
proxy_pass http://127.0.0.1:3001;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "Upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
##
|
||||||
|
## Working Copy below --------------------------------------------
|
||||||
|
##
|
||||||
|
|
||||||
|
server {
|
||||||
|
|
||||||
|
listen 443 ssl;
|
||||||
|
|
||||||
|
ssl_certificate /home/mab/ss/client/certs/192.168.1.164+4.pem;
|
||||||
|
ssl_certificate_key /home/mab/ss/client/certs/192.168.1.164+4-key.pem;
|
||||||
|
ssl_session_cache shared:SSL:1m;
|
||||||
|
ssl_session_timeout 5m;
|
||||||
|
ssl_protocols TLSV1.1 TLSV1.2 TLSV1.3;
|
||||||
|
|
||||||
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
|
||||||
|
access_log /var/log/nginx/httpslocalhost.access.log;
|
||||||
|
error_log /var/log/nginx/httpslocalhost.error.log;
|
||||||
|
|
||||||
|
client_max_body_size 20M;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass https://127.0.0.1:8081;
|
||||||
|
proxy_set_header Host localhost;
|
||||||
|
proxy_set_header X-Forwarded-Host localhost;
|
||||||
|
proxy_set_header X-Forwarded-Server localhost;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_connect_timeout 90s;
|
||||||
|
proxy_read_timeout 90s;
|
||||||
|
proxy_send_timeout 90s;
|
||||||
|
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /sockjs-node {
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-NginX-Proxy true;
|
||||||
|
|
||||||
|
proxy_pass https://127.0.0.1:8081;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api {
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-NginX-Proxy true;
|
||||||
|
|
||||||
|
proxy_pass http://127.0.0.1:3000;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /socket {
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-NginX-Proxy true;
|
||||||
|
|
||||||
|
proxy_pass http://127.0.0.1:3001;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Prod settings to serve static index
|
||||||
|
# location / {
|
||||||
|
# autoindex on;
|
||||||
|
# #try_files $uri $uri/ /index.html;
|
||||||
|
# }
|
||||||
|
|
||||||
|
# location / {
|
||||||
|
# #autoindex on
|
||||||
|
#
|
||||||
|
# proxy_pass http://127.0.0.1:8444;
|
||||||
|
# proxy_http_version 1.1;
|
||||||
|
# proxy_set_header Upgrade $http_upgrade;
|
||||||
|
# proxy_set_header Connection 'upgrade';
|
||||||
|
# proxy_set_header Host $host;
|
||||||
|
# proxy_cache_bypass $http_upgrade;
|
||||||
|
# }
|
@ -46,14 +46,17 @@ Attachment.textSearch = (userId, searchTerm) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Attachment.search = (userId, noteId, attachmentType, offset, setSize) => {
|
Attachment.search = (userId, noteId, attachmentType, offset, setSize, includeShared) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
let params = [userId]
|
let params = [userId]
|
||||||
let query = 'SELECT * FROM attachment WHERE user_id = ? AND visible = 1 '
|
let query = `
|
||||||
|
SELECT attachment.*, note.share_user_id FROM attachment
|
||||||
|
JOIN note ON (attachment.note_id = note.id)
|
||||||
|
WHERE attachment.user_id = ? AND visible = 1 `
|
||||||
|
|
||||||
if(noteId && noteId > 0){
|
if(noteId && noteId > 0){
|
||||||
query += 'AND note_id = ? '
|
query += 'AND attachment.note_id = ? '
|
||||||
params.push(noteId)
|
params.push(noteId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,11 +67,16 @@ Attachment.search = (userId, noteId, attachmentType, offset, setSize) => {
|
|||||||
query += 'AND attachment_type > 1 '
|
query += 'AND attachment_type > 1 '
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!noteId){
|
||||||
|
const sharedOrNot = includeShared ? ' NOT ':' '
|
||||||
|
query += `AND note.share_user_id IS${sharedOrNot}NULL `
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
query += 'ORDER BY last_indexed DESC '
|
query += 'ORDER BY last_indexed DESC '
|
||||||
|
|
||||||
const limitOffset = parseInt(offset, 10) || 0 //Either parse int, or use zero
|
const limitOffset = parseInt(offset, 10) || 0 //Either parse int, or use zero
|
||||||
const parsedSetSize = parseInt(setSize, 10) || 20 //Either parse int, or use zero
|
const parsedSetSize = parseInt(setSize, 10) || 20
|
||||||
query += ` LIMIT ${limitOffset}, ${parsedSetSize}`
|
query += ` LIMIT ${limitOffset}, ${parsedSetSize}`
|
||||||
|
|
||||||
db.promise()
|
db.promise()
|
||||||
|
@ -9,7 +9,7 @@ const speakeasy = require('speakeasy')
|
|||||||
|
|
||||||
let User = module.exports = {}
|
let User = module.exports = {}
|
||||||
|
|
||||||
const version = '3.4.3'
|
const version = '3.5.0'
|
||||||
|
|
||||||
//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
|
||||||
@ -255,7 +255,7 @@ User.getCounts = (userId) => {
|
|||||||
WHERE user_id = ?
|
WHERE user_id = ?
|
||||||
GROUP BY tag_id
|
GROUP BY tag_id
|
||||||
ORDER BY uses DESC
|
ORDER BY uses DESC
|
||||||
LIMIT 5
|
LIMIT 16
|
||||||
`, [userId])
|
`, [userId])
|
||||||
|
|
||||||
}).then( (rows, fields) => {
|
}).then( (rows, fields) => {
|
||||||
|
@ -26,7 +26,7 @@ router.use(function setUserId (req, res, next) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
router.post('/search', function (req, res) {
|
router.post('/search', function (req, res) {
|
||||||
Attachment.search(userId, req.body.noteId, req.body.attachmentType, req.body.offset, req.body.setSize)
|
Attachment.search(userId, req.body.noteId, req.body.attachmentType, req.body.offset, req.body.setSize, req.body.includeShared)
|
||||||
.then( data => res.send(data) )
|
.then( data => res.send(data) )
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user