Add files via upload
This commit is contained in:
@@ -34,24 +34,22 @@
|
||||
border: 0px solid #dcdee2;
|
||||
border-color: #e8eaec;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
<template>
|
||||
<div class="layout" onkeydown="keydown">
|
||||
<Layout>
|
||||
<Affix :offset-top="0">
|
||||
|
||||
|
||||
<Header class="header">
|
||||
<div>
|
||||
<Row>
|
||||
<Col :xs="{ span: 24, offset: 0 }" :sm="{ span: 22, offset: 1 }" :md="{ span: 20, offset: 2 }"
|
||||
:lg="{ span: 18, offset: 3 }" :xl="{ span: 16, offset: 4 }" :xxl="{ span: 16, offset: 4 }">
|
||||
|
||||
<Header class="header">
|
||||
<div>
|
||||
<Row>
|
||||
<Col :xs="{ span: 24, offset: 0 }" :sm="{ span: 22, offset: 1 }" :md="{ span: 20, offset: 2 }"
|
||||
:lg="{ span: 18, offset: 3 }" :xl="{ span: 16, offset: 4 }" :xxl="{ span: 16, offset: 4 }">
|
||||
<Affix :offset-top="0">
|
||||
|
||||
<div style="background: white;width:100%;height:40px;">
|
||||
<img style="height:40px;float:left;" src="/static/favicon.png">
|
||||
@@ -71,20 +69,22 @@
|
||||
|
||||
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Header>
|
||||
</Affix>
|
||||
</Affix>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Header>
|
||||
|
||||
<Content class="content">
|
||||
<div style="min-height: 650px;">
|
||||
<Row>
|
||||
<Col :xs="{ span: 24, offset: 0 }" :sm="{ span: 22, offset: 1 }" :md="{ span: 20, offset: 2 }"
|
||||
:lg="{ span: 18, offset: 3 }" :xl="{ span: 16, offset: 4 }" :xxl="{ span: 16, offset: 4 }">
|
||||
<Card :padding="0">
|
||||
<div style="border-left: 0px solid #FF3366;">
|
||||
<div id="wrapper" style="border-left: 0px solid #FF3366;">
|
||||
<div id="noteText" style="text-align: center;min-height: 650px;" class="monoFt">
|
||||
<h1>{{$t("content.blankTip")}}</h1>
|
||||
<h1></h1>
|
||||
{{ $t("content.blankTip") }}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
@@ -132,7 +132,28 @@ export default {
|
||||
created() {
|
||||
this.noteForm.key = this.$route.params.name;
|
||||
},
|
||||
mounted() {
|
||||
//this.bindCopyTextEvent();
|
||||
|
||||
const myObserver = new ResizeObserver(entries => {
|
||||
// iterate over the entries, do something.
|
||||
entries.forEach(entry => {
|
||||
let affix = document.querySelector('.ivu-affix');
|
||||
if (affix) {
|
||||
affix.setAttribute("style", "top: 0px; width: " + entry.contentRect.width + "px;");
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
const someOtherEl = document.querySelector('#wrapper');
|
||||
myObserver.observe(someOtherEl);
|
||||
|
||||
},
|
||||
methods: {
|
||||
refreshPage() {
|
||||
window.location.reload();
|
||||
},
|
||||
createNote() {
|
||||
window.open("/");
|
||||
}
|
||||
|
||||
@@ -63,10 +63,10 @@
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.ivu-btn-text:focus {
|
||||
/* .ivu-btn-text:focus {
|
||||
margin-top: -3px;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
} */
|
||||
</style>
|
||||
|
||||
|
||||
@@ -83,20 +83,19 @@
|
||||
<Affix :offset-top="0">
|
||||
<div style="background: white;width:100%;height:40px;">
|
||||
|
||||
<img style="height:40px;float:left;" alt="refresh flagnote" src="/static/favicon.png">
|
||||
<img style="height:40px;float:left;cursor: pointer;" alt="refresh flagnote" src="/static/favicon.png"
|
||||
v-on:click="refreshPage()" />
|
||||
|
||||
<div style="float:left;width:auto;">
|
||||
|
||||
<Button-group size="large">
|
||||
<Button aria-label="publish" type="error" :loading="loading"
|
||||
style="margin-left:5px; border-radius: 0px;font-size: 24px;" @click="submitNote()"
|
||||
icon="md-cloud-upload"></Button>
|
||||
|
||||
<Button aria-label="download text" v-show="model.showDownloadText" type="error"
|
||||
style="margin-left:5px; border-radius: 0px; font-size: 22px;" @click="downLoadText()"
|
||||
icon="md-download"></Button>
|
||||
|
||||
|
||||
<Button aria-label="to top" v-show="toTopState" type="text"
|
||||
style="margin-left:5px; border-radius: 0px; font-size: 28px;color:red;line-height: 20px;"
|
||||
@click="toTop()" icon="ios-arrow-up" ghost></Button>
|
||||
|
||||
</Button-group>
|
||||
|
||||
</div>
|
||||
@@ -106,22 +105,38 @@
|
||||
<div style="float:right;width:auto;">
|
||||
|
||||
<Button-group size="large">
|
||||
|
||||
<Button aria-label="to top" v-show="toTopState" type="text"
|
||||
style="margin-left:0px; border-radius: 0px; font-size: 28px;color:red;line-height: 20px;"
|
||||
@click="toTop()" icon="ios-arrow-up" ghost></Button>
|
||||
|
||||
|
||||
<Button aria-label="create note" type="error"
|
||||
style="margin-left:10px; border-radius: 0px;font-size: 24px;" @click="createNote()"
|
||||
icon="md-add"></Button>
|
||||
<Button aria-label="delete note" type="error"
|
||||
style="margin-left:5px; border-radius: 0px;font-size: 24px;" @click="showDeleteModel()"
|
||||
icon="md-trash"></Button>
|
||||
<Button aria-label="publish" type="error" :loading="model.submitting"
|
||||
style="margin-left:5px; border-radius: 0px;font-size: 24px;" @click="submitNote()"
|
||||
icon="md-cloud-upload"></Button>
|
||||
<Button aria-label="menu" type="error" style="margin-left:5px; border-radius: 0px;font-size: 24px;"
|
||||
@click="switchMenu()" @blur.native="hideMenu()" icon="md-menu"></Button>
|
||||
|
||||
</Button-group>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="noteMenu" :class="[showMenuState ? 'showBlock' : 'hideBlock']"
|
||||
style="z-index: 100; position: absolute;top:41px;right:0px;left:auto;">
|
||||
<Button-group vertical size="large">
|
||||
<Button aria-label="create note" type="error" style="border-radius: 0px;font-size: 24px;"
|
||||
@click="createNote(); switchMenu(); " icon="md-add"></Button>
|
||||
<!--
|
||||
|
||||
<Button type="error" icon="md-refresh" style="border-radius: 0px;font-size: 14px;font-size: 24px;"
|
||||
@click="refreshPage()"></Button>
|
||||
-->
|
||||
|
||||
<Button aria-label="download text" v-show="model.showDownloadText" type="error"
|
||||
style="border-radius: 0px;font-size: 24px;" @click="downLoadText(); switchMenu(); "
|
||||
icon="md-download"></Button>
|
||||
|
||||
<Button type="error" icon="md-trash" style="border-radius: 0px;font-size: 24px;"
|
||||
@click="showDeleteModel(); switchMenu(); "></Button>
|
||||
|
||||
</Button-group>
|
||||
|
||||
|
||||
</div>
|
||||
</Affix>
|
||||
|
||||
|
||||
@@ -138,9 +153,9 @@
|
||||
<Card :padding="0">
|
||||
<Form :model="noteForm" :label-width="80">
|
||||
<div id="wrapper" style="border-left: 0px solid #FF3366;">
|
||||
<Input element-id="noteText" type="textarea" :border="false" v-model="noteForm.text"
|
||||
:autosize="{ minRows: 30, maxRows: 20480 }" placeholder="Enter something..." v-on:input="log"
|
||||
@on-keydown="down" />
|
||||
<Input element-id="noteText" type="textarea" :border="false" v-model="noteForm.text" autofocus
|
||||
:autosize="{ minRows: 30, maxRows: 20480 }" placeholder="Enter something..." @input="recordText"
|
||||
@on-keydown="recordEventKdown" />
|
||||
</div>
|
||||
</Form>
|
||||
</Card>
|
||||
@@ -153,17 +168,6 @@
|
||||
|
||||
<Footer class="layout-footer-center">2022 © flagnote.com</Footer>
|
||||
</Layout>
|
||||
<Modal v-model="modal1" title="Common Modal dialog box title" @on-ok="ok" @on-cancel="cancel">
|
||||
|
||||
<p>Content of dialog</p>
|
||||
<i-switch true-color="#ff4949" @on-change="change">
|
||||
<Icon type="md-lock" slot="open"></Icon>
|
||||
<Icon type="md-unlock" slot="close"></Icon>
|
||||
</i-switch>
|
||||
<Input v-show="showPassword" maxlength="10" placeholder="Enter password..."
|
||||
style="width: 150px;margin-left:20px;" />
|
||||
<p>Content of dialog</p>
|
||||
</Modal>
|
||||
|
||||
<Modal v-model="model.showDelete" width="330" footer-hide class-name="fnmodal" :styles="{ borderRadius: 0 }">
|
||||
<p style="text-align: center;font-size:medium ;margin-bottom: 20px;">
|
||||
@@ -182,9 +186,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { unzip, aesDecrypt } from '../libs/secret'
|
||||
// import html2canvas from "html2canvas";
|
||||
import Jquery from "jquery";
|
||||
import { unwrap } from '../libs/secret'
|
||||
import { saveNote } from "@/api/note";
|
||||
import { getSecretKey, getStoreKey } from "@/api/lock";
|
||||
import storage from "@/libs/storage";
|
||||
@@ -198,11 +200,6 @@ export default {
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
show: true,
|
||||
loading: false,
|
||||
modal1: false,
|
||||
showExt: false,
|
||||
showPassword: false,
|
||||
noteForm: {
|
||||
text: '',
|
||||
key: '',
|
||||
@@ -211,20 +208,23 @@ export default {
|
||||
storeKey: '',
|
||||
secretKey: '',
|
||||
cipher: '',
|
||||
currentTime: '',
|
||||
initTime: '',
|
||||
password: '',
|
||||
},
|
||||
state: {
|
||||
lock: 0,
|
||||
locking: 0,
|
||||
commited: 0
|
||||
commited: 0,
|
||||
serverTime: '',
|
||||
initTime: '',
|
||||
},
|
||||
model: {
|
||||
submitting: false,
|
||||
showDelete: false,
|
||||
deleting: false,
|
||||
showDownloadText: false,
|
||||
},
|
||||
toTopState: false,
|
||||
showMenuState: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -244,50 +244,41 @@ export default {
|
||||
// let noteMeta = this.$route.meta.noteMeta;
|
||||
let storeKey = getStoreKey(this.noteForm.key);
|
||||
this.secret.storeKey = storeKey;
|
||||
let secretKey = getSecretKey(this.noteForm.key, this.secret.password);
|
||||
this.secret.secretKey = secretKey;
|
||||
|
||||
// first edit
|
||||
if (keyMeta) {
|
||||
this.state.lock = 0;
|
||||
this.secret.cipher = keyMeta.cipher;
|
||||
this.secret.currentTime = keyMeta.currentTime;
|
||||
this.state.serverTime = keyMeta.serverTime;
|
||||
// key init Time
|
||||
this.noteForm.initTime = keyMeta.currentTime;
|
||||
this.state.initTime = keyMeta.serverTime;
|
||||
// clear
|
||||
storage.local.dynamicClear();
|
||||
|
||||
//if local less 1m ,then deep clear,let local greater than 2m
|
||||
// if (storage.local.getAvailableSize < 1 * 1024 * 1024) {
|
||||
// storage.local.dynamicDeepClear(this.secret.currentTime, storeKey);
|
||||
// storage.local.dynamicDeepClear(this.state.serverTime, storeKey);
|
||||
// }
|
||||
|
||||
storage.local.setText(storeKey + '.text', "0|" + this.secret.cipher + "|0|" + this.noteForm.initTime + "|");
|
||||
storage.local.setText(storeKey, "0|" + this.secret.cipher + "|0|" + this.state.initTime + "|");
|
||||
} else {
|
||||
// second edit
|
||||
let storeText = storage.local.getText(storeKey + '.text');
|
||||
let starray = storeText.split('|');
|
||||
let storeInfo = storage.local.getText(storeKey);
|
||||
let starray = storeInfo.split('|');
|
||||
this.state.lock = parseInt(starray[0]);
|
||||
this.secret.cipher = starray[1];
|
||||
this.noteForm.initTime = parseInt(starray[3]);
|
||||
}
|
||||
this.state.initTime = parseInt(starray[3]);
|
||||
|
||||
//TODO: password lock
|
||||
if (this.state.lock == 1) {
|
||||
this.show = false;
|
||||
this.noteForm.text = "*****lock*****";
|
||||
return;
|
||||
} else {
|
||||
this.loadText();
|
||||
//draw text;
|
||||
if (starray[4]) {
|
||||
this.noteForm.text = unwrap(starray[4], secretKey);
|
||||
}
|
||||
}
|
||||
|
||||
this.bindCtrlAllEvent();
|
||||
|
||||
this.bindToTopEvent();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
},
|
||||
mounted() {
|
||||
const myObserver = new ResizeObserver(entries => {
|
||||
@@ -322,66 +313,54 @@ export default {
|
||||
elent.selectionEnd = 0;
|
||||
elent.focus();
|
||||
},
|
||||
showInput() {
|
||||
this.showPassword = true;
|
||||
refreshPage() {
|
||||
window.location.reload();
|
||||
},
|
||||
hideInput() {
|
||||
//this.showPassword = false;
|
||||
switchMenu() {
|
||||
this.showMenuState = !this.showMenuState;
|
||||
},
|
||||
change(status) {
|
||||
this.showPassword = status;
|
||||
},
|
||||
ok() {
|
||||
|
||||
},
|
||||
cancel() {
|
||||
|
||||
hideMenu() {
|
||||
let hbt = document.querySelector('#noteMenu > div > button:hover');
|
||||
if (!hbt) {
|
||||
this.showMenuState = false;
|
||||
}
|
||||
},
|
||||
downLoadText() {
|
||||
var blob = new Blob([this.noteForm.text], { type: "application/octet-stream;charset=utf-8" });
|
||||
saveAs(blob, this.noteForm.key + ".txt");
|
||||
},
|
||||
loadText() {
|
||||
let storeText = storage.local.getText(this.secret.storeKey + '.text');
|
||||
|
||||
if (null != storeText && '' != storeText) {
|
||||
|
||||
let starray = storeText.split('|');
|
||||
|
||||
let lock = parseInt(starray[0]);
|
||||
if (lock == 1) {
|
||||
alert("note is encrypt!");
|
||||
return;
|
||||
}
|
||||
|
||||
storeText = starray[4];
|
||||
|
||||
if (storeText.length > 0) {
|
||||
storeText = unzip(storeText);
|
||||
let secretKey = getSecretKey(this.noteForm.key);
|
||||
let plainText = aesDecrypt(storeText, secretKey);
|
||||
if (plainText.startsWith("FLAGNOTE#")) {
|
||||
this.noteForm.text = plainText.substring(9);
|
||||
this.state.lock = 0;
|
||||
} else {
|
||||
if (this.state.lock == 1) {
|
||||
alert("password is wrong!")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.noteForm.text = '';
|
||||
this.state.lock = 0;
|
||||
}
|
||||
recordText() {
|
||||
let text = this.noteForm.text;
|
||||
if (text.length > 102400) {
|
||||
alert("text length is " + text.length + ",beyond 102400!!!");
|
||||
}
|
||||
|
||||
setStoreText(this.noteForm, this.state, this.secret);
|
||||
},
|
||||
log() {
|
||||
setStoreText(this.noteForm, this.secret);
|
||||
},
|
||||
down(event) {
|
||||
if (event.keyCode == 9) {
|
||||
// recordEventKup(event) {
|
||||
// let tn = event.currentTarget.value;
|
||||
// let ss = event.currentTarget.selectionStart;
|
||||
// let cline = tn.substring(0, ss).split('\n').length;
|
||||
|
||||
// var noteTop = parseFloat(window.getComputedStyle(event.currentTarget).lineHeight) * cline;
|
||||
// var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
|
||||
// if (noteTop < scrollTop + 10) {
|
||||
// window.scrollTo(0, noteTop - 10);
|
||||
// }
|
||||
|
||||
// },
|
||||
recordEventKdown(event) {
|
||||
|
||||
if (event.key == "Tab") {
|
||||
|
||||
let start = event.currentTarget.selectionStart;
|
||||
let end = event.currentTarget.selectionEnd;
|
||||
let text = event.currentTarget.value;
|
||||
|
||||
if (text.length > 102400) {
|
||||
alert("text length is " + text.length + ",beyond 102400!!!");
|
||||
}
|
||||
|
||||
let tab = '\t';//\t
|
||||
text = text.substr(0, start) + tab + text.substr(start);
|
||||
event.currentTarget.value = text;
|
||||
@@ -391,138 +370,69 @@ export default {
|
||||
if (event.preventDefault) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
this.noteForm.text = event.currentTarget.value;
|
||||
setStoreText(this.noteForm, this.secret);
|
||||
setStoreText(this.noteForm, this.state, this.secret);
|
||||
|
||||
} else if (event.ctrlKey && (event.which == 13)) {
|
||||
|
||||
if (this.state.locking == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.validateForm()) {
|
||||
this.state.locking = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
//save
|
||||
let that = this;
|
||||
this.save().then(res => {
|
||||
if (res) {
|
||||
let storeText = storage.local.getText(that.secret.storeKey + '.text');
|
||||
let starray = storeText.split("|");
|
||||
storage.local.setText(that.secret.storeKey + '.text', starray[0] + '|' + starray[1] + '|1|' + starray[3] + '|' + starray[4]);
|
||||
that.state.commited = 1;
|
||||
setStoreText(this.noteForm, this.state, this.secret);
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
save() {
|
||||
this.noteForm.cipher = this.secret.cipher;
|
||||
this.noteForm.lock = this.state.lock;
|
||||
return saveNote(this.noteForm);
|
||||
return saveNote(this.noteForm, this.secret);
|
||||
},
|
||||
validateForm() {
|
||||
let text = this.noteForm.text;
|
||||
if (text.length > 102400) {
|
||||
alert("text length is " + text.length + ",beyond 102400!!!");
|
||||
return false;
|
||||
}
|
||||
if (text.length == 0) {
|
||||
alert("text is empty!!!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
submitNote() {
|
||||
if (this.state.locking == 1) {
|
||||
return;
|
||||
}
|
||||
this.state.locking = 1;
|
||||
|
||||
this.loading = true;
|
||||
if (!this.validateForm()) {
|
||||
this.state.locking = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
this.model.submitting = true;
|
||||
|
||||
let that = this;
|
||||
this.save().then(res => {
|
||||
if (res) {
|
||||
let storeText = storage.local.getText(that.secret.storeKey + '.text');
|
||||
let starray = storeText.split("|");
|
||||
storage.local.setText(that.secret.storeKey + '.text', starray[0] + '|' + starray[1] + '|1|' + starray[3] + '|' + starray[4]);
|
||||
let storeInfo = storage.local.getText(that.secret.storeKey);
|
||||
let starray = storeInfo.split("|");
|
||||
storage.local.setText(that.secret.storeKey, starray[0] + '|' + starray[1] + '|1|' + starray[3] + '|' + starray[4]);
|
||||
location.reload();
|
||||
this.state.locking = 0;
|
||||
}
|
||||
});
|
||||
},
|
||||
hideNote() {
|
||||
if (this.state.locking == 1) {
|
||||
return;
|
||||
}
|
||||
this.state.locking = 1;
|
||||
|
||||
if (this.state.lock == 1) {
|
||||
this.state.locking = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
let password = '123456';
|
||||
|
||||
setStoreText(this.noteForm, this.secret, password);
|
||||
|
||||
this.state.lock = 1
|
||||
|
||||
this.noteForm.text = '******lock******';
|
||||
|
||||
|
||||
var noteText = document.getElementById("noteText");
|
||||
|
||||
noteText.select();
|
||||
noteText.selectionStart = 0;
|
||||
noteText.selectionEnd = 1;
|
||||
|
||||
this.show = false;
|
||||
this.state.locking = 0;
|
||||
|
||||
|
||||
|
||||
},
|
||||
showNote() {
|
||||
if (this.state.locking == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.state.locking = 1;
|
||||
|
||||
if (this.state.lock == 0) {
|
||||
this.state.locking = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
let password = 'FLAGNOTE';
|
||||
|
||||
let storeText = storage.local.getText(this.secret.storeKey + '.text');
|
||||
if (storeText) {
|
||||
let lock = parseInt(storeText.substring(0, 1));
|
||||
|
||||
if (!lock) {
|
||||
alert("note is not encrypt!");
|
||||
}
|
||||
|
||||
storeText = storeText.substring(35 + 16);
|
||||
|
||||
storeText = unzip(storeText);
|
||||
|
||||
let secretKey = getSecretKey(this.noteForm.key, password);
|
||||
let plainText = aesDecrypt(storeText, secretKey);
|
||||
if (plainText.startsWith("FLAGNOTE#")) {
|
||||
lock = "0";
|
||||
} else {
|
||||
let secretKey = getSecretKey(this.noteForm.key);
|
||||
let plainText = aesDecrypt(storeText, secretKey);
|
||||
if (plainText.startsWith("FLAGNOTE#")) {
|
||||
lock = "0";
|
||||
} else {
|
||||
lock = "1";
|
||||
}
|
||||
}
|
||||
|
||||
if (lock == '0') {
|
||||
this.noteForm.text = plainText.substring(9);
|
||||
this.state.lock = "0";
|
||||
setStoreText(this.noteForm, this.secret);
|
||||
this.show = true;
|
||||
this.state.locking = "0";
|
||||
} else {
|
||||
alert("password is wrong!")
|
||||
this.state.locking = "0";
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
alert("storeText is deleted!")
|
||||
this.state.locking = "0";
|
||||
}
|
||||
|
||||
|
||||
|
||||
},
|
||||
refresh() {
|
||||
location.reload();
|
||||
@@ -535,10 +445,8 @@ export default {
|
||||
},
|
||||
dropNote() {
|
||||
this.model.deleting = true;
|
||||
storage.local.delete(this.secret.storeKey + '.text');
|
||||
storage.session.delete(this.secret.storeKey + '.keyMeta');
|
||||
storage.local.delete(this.secret.storeKey);
|
||||
location.reload();
|
||||
|
||||
},
|
||||
bindToTopEvent() {
|
||||
let that = this;
|
||||
@@ -549,40 +457,18 @@ export default {
|
||||
} else {
|
||||
that.toTopState = false;
|
||||
}
|
||||
|
||||
//document.getElementsByClassName("ivu-affix")[0]
|
||||
}
|
||||
},
|
||||
bindCtrlAllEvent() {
|
||||
if (document.body.createTextRange) {
|
||||
Jquery(document).keydown(function (e) {
|
||||
if ((e.ctrlKey || e.metaKey) && e.keyCode == 65) {
|
||||
if (window.getSelection && document.createRange) {
|
||||
document.onkeydown = (e) => {
|
||||
if ((e.ctrlKey || e.metaKey) && e.key == "a") {
|
||||
e.preventDefault();
|
||||
|
||||
var element = document.getElementById("noteText");
|
||||
|
||||
element.select();
|
||||
|
||||
}
|
||||
});
|
||||
} else if (window.getSelection) {
|
||||
|
||||
Jquery(document).keydown(function (e) {
|
||||
if ((e.ctrlKey || e.metaKey) && e.keyCode == 65) {
|
||||
e.preventDefault();
|
||||
|
||||
var element = document.getElementById("noteText");
|
||||
|
||||
element.select();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
//alert('none');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,32 +133,34 @@ button span {
|
||||
margin-left: -1px !important;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
/* #noteMenu button span{
|
||||
font-size: 15px;
|
||||
line-height: 20px;
|
||||
margin-left: 7px !important;
|
||||
margin-right: 5px !important;
|
||||
} */
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div class="layout">
|
||||
<Layout>
|
||||
|
||||
<Header class="header">
|
||||
<Row>
|
||||
<Col :xs="{ span: 24, offset: 0 }" :sm="{ span: 22, offset: 1 }" :md="{ span: 20, offset: 2 }"
|
||||
:lg="{ span: 18, offset: 3 }" :xl="{ span: 16, offset: 4 }" :xxl="{ span: 16, offset: 4 }">
|
||||
<Affix :offset-top="0">
|
||||
|
||||
<Header class="header">
|
||||
<Row>
|
||||
<Col :xs="{ span: 24, offset: 0 }" :sm="{ span: 22, offset: 1 }" :md="{ span: 20, offset: 2 }"
|
||||
:lg="{ span: 18, offset: 3 }" :xl="{ span: 16, offset: 4 }" :xxl="{ span: 16, offset: 4 }">
|
||||
<Affix :offset-top="0">
|
||||
<div style="background: white;width:100%;height:40px;">
|
||||
<img style="height:40px;float:left;" alt="refresh flagnote" src="/static/favicon.png">
|
||||
<img style="height:40px;float:left;cursor: pointer;" alt="refresh flagnote" src="/static/favicon.png"
|
||||
v-on:click="refreshPage()">
|
||||
<div style="float:left;width:auto;">
|
||||
|
||||
<Button-group size="large">
|
||||
<Button aria-label="to top" v-show="toTopState" type="text"
|
||||
style="margin-left:0px; border-radius: 0px; font-size: 28px;color:red;line-height: 20px;"
|
||||
@click="toTop()" icon="ios-arrow-up" ghost></Button>
|
||||
|
||||
<Button aria-label="share" type="error"
|
||||
style="margin-left:5px; border-radius: 0px;font-size: 24px; font-family: Arial, sans-serif"
|
||||
@click="showShareModel()" icon="md-cloud-done">{{ noteForm.ttlDesc }}</Button>
|
||||
|
||||
|
||||
|
||||
<Button aria-label="download text" v-show="model.showDownloadText" type="error"
|
||||
style="margin-left:5px; border-radius: 0px; font-size: 22px;" @click="downLoadText()"
|
||||
icon="md-download"></Button>
|
||||
|
||||
|
||||
|
||||
@@ -168,29 +170,51 @@ button span {
|
||||
|
||||
<div style="float:right;width:auto;">
|
||||
<Button-group size="large">
|
||||
<Button aria-label="to top" v-show="toTopState" type="text"
|
||||
style="margin-left:0px; border-radius: 0px; font-size: 28px;color:red;line-height: 20px;"
|
||||
@click="toTop()" icon="ios-arrow-up" ghost></Button>
|
||||
|
||||
<Button aria-label="create note" type="error"
|
||||
style="margin-left:10px; border-radius: 0px;font-size: 24px;" @click="createNote()"
|
||||
icon="md-add"></Button>
|
||||
<Button aria-label="delete note" type="error"
|
||||
style="margin-left:5px; border-radius: 0px;font-size: 24px;" @click="showDeleteModel()"
|
||||
icon="md-trash"></Button>
|
||||
<Button aria-label="share" type="error"
|
||||
style="margin-left:5px; border-radius: 0px;font-size: 24px; font-family: Arial, sans-serif"
|
||||
@click="showShareModel()" icon="md-cloud-done">{{ state.ttlDesc }}</Button>
|
||||
|
||||
<Button aria-label="menu" type="error" style="margin-left:5px; border-radius: 0px;font-size: 24px;"
|
||||
@click="switchMenu()" @blur.native="hideMenu()" icon="md-menu"></Button>
|
||||
|
||||
|
||||
|
||||
|
||||
</Button-group>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="noteMenu" :class="[showMenuState ? 'showBlock' : 'hideBlock']"
|
||||
style="z-index: 100; position: absolute;top:41px;right:0px;left:auto;">
|
||||
<Button-group vertical size="large">
|
||||
<Button type="error" icon="md-add" style="border-radius: 0px;font-size: 24px;"
|
||||
@click="createNote(); switchMenu();"></Button>
|
||||
|
||||
<!--
|
||||
|
||||
<Button type="error" icon="md-refresh" style="border-radius: 0px;font-size: 24px;"
|
||||
@click="refreshPage()"></Button>
|
||||
-->
|
||||
|
||||
<Button aria-label="download text" v-show="model.showDownloadText" type="error"
|
||||
style="border-radius: 0px;font-size: 24px;" @click="downLoadText(); switchMenu();"
|
||||
icon="md-download"></Button>
|
||||
|
||||
<Button type="error" icon="md-trash" style="border-radius: 0px;font-size: 24px;"
|
||||
@click="showDeleteModel(); switchMenu();"></Button>
|
||||
</Button-group>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</Affix>
|
||||
|
||||
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
</Header>
|
||||
</Col>
|
||||
</Row>
|
||||
</Header>
|
||||
|
||||
<Content class="content">
|
||||
<div style="min-height: 650px;">
|
||||
@@ -198,10 +222,7 @@ button span {
|
||||
<Col :xs="{ span: 24, offset: 0 }" :sm="{ span: 22, offset: 1 }" :md="{ span: 20, offset: 2 }"
|
||||
:lg="{ span: 18, offset: 3 }" :xl="{ span: 16, offset: 4 }" :xxl="{ span: 16, offset: 4 }">
|
||||
<Card :padding="0">
|
||||
<div id="wrapper" style="border-left: 0px solid #FF3366;" @contextmenu="showMenu">
|
||||
<vue-context-menu :contextMenuData="contextMenuData" @selectAllText="selectAllText"
|
||||
@copySelectedText="copySelectedText" @copyAllText="copyAllText">
|
||||
</vue-context-menu>
|
||||
<div id="wrapper" style="border-left: 0px solid #FF3366;">
|
||||
<div id="noteText" style="text-align: left;min-height: 650px;" class="monoFt"
|
||||
v-html="noteForm.escapeText">
|
||||
</div>
|
||||
@@ -213,8 +234,6 @@ button span {
|
||||
</Content>
|
||||
|
||||
|
||||
|
||||
|
||||
<Footer class="layout-footer-center">
|
||||
2022 © flagnote.com
|
||||
</Footer>
|
||||
@@ -237,7 +256,8 @@ button span {
|
||||
{{ $t("message.askTodelete") }}
|
||||
</p>
|
||||
<p style="text-align: center;">
|
||||
<Button type="error" :loading="model.delete" style="border-radius: 0px;" @click="dropNote()">{{ $t("button.yes")
|
||||
<Button type="error" :loading="model.deleting" style="border-radius: 0px;" @click="dropNote()">{{
|
||||
$t("button.yes")
|
||||
}}</Button>
|
||||
</p>
|
||||
</Modal>
|
||||
@@ -250,10 +270,9 @@ button span {
|
||||
|
||||
<script>
|
||||
|
||||
import { aesDecrypt, md5, unzip } from "@/libs/secret";
|
||||
import Jquery from "jquery";
|
||||
import { getSecretKey, getStoreKey } from "@/api/lock";
|
||||
import { deleteNote, getNote } from "@/api/note";
|
||||
import { md5, unwrap } from "@/libs/secret";
|
||||
import { getStoreKey, getSecretKey } from "@/api/lock";
|
||||
import { deleteNote, getNoteBlob } from "@/api/note";
|
||||
import storage from "@/libs/storage";
|
||||
import { getEscapeText } from "@/libs/noteStorage";
|
||||
import QRCode from "qrcode";
|
||||
@@ -273,23 +292,20 @@ export default {
|
||||
text: '',
|
||||
escapeText: '',
|
||||
key: '',
|
||||
md5: '',
|
||||
lock: 0,
|
||||
ttl: 3600,
|
||||
ttlDesc: '-- : --',
|
||||
},
|
||||
secret: {
|
||||
storeKey: '',
|
||||
secretKey: '',
|
||||
cipher: '',
|
||||
currentTime: '',
|
||||
md5: '',
|
||||
},
|
||||
state: {
|
||||
lock: 0,
|
||||
locking: 0,
|
||||
lock: null,
|
||||
initTime: null,
|
||||
initTtl: null,
|
||||
commited: 0,
|
||||
ttl: null,
|
||||
ttlDesc: '-- : --',
|
||||
serverTime: null,
|
||||
},
|
||||
model: {
|
||||
showDelete: false,
|
||||
@@ -298,26 +314,8 @@ export default {
|
||||
showDownloadText: false,
|
||||
},
|
||||
toTopState: false,
|
||||
contextMenuData: {
|
||||
menuName: 'textMenu',
|
||||
//菜单显示的位置
|
||||
axis: {
|
||||
x: null,
|
||||
y: null
|
||||
},
|
||||
//菜单选项
|
||||
menulists: [{
|
||||
fnHandler: 'selectAllText', //绑定事件
|
||||
btnName: this.$t("button.selectAll") //菜单名称
|
||||
}, {
|
||||
fnHandler: 'copySelectedText',
|
||||
btnName: this.$t("button.copy")
|
||||
}, {
|
||||
fnHandler: 'copyAllText',
|
||||
btnName: this.$t("button.copyAll")
|
||||
}]
|
||||
},
|
||||
tempFragment: null,
|
||||
showMenuState: false,
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
@@ -337,15 +335,18 @@ export default {
|
||||
|
||||
this.noteForm.noteUrl = getNoteUrl(this.noteForm.key);
|
||||
this.secret.storeKey = getStoreKey(this.noteForm.key);
|
||||
this.secret.secretKey = getSecretKey(this.noteForm.key, this.secret.password);
|
||||
|
||||
if (noteMeta) {
|
||||
this.state.lock = noteMeta.lock;
|
||||
this.state.initTime = new Date().getTime();
|
||||
this.state.initTtl = noteMeta.ttl;
|
||||
this.secret.currentTime = noteMeta.currentTime;
|
||||
this.state.ttl = noteMeta.ttl;
|
||||
this.state.serverTime = noteMeta.serverTime;
|
||||
|
||||
this.secret.cipher = "00000000000000000000000000000000";//noteMeta.cipher; //读者有没有值可配置
|
||||
this.noteForm.md5 = noteMeta.md5;
|
||||
this.noteForm.ttl = noteMeta.ttl;
|
||||
this.secret.md5 = noteMeta.md5;
|
||||
|
||||
|
||||
this.startClock();
|
||||
|
||||
@@ -356,7 +357,6 @@ export default {
|
||||
this.bindCtrlAllEvent();
|
||||
this.bindCopyUrlEvent();
|
||||
this.bindToTopEvent();
|
||||
this.bindMouseEvent();
|
||||
|
||||
} else {
|
||||
alert("Unconnected.");
|
||||
@@ -364,7 +364,7 @@ export default {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
this.bindCopyTextEvent();
|
||||
//this.bindCopyTextEvent();
|
||||
|
||||
const myObserver = new ResizeObserver(entries => {
|
||||
// iterate over the entries, do something.
|
||||
@@ -390,29 +390,13 @@ export default {
|
||||
computed: {},
|
||||
watch: {},
|
||||
methods: {
|
||||
selectAllText() {
|
||||
var element = document.getElementById("noteText");
|
||||
if (window.getSelection) {
|
||||
let selection = window.getSelection();
|
||||
let range = document.createRange();
|
||||
range.selectNodeContents(element);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
switchMenu() {
|
||||
this.showMenuState = !this.showMenuState;
|
||||
},
|
||||
copySelectedText() {
|
||||
|
||||
},
|
||||
copyAllText() {
|
||||
|
||||
},
|
||||
showMenu(event) {
|
||||
event.preventDefault()
|
||||
var x = event.clientX
|
||||
var y = event.clientY
|
||||
// Get the current location
|
||||
this.contextMenuData.axis = {
|
||||
x, y
|
||||
hideMenu() {
|
||||
let hbt = document.querySelector('#noteMenu > div > button:hover');
|
||||
if (!hbt) {
|
||||
this.showMenuState = false;
|
||||
}
|
||||
},
|
||||
downLoadText() {
|
||||
@@ -425,7 +409,7 @@ export default {
|
||||
startClock() {
|
||||
let that = this;
|
||||
window.setInterval(function () {
|
||||
let ittl = parseInt(that.noteForm.ttl / 1000);
|
||||
let ittl = parseInt(that.state.ttl / 1000);
|
||||
let mins = parseInt(ittl / 60);
|
||||
if (mins < 0) {
|
||||
mins = "00";
|
||||
@@ -440,20 +424,17 @@ export default {
|
||||
} else if (seds < 10) {
|
||||
seds = "0" + seds;
|
||||
}
|
||||
that.noteForm.ttlDesc = mins + ":" + seds;
|
||||
that.noteForm.ttl = that.state.initTtl - (new Date().getTime() - that.state.initTime);
|
||||
that.state.ttlDesc = mins + ":" + seds;
|
||||
that.state.ttl = that.state.initTtl - (new Date().getTime() - that.state.initTime);
|
||||
|
||||
if (that.noteForm.ttl <= 0) {
|
||||
storage.local.delete(that.secret.storeKey + '.text');
|
||||
if (that.state.ttl <= 0) {
|
||||
storage.local.delete(that.secret.storeKey);
|
||||
location.reload();
|
||||
}
|
||||
}, 1000)
|
||||
},
|
||||
decryptNote() {
|
||||
// let password = "123456";
|
||||
// let secretKey = getSecretKey(this.noteForm.key, password);
|
||||
// this.loadText(secretKey);
|
||||
|
||||
refreshPage() {
|
||||
window.location.reload();
|
||||
},
|
||||
createNote() {
|
||||
window.open("/");
|
||||
@@ -484,7 +465,7 @@ export default {
|
||||
let that = this;
|
||||
deleteNote(this.noteForm.key).then(res => {
|
||||
if (res) {
|
||||
storage.local.delete(that.secret.storeKey + '.text');
|
||||
storage.local.delete(that.secret.storeKey);
|
||||
location.reload();
|
||||
} else {
|
||||
that.model.deleting = false;
|
||||
@@ -492,36 +473,58 @@ export default {
|
||||
});
|
||||
},
|
||||
loadText() {
|
||||
let password = '';
|
||||
let that = this;
|
||||
|
||||
if (this.noteForm.lock == 1) {
|
||||
password = "FLAGNOTE"; //默认密码
|
||||
let storeInfo = storage.local.getText(this.secret.storeKey);
|
||||
|
||||
let starray = [];
|
||||
if (storeInfo) {
|
||||
starray = storeInfo.split('|');
|
||||
}
|
||||
|
||||
let secretKey = getSecretKey(this.noteForm.key, password);
|
||||
let storeText = storage.local.getText(this.secret.storeKey + '.text');
|
||||
if (!storeText || (md5(storeText.substring(51)) != this.noteForm.md5)) {
|
||||
if (!storeInfo || !starray[4] || (md5(starray[4]) != this.secret.md5)) {
|
||||
// local is useless
|
||||
let note = getNote(this.noteForm.key);
|
||||
// if lack of local , not set local
|
||||
if (storage.local.getAvailableSize() > 1 * 1024 * 1024) {
|
||||
storeText = this.noteForm.lock + '|' + this.secret.cipher + '|1|' + this.secret.currentTime + '|' + note.text;
|
||||
storage.local.setText(this.secret.storeKey + '.text', storeText);
|
||||
}
|
||||
} else {
|
||||
// local is usable, and set commited flag
|
||||
var starray = storeText.split('|');
|
||||
if ("0" == starray[2]) {
|
||||
storage.local.setText(this.secret.storeKey + '.text', starray[0] + "|" + starray[1] + "|1|" + starray[3] + "|" + starray[4]);
|
||||
}
|
||||
}
|
||||
getNoteBlob(this.noteForm.key).then((res) => {
|
||||
if (!res.data || res.data.size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (storeText) {
|
||||
storeText = unzip(storeText.split('|')[4]);
|
||||
let plainText = aesDecrypt(storeText, secretKey);
|
||||
if (plainText.startsWith("FLAGNOTE#")) {
|
||||
this.noteForm.text = plainText.substring(9);
|
||||
this.noteForm.escapeText = getEscapeText(this.noteForm.text);
|
||||
let blob = new Blob([res.data], {
|
||||
type: res.data.type
|
||||
});
|
||||
|
||||
let reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
if (!e.target.result || e.target.result.byteLength == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var bytes = new Uint8Array(e.target.result);
|
||||
let bytesString = bytes.join(",");
|
||||
that.noteForm.text = unwrap(bytesString, that.secret.secretKey);
|
||||
that.noteForm.escapeText = getEscapeText(that.noteForm.text);
|
||||
|
||||
// if local is enough, set local
|
||||
if (storage.local.getAvailableSize() > 1 * 1024 * 1024) {
|
||||
storage.local.setText(that.secret.storeKey, that.state.lock + '|' + that.secret.cipher + '|1|' + that.state.serverTime + '|' + bytesString);
|
||||
}
|
||||
};
|
||||
reader.readAsArrayBuffer(blob);
|
||||
});
|
||||
|
||||
} else {
|
||||
starray = storeInfo.split('|');
|
||||
|
||||
if (!starray[4]) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.noteForm.text = unwrap(starray[4], this.secret.secretKey);
|
||||
this.noteForm.escapeText = getEscapeText(this.noteForm.text);
|
||||
|
||||
// local is usable, and set commited flag
|
||||
if ("0" == starray[2]) {
|
||||
storage.local.setText(this.secret.storeKey, starray[0] + "|" + starray[1] + "|1|" + starray[3] + "|" + starray[4]);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -540,97 +543,28 @@ export default {
|
||||
let that = this;
|
||||
var clipboard = new Clipboard("#tag-copy")
|
||||
clipboard.on('success', function () {
|
||||
that.$Message.success({ content: 'url copied' });
|
||||
that.$Message.success({ content: 'url copied.' });
|
||||
});
|
||||
|
||||
clipboard.on('error', function () {
|
||||
that.$Message.error('not allow to copy');
|
||||
});
|
||||
},
|
||||
bindCopyTextEvent() {
|
||||
|
||||
let ele1 = document.getElementsByClassName("vue-contextmenuName-textMenu")[0].children[1].children[0].children[0];
|
||||
let ele2 = document.getElementsByClassName("vue-contextmenuName-textMenu")[0].children[2].children[0].children[0];
|
||||
|
||||
let that = this;
|
||||
|
||||
const clipboard1 = new Clipboard(ele1, { // 绑定需要的触发的dom
|
||||
text: function () {
|
||||
let fragment = that.tempFragment;
|
||||
|
||||
if (fragment) {
|
||||
let copyText = "";
|
||||
|
||||
fragment.childNodes.forEach(element => {
|
||||
if (3 == element.nodeType) {
|
||||
copyText += element.textContent.replace(new RegExp('\u00a0', 'gm'), " ");
|
||||
} else if (1 == element.nodeType) {
|
||||
if ("BR" == element.nodeName) {
|
||||
copyText += "\r\n";
|
||||
} else if ("PRE" == element.nodeName) {
|
||||
copyText += "\t";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return copyText;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
clipboard1.on('success', function () {
|
||||
that.$Message.success({ content: 'selected text copied' });
|
||||
});
|
||||
clipboard1.on('error', function () {
|
||||
that.$Message.error('not allow to copy');
|
||||
});
|
||||
|
||||
const clipboard2 = new Clipboard(ele2, { // 绑定需要的触发的dom
|
||||
text: function () {
|
||||
return that.noteForm.text;
|
||||
}
|
||||
});
|
||||
clipboard2.on('success', function () {
|
||||
that.$Message.success({ content: 'text copied' });
|
||||
});
|
||||
clipboard2.on('error', function () {
|
||||
that.$Message.error('not allow to copy');
|
||||
that.$Message.error('not allow to copy.');
|
||||
});
|
||||
},
|
||||
bindCtrlAllEvent() {
|
||||
if (window.getSelection) {
|
||||
|
||||
Jquery(document).keydown(function (e) {
|
||||
if ((e.ctrlKey || e.metaKey) && e.keyCode == 65) {
|
||||
if (window.getSelection && document.createRange) {
|
||||
document.onkeydown = (e) => {
|
||||
if ((e.ctrlKey || e.metaKey) && e.key == "a") {
|
||||
e.preventDefault();
|
||||
|
||||
var element = document.getElementById("noteText");
|
||||
|
||||
let selection = window.getSelection();
|
||||
let range = document.createRange();
|
||||
range.selectNodeContents(element);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
bindMouseEvent() {
|
||||
let that = this;
|
||||
document.addEventListener('mouseup', function (e) {
|
||||
if (e.button === 2) {
|
||||
if (window.getSelection) {
|
||||
let sel = window.getSelection();
|
||||
if (sel.rangeCount > 0) {
|
||||
that.tempFragment = sel.getRangeAt(0).cloneContents();
|
||||
}
|
||||
}
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user