aboutsummaryrefslogtreecommitdiffstats
path: root/opener.js
blob: 2036e1818a6172328559add81810c4cf56bc7ed6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// PLUGIN_INFO {{{
let PLUGIN_INFO =
<VimperatorPlugin>
  <name>opener</name>
  <name lang="ja">opener</name>
  <description> --- </description>
  <description lang="ja">URL 移動時にそのURLが既に開かれていたらそのタブに移動する</description>
  <version>1.0.0</version>
  <author homepage="http://vimperator.g.hatena.ne.jp/voidy21/">voidy21</author>
  <author mail="anekos@snca.net" homepage="http://d.hatena.ne.jp/nokturnalmortum/">anekos</author>
  <updateURL>https://github.com/vimpr/vimperator-plugins/raw/master/opener.js</updateURL>
  <minVersion>2.3</minVersion>
  <maxVersion>2.3</maxVersion>
  <detail><![CDATA[
    URL 移動時にそのURLが既に開かれていたらそのタブに移動する
  ]]></detail>
  <detail lang="ja"><![CDATA[
    URL 移動時にそのURLが既に開かれていたらそのタブに移動する
  ]]></detail>
</VimperatorPlugin>;
// }}}
// INFO {{{
let INFO =
<>
  <plugin name="opener" version="1.0.0"
          href="http://svn.coderepos.org/share/lang/javascript/vimperator-plugins/trunk/opener.js"
          summary="URL 移動時にそのURLが既に開かれていたら、そのタブに移動する"
          xmlns="http://vimperator.org/namespaces/liberator">
    <author>voidy21</author>
    <author email="anekos@snca.net">anekos</author>
    <project name="Vimperator" minVersion="2.3"/>
    <p>URL 移動時にそのURLが既に開かれていたらそのタブに移動する</p>
  </plugin>
</>;
// }}}

/*
 * Original version by voidy21:
 *  http://vimperator.g.hatena.ne.jp/voidy21/20100119/1263907211
 *  http://vimperator.g.hatena.ne.jp/voidy21/20100127/1264542669
 */

(function () {
  let U = liberator.plugins.libly.$U;

  function jump (url) {
    let index = 0;
    let url = util.stringToURLArray(url).toString();
    if (url == buffer.URL){
      return false;
    }
    for each ( [,tab] in tabs.browsers ) {
      if (url == tab.currentURI.spec){
        tabs.select(index);
        return true;
      }
      ++index;
    }
    return false;
  }

  "open tabopen edit".split(/\s/).forEach(
    function (name) {
      let command = commands.get(name);
      if (!command)
        return;
      U.around(
        command,
        "action",
        function (next, args) {
          let url = args[0].string;
          if (!(url && jump(url)))
            return next();
        }
      );
    }
  );

  //buffer.followLink()を変更
  //hint-a-hint時[f,F]に対象のタブが既に開いてあったらjump
  let (ignore = false) {
    let ignoreBlock = function (block) {
      ignore = true;
      let result = block();
      ignore = false;
      return result;
    };

    U.around(
      buffer,
      "followLink",
      function (next, args) {
        return ignoreBlock(function () {
          let [elem,] = args;
          let url = elem.href;
          if (!(url && jump(url))){
            liberator.echo("Now Loading... " + url);
            return next();
          }
        });
      }
    );

    document.addEventListener(
      'click',
      function (event) {
        if (ignore)
          return;
        let e = event.target;
        if (e && e.tagName.match(/^a$/i) && e.href && jump(e.href)) {
          event.preventDefault();
          event.stopPropagation();
        }
      },
      true
    );
  }

})();
try { dict = this.engine.dictionary; } catch (e) {} return dict ? dict : null; }, /** * @param {String} dict */ setDictionary: function (dict) { var dictionaries = this.getDictionaryList(); for (let i=0, max=dictionaries.length ; i<max ; ++i) { if (dictionaries[i] === dict) { this.engine.dictionary = dict; return dict; } } return null; }, /** * @param {Boolean} isBeginningWith */ setBeginningWith: function (isBeginningWith) { this.isBeginningWith = isBeginningWith; }, /** * @param {String} spell * @return {Boolean} */ check: function (spell) { return this.engine.check(spell); }, /** * @param {String} spell * @return {Array} */ suggest: function (spell) { var suggestions = {}; this.engine.suggest(spell, suggestions, {}); suggestions = suggestions.value; if (this.isBeginningWith) { suggestions = suggestions.filter( function (cand) { return (cand.toLowerCase().indexOf(spell) === 0); }); } return suggestions; }, }; var spellChecker = buildSpellChecker(); SITE_DEFINITION.forEach(function (dictionary) { commands.addUserCommand( dictionary.names, dictionary.shortHelp, function (args,special) { var arg = args.string; var sel = (window.content.window.getSelection) ? window.content.window.getSelection().toString() : null; if (special && sel) arg = sel; if (!arg) return; var url; if (dictionary.urlEncode) { let ttbu = Components.classes['@mozilla.org/intl/texttosuburi;1'] .getService( Components.interfaces.nsITextToSubURI); url = dictionary.url.replace(/%s/g, ttbu.ConvertAndEscape(dictionary.urlEncode, arg)); } else { url = dictionary.url.replace(/%s/g,encodeURIComponent(arg)); } //liberator.log('URL: ' +url); var result; getHTML(url, function (str) { var doc = createHTMLDocument(str); var result = getNodeFromXPath(dictionary.xpath, doc, dictionary.multi); if (!result) { liberator.echoerr('Nothing to show...'); } var xs = new XMLSerializer(); liberator.echo(new XMLList('<div style="white-space:normal;"><base href="' + util.escapeHTML(url) + '"/>' + xs.serializeToString( result ).replace(/<[^>]+>/g,function (all) all.toLowerCase() ) + '</div>'), true); }, dictionary.srcEncode ? dictionary.srcEncode : null); }, { completer: function (arg) { if (!spellChecker || !dictionary.dictionary || !spellChecker.setDictionary(dictionary.dictionary)) return [0, []]; var suggestions = spellChecker.suggest(arg); var candidates = []; for (let i=0, max=suggestions.length ; i<max ; ++i) { candidates.push([suggestions[i], 'suggest']); } if (!spellChecker.check(arg)) { candidates.unshift(['', 'not exist']); } return [0, candidates]; }, bang: true } ); }); commands.addUserCommand( ['availabledictionaries'], 'display available dictionaries', function () { liberator.echo('available dictionaries: ' + spellChecker.getDictionaryList()); }, {} ); /** * @param {String} url * @param {Function} callback * @param {String} charset */ function getHTML(url, callback, charset) { var xhr= new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (xhr.status == 200) { callback.call(this,xhr.responseText); } else { throw new Error(xhr.statusText); } } }; xhr.open('GET',url,true); if (charset) xhr.overrideMimeType('text/html; charset=' + charset); xhr.send(null); } /** * @param {String} str * @return {DOMDocument} */ function createHTMLDocument(str) { str = str.replace(/^[\s\S]*?<html(?:[ \t\r\n][^>]*)?>[ \t\n\r]*|[ \t\n\r]*<\/html[ \t\r\n]*>[\S\s]*$/ig,'').replace(/[\r\n]+/g,' '); var htmlFragment = content.document.implementation.createDocument(null,'html',null); var range = content.document.createRange(); range.setStartAfter(window.content.document.body); htmlFragment.documentElement.appendChild(htmlFragment.importNode(range.createContextualFragment(str),true)); return htmlFragment; } /** * @param {String} xpath XPath Expression * @param {DOMDocument} doc * @param {Boolean} isMulti * @return {Element} */ function getNodeFromXPath(xpath,doc,isMulti) { if (!xpath || !doc) return; var result; if (isMulti) { let nodesSnapshot = doc.evaluate(xpath,doc.documentElement,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null); if (nodesSnapshot.snapshotLength == 0) return; result = document.createElementNS(null,'div'); for (let i=0; i<nodesSnapshot.snapshotLength; result.appendChild(nodesSnapshot.snapshotItem(i++))); } else { let node = doc.evaluate(xpath,doc.documentElement,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null); if (!node.singleNodeValue) return; result = node.singleNodeValue; } return result; } /** * @return {Object} */ function buildSpellChecker() { var enable = liberator.globalVariables.lookupDictionary_enableSuggestion; enable = (enable === undefined) ? true : !!parseInt(enable, 10); if (!enable) return; var spellChecker = new SpellChecker(); var isBeginningWith = liberator.globalVariables.lookupDictionary_beginningWith; isBeginningWith = (isBeginningWith === undefined) ? false : !!parseInt(isBeginningWith, 10); spellChecker.setBeginningWith(isBeginningWith); return spellChecker; } })(); // vim: fdm=marker sw=4 ts=4 et: