1 // -* coding: utf-8; -*
6 UnknownError: "unknown-error",
7 WrongArgument: "wrong-argument",
9 InvalidInteger: "invalid-integer",
10 TermTypeInvalid: "term-type-invalid",
11 FunctionConflict: "function-conflict",
12 VariableTypeConflict: "variable-type-conflict",
13 VariableRangeConflict: "variable-range-conflict",
14 VariableWrongRange: "variable-wrong-range",
15 VariableWrongValue: "variable-wrong-value",
17 UnknownFunction: "unknown-function",
18 MacroExpansionError: "macro-expansion-error",
19 NoVariableName: "no-variable-anme",
22 ArithmeticError: "arithmetic-error",
23 WrongType: "wrong-type",
24 IndexOutOfRange: "index-out-of-range",
25 ValueOutOfRange: "value-out-of-range",
26 NoLoopToBreak: "no-loop-to-break",
27 UncaughtThrow: "uncaught-throw"
30 Xex.Variable = function (domain, name, val)
37 Xex.Variable.prototype.clone = function () {
38 return new Xex.Variable (this.domain, this.name, this.value);
41 Xex.Variable.prototype.Equals = function (obj) {
42 return ((obj instanceof Xex.Variable)
43 && obj.name == this.name);
46 Xex.Variable.prototype.SetValue = function (term) {
51 Xex.Function = function (name, with_var, min_args, max_args) {
53 this.with_var = with_var;
54 this.min_args = min_args;
55 this.max_args = max_args;
58 Xex.Subrountine = function (builtin, name, with_var, min_args, max_args) {
60 this.with_var = with_var;
61 this.min_args = min_args;
62 this.max_args = max_args;
63 this.builtin = builtin;
66 Xex.Subrountine.prototype.Call = function (domain, vari, args)
68 newargs = new Array ();
69 for (var i = 0; i < args.length; i++)
71 newargs[i] = args[i].Eval (domain);
75 return this.builtin (domain, vari, newargs)
78 Xex.SpecialForm = function (builtin, name, with_var, min_args, max_args)
81 this.with_var = with_var;
82 this.min_args = min_args;
83 this.max_args = max_args;
84 this.builtin = builtin;
87 Xex.SpecialForm.prototype.Call = function (domain, vari, args)
89 return this.builtin (domain, vari, args)
92 Xex.Lambda = function (name, min_args, max_args, args, body)
95 this.with_var = with_var;
96 this.min_args = min_args;
97 this.max_args = max_args;
102 Xex.Lambda.prototype.Call = function (domain, vari, args)
104 var current = domain.bindings;
105 var result = Xex.Zero;
106 var limit = max_args >= 0 ? args.length : args.length - 1;
110 for (i = 0; i < limit; i++)
112 result = args[i].Eval (domain);
113 if (domain.Thrown ())
115 domain.Bind (this.args[i], result);
119 var list = new Array ();
120 for (i = 0; i < args[limit].length; i++)
122 result = args[limit].Eval (domain);
123 if (domain.Thrown ())
127 domain.Bind (this.args[limit], list);
130 domain.Catch (Xex.CatchTag.Return);
131 for (var term in this.body)
133 result = term.Eval (domain);
134 if (domain.Thrown ())
141 domain.UnboundTo (current);
146 Xex.Macro = function (name, min_args, max_args, args, body)
149 this.with_var = with_var;
150 this.min_args = min_args;
151 this.max_args = max_args;
156 Xex.Macro.prototype.Call = function (domain, vari, args)
158 var current = domain.bindings;
159 var result = Xex.Zero;
163 for (i = 0; i < args.length; i++)
164 domain.Bind (this.args[i], args[i]);
166 domain.Catch (Xex.CatchTag.Return);
167 for (var term in body)
169 result = term.Eval (domain);
170 if (domain.Thrown ())
177 domain.UnboundTo (current);
182 Xex.Bindings = function (vari)
185 this.old_value = vari.val;
188 Xex.Bindings.prototype.UnboundTo = function (boundary)
190 for (var b = this; b != boundary; b = b.next)
191 b.vari.val = b.old_value;
195 Xex.Bind = function (bindings, vari, val)
197 var b = new Xex.Bindings (vari);
208 Xex.Domain = function (name, parent, context)
211 this.context = context;
214 if (name != 'basic' && ! parent)
215 parent = Xex.BasicDomain
216 this.parent = parent;
223 for (elt in parent.termtypes)
224 this.termtypes[elt] = parent.termtypes[elt];
225 for (elt in parent.functions)
226 this.functions[elt] = parent.functions[elt];
227 for (elt in parent.variables)
228 this.variables[elt] = parent.variables[elt];
231 this.call_stack = new Array ();
232 this.bindings = null;
233 this.catch_stack = new Array ();
234 this.catch_count = 0;
238 Xex.Domain.prototype = {
239 CallStackCount: function () { return this.call_stack.length; },
240 CallStackPush: function (term) { this.call_stack.push (term); },
241 CallStackPop: function () { this.call_stack.pop (); },
242 Bind: function (vari, val)
244 this.bindings = Xex.Bind (this.bindings, vari, val);
246 UnboundTo: function (boundary)
249 this.bindings = this.bindings.UnboundTo (boundary);
251 Catch: function (tag) { this.catch_stack.push (tag); this.catch_count++; },
254 this.catch_stack.pop ();
255 if (this.catch_count > this.catch_stack.length)
260 if (this.catch_count < this.catch_stack.length)
262 this.caught = (this.catch_count == this.catch_stack.length - 1);
268 ThrowReturn: function ()
270 for (var i = this.catch_stack.length - 1; i >= 0; i--)
273 if (this.catch_stack[i] == Xex.CatchTag.Return)
277 ThrowBreak: function ()
279 if (this.catch_stack[this.catch_stack.length - 1] != Xex.CatchTag.Break)
280 throw new Xex.ErrTerm (Xex.Error.NoLoopToBreak,
281 "No surrounding loop to break");
284 ThrowSymbol: function (tag)
286 var i = this.catch_count;
287 for (var j = this.catch_stack.length - 1; j >= 0; j--)
290 if (Xex.CatchTag.Matches (this.catch_stack[i], tag))
292 this.catch_count = i;
296 throw new Xex.ErrTerm (Xex.Error.UncaughtThrow,
297 "No corresponding catch: " + tag);
299 DefType: function (obj)
302 if (this.termtypes[type])
303 throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
304 "Already defined: " + type);
305 if (this.functions[type])
306 throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
307 "Already defined as a funciton or a macro: "
309 this.termtypes[type] = obj.Parser;
311 DefSubr: function (builtin, name, with_var, min_args, max_args)
313 this.functions[name] = new Xex.Subrountine (builtin, name, with_var,
316 DefSpecial: function (builtin, name, with_var, min_args, max_args)
318 this.functions[name] = new Xex.SpecialForm (builtin, name, with_var,
321 Defun: function (name, min_args, max_args, args, body)
323 this.functions[name] = new Xex.Lambda (name, min_args, max_args,
326 DefunByFunc: function (func) { this.functions[func.Name] = func; },
327 Defmacro: function (name, min_args, max_args, args, body)
329 this.functions[name] = new Xex.Macro (name, min_args, max_args,
332 DefAlias: function (alias, fname)
334 var func = this.functions[fname];
336 if (this.termtypes[alias])
337 throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
338 "Already defined as a term type: " + alias);
339 if (this.functions[alias])
340 throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
341 "Already defined as a function: " + alias);
343 throw new Xex.ErrTerm (Xex.Error.UnknownFunction, fname);
344 this.functions[alias] = func;
346 Defvar: function (name)
348 if (name instanceof Xex.Variable)
350 name = name.Clone (this);
351 this.variables[name.name] = name;
354 var vari = this.variables[name];
358 throw new Xex.ErrTerm (Xex.Error.VariableTypeConflict,
359 "Not a non-typed variable: " + name);
363 vari = new Xex.Variable (this, name, Xex.Zero);
364 this.variables[name] = vari;
368 GetFunc: function (name)
370 var func = this.functions[name];
372 throw new Xex.ErrTerm (Xex.Error.UnknownFunction,
373 "Unknown function: " + name);
376 CopyFunc: function (domain, name)
378 var func = this.functions[name];
379 domain.DefunByFunc (func);
382 CopyFuncAll: function (domain)
384 for (var elt in this.functions)
385 domain.DefunByFunc (this.functions[elt]);
387 GetVarCreate: function (name)
389 var vari = this.variables[name];
391 vari = this.variables[name] = new Xex.Variable (this, name, Xex.Zero);
394 GetVar: function (name) { return this.variables[name]; },
395 SaveValues: function ()
398 for (var elt in this.variables)
399 values[elt] = this.variables[elt].val.Clone ();
402 RestoreValues: function (values)
407 var vari = this.variables[name];
408 vari.val = values[name];
413 Xex.Term = function (type) { this.type = type; }
414 Xex.Term.prototype = {
415 IsTrue: function () { return true; },
416 Eval: function (domain) { return this.Clone (); },
417 Clone: function (domain) { return this; },
418 Equals: function (obj)
420 return (this.type == obj.type
422 && obj.val == this.val);
424 Matches: function (obj) { return this.Equals (obj); },
425 toString: function ()
427 if (this.val != undefined)
428 return '<' + this.type + '>' + this.val + '</' + this.type + '>';
429 return '<' + this.type + '/>';
433 Xex.ParseTerm = function (domain, node)
435 var name = node.nodeName;
436 var parser = domain.termtypes[name];
439 return parser (domain, node);
440 if (name == 'defun' || name == 'defmacro')
442 name = parse_defun_head (domain, node);
443 parse_defun_body (domain, node);
444 return new Xex.StrTerm (name);
446 if (name == 'defvar')
448 name = parse_defvar (doamin, node);
449 return new Xex.StrTerm (nanme);
452 return new Xex.Funcall.prototype.Parser (domain, node);
455 Xex.ParseTermList = function (domain, node)
457 for (var n = node; n; n = n.nextSibling)
460 if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
461 Xex.parse_defun_head (domain, n);
464 for (var n = node; n; n = n.nextSibling)
468 terms = new Array ();
469 if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
470 Xex.parse_defun_body (domain, n);
471 else if (n.nodeName == 'defvar')
472 Xex.parse_defvar (domain, n);
474 terms.push (Xex.ParseTerm (domain, n));
479 Xex.Varref = function (vname)
485 var proto = new Xex.Term ('varref');
487 proto.Clone = function () { return new Xex.Varref (this.val); }
488 proto.Eval = function (domain)
490 if (! this.vari || this.vari.domain != domain)
491 this.vari = domain.GetVarCreate (this.val);
492 return this.vari.val;
495 proto.Parser = function (domain, node)
497 return new Xex.Varref (node.attributes['vname'].nodeValue);
500 Xex.Varref.prototype = proto;
503 var null_args = new Array ();
505 Xex.Funcall = function (func, vari, args)
509 this.args = args || null_args;
513 var proto = new Xex.Term ('funcall');
515 proto.Parser = function (domain, node)
517 var fname = node.nodeName;
520 if (fname == 'funcall')
521 fname = node.attributes['fname']
522 var func = domain.GetFunc (fname);
524 attr = node.attributes['vname'];
525 vari = attr != undefined ? domain.GetVarCreate (attr.nodeValue) : false;
526 var args = Xex.ParseTermList (domain, node.firstChild);
527 return new Xex.Funcall (func, vari, args);
530 proto.New = function (domain, fname, vname, args)
532 var func = domain.GetFunc (fname);
533 var vari = vname ? domain.GetVarCreate (vname) : null;
534 var funcall = new Xex.Funcall (func, vari, args);
535 if (func instanceof Xex.Macro)
536 funcall = funcall.Eval (domain);
540 proto.Eval = function (domain)
542 return this.func.Call (domain, this.vari, this.args);
545 proto.Clone = function ()
547 return new Xex.Funcall (this.func, this.vari, this.args);
550 proto.Equals = function (obj)
552 return (obj.type == 'funcall'
553 && obj.func == this.func
554 && obj.vari.Equals (this.vari)
555 && obj.args.length == this.func.length);
558 proto.toString = function ()
561 var len = this.args.length;
563 return '<' + this.func.name + '/>';
564 for (var i = 0; i < len; i++)
565 arglist += this.args[i].toString ();
566 return '<' + this.func.name + '>' + arglist + '</' + this.func.name + '>';
569 Xex.Funcall.prototype = proto;
572 Xex.ErrTerm = function (ename, message, stack)
575 this.message = message;
580 var proto = new Xex.Term ('error');
582 proto.IsError = true;
584 proto.Parser = function (domain, node)
586 return new Xex.ErrTerm (node.attributes['ename'].nodeValue,
587 node.innerText, false);
590 proto.CallStack = function () { return stack; }
592 proto.SetCallStack = function (value) { statck = value; }
594 proto.Clone = function ()
596 return new Xex.ErrTerm (ename, message, false);
599 proto.Equals = function (obj)
602 && obj.ename == ename && obj.message == message
603 && (obj.stack ? (stack && stack.length == obj.stack.length)
607 proto.Matches = function (obj)
609 return (obj.IsError && obj.ename == ename);
612 proto.toString = function ()
614 return '<error ename="' + this.ename + '">' + this.message + '</error>';
617 Xex.ErrTerm.prototype = proto;
620 Xex.IntTerm = function (num) { this.val = num; };
622 var proto = new Xex.Term ('integer');
624 proto.IsTrue = function () { return this.val != 0; }
625 proto.Clone = function () { return new Xex.IntTerm (this.val); }
626 proto.Parser = function (domain, node)
628 var str = node.firstChild.nodeValue;
630 if (str.charAt (0) == '?' && str.length == 2)
631 return new Xex.IntTerm (str.charCodeAt (1));
632 return new Xex.IntTerm (parseInt (node.firstChild.nodeValue));
634 Xex.IntTerm.prototype = proto;
637 Xex.StrTerm = function (str) { this.val = str; };
639 var proto = new Xex.Term ('string');
641 proto.IsTrue = function () { return this.val.length > 0; }
642 proto.Clone = function () { return new Xex.StrTerm (this.val); }
643 proto.Parser = function (domain, node)
645 return new Xex.StrTerm (node.firstChild.nodeValue);
647 Xex.StrTerm.prototype = proto;
650 Xex.SymTerm = function (str) { this.val = str; };
652 var proto = new Xex.Term ('symbol');
653 proto.IsSymbol = true;
654 proto.IsTrue = function () { return this.val != 'nil'; }
655 proto.Clone = function () { return new Xex.SymTerm (this.val); }
656 proto.Parser = function (domain, node)
658 return new Xex.SymTerm (node.firstChild.nodeValue);
660 Xex.SymTerm.prototype = proto;
663 Xex.LstTerm = function (list) { this.val = list; };
665 var proto = new Xex.Term ('list');
667 proto.IsTrue = function () { return this.val.length > 0; }
668 proto.Clone = function () { return new Xex.LstTerm (this.val.slice (0)); }
670 proto.Equals = function (obj)
672 if (obj.type != 'list' || obj.val.length != this.val.length)
674 var i, len = this.val.length;
675 for (i = 0; i < len; i++)
676 if (! this.val[i].Equals (obj.val[i]))
681 proto.Parser = function (domain, node)
683 var list = Xex.ParseTermList (domain, node.firstChild);
684 return new Xex.LstTerm (list);
687 proto.toString = function ()
689 var len = this.val.length;
694 for (var i = 0; i < len; i++)
695 str += this.val[i].toString ();
696 return str + '</list>';
698 Xex.LstTerm.prototype = proto;
702 var basic = new Xex.Domain ('basic', null, null);
704 function Fset (domain, vari, args)
706 return vari.SetValue (args[0]);
709 function maybe_set_intvar (vari, n)
711 var term = new Xex.IntTerm (n);
713 vari.SetValue (term);
717 function Fadd (domain, vari, args)
719 var n = vari ? vari.val.val : 0;
720 var len = args.length;
722 for (var i = 0; i < len; i++)
724 return maybe_set_intvar (vari, n);
727 function Fand (domain, vari, args)
729 var len = args.length;
730 for (var i = 0; i < len; i++)
732 var result = args[i].Eval (domain);
733 if (domain.Thrown ())
741 function For (domain, vari, args)
743 var len = args.length;
744 for (var i = 0; i < len; i++)
746 var result = args[i].Eval (domain);
747 if (domain.Thrown ())
755 function Fprogn (domain, vari, args)
757 var result = Xex.One;
758 var len = args.length;
760 for (var i = 0; i < len; i++)
762 result = args[i].Eval (domain);
763 if (domain.Thrown ())
769 function Fif (domain, vari, args)
771 var result = args[0].Eval (domain);
773 if (domain.Thrown ())
776 return args[1].Eval (domain);
777 if (args.length == 2)
779 return args[2].Eval (domain);
782 function eval_terms (domain, terms, idx)
784 var result = Xex.Zero;
785 domain.caught = false;
786 for (var i = idx; i < terms.length; i++)
788 result = terms[i].Eval (domain);
789 if (domain.Thrown ())
795 function Fcatch (domain, vari, args)
803 result = eval_terms (domain, args, 1);
805 if (e instanceof Xex.ErrTerm)
807 if (! args[0].Matches (e))
815 else if (args[0].IsSymbol)
818 domain.Catch (args[0].val);
819 result = eval_terms (domain, args, 1);
823 vari.SetValue (result);
831 throw new Xex.ErrTerm (Xex.Error.WrongArgument,
832 "Not a symbol nor an error: " + args[0]);
835 function Fthrow (domain, vari, args)
839 domain.ThrowSymbol (args[0]);
840 return (args[args.length - 1]);
846 throw new Xex.ErrTerm (Xex.Error.WrongArgument,
847 "Not a symbol nor an error:" + args[0]);
850 Xex.BasicDomain = basic;
852 basic.DefSubr (Fset, "set", true, 1, 1);
853 basic.DefSubr (Fadd, "add", true, 1, -1);
854 basic.DefSubr (Fthrow, "throw", false, 1, 2);
856 basic.DefSpecial (Fand, "and", false, 1, -1);
857 basic.DefSpecial (For, "or", false, 1, -1);
858 basic.DefAlias ("=", "set");
859 basic.DefSpecial (Fprogn, "progn", false, 1, -1);
860 basic.DefSpecial (Fif, "if", false, 2, 3);
861 basic.DefSpecial (Fcatch, "catch", true, 2, -1);
863 basic.DefType (Xex.Funcall.prototype);
864 basic.DefType (Xex.Varref.prototype);
865 basic.DefType (Xex.ErrTerm.prototype);
866 basic.DefType (Xex.IntTerm.prototype);
867 basic.DefType (Xex.StrTerm.prototype);
868 basic.DefType (Xex.SymTerm.prototype);
869 basic.DefType (Xex.LstTerm.prototype);
873 Xex.Zero = new Xex.IntTerm (0);
874 Xex.One = new Xex.IntTerm (1);
876 Xex.Load = function (server, file)
878 var obj = new XMLHttpRequest ();
879 var url = server ? server + '/' + file : file;
880 obj.open ('GET', url, false);
881 obj.overrideMimeType ('text/xml');
883 return obj.responseXML.firstChild;
887 // URL of the input method server.
888 server: "http://www.m17n.org/common/mim-js",
889 // Boolean flag to tell if MIM is active or not.
891 // Boolean flag to tell if MIM is running in debug mode or not.
893 // List of registered input methods.
895 // Global input method data
897 // Currently selected input method.
901 LoadStatus: { NotLoaded:0, Loading:1, Loaded:2, Error:-1 },
910 Preedit: 0x06, // PreeditText | CursorPos
911 Candidate: 0x38 // CandidateList | CandidateIndex | CandidateShow
933 ParseError: "parse-error"
938 var keysyms = new Array ();
939 keysyms["bs"] = "backspace";
940 keysyms["lf"] = "linefeed";
941 keysyms["cr"] = keysyms["enter"] = "return";
942 keysyms["esc"] = "escape";
943 keysyms["spc"] = "space";
944 keysyms["del"] = "delete";
946 function decode_keysym (str) {
947 var parts = str.split ("-");
948 var len = parts.length, i;
949 var has_modifier = len > 1;
951 for (i = 0; i < len - 1; i++)
952 if (! MIM.KeyModifier.hasOwnProperty (parts[i]))
954 var key = parts[len - 1];
957 key = keysyms[key.toLowerCase ()];
963 for (i = 1; i < len - 1; i++)
964 str += '-' + parts[i];
973 parts = new Array ();
980 MIM.Key = function (val)
983 this.has_modifier = false;
984 if (typeof val == 'string' || val instanceof String)
986 this.key = decode_keysym (val);
988 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + val);
989 if (this.key instanceof Array)
991 this.key = this.key[0];
992 this.has_modifier = true;
995 else if (typeof val == 'number' || val instanceof Number)
996 this.key = String.fromCharCode (val);
998 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + val);
1001 MIM.Key.prototype.toString = function () { return this.key; };
1005 MIM.KeySeq = function (seq)
1007 this.val = new Array ();
1008 this.has_modifier = false;
1014 var len = seq.val.length;
1015 for (var i = 0; i < len; i++)
1018 if (v.type != 'string' && v.type != 'integer'
1019 && v.type != 'symbol')
1020 throw new Xex.ErrTerm (MIM.Error.ParseError,
1021 "Invalid key: " + v);
1022 var key = new MIM.Key (v.val);
1023 this.val.push (key);
1024 if (key.has_modifier)
1025 this.has_modifier = true;
1030 var len = seq.val.length;
1031 for (var i = 0; i < len; i++)
1032 this.val.push (new MIM.Key (seq.val.charCodeAt (i)));
1035 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + seq);
1039 var proto = new Xex.Term ('keyseq');
1040 proto.Clone = function () { return this; }
1041 proto.Parser = function (domain, node)
1043 var seq = new Array ();
1044 for (node = node.firstChild; node; node = node.nextSibling)
1045 if (node.nodeType == 1)
1047 var term = Xex.ParseTerm (domain, node);
1048 return new MIM.KeySeq (term);
1050 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid keyseq");
1052 proto.toString = function ()
1054 var len = this.val.length;
1058 var str = '<keyseq>';
1059 for (var i = 0; i < len; i++)
1063 else if (this.has_modifier)
1065 str += this.val[i].toString ();
1067 return str + '</keyseq>';
1070 MIM.KeySeq.prototype = proto;
1074 MIM.Marker = function () { }
1075 MIM.Marker.prototype = new Xex.Term ('marker');
1076 MIM.Marker.prototype.CharAt = function (ic)
1078 var p = this.Position (ic);
1080 return ic.GetSurroundingChar (p);
1081 else if (pos >= ic.preedit.length)
1082 return ic.GetSurroundingChar (p - ic.preedit.length);
1083 return ic.preedit.charCodeAt (p);
1086 MIM.NamedMarker = function (name) { this.val = name; }
1087 MIM.NamedMarker.prototype = new MIM.Marker ();
1088 MIM.NamedMarker.prototype.Position = function (ic)
1090 var p = ic.marker_positions[this.val];
1091 return (p == undefined ? 0 : p);
1093 MIM.NamedMarker.prototype.Mark = function (ic)
1095 ic.marker_positions[this.val] = ic.cursor_pos;
1098 MIM.PredefinedMarker = function (name) { this.val = name; }
1099 MIM.PredefinedMarker.prototype = new MIM.Marker ();
1100 MIM.PredefinedMarker.prototype.Position = function (ic)
1102 if (typeof this.pos == 'number')
1104 return this.pos (ic);
1107 var predefined = { }
1109 function def_predefined (name, position)
1111 predefined[name] = new MIM.PredefinedMarker (name);
1112 predefined[name].pos = position;
1115 def_predefined ('@<', 0);
1116 def_predefined ('@>', function (ic) { return ic.preedit.length; });
1117 def_predefined ('@-', function (ic) { return ic.cursor_pos - 1; });
1118 def_predefined ('@+', function (ic) { return ic.cursor_pos + 1; });
1119 def_predefined ('@[', function (ic) {
1120 if (ic.cursor_pos > 0)
1122 var pos = ic.cursor_pos;
1123 return ic.preedit.FindProp ('candidates', pos - 1).from;
1127 def_predefined ('@]', function (ic) {
1128 if (ic.cursor_pos < ic.preedit.length - 1)
1130 var pos = ic.cursor_pos;
1131 return ic.preedit.FindProp ('candidates', pos).to;
1133 return ic.preedit.length;
1135 for (var i = 0; i < 10; i++)
1136 def_predefined ("@" + i, i);
1137 predefined['@first'] = predefined['@<'];
1138 predefined['@last'] = predefined['@>'];
1139 predefined['@previous'] = predefined['@-'];
1140 predefined['@next'] = predefined['@+'];
1141 predefined['@previous-candidate-change'] = predefined['@['];
1142 predefined['@next-candidate-change'] = predefined['@]'];
1144 MIM.SurroundMarker = function (name)
1147 this.distance = parseInt (name.slice (2));
1148 if (isNaN (this.distance))
1149 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid marker: " + name);
1151 MIM.SurroundMarker.prototype = new MIM.Marker ();
1152 MIM.SurroundMarker.prototype.Position = function (ic)
1154 return ic.cursor_pos + this.distance;
1157 MIM.Marker.prototype.Parser = function (domain, node)
1159 var name = node.firstChild.nodeValue;
1160 if (name.charAt (0) == '@')
1162 var n = predefined[name];
1165 if (name.charAt (1) == '-')
1166 return new MIM.SurroundMarker (name);
1167 throw new Xex.ErrTerm (MIM.Error.ParseError,
1168 "Invalid marker: " + name);
1170 return new MIM.NamedMarker (name);
1174 MIM.Selector = function (name)
1178 MIM.Selector.prototype = new Xex.Term ('selector');
1181 selectors["@<"] = selectors["@first"] = new MIM.Selector ('@<');
1182 selectors["@="] = selectors["@current"] = new MIM.Selector ('@=');
1183 selectors["@>"] = selectors["@last"] = new MIM.Selector ('@>');
1184 selectors["@-"] = selectors["@previous"] = new MIM.Selector ('@-');
1185 selectors["@+"] = selectors["@next"] = new MIM.Selector ('@+');
1186 selectors["@["] = selectors["@previous-candidate-change"]
1187 = new MIM.Selector ('@[');
1188 selectors["@]"] = selectors["@next-candidate-change"]
1189 = new MIM.Selector ('@]');
1191 MIM.Selector.prototype.Parser = function (domain, node)
1193 var name = node.firstChild.nodeValue;
1194 var s = selectors[name];
1196 throw new Xex.ErrTerm (MIM.Error.ParseError,
1197 "Invalid selector: " + name);
1202 MIM.Rule = function (keyseq, actions)
1204 this.keyseq = keyseq;
1205 this.actions = actions;
1207 MIM.Rule.prototype = new Xex.Term ('rule');
1208 MIM.Rule.prototype.Parser = function (domain, node)
1211 for (n = node.firstChild; n && n.nodeType != 1; n = n.nextSibling);
1213 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid rule:" + node);
1214 var keyseq = Xex.ParseTerm (domain, n);
1215 if (keyseq.type != 'keyseq')
1216 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid rule:" + node);
1217 var actions = Xex.ParseTermList (domain, n.nextSibling);
1218 return new MIM.Rule (keyseq, actions);
1220 MIM.Rule.prototype.toString = function ()
1225 MIM.Map = function (name)
1228 this.rules = new Array ();
1231 var proto = new Xex.Term ('map');
1233 proto.Parser = function (domain, node)
1235 var name = node.attributes['mname'].nodeValue;
1237 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map");
1238 var map = new MIM.Map (name);
1239 for (var n = node.firstChild; n; n = n.nextSibling)
1240 if (n.nodeType == 1)
1241 map.rules.push (Xex.ParseTerm (domain, n));
1245 proto.toString = function ()
1247 var str = '<map mname="' + this.name + '">';
1248 var len = this.rules.length;
1249 for (i = 0; i < len; i++)
1250 str += this.rules[i];
1251 return str + '</map>';
1254 MIM.Map.prototype = proto;
1257 Xex.CatchTag._mimtag = new Xex.SymTerm ('@mimtag');
1259 MIM.Action = function (domain, terms)
1261 var args = new Array ();
1262 args.push (Xex.CatchTag_.mimtag);
1263 for (var i = 0; i < terms.length; i++)
1264 args.push (terms[i]);
1265 this.action = Xex.Funcall.prototype.New (domain, 'catch', null, args);
1268 MIM.Action.prototype.Run = function (domain)
1270 var result = this.action.Eval (domain);
1271 if (result.type == 'error')
1273 domain.context.Error = result.toString ();
1276 return (result != Xex.CatchTag._mimtag);
1279 MIM.Keymap = function ()
1282 this.submaps = null;
1283 this.actions = null;
1288 function add_rule (keymap, rule)
1290 var keyseq = rule.keyseq;
1291 var len = keyseq.val.length;
1294 for (var i = 0; i < len; i++)
1296 var key = keyseq.val[i];
1300 if (! keymap.submaps)
1301 keymap.submaps = {};
1303 sub = keymap.submaps[key.key];
1305 keymap.submaps[key.key] = sub = new MIM.Keymap ();
1309 keymap.actions = rule.actions;
1312 proto.Add = function (map)
1314 var rules = map.rules;
1315 var len = rules.length;
1317 for (var i = 0; i < len; i++)
1318 add_rule (this, rules[i]);
1320 proto.Lookup = function (keys, index)
1324 if (index < keys.val.length && this.submaps
1325 && (sub = this.submaps[keys.val[index].key]))
1328 return sub.Lookup (keys, index);
1330 return { map: this, index: index };
1333 MIM.Keymap.prototype = proto;
1336 MIM.State = function (name)
1339 this.keymap = new MIM.Keymap ();
1342 var proto = new Xex.Term ('state');
1344 proto.Parser = function (domain, node)
1346 var map_list = domain.map_list;
1347 var name = node.attributes['sname'].nodeValue;
1349 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map");
1350 var state = new MIM.State (name);
1351 for (node = node.firstChild; node; node = node.nextSibling)
1353 if (node.nodeType != 1)
1355 if (node.nodeName == 'branch')
1357 state.keymap.Add (map_list[node.attributes['mname'].nodeValue]);
1358 state.keymap.actions = Xex.ParseTermList (domain, node.firstChild);
1360 else if (node.nodeName == 'state-hook')
1361 state.enter_actions = Xex.ParseTermList (domain, node.firstChild);
1362 else if (node.nodeName == 'catch-all-branch')
1363 state.fallback_actions = Xex.ParseTermList (domain, node.firstChild);
1364 else if (node.nodeName == 'title')
1365 state.title = node.firstChild.nodeValue;
1370 proto.toString = function ()
1372 return '<state sname="' + this.name + '">' + this.keymap + '</state>';
1375 MIM.State.prototype = proto;
1378 MIM.im_domain = new Xex.Domain ('input-method', null, null);
1379 MIM.im_domain.DefType (MIM.KeySeq.prototype);
1380 MIM.im_domain.DefType (MIM.Marker.prototype);
1381 MIM.im_domain.DefType (MIM.Selector.prototype);
1382 MIM.im_domain.DefType (MIM.Rule.prototype);
1383 MIM.im_domain.DefType (MIM.Map.prototype);
1384 MIM.im_domain.DefType (MIM.State.prototype);
1387 var im_domain = MIM.im_domain;
1389 function Finsert (domain, vari, args)
1392 if (args[0].type == 'integer')
1393 text = String.fromCharCode (args[0].val);
1396 domain.context.insert (text, null);
1399 function Finsert_candidates (domain, vari, args)
1401 var ic = domain.context;
1402 var candidates = new Candidates (args, column);
1403 ic.insert (candidates.Current (), candidates);
1407 im_domain.DefSubr (Finsert, "insert", false, 1, 1);
1412 parsers['description'] = function (node)
1414 this.description = node.firstChild.nodeValue;
1416 parses['variable-list'] = function (node)
1418 for (node = node.firstChild; node; node = node.nextSibling)
1420 if (node.nodeType != 1)
1422 var name = node.attributes['vname'].nodeValue;
1423 var vari = get_global_bar (name);
1425 domain.Defvar (name);
1426 Xex.Parse (domain, node);
1429 parsers['title'] = function (node)
1431 this.title = node.firstChild.nodeValue;
1433 parsers['map-list'] = function (node)
1435 for (node = node.firstChild; node; node = node.nextSibling)
1437 if (node.nodeType != 1 || node.nodeName != 'map')
1439 var map = Xex.ParseTerm (this.domain, node);
1440 this.map_list[map.name] = map;
1443 parsers['state-list'] = function (node)
1445 this.domain.map_list = this.map_list;
1446 for (node = node.firstChild; node; node = node.nextSibling)
1448 if (node.nodeType != 1 || node.nodeName != 'state')
1450 var state = Xex.ParseTerm (this.domain, node);
1452 state.title = this.title;
1453 if (! this.initial_state)
1454 this.initial_state = state;
1455 this.state_list[state.name] = state;
1457 delete this.domain.map_list;
1460 MIM.IM = function (lang, name, extra_id, file)
1464 this.extra_id = extra_id;
1466 this.load_status = MIM.LoadStatus.NotLoaded;
1467 this.domain = new Xex.Domain (this.lang + '-' + this.name,
1468 MIM.im_domain, null);
1474 var node = Xex.Load (null, this.file);
1477 this.load_status = MIM.LoadStatus.Error;
1481 this.initial_state = null;
1482 this.state_list = {};
1483 for (node = node.firstChild; node; node = node.nextSibling)
1485 if (node.nodeType != 1)
1487 var name = node.nodeName;
1488 var parser = parsers[name];
1490 parser.call (this, node);
1492 this.load_status = MIM.LoadStatus.Loaded;
1497 MIM.IM.prototype = proto;
1499 MIM.IC = function (im)
1501 if (im.load_status == MIM.LoadStatus.NotLoaded)
1503 if (im.load_status != MIM.LoadStatus.Loaded)
1504 alert ('im:' + im.name + ' error:' + im.load_status);
1506 this.domain = new Xex.Domain ('context', im.domain, this);
1512 MIM.CandidateTable = function ()
1514 this.table = new Array ();
1517 MIM.CandidateTable.prototype.get = function (from)
1519 for (var i = 0; i < this.table.length; i++)
1521 var elt = this.table[i];
1522 if (elt.from <= from && elt.to > from)
1527 MIM.CandidateTable.prototype.put = function (from, to, candidates)
1529 for (var i = 0; i < this.table.length; i++)
1531 var elt = this.table[i];
1532 if (elt.from >= from && elt.from < to
1533 || elt.to >= from && elt.to < to)
1537 elt.val = candidates;
1541 this.table.push ({ from: from, to: to, val: candidates });
1544 MIM.CandidateTable.prototype.adjust = function (from, to, inserted)
1546 var diff = inserted - (to - from);
1547 for (var i = 0; i < this.table.length; i++)
1549 var elt = this.table[i];
1558 MIM.CandidateTable.prototype.clear = function ()
1560 this.table.length = 0;
1563 function Block (index, term)
1567 this.Data = term.val;
1568 else if (term.IsList)
1570 this.Data = new Array ();
1571 for (var i = 0; i < term.val.length; i++)
1572 this.Data.push (term.val[i].val);
1576 Block.prototype.Count = function () { return this.Data.length; }
1577 Block.prototype.get = function (i)
1579 return (this.Data instanceof Array ? this.Data[i] : this.Data.charAt (i));
1582 function fill_group (start)
1584 var nitems = this.group.length;
1586 var b = this.blocks[r];
1588 if (start < b.Index)
1589 while (start < b.Index)
1590 b = this.blocks[--r];
1592 while (start >= b.Index + b.Count ())
1593 b = this.blocks[++r];
1596 var count = b.Count ();
1598 for (var i = 0; i < nitems; i++, start++)
1603 if (r == this.blocks.Length)
1609 this.group[i] = b.get (start);
1614 function Candidates (candidates, column)
1616 this.column = column;
1620 this.blocks = new Array ();
1622 for (var i = 0; i < candidates.length; i++)
1624 var block = new Block (this.total, candidates[i]);
1625 this.blocks.push (block);
1626 this.total += block.Count ();
1630 Candidates.prototype.Column = function ()
1632 return (this.column > 0 ? this.index % this.column
1633 : this.index - this.blocks[this.row].Index);
1636 Candidates.prototype.GroupLength = function ()
1638 if (this.column > 0)
1640 var start = this.index - (this.index % this.column);
1641 return (start + this.column <= this.total ? this.column
1642 : this.total - start);
1644 return this.blocks[this.row].Count;
1647 Candidates.prototype.Current = function ()
1649 var b = this.blocks[this.row];
1650 return b.get (this.index - b.Index);
1653 Candidates.prototype.PrevGroup ()
1655 var col = this.Column ();
1657 if (this.column > 0)
1659 this.index -= this.column;
1660 if (this.index >= 0)
1661 nitems = this.column;
1664 var lastcol = (this.total - 1) % this.column;
1665 this.index = (col < lastcol ? this.total - lastcol + col
1667 this.row = this.blocks.length - 1;
1668 nitems = lastcol + 1;
1670 while (this.blocks[this.row].Index > this.index)
1675 this.row = this.row > 0 ? this.row - 1 : this.blocks.length - 1;
1676 nitems = this.blocks[this.row].Count ();
1677 this.index = (this.blocks[this.row].Index
1678 + (col < nitems ? col : nitems - 1));
1683 Candidates.prototype.NextGroup = function ()
1685 var col = this.Column ();
1687 if (this.column > 0)
1689 this.index += this.column - col;
1690 if (this.index < this.total)
1692 if (this.index + col >= this.total)
1694 nitems = this.total - this.index;
1695 this.index = this.total - 1;
1699 nitems = this.column;
1708 while (this.blocks[this.row].Index > this.index)
1713 this.row = this.row < this.blocks.length - 1 ? this.row + 1 : 0;
1714 nitems = this.blocks[this.row].Count ();
1715 this.index = (this.blocks[this.row].Index
1716 + (col < nitems ? col : nitems - 1));
1721 Candidates.prototype.Prev = function ()
1723 if (this.index == 0)
1725 this.index = this.total - 1;
1726 this.row = this.blocks.length - 1;
1731 if (this.blocks[this.row].Index > this.index)
1736 Candidates.prototype.Next = function ()
1739 if (this.index == this.total)
1746 var b = this.blocks[this.row];
1747 if (this.index == b.Index + b.Count ())
1752 Candidates.prototype.First = function ()
1754 this.index -= this.Column ();
1755 while (this.blocks[this.row].Index > this.index)
1759 Candidates.prototype.Last = function ()
1761 var b = this.blocks[this.row];
1762 if (this.column > 0)
1764 if (this.index + 1 < this.total)
1766 this.index += this.column - this.Column () + 1;
1767 while (b.Index + b.Count () <= this.index)
1768 b = this.blocks[++this.row];
1771 this.index = b.Index + b.Count () - 1;
1774 Candidates.prototype.Select = funciton (selector)
1776 if (selector instanceof MIM.Selector)
1778 switch (selector.val)
1780 case '@<': this.First (); break;
1781 case '@>': this.Last (); break;
1782 case '@-': this.Prev (); break;
1783 case '@+': this.Next (); break;
1784 case '@[': this.PrevGroup (); break;
1785 case '@]': this.NextGroup (); break;
1788 return this.Current ();
1791 if (this.column > 0)
1793 col = this.index % this.column;
1794 start = this.index - col;
1795 end = start + this.column;
1799 start = this.blocks[this.row].Index;
1800 col = this.index - start;
1801 end = start + this.blocks[this.row].Count;
1803 if (end > this.total)
1805 this.index += selector - col;
1806 if (this.index >= end)
1807 this.index = end - 1;
1808 if (this.column > 0)
1811 while (this.blocks[this.row].Index + this.blocks[this.row].Count
1815 while (this.blocks[this.row].Index > this.index)
1818 return this.Current ();
1821 function detach_candidates (ic)
1823 ic.candidate_table.clear ();
1824 ic.candidates = null;
1825 ic.changed |= (MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos
1826 | ChangedStatus.CandidateList
1827 | ChangedStatus.CandidateIndex
1828 | ChangedStatus.CandidateShow);
1831 function set_cursor (prefix, pos)
1833 this.cursor_pos = pos;
1835 this.candidates = this.candidate_table.get (pos - 1);
1837 this.candidates = null;
1840 function save_state ()
1842 this.state_var_values = this.domain.SaveValues ();
1843 this.state_preedit = this.preedit;
1844 this.state_key_head = this.key_head;
1845 this.state_pos = this.cursor_pos;
1848 function restore_state ()
1850 this.domain.RestoreValues (this.state_var_values);
1851 this.preedit = this.state_preedit;
1852 set_cursor.call (this, "restore", this.state_pos);
1855 function handle_key ()
1857 var out = this.keymap.Lookup (this.keys, this.key_head);
1859 var branch_actions = this.state.keymap.actions;
1861 MIM.log ('handling ' + this.keys.val[this.key_head]
1862 + ' in ' + this.state.name + ':' + this.keymap.name);
1863 this.key_head = out.index;
1864 if (sub != this.keymap)
1867 restore_state.call (this);
1869 MIM.log ('submap found');
1870 if (this.keymap.actions)
1872 MIM.log ('taking map actions:');
1873 if (! this.take_actions (this.keymap.actions))
1876 else if (this.keymap.submaps)
1878 MIM.log ('no map actions');
1879 for (var i = this.state_key_head; i < this.key_head; i++)
1881 MIM.log ('inserting key:' + this.keys.val[i].key);
1882 this.insert (this.keys.val[i].key, null);
1885 if (! this.keymap.submaps)
1887 MIM.log ('terminal:');
1888 if (this.keymap.branch_actions != null)
1890 MIM.log ('branch actions:');
1891 if (! this.take_actions (branch_actions))
1894 if (this.keymap != this.state.keymap)
1895 this.shift (this.state);
1900 MIM.log ('no submap');
1901 var current_state = this.state;
1902 var map = this.keymap;
1906 MIM.log ('branch actions');
1907 if (! this.take_actions (this.keymap.branch_actions))
1911 if (map == this.keymap)
1913 MIM.log ('no state change');
1914 if (map == this.initial_state.keymap
1915 && this.key_head < this.keys.val.length)
1917 MIM.log ('unhandled');
1920 if (this.keymap != current_state.keymap)
1921 this.shift (current_state);
1922 else if (this.keymap.actions == null)
1923 this.shift (this.initial_state);
1932 this.produced = null;
1934 this.preedit_saved = '';
1935 this.cursor_pos = 0;
1936 this.marker_positions = {};
1937 this.candidates = null;
1938 this.candidate_show = false;
1940 this.prev_state = null;
1941 this.initial_state = this.im.initial_state;
1942 this.title = this.initial_state.title;
1943 this.state_preedit = '';
1944 this.state_key_head = 0;
1945 this.state_var_values = {};
1948 this.keys = new MIM.KeySeq ();
1950 this.key_unhandled = false;
1951 this.unhandled_key = null;
1952 this.changed = MIM.ChangedStatus.None;
1953 this.error_message = '';
1954 this.title = this.initial_state.title;
1957 this.preedit_saved = '';
1958 this.marker_positions = {};
1959 this.candidate_table = new MIM.CandidateTable ();
1960 this.candidates = null;
1961 this.candidate_show = false;
1962 this.shift (this.initial_state);
1965 catch_args: new Array (Xex.CatchTag._mimtag, null),
1967 take_actions: function (actions)
1969 var func_progn = this.domain.GetFunc ('progn');
1970 var func_catch = this.domain.GetFunc ('catch');
1971 this.catch_args[1] = new Xex.Funcall (func_progn, null, actions);
1972 var term = new Xex.Funcall (func_catch, null, this.catch_args);
1973 term = term.Eval (this.domain);
1974 return (! term.IsSymbol || term.val != '@mimtag');
1977 GetSurroundingChar: function (pos)
1979 if (pos < 0 ? this.caret_pos < - pos : this.target.value.length < pos)
1981 return this.target.value.charCodeAt (this.caret_pos + pos);
1984 adjust_markers: function (from, to, inserted)
1986 var diff = inserted - (to - from);
1988 for (var m in this.marker_positions)
1989 if (this.marker_positions[m] > from)
1990 this.marker_positions[m] = (this.marker_positions[m] >= to
1991 ? pos + diff : from);
1992 if (this.cursor_pos >= to)
1993 set_cursor.call (this, 'adjust', this.cursor_pos + diff);
1994 else if (this.cursor_pos > from)
1995 set_cursor.call (this, 'adjust', from)
1998 preedit_replace: function (from, to, text, candidates)
2000 this.preedit = (this.preedit.substring (0, from)
2001 + text + this.preedit.substring (to));
2002 this.adjust_markers (from, to, text.length);
2003 this.candidate_table.adjust (from, to, text.length);
2005 this.candidate_table.put (from, from + text.length, candidates)
2008 insert: function (text, candidates)
2010 this.preedit_replace (this.cursor_pos, this.cursor_pos, text, candidates);
2011 this.changed = MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos;
2018 this.DelSurroundText (pos);
2021 else if (pos > this.preedit.length)
2023 this.DelSurroundText (pos - this.preedit.length);
2024 pos = this.preedit.length;
2026 if (pos < this.cursor_pos)
2027 this.preedit = (this.predit.substring (0, pos)
2028 + this.preedit.substring (this.cursor_pos));
2030 this.preedit = (this.preedit.substring (0, this.cursor_pos)
2031 + this.predit.substring (pos));
2036 this.candidate_show = true;
2037 this.changed |= MIM.ChangedStatus.CandidateShow;
2042 this.candidate_show = false;
2043 this.changed |= MIM.ChangedStatus.CandidateShow;
2046 move: function (pos)
2050 else if (pos > this.preedit.length)
2051 pos = this.preedit.length;
2052 if (pos != this.cursor_pos)
2054 set_cursor.call (this, 'move', pos);
2055 this.changed |= MIM.ChangedStatus.Preedit;
2059 pushback: function (n)
2061 if (n instanceof MIM.KeySeq)
2063 if (this.key_head > 0)
2065 if (this.key_head < this.keys.val.length)
2066 this.keys.val.splice (this.key_head,
2067 this.keys.val.length - this.key_head);
2068 for (var i = 0; i < n.val.length; i++)
2069 this.keys.val.push (n.val[i]);
2075 if (this.key_head < 0)
2082 this.key_head = - n;
2083 if (this.key_head > this.keys.val.length)
2084 this.key_head = this.keys.val.length;
2090 if (this.key_head < this.keys.val.length)
2091 this.keys.val.splice (this.key_head, 1);
2096 if (this.preedit.length > 0)
2098 this.candidate_table.clear ();
2099 this.produced += this.preedit;
2100 this.preedit_replace.call (this, 0, this.preedit.length, '', null);
2104 shift: function (state)
2108 MIM.log ("shifting back to previous");
2109 if (this.prev_state == null)
2111 state = this.prev_state;
2114 MIM.log ("shifting to " + state.name);
2116 if (state == this.initial_state)
2121 this.keys.val.splice (0, this.key_head);
2123 this.prev_state = null;
2128 if (state != this.state)
2129 this.prev_state = this.state;
2131 if (state != this.state && state.enter_actions)
2132 take_actions.call (state.enter_actions);
2133 if (! this.state || this.state.title != state.title)
2134 this.changed |= MIM.ChangedStatus.StateTitle;
2136 this.keymap = state.keymap;
2137 this.state_key_head = this.key_head;
2138 save_state.call (this);
2141 Filter: function (key)
2145 this.key_unhandled = true;
2146 this.unhandled_key = key;
2149 if (key.key == '_reload')
2151 this.changed = MIM.ChangedStatus.None;
2153 this.key_unhandled = false;
2154 this.keys.val.push (key);
2156 while (this.key_head < this.keys.val.length)
2158 if (! handle_key.call (this))
2160 if (this.key_head < this.keys.val.length)
2162 this.unhandled_key = this.keys.val[this.key_head];
2163 this.keys.val.splice (this.key_head, this.key_head + 1);
2165 this.key_unhandled = true;
2171 this.key_unhandled = true;
2175 if (this.key_unhandled)
2177 this.keys.val.length = 0;
2178 this.key_head = this.state_key_head = this.commit_key_head = 0;
2180 return (! this.key_unhandled
2181 && this.produced.length == 0
2182 && this.preedit.length == 0);
2186 MIM.IC.prototype = proto;
2188 var node = Xex.Load (null, "imlist.xml");
2189 for (node = node.firstChild; node; node = node.nextSibling)
2190 if (node.nodeName == 'input-method')
2192 var lang, name, extra_id, file;
2194 for (var n = node.firstChild; n; n = n.nextSibling)
2196 if (n.nodeName == 'language')
2197 lang = n.firstChild.nodeValue;
2198 else if (n.nodeName == 'name')
2199 name = n.firstChild.nodeValue;
2200 else if (n.nodeName == 'extra-id')
2201 extra_id = n.firstChild.nodeValue;
2202 else if (n.nodeName == 'filename')
2203 file = n.firstChild.nodeValue;
2205 if (! MIM.im_list[lang])
2206 MIM.im_list[lang] = {};
2207 MIM.im_list[lang][name] = new MIM.IM (lang, name, extra_id, file);
2213 var keys = new Array ();
2215 keys[0x08] = 'backspace';
2216 keys[0x0D] = 'return';
2217 keys[0x1B] = 'escape';
2218 keys[0x20] = 'space';
2219 keys[0x21] = 'pageup';
2220 keys[0x22] = 'pagedown';
2222 keys[0x24] = 'home';
2223 keys[0x25] = 'left';
2225 keys[0x27] = 'right';
2226 keys[0x28] = 'down';
2227 keys[0x2D] = 'insert';
2228 keys[0x2E] = 'delete';
2229 for (var i = 1; i <= 12; i++)
2230 keys[111 + i] = "f" + i;
2231 keys[0x90] = "numlock";
2232 keys[0xF0] = "capslock";
2234 MIM.decode_key_event = function (event)
2236 var key = ((event.type == 'keydown' || event.keyCode) ? event.keyCode
2237 : event.charCode ? event.charCode
2241 if (event.type == 'keydown')
2246 if (event.shiftKey) key = "S-" + key ;
2249 key = String.fromCharCode (key);
2250 if (event.altKey) key = "A-" + key ;
2251 if (event.ctrlKey) key = "C-" + key ;
2252 return new MIM.Key (key);
2256 MIM.add_event_listener
2257 = (window.addEventListener
2258 ? function (target, type, listener) {
2259 target.addEventListener (type, listener, false);
2261 : window.attachEvent
2262 ? function (target, type, listener) {
2263 target.attachEvent ('on' + type,
2265 listener.call (target, window.event);
2268 : function (target, type, listener) {
2270 = function (e) { listener.call (target, e || window.event); };
2273 MIM.log = function (msg)
2275 var node = document.getElementById ('log');
2276 node.value = msg + "\n" + node.value;
2279 MIM.debug_print = function (event, ic)
2283 if (! MIM.debug_nodes)
2285 MIM.debug_nodes = new Array ();
2286 MIM.debug_nodes['keydown'] = document.getElementById ('keydown');
2287 MIM.debug_nodes['keypress'] = document.getElementById ('keypress');
2288 MIM.debug_nodes['status0'] = document.getElementById ('status0');
2289 MIM.debug_nodes['status1'] = document.getElementById ('status1');
2290 MIM.debug_nodes['keymap0'] = document.getElementById ('keymap0');
2291 MIM.debug_nodes['keymap1'] = document.getElementById ('keymap1');
2292 MIM.debug_nodes['preedit0'] = document.getElementById ('preedit0');
2293 MIM.debug_nodes['preedit1'] = document.getElementById ('preedit1');
2295 var target = event.target;
2296 var code = event.keyCode;
2297 var ch = event.type == 'keydown' ? 0 : event.charCode;
2298 var key = MIM.decode_key_event (event);
2301 MIM.debug_nodes[event.type].innerHTML = "" + code + "/" + ch + " : " + key;
2302 index = (event.type == 'keydown' ? '0' : '1');
2304 MIM.debug_nodes['status' + index].innerHTML = ic.im.load_status;
2306 MIM.debug_nodes['status' + index].innerHTML = 'no IM';
2307 MIM.debug_nodes['keymap' + index].innerHTML = ic.keymap.name;
2308 MIM.debug_nodes['preedit' + index].innerHTML = ic.preedit;
2311 MIM.get_range = function (target, range)
2313 if (target.selectionStart != null) // for Mozilla
2315 range[0] = target.selectionStart;
2316 range[1] = target.selectionEnd;
2320 var r = document.selection.createRange ();
2321 var rr = r.duplicate ();
2323 rr.moveToElementText (target);
2324 rr.setEndPoint ('EndToEnd', range);
2325 range[0] = rr.text.length - r.text.length;
2326 range[1] = rr.text.length;
2330 MIM.set_caret = function (target, ic)
2332 if (target.setSelectionRange) // Mozilla
2334 var scrollTop = target.scrollTop;
2335 target.setSelectionRange (ic.spot, ic.spot + ic.preedit.length);
2336 target.scrollTop = scrollTop;
2340 var range = target.createTextRange ();
2341 range.moveStart ('character', ic.spot);
2342 range.moveEnd ('character', ic.spot + ic.preedit.length);
2348 var range = new Array ();
2350 MIM.check_range = function (target, ic)
2352 MIM.get_range (target, range);
2353 if (range[0] != ic.spot || range[1] - range[0] != ic.preedit.length
2354 || target.value.substring (range[0], range[1]) != ic.preedit)
2356 MIM.log ('reset:' + ic.spot + '-' + (ic.spot + ic.preedit.length)
2357 + '/' + range[0] + '-' + range[1]);
2360 target.value = (target.value.substring (0, range[0])
2361 + target.value.substring (range[1]));
2366 MIM.update = function (target, ic)
2368 var text = target.value;
2369 target.value = (text.substring (0, ic.spot)
2372 + text.substring (ic.spot));
2373 ic.spot += ic.produced.length;
2374 MIM.set_caret (target, ic);
2377 MIM.reset_ic = function (event)
2379 if (event.target.mim_ic)
2381 var ic = event.target.mim_ic;
2382 var pos = ic.spot + ic.preedit.length;
2385 event.target.setSelectionRange (pos, pos);
2389 MIM.keydown = function (event)
2391 var target = event.target;
2392 if (! (target.type == "text" || target.type == "textarea"))
2395 var ic = target.mim_ic;
2396 if (! ic || ic.im != MIM.current)
2398 MIM.log ('creating IC');
2399 ic = new MIM.IC (MIM.current);
2401 MIM.add_event_listener (target, 'blur', MIM.reset_ic);
2403 if (ic.im.load_status != MIM.LoadStatus.Loaded)
2405 MIM.check_range (target, ic);
2406 MIM.debug_print (event, ic);
2407 ic.key = MIM.decode_key_event (event);
2410 MIM.keypress = function (event)
2412 if (! (event.target.type == "text" || event.target.type == "textarea"))
2415 var ic = event.target.mim_ic;
2419 if (ic.im.load_status != MIM.LoadStatus.Loaded)
2422 ic.key = MIM.decode_key_event (event);
2429 MIM.log ("filtering " + ic.key);
2430 var result = ic.Filter (ic.key);
2431 MIM.update (event.target, ic);
2432 if (! ic.key_unhandled)
2433 event.preventDefault ();
2435 MIM.debug_print (event, ic);
2440 MIM.select_im = function (event)
2442 var target = event.target.parentNode;
2443 while (target.tagName != "SELECT")
2444 target = target.parentNode;
2447 for (var lang in MIM.im_list)
2448 for (var name in MIM.im_list[lang])
2449 if (idx++ == target.selectedIndex)
2451 im = MIM.im_list[lang][name];
2454 document.getElementsByTagName ('body')[0].removeChild (target);
2455 target.target.focus ();
2456 if (im && im != MIM.current)
2459 MIM.log ('select IM: ' + im.name);
2463 MIM.destroy_menu = function (event)
2465 if (event.target.tagName == "SELECT")
2466 document.getElementsByTagName ('body')[0].removeChild (event.target);
2469 MIM.select_menu = function (event)
2471 var target = event.target;
2473 if (! ((target.type == "text" || target.type == "textarea")
2474 && event.which == 1 && event.ctrlKey))
2477 var sel = document.createElement ('select');
2478 sel.onclick = MIM.select_im;
2479 sel.onmouseout = MIM.destroy_menu;
2480 sel.style.position='absolute';
2481 sel.style.left = (event.clientX - 10) + "px";
2482 sel.style.top = (event.clientY - 10) + "px";
2483 sel.target = target;
2485 for (var lang in MIM.im_list)
2486 for (var name in MIM.im_list[lang])
2488 var option = document.createElement ('option');
2489 var imname = lang + "-" + name;
2490 option.appendChild (document.createTextNode (imname));
2491 option.value = imname;
2492 sel.appendChild (option);
2493 if (MIM.im_list[lang][name] == MIM.current)
2494 sel.selectedIndex = idx;
2498 document.getElementsByTagName ('body')[0].appendChild (sel);
2501 MIM.test = function ()
2503 var im = MIM.im_list['t']['latn-post'];
2504 var ic = new MIM.IC (im);
2506 ic.Filter (new MIM.Key ('a'));
2507 ic.Filter (new MIM.Key ("'"));
2510 document.getElementById ('text').value = ic.produced + ic.preedit;
2513 document.getElementById ('text').value
2514 = Xex.ParseTerm (domain, body).Eval (domain).toString ();
2516 if (e instanceof Xex.ErrTerm)
2524 MIM.init = function ()
2526 MIM.add_event_listener (window, 'keydown', MIM.keydown);
2527 MIM.add_event_listener (window, 'keypress', MIM.keypress);
2528 MIM.add_event_listener (window, 'mousedown', MIM.select_menu);
2529 if (window.location == 'http://localhost/mim/index.html')
2530 MIM.server = 'http://localhost/mim';
2531 MIM.current = MIM.im_list['vi']['telex'];
2534 MIM.init_debug = function ()