1 // -* coding: utf-8; -*
5 var server = "http://www.m17n.org/common/mim-js",
6 /* Boolean flag to tell if MIM is active or not. */
8 /* Boolean flag to tell if MIM is running in debug mode or not. */
10 var current_im = false;
12 function im (lang, name, filename)
14 this.status = 0; /* 0: not-yet-loaded, 1:loading, 2:loaded, -1:error */
15 this.url = server + "/" + filename;
20 function add_keystring (map, keystring, str)
24 var intermediate_string = "";
26 for (i = 0; i < keystring.length; i++)
28 c = keystring.charAt (i);
32 if ('_target_text' in map)
33 intermediate_string = map['_target_text'];
35 intermediate_string += c;
39 newmap = new Array ();
41 map['_has_child'] = true;
43 intermediate_string += c;
44 map['_target_text'] = intermediate_string;
47 map['_target_text'] = str;
50 function lookup_keyseq (keyseq, limit)
52 var map = this.keymap;
54 if (limit > keyseq.length)
55 limit = keyseq.length;
56 for (var i = 0; i < limit; i++)
66 function load_map (mapdef)
68 this.keymap = new Array ();
69 for (var keystring in mapdef)
70 add_keystring (this.keymap, keystring, mapdef[keystring]);
73 this.load_mapdef = load_map;
74 this.lookup = lookup_keyseq;
80 function MIM_register (url, lang, name)
82 var im = new M17N_im (url, lang, name);
83 if (! (lang in MIM_list))
84 MIM_list[lang] = new Array ();
85 MIM_list[lang][name] = im;
89 function MIM_find (lang, name)
91 if (! (lang in MIM_list))
93 if (! (name in MIM_list[lang]))
95 return MIM_list[lang][name];
99 function MIM_load_async (im)
101 var filename = MIM_url + "/" + im.url;
102 var obj = (window.XMLHttpRequest ? new XMLHttpRequest ()
103 : window.ActiveXObject ? new ActiveXObject ("Msxml2.XMLHTTP")
107 alert ("XMLHttpRequest not supported");
108 alert ("loading " + filename);
109 obj.open ('GET', filename, true);
110 im.status = 1; /* loading */
111 obj.onreadystatechange = function () {
112 alert (obj.readyState + ":" + obj.statusText);
113 if (obj.readyState == 4)
116 eval (obj.responseText);
117 im.status = 2; /* loaded */
118 alert ("loaded:"+obj.responseXML);
120 alert ("load error:" + e.message + " at " + e.lineNumber
121 + " " + obj.responseText);
122 im.status = -1; /* load fail */
130 function MIM_load (im)
132 var filename = MIM_url + "/" + im.url;
133 var s = document.createElement ('script');
137 document.body.appendChild (s);
138 document.body.removeChild (s);
143 function MIM_add_event_listener (target, type, listener)
145 if (target.addEventListener)
146 target.addEventListener (type, listener, false);
147 else if (target.attachEvent)
148 target.attachEvent ('on' + type,
149 function() { listener.call (target, window.event); });
152 = function(e) { listener.call (target, e || window.event); };
155 var MIM_key = new Array ();
156 MIM_key[0x09] = 'tab';
157 MIM_key[0x08] = 'backspace';
158 MIM_key[0x0D] = 'return';
159 MIM_key[0x1B] = 'escape';
160 MIM_key[0x20] = 'space';
161 MIM_key[0x21] = 'pageup';
162 MIM_key[0x22] = 'pagedown';
163 MIM_key[0x23] = 'end';
164 MIM_key[0x24] = 'home';
165 MIM_key[0x25] = 'left';
166 MIM_key[0x26] = 'up';
167 MIM_key[0x27] = 'right';
168 MIM_key[0x28] = 'down';
169 MIM_key[0x2D] = 'insert';
170 MIM_key[0x2E] = 'delete';
171 for (var i = 1; i <= 12; i++)
172 MIM_key[111 + i] = "f" + i;
173 MIM_key[0x90] = "numlock";
174 MIM_key[0xF0] = "capslock";
176 function MIM_decode_key (event)
178 var key = ((event.type == 'keydown' || event.keyCode) ? event.keyCode
179 : event.charCode ? event.charCode
183 if (event.type == 'keydown')
188 if (event.shiftKey) key = "S-" + key ;
191 key = String.fromCharCode (key);
192 if (event.altKey) key = "A-" + key ;
193 if (event.ctrlKey) key = "C-" + key ;
197 function debug_print (event, ic)
201 var target = event.target;
202 var code = event.keyCode;
203 var ch = event.type == 'keydown' ? "-none-" : event.charCode;
204 var key = MIM_decode_key (event);
206 document.getElementById (event.type).innerHTML = "" + code + "/" + ch + " : " + key;
207 document.getElementById ('status').innerHTML = ic.im.status;
209 for (var i = 0; i < ic.keyseq.length; i++)
210 keyseq += ic.keyseq[i];
211 document.getElementById ('keyseq').innerHTML = keyseq + ":" + ic.keyseq.length;
212 document.getElementById ('range').innerHTML = "" + ic.range[0] + "," + ic.range[1];;
215 function MIM_get_range (target, range)
217 if (target.selectionStart != null)
220 range[0] = target.selectionStart;
221 range[1] = target.selectionEnd;
224 if (document.selection != null)
228 var range = document.selection.createRange ();
229 var bookmark = range.getBookmark ();
230 var value = target.value;
231 var saved_value = value;
232 var marker = "_#_MARKER_#_";
233 while (value.indexOf (marker) != -1)
235 var parent = range.parentElement ();
236 if (parent == null || parent.type != "textarea")
238 range[0] = range[1] = 0;
242 range.text = marker + range.text + marker;
243 contents = this.element.value;
244 range[0] = contents.indexOf (marker);
245 contents = contents.replace(marker, "");
246 range[1] = contents.indexOf(marker);
247 target.value = originalContents;
248 range.moveToBookmark (bookmark);
256 function MIM_set_caret (target, pos)
258 if (target.selectionStart != null)
262 target.setSelectionRange (pos, pos);
265 if (target.createTextRange != null)
268 var range = target.createTextRange ();
269 range.move ('character', pos);
278 function MIM_ic (im, target)
281 this.target = target;
283 this.keyseq = new Array ();
284 this.range = new Array (-1, -1);
288 MIM_ic.prototype.reset = function ()
291 while (this.keyseq.length > 0)
293 this.range[0] = this.range[1] = -1;
296 MIM_ic.prototype.check_caret = function ()
298 var from = this.range[0];
299 var to = this.range[1];
301 MIM_get_range (this.target, this.range);
304 if (this.range[0] != this.range[1] || to != this.range[0])
307 this.range[0] = from;
311 function MIM_insert (ic, insert)
313 var text = ic.target.value;
314 ic.target.value = (text.substring (0, ic.range[0])
316 + text.substring (ic.range[1]));
317 ic.range[1] = ic.range[0] + insert.length;
318 MIM_set_caret (ic.target, ic.range[1]);
321 function keyseq_string (keyseq)
324 for (var i = 0; i < keyseq.length; i++)
329 function MIM_handle_keyseq (event, ic)
331 var map = ic.im.lookup (ic.keyseq, 1000);
332 if (map instanceof Array)
334 MIM_insert (ic, map['_target_text']);
335 if (! ('_has_child' in map))
337 event.preventDefault ();
338 //document.getElementById ('text').value
339 //= keyseq_string (ic.keyseq) + " handled";
343 MIM_insert (ic, ic.im.lookup (ic.keyseq, map)['_target_text']);
349 ic.range[0] = ic.range[1];
350 if (ic.keyseq.length > 0)
351 MIM_handle_keyseq (event, ic);
356 //document.getElementById ('text').value
357 //= keyseq_string (ic.keyseq) + " unhandled";
361 function MIM_reset_ic (event)
363 var ic = event.target.mim_ic;
368 function MIM_keydown (event)
370 if (! (event.target.type == "text" || event.target.type == "textarea"))
373 var ic = event.target.mim_ic;
374 if (! ic || ic.im != MIM_current_im)
376 ic = new MIM_ic (MIM_current_im, event.target);
377 event.target.mim_ic = ic;
379 MIM_add_event_listener (event.target, 'blur', MIM_reset_ic);
380 debug_print (event, ic);
381 if (ic.im.status < 0)
384 ic.key = MIM_decode_key (event);
387 function MIM_keypress (event)
389 if (! (event.target.type == "text" || event.target.type == "textarea"))
392 var ic = event.target.mim_ic;
395 debug_print (event, ic);
396 if (ic.im.status < 0)
399 ic.key = MIM_decode_key (event);
405 ic.keyseq.push (ic.key);
406 if (ic.im.status == 1) // Still loading.
408 MIM_handle_keyseq (event, ic);
412 function MIM_select_im (event)
414 var target = event.target.parentNode;
415 while (target.tagName != "SELECT")
416 target = target.parentNode;
419 for (var lang in MIM_list)
420 for (var name in MIM_list[lang])
421 if (idx++ == target.selectedIndex)
423 im = MIM_list[lang][name];
426 document.getElementsByTagName ('body')[0].removeChild (target);
427 target.target.focus ();
428 if (im && im != MIM_current_im)
429 MIM_current_im = MIM_load (im);
432 function MIM_destroy_menu (event)
434 if (event.target.tagName == "SELECT")
435 document.getElementsByTagName ('body')[0].removeChild (event.target);
438 function MIM_select_menu (event)
440 var target = event.target;
442 if (! ((target.type == "text" || target.type == "textarea")
443 && event.which == 1 && event.ctrlKey))
446 var sel = document.createElement ('select');
447 sel.onclick = MIM_select_im;
448 sel.onmouseout = MIM_destroy_menu;
449 sel.style.position='absolute';
450 sel.style.left = (event.clientX - 10) + "px";
451 sel.style.top = (event.clientY - 10) + "px";
454 for (var lang in MIM_list)
455 for (var name in MIM_list[lang])
457 var option = document.createElement ('option');
458 var imname = lang + "-" + name;
459 option.appendChild (document.createTextNode (imname));
460 option.value = imname;
461 sel.appendChild (option);
462 if (MIM_list[lang][name] == MIM_current_im)
463 sel.selectedIndex = idx;
467 document.getElementsByTagName ('body')[0].appendChild (sel);
470 MIM_current_im = MIM_register ('latn-post.js', 'latin', 'post');
471 MIM_register ('th-kesmanee.js', 'th', 'kesmanee');
475 MIM_add_event_listener (window, 'keydown', MIM_keydown);
476 MIM_add_event_listener (window, 'keypress', MIM_keypress);
477 MIM_add_event_listener (window, 'mousedown', MIM_select_menu);
478 if (window.location == 'http://localhost/mim/index.html')
479 MIM_url = 'http://localhost/mim';
480 MIM_load (MIM_current_im);
483 function MIM_init_debug ()