// ==UserScript==
// @name 谷歌搜索 - 优化
// @namespace http://tampermonkey.net/
// @version 0.1.8
// @description 1.屏蔽推广 2.普通样式 3.单列居中 4双列居中
// @author 浮生未歇
// @run-at document-start
// @include https://www.google.com*/search*
// @exclude https://www.google.com*/search*&source=lnms*
// @resource googleCommon https://cdn.jsdelivr.net/gh/sinlin/google@1.2.1/2019-03-16/google-common.css
// @resource googleOne https://cdn.jsdelivr.net/gh/sinlin/google@1.2.1/2019-03-16/google-one.css
// @resource googleTwo https://cdn.jsdelivr.net/gh/sinlin/google@1.2.1/2019-03-16/google-two.css
// @grant GM_addStyle
// @grant GM_getResourceText
// @grant GM_getResourceURL
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @grant GM_xmlhttpRequest
// ==/UserScript==
(() => {
//初始化配置
let Configs = {
//是否调试
IS_DEBUG: false,
//功能配置
OPTIONS: [
//页面布局:1:普通页面,2:单列居中,3:双列居中,
{ name: "SELECT_PAGE", value: 1 }
],
//谷歌样式
GOOGLE_STYLES: {
COMMON: GM_getResourceText("googleCommon"),
ONE: GM_getResourceText("googleOne"),
TWO: GM_getResourceText("googleTwo"),
}
};
//Google对象参数配置
let googleParamConfig = { Configs, window, document, location };
//Google对象
let Google = (({ Config, window, document, location }, undefined) => {
//创建空对象
let Google = Object.create(null);
//绑定 Google.ready = functon(){} 功能
Reflect.defineProperty(Google, "ready", {
set: fn => {
if (document.readyState === "complete") {
fn();
} else if (!!document.addEventListener) {
document.addEventListener(
"DOMContentLoaded",
() => {
fn();
},
true
);
} else {
throw new Error("Google.ready can't use");
}
}
});
/**
* 函数执行器 - 组合执行
*/
class Command {
constructor() {
this.commondList = [];
}
/**
* 添加数组缓存中
* @param {object} command 对象实例
*/
add(command) {
this.commondList.push(command);
}
/**
* 执行数值缓存中的实例
*/
execute() {
for (let i = 0, command; (command = this.commondList[i++]); ) {
command.execute();
}
}
}
/**
* GM
* 用于调用 TamperMonkey 内置API
*/
class GM {
/**
* 获取数据储存
*/
getGmValue(selection) {
return GM_getValue(selection.name, selection.value);
}
/**
* 设置数据储存
*/
SetGmValue(name, value) {
GM_setValue(name, value);
}
/**
* 使用GM导入样式
* @param {string} styles 样式
*/
importGmStyle(styles) {
if (typeof styles === "string") {
GM_addStyle(styles);
}
}
}
/**
* 数据类
* 用于获取跟初始化配置相关的信息
*/
class Data extends GM {
constructor() {
super();
this.DEFAULT_PAGE_LAYOUT_TYPE = Configs.OPTIONS[0];
this.STYLE_CONTENT_COMMON = Configs.GOOGLE_STYLES.COMMON;
this.STYLE_CONTENT_ONE_CENTER = Configs.GOOGLE_STYLES.ONE;
this.STYLE_CONTENT_TWO_CENTER = Configs.GOOGLE_STYLES.TWO;
}
getPageLayoutName () {
return this.DEFAULT_PAGE_LAYOUT_TYPE["name"];
}
getCurrentPageLayoutType() {
return Number(this.getGmValue(this.DEFAULT_PAGE_LAYOUT_TYPE)) || 1;
}
getCommonPageStyleContent() {
return this.STYLE_CONTENT_COMMON || "";
}
getOneCenterStyleContent() {
return this.STYLE_CONTENT_ONE_CENTER || "";
}
getTwoCenterStyleContent() {
return this.STYLE_CONTENT_TWO_CENTER || "";
}
}
/**
* 基础类
*/
class Base extends Data{
isHideElement(element) {
return element.style.display === "none";
}
hideElement(element) {
element.style.display = "none";
}
showElement(element) {
element.style.display = "block";
}
}
/**
* 样式类
* @class Style
*/
class Style extends Base {
constructor() {
super();
this.cache = "";
}
/**
* 清除缓存
*/
clearCache() {
this.cache = "";
}
/**
* 导入样式
*/
importStyle() {
super.importGmStyle(this.cache);
}
/**
* 将样式内容添加到缓存
* @param {string} styleContent
*/
add(styleContent) {
if (typeof styleContent === "string") {
this.cache += styleContent;
} else {
this.cache += "";
}
return this;
}
/**
* 结束标识符
* 开始调用导入功能
* 清空缓存
*/
end() {
this.importStyle();
this.clearCache();
}
}
/**
* 样式-普通页
*/
class StyleByCommon extends Style {
constructor() {
super();
}
/**
* 获取普通样式
*/
getCommonPageStyleContent() {
return super.getCommonPageStyleContent();
}
getMulPageStyleContent(){
let currentLayoutType = this.getCurrentPageLayoutType();
let style = "";
switch (currentLayoutType) {
//普通样式
case 1: style = ""; break;
//单页居中
case 2: style = this.getOneCenterStyleContent(); break;
//双页居中
case 3: style = this.getTwoCenterStyleContent(); break;
}
return style;
}
init () {
super.add(this.getCommonPageStyleContent())
.add(this.getMulPageStyleContent())
.end();
}
execute () {
this.init();
}
}
/**
* 菜单
*/
class MenuNode extends Base {
constructor() {
super();
this.MENU_BTN_ID = "myGoogleMenuButton";
this.MENU_LISTS_ID = "myGoogleLists";
this.MENU_SAVE_NAME="myGooglesave";
}
/**
* 获取父节点
*/
getContainerNode() {
// return document
// .getElementById("gb")
// .querySelector(".gb_Jf");
//return document.getElementById("ab_options");
return document.getElementById("abar_button_opt");
}
getMenuSaveIdName () {
return this.MENU_SAVE_NAME;
}
getPageLayoutName () {
return super.getPageLayoutName();
}
/**
* 获得 HTML - 页面布局选项
* @param content 显示的内容
* @param layoutType 页面布局类型
*/
getContentPageSelect(content, layoutType) {
let checked = super.getCurrentPageLayoutType() === layoutType ? "checked" : "";
return `<li><input type="radio" name="${ this.getPageLayoutName()
}" value="${ layoutType }" ${ checked }>${ content }</li>`;
}
/**
* 获得 HTML - 保存
* @param content 显示的内容
*/
getContentSava(content) {
let menuSaveIdName = this.getMenuSaveIdName();
return `<input id='${menuSaveIdName}' type='button' style='margin-top:3px;display:block;width:100%' value='${content}'>`;
}
//获取整体 HTML
getContent() {
let content = "";
content += "<ol>页面选择";
content += this.getContentPageSelect("普通页面", 1);
content += this.getContentPageSelect("单页居中", 2);
content += this.getContentPageSelect("双页居中", 3);
content += "</ol>";
content += this.getContentSava("保存");
return content;
}
/**
* 插入按钮
*/
insertMenuBtnNode() {
let container = this.getContainerNode();
let div = document.createElement("div");
div.innerHTML = "自定义";
div.id = this.MENU_BTN_ID;
// container.insertBefore(div, container.parentNode.firstChild);
// container.appendChild(div);
container.before(div);
}
/**
* 插入功能列表
*/
insertMenuItemsNode() {
let container = this.getContainerNode();
let div = document.createElement("div");
div.innerHTML = this.getContent();
div.id = this.MENU_LISTS_ID;
div.style.display = "none";
// container.insertBefore(div, container.firstChild);
container.before(div);
}
bindMenuBtnEvent () {
let btn = document.getElementById(this.MENU_BTN_ID);
let lists = document.getElementById(this.MENU_LISTS_ID);
btn.onclick = () => {
if(this.isHideElement(lists)){
this.showElement(lists);
}else{
this.hideElement(lists);
}
}
}
bindMenuSaveEvent () {
let save = document.getElementById(this.MENU_SAVE_NAME);
save.onclick = (event) => {
let e = event || window.event;
let radios = document.getElementsByName(this.getPageLayoutName());
for(let i = 0, raido; (raido = radios[i++]);){
if (!!raido.checked){
super.SetGmValue(this.getPageLayoutName(), raido.value);
break;
}
}
e.stopPropagation();
location.href = location.href;
}
}
init() {
this.insertMenuBtnNode();
this.insertMenuItemsNode();
Promise.resolve().then(() => {
this.bindMenuBtnEvent();
this.bindMenuSaveEvent();
});
}
execute() {
Google.ready = () => {
this.init();
};
}
}
/**
* 多页布局
* @class MulPageLayout
*/
class MulPageLayout extends Base {
constructor () {
super();
this.PageLayouts = [3];
this.LISTS_CLASS_NAME = "googlelists";
}
isMulPageLayout () {
let currentLayoutType = super.getCurrentPageLayoutType();
return this.PageLayouts.includes(currentLayoutType);
}
getContainer () {
return document.getElementById("rso");
}
getLists () {
return document.getElementsByClassName(this.LISTS_CLASS_NAME);
}
getSearchResults () {
// return document.getElementById("rso").querySelectorAll(".bkWMgd>.g, .srg>.g #rso>.g");
return document.querySelectorAll("#rso>.g");
}
getListsHeight(){
let heights = [];
let lists = this.getLists();
for(let i = 0, list; (list = lists[i++]);){
heights.push(list.clientHeight || 0);
}
return heights;
}
isExistListsElement () {
return document.getElementsByName(this.LISTS_CLASS_NAME).length > 0;
}
insertListsElement () {
if(this.isExistListsElement()){
return;
}
let className = this.LISTS_CLASS_NAME;
let container = this.getContainer();
let frame = document.createDocumentFragment();
for(let i = 1; i <= 2; i++){
let div = document.createElement("div");
div.className = `${className} ${className}${i}`;
frame.appendChild(div);
}
container.insertBefore(frame, container.firstChild);
}
moveSearchResultElement () {
let lists = this.getLists();
let items = this.getSearchResults()
let heights = this.getListsHeight();
let frames = [];
//初始化
for (let i = 0, length = lists.length; i < length; i++) {
//缓存
frames.push(document.createDocumentFragment());
}
//将 item 添加到虚拟DOM中
for (let i = 0, item; (item = items[i++]); ) {
//获取最小的高度值
let minHeight = Reflect.apply(Math.min, null, heights);
//获取最小的高度的索引值
let index = heights.indexOf(minHeight);
//添加到高度
heights[index] += item.clientHeight;
//缓存
frames[index].appendChild(item);
}
//添加到真实DOM
for (let i = 0, length = lists.length; i < length; i++) {
lists[i].appendChild(frames[i]);
}
}
init () {
this.insertListsElement();
this.moveSearchResultElement();
}
execute () {
if(this.isMulPageLayout()){
Google.ready = () => {
this.init();
}
}
}
}
/**
* 普通页控制
*/
class CommonPageControl {
run() {
let command = new Command();
command.add(new StyleByCommon());
command.add(new MulPageLayout());
command.add(new MenuNode());
command.execute();
}
}
/**
* 简单工厂模式
*/
class Factory {
static getConfig() {
return [{ reg: /https/, useObject: CommonPageControl }];
}
static create(URL) {
let configs = this.getConfig();
for (let { reg, useObject } of configs) {
if (reg.test(URL)) {
return new useObject();
}
}
}
}
/**
* 启动函数
*/
Google.start = () => {
Factory.create(location.href).run();
};
return Google;
})(googleParamConfig);
Google.start();
})();