Полезная информация

Хотите узнать больше о расширениях? Посмотрите ролики, рассказывающие о работе с расширениями Firefox.

№103-12-2011 16:47:15

bunda1
Moderator
 
Группа: Moderators
Откуда: Латвия
Зарегистрирован: 09-02-2010
Сообщений: 4811
UA: Firefox 3.6

[CB]Context Search

Context Search( Firefox24+ )
Автор: bunda1
Версия: от 19.12.2015
Описание: код заменяет стандартный пункт контекстного меню страницы для поиска в текущем поисковике на новый пункт который открывает подменю со всеми установленными поисковиками и позволяет выбрать поисковик в котором вы хотите искать выделенный текст.

Клики на пункте контекстного меню или на пункте подменю:
ЛКМ => Открыть поиск в новой активной вкладке,
ПКМ => Открыть поиск в новой фоновой вкладке.

Скриншот:
60933131e32715a354b9be338cfafc8f.jpg

Использование: положите код в любую Custom Buttons кнопку, в инициализацию. Не обязательно создавать новую CB кнопку, можно использовать уже существующую.

Выделить код

Код:

// Context Search, от 19.12.2015. ........................
((contextMenu, searchSelect, searchService)=> {
   searchSelect.collapsed = true; // удалить стандартный пункт меню для поиска
   
   
   // Создать новый пункт меню для поиска ....
   var menu = contextMenu.insertBefore(document.createElement('menu'), searchSelect);
   menu.setAttribute("class", "menu-iconic");
   addEventListener("popupshowing", (e)=> menu.hidden = searchSelect.hidden, false, contextMenu); 
      
   function setMenu() {  
      menu.engine = searchService.currentEngine;
      menu.setAttribute("label", "Искать в " + menu.engine.name + " или в ...");
      menu.setAttribute("image", menu.engine.iconURI.spec );
   };
   setMenu();

   
   // Создать подменю с поисковиками .... 
   var menuPopup = menu.appendChild(document.createElement("menupopup")); 
   menuPopup.setAttribute('style', 'overflow: scroll'); 

   function setItemsToMenuPopup(e) {
      menuPopup.textContent = "";      

      var engines = searchService.getVisibleEngines({});
      engines.forEach((engine)=> { 
         var mItem = document.createElement("menuitem");
         mItem.setAttribute("label", engine.name);
         mItem.setAttribute("class", "menuitem-iconic");
         mItem.setAttribute("src", engine.iconURI.spec);
         mItem.engine = engine;
         menuPopup.appendChild(mItem);
      })
   };  
   setItemsToMenuPopup();
   
   // установить действие для клика на меню и подменю
   menu.onmouseup =e=> {
      var background = (e.button == 0) ? false : true;
      var clip = gClipboard.read();
      goDoCommand('cmd_copy');
      setTimeout(()=> {
         contextMenu.hidePopup();
         var submission = e.target.engine.getSubmission(gClipboard.read(), null);
         gBrowser.loadOneTab(submission.uri.spec, null, null, submission.postData, background, false);
         gClipboard.write(clip);
      }, 0);
   };      
      
   
   // Наблюдатель за изменениями в поисковиках пересоздаёт меню и подменю .... 
   var getEngineModified = {
      observe:(subject, topic, data)=> {
         if ( /changed|removed|current/.test(data) ) { setMenu(), setItemsToMenuPopup() };             
      }
   };
   Services.obs.addObserver(getEngineModified, "browser-search-engine-modified", false);   
   
   
   // Удалять наблюдатели и меню, показать стандартный пункт ....
   addDestructor(()=> {
      menu.remove();            
      searchSelect.collapsed = false; 
      Services.obs.removeObserver(getEngineModified, "browser-search-engine-modified"); 
   });
      
})(document.getElementById("contentAreaContextMenu"), document.getElementById("context-searchselect"), Services.search);

Отредактировано bunda1 (13-12-2013 09:22:46)

Отсутствует

 

№218-12-2011 23:02:20

iDev.Pi
баг-репортёр
 
Группа: Extensions
Зарегистрирован: 31-01-2010
Сообщений: 2718
UA: Nightly 11.0

Re: [CB]Context Search

Аналогичное Context Search-у дополнение есть и в виде джетпака (его установка не требует перезапуска браузера): Context Search RG.
+ в нём есть одна мелкая удобная фишка, что сам пункт меню из которого выпадает список со всеми поисковыми машинами - он кликабельный и отвечает за текущую выбранную в Панели поиска поисковую машину.


mzfx

Отсутствует

 

№318-12-2011 23:53:38

vitalii201
Участник
 
Группа: Members
Зарегистрирован: 24-03-2011
Сообщений: 679
UA: Firefox 8.0

Re: [CB]Context Search

iDev.Pi пишет

пункт меню из которого выпадает список со всеми поисковыми машинами - он кликабельный

Здесь также ;)
Есть такая проблема, если выделенное находится с правого края, то меню выбора поисковиков закрывает осн. меню.
image004uk.jpg
Было бы не плохо что-бы открывалось только при наведении курсора на стрелку или хотя бы не так быстро(~ 1.5-2 сек.), что бы успеть нажать на поиск по текущему поисковому плагину.

Отсутствует

 

№419-12-2011 01:44:38

bunda1
Moderator
 
Группа: Moderators
Откуда: Латвия
Зарегистрирован: 09-02-2010
Сообщений: 4811
UA: Firefox 3.6

Re: [CB]Context Search

vitalii201 пишет

Было бы не плохо что-бы открывалось только при наведении курсора на стрелку или хотя бы не так быстро(~ 1.5-2 сек.), что бы успеть нажать на поиск по текущему поисковому плагину.

измени в коде

Выделить код

Код:

this.menu._menuDelay = 300;

на

Выделить код

Код:

this.menu._menuDelay = 1000;

или на

Выделить код

Код:

this.menu._menuDelay = 1500;

Отсутствует

 

№523-09-2012 00:44:41

villa7
Участник
 
Группа: Members
Зарегистрирован: 21-07-2012
Сообщений: 2235
UA: Firefox 15.0

Re: [CB]Context Search

bunda1
А можно сделать без подменю, а что-бы сразу показывались поисковики и без надписи выделенного, сижу на старом, кем то переделанном без подменю расширении Context Search и всякий раз обновления просятся, а там уже с подменю, да и от расширения избавиться неплохо бы.


Лучше спросить у знающих - чем лезть не зная.

Отсутствует

 

№623-09-2012 09:22:04

bunda1
Moderator
 
Группа: Moderators
Откуда: Латвия
Зарегистрирован: 09-02-2010
Сообщений: 4811
UA: Firefox 3.6

Re: [CB]Context Search

Как без подменю, объясни подробней.

Отсутствует

 

№723-09-2012 10:13:26

villa7
Участник
 
Группа: Members
Зарегистрирован: 21-07-2012
Сообщений: 2235
UA: Firefox 15.0

Re: [CB]Context Search

bunda1 пишет

Как без подменю, объясни подробней.

Выделяю слово, жму правую кнопку, и у меня сразу вместе с пунктами копировать, выделить и т.д., все поисковики, не надо еще открывать подпункт с поисковиками, у меня как-то так с самого начала было, привык, меньше телодвижений.


Лучше спросить у знающих - чем лезть не зная.

Отсутствует

 

№823-09-2012 10:27:34

bunda1
Moderator
 
Группа: Moderators
Откуда: Латвия
Зарегистрирован: 09-02-2010
Сообщений: 4811
UA: Firefox 3.6

Re: [CB]Context Search

Если ты используешь кнопку CB Mouse Gestures то там есть жест RLRL - [Popup] Поиск текста в выбранном поисковике. Это практически аналог Context Search, попробуй.

Отсутствует

 

№923-09-2012 11:11:42

villa7
Участник
 
Группа: Members
Зарегистрирован: 21-07-2012
Сообщений: 2235
UA: Firefox 15.0

Re: [CB]Context Search

bunda1 пишет

Если ты используешь кнопку CB Mouse Gestures то там есть жест RLRL - [Popup] Поиск текста в выбранном поисковике. Это практически аналог Context Search, попробуй.

Попробовал, там выходит один поисковик, а у меня их с десяток для разных целей, надо дополнительно переключаться, получается еще более неудобнее чем с подменю, если трудоемко убрать подменю то ладно, буду дальше старым расширением пользоваться, пока не сломается в новых версиях лисы, что теперь поделаешь.


Лучше спросить у знающих - чем лезть не зная.

Отсутствует

 

№1023-09-2012 11:48:03

voqabuhe
Участник
 
Группа: Members
Зарегистрирован: 06-12-2011
Сообщений: 3231
UA: Firefox 18.0

Re: [CB]Context Search

villa7 пишет

Попробовал, там выходит один поисковик, а у меня их с десяток для разных целей, надо дополнительно переключаться, получается еще более неудобнее чем с подменю,

Попробуй FireGestures :: Дополнения Firefox, там весь список поисковиков выдаёт.

Отсутствует

 

№1123-09-2012 12:52:59

bunda1
Moderator
 
Группа: Moderators
Откуда: Латвия
Зарегистрирован: 09-02-2010
Сообщений: 4811
UA: Firefox 3.6

Re: [CB]Context Search

villa7 пишет

Попробовал, там выходит один поисковик, а у меня их с десяток для разных целей

У меня этот жест выдаёт весь список поисковиков.

Отсутствует

 

№1223-09-2012 16:09:08

villa7
Участник
 
Группа: Members
Зарегистрирован: 21-07-2012
Сообщений: 2235
UA: Firefox 15.0

Re: [CB]Context Search

bunda1
'RLRL':{name:'[Popup]Search
Engines'

Всем спасибо за участие , добавил эту команду и стало то что нужно, до этого неправильно копировал из списка удаленных команд.


А еще такой вопрос,у знакомого ссылки на код кнопки кликабельны, а у меня нет, ставлю кнопки перетаскиванием в адресную строку. Скрипт текстовых ссылок Linkification стоит, если это от него зависит, или как.

Отредактировано villa7 (23-09-2012 16:19:32)


Лучше спросить у знающих - чем лезть не зная.

Отсутствует

 

№1324-09-2012 00:11:10

villa7
Участник
 
Группа: Members
Зарегистрирован: 21-07-2012
Сообщений: 2235
UA: Firefox 15.0

Re: [CB]Context Search

LongLogin
Easy DragToGo+

У меня раньше стояло, сменил на кнопку Drag and go, и потом там нужно сначала выделить потом дернуть, а Linkification сразу клацнул и все, пока браузер не крашился, тьфу,тфу. Все равно спасибо.


Лучше спросить у знающих - чем лезть не зная.

Отсутствует

 

№1424-09-2012 07:09:07

Kamui
Участник
 
Группа: Members
Зарегистрирован: 31-03-2011
Сообщений: 1796
UA: Firefox 16.0

Re: [CB]Context Search

LongLogin
Подозреваю что это

Отсутствует

 

№1524-09-2012 14:28:34

villa7
Участник
 
Группа: Members
Зарегистрирован: 21-07-2012
Сообщений: 2235
UA: Firefox 15.0

Re: [CB]Context Search

Kamui пишет

LongLoginПодозреваю что это

Да, именно эту кнопку поставил.


Лучше спросить у знающих - чем лезть не зная.

Отсутствует

 

№1624-09-2012 16:15:11

villa7
Участник
 
Группа: Members
Зарегистрирован: 21-07-2012
Сообщений: 2235
UA: Firefox 15.0

Re: [CB]Context Search

LongLogin

LongLogin пишет

всёже обращу внимание, что при большом кол-ве поисковиков, искать по вертикальному списку может оказаться крайне утомительно

Иеется ввиду Quick Search Bar?, я пробовал ставить, но у меня по правой кнопке вообще ни какие поисковики не появляются, может какие-то настройки поменять, а может на 15 лисе не работает.

Отредактировано villa7 (24-09-2012 16:20:11)


Лучше спросить у знающих - чем лезть не зная.

Отсутствует

 

№1729-10-2012 14:40:22

Lenya1995
Участник
 
Группа: Members
Зарегистрирован: 20-03-2009
Сообщений: 40
UA: Firefox 19.0

Re: [CB]Context Search

bunda1
Данный код в свежей сборке Nightly не хочет работать:( . Можно ли как-нибудь вернуть ее функциональность?

Отсутствует

 

№1806-11-2012 11:27:50

LBra
Участник
 
Группа: Members
Зарегистрирован: 20-10-2011
Сообщений: 40

Re: [CB]Context Search

villa7 пишет

bunda1
А можно сделать без подменю, а что-бы сразу показывались поисковики и без надписи выделенного, сижу на старом, кем то переделанном без подменю расширении Context Search и всякий раз обновления просятся, а там уже с подменю, да и от расширения избавиться неплохо бы.

Без подменю есть расширение Context Search X
Там вручную отредактируешь параметр extensions.contextsearchx.menuItems в about:config и получишь столько пунктов меню с собственными названиями сколько тебе потребуется, стандартно есть только два или три пункта...

Отсутствует

 

№1922-12-2012 21:40:07

lokiju
Участник
 
Группа: Members
Зарегистрирован: 30-01-2012
Сообщений: 208
UA: Firefox 17.0

Re: [CB]Context Search

Griever обновил contextSearcher до версии 0.0.7

слегка русифицированный contextSearcher

Выделить код

Код:

// ==UserScript==
// @name contextSearcher.uc.js
// @namespace http://d.hatena.ne.jp/Griever/
// @description 右クリック→検索の強化
// @include main
// @compatibility Firefox 4
// @version 0.0.7
// @note 0.0.7 Изменен чтобы получить слово, даже на ссылку
// @note 0.0.7 Оптимизация приобретение слова
// @note 0.0.6 カタカナの正規表現のミスを修正
// @note 0.0.6 splitmenu をやめた(menu 部分をクリックして検索可能)
// @note 0.0.6 Mac でカーソル下の単語をうまく拾えてなかったらしいのを修正したかも
// @note 0.0.5 サブメニューを中クリックすると2回実行される問題を修正
// @note 0.0.5 メニューの検索エンジン名を非表示にした
// @note 0.0.5 カーソル下の単語の取得を調整
// @note 0.0.5 "・"をカタカナとして処理していたのを修正
// @note 0.0.4 アイコンの無い検索エンジンがあるとエラーになるのを修正
// ==/UserScript==
// http://f.hatena.ne.jp/Griever/20100918161044
// ホイールで既定のエンジン変更、サブメニューから他の検索エンジンの利用
// 右クリックの位置により選択文字列、カーソル下の単語を検索可能

if (window.contextSearcher) {
  window.contextSearcher.destroy();
  delete window.contextSearcher;
}

window.contextSearcher = {
  NEW_TAB: true,

  _regexp: {
    hiragana: "[\\u3040-\\u309F]+",
    katakana: "[\\u30A0-\\u30FA\\u30FC]+",
    kanji : "[\\u4E00-\\u9FA0]+",
    suuji : "[0-9_./,%-]+",
    eisu_han: "\\w[\\w\\-]*",
    eisu_zen: "[\\uFF41-\\uFF5A\\uFF21-\\uFF3A\\uFF10-\\uFF19]+",
    hankaku : "[\\uFF00-\\uFFEF]+",
    hangul : "[\\u1100-\\u11FF\\uAC00-\\uD7AF\\u3130-\\u318F]+",
  },

  get startReg() {
    let reg = {};
    for(let n in this._regexp) {
      reg[n] = new RegExp('^' + this._regexp[n]);
    }
    delete this.startReg;
    return this.startReg = reg;
  },
  get endReg() {
    let reg = {};
    for(let n in this._regexp) {
      reg[n] = new RegExp(this._regexp[n] + '$');
    }
    delete this.endReg;
    return this.endReg = reg;
  },
  getCharType: function(aChar) {
    var c = aChar.charCodeAt(0);
    //if (c >= 0x30 && c <= 0x39) return "suuji";
    if (c >= 0x30 && c <= 0x39 || c >= 0x41 && c <= 0x5A || c >= 0x61 && c <= 0x7A || c === 0x5F) return "eisu_han";
    if (c >= 0x30A0 && c <= 0x30FA || c === 0x30FC) return "katakana";
    if (c >= 0x3040 && c <= 0x309F) return "hiragana";
    if (c >= 0x4E00 && c <= 0x9FA0) return "kanji";
    if (c >= 0xFF41 && c <= 0x9F5A || c >= 0xFF21 && c <= 0xFF3A || c >= 0xFF10 && c <= 0xFF19) return "eisu_zen";
    if (c >= 0xFF00 && c <= 0xFFEF) return "hankaku";
    if (c >= 0x1100 && c <= 0x11FF || c >= 0xAC00 && c <= 0xD7AF || c >= 0x3130 && c <= 0x318F) return "hangul";
    return "";
  },

  searchText: '',
  searchEngines: [],
  init: function(){
    this.isMac = navigator.platform.indexOf("Mac") == 0;
    this.searchService = Cc["@mozilla.org/browser/search-service;1"].getService(Ci.nsIBrowserSearchService);
    this.context = document.getElementById('contentAreaContextMenu');
    var searchselect = document.getElementById('context-searchselect');
    searchselect.style.display = 'none';

    this.menu = this.context.insertBefore(document.createElement('menu'), searchselect);
    this.menu.setAttribute('id', 'context-searcher');
    this.menu.setAttribute('class', 'menu-iconic');
    this.menu.setAttribute('accesskey', searchselect.accessKey);
    this.menu.setAttribute('onclick', 'if (event.target == this) { contextSearcher.command(event); closeMenus(this); }');

    this.popup = this.menu.appendChild( document.createElement('menupopup') );

    this.context.addEventListener('popupshowing', this, false);
    this.menu.addEventListener('DOMMouseScroll', this, false);
    gBrowser.mPanelContainer.addEventListener(this.isMac ? 'mousedown' : 'click', this, false);
    window.addEventListener('unload', this, false);
  },

  uninit: function() {
    this.context.removeEventListener('popupshowing', this, false);
    this.menu.removeEventListener('DOMMouseScroll', this, false);
    gBrowser.mPanelContainer.removeEventListener('click', this, false);
    gBrowser.mPanelContainer.removeEventListener('mousedown', this, false);
    window.removeEventListener('unload', this, false);
  },

  destroy: function(){
    this.uninit();
    document.getElementById('context-searchselect').style.removeProperty('display');
    var m = document.getElementById('context-searcher');
    if (m)
      m.parentNode.removeChild(m);
  },

  handleEvent: function(event) {
    if (this[event.type])
      this[event.type](event);
  },
  
  unload: function(e){
    this.uninit();
  },

  DOMMouseScroll: function(e) {
    if (this.searchEngines.length === 0)
      this.searchEngines = this.searchService.getVisibleEngines({});
    if (!this.searchEngines || this.searchEngines.length == 0)
      return;
    
    var index = this.searchEngines.indexOf(this.searchService.currentEngine);
// var newEngine = e.detail > 0?
// this.searchEngines[index+1] || this.searchEngines[0]:
// this.searchEngines[index-1] || this.searchEngines[this.searchEngines.length -1];
    var newEngine = e.detail > 0? this.searchEngines[index+1] : this.searchEngines[index-1];
    if (!newEngine)
      return;
    this.searchService.currentEngine = newEngine;
    this.setMenuitem();
  },

  command: function(e){
    var target = e.target;
    var engine = e.target.engine || this.menu.engine;

    var submission = engine.getSubmission(this.searchText, null);
    if (!submission)
      return;

    var newtab = this.NEW_TAB || e.button === 1 || e.shiftKey || e.ctrlKey;
    if (!newtab) {
      loadURI(submission.uri.spec, null, submission.postData, false);
    } else {
      gBrowser.selectedTab = gBrowser.addTab(submission.uri.spec, {
        postData: submission.postData,
        ownerTab: gBrowser.mCurrentTab,
      });
    }
  },

  click: function(event) {
    if (event.button === 2) {
      this._clickNode = event.rangeParent;
      this._clickOffset = event.rangeOffset;
      this._clientX = event.clientX;
    } else {
      this._clickNode = null;
      this._clickOffset = 0;
      this._clientX = 0;
    }
  },

  mousedown: function(event) {
    this.click(event);
  },

  setMenuitem: function() {
    var currentEngine = this.searchService.currentEngine;
    var l = this.searchText.length > 16? this.searchText.substr(0, 16) + '...' : this.searchText;
    this.menu.engine = currentEngine;
    this.menu.setAttribute('label', gNavigatorBundle.getFormattedString("contextMenuSearchText", [currentEngine.name, l]));
    //this.menu.setAttribute('label', 'Искать "' + l + '"');
    //this.menu.setAttribute('tooltiptext', currentEngine.name);
    if (currentEngine.iconURI)
      this.menu.style.listStyleImage = 'url("' + currentEngine.iconURI.spec + '")';
    else
      this.menu.style.removeProperty('list-style-image');
  },

  popupshowing: function(e){
    if (e.target != this.context) return;

    this.searchText =
      gContextMenu.isTextSelected? this.getBrowserSelection() :
      gContextMenu.onImage? gContextMenu.target.getAttribute('alt') :
      //gContextMenu.onLink? gContextMenu.linkText() :
      gContextMenu.onTextInput? this.getTextInputSelection() :
      this.getCursorPositionText();

    if (!this.searchText || !/\S/.test(this.searchText)) {
      this.menu.hidden = true;
      return;
    }
    if (this.searchText.length > 256)
      this.searchText = this.searchText.substr(0, 256);
    this.menu.hidden = false;
    
    if (!this.popup.hasChildNodes() || e.ctrlKey)
      this.createMenuitem();
    
    this.setMenuitem();
  },
  
  createMenuitem: function(){
    this.searchEngines = this.searchService.getVisibleEngines({});
    if (!this.searchEngines || this.searchEngines.length == 0)
      return;

    var f;
    while (f = this.popup.firstChild) {
      this.popup.removeChild(f);
    }

    this.menu.engine = this.searchService.currentEngine;
    if (this.menu.engine.iconURI)
      this.menu.style.listStyleImage = 'url("' + this.menu.engine.iconURI.spec + '")';
    else
      this.menu.style.removeProperty('list-style-image');
    for (var i = 0, s = this.searchEngines, l = s.length; i < l; i++) {
      var engine = s[i];
      var m = document.createElement('menuitem');
      m.setAttribute('label', engine.name);
      m.setAttribute('class', 'menuitem-iconic bookmark-item');
      if (engine.iconURI) {
        m.setAttribute('image', engine.iconURI.spec);
      }
      m.setAttribute('oncommand', 'contextSearcher.command(event);');
      m.setAttribute('onclick', 'checkForMiddleClick(this, event);');
      m.engine = engine;
      this.popup.appendChild(m);
    }
  },
  
  getBrowserSelection: function () {
    var win = document.commandDispatcher.focusedWindow;
    var sel = win.getSelection();
    var str = '';
    if (sel.isCollapsed)
      return str;

    for(var i = 0, l = sel.rangeCount; i < l; i++) {
      str += sel.getRangeAt(i) + ' ';
    }
    return str.replace(/^\s*|\s*$/g, '').replace(/\s+/g, ' ');
  },
  
  getTextInputSelection: function () {
    var elem = document.commandDispatcher.focusedElement;
    var str = elem.value.slice(elem.selectionStart, elem.selectionEnd);
    return str.replace(/^\s*|\s*$/g, '').replace(/\s+/g, ' ');
  },

  getCursorPositionText: function() {
    var node = this._clickNode;
    var offset = this._clickOffset;
    if (!node || node.nodeType !== Node.TEXT_NODE)
      return "";

    var text = node.nodeValue;

    // 文字の右半分をクリック時に次の文字を取得する対策
    var range = node.ownerDocument.createRange();
    range.setStart(node, offset);
    var rect = range.getBoundingClientRect();
    range.detach();
    if (rect.left >= this._clientX)
      offset--;

    if (!text[offset]) return "";
    var type = this.getCharType(text[offset]);
    if (!type) return "";

    var mae = text.substr(0, offset);
    var ato = text.substr(offset); // text[offset] はこっちに含まれる
    var ato_word = (this.startReg[type].exec(ato) || [""])[0];
    var str = this.endReg[type].test(mae) ? RegExp.lastMatch + ato_word : ato_word;

    if (str.length === 1) {
      if (type === "kanji") {
        if (this.startReg["hiragana"].test(ato.substr(ato_word.length)))
          str += RegExp.lastMatch;
      } else {
        return "";
      }
    }
    
    return str;
  },
  
  log: function() {
    Application.console.log("[contextSearcher] " + Array.slice(arguments));
  }
}

window.contextSearcher.init();

Отсутствует

 

№2019-09-2013 20:47:18

PEAKTOP
Участник
 
Группа: Members
Зарегистрирован: 07-10-2009
Сообщений: 116
UA: Firefox 24.0

Re: [CB]Context Search

Обновлённый и русифицированный вариант

contextSearcher версии 0.0.8

Выделить код

Код:

// ==UserScript==
// @name           contextSearcher.uc.js
// @namespace      http://d.hatena.ne.jp/Griever/
// @description    右クリック→検索の強化
// @include        main
// @compatibility  Firefox 4
// @version        0.0.8
// @note           0.0.8 Firefox 19 で入力欄で使えなくなったのを修正
// @note           0.0.8 NEW_TAB の初期値を browser.search.openintab にした
// @note           0.0.7 リンク上でも単語を取得するように変更
// @note           0.0.7 単語の取得を効率化
// @note           0.0.6 カタカナの正規表現のミスを修正
// @note           0.0.6 splitmenu をやめた(menu 部分をクリックして検索可能)
// @note           0.0.6 Mac でカーソル下の単語をうまく拾えてなかったらしいのを修正したかも
// @note           0.0.5 サブメニューを中クリックすると2回実行される問題を修正
// @note           0.0.5 メニューの検索エンジン名を非表示にした
// @note           0.0.5 カーソル下の単語の取得を調整
// @note           0.0.5 "・"をカタカナとして処理していたのを修正
// @note           0.0.4 アイコンの無い検索エンジンがあるとエラーになるのを修正
// ==/UserScript==
// http://f.hatena.ne.jp/Griever/20100918161044
// ホイールで既定のエンジン変更、サブメニューから他の検索エンジンの利用
// 右クリックの位置により選択文字列、カーソル下の単語を検索可能

if (window.contextSearcher) {
  window.contextSearcher.destroy();
  delete window.contextSearcher;
}

window.contextSearcher = {
  NEW_TAB: Services.prefs.getBoolPref("browser.search.openintab"),

  _regexp: {
    hiragana: "[\\u3040-\\u309F]+",
    katakana: "[\\u30A0-\\u30FA\\u30FC]+",
    kanji   : "[\\u4E00-\\u9FA0]+",
    suuji   : "[0-9_./,%-]+",
    eisu_han: "\\w[\\w\\-]*",
    eisu_zen: "[\\uFF41-\\uFF5A\\uFF21-\\uFF3A\\uFF10-\\uFF19]+",
    hankaku : "[\\uFF00-\\uFFEF]+",
    hangul  : "[\\u1100-\\u11FF\\uAC00-\\uD7AF\\u3130-\\u318F]+",
  },

  get startReg() {
    let reg = {};
    for(let n in this._regexp) {
      reg[n] = new RegExp('^' + this._regexp[n]);
    }
    delete this.startReg;
    return this.startReg = reg;
  },
  get endReg() {
    let reg = {};
    for(let n in this._regexp) {
      reg[n] = new RegExp(this._regexp[n] + '$');
    }
    delete this.endReg;
    return this.endReg = reg;
  },
  getCharType: function(aChar) {
    var c = aChar.charCodeAt(0);
    //if (c >= 0x30 && c <= 0x39) return "suuji";
    if (c >= 0x30 && c <= 0x39 || c >= 0x41 && c <= 0x5A || c >= 0x61 && c <= 0x7A || c === 0x5F) return "eisu_han";
    if (c >= 0x30A0 && c <= 0x30FA || c === 0x30FC) return "katakana";
    if (c >= 0x3040 && c <= 0x309F) return "hiragana";
    if (c >= 0x4E00 && c <= 0x9FA0) return "kanji";
    if (c >= 0xFF41 && c <= 0x9F5A || c >= 0xFF21 && c <= 0xFF3A || c >= 0xFF10 && c <= 0xFF19) return "eisu_zen";
    if (c >= 0xFF00 && c <= 0xFFEF) return "hankaku";
    if (c >= 0x1100 && c <= 0x11FF || c >= 0xAC00 && c <= 0xD7AF || c >= 0x3130 && c <= 0x318F) return "hangul";
    return "";
  },

  searchText: '',
  searchEngines: [],
  init: function(){
    this.isMac = navigator.platform.indexOf("Mac") == 0;
    this.searchService = Cc["@mozilla.org/browser/search-service;1"].getService(Ci.nsIBrowserSearchService);
    this.context = document.getElementById('contentAreaContextMenu');
    var searchselect = document.getElementById('context-searchselect');
    searchselect.style.display = 'none';

    this.menu = this.context.insertBefore(document.createElement('menu'), searchselect);
    this.menu.setAttribute('id', 'context-searcher');
    this.menu.setAttribute('class', 'menu-iconic');
    this.menu.setAttribute('accesskey', searchselect.accessKey);
    this.menu.setAttribute('onclick', 'if (event.target == this) { contextSearcher.command(event); closeMenus(this); }');

    this.popup = this.menu.appendChild( document.createElement('menupopup') );

    this.context.addEventListener('popupshowing', this, false);
    this.menu.addEventListener('DOMMouseScroll', this, false);
    gBrowser.mPanelContainer.addEventListener(this.isMac ? 'mousedown' : 'click', this, false);
    window.addEventListener('unload', this, false);
  },

  uninit: function() {
    this.context.removeEventListener('popupshowing', this, false);
    this.menu.removeEventListener('DOMMouseScroll', this, false);
    gBrowser.mPanelContainer.removeEventListener('click', this, false);
    gBrowser.mPanelContainer.removeEventListener('mousedown', this, false);
    window.removeEventListener('unload', this, false);
  },

  destroy: function(){
    this.uninit();
    document.getElementById('context-searchselect').style.removeProperty('display');
    var m = document.getElementById('context-searcher');
    if (m)
      m.parentNode.removeChild(m);
  },

  handleEvent: function(event) {
    if (this[event.type])
      this[event.type](event);
  },
  
  unload: function(e){
    this.uninit();
  },

  DOMMouseScroll: function(e) {
    if (this.searchEngines.length === 0)
      this.searchEngines = this.searchService.getVisibleEngines({});
    if (!this.searchEngines || this.searchEngines.length == 0)
      return;
    
    var index = this.searchEngines.indexOf(this.searchService.currentEngine);
//    var newEngine = e.detail > 0?
//      this.searchEngines[index+1] || this.searchEngines[0]:
//      this.searchEngines[index-1] || this.searchEngines[this.searchEngines.length -1];
    var newEngine = e.detail > 0? this.searchEngines[index+1] : this.searchEngines[index-1];
    if (!newEngine)
      return;
    this.searchService.currentEngine = newEngine;
    this.setMenuitem();
  },

  command: function(e){
    var target = e.target;
    var engine = e.target.engine || this.menu.engine;

    var submission = engine.getSubmission(this.searchText, null);
    if (!submission)
      return;

    var where = whereToOpenLink(e);
    if (this.NEW_TAB && where === 'current' || where === 'save')
      where = 'tab';

    openLinkIn(submission.uri.spec, where, {
      postData: submission.postData,
      relatedToCurrent: true
    });
  },

  click: function(event) {
    if (event.button === 2) {
      this._clickNode = event.rangeParent;
      this._clickOffset = event.rangeOffset;
      this._clientX = event.clientX;
    } else {
      this._clickNode = null;
      this._clickOffset = 0;
      this._clientX = 0;
    }
  },

  mousedown: function(event) {
    this.click(event);
  },

  setMenuitem: function() {
    var currentEngine = this.searchService.currentEngine;
    var l = this.searchText.length > 16? this.searchText.substr(0, 16) + '...' : this.searchText;
    this.menu.engine = currentEngine;
    //this.menu.setAttribute('label', gNavigatorBundle.getFormattedString("contextMenuSearchText", [currentEngine.name, l]));
    this.menu.setAttribute('label', 'Искать "' + l + '"' +' в ' + currentEngine.name);
    this.menu.setAttribute('tooltiptext', currentEngine.name);
       this.menu.setAttribute('tooltiptext', currentEngine.name);
    if (currentEngine.iconURI)
      this.menu.style.listStyleImage = 'url("' + currentEngine.iconURI.spec + '")';
    else 
      this.menu.style.removeProperty('list-style-image');
  },

  popupshowing: function(e){
    if (e.target != this.context) return;

    this.searchText = 
      gContextMenu.onTextInput? this.getTextInputSelection() :
      gContextMenu.isTextSelected? this.getBrowserSelection() :
      gContextMenu.onImage? gContextMenu.target.getAttribute('alt') :
      //gContextMenu.onLink? gContextMenu.linkText() :
      this.getCursorPositionText();

    if (!this.searchText || !/\S/.test(this.searchText)) {
      this.menu.hidden = true;
      return;
    }
    if (this.searchText.length > 256)
      this.searchText = this.searchText.substr(0, 256);
    this.menu.hidden = false;
    
    if (!this.popup.hasChildNodes() || e.ctrlKey)
      this.createMenuitem();
    
    this.setMenuitem();
  },
  
  createMenuitem: function(){
    this.searchEngines = this.searchService.getVisibleEngines({});
    if (!this.searchEngines || this.searchEngines.length == 0)
      return;

    var f;
    while (f = this.popup.firstChild) {
      this.popup.removeChild(f);
    }

    this.menu.engine = this.searchService.currentEngine;
    if (this.menu.engine.iconURI)
      this.menu.style.listStyleImage = 'url("' + this.menu.engine.iconURI.spec + '")';
    else 
      this.menu.style.removeProperty('list-style-image');
    for (var i = 0, s = this.searchEngines, l = s.length; i < l; i++) {
      var engine = s[i];
      var m = document.createElement('menuitem');
      m.setAttribute('label', engine.name);
      m.setAttribute('class', 'menuitem-iconic bookmark-item');
      if (engine.iconURI) {
        m.setAttribute('image', engine.iconURI.spec);
      }
      m.setAttribute('oncommand', 'contextSearcher.command(event);');
      m.setAttribute('onclick', 'checkForMiddleClick(this, event);');
      m.engine = engine;
      this.popup.appendChild(m);
    }
  },
  
  getBrowserSelection: function () {
    var win = document.commandDispatcher.focusedWindow;
    var sel = win.getSelection();
    var str = '';
    if (sel.isCollapsed)
      return str;

    for(var i = 0, l = sel.rangeCount; i < l; i++) {
      str += sel.getRangeAt(i) + ' ';
    }
    return str.replace(/^\s*|\s*$/g, '').replace(/\s+/g, ' ');
  },
  
  getTextInputSelection: function () {
    var elem = document.commandDispatcher.focusedElement;
    var str = elem.value.slice(elem.selectionStart, elem.selectionEnd);
    return str.replace(/^\s*|\s*$/g, '').replace(/\s+/g, ' ');
  },

  getCursorPositionText: function() {
    var node = this._clickNode;
    var offset = this._clickOffset;
    if (!node || node.nodeType !== Node.TEXT_NODE)
      return "";

    var text = node.nodeValue;

    // 文字の右半分をクリック時に次の文字を取得する対策
    var range = node.ownerDocument.createRange();
    range.setStart(node, offset);
    var rect = range.getBoundingClientRect();
    range.detach();
    if (rect.left >= this._clientX)
      offset--;

    if (!text[offset]) return "";
    var type = this.getCharType(text[offset]);
    if (!type) return "";

    var mae = text.substr(0, offset);
    var ato = text.substr(offset); // text[offset] はこっちに含まれる
    var ato_word = (this.startReg[type].exec(ato) || [""])[0];
    var str = this.endReg[type].test(mae) ? RegExp.lastMatch + ato_word : ato_word;

    if (str.length === 1) {
      if (type === "kanji") {
        if (this.startReg["hiragana"].test(ato.substr(ato_word.length)))
          str += RegExp.lastMatch;
      } else {
        return "";
      }
    }
    
    return str;
  },
  
  log: function() {
    Application.console.log("[contextSearcher] " + Array.slice(arguments));
  }
}

window.contextSearcher.init();

Отредактировано PEAKTOP (19-09-2013 23:08:03)


1. Приму из добрых рук щедрый дар - инвайт на Хабр и Лепру
2. Бессмысленно осмысливать смысл неосмысленными мыслями!
3. Прежде чем подумать - подумай!

Отсутствует

 

№2119-09-2013 22:31:29

SendInfo
.
 
Группа: Members
Зарегистрирован: 14-02-2011
Сообщений: 271
UA: Firefox 27.0

Re: [CB]Context Search

PEAKTOP
См. пост №19( у меня работает бесперебойно на [firefox] 23, 24, 25, 26 и [nightly] 27 )

Отредактировано SendInfo (19-09-2013 22:32:19)

Отсутствует

 

№2220-09-2013 00:12:20

PEAKTOP
Участник
 
Группа: Members
Зарегистрирован: 07-10-2009
Сообщений: 116
UA: Firefox 24.0

Re: [CB]Context Search

SendInfo, в том-то и дело, что код из поста №19 не совсем корректно работал - не отображал текст в пункте контекстного меню 3136439.png 
В моём предыдущем посте код с исправлением этого недоразумения.


Попутно два вопроса к знатокам:
1. Как зафиксировать этот пункт в определённом месте контекстного меню, а именно на второй позиции сверху?
2. Как заставить скрипт по умолчанию использовать поисковую систему не ту, что сейчас указана в панели поиска? Сейчас у меня в "панели поиска" задана Wikipedia, соответственно в пункте контекстного меню тоже будет она, а мне надо, чтобы там был Google (для справки он у меня первый в списке поисковых систем в панели поиска).  Т.е., независимо от того, какая поисковая система указана в "панели поиска", скрипт должен подставлять  в пункт меню Google.

Отредактировано PEAKTOP (20-09-2013 00:16:41)


1. Приму из добрых рук щедрый дар - инвайт на Хабр и Лепру
2. Бессмысленно осмысливать смысл неосмысленными мыслями!
3. Прежде чем подумать - подумай!

Отсутствует

 

№2321-09-2013 13:48:55

bunda1
Moderator
 
Группа: Moderators
Откуда: Латвия
Зарегистрирован: 09-02-2010
Сообщений: 4811
UA: Firefox 3.6

Re: [CB]Context Search

PEAKTOP пишет

2. Как заставить скрипт по умолчанию использовать поисковую систему не ту, что сейчас указана в панели поиска? Сейчас у меня в "панели поиска" задана Wikipedia, соответственно в пункте контекстного меню тоже будет она, а мне надо, чтобы там был Google (для справки он у меня первый в списке поисковых систем в панели поиска).  Т.е., независимо от того, какая поисковая система указана в "панели поиска", скрипт должен подставлять  в пункт меню Google.

Если по простому :):
ybyc.jpg

Выделить код

Код:

// Context Search mini, от 21.09.2013. ................................
(function () {
   var searchSelect = document.getElementById('context-searchselect');  
   searchSelect.collapsed = true;

   
   var contextMenu = document.getElementById("contentAreaContextMenu");  
   var menu = contextMenu.insertBefore( document.createElement('menu'), searchSelect );
   menu.setAttribute("label", "Искать в Google или в ...");
   menu.setAttribute("class", "menu-iconic");
   menu.style.listStyleImage = 'url("https://www.google.lv/favicon.ico")';
   menu.setAttribute("onclick", "\
      if ( !!event.target.engine ) return;\
      gBrowser.loadOneTab('http://www.google.com/search?q=' + getBrowserSelection(), null, null, null, false, false);\
      setTimeout(function() { document.getElementById('contentAreaContextMenu').hidePopup() }, 0);\
   ");
   var observeStatus = new MutationObserver(function() {
          menu.hidden = searchSelect.hidden;          
   });
   observeStatus.observe( searchSelect, { attributes: true, attributeFilter: ["hidden"]  } );
   addDestructor(function() { contextMenu.removeChild( menu ); observeStatus.disconnect(); searchSelect.collapsed = false });   
   
   
   var menuPopup = menu.appendChild(document.createElement("menupopup"));
   var searchService = Cc["@mozilla.org/browser/search-service;1"].getService(Ci.nsIBrowserSearchService); 
   
   addEventListener('popupshowing', function(e) {
      menuPopup.textContent = "";      
      
      var engines = searchService.getVisibleEngines({});
      engines.forEach(function( engine ) {
         var mItem = document.createElement("menuitem");
         mItem.setAttribute("label", engine.name );
         mItem.setAttribute("class", "menuitem-iconic");
         mItem.setAttribute("src", engine.iconURI.spec );
         mItem.engine = engine;
         menuPopup.appendChild( mItem );
      });
      menuPopup.setAttribute("oncommand", "\
         var submission = event.target.engine.getSubmission( getBrowserSelection(), null );\
         gBrowser.loadOneTab( submission.uri.spec, null, null, submission.postData, false, false );\
      ");
   }, false, menu );  
      
})();
PEAKTOP пишет

1. Как зафиксировать этот пункт в определённом месте контекстного меню, а именно на второй позиции сверху?

Выделить код

Код:

var menu = contextMenu.insertBefore( document.createElement('menu'), searchSelect );

Тут вместо searchSelect укажи пункт контекстного меню над которым пункт Искать в Google должен находится, например пункт Копировать:

Выделить код

Код:

document.getElementById('context-copy');

Отредактировано bunda1 (21-09-2013 15:23:34)

Отсутствует

 

№2421-09-2013 19:30:55

PEAKTOP
Участник
 
Группа: Members
Зарегистрирован: 07-10-2009
Сообщений: 116
UA: Firefox 24.0

Re: [CB]Context Search

bunda1, БОЛЬШОЕ ПРЕБОЛЬШОЕ СПАСИБО!
Ещё одна просьба. Можешь добавить в текст пункта меню выделенное/искомое слово?
как здесь
3146601.png

Отредактировано PEAKTOP (21-09-2013 19:39:00)


1. Приму из добрых рук щедрый дар - инвайт на Хабр и Лепру
2. Бессмысленно осмысливать смысл неосмысленными мыслями!
3. Прежде чем подумать - подумай!

Отсутствует

 

№2521-09-2013 21:28:28

dedmazai1870
Забанен
 
Группа: Members
Откуда: Москва
Зарегистрирован: 24-08-2013
Сообщений: 57
UA: Firefox 24.0

Re: [CB]Context Search

PEAKTOP
Это если одно слово, а если ищешь фразу - или меню на весь экран расползётся или обрежется до "Программа..." в зависимости от реализации. Лично мне кажется, что это не принципиально.
bunda1
Всё работает, замечательно! Спасибо.
Context Search X дополнительно к списку моих поисков подключает поиск google последней строкой "Включает строку поиска выделенного текста на текущем сайте."
Чтобы из выделенного мной текста, например "поиск по сайту" получилась такая строка:

скрытый текст
https://www.google.com/search?q=%D0%BF%D0%BE%D0%B8%D1%81%D0%BA+%D0%BF%D0%BE+%D1%81%D0%B0%D0%B9%D1%82%D1%83&filter=0&as_q=site%3Aforum.mozilla-russia.org

Эта строка в виде ссылки.

Это пример, сайт должен подставляться тот, на котором я выделил какую-то фразу.


Можно в кнопке это реализовать?
P.S. Я перешёл на [firefox] с [opera]. Там поиск по форуму отломан и человек сделал javascript, который реализовал поиск по форуму через google именно такой функцией.
Я не знаю javascript и самостоятельно прикрутить к Вашей кнопке не смогу. Может этот код Вам пригодится?
скрытый текст

Выделить код

Код:

document.addEventListener('DOMContentLoaded', function() {
    if (typeof(searchform) != 'undefined')
    {
        var all_f = location.host + location.pathname.substring(0, location.pathname.lastIndexOf('/'));
        //opera.postError(all_f);
        var google_search = '<div>';
        google_search += '<input type="text" name="q" size="30" value="поиск в google" onblur="if (this.value == \'\') this.value = \'поиск в google\'" onfocus="if (this.value == \'поиск в google\') this.value = \'\'">';
        google_search += '<input type="submit" value=" Поиск ">';
        google_search += '<input type="hidden" name="filter" value="0">';
        if (location.pathname.indexOf('topic.dml') != '-1')
        {
            var topic_id = location.search.substring(location.search.indexOf('id='));
            if (topic_id.indexOf('&') != '-1')
                topic_id = topic_id.substring(0, topic_id.indexOf('&'));
            //opera.postError(topic_id);
            google_search += '<p>';
            google_search += '<input type="radio" name="as_q" value="site:' + all_f + ' inurl:' + topic_id + '" checked id="this-forum">';
            google_search += '<label for="this-topic">В этой теме</label>';
            google_search += '<input type="radio" name="as_q" value="site:' + all_f + '" id="all-forums">';
            google_search += '<label for="all-forums">Во всех форумах</label>';
            google_search += '</p>';
        }
        else
            google_search += '<input type="hidden" name="as_q" value="site:' + all_f + '">';
        google_search += '</div>';
        searchform.action = 'http://www.google.com/search';
        searchform.innerHTML = google_search;
    }
}, false)


P.P.S. Ещё раз спасибо.

Отсутствует

 

Board footer

Powered by PunBB
Modified by Mozilla Russia
Copyright © 2004–2020 Mozilla Russia GitHub mark
Язык отображения форума: [Русский] [English]