+// 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.
+
+// Known bugs:
+// * MIM.get_preedit_pos () returns incorrect position sometimes.
+
var MIM = {
// URL of the input method server.
server: "http://www.m17n.org/common/mim-js",
}
};
+//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)
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;
}
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;
if (node.nodeName != 'tags')
return null;
- var lang = null, name = null, extra = null;
+ var lang = null, name = null, extra = null, im;
for (node = node.firstElement (); node; node = node.nextElement ())
{
if (node.nodeName == 'language')
if (! (im = MIM.imextra[lang][extra]))
return null;
}
- if (im.load_status != MIM.LoadStatus.Loaded
- && (im.load_status != MIM.LoadStatus.NotLoaded || ! im.Load ()))
- return null;
+ if (im.load_status != MIM.LoadStatus.Loaded)
+ {
+ if (im.load_status == MIM.LoadStatus.NotLoaded)
+ im.Load ();
+ if (im.load_status != MIM.LoadStatus.Loading)
+ return null;
+ }
return im;
}
parsers['description'] = function (node)
{
this.description = node.firstChild.nodeValue;
+ return true;
}
parsers['variable-list'] = function (node)
{
}
vname = Xex.Term.Parse (this.domain, node)
}
+ return true;
}
parsers['command-list'] = function (node)
{
+ return true;
}
parsers['macro-list'] = function (node)
{
{
var im = include (n);
if (! im)
- alert ('inclusion fail');
- else
- for (var macro in im.domain.functions)
- {
- var func = im.domain.functions[macro];
- if (func instanceof Xex.Macro)
- im.domain.CopyFunc (this.domain, macro);
- }
+ {
+ alert ('inclusion fail');
+ throw new Xex.ErrTerm (MIM.Error.ParseError, "inclusion fail: ");
+ }
+ if (im.load_status == MIM.LoadStatus.Loading)
+ return false; // force reloading
+ for (var macro in im.domain.functions)
+ {
+ var func = im.domain.functions[macro];
+ if (func instanceof Xex.Macro)
+ im.domain.CopyFunc (this.domain, macro);
+ }
n = n.previousSibling;
node.removeChild (n.nextSibling);
}
Xex.Term.Parse (this.domain, node.firstElement (), null);
+ return true;
}
parsers['title'] = function (node)
{
this.title = node.firstChild.nodeValue;
+ return true;
}
parsers['map-list'] = function (node)
{
if (! im)
{
alert ('inclusion fail');
- continue;
+ throw new Xex.ErrTerm (MIM.Error.ParseError, "inclusion fail: ");
}
+ else if (im.load_status == MIM.LoadStatus.Loading)
+ return false;
for (var mname in im.map_list)
this.map_list[mname] = im.map_list[mname];
}
this.map_list[map.name] = map;
}
}
+ return true;
}
parsers['state-list'] = function (node)
{
{
var im = include (node);
if (! im)
- alert ('inclusion fail');
+ {
+ alert ('inclusion fail');
+ throw new Xex.ErrTerm (MIM.Error.ParseError, "inclusion fail: ");
+ }
+ else if (im.load_status == MIM.LoadStatus.Loading)
+ return false;
for (var sname in im.state_list)
{
state = im.state_list[sname];
}
}
delete this.domain.map_list;
+ return true;
}
MIM.IM = function (lang, name, extra_id, file)
+ (this.name != 'nil'
? this.name : this.extra_id),
MIM.im_domain, null);
+ };
+
+ function load_im (node, im)
+ {
+ //alert ('Loading IM (' + im + ':' + im.lang + '-' + im.name + ')');
+ im.map_list = {};
+ im.initial_state = null;
+ im.state_list = {};
+ for (node = node.firstElement (); node; node = node.nextElement ())
+ {
+ var name = node.nodeName;
+ var parser = parsers[name];
+ if (parser && ! parser.call (im, node))
+ {
+ im.Load ();
+ return;
+ }
+ }
+ //alert ('initial state = ' + im.initial_state);
+ im.load_status = MIM.LoadStatus.Loaded;
}
- var proto = {
+ MIM.IM.prototype = {
Load: function ()
{
- var node = Xex.Load (null, this.file);
- if (! node)
- {
- this.load_status = MIM.LoadStatus.Error;
- return false;
- }
- this.map_list = {};
- this.initial_state = null;
- this.state_list = {};
- for (node = node.firstElement (); node; node = node.nextElement ())
- {
- var name = node.nodeName;
- var parser = parsers[name];
- if (parser)
- parser.call (this, node);
- }
- this.load_status = MIM.LoadStatus.Loaded;
- return true;
+ this.load_status = MIM.LoadStatus.Loading;
+ Xex.Load (MIM.server, this.file, load_im, this);
}
- }
-
- MIM.IM.prototype = proto;
+ };
MIM.IC = function (im, target)
{
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)
}
else
{
- Xex.Log (' without submap', false, true);
+ Xex.Log (' without submap', -1);
this.keymap = sub;
var current_state = this.state;
var map = this.keymap;
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);
return true;
}
- proto = {
+ MIM.IC.prototype = {
reset: function (clear_keys)
{
this.cursor_pos = 0;
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;
return (! this.key_unhandled
&& this.produced.length == 0);
}
- }
+ };
- MIM.IC.prototype = proto;
+ MIM.create_list = function (node)
+ {
+ // Load the list of input methods.
+ 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)
{
- 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 = MIM.imextra.t.global;
+ MIM.im_global.Load ();
}
- 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;
+ else
+ {
+ MIM.im_global = new MIM.IM ('t', 'nil', 'global', null);
+ MIM.im_global.load_status = MIM.LoadStatus.Error;
+ }
+ MIM.current = MIM.imlist['t']['latn-post'];
+ MIM.current.Load ();
+ }
}) ();
(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;
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-';
{
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
};
(function () {
- var temp;
-
var style_props = {
width: 'width',
height: 'height',
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',
{
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)
}
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
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';
}
if (! ic || ic.im != MIM.current)
{
target.mim_ic = null;
- Xex.Log ('creating IC');
+ Xex.Log ('creating IC for ' + MIM.current.lang + '-' + MIM.current.name);
ic = new MIM.IC (MIM.current, target);
if (ic.im.load_status != MIM.LoadStatus.Loaded)
return true;
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);
}
}
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 ();
}
if (target.im)
{
MIM.current = target.im;
+ MIM.current.Load ();
destroy ();
}
event.preventDefault ();
function create_ul (visibility)
{
var ul = document.createElement ('ul');
+ ul.name = 'elm';
ul.style.position = 'absolute';
ul.style.margin = '0px';
ul.style.padding = '0px';
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)
{
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)
{
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)
{
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'];
+ Xex.Load (MIM.server, "imlist.xml", MIM.create_list);
};
}) ();