diff --git a/asset-manifest.json b/asset-manifest.json index 3e9fbc8..6a0d150 100644 --- a/asset-manifest.json +++ b/asset-manifest.json @@ -1,15 +1,15 @@ { "files": { "main.css": "https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages-master/static/css/main.79dcf351.chunk.css", - "main.js": "https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages-master/static/js/main.47e96665.chunk.js", - "main.js.map": "https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages-master/static/js/main.47e96665.chunk.js.map", + "main.js": "https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages-master/static/js/main.50ae84bd.chunk.js", + "main.js.map": "https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages-master/static/js/main.50ae84bd.chunk.js.map", "runtime-main.js": "https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages-master/static/js/runtime-main.4687ccd5.js", "runtime-main.js.map": "https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages-master/static/js/runtime-main.4687ccd5.js.map", "static/css/2.f2d92645.chunk.css": "https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages-master/static/css/2.f2d92645.chunk.css", "static/js/2.c92cdfa8.chunk.js": "https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages-master/static/js/2.c92cdfa8.chunk.js", "static/js/2.c92cdfa8.chunk.js.map": "https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages-master/static/js/2.c92cdfa8.chunk.js.map", "index.html": "./index.html", - "precache-manifest.6654b9891a4af70ea20d206ac91b4e7b.js": "https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages-master/precache-manifest.6654b9891a4af70ea20d206ac91b4e7b.js", + "precache-manifest.b7b6b8f31159a60daffb5c0c6a7b27e4.js": "https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages-master/precache-manifest.b7b6b8f31159a60daffb5c0c6a7b27e4.js", "service-worker.js": "./service-worker.js", "static/css/2.f2d92645.chunk.css.map": "https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages-master/static/css/2.f2d92645.chunk.css.map", "static/css/main.79dcf351.chunk.css.map": "https://cdn.jsdelivr.net/gh/thuhole/webhole@gh-pages-master/static/css/main.79dcf351.chunk.css.map", @@ -21,6 +21,6 @@ "static/css/2.f2d92645.chunk.css", "static/js/2.c92cdfa8.chunk.js", "static/css/main.79dcf351.chunk.css", - "static/js/main.47e96665.chunk.js" + "static/js/main.50ae84bd.chunk.js" ] } \ No newline at end of file diff --git a/index.html b/index.html index 960d85b..42ece78 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ -
\n {props.text}\n
\n )\n}\n\nexport function GlobalTitle(props) {\n return (\n{props.text}
\n\n// {!!dropdown_cur_app ?\n// app_elem((()=>{\n// let [id,title,_url,icon_normal,icon_hover,_new_tab]=dropdown_cur_app;\n// return [id,title+'▾',null,icon_normal,icon_hover,false];\n// })(),true) :\n// app_elem(['-placeholder-elem','更多▾',null,appicon_dropdown,appicon_dropdown_rev,false],true)\n// }\n//
\n// {this.state.apps.dropdown.map((app)=>{\n// let ref=React.createRef();\n// return (\n//{\n// if(!e.target.closest('a') && ref.current)\n// ref.current.click();\n// }}>\n// {app_elem(app,true,ref)}\n//
\n// );\n// })}\n//\n 接收验证码来登录 T大树洞\n
\n\n \n \n {/*this.do_sendcode('sms')}>*/}\n {/* 短信 */}\n {/**/}\n {/*/*/}\n this.do_sendcode('mail')}>\n 发送邮件 \n \n \n
\n\n \n \n
\n\n 从其他设备导入登录状态\n
\n\n \n \n
\n\n This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.\n
\n\n \n
\n' +\n hljs.highlight(lang, str, true).value +\n '
'\n );\n } catch (__) {}\n }\n return (\n '' + md.utils.escapeHtml(str) + '
'\n );\n },\n}).use(MarkdownItKaTeX, {\n throwOnError: false,\n errorColor: '#aa0000',\n});\n\nexport default (text) => md.render(text);\n","import React, { Component, PureComponent } from 'react';\nimport { format_time, Time, TitleLine } from './infrastructure/widgets';\nimport { THUHOLE_API_ROOT } from './flows_api';\n\nimport HtmlToReact from 'html-to-react';\n\nimport './Common.css';\nimport {\n URL_PID_RE,\n URL_RE,\n PID_RE,\n NICKNAME_RE,\n split_text,\n} from './text_splitter';\n\nimport renderMd from './Markdown';\n\nexport { format_time, Time, TitleLine };\n\nexport const API_BASE = THUHOLE_API_ROOT + 'services/thuhole';\n\n// https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex\nfunction escape_regex(string) {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'); // $& means the whole matched string\n}\n\nexport function build_highlight_re(\n txt,\n split = ' ',\n option = 'g',\n isRegex = false,\n) {\n if (isRegex) {\n try {\n return new RegExp('(' + txt.slice(1, -1) + ')', option);\n } catch (e) {\n return /^$/g;\n }\n } else {\n return txt\n ? new RegExp(\n `(${txt\n .split(split)\n .filter((x) => !!x)\n .map(escape_regex)\n .join('|')})`,\n option,\n )\n : /^$/g;\n }\n}\n\nexport function ColoredSpan(props) {\n return (\n \n {props.children}\n \n );\n}\n\nfunction normalize_url(url) {\n return /^https?:\\/\\//.test(url) ? url : 'http://' + url;\n}\n\nexport class HighlightedText extends PureComponent {\n render() {\n return (\n \n {this.props.parts.map((part, idx) => {\n let [rule, p] = part;\n return (\n \n {rule === 'url_pid' ? (\n \n /##\n \n ) : rule === 'url' ? (\n \n {p}\n \n ) : rule === 'pid' ? (\n {\n e.preventDefault();\n this.props.show_pid(p.substring(1));\n }}\n >\n {p}\n \n ) : rule === 'nickname' ? (\n \n {p}\n \n ) : rule === 'search' ? (\n {p}\n ) : (\n p\n )}\n \n );\n })}\n
\n );\n }\n}\n\n// props: text, show_pid, color_picker\nexport class HighlightedMarkdown extends Component {\n render() {\n const props = this.props;\n const processDefs = new HtmlToReact.ProcessNodeDefinitions(React);\n const processInstructions = [\n {\n shouldProcessNode: (node) => node.name === 'img', // disable images\n processNode(node, children, index) {\n return \n 加载音频\n
\n );\n if (this.state.state === 'loading') return正在下载……
;\n else if (this.state.state === 'decoding') return正在解码……
;\n else if (this.state.state === 'loaded')\n return (\n\n \n
\n );\n }\n}\n","import React, { PureComponent } from 'react';\nimport { THUHOLE_API_ROOT, get_json, API_VERSION_PARAM } from './flows_api';\nimport { Time } from './Common';\n\nexport class MessageViewer extends PureComponent {\n constructor(props) {\n super(props);\n this.state = {\n loading_status: 'idle',\n msg: [],\n };\n }\n\n componentDidMount() {\n this.load();\n }\n\n load() {\n if (this.state.loading_status === 'loading') return;\n this.setState(\n {\n loading_status: 'loading',\n },\n () => {\n fetch(\n THUHOLE_API_ROOT +\n 'api_xmcp/hole/system_msg?user_token=' +\n encodeURIComponent(this.props.token) +\n API_VERSION_PARAM(),\n )\n .then(get_json)\n .then((json) => {\n if (json.error) throw new Error(json.error);\n else\n this.setState({\n loading_status: 'done',\n msg: json.result,\n });\n })\n .catch((err) => {\n console.error(err);\n alert('' + err);\n this.setState({\n loading_status: 'failed',\n });\n });\n },\n );\n }\n\n render() {\n if (this.state.loading_status === 'loading')\n return加载中……
;\n else if (this.state.loading_status === 'failed')\n return (\n \n );\n else if (this.state.loading_status === 'done')\n return this.state.msg.map((msg) => (\n{msg.content}\n
\n 背景图片:\n \n \n #background_img \n {img_select === '##other' && (\n \n )}\n {img_select === '##color' && (\n \n )}\n
\n \n\n 夜间模式:\n \n #color_scheme\n
\n\n 选择浅色或深色模式,深色模式下将会调暗图片亮度\n
\n\n {' '}\n 设置屏蔽词 \n
\n\n \n
\n\n \n
\n{this.props.description}
\n\n 这些功能仍在测试,可能不稳定(\n 全部重置)\n
\n\n \n 修改设置后{' '}\n {\n window.location.reload();\n }}\n >\n 刷新页面\n {' '}\n 方可生效\n \n
\n\n 新功能建议或问题反馈请在 \n \n GitHub \n \n 提出。\n
\n\n {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker\n .getRegistrations()\n .then((registrations) => {\n for (let registration of registrations) {\n console.log('unregister', registration);\n registration.unregister();\n }\n });\n }\n cache().clear();\n setTimeout(() => {\n window.location.reload(true);\n }, 200);\n }}\n >\n 强制检查更新\n \n (当前版本:【{process.env.REACT_APP_BUILD_INFO || '---'}{' '}\n {process.env.NODE_ENV}】 会自动在后台检查更新并在下次访问时更新)\n
\n联系我们:thuhole at protonmail dot com
\n\n T大树洞 网页版 by @thuhole, 基于 \n \n GPLv3\n \n 协议在{' '}\n \n GitHub\n {' '}\n 开源\n
\n\n T大树洞 网页版的诞生离不开 \n \n P大树洞网页版 by @xmcp\n \n 、\n \n React\n \n 、\n \n IcoMoon\n \n 等开源项目\n
\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 3 of the License, or (at\n your option) any later version.\n
\n\n This program is distributed in the hope that it will be useful, but\n WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \n \n GNU General Public License\n \n for more details.\n
\n\n 您已登录。\n \n
\n
*/}\n {/*根据计算中心要求,访问授权三个月内有效,过期需重新登录。*/}\n {/*T大树洞将会单向加密(i.e. 哈希散列)您的邮箱后再存入数据库,因此您的发帖具有较强的匿名性。具体可见我们的后端开源代码。*/}\n {/*
*/}\n\n {\n this.props.show_sidebar(\n '系统消息',\n
\n 当您发送的内容违规时,我们将用系统消息提示您\n
\n \n 复制 User Token\n \n
\n 复制 User Token\n 可以在新设备登录,切勿告知他人。若怀疑被盗号请重新邮箱验证码登录以重置Token。\n {/*,若怀疑被盗号请尽快
\n \n
\n\n \n T大树洞\n 面向T大学生,通过T大邮箱验证您的身份并提供服务。\n \n
\n\n load_single_meta(show_sidebar, token)(pid, true)}>\n 重新加载\n \n
\n{'' + e}
\n#{this.props.info.cid}
\n {!!this.props.do_filter_name && (\n {\n this.props.do_filter_name(this.props.info.name);\n }}\n >\n \n \n )}\n \n {this.props.info.tag !== null && (\n {this.props.info.tag}\n )}\n \n \n \n #{props.info.pid}\n \n
\n \n {props.info.tag !== null && props.info.tag !== '折叠' && (\n {props.info.tag}\n )}\n \n \n {props.img_clickable ? (\n \n {\n if (e.target.src === IMAGE_BASE + props.info.url) {\n e.target.src = IMAGE_BAK_BASE + props.info.url;\n }\n }}\n alt={IMAGE_BASE + props.info.url}\n />\n \n ) : (\n
{\n if (e.target.src === IMAGE_BASE + props.info.url) {\n e.target.src = IMAGE_BAK_BASE + props.info.url;\n }\n }}\n alt={IMAGE_BASE + props.info.url}\n />\n )}\n
\n 最新回复{' '}\n \n
\n )}\n加载中……
;\n\n let show_pid = load_single_meta(this.props.show_sidebar, this.props.token);\n\n let replies_to_show = this.state.filter_name\n ? this.state.replies.filter((r) => r.name === this.state.filter_name)\n : this.state.replies.slice();\n if (this.state.rev) replies_to_show.reverse();\n\n // may not need key, for performance\n // key for lazyload elem\n // let view_mode_key =\n // (this.state.rev ? 'y-' : 'n-') + (this.state.filter_name || 'null');\n\n let replies_cnt = { [DZ_NAME]: 1 };\n replies_to_show.forEach((r) => {\n if (replies_cnt[r.name] === undefined) replies_cnt[r.name] = 0;\n replies_cnt[r.name]++;\n });\n\n // hide main thread when filtered\n let main_thread_elem =\n this.state.filter_name && this.state.filter_name !== DZ_NAME ? null : (\n\n \n {\n this.set_filter_name(null);\n }}\n >\n 还原\n \n \n \n 当前只看 \n
回复加载失败
\n{this.state.error_msg}
\n\n {\n this.load_replies();\n }}\n >\n 重新加载评论\n \n
\n{this.state.reply_error}
\n#{this.props.info.pid}
\n \n {this.props.info.tag !== null && this.props.info.tag !== '折叠' && (\n {this.props.info.tag}\n )}\n \n 已隐藏\n \n \n 重新加载\n
\n{this.state.error_msg}
\n\n {\n this.load_page(this.state.loaded_pages + 1);\n }}\n >\n 重新加载\n \n
\n{this.state.error_msg}
\n\n \n props.show_sidebar(\n 'T大树洞',\n
\n
'+fe.a.highlight(t,e,!0).value+"
"}catch(n){}return''+ge.utils.escapeHtml(e)+"
"}}).use(de.a,{throwOnError:!1,errorColor:"#aa0000"})),be=function(e){return ge.render(e)},ve="https://thuhole.com/services/thuhole";function Ee(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function _e(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:" ",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"g",a=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if(!a)return e?new RegExp("(".concat(e.split(t).filter((function(e){return!!e})).map(Ee).join("|"),")"),n):/^$/g;try{return new RegExp("("+e.slice(1,-1)+")",n)}catch(o){return/^$/g}}function we(e){return o.a.createElement("span",{className:"colored-span",style:{"--coloredspan-bgcolor-light":e.colors[0],"--coloredspan-bgcolor-dark":e.colors[1]}},e.children)}function ke(e){return/^https?:\/\//.test(e)?e:"http://"+e}a.PureComponent;var Ae=function(e){Object(u.a)(n,e);var t=Object(h.a)(n);function n(){return Object(s.a)(this,n),t.apply(this,arguments)}return Object(c.a)(n,[{key:"render",value:function(){var e=this.props,t=[{shouldProcessNode:function(e){return"img"===e.name},processNode:function(e,t,n){return o.a.createElement("div",{key:n},"[\u56fe\u7247]")}},{shouldProcessNode:function(e){return/^h[123456]$/.test(e.name)},processNode:function(e,t,n){var a=+e.name[1];a<3&&(a=3);var r="h".concat(a);return o.a.createElement(r,{key:n},t)}},{shouldProcessNode:function(e){return"a"===e.name},processNode:function(e,t,n){return o.a.createElement("a",{href:ke(e.attribs.href),target:"_blank",rel:"noopenner noreferrer",className:"ext-link",key:n},t,o.a.createElement("span",{className:"icon icon-new-tab"}))}},{shouldProcessNode:function(e){return"text"===e.type&&(!e.parent||!e.parent.attribs||"application/x-tex"!==e.parent.attribs.encoding)},processNode:function(t,n,a){var r=O(t.data,[["url_pid",k],["url",y],["pid",w],["nickname",A]]);return o.a.createElement(o.a.Fragment,{key:a},r.map((function(t,n){var a=Object(p.a)(t,2),r=a[0],i=a[1];return o.a.createElement("span",{key:n},"url_pid"===r?o.a.createElement("span",{className:"url-pid-link",title:i},"/##"):"url"===r?o.a.createElement("a",{href:ke(i),className:"ext-link",target:"_blank",rel:"noopener noreferrer"},i,o.a.createElement("span",{className:"icon icon-new-tab"})):"pid"===r?o.a.createElement("a",{href:"#"+i,onClick:function(t){t.preventDefault(),e.show_pid(i.substring(1))}},i):"nickname"===r?o.a.createElement(we,{colors:e.color_picker.get(i)},i):"search"===r?o.a.createElement("span",{className:"search-query-highlight"},i):i)})))}},{shouldProcessNode:function(){return!0},processNode:new le.a.ProcessNodeDefinitions(o.a).processDefaultNode}],n=new le.a.Parser;if(e.author&&e.text.match(/^(?:#+ |>|```|\t|\s*-|\s*\d+\.)/)){var a=be(e.text);return o.a.createElement(o.a.Fragment,null,e.author,n.parseWithInstructions(a,(function(e){return"script"!==e.type}),t)||"")}var r=e.text;e.author&&(r=e.author+" "+r);var i=be(r);return n.parseWithInstructions(i,(function(e){return"script"!==e.type}),t)||null}}]),n}(a.Component);window.TEXTAREA_BACKUP={};var ye=function(e){Object(u.a)(n,e);var t=Object(h.a)(n);function n(e){var a;return Object(s.a)(this,n),(a=t.call(this,e)).state={text:""},a.on_change_bound=a.on_change.bind(Object(l.a)(a)),a.on_keydown_bound=a.on_keydown.bind(Object(l.a)(a)),a.clear=a.clear.bind(Object(l.a)(a)),a.area_ref=o.a.createRef(),a.change_callback=e.on_change||function(){},a.submit_callback=e.on_submit||function(){},a}return Object(c.a)(n,[{key:"componentDidMount",value:function(){var e=this;this.setState({text:window.TEXTAREA_BACKUP[this.props.id]||""},(function(){e.change_callback(e.state.text)}))}},{key:"componentWillUnmount",value:function(){window.TEXTAREA_BACKUP[this.props.id]=this.state.text,this.change_callback(this.state.text)}},{key:"on_change",value:function(e){this.setState({text:e.target.value}),this.change_callback(e.target.value)}},{key:"on_keydown",value:function(e){"Enter"===e.key&&e.ctrlKey&&!e.altKey&&(e.preventDefault(),this.submit_callback())}},{key:"clear",value:function(){this.setState({text:""})}},{key:"set",value:function(e){this.change_callback(e),this.setState({text:e})}},{key:"get",value:function(){return this.state.text}},{key:"focus",value:function(){this.area_ref.current.focus()}},{key:"render",value:function(){return o.a.createElement("textarea",{ref:this.area_ref,onChange:this.on_change_bound,value:this.state.text,onKeyDown:this.on_keydown_bound})}}]),n}(a.Component),Oe=null;function xe(e){var t=/iPhone|iPad|iPod/i.test(window.navigator.userAgent);return window.matchMedia("(display-mode: standalone)").matches||window.navigator.standalone?null:t?navigator.standalone?null:o.a.createElement("div",{className:"box promotion-bar"},o.a.createElement("span",{className:"icon icon-about"}),"\xa0 \u7528 Safari \u628a\u6811\u6d1e ",o.a.createElement("b",null,"\u6dfb\u52a0\u5230\u4e3b\u5c4f\u5e55")," \u66f4\u597d\u7528"):Oe?o.a.createElement("div",{className:"box promotion-bar"},o.a.createElement("span",{className:"icon icon-about"}),"\xa0 \u628a\u7f51\u9875\u7248\u6811\u6d1e"," ",o.a.createElement("b",null,o.a.createElement("a",{onClick:function(){Oe&&Oe.prompt()}},"\u5b89\u88c5\u5230\u684c\u9762"))," ","\u66f4\u597d\u7528"):null}window.addEventListener("beforeinstallprompt",(function(e){console.log("pwa: received before install prompt"),Oe=e}));var Ne=function(e){Object(u.a)(n,e);var t=Object(h.a)(n);function n(e){var a;return Object(s.a)(this,n),(a=t.call(this,e)).state={moved:!0,init_y:0,init_x:0},a.on_begin_bound=a.on_begin.bind(Object(l.a)(a)),a.on_move_bound=a.on_move.bind(Object(l.a)(a)),a.on_end_bound=a.on_end.bind(Object(l.a)(a)),a.MOVE_THRESHOLD=3,a.last_fire=0,a}return Object(c.a)(n,[{key:"on_begin",value:function(e){this.setState({moved:!1,init_y:(e.touches?e.touches[0]:e).screenY,init_x:(e.touches?e.touches[0]:e).screenX})}},{key:"on_move",value:function(e){this.state.moved||Math.abs((e.touches?e.touches[0]:e).screenY-this.state.init_y)+Math.abs((e.touches?e.touches[0]:e).screenX-this.state.init_x)>this.MOVE_THRESHOLD&&this.setState({moved:!0})}},{key:"on_end",value:function(e){this.state.moved||this.do_callback(e),this.setState({moved:!0})}},{key:"do_callback",value:function(e){this.last_fire+100>+new Date||(this.last_fire=+new Date,this.props.callback(e))}},{key:"render",value:function(){return o.a.createElement("div",{onTouchStart:this.on_begin_bound,onMouseDown:this.on_begin_bound,onTouchMove:this.on_move_bound,onMouseMove:this.on_move_bound,onClick:this.on_end_bound},this.props.children)}}]),n}(a.PureComponent);n(436);function Ce(e,t,n,a){a=a||!1,e.addEventListener?e.addEventListener(t,n,a):e.attachEvent&&e.attachEvent("on".concat(t),(function(t){n.call(e,t||window.event)}))}function je(e,t,n,a){a=a||!1,e.removeEventListener?e.removeEventListener(t,n,a):e.detachEvent&&e.detachEvent("on".concat(t),n)}var Se=function(e){if(!(e instanceof HTMLElement))return document.documentElement;for(var t="absolute"===e.style.position,n=/(scroll|auto)/,a=e;a;){if(!a.parentNode)return e.ownerDocument||document.documentElement;var o=window.getComputedStyle(a),r=o.position,i=o.overflow,s=o["overflow-x"],c=o["overflow-y"];if("static"===r&&t)a=a.parentNode;else{if(n.test(i)&&n.test(s)&&n.test(c))return a;a=a.parentNode}}return e.ownerDocument||e.documentElement||document.documentElement};var Ie=0,De=0,Ue="data-lazyload-listened",Re=[],He=[],Te=!1;try{var Le=Object.defineProperty({},"passive",{get:function(){Te=!0}});window.addEventListener("test",null,Le)}catch(Rt){}var Qe,Me=!!Te&&{capture:!1,passive:!0},Pe=function(e){var t=i.a.findDOMNode(e);if(t instanceof HTMLElement){var n=Se(t);(e.props.overflow&&n!==t.ownerDocument&&n!==document&&n!==document.documentElement?function(e,t){var n,a,o=i.a.findDOMNode(e);try{var r=t.getBoundingClientRect();n=r.top,a=r.height}catch(Rt){n=Ie,a=De}var s,c,l=window.innerHeight||document.documentElement.clientHeight,u=Math.max(n,0),h=Math.min(l,n+a)-u;try{var p=o.getBoundingClientRect();s=p.top,c=p.height}catch(Rt){s=Ie,c=De}var d=s-u,m=Array.isArray(e.props.offset)?e.props.offset:[e.props.offset,e.props.offset];return d-m[0]<=h&&d+c+m[1]>=0}(e,n):function(e){var t,n,a=i.a.findDOMNode(e);if(!(a.offsetWidth||a.offsetHeight||a.getClientRects().length))return!1;try{var o=a.getBoundingClientRect();t=o.top,n=o.height}catch(Rt){t=Ie,n=De}var r=window.innerHeight||document.documentElement.clientHeight,s=Array.isArray(e.props.offset)?e.props.offset:[e.props.offset,e.props.offset];return t-s[0]<=r&&t+n+s[1]>=0}(e))?e.state.visible&&!e.state.hidden||(e.props.once&&He.push(e),e.setState({visible:!0,hidden:!1})):e.props.once||(e.props.unmountIfInvisible?!0===e.visible&&e.setState({visible:!1}):e.props.hiddenIfInvisible&&!1===e.state.hidden&&e.setState({hidden:!0}))}},Ge=function(){for(var e=0;e'+fe.a.highlight(t,e,!0).value+"
"}catch(n){}return''+ge.utils.escapeHtml(e)+"
"}}).use(de.a,{throwOnError:!1,errorColor:"#aa0000"})),be=function(e){return ge.render(e)},ve="https://thuhole.com/services/thuhole";function Ee(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function _e(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:" ",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"g",a=arguments.length>3&&void 0!==arguments[3]&&arguments[3];if(!a)return e?new RegExp("(".concat(e.split(t).filter((function(e){return!!e})).map(Ee).join("|"),")"),n):/^$/g;try{return new RegExp("("+e.slice(1,-1)+")",n)}catch(o){return/^$/g}}function we(e){return o.a.createElement("span",{className:"colored-span",style:{"--coloredspan-bgcolor-light":e.colors[0],"--coloredspan-bgcolor-dark":e.colors[1]}},e.children)}function ke(e){return/^https?:\/\//.test(e)?e:"http://"+e}a.PureComponent;var Ae=function(e){Object(u.a)(n,e);var t=Object(h.a)(n);function n(){return Object(s.a)(this,n),t.apply(this,arguments)}return Object(c.a)(n,[{key:"render",value:function(){var e=this.props,t=[{shouldProcessNode:function(e){return"img"===e.name},processNode:function(e,t,n){return o.a.createElement("div",{key:n},"[\u56fe\u7247]")}},{shouldProcessNode:function(e){return/^h[123456]$/.test(e.name)},processNode:function(e,t,n){var a=+e.name[1];a<3&&(a=3);var r="h".concat(a);return o.a.createElement(r,{key:n},t)}},{shouldProcessNode:function(e){return"a"===e.name},processNode:function(e,t,n){return o.a.createElement("a",{href:ke(e.attribs.href),target:"_blank",rel:"noopenner noreferrer",className:"ext-link",key:n},t,o.a.createElement("span",{className:"icon icon-new-tab"}))}},{shouldProcessNode:function(e){return"text"===e.type&&(!e.parent||!e.parent.attribs||"application/x-tex"!==e.parent.attribs.encoding)},processNode:function(t,n,a){var r=O(t.data,[["url_pid",k],["url",y],["pid",w],["nickname",A]]);return o.a.createElement(o.a.Fragment,{key:a},r.map((function(t,n){var a=Object(p.a)(t,2),r=a[0],i=a[1];return o.a.createElement("span",{key:n},"url_pid"===r?o.a.createElement("span",{className:"url-pid-link",title:i},"/##"):"url"===r?o.a.createElement("a",{href:ke(i),className:"ext-link",target:"_blank",rel:"noopener noreferrer"},i,o.a.createElement("span",{className:"icon icon-new-tab"})):"pid"===r?o.a.createElement("a",{href:"#"+i,onClick:function(t){t.preventDefault(),e.show_pid(i.substring(1))}},i):"nickname"===r?o.a.createElement(we,{colors:e.color_picker.get(i)},i):"search"===r?o.a.createElement("span",{className:"search-query-highlight"},i):i)})))}},{shouldProcessNode:function(){return!0},processNode:new le.a.ProcessNodeDefinitions(o.a).processDefaultNode}],n=new le.a.Parser;if(e.author&&e.text.match(/^(?:#+ |>|```|\t|\s*-|\s*\d+\.)/)){var a=be(e.text);return o.a.createElement(o.a.Fragment,null,e.author,n.parseWithInstructions(a,(function(e){return"script"!==e.type}),t)||"")}var r=e.text;e.author&&(r=e.author+" "+r);var i=be(r);return n.parseWithInstructions(i,(function(e){return"script"!==e.type}),t)||null}}]),n}(a.Component);window.TEXTAREA_BACKUP={};var ye=function(e){Object(u.a)(n,e);var t=Object(h.a)(n);function n(e){var a;return Object(s.a)(this,n),(a=t.call(this,e)).state={text:""},a.on_change_bound=a.on_change.bind(Object(l.a)(a)),a.on_keydown_bound=a.on_keydown.bind(Object(l.a)(a)),a.clear=a.clear.bind(Object(l.a)(a)),a.area_ref=o.a.createRef(),a.change_callback=e.on_change||function(){},a.submit_callback=e.on_submit||function(){},a}return Object(c.a)(n,[{key:"componentDidMount",value:function(){var e=this;this.setState({text:window.TEXTAREA_BACKUP[this.props.id]||""},(function(){e.change_callback(e.state.text)}))}},{key:"componentWillUnmount",value:function(){window.TEXTAREA_BACKUP[this.props.id]=this.state.text,this.change_callback(this.state.text)}},{key:"on_change",value:function(e){this.setState({text:e.target.value}),this.change_callback(e.target.value)}},{key:"on_keydown",value:function(e){"Enter"===e.key&&e.ctrlKey&&!e.altKey&&(e.preventDefault(),this.submit_callback())}},{key:"clear",value:function(){this.setState({text:""})}},{key:"set",value:function(e){this.change_callback(e),this.setState({text:e})}},{key:"get",value:function(){return this.state.text}},{key:"focus",value:function(){this.area_ref.current.focus()}},{key:"render",value:function(){return o.a.createElement("textarea",{ref:this.area_ref,onChange:this.on_change_bound,value:this.state.text,onKeyDown:this.on_keydown_bound})}}]),n}(a.Component),Oe=null;function xe(e){var t=/iPhone|iPad|iPod/i.test(window.navigator.userAgent);return window.matchMedia("(display-mode: standalone)").matches||window.navigator.standalone?null:t?navigator.standalone?null:o.a.createElement("div",{className:"box promotion-bar"},o.a.createElement("span",{className:"icon icon-about"}),"\xa0 \u7528 Safari \u628a\u6811\u6d1e ",o.a.createElement("b",null,"\u6dfb\u52a0\u5230\u4e3b\u5c4f\u5e55")," \u66f4\u597d\u7528"):Oe?o.a.createElement("div",{className:"box promotion-bar"},o.a.createElement("span",{className:"icon icon-about"}),"\xa0 \u628a\u7f51\u9875\u7248\u6811\u6d1e"," ",o.a.createElement("b",null,o.a.createElement("a",{onClick:function(){Oe&&Oe.prompt()}},"\u5b89\u88c5\u5230\u684c\u9762"))," ","\u66f4\u597d\u7528"):null}window.addEventListener("beforeinstallprompt",(function(e){console.log("pwa: received before install prompt"),Oe=e}));var Ne=function(e){Object(u.a)(n,e);var t=Object(h.a)(n);function n(e){var a;return Object(s.a)(this,n),(a=t.call(this,e)).state={moved:!0,init_y:0,init_x:0},a.on_begin_bound=a.on_begin.bind(Object(l.a)(a)),a.on_move_bound=a.on_move.bind(Object(l.a)(a)),a.on_end_bound=a.on_end.bind(Object(l.a)(a)),a.MOVE_THRESHOLD=3,a.last_fire=0,a}return Object(c.a)(n,[{key:"on_begin",value:function(e){this.setState({moved:!1,init_y:(e.touches?e.touches[0]:e).screenY,init_x:(e.touches?e.touches[0]:e).screenX})}},{key:"on_move",value:function(e){this.state.moved||Math.abs((e.touches?e.touches[0]:e).screenY-this.state.init_y)+Math.abs((e.touches?e.touches[0]:e).screenX-this.state.init_x)>this.MOVE_THRESHOLD&&this.setState({moved:!0})}},{key:"on_end",value:function(e){this.state.moved||this.do_callback(e),this.setState({moved:!0})}},{key:"do_callback",value:function(e){this.last_fire+100>+new Date||(this.last_fire=+new Date,this.props.callback(e))}},{key:"render",value:function(){return o.a.createElement("div",{onTouchStart:this.on_begin_bound,onMouseDown:this.on_begin_bound,onTouchMove:this.on_move_bound,onMouseMove:this.on_move_bound,onClick:this.on_end_bound},this.props.children)}}]),n}(a.PureComponent);n(436);function Ce(e,t,n,a){a=a||!1,e.addEventListener?e.addEventListener(t,n,a):e.attachEvent&&e.attachEvent("on".concat(t),(function(t){n.call(e,t||window.event)}))}function je(e,t,n,a){a=a||!1,e.removeEventListener?e.removeEventListener(t,n,a):e.detachEvent&&e.detachEvent("on".concat(t),n)}var Se=function(e){if(!(e instanceof HTMLElement))return document.documentElement;for(var t="absolute"===e.style.position,n=/(scroll|auto)/,a=e;a;){if(!a.parentNode)return e.ownerDocument||document.documentElement;var o=window.getComputedStyle(a),r=o.position,i=o.overflow,s=o["overflow-x"],c=o["overflow-y"];if("static"===r&&t)a=a.parentNode;else{if(n.test(i)&&n.test(s)&&n.test(c))return a;a=a.parentNode}}return e.ownerDocument||e.documentElement||document.documentElement};var Ie=0,De=0,Ue="data-lazyload-listened",Re=[],He=[],Te=!1;try{var Le=Object.defineProperty({},"passive",{get:function(){Te=!0}});window.addEventListener("test",null,Le)}catch(Rt){}var Qe,Me=!!Te&&{capture:!1,passive:!0},Pe=function(e){var t=i.a.findDOMNode(e);if(t instanceof HTMLElement){var n=Se(t);(e.props.overflow&&n!==t.ownerDocument&&n!==document&&n!==document.documentElement?function(e,t){var n,a,o=i.a.findDOMNode(e);try{var r=t.getBoundingClientRect();n=r.top,a=r.height}catch(Rt){n=Ie,a=De}var s,c,l=window.innerHeight||document.documentElement.clientHeight,u=Math.max(n,0),h=Math.min(l,n+a)-u;try{var p=o.getBoundingClientRect();s=p.top,c=p.height}catch(Rt){s=Ie,c=De}var d=s-u,m=Array.isArray(e.props.offset)?e.props.offset:[e.props.offset,e.props.offset];return d-m[0]<=h&&d+c+m[1]>=0}(e,n):function(e){var t,n,a=i.a.findDOMNode(e);if(!(a.offsetWidth||a.offsetHeight||a.getClientRects().length))return!1;try{var o=a.getBoundingClientRect();t=o.top,n=o.height}catch(Rt){t=Ie,n=De}var r=window.innerHeight||document.documentElement.clientHeight,s=Array.isArray(e.props.offset)?e.props.offset:[e.props.offset,e.props.offset];return t-s[0]<=r&&t+n+s[1]>=0}(e))?e.state.visible&&!e.state.hidden||(e.props.once&&He.push(e),e.setState({visible:!0,hidden:!1})):e.props.once||(e.props.unmountIfInvisible?!0===e.visible&&e.setState({visible:!1}):e.props.hiddenIfInvisible&&!1===e.state.hidden&&e.setState({hidden:!0}))}},Ge=function(){for(var e=0;e\n {props.text}\n
\n )\n}\n\nexport function GlobalTitle(props) {\n return (\n{props.text}
\n\n// {!!dropdown_cur_app ?\n// app_elem((()=>{\n// let [id,title,_url,icon_normal,icon_hover,_new_tab]=dropdown_cur_app;\n// return [id,title+'▾',null,icon_normal,icon_hover,false];\n// })(),true) :\n// app_elem(['-placeholder-elem','更多▾',null,appicon_dropdown,appicon_dropdown_rev,false],true)\n// }\n//
\n// {this.state.apps.dropdown.map((app)=>{\n// let ref=React.createRef();\n// return (\n//{\n// if(!e.target.closest('a') && ref.current)\n// ref.current.click();\n// }}>\n// {app_elem(app,true,ref)}\n//
\n// );\n// })}\n//\n 接收验证码来登录 T大树洞\n
\n\n \n \n {/*this.do_sendcode('sms')}>*/}\n {/* 短信 */}\n {/**/}\n {/*/*/}\n this.do_sendcode('mail')}>\n 发送邮件 \n \n \n
\n\n \n \n
\n\n 从其他设备导入登录状态\n
\n\n \n \n
\n\n This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.\n
\n\n \n
\n' +\n hljs.highlight(lang, str, true).value +\n '
'\n );\n } catch (__) {}\n }\n return (\n '' + md.utils.escapeHtml(str) + '
'\n );\n },\n}).use(MarkdownItKaTeX, {\n throwOnError: false,\n errorColor: '#aa0000',\n});\n\nexport default (text) => md.render(text);\n","import React, { Component, PureComponent } from 'react';\nimport { format_time, Time, TitleLine } from './infrastructure/widgets';\nimport { THUHOLE_API_ROOT } from './flows_api';\n\nimport HtmlToReact from 'html-to-react';\n\nimport './Common.css';\nimport {\n URL_PID_RE,\n URL_RE,\n PID_RE,\n NICKNAME_RE,\n split_text,\n} from './text_splitter';\n\nimport renderMd from './Markdown';\n\nexport { format_time, Time, TitleLine };\n\nexport const API_BASE = THUHOLE_API_ROOT + 'services/thuhole';\n\n// https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex\nfunction escape_regex(string) {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'); // $& means the whole matched string\n}\n\nexport function build_highlight_re(\n txt,\n split = ' ',\n option = 'g',\n isRegex = false,\n) {\n if (isRegex) {\n try {\n return new RegExp('(' + txt.slice(1, -1) + ')', option);\n } catch (e) {\n return /^$/g;\n }\n } else {\n return txt\n ? new RegExp(\n `(${txt\n .split(split)\n .filter((x) => !!x)\n .map(escape_regex)\n .join('|')})`,\n option,\n )\n : /^$/g;\n }\n}\n\nexport function ColoredSpan(props) {\n return (\n \n {props.children}\n \n );\n}\n\nfunction normalize_url(url) {\n return /^https?:\\/\\//.test(url) ? url : 'http://' + url;\n}\n\nexport class HighlightedText extends PureComponent {\n render() {\n return (\n \n {this.props.parts.map((part, idx) => {\n let [rule, p] = part;\n return (\n \n {rule === 'url_pid' ? (\n \n /##\n \n ) : rule === 'url' ? (\n \n {p}\n \n ) : rule === 'pid' ? (\n {\n e.preventDefault();\n this.props.show_pid(p.substring(1));\n }}\n >\n {p}\n \n ) : rule === 'nickname' ? (\n \n {p}\n \n ) : rule === 'search' ? (\n {p}\n ) : (\n p\n )}\n \n );\n })}\n
\n );\n }\n}\n\n// props: text, show_pid, color_picker\nexport class HighlightedMarkdown extends Component {\n render() {\n const props = this.props;\n const processDefs = new HtmlToReact.ProcessNodeDefinitions(React);\n const processInstructions = [\n {\n shouldProcessNode: (node) => node.name === 'img', // disable images\n processNode(node, children, index) {\n return \n 加载音频\n
\n );\n if (this.state.state === 'loading') return正在下载……
;\n else if (this.state.state === 'decoding') return正在解码……
;\n else if (this.state.state === 'loaded')\n return (\n\n \n
\n );\n }\n}\n","import React, { PureComponent } from 'react';\nimport { THUHOLE_API_ROOT, get_json, API_VERSION_PARAM } from './flows_api';\nimport { Time } from './Common';\n\nexport class MessageViewer extends PureComponent {\n constructor(props) {\n super(props);\n this.state = {\n loading_status: 'idle',\n msg: [],\n };\n }\n\n componentDidMount() {\n this.load();\n }\n\n load() {\n if (this.state.loading_status === 'loading') return;\n this.setState(\n {\n loading_status: 'loading',\n },\n () => {\n fetch(\n THUHOLE_API_ROOT +\n 'api_xmcp/hole/system_msg?user_token=' +\n encodeURIComponent(this.props.token) +\n API_VERSION_PARAM(),\n )\n .then(get_json)\n .then((json) => {\n if (json.error) throw new Error(json.error);\n else\n this.setState({\n loading_status: 'done',\n msg: json.result,\n });\n })\n .catch((err) => {\n console.error(err);\n alert('' + err);\n this.setState({\n loading_status: 'failed',\n });\n });\n },\n );\n }\n\n render() {\n if (this.state.loading_status === 'loading')\n return加载中……
;\n else if (this.state.loading_status === 'failed')\n return (\n \n );\n else if (this.state.loading_status === 'done')\n return this.state.msg.map((msg) => (\n{msg.content}\n
\n 背景图片:\n \n \n #background_img \n {img_select === '##other' && (\n \n )}\n {img_select === '##color' && (\n \n )}\n
\n \n\n 夜间模式:\n \n #color_scheme\n
\n\n 选择浅色或深色模式,深色模式下将会调暗图片亮度\n
\n\n {' '}\n 设置屏蔽词 \n
\n\n \n
\n\n \n
\n{this.props.description}
\n\n 这些功能仍在测试,可能不稳定(\n 全部重置)\n
\n\n \n 修改设置后{' '}\n {\n window.location.reload();\n }}\n >\n 刷新页面\n {' '}\n 方可生效\n \n
\n\n 新功能建议或问题反馈请在 \n \n GitHub \n \n 提出。\n
\n\n {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker\n .getRegistrations()\n .then((registrations) => {\n for (let registration of registrations) {\n console.log('unregister', registration);\n registration.unregister();\n }\n });\n }\n cache().clear();\n setTimeout(() => {\n window.location.reload(true);\n }, 200);\n }}\n >\n 强制检查更新\n \n (当前版本:【{process.env.REACT_APP_BUILD_INFO || '---'}{' '}\n {process.env.NODE_ENV}】 会自动在后台检查更新并在下次访问时更新)\n
\n联系我们:thuhole at protonmail dot com
\n\n T大树洞 网页版 by @thuhole, 基于 \n \n GPLv3\n \n 协议在{' '}\n \n GitHub\n {' '}\n 开源\n
\n\n T大树洞 网页版的诞生离不开 \n \n P大树洞网页版 by @xmcp\n \n 、\n \n React\n \n 、\n \n IcoMoon\n \n 等开源项目\n
\n\n This program is free software: you can redistribute it and/or modify\n it under the terms of the GNU General Public License as published by\n the Free Software Foundation, either version 3 of the License, or (at\n your option) any later version.\n
\n\n This program is distributed in the hope that it will be useful, but\n WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \n \n GNU General Public License\n \n for more details.\n
\n\n 您已登录。\n \n
\n
*/}\n {/*根据计算中心要求,访问授权三个月内有效,过期需重新登录。*/}\n {/*T大树洞将会单向加密(i.e. 哈希散列)您的邮箱后再存入数据库,因此您的发帖具有较强的匿名性。具体可见我们的后端开源代码。*/}\n {/*
*/}\n\n {\n this.props.show_sidebar(\n '系统消息',\n
\n 当您发送的内容违规时,我们将用系统消息提示您\n
\n \n 复制 User Token\n \n
\n 复制 User Token\n 可以在新设备登录,切勿告知他人。若怀疑被盗号请重新邮箱验证码登录以重置Token。\n {/*,若怀疑被盗号请尽快
\n \n
\n\n \n T大树洞\n 面向T大学生,通过T大邮箱验证您的身份并提供服务。\n \n
\n\n load_single_meta(show_sidebar, token)(pid, true)}>\n 重新加载\n \n
\n{'' + e}
\n#{this.props.info.cid}
\n {!!this.props.do_filter_name && (\n {\n this.props.do_filter_name(this.props.info.name);\n }}\n >\n \n \n )}\n \n {this.props.info.tag !== null && (\n {this.props.info.tag}\n )}\n \n \n \n #{props.info.pid}\n \n
\n \n {props.info.tag !== null && props.info.tag !== '折叠' && (\n {props.info.tag}\n )}\n \n \n {props.img_clickable ? (\n \n {\n if (e.target.src === IMAGE_BASE + props.info.url) {\n e.target.src = IMAGE_BAK_BASE + props.info.url;\n }\n }}\n alt={IMAGE_BASE + props.info.url}\n />\n \n ) : (\n
{\n if (e.target.src === IMAGE_BASE + props.info.url) {\n e.target.src = IMAGE_BAK_BASE + props.info.url;\n }\n }}\n alt={IMAGE_BASE + props.info.url}\n />\n )}\n
\n 最新回复{' '}\n \n
\n )}\n加载中……
;\n\n let show_pid = load_single_meta(this.props.show_sidebar, this.props.token);\n\n let replies_to_show = this.state.filter_name\n ? this.state.replies.filter((r) => r.name === this.state.filter_name)\n : this.state.replies.slice();\n if (this.state.rev) replies_to_show.reverse();\n\n // may not need key, for performance\n // key for lazyload elem\n // let view_mode_key =\n // (this.state.rev ? 'y-' : 'n-') + (this.state.filter_name || 'null');\n\n let replies_cnt = { [DZ_NAME]: 1 };\n replies_to_show.forEach((r) => {\n if (replies_cnt[r.name] === undefined) replies_cnt[r.name] = 0;\n replies_cnt[r.name]++;\n });\n\n // hide main thread when filtered\n let main_thread_elem =\n this.state.filter_name && this.state.filter_name !== DZ_NAME ? null : (\n\n \n {\n this.set_filter_name(null);\n }}\n >\n 还原\n \n \n \n 当前只看 \n
回复加载失败
\n{this.state.error_msg}
\n\n {\n this.load_replies();\n }}\n >\n 重新加载评论\n \n
\n{this.state.reply_error}
\n#{this.props.info.pid}
\n \n {this.props.info.tag !== null && this.props.info.tag !== '折叠' && (\n {this.props.info.tag}\n )}\n \n {this.needFold ? '已隐藏' : '已屏蔽'}\n \n \n 重新加载\n
\n{this.state.error_msg}
\n\n {\n this.load_page(this.state.loaded_pages + 1);\n }}\n >\n 重新加载\n \n
\n{this.state.error_msg}
\n\n \n props.show_sidebar(\n 'T大树洞',\n
\n