*** empty log message ***
[m17n/m17n-lib-js.git] / xex.js
diff --git a/xex.js b/xex.js
index 542e94d..4f567b0 100644 (file)
--- a/xex.js
+++ b/xex.js
@@ -2,23 +2,22 @@
 
 var Xex = {
   LogNode: null,
-  LogSuspended: '',
-  Log: function (arg, indent, suspend)
+  Log: function (arg, indent, cont)
   {
     if (! Xex.LogNode)
       return;
     if (! arg)
       Xex.LogNode.value = '';
-    else if (suspend)
-      Xex.LogSuspended += arg;
     else
       {
-       var str = Xex.LogSuspended;
-       Xex.LogSuspended = '';
+       var str = '';
        if (indent != undefined)
          for (var i = 0; i <= indent; i++)
            str += '  ';
-       Xex.LogNode.value = str + arg + "\n" + Xex.LogNode.value;
+       if (! cont)
+         Xex.LogNode.value += "\n";
+       Xex.LogNode.value += str + arg;
+       Xex.LogNode.scrollTop = Xex.LogNode.scrollHeight;
       }
   }
 };
@@ -1395,7 +1394,6 @@ var MIM = {
   MIM.Key = function (val)
   {
     this.key;
-    this.has_modifier = false;
     if (val instanceof Xex.Term)
       this.key = val.val;
     else if (typeof val == 'string' || val instanceof String)
@@ -1426,7 +1424,6 @@ var MIM = {
   MIM.KeySeq = function (seq)
   {
     this.val = new Array ();
-    this.has_modifier = false;
 
     if (seq)
       {
@@ -1610,10 +1607,8 @@ MIM.Selector.prototype = new Xex.Term ('selector');
   selectors["@>"] = selectors["@last"] = new MIM.Selector ('@>');
   selectors["@-"] = selectors["@previous"] = new MIM.Selector ('@-');
   selectors["@+"] = selectors["@next"] = new MIM.Selector ('@+');
-  selectors["@["] = selectors["@previous-candidate-change"]
-    = new MIM.Selector ('@[');
-  selectors["@]"] = selectors["@next-candidate-change"]
-    = new MIM.Selector ('@]');
+  selectors["@["] = selectors["@previous-group"] = new MIM.Selector ('@[');
+  selectors["@]"] = selectors["@next-group"] = new MIM.Selector ('@]');
 
   MIM.Selector.prototype.Parser = function (domain, node)
   {
@@ -1751,6 +1746,13 @@ MIM.Keymap = function ()
     var sub;
 
     if (index < keys.val.length && this.submaps
+       && ! keys.val[index])
+      {
+       Xex.Log ('invalid key at ' + index);
+       throw 'invalid key';
+      }
+
+    if (index < keys.val.length && this.submaps
        && (sub = this.submaps[keys.val[index].key]))
       {
        index++;
@@ -2021,6 +2023,38 @@ MIM.State = function (name)
       }
     return this.Current ();
   }
+
+  MIM.Candidates.prototype.CurrentGroup = function (selector)
+  {
+    var col, start, end
+    if (this.column > 0)
+      {
+       col = this.index % this.column;
+       start = this.index - col;
+       end = start + this.column;
+       if (end > this.total)
+         end = this.total;
+      }
+    else
+      {
+       start = this.blocks[this.row].Index;
+       col = this.index - start;
+       end = start + this.blocks[this.row].Count ();
+      }
+    var group = new Array ();
+    group.push (col);
+    var row = this.row;
+    var block = this.blocks[row++];
+    while (start < end)
+      {
+       var c = block.get (start - block.Index);
+       group.push (c);
+       start++;
+       if (start == block.Index + block.Count ())
+         block = this.blocks[row++];
+      }
+    return group;
+  }
 }) ();
 
 MIM.im_domain = new Xex.Domain ('input-method', null, null);
@@ -2486,24 +2520,26 @@ MIM.im_domain.DefType (MIM.State.prototype);
 
   function handle_key ()
   {
-    var out = this.keymap.Lookup (this.keys, this.key_head);
+    Xex.Log ('Key(' + this.key_head + ') "' + this.keys.val[this.key_head]
+            + '" in ' + this.state.name + ':' + this.keymap.name
+            + " key/state/commit-head/len:"
+            + this.key_head + '/' + this.state_key_head + '/' + this.commit_key_head + '/' + this.keys.val.length);
+    var out = this.state.keymap.Lookup (this.keys, this.state_key_head);
     var sub = out.map;
 
-    Xex.Log ('handling ' + this.keys.val[this.key_head]
-            + ' in ' + this.state.name + ':' + this.keymap.name, 0, true);
-    this.key_head = out.index;
-    if (sub != this.keymap)
+    if (out.index > this.key_head)
       {
-       Xex.Log (' with submap');
+       this.key_head = out.index;
+       Xex.Log (' with submap for ' + this.key_head + 'keys', false, true);
        restore_state.call (this);
        this.keymap = sub;
-       if (this.keymap.map_actions)
+       if (sub.map_actions)
          {
            Xex.Log ('taking map actions:');
-           if (! this.take_actions (this.keymap.map_actions))
+           if (! this.take_actions (sub.map_actions))
              return false;
          }
-       else if (this.keymap.submaps)
+       else if (sub.submaps)
          {
            Xex.Log ('no map actions');
            for (var i = this.state_key_head; i < this.key_head; i++)
@@ -2512,7 +2548,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
                this.ins (this.keys.val[i].key, null);
              }
          }
-       if (! this.keymap.submaps)
+       if (! sub.submaps)
          {
            Xex.Log ('terminal:');
            if (this.keymap.branch_actions != null)
@@ -2521,13 +2557,14 @@ MIM.im_domain.DefType (MIM.State.prototype);
                if (! this.take_actions (this.keymap.branch_actions))
                  return false;
              }
-           if (this.keymap != this.state.keymap)
+           if (sub != this.state.keymap)
              this.shift (this.state);
          }
       }
     else
       {
-       Xex.Log (' without submap');
+       Xex.Log (' without submap', false, true);
+       this.keymap = sub;
        var current_state = this.state;
        var map = this.keymap;
 
@@ -2679,6 +2716,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
     {
       this.preedit_replace (this.cursor_pos, this.cursor_pos, text, candidates);
       this.changed = MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos;
+      this.candidates = candidates;
     },
 
     rep: function (old_text, new_text, candidates)
@@ -2770,6 +2808,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
        if (this.key_head > this.keys.val.length)
          this.key_head = this.keys.val.length;
       }
+      Xex.Log ('0: key head = ' + this.key_head); 
     },
 
     pop: function ()
@@ -2806,7 +2845,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
            {
              this.commit ();
              this.keys.val.splice (0, this.key_head);
-             this.key_head = 0;
+             this.key_head = this.state_key_head = this.commit_key_head = 0;
              this.prev_state = null;
            }
        }
@@ -2821,7 +2860,6 @@ MIM.im_domain.DefType (MIM.State.prototype);
        this.changed |= MIM.ChangedStatus.StateTitle;
       this.state = state;
       this.keymap = state.keymap;
-      this.state_key_head = this.key_head;
       save_state.call (this);
     },
 
@@ -2829,6 +2867,7 @@ MIM.im_domain.DefType (MIM.State.prototype);
     {
       if (! this.active)
        {
+         Xex.Log ("active = false");
          this.key_unhandled = true;
          this.unhandled_key = key;
          return false;
@@ -2876,8 +2915,17 @@ MIM.im_domain.DefType (MIM.State.prototype);
       if (this.key_unhandled)
        {
          this.keys.val.length = 0;
+         //this.keys.val.splice (0, this.keys.val.length);
          this.key_head = this.state_key_head = this.commit_key_head = 0;
        }
+      MIM.show (this);
+      if (false && (this.changed & MIM.ChangedStatus.Candidate))
+       {
+         if (this.candidate_show)
+           MIM.show (this);
+         else
+           MIM.hide (this);
+       }
       return (! this.key_unhandled
              && this.produced.length == 0);
     }
@@ -3110,8 +3158,6 @@ MIM.set_caret = function (target, ic)
     }
 };
 
-MIM.ignore_focus = false;
-
 MIM.update = function (target, ic)
 {
   var text = target.value;
@@ -3124,69 +3170,126 @@ MIM.update = function (target, ic)
   MIM.set_caret (target, ic);
 };
 
+(function () {
+  var style_props = {
+    width: 'width',
+    height: 'height',
+    padingLeft: 'padding-left',
+    paddingRight: 'padding-right',
+    paddingTop: 'padding-top',
+    paddintBottom: 'padding-bottom', 
+    borderLeftStyle: 'border-left-style',
+    borderRightStyle: 'border-right-style',
+    borderTopStyle: 'border-top-style',
+    borderBottomStyle: 'border-bottom-style',
+    borderLeftWidth: 'border-left-width',
+    borderRightWidth: 'border-right-width',
+    borderTopWidth: 'border-top-width',
+    borderBottomWidth: 'border-bottom-width',
+    fontFamily: 'font-family',
+    fontSize: 'font-size',
+    lineHeight: 'line-height',
+    letterSpacing: 'letter-spacing',
+    wordSpacing: 'word-spacing' };
+
+  function copy_style (from, to)
+  {
+    var from_style = getComputedStyle(from,'');
+    for(var name in style_props)
+      to.style[name] = from_style.getPropertyValue (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;
+  }
+
+  MIM.show = function (ic)
+  {
+    Xex.Log ('show:' + ic.candidates);
+    if (! ic.candidates)
+      return;
+    var target = ic.target;
+    if (! ic.div_node)
+      {
+       ic.target_top = 0;
+       ic.target_left = 0;
+       for (var elm = ic.target.offsetParent; elm; elm = elm.offsetParent)
+         {
+           ic.target_top += elm.offsetTop;
+           ic.target_left += elm.offsetLeft;
+         }
+       ic.div_node = document.createElement ('div');
+       copy_style (target, ic.div_node);
+       ic.div_node.style.visibility="hidden";
+       ic.div_node.style.position = "absolute";
+       document.getElementsByTagName ('body')[0].appendChild (ic.div_node);
+       ic.div_node_first = document.createElement ('span');
+       ic.div_node_last = document.createElement('span');
+       ic.div_node_last.innerHTML = '.';
+       ic.div_node.appendChild (ic.div_node_first);
+       ic.div_node.appendChild (ic.div_node_last);
+       ic.can_node = document.createElement ('table');
+       ic.can_node.style.position = 'absolute';
+       ic.can_node.style.display = 'none';
+       ic.can_node.style.backgroundColor = "white";
+       ic.can_node.style.border = "1px solid black";
+       document.getElementsByTagName ('body')[0].appendChild (ic.can_node);
+      }
+
+    ic.can_node.innerHTML = '';
+    var tr = document.createElement ('tr');
+    ic.can_node.appendChild (tr);
+    var group = ic.candidates.CurrentGroup ();
+    for (var i = 1; i < group.length; i++)
+      {
+       var td = document.createElement ('td');
+       td.nowrap = true;
+       td.innerHTML = i + '.' + group[i];
+       if (i == group[0] + 1)
+         td.style.backgroundColor = 'lightblue';
+       ic.can_node.appendChild (td);
+      }
+    ic.div_node_first.innerHTML = target.value.substr (0, ic.range[0]);
+    var x = ic.target_left + ic.div_node.lastChild.offsetLeft;
+    var y = (ic.target_top + ic.div_node.lastChild.offsetTop
+            + ic.div_node.lastChild.offsetHeight - target.scrollTop + 10);
+    ic.can_node.style.left = x + 'px';
+    ic.can_node.style.top = y + 'px';
+    ic.can_node.style.display = 'block';
+  }
+}) ();
+
 MIM.focus_in = function (event)
 {
   var target = event.target;
   var ic = target.mim_ic;
-  if (ic)
-    {
-      if (target.mim_ignore_focus_in)
-       {
-         Xex.Log ('ignore focus_in in ' + target.tagName);
-         // Ignore this event which is caused by setSelectionRange ().
-         target.mim_ignore_focus_in = false;
-         event.preventDefault ();
-       }
-      else
-       {
-         Xex.Log ('focus_in in ' + target.tagName);
-         try {
-           ic.Filter (MIM.Key.FocusIn);
-           MIM.update (target, ic);
-           // Ignore further focus-in caused by setSelectionRange ().
-           // target.mim_ignore_focus_in = true;
-         }
-         catch (e) { Xex.Log ('Error:' + e); throw (e); }
-       }
-    }
-}
-
-MIM.cancel_ignore_focus = function ()
-{
-  if (MIM.focus_ignore_target)
+  if (ic.wait_update == true)
     {
-      MIM.focus_ignore_target.mim_ignore_focus_in = false;
-      MIM.focus_ignore_target.mim_ignore_focus_out = false;
+      Xex.Log ("Focus in " + target.tagName + ' IGNORED');
+      event.preventDefault ();
+      return false;
     }
+  Xex.Log ("Focus in " + target.tagName);
+  ic.Filter (MIM.Key.FocusIn);
+  MIM.update (target, ic);
 }
 
 MIM.focus_out = function (event)
 {
   var target = event.target;
   var ic = target.mim_ic;
-  if (ic)
+  function reset_update () { ic.wait_update = false; };
+  if (ic.wait_update == true)
     {
-      if (target.mim_ignore_focus_out)
-       {
-         Xex.Log ('ignore focus_out in ' + target.tagName);
-         // Ignore this event which is caused by setSelectionRange ().
-         target.mim_ignore_focus_out = false;
-         event.preventDefault ();
-       }
-      else
-       {
-         Xex.Log ('focus_out in ' + target.tagName);
-         if (! MIM.get_range (target, ic))
-           ic.reset ();
-         ic.Filter (MIM.Key.FocusOut);
-         // Ignore further focus-out caused by setSelectionRange ().
-         target.mim_ignore_focus_in = true;
-         target.mim_ignore_focus_out = true;
-         MIM.focus_ignore_target = target;
-         MIM.update (target, ic);
-         setTimeout (MIM.cancel_ignore_focus, 100);
-       }
+      Xex.Log ("Focus out " + target.tagName + ' IGNORED');
+      event.preventDefault ();
+      return false;
     }
+  Xex.Log ("Focus out " + target.tagName);
+  ic.Filter (MIM.Key.FocusOut);
+  ic.wait_update = true;
+  MIM.update (target, ic, true);
+  setTimeout (reset_update, 1000);
 };
 
 MIM.keydown = function (event)
@@ -3196,7 +3299,6 @@ MIM.keydown = function (event)
     return;
   if (! (target.type == "text" || target.type == "textarea"))
     return;
-  document.akey = event;
 
   var ic = target.mim_ic;
   if (! ic || ic.im != MIM.current)
@@ -3216,6 +3318,7 @@ MIM.keydown = function (event)
       if (! MIM.get_range (target, ic))
        ic.reset ();
     }
+  //MIM.show (target, ic);
   MIM.debug_print (event, ic);
   ic.key = MIM.decode_key_event (event);
   if (ic.key)
@@ -3259,7 +3362,7 @@ MIM.keypress = function (event)
     try {
       var result = ic.Filter (ic.key);
     } catch (e) {
-      Xex.Log ('Error;' + e);
+      Xex.Log ('Error:' + e);
       throw (e);
     }
     MIM.update (target, ic);
@@ -3271,6 +3374,7 @@ MIM.keypress = function (event)
   } finally {
     MIM.debug_print (event, ic);
   }
+
   return;
 };
 
@@ -3292,7 +3396,6 @@ MIM.keypress = function (event)
       sk: { name: 'Slovak' },
       sr: { name: 'Serbian' },
       sv: { name: 'Swedish' },
-      vi: { name: 'Vietnamese' },
       yi: { name: 'Yiddish' } },
     MiddleEast: {
       ar: { name: 'Arabic' },
@@ -3359,12 +3462,10 @@ MIM.keypress = function (event)
              list = lang_category[cat][lang].list;
              if (! list)
                list = lang_category[cat][lang].list = {};
-             break;
+             for (name in MIM.imlist[lang])
+               list[name] = MIM.imlist[lang][name];
            }
-       if (list)
-         for (name in MIM.imlist[lang])
-           list[name] = MIM.imlist[lang][name];
-       else
+       if (! list)
          for (name in MIM.imlist[lang])
            Xex.Log ('no category ' + lang + '-' + name);
       }
@@ -3462,7 +3563,9 @@ MIM.keypress = function (event)
     li.style.top = '0px';
     li.style.listStyle = 'none';
     li.menu_level = level;
-    li.appendChild (document.createTextNode (text));
+    var nobr = document.createElement ('nobr');
+    nobr.innerHTML = text;
+    li.appendChild (nobr);
     return li;
   }
 
@@ -3512,7 +3615,6 @@ MIM.keypress = function (event)
            li.appendChild (sub);
            menu.appendChild (li);
          }
-       document.mimmenu = menu;
        lang_category = null;
       }
     menu.style.left = (event.clientX - 10) + "px";