您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
"Set date color according to date 根据网页上日期的新旧程度, 给日期进行着色, 比如说已经是5年前的一个日期会成为红色, 以便提醒阅览者,注意信息可能过于陈旧。"
// ==UserScript== // @name colorDate // @namespace https://github.com/mika-cn/user-scripts // @description "Set date color according to date 根据网页上日期的新旧程度, 给日期进行着色, 比如说已经是5年前的一个日期会成为红色, 以便提醒阅览者,注意信息可能过于陈旧。" // @version 1.3.0 // @grant none // @include * // @author mika // ==/UserScript== /** * * # CHANGE LOG * 2018-06-18 [修复] 对于隐藏的文本,不再进行着色 * 2018-04-17 支持<01.01> <2007.09> 格式 * 修正标签正则 * 2018-04-16 支持<01 Feb 2017> 格式 * 添加 noscript 等特殊标签到黑名单 * 兼容类似<textarea>$HTML</textarea>这种s13用法 * 2018-04-14 支持<Feb 01 '17> 和 <2018年> 格式 * 2018-04-13 修改替换方式,可应对多个正则存在包含关系的情况 * */ (function(){ 'use strict'; /* * 时长阀值与色值 */ var day = 24 * 60 * 60 * 1000; var year = 365 * day; var colors = [ {color: "#ff0000", threshold: 5 * year}, {color: "#ff5f00", threshold: 3 * year}, {color: "#d700ff", threshold: 1 * year}, {color: "#8700ff", threshold: 183 * day}, {color: "#00af00", threshold: 7 * day}, {color: "#00d700", threshold: 1 * day}, ]; var monthPart = (` Jan|January| Feb|February| Mar|March| Apr|April| May| Jun|June| Jul|July| Aug|Augest| Sep|Sept|September| Oct|October| Nov|November| Dec|December `).replace(/\n\s*/gm, ''); /* * 判断规则(信息越详细,放在前面) */ var rules = [ // yyyy-mm-dd {key: "01", regExp: /\d{4}-[01]?\d-[0-3]?\d/mg}, // yyyy/mm/dd {key: "01", regExp: /\d{4}\/[01]?\d\/[0-3]?\d/mg}, // yyyy.mm.dd {key: "01", regExp: /\d{4}\.[01]?\d\.[0-3]?\d/mg}, // month dd, yyyy {key: "01", regExp: new RegExp("(?:"+ monthPart +") [0-3]?\\d[,\\s]{1}\\s?\\d{4}", 'igm')}, // dd month yyyy {key: "01", regExp: new RegExp("[0-3]?\\d (?:"+ monthPart +")\\s?\\d{4}", 'igm')}, // month dd 'yy {key: "09", regExp: new RegExp("(?:"+ monthPart +") [0-3]?\\d\\s'\\d{2}", 'igm')}, // yyyy年mm月dd日 {key: "01", regExp: /\d{4}\s?年\s?[01]?\d\s?月\s?[0-3]?\d\s?日/mg}, // yyyy-mm | yyyy/mm | yyyy.mm {key: "02", regExp: /\d{4}[-\/\.]{1}[01]{1}\d/mg}, // yyyy年mm月 {key: "02", regExp: /\d{4}\s?年\s?[01]?\d\s?月/mg}, // mm-dd | mm/dd | mm.dd {key: "03", regExp: /[01]{1}\d[-\/\.][0-3]{1}\d/mg}, // mm月dd日 {key: "03", regExp: /[01]?\d\s?月\s?[0-3]?\d\s?日/mg}, // N 天前 {key: "04", regExp: /\d+\s?天前/mg}, // N days ago {key: "04", regExp: /\d+\s?days?\sago/mg}, // N 月前 {key: "05", regExp: /\d+\s?月前/mg}, // N months ago {key: "05", regExp: /\d+\s?months?\sago/mg}, // N 年前 {key: "07", regExp: /\d+\s?年前/mg}, // yyyy年 {key: "10", regExp: /\d{4}\s?年/mg}, // N years ago {key: "07", regExp: /\d+\s?years?\sago/mg}, // month yyyy {key: "08", regExp: new RegExp("(?:"+ monthPart +")['\\s]{1}\\d{4}", 'igm')}, // month dd {key: "06", regExp: new RegExp("(?:"+ monthPart +")['\\s]{1}[0-3]?\\d", 'igm')}, ]; // 主函数 function colorDate(){ var nodes = getMatchNode(); nodes.forEach(function(node){ var newNode = document.createElement("datetext"); newNode.innerHTML = applyRules(node.nodeValue, rules) // replace child node node.parentNode.replaceChild(newNode, node); }); } /* * 根据规则(判断是否是日期),获取满足的节点 */ function getMatchNode(){ var nodes = []; var currentNode; var nodeIterator = getTextNodeIterator(); while (currentNode = nodeIterator.nextNode()) { var v = currentNode.nodeValue; var rule = rules.some(function(rule){ return !!v.match(rule.regExp); }); if(rule){ nodes.push(currentNode); } } return nodes; } /* * 获取文本节点迭代器 */ function getTextNodeIterator(){ return document.createNodeIterator( document.body, NodeFilter.SHOW_TEXT, function(node) { var blackList = ['style', 'script', 'noscript', 'noframes', 'canvas', 'template', 'datetext', 'datespan']; var parentNode = node.parentNode; if(blackList.indexOf(parentNode.nodeName.toLowerCase()) > -1){ return NodeFilter.FILTER_REJECT; } /* * 隐藏了的文本,不处理 * - 有的程序员会使用隐藏文本来存储数据(比如存储 html 或者 链接) */ var style = window.getComputedStyle(parentNode); if(style.display === "none"){ return NodeFilter.FILTER_REJECT; } if(style.visibility === "hidden"){ return NodeFilter.FILTER_REJECT; } return NodeFilter.FILTER_ACCEPT; } ); } /* * 根据不同的正则,返回处理函数 */ function getHandler(key){ switch(key){ case "01" : return handler_01(); case "02" : return handler_02(); case "03" : return handler_03(); case "04" : return handler_04(); case "05" : return handler_05(); case "06" : return handler_06(); case "07" : return handler_07(); case "08" : return handler_08(); case "09" : return handler_09(); case "10" : return handler_10(); default: return function(match){ return match;}; } } function handler_01(){ return function(match){ var dateStr = match.replace(/年|月|\./g, '-').replace("日", ''); return replace(match, dateStr); }; } function handler_09(){ return function(match){ var parts = match.split("'"); var year = parts.pop(); var curr = new Date().getFullYear(); var yStr = '' + Math.floor(curr%100 > parseInt(year) ? curr/100 : curr/100 - 1).toString() + year; parts.push(yStr); return replace(match, parts.join(" ")); } } function handler_02(){ return function(match){ var dateStr = match.replace(/年|\/|\./g, '-').replace("月", '') + "-01"; return replace(match, dateStr); }; } function handler_03(){ return function(match){ var dateStr = (new Date()).getFullYear().toString() + "-" + match.trim().replace(/月|\/|\./g, '-').replace("日", ''); return replace(match, dateStr); }; } function handler_04(){ return function(match){ var n = parseInt(match.match(/\d+/)[0]); return replace(match, (new Date() - n * day)); }; } function handler_05(){ return function(match){ var n = parseInt(match.match(/\d+/)[0]); return replace(match, (new Date() - n * 30 * day)); }; } function handler_06(){ return function(match){ return replace(match, match.replace(/'/, ' ') + " " + (new Date()).getFullYear().toString()); }; } function handler_07(){ return function(match){ var n = parseInt(match.match(/\d+/)[0]); return replace(match, (new Date() - n * 365 * day)); }; } function handler_08(){ return function(match){ var v = match.replace(/'/, ' ').split(' ').join(" 01 "); return replace(match, v); }; } function handler_10(){ return function(match){ var year = parseInt(match.match(/\d+/)[0]).toString(); return replace(match, year + "-01-01"); } } /* * 处理函数, 根据时长阀值着色 */ function replace(match, dateStr){ try{ var result = match; var diff = Date.now() - new Date(dateStr); colors.some(function(item){ if(diff >= item.threshold){ result = "<datespan style='color:"+ item.color +";'>" + match +"</datespan>"; return true; } return false; }); return result; }catch(e){ return match; } } function applyRules(text, rules){ var r = matchRules(text, rules); return replaceMark(r.markedText, r.values); } /* * 根据rules,进行匹配,标记匹配, 并计算出替换值 * 用来避免两个正则是包含关系的情况 */ function matchRules(text, rules){ var idxUtil = makeIdxUtil(-1); var values = []; rules.forEach(function(rule){ var handler = getHandler(rule.key); text = text.replace(rule.regExp, function(match){ values.push(handler(match)); var mark = "@[["+ idxUtil.next() +"]]"; return mark }); }); return { markedText: text, values: values } } // 索引工具 function makeIdxUtil(init){ return { curr: init, next: function(){ this.curr++; return this.curr; }, } } // 把标记替换为着色后的人日期 function replaceMark(text, values){ return text.replace(/@\[\[\d+\]\]/mg, function(mark){ var idx = parseInt(mark.match(/\d+/)[0]); return values[idx] }); } /* * 创建延迟调用对象 * 用来防止短时间内被调用多次 */ var createDelayCall = function(fn, delay){ var dc = {}; dc.action = fn; dc.clearTimeout = function(){ if(dc.timeoutId){ clearTimeout(dc.timeoutId); } }; dc.run = function(){ dc.clearTimeout(); dc.timeoutId = setTimeout(function(){ dc.action(); dc.clearTimeout(); }, delay); }; return dc; }; /* * 判断变更是否来自脚本 */ function isColorDateMotation(mutationRecords){ return mutationRecords.every(function(record){ return record.type === "childList" && record.addedNodes.length > 0 && record.addedNodes[0].nodeName.toLowerCase() === "datetext"; }); } /* * 初始化 mutationObserver */ function initMutationObserver(){ var delayColorDate = createDelayCall(colorDate, 400); var observer = new MutationObserver(function(mutationRecords){ if(isColorDateMotation(mutationRecords)){ // 本脚本产生的变更,不触发 // console.log("Ignore motation") }else{ delayColorDate.run(); } }); observer.observe(document, { attributes: false, childList: true, subtree: true }); //console.log("init mutationObserver"); } // 监听变更,触发着色 (适用于动态网页,如: ajax加载内容后产生变更) if(MutationObserver){ initMutationObserver(); } // 静态网页加载过程中不会产生变更, 直接调用 setTimeout(colorDate, 400); setTimeout(colorDate, 1000); setTimeout(colorDate, 4000); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址