Add files via upload

This commit is contained in:
Jesse-Ma
2022-11-22 14:58:24 +08:00
committed by GitHub
parent 732907c3b6
commit 79c1831e6f
19 changed files with 638 additions and 796 deletions

View File

@@ -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 &copy; 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>