Google Searching Tags Box

Make your searches easier by adding tags to your search queries with one click

当前为 2022-05-09 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Google Searching Tags Box
// @version      1.0
// @description  Make your searches easier by adding tags to your search queries with one click
// @author       OpenDec
// @license      MIT
// @match        https://www.google.com/
// @match        https://www.google.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=google.com
// @grant        none
// @run-at       document-start
// @namespace https://greasyfork.org/users/873547
// ==/UserScript==

window.addEventListener('DOMContentLoaded', function stageReady() {

  // INIT
  var input = document.querySelector('input.gLFyf.gsfi');
  var container = document.querySelector('.RNNXgb');
  var tagsBox = document.createElement('div');
  var items;
  var validTarget;
  var data = [];
  var draggedItem = null;

  tagsBox.id = 'od-tagsbox';
  tagsBox.draggable = true;
  container.parentNode.insertBefore(tagsBox, container.nextSibling);

  // tagsBox is a valid target
  tagsBox.addEventListener('dragover', function (e) {
    e.preventDefault();
  });
  tagsBox.addEventListener('drop', function (e) {
    e.preventDefault();
    validTarget = true;
  });

  // DATA STORAGE
  function loadData() {
    data = JSON.parse(localStorage.getItem('odtagsbox') || '[]');
  }
  function saveData() {
    updateData();
    localStorage.setItem('odtagsbox', JSON.stringify(data));
  }

  // PARSING
  function parseData() {
    addItem();
    for (var i in data) {
      addItem(data[i].text, data[i].color);
    }
  }
  function updateData() {
    data = Array.from(items).flatMap(function(e){return e.classList.contains('od-additem') ? [] : [{ text: e.dataset.title, color: e.dataset.color }]; });
  }

  // ADD ITEM
  function addItem(str, color, index) {
    str = str || '';
    color = color || randomHSL();
    index = index || tagsBox.childElementCount;

    var item = document.createElement('div');
    var label = document.createElement('i');

    item.classList.add('od-item');
    if(!str) item.classList.add('od-additem');

    label.title = str;
    label.style.backgroundColor = color;

    item.dataset.title = str;
    item.dataset.color = color;
    item.draggable = true;

    item.appendChild(label);

    (index < tagsBox.childElementCount) ? tagsBox.insertBefore(item, tagsBox.children[index]) : tagsBox.appendChild(item);

    // :: ACTIONS ::

    // ON CLICK
    item.addEventListener('click', str ?
    // Add my tag in the search field
      function () {
        if (typeof input.selectionStart !== 'undefined') {
          var startPos = input.selectionStart;
          var endPos = input.selectionEnd;
          var text = (startPos > 0 ? ' ' : '') + str + ' ';

          if (startPos > 0 && input.value[startPos-1] === ' ') startPos--;

          if (endPos < input.value.length && input.value[endPos] === ' ') endPos++;

          input.value = input.value.slice(0, startPos) + text + input.value.slice(endPos);
          input.focus();
          input.selectionStart = input.selectionEnd = startPos + text.length;
        } else {
          input.value = input.value.trim() + ' ' + str + ' ';
          input.focus();
        }
        input.click();
      } :
    // Create a new tag from the search field (highlighted) text
      function () {
      	var text;
        if (input.selectionStart !== input.selectionEnd) {
          text = input.value.substring(input.selectionStart, input.selectionEnd).trim().toLowerCase();
        } else {
          text = input.value.trim().toLowerCase();
        }

        if (!text) {
          input.focus();
          return;
        }

        var newColor = randomHSL();

        var dupl = tagsBox.querySelector('.od-item[data-title=\'' + text + '\']');
        if (dupl) removeItem(dupl);

        label.style.backgroundColor = newColor;
        item.dataset.color = newColor;

        var index = Array.from(tagsBox.children).indexOf(this) + 1;

        addItem(text, color, index);

        color = newColor;

        saveData();
      }
    );

    // DRAG START
    item.addEventListener('dragstart', function (e) {
      e.dataTransfer.effectAllowed = "move";
      draggedItem = this;
      tagsBox.classList.add('od-grabbing');
      for (var i = 0; i < items.length; i++) {
        items.item(i).classList.add(items.item(i) == draggedItem ? 'od-draggeditem' : 'od-hintitem');
      }
    });

    // DRAG ENTER
    item.addEventListener('dragenter', function () {
      if (this != draggedItem) { this.classList.add('od-activeitem'); }
    });

    // DRAG LEAVE
    item.addEventListener('dragleave', function () {
      this.classList.remove('od-activeitem');
    });

    // DRAG END
    item.addEventListener('dragend', function () {
      if (!validTarget && !this.classList.contains('od-additem')) {
        removeItem(this);
      }
      validTarget = false;

      tagsBox.classList.remove('od-grabbing')
      for (var i = 0; i < items.length; i++) {
        items.item(i).classList.remove('od-hintitem');
        items.item(i).classList.remove('od-activeitem');
        items.item(i).classList.remove('od-draggeditem');
      }
    });

    // DRAG OVER - PREVENT THE DEFAULT 'DROP', SO WE CAN DO OUR OWN
    item.addEventListener('dragover', function (e) {
      e.preventDefault();
    });

    // ON DROP
    item.addEventListener('drop', function (e) {
      e.dataTransfer.dropEffect = 'move';
      e.preventDefault();
      validTarget = true;

      if (this != draggedItem) {
        var currentpos = 0, droppedpos = 0;
        for (var it = 0; it < items.length; it++) {
          if (draggedItem == items[it]) { currentpos = it; }
          if (this == items[it]) { droppedpos = it; }
        }
        if (currentpos < droppedpos) {
          this.parentNode.insertBefore(draggedItem, this.nextSibling);
        } else {
          this.parentNode.insertBefore(draggedItem, this);
        }
        saveData();
      }
    });
  }

  // REMOVE ITEM
  function removeItem(el){
    var text = el.dataset.title;
    var removeIndex = data.findIndex(function(i){return i.text === text;});
    data.splice(removeIndex, 1);
    tagsBox.removeChild(el);
    saveData();
  }

  // START
  function start(){
    addGlobalStyle(css);
    tagsBox.innerHTML = '';
    loadData();
    parseData();
    items = tagsBox.getElementsByTagName('div');
  }






// STYLE

var css = '/* RESET */';

css+= '.ikrT4e { max-height: initial !important; }';
css+= '.e9EfHf { padding-top: 30px !important; }';
css+= '.Q3DXx.yIbDgf { margin-top: 16px !important; }';
css+= '#searchform > .sfbg { margin-top: 0 !important }';

css+= '/* CONTAINER */';

css+= '#od-tagsbox {';
css+= '    position: absolute;';
css+= '    top: -34px;';
css+= '    max-width: 100%;';
css+= '    max-height: 30px;';
css+= '    margin-top: 2px;';
css+= '    border: 1px solid transparent;';
css+= '    border-radius: 20px;';
css+= '    background: rgba(255,255,255, 0);';
css+= '    overflow: hidden;';
css+= '    transition: .3s ease-out;';
css+= '    z-index: 999;';
css+= '}';
css+= '#od-tagsbox * {';
css+= '    box-sizing: border-box;';
css+= '}';
css+= '#searchform #od-tagsbox {';
css+= '    top: -42px;';
css+= '    left: 30px;';
css+= '}';
css+= '#searchform.minidiv #od-tagsbox {';
css+= '    top: -33px;';
css+= '}';
css+= '#od-tagsbox:hover {';
css+= '    max-height: 100px;';
css+= '		border-color: rgba(200,200,200, .2);';
css+= '		box-shadow: 0 2px 5px 1px rgba(64,60,67,.3);';
css+= '		background: rgba(255,255,255, .2);';
css+= '}';

css+= '/* ITEMS */';

css+= '.od-item {';
css+= '    float: left;';
css+= '    padding: 3px;';
css+= '    transition: opacity .3s .1s ease-out;';
css+= '    cursor: pointer;';
css+= '}';
css+= '.od-item > i {';
css+= '    position: relative;';
css+= '    top: 0;';
css+= '    display: block;';
css+= '    width: 24px;';
css+= '    height: 24px;';
css+= '    border: 2px solid #0002;';
css+= '    text-align: center;';
css+= '    text-transform: uppercase;';
css+= '    white-space: nowrap;';
css+= '    font: normal 12px/20px Arial, sans-serif;';
css+= '    color: #fff;';
css+= '    border-radius: 50%;';
css+= '    overflow: hidden;';
css+= '    cursor: pointer;';
css+= '    transition: .2s ease-out, font-size 0s, font-weight 0s;';
css+= '}';
css+= '.od-item > i::before {';
css+= '    content: attr(title);';
css+= '}';
css+= '.od-item.od-additem > i{';
css+= '    font-size: 18px;';
css+= '    font-weight: bold;';
css+= '}';
css+= '.od-item.od-additem > i::before {';
css+= '    content: "+";';
css+= '}';

css+= '/* DRAGGING */';

css+= '#od-tagsbox.od-grabbing {';
css+= '    cursor: move;';
css+= '}';
css+= '#od-tagsbox.od-grabbing > .od-item {';
css+= '    transition-delay: 0;';
css+= '}';
css+= '.od-hintitem {';
css+= '    opacity: .4;';
css+= '}';
css+= '.od-hintitem > i {';
css+= '    pointer-events: none;';
css+= '}';
css+= '.od-draggeditem {';
css+= '    opacity: 0;';
css+= '}';
css+= '.od-activeitem {';
css+= '    opacity: .25;';
css+= '}';
css+= '.od-activeitem > i {';
css+= '    top: -3px;';
css+= '}';

  function randomHSL() {
    return 'hsl(' + ~~(360 * Math.random()) + ',50%,50%)';
  }

  function addGlobalStyle(css) {
    var h = document.querySelector('head');
    if (!h) return;
    var s = document.createElement('style');
    s.type = 'text/css';
    s.innerHTML = css;
    h.appendChild(s);
  }

  start();

});