知乎增强

移除登录弹窗、一键收起回答、收起当前回答/评论(点击两侧空白处)、快捷回到顶部(右键两侧空白处)、屏蔽指定用户、屏蔽盐选内容、置顶显示时间、显示问题时间、区分问题文章、默认高清原图、默认站外直链

当前为 2021-05-23 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name 知乎增强
  3. // @version 1.4.2
  4. // @author X.I.U
  5. // @description 移除登录弹窗、一键收起回答、收起当前回答/评论(点击两侧空白处)、快捷回到顶部(右键两侧空白处)、屏蔽指定用户、屏蔽盐选内容、置顶显示时间、显示问题时间、区分问题文章、默认高清原图、默认站外直链
  6. // @match *://www.zhihu.com/*
  7. // @match *://zhuanlan.zhihu.com/*
  8. // @icon https://static.zhihu.com/heifetz/favicon.ico
  9. // @grant GM_registerMenuCommand
  10. // @grant GM_unregisterMenuCommand
  11. // @grant GM_openInTab
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // @grant GM_notification
  15. // @license GPL-3.0 License
  16. // @run-at document-end
  17. // @namespace https://greasyfork.org/scripts/412205
  18. // ==/UserScript==
  19.  
  20. var menu_ALL = [
  21. ['menu_collapsedAnswer', '一键收起回答', '一键收起回答', true],
  22. ['menu_collapsedNowAnswer', '收起当前回答/评论(点击两侧空白处)', '收起当前回答/评论', true],
  23. ['menu_backToTop', '快捷回到顶部(右键两侧空白处)', '快捷回到顶部', true],
  24. ['menu_blockUsers', '屏蔽指定用户', '屏蔽指定用户', false],
  25. ['menu_customBlockUsers', '自定义屏蔽用户', '自定义屏蔽用户', ['故事档案局', '盐选推荐', '盐选科普', '盐选成长计划', '知乎盐选会员', '知乎盐选创作者', '盐选心理', '盐选健康必修课', '盐选奇妙物语', '盐选生活馆', '盐选职场', '盐选文学甄选', '盐选作者小管家', '盐选博物馆', '盐选点金', '盐选测评室', '盐选科技前沿', '盐选会员精品']],
  26. ['menu_blockYanXuan', '屏蔽盐选内容', '屏蔽盐选内容', false],
  27. ['menu_publishTop', '置顶显示时间', '置顶显示时间', true],
  28. ['menu_allTime', '完整显示时间', '完整显示时间', true],
  29. ['menu_typeTips', '区分问题文章', '区分问题文章', true],
  30. ['menu_directLink', '默认站外直链', '默认站外直链', true]
  31. ], menu_ID = [];
  32. for (let i=0;i<menu_ALL.length;i++){ // 如果读取到的值为 null 就写入默认值
  33. if (GM_getValue(menu_ALL[i][0]) == null){GM_setValue(menu_ALL[i][0], menu_ALL[i][3])};
  34. }
  35. registerMenuCommand();
  36.  
  37. // 注册脚本菜单
  38. function registerMenuCommand() {
  39. if (menu_ID.length > menu_ALL.length){ // 如果菜单ID数组多于菜单数组,说明不是首次添加菜单,需要卸载所有脚本菜单
  40. for (let i=0;i<menu_ID.length;i++){
  41. GM_unregisterMenuCommand(menu_ID[i]);
  42. }
  43. }
  44. for (let i=0;i<menu_ALL.length;i++){ // 循环注册脚本菜单
  45. menu_ALL[i][3] = GM_getValue(menu_ALL[i][0]);
  46. if (menu_ALL[i][0] === 'menu_customBlockUsers') {
  47. menu_ID[i] = GM_registerMenuCommand(`[ ] ${menu_ALL[i][1]}`, function(){customBlockUsers()});
  48. } else {
  49. menu_ID[i] = GM_registerMenuCommand(`[ ${menu_ALL[i][3]?'√':'×'} ] ${menu_ALL[i][1]}`, function(){menu_switch(`${menu_ALL[i][3]}`,`${menu_ALL[i][0]}`,`${menu_ALL[i][2]}`)});
  50. }
  51. }
  52. menu_ID[menu_ID.length] = GM_registerMenuCommand('反馈 & 建议', function () {window.GM_openInTab('https://github.com/XIU2/UserScript#xiu2userscript', {active: true,insert: true,setParent: true});window.GM_openInTab('https://greasyfork.org/zh-CN/scripts/419081/feedback', {active: true,insert: true,setParent: true});});
  53. }
  54.  
  55.  
  56. // 菜单开关
  57. function menu_switch(menu_status, Name, Tips) {
  58. if (menu_status == 'true'){
  59. GM_setValue(`${Name}`, false);
  60. GM_notification({text: `已关闭 [${Tips}] 功能\n(刷新网页后生效)`, timeout: 3500});
  61. }else{
  62. GM_setValue(`${Name}`, true);
  63. GM_notification({text: `已开启 [${Tips}] 功能\n(刷新网页后生效)`, timeout: 3500});
  64. }
  65. registerMenuCommand(); // 重新注册脚本菜单
  66. };
  67.  
  68.  
  69. // 返回菜单值
  70. function menu_value(menuName) {
  71. for (let menu of menu_ALL) {
  72. if (menu[0] == menuName) {
  73. return menu[3]
  74. }
  75. }
  76. }
  77.  
  78.  
  79. // 一键收起回答
  80. function collapsedAnswer() {
  81. if (!menu_value('menu_collapsedAnswer')) return
  82. let button_Add = `<button id="collapsed-button" data-tooltip="收起回答" data-tooltip-position="left" data-tooltip-will-hide-on-click="false" aria-label="收起回答" type="button" class="Button CornerButton Button--plain"><svg class="ContentItem-arrowIcon is-active" aria-label="收起回答" fill="currentColor" viewBox="0 0 24 24" width="24" height="24"><path d="M16.036 19.59a1 1 0 0 1-.997.995H9.032a.996.996 0 0 1-.997-.996v-7.005H5.03c-1.1 0-1.36-.633-.578-1.416L11.33 4.29a1.003 1.003 0 0 1 1.412 0l6.878 6.88c.782.78.523 1.415-.58 1.415h-3.004v7.005z"></path></svg></button>`
  83. let style_Add = document.createElement('style');
  84. style_Add.innerHTML = '.CornerButton{margin-bottom:8px !important;}.CornerButtons{bottom:45px !important;}';
  85. document.head.appendChild(style_Add);
  86. document.querySelector('.CornerAnimayedFlex').insertAdjacentHTML('afterBegin', button_Add);
  87. document.getElementById('collapsed-button').onclick = function () {
  88. document.querySelectorAll('.ContentItem-rightButton').forEach(function (el) {
  89. if (el.hasAttribute('data-zop-retract-question')) {
  90. el.click()
  91. }
  92. });
  93. }
  94. }
  95.  
  96.  
  97. // 收起当前回答、评论(监听点击事件,点击网页两侧空白处)
  98. function collapsedNowAnswer(selectors) {
  99. backToTop(selectors) // 快捷回到顶部
  100. if (!menu_value('menu_collapsedNowAnswer')) return
  101. document.querySelector(selectors).onclick = function(event){
  102. if (event.target==this) {
  103. let rightButton = document.querySelector('.ContentItem-actions.Sticky.RichContent-actions.is-fixed.is-bottom')
  104. if (rightButton) { // 悬浮的 [收起回答](此时正在浏览回答内容 [头部区域 + 中间区域])
  105. // 固定的 [收起评论](先看看是否展开评论)
  106. let commentCollapseButton = rightButton.querySelector('button.Button.ContentItem-action.Button--plain.Button--withIcon.Button--withLabel:first-of-type')
  107. if (commentCollapseButton && commentCollapseButton.innerText.indexOf('收起评论') > -1) {
  108. commentCollapseButton.click();
  109. }
  110. // 再去收起回答
  111. rightButton = rightButton.querySelector('.ContentItem-rightButton')
  112. if (rightButton && rightButton.hasAttribute('data-zop-retract-question')) {
  113. rightButton.click();
  114. }
  115. } else { // 固定的 [收起回答](此时正在浏览回答内容 [尾部区域])
  116. for (let el of document.querySelectorAll('.ContentItem-rightButton')) {
  117. if (el.hasAttribute('data-zop-retract-question')) {
  118. if (isElementInViewport(el)) {
  119. // 固定的 [收起评论](先看看是否展开评论)
  120. let commentCollapseButton = el.parentNode.querySelector('button.Button.ContentItem-action.Button--plain.Button--withIcon.Button--withLabel:first-of-type')
  121. if (commentCollapseButton && commentCollapseButton.innerText.indexOf('收起评论') > -1) {
  122. commentCollapseButton.click(); // 如果展开了评论,就收起评论
  123. }
  124. el.click() // 再去收起回答
  125. break
  126. }
  127. }
  128. }
  129. }
  130.  
  131. var commentCollapseButton_ = false, commentCollapseButton__ = false;
  132. // 悬浮的 [收起评论](此时正在浏览评论内容 [中间区域])
  133. let commentCollapseButton = document.querySelector('.CommentCollapseButton')
  134. if (commentCollapseButton) {
  135. commentCollapseButton.click();
  136. } else { // 固定的 [收起评论](此时正在浏览评论内容 [头部区域])
  137. let commentCollapseButton_1 = document.querySelectorAll('.ContentItem-actions > button.Button.ContentItem-action.Button--plain.Button--withIcon.Button--withLabel:first-of-type, .ContentItem-action > button.Button.Button--plain.Button--withIcon.Button--withLabel:first-of-type')
  138. if (commentCollapseButton_1.length > 0) {
  139. for (let el of commentCollapseButton_1) {
  140. if (el.innerText.indexOf('收起评论') > -1) {
  141. if (isElementInViewport(el)) {
  142. el.click()
  143. commentCollapseButton_ = true // 如果找到并点击了,就没必要执行下面的代码了(可视区域中没有 [收起评论] 时)
  144. break
  145. }
  146. }
  147. }
  148. }
  149. if (commentCollapseButton_ == false) { // 可视区域中没有 [收起评论] 时(此时正在浏览评论内容 [头部区域] + [尾部区域](不上不下的,既看不到固定的 [收起评论] 又看不到悬浮的 [收起评论])),需要判断可视区域中是否存在评论元素
  150. let commentCollapseButton_1 = document.querySelectorAll('.NestComment')
  151. if (commentCollapseButton_1.length > 0) {
  152. for (let el of commentCollapseButton_1) {
  153. if (isElementInViewport(el)) {
  154. let commentCollapseButton = el.parentNode.parentNode.parentNode.parentNode.parentNode.querySelector('.ContentItem-actions > button.Button.ContentItem-action.Button--plain.Button--withIcon.Button--withLabel:first-of-type')
  155. if (commentCollapseButton.innerText.indexOf('收起评论') > -1) {
  156. commentCollapseButton.click()
  157. commentCollapseButton__ = true // 如果找到并点击了,就没必要执行下面的代码了(可视区域中没有 评论元素 时)
  158. break
  159. }
  160. }
  161. }
  162. }
  163. if (commentCollapseButton__ == false) { // 如果上面的都没找到,那么就尝试寻找评论末尾的 [评论回复框]
  164. let commentCollapseButton_2 = document.querySelectorAll('.CommentsV2-footer.CommentEditorV2--normal .CommentEditorV2-inputWrap')
  165. if (commentCollapseButton_2.length > 0) {
  166. for (let el of commentCollapseButton_2) {
  167. if (isElementInViewport(el)) {
  168. let commentCollapseButton = el.parentNode.parentNode.parentNode.parentNode.parentNode.querySelector('.ContentItem-actions > button.Button.ContentItem-action.Button--plain.Button--withIcon.Button--withLabel:first-of-type')
  169. console.log(commentCollapseButton)
  170. if (commentCollapseButton.innerText.indexOf('收起评论') > -1) {
  171. commentCollapseButton.click()
  172. break
  173. }
  174. }
  175. }
  176. }
  177. }
  178. }
  179. }
  180. }
  181. }
  182. }
  183.  
  184.  
  185. // 回到顶部(监听点击事件,鼠标右键点击网页两侧空白处)
  186. function backToTop(selectors) {
  187. if (!menu_value('menu_backToTop')) return
  188. document.querySelector(selectors).oncontextmenu = function(event){
  189. if (event.target==this) {
  190. event.preventDefault();
  191. window.scrollTo(0,0)
  192. }
  193. }
  194. }
  195.  
  196.  
  197. //获取元素是否在可视区域
  198. function isElementInViewport(el) {
  199. let rect = el.getBoundingClientRect();
  200. return (
  201. rect.top >= 0 &&
  202. rect.left >= 0 &&
  203. rect.bottom <=
  204. (window.innerHeight || document.documentElement.clientHeight) &&
  205. rect.right <=
  206. (window.innerWidth || document.documentElement.clientWidth)
  207. );
  208. }
  209.  
  210.  
  211. // 自定义屏蔽用户
  212. function customBlockUsers() {
  213. let nowBlockUsers = '';
  214. menu_value('menu_customBlockUsers').forEach(function(item){nowBlockUsers = nowBlockUsers + '|' + item})
  215. let newBlockUsers = prompt('编辑 [自定义屏蔽用户]\n(不同用户名之间使用 "|" 分隔,例如:用户A|用户B|用户C )', nowBlockUsers.replace('|',''));
  216. if (newBlockUsers === '') {
  217. GM_setValue('menu_customBlockUsers', []);
  218. registerMenuCommand(); // 重新注册脚本菜单
  219. } else if (newBlockUsers != null) {
  220. GM_setValue('menu_customBlockUsers', newBlockUsers.split('|'));
  221. registerMenuCommand(); // 重新注册脚本菜单
  222. }
  223. };
  224.  
  225.  
  226. // 屏蔽指定用户
  227. function blockUsers(type) {
  228. if (!menu_value('menu_blockUsers')) return
  229. if (!menu_value('menu_customBlockUsers') || menu_value('menu_customBlockUsers').length < 1) return
  230. switch(type) {
  231. case 'index':
  232. blockUsers_index();
  233. break;
  234. case 'question':
  235. blockUsers_question();
  236. break;
  237. case 'search':
  238. blockUsers_search();
  239. break;
  240. }
  241.  
  242. function blockUsers_index() {
  243. let blockUsers = e => {
  244. if (e.target.innerHTML && e.target.getElementsByClassName('Feed').length > 0) {
  245. let item = e.target.getElementsByClassName('Feed')[0].getElementsByClassName('ContentItem AnswerItem')[0]; // 用户名所在元素
  246. if (item) {
  247. menu_value('menu_customBlockUsers').forEach(function(item1){ // 遍历用户黑名单
  248. if (item.dataset.zop.indexOf('authorName":"' + item1 + '",') > -1) { // 找到就删除该信息流
  249. console.log(item.dataset.zop);
  250. item.parentNode.parentNode.remove();
  251. }
  252. })
  253. }
  254. }
  255. }
  256. document.addEventListener('DOMNodeInserted', blockUsers); // 监听插入事件
  257.  
  258. let listItem = document.getElementsByClassName('Card TopstoryItem TopstoryItem--old TopstoryItem-isRecommend');
  259. Array.from(listItem).forEach(function(item){ // 遍历所有回答
  260. let listName = item.querySelector('.ContentItem.AnswerItem') // 用户名所在元素
  261. if (listName) {
  262. menu_value('menu_customBlockUsers').forEach(function(item1){ // 遍历用户黑名单
  263. if (listName.dataset.zop.indexOf('authorName":"' + item1 + '",') > -1) { // 找到就删除该信息流
  264. console.log(listName.dataset.zop);
  265. item.remove();
  266. }
  267. })
  268. }
  269. })
  270. }
  271.  
  272. function blockUsers_question() {
  273. let blockUsers = e => {
  274. if (e.target.innerHTML && e.target.getElementsByClassName('ContentItem AnswerItem').length > 0) {
  275. let item = e.target.getElementsByClassName('ContentItem AnswerItem')[0]; // 用户名所在元素
  276. if (item) {
  277. menu_value('menu_customBlockUsers').forEach(function(item1){ // 遍历用户黑名单
  278. if (item.dataset.zop.indexOf('authorName":"' + item1 + '",') > -1) { // 找到就删除该回答
  279. console.log(item.dataset.zop)
  280. item.parentNode.remove();
  281. }
  282. })
  283. }
  284. }
  285. }
  286. document.addEventListener('DOMNodeInserted', blockUsers); // 监听插入事件
  287.  
  288. let listItem = document.getElementsByClassName('ContentItem AnswerItem');
  289. Array.from(listItem).forEach(function(item){ // 遍历所有回答 // 用户名所在元素
  290. if (item) {
  291. menu_value('menu_customBlockUsers').forEach(function(item1){ // 遍历用户黑名单
  292. if (item.dataset.zop.indexOf('authorName":"' + item1 + '",') > -1) { // 找到就删除该回答
  293. console.log(item.dataset.zop)
  294. item.parentNode.remove();
  295. }
  296. })
  297. }
  298. })
  299. }
  300.  
  301. function blockUsers_search() {
  302. let blockUsers = e => {
  303. if (e.target.innerHTML && e.target.getElementsByClassName('List-item').length > 0) {
  304. let item = e.target.getElementsByClassName('List-item')[0];
  305. let listName = item.querySelector('.RichText.ztext.CopyrightRichText-richText b') // 用户名所在元素
  306. if (listName) {
  307. menu_value('menu_customBlockUsers').forEach(function(item1){ // 遍历用户黑名单
  308. if (item1 === listName.innerText) { // 找到就删除该搜索结果
  309. console.log(listName.innerText);
  310. item.parentNode.remove();
  311. }
  312. })
  313. }
  314. }
  315. }
  316. document.addEventListener('DOMNodeInserted', blockUsers); // 监听插入事件
  317. }
  318. }
  319.  
  320.  
  321. // 屏蔽盐选内容
  322. function blockYanXuan() {
  323. if (!menu_value('menu_blockYanXuan')) return
  324. let blockYanXuan = e => {
  325. if (e.target.innerHTML && e.target.getElementsByClassName('KfeCollection-PurchaseBtn-mask').length > 0) {
  326. let item = e.target.getElementsByClassName('KfeCollection-PurchaseBtn-mask')[0];
  327. item.parentNode.parentNode.parentNode.parentNode.parentNode.remove();
  328. }
  329. }
  330. document.addEventListener('DOMNodeInserted', blockYanXuan); // 监听插入事件
  331.  
  332. let listItem = document.getElementsByClassName('List-item');
  333. Array.from(listItem).forEach(function(item){
  334. if (item.getElementsByClassName('KfeCollection-PurchaseBtn-mask').length > 0) {
  335. item.remove();
  336. }
  337. })
  338. }
  339.  
  340.  
  341. var postNum;
  342. // 区分问题文章
  343. function addTypeTips() {
  344. if (!menu_value('menu_typeTips')) return
  345. // URL 匹配正则表达式
  346. let patt_zhuanlan = /zhuanlan.zhihu.com/,
  347. patt_question = /question\/\d+/,
  348. patt_question_answer = /answer\/\d+/,
  349. patt_video = /\/zvideo\//,
  350. patt_tip = /zhihu_e_tips/
  351. let postList = document.querySelectorAll('h2.ContentItem-title a');
  352. postNum = document.querySelectorAll('small.zhihu_e_tips');
  353. //console.log(`${postList.length} ${postNum.length}`)
  354. if (postList.length > postNum.length) {
  355. for (let num = postNum.length;num<postList.length;num++) {
  356. if (!patt_tip.test(postList[num].innerHTML)) { // 判断是否已添加
  357. if (patt_zhuanlan.test(postList[num].href)) { // 如果是文章
  358. postList[num].innerHTML = `<small class="zhihu_e_tips" style="color: #ffffff;font-weight: normal;font-size: 12px;padding: 0 3px;border-radius: 2px;background-color: #2196F3;display: inline-block;height: 18px;">文章</small> ` + postList[num].innerHTML
  359. } else if (patt_question.test(postList[num].href)) { // 如果是问题
  360. if (!postList[num].getAttribute('data-tooltip')) { // 排除用户名后面的蓝标、黄标等链接
  361. if (patt_question_answer.test(postList[num].href)) { // 如果是指向回答的问题(而非指向纯问题的链接)
  362. postList[num].innerHTML = `<small class="zhihu_e_tips" style="color: #ffffff;font-weight: normal;font-size: 12px;padding: 0 3px;border-radius: 2px;background-color: #f68b83;display: inline-block;height: 18px;">问题</small> ` + postList[num].innerHTML
  363. } else {
  364. postList[num].innerHTML = `<small class="zhihu_e_tips" style="color: #ffffff;font-weight: normal;font-size: 12px;padding: 0 3px;border-radius: 2px;background-color: #ff5a4e;display: inline-block;height: 18px;">问题</small> ` + postList[num].innerHTML
  365. }
  366. }
  367. } else if (patt_video.test(postList[num].href)) { // 如果是视频
  368. postList[num].innerHTML = `<small class="zhihu_e_tips" style="color: #ffffff;font-weight: normal;font-size: 12px;padding: 0 3px;border-radius: 2px;background-color: #00BCD4;display: inline-block;height: 18px;">视频</small> ` + postList[num].innerHTML
  369. }
  370. //postNum += 1;
  371. }
  372. }
  373. }
  374. }
  375.  
  376.  
  377. // 监听 网页插入元素 事件
  378. function addEventListener_DOMNodeInserted() {
  379. // 知乎免登录,修改自:https://greasyfork.org/zh-CN/scripts/417126
  380. let removeLoginModal = e => {
  381. if (e.target.innerHTML && e.target.getElementsByClassName('Modal-wrapper').length > 0) {
  382. if (e.target.getElementsByClassName('Modal-wrapper')[0].querySelector('.signFlowModal')){
  383. let button = e.target.getElementsByClassName('Button Modal-closeButton Button--plain')[0];
  384. if (button)button.click();
  385. }
  386. }
  387. }
  388.  
  389. // 收起当前评论(监听点击事件,点击网页两侧空白处)
  390. let collapseNowComment = e => {
  391. if (e.target.innerHTML && e.target.getElementsByClassName('Modal-wrapper Modal-enter').length > 0) {
  392. document.getElementsByClassName('Modal-backdrop')[0].onclick = function(event){
  393. if (event.target==this) {
  394. let closeButton = document.getElementsByClassName('Modal-closeButton')[0]
  395. if(closeButton) {
  396. closeButton.click();
  397. }
  398. }
  399. }
  400. }
  401. }
  402.  
  403. // 未登录时才会监听并移除登录弹窗
  404. if(window.location.href.indexOf("zhuanlan") > -1) { // 如果是文章页
  405. if (!document.querySelector('button.ColumnPageHeader-MenuToggler')) { // 判断不存在,则已登录
  406. document.addEventListener('DOMNodeInserted', removeLoginModal);
  407. }
  408. } else { // 不是文章页
  409. if (document.querySelector('button.AppHeader-login')) { // 如果存在,则未登录
  410. document.addEventListener('DOMNodeInserted', removeLoginModal);
  411. document.querySelector('button.AppHeader-login').onclick=function(){location.href='https://www.zhihu.com/signin';} // [登录] 按钮跳转至登录页面
  412. document.querySelector('.AppHeader-profile button.Button--primary').onclick=function(){location.href='https://www.zhihu.com/signin';} // [加入知乎] 按钮跳转至注册页面(实际上是同一个页面)
  413. }
  414. }
  415.  
  416. document.addEventListener('DOMNodeInserted', collapseNowComment); // 收起当前评论(监听点击事件,点击网页两侧空白处)
  417. }
  418.  
  419.  
  420. // 监听 XMLHttpRequest 事件
  421. function EventXMLHttpRequest() {
  422. var _send = window.XMLHttpRequest.prototype.send
  423. function sendReplacement(data) {
  424. addTypeTips();
  425. return _send.apply(this, arguments);
  426. }
  427. window.XMLHttpRequest.prototype.send = sendReplacement;
  428. }
  429.  
  430.  
  431.  
  432. // [完整显示时间 + 置顶显示时间] 功能修改自:https://greasyfork.org/scripts/402808(从 JQuery 改为原生 JavaScript,且优化了代码)
  433. // 完整显示时间 + 置顶显示时间 - 首页
  434. function topTime_index() {
  435. let topTime = document.querySelectorAll('.TopstoryItem');if (!topTime) return
  436. topTime.forEach(function(_this) {
  437. let ContentItemTime = _this.querySelector('.ContentItem-time');if (!ContentItemTime) return
  438. if (!(ContentItemTime.classList.contains('full')) && ContentItemTime.querySelector('span') && ContentItemTime.querySelector('span').innerText != null) {
  439. // 完整显示时间
  440. topTime_allTime(ContentItemTime)
  441. // 发布时间置顶
  442. topTime_publishTop(ContentItemTime, _this, 'ContentItem-meta')
  443. }
  444. });
  445. }
  446.  
  447.  
  448. // 完整显示时间 + 置顶显示时间 - 回答页
  449. function topTime_question() {
  450. let topTime = document.querySelectorAll('.ContentItem.AnswerItem');if (!topTime) return
  451. topTime.forEach(function(_this) {
  452. let ContentItemTime = _this.querySelector('.ContentItem-time');if (!ContentItemTime) return
  453. if (!(ContentItemTime.classList.contains('full')) && ContentItemTime.querySelector('span') && ContentItemTime.querySelector('span').innerText != null) {
  454. // 完整显示时间
  455. topTime_allTime(ContentItemTime)
  456. // 发布时间置顶
  457. topTime_publishTop(ContentItemTime, _this, 'ContentItem-meta')
  458. }
  459.  
  460. });
  461.  
  462. // 问题创建时间
  463. if (!(document.querySelector('.QuestionPage .QuestionHeader-side p')) && window.location.href.indexOf("log") == -1) { // 没有执行过 且 非问题日志页
  464. let createtime = document.querySelector('.QuestionPage>[itemprop~=dateCreated]').getAttribute('content');
  465. let modifiedtime = document.querySelector('.QuestionPage>[itemprop~=dateModified]').getAttribute('content');
  466. createtime = getUTC8(new Date(createtime));
  467. modifiedtime = getUTC8(new Date(modifiedtime));
  468. // 添加到问题页右上角
  469. document.querySelector('.QuestionPage .QuestionHeader-side').insertAdjacentHTML('beforeEnd', '<div style=\"color:#8590a6; margin-top:15px\"><p>创建时间:&nbsp;&nbsp;' + createtime + '</p><p>最后编辑:&nbsp;&nbsp;' + modifiedtime + '</p></div>');
  470. }
  471. }
  472.  
  473.  
  474. // 完整显示时间 + 置顶显示时间 - 搜索结果页
  475. function topTime_search() {
  476. let topTime = document.querySelectorAll('.ContentItem.AnswerItem, .ContentItem.ArticleItem');if (!topTime) return
  477. topTime.forEach(function(_this) {
  478. let ContentItemTime = _this.querySelector('.ContentItem-time');if (!ContentItemTime) return
  479. if (!(ContentItemTime.classList.contains('full')) && ContentItemTime.querySelector('span') && ContentItemTime.querySelector('span').innerText != null) {
  480. // 完整显示时间
  481. topTime_allTime(ContentItemTime)
  482. // 发布时间置顶
  483. topTime_publishTop(ContentItemTime, _this, 'SearchItem-meta')
  484. }
  485.  
  486. });
  487. }
  488.  
  489.  
  490. // 完整显示时间 + 置顶显示时间 - 用户主页
  491. function topTime_people() {
  492. let topTime = document.querySelectorAll('.ContentItem.AnswerItem, .ContentItem.ArticleItem');if (!topTime) return
  493. topTime.forEach(function(_this) {
  494. let ContentItemTime = _this.querySelector('.ContentItem-time');if (!ContentItemTime) return
  495. if (!(ContentItemTime.classList.contains('full')) && ContentItemTime.querySelector('span') && ContentItemTime.querySelector('span').innerText != null) {
  496. // 完整显示时间
  497. topTime_allTime(ContentItemTime)
  498. // 发布时间置顶
  499. topTime_publishTop(ContentItemTime, _this, 'ContentItem-meta')
  500. }
  501.  
  502. });
  503. }
  504.  
  505.  
  506. // 完整显示时间 + 置顶显示时间 - 专栏/文章
  507. function topTime_zhuanlan() {
  508. let ContentItemTime = document.querySelector('.ContentItem-time');if (!ContentItemTime) return
  509. // 完整显示时间
  510. if (menu_value('menu_allTime')) {
  511. if (ContentItemTime.innerText.indexOf('编辑于') > -1 && !(ContentItemTime.classList.contains('doneeeeee'))) {
  512. let bianjiyu = ContentItemTime.innerText;
  513. ContentItemTime.click();
  514. ContentItemTime.innerText = (ContentItemTime.innerText + "," + bianjiyu)
  515. ContentItemTime.classList.add("doneeeeee");
  516. }
  517. }
  518.  
  519. //发布时间置顶
  520. if (menu_value('menu_publishTop') && !(document.querySelector('.Post-Header > .ContentItem-time')) && !(document.querySelector('.ContentItem-meta > .ContentItem-time'))) {
  521. ContentItemTime.style.cssText = 'padding:0px 0px 0px 0px; margin-top: 14px'
  522. let temp_time = ContentItemTime.cloneNode(true);
  523. // ContentItemTime.style.display = 'none';
  524. if (window.location.href.indexOf("column") > -1){
  525. document.querySelector('.ContentItem-meta').insertAdjacentElement('beforeEnd', temp_time);
  526. } else {
  527. document.querySelector('.Post-Header').insertAdjacentElement('beforeEnd', temp_time);
  528. }
  529. }
  530. }
  531.  
  532.  
  533. // 完整显示时间
  534. function topTime_allTime(ContentItemTime) {
  535. if (!menu_value('menu_allTime')) return
  536. if (ContentItemTime.innerText.indexOf("发布于") == -1 && ContentItemTime.innerText.indexOf("编辑于") > -1) { //只有 "编辑于" 时增加具体发布时间 data-tooltip
  537. let data_tooltip = ContentItemTime.querySelector('span').getAttribute('data-tooltip');
  538. let oldtext = ContentItemTime.querySelector('span').innerText;
  539. ContentItemTime.querySelector('span').innerText = data_tooltip + "," + oldtext;
  540. ContentItemTime.classList.add('full');
  541. } else if (ContentItemTime.innerText.indexOf("发布于") > -1 && ContentItemTime.innerText.indexOf("编辑于") == -1) { //只有 "发布于" 时替换为具体发布时间 data-tooltip
  542. let data_tooltip = ContentItemTime.querySelector('span').getAttribute('data-tooltip');
  543. ContentItemTime.querySelector('span').innerText = data_tooltip;
  544. ContentItemTime.classList.add('full');
  545. }
  546. }
  547.  
  548.  
  549. // 发布时间置顶
  550. function topTime_publishTop(ContentItemTime, _this, class_) {
  551. if (!menu_value('menu_publishTop')) return
  552. if (!ContentItemTime.parentNode.classList.contains(class_)) {
  553. let temp_time = ContentItemTime.cloneNode(true);
  554. //_this.querySelector('.RichContent .ContentItem-time').style.display = 'none';
  555. _this.querySelector('.' + class_).insertAdjacentElement('beforeEnd', temp_time);
  556. }
  557. }
  558.  
  559.  
  560. // UTC 标准时转 UTC+8 北京时间,来自:https://greasyfork.org/zh-CN/scripts/402808
  561. function getUTC8(datetime) {
  562. let month = (datetime.getMonth() + 1) < 10 ? "0" + (datetime.getMonth() + 1) : (datetime.getMonth() + 1);
  563. let date = datetime.getDate() < 10 ? "0" + datetime.getDate() : datetime.getDate();
  564. let hours = datetime.getHours() < 10 ? "0" + datetime.getHours() : datetime.getHours();
  565. let minutes = datetime.getMinutes() < 10 ? "0" + datetime.getMinutes() : datetime.getMinutes();
  566. let seconds = datetime.getSeconds() < 10 ? "0" + datetime.getSeconds() : datetime.getSeconds();
  567. return (datetime.getFullYear() + "-" + month + "-" + date + "\xa0\xa0" + hours + ":" + minutes + ":" + seconds);
  568. }
  569.  
  570.  
  571. // 默认站外直链,修改自:https://greasyfork.org/scripts/402808(从 JQuery 改为原生 JavaScript)
  572. function directLink () {
  573. let link, equal, colon, externalHref, protocol, path, newHref;
  574. // 文字链接
  575. link = document.querySelectorAll('a[class*="external"]')
  576. if (link) {
  577. link.forEach(function (_this) {
  578. if (_this.getElementsByTagName('span').length > 0) {
  579. newHref = _this.innerText;
  580. _this.setAttribute('href', newHref);
  581. } else if (_this.href.indexOf("link.zhihu.com/?target=") > -1) {
  582. externalHref = _this.href;
  583. newHref = externalHref.substring(externalHref = _this.href.indexOf("link.zhihu.com/?target=") + "link.zhihu.com/?target=".length);
  584. _this.setAttribute('href', decodeURIComponent(newHref));
  585. } else {
  586. externalHref = _this.href;
  587. if (externalHref.lastIndexOf("https%3A")) {
  588. newHref = _this.href.substring(_this.href.lastIndexOf("https%3A"));
  589. } else if (externalHref.lastIndexOf("http%3A%2F%2F")) {
  590. newHref = _this.href.substring(_this.href.lastIndexOf("http%3A"));
  591. }
  592. _this.setAttribute('href', decodeURIComponent(newHref));
  593. }
  594. });
  595. }
  596.  
  597. // 卡片链接
  598. link = document.querySelectorAll('a[class*="LinkCard"]:not([class*="MCNLinkCard"]):not([class*="ZVideoLinkCard"])')
  599. if (link) {
  600. link.forEach(function (_this) {
  601. if (_this.getElementsByTagName('LinkCard-title').length > 0 && _this.getElementsByTagName('LinkCard-title')[0].indexOf("http") > -1) {
  602. newHref = _this.getElementsByTagName('LinkCard-title').innerText;
  603. _this.setAttribute('href', newHref);
  604. } else if (_this.href.indexOf("link.zhihu.com/?target=") > -1) {
  605. externalHref = _this.href;
  606. newHref = externalHref.substring(externalHref = _this.href.indexOf("link.zhihu.com/?target=") + "link.zhihu.com/?target=".length);
  607. _this.setAttribute('href', decodeURIComponent(newHref));
  608. } else {
  609. externalHref = _this.href;
  610. if (externalHref.lastIndexOf("https%3A")) {
  611. newHref = _this.href.substring(_this.href.lastIndexOf("https%3A"));
  612. } else if (externalHref.lastIndexOf("http%3A%2F%2F")) {
  613. newHref = _this.href.substring(_this.href.lastIndexOf("http%3A"));
  614. }
  615. _this.setAttribute('href', decodeURIComponent(newHref));
  616. }
  617. });
  618. }
  619.  
  620. // 旧版视频卡片链接
  621. link = document.querySelectorAll('a.VideoCard-link')
  622. if (link) {
  623. link.forEach(function (_this) {
  624. if (_this.href.indexOf('link.zhihu.com/?target=') > -1) {
  625. externalHref = _this.href;
  626. equal = externalHref.lastIndexOf('http');
  627. colon = externalHref.lastIndexOf('%3A');
  628. protocol = externalHref.substring(equal, colon);
  629. path = externalHref.substring(colon + 5, externalHref.length);
  630. newHref = protocol + '://' + path;
  631. _this.setAttribute('href', decodeURIComponent(newHref));
  632. }
  633. });
  634. }
  635. }
  636.  
  637.  
  638. // 默认高清原图,修改自:https://greasyfork.org/scripts/402808(从 JQuery 改为原生 JavaScript)
  639. function originalPic(){
  640. let pic = document.getElementsByTagName('img');if (!pic) return
  641. Array.from(pic).forEach(function(pic1){
  642. if (pic1.getAttribute('data-original') != undefined && pic1.className != 'comment_sticker') {
  643. if (pic1.getAttribute('src') != pic1.getAttribute('data-original')) {
  644. pic1.setAttribute('src', pic1.getAttribute('data-original'))
  645. }
  646. }
  647. });
  648. }
  649.  
  650.  
  651. // 默认折叠邀请,修改自:https://greasyfork.org/scripts/402808(从 JQuery 改为原生 JavaScript)
  652. function questionInvitation(){
  653. let timer = setInterval(function(){
  654. let QuestionInvitation = document.querySelector('.QuestionInvitation-content');if (!QuestionInvitation) return
  655. clearInterval(timer);
  656. QuestionInvitation.style.display = "none";
  657. document.querySelector('.QuestionInvitation-title').innerHTML = document.querySelector('.QuestionInvitation-title').innerText + '<span style="color: #8590a6;font-size: 14px;"> 展开/折叠</span>'
  658. // 点击事件(展开/折叠)
  659. document.querySelector('.Topbar').onclick = function(){
  660. let QuestionInvitation = document.querySelector('.QuestionInvitation-content')
  661. if (QuestionInvitation.style.display == 'none') {
  662. QuestionInvitation.style.display = ''
  663. } else {
  664. QuestionInvitation.style.display = 'none'
  665. }
  666. }
  667. });
  668. }
  669.  
  670.  
  671. (function() {
  672. addEventListener_DOMNodeInserted(); // 监听 网页插入元素 事件
  673. questionInvitation(); // 默认折叠邀请
  674. setInterval(originalPic,100); // 默认高清原图
  675. if (menu_value('menu_directLink')) setInterval(directLink, 100); // 默认站外直链
  676.  
  677. if (window.location.href.indexOf("question") > -1) { // 回答页 //
  678. if (window.location.href.indexOf("waiting") == -1) {
  679. collapsedAnswer(); // 一键收起回答
  680. collapsedNowAnswer(".QuestionPage"); // 收起当前回答 + 快捷返回顶部
  681. collapsedNowAnswer(".Question-main"); // 收起当前回答 + 快捷返回顶部
  682. blockUsers('question'); // 屏蔽指定用户
  683. blockYanXuan(); // 屏蔽盐选内容
  684. }
  685. setInterval(topTime_question, 300); // 置顶显示时间
  686. } else if (window.location.href.indexOf("search") > -1) { // 搜索结果页 //
  687. collapsedAnswer(); // 一键收起回答
  688. collapsedNowAnswer("main div"); // 收起当前回答 + 快捷返回顶部
  689. collapsedNowAnswer(".Search-container"); // 收起当前回答 + 快捷返回顶部
  690. setInterval(topTime_search, 300); // 置顶显示时间
  691. EventXMLHttpRequest(); // 区分问题文章
  692. blockUsers('search'); // 屏蔽指定用户
  693. } else if (window.location.href.indexOf("topic") > -1) { // 话题页 //
  694. if (window.location.href.indexOf("hot") > -1 || window.location.href.indexOf("top-answers") > -1) { // 仅限 [讨论] [精华]
  695. collapsedAnswer(); // 一键收起回答
  696. collapsedNowAnswer("main.App-main"); // 收起当前回答 + 快捷返回顶部
  697. collapsedNowAnswer(".ContentLayout"); // 收起当前回答 + 快捷返回顶部
  698. setInterval(topTime_people, 300); // 置顶显示时间
  699. EventXMLHttpRequest(); // 区分问题文章
  700. }
  701. } else if (window.location.href.indexOf("zhuanlan") > -1){ // 文章 //
  702. backToTop("article.Post-Main.Post-NormalMain"); // 快捷返回顶部
  703. backToTop("div.Post-Sub.Post-NormalSub"); // 快捷返回顶部
  704. setInterval(topTime_zhuanlan, 300); // 置顶显示时间
  705. } else if (window.location.href.indexOf("column") > -1) { // 专栏 //
  706. collapsedAnswer(); // 一键收起回答
  707. collapsedNowAnswer("main div"); // 收起当前回答 + 快捷返回顶部
  708. setInterval(topTime_zhuanlan, 300); // 置顶显示时间
  709. } else if (window.location.href.indexOf("people") > -1 || window.location.href.indexOf("org") > -1) { // 用户主页 //
  710. collapsedAnswer(); // 一键收起回答
  711. collapsedNowAnswer("main div"); // 收起当前回答 + 快捷返回顶部
  712. collapsedNowAnswer(".Profile-main"); // 收起当前回答 + 快捷返回顶部
  713. setInterval(topTime_people, 300); // 置顶显示时间
  714. } else { // 首页 //
  715. collapsedAnswer(); // 一键收起回答
  716. collapsedNowAnswer("main div"); // 收起当前回答 + 快捷返回顶部
  717. collapsedNowAnswer(".Topstory-container"); // 收起当前回答 + 快捷返回顶部
  718. setInterval(topTime_index, 300); // 置顶显示时间
  719. EventXMLHttpRequest(); // 区分问题文章
  720. blockUsers('index'); // 屏蔽指定用户
  721. }
  722. })();