*** empty log message ***
[m17n/m17n-lib-js.git] / xex.js
diff --git a/xex.js b/xex.js
index ed3996e..6e4a6f5 100644 (file)
--- a/xex.js
+++ b/xex.js
@@ -1305,6 +1305,8 @@ var MIM = {
   keysyms["del"] = "delete";
 
   function decode_keysym (str) {
+    if (str.length == 1)
+      return str;
     var parts = str.split ("-");
     var len = parts.length, i;
     var has_modifier = len > 1;
@@ -2823,22 +2825,61 @@ MIM.im_domain.DefType (MIM.State.prototype);
   keys[0x90] = "numlock";
   keys[0xF0] = "capslock";
 
+  var keyids = {};
+  keyids['U+0008'] = 'backspace';
+  keyids['U+0009'] = 'tab';
+  keyids['U+0018'] = 'cancel';
+  keyids['U+001B'] = 'escape';
+  keyids['U+0020'] = 'space';
+  keyids['U+007F'] = 'delete';
+
+  var modifiers = {}
+  modifiers.Shift = 1;
+  modifiers.Control = 1;
+  modifiers.Alt = 1;
+  modifiers.AltGraph = 1;
+  modifiers.Meta = 1
+
   MIM.decode_key_event = function (event)
   {
-    var key = ((event.type == 'keydown' || event.keyCode) ? event.keyCode
-              : event.charCode ? event.charCode
-              : false);
-    if (! key)
-      return false;
-    if (event.type == 'keydown')
+    var key = event.keyIdentifier;
+
+    if (key)                   // keydown event of Chrome
       {
-       key = keys[key];
-       if (! key)
+       if (modifiers[key])
          return false;
+       var keysym = keyids[key];
+       if (keysym)
+         key = keysym;
+       else if (key.match(/^U\+([0-9A-Z]+)$/))
+         key = String.fromCharCode (parseInt (RegExp.$1, 16));
+       else
+         key = key.toLowerCase ();
        if (event.shiftKey) key = "S-" + key ;
+       if (event.altKey) key = "A-" + key ;
+       if (event.metaKey) key = "M-" + key ;
+       if (event.ctrlKey) key = "C-" + key ;
+       if (key.length == 1)
+         return false;
+       return new MIM.Key (key);
       }
     else
-      key = String.fromCharCode (key);
+      {
+       key = ((event.type == 'keydown' || event.keyCode) ? event.keyCode
+              : event.charCode ? event.charCode
+              : false);
+       if (! key)
+         return false;
+       if (event.type == 'keydown')
+         {
+           key = keys[key];
+           if (! key)
+             return false;
+           if (event.shiftKey) key = "S-" + key ;
+         }
+       else
+         key = String.fromCharCode (key);
+      }
     if (event.altKey) key = "A-" + key ;
     if (event.ctrlKey) key = "C-" + key ;
     return new MIM.Key (key);
@@ -2869,10 +2910,10 @@ MIM.debug_print = function (event, ic)
   if (! MIM.debug_nodes)
     {
       MIM.debug_nodes = new Array ();
-      MIM.debug_nodes['keydown'] = document.getElementById ('keydown');
-      MIM.debug_nodes['keypress'] = document.getElementById ('keypress');
       MIM.debug_nodes['status0'] = document.getElementById ('status0');
       MIM.debug_nodes['status1'] = document.getElementById ('status1');
+      MIM.debug_nodes['keydown'] = document.getElementById ('keydown');
+      MIM.debug_nodes['keypress'] = document.getElementById ('keypress');
       MIM.debug_nodes['keymap0'] = document.getElementById ('keymap0');
       MIM.debug_nodes['keymap1'] = document.getElementById ('keymap1');
       MIM.debug_nodes['preedit0'] = document.getElementById ('preedit0');
@@ -2880,11 +2921,11 @@ MIM.debug_print = function (event, ic)
     }
   var target = event.target;
   var code = event.keyCode;
-  var ch = event.type == 'keydown' ? 0 : event.charCode;
+  var ch = event.type == 'keypress' ? event.charCode : 0;
   var key = MIM.decode_key_event (event);
   var index;
 
-  MIM.debug_nodes[event.type].innerHTML = "" + code + "/" + ch + " : " + key;
+  MIM.debug_nodes[event.type].innerHTML = "" + code + "/" + ch + ":" + key + '/' + event.keyIdentifier;
   index = (event.type == 'keydown' ? '0' : '1');
   if (ic)
     MIM.debug_nodes['status' + index].innerHTML = ic.im.load_status;
@@ -2995,6 +3036,14 @@ MIM.keydown = function (event)
     }
   MIM.debug_print (event, ic);
   ic.key = MIM.decode_key_event (event);
+  if (ic.key)
+    {
+      Xex.Log ("filtering " + ic.key);
+      var result = ic.Filter (ic.key);
+      MIM.update (target, ic);
+      if (! ic.key_unhandled)
+       event.preventDefault ();
+    }
 };
 
 MIM.keypress = function (event)
@@ -3024,6 +3073,9 @@ MIM.keypress = function (event)
     MIM.update (target, ic);
     if (! ic.key_unhandled)
       event.preventDefault ();
+  } catch (e) {
+    Xex.Log ("error:" + e);
+    event.preventDefault ();
   } finally {
     MIM.debug_print (event, ic);
   }
@@ -3036,10 +3088,13 @@ MIM.keypress = function (event)
       cs: { name: 'Czech' },
       da: { name: 'Danish' },
       el: { name: 'Greek' },
+      en: { name: 'English' },
       eo: { name: 'Esperanto' },
       fr: { name: 'French' },
+      grc: { name: 'ClassicGreek' },
       hr: { name: 'Croatian' },
       hy: { name: 'Armenian' },
+      ka: { name: 'Georgian' },
       kk: { name: 'Kazakh' },
       ru: { name: 'Russian' },
       sk: { name: 'Slovak' },
@@ -3076,6 +3131,7 @@ MIM.keypress = function (event)
       te: { name: 'Telugu' },
       ur: { name: 'Urdu' } },
     SouthEastAsia: {
+      cmc: { name: 'Cham' },
       km: { name: 'Khmer'},
       lo: { name: 'Lao' },
       my: { name: 'Burmese' },
@@ -3095,7 +3151,8 @@ MIM.keypress = function (event)
       eo: { name: 'Esperanto' },
       iu: { name: 'Inuktitut' },
       nsk: { name: 'Naskapi' },
-      oj: { name: 'Ojibwe' } }
+      oj: { name: 'Ojibwe' },
+      t: { name: 'Generic' } }
   };
 
   function categorize_im ()
@@ -3115,82 +3172,106 @@ MIM.keypress = function (event)
        if (list)
          for (name in MIM.imlist[lang])
            list[name] = MIM.imlist[lang][name];
+       else
+         for (name in MIM.imlist[lang])
+           Xex.Log ('no category ' + lang + '-' + name);
       }
   }
 
   var destroy_timer;
+  var last_target;
 
   function destroy ()
   {
     clearTimeout (destroy_timer);
+    destroy_timer = null;
     var target = document.getElementById ('mim-menu');
     if (target)
-      document.getElementsByTagName ('body')[0].removeChild (target);
+      {
+       for (; last_target && last_target.menu_level;
+            last_target = last_target.parentLi)
+         last_target.style.backgroundColor = 'white';
+       var nodes = target.getElementsByTagName ('ul');
+       for (var i = 0; i < nodes.length; i++)
+         nodes[i].style.visibility = 'hidden';
+       document.getElementsByTagName ('body')[0].removeChild (target);
+      }
   }    
 
-  function destroy_menu () { destroy_timer = setTimeout (destroy, 1000); }
-
-  var last_target;
+  function destroy_menu () {
+    if (! destroy_timer)
+      destroy_timer = setTimeout (destroy, 1000);
+  }
 
   function show_submenu (event)
   {
     if (destroy_timer)
-      clearTimeout (destroy_timer);
+      {
+       clearTimeout (destroy_timer);
+       destroy_timer = null;
+      }
     var target = event.target;
-    if (target.menu_level)
+    if (! target.menu_level)
+      return;
+    if (last_target && target.parentLi != last_target)
       {
-       Xex.Log ("menu show level " + target.menu_level
-                + ': ' + target.tagName);
-       if (! last_target || last_target.parentLi == target)
+       last_target.style.backgroundColor = 'white';
+       if (target.menu_level < last_target.menu_level)
          {
-           Xex.Log ('Sub opened');
-         }
-       else
-         {
-           Xex.Log ('Sibling opened');
+           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';
          }
-       last_target = target;
-       target.style.backgroundColor = 'yellow';
+       var uls = last_target.getElementsByTagName ('ul');
+       for (var i = 0; i < uls.length; i++)
+         uls[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';
-       event.preventDefault ();        
       }
+    event.preventDefault ();   
   }
 
-  function hide_submenu (event)
+  function select_im (event)
   {
     var target = event.target;
-    target.style.backgroundColor = 'white';
-    for (var ul = target.firstChild; ul; ul = ul.nextSibling)
-      if (ul.tagName == 'UL')
-       ul.style.visibility = 'hidden';
+    if (target.im)
+      {
+       MIM.current = target.im;
+       destroy ();
+      }
+    event.preventDefault ();
   }
 
-  function select_im (event)
+  function create_ul (visibility)
   {
-    var target = event.target.parentNode;
-    while (target.tagName != "mim-menu")
-      target = target.parentNode;
-    var idx = 0;
-    var im = false;
-    for (var lang in MIM.imlist)
-      for (var name in MIM.imlist[lang])
-       if (idx++ == target.selectedIndex)
-         {
-           im = MIM.imlist[lang][name];
-           break;
-         }
-    document.getElementsByTagName ('body')[0].removeChild (target);
-    target.target.focus ();
-    if (im && im != MIM.current)
-      {
-       MIM.current = im;
-       Xex.Log ('select IM: ' + im.name);
-      }
+    var ul = document.createElement ('ul');
+    ul.style.position = 'absolute';
+    ul.style.margin = '0px';
+    ul.style.padding = '0px';
+    ul.style.border = '1px solid gray';
+    ul.style.borderBottom = 'none';
+    ul.style.top = '-1px';
+    ul.style.backgroundColor = 'white';
+    ul.style.visibility = visibility;
+    return ul;
+  }
+
+  function create_li (level, text)
+  {
+    var li = document.createElement ('li');
+    li.style.position = 'relative';
+    li.style.margin = '0px';
+    li.style.padding = '1px';
+    li.style.borderBottom = '1px solid gray';
+    li.style.top = '0px';
+    li.style.listStyle = 'none';
+    li.menu_level = level;
+    li.appendChild (document.createTextNode (text));
+    return li;
   }
 
   var menu;
@@ -3205,101 +3286,45 @@ MIM.keypress = function (event)
     if (! menu)
       {
        categorize_im ();
-       menu = document.createElement ('ul');
+       menu = create_ul ('visible');
        menu.style.fontFamily = 'sans-serif';
        menu.style.fontWeight = 'bold';
-       menu.style.margin = '0px';
-       menu.style.padding = '0px';
-       menu.style.border = '1px solid gray';
-       menu.style.borderBottom = 'none';
-       menu.style.backgroundColor = 'white';
-       menu.style.position='absolute';
-       menu.style.left = (event.clientX - 10) + "px";
-       menu.style.top = (event.clientY - 10) + "px";
-       //menu.style.width = '100px';
        menu.id = 'mim-menu';
        menu.onclick = select_im;
+       menu.onmouseover = show_submenu;
        menu.onmouseout = destroy_menu;
-       menu.target = target;
-       var idx = 0;
        for (var catname in lang_category)
          {
            var cat = lang_category[catname];
-           var li = document.createElement ('li');
-           li.menu_level = 1;
-           li.parentLi = menu;
-           li.style.position = 'relative';
-           li.style.listStyle= 'none';
-           li.style.margin = '0';
-           li.style.padding = '1px';
-           li.style.borderBottom = '1px solid gray';
-           li.onmouseover = show_submenu;
-           //li.onmouseout = hide_submenu;
-           li.appendChild (document.createTextNode (catname));
-           var sub = document.createElement ('ul');
-           sub.style.position = 'absolute';
-           sub.style.margin = '0px';
-           sub.style.padding = '0px';
-           sub.style.border = '1px solid gray';
-           sub.style.borderBottom = 'none';
-           sub.style.top = '-1px';
-           //sub.style.width = '100px';
-           sub.style.listStyle = 'disc inside';
-           sub.style.visibility = 'hidden';
-           sub.style.backgroundColor = 'white';
-           li.appendChild (sub);
+           var li = create_li (1, catname);
+           var sub = create_ul ('hidden');
            for (var langname in cat)
              {
                var lang = cat[langname];
                if (! lang.list)
                  continue;
-               var sub_li = document.createElement ('li');
-               sub_li.menu_level = 2;
+               var sub_li = create_li (2, lang.name);
                sub_li.parentLi = li;
-               sub_li.style.position = 'relative';
-               sub_li.style.padding = '1px';
-               sub_li.style.borderBottom = '1px solid gray';
-               sub_li.style.listStyle= 'none';
-               sub_li.style.backgroundColor = 'white';
-               //sub_li.onmouseover = show_submenu;
-               //sub_li.onmouseout = hide_submenu;
-               sub_li.appendChild (document.createTextNode (lang.name));
-               sub.appendChild (sub_li);
-               var subsub = document.createElement ('ul');
-               subsub.style.position = 'absolute';
-               subsub.style.margin = '0px';
-               subsub.style.padding = '0px';
-               subsub.style.border = '1px solid gray';
-               subsub.style.borderBottom = 'none';
-               subsub.style.top = '-1px';
-               //subsub.style.width = '100px';
-               //subsub.style.listStyle = 'disc inside';
-               subsub.style.visibility = 'hidden';
-               subsub.style.backgroundColor = 'white';
+               var subsub = create_ul ('hidden');
                for (var name in lang.list)
                  {
                    var im = lang.list[name];
-                   var subsub_li = document.createElement ('li');
-                   subsub_li.menu_level = 3;
+                   var subsub_li = create_li (3, im.name);
                    subsub_li.parentLi = sub_li;
-                   subsub_li.style.position = 'relative';
-                   subsub_li.style.padding = '1px';
-                   subsub_li.style.borderBottom = '1px solid gray';
-                   subsub_li.style.listStyle= 'none';
-                   subsub_li.style.backgroundColor = 'white';
-                   //subsub_li.onmouseover = show_submenu;
-                   //subsub_li.onmouseout = hide_submenu;
-                   subsub_li.appendChild (document.createTextNode (im.name));
                    subsub_li.im = im;
                    subsub.appendChild (subsub_li);
                  }
                sub_li.appendChild (subsub);
-               idx++;
+               sub.appendChild (sub_li);
              }
+           li.appendChild (sub);
            menu.appendChild (li);
          }
        document.mimmenu = menu;
+       lang_category = null;
       }
+    menu.style.left = (event.clientX - 10) + "px";
+    menu.style.top = (event.clientY - 10) + "px";
     document.getElementsByTagName ('body')[0].appendChild (menu);
   };