LLWiki正在建设中,欢迎加入我们!
MediaWiki:Gadget-TalkHelper.js
跳转到导航
跳转到搜索
注意:在保存之后,您可能需要清除浏览器缓存才能看到所作出的变更的影响。
- Firefox或Safari:按住Shift的同时单击刷新,或按Ctrl-F5或Ctrl-R(Mac为⌘-R)
- Google Chrome:按Ctrl-Shift-R(Mac为⌘-Shift-R)
- Internet Explorer:按住Ctrl的同时单击刷新,或按Ctrl-F5
- Opera:前往菜单 → 设置(Mac为Opera → Preferences),然后隐私和安全 → 清除浏览数据 → 缓存的图片和文件。
//<nowiki> // 由ResourceLoader直接调用,不可使用ES6语法 /** * @Source: [[wikipedia:user:GhostInTheMachine/TalkHelper.js]] * @Dependencies: mediawiki.storage, ext.gadget.CommentsInLocalTime, moment * @ModifiedBy: [[User:Bhsd]] * @Function: 上次访问(依赖localStorage)以来的新回复会高亮显示,同时屏幕右侧的滚动至底部按钮将修改为滚动至下一处新回复 * @Issue: 与inspect小工具的原位预览不兼容 */ "use strict"; /*global mw, $, moment, wgULS*/ const id = mw.config.get( 'wgArticleId' ), ns = mw.config.get( 'wgNamespaceNumber' ); // 包括更新localStorage在内,以下所有内容只应在阅读讨论页的最新版本(含历史版本与当前的差异)时生效 if (mw.config.get('wgAction') == 'view' && mw.config.get( 'wgRevisionId' ) == mw.config.get( 'wgCurRevisionId' ) && ns >= 0 && id > 0 && (ns % 2 == 1 || mw.config.get( 'wgPageName' ) == 'LLWiki:互助客棧')) { const gadgets = mw.gadgets || {}, talkHelper = gadgets.talkHelper || {}, expiry = (talkHelper.expiry || 7) * 1000 * 3600 * 24, // localStorage的有效期恰好与新回复的最长追溯时限一致 now = mw.now(), expired = now - expiry, // 更新localStorage只应该在最开始执行一次,且这不依赖于本次访问有无新回复 hist = Object.fromEntries( (mw.storage.getObject( 'LLWiki-talkHelper' ) || []) .filter(function(ele) { return ele[1] > expired; }) ), last = moment( hist[id] || expired ); hist[id] = now; // 转换为数组格式是为了方便调用filter方法,否则也可以遍历对象后使用delete语法 mw.storage.setObject( 'LLWiki-talkHelper', Object.entries(hist) ); // 第一部分为在ext.gadget.CommentsInLocalTime执行完后识别新回复,没有签名时间戳时不会触发 mw.hook( 'local.comments' ).add(function($content) { // 排除掉Wikiplus预览的情形,但无法排除inspect小工具的预览 if ($content.closest( '#Wikiplus-Quickedit-Preview-Output' ).length) { return; } // $content是页面内容,即#mw-content-text;.LocalComments是时间戳,title为CST时区的ISO时间 const $comments = $content.find( '.LocalComments' ).filter(function() { // 非法时间戳也会被过滤掉,未来可能不会给非法时间戳添加LocalComments类 return moment.utc(this.title, 'YYYY-MM-DD HH:mm').add(-8, 'hours').isAfter(last); }); if ($comments.length === 0) { mw.notify( wgULS('没有新回复!', '沒有新回覆!') ); return; } console.log('Hook: local.comments, 开始标注新增回复'); // 以下代码用于分离各人的回复 // 首先分离同一个dd内的text节点和下一级dl,一个dd内存在多个子节点只可能是因为第一个为text或其他节点 $content.find( 'dd:has(dl)' ).filter(function() { return $(this).contents().length > 1; }).after(function() { return $(this).children('dl').wrap( '<dd>' ).parent(); }); // 继续分离dl的不同dd子节点,但只有最后一个子节点包含签名时间戳时可以不用分离 $content.find( 'dd:not(:last-child):has(.LocalComments)' ).parent('dl').each(function() { const $self = $(this), $parents = $self.parents('dl'), // 有可能自己就是最外层dl $ancestor = $parents.addBack().first(); // 最后一个子节点即使没有签名时间戳也需要分离 $self.children( ':has(.LocalComments)' ).add( $self.children().last() ).map(function() { return $(this).prevUntil( ':has(.LocalComments)' ).addBack().wrapAll( '<dl>' ).parent()[0]; }).insertAfter( $ancestor ).wrap( '<dl><dd>'.repeat( $parents.length ) ); // 注意顺序,必须现移至$ancestor外再wrap;最好还需要移除残留的空dl }); // 高亮显示新回复所在的最外层容器 $comments.each(function() { const $ancestor = $(this).parents('dl, p').last(), $siblings = $ancestor.prevUntil( ':header, :has( .LocalComments )' ); if ($siblings.length === 0) { $ancestor.addClass( 'newLocalComments' ); } else { $siblings.add( $ancestor ).wrapAll( $('<div>', {class: 'newLocalComments'}) ); } }); // 换个气泡样式表示标注成功 mw.notify('共有' + $comments.length + wgULS('条新回复!', '條新回覆!'), {type: 'success'}); }); // 第二部分为在有新回复的情况下修改按钮功能,to.bottom总是发生在在local.comments之后 mw.hook( 'to.bottom' ).add(function($btn) { const $comments = $('.newLocalComments'), n = $comments.length; // 没有新回复时什么都不用改 if (!talkHelper.scroll || n === 0) { return; } var i = 0; const $body = $(document.scrollingElement || 'html'), // 兼容不同浏览器 $doc = $(document), $win = $(window), // 用于处理粘性章节标题 offset = mw.config.get('skin') == 'vector' ? 40 : 70; // 移除原有的事件处理函数 $btn.off('click').click(function() { // $doc.height() - $win.height()相当于FireFox独有的window.scrollMaxY,高度不能提前计算 $body.animate({scrollTop: i < n ? $comments.eq(i).offset().top - offset : $doc.height() - $win.height()}); i++; }); // to.bottom事件发生时回到顶部按钮一定存在 $('.backtotop').first().click(function() { i = 0; }); $comments.click(function() { i = $(this).index( '.newLocalComments' ) + 1; }); }); } //</nowiki> // [[category:讨论工具]] [[category:作为模块的小工具]] [[category:桌面版小工具]] [[category:手机版小工具]] // {{DEFAULTSORT:TalkHelper.js}}