来自:Bing随机壁纸
移植哔哔广场过程记录
10700 字
54 分钟
移植哔哔广场过程记录
最近看到哔哔广场,想移植到博客里用,但是由于pjax的关系,原本的JS文件没法用,所以我稍微修改了一下,适配Solitude主题。以下是折腾的过程 注:折腾Memos的过程,以后大概会单独写一篇。
一、修改配置文件
在博客主文件夹中找到主题配置文件,添加以下内容:
# BB# 哔哔广场bb: enable: true #true: 打开说说; false: 关闭说说 geminiKey: false #true: 显示Gemini相关内容; false: 不显示Gemini相关内容 cfwkAiUrl: false #true: 显示Cloudflare AI相关内容; false: 不显示Cloudflare AIi相关内容二、修改JS
(一)添加JS文件
在Solitude主题文件夹\source\js\中添加memos.js,在memos.js中添加以下内容:
/** * Lately.min.js 2.5.2 * https://tokinx.github.io/lately/ */!function(){window.Lately=new function(){var t=this;this.lang={second:"秒",minute:"分钟",hour:"小时",day:"天",month:"个月",year:"年",ago:"前",error:"NaN"};var e=function(e){e=new Date(n(e));var r=new function(){this.second=(Date.now()-e.getTime())/1e3,this.minute=this.second/60,this.hour=this.minute/60,this.day=this.hour/24,this.month=this.day/30,this.year=this.month/12},i=Object.keys(r).reverse().find(function(t){return r[t]>=1});return(i?function(t,e){return Math.floor(t)+e}(r[i],t.lang[i]):t.lang.error)+t.lang.ago},n=function(t){return t=new Date(t&&("number"==typeof t?t:t.replace(/-/g,"/").replace("T"," "))),!isNaN(t.getTime())&&t.getTime()};return{init:function(){var r=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},i=r.target,a=void 0===i?"time":i,o=r.lang;o&&(t.lang=o);var u=!0,h=!1,l=void 0;try{for(var s,c=document.querySelectorAll(a)[Symbol.iterator]();!(u=(s=c.next()).done);u=!0){var f=s.value,g=n(f.dateTime)||n(f.title)||n(f.innerHTML)||0;if(!g)return;f.title=new Date(g).toLocaleString(),f.innerHTML=e(g)}}catch(t){h=!0,l=t}finally{try{!u&&c.return&&c.return()}finally{if(h)throw l}}},format:e}}}();/** * ViewImage.min.js 2.0.2 * https://tokinx.github.io/ViewImage/ */var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.createTemplateTagFirstArg=function(b){return b.raw=b};$jscomp.createTemplateTagFirstArgWithRaw=function(b,a){b.raw=a;return b};$jscomp.arrayIteratorImpl=function(b){var a=0;return function(){return a<b.length?{done:!1,value:b[a++]}:{done:!0}}};$jscomp.arrayIterator=function(b){return{next:$jscomp.arrayIteratorImpl(b)}};$jscomp.makeIterator=function(b){var a="undefined"!=typeof Symbol&&Symbol.iterator&&b[Symbol.iterator];return a?a.call(b):$jscomp.arrayIterator(b)};$jscomp.arrayFromIterator=function(b){for(var a,d=[];!(a=b.next()).done;)d.push(a.value);return d};$jscomp.arrayFromIterable=function(b){return b instanceof Array?b:$jscomp.arrayFromIterator($jscomp.makeIterator(b))};(function(){window.ViewImage=new function(){var b=this;this.target="[view-image] img";this.listener=function(a){if(!(a.ctrlKey||a.metaKey||a.shiftKey||a.altKey)){var d=String(b.target.split(",").map(function(g){return g.trim()+":not([no-view])"})),c=a.target.closest(d);if(c){var e=c.closest("[view-image]")||document.body;d=[].concat($jscomp.arrayFromIterable(e.querySelectorAll(d))).map(function(g){return g.href||g.src});b.display(d,c.href||c.src);a.stopPropagation();a.preventDefault()}}};this.init=function(a){a&&(b.target=a);["removeEventListener","addEventListener"].forEach(function(d){document[d]("click",b.listener,!1)})};this.display=function(a,d){var c=a.indexOf(d),e=(new DOMParser).parseFromString('\n <div class="view-image">\n <style>.view-image{position:fixed;inset:0;z-index:500;padding:1rem;display:flex;flex-direction:column;animation:view-image-in 300ms;backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px)}.view-image__out{animation:view-image-out 300ms}@keyframes view-image-in{0%{opacity:0}}@keyframes view-image-out{100%{opacity:0}}.view-image-btn{width:32px;height:32px;display:flex;justify-content:center;align-items:center;cursor:pointer;border-radius:3px;background-color:rgba(255,255,255,0.2)}.view-image-btn:hover{background-color:rgba(255,255,255,0.5)}.view-image-close__full{position:absolute;inset:0;background-color:rgba(48,55,66,0.3);z-index:unset;cursor:zoom-out;margin:0}.view-image-container{height:0;flex:1;display:flex;align-items:center;justify-content:center;}.view-image-lead{display:contents}.view-image-lead img{position:relative;z-index:1;max-width:100%;max-height:100%;object-fit:contain;border-radius:3px}.view-image-lead__in img{animation:view-image-lead-in 300ms}.view-image-lead__out img{animation:view-image-lead-out 300ms forwards}@keyframes view-image-lead-in{0%{opacity:0;transform:translateY(-20px)}}@keyframes view-image-lead-out{100%{opacity:0;transform:translateY(20px)}}[class*=__out] ~ .view-image-loading{display:block}.view-image-loading{position:absolute;inset:50%;width:8rem;height:2rem;color:#aab2bd;overflow:hidden;text-align:center;margin:-1rem -4rem;z-index:1;display:none}.view-image-loading::after{content:"";position:absolute;inset:50% 0;width:100%;height:3px;background:rgba(255,255,255,0.5);transform:translateX(-100%) translateY(-50%);animation:view-image-loading 800ms -100ms ease-in-out infinite}@keyframes view-image-loading{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}.view-image-tools{position:relative;display:flex;justify-content:space-between;align-content:center;color:#fff;max-width:600px;position: absolute; bottom: 5%; left: 1rem; right: 1rem; backdrop-filter: blur(10px);margin:0 auto;padding:10px;border-radius:5px;background:rgba(0,0,0,0.1);margin-bottom:constant(safe-area-inset-bottom);margin-bottom:env(safe-area-inset-bottom);z-index:1}.view-image-tools__count{width:60px;display:flex;align-items:center;justify-content:center}.view-image-tools__flip{display:flex;gap:10px}.view-image-tools [class*=-close]{margin:0 10px}.view-image{backdrop-filter:blur(5px)!important;-webkit-backdrop-filter:blur(5px)!important}.view-image-tools{opacity:1;animation:1s 1.5s forwards fadeOut}.view-image-tools:hover{opacity:1;animation:none;transition:opacity .2s}.view-image-container{margin-top:3rem}@keyframes fadeOut{to{opacity:0}}</style>\n <div class="view-image-container">\n <div class="view-image-lead"></div>\n <div class="view-image-loading"></div>\n <div class="view-image-close view-image-close__full"></div>\n </div>\n <div class="view-image-tools">\n <div class="view-image-tools__count">\n <span><b class="view-image-index">'+(c+1)+"</b>/"+a.length+'</span>\n </div>\n <div class="view-image-tools__flip">\n <div class="view-image-btn view-image-tools__flip-prev">\n <svg width="20" height="20" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M31 36L19 24L31 12" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>\n </div>\n <div class="view-image-btn view-image-tools__flip-next">\n <svg width="20" height="20" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M19 12L31 24L19 36" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>\n </div>\n </div>\n <div class="view-image-btn view-image-close">\n <svg width="16" height="16" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="48" height="48" fill="white" fill-opacity="0.01"/><path d="M8 8L40 40" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M8 40L40 8" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>\n </div>\n </div>\n </div>\n ',"text/html").body.firstChild,g=function(f){var h={Escape:"close",ArrowLeft:"tools__flip-prev",ArrowRight:"tools__flip-next"};h[f.key]&&e.querySelector(".view-image-"+h[f.key]).click()},l=function(f){var h=new Image,k=e.querySelector(".view-image-lead");k.className="view-image-lead view-image-lead__out";setTimeout(function(){k.innerHTML="";h.onload=function(){setTimeout(function(){k.innerHTML='<img src="'+h.src+'" alt="ViewImage" no-view/>';k.className="view-image-lead view-image-lead__in"},100)};h.src=f},300)};document.body.appendChild(e);l(d);window.addEventListener("keydown",g);e.onclick=function(f){f.target.closest(".view-image-close")?(window.removeEventListener("keydown",g),e.onclick=null,e.classList.add("view-image__out"),setTimeout(function(){return e.remove()},290)):f.target.closest(".view-image-tools__flip")&&(c=f.target.closest(".view-image-tools__flip-prev")?0===c?a.length-1:c-1:c===a.length-1?0:c+1,l(a[c]),e.querySelector(".view-image-index").innerHTML=c+1)}}}})();/** * coco-message * https://github.com/TheWindRises-2/coco-message */"use strict";function _typeof(o){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(o){return typeof o}:function(o){return o&&"function"==typeof Symbol&&o.constructor===Symbol&&o!==Symbol.prototype?"symbol":typeof o},_typeof(o)}!function(o,t){"object"===("undefined"==typeof exports?"undefined":_typeof(exports))&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(o=o||self,o.cocoMessage=t())}(void 0,function(){function o(o,t){var e=document.createElement("div");for(var n in o){var i=o[n];"className"==n?(n="class",e.setAttribute(n,i)):"_"==n[0]&&e.addEventListener(n.slice(1),i)}if("string"==typeof t)e.innerHTML=t;else if("object"==_typeof(t)&&t.tagName)e.appendChild(t);else if(t)for(var s=0;s<t.length;s++){var r=t[s];e.appendChild(r)}return e}function t(o,t){for(var e in t)o.style[e]=t[e];""===o.getAttribute("style")&&o.removeAttribute("style")}function e(o,t){var e=o.className||"";if(!n(e,t)){var i=e.split(/\s+/);i.push(t),o.className=i.join(" ")}}function n(o,t){return o.indexOf(t)>-1}function i(o,t){var e=o.className||"";if(n(e,t)){var i=e.split(/\s+/),s=i.indexOf(t);i.splice(s,1),o.className=i.join(" ")}""===o.className&&o.removeAttribute("class")}function s(){return r(arguments,"info")}function r(o,t){var e={};for(var n in h)e[n]=h[n];for(var i=0;i<o.length;i++){var s=o[i];void 0!==s&&("string"==typeof s||"object"==_typeof(s)?e.msg=s:"boolean"==typeof s?e.showClose=s:"function"==typeof s?e.onClose=s:"number"==typeof s&&(e.duration=s))}return e.type=t,a(e)}function a(e){var n=e.type,s=e.duration,r=e.msg,a=e.showClose,d=e.onClose,g=0===s,p=l();"loading"==n&&(r=""===r?"正在加载":r,g=a,s=0);var h=o({className:"coco-msg-wrapper"},[o({className:"coco-msg coco-msg-fade-in ".concat(n)},[o({className:"coco-msg-icon"},p[n]),o({className:"coco-msg-content"},r),o({className:"coco-msg-wait ".concat(g?"coco-msg-pointer":"coco-msg-wait-hidden"),_click:function(){f(h,d)}},c(g)||"")])]);return 0!==s&&setTimeout(function(){f(h,d)},s),m.children.length||document.body.appendChild(m),m.appendChild(h),t(h,{height:h.offsetHeight+"px"}),setTimeout(function(){i(h.children[0],"coco-msg-fade-in")},300),function(){f(h,d)}}function c(o){return o?'<svg class="coco-msg-close" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5514"><path d="M810 274l-238 238 238 238-60 60-238-238-238 238-60-60 238-238-238-238 60-60 238 238 238-238z" p-id="5515"></path></svg>':""}function f(o,n){o&&(t(o,{padding:0,height:0}),e(o.children[0],"coco-msg-fade-out"),n&&n(),setTimeout(function(){if(o){for(var t=!1,e=0;e<m.children.length;e++)m.children[e]===o&&(t=!0);t&&d(o),o=null,m.children.length||t&&d(m)}},300))}function l(){return{info:'\n <svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3250"><path d="M469.333333 341.333333h85.333334v469.333334H469.333333z" fill="#ffffff" p-id="3251"></path><path d="M469.333333 213.333333h85.333334v85.333334H469.333333z" fill="#ffffff" p-id="3252"></path><path d="M384 341.333333h170.666667v85.333334H384z" fill="#ffffff" p-id="3253"></path><path d="M384 725.333333h256v85.333334H384z" fill="#ffffff" p-id="3254"></path></svg>\n ',success:'\n <svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1807"><path d="M455.42 731.04c-8.85 0-17.75-3.05-24.99-9.27L235.14 553.91c-16.06-13.81-17.89-38.03-4.09-54.09 13.81-16.06 38.03-17.89 54.09-4.09l195.29 167.86c16.06 13.81 17.89 38.03 4.09 54.09-7.58 8.83-18.31 13.36-29.1 13.36z" p-id="1808" fill="#ffffff"></path><path d="M469.89 731.04c-8.51 0-17.07-2.82-24.18-8.6-16.43-13.37-18.92-37.53-5.55-53.96L734.1 307.11c13.37-16.44 37.53-18.92 53.96-5.55 16.43 13.37 18.92 37.53 5.55 53.96L499.67 716.89c-7.58 9.31-18.64 14.15-29.78 14.15z" p-id="1809" fill="#ffffff"></path></svg>\n ',warning:'\n <svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="18912"><path d="M468.114286 621.714286c7.314286 21.942857 21.942857 36.571429 43.885714 36.571428s36.571429-14.628571 43.885714-36.571428L585.142857 219.428571c0-43.885714-36.571429-73.142857-73.142857-73.142857-43.885714 0-73.142857 36.571429-73.142857 80.457143l29.257143 394.971429zM512 731.428571c-43.885714 0-73.142857 29.257143-73.142857 73.142858s29.257143 73.142857 73.142857 73.142857 73.142857-29.257143 73.142857-73.142857-29.257143-73.142857-73.142857-73.142858z" p-id="18913" fill="#ffffff"></path></svg>\n ',error:'\n <svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5514"><path d="M810 274l-238 238 238 238-60 60-238-238-238 238-60-60 238-238-238-238 60-60 238 238 238-238z" p-id="5515" fill="#ffffff"></path></svg>\n ',loading:'\n <div class="coco-msg_loading">\n <svg class="coco-msg-circular" viewBox="25 25 50 50">\n <circle class="coco-msg-path" cx="50" cy="50" r="20" fill="none" stroke-width="4" stroke-miterlimit="10"/>\n </svg>\n </div>\n '}}function d(o){o&&o.parentNode.removeChild(o)}function g(){for(var o=0;o<m.children.length;o++){var t=m.children[o];f(t)}}function p(){var o=document;if(o&&o.head){var t=o.head,e=o.createElement("style"),n=".coco-msg-stage *{box-sizing:border-box}.coco-msg-stage{position:fixed;top:20px;left:50%;width:auto;transform:translate(-50%,0);z-index:3000;padding-top:constant(safe-area-inset-top);padding-top:env(safe-area-inset-top)}.coco-msg-wrapper{position:relative;left:50%;transform:translate(-50%,0);transition:height .35s ease-out,padding .35s ease-out;padding:8px 0}.coco-msg{padding:8px 16px;border-radius:7px;position:relative;left:50%;transform:translate(-50%,0);display:inline-flex;align-items:center;box-shadow:0 4px 16px rgba(15,15,15,.15);color:rgba(44,44,44,.9);background-color:rgba(255,255,255,.95);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.dark .coco-msg{color:rgba(255,255,255,.9);background-color:rgba(36,36,36,.95);box-shadow:0 0 1px 0 rgba(55,55,55,.3)}.coco-msg-icon{position:relative;width:16px;height:16px;border-radius:100px;display:flex;justify-content:center;align-items:center}.coco-msg-icon svg{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:12px;height:12px}.coco-msg-wait{width:20px;height:20px;position:relative;display:inline-flex;justify-content:center;align-items:center;margin-left:10px}.coco-msg-wait:active svg{transform:scale(.7)}.coco-msg-wait svg{transition:.12s ease-out;fill:currentColor}.coco-msg-close{width:14px;height:14px}.coco-msg-content{margin-left:10px;text-align:left;font-size:14px;font-weight:400;word-break:keep-all;line-height:1.57143;display:inline-block}.coco-msg.info .coco-msg-icon{background-color:#3491fa}.coco-msg.success .coco-msg-icon{background-color:#00b42a}.coco-msg.warning .coco-msg-icon{background-color:#f7ba1e}.coco-msg.error .coco-msg-icon{background-color:#f53f3f}.dark .coco-msg.info .coco-msg-icon{background-color:#1d4dd2}.dark .coco-msg.success .coco-msg-icon{background-color:#129a37}.dark .coco-msg.warning .coco-msg-icon{background-color:#cc961f}.dark .coco-msg.error .coco-msg-icon{background-color:#cb2e34}.dark .coco-msg .coco-msg-icon path{fill:rgba(36,36,36,.95)}.coco-msg_loading{flex-shrink:0;width:20px;height:20px;position:relative}.coco-msg-circular{-webkit-animation:coco-msg-rotate 2s linear infinite both;animation:coco-msg-rotate 2s linear infinite both;transform-origin:center center;height:20px!important;width:20px!important;color:#3491fa;margin-top:-1px}.dark .coco-msg-circular{color:#1d4dd2}.coco-msg-path{stroke-dasharray:1,200;stroke-dashoffset:0;stroke:currentColor;-webkit-animation:coco-msg-dash 1.5s ease-in-out infinite;animation:coco-msg-dash 1.5s ease-in-out infinite;stroke-linecap:round}@-webkit-keyframes coco-msg-rotate{100%{transform:translate(-50%,-50%) rotate(360deg)}}@keyframes coco-msg-rotate{100%{transform:translate(-50%,-50%) rotate(360deg)}}@-webkit-keyframes coco-msg-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:89,200;stroke-dashoffset:-35px}100%{stroke-dasharray:89,200;stroke-dashoffset:-124px}}@keyframes coco-msg-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:89,200;stroke-dashoffset:-35px}100%{stroke-dasharray:89,200;stroke-dashoffset:-124px}}.coco-msg-pointer{cursor:pointer}.coco-msg-wait-hidden{display:none}.coco-msg-fade-in{-webkit-animation:coco-msg-fade .22s ease-out both;animation:coco-msg-fade .22s ease-out both}.coco-msg-fade-out{animation:coco-msg-fade .22s linear reverse both}@-webkit-keyframes coco-msg-fade{0%{opacity:0;transform:translate(-50%,-80%)}to{opacity:1;transform:translate(-50%,0)}}@keyframes coco-msg-fade{0%{opacity:0;transform:translate(-50%,-80%)}to{opacity:1;transform:translate(-50%,0)}}";e.innerHTML=n,t.appendChild(e)}}if("undefined"!=typeof window){var m=o({className:"coco-msg-stage"}),h={msg:"",duration:2e3,showClose:!1},u={info:function(){return r(arguments,"info")},success:function(){return r(arguments,"success")},warning:function(){return r(arguments,"warning")},error:function(){return r(arguments,"error")},loading:function(){return r(arguments,"loading")},destroyAll:function(){g()},config:function(o){for(var t in o)Object.hasOwnProperty.call(o,t)&&void 0!==o[t]&&(h[t]=o[t])}};for(var v in u)s[v]=u[v];return p(),s}});
/** * memobbs * 一个纯 HTML、JS、CSS 造的静态页面,实现个人 Memos 前端登录发布、编辑等管理功能,集成广场模式、随机模式。当然,也支持嵌入到自己的博客中。 * Author: 林木木(@lmm214) * Memos v0.18.2 and below only * Introduction: https://immmmm.com/memobbs-app/ * Github Repo: https://github.com/lmm214/memobbs * Demo: https://memobbs.app/ * modified by D-Bood 2024-08-31 */class MemosBbs {
constructor() { this.memosData = { dom: "#memos", listDom: "#memo-list", limit: "8" }; this.memosDom = document.querySelector(this.memosData.dom);
this.memoList this.memosMyList = [ { "creatorName": #自己的名字, "website": #自己的网站地址, "link": #自己的Memos地址, "creatorId": #自己的Memos账号id, "avatar": #自己的头像url, "twikoo": #自己的twikoo地址 } ] this.memoDefaultList = [ { "creatorName": "林木木", "website": "https://immmmm.com", "link": "https://me.edui.fun", "creatorId": "101", "avatar": "https://gravatar.memobbs.app/avatar/ba83fa02fc4b2ba621514941307e21be?s=80", "twikoo": "https://metk.edui.fun" },{ "creatorName": "归臧", "website": "https://nuoea.com", "link": "https://memos.nuoea.com", "creatorId": "101", "avatar": "https://gravatar.memobbs.app/avatar/020d365ea2596ef6d516143bb0552704?s=80", "twikoo": "https://twikoo.nuoea.com" },{ "creatorName": "koobai", "website": "https://koobai.com", "link": "https://memos.koobai.com", "creatorId": "1", "avatar": "https://gravatar.memobbs.app/avatar/3b3d336a7d389b7ae8531cbe177ae9b7?s=80", "artalk": "https://c.koobai.com", "artSite": "空白唠叨" } ];
this.getEditor = window.localStorage && window.localStorage.getItem("memos-editor-display"); this.getMode = window.localStorage && window.localStorage.getItem("memos-mode"); this.memosOpenId = window.localStorage && window.localStorage.getItem("memos-access-token"); this.memosPath = window.localStorage && window.localStorage.getItem("memos-access-path"); this.memosMeID = window.localStorage && window.localStorage.getItem("memos-me-id"); this.memosMeNickname = window.localStorage && window.localStorage.getItem("memos-me-nickname"); this.memosMeAvatarUrl = window.localStorage && window.localStorage.getItem("memos-me-avatarurl"); this.memosMeArtalk = window.localStorage && window.localStorage.getItem("memos-artalk-input"); this.memosMeArtalkSite = window.localStorage && window.localStorage.getItem("memos-artalksite-input"); this.memosMeTwikoo = window.localStorage && window.localStorage.getItem("memos-twikoo-input"); this.cfwkAiUrl = window.localStorage && window.localStorage.getItem("memos-cfwkai-url") this.geminiKey = window.localStorage && window.localStorage.getItem("memos-gemini-key") this.filterName = window.localStorage && window.localStorage.getItem("memos-filter-name")
// this.themeTogglebtn = document.querySelector(".memos-theme-toggle"); this.myFeedsBtn = document.querySelector(".my-blog-feeds"); this.memosEditorInner = document.querySelector(".memos-editor-inner"); this.memosEditorOption = document.querySelector(".memos-editor-option"); this.memosRadomCont = document.querySelector(".memos-random"); this.taglistBtn = document.querySelector(".tag-btn"); this.codeoneBtn = document.querySelector(".codeone-btn"); this.codeBtn = document.querySelector(".code-btn"); this.linkBtn = document.querySelector(".link-btn"); this.linkPicBtn = document.querySelector(".linkpic-btn"); this.cfAiBtn = document.querySelector(".cfworkerai-btn") || ""; this.cfAiLoadBtn = document.querySelector(".cfworkerai-load-btn"); this.geminiAIBtn = document.querySelector(".geminiai-btn") || ""; this.geminiAILoadBtn = document.querySelector(".geminiai-load-btn"); this.randomBtn = document.querySelector(".random-btn"); this.oneDayBtn = document.querySelector(".oneday-btn"); this.userButton = document.querySelector('.user-button-span'); this.privateBtn = document.querySelector(".private-btn"); this.switchUserBtn = document.querySelector(".switchUser-btn"); this.backToEditerBtn = document.querySelector(".backto-editer-btn"); this.loadEditorBtn = document.querySelector(".call-memos-editor"); this.searchBtn = document.querySelector(".search-memos-btn"); this.searchInput = document.querySelector(".search-memos-input"); this.userlistBtn = document.querySelector(".userlist-memos"); this.randomUserBtn = document.querySelector(".randomuser-memos"); this.submitApiBtn = document.querySelector(".submit-openapi-btn"); this.submitMemoBtn = document.querySelector(".submit-memos-btn"); this.memosVisibilitySelect = document.querySelector(".select-memos-value"); this.pathInput = document.querySelector(".memos-path-input"); this.tokenInput = document.querySelector(".memos-token-input"); this.artalkInput = document.querySelector(".memos-artalk-input"); this.artalkSiteInput = document.querySelector(".memos-artalksite-input"); this.twikooInput = document.querySelector(".memos-twikoo-input"); this.cfwkAiUrlInput = document.querySelector(".cfwkai-url-input"); this.geminiKeyInput = document.querySelector(".gemini-key-input"); this.filterNameInput = document.querySelector(".filter-name-input"); this.uploadImageInput = document.querySelector(".memos-upload-image-input"); //Webp格式 this.uploadWebpImageInput = document.querySelector(".memos-upload-Webp-image-input");
this.memosTextarea = document.querySelector(".memos-editor-textarea");
this.editMemoDom = document.querySelector(".edit-memos"); this.editMemoBtn = document.querySelector(".edit-memos-btn"); this.cancelEditBtn = document.querySelector(".cancel-edit-btn"); this.biaoqingBtn = document.querySelector(".biao-qing-btn"); this.usernowDom = document.querySelector(".user-now"); this.usernowBtnDom = document.querySelectorAll(".user-now .button"); this.goHomeBtn = document.querySelector('.gohome-memos') this.goBbsBtn = document.querySelector('.gobbs-memos')
this.memoDom = document.querySelector(this.memosData.listDom); this.skeleton = `<div class="el-loading"><div class="el-skeleton mb-3"></div><div class="el-skeleton mb-3"></div><div class="el-skeleton width-50 mb-3"></div><div class="el-skeleton mb-3"></div><div class="el-skeleton mb-3"></div><div class="el-skeleton width-50 mb-3"></div></div>`;
this.loadBtn = document.querySelector("button.button-load");
this.limit = this.memosData.limit; this.page = 1; this.nums = this.dataNum = this.memosContType = this.memosAccess = this.randomUser = 0;// = 0,this.dataNum = 0,this.memosContType = 0, this.memosAccess = 0,this.randomUser = 0; this.memoData = this.memosStr = []; this.memoCreatorMap = this.twikooCount = this.artalkCount = {}; // this.memosStr = [],this.memoCreatorMap = {},this.twikooCount = {},this.artalkCount = {}; this.memosMode; this.nowLink; this.nowId; this.nowName; this.nowAvatar; this.nowV1; this.nowTagList = ""; this.memoChangeDate = 0; this.getSelectedValue = window.localStorage && window.localStorage.getItem("memos-visibility-select") || "PUBLIC";
this._getTheme(); // this.themeTogglebtn.addEventListener('click', () => { // if(!document.body.classList.contains("dark")){ // document.body.classList.add("dark-theme","dark"); // window.localStorage && window.localStorage.setItem("theme","dark"); // }else{ // document.body.classList.remove("dark-theme","dark"); // window.localStorage && window.localStorage.setItem("theme","light"); // } // }); this._init(); this.myFeedsBtn.addEventListener('click', (event) => { this.loadBtn.classList.add('d-none'); this.memoDom.innerHTML = this.skeleton; this.usernowBtnDom.forEach((item) => {item.classList.remove('current');}) this.myFeedsBtn.classList.add("current") let fetchUrl = "https://cf.edui.fun/all?rule=created&end=20" fetch(fetchUrl).then(res => res.json()).then(resdata =>{ let myFeedData = resdata.article_data let myFeedArticle = ''; for (var i = 0;i<myFeedData.length;i++){ let item = myFeedData[i]; myFeedArticle +=` <div class="card-item flex-fill p-3"> <div class="d-flex flex-fill"> <div class="item-avatar mr-2" style="background-image:url(${item.avatar})"></div> <div class="item-sub d-flex flex-column p-1"> <div class="item-creator"><a href="${item.link}" target="_blank" rel="noopener nofollow" >${item.title}</a></div> <span class="myfeeds-floor">${item.floor}</span> <div class="item-mate mt-2 text-xs">${item.updated}</div> </div> </div> </div> `; } this.memoDom.innerHTML = `<div class="myfeeds-option row px-2 pb-2"> <div class="myfeeds-xml card-item px-3 py-2 mr-3" data-type="bfind" onclick="window.memosbbs._myFeedsXML(this)">BlogFinder</div> <div class="myfeeds-xml card-item px-3 py-2 mr-3" data-type="boyou" onclick="window.memosbbs._myFeedsXML(this)">博友圈</div> <div class="myfeeds-xml card-item px-3 py-2 mr-3" data-type="shinian" onclick="window.memosbbs._myFeedsXML(this)">十年之约</div> </div> <div class="myfeeds">${myFeedArticle}</div>`; window.Lately && Lately.init({ target: '.item-mate' }); }) }); this.memosTextarea.addEventListener('focus', () => { let nowTag = document.querySelector(".memos-tagnow-name") if(nowTag !== null && this.memosTextarea.value == ""){ this.memosTextarea.value = "#"+nowTag.textContent+" "; } }); //搜索 Memo this.searchBtn.addEventListener("click", () => { if(this.searchInput.classList.contains("d-none")){ this.userButton.classList.add("d-none") this.searchInput.classList.remove("d-none") this.searchInput.focus(); }else if(!this.searchInput.classList.contains("d-none") && this.searchInput.value == ""){ this.searchInput.classList.add("animate__fadeOutRight") setTimeout(() => { this.userButton.classList.remove("d-none") this.searchInput.classList.add("d-none") this.searchInput.classList.remove("animate__fadeOutRight") }, 500); }else if(this.searchInput.value !== ""){ this._searchNow(this.searchInput.value) } this.searchInput.addEventListener('keydown', (event) => { if (event.key === 'Enter') { this._searchNow(this.searchInput.value) } }); }); //显示订阅列表 this.userlistBtn.addEventListener("click", () => { let userlistDom = document.querySelector(".userlist"); if(userlistDom){ userlistDom.remove(); }else{ let userlistDom = `<div class="userlist card-item d-flex flex-wrap mb-3 animate__animated animate__fadeIn">`; for (var i = 0; i < this.memoList.length; i++) { let nowMemo = this.memoList[i] userlistDom += `<div onclick="window.memosbbs._getUserMemos('${nowMemo.link}', '${nowMemo.creatorId}','${nowMemo.creatorName.replace(/'/g, "’")}','${nowMemo.avatar}')" class="item-avatar" style="background-image:url(${nowMemo.avatar})"></div>` } userlistDom += `</div>`; this.memosDom.insertAdjacentHTML('beforebegin', userlistDom); } }); this.goHomeBtn.addEventListener("click", () => { window.localStorage && window.localStorage.setItem("memos-mode", "MEMOSHOME"); let tagnowHas = document.querySelector(".memos-tagnow") if(tagnowHas) tagnowHas.remove(); this._goHome(); }); this.goBbsBtn.addEventListener("click", () => { window.localStorage && window.localStorage.setItem("memos-mode", "MEMOSBBS"); let tagnowHas = document.querySelector(".memos-tagnow") if(tagnowHas) tagnowHas.remove(); this._goBbs() }); this.randomUserBtn.addEventListener("click", () => { window.localStorage && window.localStorage.setItem("memos-mode", "RANDUSER"); let tagnowHas = document.querySelector(".memos-tagnow") if(tagnowHas) tagnowHas.remove(); this._goRandUser(); }); this.memosOldSelect; this.editMemoBtn.addEventListener("click", () => { let dataformNow = JSON.parse(window.localStorage && window.localStorage.getItem("memos-editor-dataform")); let memoId = dataformNow.id; let memoRelationList = dataformNow.relationList; this.memosOpenId = window.localStorage && window.localStorage.getItem("memos-access-token"); let memoContent = this.memosTextarea.value; let memocreatedTs = dataformNow.createdTs; let memoVisibility = this.memosVisibilitySelect.value; let memoResourceList = window.localStorage && JSON.parse(window.localStorage.getItem("memos-resource-list")); if(this.memoChangeDate == 1){ memocreatedTs = Math.floor(Date.now() / 1000);; } let hasContent = memoContent.length !== 0; if (hasContent) { let memoUrl = `${this.memosPath}api/v1/memo/${memoId}`; let memoBody = {content:memoContent,id:memoId,createdTs:memocreatedTs,relationList:memoRelationList,resourceIdList:memoResourceList,visibility:memoVisibility} fetch(memoUrl, { method: 'PATCH', body: JSON.stringify(memoBody), headers: { 'Authorization': `Bearer ${this.memosOpenId}`, 'Content-Type': 'application/json' } }).then((res) => { if (res.ok) { let tagnowHas = document.querySelector(".memos-tagnow") if(tagnowHas) tagnowHas.remove(); cocoMessage.success( '修改成功', ()=>{ this.memosVisibilitySelect.value = this.memosOldSelect; this.memoChangeDate = 0; this._clearTextarea(); }) } }) } }); this.cancelEditBtn.addEventListener("click", () => { if (!this.editMemoDom.classList.contains("d-none")) { this.memosVisibilitySelect.value = this.memosOldSelect; window.localStorage && window.localStorage.removeItem("memos-editor-dataform"); this.editMemoDom.classList.add("d-none"); this.submitMemoBtn.classList.remove("d-none"); this._clearTextarea("cancel") } }); // 获取 owo.json 文件中的数据 this.emojiSelectorVisible = false; this.emojiSelector; this.emojis = [{"icon": "😂","text": "哭笑不得"},{"icon": "😎","text": "酷"},{"icon": "😏","text": "坏笑"},{"icon": "😅","text": "流汗"},{"icon": "😄","text": "笑"},{"icon": "😜","text": "调皮"},{"icon": "🤣","text": "笑倒"},{"icon": "😭","text": "大哭"},{"icon": "🙄","text": "白眼"},{"icon": "🤐","text": "嘘"},{"icon": "😋","text": "美食脸"},{"icon": "🥶","text": "冰冻"},{"icon": "🥵","text": "热"},{"icon": "😴","text": "睡觉"},{"icon": "🤧","text": "打喷嚏"},{"icon": "🍉","text": "西瓜"},{"icon": "😱","text": "惊恐"},{"icon": "👋","text": "招手"},{"icon": "🔨","text": "锤子"},{"icon": "🐶","text": "小狗"},{"icon": "👏","text": "鼓掌"},{"icon": "🙈","text": "不看"},{"icon": "😓","text": "汗"},{"icon": "😍","text": "爱心眼"},{"icon": "🤝","text": "握手"},{"icon": "🥺","text": "求你"},{"icon": "😔","text": "沮丧"},{"icon": "😪","text": "困"},{"icon": "😕","text": "困惑"},{"icon": "🤷♂️","text": "摊手"},{"icon": "😛","text": "舌头"},{"icon": "🤭","text": "偷笑"},{"icon": "🤮","text": "呕吐"},{"icon": "🥺","text": "求你"},{"icon": "🙂","text": "轻松的笑"},{"icon": "😈","text": "恶魔"},{"icon": "😃","text": "笑脸"},{"icon": "🤫","text": "嘘"},{"icon": "😒","text": "无语"},{"icon": "😵","text": "晕"},{"icon": "💪","text": "加油"},{"icon": "👍","text": "赞"},{"icon": "👎", "text": "踩"},{"icon": "😡","text": "愤怒"},{"icon": "🤬","text": "怒骂"},{"icon": "😖","text": "心烦"},{"icon": "🌹","text": "玫瑰"},{"icon": "🏃","text": "跑步"},{"icon": "😆","text": "大笑"},{"icon": "💵","text": "钞票"},{"icon": "😘","text": "飞吻"},{"icon": "😷","text": "生病"},{"icon": "🤕","text": "受伤"},{"icon": "🎉","text": "庆祝"},{"icon": "❤️","text": "红心"},{"icon": "💔","text": "心碎"},{"icon": "😣","text": "无奈"},{"icon": "😘","text": "飞吻"},{"icon": "💩","text": "一坨便便"},{"icon": "🤩","text": "爱慕"}]; // 表情选择器点击事件处理 this.biaoqingBtn.addEventListener("click", (event) => { event.stopPropagation(); this.emojiSelectorVisible = !this.emojiSelectorVisible; if (this.emojiSelectorVisible) { this._displayEmojiSelector(); } else { this.emojiSelector?.remove(); } }); this._backToTop(); // this._cfAiBtnClick(); if(this.cfwkAiUrl != null && this.cfwkAiUrl !== "") { this.cfAiBtn.addEventListener('click', async () => { this.cfAiBtn.classList.add("d-none","noclick") this.cfAiLoadBtn.classList.remove("d-none") try{ let textOld = this.memosTextarea.value let input = encodeURIComponent(this.memosTextarea.value) let fetchUrl = `${this.cfwkAiUrl}/?q=${input}` const source = new EventSource(fetchUrl); this.memosTextarea.value = `${textOld}\n----------\n` source.onmessage = (event) => { if(event.data=="[DONE]") { this.cfAiBtn.classList.remove("d-none","noclick") this.cfAiLoadBtn.classList.add("d-none") source.close(); return; } const data = JSON.parse(event.data); this.memosTextarea.value += data.response this.memosTextarea.style.height = this.memosTextarea.scrollHeight + 'px'; } } catch (error) { this.cfAiBtn.classList.add("d-none","noclick") this.cfAiLoadBtn.classList.remove("d-none") cocoMessage.error('已超时,请稍后再试~'); } }); } this.GeminiFetch = "https://lmm-api-gemini.deno.dev/v1/chat/completions"; }
_getTheme() { let getTheme = window.localStorage && window.localStorage.getItem("theme"); if (getTheme !== null && getTheme == "dark"){ document.body.classList.add("dark-theme","dark"); }else{ document.body.classList.remove("dark-theme","dark"); } if (getTheme == null && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { document.body.classList.add("dark-theme","dark"); } }
async _init() { // 获取自定义列表 let memoOurList; if(typeof memosJson !== 'undefined') { try { memoOurList = await this._getMemoListData(memosJson.url); // 获取自定义列表 } catch (error) { memoOurList = this.memoDefaultList } } else { try { memoOurList = await this._getMemoListData("https://memobbs.app/memos.json"); // 获取自定义列表 } catch (error) { memoOurList = this.memoDefaultList } } if(typeof this.memosMyList !== 'undefined') { const mergedArray = [...this.memosMyList, ...memoOurList]; this.memoList = mergedArray.filter((item, index) => { const stringifiedItem = JSON.stringify(item); return index === mergedArray.findIndex(obj => { return JSON.stringify(obj) === stringifiedItem; }); }); } else { this.memoList = memoOurList }
//查询当前页面 window.location.origin 作为主页展示 let memobbsAdmin = [] let memobbsLink = window.location.origin; let linkIndex = this.memoList.findIndex(item => (item.website == memobbsLink)) if(linkIndex >= 0){ memobbsAdmin.push(this.memoList[linkIndex]) const mergedArray2 = [...memobbsAdmin, ...this.memoList]; this.memoList = mergedArray2.filter((item, index) => { const stringifiedItem = JSON.stringify(item); return index === mergedArray2.findIndex(obj => { return JSON.stringify(obj) === stringifiedItem; }); }); }
this.nowLink = this.memosPath || this.memoList[0].link; if (!this.nowLink.endsWith('/')) { this.nowLink += '/'; } this.nowId = this.memosMeID || this.memoList[0].creatorId; this.nowName = this.memosMeNickname || this.memoList[0].creatorName; this.nowAvatar = this.memosMeAvatarUrl || this.memoList[0].avatar; this.nowV1 = this.memoList[0].v1 || 'memo' this._memoFollow(this.getMode); this._getEditIcon(); }
// 获取自定义 memos.json 订阅列表 async _getMemoListData(url) { const response = await fetch(url); const data = await response.json(); if(this.filterName){ let namesToRemove = this.filterName.replace(/,/g, ",").split(','); for (let name of namesToRemove) { let nameIndex = data.myMemoList.findIndex(item => (item.creatorName == name)); if (nameIndex !== -1) { delete data.myMemoList.splice(nameIndex, 1); } }; } return data.myMemoList }
_memoFollow(mode) { //记忆显示模式 this.usernowBtnDom.forEach((item) => {item.classList.remove('current');}) if(mode == "MEMOSHOME"){ this.goHomeBtn.classList.add("current") this._getUserMemos(this.nowLink,this.nowId,this.nowName,this.nowAvatar,"","","MEMOSHOME") }else if(mode == "MEMOSBBS"){ this.goBbsBtn.classList.add("current") this._getMemos(); }else if(mode == "RANDUSER"){ this.randomUserBtn.classList.add("current") this._goRandUser() }else if(mode == "NOPUBLIC"){ this._getUserMemos(this.nowLink,this.nowId,this.nowName,this.nowAvatar,"","",mode) }else if(mode == "oneday"){ this._getUserMemos(this.nowLink,this.nowId,this.nowName,this.nowAvatar,"","",mode) }else{ this.goHomeBtn.classList.add("current") this._getUserMemos(this.nowLink,this.nowId,this.nowName,this.nowAvatar,"","","") }
this.loadBtn.addEventListener("click", () => { if(this.page < this.dataNum) { this.page++; } this._updateData(this.memoData) cocoMessage.success("加载中"); }); }
async _getMemoCount(m) { let twikooData = m.filter(item => item.twikoo); if (twikooData.length !== 0) { let twikooRes = {}; for (const { creatorName, twikoo, link, id } of twikooData) { if (!twikooRes[creatorName]) { twikooRes[creatorName] = { creatorName, envId: twikoo, urls: [] }; } twikooRes[creatorName].urls.push(`${link}m/${id}`); } let twikooList = Object.values(twikooRes); let twikooPromise = await Promise.all( twikooList.map(async (item) => { try { let res = await twikoo.getCommentsCount({ envId: item.envId, urls: item.urls, includeReply: false }); return res; } catch (err) { console.error(err); return []; } }) ); this.twikooCount = twikooPromise.flatMap(r => r); } let artalkData = m.filter(item => item.artalk); if (artalkData.length !== 0) { let artalkRes = {}; for (const { creatorName, artalk, artSite, link, id } of artalkData) { if (!artalkRes[creatorName]) { artalkRes[creatorName] = { creatorName, envId: artalk, site_name: artSite, link, urls: [] }; } artalkRes[creatorName].urls.push(`/m/${id}`); } let artalkList = Object.values(artalkRes); let artalkPromise = await Promise.all( artalkList.map(async (item) => { try { let pageKeys = item.urls.join(','); let siteName = item.site_name; let response = await fetch(`${item.envId}/api/v2/stats/page_comment?page_keys=${pageKeys}&site_name=${siteName}`); if (!response.ok) { throw new Error(`Request failed`); } let results = await response.json(); let countList = item.urls.map(url => { let count = results.data[url] || 0; return { url: item.link + url, count }; }); return countList; } catch (err) { return []; } }) ) this.artalkCount = artalkPromise.flatMap(r => r); } for (const item of m) { let count = 0; let url = `${item.link}/m/${item.id}`; if (item.twikoo) { let memoCount = this.twikooCount.find((o) => o.url === url); if (memoCount) { count = memoCount.count; } } else if (item.artalk) { let memoCount = this.artalkCount.find((o) => o.url === url); if (memoCount) { count = memoCount.count; } } item.count = count; } return m; }
_updateData(res) { let oneDayTag = window.localStorage && window.localStorage.getItem("memos-oneday-tag"); if(oneDayTag !== null){ const firstItem = res.slice(0, 1); const restItems = res.slice(1); // 对后面的内容进行排序 restItems.sort((a, b) => b.createdTs - a.createdTs); // 将两部分合并在一起 const sortedArray = firstItem.concat(restItems); // 返回排序后的数组 this._pagination(sortedArray) this.dataNum = Math.ceil(sortedArray.length/this.limit); this.nums = this.dataNum - 1; if (this.page > this.nums) { this.loadBtn.classList.add('d-none'); return }; }else{ res.sort((i,o)=>{ return( o.createdTs - i.createdTs) }) this._pagination(res) this.dataNum = Math.ceil(res.length/this.limit); this.nums = this.dataNum - 1; if (this.page > this.nums) { this.loadBtn.classList.add('d-none'); return }; } }
_pagination(data) { this.memosStr = []; var last = this.page * this.limit - 1; last = last >= data.length ? (data.length - 1) : last; for (var i = (this.page * this.limit - this.limit); i <= last; i++) { this.memosStr.push(data[i]) }; this._updateHtml(this.memosStr); }
// 插入 html async _updateHtml(data) { let oneDayClass = "oneday"; let tagnowHas = document.querySelector(".memos-tagnow") this.memosMode = window.localStorage && window.localStorage.getItem("memos-mode"); let oneDayTag = window.localStorage && window.localStorage.getItem("memos-oneday-tag"); let result = '',itemOption = '',itemContent = ''; let TAG_REG = /#([^#\s!.,;:?"'()]+)(?= )/g, IMG_REG = /\!\[(.*?)\]\((.*?)\)/g, LINK_REG = /(?<!!)\[(.*?)\]\((.*?)\)/g, LINE_REG = /\n/g, BLOCKQUDTE_REG = /\>.*$/g, CODE_REG = /\```.*$/g, DOUDB_LINK_REG = /(https:\/\/(www|movie|book)\.douban\.com\/(game|subject)\/[0-9]+\/).*?/g, NEODB_LINK_REG = /(https:\/\/neodb\.social\/(game|movie|tv\/season|book)\/[0-9a-zA-Z]+)(?= )/g, BILIBILI_REG2 = /{ bilibili ([0-9a-zA-Z]+) }/g, BILIBILI_REG = /<a.*?href="https:\/\/www\.bilibili\.com\/video\/((av[\d]{1,10})|(BV([\w]{10})))\/?".*?>.*<\/a>/g, NETEASE_MUSIC_REG = /<a.*?href="https:\/\/music\.163\.com\/.*id=([0-9]+)".*?>.*<\/a>/g, QQMUSIC_REG = /<a.*?href="https\:\/\/y\.qq\.com\/.*(\/[0-9a-zA-Z]+)(\.html)?".*?>.*?<\/a>/g, QQVIDEO_REG = /<a.*?href="https:\/\/v\.qq\.com\/.*\/([a-z|A-Z|0-9]+)\.html".*?>.*<\/a>/g, YOUKU_REG = /<a.*?href="https:\/\/v\.youku\.com\/.*\/id_([a-z|A-Z|0-9|==]+)\.html".*?>.*<\/a>/g, YOUTUBE_REG = /<a.*?href="https:\/\/www\.youtube\.com\/watch\?v\=([a-z|A-Z|0-9]{11})\".*?>.*<\/a>/g, APLAYER_REG = /\{aplayer:[^}]+\}/g, SONG_TITLE_REG = /(?<=title:)[^;]+/i, SONG_ARTIST_REG = /(?<=artist:)[^;]+/i, SONG_COVER_REG = /(?<=cover:)[^;]+/i, APLAYER_SERVER_REG = /(?<=server:)([^;]+)/i, APLAYER_ID_REG = /(?<=id:)[^}]+/i, APLAYER_TYPE_REG = /(?<=type:)[^;]+/i;
marked.setOptions({ breaks: true, smartypants: false, langPrefix: 'language-' }); for (var i = 0; i < data.length; i++) { let memo = data[i]; let link = memo.link; if (!link.endsWith('/')) { link += '/'; } let memoString = JSON.stringify(memo).replace(/"/g, '"'); let avatar = memo.avatar; let count = memo.count || ""; let website = memo.website; let creatorId = memo.creatorId; let creatorName = memo.creatorName; let createdTs = memo.createdTs; let in2Week = Math.floor(new Date().getTime()/ 1000) - createdTs <= 1209600 ? "in2week" : "out2week"; let memosId = createdTs+memo.id; let memosVisibility = memo.visibility let twikooEnv = memo.twikoo; let artalkEnv = memo.artalk; let artSite = `${memo.artSite}`; let memosLink = link + "m/" + (memo.uid || memo.name || memo.id); let memosRes = memo.content .replace(TAG_REG, "") .replace(IMG_REG, "") .replace(DOUDB_LINK_REG, "") .replace(NEODB_LINK_REG, "") .replace(LINK_REG, `<a class='primary' href='$2' target='_blank'>$1</a>`) memosRes = marked.parse(memosRes) .replace(BILIBILI_REG, `<div class='video-wrapper'><iframe src='//player.bilibili.com/player.html?autoplay=0&bvid=$1' scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div>`) .replace(BILIBILI_REG2, `<div class='video-wrapper'><iframe src='//player.bilibili.com/player.html?autoplay=0&bvid=$1' scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div>`) .replace(NETEASE_MUSIC_REG, `<meting-js auto='https://music.163.com/#/song?id=$1'></meting-js>`) .replace(QQMUSIC_REG, `<meting-js auto='https://y.qq.com/n/yqq/song$1.html'></meting-js>`) .replace(QQVIDEO_REG, `<div class='video-wrapper'><iframe src='//v.qq.com/iframe/player.html?vid=$1' allowFullScreen='true' frameborder='no'></iframe></div>`) .replace(YOUKU_REG, `<div class='video-wrapper'><iframe src='https://player.youku.com/embed/$1' frameborder=0 'allowfullscreen'></iframe></div>`) .replace(YOUTUBE_REG, `<div class='video-wrapper'><iframe src='https://www.youtube.com/embed/$1' title='YouTube video player' frameborder='0' allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture' allowfullscreen title='YouTube Video'></iframe></div>`) .replace(APLAYER_REG, ""); let transData = memo.content.replace(TAG_REG, "").replace(IMG_REG, "").replace(LINK_REG, "$1").replace(LINE_REG, " ").replace(BLOCKQUDTE_REG, "").replace(CODE_REG, ""); if(transData.length>140){transData = transData.substring(0,140) + '...'}; let memosForm = {creatorName:creatorName,content:transData,url:memosLink}; let memosFormString = JSON.stringify(memosForm).replace(/"/g, '"'); //解析 content 内 md 格式图片 let imgArr = memo.content.match(IMG_REG); let imgStr = String(imgArr).replace(/[,]/g, ''); if (imgArr) { let memosImg = imgStr.replace(IMG_REG, `<div class="memo-resource width-100"><img class="lozad" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-src="$2"></div>`) memosRes += `<div class="resource-wrapper"><div class="images-wrapper my-2" view-image>${memosImg}</div></div>` } // aplayer let aplayerArr = memo.content.match(APLAYER_REG); let musicDom = ''; if (aplayerArr) { for(let x=0;x < aplayerArr.length;x++){ let server = APLAYER_SERVER_REG.exec(aplayerArr[x]), type = APLAYER_TYPE_REG.exec(aplayerArr[x]), id = APLAYER_ID_REG.exec(aplayerArr[x]), cover = SONG_COVER_REG.exec(aplayerArr[x]), title = SONG_TITLE_REG.exec(aplayerArr[x]), artist = SONG_ARTIST_REG.exec(aplayerArr[x]) musicDom += `<button class="bber-music" onclick="sco.changePlaylist('${server[0]}', '${type}', '${id}')" data-pjax-state=""><div class="bber-music-wrap"><div class="bber-music-pic" style="background: url("${cover}") center/contain no-repeat"></div><div class="bber-music-info"><div class="bber-music-title">${title}</div><div class="bber-music-artist">${artist}</div></div></div><svg fill="#000000" width="800px" height="800px" viewBox="-5.5 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M5.688 9.656v10.906c-0.469-0.125-0.969-0.219-1.406-0.219-1 0-2.031 0.344-2.875 0.906s-1.406 1.469-1.406 2.531c0 1.125 0.563 1.969 1.406 2.531s1.875 0.875 2.875 0.875c0.938 0 2-0.313 2.844-0.875s1.375-1.406 1.375-2.531v-11.438l9.531-2.719v7.531c-0.438-0.125-0.969-0.188-1.438-0.188-0.969 0-2.031 0.281-2.875 0.844s-1.375 1.469-1.375 2.531c0 1.125 0.531 2 1.375 2.531 0.844 0.563 1.906 0.906 2.875 0.906 0.938 0 2.031-0.344 2.875-0.906 0.875-0.531 1.406-1.406 1.406-2.531v-14.406c0-0.688-0.469-1.156-1.156-1.156-0.063 0-0.438 0.125-1.031 0.281-1.25 0.344-3.125 0.875-5.25 1.5-1.094 0.281-2.063 0.594-3.031 0.844-0.938 0.281-1.75 0.563-2.469 0.75-0.75 0.219-1.219 0.344-1.406 0.406-0.5 0.156-0.844 0.594-0.844 1.094z"></path></svg></button>` } } // DoubanDB let doudbArr = memo.content.match(DOUDB_LINK_REG); let neodbDom = ''; if(doudbArr){ for(let k=0;k < doudbArr.length;k++){ neodbDom += await this._fetchNeoDB(doudbArr[k],"douban") } } // DoubanDB let neodbArr = memo.content.match(NEODB_LINK_REG); if(neodbArr){ for(let l=0;l < neodbArr.length;l++){ neodbDom += await this._fetchNeoDB(neodbArr[l],"neodb") } } //标签 let tagArr = memo.content.match(TAG_REG); let memosTag = ''; if (tagArr) { memosTag = tagArr.map(t=>{ return `<div class="item-tag d-flex align-items-center text-sm line-xl mr-2 px-2" onclick="window.memosbbs._getTagNow('${link}','${creatorId}','${creatorName}','${avatar}',this)">${String(t).replace(/[#]/, '')}</div>`; }).join(''); }else{ memosTag = `<div class="item-tag d-flex align-items-center text-sm line-xl mr-2 px-2 no-cursor">动态</div>`; }
//解析内置资源文件 if (memo.resourceList && memo.resourceList.length > 0) { let resourceList = memo.resourceList; let imgUrl = '',resUrl = '',resImgLength = 0; for (let j = 0; j < resourceList.length; j++) { let restype = resourceList[j].type.slice(0, 5); let resexlink = resourceList[j].externalLink; let imgLink = '', fileId = ''; if (resexlink) { imgLink = resexlink } else { fileId = resourceList[j].id; if(resourceList[j].uid !== undefined){ fileId = resourceList[j].uid }else if(resourceList[j].name !== undefined){ fileId = resourceList[j].name+"?thumbnail=1" } imgLink = `${link}o/r/${fileId}`; } if (restype == 'image') { imgUrl += `<div class="memo-resource w-100"><img class="lozad" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-src="${imgLink}"/></div>`; resImgLength = resImgLength + 1 } if (restype == 'video') { resUrl += `<video style="width:100%;max-height:50vh;" crossorigin="anonymous" src="${imgLink}" controls=""></video>` } if (restype !== 'video' && restype !== 'image') { resUrl += `<a class="memos-tag p-1" target="_blank" rel="noreferrer" href="${imgLink}">${resourceList[j].filename}</a>`; } } if (imgUrl) { memosRes += `<div class="resource-wrapper"><div class="images-wrapper my-2" view-image>${imgUrl}</div></div>` } if (resUrl) { memosRes += `<p class="datasource">${resUrl}</p>` } } this.memosOpenId = window.localStorage && window.localStorage.getItem("memos-access-token"); if (this.memosOpenId != null && this.memosOpenId !== "" && this.nowId == creatorId && this.nowLink == link) { itemOption = `<div class="item-option mr-1"><div class="d-flex dropdown"><svg xmlns="http://www.w3.org/2000/svg" width="1.15rem" height="1.15rem" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></g></svg><div class="dropdown-wrapper d-none"><a class="btn edit-btn" data-form="${memoString}" onclick="window.memosbbs._editMemo(this)">编辑</a><a class="btn arch-btn" onclick="window.memosbbs._archiveMemo('${memo.id}')">归档</a><a class="btn del-btn" onclick="window.memosbbs._deleteMemo('${memo.id}')">删除</a></div></div></div>`; }else if (this.memosOpenId != null && this.memosOpenId !== "") { itemOption = `<div class="item-option mr-1"> <div class="d-flex dropdown"> <svg xmlns="http://www.w3.org/2000/svg" width="1.15rem" height="1.15rem" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></g></svg> <div class="dropdown-wrapper d-none"> <a class="btn sav-btn" data-form="${memoString}" onclick="window.memosbbs._saveMemo(this)">收藏</a> <a class="btn via-btn" data-form="${memoString}" onclick="window.memosbbs._viaNow(this)">引用</a> <a class="btn jump-btn" href="${memosLink}" target="_blank" rel="noopener noreferrer">跳转</a> </div> </div> </div>`; }else{ itemOption = `<div class="item-option mr-1"><a class="d-flex" href="${memosLink}" target="_blank" rel="noopener noreferrer"><svg xmlns="http://www.w3.org/2000/svg" width="1.15rem" height="1.15rem" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6m4-3h6v6m-11 5L21 3"></path></svg></a></div>`; } itemContent = `<div class="item-content"><div class="item-inner">${memosRes+musicDom}</div><div class="item-footer d-flex mt-2"><div class="d-flex">${memosTag}</div>`; if (twikooEnv && memosVisibility == "PUBLIC") { itemContent += `<div class="d-flex flex-fill justify-content-end"><div class="item d-flex align-items-center"><a data-id="${memo.id}" data-time="${createdTs}" data-env="${twikooEnv}" data-path="${memosLink}" onclick="window.memosbbs._loadTwikoo(this)" rel="noopener noreferrer" class="d-flex twikoo-btn"><svg xmlns="http://www.w3.org/2000/svg" width="1.25rem" height="1.25rem" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2zM8 10h.01M12 10h.01M16 10h.01"/></svg></a><span class="ml-1">${count}</span></div></div></div><div id="${memosId}" class="item-comment mt-3 d-none"></div>`; } else if (artalkEnv && memosVisibility == "PUBLIC") { itemContent += `<div class="d-flex flex-fill justify-content-end"><div class="item d-flex align-items-center"><a data-id="${memo.id}" data-time="${createdTs}" data-env="${artalkEnv}" data-path="${artSite}" onclick="window.memosbbs._loadArtalk(this)" rel="noopener noreferrer" class="d-flex artalk-btn"><svg xmlns="http://www.w3.org/2000/svg" width="1.25rem" height="1.25rem" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2zM8 10h.01M12 10h.01M16 10h.01"/></svg></a><span class="ml-1">${count}</span></div></div></div><div id="${memosId}" class="item-comment mt-3 d-none"></div>`; } else if(memosVisibility !== "PUBLIC"){ itemContent += `<div class="d-flex flex-fill justify-content-end"><div class="item d-flex align-items-center mr-1 pri-btn" onclick="window.memosbbs._getUserMemos('${link}','${creatorId}','${creatorName}','${avatar}','','','NOPUBLIC')"><svg xmlns="http://www.w3.org/2000/svg" width="1.15rem" height="1.15rem" viewBox="0 0 14 14"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="M1.68 4.206C2.652 6.015 4.67 7.258 7 7.258c2.331 0 4.348-1.243 5.322-3.052M2.75 5.596L.5 7.481m4.916-.415L4.333 9.794m6.917-4.198l2.25 1.885m-4.92-.415l1.083 2.728"/></svg></div></div></div>`; } else { itemContent += `<div class="d-flex flex-fill justify-content-end"></div></div>`; } itemContent += `</div></div></div>` result = `<div class="${this.memosMode == "MEMOSHOME" && tagnowHas == null &&oneDayTag !== null && i == 0 ? oneDayClass : ''} memo-${memosId} d-flex animate__animated mb-3 memos-item"><div class="card-item flex-fill p-3"><div class="item-header d-flex mb-3"><div class="d-flex flex-fill"><div class="item-avatar mr-2" style="background-image:url(${avatar})"></div><div class="item-sub d-flex flex-column p-1"><div class="item-creator"><a ${website !== undefined ? 'href=\"' + website + '\"': ''} target="_blank">${creatorName}</a></div><div class="item-mate ${in2Week} mt-2 text-xs">${new Date(createdTs * 1000 - 5 ).toLocaleString()}</div></div></div>${itemOption}</div>${neodbDom+itemContent}</div></div>`; this.memoDom.insertAdjacentHTML('beforeend', result);
//循环绑定事件,替代元素内onclick方法 update: 放弃了,如果有更好的办法的话请告诉我吧,谢谢! let queryAvatarList = document.querySelectorAll('#memo-list .item-avatar'), lastAvatar = queryAvatarList[queryAvatarList.length - 1]; lastAvatar.addEventListener('click', () => {this._getUserMemos(link, creatorId, creatorName, avatar)}); } // end for
this.loadBtn.textContent = "加载更多"; function animation() { var animate = document.getElementsByClassName("animate__animated"); Array.prototype.slice.call(animate,0).forEach((i,index) => { const top = i.getBoundingClientRect().top; // 目标元素dom距离顶部的高度 if (top <= window.innerHeight) { // 当top小于等于文档显示区域的高时,就进入可视区域了 i.classList.contains('animate__fadeIn"') ? '' : i.classList.add("animate__fadeIn") } }) } animation();
window.addEventListener('scroll', animation); //图片灯箱 window.ViewImage && ViewImage.init('.images-wrapper img') //相对时间 window.Lately && Lately.init({ target: '.item-mate.in2week' }); //延迟加载 let observer = lozad('.lozad'); observer.observe(); //下拉菜单 let dropdowns = document.querySelectorAll(".dropdown"); Array.from(dropdowns).forEach((dropdown) => { let lis = Array.from(dropdown.children).slice(1); dropdown.addEventListener("mouseenter", () => { lis.forEach((item) => { item.classList.remove("d-none"); }); }); dropdown.addEventListener("mouseleave", () => { lis.forEach((item) => { item.classList.add("d-none"); }); }); }); }
_withTimeout(millis, promise) { let timeout = new Promise((resolve, reject) => setTimeout(() => reject(`Timed out after ${millis} ms.`), millis) ); return Promise.race([promise, timeout]); };
async _getMemos(search) { this.memoData = [], this.memoCreatorMap = {}, this.page = 1, this.nums = 0, this.dataNum = 0, this.memosContType = 0, this.memosAccess = 0; this.memoDom.innerHTML = this.skeleton; this.loadBtn.classList.add("d-none"); let results; if(search && search != "" && search != null ){ results = await Promise.allSettled(this.memoList.map(u => { let uLink = u.link if (!uLink.endsWith('/')) { uLink += '/'; } const fetchUrl = `${uLink}api/v1/memo?creatorId=${u.creatorId}&content=${search}&rowStatus=NORMAL&limit=${this.limit}`; return this._withTimeout(2000, fetch(fetchUrl) .then(response => { if (!response.ok) { throw new Error(response.statusText); } return response.json(); }) ); })); }else{ results = await Promise.allSettled(this.memoList.map(async(u) => { let matchedMemo = this.memoList.find(item => item.link === u.link); let matchedV1 = matchedMemo ? matchedMemo.v1 : undefined; let fetchUrl; let uLink = u.link if (!uLink.endsWith('/')) { uLink += '/'; } if (matchedV1) { const filter = `creator=='users/${matchedMemo.creatorId}'&&visibilities==['PUBLIC']` fetchUrl = `${uLink}api/v1/memos?pageSize=${this.limit}&filter=${encodeURIComponent(filter)}` }else{ fetchUrl = `${uLink}api/v1/memo?creatorId=${u.creatorId}&rowStatus=NORMAL&limit=${this.limit}`; }
const response = await this._withTimeout(2000, fetch(fetchUrl)); if (!response.ok) { throw new Error(response.statusText); } const data = await response.json(); const memosData = matchedV1 ? data.memos : data;
memosData.forEach(item => { if (matchedV1 && item.createTime) { item.createdTs = Math.floor(new Date(item.createTime).getTime() / 1000); } for (let key in matchedMemo) { if (matchedMemo.hasOwnProperty(key)) { item[key] = matchedMemo[key]; } } }); return memosData })); } results = results.filter(i => i.status === 'fulfilled'); this.memoData = results.flatMap(result => result.value);
//this.memoData = await getMemoCount(this.memoData); this.memoDom.innerHTML = ""; this._updateData(this.memoData); setTimeout(() => { this.loadBtn.classList.remove('d-none'); }, 1000); //setTimeout(() => { window.scrollTo({ top: this.usernowDom.offsetTop - 30, behavior: "smooth" }); //}, 800); this.goBbsBtn.classList.remove("noclick") }
_myFeedsXML(e){ this.loadBtn.classList.add('d-none'); let myfeedsDom = document.querySelector(".myfeeds") document.querySelectorAll('.myfeeds-xml').forEach((item) => { item.classList.add('noclick'); item.classList.remove('current'); }) e.classList.add("current") let type = e.getAttribute("data-type") myfeedsDom.innerHTML = "" let myFeedArticle = '',entries; myfeedsDom.innerHTML = this.skeleton; if(type=="bfind"){ fetch('https://cors.memobbs.app/https://bf.zzxworld.com/feed.xml').then(response => response.text()).then(str => new window.DOMParser().parseFromString(str, 'text/xml')) .then(data => { entries = Array.from(data.querySelectorAll('entry')).map(entry => { return { title: entry.querySelector('title').textContent, link: entry.querySelector('link').getAttribute('href'), published: entry.querySelector('published').textContent, creator: entry.querySelector('author name').textContent }; }); var myFeedArticle = ''; for (var i = 0;i<20;i++){ let item = entries[i]; myFeedArticle +=` <div class="card-item flex-fill p-3"> <div class="d-flex flex-fill"> <div class="item-avatar mr-2 face" style="background-image:url('https://favicon.memobbs.app?url=${item.link}')"></div> <div class="item-sub d-flex flex-column p-1"> <div class="item-creator"><a href="${item.link}" target="_blank" rel="noopener nofollow" >${item.title}</a></div> <span class="myfeeds-floor">${i+1}</span> <div class="item-mate mt-2 text-xs">${item.published}</div> </div> </div> </div> `; myfeedsDom.innerHTML = myFeedArticle } document.querySelectorAll('.myfeeds-xml').forEach((item) => {item.classList.remove('noclick');}) window.Lately && Lately.init({target: '.item-mate'}); }); } if(type=="boyou"){ fetch("https://www.boyouquan.com/feed.xml").then(response => response.text()).then(str => new window.DOMParser().parseFromString(str, 'text/xml')) .then(data => { entries = Array.from(data.querySelectorAll('item')).map(entry => { return { title: entry.querySelector('title').textContent, link: decodeURIComponent(entry.querySelector('link').textContent.replace('https://www.boyouquan.com/go?from=feed&link=',"")), published: entry.getElementsByTagName('dc:date')[0].textContent, creator: entry.getElementsByTagName('dc:creator')[0].textContent }; }); for (var i = 0;i<20;i++){ let item = entries[i]; myFeedArticle +=` <div class="card-item flex-fill p-3"> <div class="d-flex flex-fill"> <div class="item-avatar mr-2 face" style="background-image:url('https://favicon.memobbs.app?url=${item.link}')"></div> <div class="item-sub d-flex flex-column p-1"> <div class="item-creator"><a href="${item.link}" target="_blank" rel="noopener nofollow" >${item.title}</a></div> <span class="myfeeds-floor">${i+1}</span> <div class="item-mate mt-2 text-xs">${item.published}</div> </div> </div> </div> `; myfeedsDom.innerHTML = myFeedArticle } document.querySelectorAll('.myfeeds-xml').forEach((item) => {item.classList.remove('noclick');}) window.Lately && Lately.init({target: '.item-mate'}); }); } if(type=="shinian"){ fetch("https://www.foreverblog.cn/api/v1/blog/feeds?page=1").then(res => res.json()).then(resdata =>{ for (var i = 0;i<20;i++){ let item = resdata.data.data[i]; myFeedArticle +=` <div class="card-item flex-fill p-3"> <div class="d-flex flex-fill"> <div class="item-avatar mr-2" style="background-image:url(https://gravatar.loli.net/avatar/${item.email})"></div> <div class="item-sub d-flex flex-column p-1"> <div class="item-creator"><a href="${item.link}" target="_blank" rel="noopener nofollow" >${item.title}</a></div> <span class="myfeeds-floor">${i+1}</span> <div class="item-mate mt-2 text-xs">${item.created_at}</div> </div> </div> </div> `; myfeedsDom.innerHTML = myFeedArticle } document.querySelectorAll('.myfeeds-xml').forEach((item) => {item.classList.remove('noclick');}) window.Lately && Lately.init({target: '.item-mate'}); }); } }
//标签筛选且输入框为空,自动插入标签 _memosTextareaFocus() { let nowTag = document.querySelector(".memos-tagnow-name") if(nowTag !== null && this.memosTextarea.value == ""){ this.memosTextarea.value = "#"+nowTag.textContent+" "; } };
_searchNow(serchText){ if(serchText !== ""){ let tagnowHas = document.querySelector(".memos-tagnow") if(tagnowHas) tagnowHas.remove(); let usernowName = document.querySelector(".user-now-name").innerHTML; let serchDom = ` <div class="memos-tagnow row p-2 mb-2"> <div class="memos-tagnow-title mr-3">当前搜索b:</div> <div class="memos-tagnow-name card-item pr-2 pl-2" onclick="window.memosbbs._reloadUser('search')">${serchText}<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-auto ml-1 opacity-40"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg></div> </div>` this.memosDom.insertAdjacentHTML('beforebegin', serchDom); if(usernowName == ""){ this._getMemos(serchText) }else{ let userNameIndex = this.memoList.findIndex(item => (item.creatorName == usernowName)); if(userNameIndex == -1){ this._getUserMemos(this.nowLink,this.nowId,this.nowName,this.nowAvatar,"",serchText) }else{ let userNowData = this.memoList[userNameIndex] this._getUserMemos(userNowData.link,userNowData.creatorId,userNowData.creatorName,userNowData.avatar,"",serchText) } } this.searchInput.value = ''
this.searchInput.classList.add("animate__fadeOutRight") setTimeout(() => { this.userButton.classList.remove("d-none") this.searchInput.classList.add("d-none") this.searchInput.classList.remove("animate__fadeOutRight") }, 500); } }
//返回个人主页 _goHome(){ this.goHomeBtn.classList.add("noclick") this.usernowBtnDom.forEach((item) => {item.classList.remove('current');}) this.goHomeBtn.classList.add("current") this.goBbsBtn.classList.remove("current") this.randomUser = 0; this._getUserMemos(this.nowLink,this.nowId,this.nowName,this.nowAvatar) cocoMessage.success("Hi, "+this.nowName); };
//切换为广场模式 _goBbs(){ this.goBbsBtn.classList.add("noclick") this.usernowBtnDom.forEach((item) => {item.classList.remove('current');}) this.goBbsBtn.classList.add("current") this.goHomeBtn.classList.remove("current") this._getMemos(); let usernowName = document.querySelector(".user-now-name"); let usernowAvatar = document.querySelector(".user-now-avatar"); usernowName.innerHTML = ""; usernowAvatar.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; //this.goBbsBtn.classList.remove("noclick") cocoMessage.success("有啥新鲜事儿?"); };
//随机个人 _goRandUser(){ this.randomUser = 1; this.usernowBtnDom.forEach((item) => {item.classList.remove('current');}) this.randomUserBtn.classList.add("current") let usernowName = document.querySelector(".user-now-name"); let usernowAvatar = document.querySelector(".user-now-avatar"); usernowName.innerHTML = "" usernowAvatar.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" let randomIndex = Math.round(Math.random() * (this.memoList.length - 1)); let userNowData = this.memoList[randomIndex] this._getUserMemos(userNowData.link,userNowData.creatorId,userNowData.creatorName,userNowData.avatar,"","") cocoMessage.success(userNowData.creatorName+" 上线~"); }
//重载当前 user _reloadUser(mode){ let tagnowHas = document.querySelector(".memos-tagnow") if(tagnowHas) tagnowHas.remove(); let usernowName = document.querySelector(".user-now-name").innerHTML; if(usernowName == ""){ this._getMemos() }else{ let userNameIndex = this.memoList.findIndex(item => (item.creatorName == usernowName)); if(userNameIndex == -1){ this._getUserMemos(this.nowLink,this.nowId,this.nowName,this.nowAvatar) }else{ let userNowData = this.memoList[userNameIndex] this._getUserMemos(userNowData.link,userNowData.creatorId,userNowData.creatorName,userNowData.avatar) } } if(mode == "search"){ this.memosTextarea.value = ''; } }
// 获取指定用户列表 async _getUserMemos(link,id,name,avatar,tag,search,mode,random) { let matchedMemo = this.memoList.find(item => (item.link === link)) let matchedV1 = matchedMemo ? matchedMemo.v1 : undefined; this.memoDom.innerHTML = this.skeleton; this.loadBtn.classList.add('d-none'); this.randomUserBtn.classList.add("noclick"); this.memoData = [],this.memoCreatorMap = {}, this.page = 1,this.nums = 0,this.dataNum = 0,this.memosContType = 1; this.memosPath = window.localStorage && window.localStorage.getItem("memos-access-path"); let usernowName = document.querySelector(".user-now-name"); let usernowAvatar = document.querySelector(".user-now-avatar"); usernowName.innerHTML = name; usernowAvatar.src = avatar; if (!link.endsWith('/')) { link += '/'; } if (this.memosPath && !this.memosPath.endsWith('/')) { this.memosPath += '/'; } if (link == this.memosPath) { this.memosAccess = 1; }; let userMemoUrl; if(tag && (random == null || random == "" )){ userMemoUrl = `${link}api/v1/memo?creatorId=${id}&tag=${tag}&rowStatus=NORMAL&limit=50`; }else if(search){ userMemoUrl = `${link}api/v1/memo?creatorId=${id}&content=${search}&rowStatus=NORMAL&limit=${this.limit}`; }else if(mode == "NOPUBLIC"){ userMemoUrl = `${link}api/v1/memo`; }else if(random){ if(tag){ userMemoUrl = `${link}api/v1/memo?tag=${tag}&limit=1&offset=${random}`; }else{ userMemoUrl = `${link}api/v1/memo?&limit=1&offset=${random}`; } }else{ if (matchedV1) { const filter = `creator=='users/${id}'&&visibilities==['PUBLIC']` userMemoUrl = `${link}api/v1/memos?pageSize=50&filter=${encodeURIComponent(filter)}` }else{ userMemoUrl = `${link}api/v1/memo?creatorId=${id}&rowStatus=NORMAL&limit=50`; } }
if (link == this.memosPath) { try { let response = await fetch(userMemoUrl,{ headers: { 'Authorization': `Bearer ${this.memosOpenId}`, 'Content-Type': 'application/json', 'Cache-Control': 'no-cache', }, cache: 'no-store', }); if (response.ok) { let data = await response.json(); if(this.nowV1 == "memos"){ data = data.memos } let oneDayTag = window.localStorage && window.localStorage.getItem("memos-oneday-tag"); let oneDayTagCount = window.localStorage && window.localStorage.getItem("memos-oneday-count"); if( oneDayTag !== null && oneDayTagCount !== null && !search ){ let randomOneNum = Math.floor(Math.random() * oneDayTagCount) let oneDayUrl = `${link}api/v1/memo?tag=${oneDayTag}&limit=1&offset=${randomOneNum}` try { let responseOne = await fetch(oneDayUrl,{ headers: { 'Authorization': `Bearer ${this.memosOpenId}`, 'Content-Type': 'application/json', 'Cache-Control': 'no-cache', }, cache: 'no-store', }); if (!responseOne.ok) { throw new Error(`Request failed oneDay`); } dataone = await responseOne.json(); data.splice(0, 0, ...dataone); } catch (error) { console.error(error); } } data.forEach(item => { item.avatar = this.memosMeAvatarUrl item.link = this.memosPath item.twikoo = this.memosMeTwikoo item.artalk = this.memosMeArtalk item.artSite = `${this.memosMeArtalkSite}` }); if (mode == "NOPUBLIC") { let memosCount = data.length; window.localStorage && window.localStorage.setItem("memos-response-count", memosCount); data = data.filter((item) => item.visibility !== "PUBLIC"); } this.memoData = data.flatMap(result => result); if(this.nowV1 == "memos"){ let creatorName = name let creatorId = id let linkFind = this.memoList.find(item => (item.link == link)); let website = linkFind ? linkFind.website : undefined; this.memoData = this.memoData.map(item => { let cTime = new Date(item.createTime) let createdTs = Math.floor(cTime.getTime() / 1000); return {...item, creatorName,avatar,createdTs,creatorId,link,website}; }); }else{ this.memoList.forEach(item => { this.memoCreatorMap[item.creatorName] = item; }); this.memoData = this.memoData.map(item => { let data = this.memoCreatorMap[item.creatorName]; return {...item, ...data}; }); } if (mode !== "NOPUBLIC") { this.memoData = await this._getMemoCount(this.memoData); } this.memoDom.innerHTML = ""; this._updateData(this.memoData); if(!random && this.memoData.length >= 8 ){ setTimeout(() => { this.loadBtn.classList.remove('d-none'); }, 1000); } } } catch (error) { console.error(error); } }else{ try { let response = await fetch(userMemoUrl); if (!response.ok) { throw new Error(response.statusText); } let data = await response.json(); if(matchedV1){ data = data.memos let creatorName = name let creatorId = id let linkFind = this.memoList.find(item => (item.link == link)); let website = linkFind ? linkFind.website : undefined; this.memoData = data.flatMap(result => result); this.memoData = this.memoData.map(item => { let cTime = new Date(item.createTime) let createdTs = Math.floor(cTime.getTime() / 1000); return {...item, creatorName,avatar,createdTs,creatorId,link,website}; }); }else{ this.memoData = data.flatMap(result => result); this.memoList.forEach(item => { this.memoCreatorMap[item.creatorName] = item; }); this.memoData = this.memoData.map(item => { let data = this.memoCreatorMap[item.creatorName]; return {...item, ...data}; }); } this.memoData = await this._getMemoCount(this.memoData); this.memoDom.innerHTML = ""; this._updateData(this.memoData); if(this.memoData.length >= 8 ){ setTimeout(() => { this.loadBtn.classList.remove('d-none'); }, 1000); } } catch (error) { console.error(error); } } setTimeout(() => { this.goHomeBtn.classList.remove("noclick") this.randomUserBtn.classList.remove("noclick") }, 800); window.scrollTo({ top: this.usernowDom.offsetTop - 30, behavior: "smooth" }); } // Fetch NeoDB async _fetchNeoDB(url,mode){ let urlNow; if(mode == "douban"){ urlNow = "https://api-neodb.immmmm.com/?url="+url }else if(mode = "neodb"){ urlNow = url.replace("social/","social/api/") } let response = await fetch(urlNow); let dbFetch = await response.json(); let neodbDom = `<div class="db-card"> <div class="db-card-subject"> <div class="db-card-post"><img loading="lazy" decoding="async" referrerpolicy="no-referrer" src="https://cors.immmmm.com/${dbFetch.cover_image_url}"></div> <div class="db-card-content"> <div class="db-card-title"><a href="${url}" class="cute" target="_blank" rel="noreferrer">${dbFetch.title}</a></div> <div class="rating"><span class="allstardark"><span class="allstarlight" style="width:${dbFetch.rating*10}%"></span></span><span class="rating_nums">${dbFetch.rating}</span></div> <div class="db-card-abstract">${dbFetch.brief}</div> </div> <div class="db-card-cate">${dbFetch.category}</div> </div> </div>` return neodbDom } //获取指定 Tag _getTagNow(u,i,n,a,e){ let tagnowHas = document.querySelector(".memos-tagnow") if(tagnowHas) tagnowHas.remove(); let tagName = e.innerHTML let tagnowDom = ` <div class="memos-tagnow row p-2 mb-2"> <div class="memos-tagnow-title mr-3">标签筛选:</div> <div class="memos-tagnow-name card-item pr-2 pl-2" onclick="window.memosbbs._reloadUser()">${tagName}<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-auto ml-1 opacity-40"><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg></div> </div>` this.memosDom.insertAdjacentHTML('beforebegin', tagnowDom); this._getUserMemos(u,i,n,a,tagName); }
// 加载Twikoo评论 _loadTwikoo(i) { let twikooEnv = i.getAttribute("data-env") let twikooPath = i.getAttribute("data-path") let twikooId = i.getAttribute("data-id") let twikooTime = i.getAttribute("data-time") let twikooDom = document.getElementById(`${Number(twikooTime)+Number(twikooId)}`); let twikooCon = "<div id='twikoo'></div>" if (twikooDom.classList.contains('d-none')) { document.querySelectorAll('.item-comment').forEach((item) => {item.classList.add('d-none');}) if(document.getElementById("twikoo")){ document.getElementById("twikoo").remove() } twikooDom.insertAdjacentHTML('beforeend', twikooCon); twikooDom.classList.remove('d-none'); twikoo.init({ envId: twikooEnv, el: '#twikoo', path: twikooPath }); }else{ twikooDom.classList.add('d-none'); document.getElementById("twikoo").remove() } }
// 加载Artalk评论 _loadArtalk(e) { let artalkEnv = e.getAttribute("data-env") let artalkPath= e.getAttribute("data-path") let artalkId = e.getAttribute("data-id") let artalkTime = e.getAttribute("data-time") let artalkDom = document.getElementById(`${Number(artalkTime) + Number(artalkId)}`); let artalkCon = "<div id='artalk'></div>" if (artalkDom.classList.contains('d-none')) { document.querySelectorAll('.item-comment').forEach((item) => {item.classList.add('d-none');}) if(document.getElementById("artalk")){ document.getElementById("artalk").remove() } artalkDom.insertAdjacentHTML('beforeend', artalkCon); artalkDom.classList.remove('d-none'); Artalk.init({ el: '#artalk', pageKey: '/m/' + artalkId, pageTitle: '', site: artalkPath, server: artalkEnv, emoticons: false }); }else{ artalkDom.classList.add('d-none'); document.getElementById("artalk").remove() } } //收藏 _saveMemo(memo) { let e = JSON.parse(memo.getAttribute("data-form")); let memosContent = e.content; this.memosOpenId = window.localStorage && window.localStorage.getItem("memos-access-token"); let hasContent = memosContent.length !== 0; if (this.memosOpenId && hasContent) { this.submitMemoBtn.classList.add("noclick") let memoUrl = `${this.memosPath}api/v1/memo`; let memoBody = {content:memosContent,visibility:"PRIVATE"} fetch(memoUrl, { method: 'POST', body: JSON.stringify(memoBody), headers: { 'Authorization': `Bearer ${this.memosOpenId}`, 'Content-Type': 'application/json' } }).then((res) => { cocoMessage.success('收藏成功') }); }else if(!hasContent){ cocoMessage.info('内容不能为空'); } }
//编辑修改 _editMemo(memo) { this.memosOldSelect = this.memosVisibilitySelect.value; this.getEditor = window.localStorage && window.localStorage.getItem("memos-editor-display"); this.memosOpenId = window.localStorage && window.localStorage.getItem("memos-access-token"); if(this.memosOpenId && this.getEditor == "show"){ document.querySelector(".memos-image-list").innerHTML = ''; let e = JSON.parse(memo.getAttribute("data-form")); let memoResList = e.resourceList,memosResource = [],imageList = ""; this.memosVisibilitySelect.value = e.visibility; window.localStorage && window.localStorage.setItem("memos-editor-dataform",JSON.stringify(e)); window.localStorage && window.localStorage.setItem("memos-visibility-select",this.memosVisibilitySelect.value); this.memosTextarea.value = e.content; this.memosTextarea.style.height = this.memosTextarea.scrollHeight + 'px'; this.submitMemoBtn.classList.add("d-none"); this.editMemoDom.classList.remove("d-none"); if(memoResList.length > 0){ for (let i = 0; i < memoResList.length; i++) { let imgLink = '', fileId = '',resexlink = memoResList[i].externalLink; if (resexlink) { imgLink = resexlink } else { fileId = memoResList[i].publicId || memoResList[i].filename imgLink = `${this.memosPath}/o/r/${memoResList[i].id}`;///${fileId} } memosResource.push(memoResList[i].id); imageList += `<div data-id="${memoResList[i].id}" class="imagelist-item d-flex text-xs mt-2 mr-2" onclick="window.memosbbs._deleteImage(this)"><div class="d-flex image-background" style="background-image:url(${imgLink})"><span class="d-none">${fileId}</span></div></div>`; } window.localStorage && window.localStorage.setItem("memos-resource-list", JSON.stringify(memosResource)); document.querySelector(".memos-image-list").insertAdjacentHTML('afterbegin', imageList); //this._imageListDrag() } document.body.scrollIntoView({behavior: 'smooth'}); } }
_setMemoTag(e){ let memoTag = ''; const inputValue = this.memosTextarea.value; const lastWord = inputValue.charAt(inputValue.length - 1); if (lastWord == '#') { memoTag = e.textContent.replace("#","") + " "; }else{ memoTag = e.textContent + " "; } this.memosTextarea.value += memoTag; this.memosTextarea.focus() document.querySelector(".memos-tag-list").classList.add("d-none"); } //归档 _archiveMemo(memoId) { let isOk = confirm("确认归档?"); if(isOk){ this.memosOpenId = window.localStorage && window.localStorage.getItem("memos-access-token"); if(this.memosOpenId && memoId){ let memoUrl = `${this.memosPath}api/v1/memo/${memoId}`; let memoBody = {id:memoId,rowStatus:"ARCHIVED"}; fetch(memoUrl, { method: 'PATCH', body: JSON.stringify(memoBody), headers: { 'Authorization': `Bearer ${this.memosOpenId}`, 'Content-Type': 'application/json' } }).then((res) => { if (res.ok) { cocoMessage.success( '归档成功', ()=>{ this.memosMode = window.localStorage && window.localStorage.getItem("memos-mode"); this._getUserMemos(this.nowLink,this.nowId,this.nowName,this.nowAvatar,"","",this.memosMode) }) } }) } } }
//删除 _deleteMemo(memoId) { let isOk = confirm("确认删除?"); if(isOk){ this.memosOpenId = window.localStorage && window.localStorage.getItem("memos-access-token"); if(this.memosOpenId && memoId){ let memoUrl = `${this.memosPath}api/v1/memo/${memoId}`; fetch(memoUrl, { method: 'DELETE', headers: { 'Authorization': `Bearer ${this.memosOpenId}`, 'Content-Type': 'application/json' } }).then((res) => { if (res.ok) { cocoMessage.success( '删除成功', ()=>{ this.memosMode = window.localStorage && window.localStorage.getItem("memos-mode"); this._getUserMemos(this.nowLink,this.nowId,this.nowName,this.nowAvatar,"","",this.memosMode) }) } }).catch(err => { cocoMessage.error('出错了,再检查一下吧') }) } } }
_viaNow(e){ let dataForm = JSON.parse(e.getAttribute("data-form")); let memoName = dataForm.creatorName let memoLink = dataForm.link+ "/m/" + (dataForm.name || dataForm.id); let memoContent = dataForm.content if(memoContent.length > 120){ memoContent = memoContent.substring(0, 119) + '...'; } let viaCopy = `${memoContent}(via [@${memoName}](${memoLink}))` navigator.clipboard.writeText(viaCopy).then(() => { cocoMessage.success("引用内容已复制") }); }
_getEditIcon() { let memosContent = ''; let memosVisibility = ''; let memosResource = []; let memosRelation = []; let memosCount = window.localStorage && window.localStorage.getItem("memos-response-count"); this.memosPath = window.localStorage && window.localStorage.getItem("memos-access-path"); this.memosOpenId = window.localStorage && window.localStorage.getItem("memos-access-token"); this.getEditor = window.localStorage && window.localStorage.getItem("memos-editor-display"); let isHide = this.getEditor === "hide"; this.memosVisibilitySelect.value = this.getSelectedValue; window.localStorage && window.localStorage.setItem("memos-resource-list", JSON.stringify(memosResource)); window.localStorage && window.localStorage.setItem("memos-relation-list", JSON.stringify(memosRelation));
let memosTagList = document.querySelector(".memos-tag-list") let selectedTagIndex = -1; this.memosTextarea.addEventListener('input', (e) => { this.memosTextarea.style.height = 'inherit'; this.memosTextarea.style.height = e.target.scrollHeight + 'px'; const inputValue = this.memosTextarea.value; const lastWord = inputValue.slice(-2); if (lastWord == ' #') { memosTagList.classList.remove('d-none'); } else { memosTagList.classList.add('d-none'); } });
this.memosTextarea.addEventListener('keydown', event => { const keyCode = event.keyCode; if (memosTagList.classList.contains("d-none") === false) { const matchingTags = Array.from(memosTagList.querySelectorAll('.memos-tag')).map(tag => tag.textContent); if (keyCode === 38 || keyCode === 40 || keyCode === 37 || keyCode === 39) { // 添加左右方向键的处理 event.preventDefault(); if (keyCode === 37 || keyCode === 39) { // 处理左右方向键 const direction = keyCode === 37 ? -1 : 1; selectedTagIndex = (selectedTagIndex + direction + matchingTags.length) % matchingTags.length; } else { // 处理上下方向键 selectedTagIndex = (selectedTagIndex + (keyCode === 38 ? -1 : 1) + matchingTags.length) % matchingTags.length; } Array.from(memosTagList.querySelectorAll('.memos-tag')).forEach((option, index) => option.classList.toggle('selected', index === selectedTagIndex)); } else if (keyCode === 13 && selectedTagIndex !== -1) { event.preventDefault(); let tagName = matchingTags[selectedTagIndex].replace(/[#]/,'') + " " this._insertValue(tagName,"",0) memosTagList.querySelector('.memos-tag').classList.remove('selected'); memosTagList.classList.add('d-none'); selectedTagIndex = -1; } } });
if (this.getEditor !== null) { document.querySelector(".memos-editor").classList.toggle("d-none",isHide); this.getEditor == "show" ? this._hasMemosOpenId() : ''; };
this.loadEditorBtn.addEventListener("click", () => { this.getEditor != "show" ? this._hasMemosOpenId() : ''; document.querySelector(".memos-editor").classList.toggle("d-none"); window.localStorage && window.localStorage.setItem("memos-editor-display", document.querySelector(".memos-editor").classList.contains("d-none") ? "hide" : "show"); this.getEditor = window.localStorage && window.localStorage.getItem("memos-editor-display"); });
this.taglistBtn.addEventListener("click", () => { document.querySelector(".memos-tag-list").classList.toggle("d-none"); });
//todoBtn.addEventListener("click", () => { // let memoTodo = '- [] \n'; // this._insertValue(memoTodo); // let bracketIndex = this.memosTextarea.value.indexOf("[]"); // if (bracketIndex !== -1) { // this.memosTextarea.selectionStart = bracketIndex + 1; // this.memosTextarea.selectionEnd = bracketIndex + 1; // } //});
this.codeoneBtn.addEventListener("click", () => { this._insertValue(" `` ","`",2) });
this.codeBtn.addEventListener("click", () => { let memoCode = "```\n\n```\n"; this._insertValue(memoCode,"",5); this.memosTextarea.style.height = this.memosTextarea.scrollHeight + 'px'; });
this.linkBtn.addEventListener("click", () => { this._insertValue(" []() ","[",2) });
this.linkPicBtn.addEventListener("click", () => { this._insertValue(" ![]() ","!",2) });
this.memosVisibilitySelect.addEventListener('change', () => { let memoNowSelct = window.localStorage && window.localStorage.getItem("memos-visibility-select"); var selectedValue = this.memosVisibilitySelect.value; window.localStorage && window.localStorage.setItem("memos-visibility-select",selectedValue); if(memoNowSelct == "PRIVATE" && selectedValue == "PUBLIC"){ this.memoChangeDate = 1; } });
this.privateBtn.addEventListener("click", async () => { if (!this.privateBtn.classList.contains("private")) { this.privateBtn.classList.add("private") this.memosVisibilitySelect.value = "PRIVATE" this.usernowBtnDom.forEach((item) => {item.classList.remove('current');}) window.localStorage && window.localStorage.setItem("memos-mode", "NOPUBLIC"); this.memosMode = window.localStorage && window.localStorage.getItem("memos-mode"); this._getUserMemos(this.nowLink,this.nowId,this.nowName,this.nowAvatar,"","","NOPUBLIC") cocoMessage.success("进入「私有浏览」模式") }else{ this.memosVisibilitySelect.value = "PUBLIC" window.localStorage && window.localStorage.setItem("memos-mode", ""); this.privateBtn.classList.remove("private") this._getUserMemos(this.nowLink,this.nowId,this.nowName,this.nowAvatar,"","","") cocoMessage.success("已退出「私有浏览」模式") } });
this.randomBtn.addEventListener("click", async () => { let memosAllCount = window.localStorage && window.localStorage.getItem("memos-response-count"); let nowTag,userMemoUrl,nowTagText = document.querySelector(".memos-tagnow-name") || '' if(nowTagText){ nowTag = nowTagText.textContent; userMemoUrl= `${this.nowLink}api/v1/memo?tag=${nowTag}` }else{ userMemoUrl = `${this.nowLink}api/v1/memo/stats?creatorId=${this.nowId}` } if(!memosAllCount || nowTagText){ try { let response = await fetch(userMemoUrl,{ headers: { 'Authorization': `Bearer ${this.memosOpenId}`, 'Content-Type': 'application/json', 'Cache-Control': 'no-cache', }, cache: 'no-store', }); if (!response.ok) { throw new Error(response.statusText); } let data = await response.json(); memosAllCount = data.length - 1; if(!nowTag){ window.localStorage && window.localStorage.setItem("memos-response-count",memosAllCount); } let randomNum = this._random(0,memosAllCount); this._getUserMemos(this.nowLink,this.nowId,this.nowName,this.nowAvatar,nowTag,"","",randomNum) } catch (error) { console.error(error); } if(nowTagText){ this.oneDayBtn.classList.remove("d-none") } }else{ let randomNum = this._random(0,memosAllCount); this._getUserMemos(this.nowLink,this.nowId,this.nowName,this.nowAvatar,nowTag,"","",randomNum) } });
//开启回忆一条 this.oneDayBtn.addEventListener("click", async () => { let oneDayNow = window.localStorage && window.localStorage.getItem("memos-oneday-tag"); if (oneDayNow == null ) { let nowTag = document.querySelector(".memos-tagnow-name").textContent let nowTagCount; let nowTagUrl= `${this.nowLink}api/v1/memo?tag=${nowTag}` try { let response = await fetch(nowTagUrl,{ headers: { 'Authorization': `Bearer ${this.memosOpenId}`, 'Content-Type': 'application/json', 'Cache-Control': 'no-cache', }, cache: 'no-store', }); if (!response.ok) { throw new Error(response.statusText); } let data = await response.json(); nowTagCount = data.length - 1; window.localStorage && window.localStorage.setItem("memos-oneday-tag",nowTag); window.localStorage && window.localStorage.setItem("memos-oneday-count",nowTagCount); } catch (error) { console.error(error); } cocoMessage.success("开启「OneDay」") }else{ window.localStorage && window.localStorage.removeItem("memos-oneday-tag"); window.localStorage && window.localStorage.removeItem("memos-oneday-count"); cocoMessage.success("已退出「OneDay」") } this.oneDayBtn.classList.add("d-none") });
this.uploadWebpImageInput.addEventListener('change', () => { let filesData = this.uploadWebpImageInput.files; if (filesData.length !== 0) { for (let i = 0; i < filesData.length; i++) { this._uploadWebpImage(filesData[i]); } cocoMessage.info('压缩并上传中……'); } });
this.uploadImageInput.addEventListener('change', () => { let filesData = this.uploadImageInput.files[0]; if (this.uploadImageInput.files.length !== 0){ this._uploadImage(filesData); cocoMessage.info('图片上传中……'); } });
this.switchUserBtn.addEventListener("click", () => { this.memosEditorOption.classList.remove("d-none"); this.memosEditorInner.classList.add("d-none"); this.memosRadomCont.innerHTML = ''; //this.tokenInput.value = ''; //this.pathInput.value = ''; }); this.backToEditerBtn.addEventListener("click", () => { this.memosEditorOption.classList.add("d-none"); this.memosEditorInner.classList.remove("d-none"); this.memosRadomCont.innerHTML = ''; });
this.submitApiBtn.addEventListener("click", () => { if(this.tokenInput.value == null || this.tokenInput.value == ''){ cocoMessage.info('请输入Token'); }else if(this.pathInput.value == null || this.pathInput.value == ''){ cocoMessage.info('请输入Path'); }else{ let pathInputValue = this.pathInput.value; if (pathInputValue.substr(-1) === '/') { pathInputValue = pathInputValue.substr(0, pathInputValue.length - 1); } this._getMemosData(pathInputValue,this.tokenInput.value); if(this.artalkInput.value !== null || this.artalkInput.value !== '') window.localStorage && window.localStorage.setItem("memos-artalk-input", this.artalkInput.value); if(this.artalkSiteInput.value !== null || this.artalkSiteInput.value !== '') window.localStorage && window.localStorage.setItem("memos-artalksite-input", this.artalkSiteInput.value); if(this.twikooInput.value !== null || this.twikooInput.value !== '') window.localStorage && window.localStorage.setItem("memos-twikoo-input", this.twikooInput.value); if(this.cfwkAiUrlInput.value !== null || this.cfwkAiUrlInput.value !== '') window.localStorage && window.localStorage.setItem("memos-cfwkai-url", this.cfwkAiUrlInput.value); if(this.geminiKeyInput.value !== null || this.geminiKeyInput.value !== '') window.localStorage && window.localStorage.setItem("memos-gemini-key", this.geminiKeyInput.value); if(this.filterNameInput.value !== null || this.filterNameInput.value !== '') window.localStorage && window.localStorage.setItem("memos-filter-name", this.filterNameInput.value); } });
this.submitMemoBtn.addEventListener("click", () => { let memosContent = this.memosTextarea.value; let memosVisibility = this.memosVisibilitySelect.value; let memosResource = window.localStorage && JSON.parse(window.localStorage.getItem("memos-resource-list")); let memosOpenId = window.localStorage && window.localStorage.getItem("memos-access-token"); let TAG_REG = /(?<=#)([^#\s!.,;:?"'()]+)(?= )/g; let memosTag = memosContent.match(TAG_REG); let hasContent = memosContent.length !== 0; if (memosOpenId && hasContent) { this.submitMemoBtn.classList.add("noclick") let memoUrl = `${this.memosPath}api/v1/${this.nowV1}`; let memoBody = {content:memosContent,relationList:memosRelation,resourceIdList:memosResource,visibility:memosVisibility} fetch(memoUrl, { method: 'POST', body: JSON.stringify(memoBody), headers: { 'Authorization': `Bearer ${this.memosOpenId}`, 'Content-Type': 'application/json' } }).then((res) => { if (res.status == 200) { if (memosTag !== null && this.nowV1 !== 'memos') { let memoTagUrl = `${this.memosPath}api/v1/tag`; (async () => { for await (const i of memosTag) { const response = await fetch(memoTagUrl, { method: 'POST', headers: { 'Authorization': `Bearer ${this.memosOpenId}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ name: i }) }); } })(); } cocoMessage.success( '发送成功', () => { this._clearTextarea() }) } }); }else if(!hasContent){ cocoMessage.info('内容不能为空'); }else{ cocoMessage.info( '请设置 Access Tokens', () => { this.memosEditorInner.classList.add("d-none"); this.memosEditorOption.classList.remove("d-none"); } ); } }); }
async _uploadWebpImage(data) { let memosPath = window.localStorage && window.localStorage.getItem("memos-access-path"); let memosOpenId = window.localStorage && window.localStorage.getItem("memos-access-token"); let memosResourceListNow = JSON.parse(window.localStorage && window.localStorage.getItem("memos-resource-list")) || []; let imageData = new FormData(); let blobUrl = `${memosPath}api/v1/resource/blob`; const webpData = await this._convertToWebP(data); const timestamp = new Date().getTime(); const fileName = `${timestamp}_${Math.random()}.webp`; imageData.append('file', webpData, fileName); let resp = await fetch(blobUrl, { method: "POST", body: imageData, headers: { 'Authorization': `Bearer ${memosOpenId}` } }); let res = await resp.json(); if (res.id) { let resexlink = res.externalLink; let imgLink = '', fileId = ''; if (resexlink) { imgLink = resexlink; } else { fileId = res.publicId || res.filename; imgLink = `${memosPath}/o/r/${res.id}`; } let imageList = ""; imageList += `<div data-id="${res.id}" class="imagelist-item d-flex text-xs mt-2 mr-2" onclick="window.memosbbs._deleteImage(this)"> <div class="d-flex image-background" style="background-image:url(${imgLink})"> <span class="d-none">${fileId}</span> </div> </div>`; document.querySelector(".memos-image-list").insertAdjacentHTML('afterbegin', imageList); cocoMessage.success('上传成功', () => { memosResourceListNow.push(res.id); window.localStorage && window.localStorage.setItem("memos-resource-list", JSON.stringify(memosResourceListNow)); this._imageListDrag(); }); } }
_convertToWebP(imageData) { return new Promise((resolve) => { const img = new Image(); img.onload = () => { const canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0, img.width, img.height); canvas.toBlob((blob) => { resolve(blob); }, 'image/webp', 0.7); // 设置压缩质量为70% }; img.src = URL.createObjectURL(imageData); }); };
async _uploadImage(data) { let memosPath = window.localStorage && window.localStorage.getItem("memos-access-path"); let memosOpenId = window.localStorage && window.localStorage.getItem("memos-access-token"); let memosResourceListNow = JSON.parse(window.localStorage && window.localStorage.getItem("memos-resource-list")) || []; let imageData = new FormData(); let blobUrl = `${memosPath}api/v1/resource/blob`; imageData.append('file', data, data.name) let resp = await fetch(blobUrl, { method: "POST", body: imageData, headers: { 'Authorization': `Bearer ${memosOpenId}` } }) let res = await resp.json(); if(res.id){ let resexlink = res.externalLink; let imgLink = '', fileId = ''; if (resexlink) { imgLink = resexlink } else { fileId = res.publicId || res.filename imgLink = `${memosPath}/o/r/${res.id}`;///${fileId} } let imageList = ""; imageList += `<div data-id="${res.id}" class="imagelist-item d-flex text-xs mt-2 mr-2" onclick="window.memosbbs._deleteImage(this)"><div class="d-flex image-background" style="background-image:url(${imgLink})"><span class="d-none">${fileId}</span></div></div>`; document.querySelector(".memos-image-list").insertAdjacentHTML('afterbegin', imageList); cocoMessage.success( '上传成功', ()=>{ memosResourceListNow.push(res.id); window.localStorage && window.localStorage.setItem("memos-resource-list", JSON.stringify(memosResourceListNow)); this._imageListDrag() }) } };
_hasMemosOpenId() { if (!this.memosOpenId) { this.memosEditorOption.classList.remove("d-none"); cocoMessage.info('请设置 Access Tokens'); }else{ if (!this.memosPath.endsWith('/')) { this.memosPath += '/'; } let tagUrl = `${this.memosPath}api/v1/tag`; if(this.nowV1 == 'memos'){ var filter = "?filter=" + encodeURIComponent(`creator == 'users/${this.memosMeID}'`); tagUrl = this.memosPath+'api/v1/memos/-/tags' + filter; } const response = fetch(tagUrl,{ method: 'GET', headers: { 'Authorization': `Bearer ${this.memosOpenId}`, 'Content-Type': 'application/json' } }).then(resdata => resdata.json()).then(response => { let taglist = ""; if(this.nowV1 == 'memos'){ Object.keys(response.tagAmounts).map((t)=>{ this.nowTagList += `${t},`; taglist += `<div class="memos-tag d-flex text-xs mt-2 mr-2 px-2" onclick="window.memosbbs._setMemoTag(this)">#${t}</div>`; }) }else{ response.map((t)=>{ this.nowTagList += `${t},`; taglist += `<div class="memos-tag d-flex text-xs mt-2 mr-2 px-2" onclick="window.memosbbs._setMemoTag(this)">#${t}</div>`; }) } document.querySelector(".memos-tag-list").innerHTML = taglist; //cocoMessage.success('准备就绪'); this.memosEditorInner.classList.remove("d-none"); this.memosEditorOption.classList.add("d-none"); this.memosRadomCont.innerHTML = ''; this.memosRadomCont.classList.remove("d-none"); }).catch(err => { this.memosEditorOption.classList.remove("d-none"); cocoMessage.error('Access Tokens 有误,请重新输入!'); }); } }
_random(a,b) { let choices = b - a + 1; return Math.floor(Math.random() * choices + a); }
async _getMemosData(p,t) { if (p.length > 0 && !p.endsWith('/')) { p += '/'; } try { let response; if(this.nowV1 == 'memos'){ response = await fetch(`${p}api/v1/auth/status`,{ async: true, crossDomain: true, method: 'POST', headers: { 'Authorization': `Bearer ${t}` } }); }else{ response = await fetch(`${p}api/v1/user/me`,{ method: 'GET', headers: { 'Authorization': `Bearer ${t}`, 'Content-Type': 'application/json' } }); } if (response.ok) { let resdata = await response.json(); if (resdata) { this.memosMeID = resdata.id; this.memosMeNickname = resdata.nickname || resdata.username ; this.memosMeAvatarUrl = resdata.avatarUrl || "https://memobbs.app/pwa/48.png"; window.localStorage && window.localStorage.setItem("memos-access-path", p); window.localStorage && window.localStorage.setItem("memos-access-token", t); window.localStorage && window.localStorage.setItem("memos-visibility-select","PUBLIC"); window.localStorage && window.localStorage.setItem("memos-me-id", this.memosMeID); window.localStorage && window.localStorage.setItem("memos-me-nickname", this.memosMeNickname); window.localStorage && window.localStorage.setItem("memos-me-avatarurl", this.memosMeAvatarUrl); cocoMessage.success('保存成功', () => { this.memosPath = window.localStorage && window.localStorage.getItem("memos-access-path"); this.memosOpenId = window.localStorage && window.localStorage.getItem("memos-access-token"); window.location.reload(); //this._getUserMemos(this.memosPath,this.memosMeID,this.memosMeNickname,this.memosMeNickname,"") this._hasMemosOpenId(); }); } } else { cocoMessage.error('出错了,再检查一下吧!'); } } catch (error) { cocoMessage.error('出错了,再检查一下吧!'); } }
_insertValue(text,wrap,back) { this.memosTextarea.focus(); const start = this.memosTextarea.selectionStart; const end = this.memosTextarea.selectionEnd; const selectedText = this.memosTextarea.value.substring(start, end); if(selectedText == ""){ this.memosTextarea.value = this.memosTextarea.value.substring(0, start) + text + this.memosTextarea.value.substring(end); this.memosTextarea.selectionStart = start + text.length - back; this.memosTextarea.selectionEnd = start + text.length - back; }else{ let wrapSelText; if( wrap == "`" ){ wrapSelText = " `" + selectedText + "` "; back = 0; } if( wrap == "[" ){ wrapSelText = " [" + selectedText + "]() "; } if( wrap == "!" ){ wrapSelText = " ![" + selectedText + "]() "; } const newText = this.memosTextarea.value.substring(0, start) + wrapSelText + this.memosTextarea.value.substring(end); this.memosTextarea.value = newText; this.memosTextarea.selectionStart = start + wrapSelText.length - back; this.memosTextarea.selectionEnd = end + wrapSelText.length - back - selectedText.length; } }
_deleteImage(e){ if(e){ let memoId = e.getAttribute("data-id") let memosResource = window.localStorage && JSON.parse(window.localStorage.getItem("memos-resource-list")); let memosResourceList = memosResource.filter((item) => { return item != memoId}); window.localStorage && window.localStorage.setItem("memos-resource-list", JSON.stringify(memosResourceList)); e.remove() } }
_imageListDrag(){// 获取包含所有图像元素的父元素 const imageList = document.querySelector('.memos-image-list'); // 存储被拖动的元素 let draggedItem = null; let memosResourceList; // 为每个图像元素添加拖动事件监听器 imageList.querySelectorAll('.imagelist-item').forEach(item => { item.draggable = true; // 当拖动开始时 item.addEventListener('dragstart', (e) => { // 存储被拖动的元素 draggedItem = this; memosResourceList = []; }); // 当拖动元素进入目标区域时 item.addEventListener('dragover', (e) => { e.preventDefault(); // 阻止默认行为 this.classList.add('dragover'); // 添加拖动进入样式 });
// 当拖动元素离开目标区域时 item.addEventListener('dragleave', () => { this.classList.remove('dragover'); // 移除拖动进入样式 });
// 当拖动元素放置到目标区域时 item.addEventListener('drop', (e) => { e.preventDefault(); // 阻止默认行为 this.classList.remove('dragover'); // 移除拖动进入样式 // 计算拖动元素中心点 const rect = this.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; // 判断鼠标相对中心点的位置 const isLeft = e.clientX < centerX; if (isLeft) { // 插入到前一个元素前 this.parentNode.insertBefore(draggedItem, this.previousElementSibling); } else { // 插入到后一个元素后 this.parentNode.insertBefore(draggedItem, this.nextElementSibling); } document.querySelectorAll('.memos-image-list .imagelist-item').forEach((item) => { let itemId = Number(item.dataset.id) memosResourceList.push(itemId); }) window.localStorage && window.localStorage.setItem("memos-resource-list", JSON.stringify(memosResourceList)); }); }); }
_clearTextarea(mode){ if (!this.editMemoDom.classList.contains("d-none")) { window.localStorage && window.localStorage.removeItem("memos-editor-dataform"); this.editMemoDom.classList.add("d-none"); this.submitMemoBtn.classList.remove("d-none"); } this.submitMemoBtn.classList.remove("noclick"); document.querySelector(".memos-image-list").innerHTML = ''; window.localStorage && window.localStorage.removeItem("memos-resource-list"); window.localStorage && window.localStorage.removeItem("memos-relation-list"); this.memosTextarea = document.querySelector(".memos-editor-textarea") this.memosTextarea.value = ''; this.memosTextarea.style.height = 'inherit'; this.memosMode = mode || window.localStorage && window.localStorage.getItem("memos-mode"); if(this.memosMode != "cancel"){ this._getUserMemos(this.nowLink,this.nowId,this.nowName,this.nowAvatar,"","",this.memosMode) } }
// 显示表情选择器 _displayEmojiSelector() { if (!this.emojiSelector) { this.emojiSelector = document.createElement('div'); this.emojiSelector.classList.add('emoji-selector'); this.emojiSelector.addEventListener('click', (event) => { const target = event.target; if (target.classList.contains('emoji-item')) { this._insertEmoji(target.innerHTML); } }); } this.emojiSelector.innerHTML = ''; this.emojis.forEach(emoji => { const emojiItem = document.createElement('div'); emojiItem.classList.add('emoji-item'); emojiItem.innerHTML = emoji.icon; emojiItem.title = emoji.text; this.emojiSelector.appendChild(emojiItem); }); const memosEditorTools = document.querySelector(".memos-editor-tools"); if (memosEditorTools) { memosEditorTools.insertAdjacentElement('afterend', this.emojiSelector); } } // 表情光标位置 _insertEmoji(emojiText) { const selectionStart = this.memosTextarea.selectionStart; const newValue = `${this.memosTextarea.value.substring(0, selectionStart)}${emojiText}${this.memosTextarea.value.substring(this.memosTextarea.selectionEnd)}`; this.memosTextarea.value = newValue; this.memosTextarea.dispatchEvent(new Event('input')); const newCursorPosition = selectionStart + emojiText.length; this.memosTextarea.setSelectionRange(newCursorPosition, newCursorPosition); this.memosTextarea.focus(); }
// 回到顶部 _backToTop() { let BackTop = document.querySelector(".backtop") document.onscroll = () => { let iRollingLength = document.documentElement.scrollTop if(iRollingLength > 300){ BackTop.classList.add("d-md-flex") }else{ BackTop.classList.remove("d-md-flex") } } BackTop.onclick = () => { document.body.scrollIntoView({behavior: 'smooth'}) }; }
_geminiAI(e){ let AIMode = e.innerText; let textOld = this.memosTextarea.value; let memosContent; if(!textOld){ cocoMessage.info('内容不能为空'); return } if(AIMode == "语音润色"){ this.memosTextarea.value = `${textOld}\n---\n` memosContent = `请用简洁明了的语言,编辑以下段落,以改善其逻辑流程,消除任何印刷错误。请务必保持文章的原意,禁止回答解释文字里的问题,只返回编辑后的文字,以简体中文回复。请从编辑以下文字开始:[${textOld}]` }else if(AIMode == "自动标签"){ memosContent = `分析这段文本内容:[${textOld}],从这些标签列表中: ["${this.nowTagList}"] 尝试找出1个最适合的标签,并"#TAG "的形式反馈给我` }else if(AIMode == "智囊团队"){ this.memosTextarea.value = `${textOld}\n---\n` memosContent = `你是我的智囊团,团内有 6 个不同的董事作为教练,分别是乔布斯、伊隆马斯克、马云、柏拉图、维达利和慧能大师。他们都有自己的个性、世界观、价值观,对问题有不同的看法、建议和意见。我会在这里说出我的处境和我的决策。先分别以这 6 个身份,以他们的视角来审视我的决策,给出他们的批评和建议,我的第一个处境是 [${textOld}]` }else if(AIMode == "育儿帮手"){ this.memosTextarea.value = `${textOld}\n---\n` memosContent = `As an expert in child development, you are tasked with answering various imaginative questions from children between the ages of 5 and 10, as if you were a kindergarten teacher. Your responses should be lively, patient, and friendly in tone and manner, and as concrete and understandable as possible, avoiding complex or abstract vocabulary. Use metaphors and examples whenever possible, and extend your answers to cover more scenarios, not just explaining why, but also suggesting concrete actions to deepen understanding. Respond in Chinese.My first questions: [${textOld}]` }else if(AIMode == "智能问答"){ this.memosTextarea.value = `${textOld}\n---\n` memosContent = `${textOld}` } this.geminiAIBtn.classList.add("d-none","noclick") this.geminiAILoadBtn.classList.remove("d-none") this._sendToGemini(memosContent) };
//"https://gemini-openai-proxy.deno.dev/v1/chat/completions" async _sendToGemini(memosContent) { const res = await fetch(this.GeminiFetch, { headers: { 'Authorization': `Bearer ${this.geminiKey}`, 'Content-Type': 'application/json' }, method: 'POST', body: JSON.stringify({ model: 'gemini-pro', messages: [{ role: 'user', content: memosContent }], temperature: 0.7, stream: true }) }) if(!res.ok){ setTimeout(() => { this.geminiAIBtn.classList.remove("d-none","noclick") this.geminiAILoadBtn.classList.add("d-none") cocoMessage.error("出错咯,稍后再试") }, 1000); } const reader = res.body.getReader() while(true) { const {value, done} = await reader.read() if (done) { this.geminiAIBtn.classList.remove("d-none","noclick") this.geminiAILoadBtn.classList.add("d-none") break } const text = new TextDecoder().decode(value) const match = text.match(/DONE/) if(!match){ const textJson = JSON.parse(text.substring(5)) const resData = textJson.choices[0].delta.content if(resData.length > 0){ this.memosTextarea.value += resData this.memosTextarea.style.height = this.memosTextarea.scrollHeight + 'px'; } } } }
async _getMemosForAI() { let fetchUrl = `${this.nowLink}api/v1/memo?creatorId=${this.nowId}&limit=100` let response = await fetch(fetchUrl,{ headers: { 'Authorization': `Bearer ${this.memosOpenId}`, 'Content-Type': 'application/json', 'Cache-Control': 'no-cache', }, cache: 'no-store', }); if (!response.ok) { throw new Error(`Request failed oneDay`); } let originalArray = await response.json()
const filteredArray = originalArray.map(item => { return { id: item.id, content: item.content }; });
return JSON.stringify(filteredArray).substring(0, 30000); }}
class MemosElement extends HTMLElement { connectedCallback() { window.memosbbs = new MemosBbs(); } disconnectedCallback() { delete window.memosbbs; }}
if (window.customElements && !window.customElements.get('memos-bbs')) { window.MemosElement = MemosElement window.customElements.define('memos-bbs', MemosElement)}(二)在模板中注册JS文件
打开Solitude主题文件夹\scripts\event\cdn.js,在里面找到const internalSrc部分,并在里面添加以下内容:
memos_js:{ name: 'hexo-theme-solitude', file: 'js/memos.js', version },三、增加模板
(一)添加说说页面模板
在Solitude主题文件夹\layout\includes\page中添加bb.pug,在bb.pug中添加以下内容:
include ../widgets/page/bannerif theme.bb.enable memos-bbs link(rel="stylesheet" href="https://cdn.staticfile.org/animate.css/4.1.1/animate.min.css") link(rel="stylesheet" href="https://memobbs.app/grid.css") link(rel="stylesheet" href="https://memobbs.app/memos.css") .user-now.card-item.flex-fill.mb-3.row .call-memos-editor.item-avatar.p-3 img.user-now-avatar(src='data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' style='pointer-events: none;') span.user-now-name .row-fill input.search-memos-input.border-b.input-text.py-2.animate__animated.animate__fadeIn.animate__fadeInRight.d-none(type='text' placeholder='想搜点啥?' id='') span.search-memos-btn.button.d-md-flex.p-2.mr-2 svg(xmlns='http://www.w3.org/2000/svg' width='1.15rem' height='1.15rem' viewbox='0 0 24 24') g(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2') circle(cx='11' cy='11' r='8') path(d='m21 21l-4.3-4.3') .user-button-span.row-fill // span.memos-theme-toggle.button.d-md-flex.p-2.mr-2 // svg(xmlns='http://www.w3.org/2000/svg' width='1.15rem' height='1.15rem' viewbox='0 0 24 24') // path(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M12 8a2.83 2.83 0 0 0 4 4a4 4 0 1 1-4-4m0-6v2m0 16v2M4.9 4.9l1.4 1.4m11.4 11.4l1.4 1.4M2 12h2m16 0h2M6.3 17.7l-1.4 1.4M19.1 4.9l-1.4 1.4') span.my-blog-feeds.button.d-md-flex.p-2.mr-2 svg(xmlns='http://www.w3.org/2000/svg' width='1.15rem' height='1.15rem' viewbox='0 0 24 24') g(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2') path(d='M10 10v.2A3 3 0 0 1 8.9 16v0H5v0h0a3 3 0 0 1-1-5.8V10a3 3 0 0 1 6 0m-3 6v6m6-3v3') path(d='M12 19h8.3a1 1 0 0 0 .7-1.7L18 14h.3a1 1 0 0 0 .7-1.7L16 9h.2a1 1 0 0 0 .8-1.7L13 3l-1.4 1.5') span.userlist-memos.button.d-md-flex.p-2.mr-2 svg(xmlns='http://www.w3.org/2000/svg' width='1.15rem' height='1.15rem' viewbox='0 0 24 24') g(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2') path(d='M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2') circle(cx='9' cy='7' r='4') path(d='M22 21v-2a4 4 0 0 0-3-3.87m-3-12a4 4 0 0 1 0 7.75') span.randomuser-memos.button.d-md-flex.p-2.mr-2 svg(xmlns='http://www.w3.org/2000/svg' width='1.15rem' height='1.15rem' viewbox='0 0 24 24') path(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 16v-2.38C4 11.5 2.97 10.5 3 8c.03-2.72 1.49-6 4.5-6C9.37 2 10 3.8 10 5.5c0 3.11-2 5.66-2 8.68V16a2 2 0 1 1-4 0m16 4v-2.38c0-2.12 1.03-3.12 1-5.62c-.03-2.72-1.49-6-4.5-6C14.63 6 14 7.8 14 9.5c0 3.11 2 5.66 2 8.68V20a2 2 0 1 0 4 0m-4-3h4M4 13h4') span.gobbs-memos.button.d-md-flex.p-2.mr-2 svg(xmlns='http://www.w3.org/2000/svg' width='1.15rem' height='1.15rem' viewbox='0 0 24 24') path(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M8.8 20v-4.1l1.9.2a2.3 2.3 0 0 0 2.164-2.1V8.3A5.37 5.37 0 0 0 2 8.25c0 2.8.656 3.054 1 4.55a5.77 5.77 0 0 1 .029 2.758L2 20m17.8-2.2a7.5 7.5 0 0 0 .003-10.603M17 15a3.5 3.5 0 0 0-.025-4.975') span.gohome-memos.button.d-md-flex.p-2.mr-3 svg(xmlns='http://www.w3.org/2000/svg' width='1.15rem' height='1.15rem' viewbox='0 0 24 24') g(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2') path(d='m3 9l9-7l9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z') path(d='M9 22V12h6v10')
#memos .memos-editor.animate__animated.animate__fadeIn.col-12.d-none .memos-editor-body.mb-3.p-3 .memos-editor-inner.animate__animated.animate__fadeIn.d-none .memos-editor-content textarea.memos-editor-textarea.text-sm(rows='1' placeholder=' 任何想法...' style='padding: 1rem;') .memos-image-list.d-flex.flex-fill.line-xl.flex-wrap .memos-editor-tools.pt-1 .d-flex.flex-wrap .button.outline.action-btn.biao-qing-btn.mr-2 svg(xmlns='http://www.w3.org/2000/svg' width='1.35rem' height='1.35rem' viewbox='0 0 24 24') g(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2') circle(cx='12' cy='12' r='10') path(d='M8 14s1.5 2 4 2s4-2 4-2M9 9h.01M15 9h.01') .button.outline.action-btn.tag-btn.mr-2 svg(xmlns='http://www.w3.org/2000/svg' width='1.35rem' height='1.35rem' viewbox='0 0 24 24') path(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 9h16M4 15h16M10 3L8 21m8-18l-2 18') .button.outline.action-btn.codeone-btn.mr-2 svg(xmlns='http://www.w3.org/2000/svg' width='1.35rem' height='1.35rem' viewbox='0 0 24 24') path(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m8 7l-5 5l5 5m8 0l5-5l-5-5') .button.outline.action-btn.code-btn.mr-2 svg(xmlns='http://www.w3.org/2000/svg' width='1.35rem' height='1.35rem' viewbox='0 0 24 24') path(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m7 8l-4 4l4 4m10-8l4 4l-4 4M14 4l-4 16') .button.outline.action-btn.mr-2.link-btn svg(xmlns='http://www.w3.org/2000/svg' width='1.35rem' height='1.35rem' viewbox='0 0 24 24') path(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 17H7A5 5 0 0 1 7 7h2m6 0h2a5 5 0 1 1 0 10h-2m-7-5h8') .button.outline.action-btn.mr-2.dropdown.aitop svg(xmlns='http://www.w3.org/2000/svg' width='1.35rem' height='1.35rem' viewbox='0 0 24 24') g(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2') path(d='M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7m4 2h6m-3-3v6') circle(cx='9' cy='9' r='2') path(d='m21 15l-3.086-3.086a2 2 0 0 0-2.828 0L6 21') .dropdown-wrapper.d-none span.btn.linkpic-btn 外链 span.btn.image-btn(onclick='this.nextElementSibling.click()') WebP+ input.memos-upload-Webp-image-input.d-none(type='file' accept='image/*') span.btn.image-btn(onclick='this.nextElementSibling.click()') 原图+ input.memos-upload-image-input.d-none(type='file' accept='image/*') if theme.bb.geminiKey .button.outline.geminiai-btn.action-btn.mr-2.dropdown.aitop svg(xmlns='http://www.w3.org/2000/svg' width='1.15rem' height='1.15rem' viewbox='0 0 24 24') path(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m21.64 3.64l-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72M14 7l3 3M5 6v4m14 4v4M10 2v2M7 8H3m18 8h-4M11 3H9') .dropdown-wrapper.d-none span.btn(onclick='geminiAI(this)') 语音润色 span.btn(onclick='geminiAI(this)') 自动标签 span.btn(onclick='geminiAI(this)') 育儿帮手 span.btn(onclick='geminiAI(this)') 智囊团队 span.btn(onclick='geminiAI(this)') 智能问答 .button.outline.geminiai-load-btn.d-none.noclick.action-btn.mr-2 svg(xmlns='http://www.w3.org/2000/svg' width='1.15rem' height='1.15rem' viewbox='0 0 24 24') path(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M21 12a9 9 0 1 1-6.219-8.56')
if theme.bb.cfwkAiUrl .button.outline.action-btn.mr-2.cfworkerai-btn svg(xmlns='http://www.w3.org/2000/svg' width='1.15rem' height='1.15rem' viewbox='0 0 24 24') g(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2') path(d='M12 8V4H8') rect(width='16' height='12' x='4' y='8' rx='2') path(d='M2 14h2m16 0h2m-7-1v2m-6-2v2') .button.outline.action-btn.mr-2.cfworkerai-load-btn.d-none.noclick svg(xmlns='http://www.w3.org/2000/svg' width='1.15rem' height='1.15rem' viewbox='0 0 24 24') path(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M21 12a9 9 0 1 1-6.219-8.56')
.d-flex.flex-fill .memos-tag-list.d-none.mt-2.animate__animated.animate__fadeIn .memos-editor-footer.border-t.mt-2.pt-2.flex-wrap .d-flex .button.outline.switchUser-btn.mr-2.p-2 svg(xmlns='http://www.w3.org/2000/svg' width='.9rem' height='.9rem' viewbox='0 0 24 24') g(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2') path(d='M20 7h-9m3 10H5') circle(cx='17' cy='17' r='3') circle(cx='7' cy='7' r='3') .button.outline.private-btn.mr-2.p-2 svg(xmlns='http://www.w3.org/2000/svg' width='.9rem' height='.9rem' viewbox='0 0 24 24') path(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 10h.01M15 10h.01M12 2a8 8 0 0 0-8 8v12l3-3l2.5 2.5L12 19l2.5 2.5L17 19l3 3V10a8 8 0 0 0-8-8') .button.outline.random-btn.mr-2.p-2 svg(xmlns='http://www.w3.org/2000/svg' width='.9rem' height='.9rem' viewbox='0 0 24 24') g(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2') path(d='M2 18h1.4c1.3 0 2.5-.6 3.3-1.7l6.1-8.6c.7-1.1 2-1.7 3.3-1.7H22') path(d='m18 2l4 4l-4 4M2 6h1.9c1.5 0 2.9.9 3.6 2.2M22 18h-5.9c-1.3 0-2.6-.7-3.3-1.8l-.5-.8') path(d='m18 14l4 4l-4 4') .button.outline.oneday-btn.d-none.p-2 svg(xmlns='http://www.w3.org/2000/svg' width='.9rem' height='.9rem' viewbox='0 0 24 24') g(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2') rect(width='18' height='18' x='3' y='4' rx='2' ry='2') path(d='M16 2v4M8 2v4m-5 4h18M8 14h.01M12 14h.01M16 14h.01M8 18h.01M12 18h.01M16 18h.01') .editor-submit.d-flex.flex-fill.justify-content-end .editor-selector.select.outline.mr-5 select.select-memos-value.pl-2.pr-4.py-2 option(value='PUBLIC') 公开 option(value='PRIVATE') 私有 .edit-memos.d-none button.outline.cancel-edit-btn.mr-2.px-2.py-2(title='取消') 取消 button.primary.edit-memos-btn.px-5.py-2(title='保存') 保存 button.primary.submit-memos-btn.px-5.py-2(title='发布') 发布 .memos-editor-option.animate__animated.animate__fadeIn.d-none .reg-editor.row.flex-fill.mr-3.p-2 input.memos-path-input.border-b.input-text.col-6.py-2(name='memos-path-url' type='text' value='' placeholder='Memo 网址') input.memos-token-input.border-b.input-text.col-6.py-2(name='memos-token-url' type='text' value='' placeholder='Access Tokens') input.memos-artalk-input.border-b.input-text.col-6.py-2(name='artalk-url' type='text' value='' placeholder='[可选] Artalk 评论网址') input.memos-artalksite-input.border-b.input-text.col-6.py-2(name='artalk-site-name' type='text' value='' placeholder='[可选] Artalk 站点名称') input.memos-twikoo-input.border-b.input-text.col-6.py-2(name='twikoo-path-url' type='text' value='' placeholder='[可选] Twikoo 评论网址') input.cfwkai-url-input.border-b.input-text.col-6.py-2(name='cfwkai-url' type='text' value='' placeholder='[可选] Cloudflare AI 网址') input.gemini-key-input.border-b.input-text.col-6.py-2(name='gemini-key' type='text' value='' placeholder='[可选] Gemini Pro Key') input.filter-name-input.border-b.input-text.col-6.py-2(name='filter-name' type='text' value='' placeholder='[可选] 广场过滤名单( , 分隔多个)') .editor-btn-wrap.row.flex-fill button.primary.backto-editer-btn.px-5.py-2 返回 button.primary.submit-openapi-btn.px-5.py-2 保存 .memos-random.d-none .backtop.d-none svg(xmlns='http://www.w3.org/2000/svg' width='1.25rem' height='1.25rem' viewbox='0 0 24 24') path(fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m18 15l-6-6l-6 6')
#memo-list
button.col-12.load-btn.button-load.d-none.flex-fill.mb-3.p-3.animate__animated.animate__fadeIn 加载更多
script(src="https://cdn.staticfile.net/marked/14.1.0/marked.min.js") script(src="https://cdn.staticfile.org/lozad.js/1.16.0/lozad.min.js")(二)修改主题相关模板
打开Solitude主题文件夹\layout\includes\inject\body.pug,在里面找到script(src=url_for(theme.cdn.pjax))部分,并在里面添加以下内容:
if theme.bb.enable script(src=url_for(theme.cdn.memos_js))(三)添加样式
打开Solitude主题文件夹\source\css\_layout,新建bb.styl,并在里面添加以下内容:
if hexo-config('bb.enable') html[data-theme=dark] .el-skeleton animation: skeleton-loading-dark 1.5s linear infinite; background-image: unset !important;
html[data-theme=light] .el-skeleton animation: skeleton-loading-light 1.5s linear infinite; background-image: unset !important;
memos-bbs display block margin: 1rem auto; .backtop z-index 9 !important &:hover background-color: var(--efu-lighttext) !important .user-now, .memos-editor-body, .card-item, .editor-selector background-color: var(--efu-card-bg) !important border: var(--style-border-always) !important; transition: all 0.3s ease 0s !important; &:hover border: var(--style-border-hover) !important; .user-now .user-info display: flex; .user-now.row justify-content: space-between; .row-fill margin-left: 0 !important; margin-right: 1rem !important .user-button-span margin-right: 0 !important .button margin-right 0 !important @media (max-width: 768px) padding: .3rem !important .gohome-memos @media (max-width: 768px) margin-right: 0 !important .userlist align-items: center .item-avatar border: var(--style-border); .button border: var(--style-border-always) !important; &:hover background: var(--efu-lighttext) !important color var(--efu-card-bg) !important .search-memos-btn, .memos-theme-toggle, .my-blog-feeds, .userlist-memos, .randomuser-memos, .gobbs-memos, .gohome-memos border unset !important; &:hover background-color: transparent !important; color: var(--efu-lighttext) !important; &.current color: var(--efu-lighttext) !important; .border-t border-top var(--style-border-always) !important .item-mate color: #999999 !important; .item-tag background-color: var(--efu-secondbg) !important; button.primary background-color: var(--efu-lighttext) !important; color: var(--efu-card-bg) !important; &:hover box-shadow: 0px 5px 20px -3px var(--efu-lighttext) !important; button.outline border: var(--style-border-always) !important; &:hover background-color: var(--efu-secondbg) !important; textarea background-color var(--efu-secondbg) !important; border-radius: 6.6px .item-comment background-color var(--efu-secondbg) !important; .dropdown-wrapper, select>option background-color var(--efu-secondbg) !important; .select::after border-color var(--efu-fontcolor) transparent transparent transparent !important; .dropdown-wrapper>.btn color: var(--efu-fontcolor); .editor-submit @media (max-width: 768px) justify-content: flex-start !important; margin-top: .5rem; code background-color: transparent !important; .db-card margin: 0; height: 7rem; .db-card-subject border var(--style-border) border-radius: 6.6px height: 100%; .db-card-post height: 100%; width unset !important img width: unset !important height 100% !important object-fit: contain !important .db-card-cate border-top-right-radius: 6.6px #memo-list a.primary color: var(--efu-lighttext) !important; .video-wrapper width 0 position: relative; padding: 14.0625% 25%; margin: 0.5rem 0px; +maxWidth768() padding 30% 50% iframe position: absolute; width: 100%; height: 100%; left: 0px; top: 0px; margin: 0px; border-radius: 8px; border: var(--style-border); .myfeeds-xml.current, .myfeeds-xml:hover color var(--efu-lighttext) !important .myfeeds-floor color var(--efu-secondbg) top: 12px !important; .item-creator z-index 5 .memos-editor-option>.editor-btn-wrap @media (max-width: 768px) flex-direction: row justify-content: space-around; button margin: 5px 0 !important;
@media (max-width: 768px) .user-now flex-wrap: nowrap .memos-editor-option flex-direction: column .reg-editor flex-direction: column; flex-wrap: nowrap; margin 0 !important input height: 1rem flex: 0 0 content; max-width: unset; width 100% .myfeeds-option flex-wrap: nowrap justify-content: space-between; .myfeeds-xml margin 0 !important
.bber-music display flex justify-content space-between align-items center width 100% height 90px margin .5rem 0 border-radius 8px overflow hidden border var(--style-border-always) background var(--efu-secondbg) cursor pointer user-select none &>svg width 30px height 30px fill var(--efu-fontcolor) opacity 0.3 margin-right 10px flex-shrink 0 .bber-music-wrap display flex align-items center .bber-music-pic height: 80px; width: 80px; background-size: contain !important; border: var(--style-border-always); border-radius: 8px; margin-left: 10px; flex-shrink: 0;
.bber-music-info display flex flex-direction: column; margin-left: 10px; align-items: center;
.bber-music-title,.bber-music-artist text-align: left; width: 100%; .bber-music-title font-size: 0.8rem; line-height: 1.6rem; .bber-music-artist font-size: 0.6rem; line-height: 0.8rem;
@keyframes skeleton-loading-dark 0% background-color #30343f 50% background-color #30343f80 100% background-color #30343f
@keyframes skeleton-loading-light 0% background-color #e3e3e6 50% background-color #e3e3e680 100% background-color #e3e3e6四、添加相关页面
在博客主文件夹中打开终端,输入hexo new page bb,然后在博客主文件夹\source\bb中打开index.md,输入以下内容:
---title: 说说date: 2024-08-24 16:18:46cover: 'https://cn.bing.com/th?id=OHR.BridgeNorway_ZH-CN9063814637_1920x1080.jpg'desc: 基于 Memos 与哔哔广场type: bbleftend: '支离破碎的'rightend: '思考·发言'comment: false---然后访问博客网址/bb,大功告成😊
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
随机文章 随机推荐