代码拉取完成,页面将自动刷新
<!DOCTYPE html>
<html lang="zh-CN" style="--siteFont:PT Sans; --defaultTheme:dark; --codeFontFamily:Roboto Mono, Monaco, courier, monospace; --bodyFontSize:17px; --accent:#42b983; --toogleBackground:#ffffff; --background:#091a28; --textColor:#b4b4b4; --codeTextColor:#ffffff; --codeBackgroundColor:#0e2233; --borderColor:#0d2538; --blockQuoteColor:#858585; --highlightColor:#d22778; --sidebarSublink:#b4b4b4; --codeTypeColor:#ffffff; --coverBackground:linear-gradient(to left bottom, hsl(118, 100%, 85%) 0%,hsl(181, 100%, 85%) 100%);">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>笔记</title>
<style>
.items {
padding: 0px 10px 0px 10px;
background: var(--codeBackgroundColor);
border-radius: 5px;
margin-bottom: 5px;
margin-top: 5px;
}
.items-img img {
width: 30%;
}
.send-button {
width: 80px;
height: 50px;
border-radius: 5px;
float: right;
border-color: transparent;
background: rgba(255, 255, 255, 0.01)
}
/* 此页不需要工具栏 */
.footer-c {
display: none;
}
.container {
width: 100%;
min-height: 75px;
border-radius: 5px;
font-size: 20px;
line-height: 30px;
border: none;
outline: none;
background: rgba(255, 255, 255, 0.05);
-webkit-user-modify: read-write-plaintext-only;
}
.textarea {
font-size: 18px;
font-weight: 400;
color: var(--textColor);
}
.textarea {
border: none;
outline: none;
appearance: none;
padding: 12px;
box-sizing: border-box;
height: 200px;
border-radius: 3px;
width: 100%;
margin-bottom: 12px;
background: rgba(255, 255, 255, 0.05)
}
</style>
</head>
<body style="background: var(--background);color: var(--textColor);">
<div id="box">
<h5>{{ topDataTile }} localStorage {{ version }}</h5>
<div v-if="mConfig.canPreview" v-html="previewHtml" style="min-height: 75px;"></div>
<div id="inputTextId" class="container plaintext-only" contenteditable="true" ref="edit"
v-on:input="inputTextChange" placeholder="这一刻的想法..."></div>
<div style="height:50px">
<button type="button" @click="clickSend" :disabled="!inputText" class="send-button">📝发送</button>
<button type="button" @click="forwardStep" :disabled="!circularQueue.allowForwad()"
class="send-button">➡️</button>
<button type="button" @click="backStep" :disabled="!circularQueue.allowBack()" class="send-button">⬅️</button>
<button type="button" @click="mConfig.configBar=!mConfig.configBar" class="send-button"
style="float:left;">⚙️</button>
</div>
<div v-if="mConfig.configBar">
<input type="checkbox" v-model="mConfig.showDebug"><a href="#/ZK/202209050658?id=debug">Debug</a>
<input type="checkbox" v-model="mConfig.canPreview" @click="clickForPreview">预览模式
<textarea id="mdSourceInput" v-model="mdSource" placeholder="盯←_←" class="textarea"></textarea>
<button type="button" @click="confirmPostAllMdSource(mdSource)" class="send-button">💾保存</button>
<button @click="canShowMainList=!canShowMainList">隐藏</button>
</div><br>
<div id="ltop"></div>
<div v-show="!canShowMainList" v-for="(item,index) in mainList" :key="index">
<div class="items items-img" v-html="item" ref="mit" @click="clickChangePicWidth(index)"></div>
</div>
<div v-if="mConfig.showDebug" id="debug">
<details open>
<summary>Debug</summary>
<a href="#/ZK/202209050658?id=ltop">跳转到list隐藏锚点</a><br>
<input type="text" v-model="apiUrl">
<input type="text" v-model="token">
<br>{{ debugMessageList }}<br>
<button type="button" @click="clickShowConfig">showConfig</button>
<button type="button" @click="clickUpdateConfig">updateConfig</button>
<button type="button" @click="clickInitConfig">initConfig</button>
<button type="button" @click="clickGetTodayData">获取今日数据</button>
<span>撤销恢复Debug-循环队列-</span>{{ circularQueue }}
</details>
</div>
</div>
</body>
<script src="//cdn.jsdelivr.net/npm/vue@2/dist/vue.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/axios@0.27.2/dist/axios.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/marked@3/marked.min.js"></script>
<script>
class CircularQueue {
constructor(k) {
//用来保存数据长度为k的数据结构
this.list = Array(k).fill("")
this.allowforwad = 0// 允许前进数
this.allowback = 0 // 允许后退数 可通过检测list[0]判断是否套圈。套圈后此值可通过max-allowforwad 获取 实际上使用栈更好写一点 暂时未考虑套圈
this.rear = 0 //当前元素指针
this.max = k //队列的长度
this.allowAdd = 0 //豁免入队列次数 因为撤销重做操作触发入队列
}
addQueue(addstr) { //新增内容
if (this.allowAdd != 0) { return; }
this.rear = (this.rear + 1) % this.max
this.list[this.rear] = addstr
this.allowback += 1
this.allowforwad = 0
}
back() { // 指针往后 撤销操作
this.rear -= 1
if (this.rear < 0) { this.rear = this.max - 1 }
this.allowback -= 1
this.allowforwad += 1
return this.list[this.rear]
}
forward() { // 指针往前 恢复操作
this.rear += 1
if (this.rear > this.max) { this.rear = 0 }
this.allowback += 1
this.allowforwad -= 1
return this.list[this.rear]
}
allowBack() { return (this.allowback > 0) ? true : false }
allowForwad() { return (this.allowforwad > 0) ? true : false }
}
var allMdArr = new Array() // 存储所有 json 每个 json 有 data,date,md_show_data,serverTime 字段
var vm = new Vue({
el: '#box',
data: {
version: '2.5',
mConfig: null,
apiUrl: "", token: "",
inputText: "",
mainList: null,
debugMessageList: ["两个输入框,第一个是后端api。第二个是 token。api填写类似 api.ftls.xyz/ob ,不需要协议头和尾部斜杠。另外token将加入到和后端 api 的 headers 中 Token 字段。填写完成后,点击 updateConfig 按钮并刷新页面"],
previewHtml: '',
stepTimer: null,
circularQueue: null,
mdSource: "",
canShowMainList: false,
},
created() {
if (!localStorage.hasOwnProperty("mConfig")) {
console.log("没有配置,初始化")
this.clickInitConfig()
}
else {
this.mConfig = JSON.parse(localStorage.getItem("mConfig"))
}
if (this.getQueryString("backend_address") != null) {
this.mConfig.apiUrl = this.getQueryString("backend_address") + "/ob"
}
if (this.getQueryString("token") != null) {
this.mConfig.token = this.getQueryString("token")
}
this.topDataTile = (new Date()).toDateString()
this.inputText = localStorage.getItem('inputTextCache')
this.moveFocurToEnd("inputTextId")
this.circularQueue = new CircularQueue(200);
if (localStorage.hasOwnProperty('mainListCache')) {
this.mainList = JSON.parse(localStorage.getItem('mainListCache'))
// allMdArr = respCache.data
// this.mainAllListUpdate()
}
this.getData('/recent').then(function (response) {
allMdArr = response.data; // 长度为3的数组
vm.mainAllListUpdate()
})
},
mounted() {
this.$refs.edit.innerHTML = this.inputText
},
beforeDestroy() {
clearTimeout(this.stepTimer);
},
watch: {
inputText(val, oldVal) {
clearTimeout(this.stepTimer);
this.stepTimer = setTimeout(function () {
//console.log(val)
if (vm.circularQueue.allowAdd != 0) {
vm.circularQueue.allowAdd -= 1
}
else {
vm.storageStep(val)
localStorage.setItem('inputTextCache', val)
}
}, 300);
if (vm.mConfig.canPreview) { vm.previewHtml = marked(val || '', { breaks: true }); }
},
mConfig: {
handler(val, oldVal) {
localStorage.setItem('mConfig', JSON.stringify(val))
},
deep: true
}
},
methods: {
addDebugList(text) {
// console.log(text)
this.debugMessageList.push(text)
},
mainAllListUpdate() {
var val = allMdArr
this.addDebugList("触发三天json更新")
this.mdSource = val[val.length - 1].data
var allHtmlArr = new Array()
val.forEach(item => {
// console.log(item.data)
allHtmlArr.push(this.dealDayRaw(item.data, item.date))
})
var allItem = []
for (var i = 0; i < allHtmlArr.length; i++) {
for (var j = 0; j < allHtmlArr[i].length; j++)
allItem.push(allHtmlArr[i][j])
}
this.mainList = allItem.reverse()
localStorage.setItem('mainListCache', JSON.stringify(this.mainList))
},
async getData(partUrlPath) {
let rData;
url = "//" + this.mConfig.apiUrl + partUrlPath
let req = axios.create({
headers: {
Token: this.mConfig.token,
'Content-Type': 'application/json'
}
})
await req.get(url).then(function (response) {
vm.addDebugList("Successfully Get")
rData = response
localStorage.setItem('getDataCache', JSON.stringify(response)) //缓存到本地
}).catch(function (error) {
vm.addDebugList("Get Error:")
vm.addDebugList(error)
})
return rData // raw response
},
async postData(text, partUrlPath) {
let rData;
url = "//" + this.mConfig.apiUrl + partUrlPath
let req = axios.create({
headers: {
Token: this.mConfig.token,
'Content-Type': 'application/json'
}
})
await req.post(url, JSON.stringify({ "content": text })).then(function (response) {
vm.addDebugList("Successfully Post")
rData = response
}).catch(function (error) {
vm.addDebugList(error)
})
return rData
},
dealDayRaw(oneDayRaw, date) {
var data_pre = oneDayRaw // 一天md数据 md 内容的 str
// console.log(data_pre)
data_pre = data_pre.replace(/\!\[(http.*?)\]\((.*?)\)/g, "![$2]($1)")
data_pre = data_pre.split("\n-")
// datamd = marked( data_pre || '', { sanitize: true });
data_pre = data_pre.map(item => {
item = item.replace(/(\s\[.\]\s)*([0-2][0-9]\:[0-5][0-9])\s(.*)/g, "$1 <small>" + date + " $2</small><br>$3").replace(/(\s*\[.\])/g, "-$1")
item = marked(item || '', { breaks: true });
item = item.replace(/<p>(.*)<\/p>/g, "$1")
return item
})
return data_pre
},
clickSend() {
vm.addDebugList("send 触发")
var tem = this
this.postData(this.inputText, '/today').then(function (res) {
vm.addDebugList("send 触发post完成")
vm.setPostText('')
vm.moveFocurToEnd("inputTextId")
vm.circularQueue.allowback = 0 // 允许后退撤销数 0发送后可以撤销回到最后 -1发送后禁用撤销
vm.getData('/today').then(function (response) {
vm.addDebugList("send 触发get完成")
allMdArr[allMdArr.length - 1] = response.data[0]
vm.mainAllListUpdate()
})
})
},
clickGetTodayData() {
var tem = this
vm.getData('/today').then(function (response) {
allMdArr[allMdArr.length - 1] = response.data[0]
vm.mainAllListUpdate()
})
},
confirmPostAllMdSource(mdSource) {
if (confirm('更新源码?❗️')) {
vm.postData(mdSource, '/today/all').then(function (res) {
vm.getData('/today').then(function (response) {
allMdArr[allMdArr.length - 1] = response.data[0]
vm.mainAllListUpdate()
})
})
}
},
clickShowConfig() {
vm.addDebugList(this.mConfig)
},
clickUpdateConfig() {
this.mConfig.apiUrl = this.apiUrl
this.mConfig.token = this.token
},
clickInitConfig() {
tem = {
apiUrl: "api.ftls.xyz/ob", token: "yourtoken",
preview: false, configBar: false, showDebug: false, canPreview: false
}
localStorage.setItem('mConfig', JSON.stringify(tem))
},
clickForPreview() {
this.previewHtml = marked(this.inputText || '', { breaks: true });
vm.mConfig.canPreview = !vm.mConfig.canPreview
},
storageStep(addstr) {
this.circularQueue.addQueue(addstr)
},
backStep() {
this.circularQueue.allowAdd += 1
this.setPostText(this.circularQueue.back())
this.moveFocurToEnd("inputTextId")
},
forwardStep() {
this.circularQueue.allowAdd += 1
this.setPostText(this.circularQueue.forward())
this.moveFocurToEnd("inputTextId")
},
setPostText(instr) {
this.inputText = instr
this.$refs.edit.innerHTML = instr
},
inputTextChange() {
this.inputText = this.$refs.edit.innerHTML
},
clickChangePicWidth(obj) {
this.$nextTick(() => {
this.$refs.mit[obj].classList.toggle('items-img')
});
},
moveFocurToEnd(id) {
this.$nextTick(() => {
let notesDom = document.getElementById(id);
if (window.getSelection) {
let range = window.getSelection(); // 创建range
range.selectAllChildren(notesDom); // range 选择notesDom下所有子内容
range.collapseToEnd(); // 光标移至最后
} else if (document.selection) {
let range = document.selection.createRange(); // 创建选择对象
range.moveToElementText(notesDom); // range定位到notesDom
range.collapse(false); // 光标移至最后
range.select();
}
});
},
getQueryString(name) {
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
var r = window.location.search.substr(1).match(reg);
if (r != null) {
return unescape(r[2]);
}
return null;
}
}
})
</script>
</html>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。