fix theme...
154
public/404.html
@@ -1,154 +0,0 @@
|
||||
<!DOCTYPE html><html lang="zh-Hans" data-theme="light"><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,viewport-fit=cover"><title>Page Not Found | QuickReference</title><meta name="author" content="shenjianZ"><meta name="copyright" content="shenjianZ"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="一份快捷简便的文档,便于查阅编程的细节">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="QuickReference">
|
||||
<meta property="og:url" content="http://rq.shenjianl.cn/404.html">
|
||||
<meta property="og:site_name" content="QuickReference">
|
||||
<meta property="og:description" content="一份快捷简便的文档,便于查阅编程的细节">
|
||||
<meta property="og:locale">
|
||||
<meta property="og:image" content="http://rq.shenjianl.cn/img/avatar.jpg">
|
||||
<meta property="article:author" content="shenjianZ">
|
||||
<meta property="article:tag" content="doucment">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:image" content="http://rq.shenjianl.cn/img/avatar.jpg"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="http://rq.shenjianl.cn/404.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css?v=4.13.0"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.5.1/css/all.min.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0.33/dist/fancybox/fancybox.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = {
|
||||
root: '/',
|
||||
algolia: undefined,
|
||||
localSearch: undefined,
|
||||
translate: undefined,
|
||||
noticeOutdate: undefined,
|
||||
highlight: {"plugin":"highlight.js","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
|
||||
copy: {
|
||||
success: 'Copy Successful',
|
||||
error: 'Copy Error',
|
||||
noSupport: 'Browser Not Supported'
|
||||
},
|
||||
relativeDate: {
|
||||
homepage: false,
|
||||
post: false
|
||||
},
|
||||
runtime: 'days',
|
||||
dateSuffix: {
|
||||
just: 'Just now',
|
||||
min: 'minutes ago',
|
||||
hour: 'hours ago',
|
||||
day: 'days ago',
|
||||
month: 'months ago'
|
||||
},
|
||||
copyright: undefined,
|
||||
lightbox: 'fancybox',
|
||||
Snackbar: undefined,
|
||||
infinitegrid: {
|
||||
js: 'https://cdn.jsdelivr.net/npm/@egjs/infinitegrid@4.11.1/dist/infinitegrid.min.js',
|
||||
buttonText: 'Load More'
|
||||
},
|
||||
isPhotoFigcaption: false,
|
||||
islazyload: false,
|
||||
isAnchor: false,
|
||||
percent: {
|
||||
toc: true,
|
||||
rightside: false,
|
||||
},
|
||||
autoDarkmode: false
|
||||
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
|
||||
title: 'Page Not Found',
|
||||
isPost: false,
|
||||
isHome: false,
|
||||
isHighlightShrink: false,
|
||||
isToc: false,
|
||||
postUpdate: '2024-07-30 21:38:06'
|
||||
}</script><script>(win=>{
|
||||
win.saveToLocal = {
|
||||
set: (key, value, ttl) => {
|
||||
if (ttl === 0) return
|
||||
const now = Date.now()
|
||||
const expiry = now + ttl * 86400000
|
||||
const item = {
|
||||
value,
|
||||
expiry
|
||||
}
|
||||
localStorage.setItem(key, JSON.stringify(item))
|
||||
},
|
||||
|
||||
get: key => {
|
||||
const itemStr = localStorage.getItem(key)
|
||||
|
||||
if (!itemStr) {
|
||||
return undefined
|
||||
}
|
||||
const item = JSON.parse(itemStr)
|
||||
const now = Date.now()
|
||||
|
||||
if (now > item.expiry) {
|
||||
localStorage.removeItem(key)
|
||||
return undefined
|
||||
}
|
||||
return item.value
|
||||
}
|
||||
}
|
||||
|
||||
win.getScript = (url, attr = {}) => new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script')
|
||||
script.src = url
|
||||
script.async = true
|
||||
script.onerror = reject
|
||||
script.onload = script.onreadystatechange = function() {
|
||||
const loadState = this.readyState
|
||||
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
|
||||
script.onload = script.onreadystatechange = null
|
||||
resolve()
|
||||
}
|
||||
|
||||
Object.keys(attr).forEach(key => {
|
||||
script.setAttribute(key, attr[key])
|
||||
})
|
||||
|
||||
document.head.appendChild(script)
|
||||
})
|
||||
|
||||
win.getCSS = (url, id = false) => new Promise((resolve, reject) => {
|
||||
const link = document.createElement('link')
|
||||
link.rel = 'stylesheet'
|
||||
link.href = url
|
||||
if (id) link.id = id
|
||||
link.onerror = reject
|
||||
link.onload = link.onreadystatechange = function() {
|
||||
const loadState = this.readyState
|
||||
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
|
||||
link.onload = link.onreadystatechange = null
|
||||
resolve()
|
||||
}
|
||||
document.head.appendChild(link)
|
||||
})
|
||||
|
||||
win.activateDarkMode = () => {
|
||||
document.documentElement.setAttribute('data-theme', 'dark')
|
||||
if (document.querySelector('meta[name="theme-color"]') !== null) {
|
||||
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
|
||||
}
|
||||
}
|
||||
win.activateLightMode = () => {
|
||||
document.documentElement.setAttribute('data-theme', 'light')
|
||||
if (document.querySelector('meta[name="theme-color"]') !== null) {
|
||||
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
|
||||
}
|
||||
}
|
||||
const t = saveToLocal.get('theme')
|
||||
|
||||
if (t === 'dark') activateDarkMode()
|
||||
else if (t === 'light') activateLightMode()
|
||||
|
||||
const asideStatus = saveToLocal.get('aside-status')
|
||||
if (asideStatus !== undefined) {
|
||||
if (asideStatus === 'hide') {
|
||||
document.documentElement.classList.add('hide-aside')
|
||||
} else {
|
||||
document.documentElement.classList.remove('hide-aside')
|
||||
}
|
||||
}
|
||||
|
||||
const detectApple = () => {
|
||||
if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
|
||||
document.documentElement.classList.add('apple')
|
||||
}
|
||||
}
|
||||
detectApple()
|
||||
})(window)</script><meta name="generator" content="Hexo 7.3.0"></head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="/img/avatar.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">Articles</div><div class="length-num">2</div></a><a href="/tags/"><div class="headline">Tags</div><div class="length-num">0</div></a><a href="/categories/"><div class="headline">Categories</div><div class="length-num">0</div></a></div><hr class="custom-hr"/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> Home</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> Archives</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> Tags</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> Categories</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> List</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/music/"><i class="fa-fw fas fa-music"></i><span> Music</span></a></li><li><a class="site-page child" href="/movies/"><i class="fa-fw fas fa-video"></i><span> Movie</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> Link</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> About</span></a></div></div></div></div><div class="error404" id="body-wrap"><header class="not-top-img fixed" id="page-header"><nav id="nav"><span id="blog-info"><a href="/" title="QuickReference"><span class="site-name">QuickReference</span></a></span><div id="menus"><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> Home</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> Archives</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> Tags</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> Categories</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> List</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/music/"><i class="fa-fw fas fa-music"></i><span> Music</span></a></li><li><a class="site-page child" href="/movies/"><i class="fa-fw fas fa-video"></i><span> Movie</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> Link</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> About</span></a></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav></header><div id="error-wrap"><div class="error-content"><div class="error-img"><img src="https://i.loli.net/2020/05/19/aKOcLiyPl2JQdFD.png" alt="Page not found"></div><div class="error-info"><h1 class="error_title">404</h1><div class="error_subtitle">Page Not Found</div></div></div></div></div><div id="rightside"><div id="rightside-config-hide"><button id="darkmode" type="button" title="Toggle Between Light And Dark Mode"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="Toggle between Single-column and Double-column"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside-config" type="button" title="Setting"><i class="fas fa-cog fa-spin"></i></button><button id="go-up" type="button" title="Back To Top"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js?v=4.13.0"></script><script src="/js/main.js?v=4.13.0"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0.33/dist/fancybox/fancybox.umd.min.js"></script><div class="js-pjax"></div><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div></body></html>
|
||||
156
public/categories/index.html
Normal file
@@ -0,0 +1,156 @@
|
||||
<!DOCTYPE html><html lang="zh-CN" data-theme="light"><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,viewport-fit=cover"><title>categories | QuickReference</title><meta name="author" content="shenjianZ"><meta name="copyright" content="shenjianZ"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="一份快捷简便的文档,便于查阅编程的细节">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:title" content="categories">
|
||||
<meta property="og:url" content="http://rq.shenjianl.cn/categories/index.html">
|
||||
<meta property="og:site_name" content="QuickReference">
|
||||
<meta property="og:description" content="一份快捷简便的文档,便于查阅编程的细节">
|
||||
<meta property="og:locale" content="zh_CN">
|
||||
<meta property="og:image" content="https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png">
|
||||
<meta property="article:published_time" content="2024-07-31T00:33:49.000Z">
|
||||
<meta property="article:modified_time" content="2024-07-31T00:34:01.357Z">
|
||||
<meta property="article:author" content="shenjianZ">
|
||||
<meta property="article:tag" content="doucment">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:image" content="https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="http://rq.shenjianl.cn/categories/index.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css?v=4.13.0"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.5.1/css/all.min.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0.33/dist/fancybox/fancybox.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = {
|
||||
root: '/',
|
||||
algolia: undefined,
|
||||
localSearch: undefined,
|
||||
translate: undefined,
|
||||
noticeOutdate: undefined,
|
||||
highlight: {"plugin":"highlight.js","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
|
||||
copy: {
|
||||
success: '复制成功',
|
||||
error: '复制错误',
|
||||
noSupport: '浏览器不支持'
|
||||
},
|
||||
relativeDate: {
|
||||
homepage: false,
|
||||
post: false
|
||||
},
|
||||
runtime: '',
|
||||
dateSuffix: {
|
||||
just: '刚刚',
|
||||
min: '分钟前',
|
||||
hour: '小时前',
|
||||
day: '天前',
|
||||
month: '个月前'
|
||||
},
|
||||
copyright: undefined,
|
||||
lightbox: 'fancybox',
|
||||
Snackbar: undefined,
|
||||
infinitegrid: {
|
||||
js: 'https://cdn.jsdelivr.net/npm/@egjs/infinitegrid@4.11.1/dist/infinitegrid.min.js',
|
||||
buttonText: '加载更多'
|
||||
},
|
||||
isPhotoFigcaption: false,
|
||||
islazyload: false,
|
||||
isAnchor: false,
|
||||
percent: {
|
||||
toc: true,
|
||||
rightside: false,
|
||||
},
|
||||
autoDarkmode: false
|
||||
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
|
||||
title: 'categories',
|
||||
isPost: false,
|
||||
isHome: false,
|
||||
isHighlightShrink: false,
|
||||
isToc: false,
|
||||
postUpdate: '2024-07-31 08:34:01'
|
||||
}</script><script>(win=>{
|
||||
win.saveToLocal = {
|
||||
set: (key, value, ttl) => {
|
||||
if (ttl === 0) return
|
||||
const now = Date.now()
|
||||
const expiry = now + ttl * 86400000
|
||||
const item = {
|
||||
value,
|
||||
expiry
|
||||
}
|
||||
localStorage.setItem(key, JSON.stringify(item))
|
||||
},
|
||||
|
||||
get: key => {
|
||||
const itemStr = localStorage.getItem(key)
|
||||
|
||||
if (!itemStr) {
|
||||
return undefined
|
||||
}
|
||||
const item = JSON.parse(itemStr)
|
||||
const now = Date.now()
|
||||
|
||||
if (now > item.expiry) {
|
||||
localStorage.removeItem(key)
|
||||
return undefined
|
||||
}
|
||||
return item.value
|
||||
}
|
||||
}
|
||||
|
||||
win.getScript = (url, attr = {}) => new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script')
|
||||
script.src = url
|
||||
script.async = true
|
||||
script.onerror = reject
|
||||
script.onload = script.onreadystatechange = function() {
|
||||
const loadState = this.readyState
|
||||
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
|
||||
script.onload = script.onreadystatechange = null
|
||||
resolve()
|
||||
}
|
||||
|
||||
Object.keys(attr).forEach(key => {
|
||||
script.setAttribute(key, attr[key])
|
||||
})
|
||||
|
||||
document.head.appendChild(script)
|
||||
})
|
||||
|
||||
win.getCSS = (url, id = false) => new Promise((resolve, reject) => {
|
||||
const link = document.createElement('link')
|
||||
link.rel = 'stylesheet'
|
||||
link.href = url
|
||||
if (id) link.id = id
|
||||
link.onerror = reject
|
||||
link.onload = link.onreadystatechange = function() {
|
||||
const loadState = this.readyState
|
||||
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
|
||||
link.onload = link.onreadystatechange = null
|
||||
resolve()
|
||||
}
|
||||
document.head.appendChild(link)
|
||||
})
|
||||
|
||||
win.activateDarkMode = () => {
|
||||
document.documentElement.setAttribute('data-theme', 'dark')
|
||||
if (document.querySelector('meta[name="theme-color"]') !== null) {
|
||||
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
|
||||
}
|
||||
}
|
||||
win.activateLightMode = () => {
|
||||
document.documentElement.setAttribute('data-theme', 'light')
|
||||
if (document.querySelector('meta[name="theme-color"]') !== null) {
|
||||
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
|
||||
}
|
||||
}
|
||||
const t = saveToLocal.get('theme')
|
||||
|
||||
if (t === 'dark') activateDarkMode()
|
||||
else if (t === 'light') activateLightMode()
|
||||
|
||||
const asideStatus = saveToLocal.get('aside-status')
|
||||
if (asideStatus !== undefined) {
|
||||
if (asideStatus === 'hide') {
|
||||
document.documentElement.classList.add('hide-aside')
|
||||
} else {
|
||||
document.documentElement.classList.remove('hide-aside')
|
||||
}
|
||||
}
|
||||
|
||||
const detectApple = () => {
|
||||
if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
|
||||
document.documentElement.classList.add('apple')
|
||||
}
|
||||
}
|
||||
detectApple()
|
||||
})(window)</script><meta name="generator" content="Hexo 7.3.0"></head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">2</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">0</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">0</div></a></div><hr class="custom-hr"/></div></div><div class="page" id="body-wrap"><header class="not-top-img" id="page-header"><nav id="nav"><span id="blog-info"><a href="/" title="QuickReference"><span class="site-name">QuickReference</span></a></span><div id="menus"><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav></header><main class="layout hide-aside" id="content-inner"><div id="page"><h1 class="page-title">categories</h1><div class="category-lists"></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">©2020 - 2024 By shenjianZ</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button></div><div id="rightside-config-show"><button id="rightside-config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js?v=4.13.0"></script><script src="/js/main.js?v=4.13.0"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui@5.0.33/dist/fancybox/fancybox.umd.min.js"></script><div class="js-pjax"></div><canvas class="fireworks" mobile="false"></canvas><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1.1.3/dist/fireworks.min.js"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div></body></html>
|
||||
24547
public/css/index.css
BIN
public/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 138 KiB |
BIN
public/img/512.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
9
public/img/algolia.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1366 362">
|
||||
<linearGradient id="a" x1="428.258" x2="434.145" y1="404.15" y2="409.85" gradientUnits="userSpaceOnUse" gradientTransform="matrix(94.045 0 0 -94.072 -40381.527 38479.52)">
|
||||
<stop offset="0" stop-color="#00aeff"/>
|
||||
<stop offset="1" stop-color="#3369e7"/>
|
||||
</linearGradient>
|
||||
<path fill="url(#a)" d="M61.8 15.4h242.8c23.9 0 43.4 19.4 43.4 43.4v242.9c0 23.9-19.4 43.4-43.4 43.4H61.8c-23.9 0-43.4-19.4-43.4-43.4v-243c0-23.9 19.4-43.3 43.4-43.3z"/>
|
||||
<path fill="#FFF" d="M187 98.7c-51.4 0-93.1 41.7-93.1 93.2S135.6 285 187 285s93.1-41.7 93.1-93.2-41.6-93.1-93.1-93.1zm0 158.8c-36.2 0-65.6-29.4-65.6-65.6s29.4-65.6 65.6-65.6 65.6 29.4 65.6 65.6-29.3 65.6-65.6 65.6zm0-117.8v48.9c0 1.4 1.5 2.4 2.8 1.7l43.4-22.5c1-.5 1.3-1.7.8-2.7-9-15.8-25.7-26.6-45-27.3-1 0-2 .8-2 1.9zm-60.8-35.9l-5.7-5.7c-5.6-5.6-14.6-5.6-20.2 0l-6.8 6.8c-5.6 5.6-5.6 14.6 0 20.2l5.6 5.6c.9.9 2.2.7 3-.2 3.3-4.5 6.9-8.8 10.9-12.8 4.1-4.1 8.3-7.7 12.9-11 1-.6 1.1-2 .3-2.9zM217.5 89V77.7c0-7.9-6.4-14.3-14.3-14.3h-33.3c-7.9 0-14.3 6.4-14.3 14.3v11.6c0 1.3 1.2 2.2 2.5 1.9 9.3-2.7 19.1-4.1 29-4.1 9.5 0 18.9 1.3 28 3.8 1.2.3 2.4-.6 2.4-1.9z"/>
|
||||
<path fill="#182359" d="M842.5 267.6c0 26.7-6.8 46.2-20.5 58.6-13.7 12.4-34.6 18.6-62.8 18.6-10.3 0-31.7-2-48.8-5.8l6.3-31c14.3 3 33.2 3.8 43.1 3.8 15.7 0 26.9-3.2 33.6-9.6s10-15.9 10-28.5v-6.4c-3.9 1.9-9 3.8-15.3 5.8-6.3 1.9-13.6 2.9-21.8 2.9-10.8 0-20.6-1.7-29.5-5.1-8.9-3.4-16.6-8.4-22.9-15-6.3-6.6-11.3-14.9-14.8-24.8s-5.3-27.6-5.3-40.6c0-12.2 1.9-27.5 5.6-37.7 3.8-10.2 9.2-19 16.5-26.3 7.2-7.3 16-12.9 26.3-17s22.4-6.7 35.5-6.7c12.7 0 24.4 1.6 35.8 3.5 11.4 1.9 21.1 3.9 29 6.1v155.2zm-108.7-77.2c0 16.4 3.6 34.6 10.8 42.2 7.2 7.6 16.5 11.4 27.9 11.4 6.2 0 12.1-.9 17.6-2.6 5.5-1.7 9.9-3.7 13.4-6.1v-97.1c-2.8-.6-14.5-3-25.8-3.3-14.2-.4-25 5.4-32.6 14.7-7.5 9.3-11.3 25.6-11.3 40.8zm294.3 0c0 13.2-1.9 23.2-5.8 34.1s-9.4 20.2-16.5 27.9c-7.1 7.7-15.6 13.7-25.6 17.9s-25.4 6.6-33.1 6.6c-7.7-.1-23-2.3-32.9-6.6-9.9-4.3-18.4-10.2-25.5-17.9-7.1-7.7-12.6-17-16.6-27.9s-6-20.9-6-34.1c0-13.2 1.8-25.9 5.8-36.7 4-10.8 9.6-20 16.8-27.7s15.8-13.6 25.6-17.8c9.9-4.2 20.8-6.2 32.6-6.2s22.7 2.1 32.7 6.2c10 4.2 18.6 10.1 25.6 17.8 7.1 7.7 12.6 16.9 16.6 27.7 4.2 10.8 6.3 23.5 6.3 36.7zm-40 .1c0-16.9-3.7-31-10.9-40.8-7.2-9.9-17.3-14.8-30.2-14.8-12.9 0-23 4.9-30.2 14.8-7.2 9.9-10.7 23.9-10.7 40.8 0 17.1 3.6 28.6 10.8 38.5 7.2 10 17.3 14.9 30.2 14.9 12.9 0 23-5 30.2-14.9 7.2-10 10.8-21.4 10.8-38.5zm127.1 86.4c-64.1.3-64.1-51.8-64.1-60.1L1051 32l39.1-6.2v183.6c0 4.7 0 34.5 25.1 34.6v32.9zm68.9 0h-39.3V108.1l39.3-6.2v175zm-19.7-193.5c13.1 0 23.8-10.6 23.8-23.7S1177.6 36 1164.4 36s-23.8 10.6-23.8 23.7 10.7 23.7 23.8 23.7zm117.4 18.6c12.9 0 23.8 1.6 32.6 4.8 8.8 3.2 15.9 7.7 21.1 13.4s8.9 13.5 11.1 21.7c2.3 8.2 3.4 17.2 3.4 27.1v100.6c-6 1.3-15.1 2.8-27.3 4.6s-25.9 2.7-41.1 2.7c-10.1 0-19.4-1-27.7-2.9-8.4-1.9-15.5-5-21.5-9.3-5.9-4.3-10.5-9.8-13.9-16.6-3.3-6.8-5-16.4-5-26.4 0-9.6 1.9-15.7 5.6-22.3 3.8-6.6 8.9-12 15.3-16.2 6.5-4.2 13.9-7.2 22.4-9s17.4-2.7 26.6-2.7c4.3 0 8.8.3 13.6.8s9.8 1.4 15.2 2.7v-6.4c0-4.5-.5-8.8-1.6-12.8-1.1-4.1-3-7.6-5.6-10.7-2.7-3.1-6.2-5.5-10.6-7.2s-10-3-16.7-3c-9 0-17.2 1.1-24.7 2.4-7.5 1.3-13.7 2.8-18.4 4.5l-4.7-32.1c4.9-1.7 12.2-3.4 21.6-5.1s19.5-2.6 30.3-2.6zm3.3 141.9c12 0 20.9-.7 27.1-1.9v-39.8c-2.2-.6-5.3-1.3-9.4-1.9-4.1-.6-8.6-1-13.6-1-4.3 0-8.7.3-13.1 1-4.4.6-8.4 1.8-11.9 3.5s-6.4 4.1-8.5 7.2c-2.2 3.1-3.2 4.9-3.2 9.6 0 9.2 3.2 14.5 9 18 5.9 3.6 13.7 5.3 23.6 5.3zM512.9 103c12.9 0 23.8 1.6 32.6 4.8 8.8 3.2 15.9 7.7 21.1 13.4 5.3 5.8 8.9 13.5 11.1 21.7 2.3 8.2 3.4 17.2 3.4 27.1v100.6c-6 1.3-15.1 2.8-27.3 4.6-12.2 1.8-25.9 2.7-41.1 2.7-10.1 0-19.4-1-27.7-2.9-8.4-1.9-15.5-5-21.5-9.3-5.9-4.3-10.5-9.8-13.9-16.6-3.3-6.8-5-16.4-5-26.4 0-9.6 1.9-15.7 5.6-22.3 3.8-6.6 8.9-12 15.3-16.2 6.5-4.2 13.9-7.2 22.4-9s17.4-2.7 26.6-2.7c4.3 0 8.8.3 13.6.8 4.7.5 9.8 1.4 15.2 2.7v-6.4c0-4.5-.5-8.8-1.6-12.8-1.1-4.1-3-7.6-5.6-10.7-2.7-3.1-6.2-5.5-10.6-7.2-4.4-1.7-10-3-16.7-3-9 0-17.2 1.1-24.7 2.4-7.5 1.3-13.7 2.8-18.4 4.5l-4.7-32.1c4.9-1.7 12.2-3.4 21.6-5.1 9.4-1.8 19.5-2.6 30.3-2.6zm3.4 142c12 0 20.9-.7 27.1-1.9v-39.8c-2.2-.6-5.3-1.3-9.4-1.9-4.1-.6-8.6-1-13.6-1-4.3 0-8.7.3-13.1 1-4.4.6-8.4 1.8-11.9 3.5s-6.4 4.1-8.5 7.2c-2.2 3.1-3.2 4.9-3.2 9.6 0 9.2 3.2 14.5 9 18s13.7 5.3 23.6 5.3zm158.5 31.9c-64.1.3-64.1-51.8-64.1-60.1L610.6 32l39.1-6.2v183.6c0 4.7 0 34.5 25.1 34.6v32.9z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
BIN
public/img/comment_bg.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
public/img/default_cover.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/img/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 590 KiB |
BIN
public/img/loading.gif
Normal file
|
After Width: | Height: | Size: 721 KiB |
BIN
public/img/siteicon/16.png
Normal file
|
After Width: | Height: | Size: 283 B |
BIN
public/img/siteicon/32.png
Normal file
|
After Width: | Height: | Size: 431 B |
BIN
public/img/siteicon/apple-icon-180.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
public/img/siteicon/manifest-icon-192.maskable.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
public/img/siteicon/manifest-icon-512.maskable.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
438
public/js/anzhiyu/ai_abstract.js
Normal file
@@ -0,0 +1,438 @@
|
||||
(function () {
|
||||
const {
|
||||
randomNum,
|
||||
basicWordCount,
|
||||
btnLink,
|
||||
key: AIKey,
|
||||
Referer: AIReferer,
|
||||
gptName,
|
||||
switchBtn,
|
||||
mode: initialMode,
|
||||
} = GLOBAL_CONFIG.postHeadAiDescription;
|
||||
|
||||
const { title, postAI, pageFillDescription } = GLOBAL_CONFIG_SITE;
|
||||
|
||||
let lastAiRandomIndex = -1;
|
||||
let animationRunning = true;
|
||||
let mode = initialMode;
|
||||
let refreshNum = 0;
|
||||
let prevParam;
|
||||
let audio = null;
|
||||
let isPaused = false;
|
||||
let summaryID = null;
|
||||
|
||||
const post_ai = document.querySelector(".post-ai-description");
|
||||
const aiTitleRefreshIcon = post_ai.querySelector(".ai-title .anzhiyufont.anzhiyu-icon-arrow-rotate-right");
|
||||
let aiReadAloudIcon = post_ai.querySelector(".anzhiyu-icon-circle-dot");
|
||||
const explanation = post_ai.querySelector(".ai-explanation");
|
||||
|
||||
let aiStr = "";
|
||||
let aiStrLength = "";
|
||||
let delayInit = 600;
|
||||
let indexI = 0;
|
||||
let indexJ = 0;
|
||||
let timeouts = [];
|
||||
let elapsed = 0;
|
||||
|
||||
const observer = createIntersectionObserver();
|
||||
const aiFunctions = [introduce, aiTitleRefreshIconClick, aiRecommend, aiGoHome];
|
||||
|
||||
const aiBtnList = post_ai.querySelectorAll(".ai-btn-item");
|
||||
const filteredHeadings = Array.from(aiBtnList).filter(heading => heading.id !== "go-tianli-blog");
|
||||
filteredHeadings.forEach((item, index) => {
|
||||
item.addEventListener("click", () => {
|
||||
aiFunctions[index]();
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById("ai-tag").addEventListener("click", onAiTagClick);
|
||||
aiTitleRefreshIcon.addEventListener("click", onAiTitleRefreshIconClick);
|
||||
document.getElementById("go-tianli-blog").addEventListener("click", () => {
|
||||
window.open(btnLink, "_blank");
|
||||
});
|
||||
aiReadAloudIcon.addEventListener("click", readAloud);
|
||||
|
||||
async function readAloud() {
|
||||
if (!summaryID) {
|
||||
anzhiyu.snackbarShow("摘要还没加载完呢,请稍后。。。");
|
||||
return;
|
||||
}
|
||||
aiReadAloudIcon = post_ai.querySelector(".anzhiyu-icon-circle-dot");
|
||||
aiReadAloudIcon.style.opacity = "0.2";
|
||||
if (audio && !isPaused) {
|
||||
audio.pause();
|
||||
isPaused = true;
|
||||
aiReadAloudIcon.style.opacity = "1";
|
||||
aiReadAloudIcon.style.animation = "";
|
||||
aiReadAloudIcon.style.cssText = "animation: ''; opacity: 1;cursor: pointer;";
|
||||
return;
|
||||
}
|
||||
|
||||
if (audio && isPaused) {
|
||||
audio.play();
|
||||
isPaused = false;
|
||||
aiReadAloudIcon.style.cssText = "animation: breathe .5s linear infinite; opacity: 0.2;cursor: pointer";
|
||||
return;
|
||||
}
|
||||
|
||||
const options = {
|
||||
key: AIKey,
|
||||
Referer: AIReferer,
|
||||
};
|
||||
const requestParams = new URLSearchParams({
|
||||
key: options.key,
|
||||
id: summaryID,
|
||||
});
|
||||
|
||||
const requestOptions = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Referer: options.Referer,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(`https://summary.tianli0.top/audio?${requestParams}`, requestOptions);
|
||||
if (response.status === 403) {
|
||||
console.error("403 refer与key不匹配。");
|
||||
} else if (response.status === 500) {
|
||||
console.error("500 系统内部错误");
|
||||
} else {
|
||||
const audioBlob = await response.blob();
|
||||
const audioURL = URL.createObjectURL(audioBlob);
|
||||
audio = new Audio(audioURL);
|
||||
audio.play();
|
||||
aiReadAloudIcon.style.cssText = "animation: breathe .5s linear infinite; opacity: 0.2;cursor: pointer";
|
||||
audio.addEventListener("ended", () => {
|
||||
audio = null;
|
||||
aiReadAloudIcon.style.opacity = "1";
|
||||
aiReadAloudIcon.style.animation = "";
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("请求发生错误❎");
|
||||
}
|
||||
}
|
||||
if (switchBtn) {
|
||||
document.getElementById("ai-Toggle").addEventListener("click", changeShowMode);
|
||||
}
|
||||
|
||||
aiAbstract();
|
||||
showAiBtn();
|
||||
|
||||
function createIntersectionObserver() {
|
||||
return new IntersectionObserver(
|
||||
entries => {
|
||||
let isVisible = entries[0].isIntersecting;
|
||||
animationRunning = isVisible;
|
||||
if (animationRunning) {
|
||||
delayInit = indexI === 0 ? 200 : 20;
|
||||
timeouts[1] = setTimeout(() => {
|
||||
if (indexJ) {
|
||||
indexI = 0;
|
||||
indexJ = 0;
|
||||
}
|
||||
if (indexI === 0) {
|
||||
explanation.innerHTML = aiStr.charAt(0);
|
||||
}
|
||||
requestAnimationFrame(animate);
|
||||
}, delayInit);
|
||||
}
|
||||
},
|
||||
{ threshold: 0 }
|
||||
);
|
||||
}
|
||||
|
||||
function animate(timestamp) {
|
||||
if (!animationRunning) {
|
||||
return;
|
||||
}
|
||||
if (!animate.start) animate.start = timestamp;
|
||||
elapsed = timestamp - animate.start;
|
||||
if (elapsed >= 20) {
|
||||
animate.start = timestamp;
|
||||
if (indexI < aiStrLength - 1) {
|
||||
let char = aiStr.charAt(indexI + 1);
|
||||
let delay = /[,.,。!?!?]/.test(char) ? 150 : 20;
|
||||
if (explanation.firstElementChild) {
|
||||
explanation.removeChild(explanation.firstElementChild);
|
||||
}
|
||||
explanation.innerHTML += char;
|
||||
let div = document.createElement("div");
|
||||
div.className = "ai-cursor";
|
||||
explanation.appendChild(div);
|
||||
indexI++;
|
||||
if (delay === 150) {
|
||||
post_ai.querySelector(".ai-explanation .ai-cursor").style.opacity = "0.2";
|
||||
}
|
||||
if (indexI === aiStrLength - 1) {
|
||||
observer.disconnect();
|
||||
explanation.removeChild(explanation.firstElementChild);
|
||||
}
|
||||
timeouts[0] = setTimeout(() => {
|
||||
requestAnimationFrame(animate);
|
||||
}, delay);
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
}
|
||||
|
||||
function clearTimeouts() {
|
||||
if (timeouts.length) {
|
||||
timeouts.forEach(item => {
|
||||
if (item) {
|
||||
clearTimeout(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function startAI(str, df = true) {
|
||||
indexI = 0;
|
||||
indexJ = 1;
|
||||
clearTimeouts();
|
||||
animationRunning = false;
|
||||
elapsed = 0;
|
||||
observer.disconnect();
|
||||
explanation.innerHTML = df ? "生成中. . ." : "请等待. . .";
|
||||
aiStr = str;
|
||||
aiStrLength = aiStr.length;
|
||||
observer.observe(post_ai);
|
||||
}
|
||||
|
||||
async function aiAbstract(num = basicWordCount) {
|
||||
if (mode === "tianli") {
|
||||
await aiAbstractTianli(num);
|
||||
} else {
|
||||
aiAbstractLocal();
|
||||
}
|
||||
}
|
||||
|
||||
async function aiAbstractTianli(num) {
|
||||
indexI = 0;
|
||||
indexJ = 1;
|
||||
clearTimeouts();
|
||||
animationRunning = false;
|
||||
elapsed = 0;
|
||||
observer.disconnect();
|
||||
|
||||
num = Math.max(10, Math.min(2000, num));
|
||||
const options = {
|
||||
key: AIKey,
|
||||
Referer: AIReferer,
|
||||
};
|
||||
const truncateDescription = (title + pageFillDescription).trim().substring(0, num);
|
||||
|
||||
const requestBody = {
|
||||
key: options.key,
|
||||
content: truncateDescription,
|
||||
url: location.href,
|
||||
};
|
||||
|
||||
const requestOptions = {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Referer: options.Referer,
|
||||
},
|
||||
body: JSON.stringify(requestBody),
|
||||
};
|
||||
console.info(truncateDescription.length);
|
||||
try {
|
||||
let animationInterval = null;
|
||||
let summary;
|
||||
if (animationInterval) clearInterval(animationInterval);
|
||||
animationInterval = setInterval(() => {
|
||||
const animationText = "生成中" + ".".repeat(indexJ);
|
||||
explanation.innerHTML = animationText;
|
||||
indexJ = (indexJ % 3) + 1;
|
||||
}, 500);
|
||||
const response = await fetch(`https://summary.tianli0.top/`, requestOptions);
|
||||
let result;
|
||||
if (response.status === 403) {
|
||||
result = {
|
||||
summary: "403 refer与key不匹配。",
|
||||
};
|
||||
} else if (response.status === 500) {
|
||||
result = {
|
||||
summary: "500 系统内部错误",
|
||||
};
|
||||
} else {
|
||||
result = await response.json();
|
||||
}
|
||||
|
||||
summary = result.summary.trim();
|
||||
summaryID = result.id;
|
||||
|
||||
setTimeout(() => {
|
||||
aiTitleRefreshIcon.style.opacity = "1";
|
||||
}, 300);
|
||||
if (summary) {
|
||||
startAI(summary);
|
||||
} else {
|
||||
startAI("摘要获取失败!!!请检查Tianli服务是否正常!!!");
|
||||
}
|
||||
clearInterval(animationInterval);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
explanation.innerHTML = "发生异常" + error;
|
||||
}
|
||||
}
|
||||
|
||||
function aiAbstractLocal() {
|
||||
const strArr = postAI.split(",").map(item => item.trim());
|
||||
if (strArr.length !== 1) {
|
||||
let randomIndex = Math.floor(Math.random() * strArr.length);
|
||||
while (randomIndex === lastAiRandomIndex) {
|
||||
randomIndex = Math.floor(Math.random() * strArr.length);
|
||||
}
|
||||
lastAiRandomIndex = randomIndex;
|
||||
startAI(strArr[randomIndex]);
|
||||
} else {
|
||||
startAI(strArr[0]);
|
||||
}
|
||||
setTimeout(() => {
|
||||
aiTitleRefreshIcon.style.opacity = "1";
|
||||
}, 600);
|
||||
}
|
||||
|
||||
function aiRecommend() {
|
||||
indexI = 0;
|
||||
indexJ = 1;
|
||||
clearTimeouts();
|
||||
animationRunning = false;
|
||||
elapsed = 0;
|
||||
explanation.innerHTML = "生成中. . .";
|
||||
aiStr = "";
|
||||
aiStrLength = "";
|
||||
observer.disconnect();
|
||||
timeouts[2] = setTimeout(() => {
|
||||
explanation.innerHTML = recommendList();
|
||||
}, 600);
|
||||
}
|
||||
|
||||
function recommendList() {
|
||||
let thumbnail = document.querySelectorAll(".relatedPosts-list a");
|
||||
if (!thumbnail.length) {
|
||||
const cardRecentPost = document.querySelector(".card-widget.card-recent-post");
|
||||
if (!cardRecentPost) return "";
|
||||
|
||||
thumbnail = cardRecentPost.querySelectorAll(".aside-list-item a");
|
||||
|
||||
let list = "";
|
||||
for (let i = 0; i < thumbnail.length; i++) {
|
||||
const item = thumbnail[i];
|
||||
list += `<div class="ai-recommend-item"><span class="index">${
|
||||
i + 1
|
||||
}:</span><a href="javascript:;" onclick="pjax.loadUrl('${item.href}')" title="${
|
||||
item.title
|
||||
}" data-pjax-state="">${item.title}</a></div>`;
|
||||
}
|
||||
|
||||
return `很抱歉,无法找到类似的文章,你也可以看看本站最新发布的文章:<br /><div class="ai-recommend">${list}</div>`;
|
||||
}
|
||||
|
||||
let list = "";
|
||||
for (let i = 0; i < thumbnail.length; i++) {
|
||||
const item = thumbnail[i];
|
||||
list += `<div class="ai-recommend-item"><span>推荐${
|
||||
i + 1
|
||||
}:</span><a href="javascript:;" onclick="pjax.loadUrl('${item.href}')" title="${
|
||||
item.title
|
||||
}" data-pjax-state="">${item.title}</a></div>`;
|
||||
}
|
||||
|
||||
return `推荐文章:<br /><div class="ai-recommend">${list}</div>`;
|
||||
}
|
||||
|
||||
function aiGoHome() {
|
||||
startAI("正在前往博客主页...", false);
|
||||
timeouts[2] = setTimeout(() => {
|
||||
if (window.pjax) {
|
||||
pjax.loadUrl("/");
|
||||
} else {
|
||||
location.href = location.origin;
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function introduce() {
|
||||
if (mode == "tianli") {
|
||||
startAI("我是文章辅助AI: TianliGPT,点击下方的按钮,让我生成本文简介、推荐相关文章等。");
|
||||
} else {
|
||||
startAI(`我是文章辅助AI: ${gptName} GPT,点击下方的按钮,让我生成本文简介、推荐相关文章等。`);
|
||||
}
|
||||
}
|
||||
|
||||
function aiTitleRefreshIconClick() {
|
||||
aiTitleRefreshIcon.click();
|
||||
}
|
||||
|
||||
function onAiTagClick() {
|
||||
if (mode === "tianli") {
|
||||
post_ai.querySelectorAll(".ai-btn-item").forEach(item => (item.style.display = "none"));
|
||||
document.getElementById("go-tianli-blog").style.display = "block";
|
||||
startAI(
|
||||
"你好,我是Tianli开发的摘要生成助理TianliGPT,是一个基于GPT-4的生成式AI。我在这里只负责摘要的预生成和显示,你无法与我直接沟通,如果你也需要一个这样的AI摘要接口,可以在下方购买。"
|
||||
);
|
||||
} else {
|
||||
post_ai.querySelectorAll(".ai-btn-item").forEach(item => (item.style.display = "block"));
|
||||
document.getElementById("go-tianli-blog").style.display = "none";
|
||||
startAI(
|
||||
`你好,我是本站摘要生成助理${gptName} GPT,是一个基于GPT-4的生成式AI。我在这里只负责摘要的预生成和显示,你无法与我直接沟通。`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function onAiTitleRefreshIconClick() {
|
||||
const truncateDescription = (title + pageFillDescription).trim().substring(0, basicWordCount);
|
||||
|
||||
aiTitleRefreshIcon.style.opacity = "0.2";
|
||||
aiTitleRefreshIcon.style.transitionDuration = "0.3s";
|
||||
aiTitleRefreshIcon.style.transform = "rotate(" + 360 * refreshNum + "deg)";
|
||||
if (truncateDescription.length <= basicWordCount) {
|
||||
let param = truncateDescription.length - Math.floor(Math.random() * randomNum);
|
||||
while (param === prevParam || truncateDescription.length - param === prevParam) {
|
||||
param = truncateDescription.length - Math.floor(Math.random() * randomNum);
|
||||
}
|
||||
prevParam = param;
|
||||
aiAbstract(param);
|
||||
} else {
|
||||
let value = Math.floor(Math.random() * randomNum) + basicWordCount;
|
||||
while (value === prevParam || truncateDescription.length - value === prevParam) {
|
||||
value = Math.floor(Math.random() * randomNum) + basicWordCount;
|
||||
}
|
||||
aiAbstract(value);
|
||||
}
|
||||
refreshNum++;
|
||||
}
|
||||
|
||||
function changeShowMode() {
|
||||
mode = mode === "tianli" ? "local" : "tianli";
|
||||
if (mode === "tianli") {
|
||||
document.getElementById("ai-tag").innerHTML = "TianliGPT";
|
||||
|
||||
aiReadAloudIcon.style.opacity = "1";
|
||||
aiReadAloudIcon.style.cursor = "pointer";
|
||||
} else {
|
||||
aiReadAloudIcon.style.opacity = "0";
|
||||
aiReadAloudIcon.style.cursor = "auto";
|
||||
if ((document.getElementById("go-tianli-blog").style.display = "block")) {
|
||||
document.querySelectorAll(".ai-btn-item").forEach(item => (item.style.display = "block"));
|
||||
document.getElementById("go-tianli-blog").style.display = "none";
|
||||
}
|
||||
document.getElementById("ai-tag").innerHTML = gptName + " GPT";
|
||||
}
|
||||
aiAbstract();
|
||||
}
|
||||
|
||||
function showAiBtn() {
|
||||
if (mode === "tianli") {
|
||||
document.getElementById("ai-tag").innerHTML = "TianliGPT";
|
||||
} else {
|
||||
document.getElementById("ai-tag").innerHTML = gptName + " GPT";
|
||||
}
|
||||
}
|
||||
})();
|
||||
179
public/js/anzhiyu/comment_barrage.js
Normal file
@@ -0,0 +1,179 @@
|
||||
if (document.querySelector(".comment-barrage")) {
|
||||
var commentBarrageConfig = {
|
||||
maxBarrage: GLOBAL_CONFIG.commentBarrageConfig.maxBarrage,
|
||||
barrageTime: GLOBAL_CONFIG.commentBarrageConfig.barrageTime,
|
||||
twikooUrl: GLOBAL_CONFIG.twikooEnvId,
|
||||
accessToken: GLOBAL_CONFIG.commentBarrageConfig.accessToken,
|
||||
mailMd5: GLOBAL_CONFIG.commentBarrageConfig.mailMd5,
|
||||
pageUrl: window.location.pathname,
|
||||
barrageTimer: [],
|
||||
barrageList: [],
|
||||
barrageIndex: 0,
|
||||
dom: document.querySelector(".comment-barrage"),
|
||||
};
|
||||
var commentInterval = null;
|
||||
var hoverOnCommentBarrage = false;
|
||||
|
||||
document.querySelector(".comment-barrage").addEventListener("mouseenter", function () {
|
||||
hoverOnCommentBarrage = true;
|
||||
});
|
||||
document.querySelector(".comment-barrage").addEventListener("mouseleave", function () {
|
||||
hoverOnCommentBarrage = false;
|
||||
});
|
||||
|
||||
function initCommentBarrage() {
|
||||
if (!commentBarrageConfig.dom) return;
|
||||
|
||||
var data = JSON.stringify({
|
||||
event: "COMMENT_GET",
|
||||
"commentBarrageConfig.accessToken": commentBarrageConfig.accessToken,
|
||||
url: commentBarrageConfig.pageUrl,
|
||||
});
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.withCredentials = true;
|
||||
xhr.addEventListener("readystatechange", function () {
|
||||
if (this.readyState === 4 && this.responseText) {
|
||||
commentBarrageConfig.barrageList = commentLinkFilter(JSON.parse(this.responseText).data);
|
||||
commentBarrageConfig.dom.innerHTML = "";
|
||||
}
|
||||
});
|
||||
xhr.open("POST", commentBarrageConfig.twikooUrl);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.send(data);
|
||||
|
||||
clearInterval(commentInterval);
|
||||
commentInterval = null;
|
||||
|
||||
commentInterval = setInterval(() => {
|
||||
if (commentBarrageConfig.barrageList.length && !hoverOnCommentBarrage) {
|
||||
popCommentBarrage(commentBarrageConfig.barrageList[commentBarrageConfig.barrageIndex]);
|
||||
commentBarrageConfig.barrageIndex += 1;
|
||||
commentBarrageConfig.barrageIndex %= commentBarrageConfig.barrageList.length;
|
||||
}
|
||||
if (
|
||||
commentBarrageConfig.barrageTimer.length >
|
||||
(commentBarrageConfig.barrageList.length > commentBarrageConfig.maxBarrage
|
||||
? commentBarrageConfig.maxBarrage
|
||||
: commentBarrageConfig.barrageList.length) &&
|
||||
!hoverOnCommentBarrage
|
||||
) {
|
||||
removeCommentBarrage(commentBarrageConfig.barrageTimer.shift());
|
||||
}
|
||||
}, commentBarrageConfig.barrageTime);
|
||||
}
|
||||
|
||||
function commentLinkFilter(data) {
|
||||
data.sort((a, b) => {
|
||||
return a.created - b.created;
|
||||
});
|
||||
let newData = [];
|
||||
data.forEach(item => {
|
||||
newData.push(...getCommentReplies(item));
|
||||
});
|
||||
return newData;
|
||||
}
|
||||
|
||||
function getCommentReplies(item) {
|
||||
if (item.replies) {
|
||||
let replies = [item];
|
||||
item.replies.forEach(item => {
|
||||
replies.push(...getCommentReplies(item));
|
||||
});
|
||||
return replies;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function popCommentBarrage(data) {
|
||||
let barrage = document.createElement("div");
|
||||
barrage.className = "comment-barrage-item";
|
||||
barrage.innerHTML = `
|
||||
<div class="barrageHead">
|
||||
<a class="barrageTitle ${
|
||||
data.mailMd5 === commentBarrageConfig.mailMd5 ? "barrageBloggerTitle" : ""
|
||||
}" href="javascript:anzhiyu.scrollTo('#post-comment')"">
|
||||
${data.mailMd5 === commentBarrageConfig.mailMd5 ? "博主" : "热评"}
|
||||
</a>
|
||||
<div class="barrageNick">${data.nick}</div>
|
||||
<img class="nolazyload barrageAvatar" src="https://cravatar.cn/avatar/${data.mailMd5}"/>
|
||||
<a class="comment-barrage-close" href="javascript:anzhiyu.switchCommentBarrage()"><i class="anzhiyufont anzhiyu-icon-xmark"></i></a>
|
||||
</div>
|
||||
<anzhiyu class="barrageContent" onClick="window.location.hash = '${data.id}'">
|
||||
${data.comment}
|
||||
</anzhiyu>
|
||||
`;
|
||||
|
||||
// 获取anzhiyu标签内的所有pre元素
|
||||
let anzhiyuPres = barrage.querySelectorAll("anzhiyu pre");
|
||||
|
||||
// 遍历每个pre元素,将其替换为"【代码】"
|
||||
anzhiyuPres.forEach(pre => {
|
||||
let codePlaceholder = document.createElement("span");
|
||||
codePlaceholder.innerText = "【代码】";
|
||||
pre.parentNode.replaceChild(codePlaceholder, pre);
|
||||
});
|
||||
|
||||
// 获取anzhiyu标签内的所有图片元素
|
||||
let anzhiyuImages = barrage.querySelectorAll("anzhiyu img");
|
||||
|
||||
// 遍历每个图片元素,将其替换为"【图片】",但排除带有class=tk-owo-emotion的图片
|
||||
anzhiyuImages.forEach(image => {
|
||||
if (!image.classList.contains("tk-owo-emotion")) {
|
||||
image.style.display = "none"; // 隐藏图片
|
||||
let placeholder = document.createElement("span");
|
||||
placeholder.innerText = "【图片】";
|
||||
image.parentNode.replaceChild(placeholder, image);
|
||||
}
|
||||
});
|
||||
commentBarrageConfig.barrageTimer.push(barrage);
|
||||
commentBarrageConfig.dom.append(barrage);
|
||||
}
|
||||
|
||||
function removeCommentBarrage(barrage) {
|
||||
barrage.className = "comment-barrage-item out";
|
||||
|
||||
setTimeout(() => {
|
||||
if (commentBarrageConfig.dom && commentBarrageConfig.dom.contains(barrage)) {
|
||||
commentBarrageConfig.dom.removeChild(barrage);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// 自动隐藏
|
||||
const commentEntryCallback = entries => {
|
||||
const commentBarrage = document.querySelector(".comment-barrage");
|
||||
const postComment = document.getElementById("post-comment");
|
||||
|
||||
entries.forEach(entry => {
|
||||
if (postComment && commentBarrage && document.body.clientWidth > 768) {
|
||||
commentBarrage.style.bottom = entry.isIntersecting ? `-${commentBarrageConfig.maxBarrage * 200}px` : "0";
|
||||
}
|
||||
});
|
||||
};
|
||||
// 创建IntersectionObserver实例
|
||||
const observer = new IntersectionObserver(commentEntryCallback, {
|
||||
root: null,
|
||||
rootMargin: "0px",
|
||||
threshold: 0,
|
||||
});
|
||||
// 监视目标元素
|
||||
const postCommentTarget = document.getElementById("post-comment");
|
||||
if (postCommentTarget) {
|
||||
observer.observe(postCommentTarget);
|
||||
}
|
||||
|
||||
initCommentBarrage();
|
||||
|
||||
if (localStorage.getItem("commentBarrageSwitch") !== "false") {
|
||||
document.querySelector(".comment-barrage").style.display = "flex";
|
||||
document.querySelector(".menu-commentBarrage-text").textContent = "关闭热评";
|
||||
} else {
|
||||
document.querySelector(".comment-barrage").style.display = "none";
|
||||
document.querySelector(".menu-commentBarrage-text").textContent = "显示热评";
|
||||
}
|
||||
|
||||
document.addEventListener("pjax:send", function () {
|
||||
clearInterval(commentInterval);
|
||||
});
|
||||
}
|
||||
271
public/js/anzhiyu/people.js
Normal file
@@ -0,0 +1,271 @@
|
||||
"use strict";
|
||||
function _toConsumableArray(e) {
|
||||
return _arrayWithoutHoles(e) || _iterableToArray(e) || _unsupportedIterableToArray(e) || _nonIterableSpread();
|
||||
}
|
||||
|
||||
function _nonIterableSpread() {
|
||||
throw new TypeError(
|
||||
"Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
|
||||
);
|
||||
}
|
||||
|
||||
function _unsupportedIterableToArray(e, r) {
|
||||
if (e) {
|
||||
if ("string" == typeof e) return _arrayLikeToArray(e, r);
|
||||
var t = Object.prototype.toString.call(e).slice(8, -1);
|
||||
return (
|
||||
"Object" === t && e.constructor && (t = e.constructor.name),
|
||||
"Map" === t || "Set" === t
|
||||
? Array.from(e)
|
||||
: "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)
|
||||
? _arrayLikeToArray(e, r)
|
||||
: void 0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function _iterableToArray(e) {
|
||||
if (("undefined" != typeof Symbol && null != e[Symbol.iterator]) || null != e["@@iterator"]) return Array.from(e);
|
||||
}
|
||||
|
||||
function _arrayWithoutHoles(e) {
|
||||
if (Array.isArray(e)) return _arrayLikeToArray(e);
|
||||
}
|
||||
|
||||
function _arrayLikeToArray(e, r) {
|
||||
(null == r || r > e.length) && (r = e.length);
|
||||
for (var t = 0, a = new Array(r); t < r; t++) a[t] = e[t];
|
||||
return a;
|
||||
}
|
||||
|
||||
function _classCallCheck(e, r) {
|
||||
if (!(e instanceof r)) throw new TypeError("Cannot call a class as a function");
|
||||
}
|
||||
|
||||
function _defineProperties(e, r) {
|
||||
for (var t = 0; t < r.length; t++) {
|
||||
var a = r[t];
|
||||
(a.enumerable = a.enumerable || !1),
|
||||
(a.configurable = !0),
|
||||
"value" in a && (a.writable = !0),
|
||||
Object.defineProperty(e, a.key, a);
|
||||
}
|
||||
}
|
||||
|
||||
function _createClass(e, r, t) {
|
||||
return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), e;
|
||||
}
|
||||
var peopleConfig = {
|
||||
src: GLOBAL_CONFIG.peoplecanvas.img,
|
||||
rows: 15,
|
||||
cols: 7,
|
||||
},
|
||||
randomRange = function (e, r) {
|
||||
return e + Math.random() * (r - e);
|
||||
},
|
||||
randomIndex = function (e) {
|
||||
return 0 | randomRange(0, e.length);
|
||||
},
|
||||
removeFromArray = function (e, r) {
|
||||
return e.splice(r, 1)[0];
|
||||
},
|
||||
removeItemFromArray = function (e, r) {
|
||||
return removeFromArray(e, e.indexOf(r));
|
||||
},
|
||||
removeRandomFromArray = function (e) {
|
||||
return removeFromArray(e, randomIndex(e));
|
||||
},
|
||||
getRandomFromArray = function (e) {
|
||||
return e[0 | randomIndex(e)];
|
||||
},
|
||||
resetPeep = function (e) {
|
||||
var r,
|
||||
t,
|
||||
a = e.stage,
|
||||
n = e.peep,
|
||||
o = 0.5 < Math.random() ? 1 : -1,
|
||||
i = 100 - 250 * gsap.parseEase("power2.in")(Math.random()),
|
||||
s = a.height - n.height + i;
|
||||
return (
|
||||
1 == o ? ((r = -n.width), (t = a.width), (n.scaleX = 1)) : ((r = a.width + n.width), (t = 0), (n.scaleX = -1)),
|
||||
(n.x = r),
|
||||
(n.y = s),
|
||||
{
|
||||
startX: r,
|
||||
startY: (n.anchorY = s),
|
||||
endX: t,
|
||||
}
|
||||
);
|
||||
},
|
||||
normalWalk = function (e) {
|
||||
var r = e.peep,
|
||||
t = e.props,
|
||||
a = (t.startX, t.startY),
|
||||
n = t.endX,
|
||||
o = gsap.timeline();
|
||||
return (
|
||||
o.timeScale(randomRange(0.5, 1.5)),
|
||||
o.to(
|
||||
r,
|
||||
{
|
||||
duration: 10,
|
||||
x: n,
|
||||
ease: "none",
|
||||
},
|
||||
0
|
||||
),
|
||||
o.to(
|
||||
r,
|
||||
{
|
||||
duration: 0.25,
|
||||
repeat: 40,
|
||||
yoyo: !0,
|
||||
y: a - 10,
|
||||
},
|
||||
0
|
||||
),
|
||||
o
|
||||
);
|
||||
},
|
||||
walks = [normalWalk],
|
||||
Peep = (function () {
|
||||
function a(e) {
|
||||
var r = e.image,
|
||||
t = e.rect;
|
||||
_classCallCheck(this, a),
|
||||
(this.image = r),
|
||||
this.setRect(t),
|
||||
(this.x = 0),
|
||||
(this.y = 0),
|
||||
(this.anchorY = 0),
|
||||
(this.scaleX = 1),
|
||||
(this.walk = null);
|
||||
}
|
||||
return (
|
||||
_createClass(a, [
|
||||
{
|
||||
key: "setRect",
|
||||
value: function (e) {
|
||||
(this.rect = e),
|
||||
(this.width = e[2]),
|
||||
(this.height = e[3]),
|
||||
(this.drawArgs = [this.image].concat(_toConsumableArray(e), [0, 0, this.width, this.height]));
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "render",
|
||||
value: function (e) {
|
||||
e.save(),
|
||||
e.translate(this.x, this.y),
|
||||
e.scale(this.scaleX, 1),
|
||||
e.drawImage.apply(e, _toConsumableArray(this.drawArgs)),
|
||||
e.restore();
|
||||
},
|
||||
},
|
||||
]),
|
||||
a
|
||||
);
|
||||
})(),
|
||||
img = document.createElement("img");
|
||||
(img.onload = init), (img.src = peopleConfig.src);
|
||||
let peoplecanvasEl = document.getElementById("peoplecanvas");
|
||||
|
||||
let ctx = peoplecanvasEl ? peoplecanvasEl.getContext("2d") : undefined,
|
||||
stage = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
allPeeps = [],
|
||||
availablePeeps = [],
|
||||
crowd = [];
|
||||
|
||||
function init() {
|
||||
if (!peoplecanvasEl) return;
|
||||
createPeeps(), resize(), gsap.ticker.add(render), window.addEventListener("resize", resize);
|
||||
}
|
||||
document.addEventListener("pjax:success", e => {
|
||||
peoplecanvasEl = document.getElementById("peoplecanvas");
|
||||
if (peoplecanvasEl) {
|
||||
(ctx = peoplecanvasEl ? peoplecanvasEl.getContext("2d") : undefined), window.removeEventListener("resize", resize);
|
||||
gsap.ticker.remove(render);
|
||||
setTimeout(() => {
|
||||
if (!peoplecanvasEl) return;
|
||||
resize(), gsap.ticker.add(render), window.addEventListener("resize", resize);
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
|
||||
function createPeeps() {
|
||||
for (
|
||||
var e = peopleConfig.rows,
|
||||
r = peopleConfig.cols,
|
||||
t = e * r,
|
||||
a = img.naturalWidth / e,
|
||||
n = img.naturalHeight / r,
|
||||
o = 0;
|
||||
o < t;
|
||||
o++
|
||||
)
|
||||
allPeeps.push(
|
||||
new Peep({
|
||||
image: img,
|
||||
rect: [(o % e) * a, ((o / e) | 0) * n, a, n],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function resize() {
|
||||
if (peoplecanvasEl && peoplecanvasEl.clientWidth != 0) {
|
||||
(stage.width = peoplecanvasEl.clientWidth),
|
||||
(stage.height = peoplecanvasEl.clientHeight),
|
||||
(peoplecanvasEl.width = stage.width * devicePixelRatio),
|
||||
(peoplecanvasEl.height = stage.height * devicePixelRatio),
|
||||
crowd.forEach(function (e) {
|
||||
e.walk.kill();
|
||||
}),
|
||||
(crowd.length = 0),
|
||||
(availablePeeps.length = 0),
|
||||
availablePeeps.push.apply(availablePeeps, allPeeps),
|
||||
initCrowd();
|
||||
}
|
||||
}
|
||||
|
||||
function initCrowd() {
|
||||
for (; availablePeeps.length; ) addPeepToCrowd().walk.progress(Math.random());
|
||||
}
|
||||
|
||||
function addPeepToCrowd() {
|
||||
var e = removeRandomFromArray(availablePeeps),
|
||||
r = getRandomFromArray(walks)({
|
||||
peep: e,
|
||||
props: resetPeep({
|
||||
peep: e,
|
||||
stage: stage,
|
||||
}),
|
||||
}).eventCallback("onComplete", function () {
|
||||
removePeepFromCrowd(e), addPeepToCrowd();
|
||||
});
|
||||
return (
|
||||
(e.walk = r),
|
||||
crowd.push(e),
|
||||
crowd.sort(function (e, r) {
|
||||
return e.anchorY - r.anchorY;
|
||||
}),
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
function removePeepFromCrowd(e) {
|
||||
removeItemFromArray(crowd, e), availablePeeps.push(e);
|
||||
}
|
||||
|
||||
function render() {
|
||||
if (!peoplecanvasEl) return;
|
||||
(peoplecanvasEl.width = peoplecanvasEl.width),
|
||||
ctx.save(),
|
||||
ctx.scale(devicePixelRatio, devicePixelRatio),
|
||||
crowd.forEach(function (e) {
|
||||
e.render(ctx);
|
||||
}),
|
||||
ctx.restore();
|
||||
}
|
||||
215
public/js/anzhiyu/random_friends_post.js
Normal file
@@ -0,0 +1,215 @@
|
||||
var fdata = {
|
||||
apiurl: GLOBAL_CONFIG.friends_vue_info.apiurl,
|
||||
defaultFish: 100,
|
||||
hungryFish: 100,
|
||||
};
|
||||
//可通过 var fdataUser 替换默认值
|
||||
if (typeof fdataUser !== "undefined") {
|
||||
for (var key in fdataUser) {
|
||||
if (fdataUser[key]) {
|
||||
fdata[key] = fdataUser[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
var randomPostTimes = 0;
|
||||
var randomPostWorking = false;
|
||||
var randomPostTips = [
|
||||
"钓到了绝世好文!",
|
||||
"在河边打了个喷嚏,吓跑了",
|
||||
"你和小伙伴抢夺着",
|
||||
"你击败了巨龙,在巢穴中发现了",
|
||||
"挖掘秦始皇坟时找到了",
|
||||
"在路边闲逛的时候随手买了一个",
|
||||
"从学校班主任那拿来了孩子上课偷偷看的",
|
||||
"你的同桌无情的从你的语文书中撕下了那篇你最喜欢的",
|
||||
"考古学家近日发现了",
|
||||
"外星人降临地球学习地球文化,落地时被你塞了",
|
||||
"从图书馆顶层的隐秘角落里发现了闪着金光的",
|
||||
"徒弟修炼走火入魔,为师立刻掏出了",
|
||||
"在大山中唱山歌,隔壁的阿妹跑来了,带着",
|
||||
"隔壁家的孩子数学考了满分,都是因为看了",
|
||||
"隔壁家的孩子英语考了满分,都是因为看了",
|
||||
"小米研发了全新一代MIX手机,据说灵感",
|
||||
"修炼渡劫成功,还好提前看了",
|
||||
"库克坐上了苹果CEO的宝座,因为他面试的时候看了",
|
||||
"阿里巴巴大喊芝麻开门,映入眼帘的就是",
|
||||
"师傅说练武要先炼心,然后让我好生研读",
|
||||
"科考队在南极大陆发现了被冰封的",
|
||||
"飞机窗户似乎被一张纸糊上了,仔细一看是",
|
||||
"历史上满写的仁义道德四个字,透过字缝里却全是",
|
||||
"十几年前的录音机似乎还能够使用,插上电发现正在播的是",
|
||||
"新版语文书拟增加一篇熟读并背诵的",
|
||||
"经调查,99%的受访者都没有背诵过",
|
||||
"今年的高考满分作文是",
|
||||
"唐僧揭开了佛祖压在五指山上的",
|
||||
"科学家发现能够解决衰老的秘密,就是每日研读",
|
||||
"英特尔发布了全新的至强处理器,其芯片的制造原理都是",
|
||||
"新的iPhone产能很足,新的进货渠道是",
|
||||
"今年亩产突破了八千万斤,多亏了",
|
||||
"陆隐一统天上宗,在无数祖境高手的目光下宣读了",
|
||||
"黑钻风跟白钻风说道,吃了唐僧肉能长生不老,他知道是因为看了",
|
||||
"上卫生间没带纸,直接提裤跑路也不愿意玷污手中",
|
||||
"种下一篇文章就会产生很多很多文章,我种下了",
|
||||
"三十年河东,三十年河西,莫欺我没有看过",
|
||||
"踏破铁血无觅处,得来全靠",
|
||||
"今日双色球中了两千万,预测全靠",
|
||||
"因为卷子上没写名字,老师罚抄",
|
||||
"为了抗议世间的不公,割破手指写下了",
|
||||
"在艺术大街上被贴满了相同的纸,走近一看是",
|
||||
"这区区迷阵岂能难得住我?其实能走出来多亏了",
|
||||
"今日被一篇文章顶上了微博热搜,它是",
|
||||
"你送给乞丐一个暴富秘籍,它是",
|
||||
"UZI一个走A拿下五杀,在事后采访时说他当时回想起了",
|
||||
"科学家解刨了第一个感染丧尸病毒的人,发现丧尸抗体存在于",
|
||||
"如果你有梦想的话,就要努力去看",
|
||||
"决定我们成为什么样人的,不是我们的能力,而是是否看过",
|
||||
"有信心不一定会成功,没信心就去看",
|
||||
"你真正是谁并不重要,重要的是你看没看过",
|
||||
"玄天境重要的是锻体,为师赠你此书,好好修炼去吧,这是",
|
||||
"上百祖境高手在天威湖大战三天三夜为了抢夺",
|
||||
"这化仙池水乃上古真仙对后人的考校,要求熟读并背诵",
|
||||
"庆氏三千年根基差点竟被你小子毁于一旦,能够被我拯救全是因为我看了",
|
||||
"我就是神奇宝贝大师!我这只皮卡丘可是",
|
||||
"我就是神奇宝贝大师!我这只小火龙可是",
|
||||
"我就是神奇宝贝大师!我这只可达鸭可是",
|
||||
"我就是神奇宝贝大师!我这只杰尼龟可是",
|
||||
"上古遗迹中写道,只要习得此书,便得成功。你定睛一看,原来是",
|
||||
"奶奶的,玩阴的是吧,我就是双料特工代号穿山甲,",
|
||||
"你的背景太假了,我的就逼真多了,学到这个技术全是因为看了",
|
||||
"我是云南的,云南怒江的,怒江芦水市,芦水市六库,六库傈僳族,傈僳族是",
|
||||
"我真的栓Q了,我真的会谢如果你看",
|
||||
"你已经习得退退退神功,接下来的心法已经被记录在",
|
||||
"人生无常大肠包小肠,小肠包住了",
|
||||
"你抽到了普通文章,它是",
|
||||
"你收到了稀有文章,它是",
|
||||
"你抽到了金色普通文章,它是",
|
||||
"你抽到了金色稀有文章,它是",
|
||||
"你抽到了传说文章!它是",
|
||||
"哇!金色传说!你抽到了金色传说文章,它是",
|
||||
"报告!侦察兵说在前往300米有一个男子在偷偷看一本书,上面赫然写着",
|
||||
"芷莲姑娘大摆擂台,谁若是能读完此书,便可娶了她。然后从背后掏出了",
|
||||
"请问你的梦想是什么?我的梦想是能读到",
|
||||
"读什么才能增智慧?当然是读",
|
||||
"纳兰嫣然掏出了退婚书,可是发现出门带错了,结果拿出了一本",
|
||||
"你要尽全力保护你的梦想。那些嘲笑你的人,他们必定会失败,他们想把你变成和他们一样的人。如果你有梦想的话,就要努力去读",
|
||||
"走人生的路就像爬山一样,看起来走了许多冤枉的路,崎岖的路,但终究需要读完",
|
||||
"游戏的规则就是这么的简单,你听懂了吗?管你听没听懂,快去看",
|
||||
];
|
||||
var randomPostClick = 0;
|
||||
function fetchRandomPost() {
|
||||
if (!document.getElementById("random-post")) return;
|
||||
if (randomPostWorking == false) {
|
||||
randomPostWorking = true;
|
||||
//获取旋转角度
|
||||
let randomRotate = randomPostTimes * 360;
|
||||
let randomPostTipsItem = randomPostTips[Math.floor(Math.random() * randomPostTips.length)];
|
||||
let randomPostLevel = "";
|
||||
if (randomPostTimes > 10000) {
|
||||
randomPostLevel = "愿者上钩";
|
||||
} else if (randomPostTimes > 1000) {
|
||||
randomPostLevel = "俯览天下";
|
||||
} else if (randomPostTimes > 1000) {
|
||||
randomPostLevel = "超越神了";
|
||||
} else if (randomPostTimes > 100) {
|
||||
randomPostLevel = "绝世渔夫";
|
||||
} else if (randomPostTimes > 75) {
|
||||
randomPostLevel = "钓鱼王者";
|
||||
} else if (randomPostTimes > 50) {
|
||||
randomPostLevel = "钓鱼宗师";
|
||||
} else if (randomPostTimes > 20) {
|
||||
randomPostLevel = "钓鱼专家";
|
||||
} else if (randomPostTimes > 5) {
|
||||
randomPostLevel = "钓鱼高手";
|
||||
} else {
|
||||
randomPostLevel = "钓鱼新手";
|
||||
}
|
||||
if (randomPostTimes >= 5) {
|
||||
document.getElementById("random-post").innerHTML =
|
||||
`钓鱼中... (Lv.` + randomPostTimes + ` 当前称号:` + randomPostLevel + `)`;
|
||||
} else {
|
||||
document.getElementById("random-post").innerHTML = `钓鱼中...`;
|
||||
}
|
||||
|
||||
let randomTime = randomNum(1000, 3000);
|
||||
|
||||
if (randomPostTimes == 0) {
|
||||
randomTime = 0;
|
||||
}
|
||||
|
||||
document.querySelector(".random-post-start").style.opacity = "0.2";
|
||||
document.querySelector(".random-post-start").style.transitionDuration = "0.3s";
|
||||
document.querySelector(".random-post-start").style.transform = "rotate(" + randomRotate + "deg)";
|
||||
|
||||
//判断是否饥饿
|
||||
if (
|
||||
document.getElementById("random-post") &&
|
||||
randomPostClick * fdata.hungryFish + fdata.defaultFish < randomPostTimes &&
|
||||
Math.round(Math.random()) == 0
|
||||
) {
|
||||
document.getElementById("random-post").innerHTML =
|
||||
"因为只钓鱼不吃鱼,过分饥饿导致本次钓鱼失败...(点击任意一篇钓鱼获得的文章即可恢复)";
|
||||
randomPostWorking = false;
|
||||
} else {
|
||||
var fetchUrl = fdata.apiurl + "randompost";
|
||||
fetch(fetchUrl)
|
||||
.then(res => res.json())
|
||||
.then(json => {
|
||||
var title = json.title;
|
||||
var link = json.link;
|
||||
var author = json.author;
|
||||
if (document.getElementById("random-post")) {
|
||||
window.setTimeout(function () {
|
||||
document.getElementById("random-post").innerHTML =
|
||||
randomPostTipsItem +
|
||||
`来自友链 <b>` +
|
||||
author +
|
||||
`</b> 的文章:<a class="random-friends-post" onclick="randomClickLink()" target="_blank" href="` +
|
||||
link +
|
||||
`" rel="external nofollow">` +
|
||||
title +
|
||||
`</a>`;
|
||||
randomPostTimes += 1;
|
||||
localStorage.setItem("randomPostTimes", randomPostTimes);
|
||||
document.querySelector(".random-post-start").style.opacity = "1";
|
||||
}, randomTime);
|
||||
}
|
||||
});
|
||||
randomPostWorking = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//初始化检查
|
||||
function initRandomPost() {
|
||||
// 获取已经存储的数据
|
||||
if (localStorage.randomPostTimes) {
|
||||
randomPostTimes = parseInt(localStorage.randomPostTimes);
|
||||
randomPostClick = parseInt(localStorage.randomPostClick);
|
||||
document.querySelector(".random-post-start").style.transitionDuration = "0.3s";
|
||||
document.querySelector(".random-post-start").style.transform = "rotate(" + 360 * randomPostTimes + "deg)";
|
||||
}
|
||||
fetchRandomPost();
|
||||
}
|
||||
|
||||
initRandomPost();
|
||||
|
||||
//添加点击统计
|
||||
function randomClickLink() {
|
||||
randomPostClick += 1;
|
||||
localStorage.setItem("randomPostClick", randomPostClick);
|
||||
}
|
||||
|
||||
// 生成随机数
|
||||
function randomNum(minNum, maxNum) {
|
||||
switch (arguments.length) {
|
||||
case 1:
|
||||
return parseInt(Math.random() * minNum + 1, 10);
|
||||
break;
|
||||
case 2:
|
||||
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
479
public/js/anzhiyu/right_click_menu.js
Normal file
@@ -0,0 +1,479 @@
|
||||
// 初始化函数
|
||||
rm = {};
|
||||
|
||||
//禁止图片与超链接拖拽
|
||||
let aElements = document.getElementsByTagName("a");
|
||||
for (let i = 0; i < aElements.length; i++) {
|
||||
aElements[i].setAttribute("draggable", "false");
|
||||
let imgElements = aElements[i].getElementsByTagName("img");
|
||||
for (let j = 0; j < imgElements.length; j++) {
|
||||
imgElements[j].setAttribute("draggable", "false");
|
||||
}
|
||||
}
|
||||
|
||||
// 显示菜单
|
||||
rm.showRightMenu = function (isTrue, x = 0, y = 0) {
|
||||
console.info(x, y);
|
||||
let rightMenu = document.getElementById("rightMenu");
|
||||
rightMenu.style.top = x + "px";
|
||||
rightMenu.style.left = y + "px";
|
||||
if (isTrue) {
|
||||
rightMenu.style.display = "block";
|
||||
stopMaskScroll();
|
||||
} else {
|
||||
rightMenu.style.display = "none";
|
||||
}
|
||||
};
|
||||
|
||||
// 隐藏菜单
|
||||
rm.hideRightMenu = function () {
|
||||
rm.showRightMenu(false);
|
||||
let rightMenuMask = document.querySelector("#rightmenu-mask");
|
||||
rightMenuMask.style.display = "none";
|
||||
};
|
||||
|
||||
// 尺寸
|
||||
let rmWidth = document.getElementById("rightMenu").offsetWidth;
|
||||
let rmHeight = document.getElementById("rightMenu").offsetHeight;
|
||||
|
||||
// 重新定义尺寸
|
||||
rm.reloadrmSize = function () {
|
||||
rightMenu.style.visibility = "hidden";
|
||||
rightMenu.style.display = "block";
|
||||
// 获取宽度和高度
|
||||
rmWidth = document.getElementById("rightMenu").offsetWidth;
|
||||
rmHeight = document.getElementById("rightMenu").offsetHeight;
|
||||
rightMenu.style.visibility = "visible";
|
||||
};
|
||||
|
||||
// 获取点击的href
|
||||
let domhref = "";
|
||||
let domImgSrc = "";
|
||||
let globalEvent = null;
|
||||
|
||||
var oncontextmenuFunction = function (event) {
|
||||
if (document.body.clientWidth > 768) {
|
||||
let pageX = event.clientX + 10; //加10是为了防止显示时鼠标遮在菜单上
|
||||
let pageY = event.clientY;
|
||||
|
||||
//其他额外菜单
|
||||
const $rightMenuOther = document.querySelector(".rightMenuOther");
|
||||
const $rightMenuPlugin = document.querySelector(".rightMenuPlugin");
|
||||
const $rightMenuCopyText = document.querySelector("#menu-copytext");
|
||||
const $rightMenuPasteText = document.querySelector("#menu-pastetext");
|
||||
const $rightMenuCommentText = document.querySelector("#menu-commenttext");
|
||||
const $rightMenuNewWindow = document.querySelector("#menu-newwindow");
|
||||
const $rightMenuNewWindowImg = document.querySelector("#menu-newwindowimg");
|
||||
const $rightMenuCopyLink = document.querySelector("#menu-copylink");
|
||||
const $rightMenuCopyImg = document.querySelector("#menu-copyimg");
|
||||
const $rightMenuDownloadImg = document.querySelector("#menu-downloadimg");
|
||||
const $rightMenuSearch = document.querySelector("#menu-search");
|
||||
const $rightMenuSearchBaidu = document.querySelector("#menu-searchBaidu");
|
||||
const $rightMenuMusicToggle = document.querySelector("#menu-music-toggle");
|
||||
const $rightMenuMusicBack = document.querySelector("#menu-music-back");
|
||||
const $rightMenuMusicForward = document.querySelector("#menu-music-forward");
|
||||
const $rightMenuMusicPlaylist = document.querySelector("#menu-music-playlist");
|
||||
const $rightMenuMusicCopyMusicName = document.querySelector("#menu-music-copyMusicName");
|
||||
|
||||
let href = event.target.href;
|
||||
let imgsrc = event.target.currentSrc;
|
||||
|
||||
// 判断模式 扩展模式为有事件
|
||||
let pluginMode = false;
|
||||
$rightMenuOther.style.display = "block";
|
||||
globalEvent = event;
|
||||
|
||||
// 检查是否需要复制 是否有选中文本
|
||||
if (selectTextNow && window.getSelection()) {
|
||||
pluginMode = true;
|
||||
$rightMenuCopyText.style.display = "block";
|
||||
$rightMenuCommentText.style.display = "block";
|
||||
$rightMenuSearch.style.display = "block";
|
||||
$rightMenuSearchBaidu.style.display = "block";
|
||||
} else {
|
||||
$rightMenuCopyText.style.display = "none";
|
||||
$rightMenuCommentText.style.display = "none";
|
||||
$rightMenuSearchBaidu.style.display = "none";
|
||||
$rightMenuSearch.style.display = "none";
|
||||
}
|
||||
|
||||
//检查是否右键点击了链接a标签
|
||||
if (href) {
|
||||
pluginMode = true;
|
||||
$rightMenuNewWindow.style.display = "block";
|
||||
$rightMenuCopyLink.style.display = "block";
|
||||
domhref = href;
|
||||
} else {
|
||||
$rightMenuNewWindow.style.display = "none";
|
||||
$rightMenuCopyLink.style.display = "none";
|
||||
}
|
||||
|
||||
//检查是否需要复制图片
|
||||
if (imgsrc) {
|
||||
pluginMode = true;
|
||||
$rightMenuCopyImg.style.display = "block";
|
||||
$rightMenuDownloadImg.style.display = "block";
|
||||
$rightMenuNewWindowImg.style.display = "block";
|
||||
document.getElementById("rightMenu").style.width = "12rem";
|
||||
domImgSrc = imgsrc;
|
||||
} else {
|
||||
$rightMenuCopyImg.style.display = "none";
|
||||
$rightMenuDownloadImg.style.display = "none";
|
||||
$rightMenuNewWindowImg.style.display = "none";
|
||||
}
|
||||
|
||||
// 判断是否为输入框
|
||||
if (event.target.tagName.toLowerCase() === "input" || event.target.tagName.toLowerCase() === "textarea") {
|
||||
pluginMode = true;
|
||||
$rightMenuPasteText.style.display = "block";
|
||||
} else {
|
||||
$rightMenuPasteText.style.display = "none";
|
||||
}
|
||||
const navMusicEl = document.querySelector("#nav-music");
|
||||
//判断是否是音乐
|
||||
if (navMusicEl && navMusicEl.contains(event.target)) {
|
||||
pluginMode = true;
|
||||
$rightMenuMusicToggle.style.display = "block";
|
||||
$rightMenuMusicBack.style.display = "block";
|
||||
$rightMenuMusicForward.style.display = "block";
|
||||
$rightMenuMusicPlaylist.style.display = "block";
|
||||
$rightMenuMusicCopyMusicName.style.display = "block";
|
||||
} else {
|
||||
$rightMenuMusicToggle.style.display = "none";
|
||||
$rightMenuMusicBack.style.display = "none";
|
||||
$rightMenuMusicForward.style.display = "none";
|
||||
$rightMenuMusicPlaylist.style.display = "none";
|
||||
$rightMenuMusicCopyMusicName.style.display = "none";
|
||||
}
|
||||
|
||||
// 如果不是扩展模式则隐藏扩展模块
|
||||
if (pluginMode) {
|
||||
$rightMenuOther.style.display = "none";
|
||||
$rightMenuPlugin.style.display = "block";
|
||||
} else {
|
||||
$rightMenuPlugin.style.display = "none";
|
||||
}
|
||||
|
||||
rm.reloadrmSize();
|
||||
|
||||
// 鼠标默认显示在鼠标右下方,当鼠标靠右或靠下时,将菜单显示在鼠标左方\上方
|
||||
if (pageX + rmWidth > window.innerWidth) {
|
||||
pageX -= rmWidth + 10;
|
||||
}
|
||||
if (pageY + rmHeight > window.innerHeight) {
|
||||
pageY -= pageY + rmHeight - window.innerHeight;
|
||||
}
|
||||
|
||||
rm.showRightMenu(true, pageY, pageX);
|
||||
document.getElementById("rightmenu-mask").style.display = "flex";
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 监听右键初始化
|
||||
window.oncontextmenu = oncontextmenuFunction;
|
||||
|
||||
// 下载图片状态
|
||||
rm.downloadimging = false;
|
||||
|
||||
// 复制图片到剪贴板
|
||||
rm.writeClipImg = function (imgsrc) {
|
||||
console.log("按下复制");
|
||||
rm.hideRightMenu();
|
||||
anzhiyu.snackbarShow("正在下载中,请稍后", false, 10000);
|
||||
if (rm.downloadimging == false) {
|
||||
rm.downloadimging = true;
|
||||
setTimeout(function () {
|
||||
copyImage(imgsrc);
|
||||
anzhiyu.snackbarShow("复制成功!图片已添加盲水印,请遵守版权协议");
|
||||
rm.downloadimging = false;
|
||||
}, "10000");
|
||||
}
|
||||
};
|
||||
|
||||
function imageToBlob(imageURL) {
|
||||
const img = new Image();
|
||||
const c = document.createElement("canvas");
|
||||
const ctx = c.getContext("2d");
|
||||
img.crossOrigin = "";
|
||||
img.src = imageURL;
|
||||
return new Promise(resolve => {
|
||||
img.onload = function () {
|
||||
c.width = this.naturalWidth;
|
||||
c.height = this.naturalHeight;
|
||||
ctx.drawImage(this, 0, 0);
|
||||
c.toBlob(
|
||||
blob => {
|
||||
// here the image is a blob
|
||||
resolve(blob);
|
||||
},
|
||||
"image/png",
|
||||
0.75
|
||||
);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function copyImage(imageURL) {
|
||||
const blob = await imageToBlob(imageURL);
|
||||
const item = new ClipboardItem({ "image/png": blob });
|
||||
navigator.clipboard.write([item]);
|
||||
}
|
||||
|
||||
rm.copyUrl = function (id) {
|
||||
const input = document.createElement("input"); // Create a new <input> element
|
||||
input.id = "copyVal"; // Set the id of the new element to "copyVal"
|
||||
document.body.appendChild(input); // Append the new element to the end of the <body> element
|
||||
|
||||
const text = id;
|
||||
input.value = text;
|
||||
input.select();
|
||||
input.setSelectionRange(0, input.value.length);
|
||||
document.execCommand("copy");
|
||||
|
||||
input.remove(); // Remove the <input> element from the DOM
|
||||
};
|
||||
|
||||
function stopMaskScroll() {
|
||||
if (document.getElementById("rightmenu-mask")) {
|
||||
let xscroll = document.getElementById("rightmenu-mask");
|
||||
xscroll.addEventListener(
|
||||
"mousewheel",
|
||||
function (e) {
|
||||
//阻止浏览器默认方法
|
||||
rm.hideRightMenu();
|
||||
// e.preventDefault();
|
||||
},
|
||||
{ passive: true }
|
||||
);
|
||||
}
|
||||
if (document.getElementById("rightMenu")) {
|
||||
let xscroll = document.getElementById("rightMenu");
|
||||
xscroll.addEventListener(
|
||||
"mousewheel",
|
||||
function (e) {
|
||||
//阻止浏览器默认方法
|
||||
rm.hideRightMenu();
|
||||
// e.preventDefault();
|
||||
},
|
||||
{ passive: true }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
rm.rightmenuCopyText = function (txt) {
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(txt);
|
||||
}
|
||||
rm.hideRightMenu();
|
||||
};
|
||||
|
||||
rm.copyPageUrl = function (url) {
|
||||
if (!url) {
|
||||
url = window.location.href;
|
||||
}
|
||||
rm.copyUrl(url);
|
||||
anzhiyu.snackbarShow("复制链接地址成功", false, 2000);
|
||||
rm.hideRightMenu();
|
||||
};
|
||||
|
||||
// 复制当前选中文本
|
||||
var selectTextNow = "";
|
||||
document.onmouseup = document.ondblclick = selceText;
|
||||
|
||||
function selceText() {
|
||||
var txt;
|
||||
if (document.selection) {
|
||||
txt = document.selection.createRange().text;
|
||||
} else {
|
||||
txt = window.getSelection().toString();
|
||||
}
|
||||
selectTextNow = txt !== "" ? txt : "";
|
||||
}
|
||||
|
||||
// 读取剪切板
|
||||
rm.readClipboard = function () {
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.readText().then(clipText => rm.insertAtCaret(globalEvent.target, clipText));
|
||||
}
|
||||
};
|
||||
|
||||
// 粘贴文本到焦点
|
||||
rm.insertAtCaret = function (elemt, value) {
|
||||
const startPos = elemt.selectionStart,
|
||||
endPos = elemt.selectionEnd;
|
||||
if (document.selection) {
|
||||
elemt.focus();
|
||||
var sel = document.selection.createRange();
|
||||
sel.text = value;
|
||||
elemt.focus();
|
||||
} else {
|
||||
if (startPos || startPos == "0") {
|
||||
var scrollTop = elemt.scrollTop;
|
||||
elemt.value = elemt.value.substring(0, startPos) + value + elemt.value.substring(endPos, elemt.value.length);
|
||||
elemt.focus();
|
||||
elemt.selectionStart = startPos + value.length;
|
||||
elemt.selectionEnd = startPos + value.length;
|
||||
elemt.scrollTop = scrollTop;
|
||||
} else {
|
||||
elemt.value += value;
|
||||
elemt.focus();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//粘贴文本
|
||||
rm.pasteText = function () {
|
||||
const result = rm.readClipboard() || "";
|
||||
rm.hideRightMenu();
|
||||
};
|
||||
|
||||
//引用到评论
|
||||
rm.rightMenuCommentText = function (txt) {
|
||||
rm.hideRightMenu();
|
||||
const postCommentDom = document.getElementById("post-comment");
|
||||
var domTop = postCommentDom.offsetTop;
|
||||
window.scrollTo(0, domTop - 80);
|
||||
if (txt == "undefined" || txt == "null") txt = "好棒!";
|
||||
function setText() {
|
||||
setTimeout(() => {
|
||||
var input = document.getElementsByClassName("el-textarea__inner")[0];
|
||||
if (!input) setText();
|
||||
let evt = document.createEvent("HTMLEvents");
|
||||
evt.initEvent("input", true, true);
|
||||
let inputValue = replaceAll(txt, "\n", "\n> ");
|
||||
input.value = "> " + inputValue + "\n\n";
|
||||
input.dispatchEvent(evt);
|
||||
input.focus();
|
||||
input.setSelectionRange(-1, -1);
|
||||
if (document.getElementById("comment-tips")) {
|
||||
document.getElementById("comment-tips").classList.add("show");
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
setText();
|
||||
};
|
||||
|
||||
//替换所有内容
|
||||
function replaceAll(string, search, replace) {
|
||||
return string.split(search).join(replace);
|
||||
}
|
||||
|
||||
// 百度搜索
|
||||
rm.searchBaidu = function () {
|
||||
anzhiyu.snackbarShow("即将跳转到百度搜索", false, 2000);
|
||||
setTimeout(function () {
|
||||
window.open("https://www.baidu.com/s?wd=" + selectTextNow);
|
||||
}, "2000");
|
||||
rm.hideRightMenu();
|
||||
};
|
||||
|
||||
//分享链接
|
||||
rm.copyLink = function () {
|
||||
rm.rightmenuCopyText(domhref);
|
||||
anzhiyu.snackbarShow("已复制链接地址");
|
||||
};
|
||||
|
||||
function addRightMenuClickEvent() {
|
||||
// 添加点击事件
|
||||
document.getElementById("menu-backward").addEventListener("click", function () {
|
||||
window.history.back();
|
||||
rm.hideRightMenu();
|
||||
});
|
||||
|
||||
document.getElementById("menu-forward").addEventListener("click", function () {
|
||||
window.history.forward();
|
||||
rm.hideRightMenu();
|
||||
});
|
||||
|
||||
document.getElementById("menu-refresh").addEventListener("click", function () {
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
document.getElementById("menu-top").addEventListener("click", function () {
|
||||
anzhiyu.scrollToDest(0, 500);
|
||||
rm.hideRightMenu();
|
||||
});
|
||||
|
||||
document.getElementById("menu-translate").addEventListener("click", function () {
|
||||
window.translateFn.translatePage();
|
||||
rm.hideRightMenu();
|
||||
});
|
||||
|
||||
const menuLinks = document.querySelectorAll(".menu-link");
|
||||
menuLinks.forEach(function (link) {
|
||||
link.addEventListener("click", rm.hideRightMenu);
|
||||
});
|
||||
|
||||
document.getElementById("menu-home") &&
|
||||
document.getElementById("menu-home").addEventListener("click", function () {
|
||||
window.location.href = window.location.origin;
|
||||
});
|
||||
|
||||
document.getElementById("menu-randomPost").addEventListener("click", function () {
|
||||
toRandomPost();
|
||||
});
|
||||
|
||||
document.getElementById("menu-commentBarrage").addEventListener("click", anzhiyu.switchCommentBarrage);
|
||||
|
||||
document.getElementById("rightmenu-mask").addEventListener("click", rm.hideRightMenu);
|
||||
|
||||
document.getElementById("rightmenu-mask").addEventListener("contextmenu", function (event) {
|
||||
rm.hideRightMenu();
|
||||
event.preventDefault(); // Prevent the default context menu from appearing
|
||||
});
|
||||
|
||||
document.getElementById("menu-copy").addEventListener("click", () => {
|
||||
rm.copyPageUrl();
|
||||
});
|
||||
|
||||
document.getElementById("menu-pastetext").addEventListener("click", rm.pasteText);
|
||||
|
||||
document.getElementById("menu-copytext").addEventListener("click", function () {
|
||||
rm.rightmenuCopyText(selectTextNow);
|
||||
const copyright = GLOBAL_CONFIG.copyright;
|
||||
if (copyright.copy) {
|
||||
anzhiyu.snackbarShow(copyright.languages.copySuccess);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById("menu-commenttext").addEventListener("click", function () {
|
||||
rm.rightMenuCommentText(selectTextNow);
|
||||
});
|
||||
|
||||
document.getElementById("menu-newwindow").addEventListener("click", function () {
|
||||
window.open(domhref, "_blank");
|
||||
rm.hideRightMenu();
|
||||
});
|
||||
|
||||
document.getElementById("menu-copylink").addEventListener("click", rm.copyLink);
|
||||
|
||||
document.getElementById("menu-downloadimg").addEventListener("click", function () {
|
||||
anzhiyu.downloadImage(domImgSrc, "anzhiyu");
|
||||
});
|
||||
|
||||
document.getElementById("menu-newwindowimg").addEventListener("click", function () {
|
||||
window.open(domImgSrc, "_blank");
|
||||
rm.hideRightMenu();
|
||||
});
|
||||
|
||||
document.getElementById("menu-copyimg").addEventListener("click", function () {
|
||||
rm.writeClipImg(domImgSrc);
|
||||
});
|
||||
|
||||
document.getElementById("menu-searchBaidu").addEventListener("click", rm.searchBaidu);
|
||||
|
||||
//音乐
|
||||
document.getElementById("menu-music-toggle").addEventListener("click", anzhiyu.musicToggle);
|
||||
|
||||
document.getElementById("menu-music-back").addEventListener("click", anzhiyu.musicSkipBack);
|
||||
|
||||
document.getElementById("menu-music-forward").addEventListener("click", anzhiyu.musicSkipForward);
|
||||
|
||||
document.getElementById("menu-music-copyMusicName").addEventListener("click", function () {
|
||||
rm.rightmenuCopyText(anzhiyu.musicGetName());
|
||||
anzhiyu.snackbarShow("复制歌曲名称成功", false, 3000);
|
||||
});
|
||||
}
|
||||
|
||||
addRightMenuClickEvent();
|
||||
2123
public/js/main.js
@@ -1,177 +1,192 @@
|
||||
window.addEventListener('load', () => {
|
||||
const $searchMask = document.getElementById('search-mask')
|
||||
const $searchDialog = document.querySelector('#algolia-search .search-dialog')
|
||||
window.addEventListener("load", () => {
|
||||
const $searchMask = document.getElementById("search-mask");
|
||||
const $searchDialog = document.querySelector("#algolia-search .search-dialog");
|
||||
|
||||
const openSearch = () => {
|
||||
const bodyStyle = document.body.style
|
||||
bodyStyle.width = '100%'
|
||||
bodyStyle.overflow = 'hidden'
|
||||
btf.animateIn($searchMask, 'to_show 0.5s')
|
||||
btf.animateIn($searchDialog, 'titleScale 0.5s')
|
||||
setTimeout(() => { document.querySelector('#algolia-search .ais-SearchBox-input').focus() }, 100)
|
||||
anzhiyu.animateIn($searchMask, "to_show 0.5s");
|
||||
$searchDialog.style.display = "block";
|
||||
setTimeout(() => {
|
||||
document.querySelector("#algolia-search .ais-SearchBox-input").focus();
|
||||
}, 100);
|
||||
|
||||
// shortcut: ESC
|
||||
document.addEventListener('keydown', function f (event) {
|
||||
if (event.code === 'Escape') {
|
||||
closeSearch()
|
||||
document.removeEventListener('keydown', f)
|
||||
document.addEventListener("keydown", function f(event) {
|
||||
if (event.code === "Escape") {
|
||||
closeSearch();
|
||||
document.removeEventListener("keydown", f);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
fixSafariHeight()
|
||||
window.addEventListener('resize', fixSafariHeight)
|
||||
fixSafariHeight();
|
||||
window.addEventListener("resize", fixSafariHeight);
|
||||
};
|
||||
|
||||
// shortcut: shift+S
|
||||
if (anzhiyu_keyboard) {
|
||||
window.addEventListener("keydown", function (event) {
|
||||
if (event.keyCode == 83 && event.shiftKey) {
|
||||
console.info(selectTextNow);
|
||||
if (selectTextNow) {
|
||||
openSearch();
|
||||
const t = document.querySelector("#algolia-search-input > div > form > input");
|
||||
t.value = selectTextNow;
|
||||
t.dispatchEvent(new Event("input"));
|
||||
setTimeout(() => {
|
||||
document.querySelector("#algolia-search-input > div > form > button.ais-SearchBox-submit").click();
|
||||
}, 64);
|
||||
} else {
|
||||
openSearch();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const closeSearch = () => {
|
||||
const bodyStyle = document.body.style
|
||||
bodyStyle.width = ''
|
||||
bodyStyle.overflow = ''
|
||||
btf.animateOut($searchDialog, 'search_close .5s')
|
||||
btf.animateOut($searchMask, 'to_hide 0.5s')
|
||||
window.removeEventListener('resize', fixSafariHeight)
|
||||
}
|
||||
anzhiyu.animateOut($searchDialog, "search_close .5s");
|
||||
anzhiyu.animateOut($searchMask, "to_hide 0.5s");
|
||||
window.removeEventListener("resize", fixSafariHeight);
|
||||
};
|
||||
|
||||
// fix safari
|
||||
const fixSafariHeight = () => {
|
||||
if (window.innerWidth < 768) {
|
||||
$searchDialog.style.setProperty('--search-height', window.innerHeight + 'px')
|
||||
$searchDialog.style.setProperty("--search-height", window.innerHeight + "px");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const searchClickFn = () => {
|
||||
btf.addEventListenerPjax(document.querySelector('#search-button > .search'), 'click', openSearch)
|
||||
}
|
||||
anzhiyu.addEventListenerPjax(document.querySelector("#search-button > .search"), "click", openSearch);
|
||||
};
|
||||
|
||||
const searchFnOnce = () => {
|
||||
$searchMask.addEventListener('click', closeSearch)
|
||||
document.querySelector('#algolia-search .search-close-button').addEventListener('click', closeSearch)
|
||||
}
|
||||
$searchMask.addEventListener("click", closeSearch);
|
||||
document.querySelector("#algolia-search .search-close-button").addEventListener("click", closeSearch);
|
||||
};
|
||||
|
||||
const cutContent = content => {
|
||||
if (content === '') return ''
|
||||
|
||||
const firstOccur = content.indexOf('<mark>')
|
||||
|
||||
let start = firstOccur - 30
|
||||
let end = firstOccur + 120
|
||||
let pre = ''
|
||||
let post = ''
|
||||
|
||||
if (start <= 0) {
|
||||
start = 0
|
||||
end = 140
|
||||
} else {
|
||||
pre = '...'
|
||||
}
|
||||
|
||||
if (end > content.length) {
|
||||
end = content.length
|
||||
} else {
|
||||
post = '...'
|
||||
}
|
||||
|
||||
const matchContent = pre + content.substring(start, end) + post
|
||||
return matchContent
|
||||
}
|
||||
|
||||
const algolia = GLOBAL_CONFIG.algolia
|
||||
const isAlgoliaValid = algolia.appId && algolia.apiKey && algolia.indexName
|
||||
const algolia = GLOBAL_CONFIG.algolia;
|
||||
const isAlgoliaValid = algolia.appId && algolia.apiKey && algolia.indexName;
|
||||
if (!isAlgoliaValid) {
|
||||
return console.error('Algolia setting is invalid!')
|
||||
return console.error("Algolia setting is invalid!");
|
||||
}
|
||||
|
||||
const search = instantsearch({
|
||||
indexName: algolia.indexName,
|
||||
/* global algoliasearch */
|
||||
searchClient: algoliasearch(algolia.appId, algolia.apiKey),
|
||||
searchFunction (helper) {
|
||||
helper.state.query && helper.search()
|
||||
}
|
||||
})
|
||||
searchFunction(helper) {
|
||||
if (helper.state.query) {
|
||||
let innerLoading = '<i class="anzhiyufont anzhiyu-icon-spinner anzhiyu-spin"></i>';
|
||||
document.getElementById("algolia-hits").innerHTML = innerLoading;
|
||||
helper.search();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const configure = instantsearch.widgets.configure({
|
||||
hitsPerPage: 5
|
||||
})
|
||||
hitsPerPage: algolia.hits.per_page ?? 5,
|
||||
});
|
||||
|
||||
const searchBox = instantsearch.widgets.searchBox({
|
||||
container: '#algolia-search-input',
|
||||
container: "#algolia-search-input",
|
||||
showReset: false,
|
||||
showSubmit: false,
|
||||
placeholder: GLOBAL_CONFIG.algolia.languages.input_placeholder,
|
||||
showLoadingIndicator: true
|
||||
})
|
||||
placeholder: algolia.languages.input_placeholder,
|
||||
showLoadingIndicator: true,
|
||||
searchOnEnterKeyPressOnly: true,
|
||||
searchAsYouType: false,
|
||||
});
|
||||
|
||||
const hits = instantsearch.widgets.hits({
|
||||
container: '#algolia-hits',
|
||||
container: "#algolia-hits",
|
||||
templates: {
|
||||
item (data) {
|
||||
const link = data.permalink ? data.permalink : (GLOBAL_CONFIG.root + data.path)
|
||||
const result = data._highlightResult
|
||||
const content = result.contentStripTruncate
|
||||
? cutContent(result.contentStripTruncate.value)
|
||||
: result.contentStrip
|
||||
? cutContent(result.contentStrip.value)
|
||||
: result.content
|
||||
? cutContent(result.content.value)
|
||||
: ''
|
||||
item(data) {
|
||||
const link = data.permalink ? data.permalink : GLOBAL_CONFIG.root + data.path;
|
||||
const result = data._highlightResult;
|
||||
const loadingLogo = document.querySelector("#algolia-hits .anzhiyu-spin");
|
||||
if (loadingLogo) {
|
||||
loadingLogo.style.display = "none";
|
||||
}
|
||||
setTimeout(() => {
|
||||
document.querySelector("#algolia-search .ais-SearchBox-input").focus();
|
||||
}, 200);
|
||||
return `
|
||||
<a href="${link}" class="algolia-hit-item-link">
|
||||
<span class="algolia-hits-item-title">${result.title.value || 'no-title'}</span>
|
||||
<p class="algolia-hit-item-content">${content}</p>
|
||||
</a>`
|
||||
<span class="algolia-hits-item-title">${result.title.value || "no-title"}</span>
|
||||
</a>`;
|
||||
},
|
||||
empty: function (data) {
|
||||
const loadingLogo = document.querySelector("#algolia-hits .anzhiyu-spin");
|
||||
console.info(loadingLogo);
|
||||
if (loadingLogo) {
|
||||
loadingLogo.style.display = "none";
|
||||
}
|
||||
setTimeout(() => {
|
||||
document.querySelector("#algolia-search .ais-SearchBox-input").focus();
|
||||
}, 200);
|
||||
return (
|
||||
'<div id="algolia-hits-empty">' +
|
||||
GLOBAL_CONFIG.algolia.languages.hits_empty.replace(/\$\{query}/, data.query) +
|
||||
'</div>'
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
"</div>"
|
||||
);
|
||||
},
|
||||
},
|
||||
cssClasses: {
|
||||
item: "algolia-hit-item",
|
||||
},
|
||||
});
|
||||
|
||||
const stats = instantsearch.widgets.stats({
|
||||
container: '#algolia-info > .algolia-stats',
|
||||
container: "#algolia-info > .algolia-stats",
|
||||
templates: {
|
||||
text: function (data) {
|
||||
const stats = GLOBAL_CONFIG.algolia.languages.hits_stats
|
||||
.replace(/\$\{hits}/, data.nbHits)
|
||||
.replace(/\$\{time}/, data.processingTimeMS)
|
||||
return (
|
||||
`<hr>${stats}`
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
.replace(/\$\{time}/, data.processingTimeMS);
|
||||
return `<hr>${stats}`;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const powerBy = instantsearch.widgets.poweredBy({
|
||||
container: '#algolia-info > .algolia-poweredBy'
|
||||
})
|
||||
container: "#algolia-info > .algolia-poweredBy",
|
||||
});
|
||||
|
||||
const pagination = instantsearch.widgets.pagination({
|
||||
container: '#algolia-pagination',
|
||||
totalPages: 5,
|
||||
container: "#algolia-pagination",
|
||||
totalPages: algolia.hits.per_page ?? 5,
|
||||
templates: {
|
||||
first: '<i class="fas fa-angle-double-left"></i>',
|
||||
last: '<i class="fas fa-angle-double-right"></i>',
|
||||
previous: '<i class="fas fa-angle-left"></i>',
|
||||
next: '<i class="fas fa-angle-right"></i>'
|
||||
}
|
||||
})
|
||||
first: '<i class="anzhiyufont anzhiyu-icon-angle-double-left"></i>',
|
||||
last: '<i class="anzhiyufont anzhiyu-icon-angle-double-right"></i>',
|
||||
previous: '<i class="anzhiyufont anzhiyu-icon-angle-left"></i>',
|
||||
next: '<i class="anzhiyufont anzhiyu-icon-angle-right"></i>',
|
||||
},
|
||||
scrollTo: false,
|
||||
showFirstLast: false,
|
||||
cssClasses: {
|
||||
root: "pagination",
|
||||
item: "pagination-item",
|
||||
link: "page-number",
|
||||
active: "current",
|
||||
disabled: "disabled-item",
|
||||
},
|
||||
});
|
||||
|
||||
search.addWidgets([configure, searchBox, hits, stats, powerBy, pagination]) // add the widgets to the instantsearch instance
|
||||
search.addWidgets([configure, searchBox, hits, stats, powerBy, pagination]); // add the widgets to the instantsearch instance
|
||||
|
||||
search.start()
|
||||
search.start();
|
||||
|
||||
searchClickFn()
|
||||
searchFnOnce()
|
||||
searchClickFn();
|
||||
searchFnOnce();
|
||||
|
||||
window.addEventListener('pjax:complete', () => {
|
||||
!btf.isHidden($searchMask) && closeSearch()
|
||||
searchClickFn()
|
||||
})
|
||||
window.addEventListener("pjax:complete", () => {
|
||||
!anzhiyu.isHidden($searchMask) && closeSearch();
|
||||
searchClickFn();
|
||||
});
|
||||
|
||||
window.pjax && search.on('render', () => {
|
||||
window.pjax.refresh(document.getElementById('algolia-hits'))
|
||||
})
|
||||
})
|
||||
window.pjax &&
|
||||
search.on("render", () => {
|
||||
window.pjax.refresh(document.getElementById("algolia-hits"));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,364 +1,270 @@
|
||||
/**
|
||||
* Refer to hexo-generator-searchdb
|
||||
* https://github.com/next-theme/hexo-generator-searchdb/blob/main/dist/search.js
|
||||
* Modified by hexo-theme-butterfly
|
||||
*/
|
||||
|
||||
class LocalSearch {
|
||||
constructor ({
|
||||
path = '',
|
||||
unescape = false,
|
||||
top_n_per_article = 1
|
||||
}) {
|
||||
this.path = path
|
||||
this.unescape = unescape
|
||||
this.top_n_per_article = top_n_per_article
|
||||
this.isfetched = false
|
||||
this.datas = null
|
||||
}
|
||||
|
||||
getIndexByWord (words, text, caseSensitive = false) {
|
||||
const index = []
|
||||
const included = new Set()
|
||||
|
||||
if (!caseSensitive) {
|
||||
text = text.toLowerCase()
|
||||
}
|
||||
words.forEach(word => {
|
||||
if (this.unescape) {
|
||||
const div = document.createElement('div')
|
||||
div.innerText = word
|
||||
word = div.innerHTML
|
||||
}
|
||||
const wordLen = word.length
|
||||
if (wordLen === 0) return
|
||||
let startPosition = 0
|
||||
let position = -1
|
||||
if (!caseSensitive) {
|
||||
word = word.toLowerCase()
|
||||
}
|
||||
while ((position = text.indexOf(word, startPosition)) > -1) {
|
||||
index.push({ position, word })
|
||||
included.add(word)
|
||||
startPosition = position + wordLen
|
||||
}
|
||||
})
|
||||
// Sort index by position of keyword
|
||||
index.sort((left, right) => {
|
||||
if (left.position !== right.position) {
|
||||
return left.position - right.position
|
||||
}
|
||||
return right.word.length - left.word.length
|
||||
})
|
||||
return [index, included]
|
||||
}
|
||||
|
||||
// Merge hits into slices
|
||||
mergeIntoSlice (start, end, index) {
|
||||
let item = index[0]
|
||||
let { position, word } = item
|
||||
const hits = []
|
||||
const count = new Set()
|
||||
while (position + word.length <= end && index.length !== 0) {
|
||||
count.add(word)
|
||||
hits.push({
|
||||
position,
|
||||
length: word.length
|
||||
})
|
||||
const wordEnd = position + word.length
|
||||
|
||||
// Move to next position of hit
|
||||
index.shift()
|
||||
while (index.length !== 0) {
|
||||
item = index[0]
|
||||
position = item.position
|
||||
word = item.word
|
||||
if (wordEnd > position) {
|
||||
index.shift()
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
hits,
|
||||
start,
|
||||
end,
|
||||
count: count.size
|
||||
}
|
||||
}
|
||||
|
||||
// Highlight title and content
|
||||
highlightKeyword (val, slice) {
|
||||
let result = ''
|
||||
let index = slice.start
|
||||
for (const { position, length } of slice.hits) {
|
||||
result += val.substring(index, position)
|
||||
index = position + length
|
||||
result += `<mark class="search-keyword">${val.substr(position, length)}</mark>`
|
||||
}
|
||||
result += val.substring(index, slice.end)
|
||||
return result
|
||||
}
|
||||
|
||||
getResultItems (keywords) {
|
||||
const resultItems = []
|
||||
this.datas.forEach(({ title, content, url }) => {
|
||||
// The number of different keywords included in the article.
|
||||
const [indexOfTitle, keysOfTitle] = this.getIndexByWord(keywords, title)
|
||||
const [indexOfContent, keysOfContent] = this.getIndexByWord(keywords, content)
|
||||
const includedCount = new Set([...keysOfTitle, ...keysOfContent]).size
|
||||
|
||||
// Show search results
|
||||
const hitCount = indexOfTitle.length + indexOfContent.length
|
||||
if (hitCount === 0) return
|
||||
|
||||
const slicesOfTitle = []
|
||||
if (indexOfTitle.length !== 0) {
|
||||
slicesOfTitle.push(this.mergeIntoSlice(0, title.length, indexOfTitle))
|
||||
}
|
||||
|
||||
let slicesOfContent = []
|
||||
while (indexOfContent.length !== 0) {
|
||||
const item = indexOfContent[0]
|
||||
const { position } = item
|
||||
// Cut out 120 characters. The maxlength of .search-input is 80.
|
||||
const start = Math.max(0, position - 20)
|
||||
const end = Math.min(content.length, position + 100)
|
||||
slicesOfContent.push(this.mergeIntoSlice(start, end, indexOfContent))
|
||||
}
|
||||
|
||||
// Sort slices in content by included keywords' count and hits' count
|
||||
slicesOfContent.sort((left, right) => {
|
||||
if (left.count !== right.count) {
|
||||
return right.count - left.count
|
||||
} else if (left.hits.length !== right.hits.length) {
|
||||
return right.hits.length - left.hits.length
|
||||
}
|
||||
return left.start - right.start
|
||||
})
|
||||
|
||||
// Select top N slices in content
|
||||
const upperBound = parseInt(this.top_n_per_article, 10)
|
||||
if (upperBound >= 0) {
|
||||
slicesOfContent = slicesOfContent.slice(0, upperBound)
|
||||
}
|
||||
|
||||
let resultItem = ''
|
||||
|
||||
url = new URL(url, location.origin)
|
||||
url.searchParams.append('highlight', keywords.join(' '))
|
||||
|
||||
if (slicesOfTitle.length !== 0) {
|
||||
resultItem += `<div class="local-search-hit-item"><a href="${url.href}"><span class="search-result-title">${this.highlightKeyword(title, slicesOfTitle[0])}</span>`
|
||||
} else {
|
||||
resultItem += `<div class="local-search-hit-item"><a href="${url.href}"><span class="search-result-title">${title}</span>`
|
||||
}
|
||||
|
||||
slicesOfContent.forEach(slice => {
|
||||
resultItem += `<p class="search-result">${this.highlightKeyword(content, slice)}...</p></a>`
|
||||
})
|
||||
|
||||
resultItem += '</div>'
|
||||
resultItems.push({
|
||||
item: resultItem,
|
||||
id: resultItems.length,
|
||||
hitCount,
|
||||
includedCount
|
||||
})
|
||||
})
|
||||
return resultItems
|
||||
}
|
||||
|
||||
fetchData () {
|
||||
const isXml = !this.path.endsWith('json')
|
||||
fetch(this.path)
|
||||
.then(response => response.text())
|
||||
.then(res => {
|
||||
// Get the contents from search data
|
||||
this.isfetched = true
|
||||
this.datas = isXml
|
||||
? [...new DOMParser().parseFromString(res, 'text/xml').querySelectorAll('entry')].map(element => ({
|
||||
title: element.querySelector('title').textContent,
|
||||
content: element.querySelector('content').textContent,
|
||||
url: element.querySelector('url').textContent
|
||||
}))
|
||||
: JSON.parse(res)
|
||||
// Only match articles with non-empty titles
|
||||
this.datas = this.datas.filter(data => data.title).map(data => {
|
||||
data.title = data.title.trim()
|
||||
data.content = data.content ? data.content.trim().replace(/<[^>]+>/g, '') : ''
|
||||
data.url = decodeURIComponent(data.url).replace(/\/{2,}/g, '/')
|
||||
return data
|
||||
})
|
||||
// Remove loading animation
|
||||
window.dispatchEvent(new Event('search:loaded'))
|
||||
})
|
||||
}
|
||||
|
||||
// Highlight by wrapping node in mark elements with the given class name
|
||||
highlightText (node, slice, className) {
|
||||
const val = node.nodeValue
|
||||
let index = slice.start
|
||||
const children = []
|
||||
for (const { position, length } of slice.hits) {
|
||||
const text = document.createTextNode(val.substring(index, position))
|
||||
index = position + length
|
||||
const mark = document.createElement('mark')
|
||||
mark.className = className
|
||||
mark.appendChild(document.createTextNode(val.substr(position, length)))
|
||||
children.push(text, mark)
|
||||
}
|
||||
node.nodeValue = val.substring(index, slice.end)
|
||||
children.forEach(element => {
|
||||
node.parentNode.insertBefore(element, node)
|
||||
})
|
||||
}
|
||||
|
||||
// Highlight the search words provided in the url in the text
|
||||
highlightSearchWords (body) {
|
||||
const params = new URL(location.href).searchParams.get('highlight')
|
||||
const keywords = params ? params.split(' ') : []
|
||||
if (!keywords.length || !body) return
|
||||
const walk = document.createTreeWalker(body, NodeFilter.SHOW_TEXT, null)
|
||||
const allNodes = []
|
||||
while (walk.nextNode()) {
|
||||
if (!walk.currentNode.parentNode.matches('button, select, textarea, .mermaid')) allNodes.push(walk.currentNode)
|
||||
}
|
||||
allNodes.forEach(node => {
|
||||
const [indexOfNode] = this.getIndexByWord(keywords, node.nodeValue)
|
||||
if (!indexOfNode.length) return
|
||||
const slice = this.mergeIntoSlice(0, node.nodeValue.length, indexOfNode)
|
||||
this.highlightText(node, slice, 'search-keyword')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
// Search
|
||||
const { path, top_n_per_article, unescape, languages } = GLOBAL_CONFIG.localSearch
|
||||
const localSearch = new LocalSearch({
|
||||
path,
|
||||
top_n_per_article,
|
||||
unescape
|
||||
})
|
||||
|
||||
const input = document.querySelector('#local-search-input input')
|
||||
const statsItem = document.getElementById('local-search-stats-wrap')
|
||||
const $loadingStatus = document.getElementById('loading-status')
|
||||
const isXml = !path.endsWith('json')
|
||||
|
||||
const inputEventFunction = () => {
|
||||
if (!localSearch.isfetched) return
|
||||
let searchText = input.value.trim().toLowerCase()
|
||||
isXml && (searchText = searchText.replace(/</g, '<').replace(/>/g, '>'))
|
||||
if (searchText !== '') $loadingStatus.innerHTML = '<i class="fas fa-spinner fa-pulse"></i>'
|
||||
const keywords = searchText.split(/[-\s]+/)
|
||||
const container = document.getElementById('local-search-results')
|
||||
let resultItems = []
|
||||
if (searchText.length > 0) {
|
||||
// Perform local searching
|
||||
resultItems = localSearch.getResultItems(keywords)
|
||||
}
|
||||
if (keywords.length === 1 && keywords[0] === '') {
|
||||
container.textContent = ''
|
||||
statsItem.textContent = ''
|
||||
} else if (resultItems.length === 0) {
|
||||
container.textContent = ''
|
||||
const statsDiv = document.createElement('div')
|
||||
statsDiv.className = 'search-result-stats'
|
||||
statsDiv.textContent = languages.hits_empty.replace(/\$\{query}/, searchText)
|
||||
statsItem.innerHTML = statsDiv.outerHTML
|
||||
} else {
|
||||
resultItems.sort((left, right) => {
|
||||
if (left.includedCount !== right.includedCount) {
|
||||
return right.includedCount - left.includedCount
|
||||
} else if (left.hitCount !== right.hitCount) {
|
||||
return right.hitCount - left.hitCount
|
||||
}
|
||||
return right.id - left.id
|
||||
})
|
||||
|
||||
const stats = languages.hits_stats.replace(/\$\{hits}/, resultItems.length)
|
||||
|
||||
container.innerHTML = `<div class="search-result-list">${resultItems.map(result => result.item).join('')}</div>`
|
||||
statsItem.innerHTML = `<hr><div class="search-result-stats">${stats}</div>`
|
||||
window.pjax && window.pjax.refresh(container)
|
||||
}
|
||||
|
||||
$loadingStatus.textContent = ''
|
||||
}
|
||||
|
||||
let loadFlag = false
|
||||
const $searchMask = document.getElementById('search-mask')
|
||||
const $searchDialog = document.querySelector('#local-search .search-dialog')
|
||||
|
||||
// fix safari
|
||||
const fixSafariHeight = () => {
|
||||
if (window.innerWidth < 768) {
|
||||
$searchDialog.style.setProperty('--search-height', window.innerHeight + 'px')
|
||||
}
|
||||
}
|
||||
window.addEventListener("load", () => {
|
||||
let loadFlag = false;
|
||||
let dataObj = [];
|
||||
const $searchMask = document.getElementById("search-mask");
|
||||
|
||||
const openSearch = () => {
|
||||
const bodyStyle = document.body.style
|
||||
bodyStyle.width = '100%'
|
||||
bodyStyle.overflow = 'hidden'
|
||||
btf.animateIn($searchMask, 'to_show 0.5s')
|
||||
btf.animateIn($searchDialog, 'titleScale 0.5s')
|
||||
setTimeout(() => { input.focus() }, 300)
|
||||
const bodyStyle = document.body.style;
|
||||
bodyStyle.width = "100%";
|
||||
bodyStyle.overflow = "hidden";
|
||||
anzhiyu.animateIn($searchMask, "to_show 0.5s");
|
||||
anzhiyu.animateIn(document.querySelector("#local-search .search-dialog"), "titleScale 0.5s");
|
||||
setTimeout(() => {
|
||||
document.querySelector("#local-search-input input").focus();
|
||||
}, 100);
|
||||
if (!loadFlag) {
|
||||
!localSearch.isfetched && localSearch.fetchData()
|
||||
input.addEventListener('input', inputEventFunction)
|
||||
loadFlag = true
|
||||
search();
|
||||
loadFlag = true;
|
||||
}
|
||||
// shortcut: ESC
|
||||
document.addEventListener('keydown', function f (event) {
|
||||
if (event.code === 'Escape') {
|
||||
closeSearch()
|
||||
document.removeEventListener('keydown', f)
|
||||
document.addEventListener("keydown", function f(event) {
|
||||
if (event.code === "Escape") {
|
||||
closeSearch();
|
||||
document.removeEventListener("keydown", f);
|
||||
}
|
||||
})
|
||||
|
||||
fixSafariHeight()
|
||||
window.addEventListener('resize', fixSafariHeight)
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const closeSearch = () => {
|
||||
const bodyStyle = document.body.style
|
||||
bodyStyle.width = ''
|
||||
bodyStyle.overflow = ''
|
||||
btf.animateOut($searchDialog, 'search_close .5s')
|
||||
btf.animateOut($searchMask, 'to_hide 0.5s')
|
||||
window.removeEventListener('resize', fixSafariHeight)
|
||||
}
|
||||
const bodyStyle = document.body.style;
|
||||
bodyStyle.width = "";
|
||||
bodyStyle.overflow = "";
|
||||
anzhiyu.animateOut(document.querySelector("#local-search .search-dialog"), "search_close .5s");
|
||||
anzhiyu.animateOut($searchMask, "to_hide 0.5s");
|
||||
};
|
||||
|
||||
const searchClickFn = () => {
|
||||
btf.addEventListenerPjax(document.querySelector('#search-button > .search'), 'click', openSearch)
|
||||
}
|
||||
document.querySelector("#search-button > .search").addEventListener("click", openSearch);
|
||||
document.querySelector("#menu-search").addEventListener("click", openSearch);
|
||||
};
|
||||
|
||||
const searchFnOnce = () => {
|
||||
document.querySelector('#local-search .search-close-button').addEventListener('click', closeSearch)
|
||||
$searchMask.addEventListener('click', closeSearch)
|
||||
if (GLOBAL_CONFIG.localSearch.preload) {
|
||||
localSearch.fetchData()
|
||||
const searchClickFnOnce = () => {
|
||||
document.querySelector("#local-search .search-close-button").addEventListener("click", closeSearch);
|
||||
$searchMask.addEventListener("click", closeSearch);
|
||||
if (GLOBAL_CONFIG.localSearch.preload) dataObj = fetchData(GLOBAL_CONFIG.localSearch.path);
|
||||
};
|
||||
|
||||
// check url is json or not
|
||||
const isJson = url => {
|
||||
const reg = /\.json$/;
|
||||
return reg.test(url);
|
||||
};
|
||||
|
||||
const fetchData = async path => {
|
||||
let data = [];
|
||||
const response = await fetch(path);
|
||||
if (isJson(path)) {
|
||||
data = await response.json();
|
||||
} else {
|
||||
const res = await response.text();
|
||||
const t = await new window.DOMParser().parseFromString(res, "text/xml");
|
||||
const a = await t;
|
||||
|
||||
data = [...a.querySelectorAll("entry")].map(item => {
|
||||
let tagsArr = [];
|
||||
if (item.querySelector("tags") && item.querySelector("tags").getElementsByTagName("tag")) {
|
||||
Array.prototype.forEach.call(item.querySelector("tags").getElementsByTagName("tag"), function (item, index) {
|
||||
tagsArr.push(item.textContent);
|
||||
});
|
||||
}
|
||||
let content = item.querySelector("content") && item.querySelector("content").textContent;
|
||||
let imgReg = /<img.*?(?:>|\/>)/gi; //匹配图片中的img标签
|
||||
let srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i; // 匹配图片中的src
|
||||
let arr = content.match(imgReg); //筛选出所有的img
|
||||
|
||||
let srcArr = [];
|
||||
if (arr) {
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
let src = arr[i].match(srcReg);
|
||||
// 获取图片地址
|
||||
if (!src[1].indexOf("http")) srcArr.push(src[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
title: item.querySelector("title").textContent,
|
||||
content: content,
|
||||
url: item.querySelector("url").textContent,
|
||||
tags: tagsArr,
|
||||
oneImage: srcArr && srcArr[0],
|
||||
};
|
||||
});
|
||||
}
|
||||
localSearch.highlightSearchWords(document.getElementById('article-container'))
|
||||
}
|
||||
if (response.ok) {
|
||||
const $loadDataItem = document.getElementById("loading-database");
|
||||
$loadDataItem.nextElementSibling.style.display = "block";
|
||||
$loadDataItem.remove();
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
window.addEventListener('search:loaded', () => {
|
||||
const $loadDataItem = document.getElementById('loading-database')
|
||||
$loadDataItem.nextElementSibling.style.display = 'block'
|
||||
$loadDataItem.remove()
|
||||
})
|
||||
const search = () => {
|
||||
if (!GLOBAL_CONFIG.localSearch.preload) {
|
||||
dataObj = fetchData(GLOBAL_CONFIG.localSearch.path);
|
||||
}
|
||||
const $input = document.querySelector("#local-search-input input");
|
||||
const $resultContent = document.getElementById("local-search-results");
|
||||
const $loadingStatus = document.getElementById("loading-status");
|
||||
|
||||
searchClickFn()
|
||||
searchFnOnce()
|
||||
$input.addEventListener("input", function () {
|
||||
const keywords = this.value.trim().toLowerCase().split(/[\s]+/);
|
||||
if (keywords[0] !== "")
|
||||
$loadingStatus.innerHTML = '<i class="anzhiyufont anzhiyu-icon-spinner anzhiyu-pulse-icon"></i>';
|
||||
|
||||
$resultContent.innerHTML = "";
|
||||
let str = '<div class="search-result-list">';
|
||||
if (keywords.length <= 0) return;
|
||||
let count = 0;
|
||||
// perform local searching
|
||||
dataObj.then(data => {
|
||||
data.forEach(data => {
|
||||
let isMatch = true;
|
||||
let dataTitle = data.title ? data.title.trim().toLowerCase() : "";
|
||||
let dataTags = data.tags;
|
||||
let oneImage = data.oneImage ?? "";
|
||||
const dataContent = data.content
|
||||
? data.content
|
||||
.trim()
|
||||
.replace(/<[^>]+>/g, "")
|
||||
.toLowerCase()
|
||||
: "";
|
||||
const dataUrl = data.url.startsWith("/") ? data.url : GLOBAL_CONFIG.root + data.url;
|
||||
let indexTitle = -1;
|
||||
let indexContent = -1;
|
||||
let firstOccur = -1;
|
||||
// only match articles with not empty titles and contents
|
||||
if (dataTitle !== "" || dataContent !== "") {
|
||||
keywords.forEach((keyword, i) => {
|
||||
indexTitle = dataTitle.indexOf(keyword);
|
||||
indexContent = dataContent.indexOf(keyword);
|
||||
if (indexTitle < 0 && indexContent < 0) {
|
||||
isMatch = false;
|
||||
} else {
|
||||
if (indexContent < 0) {
|
||||
indexContent = 0;
|
||||
}
|
||||
if (i === 0) {
|
||||
firstOccur = indexContent;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
isMatch = false;
|
||||
}
|
||||
|
||||
// show search results
|
||||
if (isMatch) {
|
||||
if (firstOccur >= 0) {
|
||||
// cut out 130 characters
|
||||
// let start = firstOccur - 30 < 0 ? 0 : firstOccur - 30
|
||||
// let end = firstOccur + 50 > dataContent.length ? dataContent.length : firstOccur + 50
|
||||
let start = firstOccur - 30;
|
||||
let end = firstOccur + 100;
|
||||
let pre = "";
|
||||
let post = "";
|
||||
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
if (start === 0) {
|
||||
end = 100;
|
||||
} else {
|
||||
pre = "...";
|
||||
}
|
||||
|
||||
if (end > dataContent.length) {
|
||||
end = dataContent.length;
|
||||
} else {
|
||||
post = "...";
|
||||
}
|
||||
|
||||
let matchContent = dataContent.substring(start, end);
|
||||
|
||||
// highlight all keywords
|
||||
keywords.forEach(keyword => {
|
||||
const regS = new RegExp(keyword, "gi");
|
||||
matchContent = matchContent.replace(regS, '<span class="search-keyword">' + keyword + "</span>");
|
||||
dataTitle = dataTitle.replace(regS, '<span class="search-keyword">' + keyword + "</span>");
|
||||
});
|
||||
|
||||
str += '<div class="local-search__hit-item">';
|
||||
if (oneImage) {
|
||||
str += `<div class="search-left"><img src=${oneImage} alt=${dataTitle} data-fancybox='gallery'>`;
|
||||
} else {
|
||||
str += '<div class="search-left" style="width:0">';
|
||||
}
|
||||
|
||||
str += "</div>";
|
||||
|
||||
if (oneImage) {
|
||||
str +=
|
||||
'<div class="search-right"><a href="' +
|
||||
dataUrl +
|
||||
'" class="search-result-title">' +
|
||||
dataTitle +
|
||||
"</a>";
|
||||
} else {
|
||||
str +=
|
||||
'<div class="search-right" style="width: 100%"><a href="' +
|
||||
dataUrl +
|
||||
'" class="search-result-title">' +
|
||||
dataTitle +
|
||||
"</a>";
|
||||
}
|
||||
|
||||
count += 1;
|
||||
|
||||
if (dataContent !== "") {
|
||||
str +=
|
||||
'<p class="search-result" onclick="pjax.loadUrl(`' +
|
||||
dataUrl +
|
||||
'`)">' +
|
||||
pre +
|
||||
matchContent +
|
||||
post +
|
||||
"</p>";
|
||||
}
|
||||
if (dataTags.length) {
|
||||
str += '<div class="search-result-tags">';
|
||||
|
||||
for (let i = 0; i < dataTags.length; i++) {
|
||||
const element = dataTags[i].trim();
|
||||
|
||||
str +=
|
||||
'<a class="tag-list" href="/tags/' +
|
||||
element +
|
||||
'/" data-pjax-state="" one-link-mark="yes">#' +
|
||||
element +
|
||||
"</a>";
|
||||
}
|
||||
|
||||
str += "</div>";
|
||||
}
|
||||
}
|
||||
str += "</div></div>";
|
||||
}
|
||||
});
|
||||
if (count === 0) {
|
||||
str +=
|
||||
'<div id="local-search__hits-empty">' +
|
||||
GLOBAL_CONFIG.localSearch.languages.hits_empty.replace(/\$\{query}/, this.value.trim()) +
|
||||
"</div>";
|
||||
}
|
||||
str += "</div>";
|
||||
$resultContent.innerHTML = str;
|
||||
if (keywords[0] !== "") $loadingStatus.innerHTML = "";
|
||||
window.pjax && window.pjax.refresh($resultContent);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
searchClickFn();
|
||||
searchClickFnOnce();
|
||||
|
||||
// pjax
|
||||
window.addEventListener('pjax:complete', () => {
|
||||
!btf.isHidden($searchMask) && closeSearch()
|
||||
localSearch.highlightSearchWords(document.getElementById('article-container'))
|
||||
searchClickFn()
|
||||
})
|
||||
})
|
||||
window.addEventListener("pjax:complete", () => {
|
||||
!anzhiyu.isHidden($searchMask) && closeSearch();
|
||||
searchClickFn();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
saveToLocal.get(targetEncodingCookie) === undefined
|
||||
? defaultEncoding
|
||||
: Number(saveToLocal.get('translate-chn-cht'))
|
||||
let translateButtonObject
|
||||
let translateButtonObject, translateRightMenuButtonObject;
|
||||
const isSnackbar = snackbarData !== undefined
|
||||
|
||||
function setLang () {
|
||||
@@ -56,12 +56,12 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
currentEncoding = 1
|
||||
targetEncoding = 2
|
||||
translateButtonObject.textContent = msgToTraditionalChinese
|
||||
isSnackbar && btf.snackbarShow(snackbarData.cht_to_chs)
|
||||
isSnackbar && anzhiyu.snackbarShow(snackbarData.cht_to_chs)
|
||||
} else if (targetEncoding === 2) {
|
||||
currentEncoding = 2
|
||||
targetEncoding = 1
|
||||
translateButtonObject.textContent = msgToSimplifiedChinese
|
||||
isSnackbar && btf.snackbarShow(snackbarData.chs_to_cht)
|
||||
isSnackbar && anzhiyu.snackbarShow(snackbarData.chs_to_cht)
|
||||
}
|
||||
saveToLocal.set(targetEncodingCookie, targetEncoding, 2)
|
||||
setLang()
|
||||
@@ -97,16 +97,24 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
return str
|
||||
}
|
||||
|
||||
function translateInitialization () {
|
||||
translateButtonObject = document.getElementById('translateLink')
|
||||
if (translateButtonObject) {
|
||||
function translateInitialization() {
|
||||
translateButtonObject = document.getElementById('translateLink');
|
||||
translateRightMenuButtonObject = document.getElementById('menu-translate').querySelector('span');
|
||||
|
||||
if (translateButtonObject || translateRightMenuButtonObject) {
|
||||
if (currentEncoding !== targetEncoding) {
|
||||
translateButtonObject.textContent =
|
||||
targetEncoding === 1
|
||||
? msgToSimplifiedChinese
|
||||
: msgToTraditionalChinese
|
||||
setLang()
|
||||
setTimeout(translateBody, translateDelay)
|
||||
const textContent = targetEncoding === 1 ? msgToSimplifiedChinese : msgToTraditionalChinese;
|
||||
|
||||
if (translateButtonObject) {
|
||||
translateButtonObject.textContent = textContent;
|
||||
}
|
||||
|
||||
if (translateRightMenuButtonObject) {
|
||||
translateRightMenuButtonObject.textContent = textContent;
|
||||
}
|
||||
|
||||
setLang();
|
||||
setTimeout(translateBody, translateDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,4 +127,4 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
translateInitialization()
|
||||
document.addEventListener('pjax:complete', translateInitialization)
|
||||
})
|
||||
})
|
||||