- // ==UserScript==
- // @name Search Cross
- // @namespace https://github.com/saplf/search-cross
- // @version 0.8
- // @description 不同搜索引擎间的切换,自用
- // @author saplf
- // @license GPL-3.0
- // @supportURL https://github.com/saplf/search-cross
- // @home-url https://gf.qytechs.cn/zh-CN/scripts/389989-search-cross
- // @match *://www.baidu.com/s?*
- // @match *://www.google.com/search?*
- // @match *://www.bing.com/search?*
- // @match *://www.so.com/s?*
- // @match *://github.com/search?*
- // @match *://www.zhihu.com/search?*
- // @match *://search.bilibili.com/*
- // @match *://zh.wikipedia.org/wiki/*
- // @match *://www.sogou.com/web?*
- // @match *://www.douban.com/search?*
- // @match *://mijisou.com/?*
- // @match *://duckduckgo.com/?*
- // @match *://s.taobao.com/search?*
- // @note 2020.01.10-v0.3 修复github下样式问题
- // @note 2020.06.29-v0.4 切换图标源,减小源码体积;添加中文维基
- // @note 2020.06.29-v0.5 由于 Github 的安全策略,外部样式代码改由代码下载
- // @note 2020.06.29-v0.6 添加部分搜索引擎
- // @note 2020.07.27-v0.7 添加部分搜索引擎;添加设置面板
- // @note 2020.09.28-v0.8 修复 Safari 浏览器不支持反向预查正则的 bug
- // @grant GM_addStyle
- // @grant GM_setValue
- // @grant GM_getValue
- // @grant GM_info
- // @grant GM_xmlhttpRequest
- // @connect at.alicdn.com
- // @run-at document-end
- // ==/UserScript==
-
- var config = {
- default: {
- position: 'left', // 'left' or 'right'
- height: 54,
- top: '120px',
- peekSize: 30,
- delayEnter: 120,
- delayLeave: 400,
- zIndex: 9999,
- triggleVer: '10px',
- triggleHor: '20px',
- },
- 'www.google.com': {
- top: '140px',
- },
- };
-
- var engines = {
- 'www.baidu.com': {
- name: '百度',
- icon: 'sc-baidu',
- url: 'https://www.baidu.com/s?wd={q}',
- match: /(?:wd=)([^&]+)(?=&|$)/,
- },
- 'www.google.com': {
- name: 'Google',
- icon: 'sc-google',
- url: 'https://www.google.com/search?q={q}',
- match: /(?:q=)([^&]+)(?=&|$)/,
- },
- 'www.bing.com': {
- name: 'Bing',
- icon: 'sc-bing',
- url: 'https://cn.bing.com/search?q={q}',
- match: /(?:q=)([^&]+)(?=&|$)/,
- },
- 'github.com': {
- name: 'GitHub',
- icon: 'sc-github',
- url: 'https://github.com/search?q={q}',
- match: /(?:q=)([^&]+)(?=&|$)/,
- },
- 'www.zhihu.com': {
- name: '知乎',
- icon: 'sc-zhihu',
- url: 'https://www.zhihu.com/search?q={q}',
- match: /(?:q=)([^&]+)(?=&|$)/,
- },
- 'search.bilibili.com': {
- name: 'bilibili',
- icon: 'sc-bilibili',
- url: 'https://search.bilibili.com/all?keyword={q}',
- match: /(?:keyword=)([^&]+)(?=&|$)/,
- },
- 'zh.wikipedia.org': {
- name: '维基中文',
- icon: 'sc-wiki',
- url: 'https://zh.wikipedia.org/wiki/{q}',
- match: /(?:wiki\/)([^?&]+)(?=&|$|\?)/,
- },
- 'www.so.com': {
- name: '360',
- icon: 'sc-360',
- url: 'https://www.so.com/s?q={q}',
- match: /(?:q=)([^&]+)(?=&|$)/,
- },
- 'www.sogou.com': {
- name: '搜狗',
- icon: 'sc-sougou',
- url: 'https://www.sogou.com/web?query={q}',
- match: /(?:query=)([^&]+)(?=&|$)/,
- },
- 'www.douban.com': {
- name: '豆瓣',
- icon: 'sc-douban',
- url: 'https://www.douban.com/search?q={q}',
- match: /(?:q=)([^&]+)(?=&|$)/,
- },
- 'mijisou.com': {
- name: '秘迹',
- icon: 'sc-mj',
- url: 'https://mijisou.com/?q={q}',
- match: /(?:q=)([^&]+)(?=&|$)/,
- },
- 'duckduckgo.com': {
- name: 'Duck',
- icon: 'sc-ddg',
- url: 'https://duckduckgo.com/?q={q}',
- match: /(?:q=)([^&]+)(?=&|$)/,
- },
- 's.taobao.com': {
- name: '淘宝',
- icon: 'sc-taobao',
- url: 'https://s.taobao.com/search?q={q}',
- match: /(?:q=)([^&]+)(?=&|$)/,
- },
- };
- var enginesArray = Object.entries(engines);
-
- // var configCached = GM_getValue('config', config);
- // GM_setValue('config', configCached);
- // var setting = Object.assign(config.default, configCached.default, configCached[location.host]);
- // engines = GM_getValue('sites', engines);
- // GM_setValue('sites', engines);
- var setting = config.default;
-
- // 标记用于重置存储数据的计数量
- var appClearCounter = 1;
- var cacheClearCounter = GM_getValue('cacheClearCounter', 0);
- var enabledSites;
- if (cacheClearCounter < appClearCounter) {
- GM_setValue('cacheClearCounter', appClearCounter);
- enabledSites = enginesArray.map(function (it) { return it[0] });
- } else {
- enabledSites = GM_getValue('enabledSites', enginesArray.map(function (it) { return it[0] }));
- }
-
- function appendStyles() {
- var isLeft = setting.position === 'left';
- var offsetSignal = isLeft ? '-' : '';
- GM_addStyle(`
- #sc-panel {
- position: fixed;
- ${setting.position}: ${setting.peekSize}px;
- top: ${setting.top};
- padding: 0 20px 0 80px;
- transform: translate(${offsetSignal}100%, -50%);
- transition: all .2s;
- height: ${setting.height}px;
- border-radius: ${setting.height / 2}px;
- opacity: .6;
- background: red;
- z-index: ${setting.zIndex};
-
- display: flex;
- flex-direction: row;
- align-items: stretch;
- }
-
- #sc-panel.active {
- transform: translate(${offsetSignal}${setting.peekSize * 2}px, -50%);
- box-shadow: 0 0 10px rgba(255, 0, 0, .4);
- opacity: 1;
- }
-
- #sc-panel-triggle {
- position: absolute;
- left: -${isLeft ? 0 : setting.triggleHor};
- right: -${isLeft ? setting.triggleHor : 0};
- top: -${setting.triggleVer};
- bottom: -${setting.triggleVer};
- z-index: ${setting.zIndex - 1};
- }
-
- #sc-panel .sc-panel-item {
- position: relative;
- z-index: ${setting.zIndex + 1};
- color: white;
- font-size: 12px;
- box-sizing: content-box;
-
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 0 10px;
- transition: background .3s;
- }
-
- #sc-panel .sc-panel-item:hover {
- background: rgba(255, 255, 255, .2);
- }
-
- #sc-panel .scf {
- font-size: 2em;
- margin-bottom: 2px;
- }
-
- #sc-panel .scf-setting {
- position: absolute;
- top: 50%;
- left: 48px;
- transform: translateY(-50%);
- color: rgba(255, 255, 255, .6);
- transition: all .2s;
- cursor: pointer;
- z-index: ${setting.zIndex + 1};
- padding: 4px;
- border-radius: 50%;
- }
-
- #sc-panel .scf-setting:hover {
- color: rgba(255, 255, 255, 1);
- background: rgba(255, 255, 255, .2);
- }
-
- #sc-panel .sc-setting {
- font-size: 1.4em;
- }
-
- #sc-panel-setting {
- z-index: ${setting.zIndex + 2};
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- background-color: rgba(0, 0, 0, .6);
- opacity: 0;
- transition: opacity .2s;
- }
-
- #sc-panel-setting.active {
- opacity: 1;
- }
-
- #sc-panel-setting.none {
- display: none;
- }
-
- #sc-setting-box {
- position: absolute;
- top: 120px;
- left: 50%;
- transform: translateX(-50%);
-
- width: 500px;
- height: 420px;
- background: white;
- border-radius: 4px;
- box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6);
-
- display: flex;
- flex-direction: column;
- align-items: stretch;
- }
-
- #sc-setting-box h3 {
- flex: 0 0 auto;
-
- box-sizing: border-box;
- font-weight: normal;
- font-size: x-large;
- padding: 16px 16px 12px;
- border-bottom: 1px solid rgba(0, 0, 0, 0.1);
- }
-
- #sc-tab {
- flex-grow: 1;
- overflow: auto;
- }
-
- #sc-tab .sc-list {
- padding: 16px;
- }
-
- #sc-tab .sc-list li {
- padding: 8px 4px;
- display: flex;
- align-items: baseline;
- transition: background-color .2s;
- }
-
- #sc-tab .sc-list li:hover {
- background-color: rgba(0, 0, 0, .1);
- }
-
- #sc-tab .sc-list label {
- flex-grow: 1;
- display: inline-block;
- margin: 0 4px;
- }
-
- #sc-tab .sc-list .sc-name {
- margin-left: 2px;
- }
-
- #sc-setting-box .btn-panel {
- border-top: 1px solid rgba(0, 0, 0, 0.1);
- padding: 10px 16px;
- display: flex;
- justify-content: flex-end;
- align-items: baseline;
- }
-
- #sc-setting-box .btn-panel > * {
- margin: 0 4px;
- }
- `);
- }
-
- function appendPanel() {
- var body = document.body;
- if (!body) return;
-
- var panel = generateEle('div', {
- id: 'sc-panel',
- // className: 'active',
- });
-
- // panel triggle
- var triggle = generateEle('div', { id: 'sc-panel-triggle' });
- var timerEnter = null;
- var timerLeave = null;
- var funcEnter = function() { addClassName(panel, 'active'); };
- var funcLeave = function() { removeClassName(panel, 'active'); };
- panel.onmouseenter = function() {
- clearTimeout(timerLeave);
- timerEnter = setTimeout(funcEnter, setting.delayEnter);
- }
- panel.onmouseleave = function() {
- clearTimeout(timerEnter);
- timerLeave = setTimeout(funcLeave, setting.delayLeave);
- }
- panel.appendChild(triggle);
-
- // engines
- enginesArray.forEach(function(entry) {
- var key = entry[0];
- if (key === location.host || !enabledSites.includes(key)) return;
- var engine = entry[1];
- var ele = generateEle('a', {
- className: 'sc-panel-item',
- href: engine.url.replace(/\{q\}/, queryParam()),
- });
- var iconI = generateEle('i', { className: 'scf ' + engine.icon });
- var name = generateEle('span', { innerText: engine.name });
- ele.appendChild(iconI);
- ele.appendChild(name);
- panel.appendChild(ele);
- });
-
- // setting trigger
- var settingBox = generateEle('div', {
- className: 'scf-setting',
- onclick: showPanelSetting,
- });
- var settingIcon = generateEle('i', { className: 'scf sc-setting' });
- settingBox.appendChild(settingIcon);
- panel.appendChild(settingBox);
-
- body.appendChild(panel);
- }
-
- function appendPanelSetting() {
- var body = document.body;
- if (!body) return;
-
- var panel = document.getElementById('sc-panel-setting');
- if (panel) return;
-
- panel = generateEle('div', {
- id: 'sc-panel-setting',
- // className: 'active',
- onclick: hidePanelSetting,
- });
-
- panel.addEventListener('transitionend', function () {
- if (panel.getAttribute('hide')) {
- addClassName(panel, 'none');
- }
- });
-
- var box = generateEle('div', {
- id: 'sc-setting-box',
- onclick: function (e) { e.stopPropagation() },
- });
-
- var title = generateEle('h3', {
- innerText: '搜索引擎配置',
- });
- var settingTab = generateEle('div', { id: 'sc-tab' });
-
- var listBox = generateEle('ul', {
- className: 'sc-list',
- });
- enginesArray.forEach(function(entry, index) {
- var key = entry[0];
- var item = entry[1];
- var cusId = 'sc-check-' + index;
- var listItem = generateEle('li', {});
-
- var checkbox = generateEle('input', {
- className: 'sc-site-enabled',
- type: 'checkbox',
- name: key,
- id: cusId,
- });
- var label = generateEle('label', {});
- label.setAttribute('for', cusId);
- var icon = generateEle('i', { className: 'scf ' + item.icon });
- var name = generateEle('span', {
- className: 'sc-name',
- innerText: item.name,
- });
- var suffix = generateEle('a', {
- className: 'sc-href',
- target: '_blank',
- href: 'https://' + key,
- innerText: key,
- });
-
- label.appendChild(icon);
- label.appendChild(name);
- listItem.appendChild(checkbox);
- listItem.appendChild(label);
- listItem.appendChild(suffix);
- listBox.appendChild(listItem);
- });
- settingTab.appendChild(listBox);
-
- var buttonPanel = generateEle('div', { className: 'btn-panel' });
- var hint = generateEle('span', {
- innerText: '保存后刷新生效',
- });
- var saveBtn = generateEle('button', {
- innerText: '仅保存',
- onclick: function () {
- storeEnabledSites(panel);
- hidePanelSetting();
- },
- });
- var refreshBtn = generateEle('button', {
- innerText: '保存并刷新',
- onclick: function () {
- storeEnabledSites(panel);
- hidePanelSetting();
- location.reload();
- },
- });
- buttonPanel.appendChild(hint);
- buttonPanel.appendChild(saveBtn);
- buttonPanel.appendChild(refreshBtn);
-
- box.appendChild(title);
- box.appendChild(settingTab);
- box.appendChild(buttonPanel);
- panel.appendChild(box);
- body.appendChild(panel);
- return panel;
- }
-
- function assignEnabledSites(panel) {
- var list = panel.getElementsByClassName('sc-site-enabled');
- for (var i = 0; i < list.length; i++) {
- var input = list[i];
- input.checked = enabledSites.includes(input.name);
- }
- }
-
- function storeEnabledSites(panel) {
- var list = panel.getElementsByClassName('sc-site-enabled');
- var results = [];
- for (var i = 0; i < list.length; i++) {
- var input = list[i];
- if (input.checked) {
- results.push(input.name);
- }
- }
- GM_setValue('enabledSites', results);
- }
-
- function showPanelSetting() {
- var panel = document.getElementById('sc-panel-setting');
- if (!panel) {
- panel = appendPanelSetting();
- }
- assignEnabledSites(panel);
- panel.setAttribute('hide', '');
- removeClassName(panel, 'none');
- setTimeout(function () {
- addClassName(panel, 'active');
- }, 0);
- }
-
- function hidePanelSetting() {
- var panel = document.getElementById('sc-panel-setting');
- if (!panel) {
- panel = appendPanelSetting();
- }
- panel.setAttribute('hide', '1');
- removeClassName(panel, 'active');
- }
-
- function generateEle(name, properties) {
- var ele = document.createElement(name);
- Object.entries(properties).forEach(function(it) {
- ele[it[0]] = it[1];
- });
- return ele;
- }
-
- function addClassName(ele, name) {
- var classes = (ele.className || '').split(' ').filter(function (it) { return it });
- if (!classes.includes(name)) {
- classes.push(name);
- }
- ele.className = classes.join(' ');
- }
-
- function removeClassName(ele, name) {
- var classes = (ele.className || '')
- .split(' ')
- .filter(function (it) { return it && it !== name });
- ele.className = classes.join(' ');
- }
-
- function toggleClassName(ele, name) {
- var classes = (ele.className || '')
- .split(' ')
- .filter(function (it) { return it });
- if (classes.includes(name)) {
- classes = classes.filter(function (it) { return it && it !== name });
- } else {
- classes.push(name);
- }
- ele.className = classes.join(' ');
- }
-
- function queryParam() {
- var current = engines[location.host];
- if (!current) return '';
- var result = location.href.match(current.match);
- return result && (result[1] || result[0]);
- }
-
- function appendExtraCss(url) {
- GM_xmlhttpRequest({
- method: 'GET',
- url: url,
- onload(args) {
- GM_addStyle(args.responseText);
- },
- });
- }
-
- (function() {
- 'use strict';
- if (!enabledSites.includes(location.host)) return;
-
- appendStyles();
- appendPanel();
- appendExtraCss('//at.alicdn.com/t/font_1911184_1ib7wqdqydk.css');
- })();