X-Git-Url: http://git.chise.org/gitweb/?p=m17n%2Fm17n-lib-js.git;a=blobdiff_plain;f=xex.js;h=e5f9c84673edc845a6ab9f91d85b09459a03f2e9;hp=e97c17edbfa6ef220fba125e0efb47a98a7904e4;hb=d64052eb9999afb5618be26c44d033cc8ce33c54;hpb=983c711cb17bf83071915faabaff92698ff1e0e2 diff --git a/xex.js b/xex.js index e97c17e..e5f9c84 100644 --- a/xex.js +++ b/xex.js @@ -1,24 +1,102 @@ -// -* coding: utf-8; -* +// xex.js -- Xex (XML Expression) interpreter +// Copyright (C) 2010 +// National Institute of Advanced Industrial Science and Technology (AIST) +// Registration Number H15PRO112 + +// This file is part of the m17n database; a sub-part of the m17n +// library. + +// The m17n library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. + +// The m17n library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. + +// You should have received a copy of the GNU Lesser General Public +// License along with the m17n library; if not, write to the Free +// Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301, USA. + +// Please note that the code is not yet matured. + +var Xex = {}; + +(function () { // Logging + // The logging node containing tracing information. + var log = null; + // Number of lines. + var lines; + // Style properties of the logging node. + var styles = { border: '1px solid black', + font: 'normal normal normal small monospace', + width: '100%', + minHeight: '300px', + maxHeight: '300px', + overflow: 'auto' }; + + // Toggle logging on and off. PARENT if non-null specifies the + // parent of the log node. The log node is appended to PARENT. + // If PARENT is null, 'body' node is assumed. + Xex.LogToggle = function (parent) + { + if (log) + { + log.parentNode.removeChild (log); + log = null; + return; + } + if (! parent) + parent = document.getElementsByTagName ('body')[0]; + log = document.createElement ('ol'); + for (var prop in styles) + log.style[prop] = styles[prop]; + parent.appendChild (log); + lines = 0; + return log; + } -var Xex = { - LogNode: null, - Log: function (arg, indent) + // Log ARG (string). INDENT if specified is a number of columns to + // indent. If INDENT is -1, ARG is appended to the last log. + Xex.Log = function (arg, indent) { - if (! Xex.LogNode) + if (! log) return; if (! arg) - Xex.LogNode.value = ''; + { + while (log.childNodes.length > 0) + log.removeChild (log.firstChild); + lines = 0; + } else { - var str = ''; - if (indent != undefined) - for (var i = 0; i <= indent; i++) - str += ' '; - Xex.LogNode.value += "\n" + str + arg; - Xex.LogNode.scrollTop = Xex.LogNode.scrollHeight; + var node; + if (indent == -1) + log.lastChild.innerText += arg; + else + { + lines++; + if (lines >= 256) + { + node = log.firstElement (); + log.start = lines - 254; + } + else + node = document.createElement ('li'); + if (indent != undefined) + node.style.textIndent = (indent + 1) + 'em'; + else + node.style.textIndent = '0px'; + node.innerText = arg; + log.appendChild (node); + log.scrollTop = log.scrollHeight; + } } } -}; +}) (); Xex.Error = { UnknownError: "unknown-error", @@ -46,32 +124,34 @@ Xex.Error = { UncaughtThrow: "uncaught-throw" }; -Xex.Variable = function (domain, name, desc, val, range) +Xex.Variable = function (name, desc, val, range) { - this.domain = domain; - this.name = name; - this.desc = desc; + if (name) + this.name = name; + if (desc) + this.desc = desc; this.val = val; - this.range = range; + if (range) + this.range = range; } -Xex.Variable.prototype.clone = function () -{ - return new Xex.Variable (this.domain, this.name, this.desc, - this.val, this.range); -} - -Xex.Variable.prototype.Equals = function (obj) -{ - return ((obj instanceof Xex.Variable) - && obj.name == this.name); -} +Xex.Variable.prototype = { + clone: function () + { + return new Xex.Variable (this.name, this.desc, this.val, this.range); + }, + equals: function (obj) + { + return ((obj instanceof Xex.Variable) + && obj.name == this.name); + }, + SetValue: function (term) + { + this.val = term; + return term; + } +} -Xex.Variable.prototype.SetValue = function (term) -{ - this.val = term; - return term; -} Xex.Function = function (name, with_var, min_args, max_args) { @@ -83,10 +163,7 @@ Xex.Function = function (name, with_var, min_args, max_args) Xex.Subrountine = function (builtin, name, with_var, min_args, max_args) { - this.name = name; - this.with_var = with_var; - this.min_args = min_args; - this.max_args = max_args; + Xex.Function.apply (this, [name, with_var, min_args, max_args]); this.builtin = builtin; } @@ -104,10 +181,7 @@ Xex.Subrountine.prototype.Call = function (domain, vari, args) Xex.SpecialForm = function (builtin, name, with_var, min_args, max_args) { - this.name = name; - this.with_var = with_var; - this.min_args = min_args; - this.max_args = max_args; + Xex.Function.apply (this, [name, with_var, min_args, max_args]); this.builtin = builtin; } @@ -118,9 +192,7 @@ Xex.SpecialForm.prototype.Call = function (domain, vari, args) Xex.Lambda = function (name, min_args, max_args, args, body) { - this.name = name; - this.min_args = min_args; - this.max_args = max_args; + Xex.Function.apply (this, [name, false, min_args, max_args]); this.args = args; this.body = body; } @@ -171,9 +243,7 @@ Xex.Lambda.prototype.Call = function (domain, vari, args) Xex.Macro = function (name, min_args, max_args, args, body) { - this.name = name; - this.min_args = min_args; - this.max_args = max_args; + Xex.Function.apply (this, [name, false, min_args, max_args]); this.args = args; this.body = body; } @@ -252,7 +322,7 @@ Xex.Domain = function (name, parent, context) for (elt in parent.variables) { var vari = parent.variables[elt]; - this.variables[elt] = new Xex.Variable (this, vari.name, vari.desc, + this.variables[elt] = new Xex.Variable (vari.name, vari.desc, vari.val, vari.range); } } @@ -374,7 +444,7 @@ Xex.Domain.prototype = { }, Defvar: function (name, desc, val, range) { - var vari = new Xex.Variable (this, name, desc, val, range); + var vari = new Xex.Variable (name, desc, val, range); this.variables[name] = vari; return vari; }, @@ -401,7 +471,7 @@ Xex.Domain.prototype = { { var vari = this.variables[name]; if (! vari) - vari = this.variables[name] = new Xex.Variable (this, name, null, + vari = this.variables[name] = new Xex.Variable (name, null, Xex.Zero, null); return vari; }, @@ -429,13 +499,13 @@ Xex.Term.prototype = { IsTrue: function () { return true; }, Eval: function (domain) { return this.Clone (); }, Clone: function (domain) { return this; }, - Equals: function (obj) + equals: function (obj) { return (this.type == obj.type - && this.val + && this.val != undefined && obj.val == this.val); }, - Matches: function (obj) { return this.Equals (obj); }, + Matches: function (obj) { return this.equals (obj); }, toString: function () { if (this.val != undefined) @@ -471,7 +541,7 @@ Node.prototype.nextElement = function () if (! name) throw new Xex.ErrTerm (Xex.Error.NoVariableName, node, ''); var vari = domain.variables[name]; - var desc, val, range; + var desc, val = null, range; if (vari) { desc = vari.description; @@ -519,7 +589,7 @@ Node.prototype.nextElement = function () range.push (pval); } } - if (! val) + if (val == null) val = Xex.Zero; domain.Defvar (name, desc, val, range); return name; @@ -685,8 +755,7 @@ Xex.Funcall = function (func, vname, args) proto.Eval = function (domain) { - if (! (this.func instanceof Xex.Subrountine)) - Xex.Log (this, domain.depth); + Xex.Log (this, domain.depth); var vari; if (this.vname) vari = domain.GetVarCreate (this.vname); @@ -695,7 +764,8 @@ Xex.Funcall = function (func, vname, args) try { result = this.func.Call (domain, vari, this.args); } finally { - Xex.Log (this + ' => ' + result, --domain.depth); + Xex.Log (' => ' + result, --domain.depth, + this.func instanceof Xex.Subrountine); } return result; } @@ -705,11 +775,11 @@ Xex.Funcall = function (func, vname, args) return new Xex.Funcall (this.func, this.vari, this.args); } - proto.Equals = function (obj) + proto.equals = function (obj) { return (obj.type == 'funcall' && obj.func == this.func - && obj.vari.Equals (this.vari) + && obj.vari.equals (this.vari) && obj.args.length == this.func.length); } @@ -718,8 +788,8 @@ Xex.Funcall = function (func, vname, args) var arglist = '' var len = this.args.length; var str = '<' + this.func.name; - if (this.vari) - str += ' vname="' + this.vari.name + '"'; + if (this.vname) + str += ' vname="' + this.vname + '"'; if (len == 0) return str + '/>'; if (this.func instanceof Xex.Subrountine) @@ -761,7 +831,7 @@ Xex.ErrTerm = function (ename, message, stack) return new Xex.ErrTerm (ename, message, false); } - proto.Equals = function (obj) + proto.equals = function (obj) { return (obj.IsError && obj.ename == ename && obj.message == message @@ -834,13 +904,13 @@ Xex.LstTerm = function (list) { this.val = list; }; proto.IsTrue = function () { return this.val.length > 0; } proto.Clone = function () { return new Xex.LstTerm (this.val.slice (0)); } - proto.Equals = function (obj) + proto.equals = function (obj) { if (obj.type != 'list' || obj.val.length != this.val.length) return false; var i, len = this.val.length; for (i = 0; i < len; i++) - if (! this.val[i].Equals (obj.val[i])) + if (! this.val[i].equals (obj.val[i])) return false; return true; } @@ -904,7 +974,7 @@ Xex.LstTerm = function (list) { this.val = list; }; { var n = vari ? vari.val.Intval () : 1; for (var i = 0; i < args.length; i++) - n *= arg.Intval (); + n *= args[i].Intval (); return maybe_set_intvar (vari, n); } @@ -1023,7 +1093,7 @@ Xex.LstTerm = function (list) { this.val = list; }; function Feq (domain, vari, args) { for (var i = 1; i < args.length; i++) - if (! args[i - 1].Equals (args[i])) + if (! args[i - 1].equals (args[i])) return Xex.Zero; return Xex.One; } @@ -1076,7 +1146,7 @@ Xex.LstTerm = function (list) { this.val = list; }; function Fge (domain, vari, args) { var n = args[0].Intval (); - for (var i = 1; i < args.Length; i++) + for (var i = 1; i < args.length; i++) { var n1 = args[i].Intval (); if (n < n1) @@ -1109,7 +1179,7 @@ Xex.LstTerm = function (list) { this.val = list; }; if (result.IsTrue ()) return args[1].Eval (domain); if (args.length == 2) - return Zero; + return Xex.Zero; return args[2].Eval (domain); } @@ -1288,2278 +1358,31 @@ Xex.Load = function (server, file) obj.open ('GET', url, false); obj.overrideMimeType ('text/xml'); obj.send (''); - return obj.responseXML.firstChild; -} - -var MIM = { - // URL of the input method server. - server: "http://www.m17n.org/common/mim-js", - // Boolean flag to tell if MIM is active or not. - enabled: true, - // Boolean flag to tell if MIM is running in debug mode or not. - debug: false, - // List of main input methods. - imlist: {}, - // List of extra input methods; - imextra: {}, - // Global input method data - im_global: null, - // Currently selected input method. - current: false, - - // enum - LoadStatus: { NotLoaded:0, Loading:1, Loaded:2, Error:-1 }, - ChangedStatus: { - None: 0x00, - StateTitle: 0x01, - PreeditText:0x02, - CursorPos: 0x04, - CandidateList:0x08, - CandidateIndex:0x10, - CandidateShow:0x20, - Preedit: 0x06, // PreeditText | CursorPos - Candidate: 0x38 // CandidateList | CandidateIndex | CandidateShow - }, - KeyModifier: { - SL: 0x00400000, - SR: 0x00800000, - S: 0x00C00000, - CL: 0x01000000, - CR: 0x02000000, - C: 0x03000000, - AL: 0x04000000, - AR: 0x08000000, - A: 0x0C000000, - ML: 0x04000000, - MR: 0x08000000, - M: 0x0C000000, - G: 0x10000000, - s: 0x20000000, - H: 0x40000000, - High: 0x70000000, - All: 0x7FC00000 - }, - Error: { - ParseError: "parse-error" - } -}; - -(function () { - var keysyms = new Array (); - keysyms["bs"] = "backspace"; - keysyms["lf"] = "linefeed"; - keysyms["cr"] = keysyms["enter"] = "return"; - keysyms["esc"] = "escape"; - keysyms["spc"] = "space"; - keysyms["del"] = "delete"; - - function decode_keysym (str) { - if (str.length == 1) - return str; - var parts = str.split ("-"); - var len = parts.length, i; - var has_modifier = len > 1; - - for (i = 0; i < len - 1; i++) - if (! MIM.KeyModifier.hasOwnProperty (parts[i])) - return false; - var key = parts[len - 1]; - if (key.length > 1) - { - key = keysyms[key.toLowerCase ()]; - if (key) - { - if (len > 1) - { - str = parts[0]; - for (i = 1; i < len - 1; i++) - str += '-' + parts[i]; - str += '-' + key; - } - else - str = key; - } - } - if (has_modifier) - { - parts = new Array (); - parts.push (str); - return parts; - } - return str; - } - - MIM.Key = function (val) - { - this.key; - if (val instanceof Xex.Term) - this.key = val.val; - else if (typeof val == 'string' || val instanceof String) - { - this.key = decode_keysym (val); - if (! this.key) - throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + val); - if (this.key instanceof Array) - { - this.key = this.key[0]; - this.has_modifier = true; - } - } - else if (typeof val == 'number' || val instanceof Number) - this.key = String.fromCharCode (val); - else - throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + val); - } - - MIM.Key.prototype.toString = function () { return this.key; }; - - MIM.Key.FocusIn = new MIM.Key (new Xex.StrTerm ('input-focus-in')); - MIM.Key.FocusOut = new MIM.Key (new Xex.StrTerm ('input-focus-out')); - MIM.Key.FocusMove = new MIM.Key (new Xex.StrTerm ('input-focus-move')); -}) (); - -(function () { - MIM.KeySeq = function (seq) - { - this.val = new Array (); - - if (seq) - { - if (seq.IsList) - { - var len = seq.val.length; - for (var i = 0; i < len; i++) - { - var v = seq.val[i], key; - if (v.type == 'symbol' || v.type == 'string') - key = new MIM.Key (v); - else if (v.type == 'integer') - key = new MIM.Key (v.val); - else - throw new Xex.ErrTerm (MIM.Error.ParseError, - "Invalid key: " + v); - this.val.push (key); - if (key.has_modifier) - this.has_modifier = true; - } - } - else if (seq.IsStr) - { - var len = seq.val.length; - for (var i = 0; i < len; i++) - this.val.push (new MIM.Key (seq.val.charCodeAt (i))); - } - else - throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + seq); - } - } - - var proto = new Xex.Term ('keyseq'); - proto.Clone = function () { return this; } - proto.Parser = function (domain, node) - { - var seq = new Array (); - for (node = node.firstChild; node; node = node.nextSibling) - if (node.nodeType == 1) - { - var term = Xex.Term.Parse (domain, node); - return new MIM.KeySeq (term); - } - throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid keyseq"); - } - proto.toString = function () - { - var len = this.val.length; - if (len == 0) - return ''; - var first = true; - var str = ''; - for (var i = 0; i < len; i++) - { - if (first) - first = false; - else if (this.has_modifier) - str += ' '; - str += this.val[i].toString (); - } - return str + ''; - } - - MIM.KeySeq.prototype = proto; -}) (); - -(function () { - MIM.Marker = function () { } - MIM.Marker.prototype = new Xex.Term ('marker'); - MIM.Marker.prototype.CharAt = function (ic) - { - var p = this.Position (ic); - if (p < 0 || p >= ic.preedit.length) - return 0; - return ic.preedit.charCodeAt (p); - } - - MIM.FloatingMarker = function (name) { this.val = name; }; - var proto = new MIM.Marker (); - MIM.FloatingMarker.prototype = proto; - proto.Position = function (ic) { return ic.marker_positions[this.val]; }; - proto.Mark = function (ic) { ic.marker_positions[this.val] = ic.cursor_pos; }; - - MIM.PredefinedMarker = function (name) { this.val = name; } - MIM.PredefinedMarker.prototype = new MIM.Marker (); - MIM.PredefinedMarker.prototype.Position = function (ic) - { - if (typeof this.pos == 'number') - return this.pos; - return this.pos (ic); - } - - var predefined = { } - - function def_predefined (name, position) - { - predefined[name] = new MIM.PredefinedMarker (name); - predefined[name].pos = position; - } - - def_predefined ('@<', 0); - def_predefined ('@>', function (ic) { return ic.preedit.length; }); - def_predefined ('@-', function (ic) { return ic.cursor_pos - 1; }); - def_predefined ('@+', function (ic) { return ic.cursor_pos + 1; }); - def_predefined ('@[', function (ic) { - if (ic.cursor_pos > 0) - { - var pos = ic.cursor_pos; - return ic.preedit.FindProp ('candidates', pos - 1).from; - } - return 0; - }); - def_predefined ('@]', function (ic) { - if (ic.cursor_pos < ic.preedit.length - 1) - { - var pos = ic.cursor_pos; - return ic.preedit.FindProp ('candidates', pos).to; - } - return ic.preedit.length; - }); - for (var i = 0; i < 10; i++) - def_predefined ("@" + i, i); - predefined['@first'] = predefined['@<']; - predefined['@last'] = predefined['@>']; - predefined['@previous'] = predefined['@-']; - predefined['@next'] = predefined['@+']; - predefined['@previous-candidate-change'] = predefined['@[']; - predefined['@next-candidate-change'] = predefined['@]']; - - MIM.SurroundMarker = function (name) - { - this.val = name; - this.distance = parseInt (name.slice (1)); - if (isNaN (this.distance)) - throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid marker: " + name); - } - MIM.SurroundMarker.prototype = new MIM.Marker (); - MIM.SurroundMarker.prototype.Position = function (ic) - { - return ic.cursor_pos + this.distance; - } - MIM.SurroundMarker.prototype.CharAt = function (ic) - { - if (this.val == '@-0') - return -1; - var p = this.Position (ic); - if (p < 0) - return ic.GetSurroundingChar (p); - else if (p >= ic.preedit.length) - return ic.GetSurroundingChar (p - ic.preedit.length); - return ic.preedit.charCodeAt (p); - } - - MIM.Marker.prototype.Parser = function (domain, node) - { - var name = node.firstChild.nodeValue; - if (name.charAt (0) == '@') - { - var n = predefined[name]; - if (n) - return n; - if (name.charAt (1) == '-' || name.charAt (1) == '+') - return new MIM.SurroundMarker (name); - throw new Xex.ErrTerm (MIM.Error.ParseError, - "Invalid marker: " + name); - } - return new MIM.FloatingMarker (name);; - } -}) (); - -MIM.Selector = function (name) -{ - this.val = name; -} -MIM.Selector.prototype = new Xex.Term ('selector'); - -(function () { - var selectors = {}; - selectors["@<"] = selectors["@first"] = new MIM.Selector ('@<'); - selectors["@="] = selectors["@current"] = new MIM.Selector ('@='); - selectors["@>"] = selectors["@last"] = new MIM.Selector ('@>'); - selectors["@-"] = selectors["@previous"] = new MIM.Selector ('@-'); - selectors["@+"] = selectors["@next"] = new MIM.Selector ('@+'); - selectors["@["] = selectors["@previous-candidate-change"] - = new MIM.Selector ('@['); - selectors["@]"] = selectors["@next-candidate-change"] - = new MIM.Selector ('@]'); - - MIM.Selector.prototype.Parser = function (domain, node) - { - var name = node.firstChild.nodeValue; - var s = selectors[name]; - if (! s) - throw new Xex.ErrTerm (MIM.Error.ParseError, - "Invalid selector: " + name); - return s; - } -}) (); - -MIM.Rule = function (keyseq, actions) -{ - this.keyseq = keyseq; - this.actions = actions; -} -MIM.Rule.prototype = new Xex.Term ('rule'); -MIM.Rule.prototype.Parser = function (domain, node) -{ - var n; - for (n = node.firstChild; n && n.nodeType != 1; n = n.nextSibling); - if (! n) - throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid rule:" + node); - var keyseq = Xex.Term.Parse (domain, n); - if (keyseq.type != 'keyseq') - throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid rule:" + node); - var actions = Xex.Term.Parse (domain, n.nextElement (), null); - return new MIM.Rule (keyseq, actions); -} -MIM.Rule.prototype.toString = function () -{ - return ''; -} - -MIM.Map = function (name) -{ - this.name = name; - this.rules = new Array (); -}; - -(function () { - var proto = new Xex.Term ('map'); - - proto.Parser = function (domain, node) - { - var name = node.attributes['mname'].nodeValue; - if (! name) - throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map"); - var map = new MIM.Map (name); - for (var n = node.firstChild; n; n = n.nextSibling) - if (n.nodeType == 1) - map.rules.push (Xex.Term.Parse (domain, n)); - return map; - } - - proto.toString = function () - { - var str = ''; - var len = this.rules.length; - for (i = 0; i < len; i++) - str += this.rules[i]; - return str + ''; - } - - MIM.Map.prototype = proto; -}) (); - -Xex.CatchTag._mimtag = new Xex.SymTerm ('@mimtag'); - -MIM.Action = function (domain, terms) -{ - var args = new Array (); - args.push (Xex.CatchTag_.mimtag); - for (var i = 0; i < terms.length; i++) - args.push (terms[i]); - this.action = Xex.Funcall.prototype.New (domain, 'catch', null, args); -} - -MIM.Action.prototype.Run = function (domain) -{ - var result = this.action.Eval (domain); - if (result.type == 'error') - { - domain.context.Error = result.toString (); - return false; - } - return (result != Xex.CatchTag._mimtag); -} - -MIM.Keymap = function () -{ - this.name = 'TOP'; - this.submaps = null; -}; - -(function () { - var proto = {}; - - function add_rule (keymap, rule, branch_actions) - { - var keyseq = rule.keyseq; - var len = keyseq.val.length; - var name = ''; - - for (var i = 0; i < len; i++) - { - var key = keyseq.val[i]; - var sub = false; - - name += key.key; - if (! keymap.submaps) - keymap.submaps = {}; - else - sub = keymap.submaps[key.key]; - if (! sub) - keymap.submaps[key.key] = sub = new MIM.Keymap (); - keymap = sub; - keymap.name = name; - } - keymap.map_actions = rule.actions; - keymap.branch_actions = branch_actions; - } - - proto.Add = function (map, branch_actions) - { - var rules = map.rules; - var len = rules.length; - - for (var i = 0; i < len; i++) - add_rule (this, rules[i], branch_actions); - } - proto.Lookup = function (keys, index) - { - var sub; - - if (index < keys.val.length && this.submaps - && ! keys.val[index]) - { - Xex.Log ('invalid key at ' + index); - throw 'invalid key'; - } - - if (index < keys.val.length && this.submaps - && (sub = this.submaps[keys.val[index].key])) - { - index++; - return sub.Lookup (keys, index); - } - return { map: this, index: index }; - } - - MIM.Keymap.prototype = proto; -}) (); - -MIM.State = function (name) -{ - this.name = name; - this.keymap = new MIM.Keymap (); + return (obj.responseXML && obj.responseXML.firstChild); }; (function () { - var proto = new Xex.Term ('state'); - - proto.Parser = function (domain, node) + function getxml (event) { - var map_list = domain.map_list; - var name = node.attributes['sname'].nodeValue; - if (! name) - throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map"); - var state = new MIM.State (name); - for (node = node.firstElement (); node; node = node.nextElement ()) - { - if (node.nodeName == 'title') - state.title = node.firstChild.nodeValue; - else - { - var n = node.firstElement (); - if (node.nodeName == 'branch') - state.keymap.Add (map_list[node.attributes['mname'].nodeValue], - Xex.Term.Parse (domain, n, null)); - else if (node.nodeName == 'state-hook') - state.enter_actions = Xex.Term.Parse (domain, n, null); - else if (node.nodeName == 'catch-all-branch') - state.fallback_actions = Xex.Term.Parse (domain, n, null); - } - } - return state; - } + var parser = new DOMParser (); + Xex.xml = parser.parseFromString (event.data, 'text/xml'); + }; - proto.toString = function () - { - return '' + this.keymap + ''; + Xex.LoadTesting = function (server, file) + { + var body = document.getElementsByTagName ('body')[0]; + Xex.xml = undefined; + window.addEventListener ('message', getxml, false); + var iframe = document.createElement ('iframe'); + iframe.src = server + '/loadxml.html#' + file; + alert ('iframe created'); + body.appendChild (iframe); +/* + while (! Xex.xml) + alert ('wait loading ' + file); + window.removeEventListener ('message', getxml, false); + body.removeChild (iframe); + return (Xex.xml.firstChild); +*/ } - - MIM.State.prototype = proto; }) (); - -(function () { - function Block (index, term) - { - this.Index = index; - if (term.IsStr) - this.Data = term.val; - else if (term.IsList) - { - this.Data = new Array (); - for (var i = 0; i < term.val.length; i++) - this.Data.push (term.val[i].val); - } - } - - Block.prototype.Count = function () { return this.Data.length; } - Block.prototype.get = function (i) - { - return (this.Data instanceof Array ? this.Data[i] : this.Data.charAt (i)); - } - - MIM.Candidates = function (candidates, column) - { - this.column = column; - this.row = 0; - this.index = 0; - this.total = 0; - this.blocks = new Array (); - - for (var i = 0; i < candidates.length; i++) - { - var block = new Block (this.total, candidates[i]); - this.blocks.push (block); - this.total += block.Count (); - } - } - - function get_col () - { - return (this.column > 0 ? this.index % this.column - : this.index - this.blocks[this.row].Index); - } - - function prev_group () - { - var col = get_col.call (this); - var nitems; - if (this.column > 0) - { - this.index -= this.column; - if (this.index >= 0) - nitems = this.column; - else - { - var lastcol = (this.total - 1) % this.column; - this.index = (col < lastcol ? this.total - lastcol + col - : this.total - 1); - this.row = this.blocks.length - 1; - nitems = lastcol + 1; - } - while (this.blocks[this.row].Index > this.index) - this.row--; - } - else - { - this.row = this.row > 0 ? this.row - 1 : this.blocks.length - 1; - nitems = this.blocks[this.row].Count (); - this.index = (this.blocks[this.row].Index - + (col < nitems ? col : nitems - 1)); - } - return nitems; - } - - function next_group () - { - var col = get_col.call (this); - var nitems; - if (this.column > 0) - { - this.index += this.column - col; - if (this.index < this.total) - { - if (this.index + col >= this.total) - { - nitems = this.total - this.index; - this.index = this.total - 1; - } - else - { - nitems = this.column; - this.index += col; - } - } - else - { - this.index = col; - this.row = 0; - } - while (this.blocks[this.row].Index > this.index) - this.row++; - } - else - { - this.row = this.row < this.blocks.length - 1 ? this.row + 1 : 0; - nitems = this.blocks[this.row].Count (); - this.index = (this.blocks[this.row].Index - + (col < nitems ? col : nitems - 1)); - } - return nitems; - } - - function prev () - { - if (this.index == 0) - { - this.index = this.total - 1; - this.row = this.blocks.length - 1; - } - else - { - this.index--; - if (this.blocks[this.row].Index > this.index) - this.row--; - } - } - - function next () - { - this.index++; - if (this.index == this.total) - { - this.index = 0; - this.row = 0; - } - else - { - var b = this.blocks[this.row]; - if (this.index == b.Index + b.Count ()) - this.row++; - } - } - - function first () - { - this.index -= get_col.call (this); - while (this.blocks[this.row].Index > this.index) - this.row--; - } - - function last () - { - var b = this.blocks[this.row]; - if (this.column > 0) - { - if (this.index + 1 < this.total) - { - this.index += this.column - get_col.call (this) + 1; - while (b.Index + b.Count () <= this.index) - b = this.blocks[++this.row]; - } - } - else - this.index = b.Index + b.Count () - 1; - } - - MIM.Candidates.prototype.Current = function () - { - var b = this.blocks[this.row]; - return b.get (this.index - b.Index); - } - - MIM.Candidates.prototype.Select = function (selector) - { - if (selector.type == 'selector') - { - switch (selector.val) - { - case '@<': first.call (this); break; - case '@>': last.call (this); break; - case '@-': prev.call (this); break; - case '@+': next.call (this); break; - case '@[': prev_group.call (this); break; - case '@]': next_group.cal (this); break; - default: break; - } - return this.Current (); - } - var col, start, end - if (this.column > 0) - { - col = this.index % this.column; - start = this.index - col; - end = start + this.column; - } - else - { - start = this.blocks[this.row].Index; - col = this.index - start; - end = start + this.blocks[this.row].Count; - } - if (end > this.total) - end = this.total; - this.index += selector.val - col; - if (this.index >= end) - this.index = end - 1; - if (this.column > 0) - { - if (selector.val > col) - while (this.blocks[this.row].Index + this.blocks[this.row].Count - < this.index) - this.row++; - else - while (this.blocks[this.row].Index > this.index) - this.row--; - } - return this.Current (); - } -}) (); - -MIM.im_domain = new Xex.Domain ('input-method', null, null); -MIM.im_domain.DefType (MIM.KeySeq.prototype); -MIM.im_domain.DefType (MIM.Marker.prototype); -MIM.im_domain.DefType (MIM.Selector.prototype); -MIM.im_domain.DefType (MIM.Rule.prototype); -MIM.im_domain.DefType (MIM.Map.prototype); -MIM.im_domain.DefType (MIM.State.prototype); - -(function () { - var im_domain = MIM.im_domain; - - function Finsert (domain, vari, args) - { - var text; - if (args[0].type == 'integer') - text = String.fromCharCode (args[0].val); - else - text = args[0].val; - domain.context.ins (text, null); - return args[0]; - } - - function Finsert_candidates (domain, vari, args) - { - var ic = domain.context; - var gsize = domain.variables['candidates_group_size']; - var candidates = new MIM.Candidates (args, gsize ? gsize.Intval () : 0); - ic.ins (candidates.Current (), candidates); - return args[0]; - } - - function Fdelete (domain, vari, args) - { - var ic = domain.context; - var pos = args[0].IsInt ? args[0].Intval () : args[0].Position (ic); - return new Xex.IntTerm (ic.del (pos)); - } - - function Fselect (domain, vari, args) - { - var ic = domain.context; - var can = ic.candidates; - - if (can) - { - var old_text = can.Current (); - var new_text = can.Select (args[0]); - ic.rep (old_text, new_text, can); - } - else - Xex.Log ('no candidates at ' + ic.cursor_pos + ' of ' + ic.candidate_table.table.length); - return args[0]; - } - - function Fshow (domain, vari, args) - { - domain.context.candidate_show = true; - domain.context.changed |= MIM.ChangedStatus.CandidateShow; - return Xex.nil; - } - - function Fhide (domain, vari, args) - { - domain.context.candidate_show = false; - domain.context.changed |= MIM.ChangedStatus.CandidateShow; - return Xex.nil; - } - - function Fchar_at (domain, vari, args) - { - return new Xex.IntTerm (args[0].CharAt (domain.context)); - } - - function Fmove (domain, vari, args) - { - var ic = domain.context; - var pos = args[0].IsInt ? args[0].val : args[0].Position (ic); - ic.move (pos); - return new Xex.IntTerm (pos); - } - - function Fmark (domain, vari, args) - { - args[0].Mark (domain.context); - return args[0]; - } - - function Fpushback (domain, vari, args) - { - var a = (args[0].IsInt ? args[0].Intval () - : args[0].IsStr ? new KeySeq (args[0]) - : args[0]); - domain.context.pushback (a); - return args[0]; - } - - function Fpop (domain, vari, args) - { - var ic = domain.context; - if (ic.key_head < ic.keys.val.length) - ic.keys.val.splice (ic.keys_head, 1); - return Xex.nil; - } - - function Fundo (domain, vari, args) - { - var ic = domain.context; - var n = args.length == 0 ? -2 : args[0].val; - Xex.Log ('undo with arg ' + args[0]); - if (n < 0) - ic.keys.val.splice (ic.keys.val.length + n, -n); - else - ic.keys.val.splice (n, ic.keys.val.length); - ic.reset (); - return Xex.nil; - } - - function Fcommit (domain, vari, args) - { - domain.context.commit (); - return Xex.nil; - } - - function Funhandle (domain, vari, args) - { - domain.context.commit (); - return Xex.Fthrow (domain, vari, Xex.CatchTag._mimtag); - } - - function Fshift (domain, vari, args) - { - var ic = domain.context; - var state_name = args[0].val; - var state = ic.im.state_list[state_name]; - if (! state) - throw ("Unknown state: " + state_name); - ic.shift (state); - return args[0]; - } - - function Fshiftback (domain, vari, args) - { - domain.context.shift (null); - return Xex.nil; - } - - function Fkey_count (domain, vari, args) - { - return new Xex.IntTerm (domain.context.key_head); - } - - function Fsurrounding_flag (domain, vari, args) - { - return new Xex.IntTerm (-1); - } - - im_domain.DefSubr (Finsert, "insert", false, 1, 1); - im_domain.DefSubr (Finsert_candidates, "insert-candidates", false, 1, 1); - im_domain.DefSubr (Fdelete, "delete", false, 1, 1); - im_domain.DefSubr (Fselect, "select", false, 1, 1); - im_domain.DefSubr (Fshow, "show-candidates", false, 0, 0); - im_domain.DefSubr (Fhide, "hide-candidates", false, 0, 0); - im_domain.DefSubr (Fmove, "move", false, 1, 1); - im_domain.DefSubr (Fmark, "mark", false, 1, 1); - im_domain.DefSubr (Fpushback, "pushback", false, 1, 1); - im_domain.DefSubr (Fpop, "pop", false, 0, 0); - im_domain.DefSubr (Fundo, "undo", false, 0, 1); - im_domain.DefSubr (Fcommit, "commit", false, 0, 0); - im_domain.DefSubr (Funhandle, "unhandle", false, 0, 0); - im_domain.DefSubr (Fshift, "shift", false, 1, 1); - im_domain.DefSubr (Fshiftback, "shiftback", false, 0, 0); - im_domain.DefSubr (Fchar_at, "char-at", false, 1, 1); - im_domain.DefSubr (Fkey_count, "key-count", false, 0, 0); - im_domain.DefSubr (Fsurrounding_flag, "surrounding-text-flag", false, 0, 0); -}) (); - - -(function () { - function get_global_var (vname) - { - if (MIM.im_global.load_status == MIM.LoadStatus.NotLoaded) - MIM.im_global.Load () - return MIM.im_global.domain.variables[vname]; - } - - function include (node) - { - node = node.firstElement (); - if (node.nodeName != 'tags') - return null; - - var lang = null, name = null, extra = null; - for (node = node.firstElement (); node; node = node.nextElement ()) - { - if (node.nodeName == 'language') - lang = node.firstChild.nodeValue; - else if (node.nodeName == 'name') - name = node.firstChild.nodeValue; - else if (node.nodeName == 'extra-id') - extra = node.firstChild.nodeValue; - } - if (! lang || ! MIM.imlist[lang]) - return null; - if (! extra) - { - if (! name || ! (im = MIM.imlist[lang][name])) - return null; - } - else - { - if (! (im = MIM.imextra[lang][extra])) - return null; - } - if (im.load_status != MIM.LoadStatus.Loaded - && (im.load_status != MIM.LoadStatus.NotLoaded || ! im.Load ())) - return null; - return im; - } - - var parsers = { }; - - parsers['description'] = function (node) - { - this.description = node.firstChild.nodeValue; - } - parsers['variable-list'] = function (node) - { - for (node = node.firstElement (); node; node = node.nextElement ()) - { - var vname = node.attributes['vname'].nodeValue; - if (this != MIM.im_global) - { - var vari = get_global_var (vname); - if (vari != null) - this.domain.Defvar (vname); - } - vname = Xex.Term.Parse (this.domain, node) - } - } - parsers['command-list'] = function (node) - { - } - parsers['macro-list'] = function (node) - { - for (var n = node.firstElement (); n; n = n.nextElement ()) - if (n.nodeName == 'xi:include') - { - var im = include (n); - if (! im) - alert ('inclusion fail'); - else - for (var macro in im.domain.functions) - { - var func = im.domain.functions[macro]; - if (func instanceof Xex.Macro) - im.domain.CopyFunc (this.domain, macro); - } - n = n.previousSibling; - node.removeChild (n.nextSibling); - } - Xex.Term.Parse (this.domain, node.firstElement (), null); - } - parsers['title'] = function (node) - { - this.title = node.firstChild.nodeValue; - } - parsers['map-list'] = function (node) - { - for (node = node.firstElement (); node; node = node.nextElement ()) - { - if (node.nodeName == 'xi:include') - { - var im = include (node); - if (! im) - { - alert ('inclusion fail'); - continue; - } - for (var mname in im.map_list) - this.map_list[mname] = im.map_list[mname]; - } - else - { - var map = Xex.Term.Parse (this.domain, node); - this.map_list[map.name] = map; - } - } - } - parsers['state-list'] = function (node) - { - this.domain.map_list = this.map_list; - for (node = node.firstElement (); node; node = node.nextElement ()) - { - if (node.nodeName == 'xi:include') - { - var im = include (node); - if (! im) - alert ('inclusion fail'); - for (var sname in im.state_list) - { - state = im.state_list[sname]; - if (! this.initial_state) - this.initial_state = state; - this.state_list[sname] = state; - } - } - else if (node.nodeName == 'state') - { - var state = Xex.Term.Parse (this.domain, node); - if (! state.title) - state.title = this.title; - if (! this.initial_state) - this.initial_state = state; - this.state_list[state.name] = state; - } - } - delete this.domain.map_list; - } - - MIM.IM = function (lang, name, extra_id, file) - { - this.lang = lang; - this.name = name; - this.extra_id = extra_id; - this.file = file; - this.load_status = MIM.LoadStatus.NotLoaded; - this.domain = new Xex.Domain (this.lang + '-' - + (this.name != 'nil' - ? this.name : this.extra_id), - MIM.im_domain, null); - } - - var proto = { - Load: function () - { - var node = Xex.Load (null, this.file); - if (! node) - { - this.load_status = MIM.LoadStatus.Error; - return false; - } - this.map_list = {}; - this.initial_state = null; - this.state_list = {}; - for (node = node.firstElement (); node; node = node.nextElement ()) - { - var name = node.nodeName; - var parser = parsers[name]; - if (parser) - parser.call (this, node); - } - this.load_status = MIM.LoadStatus.Loaded; - return true; - } - } - - MIM.IM.prototype = proto; - - MIM.IC = function (im, target) - { - if (im.load_status == MIM.LoadStatus.NotLoaded) - im.Load (); - if (im.load_status != MIM.LoadStatus.Loaded) - alert ('im:' + im.name + ' error:' + im.load_status); - this.im = im; - this.target = target; - this.domain = new Xex.Domain ('context', im.domain, this); - this.active = true; - this.range = new Array (); - this.range[0] = this.range[1] = 0; - this.state = null; - this.initial_state = this.im.initial_state; - this.keys = new MIM.KeySeq (); - this.marker_positions = new Array (); - this.candidate_table = new MIM.CandidateTable (); - this.reset (); - } - - MIM.CandidateTable = function () - { - this.table = new Array (); - } - - MIM.CandidateTable.prototype.get = function (pos) - { - for (var i = 0; i < this.table.length; i++) - { - var elt = this.table[i]; - if (elt.from < pos && pos <= elt.to) - return elt.val; - } - } - - MIM.CandidateTable.prototype.put = function (from, to, candidates) - { - for (var i = 0; i < this.table.length; i++) - { - var elt = this.table[i]; - if (elt.from < to && elt.to > from) - { - elt.from = from; - elt.to = to; - elt.val = candidates; - return; - } - } - this.table.push ({ from: from, to: to, val: candidates }); - } - - MIM.CandidateTable.prototype.adjust = function (from, to, inserted) - { - var diff = inserted - (to - from); - if (diff == 0) - return; - for (var i = 0; i < this.table.length; i++) - { - var elt = this.table[i]; - if (elt.from >= to) - { - elt.from += diff; - elt.to += diff; - } - } - } - - MIM.CandidateTable.prototype.clear = function () - { - this.table.length = 0; - } - - function detach_candidates (ic) - { - ic.candidate_table.clear (); - ic.candidates = null; - ic.changed |= (MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos - | MIM.ChangedStatus.CandidateList - | MIM.ChangedStatus.CandidateIndex - | MIM.ChangedStatus.CandidateShow); - } - - function set_cursor (prefix, pos) - { - this.cursor_pos = pos; - this.candidates = this.candidate_table.get (pos); - } - - function save_state () - { - this.state_var_values = this.domain.SaveValues (); - this.state_preedit = this.preedit; - this.state_key_head = this.key_head; - this.state_pos = this.cursor_pos; - } - - function restore_state () - { - this.domain.RestoreValues (this.state_var_values); - this.preedit = this.state_preedit; - set_cursor.call (this, "restore", this.state_pos); - } - - function handle_key () - { - Xex.Log ('Key(' + this.key_head + ') "' + this.keys.val[this.key_head] - + '" in ' + this.state.name + ':' + this.keymap.name - + " key/state/commit-head/len:" - + this.key_head + '/' + this.state_key_head + '/' + this.commit_key_head + '/' + this.keys.val.length); - var out = this.state.keymap.Lookup (this.keys, this.state_key_head); - var sub = out.map; - - if (out.index > this.key_head) - { - this.key_head = out.index; - Xex.Log (' with submap for ' + this.key_head + 'keys'); - restore_state.call (this); - this.keymap = sub; - if (sub.map_actions) - { - Xex.Log ('taking map actions:'); - if (! this.take_actions (sub.map_actions)) - return false; - } - else if (sub.submaps) - { - Xex.Log ('no map actions'); - for (var i = this.state_key_head; i < this.key_head; i++) - { - Xex.Log ('inserting key:' + this.keys.val[i].key); - this.ins (this.keys.val[i].key, null); - } - } - if (! sub.submaps) - { - Xex.Log ('terminal:'); - if (this.keymap.branch_actions != null) - { - Xex.Log ('branch actions:'); - if (! this.take_actions (this.keymap.branch_actions)) - return false; - } - if (sub != this.state.keymap) - this.shift (this.state); - } - } - else - { - Xex.Log (' without submap'); - this.keymap = sub; - var current_state = this.state; - var map = this.keymap; - - if (map.branch_actions) - { - Xex.Log ('branch actions'); - if (! this.take_actions (map.branch_actions)) - return false; - } - - if (map == this.keymap) - { - Xex.Log ('no state change'); - if (map == this.initial_state.keymap - && this.key_head < this.keys.val.length) - { - Xex.Log ('unhandled'); - return false; - } - if (this.keymap != current_state.keymap) - this.shift (current_state); - else if (this.keymap.actions == null) - this.shift (this.initial_state); - } - } - return true; - } - - proto = { - reset: function () - { - this.cursor_pos = 0; - this.candidate_show = false; - this.prev_state = null; - this.title = this.initial_state.title; - this.state_preedit = ''; - this.state_key_head = 0; - this.state_var_values = {}; - this.state_pos = 0; - this.key_head = 0; - this.commit_key_head = 0; - this.key_unhandled = false; - this.unhandled_key = null; - this.changed = MIM.ChangedStatus.None; - this.error_message = ''; - this.title = this.initial_state.title; - this.produced = ''; - this.preedit = ''; - this.preedit_saved = ''; - this.candidate_table.clear (); - this.candidates = null; - this.candidate_show = false; - for (var elt in this.marker_positions) - this.marker_positions[elt] = 0; - this.shift (this.initial_state); - }, - - catch_args: new Array (Xex.CatchTag._mimtag, null), - - take_actions: function (actions) - { - var func_progn = this.domain.GetFunc ('progn'); - var func_catch = this.domain.GetFunc ('catch'); - this.catch_args[1] = new Xex.Funcall (func_progn, null, actions); - var term = new Xex.Funcall (func_catch, null, this.catch_args); - term = term.Eval (this.domain); - return (! term.IsSymbol || term.val != '@mimtag'); - }, - - GetSurroundingChar: function (pos) - { - if (pos < 0) - { - pos += this.range[0]; - if (pos < 0) - return 0; - } - else - { - pos += this.range[1]; - if (pos >= this.target.value.length) - return 0; - } - return this.target.value.charCodeAt (pos); - }, - - DelSurroundText: function (pos) - { - var text; - if (pos < 0) - { - pos += this.range[0]; - if (pos <= 0) - { - pos = 0; text = ''; - } - else - text = this.target.value.substring (0, pos); - if (this.range[0] < this.target.value.length) - text += this.target.value.substring (this.range[0]); - this.target.value = text; - this.range[1] -= this.range[0] - pos; - this.range[0] = pos; - } - else - { - pos += this.range[1]; - text = this.target.value.substring (0, this.range[1]); - if (pos >= this.target.value.length) - pos = this.target.value.length; - else - text += this.target.value.substring (pos); - this.target.value = text; - } - }, - - adjust_markers: function (from, to, inserted) - { - var diff = inserted - (to - from); - - for (var name in this.marker_positions) - { - var pos = this.marker_positions[name]; - if (pos > from) - { - if (pos >= to) - this.marker_positions[name] += diff; - else if (pos > from) - this.marker_positions[name] = from; - } - } - if (this.cursor_pos >= to) - set_cursor.call (this, 'adjust', this.cursor_pos + diff); - else if (this.cursor_pos > from) - set_cursor.call (this, 'adjust', from) - }, - - preedit_replace: function (from, to, text, candidates) - { - this.preedit = (this.preedit.substring (0, from) - + text + this.preedit.substring (to)); - this.adjust_markers (from, to, text.length); - this.candidate_table.adjust (from, to, text.length); - if (candidates) - this.candidate_table.put (from, from + text.length, candidates) - }, - - ins: function (text, candidates) - { - this.preedit_replace (this.cursor_pos, this.cursor_pos, text, candidates); - this.changed = MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos; - }, - - rep: function (old_text, new_text, candidates) - { - this.preedit_replace (this.cursor_pos - old_text.length, - this.cursor_pos, new_text, candidates); - this.changed = MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos; - }, - - del: function (pos) - { - var deleted = pos - this.cursor_pos; - if (pos < this.cursor_pos) - { - if (pos < 0) - { - this.DelSurroundText (pos); - deleted = - this.cursor_pos; - pos = 0; - } - if (pos < this.cursor_pos) - this.preedit_replace (pos, this.cursor_pos, '', null); - } - else - { - if (pos > this.preedit.length) - { - this.DelSurroundText (pos - this.preedit.length); - deleted = this.preedit.length - this.cursor_pos; - pos = this.preedit.length; - } - if (pos > this.cursor_pos) - this.preedit_replace (this.cursor_pos, pos, '', null); - } - if (deleted != 0) - this.changed = MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos; - return deleted; - }, - - show: function () - { - this.candidate_show = true; - this.changed |= MIM.ChangedStatus.CandidateShow; - }, - - hide: function () - { - this.candidate_show = false; - this.changed |= MIM.ChangedStatus.CandidateShow; - }, - - move: function (pos) - { - if (pos < 0) - pos = 0; - else if (pos > this.preedit.length) - pos = this.preedit.length; - if (pos != this.cursor_pos) - { - set_cursor.call (this, 'move', pos); - this.changed |= MIM.ChangedStatus.Preedit; - } - }, - - pushback: function (n) - { - if (n instanceof MIM.KeySeq) - { - if (this.key_head > 0) - this.key_head--; - if (this.key_head < this.keys.val.length) - this.keys.val.splice (this.key_head, - this.keys.val.length - this.key_head); - for (var i = 0; i < n.val.length; i++) - this.keys.val.push (n.val[i]); - return; - } - if (n > 0) - { - this.key_head -= n; - if (this.key_head < 0) - this.key_head = 0; - } - else if (n == 0) - this.key_head = 0; - else - { - this.key_head = - n; - if (this.key_head > this.keys.val.length) - this.key_head = this.keys.val.length; - } - Xex.Log ('0: key head = ' + this.key_head); - }, - - pop: function () - { - if (this.key_head < this.keys.val.length) - this.keys.val.splice (this.key_head, 1); - }, - - commit: function () - { - if (this.preedit.length > 0) - { - this.candidate_table.clear (); - this.produced += this.preedit; - this.preedit_replace.call (this, 0, this.preedit.length, '', null); - this.preedit_saved = ''; - this.state_pos = 0; - this.commit_key_head = this.key_head; - } - }, - - shift: function (state) - { - if (state == null) - { - if (this.prev_state == null) - return; - state = this.prev_state; - } - - if (state == this.initial_state) - { - if (this.state) - { - this.commit (); - this.keys.val.splice (0, this.key_head); - this.key_head = 0; - this.prev_state = null; - } - } - else - { - if (state != this.state) - this.prev_state = this.state; - } - if (state != this.state && state.enter_actions) - this.take_actions (state.enter_actions); - if (! this.state || this.state.title != state.title) - this.changed |= MIM.ChangedStatus.StateTitle; - this.state = state; - this.keymap = state.keymap; - save_state.call (this); - }, - - Filter: function (key) - { - if (! this.active) - { - this.key_unhandled = true; - this.unhandled_key = key; - return false; - } - if (key.key == '_reload') - return true; - this.changed = MIM.ChangedStatus.None; - this.produced = ''; - this.key_unhandled = false; - this.keys.val.push (key); - var count = 0; - while (this.key_head < this.keys.val.length) - { - if (! handle_key.call (this)) - { - if (this.key_head < this.keys.val.length) - { - this.unhandled_key = this.keys.val[this.key_head]; - this.keys.val.splice (this.key_head, this.key_head + 1); - } - if (this.state_key_head > 0) - this.state_key_head--; - if (this.commit_key_head > 0) - this.commit_key_head--; - this.key_unhandled = true; - break; - } - if (++count == 10) - { - this.reset (); - this.key_unhandled = true; - break; - } - } - if (this.keymap == this.initial_state.keymap) - this.commit (); - - if (this.commit_key_head > 0) - { - this.keys.val.splice (0, this.commit_key_head); - this.key_head -= this.commit_key_head; - if (this.key_head < 0) - { - Xex.Log ('RECOVER key_head'); - this.key_head = 0; - } - this.state_key_head -= this.commit_key_head; - if (this.state_key_head < 0) - { - Xex.Log ('RECOVER state_key_head'); - this.state_key_head = 0; - } - this.commit_key_head = 0; - } - if (this.key_unhandled) - { - this.keys.val.length = 0; - //this.keys.val.splice (0, this.keys.val.length); - this.key_head = this.state_key_head = this.commit_key_head = 0; - } - return (! this.key_unhandled - && this.produced.length == 0); - } - } - - MIM.IC.prototype = proto; - - var node = Xex.Load (null, "imlist.xml"); - for (node = node.firstChild; node; node = node.nextSibling) - if (node.nodeName == 'input-method') - { - var lang = null, name = null, extra_id = null, file = null; - - for (var n = node.firstChild; n; n = n.nextSibling) - { - if (n.nodeName == 'language') - lang = n.firstChild.nodeValue; - else if (n.nodeName == 'name') - name = n.firstChild.nodeValue; - else if (n.nodeName == 'extra-id') - extra_id = n.firstChild.nodeValue; - else if (n.nodeName == 'filename') - file = n.firstChild.nodeValue; - } - if (name && name != 'nil') - { - if (! MIM.imlist[lang]) - MIM.imlist[lang] = {}; - MIM.imlist[lang][name] = new MIM.IM (lang, name, extra_id, file); - } - else if (extra_id && extra_id != 'nil') - { - if (! MIM.imextra[lang]) - MIM.imextra[lang] = {}; - MIM.imextra[lang][extra_id] = new MIM.IM (lang, name, extra_id, file); - } - } - if (MIM.imextra.t && MIM.imextra.t.global) - MIM.im_global = MIM.imextra.t.global; - else - { - MIM.im_global = new MIM.IM ('t', 'nil', 'global', null); - MIM.im_global.load_status = MIM.LoadStatus.Error; - } - node = undefined; -}) (); - -(function () { - var keys = new Array (); - keys[0x09] = 'tab'; - keys[0x08] = 'backspace'; - keys[0x0D] = 'return'; - keys[0x1B] = 'escape'; - keys[0x20] = 'space'; - keys[0x21] = 'pageup'; - keys[0x22] = 'pagedown'; - keys[0x23] = 'end'; - keys[0x24] = 'home'; - keys[0x25] = 'left'; - keys[0x26] = 'up'; - keys[0x27] = 'right'; - keys[0x28] = 'down'; - keys[0x2D] = 'insert'; - keys[0x2E] = 'delete'; - for (var i = 1; i <= 12; i++) - keys[111 + i] = "f" + i; - keys[0x90] = "numlock"; - keys[0xF0] = "capslock"; - - var keyids = {}; - keyids['U+0008'] = 'backspace'; - keyids['U+0009'] = 'tab'; - keyids['U+0018'] = 'cancel'; - keyids['U+001B'] = 'escape'; - keyids['U+0020'] = 'space'; - keyids['U+007F'] = 'delete'; - - var modifiers = {} - modifiers.Shift = 1; - modifiers.Control = 1; - modifiers.Alt = 1; - modifiers.AltGraph = 1; - modifiers.Meta = 1 - - MIM.decode_key_event = function (event) - { - var key = event.keyIdentifier; - - if (key) // keydown event of Chrome - { - if (modifiers[key]) - return false; - var mod = ''; - if (event.ctrlKey) mod += 'C-'; - if (event.metaKey) mod += 'M-'; - if (event.altKey) mod += 'A-'; - var keysym = keyids[key]; - if (keysym) - key = keysym; - else if (key.match(/^U\+([0-9A-Z]+)$/)) - { - if (mod.length == 0) - return false; - key = String.fromCharCode (parseInt (RegExp.$1, 16)); - } - else - key = key.toLowerCase (); - if (event.shiftKey) mod += 'S-'; - return new MIM.Key (mod + key); - } - else - { - key = ((event.type == 'keydown' || event.keyCode) ? event.keyCode - : event.charCode ? event.charCode - : false); - if (! key) - return false; - if (event.type == 'keydown') - { - key = keys[key]; - if (! key) - return false; - if (event.shiftKey) key = "S-" + key ; - } - else - key = String.fromCharCode (key); - } - if (event.altKey) key = "A-" + key ; - if (event.ctrlKey) key = "C-" + key ; - return new MIM.Key (key); - } -}) (); - -MIM.add_event_listener - = (window.addEventListener - ? function (target, type, listener) { - target.addEventListener (type, listener, false); - } - : window.attachEvent - ? function (target, type, listener) { - target.attachEvent ('on' + type, - function() { - listener.call (target, window.event); - }); - } - : function (target, type, listener) { - target['on' + type] - = function (e) { listener.call (target, e || window.event); }; - }); - -MIM.debug_print = function (event, ic) -{ - if (! MIM.debug) - return; - if (! MIM.debug_nodes) - { - MIM.debug_nodes = new Array (); - MIM.debug_nodes['status0'] = document.getElementById ('status0'); - MIM.debug_nodes['status1'] = document.getElementById ('status1'); - MIM.debug_nodes['keydown'] = document.getElementById ('keydown'); - MIM.debug_nodes['keypress'] = document.getElementById ('keypress'); - MIM.debug_nodes['keymap0'] = document.getElementById ('keymap0'); - MIM.debug_nodes['keymap1'] = document.getElementById ('keymap1'); - MIM.debug_nodes['preedit0'] = document.getElementById ('preedit0'); - MIM.debug_nodes['preedit1'] = document.getElementById ('preedit1'); - } - var target = event.target; - var code = event.keyCode; - var ch = event.type == 'keypress' ? event.charCode : 0; - var key = MIM.decode_key_event (event); - var index; - - MIM.debug_nodes[event.type].innerHTML = "" + code + "/" + ch + ":" + key + '/' + event.keyIdentifier; - index = (event.type == 'keydown' ? '0' : '1'); - if (ic) - MIM.debug_nodes['status' + index].innerHTML = ic.im.load_status; - else - MIM.debug_nodes['status' + index].innerHTML = 'no IM'; - MIM.debug_nodes['keymap' + index].innerHTML = ic.state.name; - MIM.debug_nodes['preedit' + index].innerHTML = ic.preedit; - if (index == 0) - { - MIM.debug_nodes.keypress.innerHTML = ''; - MIM.debug_nodes.status1.innerHTML = ''; - MIM.debug_nodes.keymap1.innerHTML = ''; - MIM.debug_nodes.preedit1.innerHTML = '' - } -}; - -MIM.get_range = function (target, ic) -{ - var from, to; - if (target.selectionStart != null) // for Mozilla - { - from = target.selectionStart; - to = target.selectionEnd; - } - else // for IE - { - var r = document.selection.createRange (); - var rr = r.duplicate (); - - rr.moveToElementText (target); - rr.setEndPoint ('EndToEnd', range); - from = rr.text.length - r.text.length; - to = rr.text.length; - } - if (ic.range[0] == from && ic.range[1] == to - && (to == from || target.value.substring (from, to) == ic.preedit)) - return true; - ic.range[0] = from; - ic.range[1] = to; - return false; -} - -MIM.set_caret = function (target, ic) -{ - if (target.setSelectionRange) // Mozilla - { - var scrollTop = target.scrollTop; - target.setSelectionRange (ic.range[0], ic.range[1]); - target.scrollTop = scrollTop; - } - else // IE - { - var range = target.createTextRange (); - range.moveStart ('character', ic.range[0]); - range.moveEnd ('character', ic.range[1]); - range.select (); - } -}; - -MIM.ignore_focus = false; - -MIM.update = function (target, ic) -{ - var text = target.value; - target.value = (text.substring (0, ic.range[0]) - + ic.produced - + ic.preedit - + text.substring (ic.range[1])); - ic.range[0] += ic.produced.length; - ic.range[1] = ic.range[0] + ic.preedit.length; - MIM.set_caret (target, ic); -}; - -MIM.focus_in = function (event) -{ - var target = event.target; - var ic = target.mim_ic; - ic.Filter (MIM.Key.FocusIn); - target.removeEventListener (''); - setTimeout (MIM.update (target, ic); - // Ignore further focus-in caused by setSelectionRange (). - target.mim_ignore_focus_in = true; - } - } -} - -MIM.cancel_ignore_focus = function () -{ - if (MIM.focus_ignore_target) - { - MIM.focus_ignore_target.mim_ignore_focus_in = false; - MIM.focus_ignore_target.mim_ignore_focus_out = false; - } -} - -MIM.focus_out = function (event) -{ - var target = event.target; - var ic = target.mim_ic; - if (ic) - { - if (target.mim_ignore_focus_out) - { - Xex.Log ('ignore focus_out in ' + target.tagName); - // Ignore this event which is caused by setSelectionRange (). - target.mim_ignore_focus_out = false; - event.preventDefault (); - } - else - { - Xex.Log ('focus_out in ' + target.tagName); - if (! MIM.get_range (target, ic)) - ic.reset (); - ic.Filter (MIM.Key.FocusOut); - // Ignore further focus-out caused by setSelectionRange (). - target.mim_ignore_focus_in = true; - target.mim_ignore_focus_out = true; - MIM.focus_ignore_target = target; - MIM.update (target, ic); - setTimeout (MIM.cancel_ignore_focus, 100); - } - } -}; - -MIM.keydown = function (event) -{ - var target = event.target; - if (target.id == 'log') - return; - if (! (target.type == "text" || target.type == "textarea")) - return; - document.akey = event; - - var ic = target.mim_ic; - if (! ic || ic.im != MIM.current) - { - target.mim_ic = null; - Xex.Log ('creating IC'); - ic = new MIM.IC (MIM.current, target); - if (ic.im.load_status != MIM.LoadStatus.Loaded) - return; - target.mim_ic = ic; - MIM.add_event_listener (target, 'focus', MIM.focus_in); - MIM.add_event_listener (target, 'blur', MIM.focus_out); - MIM.get_range (target, ic) - } - else - { - if (! MIM.get_range (target, ic)) - ic.reset (); - } - MIM.debug_print (event, ic); - ic.key = MIM.decode_key_event (event); - if (ic.key) - { - Xex.Log ("filtering " + ic.key); - try { - var result = ic.Filter (ic.key); - } catch (e) { - Xex.Log ('Error' + e); - throw (e); - } - MIM.update (target, ic); - if (! ic.key_unhandled) - event.preventDefault (); - } -}; - -MIM.keypress = function (event) -{ - var target = event.target; - if (target.id == 'log') - return; - if (! (target.type == "text" || target.type == "textarea")) - return; - - var ic = target.mim_ic; - var i; - - try { - if (ic.im.load_status != MIM.LoadStatus.Loaded) - return; - if (! ic.key) - ic.key = MIM.decode_key_event (event); - if (! ic.key) - { - ic.reset (); - return; - } - - Xex.Log ("filtering " + ic.key); - try { - var result = ic.Filter (ic.key); - } catch (e) { - Xex.Log ('Error:' + e); - throw (e); - } - MIM.update (target, ic); - if (! ic.key_unhandled) - event.preventDefault (); - } catch (e) { - Xex.Log ("error:" + e); - event.preventDefault (); - } finally { - MIM.debug_print (event, ic); - } - return; -}; - -(function () { - var lang_category = { - European: { - cs: { name: 'Czech' }, - da: { name: 'Danish' }, - el: { name: 'Greek' }, - en: { name: 'English' }, - eo: { name: 'Esperanto' }, - fr: { name: 'French' }, - grc: { name: 'ClassicGreek' }, - hr: { name: 'Croatian' }, - hy: { name: 'Armenian' }, - ka: { name: 'Georgian' }, - kk: { name: 'Kazakh' }, - ru: { name: 'Russian' }, - sk: { name: 'Slovak' }, - sr: { name: 'Serbian' }, - sv: { name: 'Swedish' }, - vi: { name: 'Vietnamese' }, - yi: { name: 'Yiddish' } }, - MiddleEast: { - ar: { name: 'Arabic' }, - dv: { name: 'Divehi' }, - fa: { name: 'Persian' }, - he: { name: 'Hebrew' }, - kk: { name: 'Kazakh' }, - ps: { name: 'Pushto' }, - ug: { name: 'Uighur' }, - yi: { name: 'Yiddish' } }, - SouthAsia: { - as: { name: 'Assamese' }, - bn: { name: 'Bengali' }, - bo: { name: 'Tibetan' }, - gu: { name: 'Gujarati' }, - hi: { name: 'Hindi' }, - kn: { name: 'Kannada' }, - ks: { name: 'Kashmiri' }, - ml: { name: 'Malayalam' }, - mr: { name: 'Marathi' }, - ne: { name: 'Nepali' }, - or: { name: 'Oriya' }, - pa: { name: 'Panjabi' }, - sa: { name: 'Sanskirit' }, - sd: { name: 'Sindhi' }, - si: { name: 'Sinhalese' }, - ta: { name: 'Tamil' }, - te: { name: 'Telugu' }, - ur: { name: 'Urdu' } }, - SouthEastAsia: { - cmc: { name: 'Cham' }, - km: { name: 'Khmer'}, - lo: { name: 'Lao' }, - my: { name: 'Burmese' }, - tai: { name: 'Tai Viet' }, - th: { name: 'Thai' }, - vi: { name: 'Vietanamese' } }, - EastAsia: { - ii: { name: 'Yii' }, - ja: { name: 'Japanese' }, - ko: { name: 'Korean' }, - zh: { name: 'Chinese' } }, - Other: { - am: { name: 'Amharic' }, - ath: { name: 'Carrier' }, - bla: { name: 'Blackfoot' }, - cr: { name: 'Cree' }, - eo: { name: 'Esperanto' }, - iu: { name: 'Inuktitut' }, - nsk: { name: 'Naskapi' }, - oj: { name: 'Ojibwe' }, - t: { name: 'Generic' } } - }; - - function categorize_im () - { - var cat, lang, list, name; - for (lang in MIM.imlist) - { - list = null; - for (cat in lang_category) - if (lang_category[cat][lang]) - { - list = lang_category[cat][lang].list; - if (! list) - list = lang_category[cat][lang].list = {}; - break; - } - if (list) - for (name in MIM.imlist[lang]) - list[name] = MIM.imlist[lang][name]; - else - for (name in MIM.imlist[lang]) - Xex.Log ('no category ' + lang + '-' + name); - } - } - - var destroy_timer; - var last_target; - - function destroy () - { - clearTimeout (destroy_timer); - destroy_timer = null; - var target = document.getElementById ('mim-menu'); - if (target) - { - for (; last_target && last_target.menu_level; - last_target = last_target.parentLi) - last_target.style.backgroundColor = 'white'; - var nodes = target.getElementsByTagName ('ul'); - for (var i = 0; i < nodes.length; i++) - nodes[i].style.visibility = 'hidden'; - document.getElementsByTagName ('body')[0].removeChild (target); - } - } - - function destroy_menu () { - if (! destroy_timer) - destroy_timer = setTimeout (destroy, 1000); - } - - function show_submenu (event) - { - if (destroy_timer) - { - clearTimeout (destroy_timer); - destroy_timer = null; - } - var target = event.target; - if (! target.menu_level) - return; - if (last_target && target.parentLi != last_target) - { - last_target.style.backgroundColor = 'white'; - if (target.menu_level < last_target.menu_level) - { - last_target = last_target.parentLi; - last_target.style.backgroundColor = 'white'; - } - var uls = last_target.getElementsByTagName ('ul'); - for (var i = 0; i < uls.length; i++) - uls[i].style.visibility = 'hidden'; - } - last_target = target; - target.style.backgroundColor = 'yellow'; - if (target.menu_level < 3) - { - target.lastChild.style.visibility = 'visible'; - target.lastChild.style.left = target.clientWidth + 'px'; - } - event.preventDefault (); - } - - function select_im (event) - { - var target = event.target; - if (target.im) - { - MIM.current = target.im; - destroy (); - } - event.preventDefault (); - } - - function create_ul (visibility) - { - var ul = document.createElement ('ul'); - ul.style.position = 'absolute'; - ul.style.margin = '0px'; - ul.style.padding = '0px'; - ul.style.border = '1px solid gray'; - ul.style.borderBottom = 'none'; - ul.style.top = '-1px'; - ul.style.backgroundColor = 'white'; - ul.style.visibility = visibility; - return ul; - } - - function create_li (level, text) - { - var li = document.createElement ('li'); - li.style.position = 'relative'; - li.style.margin = '0px'; - li.style.padding = '1px'; - li.style.borderBottom = '1px solid gray'; - li.style.top = '0px'; - li.style.listStyle = 'none'; - li.menu_level = level; - li.appendChild (document.createTextNode (text)); - return li; - } - - var menu; - - function create_menu (event) - { - var target = event.target; - - if (! ((target.type == "text" || target.type == "textarea") - && event.which == 1 && event.ctrlKey)) - return; - if (! menu) - { - categorize_im (); - menu = create_ul ('visible'); - menu.style.fontFamily = 'sans-serif'; - menu.style.fontWeight = 'bold'; - menu.id = 'mim-menu'; - menu.onclick = select_im; - menu.onmouseover = show_submenu; - menu.onmouseout = destroy_menu; - for (var catname in lang_category) - { - var cat = lang_category[catname]; - var li = create_li (1, catname); - var sub = create_ul ('hidden'); - for (var langname in cat) - { - var lang = cat[langname]; - if (! lang.list) - continue; - var sub_li = create_li (2, lang.name); - sub_li.parentLi = li; - var subsub = create_ul ('hidden'); - for (var name in lang.list) - { - var im = lang.list[name]; - var subsub_li = create_li (3, im.name); - subsub_li.parentLi = sub_li; - subsub_li.im = im; - subsub.appendChild (subsub_li); - } - sub_li.appendChild (subsub); - sub.appendChild (sub_li); - } - li.appendChild (sub); - menu.appendChild (li); - } - document.mimmenu = menu; - lang_category = null; - } - menu.style.left = (event.clientX - 10) + "px"; - menu.style.top = (event.clientY - 10) + "px"; - document.getElementsByTagName ('body')[0].appendChild (menu); - }; - - MIM.init = function () - { - MIM.add_event_listener (window, 'keydown', MIM.keydown); - MIM.add_event_listener (window, 'keypress', MIM.keypress); - MIM.add_event_listener (window, 'mousedown', create_menu); - if (window.location == 'http://localhost/mim/index.html') - MIM.server = 'http://localhost/mim'; - MIM.current = MIM.imlist['zh']['tonepy']; - }; -}) (); - -MIM.test = function () -{ - var im = MIM.imlist['t']['latn-post']; - var ic = new MIM.IC (im, null); - - ic.Filter (new MIM.Key ('a')); - ic.Filter (new MIM.Key ("'")); - - if (true) - document.getElementById ('text').value = ic.produced + ic.preedit; - else { - try { - document.getElementById ('text').value - = Xex.Term.Parse (domain, body).Eval (domain).toString (); - } catch (e) { - if (e instanceof Xex.ErrTerm) - alert (e); - throw e; - } - } -} - - -MIM.init_debug = function () -{ - MIM.debug = true; - Xex.LogNode = document.getElementById ('log'); - Xex.Log (null); - MIM.init (); -};