Remove TinyMce Added Squire
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
<link rel="shortcut icon" href="/api/static/assets/favicon.ico" type="image/x-icon"/>
|
||||
|
||||
<meta name="theme-color" content="#000" />
|
||||
<link rel="manifest" href="/api/static/assets/manifest.webmanifest">
|
||||
|
||||
<title>Notes</title>
|
||||
</head>
|
||||
|
@@ -13,8 +13,10 @@
|
||||
"dependencies": {
|
||||
"axios": "^0.18.0",
|
||||
"es6-promise": "^4.2.6",
|
||||
"pell": "^1.0.6",
|
||||
"postcss-loader": "^2.1.6",
|
||||
"raw-loader": "^0.5.1",
|
||||
"socket.io-client": "^2.3.0",
|
||||
"vue": "^2.5.2",
|
||||
"vue-router": "^3.0.1",
|
||||
"vuex": "^3.1.0"
|
||||
|
@@ -10,6 +10,8 @@
|
||||
|
||||
<script>
|
||||
|
||||
// import io from 'socket.io-client'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
'global-site-menu': require('@/components/GlobalSiteMenu.vue').default,
|
||||
@@ -21,6 +23,12 @@ export default {
|
||||
},
|
||||
beforeCreate: function(){
|
||||
|
||||
// const socket = io({ path:'/socket' });
|
||||
const socket = this.$io
|
||||
socket.on('connect', () => {
|
||||
this.$store.commit('setSocketIoSocket', socket.id)
|
||||
})
|
||||
|
||||
//Detect if user is on a mobile browser and set a flag in store
|
||||
this.$store.commit('detectIsUserOnMobile')
|
||||
|
||||
@@ -39,7 +47,7 @@ export default {
|
||||
|
||||
},
|
||||
mounted: function(){
|
||||
|
||||
|
||||
},
|
||||
computed: {
|
||||
loggedIn () {
|
||||
|
@@ -1,140 +1,276 @@
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Roboto'), local('Roboto-Regular'), url(/static/fonts/roboto-latin.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Roboto'), local('Roboto-Regular'), url(/static/fonts/roboto-latin.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Roboto Bold'), local('Roboto-Bold'), url(/static/fonts/roboto-latin-bold.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: local('Roboto Bold'), local('Roboto-Bold'), url(/static/fonts/roboto-latin-bold.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
|
||||
:root {
|
||||
--background_color: #fff;
|
||||
--text_color: #3d3d3d;
|
||||
--outline_color: rgba(34,36,38,.15);
|
||||
--border_color: rgba(34,36,38,.20);
|
||||
--background_color: #fff;
|
||||
--text_color: #3d3d3d;
|
||||
--outline_color: rgba(34,36,38,.15);
|
||||
--border_color: rgba(34,36,38,.20);
|
||||
}
|
||||
|
||||
div.ui.basic.segment.no-fluf-segment {
|
||||
margin-top: 0px;
|
||||
}
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
/* OVERWRITE DEFAULT SEMANTIC STYLES FOR CUSTOM/NIGHT MODES*/
|
||||
body{
|
||||
color: var(--text_color);
|
||||
background-color: var(--background_color);
|
||||
background-color: var(--background_color);
|
||||
font-family: 'Roboto', 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.ui.form input:not([type]),
|
||||
.ui.form input:not([type]):focus,
|
||||
.ui.form textarea:not([type]),
|
||||
.ui.form textarea:not([type]):focus {
|
||||
color: var(--text_color);
|
||||
background-color: var(--background_color);
|
||||
border-color: var(--border_color);
|
||||
color: var(--text_color);
|
||||
background-color: var(--background_color);
|
||||
border-color: var(--border_color);
|
||||
}
|
||||
.ui.basic.label, .ui.header, .ui.header div.sub.header {
|
||||
color: var(--text_color);
|
||||
background-color: var(--background_color);
|
||||
border-color: var(--border_color);
|
||||
color: var(--text_color);
|
||||
background-color: var(--background_color);
|
||||
border-color: var(--border_color);
|
||||
}
|
||||
div.ui.basic.green.label {
|
||||
background-color: var(--background_color) !important;
|
||||
background-color: var(--background_color) !important;
|
||||
}
|
||||
.ui.basic.button, .ui.basic.buttons .button {
|
||||
background-color: var(--background_color) !important;
|
||||
color: var(--text_color) !important;
|
||||
border: 1px solid;
|
||||
border-color: var(--border_color) !important;
|
||||
box-shadow: none;
|
||||
background-color: var(--background_color) !important;
|
||||
color: var(--text_color) !important;
|
||||
border: 1px solid;
|
||||
border-color: var(--border_color) !important;
|
||||
box-shadow: none;
|
||||
}
|
||||
.ui.basic.button:focus, .ui.basic.button:hover {
|
||||
background-color: var(--background_color) !important;
|
||||
color: var(--text_color) !important;
|
||||
box-shadow: none;
|
||||
background-color: var(--background_color) !important;
|
||||
color: var(--text_color) !important;
|
||||
box-shadow: none;
|
||||
}
|
||||
.ui.tabular.menu .item {
|
||||
background-color: var(--background_color) !important;
|
||||
color: var(--text_color) !important;
|
||||
background-color: var(--background_color) !important;
|
||||
color: var(--text_color) !important;
|
||||
}
|
||||
.ui.tabular.menu .item.active {
|
||||
background-color: var(--background_color) !important;
|
||||
color: var(--text_color) !important;
|
||||
border-color: var(--border_color) !important;
|
||||
background-color: var(--background_color) !important;
|
||||
color: var(--text_color) !important;
|
||||
border-color: var(--border_color) !important;
|
||||
}
|
||||
/* OVERWRITE DEFAULT SEMANTIC STYLES FOR CUSTOM/NIGHT MODES*/
|
||||
|
||||
/* Styles for public display pages */
|
||||
.fun {
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
color: var(--text_color);
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
color: var(--text_color);
|
||||
}
|
||||
.fun h1 {
|
||||
font-size: 2em;
|
||||
font-size: 2em;
|
||||
}
|
||||
.fun h2 {
|
||||
font-size: 1.9em;
|
||||
font-size: 1.9em;
|
||||
}
|
||||
.fun h3 {
|
||||
font-size: 1.7em;
|
||||
font-size: 1.7em;
|
||||
}
|
||||
.fun p {
|
||||
/*font-size: 1.5em;*/
|
||||
/*font-size: 1.5em;*/
|
||||
}
|
||||
.fun blockquote {
|
||||
border-left: 5px solid cornflowerblue;
|
||||
padding-left: 25px;
|
||||
margin-left: 5px;
|
||||
border-left: 5px solid cornflowerblue;
|
||||
padding-left: 25px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
/* Styles for public display pages */
|
||||
|
||||
.note-status-indicator {
|
||||
position: absolute;
|
||||
width: 100px;
|
||||
padding: 16px 0;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
color: var(--text_color);
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
cursor: pointer;
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.note-status-indicator {
|
||||
position: absolute;
|
||||
width: 100px;
|
||||
padding: 16px 0;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
color: var(--text_color);
|
||||
bottom: -13px;
|
||||
right: -7px;
|
||||
z-index: 100;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* squire text styles */
|
||||
.squire-box {
|
||||
border: none;
|
||||
height: calc(100% - 60px);
|
||||
box-sizing: border-box;
|
||||
padding: 10px 15px 40px;
|
||||
background: transparent;
|
||||
overflow-x: scroll;
|
||||
/*color: var(--text_color);*/
|
||||
font-size: 1.2em;
|
||||
line-height: 1.5em;
|
||||
word-wrap: break-word;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
/*Makes the first line real big */
|
||||
.squire-box p:first-child {
|
||||
font-size: 1.4em;
|
||||
line-height: 1.7em;
|
||||
}
|
||||
.squire-box:focus {
|
||||
outline: none;
|
||||
}
|
||||
.squire-box span.size {
|
||||
line-height: 1.3em;
|
||||
}
|
||||
.squire-box a {
|
||||
cursor: pointer;
|
||||
}
|
||||
.note-card-text i,
|
||||
.squire-box i {
|
||||
padding: 0.5em 0.99em;
|
||||
border: 1px solid #CCC;
|
||||
margin: 1px;
|
||||
border-radius: 9px;
|
||||
display: inline-block;
|
||||
}
|
||||
.squire-box p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.squire-box blockquote {
|
||||
margin: 0;
|
||||
padding: 0.8em;
|
||||
border-left: 2px solid blue;
|
||||
}
|
||||
.note-card-text img {
|
||||
max-width:100%;
|
||||
height: auto;
|
||||
max-height: 200px;
|
||||
}
|
||||
.squire-box img {
|
||||
max-width:100%;
|
||||
height: auto;
|
||||
}
|
||||
.note-card-text li > p,
|
||||
.squire-box p,
|
||||
.squire-box li > p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.note-card-text ul > li,
|
||||
.squire-box ul > li {
|
||||
position: relative;
|
||||
list-style-type: none;
|
||||
}
|
||||
.note-card-text ul > li:before,
|
||||
.squire-box ul > li:before {
|
||||
|
||||
content: "\f111";
|
||||
font-family: 'Icons';
|
||||
backface-visibility: hidden;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
text-decoration: inherit;
|
||||
text-align: center;
|
||||
line-height: 1.4em;
|
||||
font-size: 0.75em;
|
||||
|
||||
height: 17px;
|
||||
width: 17px;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
|
||||
left: -30px;
|
||||
/*border: 2px solid #444;*/
|
||||
/*border-radius: 4px;*/
|
||||
bottom: 0;
|
||||
top: 4px;
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
}
|
||||
ul > li.active:before {
|
||||
|
||||
font-family: 'Icons';
|
||||
content: "\f058";
|
||||
color: #21BA45;
|
||||
opacity: 1;
|
||||
}
|
||||
/* adjust checkboxes for mobile. Make them a little bigger, easier to click */
|
||||
@media only screen and (max-width: 740px) {
|
||||
|
||||
.note-card-text ul > li,
|
||||
.squire-box ul > li {
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
.note-card-text ul > li:before,
|
||||
.squire-box ul > li:before {
|
||||
|
||||
content: "\f111";
|
||||
font-family: outline-icons;
|
||||
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
|
||||
left: -40px;
|
||||
bottom: 0;
|
||||
top: 0px;
|
||||
cursor: pointer;
|
||||
|
||||
line-height: 0.9em;
|
||||
font-size: 1.4em;
|
||||
}
|
||||
ul > li.active:before {
|
||||
|
||||
font-family: 'Icons';
|
||||
content: "\f058";
|
||||
color: #21BA45;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.relative {
|
||||
position: relative;
|
||||
position: relative;
|
||||
}
|
||||
.float-right {
|
||||
float: right;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.textarea-height {
|
||||
height: calc(100% - 90px);
|
||||
height: calc(100% - 90px);
|
||||
}
|
||||
.mobile-textarea-height {
|
||||
height: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ui.white.button {
|
||||
background: #FFF;
|
||||
}
|
||||
.input-floating-button {
|
||||
position: absolute;
|
||||
top: 19px;
|
||||
transform: translateY(-50%);
|
||||
right: 1px;
|
||||
position: absolute;
|
||||
top: 19px;
|
||||
transform: translateY(-50%);
|
||||
right: 1px;
|
||||
}
|
||||
|
||||
.fade-in-fwd {
|
||||
@@ -147,12 +283,12 @@ div.ui.basic.green.label {
|
||||
* ----------------------------------------
|
||||
*/
|
||||
@keyframes fade-in-fwd {
|
||||
0% {
|
||||
transform: translateZ(-80px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateZ(0);
|
||||
opacity: 1;
|
||||
}
|
||||
0% {
|
||||
transform: translateZ(-80px);
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
transform: translateZ(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
4995
client/src/assets/squire.js
Normal file
4995
client/src/assets/squire.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,81 +2,125 @@
|
||||
|
||||
.attachment-display-card {
|
||||
width: 100%;
|
||||
padding: 0 0 20px;
|
||||
padding: 10px;
|
||||
display: inline-block;
|
||||
border: 1px solid;
|
||||
border-color: var(--border_color);
|
||||
border-radius: 4px;
|
||||
margin: 0 0 15px;
|
||||
max-height: 10000px;
|
||||
}
|
||||
|
||||
.attachment-image {
|
||||
width: 100%;
|
||||
max-width: 150px;
|
||||
float: left;
|
||||
margin: 0 15px 0 0;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
max-height: 300px;
|
||||
}
|
||||
.image-placeholder {
|
||||
width: 150px;
|
||||
height: 60px;
|
||||
border: 1px solid #DDD;
|
||||
float: left;
|
||||
margin: 0 15px 0 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: 100px;
|
||||
}
|
||||
.image-placeholder:after {
|
||||
content: 'No Image';
|
||||
display: block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background:
|
||||
green;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
|
||||
.text {
|
||||
width: 100%;
|
||||
/*height: 100%;*/
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-top: 1px solid;
|
||||
border-bottom: 1px solid;
|
||||
font-size: 1.4em;
|
||||
margin: 0 0 10px;
|
||||
line-height: 1.4em;
|
||||
border-color: var(--border_color);
|
||||
font-size: 1.2em;
|
||||
line-height: 1.3em;
|
||||
/*margin: 0 0 10px;*/
|
||||
padding: 10px 0 10px;
|
||||
|
||||
color: var(--text_color);
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
/*transition: height 0.4s ease; This breaks the resize */
|
||||
}
|
||||
.link {
|
||||
font-size: 1.4em;
|
||||
margin: 0 0 5px;
|
||||
margin: 20px 0 20px;
|
||||
display: inline-block;
|
||||
white-space:nowrap;
|
||||
white-space: nowrap;
|
||||
overflow:hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: calc(100% - 180px);
|
||||
width: 100%;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
.flip-out {
|
||||
animation: flip-out-hor-top 0.5s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease;
|
||||
max-height: 0;
|
||||
}
|
||||
@keyframes flip-out-hor-top {
|
||||
0% {
|
||||
transform: rotateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: rotateX(70deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div class="attachment-display-card">
|
||||
<div class="attachment-display-card" :class="{ 'flip-out':!unfolded }" v-if="visible">
|
||||
<div class="ui stackable grid">
|
||||
|
||||
<!-- image and text -->
|
||||
<div class="six wide center aligned middle aligned column">
|
||||
<a :href="linkUrl" target="_blank" >
|
||||
<img v-if="item.file_location" class="attachment-image" :src="`/api/static/thumb_${item.file_location}`">
|
||||
<span v-else>
|
||||
<img class="image-placeholder" loading="lazy" src="/api/static/assets/marketing/void.svg">
|
||||
No Image
|
||||
</span>
|
||||
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<input class="text" v-on:blur="saveIt()" v-model="text"></input>
|
||||
<div class="ten wide column">
|
||||
<textarea ref="edit" class="text" v-on:blur="saveIt()" v-on:keyup="checkKeyup" v-model="text"></textarea>
|
||||
|
||||
<div v-if="item.attachment_type == 1">
|
||||
<div class="image-holder" v-if="item.file_location">
|
||||
<a v-if="item.file_location" :href="item.url" target="_blank">
|
||||
<img class="attachment-image" :src="`/api/static/${item.file_location}`">
|
||||
</a>
|
||||
<!-- link -->
|
||||
<a class="link" :href="linkUrl" target="_blank">{{linkText}}</a>
|
||||
|
||||
<!-- Buttons -->
|
||||
<div class="ui small compact basic button" v-on:click="openNote">
|
||||
<i class="file icon"></i>
|
||||
Open Note
|
||||
</div>
|
||||
<div v-else class="image-placeholder"></div>
|
||||
|
||||
<a class="link" v-if="item.url" :href="item.url" target="_blank">{{item.url}}</a>
|
||||
</div>
|
||||
|
||||
<div v-if="item.attachment_type == 2">
|
||||
<div class="image-holder" v-if="item.file_location">
|
||||
<a v-if="item.file_location && item.type != 1" :href="`/api/static/${item.file_location}`" target="_blank">
|
||||
<img class="attachment-image" :src="`/api/static/${item.file_location}`">
|
||||
</a>
|
||||
<div class="ui small compact basic button" v-on:click="openEditAttachments"
|
||||
:class="{ 'disabled':this.searchParams.noteId }">
|
||||
<i class="folder icon"></i>
|
||||
Note Attachments
|
||||
</div>
|
||||
<div class="ui small compact basic icon button" v-on:click="deleteAttachment">
|
||||
<i v-if="!working" class="trash alternate outline icon"></i>
|
||||
<i v-if="working" class="purple spinner loading icon icon"></i>
|
||||
</div>
|
||||
<div v-else class="image-placeholder"></div>
|
||||
|
||||
<a class="link" v-if="item.file_location && item.type != 1" :href="`/api/static/${item.file_location}`" target="_blank">Download</a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="ui small compact basic button" v-on:click="openNote">
|
||||
Open Note
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@@ -84,23 +128,74 @@
|
||||
|
||||
export default {
|
||||
|
||||
props: [ 'item' ],
|
||||
props: [ 'item', 'searchParams' ],
|
||||
data: function(){
|
||||
return {
|
||||
things: [],
|
||||
text: '',
|
||||
type: null,
|
||||
|
||||
linkText: 'Link',
|
||||
linkUrl:null,
|
||||
|
||||
unfolded:true,
|
||||
visible: true,
|
||||
|
||||
working: false,
|
||||
}
|
||||
},
|
||||
beforeCreate: function(){
|
||||
},
|
||||
mounted: function(){
|
||||
this.text = this.item.text
|
||||
this.type = this.item.attachment_type
|
||||
|
||||
|
||||
//1 = URL, 2 = image, >= 3 files
|
||||
if(this.type == 1 && this.item.url != null){
|
||||
this.linkText = this.item.url
|
||||
this.linkUrl = this.item.url
|
||||
}
|
||||
if(this.type == 2){
|
||||
this.linkText = 'Download'
|
||||
this.linkUrl = `/api/static/${this.item.file_location}`
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.checkKeyup()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
checkKeyup(){
|
||||
let elm = this.$refs.edit
|
||||
if(elm){
|
||||
elm.style.height = '0'
|
||||
elm.style.height = elm.scrollHeight +'px'
|
||||
}
|
||||
},
|
||||
openNote(){
|
||||
const noteId = this.item.note_id
|
||||
this.$router.push('/notes/open/'+noteId)
|
||||
},
|
||||
openEditAttachments(){
|
||||
const noteId = this.item.note_id
|
||||
this.$router.push('/attachments/note/'+noteId)
|
||||
},
|
||||
deleteAttachment(){
|
||||
|
||||
//No double clicks
|
||||
if(this.working){ return }
|
||||
|
||||
this.working = true
|
||||
axios.post('/api/attachment/delete', {'attachmentId':this.item.id})
|
||||
.then( ({data}) => {
|
||||
if(data){
|
||||
this.unfolded = false
|
||||
setTimeout( () => {
|
||||
this.visible = false
|
||||
}, 600)
|
||||
}
|
||||
})
|
||||
},
|
||||
saveIt(){
|
||||
|
||||
//Don't save text if it didn'th change
|
||||
|
@@ -1,34 +1,68 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
|
||||
<div class="color-picker" :style="{ 'background-color':allStyles['noteBackground'], 'color':allStyles['noteText']}">
|
||||
<div class="ui grid">
|
||||
<div class="five wide column">
|
||||
<p>Note Color</p>
|
||||
<div v-for="color in colors"
|
||||
class="color-button"
|
||||
:style="{ backgroundColor:color }"
|
||||
v-on:click="chosenColor(color)"
|
||||
></div>
|
||||
</div>
|
||||
<div class="six wide column">
|
||||
<p>Note Icon
|
||||
<span v-if="allStyles.noteIcon" >
|
||||
<i :class="`large ${allStyles.noteIcon} icon`" :style="{ 'color':allStyles.iconColor }"></i>
|
||||
</span>
|
||||
</p>
|
||||
<div v-for="icon in icons" class="icon-button" v-on:click="chosenIcon(icon)" >
|
||||
<i :class="`large ${icon} icon`" :style="{ 'color':allStyles.iconColor }"></i>
|
||||
|
||||
<div class="floating-buttons">
|
||||
<div class="ui basic segment">
|
||||
<div class="ui fluid buttons">
|
||||
<div class="ui compact button" v-on:click="closeThisBitch">
|
||||
<i class="close icon"></i>
|
||||
Close
|
||||
</div>
|
||||
<div class="ui compact button" v-on:click="clearStyles">
|
||||
<i class="refresh icon"></i>
|
||||
Clear All Styles
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui compact fluid button" v-on:click="clearStyles">Clear All Styles</div>
|
||||
</div>
|
||||
<div class="five wide column">
|
||||
<p>Icon Color</p>
|
||||
<div v-for="color in colors"
|
||||
class="color-button"
|
||||
:style="{ backgroundColor:color }"
|
||||
v-on:click="chooseIconColor(color)"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui basic segment">
|
||||
<div class="ui grid">
|
||||
|
||||
<div class="row">
|
||||
<div class="sixteen wide column">
|
||||
<br>
|
||||
<p>Note Color</p>
|
||||
<div v-for="color in getReducedColors()"
|
||||
class="color-button"
|
||||
:style="{ backgroundColor:color }"
|
||||
v-on:click="chosenColor(color)"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="sixteen wide column">
|
||||
<p>Note Icon
|
||||
<span v-if="allStyles.noteIcon" >
|
||||
<i :class="`large ${allStyles.noteIcon} icon`" :style="{ 'color':allStyles.iconColor }"></i>
|
||||
</span>
|
||||
</p>
|
||||
<div v-for="icon in icons" class="icon-button" v-on:click="chosenIcon(icon)" >
|
||||
<i :class="`large ${icon} icon`" :style="{ 'color':allStyles.iconColor }"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="sixteen wide column">
|
||||
<p>Icon Color</p>
|
||||
<div v-for="color in getReducedColors()"
|
||||
class="color-button"
|
||||
:style="{ backgroundColor:color }"
|
||||
v-on:click="chooseIconColor(color)"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="shade-boy" v-on:click="closeThisBitch"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -55,9 +89,33 @@
|
||||
this.allStyles = this.styleObject
|
||||
},
|
||||
methods: {
|
||||
getReducedColors(){
|
||||
|
||||
let reduced = []
|
||||
|
||||
this.colors.forEach((color,i) => {
|
||||
|
||||
if(i%20 <= 10){
|
||||
return
|
||||
}
|
||||
|
||||
let mod = (i % 10)+1 //1 - 10
|
||||
let lines = [3, 5, 8, 9, 10]
|
||||
if(lines.includes(mod)){
|
||||
reduced.push(color)
|
||||
}
|
||||
})
|
||||
|
||||
reduced.push("#000")
|
||||
|
||||
return reduced
|
||||
},
|
||||
clearStyles(){
|
||||
this.$emit('changeColor', this.blankStyle)
|
||||
},
|
||||
closeThisBitch(){
|
||||
this.$emit('close')
|
||||
},
|
||||
chosenColor(inColor){
|
||||
|
||||
//Set not background to color that was chosen
|
||||
@@ -99,33 +157,55 @@
|
||||
}
|
||||
</script>
|
||||
<style type="text/css" scoped>
|
||||
.shade-boy {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 250;
|
||||
cursor: pointer;
|
||||
}
|
||||
.floating-buttons {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
z-index: 444;
|
||||
right: 20px;
|
||||
left: calc(30% + 10px)
|
||||
}
|
||||
.color-picker {
|
||||
color: var(--text_color);
|
||||
background-color: var(--background_color);
|
||||
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
|
||||
/*height: 100px;*/
|
||||
top: 37px;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 30%;
|
||||
bottom: 0;
|
||||
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
left: -63px;
|
||||
z-index: 300;
|
||||
border: 1px solid;
|
||||
|
||||
z-index: 500;
|
||||
border-left: 1px solid;
|
||||
border-color: var(--border_color) !important;
|
||||
|
||||
width: 750px;
|
||||
overflow-x: scroll;
|
||||
|
||||
}
|
||||
.icon-button {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
height: 40px;
|
||||
width: 14.2%;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
font-size: 1.3em;
|
||||
}
|
||||
.color-button {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
display: inline-block;
|
||||
height: 50px;
|
||||
width: 20%;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
float: left;
|
||||
}
|
||||
</style>
|
@@ -2,21 +2,20 @@
|
||||
.hidden-up {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: -500px;
|
||||
top: -50000px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div class="ui small compact basic icon button clickable">
|
||||
<form>
|
||||
<label :for="`upfile-${noteId}`" class="clickable">
|
||||
<i class="upload icon"></i>
|
||||
Upload File <span v-if="uploadPercentage != 0">{{uploadPercentage}}%</span>
|
||||
</label>
|
||||
<input class="hidden-up" type="file" :id="`upfile-${noteId}`" ref="file" v-on:change="handleFileUpload()" />
|
||||
</form>
|
||||
<form>
|
||||
<label :for="`upfile-${noteId}`" class="clickable">
|
||||
<i class="upload icon"></i>
|
||||
<span v-if="uploadPercentage != 0">{{uploadPercentage}}%</span>
|
||||
<span v-else>Upload</span>
|
||||
</label>
|
||||
<input class="hidden-up" type="file" :id="`upfile-${noteId}`" ref="file" v-on:change="handleFileUpload()" />
|
||||
<!-- <button v-if="file" v-on:click="uploadFileToServer()">Submit</button> -->
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -50,37 +49,26 @@
|
||||
}
|
||||
}
|
||||
).then(results => {
|
||||
this.uploadPercentage = 0
|
||||
this.uploadPercentage = 'Working'
|
||||
this.file = null
|
||||
console.log('SUCCESS!!');
|
||||
|
||||
console.log('File upload results')
|
||||
console.log(results.data)
|
||||
// console.log('File upload results')
|
||||
// console.log(results.data)
|
||||
|
||||
const name = results.data.fileName
|
||||
const location = results.data.fileLocation
|
||||
const location = results.data.goodFileName
|
||||
|
||||
if(name && location){
|
||||
|
||||
const imageCode = `<img alt="yup" height="200px" src="/api/static/${location}">`
|
||||
this.uploadPercentage = 0
|
||||
|
||||
//put cursor at the bottom of the window
|
||||
tinyMCE.activeEditor.selection.select(tinyMCE.activeEditor.getBody(), true);
|
||||
tinyMCE.activeEditor.selection.collapse(false);
|
||||
tinymce.activeEditor.execCommand('mceInsertContent', false, imageCode)
|
||||
const imageCode = `<img alt="image" src="/api/static/${location}">`
|
||||
|
||||
this.$bus.$emit('new_file_upload', {noteId: this.noteId, imageCode})
|
||||
}
|
||||
|
||||
//try and stick that file into the active editor
|
||||
// tinyMCE.execCommand(
|
||||
// 'mceInsertContent',
|
||||
// false,
|
||||
// '<img alt="Smiley face" height="42" width="42" src="' + src + '"/>'
|
||||
// );
|
||||
|
||||
})
|
||||
.catch(results => {
|
||||
this.uploadPercentage = 0
|
||||
console.log('FAILURE!!');
|
||||
})
|
||||
},
|
||||
handleFileUpload() {
|
||||
|
@@ -21,12 +21,15 @@
|
||||
|
||||
.menu-item {
|
||||
color: #fff;
|
||||
padding: 0.8em 0px 0.8em 0.8em;
|
||||
padding: 0.8em 0px 0.8em 10px;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
font-size: 1.15em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.menu-item i.icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.sub {
|
||||
padding-left: 20px;
|
||||
}
|
||||
@@ -40,6 +43,7 @@
|
||||
}
|
||||
.menu-button:hover {
|
||||
background-color: #534c68;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.router-link-active i {
|
||||
@@ -92,12 +96,20 @@
|
||||
<div class="top-menu-bar" v-if="(collapsed || mobile) && !menuOpen">
|
||||
<div class="ui grid">
|
||||
|
||||
<div class="three wide column">
|
||||
<div class="seven wide column">
|
||||
<div class="ui large basic compact icon button" v-on:click="collapseMenu">
|
||||
<i class="green bars icon"></i>
|
||||
</div>
|
||||
|
||||
<router-link class="ui large basic compact icon button" to="/notes" v-on:click.native="emitReloadEvent()">
|
||||
<i class="green home icon"></i>
|
||||
</router-link>
|
||||
|
||||
<div v-on:click="toggleNightMode" class="ui large basic compact icon button">
|
||||
<i class="green moon outline icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ten wide center aligned column">
|
||||
<div class="six wide center aligned column">
|
||||
<img v-if="!loggedIn" src="/api/static/assets/favicon.ico" alt="logo" />
|
||||
<search-input v-if="loggedIn"></search-input>
|
||||
</div>
|
||||
@@ -126,7 +138,7 @@
|
||||
|
||||
<div class="menu-section">
|
||||
<div class="menu-item menu-button" v-on:click="collapseMenu">
|
||||
<i class="caret square left outline icon"></i>
|
||||
<i class="angle left icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -144,16 +156,22 @@
|
||||
<i class="file icon"></i>Notes
|
||||
</router-link>
|
||||
<div>
|
||||
<div class="menu-item sub">Show Only <i class="caret down icon"></i></div>
|
||||
<div v-on:click="updateFastFilters(0)" class="menu-item menu-button sub"><i class="grey linkify icon"></i>Links</div>
|
||||
<div v-on:click="updateFastFilters(1)" class="menu-item menu-button sub"><i class="grey tags icon"></i>Tags</div>
|
||||
<div v-on:click="updateFastFilters(2)" class="menu-item menu-button sub"><i class="grey archive icon"></i>Archived</div>
|
||||
<!-- <div class="menu-item sub">Show Only <i class="caret down icon"></i></div> -->
|
||||
<!-- <div v-on:click="updateFastFilters(0)" class="menu-item menu-button sub"><i class="grey linkify icon"></i>Links</div> -->
|
||||
<!-- <div v-on:click="updateFastFilters(1)" class="menu-item menu-button sub"><i class="grey tags icon"></i>Tags</div> -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="menu-section" v-if="loggedIn">
|
||||
<div v-on:click="updateFastFilters(2)" class="menu-item menu-button">
|
||||
<i class="archive icon"></i>Archived
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="menu-section" v-if="loggedIn">
|
||||
<router-link class="menu-item menu-button" exact-active-class="active" to="/attachments">
|
||||
<i class="folder icon"></i>Attachments
|
||||
<i class="folder icon"></i>Files
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
@@ -176,9 +194,9 @@
|
||||
<div class="menu-section">
|
||||
<div v-on:click="toggleNightMode" class="menu-item menu-button">
|
||||
<span v-if="$store.getters.getIsNightMode">
|
||||
<i class="toggle on icon"></i>Dark Theme</span>
|
||||
<i class="moon outline icon"></i>Light Theme</span>
|
||||
<span v-else>
|
||||
<i class="toggle off icon"></i>Dark Theme</span>
|
||||
<i class="moon outline icon"></i>Dark Theme</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -266,7 +284,6 @@
|
||||
},
|
||||
toggleNightMode(){
|
||||
this.$store.commit('toggleNightMode')
|
||||
this.$bus.$emit('toggle_night_mode')
|
||||
},
|
||||
ucWords(str){
|
||||
return (str + '')
|
||||
|
@@ -4,7 +4,7 @@
|
||||
id="InputNotes"
|
||||
class="master-note-edit"
|
||||
@keyup.esc="close"
|
||||
:class="[{'size-down':(sizeDown == true)}, 'position-'+position ]"
|
||||
:class="[{'size-down':(sizeDown == true), 'padded-bottom':extraToolbarsVisible }, 'position-'+position ]"
|
||||
:style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}"
|
||||
>
|
||||
|
||||
@@ -15,64 +15,83 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="note-status-indicator" v-on:click="save()">{{statusText}}</span>
|
||||
<div class="note-menu">
|
||||
|
||||
<div class="nm-button" v-on:click="close">
|
||||
<i class="close icon"></i>
|
||||
</div>
|
||||
<div class="nm-button" v-on:click="toggleList('ol')">
|
||||
<i class="list ol icon"></i>
|
||||
</div>
|
||||
<div class="nm-button" v-on:click="toggleList('ul')">
|
||||
<i class="tasks icon"></i>
|
||||
</div>
|
||||
<div class="nm-button" v-on:click="toggleBold()">
|
||||
<i class="bold icon"></i>
|
||||
</div>
|
||||
|
||||
<div class="nm-button" v-on:click="toggleItalic()">
|
||||
<i class="quote left icon"></i>
|
||||
</div>
|
||||
|
||||
<div class="nm-button" v-on:click="modifyFont('2.286em') ">
|
||||
<i class="text height icon"></i>
|
||||
</div>
|
||||
|
||||
<div v-if="usersOnNote > 1" class="nm-button">
|
||||
<i class="green user circle icon"></i>{{usersOnNote}}
|
||||
</div>
|
||||
|
||||
<div class="tinymce-container">
|
||||
<textarea :id="noteid+'-tinymce-editor'">{{noteText}}</textarea>
|
||||
</div>
|
||||
|
||||
<div id="squire-id" class="squire-box" ref="squirebox"></div>
|
||||
|
||||
<!-- && this.$store.getters.getIsUserOnMobile -->
|
||||
<span class="note-status-indicator" v-on:click="save()" v-if="statusText != 'Saved' && $store.getters.getIsUserOnMobile">
|
||||
<div class="ui green button">{{statusText}}</div>
|
||||
</span>
|
||||
|
||||
<color-picker
|
||||
v-if="colorPickerVisible"
|
||||
:location="colorPickerLocation"
|
||||
@changeColor="onChangeColor"
|
||||
:style-object="styleObject"
|
||||
@changeColor="onChangeColor"
|
||||
@close="onCloseColorChanger"
|
||||
:style-object="styleObject"
|
||||
/>
|
||||
|
||||
<div v-if="$store.getters.getIsNoteSettingsOpen">
|
||||
|
||||
<div class="all-settings">
|
||||
<div class="ui grid">
|
||||
<div class="row">
|
||||
<div class="sixteen wide column">
|
||||
<!-- Note options on the bottom of note -->
|
||||
<div class="all-settings" :class="{ 'low-settings':!extraToolbarsVisible }">
|
||||
|
||||
<note-tag-edit :noteId="noteid" :key="'tags-for-note-'+noteid"/><br>
|
||||
<div class="note-menu">
|
||||
|
||||
<!-- close button -->
|
||||
<div class="ui small compact basic icon button" v-on:click="$store.commit('toggleNoteSettingsPane')">
|
||||
<i class="close icon"></i> Close Settings
|
||||
</div>
|
||||
<!-- Pin Button -->
|
||||
<div @click="onToggleArchived" class="ui small compact basic icon button">
|
||||
<i class="archive icon" :class="{green:(archived == 1)}"></i>
|
||||
{{(archived == 1)?'Archived':'Archive'}}
|
||||
</div>
|
||||
<!-- archive button -->
|
||||
<div @click="onTogglePinned" class="ui small compact basic icon button">
|
||||
<i class="pin icon" :class="{green:(pinned == 1)}"></i>
|
||||
{{(pinned == 1)?'Pinned':'Pin'}}
|
||||
</div>
|
||||
<!-- colors button -->
|
||||
<span class="relative" v-on:click="showColorPicker">
|
||||
<span class="ui small compact basic icon button">
|
||||
<i class="paint brush icon"></i>
|
||||
Colors
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<!-- attachment button -->
|
||||
<div v-if="attachmentCount > 0" class="ui small compact basic icon button" v-on:click="openEditAttachment">
|
||||
<i class="folder icon"></i> Attachments
|
||||
</div>
|
||||
<!-- file upload button -->
|
||||
<file-upload-button :noteId="noteid" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- <note-tag-edit :noteId="noteid" :key="'tags-for-note-'+noteid"/><br> -->
|
||||
|
||||
<!-- Pin Button -->
|
||||
<div @click="onToggleArchived" class="nm-button">
|
||||
<i class="archive icon" :class="{green:(archived == 1)}"></i>
|
||||
{{(archived == 1)?'Archived':'Archive'}}
|
||||
</div>
|
||||
<!-- archive button -->
|
||||
<div @click="onTogglePinned" class="nm-button">
|
||||
<i class="pin icon" :class="{green:(pinned == 1)}"></i>
|
||||
{{(pinned == 1)?'Pinned':'Pin'}}
|
||||
</div>
|
||||
<!-- colors button -->
|
||||
<span class="nm-button" v-on:click="showColorPicker">
|
||||
<i class="paint brush icon"></i>
|
||||
Colors
|
||||
</span>
|
||||
|
||||
<!-- attachment button -->
|
||||
<div class="nm-button" v-on:click="openEditAttachment">
|
||||
<i class="folder icon"></i> Files
|
||||
</div>
|
||||
<!-- file upload button -->
|
||||
<file-upload-button class="nm-button" :noteId="noteid" />
|
||||
|
||||
</div>
|
||||
<!-- <div class="shade" v-on:click="showAllSettings = false"></div> -->
|
||||
</div>
|
||||
<!-- <div class="shade" v-on:click="showAllSettings = false"></div> -->
|
||||
|
||||
</div>
|
||||
</template>
|
||||
@@ -80,6 +99,7 @@
|
||||
<script>
|
||||
|
||||
import axios from 'axios'
|
||||
const DiffMatchPatch = require('../../../server/helpers/DiffMatchPatch')
|
||||
|
||||
export default {
|
||||
name: 'InputNotes',
|
||||
@@ -96,11 +116,13 @@
|
||||
loadingMessage: 'Loading Note',
|
||||
currentNoteId: 0,
|
||||
noteText: '',
|
||||
diffNoteText: '',
|
||||
statusText: 'Saved',
|
||||
lastNoteHash: null,
|
||||
saveDebounce: null, //Prevent save from being called numerous times quickly
|
||||
updated: 'Never',
|
||||
editDebounce: null,
|
||||
emitChangeDebounce: null,
|
||||
keyPressesCounter: 0, //Determen keys pressed between saves
|
||||
pinned: 0,
|
||||
archived: 0,
|
||||
@@ -116,6 +138,13 @@
|
||||
//Settings vars
|
||||
showAllSettings: true,
|
||||
lastVisibilityState: null,
|
||||
|
||||
//All the squire settings
|
||||
editor: null,
|
||||
// pastFocusedNode: null,
|
||||
usersOnNote: 0,
|
||||
|
||||
extraToolbarsVisible: true,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -135,136 +164,189 @@
|
||||
}
|
||||
},
|
||||
beforeMount(){
|
||||
//Load tinymce into the page only do it once
|
||||
if(document.querySelectorAll('[data-mceload]').length == 0){
|
||||
let tinyMceIncluder = document.createElement('script')
|
||||
tinyMceIncluder.setAttribute('src', '/api/static/assets/tinymce/tinymce.min.js')
|
||||
tinyMceIncluder.setAttribute('data-mceload','loaded')
|
||||
document.head.appendChild(tinyMceIncluder)
|
||||
}
|
||||
this.$bus.$on('new_file_upload', ({noteId, imageCode}) => {
|
||||
if(this.noteid == noteId && this.editor){
|
||||
this.editor.moveCursorToEnd()
|
||||
this.editor.insertHTML(imageCode)
|
||||
}
|
||||
})
|
||||
},
|
||||
beforeDestroy(){
|
||||
|
||||
document.removeEventListener('visibilitychange', this.visibiltyChangeAction)
|
||||
this.$io.emit('leave_room', this.noteid)
|
||||
|
||||
// this.$off() // Remove all event listeners
|
||||
// this.$bus.$off()
|
||||
document.removeEventListener('visibilitychange', this.checkForUpdatedNote)
|
||||
|
||||
//Trash editor instance on close
|
||||
this.tinymce.remove()
|
||||
this.editor.destroy()
|
||||
|
||||
this.$bus.$off('new_file_upload')
|
||||
|
||||
},
|
||||
mounted: function() {
|
||||
|
||||
//Change TinyMce styles on nightmored change
|
||||
this.$bus.$on('toggle_night_mode', this.setEditorTextColor )
|
||||
|
||||
document.addEventListener('visibilitychange', this.checkForUpdatedNote)
|
||||
|
||||
this.$nextTick(() => {
|
||||
|
||||
this.loadNote(this.noteid)
|
||||
|
||||
//Tell server to push this note into a room
|
||||
this.$io.emit('join_room', this.noteid)
|
||||
|
||||
this.$io.on('update_user_count', userCount => {
|
||||
this.usersOnNote = userCount
|
||||
})
|
||||
|
||||
//Server will hand deliver diffs from other notes to this one
|
||||
this.$io.on('incoming_diff', incomingDiffData => {
|
||||
this.patchText(incomingDiffData)
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
},
|
||||
methods: {
|
||||
initTinyMce(){
|
||||
initSquire(){
|
||||
|
||||
//Set up squire and load note text
|
||||
this.editor = new Squire( this.$refs.squirebox, {blockTag: 'p' })
|
||||
this.setText(this.noteText)
|
||||
|
||||
// image_list: [
|
||||
// {title: 'My image 1', value: 'https://www.tinymce.com/my1.gif'},
|
||||
// {title: 'My image 2', value: 'http://www.moxiecode.com/my2.gif'}
|
||||
// ]
|
||||
//Open links when clicked in editor
|
||||
this.editor.addEventListener('click', e => {
|
||||
|
||||
//Default plugin options for big browsers
|
||||
let toolbarOptions = 'customCloseButton | mceTogglePinned | forecolor styleselect | bold italic underline | link | bullist numlist | outdent indent table | h | image'
|
||||
let pluginOptions = 'paste, link, code, lists, table, hr, image'
|
||||
//Link clicked in editor - open link
|
||||
if(e.target.nodeName == 'A' && e.target.href){
|
||||
window.open(e.target.href)
|
||||
}
|
||||
|
||||
//Tweak doc height for mobile
|
||||
let docHeight = 'calc(100vh - 1px)'
|
||||
if(this.$store.getters.getIsUserOnMobile){
|
||||
docHeight = 'calc(100vh - 1px)'
|
||||
//List Item clicked in editor - toggle link state
|
||||
if(e.target.nodeName == 'LI'){
|
||||
|
||||
toolbarOptions = 'customCloseButton | bullist numlist | mceTogglePinned'
|
||||
pluginOptions = 'lists'
|
||||
}
|
||||
let el = e.target
|
||||
|
||||
//setup skin as dark if night mode is enabled
|
||||
let skin = 'oxide'
|
||||
if(this.$store.getters.getIsNightMode){
|
||||
skin = 'oxide-dark'
|
||||
}
|
||||
//Adjust ofset by 40 px
|
||||
let correction = 40
|
||||
|
||||
const editorId = '#'+this.noteid+'-tinymce-editor'
|
||||
let vm = this
|
||||
//Determine if element was clicked or area before it, before means checkbox was clicked
|
||||
if (e.offsetX > e.target.offsetLeft - correction) {
|
||||
//Element was clicked
|
||||
} else {
|
||||
|
||||
//Globally defined included in index HTML
|
||||
tinymce.init({
|
||||
selector: editorId,
|
||||
toolbar: toolbarOptions,
|
||||
plugins: pluginOptions,
|
||||
browser_spellcheck: true,
|
||||
menubar: false,
|
||||
branding: false,
|
||||
statusbar: false,
|
||||
height: docHeight,
|
||||
skin: skin,
|
||||
contextmenu: false,
|
||||
init_instance_callback: this.editorInitCallback,
|
||||
imagetools_toolbar: "imageoptions",
|
||||
setup: editor => {
|
||||
//Add custom buttons to tinymce instance
|
||||
editor.ui.registry.addButton('customCloseButton', {
|
||||
text: 'Close',
|
||||
icon: 'close',
|
||||
onAction: function (_) {
|
||||
vm.close()
|
||||
//Will hide keyboard if clicked, much better for mobile
|
||||
this.editor.blur()
|
||||
|
||||
//Area before element was clicked, they clicked the checkbox
|
||||
this.onKeyup()
|
||||
if (el.className === 'active'){
|
||||
el.className = 'inactive';
|
||||
} else {
|
||||
el.className = 'active';
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//Add custom buttons to tinymce instance
|
||||
editor.ui.registry.addButton('mceTogglePinned', {
|
||||
text: 'Note Settings',
|
||||
icon: 'settings',
|
||||
onAction: function (_) {
|
||||
vm.$store.commit('toggleNoteSettingsPane')
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
this.editor.addEventListener('keydown', event => {
|
||||
|
||||
//Prevent new list items from having
|
||||
this.$nextTick( () => {
|
||||
//Wait a moment to get item under cursor
|
||||
let selection = this.editor.getSelection()
|
||||
let container = selection.commonAncestorContainer
|
||||
|
||||
//If user hit enter on a list, make sure the next list item isn't active
|
||||
if(container.nodeName == 'LI' && event.keyCode == 13 && container.classList){
|
||||
container.classList.remove('active')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
//Bind event handlers
|
||||
this.editor.addEventListener('keyup', event => this.onKeyup(event) )
|
||||
|
||||
//Show and hide additional toolbars
|
||||
this.editor.addEventListener('focus', e => {
|
||||
if(this.$store.getters.getIsUserOnMobile){
|
||||
this.extraToolbarsVisible = false
|
||||
}
|
||||
})
|
||||
this.editor.addEventListener('blur', e => {
|
||||
this.save()
|
||||
this.extraToolbarsVisible = true
|
||||
})
|
||||
},
|
||||
editorInitCallback(editor){
|
||||
//If nothing is selected, select the entire line
|
||||
selectLineIfNoSelect(){
|
||||
//Select entire line if range is not set
|
||||
let selection = this.editor.getSelection()
|
||||
|
||||
this.loading = false //Turn off loading screed when editor is loaded
|
||||
this.tinymce = editor
|
||||
if(selection.startOffset == selection.endOffset && selection.startContainer == selection.endContainer){
|
||||
|
||||
this.setEditorTextColor()
|
||||
|
||||
editor
|
||||
.on('Change', this.onKeyup )
|
||||
.on('keyup', this.onKeyup )
|
||||
.on('blur', this.save )
|
||||
let squireRange = this.editor.createRange(
|
||||
selection.startContainer, 0,
|
||||
selection.endContainer, selection.commonAncestorContainer.textContent.length)
|
||||
|
||||
this.editor.setSelection(squireRange)
|
||||
}
|
||||
},
|
||||
setEditorTextColor(){
|
||||
//Only Set editor text color, background is transparent and set on parent element
|
||||
modifyFont(inSize){
|
||||
this.selectLineIfNoSelect()
|
||||
|
||||
//There may be scenarios where editor has not been set up
|
||||
if(this.tinymce){
|
||||
//Set editor color to color from app, change with night mode
|
||||
this.tinymce.getBody().style.color = getComputedStyle(document.documentElement)
|
||||
.getPropertyValue('--text_color');
|
||||
let fontInfo = this.editor.getFontInfo()
|
||||
//Toggle font size between large and normal
|
||||
if(fontInfo.size){
|
||||
this.editor.setFontSize(null)
|
||||
} else {
|
||||
this.editor.setFontSize(inSize)
|
||||
}
|
||||
},
|
||||
toggleList(type){
|
||||
|
||||
//Overwrite set color if theme is set for note.
|
||||
if(this.styleObject && this.styleObject.noteText){
|
||||
this.tinymce.getBody().style.color = this.styleObject.noteText
|
||||
}
|
||||
//Undo list if its already a lits
|
||||
if(this.editor.hasFormat(type)){
|
||||
this.editor.removeList()
|
||||
return
|
||||
}
|
||||
|
||||
if(type == 'ol'){
|
||||
this.editor.makeOrderedList()
|
||||
}
|
||||
if(type == 'ul'){
|
||||
this.editor.makeUnorderedList()
|
||||
}
|
||||
},
|
||||
toggleBold(){
|
||||
this.selectLineIfNoSelect()
|
||||
if( this.editor.hasFormat('b') ){
|
||||
this.editor.removeBold()
|
||||
} else {
|
||||
this.editor.bold()
|
||||
}
|
||||
},
|
||||
toggleItalic(){
|
||||
this.selectLineIfNoSelect()
|
||||
if( this.editor.hasFormat('i') ){
|
||||
this.editor.removeItalic()
|
||||
} else {
|
||||
this.editor.italic()
|
||||
}
|
||||
},
|
||||
setText(inText){
|
||||
return this.tinymce.setContent(inText)
|
||||
|
||||
this.editor.setHTML(inText)
|
||||
this.noteText = this.editor._getHTML()
|
||||
this.diffNoteText = this.editor._getHTML()
|
||||
},
|
||||
getText(){
|
||||
//Return text from tinyMce Editor
|
||||
return this.tinymce.getContent()
|
||||
|
||||
return this.editor.getHTML()
|
||||
},
|
||||
showColorPicker(event){
|
||||
this.colorPickerVisible = !this.colorPickerVisible
|
||||
@@ -293,13 +375,14 @@
|
||||
this.lastNoteHash = 0
|
||||
this.save()
|
||||
},
|
||||
onCloseColorChanger(){
|
||||
this.colorPickerVisible = false
|
||||
},
|
||||
onChangeColor(newStyleObject){
|
||||
|
||||
//Set new style object for note, page will use some styles, styles will be saved to database
|
||||
this.styleObject = newStyleObject
|
||||
|
||||
this.setEditorTextColor()
|
||||
|
||||
this.lastNoteHash = 0 //Update hash to force note update on next save
|
||||
this.save()
|
||||
},
|
||||
@@ -320,11 +403,15 @@
|
||||
|
||||
//Set up local data
|
||||
vm.currentNoteId = noteId
|
||||
|
||||
vm.noteText = response.data.text
|
||||
vm.diffNoteText = response.data.text
|
||||
|
||||
vm.updated = response.data.updated
|
||||
vm.lastNoteHash = vm.hashString(response.data.text)
|
||||
//Set up note colors
|
||||
if(response.data.color){
|
||||
vm.styleObject = JSON.parse(response.data.color) //Load styles json from DB
|
||||
vm.styleObject = JSON.parse(response.data.color)
|
||||
}
|
||||
|
||||
if(response.data.pinned != null){
|
||||
@@ -333,8 +420,11 @@
|
||||
vm.archived = response.data.archived
|
||||
vm.attachmentCount = response.data.attachment_count
|
||||
|
||||
this.loading = false
|
||||
|
||||
vm.$nextTick(() => {
|
||||
this.initTinyMce()
|
||||
// this.initTinyMce()
|
||||
this.initSquire()
|
||||
})
|
||||
|
||||
})
|
||||
@@ -342,9 +432,176 @@
|
||||
console.log('Could not fetch note')
|
||||
}
|
||||
},
|
||||
onKeyup(){
|
||||
diffText(){
|
||||
|
||||
this.statusText = 'Modified'
|
||||
// dont emit to one user
|
||||
if(this.usersOnNote <= 1){
|
||||
return
|
||||
}
|
||||
|
||||
//Post latest diff to server, server will emit change event to all connected clients
|
||||
// clearTimeout(this.emitChangeDebounce)
|
||||
this.emitChangeDebounce = setTimeout(i => {
|
||||
|
||||
//caldulate text diff
|
||||
let oldText = this.diffNoteText
|
||||
let newText = this.getText()
|
||||
|
||||
if(oldText == newText){
|
||||
return
|
||||
}
|
||||
|
||||
const dmp = new DiffMatchPatch.diff_match_patch()
|
||||
const diff = dmp.diff_main(oldText, newText)
|
||||
// dmp.diff_cleanupSemantic(diff)
|
||||
const patch_list = dmp.patch_make(oldText, newText, diff);
|
||||
const patch_text = dmp.patch_toText(patch_list);
|
||||
|
||||
|
||||
var patches = dmp.patch_fromText(patch_text);
|
||||
var results = dmp.patch_apply(patches, oldText);
|
||||
|
||||
const computedText = results[0]
|
||||
|
||||
//Save computed diff text
|
||||
this.noteText = computedText
|
||||
this.diffNoteText = computedText
|
||||
|
||||
if(patch_text == ''){
|
||||
return
|
||||
}
|
||||
|
||||
// console.log(patch_text)
|
||||
this.$io.emit('note_diff', {
|
||||
id:this.currentNoteId,
|
||||
diff:patch_text
|
||||
})
|
||||
|
||||
|
||||
}, 5)
|
||||
},
|
||||
patchText(patch_text){
|
||||
|
||||
console.log(patch_text)
|
||||
|
||||
//
|
||||
// Capture x,y of caret and position into string
|
||||
//
|
||||
|
||||
let currentSelection = this.editor.getSelection()
|
||||
let lineText = currentSelection.startContainer.textContent
|
||||
console.log(lineText)
|
||||
let cursorOffset = parseInt(currentSelection.startOffset) //number of characters in
|
||||
let path = this.xpath(currentSelection.commonAncestorContainer.parentElement)
|
||||
console.log(path)
|
||||
|
||||
|
||||
//
|
||||
//Set up text to process diff
|
||||
//
|
||||
|
||||
let currentText = this.editor._getHTML()
|
||||
const startingLines = (currentText.match(/<br>/g) || '').length + 1
|
||||
console.log('1')
|
||||
|
||||
const dmp = new DiffMatchPatch.diff_match_patch()
|
||||
var patches = dmp.patch_fromText(patch_text);
|
||||
var results = dmp.patch_apply(patches, currentText);
|
||||
let newText = results[0]
|
||||
console.log('2')
|
||||
|
||||
this.noteText = newText
|
||||
this.diffNoteText = newText
|
||||
console.log('3')
|
||||
// this.editor._setHTML(newText)
|
||||
this.editor.setHTML(newText)
|
||||
|
||||
console.log('4')
|
||||
|
||||
//
|
||||
// I user hasn't selected the document, we are done here
|
||||
// @TODO add code to halt execution
|
||||
//
|
||||
|
||||
const endingLines = (newText.match(/<br>/g) || '').length + 1
|
||||
|
||||
// if(this.pastFocusedNode != null || true){
|
||||
setTimeout( ()=>{
|
||||
|
||||
var root = this.editor.getRoot()
|
||||
//Get node under current x,y on dom (may break on scroll)
|
||||
// let node = document.elementFromPoint(mouse.x, mouse.y)
|
||||
let node = this.getElementByXPath(path)
|
||||
|
||||
if(node.firstChild){
|
||||
node = node.firstChild
|
||||
}
|
||||
|
||||
//If the number of lines changed
|
||||
if(startingLines != endingLines){
|
||||
|
||||
//Line diff may be +1 or -1
|
||||
let lineDiff = endingLines - startingLines
|
||||
console.log('Line Diff => ', lineDiff)
|
||||
|
||||
//Pull out node number from path
|
||||
var nodeNumber = path.match(/\d+/)
|
||||
let modifyNode = null
|
||||
if(nodeNumber.length == 1){
|
||||
modifyNode = parseInt(nodeNumber[0])
|
||||
}
|
||||
|
||||
path = path.replace(modifyNode, modifyNode + lineDiff )
|
||||
console.log(path)
|
||||
let maybeNext = this.getElementByXPath(path)
|
||||
if(maybeNext && maybeNext.firstChild){
|
||||
maybeNext = maybeNext.firstChild
|
||||
}
|
||||
|
||||
if(maybeNext && maybeNext.textContent == lineText){
|
||||
node = maybeNext
|
||||
console.log('The Node Moved!')
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Targeting Node')
|
||||
console.log(node)
|
||||
|
||||
//Create and set range
|
||||
let squireRange = this.editor.createRange(node, cursorOffset)
|
||||
squireRange.collapse(true)
|
||||
this.editor.setSelection(squireRange)
|
||||
console.log('cursor set')
|
||||
|
||||
}, 20)
|
||||
// }
|
||||
|
||||
|
||||
|
||||
},
|
||||
xpath(el) {
|
||||
//Skip things we can't use
|
||||
if (typeof el == "string") return document.evaluate(el, document, null, 0, null)
|
||||
if (!el || el.nodeType != 1) return ''
|
||||
|
||||
//Anchor xpath using Ids or test-ids
|
||||
const testId = el.getAttribute('test-id')
|
||||
if (el.id) return "//*[@id='" + el.id + "']"
|
||||
|
||||
//Continue to build path
|
||||
const sames = [].filter.call(el.parentNode.children, function (x) { return x.tagName == el.tagName })
|
||||
return this.xpath(el.parentNode) + '/' + el.tagName.toLowerCase() + (sames.length > 1 ? '['+([].indexOf.call(sames, el)+1)+']' : '')
|
||||
},
|
||||
getElementByXPath(xpath) {
|
||||
return new XPathEvaluator()
|
||||
.createExpression(xpath)
|
||||
.evaluate(document, XPathResult.FIRST_ORDERED_NODE_TYPE) .singleNodeValue
|
||||
},
|
||||
onKeyup(event){
|
||||
|
||||
this.statusText = 'Save'
|
||||
|
||||
this.diffText()
|
||||
|
||||
//Each note, save after 5 seconds, focus lost or 30 characters typed.
|
||||
clearTimeout(this.editDebounce)
|
||||
@@ -364,6 +621,8 @@
|
||||
//Clear other debounced events to prevent double calling of save
|
||||
// clearTimeout(this.editDebounce)
|
||||
|
||||
// return resolve(true)
|
||||
|
||||
//Don't save note if its hash doesn't change
|
||||
const currentNoteText = this.getText()
|
||||
if( this.lastNoteHash == this.hashString( currentNoteText )){
|
||||
@@ -406,9 +665,12 @@
|
||||
},
|
||||
checkForUpdatedNote(){
|
||||
|
||||
// return
|
||||
|
||||
//If user leaves page then returns to page, reload the first batch
|
||||
if(this.lastVisibilityState == 'hidden' && document.visibilityState == 'visible'){
|
||||
console.log('Checking for changes is note data')
|
||||
console.log('Checking for note updates after visibility change.')
|
||||
|
||||
const postData = {
|
||||
noteId:this.currentNoteId,
|
||||
text:this.getText(),
|
||||
@@ -435,12 +697,12 @@
|
||||
hashString(text){
|
||||
|
||||
var hash = 0;
|
||||
if (text.length == 0) {
|
||||
if (text == null || text.length == 0) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
//Simplified for speed
|
||||
return text.length
|
||||
// return text.length
|
||||
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
let char = text.charCodeAt(i);
|
||||
@@ -472,42 +734,67 @@
|
||||
|
||||
<style type="text/css" scoped>
|
||||
|
||||
/* squire note menu button */
|
||||
|
||||
.note-menu {
|
||||
width: 100%;
|
||||
display: block;
|
||||
background: #221f2b;
|
||||
color: white;
|
||||
overflow: hidden;
|
||||
border: 1px solid #534c68;
|
||||
}
|
||||
.note-menu > .nm-button {
|
||||
padding: 10px 10px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
font-size: 1.1em;
|
||||
vertical-align: middle;
|
||||
/*height: 40px;*/
|
||||
display: table-cell;
|
||||
}
|
||||
.nm-button > i {
|
||||
font-size: 1.1em;
|
||||
margin: 0;
|
||||
}
|
||||
.nm-button:hover {
|
||||
background-color: #534c68;
|
||||
color: white;
|
||||
}
|
||||
.nm-button + .nm-button {
|
||||
border-left: 1px solid #534c68;
|
||||
}
|
||||
|
||||
/* squire styles */
|
||||
|
||||
/*Settings manager styles */
|
||||
.all-settings {
|
||||
/*border-top: 1px solid #534c68;*/
|
||||
background: #221f2b;
|
||||
position: absolute;
|
||||
bottom: -5px;
|
||||
right: 10px;
|
||||
left: 10px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 99;
|
||||
border: 1px solid;
|
||||
background-color: var(--background_color);
|
||||
border-color: var(--border_color);
|
||||
/*border: 1px solid;*/
|
||||
/*background-color: var(--background_color);*/
|
||||
/*border-color: var(--border_color);*/
|
||||
box-sizing: border-box;
|
||||
border-radius: 7px;
|
||||
box-shadow: 0px 3px 7px 0px rgba(140,140,140,1);
|
||||
padding: 1em;
|
||||
/*border-radius: 7px;*/
|
||||
/*box-shadow: 0px 3px 7px 0px rgba(140,140,140,1);*/
|
||||
/*padding: 1.2em 0 0;*/
|
||||
}
|
||||
.low-settings {
|
||||
bottom: 0px;
|
||||
cursor: pointer;
|
||||
height: 1.4em;
|
||||
padding-top: 1.5em;
|
||||
overflow: hidden;
|
||||
border: 1px solid #534c68;
|
||||
}
|
||||
/*End Settings manager styles */
|
||||
|
||||
.tinymce-container {
|
||||
/* Uncomment this to see the */
|
||||
/*border-bottom: 2px solid green !important;*/
|
||||
}
|
||||
|
||||
.note-top-menu {
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
height: 37px;
|
||||
border-left: 3px solid var(--border_color);
|
||||
}
|
||||
.note-top-menu .ui.basic.button {
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
border-right: 1px solid var(--border_color);
|
||||
margin: 0px -2px;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
/* container styles change based on mobile and number of open screens */
|
||||
.master-note-edit {
|
||||
@@ -520,6 +807,9 @@
|
||||
z-index: 1001;
|
||||
/*overflow-x: scroll;*/
|
||||
}
|
||||
.padded-bottom {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
.loading-note {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@@ -13,7 +13,7 @@
|
||||
<!-- Show title and snippet below it -->
|
||||
<div class="top aligned row" @click.self="onClick(note.id)">
|
||||
|
||||
<div class="sixteen wide column overflow-hidden" @click="e => onClick(note.id, e)">
|
||||
<div class="sixteen wide column overflow-hidden note-card-text" @click="e => onClick(note.id, e)">
|
||||
|
||||
<!-- Title display -->
|
||||
<div v-if="note.title.length > 0"
|
||||
@@ -190,7 +190,8 @@
|
||||
border-radius: .28571429rem;
|
||||
border: 1px solid;
|
||||
border-color: var(--border_color);
|
||||
width: calc(33.333% - 10px);
|
||||
/*width: calc(33.333% - 10px);*/
|
||||
width: calc(25% - 10px);
|
||||
/*transition: box-shadow 0.3s;*/
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
@@ -204,6 +205,7 @@
|
||||
}
|
||||
.icon-bar {
|
||||
opacity: 0.8;
|
||||
margin-top: -2.2rem;
|
||||
}
|
||||
.hover-hide {
|
||||
opacity: 0.0;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
// The Vue build version to load with the `import` command
|
||||
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
|
||||
|
||||
import Vue from 'vue'
|
||||
|
||||
import Vuex from 'vuex'
|
||||
@@ -28,7 +29,18 @@ require('./assets/themes/default/assets/fonts/outline-icons.ttf')
|
||||
require('./assets/themes/default/assets/fonts/outline-icons.woff')
|
||||
require('./assets/themes/default/assets/fonts/outline-icons.woff2')
|
||||
|
||||
require('./assets/squire.js')
|
||||
|
||||
//Import socket io, init using nginx configured socket path
|
||||
import io from 'socket.io-client';
|
||||
const socket = io({ path:'/socket' });
|
||||
|
||||
//integrate connected socket into vue instance
|
||||
Object.defineProperties(Vue.prototype, {
|
||||
$io: {
|
||||
get: () => socket
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -46,7 +58,7 @@ import Helpers from './Helpers'
|
||||
Vue.use(Vuex)
|
||||
Vue.config.productionTip = false
|
||||
|
||||
/* eslint-disable no-new */
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router,
|
||||
|
@@ -6,22 +6,35 @@
|
||||
<h2 class="ui header">
|
||||
<i class="folder icon"></i>
|
||||
<div class="content">
|
||||
Attachments
|
||||
<div class="sub header">Files and scraped web pages from notes</div>
|
||||
Files
|
||||
<div class="sub header">Uploaded Files and Websites from notes.</div>
|
||||
</div>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div class="ui segment" v-if="searchParams.noteId">
|
||||
Showing Attachments for note. <div class="ui button" v-on:click="clearNote">Clear</div>
|
||||
<div class="sixteen wide column" v-if="searchParams.noteId">
|
||||
<div class="ui green button" v-on:click="clearNote">
|
||||
<i class="chevron circle left icon"></i>
|
||||
Show All Attachments
|
||||
</div>
|
||||
<div class="ui green button" v-on:click="openNote">
|
||||
<i class="file icon"></i>
|
||||
Open Note
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui basic segment">
|
||||
<attachment-display
|
||||
v-for="item in attachments"
|
||||
:item="item"
|
||||
:key="item.id"
|
||||
/>
|
||||
<div class="sixteen wide column" v-if="searchParams['noteId'] && attachments.length == 0">
|
||||
<h3>There are no attachments for this note.</h3>
|
||||
<h3>Attachments are links or files added to the note.</h3>
|
||||
</div>
|
||||
|
||||
<div class="sixteen wide column">
|
||||
<attachment-display
|
||||
v-for="item in attachments"
|
||||
:item="item"
|
||||
:key="item.id"
|
||||
:search-params="searchParams"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -50,18 +63,30 @@
|
||||
mounted: function(){
|
||||
|
||||
//Mount notes on load if note ID is set
|
||||
if(this.$route.params && this.$route.params.id){
|
||||
const inputNoteId = this.$route.params.id
|
||||
this.searchParams['noteId'] = inputNoteId
|
||||
}
|
||||
|
||||
this.openNoteAttachments()
|
||||
this.searchAttachments()
|
||||
},
|
||||
watch:{
|
||||
$route (to, from){
|
||||
//Open or close notes on route change
|
||||
this.openNoteAttachments()
|
||||
this.searchAttachments()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openNoteAttachments(){
|
||||
if(this.$route.params && this.$route.params.id){
|
||||
const inputNoteId = this.$route.params.id
|
||||
this.searchParams['noteId'] = inputNoteId
|
||||
}
|
||||
},
|
||||
openNote(){
|
||||
const noteId = this.searchParams['noteId']
|
||||
this.$router.push('/notes/open/'+noteId)
|
||||
},
|
||||
clearNote(){
|
||||
this.$router.push('/attachments/')
|
||||
delete this.searchParams.noteId
|
||||
this.searchAttachments()
|
||||
},
|
||||
searchAttachments (){
|
||||
|
||||
|
@@ -115,6 +115,18 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- found attachments -->
|
||||
<div class="sixteen wide column" v-if="foundAttachments.length > 0">
|
||||
<h4><i class="green folder icon"></i> Found in Files ({{ foundAttachments.length }})</h4>
|
||||
<attachment-display
|
||||
v-for="item in foundAttachments"
|
||||
:item="item"
|
||||
:key="item.id"
|
||||
:search-params="{}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -135,6 +147,7 @@
|
||||
'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,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -176,20 +189,14 @@
|
||||
|
||||
lastVisibilityState: null,
|
||||
|
||||
foundAttachments: []
|
||||
|
||||
}
|
||||
},
|
||||
beforeMount(){
|
||||
|
||||
this.$parent.loginGateway()
|
||||
|
||||
//Load tinymce into the page only do it once
|
||||
if(document.querySelectorAll('[data-mceload]').length == 0){
|
||||
let tinyMceIncluder = document.createElement('script')
|
||||
tinyMceIncluder.setAttribute('src', '/api/static/assets/tinymce/tinymce.min.js')
|
||||
tinyMceIncluder.setAttribute('data-mceload','loaded')
|
||||
document.head.appendChild(tinyMceIncluder)
|
||||
}
|
||||
|
||||
this.$bus.$on('close_active_note', ({position, noteId}) => {
|
||||
this.closeNote(position)
|
||||
this.updateSingleNote(noteId)
|
||||
@@ -220,6 +227,9 @@
|
||||
this.searchTerm = sentInSearchTerm
|
||||
this.search(true, this.batchSize)
|
||||
.then( () => {
|
||||
|
||||
this.searchAttachments()
|
||||
|
||||
return this.fetchUserTags()
|
||||
})
|
||||
})
|
||||
@@ -244,7 +254,7 @@
|
||||
//Close notes when back button is pressed
|
||||
window.addEventListener('hashchange', this.hashChangeAction)
|
||||
|
||||
|
||||
//update note on visibility change
|
||||
document.addEventListener('visibilitychange', this.visibiltyChangeAction);
|
||||
|
||||
},
|
||||
@@ -475,6 +485,14 @@
|
||||
}
|
||||
})
|
||||
},
|
||||
searchAttachments(){
|
||||
axios.post('/api/attachment/textsearch', {'searchTerm':this.searchTerm})
|
||||
.then(results => {
|
||||
console.log('Attachment Results')
|
||||
console.log(results.data)
|
||||
this.foundAttachments = results.data
|
||||
})
|
||||
},
|
||||
search(showLoading = true, notesInNextLoad = null, mergeExisting = false){
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
@@ -595,6 +613,7 @@
|
||||
this.searchTerm = ''
|
||||
this.searchTags = []
|
||||
this.fastFilters = {}
|
||||
this.foundAttachments = [] //Remove all attachments
|
||||
this.$bus.$emit('reset_fast_filters')
|
||||
|
||||
//Load initial batch, then tags, then other batch
|
||||
|
@@ -83,7 +83,7 @@
|
||||
checkKeyup(event){
|
||||
|
||||
let element = event.target
|
||||
let padding = 22
|
||||
let padding = 0
|
||||
|
||||
element.style.height = 'auto';
|
||||
element.style.height = (element.scrollHeight + padding) +'px';
|
||||
|
@@ -11,6 +11,7 @@ export default new Vuex.Store({
|
||||
nightMode: false,
|
||||
isUserOnMobile: false,
|
||||
isNoteSettingsOpen: false, //Little note settings pane
|
||||
socket: null,
|
||||
},
|
||||
mutations: {
|
||||
setLoginToken(state, userData){
|
||||
@@ -81,7 +82,14 @@ export default new Vuex.Store({
|
||||
},
|
||||
toggleNoteSettingsPane(state){
|
||||
state.isNoteSettingsOpen = !state.isNoteSettingsOpen
|
||||
},
|
||||
setSocketIoSocket(state, socket){
|
||||
|
||||
//Put socket id in axios headers
|
||||
axios.defaults.headers.common['socketId'] = socket
|
||||
state.socket = socket
|
||||
}
|
||||
|
||||
},
|
||||
getters: {
|
||||
getUsername: state => {
|
||||
@@ -103,5 +111,8 @@ export default new Vuex.Store({
|
||||
getIsNoteSettingsOpen: state => {
|
||||
return state.isNoteSettingsOpen
|
||||
},
|
||||
getSocket: state => {
|
||||
return state.socket
|
||||
},
|
||||
}
|
||||
})
|
Reference in New Issue
Block a user