1 // -* coding: utf-8; -*
5 Xex.Alist = function ()
10 Xex.Alist.prototype.put = function (key, val)
13 return (this[key] = val);
15 Xex.Alist.prototype.clone = function ()
17 var alist = new Xex.Alist ();
19 alist[key] = this[key];
22 Xex.Alist.prototype.toString = function ()
26 str += '"' + key + '"';
30 // Xex.alist = new Xex.Alist ();
31 // Xex.alist.put ('abc', "ABC");
32 // alert (Xex.alist['abc']);
35 UnknownError: "unknown-error",
36 WrongArgument: "wrong-argument",
38 InvalidInteger: "invalid-integer",
39 TermTypeInvalid: "term-type-invalid",
40 FunctionConflict: "function-conflict",
41 VariableTypeConflict: "variable-type-conflict",
42 VariableRangeConflict: "variable-range-conflict",
43 VariableWrongRange: "variable-wrong-range",
44 VariableWrongValue: "variable-wrong-value",
46 UnknownFunction: "unknown-function",
47 MacroExpansionError: "macro-expansion-error",
48 NoVariableName: "no-variable-anme",
51 ArithmeticError: "arithmetic-error",
52 WrongType: "wrong-type",
53 IndexOutOfRange: "index-out-of-range",
54 ValueOutOfRange: "value-out-of-range",
55 NoLoopToBreak: "no-loop-to-break",
56 UncaughtThrow: "uncaught-throw"
59 Xex.Variable = function (domain, name, val)
66 Xex.Variable.prototype.clone = function () {
67 return new Xex.Variable (this.domain, this.name, this.value);
70 Xex.Variable.prototype.Equals = function (obj) {
71 return ((obj instanceof Xex.Variable)
72 && obj.name == this.name);
75 Xex.Variable.prototype.SetValue = function (term) {
80 Xex.Function = function (name, with_var, min_args, max_args) {
82 this.with_var = with_var;
83 this.min_args = min_args;
84 this.max_args = max_args;
87 Xex.Subrountine = function (builtin, name, with_var, min_args, max_args) {
89 this.with_var = with_var;
90 this.min_args = min_args;
91 this.max_args = max_args;
92 this.builtin = builtin;
95 Xex.Subrountine.prototype.Call = function (domain, vari, args)
97 newargs = new Array ();
98 for (var i = 0; i < args.length; i++)
100 newargs[i] = args[i].Eval (domain);
101 if (domain.Thrown ())
104 return this.builtin (domain, vari, newargs)
107 Xex.SpecialForm = function (builtin, name, with_var, min_args, max_args)
110 this.with_var = with_var;
111 this.min_args = min_args;
112 this.max_args = max_args;
113 this.builtin = builtin;
116 Xex.SpecialForm.prototype.Call = function (domain, vari, args)
118 return this.builtin (domain, vari, args)
121 Xex.Lambda = function (name, min_args, max_args, args, body)
124 this.with_var = with_var;
125 this.min_args = min_args;
126 this.max_args = max_args;
131 Xex.Lambda.prototype.Call = function (domain, vari, args)
133 var current = domain.bindings;
134 var result = Xex.Zero;
135 var limit = max_args >= 0 ? args.length : args.length - 1;
139 for (i = 0; i < limit; i++)
141 result = args[i].Eval (domain);
142 if (domain.Thrown ())
144 domain.Bind (this.args[i], result);
148 var list = new Array ();
149 for (i = 0; i < args[limit].length; i++)
151 result = args[limit].Eval (domain);
152 if (domain.Thrown ())
156 domain.Bind (this.args[limit], list);
159 domain.Catch (Xex.CatchTag.Return);
160 for (var term in this.body)
162 result = term.Eval (domain);
163 if (domain.Thrown ())
170 domain.UnboundTo (current);
175 Xex.Macro = function (name, min_args, max_args, args, body)
178 this.with_var = with_var;
179 this.min_args = min_args;
180 this.max_args = max_args;
185 Xex.Macro.prototype.Call = function (domain, vari, args)
187 var current = domain.bindings;
188 var result = Xex.Zero;
192 for (i = 0; i < args.length; i++)
193 domain.Bind (this.args[i], args[i]);
195 domain.Catch (Xex.CatchTag.Return);
196 for (var term in body)
198 result = term.Eval (domain);
199 if (domain.Thrown ())
206 domain.UnboundTo (current);
211 Xex.Bindings = function (vari)
214 this.old_value = vari.val;
217 Xex.Bindings.prototype.UnboundTo = function (boundary)
219 for (var b = this; b != boundary; b = b.next)
220 b.vari.val = b.old_value;
224 Xex.Bind = function (bindings, vari, val)
226 var b = new Xex.Bindings (vari);
237 Xex.Domain = function (name, parent, context)
240 this.context = context;
243 if (name != 'basic' && ! parent)
244 parent = Xex.BasicDomain
245 this.parent = parent;
252 for (elt in parent.termtypes)
253 this.termtypes[elt] = parent.termtypes[elt];
254 for (elt in parent.functions)
255 this.functions[elt] = parent.functions[elt];
256 for (elt in parent.variables)
257 this.variables[elt] = parent.variables[elt];
260 this.call_stack = new Array ();
261 this.bindings = null;
262 this.catch_stack = new Array ();
263 this.catch_count = 0;
267 Xex.Domain.prototype = {
268 CallStackCount: function () { return this.call_stack.length; },
269 CallStackPush: function (term) { this.call_stack.push (term); },
270 CallStackPop: function () { this.call_stack.pop (); },
271 Bind: function (vari, val)
273 this.bindings = Xex.Bind (this.bindings, vari, val);
275 UnboundTo: function (boundary)
278 this.bindings = this.bindings.UnboundTo (boundary);
280 Catch: function (tag) { this.catch_stack.push (tag); this.catch_count++; },
283 this.catch_stack.pop ();
284 if (this.catch_count > this.catch_stack.length)
289 if (this.catch_count < this.catch_stack.length)
291 this.caught = (this.catch_count == this.catch_stack.length - 1);
297 ThrowReturn: function ()
299 for (var i = this.catch_stack.length - 1; i >= 0; i--)
302 if (this.catch_stack[i] == Xex.CatchTag.Return)
306 ThrowBreak: function ()
308 if (this.catch_stack[this.catch_stack.length - 1] != Xex.CatchTag.Break)
309 throw new Xex.ErrTerm (Xex.Error.NoLoopToBreak,
310 "No surrounding loop to break");
313 ThrowSymbol: function (tag)
315 var i = this.catch_count;
316 for (var j = this.catch_stack.length - 1; j >= 0; j--)
319 if (Xex.CatchTag.Matches (this.catch_stack[i], tag))
321 this.catch_count = i;
325 throw new Xex.ErrTerm (Xex.Error.UncaughtThrow,
326 "No corresponding catch: " + tag);
328 DefType: function (obj)
331 if (this.termtypes[type])
332 throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
333 "Already defined: " + type);
334 if (this.functions[type])
335 throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
336 "Already defined as a funciton or a macro: "
338 this.termtypes[type] = obj.Parser;
340 DefSubr: function (builtin, name, with_var, min_args, max_args)
342 this.functions[name] = new Xex.Subrountine (builtin, name, with_var,
345 DefSpecial: function (builtin, name, with_var, min_args, max_args)
347 this.functions[name] = new Xex.SpecialForm (builtin, name, with_var,
350 Defun: function (name, min_args, max_args, args, body)
352 this.functions[name] = new Xex.Lambda (name, min_args, max_args,
355 DefunByFunc: function (func) { this.functions[func.Name] = func; },
356 Defmacro: function (name, min_args, max_args, args, body)
358 this.functions[name] = new Xex.Macro (name, min_args, max_args,
361 DefAlias: function (alias, fname)
363 var func = this.functions[fname];
365 if (this.termtypes[alias])
366 throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
367 "Already defined as a term type: " + alias);
368 if (this.functions[alias])
369 throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
370 "Already defined as a function: " + alias);
372 throw new Xex.ErrTerm (Xex.Error.UnknownFunction, fname);
373 this.functions[alias] = func;
375 Defvar: function (name)
377 var vari = this.variables[name];
381 throw new Xex.ErrTerm (Xex.Error.VariableTypeConflict,
382 "Not a non-typed variable: " + name);
386 vari = new Xex.Variable (this, name, Xex.Zero);
387 this.variables[name] = vari;
391 GetFunc: function (name)
393 var func = this.functions[name];
395 throw new Xex.ErrTerm (Xex.Error.UnknownFunction,
396 "Unknown function: " + name);
399 CopyFunc: function (domain, name)
401 var func = this.functions[name];
402 domain.DefunByFunc (func);
405 CopyFuncAll: function (domain)
407 for (var elt in this.functions)
408 domain.DefunByFunc (this.functions[elt]);
410 GetVarCreate: function (name)
412 var vari = this.variables[name];
414 vari = this.variables[name] = new Xex.Variable (this, name, Xex.Zero);
417 GetVar: function (name) { return this.variables[name]; },
418 SaveValues: function ()
421 for (var elt in this.variables)
422 values[elt] = this.variables[elt].val.Clone ();
425 RestoreValues: function (values)
430 var vari = this.variables[name];
431 vari.val = values[name];
436 Xex.Term = function (type) { this.type = type; }
437 Xex.Term.prototype = {
438 IsTrue: function () { return true; },
439 Eval: function (domain) { return this.Clone (); },
440 Clone: function (domain) { return this; },
441 Equals: function (obj)
443 return (this.type == obj.type
445 && obj.val == this.val);
447 Matches: function (obj) { return this.Equals (obj); },
448 toString: function ()
450 if (this.val != undefined)
451 return '<' + this.type + '>' + this.val + '</' + this.type + '>';
452 return '<' + this.type + '/>';
456 Xex.ParseTerm = function (domain, node)
458 var name = node.nodeName;
459 var parser = domain.termtypes[name];
462 return parser (domain, node);
463 if (name == 'defun' || name == 'defmacro')
465 name = parse_defun_head (domain, node);
466 parse_defun_body (domain, node);
467 return new Xex.StrTerm (name);
469 if (name == 'defvar')
471 name = parse_defvar (doamin, node);
472 return new Xex.StrTerm (nanme);
475 return new Xex.Funcall.prototype.Parser (domain, node);
478 Xex.ParseTermList = function (domain, node)
480 for (var n = node; n; n = n.nextSibling)
483 if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
484 Xex.parse_defun_head (domain, n);
487 for (var n = node; n; n = n.nextSibling)
491 terms = new Array ();
492 if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
493 Xex.parse_defun_body (domain, n);
494 else if (n.nodeName == 'defvar')
495 Xex.parse_defvar (domain, n);
497 terms.push (Xex.ParseTerm (domain, n));
502 Xex.Varref = function (vname)
508 var proto = new Xex.Term ('varref');
510 proto.Clone = function () { return new Xex.Varref (this.val); }
511 proto.Eval = function (domain)
513 if (! this.vari || this.vari.domain != domain)
514 this.vari = domain.GetVarCreate (this.val);
515 return this.vari.val;
518 proto.Parser = function (domain, node)
520 return new Xex.Varref (node.attributes['vname'].nodeValue);
523 Xex.Varref.prototype = proto;
526 var null_args = new Array ();
528 Xex.Funcall = function (func, vari, args)
532 this.args = args || null_args;
536 var proto = new Xex.Term ('funcall');
538 proto.Parser = function (domain, node)
540 var fname = node.nodeName;
543 if (fname == 'funcall')
544 fname = node.attributes['fname']
545 var func = domain.GetFunc (fname);
547 attr = node.attributes['vname'];
548 vari = attr != undefined ? domain.GetVarCreate (attr.nodeValue) : false;
549 var args = Xex.ParseTermList (domain, node.firstChild);
550 return new Xex.Funcall (func, vari, args);
553 proto.New = function (domain, fname, vname, args)
555 var func = domain.GetFunc (fname);
556 var vari = vname ? domain.GetVarCreate (vname) : null;
557 var funcall = new Xex.Funcall (func, vari, args);
558 if (func instanceof Xex.Macro)
559 funcall = funcall.Eval (domain);
563 proto.Eval = function (domain)
565 return this.func.Call (domain, this.vari, this.args);
568 proto.Clone = function ()
570 return new Xex.Funcall (this.func, this.vari, this.args);
573 proto.Equals = function (obj)
575 return (obj.type == 'funcall'
576 && obj.func == this.func
577 && obj.vari.Equals (this.vari)
578 && obj.args.length == this.func.length);
581 proto.toString = function ()
584 var len = this.args.length;
586 return '<' + this.func.name + '/>';
587 for (var i = 0; i < len; i++)
588 arglist += this.args[i].toString ();
589 return '<' + this.func.name + '>' + arglist + '</' + this.func.name + '>';
592 Xex.Funcall.prototype = proto;
595 Xex.ErrTerm = function (ename, message, stack)
598 this.message = message;
603 var proto = new Xex.Term ('error');
605 proto.IsError = true;
607 proto.Parser = function (domain, node)
609 return new Xex.ErrTerm (node.attributes['ename'].nodeValue,
610 node.innerText, false);
613 proto.CallStack = function () { return stack; }
615 proto.SetCallStack = function (value) { statck = value; }
617 proto.Clone = function ()
619 return new Xex.ErrTerm (ename, message, false);
622 proto.Equals = function (obj)
625 && obj.ename == ename && obj.message == message
626 && (obj.stack ? (stack && stack.length == obj.stack.length)
630 proto.Matches = function (obj)
632 return (obj.IsError && obj.ename == ename);
635 proto.toString = function ()
637 return '<error ename="' + this.ename + '">' + this.message + '</error>';
640 Xex.ErrTerm.prototype = proto;
643 Xex.IntTerm = function (num) { this.val = num; };
645 var proto = new Xex.Term ('integer');
647 proto.IsTrue = function () { return this.val != 0; }
648 proto.Clone = function () { return new Xex.IntTerm (this.val); }
649 proto.Parser = function (domain, node)
651 var str = node.firstChild.nodeValue;
653 if (str.charAt (0) == '?' && str.length == 2)
654 return new Xex.IntTerm (str.charCodeAt (1));
655 return new Xex.IntTerm (parseInt (node.firstChild.nodeValue));
657 Xex.IntTerm.prototype = proto;
660 Xex.StrTerm = function (str) { this.val = str; };
662 var proto = new Xex.Term ('string');
664 proto.IsTrue = function () { return this.val.length > 0; }
665 proto.Clone = function () { return new Xex.StrTerm (this.val); }
666 proto.Parser = function (domain, node)
668 return new Xex.StrTerm (node.firstChild.nodeValue);
670 Xex.StrTerm.prototype = proto;
673 Xex.SymTerm = function (str) { this.val = str; };
675 var proto = new Xex.Term ('symbol');
676 proto.IsSymbol = true;
677 proto.IsTrue = function () { return this.val != 'nil'; }
678 proto.Clone = function () { return new Xex.SymTerm (this.val); }
679 proto.Parser = function (domain, node)
681 return new Xex.SymTerm (node.firstChild.nodeValue);
683 Xex.SymTerm.prototype = proto;
686 Xex.LstTerm = function (list) { this.val = list; };
688 var proto = new Xex.Term ('list');
690 proto.IsTrue = function () { return this.val.length > 0; }
691 proto.Clone = function () { return new Xex.LstTerm (this.val.slice (0)); }
693 proto.Equals = function (obj)
695 if (obj.type != 'list' || obj.val.length != this.val.length)
697 var i, len = this.val.length;
698 for (i = 0; i < len; i++)
699 if (! this.val[i].Equals (obj.val[i]))
704 proto.Parser = function (domain, node)
706 var list = Xex.ParseTermList (domain, node.firstChild);
707 return new Xex.LstTerm (list);
710 proto.toString = function ()
712 var len = this.val.length;
717 for (var i = 0; i < len; i++)
718 str += this.val[i].toString ();
719 return str + '</list>';
721 Xex.LstTerm.prototype = proto;
725 var basic = new Xex.Domain ('basic', null, null);
727 function Fset (domain, vari, args)
729 return vari.SetValue (args[0]);
732 function maybe_set_intvar (vari, n)
734 var term = new Xex.IntTerm (n);
736 vari.SetValue (term);
740 function Fadd (domain, vari, args)
742 var n = vari ? vari.val.val : 0;
743 var len = args.length;
745 for (var i = 0; i < len; i++)
747 return maybe_set_intvar (vari, n);
750 function Fand (domain, vari, args)
752 var len = args.length;
753 for (var i = 0; i < len; i++)
755 var result = args[i].Eval (domain);
756 if (domain.Thrown ())
764 function For (domain, vari, args)
766 var len = args.length;
767 for (var i = 0; i < len; i++)
769 var result = args[i].Eval (domain);
770 if (domain.Thrown ())
778 function Fprogn (domain, vari, args)
780 var result = Xex.One;
781 var len = args.length;
783 for (var i = 0; i < len; i++)
785 result = args[i].Eval (domain);
786 if (domain.Thrown ())
792 function Fif (domain, vari, args)
794 var result = args[0].Eval (domain);
796 if (domain.Thrown ())
799 return args[1].Eval (domain);
800 if (args.length == 2)
802 return args[2].Eval (domain);
805 function eval_terms (domain, terms, idx)
807 var result = Xex.Zero;
808 domain.caught = false;
809 for (var i = idx; i < terms.length; i++)
811 result = terms[i].Eval (domain);
812 if (domain.Thrown ())
818 function Fcatch (domain, vari, args)
826 result = eval_terms (domain, args, 1);
828 if (e instanceof Xex.ErrTerm)
830 if (! args[0].Matches (e))
838 else if (args[0].IsSymbol)
841 domain.Catch (args[0].val);
842 result = eval_terms (domain, args, 1);
846 vari.SetValue (result);
854 throw new Xex.ErrTerm (Xex.Error.WrongArgument,
855 "Not a symbol nor an error: " + args[0]);
858 function Fthrow (domain, vari, args)
862 domain.ThrowSymbol (args[0]);
863 return (args[args.length - 1]);
869 throw new Xex.ErrTerm (Xex.Error.WrongArgument,
870 "Not a symbol nor an error:" + args[0]);
873 Xex.BasicDomain = basic;
875 basic.DefSubr (Fset, "set", true, 1, 1);
876 basic.DefSubr (Fadd, "add", true, 1, -1);
877 basic.DefSubr (Fthrow, "throw", false, 1, 2);
879 basic.DefSpecial (Fand, "and", false, 1, -1);
880 basic.DefSpecial (For, "or", false, 1, -1);
881 basic.DefAlias ("=", "set");
882 basic.DefSpecial (Fprogn, "progn", false, 1, -1);
883 basic.DefSpecial (Fif, "if", false, 2, 3);
884 basic.DefSpecial (Fcatch, "catch", true, 2, -1);
886 basic.DefType (Xex.Funcall.prototype);
887 basic.DefType (Xex.Varref.prototype);
888 basic.DefType (Xex.ErrTerm.prototype);
889 basic.DefType (Xex.IntTerm.prototype);
890 basic.DefType (Xex.StrTerm.prototype);
891 basic.DefType (Xex.SymTerm.prototype);
892 basic.DefType (Xex.LstTerm.prototype);
896 Xex.Zero = new Xex.IntTerm (0);
897 Xex.One = new Xex.IntTerm (1);
899 Xex.Load = function (server, file)
901 var obj = new XMLHttpRequest ();
902 var url = server ? server + '/' + file : file;
903 obj.open ('GET', url, false);
904 obj.overrideMimeType ('text/xml');
906 return obj.responseXML.firstChild;
910 // URL of the input method server.
911 server: "http://www.m17n.org/common/mim-js",
912 // Boolean flag to tell if MIM is active or not.
914 // Boolean flag to tell if MIM is running in debug mode or not.
916 // List of registered input methods.
918 // Global input method data
920 // Currently selected input method.
924 LoadStatus: { NotLoaded:0, Loading:1, Loaded:2, Error:-1 },
933 Preedit: 0x06, // PreeditText | CursorPos
934 Candidate: 0x38 // CandidateList | CandidateIndex | CandidateShow
956 ParseError: "parse-error"
961 var keysyms = new Array ();
962 keysyms["bs"] = "backspace";
963 keysyms["lf"] = "linefeed";
964 keysyms["cr"] = keysyms["enter"] = "return";
965 keysyms["esc"] = "escape";
966 keysyms["spc"] = "space";
967 keysyms["del"] = "delete";
969 function decode_keysym (str) {
970 var parts = str.split ("-");
971 var len = parts.length, i;
972 var has_modifier = len > 1;
974 for (i = 0; i < len - 1; i++)
975 if (! MIM.KeyModifier.hasOwnProperty (parts[i]))
977 var key = parts[len - 1];
980 key = keysyms[key.toLowerCase ()];
986 for (i = 1; i < len - 1; i++)
987 str += '-' + parts[i];
996 parts = new Array ();
1003 MIM.Key = function (val)
1006 this.has_modifier = false;
1007 if (typeof val == 'string' || val instanceof String)
1009 this.key = decode_keysym (val);
1011 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + val);
1012 if (this.key instanceof Array)
1014 this.key = this.key[0];
1015 this.has_modifier = true;
1018 else if (typeof val == 'number' || val instanceof Number)
1019 this.key = String.fromCharCode (val);
1021 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + val);
1024 MIM.Key.prototype.toString = function () { return this.key; };
1028 MIM.KeySeq = function (seq)
1030 this.val = new Array ();
1031 this.has_modifier = false;
1037 var len = seq.val.length;
1038 for (var i = 0; i < len; i++)
1041 if (v.type != 'string' && v.type != 'integer'
1042 && v.type != 'symbol')
1043 throw new Xex.ErrTerm (MIM.Error.ParseError,
1044 "Invalid key: " + v);
1045 var key = new MIM.Key (v.val);
1046 this.val.push (key);
1047 if (key.has_modifier)
1048 this.has_modifier = true;
1053 var len = seq.val.length;
1054 for (var i = 0; i < len; i++)
1055 this.val.push (new MIM.Key (seq.val.charCodeAt (i)));
1058 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + seq);
1062 var proto = new Xex.Term ('keyseq');
1063 proto.Clone = function () { return this; }
1064 proto.Parser = function (domain, node)
1066 var seq = new Array ();
1067 for (node = node.firstChild; node; node = node.nextSibling)
1068 if (node.nodeType == 1)
1070 var term = Xex.ParseTerm (domain, node);
1071 return new MIM.KeySeq (term);
1073 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid keyseq");
1075 proto.toString = function ()
1077 var len = this.val.length;
1081 var str = '<keyseq>';
1082 for (var i = 0; i < len; i++)
1086 else if (this.has_modifier)
1088 str += this.val[i].toString ();
1090 return str + '</keyseq>';
1093 MIM.KeySeq.prototype = proto;
1097 MIM.Marker = function () { }
1098 MIM.Marker.prototype = new Xex.Term ('marker');
1099 MIM.Marker.prototype.CharAt = function (ic)
1101 var p = this.Position (ic);
1103 return ic.GetSurroundingChar (p);
1104 else if (pos >= ic.preedit.length)
1105 return ic.GetSurroundingChar (p - ic.preedit.length);
1106 return ic.preedit.charCodeAt (p);
1109 MIM.NamedMarker = function (name) { this.val = name; }
1110 MIM.NamedMarker.prototype = new MIM.Marker ();
1111 MIM.NamedMarker.prototype.Position = function (ic)
1113 var p = ic.marker_positions[this.val];
1114 return (p == undefined ? 0 : p);
1116 MIM.NamedMarker.prototype.Mark = function (ic)
1118 ic.marker_positions[this.val] = ic.cursor_pos;
1121 MIM.PredefinedMarker = function (name) { this.val = name; }
1122 MIM.PredefinedMarker.prototype = new MIM.Marker ();
1123 MIM.PredefinedMarker.prototype.Position = function (ic)
1125 if (typeof this.pos == 'number')
1127 return this.pos (ic);
1130 var predefined = { }
1132 function def_predefined (name, position)
1134 predefined[name] = new MIM.PredefinedMarker (name);
1135 predefined[name].pos = position;
1138 def_predefined ('@<', 0);
1139 def_predefined ('@>', function (ic) { return ic.preedit.length; });
1140 def_predefined ('@-', function (ic) { return ic.cursor_pos - 1; });
1141 def_predefined ('@+', function (ic) { return ic.cursor_pos + 1; });
1142 def_predefined ('@[', function (ic) {
1143 if (ic.cursor_pos > 0)
1145 var pos = ic.cursor_pos;
1146 return ic.preedit.FindProp ('candidates', pos - 1).from;
1150 def_predefined ('@]', function (ic) {
1151 if (ic.cursor_pos < ic.preedit.length - 1)
1153 var pos = ic.cursor_pos;
1154 return ic.preedit.FindProp ('candidates', pos).to;
1156 return ic.preedit.length;
1158 for (var i = 0; i < 10; i++)
1159 def_predefined ("@" + i, i);
1160 predefined['@first'] = predefined['@<'];
1161 predefined['@last'] = predefined['@>'];
1162 predefined['@previous'] = predefined['@-'];
1163 predefined['@next'] = predefined['@+'];
1164 predefined['@previous-candidate-change'] = predefined['@['];
1165 predefined['@next-candidate-change'] = predefined['@]'];
1167 MIM.SurroundMarker = function (name)
1170 this.distance = parseInt (name.slice (2));
1171 if (isNaN (this.distance))
1172 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid marker: " + name);
1174 MIM.SurroundMarker.prototype = new MIM.Marker ();
1175 MIM.SurroundMarker.prototype.Position = function (ic)
1177 return ic.cursor_pos + this.distance;
1180 MIM.Marker.prototype.Parser = function (domain, node)
1182 var name = node.firstChild.nodeValue;
1183 if (name.charAt (0) == '@')
1185 var n = predefined[name];
1188 if (name.charAt (1) == '-')
1189 return new MIM.SurroundMarker (name);
1190 throw new Xex.ErrTerm (MIM.Error.ParseError,
1191 "Invalid marker: " + name);
1193 return new MIM.NamedMarker (name);
1197 MIM.Selector = function (name)
1201 MIM.Selector.prototype = new Xex.Term ('selector');
1204 selectors["@<"] = selectors["@first"] = new MIM.Selector ('@<');
1205 selectors["@="] = selectors["@current"] = new MIM.Selector ('@=');
1206 selectors["@>"] = selectors["@last"] = new MIM.Selector ('@>');
1207 selectors["@-"] = selectors["@previous"] = new MIM.Selector ('@-');
1208 selectors["@+"] = selectors["@next"] = new MIM.Selector ('@+');
1209 selectors["@["] = selectors["@previous-candidate-change"]
1210 = new MIM.Selector ('@[');
1211 selectors["@]"] = selectors["@next-candidate-change"]
1212 = new MIM.Selector ('@]');
1214 MIM.Selector.prototype.Parser = function (domain, node)
1216 var name = node.firstChild.nodeValue;
1217 var s = selectors[name];
1219 throw new Xex.ErrTerm (MIM.Error.ParseError,
1220 "Invalid selector: " + name);
1225 MIM.Rule = function (keyseq, actions)
1227 this.keyseq = keyseq;
1228 this.actions = actions;
1230 MIM.Rule.prototype = new Xex.Term ('rule');
1231 MIM.Rule.prototype.Parser = function (domain, node)
1234 for (n = node.firstChild; n && n.nodeType != 1; n = n.nextSibling);
1236 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid rule:" + node);
1237 var keyseq = Xex.ParseTerm (domain, n);
1238 if (keyseq.type != 'keyseq')
1239 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid rule:" + node);
1240 var actions = Xex.ParseTermList (domain, n.nextSibling);
1241 return new MIM.Rule (keyseq, actions);
1243 MIM.Rule.prototype.toString = function ()
1248 MIM.Map = function (name)
1251 this.rules = new Array ();
1254 var proto = new Xex.Term ('map');
1256 proto.Parser = function (domain, node)
1258 var name = node.attributes['mname'].nodeValue;
1260 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map");
1261 var map = new MIM.Map (name);
1262 for (var n = node.firstChild; n; n = n.nextSibling)
1263 if (n.nodeType == 1)
1264 map.rules.push (Xex.ParseTerm (domain, n));
1268 proto.toString = function ()
1270 var str = '<map mname="' + this.name + '">';
1271 var len = this.rules.length;
1272 for (i = 0; i < len; i++)
1273 str += this.rules[i];
1274 return str + '</map>';
1277 MIM.Map.prototype = proto;
1280 Xex.CatchTag._mimtag = new Xex.SymTerm ('@mimtag');
1282 MIM.Action = function (domain, terms)
1284 var args = new Array ();
1285 args.push (Xex.CatchTag_.mimtag);
1286 for (var i = 0; i < terms.length; i++)
1287 args.push (terms[i]);
1288 this.action = Xex.Funcall.prototype.New (domain, 'catch', null, args);
1291 MIM.Action.prototype.Run = function (domain)
1293 var result = this.action.Eval (domain);
1294 if (result.type == 'error')
1296 domain.context.Error = result.toString ();
1299 return (result != Xex.CatchTag._mimtag);
1302 MIM.Keymap = function ()
1305 this.submaps = null;
1306 this.actions = null;
1311 function add_rule (keymap, rule)
1313 var keyseq = rule.keyseq;
1314 var len = keyseq.val.length;
1317 for (var i = 0; i < len; i++)
1319 var key = keyseq.val[i];
1323 if (! keymap.submaps)
1324 keymap.submaps = {};
1326 sub = keymap.submaps[key.key];
1328 keymap.submaps[key.key] = sub = new MIM.Keymap ();
1332 keymap.actions = rule.actions;
1335 proto.Add = function (map)
1337 var rules = map.rules;
1338 var len = rules.length;
1340 for (var i = 0; i < len; i++)
1341 add_rule (this, rules[i]);
1343 proto.Lookup = function (keys, index)
1347 if (index < keys.val.length && this.submaps
1348 && (sub = this.submaps[keys.val[index].key]))
1351 return sub.Lookup (keys, index);
1353 return { map: this, index: index };
1356 MIM.Keymap.prototype = proto;
1359 MIM.State = function (name)
1362 this.keymap = new MIM.Keymap ();
1365 var proto = new Xex.Term ('state');
1367 proto.Parser = function (domain, node)
1369 var map_list = domain.map_list;
1370 var name = node.attributes['sname'].nodeValue;
1372 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map");
1373 var state = new MIM.State (name);
1374 for (node = node.firstChild; node; node = node.nextSibling)
1376 if (node.nodeType != 1)
1378 if (node.nodeName == 'branch')
1380 state.keymap.Add (map_list[node.attributes['mname'].nodeValue]);
1381 state.keymap.actions = Xex.ParseTermList (domain, node.firstChild);
1383 else if (node.nodeName == 'state-hook')
1384 state.enter_actions = Xex.ParseTermList (domain, node.firstChild);
1385 else if (node.nodeName == 'catch-all-branch')
1386 state.fallback_actions = Xex.ParseTermList (domain, node.firstChild);
1387 else if (node.nodeName == 'title')
1388 state.title = node.firstChild.nodeValue;
1393 proto.toString = function ()
1395 return '<state sname="' + this.name + '">' + this.keymap + '</state>';
1398 MIM.State.prototype = proto;
1401 MIM.im_domain = new Xex.Domain ('input-method', null, null);
1402 MIM.im_domain.DefType (MIM.KeySeq.prototype);
1403 MIM.im_domain.DefType (MIM.Marker.prototype);
1404 MIM.im_domain.DefType (MIM.Selector.prototype);
1405 MIM.im_domain.DefType (MIM.Rule.prototype);
1406 MIM.im_domain.DefType (MIM.Map.prototype);
1407 MIM.im_domain.DefType (MIM.State.prototype);
1410 var im_domain = MIM.im_domain;
1412 function Finsert (domain, vari, args)
1415 if (args[0].type == 'integer')
1416 text = String.fromCharCode (args[0].val);
1419 domain.context.insert (text, null);
1422 function Finsert_candidates (domain, vari, args)
1424 var ic = domain.context;
1425 var candidates = new Candidates (args, column);
1426 var candidate = candidates.Current ();
1432 im_domain.DefSubr (Finsert, "insert", false, 1, 1);
1437 parsers['description'] = function (node)
1439 this.description = node.firstChild.nodeValue;
1441 parsers['title'] = function (node)
1443 this.title = node.firstChild.nodeValue;
1445 parsers['map-list'] = function (node)
1447 for (node = node.firstChild; node; node = node.nextSibling)
1449 if (node.nodeType != 1 || node.nodeName != 'map')
1451 var map = Xex.ParseTerm (this.domain, node);
1452 this.map_list[map.name] = map;
1455 parsers['state-list'] = function (node)
1457 this.domain.map_list = this.map_list;
1458 for (node = node.firstChild; node; node = node.nextSibling)
1460 if (node.nodeType != 1 || node.nodeName != 'state')
1462 var state = Xex.ParseTerm (this.domain, node);
1464 state.title = this.title;
1465 if (! this.initial_state)
1466 this.initial_state = state;
1467 this.state_list[state.name] = state;
1469 delete this.domain.map_list;
1472 MIM.IM = function (lang, name, extra_id, file)
1476 this.extra_id = extra_id;
1478 this.load_status = MIM.LoadStatus.NotLoaded;
1479 this.domain = new Xex.Domain (this.lang + '-' + this.name,
1480 MIM.im_domain, null);
1486 var node = Xex.Load (null, this.file);
1489 this.load_status = MIM.LoadStatus.Error;
1493 this.initial_state = null;
1494 this.state_list = {};
1495 for (node = node.firstChild; node; node = node.nextSibling)
1497 if (node.nodeType != 1)
1499 var name = node.nodeName;
1500 var parser = parsers[name];
1502 parser.call (this, node);
1504 this.load_status = MIM.LoadStatus.Loaded;
1509 MIM.IM.prototype = proto;
1511 MIM.IC = function (im)
1513 if (im.load_status == MIM.LoadStatus.NotLoaded)
1515 if (im.load_status != MIM.LoadStatus.Loaded)
1516 alert ('im:' + im.name + ' error:' + im.load_status);
1518 this.domain = new Xex.Domain ('context', im.domain, this);
1524 MIM.CandidateTable = function ()
1526 this.table = new Array ();
1529 MIM.CandidateTable.prototype.get = function (from)
1531 for (var i = 0; i < this.table.length; i++)
1533 var elt = this.table[i];
1534 if (elt.from <= from && elt.to > from)
1539 MIM.CandidateTable.prototype.put = function (from, to, candidates)
1541 for (var i = 0; i < this.table.length; i++)
1543 var elt = this.table[i];
1544 if (elt.from >= from && elt.from < to
1545 || elt.to >= from && elt.to < to)
1549 elt.val = candidates;
1553 this.table.push ({ from: from, to: to, val: candidates });
1556 MIM.CandidateTable.prototype.adjust = function (from, to, inserted)
1558 var diff = inserted - (to - from);
1559 for (var i = 0; i < this.table.length; i++)
1561 var elt = this.table[i];
1570 MIM.CandidateTable.prototype.clear = function ()
1572 this.table.length = 0;
1575 function Block (index, term)
1579 this.Data = term.val;
1580 else if (term.IsList)
1582 this.Data = new Array ();
1583 for (var i = 0; i < term.val.length; i++)
1584 this.Data.push (term.val[i].val);
1588 Block.prototype.Count = function () { return this.Data.length; }
1589 Block.prototype.get = function (i)
1591 return (this.Data instanceof Array ? this.Data[i] : this.Data.charAt (i));
1594 function fill_group (start)
1596 var nitems = this.group.length;
1598 var b = this.blocks[r];
1600 if (start < b.Index)
1601 while (start < b.Index)
1602 b = this.blocks[--r];
1604 while (start >= b.Index + b.Count ())
1605 b = this.blocks[++r];
1608 var count = b.Count ();
1610 for (var i = 0; i < nitems; i++, start++)
1615 if (r == this.blocks.Length)
1621 this.group[i] = b.get (start);
1626 function Candidates (candidates, column)
1628 this.column = column;
1632 this.blocks = new Array ();
1634 for (var i = 0; i < candidates.length; i++)
1636 var block = new Block (this.total, candidates[i]);
1637 this.blocks.push (block);
1638 this.total += block.Count ();
1642 Candidates.prototype.Column = function ()
1644 return (this.column > 0 ? this.index % this.column
1645 : this.index - this.blocks[this.row].Index);
1648 Candidates.prototype.GroupLength = function ()
1650 if (this.column > 0)
1652 var nitems = this.group.length;
1653 var start = this.index - (this.index % nitems);
1654 return (start + this.column <= this.total ? this.column
1655 : this.total - start);
1657 return this.blocks[this.row].Count;
1660 Candidates.prototype.Current = function ()
1662 var b = this.blocks[this.row];
1663 return b.get (this.index - b.Index);
1666 Candidates.prototype.PrevGroup ()
1668 var col = this.Column ();
1670 if (this.column > 0)
1672 this.index -= this.column;
1673 if (this.index >= 0)
1674 nitems = this.column;
1677 var lastcol = (this.total - 1) % this.column;
1678 this.index = (col < lastcol ? this.total - lastcol + col
1680 this.row = this.blocks.length - 1;
1681 nitems = lastcol + 1;
1683 while (this.blocks[this.row].Index > this.index)
1688 this.row = this.row > 0 ? this.row - 1 : this.blocks.length - 1;
1689 nitems = this.blocks[this.row].Count;
1690 this.index = (this.blocks[this.row].Index
1691 + (col < nitems ? col : nitems - 1));
1696 Candidates.prototype.NextGroup = function ()
1698 var col = this.Column ();
1700 if (this.column > 0)
1702 this.index += this.column - col;
1703 if (this.index < this.total)
1705 if (this.index + col >= this.total)
1707 nitems = this.total - this.index;
1708 this.index = this.total - 1;
1712 nitems = this.column;
1721 while (this.blocks[this.row].Index > this.index)
1726 this.row = this.row < this.blocks.length - 1 ? this.row + 1 : 0;
1727 nitems = this.blocks[this.row].Count;
1728 this.index = (this.blocks[this.row].Index
1729 + (col < nitems ? col : nitems - 1));
1734 Candidates.prototype.Prev = function ()
1736 var col = this.Column ();
1740 int nitems = this.PrevGroup ();
1741 this.index += col < nitems - 1 ? col : nitems - 1;
1747 Candidates.prototype.Next = function ()
1749 int col = this.Column ();
1750 int nitems = this.GroupLength ();
1752 if (col == nitems - 1)
1754 nitems = this.NextGroup ();
1755 this.index -= this.Column ();
1761 Candidates.prototype.First = function () { this.index -= this.Column (); }
1763 Candidates.prototype.Last = function ()
1765 this.index += this.GroupLength () - (this.Column + 1);
1768 Candidates.prototype.Select = funciton (selector)
1770 if (selector instanceof MIM.Selector)
1772 switch (selector.val)
1774 case '@<': this.First (); break;
1775 case '@>': this.Last (); break;
1776 case '@-': this.Prev (); break;
1777 case '@+': this.Next (); break;
1778 case '@[': this.PrevGroup (); break;
1779 case '@]': this.NextGroup (); break;
1782 return this.Current ();
1784 var maxcol = this.GroupLength () - 1;
1785 if (selector > maxcol)
1787 this.index = this.index - this.Column () + selector;
1788 return this.Current ();
1791 function detach_candidates (ic)
1793 ic.candidate_table.clear ();
1794 ic.candidates = null;
1795 ic.changed |= (MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos
1796 | ChangedStatus.CandidateList
1797 | ChangedStatus.CandidateIndex
1798 | ChangedStatus.CandidateShow);
1801 function set_cursor (prefix, pos)
1803 this.cursor_pos = pos;
1805 this.candidates = this.candidate_table.get (pos - 1);
1807 this.candidates = null;
1810 function save_state ()
1812 this.state_var_values = this.domain.SaveValues ();
1813 this.state_preedit = this.preedit;
1814 this.state_key_head = this.key_head;
1815 this.state_pos = this.cursor_pos;
1818 function restore_state ()
1820 this.domain.RestoreValues (this.state_var_values);
1821 this.preedit = this.state_preedit;
1822 set_cursor.call (this, "restore", this.state_pos);
1825 function handle_key ()
1827 var out = this.keymap.Lookup (this.keys, this.key_head);
1829 var branch_actions = this.state.keymap.actions;
1831 MIM.log ('handling ' + this.keys.val[this.key_head]
1832 + ' in ' + this.state.name + ':' + this.keymap.name);
1833 this.key_head = out.index;
1834 if (sub != this.keymap)
1837 restore_state.call (this);
1839 MIM.log ('submap found');
1840 if (this.keymap.actions)
1842 MIM.log ('taking map actions:');
1843 if (! this.take_actions (this.keymap.actions))
1846 else if (this.keymap.submaps)
1848 MIM.log ('no map actions');
1849 for (var i = this.state_key_head; i < this.key_head; i++)
1851 MIM.log ('inserting key:' + this.keys.val[i].key);
1852 this.insert (this.keys.val[i].key, null);
1855 if (! this.keymap.submaps)
1857 MIM.log ('terminal:');
1858 if (this.keymap.branch_actions != null)
1860 MIM.log ('branch actions:');
1861 if (! this.take_actions (branch_actions))
1864 if (this.keymap != this.state.keymap)
1865 this.shift (this.state);
1870 MIM.log ('no submap');
1871 var current_state = this.state;
1872 var map = this.keymap;
1876 MIM.log ('branch actions');
1877 if (! this.take_actions (this.keymap.branch_actions))
1881 if (map == this.keymap)
1883 MIM.log ('no state change');
1884 if (map == this.initial_state.keymap
1885 && this.key_head < this.keys.val.length)
1887 MIM.log ('unhandled');
1890 if (this.keymap != current_state.keymap)
1891 this.shift (current_state);
1892 else if (this.keymap.actions == null)
1893 this.shift (this.initial_state);
1902 this.produced = null;
1904 this.preedit_saved = '';
1905 this.cursor_pos = 0;
1906 this.marker_positions = {};
1907 this.candidates = null;
1908 this.candidate_show = false;
1910 this.prev_state = null;
1911 this.initial_state = this.im.initial_state;
1912 this.title = this.initial_state.title;
1913 this.state_preedit = '';
1914 this.state_key_head = 0;
1915 this.state_var_values = {};
1918 this.keys = new MIM.KeySeq ();
1920 this.key_unhandled = false;
1921 this.unhandled_key = null;
1922 this.changed = MIM.ChangedStatus.None;
1923 this.error_message = '';
1924 this.title = this.initial_state.title;
1927 this.preedit_saved = '';
1928 this.marker_positions = {};
1929 this.candidate_table = new MIM.CandidateTable ();
1930 this.candidates = null;
1931 this.candidate_show = false;
1932 this.shift (this.initial_state);
1935 catch_args: new Array (Xex.CatchTag._mimtag, null),
1937 take_actions: function (actions)
1939 var func_progn = this.domain.GetFunc ('progn');
1940 var func_catch = this.domain.GetFunc ('catch');
1941 this.catch_args[1] = new Xex.Funcall (func_progn, null, actions);
1942 var term = new Xex.Funcall (func_catch, null, this.catch_args);
1943 term = term.Eval (this.domain);
1944 return (! term.IsSymbol || term.val != '@mimtag');
1947 GetSurroundingChar: function (pos)
1949 if (pos < 0 ? this.caret_pos < - pos : this.target.value.length < pos)
1951 return this.target.value.charCodeAt (this.caret_pos + pos);
1954 adjust_markers: function (from, to, inserted)
1956 var diff = inserted - (to - from);
1958 for (var m in this.marker_positions)
1959 if (this.marker_positions[m] > from)
1960 this.marker_positions[m] = (this.marker_positions[m] >= to
1961 ? pos + diff : from);
1962 if (this.cursor_pos >= to)
1963 set_cursor.call (this, 'adjust', this.cursor_pos + diff);
1964 else if (this.cursor_pos > from)
1965 set_cursor.call (this, 'adjust', from)
1968 preedit_replace: function (from, to, text, candidates)
1970 this.preedit = (this.preedit.substring (0, from)
1971 + text + this.preedit.substring (to));
1972 this.adjust_markers (from, to, text.length);
1973 this.candidate_table.adjust (from, to, text.length);
1975 this.candidate_table.put (from, from + text.length, candidates)
1978 insert: function (text, candidates)
1980 this.preedit_replace (this.cursor_pos, this.cursor_pos, text, candidates);
1981 this.changed = MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos;
1988 this.DelSurroundText (pos);
1991 else if (pos > this.preedit.length)
1993 this.DelSurroundText (pos - this.preedit.length);
1994 pos = this.preedit.length;
1996 if (pos < this.cursor_pos)
1997 this.preedit = (this.predit.substring (0, pos)
1998 + this.preedit.substring (this.cursor_pos));
2000 this.preedit = (this.preedit.substring (0, this.cursor_pos)
2001 + this.predit.substring (pos));
2006 this.candidate_show = true;
2007 this.changed |= MIM.ChangedStatus.CandidateShow;
2012 this.candidate_show = false;
2013 this.changed |= MIM.ChangedStatus.CandidateShow;
2016 move: function (pos)
2020 else if (pos > this.preedit.length)
2021 pos = this.preedit.length;
2022 if (pos != this.cursor_pos)
2024 set_cursor.call (this, 'move', pos);
2025 this.changed |= MIM.ChangedStatus.Preedit;
2029 pushback: function (n)
2031 if (n instanceof MIM.KeySeq)
2033 if (this.key_head > 0)
2035 if (this.key_head < this.keys.val.length)
2036 this.keys.val.splice (this.key_head,
2037 this.keys.val.length - this.key_head);
2038 for (var i = 0; i < n.val.length; i++)
2039 this.keys.val.push (n.val[i]);
2045 if (this.key_head < 0)
2052 this.key_head = - n;
2053 if (this.key_head > this.keys.val.length)
2054 this.key_head = this.keys.val.length;
2060 if (this.key_head < this.keys.val.length)
2061 this.keys.val.splice (this.key_head, 1);
2066 if (this.preedit.length > 0)
2068 this.candidate_table.clear ();
2069 this.produced += this.preedit;
2070 this.preedit_replace.call (this, 0, this.preedit.length, '', null);
2074 shift: function (state)
2078 MIM.log ("shifting back to previous");
2079 if (this.prev_state == null)
2081 state = this.prev_state;
2084 MIM.log ("shifting to " + state.name);
2086 if (state == this.initial_state)
2091 this.keys.val.splice (0, this.key_head);
2093 this.prev_state = null;
2098 if (state != this.state)
2099 this.prev_state = this.state;
2101 if (state != this.state && state.enter_actions)
2102 take_actions.call (state.enter_actions);
2103 if (! this.state || this.state.title != state.title)
2104 this.changed |= MIM.ChangedStatus.StateTitle;
2106 this.keymap = state.keymap;
2107 this.state_key_head = this.key_head;
2108 save_state.call (this);
2111 Filter: function (key)
2115 this.key_unhandled = true;
2116 this.unhandled_key = key;
2119 if (key.key == '_reload')
2121 this.changed = MIM.ChangedStatus.None;
2123 this.key_unhandled = false;
2124 this.keys.val.push (key);
2126 while (this.key_head < this.keys.val.length)
2128 if (! handle_key.call (this))
2130 if (this.key_head < this.keys.val.length)
2132 this.unhandled_key = this.keys.val[this.key_head];
2133 this.keys.val.splice (this.key_head, this.key_head + 1);
2135 this.key_unhandled = true;
2141 this.key_unhandled = true;
2145 if (this.key_unhandled)
2147 this.keys.val.length = 0;
2148 this.key_head = this.state_key_head = this.commit_key_head = 0;
2150 return (! this.key_unhandled
2151 && this.produced.length == 0
2152 && this.preedit.length == 0);
2156 MIM.IC.prototype = proto;
2158 var node = Xex.Load (null, "imlist.xml");
2159 for (node = node.firstChild; node; node = node.nextSibling)
2160 if (node.nodeName == 'input-method')
2162 var lang, name, extra_id, file;
2164 for (var n = node.firstChild; n; n = n.nextSibling)
2166 if (n.nodeName == 'language')
2167 lang = n.firstChild.nodeValue;
2168 else if (n.nodeName == 'name')
2169 name = n.firstChild.nodeValue;
2170 else if (n.nodeName == 'extra-id')
2171 extra_id = n.firstChild.nodeValue;
2172 else if (n.nodeName == 'filename')
2173 file = n.firstChild.nodeValue;
2175 if (! MIM.im_list[lang])
2176 MIM.im_list[lang] = {};
2177 MIM.im_list[lang][name] = new MIM.IM (lang, name, extra_id, file);
2183 var keys = new Array ();
2185 keys[0x08] = 'backspace';
2186 keys[0x0D] = 'return';
2187 keys[0x1B] = 'escape';
2188 keys[0x20] = 'space';
2189 keys[0x21] = 'pageup';
2190 keys[0x22] = 'pagedown';
2192 keys[0x24] = 'home';
2193 keys[0x25] = 'left';
2195 keys[0x27] = 'right';
2196 keys[0x28] = 'down';
2197 keys[0x2D] = 'insert';
2198 keys[0x2E] = 'delete';
2199 for (var i = 1; i <= 12; i++)
2200 keys[111 + i] = "f" + i;
2201 keys[0x90] = "numlock";
2202 keys[0xF0] = "capslock";
2204 MIM.decode_key_event = function (event)
2206 var key = ((event.type == 'keydown' || event.keyCode) ? event.keyCode
2207 : event.charCode ? event.charCode
2211 if (event.type == 'keydown')
2216 if (event.shiftKey) key = "S-" + key ;
2219 key = String.fromCharCode (key);
2220 if (event.altKey) key = "A-" + key ;
2221 if (event.ctrlKey) key = "C-" + key ;
2222 return new MIM.Key (key);
2226 MIM.add_event_listener
2227 = (window.addEventListener
2228 ? function (target, type, listener) {
2229 target.addEventListener (type, listener, false);
2231 : window.attachEvent
2232 ? function (target, type, listener) {
2233 target.attachEvent ('on' + type,
2235 listener.call (target, window.event);
2238 : function (target, type, listener) {
2240 = function (e) { listener.call (target, e || window.event); };
2243 MIM.log = function (msg)
2245 var node = document.getElementById ('log');
2246 node.value = msg + "\n" + node.value;
2249 MIM.debug_print = function (event, ic)
2253 if (! MIM.debug_nodes)
2255 MIM.debug_nodes = new Array ();
2256 MIM.debug_nodes['keydown'] = document.getElementById ('keydown');
2257 MIM.debug_nodes['keypress'] = document.getElementById ('keypress');
2258 MIM.debug_nodes['status0'] = document.getElementById ('status0');
2259 MIM.debug_nodes['status1'] = document.getElementById ('status1');
2260 MIM.debug_nodes['keymap0'] = document.getElementById ('keymap0');
2261 MIM.debug_nodes['keymap1'] = document.getElementById ('keymap1');
2262 MIM.debug_nodes['preedit0'] = document.getElementById ('preedit0');
2263 MIM.debug_nodes['preedit1'] = document.getElementById ('preedit1');
2265 var target = event.target;
2266 var code = event.keyCode;
2267 var ch = event.type == 'keydown' ? 0 : event.charCode;
2268 var key = MIM.decode_key_event (event);
2271 MIM.debug_nodes[event.type].innerHTML = "" + code + "/" + ch + " : " + key;
2272 index = (event.type == 'keydown' ? '0' : '1');
2274 MIM.debug_nodes['status' + index].innerHTML = ic.im.load_status;
2276 MIM.debug_nodes['status' + index].innerHTML = 'no IM';
2277 MIM.debug_nodes['keymap' + index].innerHTML = ic.keymap.name;
2278 MIM.debug_nodes['preedit' + index].innerHTML = ic.preedit;
2281 MIM.get_range = function (target, range)
2283 if (target.selectionStart != null) // for Mozilla
2285 range[0] = target.selectionStart;
2286 range[1] = target.selectionEnd;
2290 var r = document.selection.createRange ();
2291 var rr = r.duplicate ();
2293 rr.moveToElementText (target);
2294 rr.setEndPoint ('EndToEnd', range);
2295 range[0] = rr.text.length - r.text.length;
2296 range[1] = rr.text.length;
2300 MIM.set_caret = function (target, ic)
2302 if (target.setSelectionRange) // Mozilla
2304 var scrollTop = target.scrollTop;
2305 target.setSelectionRange (ic.spot, ic.spot + ic.preedit.length);
2306 target.scrollTop = scrollTop;
2310 var range = target.createTextRange ();
2311 range.moveStart ('character', ic.spot);
2312 range.moveEnd ('character', ic.spot + ic.preedit.length);
2318 var range = new Array ();
2320 MIM.check_range = function (target, ic)
2322 MIM.get_range (target, range);
2323 if (range[0] != ic.spot || range[1] - range[0] != ic.preedit.length
2324 || target.value.substring (range[0], range[1]) != ic.preedit)
2326 MIM.log ('reset:' + ic.spot + '-' + (ic.spot + ic.preedit.length)
2327 + '/' + range[0] + '-' + range[1]);
2330 target.value = (target.value.substring (0, range[0])
2331 + target.value.substring (range[1]));
2336 MIM.update = function (target, ic)
2338 var text = target.value;
2339 target.value = (text.substring (0, ic.spot)
2342 + text.substring (ic.spot));
2343 ic.spot += ic.produced.length;
2344 MIM.set_caret (target, ic);
2347 MIM.reset_ic = function (event)
2349 if (event.target.mim_ic)
2351 var ic = event.target.mim_ic;
2352 var pos = ic.spot + ic.preedit.length;
2355 event.target.setSelectionRange (pos, pos);
2359 MIM.keydown = function (event)
2361 var target = event.target;
2362 if (! (target.type == "text" || target.type == "textarea"))
2365 var ic = target.mim_ic;
2366 if (! ic || ic.im != MIM.current)
2368 MIM.log ('creating IC');
2369 ic = new MIM.IC (MIM.current);
2371 MIM.add_event_listener (target, 'blur', MIM.reset_ic);
2373 if (ic.im.load_status != MIM.LoadStatus.Loaded)
2375 MIM.check_range (target, ic);
2376 MIM.debug_print (event, ic);
2377 ic.key = MIM.decode_key_event (event);
2380 MIM.keypress = function (event)
2382 if (! (event.target.type == "text" || event.target.type == "textarea"))
2385 var ic = event.target.mim_ic;
2389 if (ic.im.load_status != MIM.LoadStatus.Loaded)
2392 ic.key = MIM.decode_key_event (event);
2399 MIM.log ("filtering " + ic.key);
2400 var result = ic.Filter (ic.key);
2401 MIM.update (event.target, ic);
2402 if (! ic.key_unhandled)
2403 event.preventDefault ();
2405 MIM.debug_print (event, ic);
2410 MIM.select_im = function (event)
2412 var target = event.target.parentNode;
2413 while (target.tagName != "SELECT")
2414 target = target.parentNode;
2417 for (var lang in MIM.im_list)
2418 for (var name in MIM.im_list[lang])
2419 if (idx++ == target.selectedIndex)
2421 im = MIM.im_list[lang][name];
2424 document.getElementsByTagName ('body')[0].removeChild (target);
2425 target.target.focus ();
2426 if (im && im != MIM.current)
2429 MIM.log ('select IM: ' + im.name);
2433 MIM.destroy_menu = function (event)
2435 if (event.target.tagName == "SELECT")
2436 document.getElementsByTagName ('body')[0].removeChild (event.target);
2439 MIM.select_menu = function (event)
2441 var target = event.target;
2443 if (! ((target.type == "text" || target.type == "textarea")
2444 && event.which == 1 && event.ctrlKey))
2447 var sel = document.createElement ('select');
2448 sel.onclick = MIM.select_im;
2449 sel.onmouseout = MIM.destroy_menu;
2450 sel.style.position='absolute';
2451 sel.style.left = (event.clientX - 10) + "px";
2452 sel.style.top = (event.clientY - 10) + "px";
2453 sel.target = target;
2455 for (var lang in MIM.im_list)
2456 for (var name in MIM.im_list[lang])
2458 var option = document.createElement ('option');
2459 var imname = lang + "-" + name;
2460 option.appendChild (document.createTextNode (imname));
2461 option.value = imname;
2462 sel.appendChild (option);
2463 if (MIM.im_list[lang][name] == MIM.current)
2464 sel.selectedIndex = idx;
2468 document.getElementsByTagName ('body')[0].appendChild (sel);
2471 MIM.test = function ()
2473 var im = MIM.im_list['t']['latn-post'];
2474 var ic = new MIM.IC (im);
2476 ic.Filter (new MIM.Key ('a'));
2477 ic.Filter (new MIM.Key ("'"));
2480 document.getElementById ('text').value = ic.produced + ic.preedit;
2483 document.getElementById ('text').value
2484 = Xex.ParseTerm (domain, body).Eval (domain).toString ();
2486 if (e instanceof Xex.ErrTerm)
2494 MIM.init = function ()
2496 MIM.add_event_listener (window, 'keydown', MIM.keydown);
2497 MIM.add_event_listener (window, 'keypress', MIM.keypress);
2498 MIM.add_event_listener (window, 'mousedown', MIM.select_menu);
2499 if (window.location == 'http://localhost/mim/index.html')
2500 MIM.server = 'http://localhost/mim';
2501 MIM.current = MIM.im_list['vi']['telex'];
2504 MIM.init_debug = function ()