*** empty log message ***
[m17n/m17n-lib-js.git] / mim.js
diff --git a/mim.js b/mim.js
index 5dac255..2461427 100644 (file)
--- a/mim.js
+++ b/mim.js
@@ -1,3 +1,28 @@
+// mim.js -- M17N Input Method driver
+// Copyright (C) 2010
+//   National Institute of Advanced Industrial Science and Technology (AIST)
+//   Registration Number H15PRO112
+
+// This file is part of the m17n database; a sub-part of the m17n
+// library.
+
+// The m17n library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public License
+// as published by the Free Software Foundation; either version 2.1 of
+// the License, or (at your option) any later version.
+
+// The m17n library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+
+// You should have received a copy of the GNU Lesser General Public
+// License along with the m17n library; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+// Please note that the code is not yet matured.
+
 var MIM = {
   // URL of the input method server.
   server: "http://www.m17n.org/common/mim-js",
@@ -6,7 +31,7 @@ var MIM = {
   // Boolean flag to tell if MIM is running in debug mode or not.
   debug: false,
   // List of main input methods.
-  imlist: {},
+  imlist: null,
   // List of extra input methods;
   imextra: {},
   // Global input method data
@@ -51,14 +76,17 @@ var MIM = {
   }
 };
   
+if (window.location.hostname == 'localhost')
+  MIM.server = 'http://localhost/mim';
+
 (function () {
   var keysyms = new Array ();
-  keysyms["bs"]        = "backspace";
-  keysyms["lf"]        = "linefeed";
-  keysyms["cr"]        = keysyms["enter"] = "return";
-  keysyms["esc"] = "escape";
+  keysyms["bs"]        = "BackSpace";
+  keysyms["lf"]        = "Linefeed";
+  keysyms["cr"]        = keysyms["enter"] = "Return";
+  keysyms["esc"] = "Escape";
   keysyms["spc"] = "space";
-  keysyms["del"] = "delete";
+  keysyms["del"] = "Delete";
 
   function decode_keysym (str) {
     if (str.length == 1)
@@ -438,7 +466,8 @@ MIM.Keymap = function ()
        keymap = sub;
        keymap.name = name;
       }
-    keymap.map_actions = rule.actions;
+    if (rule.actions)
+      keymap.map_actions = rule.actions;
     if (branch_actions)
       keymap.branch_actions = branch_actions;
   }
@@ -502,9 +531,9 @@ MIM.State = function (name)
              state.keymap.Add (map_list[node.attributes['mname'].nodeValue],
                                branch_actions);
            else if (node.nodeName == 'state-hook')
-             state.enter_actions = branch_actions;
+             state.keymap.map_actions = branch_actions;
            else if (node.nodeName == 'catch-all-branch')
-             state.fallback_actions = branch_actions;
+             state.keymap.branch_actions = branch_actions;
          }
       }
     return state;
@@ -1125,7 +1154,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
   var proto = {
     Load: function ()
     {
-      var node = Xex.Load (null, this.file);
+      var node = Xex.Load (MIM.server, this.file);
       if (! node)
        {
          this.load_status = MIM.LoadStatus.Error;
@@ -1258,7 +1287,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
     if (out.index > this.key_head)
       {
        this.key_head = out.index;
-       Xex.Log (' with submap', false, true);
+       Xex.Log (' with submap', -1);
        restore_state.call (this);
        this.keymap = sub;
        if (sub.map_actions)
@@ -1291,7 +1320,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
       }
     else
       {
-       Xex.Log (' without submap', false, true);
+       Xex.Log (' without submap', -1);
        this.keymap = sub;
        var current_state = this.state;
        var map = this.keymap;
@@ -1312,7 +1341,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
                Xex.Log ('unhandled');
                return false;
              }
-           if (this.keymap != current_state.keymap)
+           if (map != current_state.keymap)
              this.shift (current_state);
            else if (this.keymap.actions == null)
              this.shift (this.initial_state);
@@ -1321,7 +1350,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
     return true;
   }
 
-  proto = {
+  MIM.IC.prototype = {
     reset: function (clear_keys)
     {
       this.cursor_pos = 0;
@@ -1583,8 +1612,8 @@ MIM.im_domain.DefType (MIM.State.prototype);
          if (state != this.state)
            this.prev_state = this.state;
        }
-      if (state != this.state && state.enter_actions)
-       this.take_actions (state.enter_actions);
+      if (state != this.state && state.keymap.map_actions)
+       this.take_actions (state.keymap.map_actions);
       if (! this.state || this.state.title != state.title)
        this.changed |= MIM.ChangedStatus.StateTitle;
       this.state = state;
@@ -1657,79 +1686,89 @@ MIM.im_domain.DefType (MIM.State.prototype);
       return (! this.key_unhandled
              && this.produced.length == 0);
     }
-  }
+  };
 
-  MIM.IC.prototype = proto;
+  MIM.Load = function () {
+    if (MIM.imlist)
+      return;
+    MIM.imlist = {};
+    // Load the list of input methods.
+    var node = Xex.Load (MIM.server, "imlist.xml");
+    for (node = node.firstChild; node; node = node.nextSibling)
+      if (node.nodeName == 'input-method')
+       {
+         var lang = null, name = null, extra_id = null, file = null;
 
-  var node = Xex.Load (null, "imlist.xml");
-  for (node = node.firstChild; node; node = node.nextSibling)
-    if (node.nodeName == 'input-method')
+         for (var n = node.firstChild; n; n = n.nextSibling)
+           {
+             if (n.nodeName == 'language')
+               lang = n.firstChild.nodeValue;
+             else if (n.nodeName == 'name')
+               name = n.firstChild.nodeValue;
+             else if (n.nodeName == 'extra-id')
+               extra_id = n.firstChild.nodeValue;
+             else if (n.nodeName == 'filename')
+               file = n.firstChild.nodeValue;
+           }
+         if ((lang == 'ja' && name == 'anthy')
+             || (lang == 'en' && name == 'ispell'))
+           continue;
+         if (name && name != 'nil')
+           {
+             if (! MIM.imlist[lang])
+               MIM.imlist[lang] = {};
+             MIM.imlist[lang][name] = new MIM.IM (lang, name, extra_id, file);
+           }
+         else if (extra_id && extra_id != 'nil')
+           {
+             if (! MIM.imextra[lang])
+               MIM.imextra[lang] = {};
+             MIM.imextra[lang][extra_id] = new MIM.IM (lang, name, extra_id, file);
+           }
+       }
+    if (MIM.imextra.t && MIM.imextra.t.global)
+      MIM.im_global = MIM.imextra.t.global;
+    else
       {
-       var lang = null, name = null, extra_id = null, file = null;
-
-       for (var n = node.firstChild; n; n = n.nextSibling)
-         {
-           if (n.nodeName == 'language')
-             lang = n.firstChild.nodeValue;
-           else if (n.nodeName == 'name')
-             name = n.firstChild.nodeValue;
-           else if (n.nodeName == 'extra-id')
-             extra_id = n.firstChild.nodeValue;
-           else if (n.nodeName == 'filename')
-             file = n.firstChild.nodeValue;
-         }
-       if (name && name != 'nil')
-         {
-           if (! MIM.imlist[lang])
-             MIM.imlist[lang] = {};
-           MIM.imlist[lang][name] = new MIM.IM (lang, name, extra_id, file);
-         }
-       else if (extra_id && extra_id != 'nil')
-         {
-           if (! MIM.imextra[lang])
-             MIM.imextra[lang] = {};
-           MIM.imextra[lang][extra_id] = new MIM.IM (lang, name, extra_id, file);
-         }
+       MIM.im_global = new MIM.IM ('t', 'nil', 'global', null);
+       MIM.im_global.load_status = MIM.LoadStatus.Error;
       }
-  if (MIM.imextra.t && MIM.imextra.t.global)
-    MIM.im_global = MIM.imextra.t.global;
-  else
-    {
-      MIM.im_global = new MIM.IM ('t', 'nil', 'global', null);
-      MIM.im_global.load_status = MIM.LoadStatus.Error;
-    }
-  node = undefined;
+    node = undefined;
+    MIM.current = MIM.imlist['t']['latn-post'];
+  }
 }) ();
 
 (function () {
   var keys = new Array ();
-  keys[0x09] = 'tab';
-  keys[0x08] = 'backspace';
-  keys[0x0D] = 'return';
-  keys[0x1B] = 'escape';
+  keys[0x09] = 'Tab';
+  keys[0x08] = 'BackSpace';
+  keys[0x0D] = 'Return';
+  keys[0x1B] = 'Escape';
   keys[0x20] = 'space';
-  keys[0x21] = 'pageup';
-  keys[0x22] = 'pagedown';
-  keys[0x23] = 'end';
-  keys[0x24] = 'home';
-  keys[0x25] = 'left';
-  keys[0x26] = 'up';
-  keys[0x27] = 'right';
-  keys[0x28] = 'down';
-  keys[0x2D] = 'insert';
-  keys[0x2E] = 'delete';
+  keys[0x21] = 'Page_Up';
+  keys[0x22] = 'Page_Down';
+  keys[0x23] = 'End';
+  keys[0x24] = 'Home';
+  keys[0x25] = 'Left';
+  keys[0x26] = 'Up';
+  keys[0x27] = 'Right';
+  keys[0x28] = 'Down';
+  keys[0x2D] = 'Insert';
+  keys[0x2E] = 'Delete';
   for (var i = 1; i <= 12; i++)
     keys[111 + i] = "f" + i;
-  keys[0x90] = "numlock";
-  keys[0xF0] = "capslock";
+  keys[0x90] = "Num_Lock";
+  keys[0xF0] = "Caps_Lock";
 
   var keyids = {};
-  keyids['U+0008'] = 'Backspace';
+  keyids['U+0008'] = 'BackSpace';
   keyids['U+0009'] = 'Tab';
   keyids['U+0018'] = 'Cancel';
   keyids['U+001B'] = 'Escape';
-  keyids['U+0020'] = 'Space';
+  keyids['U+0020'] = 'space';
   keyids['U+007F'] = 'Delete';
+  keyids['PageUp'] = 'Page_Up';
+  keyids['PageDown'] = 'Page_Down';
 
   var modifiers = {}
   modifiers.Shift = 1;
@@ -1747,6 +1786,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
        if (modifiers[key])
          return false;
        var mod = '';
+       var shifted = event.shiftKey;
        if (event.ctrlKey) mod += 'C-';
        if (event.metaKey) mod += 'M-';
        if (event.altKey) mod += 'A-';
@@ -1757,11 +1797,17 @@ MIM.im_domain.DefType (MIM.State.prototype);
          {
            if (mod.length == 0)
              return false;
-           key = String.fromCharCode (parseInt (RegExp.$1, 16));
+           var c = parseInt (RegExp.$1, 16);
+           // Chrome sets, for instance, "U+0x00C1" when the key 'A'
+           // is typed with control or alt/meta key.
+           if (c >= 0x80)
+             c -= 0x80;
+           if (c >= 0x41 && c <= 0x5A && ! event.shiftKey)
+             c += 0x20;
+           key = String.fromCharCode (c);
+           shifted = false;
          }
-       //else
-       //key = key.toLowerCase ();
-       if (event.shiftKey) mod += 'S-';
+       if (shifted) mod += 'S-';
        return new MIM.Key (mod + key);
       }
     else
@@ -1836,8 +1882,6 @@ MIM.get_range = function (target, ic)
 };
 
 (function () {
-  var temp;
-
   var style_props = {
     width: 'width',
     height: 'height',
@@ -1845,6 +1889,8 @@ MIM.get_range = function (target, ic)
     paddingRight: 'padding-right',
     paddingTop: 'padding-top',
     paddintBottom: 'padding-bottom', 
+    marginRight: 'margin-right',
+    marginTop: 'margin-top',
     borderLeftStyle: 'border-left-style',
     borderRightStyle: 'border-right-style',
     borderTopStyle: 'border-top-style',
@@ -1863,13 +1909,16 @@ MIM.get_range = function (target, ic)
   {
     var from_style = getComputedStyle(from,'');
     for(var name in style_props)
-      to.style[name] = from_style.getPropertyValue (style_props[name]);
+      to.style[name] = from_style[style_props[name]];
     to.style.left = from.offsetLeft + 'px'; 
     to.style.top = from.offsetTop + 'px';
     to.style.width = from.offsetWidth;
     to.style.height = from.offsetHeight;
+    return from_style;
   }
 
+  var temp;                    // Temporary 'div' element
+
   MIM.get_preedit_pos = function (target, ic)
   {
     if (! temp)
@@ -1883,15 +1932,19 @@ MIM.get_range = function (target, ic)
       }
     if (temp.ic != ic)
       {
-       temp.ic = ic;
-       copy_style (target, temp);
-       ic.abs_top = 0;
-       ic.abs_left = 0;
+       var styles = copy_style (target, temp);
+       ic.abs_top = (parseInt (styles.marginTop)
+                     + parseInt (styles.borderTopWidth)
+                     + parseInt (styles.paddingTop));
+       ic.abs_left = (parseInt (styles.marginLeft)
+                      + parseInt (styles.borderLeftWidth)
+                      + parseInt (styles.paddingLeft));
        for (var elm = target.offsetParent; elm; elm = elm.offsetParent)
          {
            ic.abs_top += elm.offsetTop;
            ic.abs_left += elm.offsetLeft;
          }
+       temp.ic = ic;
       }
     temp.firstChild.innerText = target.value.substring (0, ic.range[0]);
     temp.lastChild.innerText
@@ -1918,7 +1971,7 @@ MIM.update_bar = function (target, ic)
          document.getElementsByTagName ('body')[0].appendChild (ic.bar);
        }
       ic.bar.style.display = 'block'
-      ic.bar.style.top = (ic.abs_y + 1) + 'px';
+      ic.bar.style.top = ic.abs_y + 'px';
       ic.bar.style.left = ic.abs_x0 + 'px';
       ic.bar.style.minWidth = ic.bar.style.maxWidth = (ic.abs_x1 - ic.abs_x0) + 'px';
     }
@@ -2062,6 +2115,7 @@ MIM.keydown = function (event)
   if (! (target.type == "text" || target.type == "textarea"))
     return;
 
+  MIM.Load ();
   var ic = target.mim_ic;
   if (! ic || ic.im != MIM.current)
     {
@@ -2240,6 +2294,9 @@ MIM.keypress = function (event)
        var nodes = target.getElementsByTagName ('ul');
        for (var i = 0; i < nodes.length; i++)
          nodes[i].style.visibility = 'hidden';
+       nodes = target.getElementsByTagName ('pre');
+       for (var i = 0; i < nodes.length; i++)
+         nodes[i].style.visibility = 'hidden';
        document.getElementsByTagName ('body')[0].removeChild (target);
       }
   }    
@@ -2267,21 +2324,37 @@ MIM.keypress = function (event)
     if (last_target && target.parentLi != last_target)
       {
        last_target.style.backgroundColor = 'white';
-       if (target.menu_level < last_target.menu_level)
+       while (target.menu_level < last_target.menu_level)
          {
            last_target = last_target.parentLi;
            last_target.style.backgroundColor = 'white';
          }
-       var uls = last_target.getElementsByTagName ('ul');
-       for (var i = 0; i < uls.length; i++)
-         uls[i].style.visibility = 'hidden';
+       var nodes = last_target.getElementsByTagName ('ul');
+       for (var i = 0; i < nodes.length; i++)
+         nodes[i].style.visibility = 'hidden';
+       nodes = last_target.getElementsByTagName ('pre');
+       for (var i = 0; i < nodes.length; i++)
+         nodes[i].style.visibility = 'hidden';
       }
     last_target = target;
     target.style.backgroundColor = 'yellow';
     if (target.menu_level < 3)
       {
-       target.lastChild.style.visibility = 'visible';
-       target.lastChild.style.left = target.clientWidth + 'px';
+       if (false)
+         {
+           target.lastChild.style.visibility = 'visible';
+           target.lastChild.style.left = target.clientWidth + 'px';
+         }
+       else
+         {
+       var left = target.clientWidth;
+       for (var n = target.firstElement ().nextElement (); n; n = n.nextElement ()) 
+         {
+           n.style.visibility = 'visible';
+           n.style.left = left + 'px';
+           left += n.clientWidth;
+         }
+         }
       }
     event.preventDefault ();   
   }
@@ -2309,6 +2382,7 @@ MIM.keypress = function (event)
   function create_ul (visibility)
   {
     var ul = document.createElement ('ul');
+    ul.name = 'elm';
     ul.style.position = 'absolute';
     ul.style.margin = '0px';
     ul.style.padding = '0px';
@@ -2336,6 +2410,21 @@ MIM.keypress = function (event)
     return li;
   }
 
+  function create_sep ()
+  {
+    var sep = document.createElement ('pre');
+    sep.name = 'elm';
+    sep.innerHTML = ' ';
+    sep.style.position = 'absolute';
+    sep.style.margin = '0px';
+    sep.style.padding = '2px';
+    sep.style.border = '2px solid black';
+    sep.style.top = '-1px';
+    sep.style.backgroundColor = 'black';
+    sep.style.visibility = 'hidden';
+    return sep;
+  }
+
   var menu;
 
   function create_menu (event)
@@ -2347,6 +2436,7 @@ MIM.keypress = function (event)
       return;
     if (! menu)
       {
+       MIM.Load ();
        categorize_im ();
        menu = create_ul ('visible');
        menu.style.fontFamily = 'sans-serif';
@@ -2359,6 +2449,7 @@ MIM.keypress = function (event)
          {
            var cat = lang_category[catname];
            var li = create_li (1, catname);
+           li.appendChild (create_sep ());
            var sub = create_ul ('hidden');
            for (var langname in cat)
              {
@@ -2367,6 +2458,7 @@ MIM.keypress = function (event)
                  continue;
                var sub_li = create_li (2, lang.name);
                sub_li.parentLi = li;
+               sub_li.appendChild (create_sep ());
                var subsub = create_ul ('hidden');
                for (var name in lang.list)
                  {
@@ -2394,8 +2486,5 @@ MIM.keypress = function (event)
     MIM.add_event_listener (window, 'keydown', MIM.keydown);
     MIM.add_event_listener (window, 'keypress', MIM.keypress);
     MIM.add_event_listener (window, 'mousedown', create_menu);
-    if (window.location == 'http://localhost/mim/index.html')
-      MIM.server = 'http://localhost/mim';
-    MIM.current = MIM.imlist['zh']['py-gb'];
   };
 }) ();