From cc94c262bd1e030270146ae8c62dca8549366ae7 Mon Sep 17 00:00:00 2001 From: handa Date: Wed, 27 Jan 2010 08:00:58 +0000 Subject: [PATCH] *** empty log message *** --- index.html | 2 +- latn-post.js | 4 +- mim.js | 524 +++++++++++++++++++++++++++++++++++--------------------- th-kesmanee.js | 4 +- 4 files changed, 331 insertions(+), 203 deletions(-) create mode 100644 ChangeLog diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/index.html b/index.html index f9b114d..62462a4 100644 --- a/index.html +++ b/index.html @@ -12,7 +12,7 @@ - +

m17n-lib input method in Javascript

textarea

diff --git a/latn-post.js b/latn-post.js index fb6df0b..50e1524 100644 --- a/latn-post.js +++ b/latn-post.js @@ -1,5 +1,5 @@ -im = MIM_find ('latin', 'post'); -im.load_mapdef ({ +im = MIM.find ('latin', 'post'); +im.load_map ({ " _":" ", "!/":"¡", "//":"°", diff --git a/mim.js b/mim.js index 0702a47..09d7587 100644 --- a/mim.js +++ b/mim.js @@ -1,121 +1,190 @@ // -* coding: utf-8; -* -var MIM = function () +var MIM = {}; + +// URL of the input method server. +MIM.server = "http://www.m17n.org/common/mim-js", +// Boolean flag to tell if MIM is active or not. +MIM.enabled = true; +// Boolean flag to tell if MIM is running in debug mode or not. +MIM.debug = false; +// List of registered input methods. +MIM.list = new Array (); +// Currently selected input method. +MIM.current_im = false; + +MIM.im = function (lang, name, filename) { - var server = "http://www.m17n.org/common/mim-js", - /* Boolean flag to tell if MIM is active or not. */ - var enabled = true; - /* Boolean flag to tell if MIM is running in debug mode or not. */ - var debug = false; - var current_im = false; - - function im (lang, name, filename) + this.status = 0; /* 0: not-yet-loaded, 1:loading, 2:loaded, -1:error */ + this.url = MIM.server + "/" + filename; + this.lang = lang; + this.name = name; + this.keymap = false; + this.body = null; + + function add_keystring (map, keystring, str) { - this.status = 0; /* 0: not-yet-loaded, 1:loading, 2:loaded, -1:error */ - this.url = server + "/" + filename; - this.lang = lang; - this.name = name; - this.keymap = false; + var i, c; + var newmap; + var intermediate_string = ""; - function add_keystring (map, keystring, str) + for (i = 0; i < keystring.length; i++) { - var i, c; - var newmap; - var intermediate_string = ""; - - for (i = 0; i < keystring.length; i++) - { - c = keystring.charAt (i); - if (c in map) - { - map = map[c]; - if ('_target_text' in map) - intermediate_string = map['_target_text']; - else - intermediate_string += c; - } - else - { - newmap = new Array (); - map[c] = newmap; - map['_has_child'] = true; - map = newmap; + c = keystring.charAt (i); + if (c in map) + { + map = map[c]; + if ('_target_text' in map) + intermediate_string = map['_target_text']; + else intermediate_string += c; - map['_target_text'] = intermediate_string; - } - } - map['_target_text'] = str; + } + else + { + newmap = new Array (); + map[c] = newmap; + map['_has_child'] = true; + map = newmap; + intermediate_string += c; + map['_target_text'] = intermediate_string; + } } + map['_target_text'] = str; + } - function lookup_keyseq (keyseq, limit) - { - var map = this.keymap; + this.lookup = function (keyseq, limit) + { + var map = this.keymap; - if (limit > keyseq.length) - limit = keyseq.length; - for (var i = 0; i < limit; i++) + if (limit > keyseq.length) + limit = keyseq.length; + for (var i = 0; i < limit; i++) { var c = keyseq[i]; if (! (c in map)) return i; map = map[c]; } - return map; + return map; + } + + this.load_map = function (mapdef) + { + this.keymap = new Array (); + for (var keystring in mapdef) + add_keystring (this.keymap, keystring, mapdef[keystring]); + } +}; + +MIM.error_return = function (msg, ret) +{ + alert (msg); + return ret; +} + +MIM.first_element = function (node) +{ + node.mim_index = 0; + return MIM.next_element (node); +} + +MIM.next_element = function (node) +{ + var element = node.childNodes[node.mim_index++]; + while (element && element.nodeType != 1) + element = node.childNodes[node.mim_index++]; + return element; +} + +MIM.check_map = function (im, map) +{ + var rules = map.getElementsByTagName ('rule'); + var len = rules.length; + + for (var i = 0; i < len; i++) + { + var rule = rules[i]; + var elm = MIM.first_element (rule); + + if (!elm || elm.nodeName != 'keyseq') + return false; + while ((elm = MIM.next_element (rule))) + if (elm.nodeName != 'insert') + return false; } + return true; +} - function load_map (mapdef) +MIM.check_state = function (im, state) +{ + var branches = state.getElementsByTagName ('branch'); + var len = branches.length; + + for (var i = 0; i < len; i++) { - this.keymap = new Array (); - for (var keystring in mapdef) - add_keystring (this.keymap, keystring, mapdef[keystring]); + var branch = branches[i]; + var elm = MIM.first_element (branch); + + if (elm) + return false; } + return true; +} - this.load_mapdef = load_map; - this.lookup = lookup_keyseq; - } +MIM.parse = function (im) +{ + var maps = im.body.getElementsByTagName ('map'); + var states = im.body.getElementsByTagName ('state'); + var str = ""; + var i; - return { } -} (); + if (! maps || maps.length == 0) + MIM.error_return ('No map', false); + if (! states) + MIM.error_return ('No state', false); + for (i = 0; i < maps.length; i++) + if (! MIM.check_map (im, maps[i])) + MIM.error_return ('Unsupported directive in map', false); + for (var i = 0; i < states.length; i++) + if (! MIM.check_state (im, states[i])) + MIM.error_return ('Unsupported directive in state', false); + return true; +} -function MIM_register (url, lang, name) +MIM.register = function (lang, name, url) { - var im = new M17N_im (url, lang, name); - if (! (lang in MIM_list)) - MIM_list[lang] = new Array (); - MIM_list[lang][name] = im; + var im = new MIM.im (lang, name, url); + if (! (lang in MIM.list)) + MIM.list[lang] = new Array (); + MIM.list[lang][name] = im; return im; -} +}; -function MIM_find (lang, name) +MIM.find = function (lang, name) { - if (! (lang in MIM_list)) + if (! (lang in MIM.list)) return false; - if (! (name in MIM_list[lang])) + if (! (name in MIM.list[lang])) return false; - return MIM_list[lang][name]; -} - + return MIM.list[lang][name]; +}; -function MIM_load_async (im) +MIM.load_async = function (im) { - var filename = MIM_url + "/" + im.url; var obj = (window.XMLHttpRequest ? new XMLHttpRequest () : window.ActiveXObject ? new ActiveXObject ("Msxml2.XMLHTTP") : null); if (! obj) alert ("XMLHttpRequest not supported"); - alert ("loading " + filename); - obj.open ('GET', filename, true); + obj.open ('GET', im.url, true); im.status = 1; /* loading */ obj.onreadystatechange = function () { - alert (obj.readyState + ":" + obj.statusText); if (obj.readyState == 4) { try { eval (obj.responseText); im.status = 2; /* loaded */ - alert ("loaded:"+obj.responseXML); } catch (e) { alert ("load error:" + e.message + " at " + e.lineNumber + " " + obj.responseText); @@ -125,55 +194,108 @@ function MIM_load_async (im) }; obj.send (null); return im; -} +}; -function MIM_load (im) +MIM.load_sync = function (im) +{ + var obj = (window.XMLHttpRequest ? new XMLHttpRequest () + : window.ActiveXObject ? new ActiveXObject ("Msxml2.XMLHTTP") + : null); + + if (! obj) + alert ("XMLHttpRequest not supported"); + if (true) + { + obj.open ('GET', im.url, false); + im.status = 1; /* loading */ + obj.send (""); + try { + eval (obj.responseText); + im.status = 2; /* loaded */ + } catch (e) { + alert ("load error:" + e.message + " at " + e.lineNumber + + " " + obj.responseText); + im.status = -1; /* load fail */ + }; + } + + if (true) { + obj.open ('GET', 'latn-post.mimx', false); + obj.overrideMimeType ('text/xml'); + obj.send (""); + im.body = obj.responseXML; + document.AnXml = im.body; + if (! MIM.parse (im)) + { + alert (im.parse_error); + return false; + } + } else { + var doc = document.implementation.createDocument ("", "", null); + doc.async = false; + doc.contentType = "text/xml"; + doc.load ('latn-post.mimx'); + document.AnXml = doc; + im.body = doc; + MIM.parse (im); + } + return im; +}; + +MIM.load = function (im) { - var filename = MIM_url + "/" + im.url; var s = document.createElement ('script'); s.charset = 'UTF-8'; - s.src = filename; + s.src = im.url; document.body.appendChild (s); document.body.removeChild (s); im.status = 2; return im; -} - -function MIM_add_event_listener (target, type, listener) -{ - if (target.addEventListener) - target.addEventListener (type, listener, false); - else if (target.attachEvent) - target.attachEvent ('on' + type, - function() { listener.call (target, window.event); }); - else - target['on' + type] - = function(e) { listener.call (target, e || window.event); }; -} - -var MIM_key = new Array (); -MIM_key[0x09] = 'tab'; -MIM_key[0x08] = 'backspace'; -MIM_key[0x0D] = 'return'; -MIM_key[0x1B] = 'escape'; -MIM_key[0x20] = 'space'; -MIM_key[0x21] = 'pageup'; -MIM_key[0x22] = 'pagedown'; -MIM_key[0x23] = 'end'; -MIM_key[0x24] = 'home'; -MIM_key[0x25] = 'left'; -MIM_key[0x26] = 'up'; -MIM_key[0x27] = 'right'; -MIM_key[0x28] = 'down'; -MIM_key[0x2D] = 'insert'; -MIM_key[0x2E] = 'delete'; -for (var i = 1; i <= 12; i++) - MIM_key[111 + i] = "f" + i; -MIM_key[0x90] = "numlock"; -MIM_key[0xF0] = "capslock"; - -function MIM_decode_key (event) +}; + +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); }; + }); + +(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"; + MIM.special_key = keys; +}) (); + +MIM.decode_key = function (event) { var key = ((event.type == 'keydown' || event.keyCode) ? event.keyCode : event.charCode ? event.charCode @@ -182,7 +304,7 @@ function MIM_decode_key (event) return false; if (event.type == 'keydown') { - key = MIM_key[key]; + key = MIM.special_key[key]; if (! key) return false; if (event.shiftKey) key = "S-" + key ; @@ -192,27 +314,36 @@ function MIM_decode_key (event) if (event.altKey) key = "A-" + key ; if (event.ctrlKey) key = "C-" + key ; return key; -} +}; -function debug_print (event, ic) +MIM.debug_print = function (event, ic) { - if (! MIM_debug) + if (! MIM.debug) return; + if (! MIM.debug_nodes) + { + MIM.debug_nodes = new Array (); + MIM.debug_nodes['status'] = document.getElementById ('status'); + MIM.debug_nodes['range'] = document.getElementById ('range'); + MIM.debug_nodes['keydown'] = document.getElementById ('keydown'); + MIM.debug_nodes['keypress'] = document.getElementById ('keypress'); + MIM.debug_nodes['keyseq'] = document.getElementById ('keyseq'); + } var target = event.target; var code = event.keyCode; - var ch = event.type == 'keydown' ? "-none-" : event.charCode; - var key = MIM_decode_key (event); - - document.getElementById (event.type).innerHTML = "" + code + "/" + ch + " : " + key; - document.getElementById ('status').innerHTML = ic.im.status; + var ch = event.type == 'keydown' ? 0 : event.charCode; + var key = MIM.decode_key (event); var keyseq = ""; + + MIM.debug_nodes[event.type].innerHTML = "" + code + "/" + ch + " : " + key; + MIM.debug_nodes['status'].innerHTML = ic.im.status; for (var i = 0; i < ic.keyseq.length; i++) keyseq += ic.keyseq[i]; - document.getElementById ('keyseq').innerHTML = keyseq + ":" + ic.keyseq.length; - document.getElementById ('range').innerHTML = "" + ic.range[0] + "," + ic.range[1];; -} + MIM.debug_nodes['keyseq'].innerHTML = keyseq + ":" + ic.keyseq.length; + MIM.debug_nodes['range'].innerHTML = "" + ic.range[0] + "," + ic.range[1];; +}; -function MIM_get_range (target, range) +MIM.get_range = function (target, range) { if (target.selectionStart != null) { @@ -251,31 +382,29 @@ function MIM_get_range (target, range) return true; } return false; -} +}; -function MIM_set_caret (target, pos) +MIM.set_caret = function (target, pos) { - if (target.selectionStart != null) + if(/*@cc_on ! @*/ false) // IE { - // Mozilla - target.focus (); - target.setSelectionRange (pos, pos); - return true; - } - if (target.createTextRange != null) - { - // IE var range = target.createTextRange (); range.move ('character', pos); ranges.elect (); return true; } + if (target.selectionStart != null) // Mozilla + { + target.focus (); + target.setSelectionRange (pos, pos); + return true; + } // Unknown target.focus (); return false; -} +}; -function MIM_ic (im, target) +MIM.ic = function (im, target) { this.im = im; this.target = target; @@ -283,22 +412,22 @@ function MIM_ic (im, target) this.keyseq = new Array (); this.range = new Array (-1, -1); return this; -} +}; -MIM_ic.prototype.reset = function () +MIM.ic.prototype.reset = function () { this.key = false; while (this.keyseq.length > 0) this.keyseq.pop (); this.range[0] = this.range[1] = -1; -} +}; -MIM_ic.prototype.check_caret = function () +MIM.ic.prototype.check_caret = function () { var from = this.range[0]; var to = this.range[1]; - MIM_get_range (this.target, this.range); + MIM.get_range (this.target, this.range); if (from >= 0) { if (this.range[0] != this.range[1] || to != this.range[0]) @@ -306,17 +435,17 @@ MIM_ic.prototype.check_caret = function () else this.range[0] = from; } -} +}; -function MIM_insert (ic, insert) +MIM.insert = function (ic, insert) { var text = ic.target.value; ic.target.value = (text.substring (0, ic.range[0]) + insert + text.substring (ic.range[1])); ic.range[1] = ic.range[0] + insert.length; - MIM_set_caret (ic.target, ic.range[1]); -} + MIM.set_caret (ic.target, ic.range[1]); +}; function keyseq_string (keyseq) { @@ -326,12 +455,12 @@ function keyseq_string (keyseq) return str; } -function MIM_handle_keyseq (event, ic) +MIM.handle_keyseq = function (event, ic) { var map = ic.im.lookup (ic.keyseq, 1000); if (map instanceof Array) { - MIM_insert (ic, map['_target_text']); + MIM.insert (ic, map['_target_text']); if (! ('_has_child' in map)) ic.reset (); event.preventDefault (); @@ -340,7 +469,7 @@ function MIM_handle_keyseq (event, ic) } else if (map > 0) { - MIM_insert (ic, ic.im.lookup (ic.keyseq, map)['_target_text']); + MIM.insert (ic, ic.im.lookup (ic.keyseq, map)['_target_text']); while (map > 0) { ic.keyseq.shift (); @@ -348,7 +477,7 @@ function MIM_handle_keyseq (event, ic) } ic.range[0] = ic.range[1]; if (ic.keyseq.length > 0) - MIM_handle_keyseq (event, ic); + MIM.handle_keyseq (event, ic); } else { @@ -356,35 +485,35 @@ function MIM_handle_keyseq (event, ic) //document.getElementById ('text').value //= keyseq_string (ic.keyseq) + " unhandled"; } -} +}; -function MIM_reset_ic (event) +MIM.reset_ic = function (event) { var ic = event.target.mim_ic; if (ic) ic.reset (); -} +}; -function MIM_keydown (event) +MIM.keydown = function (event) { if (! (event.target.type == "text" || event.target.type == "textarea")) return; var ic = event.target.mim_ic; - if (! ic || ic.im != MIM_current_im) + if (! ic || ic.im != MIM.current_im) { - ic = new MIM_ic (MIM_current_im, event.target); + ic = new MIM.ic (MIM.current_im, event.target); event.target.mim_ic = ic; } - MIM_add_event_listener (event.target, 'blur', MIM_reset_ic); - debug_print (event, ic); + MIM.add_event_listener (event.target, 'blur', MIM.reset_ic); + MIM.debug_print (event, ic); if (ic.im.status < 0) return; ic.check_caret (); - ic.key = MIM_decode_key (event); -} + ic.key = MIM.decode_key (event); +}; -function MIM_keypress (event) +MIM.keypress = function (event) { if (! (event.target.type == "text" || event.target.type == "textarea")) return; @@ -392,11 +521,11 @@ function MIM_keypress (event) var ic = event.target.mim_ic; var i; - debug_print (event, ic); + MIM.debug_print (event, ic); if (ic.im.status < 0) return; if (! ic.key) - ic.key = MIM_decode_key (event); + ic.key = MIM.decode_key (event); if (! ic.key) { ic.reset (); @@ -405,37 +534,37 @@ function MIM_keypress (event) ic.keyseq.push (ic.key); if (ic.im.status == 1) // Still loading. return; - MIM_handle_keyseq (event, ic); + MIM.handle_keyseq (event, ic); return; -} +}; -function MIM_select_im (event) +MIM.select_im = function (event) { var target = event.target.parentNode; while (target.tagName != "SELECT") target = target.parentNode; var idx = 0; var im = false; - for (var lang in MIM_list) - for (var name in MIM_list[lang]) + for (var lang in MIM.list) + for (var name in MIM.list[lang]) if (idx++ == target.selectedIndex) { - im = MIM_list[lang][name]; + im = MIM.list[lang][name]; break; } document.getElementsByTagName ('body')[0].removeChild (target); target.target.focus (); - if (im && im != MIM_current_im) - MIM_current_im = MIM_load (im); -} + if (im && im != MIM.current_im) + MIM.current_im = MIM.load (im); +}; -function MIM_destroy_menu (event) +MIM.destroy_menu = function (event) { if (event.target.tagName == "SELECT") document.getElementsByTagName ('body')[0].removeChild (event.target); -} +}; -function MIM_select_menu (event) +MIM.select_menu = function (event) { var target = event.target; @@ -444,44 +573,43 @@ function MIM_select_menu (event) return; var sel = document.createElement ('select'); - sel.onclick = MIM_select_im; - sel.onmouseout = MIM_destroy_menu; + sel.onclick = MIM.select_im; + sel.onmouseout = MIM.destroy_menu; sel.style.position='absolute'; sel.style.left = (event.clientX - 10) + "px"; sel.style.top = (event.clientY - 10) + "px"; sel.target = target; var idx = 0; - for (var lang in MIM_list) - for (var name in MIM_list[lang]) + for (var lang in MIM.list) + for (var name in MIM.list[lang]) { var option = document.createElement ('option'); var imname = lang + "-" + name; option.appendChild (document.createTextNode (imname)); option.value = imname; sel.appendChild (option); - if (MIM_list[lang][name] == MIM_current_im) + if (MIM.list[lang][name] == MIM.current_im) sel.selectedIndex = idx; idx++; } sel.size = idx; document.getElementsByTagName ('body')[0].appendChild (sel); -} +}; -MIM_current_im = MIM_register ('latn-post.js', 'latin', 'post'); -MIM_register ('th-kesmanee.js', 'th', 'kesmanee'); - -function MIM_init () +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', MIM_select_menu); + MIM.add_event_listener (window, 'keydown', MIM.keydown); + MIM.add_event_listener (window, 'keypress', MIM.keypress); + MIM.add_event_listener (window, 'mousedown', MIM.select_menu); if (window.location == 'http://localhost/mim/index.html') - MIM_url = 'http://localhost/mim'; - MIM_load (MIM_current_im); -} + MIM.server = 'http://localhost/mim'; + MIM.current_im = MIM.register ('latin', 'post', 'latn-post.js'); + MIM.register ('th', 'kesmanee', 'th-kesmanee.js'); + MIM.load_sync (MIM.current_im); +}; -function MIM_init_debug () +MIM.init_debug = function () { - MIM_debug = true; - MIM_init (); -} + MIM.debug = true; + MIM.init (); +}; diff --git a/th-kesmanee.js b/th-kesmanee.js index 050aa17..a57f7f2 100644 --- a/th-kesmanee.js +++ b/th-kesmanee.js @@ -1,5 +1,5 @@ -im = MIM_find ('th', 'kesmanee'); -im.load_mapdef ({ +im = MIM.find ('th', 'kesmanee'); +im.load_map ({ "!":"+", "\"":".", "#":"๒", -- 1.7.10.4