aboutsummaryrefslogtreecommitdiffstats
path: root/command_menu.js
blob: 4cabb55d978c6f66ad944dfb8b6b836f0b571695 (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
120
121
122
123
1
// Vimperator plugin: "Update mixi echo"
// Last Change: 21-Oct-2008. Jan 2008
// License: Creative Commons
// Maintainer: mattn <mattn.jp@gmail.com> - http://mattn.kaoriya.net/

(function(){
	var ucnv = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
		.createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
	ucnv.charset = "EUC-JP";
	function sprintf(format){
		var i = 1, re = /%s/, result = "" + format;
		while (re.test(result) && // ==VimperatorPlugin==
// @name           Command-MainMenu
// @description-ja メインメニューとツールバーをコマンドで実行できる
// @license        Creative Commons 2.1 (Attribution + Share Alike)
// @version        1.5
// @author         anekos (anekos@snca.net)
// ==/VimperatorPlugin==
//
// Usage:
//    :menu ツール-アドオン
//    :toolbar 戻る
//    のようにメニュー/ツールバーの"-"区切りのパスを渡すことで、メニュー/ツールバーをクリックします。
//    Migemo必須。
//
// TODO:
//    ・一度開かないと生成されないようなメニュー(ラベル)に対処できる魔法があったらいいな!
//     (ScrapBook / ブックマークメニュー)
//    ・コンテクストメニューがうまくいかない。
//
// License:
//    http://creativecommons.org/licenses/by-sa/2.1/jp/
//    http://creativecommons.org/licenses/by-sa/2.1/jp/deed

(function () {

  const migemo = Components
                  .classes['@piro.sakura.ne.jp/xmigemo/factory;1']
                  .getService(Components.interfaces.pIXMigemoFactory)
                  .getService("ja");

  function equal (x) function (y) x == y;

  function cloneArray (src) src.map(function (id) id);

  function matchPath (elem, path, getName) {
    var i = 0;
    for (let l = path.length; i < l; i++) {
      if (!path[i](getName(elem)))
        break;
    }
    if (i) {
      let res = [];
      for (let j = i, l = path.length; j < l; j++)
        res.push(path[j]);
      return res;
    }
  }

  function getElementsByPath (elem, path, getName, isTarget, isEnabled) {
    try {
      function get (point, elem, path) {
        var m = path[0](getName(elem, true));

        if (isTarget(elem)) {
          if (!isEnabled(elem))
            return [];
          if (m) {
            if (path.length == 1)
              return [[point + m, elem]];
            (path = cloneArray(path)).shift();
          } else {
            return [];
          }
        }

        //elem.containerOpen = true;
        var res, cs = elem.childNodes, result = [];
        if (cs && cs.length) {
          for (let i = 0, l = cs.length; i < l; i++) {
            if (res = get(m + point, cs[i], path))
              res.map(function (it) it && result.push(it));
          }
        }
        //elem.containerOpen = false;

        return result;
      }

      return get(0, elem, path).sort().map(function (it) it[1]);
    } catch (e) { liberator.log(e); }
  }

  function getPathMatchers (args)
    args.split('-').map(function (it)
      function (l)
        !l                                                        ? 0 :
        l == it                                                   ? 1 :
        l.toLowerCase().indexOf(it.toLowerCase()) >= 0            ? 2 :
        new RegExp(migemo.getRegExp(it.replace(/^\s+|\s+$/, '')),
                   'i').test(l)                                   ? 3 :
                                                                    0);

  function getPathString (elem, isRoot, getName, isTarget) {
    var res = [];
    while (!isRoot(elem)) {
      isTarget(elem) && res.unshift(getName(elem));
      elem = elem.parentNode;
    }
    return res.join('-');

  }



  /*********************************************************************************
   * メインメニュー
   *********************************************************************************/

  const mainMenubar = document.getElementById('main-menubar');
  const toolbox = document.getElementById('navigator-toolbox');
  const contextmenu = document.getElementById('contentAreaContextMenu');

  function fixName (name)
    name ? name.replace(/^\s+|\s+$/, '').replace(/[-\s]+/g, '_') : '';

  function getElementName (elem, multi)
    multi ? [elem.label, elem.tooltipText].map(function (it) fixName(it) || '')
                                          .join('-')
          : fixName(elem.label || elem.tooltipText || '');

  function isNotHidden (elem)
    !elem.hidden ? true : false;

  function isClickable (elem)
    /^(?:menu(?:item)?|toolbarbutton)$/.test(elem.nodeName.toLowerCase());

  function addCommand (cmds, name, root, action) {
    function _find (args, single) {
      var result = getElementsByPath(root,
                                     getPathMatchers(args),
                                     getElementName,
                                     isClickable,
                                     isNotHidden);
      return single ? result[0] : result;
    }

    if (!action) {
      action = function (elem) {
        if (!elem.click)
          return;
        elem.click();
        return true;
      };
    }

    commands.addUserCommand(
      cmds,
      name,
      function (args, _, num, extra) {
        // for HEAD (2)
        if (args.string != undefined)
          args = args.string;
        var res = _find(args.replace(/-\s*$/,''), true);
        if (!(res && action(res)))
          liberator.echoerr('menu not found');
      },
      {
        completer: function (args) {
          const gps = function (it) getPathString(it, equal(root), getElementName, isClickable);
          const fp = function (it) [gps(it), it.tooltipText || ''];
          return [0, _find(args).map(fp)];
        }
      }
    );
  }

  addCommand(['me[nu]'], 'Command MainMenu', mainMenubar);
  addCommand(['toolbar', 'tb'], 'Command Toolbar', toolbox);
  addCommand(['conme', 'contextmenu'],
             'Context Menu',
             contextmenu,
             function (elem) {
               //contextmenu.openPopup(null, null, 0, 0, true);
               //contextmenu.hidePopup();
               elem.click();
               //elem.doCommand();
               return true;
             }
  );

})();
/span>