Greasy Fork

Greasy Fork is available in English.

AC-baidu: 优化百度、搜狗、谷歌搜索结果之关键词自动高亮

1.自动提取搜索页面的搜索关键词 2.对关键词自动进行高亮处理 W键可以取消高亮 3.动态获取动态的搜索关键词,重新高亮显示

当前为 2018-10-08 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name AC-baidu: 优化百度、搜狗、谷歌搜索结果之关键词自动高亮
// @description     1.自动提取搜索页面的搜索关键词 2.对关键词自动进行高亮处理 W键可以取消高亮 3.动态获取动态的搜索关键词,重新高亮显示
// @icon            https://coding.net/u/zb227/p/zbImg/git/raw/master/img0/icon.jpg
// @author          AC
// @create          2018-05-25
// @version         2.0
// @include         *
// @home-url        http://greasyfork.icu/zh-TW/scripts/368418
// @home-url2       https://github.com/langren1353/GM_script
// @namespace       [email protected]
// @copyright       2017, AC
// @lastmodified    2018-10-08
// @feedback-url    http://greasyfork.icu/zh-TW/scripts/368418
// @note            2018.10.08-V2.0 修复多次触发导致的卡顿现象;修复搜索时高亮的问题
// @note            2018.10.03-V1.9 修复由于<span>标签导致的:1.样式被界面污染 2.特定关键词被百度重定向脚本删除;修复在部分代码界面导致的高亮失效问题;修复高亮导致的标题栏被格式化
// @note            2018.07.21-V1.8 修复由于很快的高亮导致的高亮代码被个格式化为普通文本
// @note            2018.07.06-V1.7 修复csdn的问题和w3cschool页面的代码问题
// @note            2018.06.20-V1.6 修复上次更新导致的严重bug,页面卡死问题
// @note            2018.06.18-V1.5 修复在部分csdn网页代码上,高亮不起作用
// @note            2018.06.15-V1.4 修复在CSDN代码中,高亮处理之后导致的多了一部分文字的问题;减少了多次调用可能出现的冲突问题;依旧添加G键也是高亮效果
// @note            2018.06.04-V1.3 1.修复百度翻页之后偶尔不自动高亮的问题;2.新增一定的页面高亮效果的调整;优化关键词的数量,数量到达一定程度,之后的关键词不做高亮处理
// @note            2018.05.31-V1.2 修复由于分词不准的问题导致的丢词问题;修复停止高亮然后又自动启动的问题;修复下划线分割问题;修复左右尖括号转换问题;新增W高亮时复制文字内容
// @note            2018.05.26-V1.1 修复垃圾代码,上个版本真的是垃圾代码,运行又慢,占用又高,还特么定时运行,但就是数据出现很慢,现在应该没有这个问题了
// @note            2018.05.25-V1.0 从百度重定向脚本中拆分出来
// @run-at          document-body
// @grant           GM_getValue
// @grant           GM_setValue
// @grant           GM_setClipboard
// ==/UserScript==

var isDebug = true; // 本次更新是否有新功能需要展示
var debugX = isDebug ? console.log.bind(console) : function(){};
function sayLength(){
	debugX(document.querySelectorAll(".c-container").length);
}

(function () {
	'use strict';
	var startTime = new Date().getTime();
	var renderStartTime = 5000; // 1秒钟 & 强制刷新应该优先于定时操作
	var HightLightColorList = ["#FFFF80", "#90EE90", "#33FFFF", "#FF6600", "#FF69B4", "#20B2AA", "#8470FF"];
	var isSearchWindowActive = true;    // 搜索窗口是否激活
	var OnlyDBCheck = false;            // 是否为双击事件
	var enableDBSelectText = false;
	var oldTextSelectInterval = -1;
	var hasInitBtnBind = false;
	var hasInitBtnBind_DOM = false;
	var dataRapidLock = false;
	var dataConflictLock = false;
	var disableHighLight = false;       // 是否禁用highLight
	var SiteTypeID; // 标记当前是哪个站点[百度=1;搜狗=2;3=好搜;谷歌=4;必应=5;知乎=6;其他=7]
	var SiteType={
		BAIDU:1,
		SOGOU:2,
		SO:3,
		GOOGLE:4,
		BING:5,
		ZHIHU:6,
		OTHERS:7
	};
	/*在搜索引擎上面会刷新当前搜索关键词内容*/
	if (location.host.indexOf("www.baidu.com") > -1) {
		SiteTypeID = SiteType.BAIDU;
	} else if (location.host.indexOf("sogou") > -1) {
		SiteTypeID = SiteType.SOGOU;
	}  else if (location.host.indexOf("so.com") > -1) {
		SiteTypeID = SiteType.SO;
	} else if (location.host.indexOf("google") > -1) {
		SiteTypeID = SiteType.GOOGLE;
	} else if (location.host.indexOf("bing") > -1) {
		SiteTypeID = SiteType.BING;
	} else if (location.host.indexOf("zhihu.com") > -1) {
		SiteTypeID = SiteType.ZHIHU;
	} else {
		SiteTypeID = SiteType.OTHERS;
	}
	setTimeout(function(){
		DoHighLightWithSearchText(GM_getValue("searchKeyWords", ""));
	}, renderStartTime);
	function DoHighLightWithSearchText(searchValue){
		WordAutoHighLight(searchValue);
	}
	function AC_addStyle(css, className, addToTarget, isReload){ // 添加CSS代码,不考虑文本载入时间,带有className
		var tout = setInterval(function(){
			if(addToTarget == null) addToTarget = "head";
			if(isReload == null) isReload = false;
			if(document.querySelector(addToTarget) != null){
				clearInterval(tout);
				var checkNode = document.querySelector("."+className) || null;
				if(isReload == false && checkNode != null){
					// 节点存在,并且不准备覆盖
					return;
				}
				if(checkNode!= null && css == checkNode.innerHTML) {
					// checkNode可访问 & 内容相同 == > else 没有节点 || 内容不同
					return;
				}
				safeRemove("."+className);
				var cssNode = document.createElement("style");
				if(className != null)
					cssNode.className = className;
				cssNode.innerHTML = css;
				try{
					document.querySelector(addToTarget).appendChild(cssNode);
				}catch (e){debugX(e.message);}
			}
		}, 50);
	}
	function safeRemove(cssSelector){
		try {
			document.querySelector(cssSelector).remove();
		}catch (e){}
	}
	function WordAutoHighLight(searchText){
		if(!hasInitBtnBind){
			hasInitBtnBind = true;
			setTimeout(function(){
				// 似乎过早的绑定可能出现问题,例如www.huomao.com中h5视频的LOGO一直在
				document.addEventListener('keydown', DoHighLight, true);
			}, 800);
		}
		var enableCharCode1 = 'G';
		var enableCharCode2 = 'W';
		var keySets = new Object();
		var counter = 0;
		doHighLightTextS(searchText);
		function DoHighLight(e) { // 手动W触发
			var target = e.target;
			var selectedText = getSelectedText(target);
			var s_keyup = (e.type === 'keydown') && (enableCharCode1.charCodeAt(0)==e.keyCode || enableCharCode2.charCodeAt(0)==e.keyCode);// 是按下特殊按键
			if (s_keyup) {
				if(typeof(selectedText) == "undefined" || selectedText == null || selectedText == ""){
					try{clearInterval(oldTextSelectInterval);}catch (e){debugX(e);}
					debugX("不准亮");
					GM_setValue("searchKeyWords", ""); // 置空
					hasInitBtnBind_DOM = false;
					disableHighLight = true;
					safeRemove(".AC-highLightRule");
					document.removeEventListener('DOMSubtreeModified', DOMRapidHighLightFunc, false);
					unHighLightAll_Text();
				}else{
					GM_setClipboard(selectedText);
					enableDBSelectText = true;
					disableHighLight = false;
					OnlyDBCheck = true;
					doHighLightTextS(selectedText, true);
				}
			}
		}
		function doHighLightTextS(selectedText, dbclick) {
			if(typeof(selectedText) == "undefined" || selectedText == null || selectedText == "") return;
			unHighLightAll_Text();
			if(dbclick){
				GM_setValue("searchKeyWords", selectedText);
				debugX("双击:" + selectedText + keySets.keywords);
			}
			initKeySets(selectedText);
			doHighLightAll_CSS();
			doHighLightAll_Text();
			setTimeout(function(){doHighLightAll_Text();}, 1500);
			if(hasInitBtnBind_DOM == false){
				hasInitBtnBind_DOM = true;
				document.addEventListener('DOMSubtreeModified', DOMRapidHighLightFunc, false);
			}
		}
		function DOMRapidHighLightFunc(e) {
			if(dataRapidLock == false){
				dataRapidLock = true;
				doHighLightAll_CSS();
				doHighLightAll_Text();
				setTimeout(function(){dataRapidLock = false;}, 1000);
			}
		}
		function getSelectedText(target) {
			function getTextSelection() {
				var selectedText = '';
				if (target.getAttribute("type")) {
					if (target.getAttribute("type").toLowerCase() === "checkbox") return '';
				}
				var value = target.value;
				if (value) {
					var startPos = target.selectionStart;
					var endPos = target.selectionEnd;
					if (!isNaN(startPos) && !isNaN(endPos)) selectedText = value.substring(startPos, endPos);
					return selectedText;
				} else return '';
			}
			var selectedText = window.getSelection().toString();
			if (!selectedText) selectedText = getTextSelection();
			return selectedText;
		}
		function getBLen(str) {
			if (str == null) return 0;
			if (typeof str != "string"){
				str += "";
			}
			return str.replace(/[^\x00-\xff]/g,"01").length;
		}
		function reSplitKeySet(keySet){
			var data = keySet
				.split(/\b |[\u0000-\u002F\u003A-\u0040\u005B-\u005e\u007B-\u00FF\uFF00-\uFFFF\u3000-\u303F]/g)
				.join('ACsCA')
				.replace(/[^\u4E00-\u9FA5|0-9|a-z|A-Z_]+/g, "")
				.replace(/(ACsCA){2}/g, "ACsCA")
				.replace(/(^ACsCA|ACsCA$)/g, "")
				.split("ACsCA");
			var newData = new Array();
			for(var i = 0, j = 0; i < data.length; i++){
				if(data[i].length > 1){
					newData[j++] = data[i];
				}
			}
			return newData;
		}
		// 初始化点击的文字信息
		function initKeySets(selection){
			// 1.split通过特殊字符和字符边界分割串[非[0-9A-Za-z]特殊字符]
			// 2.通过特定字符连接原始串,
			// 3.1移除多次重复的特定串,非常用串移除,避免空串
			// 3.2移除开头或者结尾的特定串,避免分割后出现空白数据,
			// 4.按特定串分割
			keySets.keywords = reSplitKeySet(selection);
			keySets.length = keySets.keywords.length;
			keySets.textcolor = new Array();
			keySets.visible = new Array();
			for(var i=0; i < keySets.keywords.length; i++){
				keySets.textcolor[i] = "rgb(0,0,0)";
				keySets.visible[i] = "true";
			}
		}
		function doHighLightAll_CSS(){ // 顶部的那一堆数组
			if (keySets.visible[0] == "true"){
				var rule = ".acWHSet{display:inline!important;box-shadow: -3px 0px 3px 0.15px rgba(0, 0, 0, 0.15);";
				if (keySets.textcolor.length > 0) rule += "color:"+keySets.textcolor[0]+";";
				rule += "font-weight:inherit;}";
				for(var i = 0; i < keySets.keywords.length; i++){
					rule += ".acWHSet[data='"+keySets.keywords[i].toLocaleLowerCase()+"']{background-color:"+HightLightColorList[i % HightLightColorList.length]+";}";
				}
				// debugX("触发重置CSS");
				AC_addStyle(rule, "AC-highLightRule", "body", true);
			}
		}
		function doHighLightAll_Text(){
			if(dataConflictLock == true) return;
			dataConflictLock = true;
			doHighLightAll_Text_Inner();
			dataConflictLock = false;
		}
		function doHighLightAll_Text_Inner(){
			var selection = GM_getValue("searchKeyWords", "");
			// debugX("执行高亮"+selection);
			keySets.keywords = reSplitKeySet(selection);
			if(keySets.keywords.length == 0) {
				return; // 退出1
			}
			var patExp = "";
			for(var index=0, sizeCount = 0; index<keySets.keywords.length-1 && index < 8 && sizeCount < 50; index++) {
				patExp += keySets.keywords[index]+"|";
				sizeCount += keySets.keywords[index].length;
			}
			patExp += keySets.keywords[index];
			var pat = new RegExp("("+patExp+")", "gi");
			var XhighLight = document.createElement('XhighLight');
			var evalRule = './/text()[normalize-space() != "" ' +
				'and not(parent::XhighLight[@txhidy15]) ' +
				'and not(parent::title)' +
				'and not(ancestor::style) ' +
				'and not(ancestor::script) ' +
				'and not(ancestor::textarea) ' +
				'and not(ancestor::div[@id="thdtopbar"]) ' +
				'and not(ancestor::div[@id="kwhiedit"]) ' +
				'and not(parent::XhighLight[@txhidy15]) ' +
				'and not(ancestor::pre) '+ // CSDN的代码文字,未初始化之前的1--->不作处理
				((new Date().getTime() - startTime > renderStartTime || OnlyDBCheck == true)?
					('or ((ancestor::pre) and not(parent::XhighLight[@txhidy15]) and ('+ // EG.http://www.w3school.com.cn/xpath/xpath_syntax.asp
						'(ancestor::code[@class]) '+ // EG.http://lib.csdn.net/article/android/8894
						'or (ancestor::div[contains(@class, "cnblogs_code")] ) '+ // EG.https://blog.csdn.net/freeape/article/details/50485067
					"))") : "") +
				']';
			var snapElements = document.evaluate(evalRule, document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
			if (!snapElements.snapshotItem(0)) {
				return;
			} // 退出2
			try{
				for (var i = 0, len = snapElements.snapshotLength; i < len; i++) {
					var node = snapElements.snapshotItem(i);
					if (node.nodeValue.length > 1 && pat.test(node.nodeValue)) {
						if(node.className!= null && node.className.indexOf("acWHSet") > 0) return;
						// if (node.parentNode.outerHTML != null && node.parentNode.outerHTML.indexOf("THmo acWHSet") >= 0) return;
						// debugX("start");
						// debugX(node.children);
						// debugX(node.className);
						// debugX(node.parentNode);
						var sp = XhighLight.cloneNode(true);
						var findResult = node.nodeValue.replace(/</g, '&lt;').replace(/>/g, '&gt;');
						// debugX("1."+findResult);
						var repNodeHTML = findResult.replace(pat, '<XhighLight class="THmo acWHSet" txhidy15="acWHSet">$1</XhighLight>');
						// debugX("2."+repNodeHTML);
						sp.innerHTML = repNodeHTML;
						if(node.parentNode == null) continue;
						node.parentNode.replaceChild(sp, node);
						sp.outerHTML = sp.innerHTML;
					}
				}
				var attributeDataResetList = document.querySelectorAll(".acWHSet");
				for(var i = 0; i < attributeDataResetList.length; i++){
					attributeDataResetList[i].setAttribute("data", attributeDataResetList[i].innerHTML.toLocaleLowerCase());
				}
			}catch (e) {
				debugX(e);
			}
			return;
		}
		function unHighLightAll_Text(){
			try{
				var tgts = document.querySelectorAll('XhighLight[txhidy15="acWHSet"]');
				for (var i=0; i<tgts.length; i++){
					var parnode = tgts[i].parentNode, parpar = parnode.parentNode, tgtspan;
					if (parnode.hasAttribute("thdcontain") && parnode.innerHTML == tgts[i].outerHTML){
						parnode.outerHTML = tgts[i].textContent.replace(/</g, '&lt;').replace(/>/g, '&gt;');
						tgtspan = parpar;
					} else {
						tgts[i].outerHTML = tgts[i].textContent.replace(/</g, '&lt;').replace(/>/g, '&gt;');
						tgtspan = parnode;
					}
					tgtspan.normalize();
					if (tgtspan.hasAttribute("thdcontain")){
						parnode = tgtspan.parentNode;
						if (parnode){
							if (parnode.hasAttribute("thdcontain") && parnode.innerHTML == tgtspan.outerHTML && tgtspan.querySelectorAll('XhighLight[txhidy15]').length == 0){
								parnode.outerHTML = tgtspan.innerHTML;
							} else if (parnode.innerHTML == tgtspan.outerHTML && tgtspan.querySelectorAll('XhighLight[txhidy15]').length == 0) {
								parnode.innerHTML = tgtspan.innerHTML;
							}
						}
					}
				}
				var oldTgs = document.querySelectorAll("XhighLight[thdcontain='true']");
				counter = 0;
				for(var i=0; i < oldTgs.length; i++){
					var curTg = oldTgs[i];
					markChildandRemove(curTg);
				}
			}catch (e){}
		}
		function markChildandRemove(node){
			try{
				if(node.tagName.toLowerCase() == "xhighlight"){
					node.outerHTML = node.innerHTML;
				}
				var childList = node.childNodes;
				for(var i=0; i < childList.length; i++){
					counter++;
					var node = childList[i];
					markChildandRemove(node);
					if(node.tagName.toLowerCase() == "xhighlight"){
						node.outerHTML = node.innerHTML;
					}
				}
			}catch (e){}
		}
	}

	// 如果是搜索引擎的话
	if(SiteTypeID != SiteType.OTHERS){ // 启用自动高亮
		// 持续拿到搜索关键词,存入GM中,避免切换页面导致的关键词丢失
		DoHighLightWithSearchText(GM_getValue("searchKeyWords", ""));
		setInterval(function(){
			if(document.hidden == true){ // 只要是搜索窗口不激活,那么flag=false
				isSearchWindowActive = false;
				enableDBSelectText = false;
			}
			// (窗口激活状态;或者是窗口之前是不激活,现在激活了) && 必须要非 禁用高亮状态
			if((isSearchWindowActive == true || (isSearchWindowActive == false && document.hidden == false)) && !disableHighLight) {
				var searchValue = (window.location.search.substr(1) + "").split("&");
				for (var i = 0; i < searchValue.length; i++) {
					var key_value = searchValue[i].split("=");
					if (/^(wd|q|query)$/.test(key_value[0])) {
						var searchWords = decodeURI(key_value[1]).toLocaleLowerCase().replace(/\+/g, " ");
						if(GM_getValue("searchKeyWords", "") != searchWords && enableDBSelectText == false){ // 避免重复掉用,一直刷新关键词
							GM_setValue("searchKeyWords", searchWords);
							DoHighLightWithSearchText(GM_getValue("searchKeyWords", ""));
						}
						break;
					}
				}
			}
		}, 200);
	}else{
		DoHighLightWithSearchText(GM_getValue("searchKeyWords", ""));
	}
})();